Eliminate struct pipe_region.
[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_context *sp,
127 struct softpipe_tile_cache *tc,
128 struct pipe_surface *ps)
129 {
130 if (tc->surface && tc->surface->map)
131 pipe_surface_unmap(tc->surface);
132
133 pipe_surface_reference(&tc->surface, ps);
134 }
135
136
137 struct pipe_surface *
138 sp_tile_cache_get_surface(struct softpipe_context *sp,
139 struct softpipe_tile_cache *tc)
140 {
141 if (tc->surface && !tc->surface->map)
142 pipe_surface_map(tc->surface);
143
144 return tc->surface;
145 }
146
147
148 void
149 sp_tile_cache_set_texture(struct softpipe_tile_cache *tc,
150 struct pipe_texture *texture)
151 {
152 uint i;
153
154 tc->texture = texture;
155
156 /* mark as entries as invalid/empty */
157 /* XXX we should try to avoid this when the teximage hasn't changed */
158 for (i = 0; i < NUM_ENTRIES; i++) {
159 tc->entries[i].x = -1;
160 }
161 }
162
163
164 void
165 sp_flush_tile_cache(struct softpipe_context *softpipe,
166 struct softpipe_tile_cache *tc)
167 {
168 struct pipe_context *pipe = &softpipe->pipe;
169 struct pipe_surface *ps = tc->surface;
170 boolean is_depth_stencil;
171 int inuse = 0, pos;
172
173 if (!ps || !ps->buffer)
174 return;
175
176 is_depth_stencil = (ps->format == PIPE_FORMAT_S8_Z24 ||
177 ps->format == PIPE_FORMAT_Z24_S8 ||
178 ps->format == PIPE_FORMAT_U_Z16 ||
179 ps->format == PIPE_FORMAT_U_Z32 ||
180 ps->format == PIPE_FORMAT_U_S8);
181
182 for (pos = 0; pos < NUM_ENTRIES; pos++) {
183 struct softpipe_cached_tile *tile = tc->entries + pos;
184 if (tile->x >= 0) {
185 if (is_depth_stencil) {
186 pipe->put_tile(pipe, ps,
187 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
188 tile->data.depth32, 0/*STRIDE*/);
189 }
190 else {
191 pipe->put_tile_rgba(pipe, ps,
192 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
193 (float *) tile->data.color);
194 }
195
196 tile->x = tile->y = -1; /* mark as empty */
197 inuse++;
198 }
199 }
200
201 /*
202 printf("flushed tiles in use: %d\n", inuse);
203 */
204 }
205
206
207 struct softpipe_cached_tile *
208 sp_get_cached_tile(struct softpipe_context *softpipe,
209 struct softpipe_tile_cache *tc, int x, int y)
210 {
211 struct pipe_context *pipe = &softpipe->pipe;
212 struct pipe_surface *ps = tc->surface;
213 boolean is_depth_stencil
214 = (ps->format == PIPE_FORMAT_S8_Z24 ||
215 ps->format == PIPE_FORMAT_Z24_S8 ||
216 ps->format == PIPE_FORMAT_U_Z16 ||
217 ps->format == PIPE_FORMAT_U_Z32 ||
218 ps->format == PIPE_FORMAT_U_S8);
219
220 /* tile pos in framebuffer: */
221 const int tile_x = x & ~(TILE_SIZE - 1);
222 const int tile_y = y & ~(TILE_SIZE - 1);
223
224 /* cache pos/entry: */
225 const int pos = CACHE_POS(x, y);
226 struct softpipe_cached_tile *tile = tc->entries + pos;
227
228 if (tile_x != tile->x ||
229 tile_y != tile->y) {
230
231 if (tile->x != -1) {
232 /* put dirty tile back in framebuffer */
233 if (is_depth_stencil) {
234 pipe->put_tile(pipe, ps,
235 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
236 tile->data.depth32, 0 /*STRIDE*/);
237 }
238 else {
239 pipe->put_tile_rgba(pipe, ps,
240 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
241 (float *) tile->data.color);
242 }
243 }
244
245 if (is_clear_flag_set(tc->clear_flags, x, y)) {
246 /* don't get tile from framebuffer, just clear it */
247 uint i, j;
248 /* XXX these loops could be optimized */
249 switch (ps->format) {
250 case PIPE_FORMAT_U_Z16:
251 {
252 ushort clear_val = (ushort) (tc->clear_value[0] * 0xffff);
253 for (i = 0; i < TILE_SIZE; i++) {
254 for (j = 0; j < TILE_SIZE; j++) {
255 tile->data.depth16[i][j] = clear_val;
256 }
257 }
258 }
259 break;
260 case PIPE_FORMAT_U_Z32:
261 {
262 uint clear_val = (uint) (tc->clear_value[0] * 0xffffffff);
263 for (i = 0; i < TILE_SIZE; i++) {
264 for (j = 0; j < TILE_SIZE; j++) {
265 tile->data.depth32[i][j] = clear_val;
266 }
267 }
268 }
269 break;
270 case PIPE_FORMAT_S8_Z24:
271 {
272 uint clear_val = (uint) (tc->clear_value[0] * 0xffffff);
273 clear_val |= ((uint) tc->clear_value[1]) << 24;
274 for (i = 0; i < TILE_SIZE; i++) {
275 for (j = 0; j < TILE_SIZE; j++) {
276 tile->data.depth32[i][j] = clear_val;
277 }
278 }
279 }
280 break;
281 case PIPE_FORMAT_Z24_S8:
282 {
283 uint clear_val = ((uint) (tc->clear_value[0] * 0xffffff)) << 8;
284 clear_val |= ((uint) tc->clear_value[1]) & 0xff;
285 for (i = 0; i < TILE_SIZE; i++) {
286 for (j = 0; j < TILE_SIZE; j++) {
287 tile->data.depth32[i][j] = clear_val;
288 }
289 }
290 }
291 break;
292 case PIPE_FORMAT_U_S8:
293 {
294 ubyte clear_val = (uint) tc->clear_value[0];
295 for (i = 0; i < TILE_SIZE; i++) {
296 for (j = 0; j < TILE_SIZE; j++) {
297 tile->data.stencil8[i][j] = clear_val;
298 }
299 }
300 }
301 break;
302 default:
303 /* color */
304 for (i = 0; i < TILE_SIZE; i++) {
305 for (j = 0; j < TILE_SIZE; j++) {
306 tile->data.color[i][j][0] = tc->clear_value[0];
307 tile->data.color[i][j][1] = tc->clear_value[1];
308 tile->data.color[i][j][2] = tc->clear_value[2];
309 tile->data.color[i][j][3] = tc->clear_value[3];
310 }
311 }
312 }
313 clear_clear_flag(tc->clear_flags, x, y);
314 }
315 else {
316 /* get new tile from framebuffer */
317 if (is_depth_stencil) {
318 pipe->get_tile(pipe, ps,
319 tile_x, tile_y, TILE_SIZE, TILE_SIZE,
320 tile->data.depth32, 0/*STRIDE*/);
321 }
322 else {
323 pipe->get_tile_rgba(pipe, ps,
324 tile_x, tile_y, TILE_SIZE, TILE_SIZE,
325 (float *) tile->data.color);
326 }
327 }
328
329 tile->x = tile_x;
330 tile->y = tile_y;
331 }
332
333 return tile;
334 }
335
336
337 /**
338 * Given the texture face, level, zslice, x and y values, compute
339 * the cache entry position/index where we'd hope to find the
340 * cached texture tile.
341 * This is basically a direct-map cache.
342 * XXX There's probably lots of ways in which we can improve this.
343 */
344 static INLINE uint
345 tex_cache_pos(int x, int y, int z, int face, int level)
346 {
347 uint entry = x + y * 5 + z * 4 + face + level;
348 return entry % NUM_ENTRIES;
349 }
350
351
352 /**
353 * Similar to sp_get_cached_tile() but for textures.
354 * Tiles are read-only and indexed with more params.
355 */
356 const struct softpipe_cached_tile *
357 sp_get_cached_tile_tex(struct pipe_context *pipe,
358 struct softpipe_tile_cache *tc, int x, int y, int z,
359 int face, int level)
360 {
361 /* tile pos in framebuffer: */
362 const int tile_x = x & ~(TILE_SIZE - 1);
363 const int tile_y = y & ~(TILE_SIZE - 1);
364 /* cache pos/entry: */
365 const uint pos = tex_cache_pos(x / TILE_SIZE, y / TILE_SIZE, z,
366 face, level);
367 struct softpipe_cached_tile *tile = tc->entries + pos;
368
369 if (tile_x != tile->x ||
370 tile_y != tile->y ||
371 z != tile->z ||
372 face != tile->face ||
373 level != tile->level) {
374 /* XXX this call is a bit heavier than we'd like: */
375 struct pipe_surface *ps
376 = pipe->get_tex_surface(pipe, tc->texture, face, level, z);
377
378 if (ps != tc->surface) {
379 if (tc->surface && tc->surface->map)
380 pipe_surface_unmap(tc->surface);
381
382 pipe_surface_reference(&tc->surface, ps);
383
384 if (!tc->surface->map)
385 pipe_surface_map(tc->surface);
386 }
387
388 pipe->get_tile_rgba(pipe, ps,
389 tile_x, tile_y, TILE_SIZE, TILE_SIZE,
390 (float *) tile->data.color);
391
392 pipe_surface_reference(&ps, NULL);
393
394 tile->x = tile_x;
395 tile->y = tile_y;
396 tile->z = z;
397 tile->face = face;
398 tile->level = level;
399 }
400
401 return tile;
402 }
403
404
405 /**
406 * When a whole surface is being cleared to a value we can avoid
407 * fetching tiles above.
408 * Save the color and set a 'clearflag' for each tile of the screen.
409 */
410 void
411 sp_tile_cache_clear(struct softpipe_tile_cache *tc, const float value[4])
412 {
413 tc->clear_value[0] = value[0];
414 tc->clear_value[1] = value[1];
415 tc->clear_value[2] = value[2];
416 tc->clear_value[3] = value[3];
417
418 #if CLEAR_OPTIMIZATION
419 memset(tc->clear_flags, 255, sizeof(tc->clear_flags));
420 #else
421 memset(tc->clear_flags, 0, sizeof(tc->clear_flags));
422 #endif
423 }