Merge branch 'mesa_7_7_branch'
[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_tile_soa.h"
42 #include "lp_tile_cache.h"
43
44
45 #define MAX_WIDTH 4096
46 #define MAX_HEIGHT 4096
47
48
49 enum llvmpipe_tile_status
50 {
51 LP_TILE_STATUS_UNDEFINED = 0,
52 LP_TILE_STATUS_CLEAR = 1,
53 LP_TILE_STATUS_DEFINED = 2
54 };
55
56
57 struct llvmpipe_cached_tile
58 {
59 enum llvmpipe_tile_status status;
60
61 /** color in SOA format */
62 uint8_t *color;
63 };
64
65
66 struct llvmpipe_tile_cache
67 {
68 struct pipe_screen *screen;
69 struct pipe_surface *surface; /**< the surface we're caching */
70 struct pipe_transfer *transfer;
71 void *transfer_map;
72
73 struct llvmpipe_cached_tile entries[MAX_WIDTH/TILE_SIZE][MAX_HEIGHT/TILE_SIZE];
74
75 uint8_t clear_color[4]; /**< for color bufs */
76 uint clear_val; /**< for z+stencil, or packed color clear value */
77
78 struct llvmpipe_cached_tile *last_tile; /**< most recently retrieved tile */
79 };
80
81
82 struct llvmpipe_tile_cache *
83 lp_create_tile_cache( struct pipe_screen *screen )
84 {
85 struct llvmpipe_tile_cache *tc;
86 int maxLevels, maxTexSize;
87
88 /* sanity checking: max sure MAX_WIDTH/HEIGHT >= largest texture image */
89 maxLevels = screen->get_param(screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
90 maxTexSize = 1 << (maxLevels - 1);
91 assert(MAX_WIDTH >= maxTexSize);
92
93 tc = CALLOC_STRUCT( llvmpipe_tile_cache );
94 if(!tc)
95 return NULL;
96
97 tc->screen = screen;
98
99 return tc;
100 }
101
102
103 void
104 lp_destroy_tile_cache(struct llvmpipe_tile_cache *tc)
105 {
106 struct pipe_screen *screen;
107 unsigned x, y;
108
109 for (y = 0; y < MAX_HEIGHT; y += TILE_SIZE) {
110 for (x = 0; x < MAX_WIDTH; x += TILE_SIZE) {
111 struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
112
113 if(tile->color)
114 align_free(tile->color);
115 }
116 }
117
118 if (tc->transfer) {
119 screen = tc->transfer->texture->screen;
120 screen->tex_transfer_destroy(tc->transfer);
121 }
122
123 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 if (tc->transfer) {
135 struct pipe_screen *screen = tc->transfer->texture->screen;
136
137 if (ps == tc->surface)
138 return;
139
140 if (tc->transfer_map) {
141 screen->transfer_unmap(screen, tc->transfer);
142 tc->transfer_map = NULL;
143 }
144
145 screen->tex_transfer_destroy(tc->transfer);
146 tc->transfer = NULL;
147 }
148
149 tc->surface = ps;
150
151 if (ps) {
152 struct pipe_screen *screen = ps->texture->screen;
153 unsigned x, y;
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 for (y = 0; y < ps->height; y += TILE_SIZE) {
161 for (x = 0; x < ps->width; x += TILE_SIZE) {
162 struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
163
164 tile->status = LP_TILE_STATUS_UNDEFINED;
165
166 if(!tile->color)
167 tile->color = align_malloc( TILE_SIZE*TILE_SIZE*NUM_CHANNELS, 16 );
168 }
169 }
170 }
171 }
172
173
174 /**
175 * Return the transfer being cached.
176 */
177 struct pipe_surface *
178 lp_tile_cache_get_surface(struct llvmpipe_tile_cache *tc)
179 {
180 return tc->surface;
181 }
182
183
184 void
185 lp_tile_cache_map_transfers(struct llvmpipe_tile_cache *tc)
186 {
187 if (tc->transfer && !tc->transfer_map)
188 tc->transfer_map = tc->screen->transfer_map(tc->screen, tc->transfer);
189 }
190
191
192 void
193 lp_tile_cache_unmap_transfers(struct llvmpipe_tile_cache *tc)
194 {
195 if (tc->transfer_map) {
196 tc->screen->transfer_unmap(tc->screen, tc->transfer);
197 tc->transfer_map = NULL;
198 }
199 }
200
201
202 /**
203 * Set a tile to a solid color.
204 */
205 static void
206 clear_tile(struct llvmpipe_cached_tile *tile,
207 uint8_t clear_color[4])
208 {
209 if (clear_color[0] == clear_color[1] &&
210 clear_color[1] == clear_color[2] &&
211 clear_color[2] == clear_color[3]) {
212 memset(tile->color, clear_color[0], TILE_SIZE * TILE_SIZE * 4);
213 }
214 else {
215 uint x, y, chan;
216 for (y = 0; y < TILE_SIZE; y++)
217 for (x = 0; x < TILE_SIZE; x++)
218 for (chan = 0; chan < 4; ++chan)
219 TILE_PIXEL(tile->color, x, y, chan) = clear_color[chan];
220 }
221 }
222
223
224 /**
225 * Flush the tile cache: write all dirty tiles back to the transfer.
226 * any tiles "flagged" as cleared will be "really" cleared.
227 */
228 void
229 lp_flush_tile_cache(struct llvmpipe_tile_cache *tc)
230 {
231 struct pipe_transfer *pt = tc->transfer;
232 unsigned x, y;
233
234 if(!pt)
235 return;
236
237 assert(tc->transfer_map);
238
239 /* push the tile to all positions marked as clear */
240 for (y = 0; y < pt->height; y += TILE_SIZE) {
241 for (x = 0; x < pt->width; x += TILE_SIZE) {
242 struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
243
244 if(tile->status != LP_TILE_STATUS_UNDEFINED) {
245 unsigned w = TILE_SIZE;
246 unsigned h = TILE_SIZE;
247
248 if (!pipe_clip_tile(x, y, &w, &h, pt)) {
249 switch(tile->status) {
250 case LP_TILE_STATUS_CLEAR:
251 /* Actually clear the tiles which were flagged as being in a
252 * clear state. */
253 util_fill_rect(tc->transfer_map, pt->texture->format, pt->stride,
254 x, y, w, h,
255 tc->clear_val);
256 break;
257
258 case LP_TILE_STATUS_DEFINED:
259 lp_tile_write_4ub(pt->texture->format,
260 tile->color,
261 tc->transfer_map, pt->stride,
262 x, y, w, h);
263 break;
264
265 default:
266 assert(0);
267 break;
268 }
269 }
270
271 tile->status = LP_TILE_STATUS_UNDEFINED;
272 }
273 }
274 }
275 }
276
277
278 /**
279 * Get a tile from the cache.
280 * \param x, y position of tile, in pixels
281 */
282 void *
283 lp_get_cached_tile(struct llvmpipe_tile_cache *tc,
284 unsigned x, unsigned y )
285 {
286 struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
287 struct pipe_transfer *pt = tc->transfer;
288
289 assert(tc->surface);
290 assert(tc->transfer);
291
292 if(!tc->transfer_map)
293 lp_tile_cache_map_transfers(tc);
294
295 assert(tc->transfer_map);
296
297 switch(tile->status) {
298 case LP_TILE_STATUS_CLEAR:
299 /* don't get tile from framebuffer, just clear it */
300 clear_tile(tile, tc->clear_color);
301 tile->status = LP_TILE_STATUS_DEFINED;
302 break;
303
304 case LP_TILE_STATUS_UNDEFINED: {
305 unsigned w = TILE_SIZE;
306 unsigned h = TILE_SIZE;
307
308 x &= ~(TILE_SIZE - 1);
309 y &= ~(TILE_SIZE - 1);
310
311 if (!pipe_clip_tile(x, y, &w, &h, tc->transfer))
312 lp_tile_read_4ub(pt->texture->format,
313 tile->color,
314 tc->transfer_map, tc->transfer->stride,
315 x, y, w, h);
316
317 tile->status = LP_TILE_STATUS_DEFINED;
318 break;
319 }
320
321 case LP_TILE_STATUS_DEFINED:
322 /* nothing to do */
323 break;
324 }
325
326 return tile->color;
327 }
328
329
330 /**
331 * When a whole surface is being cleared to a value we can avoid
332 * fetching tiles above.
333 * Save the color and set a 'clearflag' for each tile of the screen.
334 */
335 void
336 lp_tile_cache_clear(struct llvmpipe_tile_cache *tc, const float *rgba,
337 uint clearValue)
338 {
339 struct pipe_transfer *pt = tc->transfer;
340 const unsigned w = pt->width;
341 const unsigned h = pt->height;
342 unsigned x, y, chan;
343
344 for(chan = 0; chan < 4; ++chan)
345 tc->clear_color[chan] = float_to_ubyte(rgba[chan]);
346
347 tc->clear_val = clearValue;
348
349 /* push the tile to all positions marked as clear */
350 for (y = 0; y < h; y += TILE_SIZE) {
351 for (x = 0; x < w; x += TILE_SIZE) {
352 struct llvmpipe_cached_tile *tile = &tc->entries[y/TILE_SIZE][x/TILE_SIZE];
353 tile->status = LP_TILE_STATUS_CLEAR;
354 }
355 }
356 }