llvmpipe: Drop depth/stencil support from tile cache.
[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_math.h"
38 #include "util/u_tile.h"
39 #include "lp_context.h"
40 #include "lp_surface.h"
41 #include "lp_texture.h"
42 #include "lp_tile_soa.h"
43 #include "lp_tile_cache.h"
44
45
46
47 /**
48 * Return the position in the cache for the tile that contains win pos (x,y).
49 * We currently use a direct mapped cache so this is like a hack key.
50 * At some point we should investige something more sophisticated, like
51 * a LRU replacement policy.
52 */
53 #define CACHE_POS(x, y) \
54 (((x) + (y) * 5) % NUM_ENTRIES)
55
56
57
58 /**
59 * Is the tile at (x,y) in cleared state?
60 */
61 static INLINE uint
62 is_clear_flag_set(const uint *bitvec, union tile_address addr)
63 {
64 int pos, bit;
65 pos = addr.bits.y * (MAX_WIDTH / TILE_SIZE) + addr.bits.x;
66 assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
67 bit = bitvec[pos / 32] & (1 << (pos & 31));
68 return bit;
69 }
70
71
72 /**
73 * Mark the tile at (x,y) as not cleared.
74 */
75 static INLINE void
76 clear_clear_flag(uint *bitvec, union tile_address addr)
77 {
78 int pos;
79 pos = addr.bits.y * (MAX_WIDTH / TILE_SIZE) + addr.bits.x;
80 assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
81 bitvec[pos / 32] &= ~(1 << (pos & 31));
82 }
83
84
85 struct llvmpipe_tile_cache *
86 lp_create_tile_cache( struct pipe_screen *screen )
87 {
88 struct llvmpipe_tile_cache *tc;
89 uint pos;
90
91 tc = align_malloc( sizeof(struct llvmpipe_tile_cache), 16 );
92 if (tc) {
93 memset(tc, 0, sizeof *tc);
94 tc->screen = screen;
95 for (pos = 0; pos < NUM_ENTRIES; pos++) {
96 tc->entries[pos].addr.bits.invalid = 1;
97 }
98 tc->last_tile = &tc->entries[0]; /* any tile */
99 }
100 return tc;
101 }
102
103
104 void
105 lp_destroy_tile_cache(struct llvmpipe_tile_cache *tc)
106 {
107 struct pipe_screen *screen;
108 uint pos;
109
110 for (pos = 0; pos < NUM_ENTRIES; pos++) {
111 /*assert(tc->entries[pos].x < 0);*/
112 }
113 if (tc->transfer) {
114 screen = tc->transfer->texture->screen;
115 screen->tex_transfer_destroy(tc->transfer);
116 }
117 if (tc->tex_trans) {
118 screen = tc->tex_trans->texture->screen;
119 screen->tex_transfer_destroy(tc->tex_trans);
120 }
121
122 align_free( tc );
123 }
124
125
126 /**
127 * Specify the surface to cache.
128 */
129 void
130 lp_tile_cache_set_surface(struct llvmpipe_tile_cache *tc,
131 struct pipe_surface *ps)
132 {
133 assert(!tc->texture);
134
135 if (tc->transfer) {
136 struct pipe_screen *screen = tc->transfer->texture->screen;
137
138 if (ps == tc->surface)
139 return;
140
141 if (tc->transfer_map) {
142 screen->transfer_unmap(screen, tc->transfer);
143 tc->transfer_map = NULL;
144 }
145
146 screen->tex_transfer_destroy(tc->transfer);
147 tc->transfer = NULL;
148 }
149
150 tc->surface = ps;
151
152 if (ps) {
153 struct pipe_screen *screen = ps->texture->screen;
154
155 tc->transfer = screen->get_tex_transfer(screen, ps->texture, ps->face,
156 ps->level, ps->zslice,
157 PIPE_TRANSFER_READ_WRITE,
158 0, 0, ps->width, ps->height);
159 }
160 }
161
162
163 /**
164 * Return the transfer being cached.
165 */
166 struct pipe_surface *
167 lp_tile_cache_get_surface(struct llvmpipe_tile_cache *tc)
168 {
169 return tc->surface;
170 }
171
172
173 void
174 lp_tile_cache_map_transfers(struct llvmpipe_tile_cache *tc)
175 {
176 if (tc->transfer && !tc->transfer_map)
177 tc->transfer_map = tc->screen->transfer_map(tc->screen, tc->transfer);
178
179 if (tc->tex_trans && !tc->tex_trans_map)
180 tc->tex_trans_map = tc->screen->transfer_map(tc->screen, tc->tex_trans);
181 }
182
183
184 void
185 lp_tile_cache_unmap_transfers(struct llvmpipe_tile_cache *tc)
186 {
187 if (tc->transfer_map) {
188 tc->screen->transfer_unmap(tc->screen, tc->transfer);
189 tc->transfer_map = NULL;
190 }
191
192 if (tc->tex_trans_map) {
193 tc->screen->transfer_unmap(tc->screen, tc->tex_trans);
194 tc->tex_trans_map = NULL;
195 }
196 }
197
198
199 /**
200 * Set pixels in a tile to the given clear color/value, float.
201 */
202 static void
203 clear_tile_rgba(struct llvmpipe_cached_tile *tile,
204 enum pipe_format format,
205 const float clear_value[4])
206 {
207 if (clear_value[0] == 0.0 &&
208 clear_value[1] == 0.0 &&
209 clear_value[2] == 0.0 &&
210 clear_value[3] == 0.0) {
211 memset(tile->data.color, 0, sizeof(tile->data.color));
212 }
213 else {
214 uint8_t c[4];
215 uint x, y, i;
216 for (i = 0; i < 4; ++i)
217 c[i] = float_to_ubyte(clear_value[i]);
218 for (y = 0; y < TILE_SIZE; y++)
219 for (x = 0; x < TILE_SIZE; x++)
220 for (i = 0; i < 4; ++i)
221 TILE_PIXEL(tile->data.color, x, y, i) = c[i];
222 }
223 }
224
225
226 /**
227 * Set a tile to a solid value/color.
228 */
229 static void
230 clear_tile(struct llvmpipe_cached_tile *tile,
231 enum pipe_format format,
232 uint clear_value)
233 {
234 uint i, j;
235
236 if (clear_value == 0) {
237 memset(tile->data.any, 0, 4 * TILE_SIZE * TILE_SIZE);
238 }
239 else {
240 for (i = 0; i < TILE_SIZE; i++) {
241 for (j = 0; j < TILE_SIZE; j++) {
242 tile->data.color32[i][j] = clear_value;
243 }
244 }
245 }
246 }
247
248
249 /**
250 * Actually clear the tiles which were flagged as being in a clear state.
251 */
252 static void
253 lp_tile_cache_flush_clear(struct llvmpipe_tile_cache *tc)
254 {
255 struct pipe_transfer *pt = tc->transfer;
256 const uint w = tc->transfer->width;
257 const uint h = tc->transfer->height;
258 uint x, y;
259 uint numCleared = 0;
260
261 /* clear the scratch tile to the clear value */
262 clear_tile(&tc->tile, pt->format, tc->clear_val);
263
264 /* push the tile to all positions marked as clear */
265 for (y = 0; y < h; y += TILE_SIZE) {
266 for (x = 0; x < w; x += TILE_SIZE) {
267 union tile_address addr = tile_address(x, y, 0, 0, 0);
268
269 if (is_clear_flag_set(tc->clear_flags, addr)) {
270 pipe_put_tile_raw(pt,
271 x, y, TILE_SIZE, TILE_SIZE,
272 tc->tile.data.color32, 0/*STRIDE*/);
273
274 /* do this? */
275 clear_clear_flag(tc->clear_flags, addr);
276
277 numCleared++;
278 }
279 }
280 }
281 #if 0
282 debug_printf("num cleared: %u\n", numCleared);
283 #endif
284 }
285
286
287 /**
288 * Flush the tile cache: write all dirty tiles back to the transfer.
289 * any tiles "flagged" as cleared will be "really" cleared.
290 */
291 void
292 lp_flush_tile_cache(struct llvmpipe_tile_cache *tc)
293 {
294 struct pipe_transfer *pt = tc->transfer;
295 int inuse = 0, pos;
296
297 if (pt) {
298 /* caching a drawing transfer */
299 for (pos = 0; pos < NUM_ENTRIES; pos++) {
300 struct llvmpipe_cached_tile *tile = tc->entries + pos;
301 if (!tile->addr.bits.invalid) {
302 lp_put_tile_rgba_soa(pt,
303 tile->addr.bits.x * TILE_SIZE,
304 tile->addr.bits.y * TILE_SIZE,
305 tile->data.color);
306 tile->addr.bits.invalid = 1; /* mark as empty */
307 inuse++;
308 }
309 }
310
311 #if TILE_CLEAR_OPTIMIZATION
312 lp_tile_cache_flush_clear(tc);
313 #endif
314 }
315 else if (tc->texture) {
316 /* caching a texture, mark all entries as empty */
317 for (pos = 0; pos < NUM_ENTRIES; pos++) {
318 tc->entries[pos].addr.bits.invalid = 1;
319 }
320 tc->tex_face = -1;
321 }
322
323 #if 0
324 debug_printf("flushed tiles in use: %d\n", inuse);
325 #endif
326 }
327
328
329 /**
330 * Get a tile from the cache.
331 * \param x, y position of tile, in pixels
332 */
333 struct llvmpipe_cached_tile *
334 lp_find_cached_tile(struct llvmpipe_tile_cache *tc,
335 union tile_address addr )
336 {
337 struct pipe_transfer *pt = tc->transfer;
338
339 /* cache pos/entry: */
340 const int pos = CACHE_POS(addr.bits.x,
341 addr.bits.y);
342 struct llvmpipe_cached_tile *tile = tc->entries + pos;
343
344 if (addr.value != tile->addr.value) {
345
346 if (tile->addr.bits.invalid == 0) {
347 /* put dirty tile back in framebuffer */
348 lp_put_tile_rgba_soa(pt,
349 tile->addr.bits.x * TILE_SIZE,
350 tile->addr.bits.y * TILE_SIZE,
351 tile->data.color);
352 }
353
354 tile->addr = addr;
355
356 if (is_clear_flag_set(tc->clear_flags, addr)) {
357 /* don't get tile from framebuffer, just clear it */
358 clear_tile_rgba(tile, pt->format, tc->clear_color);
359 clear_clear_flag(tc->clear_flags, addr);
360 }
361 else {
362 /* get new tile data from transfer */
363 lp_get_tile_rgba_soa(pt,
364 tile->addr.bits.x * TILE_SIZE,
365 tile->addr.bits.y * TILE_SIZE,
366 tile->data.color);
367 }
368 }
369
370 tc->last_tile = tile;
371 return tile;
372 }
373
374
375 /**
376 * Given the texture face, level, zslice, x and y values, compute
377 * the cache entry position/index where we'd hope to find the
378 * cached texture tile.
379 * This is basically a direct-map cache.
380 * XXX There's probably lots of ways in which we can improve this.
381 */
382 static INLINE uint
383 tex_cache_pos( union tile_address addr )
384 {
385 uint entry = (addr.bits.x +
386 addr.bits.y * 9 +
387 addr.bits.z * 3 +
388 addr.bits.face +
389 addr.bits.level * 7);
390
391 return entry % NUM_ENTRIES;
392 }
393
394
395 /**
396 * When a whole surface is being cleared to a value we can avoid
397 * fetching tiles above.
398 * Save the color and set a 'clearflag' for each tile of the screen.
399 */
400 void
401 lp_tile_cache_clear(struct llvmpipe_tile_cache *tc, const float *rgba,
402 uint clearValue)
403 {
404 uint pos;
405
406 tc->clear_color[0] = rgba[0];
407 tc->clear_color[1] = rgba[1];
408 tc->clear_color[2] = rgba[2];
409 tc->clear_color[3] = rgba[3];
410
411 tc->clear_val = clearValue;
412
413 #if TILE_CLEAR_OPTIMIZATION
414 /* set flags to indicate all the tiles are cleared */
415 memset(tc->clear_flags, 255, sizeof(tc->clear_flags));
416 #else
417 /* disable the optimization */
418 memset(tc->clear_flags, 0, sizeof(tc->clear_flags));
419 #endif
420
421 for (pos = 0; pos < NUM_ENTRIES; pos++) {
422 struct llvmpipe_cached_tile *tile = tc->entries + pos;
423 tile->addr.bits.invalid = 1;
424 }
425 }