@@ -39,25 +39,11 @@ impl Draw {
3939 gpu_strip : GpuStrip ,
4040 external_texture_id : Option < TextureId > ,
4141 ) {
42- if let Some ( texture_id) = external_texture_id {
43- let needs_new_run = self
44- . external_texture_runs
45- . last ( )
46- . is_none_or ( |run| run. texture_id != texture_id) ;
47-
48- if needs_new_run {
49- let strips_start = if self . external_texture_runs . is_empty ( ) {
50- 0
51- } else {
52- self . strip_ranges . len ( )
53- } ;
54-
55- self . external_texture_runs . push ( ExternalTextureRun {
56- strips_start,
57- texture_id,
58- } ) ;
59- }
60- }
42+ push_external_texture_run (
43+ & mut self . external_texture_runs ,
44+ self . strip_ranges . len ( ) ,
45+ external_texture_id,
46+ ) ;
6147
6248 strips. push_ranged ( & mut self . strip_ranges , gpu_strip) ;
6349 }
@@ -71,15 +57,67 @@ impl Clear for Draw {
7157 }
7258}
7359
60+ /// Root-level opaque strips and the external texture bindings needed to render them.
61+ #[ derive( Debug , Default ) ]
62+ pub ( crate ) struct OpaqueDraw {
63+ strips : Vec < GpuStrip > ,
64+ external_texture_runs : Vec < ExternalTextureRun > ,
65+ }
66+
67+ impl OpaqueDraw {
68+ fn push ( & mut self , strip : GpuStrip , external_texture_id : Option < TextureId > ) {
69+ push_external_texture_run (
70+ & mut self . external_texture_runs ,
71+ self . strips . len ( ) ,
72+ external_texture_id,
73+ ) ;
74+
75+ self . strips . push ( strip) ;
76+ }
77+
78+ /// Reverse opaque strips for front-to-back rendering.
79+ pub ( crate ) fn reverse ( & mut self ) {
80+ self . strips . reverse ( ) ;
81+
82+ // We also need to reassign the indices for external textures.
83+ let mut original_end = self . strips . len ( ) ;
84+ for run in self . external_texture_runs . iter_mut ( ) . rev ( ) {
85+ let original_start = run. strips_start ;
86+ run. strips_start = self . strips . len ( ) - original_end;
87+ original_end = original_start;
88+ }
89+ self . external_texture_runs . reverse ( ) ;
90+ }
91+
92+ pub ( crate ) fn is_empty ( & self ) -> bool {
93+ self . strips . is_empty ( )
94+ }
95+
96+ pub ( crate ) fn strips ( & self ) -> & [ GpuStrip ] {
97+ & self . strips
98+ }
99+
100+ pub ( crate ) fn external_texture_runs ( & self ) -> & [ ExternalTextureRun ] {
101+ & self . external_texture_runs
102+ }
103+ }
104+
105+ impl Clear for OpaqueDraw {
106+ fn clear ( & mut self ) {
107+ self . strips . clear ( ) ;
108+ self . external_texture_runs . clear ( ) ;
109+ }
110+ }
111+
74112/// Appends recorded draws to a scheduled [`Draw`] and its shared buffers.
75113#[ derive( Debug ) ]
76114pub ( crate ) struct DrawBuilder < ' a , T : DrawTarget > {
77115 /// Draw whose ranges and binding state are being built.
78116 draw : & ' a mut Draw ,
79117 /// Shared buffer receiving alpha-blended strips.
80118 strips : & ' a mut Vec < GpuStrip > ,
81- /// Shared buffer receiving root-level opaque strips.
82- opaque : & ' a mut Vec < GpuStrip > ,
119+ /// Root-level opaque draw receiving fully covered strips.
120+ opaque : & ' a mut OpaqueDraw ,
83121 /// Target and depth state used to encode strips.
84122 state : & ' a mut DrawState < T > ,
85123}
@@ -93,7 +131,7 @@ impl<'a, T: DrawTarget> DrawBuilder<'a, T> {
93131 Self {
94132 draw,
95133 strips : & mut draw_buffers. strips ,
96- opaque : & mut draw_buffers. opaque_strips ,
134+ opaque : & mut draw_buffers. opaque ,
97135 state,
98136 }
99137 }
@@ -112,12 +150,12 @@ impl<'a, T: DrawTarget> DrawBuilder<'a, T> {
112150 }
113151 }
114152
115- fn push_opaque ( & mut self , strip : GpuStrip ) -> bool {
153+ fn push_opaque ( & mut self , strip : GpuStrip , external_texture_id : Option < TextureId > ) -> bool {
116154 if !self . state . use_depth_buffer || !self . state . target . enable_depth ( ) {
117155 return false ;
118156 }
119157
120- self . opaque . push ( strip) ;
158+ self . opaque . push ( strip, external_texture_id ) ;
121159 true
122160 }
123161
@@ -172,7 +210,7 @@ impl<'a, T: DrawTarget> DrawBuilder<'a, T> {
172210 depth_index,
173211 ) ;
174212
175- if !paint. opaque || !builder. push_opaque ( strip) {
213+ if !paint. opaque || !builder. push_opaque ( strip, paint . external_texture_id ) {
176214 builder
177215 . draw
178216 . push ( builder. strips , strip, paint. external_texture_id ) ;
@@ -217,7 +255,10 @@ impl<'a, T: DrawTarget> DrawBuilder<'a, T> {
217255 depth_index,
218256 ) ;
219257
220- if !( paint. opaque && part. frac == 0 && self . push_opaque ( strip) ) {
258+ if !( paint. opaque
259+ && part. frac == 0
260+ && self . push_opaque ( strip, paint. external_texture_id ) )
261+ {
221262 self . draw
222263 . push ( self . strips , strip, paint. external_texture_id ) ;
223264 }
@@ -309,15 +350,15 @@ impl<'a, T: DrawTarget> DrawBuilder<'a, T> {
309350/// Reusable strip storage shared by all draws in a schedule.
310351#[ derive( Debug , Default ) ]
311352pub ( crate ) struct DrawBuffers {
312- /// Opaque root strips rendered in the early depth-writing pass.
313- pub ( crate ) opaque_strips : Vec < GpuStrip > ,
353+ /// Root-level opaque draw rendered in the early depth-writing pass.
354+ pub ( crate ) opaque : OpaqueDraw ,
314355 /// Alpha-blended strips selected by each draw's ranges.
315356 pub ( crate ) strips : Vec < GpuStrip > ,
316357}
317358
318359impl DrawBuffers {
319360 pub ( crate ) fn clear ( & mut self ) {
320- self . opaque_strips . clear ( ) ;
361+ self . opaque . clear ( ) ;
321362 self . strips . clear ( ) ;
322363 }
323364}
@@ -403,17 +444,34 @@ impl LayerTextureRegion {
403444 }
404445}
405446
406- /// Specifies a run of strips inside a draw that can be drawn with the same external texture
407- /// binding.
447+ /// Specifies a run of strips that can be drawn with the same external texture binding.
408448#[ derive( Debug , Clone , PartialEq , Eq ) ]
409449pub ( crate ) struct ExternalTextureRun {
410450 /// External texture bound for the run.
411451 pub ( crate ) texture_id : TextureId ,
412452 /// Start index of the strip range for this run. The end is implicitly the start of the next
413- /// run, or, for the last run, the total number of strips.
453+ /// run, or, for the last run, the total number of strips in the pass .
414454 pub ( crate ) strips_start : usize ,
415455}
416456
457+ fn push_external_texture_run (
458+ runs : & mut Vec < ExternalTextureRun > ,
459+ strips_len : usize ,
460+ external_texture_id : Option < TextureId > ,
461+ ) {
462+ let Some ( texture_id) = external_texture_id else {
463+ return ;
464+ } ;
465+ if runs. last ( ) . is_some_and ( |run| run. texture_id == texture_id) {
466+ return ;
467+ }
468+
469+ runs. push ( ExternalTextureRun {
470+ texture_id,
471+ strips_start : if runs. is_empty ( ) { 0 } else { strips_len } ,
472+ } ) ;
473+ }
474+
417475/// Assigns monotonically increasing depth values to opaque strips.
418476#[ derive( Debug , Default , Clone , Copy ) ]
419477pub ( crate ) struct DepthCounter {
@@ -466,7 +524,8 @@ impl StripAlphaFillSegmentExt for StripAlphaFillSegment {
466524
467525#[ cfg( test) ]
468526mod tests {
469- use super :: { Draw , DrawBuffers , DrawBuilder , DrawState , ExternalTextureRun } ;
527+ use super :: { Draw , DrawBuffers , DrawBuilder , DrawState , ExternalTextureRun , OpaqueDraw } ;
528+ use crate :: GpuStrip ;
470529 use crate :: paint:: PaintResolver ;
471530 use crate :: scene:: { RecordedDraw , RecordedRect } ;
472531 use crate :: target:: {
@@ -540,6 +599,29 @@ mod tests {
540599 PaintResolver :: new ( & [ ] , & [ ] )
541600 }
542601
602+ fn gpu_strip ( x : u16 ) -> GpuStrip {
603+ GpuStrip {
604+ x,
605+ y : 0 ,
606+ width : 1 ,
607+ dense_width_or_rect_height : 0 ,
608+ col_idx_or_rect_frac : 0 ,
609+ payload : 0 ,
610+ paint_and_rect_flag : 0 ,
611+ depth_index : 0 ,
612+ }
613+ }
614+
615+ fn strip_xs ( draw : & OpaqueDraw ) -> Vec < u16 > {
616+ draw. strips ( ) . iter ( ) . map ( |strip| strip. x ) . collect ( )
617+ }
618+
619+ fn run_starts ( runs : & [ ExternalTextureRun ] ) -> Vec < ( TextureId , usize ) > {
620+ runs. iter ( )
621+ . map ( |run| ( run. texture_id , run. strips_start ) )
622+ . collect ( )
623+ }
624+
543625 fn external ( texture_id : TextureId ) -> EncodedPaint {
544626 EncodedPaint :: ExternalTexture ( EncodedExternalTexture {
545627 texture_id,
@@ -603,21 +685,8 @@ mod tests {
603685 }
604686
605687 assert_eq ! (
606- draw. external_texture_runs,
607- [
608- ExternalTextureRun {
609- texture_id: texture_a,
610- strips_start: 0 ,
611- } ,
612- ExternalTextureRun {
613- texture_id: texture_b,
614- strips_start: 2 ,
615- } ,
616- ExternalTextureRun {
617- texture_id: texture_a,
618- strips_start: 4 ,
619- } ,
620- ]
688+ run_starts( & draw. external_texture_runs) ,
689+ [ ( texture_a, 0 ) , ( texture_b, 2 ) , ( texture_a, 4 ) ]
621690 ) ;
622691 }
623692
@@ -636,15 +705,78 @@ mod tests {
636705 assert_eq ! ( draw. strip_ranges. len( ) , 3 ) ;
637706 // Images in the atlas are handled separately from external textures, so
638707 // it's fine to collapse them.
708+ assert_eq ! ( run_starts( & draw. external_texture_runs) , [ ( texture, 0 ) ] ) ;
709+ }
710+
711+ #[ test]
712+ fn opaque_reverse_rebases_texture_runs ( ) {
713+ let texture_a = TextureId ( 10 ) ;
714+ let texture_b = TextureId ( 20 ) ;
715+ let texture_c = TextureId ( 30 ) ;
716+ let mut draw = OpaqueDraw :: default ( ) ;
717+
718+ for ( x, texture_id) in [
719+ ( 0 , None ) ,
720+ ( 1 , Some ( texture_a) ) ,
721+ ( 2 , Some ( texture_a) ) ,
722+ ( 3 , None ) ,
723+ ( 4 , None ) ,
724+ ( 5 , None ) ,
725+ ( 6 , Some ( texture_b) ) ,
726+ ( 7 , Some ( texture_b) ) ,
727+ ( 8 , Some ( texture_c) ) ,
728+ ( 9 , None ) ,
729+ ( 10 , Some ( texture_c) ) ,
730+ ( 11 , None ) ,
731+ ( 12 , None ) ,
732+ ( 13 , Some ( texture_a) ) ,
733+ ( 14 , None ) ,
734+ ( 15 , Some ( texture_b) ) ,
735+ ] {
736+ draw. push ( gpu_strip ( x) , texture_id) ;
737+ }
639738 assert_eq ! (
640- draw. external_texture_runs,
641- [ ExternalTextureRun {
642- texture_id: texture,
643- strips_start: 0 ,
644- } ]
739+ run_starts( draw. external_texture_runs( ) ) ,
740+ [
741+ ( texture_a, 0 ) ,
742+ ( texture_b, 6 ) ,
743+ ( texture_c, 8 ) ,
744+ ( texture_a, 13 ) ,
745+ ( texture_b, 15 ) ,
746+ ]
747+ ) ;
748+
749+ draw. reverse ( ) ;
750+
751+ assert_eq ! (
752+ strip_xs( & draw) ,
753+ [ 15 , 14 , 13 , 12 , 11 , 10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1 , 0 ]
754+ ) ;
755+ assert_eq ! (
756+ run_starts( draw. external_texture_runs( ) ) ,
757+ [
758+ ( texture_b, 0 ) ,
759+ ( texture_a, 1 ) ,
760+ ( texture_c, 3 ) ,
761+ ( texture_b, 8 ) ,
762+ ( texture_a, 10 ) ,
763+ ]
645764 ) ;
646765 }
647766
767+ #[ test]
768+ fn opaque_reverse_without_texture_runs ( ) {
769+ let mut draw = OpaqueDraw :: default ( ) ;
770+ for x in 0 ..3 {
771+ draw. push ( gpu_strip ( x) , None ) ;
772+ }
773+
774+ draw. reverse ( ) ;
775+
776+ assert_eq ! ( strip_xs( & draw) , [ 2 , 1 , 0 ] ) ;
777+ assert_eq ! ( run_starts( draw. external_texture_runs( ) ) , [ ] ) ;
778+ }
779+
648780 #[ test]
649781 fn draw_clear ( ) {
650782 let texture_id = TextureId ( 10 ) ;
@@ -683,14 +815,14 @@ mod tests {
683815 no_paints ( ) ,
684816 ) ;
685817
686- assert_eq ! ( user_case. buffers. opaque_strips . len( ) , 1 ) ;
818+ assert_eq ! ( user_case. buffers. opaque . strips ( ) . len( ) , 1 ) ;
687819 assert_eq ! ( user_draw. strip_ranges. len( ) , 1 ) ;
688820
689821 let mut atlas_case = DrawCase :: new ( RootTarget :: AtlasLayer , RectU16 :: new ( 0 , 0 , 8 , 8 ) ) ;
690822 let mut atlas_draw = Draw :: default ( ) ;
691823 atlas_case. rect ( & mut atlas_draw, rect ( 0.0 ) , solid ( 1.0 ) , no_paints ( ) ) ;
692824
693- assert ! ( atlas_case. buffers. opaque_strips . is_empty( ) ) ;
825+ assert ! ( atlas_case. buffers. opaque . is_empty( ) ) ;
694826 assert_eq ! ( atlas_draw. strip_ranges. len( ) , 1 ) ;
695827 }
696828
@@ -726,7 +858,8 @@ mod tests {
726858 ) ;
727859 assert_eq ! (
728860 case. buffers
729- . opaque_strips
861+ . opaque
862+ . strips( )
730863 . iter( )
731864 . map( |strip| strip. depth_index)
732865 . collect:: <Vec <_>>( ) ,
0 commit comments