@@ -51,15 +51,13 @@ tile_dispose(GObject *object)
5151
5252 VIPS_UNREF (tile -> texture );
5353 VIPS_FREEF (g_bytes_unref , tile -> bytes );
54- VIPS_UNREF (tile -> region );
5554
5655 G_OBJECT_CLASS (tile_parent_class )-> dispose (object );
5756}
5857
5958static void
6059tile_init (Tile * tile )
6160{
62- tile -> time = tile_ticks ++ ;
6361}
6462
6563static void
@@ -78,6 +76,15 @@ tile_get_time(void)
7876 return tile_ticks ;
7977}
8078
79+ /* The pixels in the region have changed. We must regenerate the texture on
80+ * next use.
81+ */
82+ void
83+ tile_invalidate (Tile * tile )
84+ {
85+ tile -> valid = FALSE;
86+ }
87+
8188/* Update the timestamp on a tile.
8289 */
8390void
@@ -86,103 +93,84 @@ tile_touch(Tile *tile)
8693 tile -> time = tile_ticks ++ ;
8794}
8895
89- /* Make a tile on an image. left/top in this image's coordinates (not level0
90- * coordinates).
96+ /* Make a tile on an image. left/top are in level0 coordinates.
9197 */
9298Tile *
93- tile_new (VipsImage * level , int left , int top , int z )
99+ tile_new (int left , int top , int z )
94100{
95101 g_autoptr (Tile ) tile = g_object_new (TYPE_TILE , NULL );
96102
97- VipsRect tile_bounds ;
98- VipsRect image_bounds ;
99-
100- tile -> region = vips_region_new (level );
101103 tile -> z = z ;
102-
103- image_bounds .left = 0 ;
104- image_bounds .top = 0 ;
105- image_bounds .width = level -> Xsize ;
106- image_bounds .height = level -> Ysize ;
107- tile_bounds .left = left ;
108- tile_bounds .top = top ;
109- tile_bounds .width = TILE_SIZE ;
110- tile_bounds .height = TILE_SIZE ;
111- vips_rect_intersectrect (& image_bounds , & tile_bounds , & tile_bounds );
112- if (vips_region_buffer (tile -> region , & tile_bounds ))
113- return NULL ;
114-
115- /* Tile bounds in level 0 coordinates.
116- */
117- tile -> bounds .left = tile_bounds .left << z ;
118- tile -> bounds .top = tile_bounds .top << z ;
119- tile -> bounds .width = tile_bounds .width << z ;
120- tile -> bounds .height = tile_bounds .height << z ;
104+ tile -> bounds .left = left >> z ;
105+ tile -> bounds .top = top >> z ;
106+ tile -> bounds .width = TILE_SIZE ;
107+ tile -> bounds .height = TILE_SIZE ;
108+ tile -> bounds0 .left = left ;
109+ tile -> bounds0 .top = top ;
110+ tile -> bounds0 .width = TILE_SIZE << z ;
111+ tile -> bounds0 .height = TILE_SIZE << z ;
112+ tile -> valid = FALSE;
121113
122114 tile_touch (tile );
123115
124116 return g_steal_pointer (& tile );
125117}
126118
127- /* NULL means pixels have not arrived from libvips yet.
119+ /* Set the texture from the pixels in a VipsRegion. The region can be less
120+ * than TILE_SIZE x TILE_SIZE for edge tiles, and can be RGB or RGBA (we
121+ * always make full size RGBA textures).
128122 */
129- GdkTexture *
130- tile_get_texture (Tile * tile )
123+ void
124+ tile_set_texture (Tile * tile , VipsRegion * region )
131125{
132- /* This mustn't be a completely empty tile -- there must be either
133- * fresh, valid pixels, or an old texture.
134- */
135- g_assert (tile -> texture ||
136- tile -> valid );
137-
138- /* The tile is being shown, so it must be useful.
139- */
140- tile_touch (tile );
126+ g_assert (region -> valid .left == tile -> bounds .left );
127+ g_assert (region -> valid .top == tile -> bounds .top );
128+ g_assert (region -> valid .width <= tile -> bounds .width );
129+ g_assert (region -> valid .height <= tile -> bounds .height );
130+ g_assert (region -> im -> Bands == 3 || region -> im -> Bands == 4 );
131+ g_assert (region -> im -> BandFmt == VIPS_FORMAT_UCHAR );
132+ g_assert (region -> im -> Type == VIPS_INTERPRETATION_sRGB );
133+
134+ // textures are immutable, we we must always reallocate, we can't update
135+ VIPS_FREEF (g_bytes_unref , tile -> bytes );
136+ VIPS_UNREF (tile -> texture );
141137
142- /* It's three steps to make the texture:
143- *
144- * 1. We must make a copy of the pixel data from libvips, to stop
145- * it being changed under our feet.
146- *
147- * 2. Wrap a GBytes around that copy.
148- *
149- * 3. Tag it as a texture that may need upload to the GPU.
150- */
151- if (!tile -> texture ) {
152- gpointer copy = g_memdup2 (
153- VIPS_REGION_ADDR (tile -> region ,
154- tile -> region -> valid .left ,
155- tile -> region -> valid .top ),
156- VIPS_REGION_SIZEOF_LINE (tile -> region ) *
157- tile -> region -> valid .height );
158-
159- VIPS_FREEF (g_bytes_unref , tile -> bytes );
160- tile -> bytes = g_bytes_new_take (
161- copy ,
162- VIPS_REGION_SIZEOF_LINE (tile -> region ) *
163- tile -> region -> valid .height );
164-
165- tile -> texture = gdk_memory_texture_new (
166- tile -> region -> valid .width ,
167- tile -> region -> valid .height ,
168- tile -> region -> im -> Bands == 4
169- ? GDK_MEMORY_R8G8B8A8
170- : GDK_MEMORY_R8G8B8 ,
171- tile -> bytes ,
172- VIPS_REGION_LSKIP (tile -> region ));
138+ // always a full tile of RGBA pixels
139+ gsize length = TILE_SIZE * TILE_SIZE * 4 ;
140+ unsigned char * data = g_malloc0 (length );
141+
142+ for (int y = 0 ; y < region -> valid .height ; y ++ ) {
143+ VipsPel * p =
144+ VIPS_REGION_ADDR (region , region -> valid .left , region -> valid .top + y );
145+ VipsPel * q = data + 4 * TILE_SIZE * y ;
146+
147+ if (region -> im -> Bands == 4 )
148+ memcpy (q , p , VIPS_REGION_SIZEOF_LINE (region ));
149+ else
150+ // RGB to RGBA
151+ for (int x = 0 ; x < region -> valid .width ; x ++ ) {
152+ q [0 ] = p [0 ];
153+ q [1 ] = p [1 ];
154+ q [2 ] = p [2 ];
155+ q [3 ] = 255 ;
156+
157+ q += 4 ;
158+ p += 3 ;
159+ }
173160 }
174161
175- return tile -> texture ;
162+ tile -> bytes = g_bytes_new_take (data , length );
163+ tile -> texture = gdk_memory_texture_new (TILE_SIZE , TILE_SIZE ,
164+ GDK_MEMORY_R8G8B8A8 , tile -> bytes , 4 * TILE_SIZE );
165+
166+ tile -> valid = TRUE;
167+ tile_touch (tile );
176168}
177169
178- /* The pixels in the region have changed. We must regenerate the texture on
179- * next use.
180- */
181- void
182- tile_free_texture (Tile * tile )
170+ GdkTexture *
171+ tile_get_texture (Tile * tile )
183172{
184- g_assert (tile -> valid );
173+ tile_touch (tile );
185174
186- VIPS_UNREF (tile -> texture );
187- VIPS_FREEF (g_bytes_unref , tile -> bytes );
175+ return tile -> texture ;
188176}
0 commit comments