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