62ee6a27c93d9604e9de1d24da4efaddd405b929
[mesa.git] / src / mesa / pipe / softpipe / sp_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 * Framebuffer/surface tile caching.
30 *
31 * Author:
32 * Brian Paul
33 */
34
35 #include "pipe/p_util.h"
36 #include "pipe/p_inlines.h"
37 #include "sp_context.h"
38 #include "sp_surface.h"
39 #include "sp_tile_cache.h"
40
41 #define CLEAR_OPTIMIZATION 0
42
43 #define NUM_ENTRIES 20
44
45
46 /** XXX move these */
47 #define MAX_WIDTH 2048
48 #define MAX_HEIGHT 2048
49
50
51 struct softpipe_tile_cache
52 {
53 struct pipe_surface *surface; /**< the surface we're caching */
54 struct pipe_texture *texture; /**< if caching a texture */
55 struct softpipe_cached_tile entries[NUM_ENTRIES];
56 uint clear_flags[(MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32];
57 float clear_value[4];
58 };
59
60
61 /**
62 * Return the position in the cache for the tile that contains win pos (x,y).
63 * We currently use a direct mapped cache so this is like a hack key.
64 * At some point we should investige something more sophisticated, like
65 * a LRU replacement policy.
66 */
67 #define CACHE_POS(x, y) \
68 (((x) / TILE_SIZE + ((y) / TILE_SIZE) * 5) % NUM_ENTRIES)
69
70
71
72 static uint
73 is_clear_flag_set(const uint *bitvec, int x, int y)
74 {
75 int pos, bit;
76 x /= TILE_SIZE;
77 y /= TILE_SIZE;
78 pos = y * (MAX_WIDTH / TILE_SIZE) + x;
79 assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
80 bit = bitvec[pos / 32] & (1 << (pos & 31));
81 return bit;
82 }
83
84
85 static void
86 clear_clear_flag(uint *bitvec, int x, int y)
87 {
88 int pos;
89 x /= TILE_SIZE;
90 y /= TILE_SIZE;
91 pos = y * (MAX_WIDTH / TILE_SIZE) + x;
92 assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
93 bitvec[pos / 32] &= ~(1 << (pos & 31));
94 }
95
96
97 struct softpipe_tile_cache *
98 sp_create_tile_cache(void)
99 {
100 struct softpipe_tile_cache *tc;
101 uint pos;
102
103 tc = CALLOC_STRUCT( softpipe_tile_cache );
104 if (tc) {
105 for (pos = 0; pos < NUM_ENTRIES; pos++) {
106 tc->entries[pos].x =
107 tc->entries[pos].y = -1;
108 }
109 }
110 return tc;
111 }
112
113
114 void
115 sp_destroy_tile_cache(struct softpipe_tile_cache *tc)
116 {
117 uint pos;
118 for (pos = 0; pos < NUM_ENTRIES; pos++) {
119 assert(tc->entries[pos].x < 0);
120 }
121 FREE( tc );
122 }
123
124
125 void
126 sp_tile_cache_set_surface(struct softpipe_tile_cache *tc,
127 struct pipe_surface *ps)
128 {
129 pipe_surface_reference(&tc->surface, ps);
130 }
131
132
133 struct pipe_surface *
134 sp_tile_cache_get_surface(struct softpipe_tile_cache *tc)
135 {
136 return tc->surface;
137 }
138
139
140 void
141 sp_tile_cache_set_texture(struct softpipe_tile_cache *tc,
142 struct pipe_texture *texture)
143 {
144 uint i;
145
146 tc->texture = texture;
147
148 /* mark as entries as invalid/empty */
149 /* XXX we should try to avoid this when the teximage hasn't changed */
150 for (i = 0; i < NUM_ENTRIES; i++) {
151 tc->entries[i].x = -1;
152 }
153 }
154
155
156 void
157 sp_flush_tile_cache(struct softpipe_context *softpipe,
158 struct softpipe_tile_cache *tc)
159 {
160 struct pipe_context *pipe = &softpipe->pipe;
161 struct pipe_surface *ps = tc->surface;
162 boolean is_depth_stencil;
163 int inuse = 0, pos;
164
165 if (!ps || !ps->region || !ps->region->map)
166 return;
167
168 is_depth_stencil = (ps->format == PIPE_FORMAT_S8_Z24 ||
169 ps->format == PIPE_FORMAT_Z24_S8 ||
170 ps->format == PIPE_FORMAT_U_Z16 ||
171 ps->format == PIPE_FORMAT_U_Z32 ||
172 ps->format == PIPE_FORMAT_U_S8);
173
174 for (pos = 0; pos < NUM_ENTRIES; pos++) {
175 struct softpipe_cached_tile *tile = tc->entries + pos;
176 if (tile->x >= 0) {
177 if (is_depth_stencil) {
178 pipe->put_tile(pipe, ps,
179 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
180 tile->data.depth32, 0/*STRIDE*/);
181 }
182 else {
183 pipe->put_tile_rgba(pipe, ps,
184 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
185 (float *) tile->data.color);
186 }
187
188 tile->x = tile->y = -1; /* mark as empty */
189 inuse++;
190 }
191 }
192
193 /*
194 printf("flushed tiles in use: %d\n", inuse);
195 */
196 }
197
198
199 struct softpipe_cached_tile *
200 sp_get_cached_tile(struct softpipe_context *softpipe,
201 struct softpipe_tile_cache *tc, int x, int y)
202 {
203 struct pipe_context *pipe = &softpipe->pipe;
204 struct pipe_surface *ps = tc->surface;
205 boolean is_depth_stencil
206 = (ps->format == PIPE_FORMAT_S8_Z24 ||
207 ps->format == PIPE_FORMAT_Z24_S8 ||
208 ps->format == PIPE_FORMAT_U_Z16 ||
209 ps->format == PIPE_FORMAT_U_Z32 ||
210 ps->format == PIPE_FORMAT_U_S8);
211
212 /* tile pos in framebuffer: */
213 const int tile_x = x & ~(TILE_SIZE - 1);
214 const int tile_y = y & ~(TILE_SIZE - 1);
215
216 /* cache pos/entry: */
217 const int pos = CACHE_POS(x, y);
218 struct softpipe_cached_tile *tile = tc->entries + pos;
219
220 if (tile_x != tile->x ||
221 tile_y != tile->y) {
222
223 if (tile->x != -1) {
224 /* put dirty tile back in framebuffer */
225 if (is_depth_stencil) {
226 pipe->put_tile(pipe, ps,
227 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
228 tile->data.depth32, 0 /*STRIDE*/);
229 }
230 else {
231 pipe->put_tile_rgba(pipe, ps,
232 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
233 (float *) tile->data.color);
234 }
235 }
236
237 if (is_clear_flag_set(tc->clear_flags, x, y)) {
238 /* don't get tile from framebuffer, just clear it */
239 uint i, j;
240 /* XXX these loops could be optimized */
241 switch (ps->format) {
242 case PIPE_FORMAT_U_Z16:
243 {
244 ushort clear_val = (ushort) (tc->clear_value[0] * 0xffff);
245 for (i = 0; i < TILE_SIZE; i++) {
246 for (j = 0; j < TILE_SIZE; j++) {
247 tile->data.depth16[i][j] = clear_val;
248 }
249 }
250 }
251 break;
252 case PIPE_FORMAT_U_Z32:
253 {
254 uint clear_val = (uint) (tc->clear_value[0] * 0xffffffff);
255 for (i = 0; i < TILE_SIZE; i++) {
256 for (j = 0; j < TILE_SIZE; j++) {
257 tile->data.depth32[i][j] = clear_val;
258 }
259 }
260 }
261 break;
262 case PIPE_FORMAT_S8_Z24:
263 {
264 uint clear_val = (uint) (tc->clear_value[0] * 0xffffff);
265 clear_val |= ((uint) tc->clear_value[1]) << 24;
266 for (i = 0; i < TILE_SIZE; i++) {
267 for (j = 0; j < TILE_SIZE; j++) {
268 tile->data.depth32[i][j] = clear_val;
269 }
270 }
271 }
272 break;
273 case PIPE_FORMAT_Z24_S8:
274 {
275 uint clear_val = ((uint) (tc->clear_value[0] * 0xffffff)) << 8;
276 clear_val |= ((uint) tc->clear_value[1]) & 0xff;
277 for (i = 0; i < TILE_SIZE; i++) {
278 for (j = 0; j < TILE_SIZE; j++) {
279 tile->data.depth32[i][j] = clear_val;
280 }
281 }
282 }
283 break;
284 case PIPE_FORMAT_U_S8:
285 {
286 ubyte clear_val = (uint) tc->clear_value[0];
287 for (i = 0; i < TILE_SIZE; i++) {
288 for (j = 0; j < TILE_SIZE; j++) {
289 tile->data.stencil8[i][j] = clear_val;
290 }
291 }
292 }
293 break;
294 default:
295 /* color */
296 for (i = 0; i < TILE_SIZE; i++) {
297 for (j = 0; j < TILE_SIZE; j++) {
298 tile->data.color[i][j][0] = tc->clear_value[0];
299 tile->data.color[i][j][1] = tc->clear_value[1];
300 tile->data.color[i][j][2] = tc->clear_value[2];
301 tile->data.color[i][j][3] = tc->clear_value[3];
302 }
303 }
304 }
305 clear_clear_flag(tc->clear_flags, x, y);
306 }
307 else {
308 /* get new tile from framebuffer */
309 if (is_depth_stencil) {
310 pipe->get_tile(pipe, ps,
311 tile_x, tile_y, TILE_SIZE, TILE_SIZE,
312 tile->data.depth32, 0/*STRIDE*/);
313 }
314 else {
315 pipe->get_tile_rgba(pipe, ps,
316 tile_x, tile_y, TILE_SIZE, TILE_SIZE,
317 (float *) tile->data.color);
318 }
319 }
320
321 tile->x = tile_x;
322 tile->y = tile_y;
323 }
324
325 return tile;
326 }
327
328
329 /**
330 * Given the texture face, level, zslice, x and y values, compute
331 * the cache entry position/index where we'd hope to find the
332 * cached texture tile.
333 * This is basically a direct-map cache.
334 * XXX There's probably lots of ways in which we can improve this.
335 */
336 static INLINE uint
337 tex_cache_pos(int x, int y, int z, int face, int level)
338 {
339 uint entry = x + y * 5 + z * 4 + face + level;
340 return entry % NUM_ENTRIES;
341 }
342
343
344 /**
345 * Similar to sp_get_cached_tile() but for textures.
346 * Tiles are read-only and indexed with more params.
347 */
348 const struct softpipe_cached_tile *
349 sp_get_cached_tile_tex(struct pipe_context *pipe,
350 struct softpipe_tile_cache *tc, int x, int y, int z,
351 int face, int level)
352 {
353 /* tile pos in framebuffer: */
354 const int tile_x = x & ~(TILE_SIZE - 1);
355 const int tile_y = y & ~(TILE_SIZE - 1);
356 /* cache pos/entry: */
357 const uint pos = tex_cache_pos(x / TILE_SIZE, y / TILE_SIZE, z,
358 face, level);
359 struct softpipe_cached_tile *tile = tc->entries + pos;
360
361 if (tile_x != tile->x ||
362 tile_y != tile->y ||
363 z != tile->z ||
364 face != tile->face ||
365 level != tile->level) {
366 /* XXX this call is a bit heavier than we'd like: */
367 struct pipe_surface *ps
368 = pipe->get_tex_surface(pipe, tc->texture, face, level, z);
369
370 pipe->get_tile_rgba(pipe, ps,
371 tile_x, tile_y, TILE_SIZE, TILE_SIZE,
372 (float *) tile->data.color);
373
374 pipe_surface_reference(&ps, NULL);
375
376 tile->x = tile_x;
377 tile->y = tile_y;
378 tile->z = z;
379 tile->face = face;
380 tile->level = level;
381 }
382
383 return tile;
384 }
385
386
387 /**
388 * When a whole surface is being cleared to a value we can avoid
389 * fetching tiles above.
390 * Save the color and set a 'clearflag' for each tile of the screen.
391 */
392 void
393 sp_tile_cache_clear(struct softpipe_tile_cache *tc, const float value[4])
394 {
395 tc->clear_value[0] = value[0];
396 tc->clear_value[1] = value[1];
397 tc->clear_value[2] = value[2];
398 tc->clear_value[3] = value[3];
399
400 #if CLEAR_OPTIMIZATION
401 memset(tc->clear_flags, 255, sizeof(tc->clear_flags));
402 #else
403 memset(tc->clear_flags, 0, sizeof(tc->clear_flags));
404 #endif
405 }