llvmpipe: Tiles in rgba8 format.
[mesa.git] / src / gallium / drivers / llvmpipe / lp_tile_cache.c
1 /**************************************************************************
2 *
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 **************************************************************************/
27
28 /**
29 * Texture tile caching.
30 *
31 * Author:
32 * Brian Paul
33 */
34
35 #include "pipe/p_inlines.h"
36 #include "util/u_memory.h"
37 #include "util/u_tile.h"
38 #include "lp_context.h"
39 #include "lp_surface.h"
40 #include "lp_texture.h"
41 #include "lp_tile_soa.h"
42 #include "lp_tile_cache.h"
43
44
45
46 /**
47 * Return the position in the cache for the tile that contains win pos (x,y).
48 * We currently use a direct mapped cache so this is like a hack key.
49 * At some point we should investige something more sophisticated, like
50 * a LRU replacement policy.
51 */
52 #define CACHE_POS(x, y) \
53 (((x) + (y) * 5) % NUM_ENTRIES)
54
55
56
57 /**
58 * Is the tile at (x,y) in cleared state?
59 */
60 static INLINE uint
61 is_clear_flag_set(const uint *bitvec, union tile_address addr)
62 {
63 int pos, bit;
64 pos = addr.bits.y * (MAX_WIDTH / TILE_SIZE) + addr.bits.x;
65 assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
66 bit = bitvec[pos / 32] & (1 << (pos & 31));
67 return bit;
68 }
69
70
71 /**
72 * Mark the tile at (x,y) as not cleared.
73 */
74 static INLINE void
75 clear_clear_flag(uint *bitvec, union tile_address addr)
76 {
77 int pos;
78 pos = addr.bits.y * (MAX_WIDTH / TILE_SIZE) + addr.bits.x;
79 assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
80 bitvec[pos / 32] &= ~(1 << (pos & 31));
81 }
82
83
84 struct llvmpipe_tile_cache *
85 lp_create_tile_cache( struct pipe_screen *screen )
86 {
87 struct llvmpipe_tile_cache *tc;
88 uint pos;
89
90 tc = CALLOC_STRUCT( llvmpipe_tile_cache );
91 if (tc) {
92 tc->screen = screen;
93 for (pos = 0; pos < NUM_ENTRIES; pos++) {
94 tc->entries[pos].addr.bits.invalid = 1;
95 }
96 tc->last_tile = &tc->entries[0]; /* any tile */
97 }
98 return tc;
99 }
100
101
102 void
103 lp_destroy_tile_cache(struct llvmpipe_tile_cache *tc)
104 {
105 struct pipe_screen *screen;
106 uint pos;
107
108 for (pos = 0; pos < NUM_ENTRIES; pos++) {
109 /*assert(tc->entries[pos].x < 0);*/
110 }
111 if (tc->transfer) {
112 screen = tc->transfer->texture->screen;
113 screen->tex_transfer_destroy(tc->transfer);
114 }
115 if (tc->tex_trans) {
116 screen = tc->tex_trans->texture->screen;
117 screen->tex_transfer_destroy(tc->tex_trans);
118 }
119
120 FREE( tc );
121 }
122
123
124 /**
125 * Specify the surface to cache.
126 */
127 void
128 lp_tile_cache_set_surface(struct llvmpipe_tile_cache *tc,
129 struct pipe_surface *ps)
130 {
131 assert(!tc->texture);
132
133 if (tc->transfer) {
134 struct pipe_screen *screen = tc->transfer->texture->screen;
135
136 if (ps == tc->surface)
137 return;
138
139 if (tc->transfer_map) {
140 screen->transfer_unmap(screen, tc->transfer);
141 tc->transfer_map = NULL;
142 }
143
144 screen->tex_transfer_destroy(tc->transfer);
145 tc->transfer = NULL;
146 }
147
148 tc->surface = ps;
149
150 if (ps) {
151 struct pipe_screen *screen = ps->texture->screen;
152
153 tc->transfer = screen->get_tex_transfer(screen, ps->texture, ps->face,
154 ps->level, ps->zslice,
155 PIPE_TRANSFER_READ_WRITE,
156 0, 0, ps->width, ps->height);
157
158 tc->depth_stencil = (ps->format == PIPE_FORMAT_S8Z24_UNORM ||
159 ps->format == PIPE_FORMAT_X8Z24_UNORM ||
160 ps->format == PIPE_FORMAT_Z24S8_UNORM ||
161 ps->format == PIPE_FORMAT_Z24X8_UNORM ||
162 ps->format == PIPE_FORMAT_Z16_UNORM ||
163 ps->format == PIPE_FORMAT_Z32_UNORM ||
164 ps->format == PIPE_FORMAT_S8_UNORM);
165 }
166 }
167
168
169 /**
170 * Return the transfer being cached.
171 */
172 struct pipe_surface *
173 lp_tile_cache_get_surface(struct llvmpipe_tile_cache *tc)
174 {
175 return tc->surface;
176 }
177
178
179 void
180 lp_tile_cache_map_transfers(struct llvmpipe_tile_cache *tc)
181 {
182 if (tc->transfer && !tc->transfer_map)
183 tc->transfer_map = tc->screen->transfer_map(tc->screen, tc->transfer);
184
185 if (tc->tex_trans && !tc->tex_trans_map)
186 tc->tex_trans_map = tc->screen->transfer_map(tc->screen, tc->tex_trans);
187 }
188
189
190 void
191 lp_tile_cache_unmap_transfers(struct llvmpipe_tile_cache *tc)
192 {
193 if (tc->transfer_map) {
194 tc->screen->transfer_unmap(tc->screen, tc->transfer);
195 tc->transfer_map = NULL;
196 }
197
198 if (tc->tex_trans_map) {
199 tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
200 tc->tex_trans_map = NULL;
201 }
202 }
203
204
205 /**
206 * Set pixels in a tile to the given clear color/value, float.
207 */
208 static void
209 clear_tile_rgba(struct llvmpipe_cached_tile *tile,
210 enum pipe_format format,
211 const float clear_value[4])
212 {
213 if (clear_value[0] == 0.0 &&
214 clear_value[1] == 0.0 &&
215 clear_value[2] == 0.0 &&
216 clear_value[3] == 0.0) {
217 memset(tile->data.color, 0, sizeof(tile->data.color));
218 }
219 else {
220 uint i, x, y;
221 for (i = 0; i < 4; ++i)
222 for (y = 0; y < TILE_SIZE; y++)
223 for (x = 0; x < TILE_SIZE; x++)
224 tile->data.color[i][y][x] = float_to_ubyte(clear_value[i]);
225 }
226 }
227
228
229 /**
230 * Set a tile to a solid value/color.
231 */
232 static void
233 clear_tile(struct llvmpipe_cached_tile *tile,
234 enum pipe_format format,
235 uint clear_value)
236 {
237 uint i, j;
238
239 switch (pf_get_size(format)) {
240 case 1:
241 memset(tile->data.any, 0, TILE_SIZE * TILE_SIZE);
242 break;
243 case 2:
244 if (clear_value == 0) {
245 memset(tile->data.any, 0, 2 * TILE_SIZE * TILE_SIZE);
246 }
247 else {
248 for (i = 0; i < TILE_SIZE; i++) {
249 for (j = 0; j < TILE_SIZE; j++) {
250 tile->data.depth16[i][j] = (ushort) clear_value;
251 }
252 }
253 }
254 break;
255 case 4:
256 if (clear_value == 0) {
257 memset(tile->data.any, 0, 4 * TILE_SIZE * TILE_SIZE);
258 }
259 else {
260 for (i = 0; i < TILE_SIZE; i++) {
261 for (j = 0; j < TILE_SIZE; j++) {
262 tile->data.color32[i][j] = clear_value;
263 }
264 }
265 }
266 break;
267 default:
268 assert(0);
269 }
270 }
271
272
273 /**
274 * Actually clear the tiles which were flagged as being in a clear state.
275 */
276 static void
277 lp_tile_cache_flush_clear(struct llvmpipe_tile_cache *tc)
278 {
279 struct pipe_transfer *pt = tc->transfer;
280 const uint w = tc->transfer->width;
281 const uint h = tc->transfer->height;
282 uint x, y;
283 uint numCleared = 0;
284
285 /* clear the scratch tile to the clear value */
286 clear_tile(&tc->tile, pt->format, tc->clear_val);
287
288 /* push the tile to all positions marked as clear */
289 for (y = 0; y < h; y += TILE_SIZE) {
290 for (x = 0; x < w; x += TILE_SIZE) {
291 union tile_address addr = tile_address(x, y, 0, 0, 0);
292
293 if (is_clear_flag_set(tc->clear_flags, addr)) {
294 pipe_put_tile_raw(pt,
295 x, y, TILE_SIZE, TILE_SIZE,
296 tc->tile.data.color32, 0/*STRIDE*/);
297
298 /* do this? */
299 clear_clear_flag(tc->clear_flags, addr);
300
301 numCleared++;
302 }
303 }
304 }
305 #if 0
306 debug_printf("num cleared: %u\n", numCleared);
307 #endif
308 }
309
310
311 /**
312 * Flush the tile cache: write all dirty tiles back to the transfer.
313 * any tiles "flagged" as cleared will be "really" cleared.
314 */
315 void
316 lp_flush_tile_cache(struct llvmpipe_tile_cache *tc)
317 {
318 struct pipe_transfer *pt = tc->transfer;
319 int inuse = 0, pos;
320
321 if (pt) {
322 /* caching a drawing transfer */
323 for (pos = 0; pos < NUM_ENTRIES; pos++) {
324 struct llvmpipe_cached_tile *tile = tc->entries + pos;
325 if (!tile->addr.bits.invalid) {
326 if (tc->depth_stencil) {
327 pipe_put_tile_raw(pt,
328 tile->addr.bits.x * TILE_SIZE,
329 tile->addr.bits.y * TILE_SIZE,
330 TILE_SIZE, TILE_SIZE,
331 tile->data.depth32, 0/*STRIDE*/);
332 }
333 else {
334 lp_put_tile_rgba_soa(pt,
335 tile->addr.bits.x * TILE_SIZE,
336 tile->addr.bits.y * TILE_SIZE,
337 tile->data.color);
338 }
339 tile->addr.bits.invalid = 1; /* mark as empty */
340 inuse++;
341 }
342 }
343
344 #if TILE_CLEAR_OPTIMIZATION
345 lp_tile_cache_flush_clear(tc);
346 #endif
347 }
348 else if (tc->texture) {
349 /* caching a texture, mark all entries as empty */
350 for (pos = 0; pos < NUM_ENTRIES; pos++) {
351 tc->entries[pos].addr.bits.invalid = 1;
352 }
353 tc->tex_face = -1;
354 }
355
356 #if 0
357 debug_printf("flushed tiles in use: %d\n", inuse);
358 #endif
359 }
360
361
362 /**
363 * Get a tile from the cache.
364 * \param x, y position of tile, in pixels
365 */
366 struct llvmpipe_cached_tile *
367 lp_find_cached_tile(struct llvmpipe_tile_cache *tc,
368 union tile_address addr )
369 {
370 struct pipe_transfer *pt = tc->transfer;
371
372 /* cache pos/entry: */
373 const int pos = CACHE_POS(addr.bits.x,
374 addr.bits.y);
375 struct llvmpipe_cached_tile *tile = tc->entries + pos;
376
377 if (addr.value != tile->addr.value) {
378
379 if (tile->addr.bits.invalid == 0) {
380 /* put dirty tile back in framebuffer */
381 if (tc->depth_stencil) {
382 pipe_put_tile_raw(pt,
383 tile->addr.bits.x * TILE_SIZE,
384 tile->addr.bits.y * TILE_SIZE,
385 TILE_SIZE, TILE_SIZE,
386 tile->data.depth32, 0/*STRIDE*/);
387 }
388 else {
389 lp_put_tile_rgba_soa(pt,
390 tile->addr.bits.x * TILE_SIZE,
391 tile->addr.bits.y * TILE_SIZE,
392 tile->data.color);
393 }
394 }
395
396 tile->addr = addr;
397
398 if (is_clear_flag_set(tc->clear_flags, addr)) {
399 /* don't get tile from framebuffer, just clear it */
400 if (tc->depth_stencil) {
401 clear_tile(tile, pt->format, tc->clear_val);
402 }
403 else {
404 clear_tile_rgba(tile, pt->format, tc->clear_color);
405 }
406 clear_clear_flag(tc->clear_flags, addr);
407 }
408 else {
409 /* get new tile data from transfer */
410 if (tc->depth_stencil) {
411 pipe_get_tile_raw(pt,
412 tile->addr.bits.x * TILE_SIZE,
413 tile->addr.bits.y * TILE_SIZE,
414 TILE_SIZE, TILE_SIZE,
415 tile->data.depth32, 0/*STRIDE*/);
416 }
417 else {
418 lp_get_tile_rgba_soa(pt,
419 tile->addr.bits.x * TILE_SIZE,
420 tile->addr.bits.y * TILE_SIZE,
421 tile->data.color);
422 }
423 }
424 }
425
426 tc->last_tile = tile;
427 return tile;
428 }
429
430
431 /**
432 * Given the texture face, level, zslice, x and y values, compute
433 * the cache entry position/index where we'd hope to find the
434 * cached texture tile.
435 * This is basically a direct-map cache.
436 * XXX There's probably lots of ways in which we can improve this.
437 */
438 static INLINE uint
439 tex_cache_pos( union tile_address addr )
440 {
441 uint entry = (addr.bits.x +
442 addr.bits.y * 9 +
443 addr.bits.z * 3 +
444 addr.bits.face +
445 addr.bits.level * 7);
446
447 return entry % NUM_ENTRIES;
448 }
449
450
451 /**
452 * When a whole surface is being cleared to a value we can avoid
453 * fetching tiles above.
454 * Save the color and set a 'clearflag' for each tile of the screen.
455 */
456 void
457 lp_tile_cache_clear(struct llvmpipe_tile_cache *tc, const float *rgba,
458 uint clearValue)
459 {
460 uint pos;
461
462 tc->clear_color[0] = rgba[0];
463 tc->clear_color[1] = rgba[1];
464 tc->clear_color[2] = rgba[2];
465 tc->clear_color[3] = rgba[3];
466
467 tc->clear_val = clearValue;
468
469 #if TILE_CLEAR_OPTIMIZATION
470 /* set flags to indicate all the tiles are cleared */
471 memset(tc->clear_flags, 255, sizeof(tc->clear_flags));
472 #else
473 /* disable the optimization */
474 memset(tc->clear_flags, 0, sizeof(tc->clear_flags));
475 #endif
476
477 for (pos = 0; pos < NUM_ENTRIES; pos++) {
478 struct llvmpipe_cached_tile *tile = tc->entries + pos;
479 tile->addr.bits.invalid = 1;
480 }
481 }