@@ -23,10 +23,6 @@ var<storage> segments: array<Segment>;
2323
2424const GRADIENT_WIDTH = 512 ;
2525
26- const IMAGE_QUALITY_LOW = 0u ;
27- const IMAGE_QUALITY_MEDIUM = 1u ;
28- const IMAGE_QUALITY_HIGH = 2u ;
29-
3026const LUMINANCE_MASK_LAYER = 0x10000u ;
3127
3228@group (0 ) @binding (2 )
@@ -153,15 +149,14 @@ fn read_image(cmd_ix: u32) -> CmdImage {
153149 let alpha = f32 (sample_alpha & 0xFFu ) / 255 .0 ;
154150 let format = sample_alpha >> 15u ;
155151 let alpha_type = (sample_alpha >> 14u ) & 0x1u ;
156- let quality = (sample_alpha >> 12u ) & 0x3u ;
157152 let x_extend = (sample_alpha >> 10u ) & 0x3u ;
158153 let y_extend = (sample_alpha >> 8u ) & 0x3u ;
159154 // The following are not intended to be bitcasts
160155 let x = f32 (xy >> 16u );
161156 let y = f32 (xy & 0xffffu );
162157 let width = f32 (width_height >> 16u );
163158 let height = f32 (width_height & 0xffffu );
164- return CmdImage (matrx , xlat , vec2 (x , y ), vec2 (width , height ), format , x_extend , y_extend , quality , alpha , alpha_type );
159+ return CmdImage (matrx , xlat , vec2 (x , y ), vec2 (width , height ), format , x_extend , y_extend , alpha , alpha_type );
165160}
166161
167162fn read_end_clip (cmd_ix : u32 ) -> CmdEndClip {
@@ -338,33 +333,20 @@ fn extend_mode(t: f32, mode: u32, max: f32) -> f32 {
338333 }
339334}
340335
341- fn image_extend_mode_normalized (t : f32 , mode : u32 ) -> f32 {
342- switch mode {
343- case EXTEND_PAD : {
344- return clamp (t , 0 .0 , 1 .0 );
345- }
346- case EXTEND_REPEAT : {
347- return fract (t );
348- }
349- case EXTEND_REFLECT , default : {
350- let reflected = fract (0 .5 * t ) * 2 .0 ;
351- return 1 .0 - abs (reflected - 1 .0 );
352- }
353- }
336+ fn image_repeat_mode_i32 (t : f32 , max : i32 ) -> i32 {
337+ let value = i32 (t );
338+ let magnitude = select (value , - value , value < 0 );
339+ let remainder = magnitude % max ;
340+ let signed_remainder = select (remainder , - remainder , value < 0 );
341+
342+ // Match the CPU ImageBrush index calculation: ((value % max) + max) % max.
343+ return (signed_remainder + max ) % max ;
354344}
355345
356- fn image_extend_mode (t : f32 , mode : u32 , max : f32 ) -> f32 {
357- switch mode {
358- case EXTEND_PAD : {
359- return clamp (t , 0 .0 , max );
360- }
361- case EXTEND_REPEAT : {
362- return image_extend_mode_normalized (t / max , mode ) * max ;
363- }
364- case EXTEND_REFLECT , default : {
365- return image_extend_mode_normalized (t / max , mode ) * max ;
366- }
367- }
346+ fn image_reflect_mode_i32 (t : f32 , max : i32 ) -> i32 {
347+ let reflected = fract (0 .5 * t ) * 2 .0 ;
348+ let wrapped = (1 .0 - abs (reflected - 1 .0 )) * f32 (max );
349+ return i32 (clamp (wrapped , 0 .0 , f32 (max - 1 )));
368350}
369351
370352fn image_extend_mode_i32 (t : f32 , mode : u32 , max : i32 ) -> i32 {
@@ -373,12 +355,10 @@ fn image_extend_mode_i32(t: f32, mode: u32, max: i32) -> i32 {
373355 return clamp (i32 (t ), 0 , max - 1 );
374356 }
375357 case EXTEND_REPEAT : {
376- let wrapped = i32 (t ) % max ;
377- return select (wrapped + max , wrapped , wrapped >= 0 );
358+ return image_repeat_mode_i32 (t , max );
378359 }
379360 case EXTEND_REFLECT , default : {
380- let reflected = clamp (image_extend_mode (t , mode , f32 (max )), 0 .0 , f32 (max - 1 ));
381- return i32 (reflected );
361+ return image_reflect_mode_i32 (t , max );
382362 }
383363 }
384364}
@@ -842,50 +822,17 @@ fn main(
842822 case CMD_IMAGE : {
843823 let image = read_image (cmd_ix );
844824 let draw_flags = info [ptcl [cmd_ix + 1u ] - 1u ];
845- let atlas_max = image . atlas_offset + image . extents - vec2 (1 .0 );
846- switch image . quality {
847- case IMAGE_QUALITY_LOW : {
848- for (var i = 0u ; i < PIXELS_PER_THREAD ; i += 1u ) {
849- // We only need to load from the textures if the value will be used.
850- if area [i ] != 0 .0 {
851- let my_xy = vec2 (xy . x + f32 (i ), xy . y );
852- var atlas_uv = image . matrx . xy * my_xy . x + image . matrx . zw * my_xy . y + image . xlat ;
853- let atlas_ix = image_extend_mode_i32 (atlas_uv . x , image . x_extend_mode , i32 (image . extents . x ));
854- let atlas_iy = image_extend_mode_i32 (atlas_uv . y , image . y_extend_mode , i32 (image . extents . y ));
855- let atlas_uv_clamped = vec2 <i32 >(i32 (image . atlas_offset . x ) + atlas_ix , i32 (image . atlas_offset . y ) + atlas_iy );
856- // Nearest neighbor sampling
857- let fg_rgba = maybe_premul_alpha (textureLoad (image_atlas , atlas_uv_clamped , 0 ), image . alpha_type );
858- let fg_i = pixel_format (fg_rgba * area [i ] * image . alpha , image . format );
859- rgba [i ] = compose_draw (rgba [i ], fg_i , draw_flags );
860- }
861- }
862- }
863- case IMAGE_QUALITY_MEDIUM , default : {
864- // We don't have an implementation for `IMAGE_QUALITY_HIGH` yet, just use the same as medium
865- for (var i = 0u ; i < PIXELS_PER_THREAD ; i += 1u ) {
866- // We only need to load from the textures if the value will be used.
867- if area [i ] != 0 .0 {
868- let my_xy = vec2 (xy . x + f32 (i ), xy . y );
869- var atlas_uv = image . matrx . xy * my_xy . x + image . matrx . zw * my_xy . y + image . xlat ;
870- atlas_uv . x = image_extend_mode (atlas_uv . x , image . x_extend_mode , image . extents . x );
871- atlas_uv . y = image_extend_mode (atlas_uv . y , image . y_extend_mode , image . extents . y );
872- atlas_uv = atlas_uv + image . atlas_offset - vec2 (0 .5 );
873- // TODO: If the image couldn't be added to the atlas (i.e. was too big), this isn't robust
874- let atlas_uv_clamped = clamp (atlas_uv , image . atlas_offset , atlas_max );
875- // We know that the floor and ceil are within the atlas area because atlas_max and
876- // atlas_offset are integers
877- let uv_quad = vec4 (floor (atlas_uv_clamped ), ceil (atlas_uv_clamped ));
878- let uv_frac = fract (atlas_uv );
879- let a = maybe_premul_alpha (textureLoad (image_atlas , vec2 <i32 >(uv_quad . xy ), 0 ), image . alpha_type );
880- let b = maybe_premul_alpha (textureLoad (image_atlas , vec2 <i32 >(uv_quad . xw ), 0 ), image . alpha_type );
881- let c = maybe_premul_alpha (textureLoad (image_atlas , vec2 <i32 >(uv_quad . zy ), 0 ), image . alpha_type );
882- let d = maybe_premul_alpha (textureLoad (image_atlas , vec2 <i32 >(uv_quad . zw ), 0 ), image . alpha_type );
883- // Bilinear sampling
884- let fg_rgba = mix (mix (a , b , uv_frac . y ), mix (c , d , uv_frac . y ), uv_frac . x );
885- let fg_i = pixel_format (fg_rgba * area [i ] * image . alpha , image . format );
886- rgba [i ] = compose_draw (rgba [i ], fg_i , draw_flags );
887- }
888- }
825+ for (var i = 0u ; i < PIXELS_PER_THREAD ; i += 1u ) {
826+ // We only need to load from the textures if the value will be used.
827+ if area [i ] != 0 .0 {
828+ let my_xy = vec2 (xy . x + f32 (i ), xy . y );
829+ var atlas_uv = image . matrx . xy * my_xy . x + image . matrx . zw * my_xy . y + image . xlat ;
830+ let atlas_ix = image_extend_mode_i32 (atlas_uv . x , image . x_extend_mode , i32 (image . extents . x ));
831+ let atlas_iy = image_extend_mode_i32 (atlas_uv . y , image . y_extend_mode , i32 (image . extents . y ));
832+ let atlas_uv_clamped = vec2 <i32 >(i32 (image . atlas_offset . x ) + atlas_ix , i32 (image . atlas_offset . y ) + atlas_iy );
833+ let fg_rgba = maybe_premul_alpha (textureLoad (image_atlas , atlas_uv_clamped , 0 ), image . alpha_type );
834+ let fg_i = pixel_format (fg_rgba * area [i ] * image . alpha , image . format );
835+ rgba [i ] = compose_draw (rgba [i ], fg_i , draw_flags );
889836 }
890837 }
891838 cmd_ix += 2u ;
@@ -903,7 +850,7 @@ fn main(
903850 let rgba_sep = vec4 (fg . rgb * a_inv , fg . a );
904851 textureStore (output , vec2 <i32 >(coords ), rgba_sep );
905852 }
906- }
853+ }
907854}
908855
909856fn premul_alpha (rgba : vec4 <f32 >) -> vec4 <f32 > {
0 commit comments