1 /**************************************************************************
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
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:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
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.
26 **************************************************************************/
29 * Texture tile caching.
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"
47 #define MAX_WIDTH 4096
48 #define MAX_HEIGHT 4096
51 enum llvmpipe_tile_status
53 LP_TILE_STATUS_UNDEFINED
= 0,
54 LP_TILE_STATUS_CLEAR
= 1,
55 LP_TILE_STATUS_DEFINED
= 2
59 struct llvmpipe_cached_tile
61 enum llvmpipe_tile_status status
;
63 /** color in SOA format */
68 struct llvmpipe_tile_cache
70 struct pipe_screen
*screen
;
71 struct pipe_surface
*surface
; /**< the surface we're caching */
72 struct pipe_transfer
*transfer
;
75 struct llvmpipe_cached_tile entries
[MAX_WIDTH
/TILE_SIZE
][MAX_HEIGHT
/TILE_SIZE
];
77 uint8_t clear_color
[4]; /**< for color bufs */
78 uint clear_val
; /**< for z+stencil, or packed color clear value */
80 struct llvmpipe_cached_tile
*last_tile
; /**< most recently retrieved tile */
84 struct llvmpipe_tile_cache
*
85 lp_create_tile_cache( struct pipe_screen
*screen
)
87 struct llvmpipe_tile_cache
*tc
;
88 int maxLevels
, maxTexSize
;
90 /* sanity checking: max sure MAX_WIDTH/HEIGHT >= largest texture image */
91 maxLevels
= screen
->get_param(screen
, PIPE_CAP_MAX_TEXTURE_2D_LEVELS
);
92 maxTexSize
= 1 << (maxLevels
- 1);
93 assert(MAX_WIDTH
>= maxTexSize
);
95 tc
= CALLOC_STRUCT( llvmpipe_tile_cache
);
106 lp_destroy_tile_cache(struct llvmpipe_tile_cache
*tc
)
108 struct pipe_screen
*screen
;
111 for (y
= 0; y
< MAX_HEIGHT
; y
+= TILE_SIZE
) {
112 for (x
= 0; x
< MAX_WIDTH
; x
+= TILE_SIZE
) {
113 struct llvmpipe_cached_tile
*tile
= &tc
->entries
[y
/TILE_SIZE
][x
/TILE_SIZE
];
116 align_free(tile
->color
);
121 screen
= tc
->transfer
->texture
->screen
;
122 screen
->tex_transfer_destroy(tc
->transfer
);
130 * Specify the surface to cache.
133 lp_tile_cache_set_surface(struct llvmpipe_tile_cache
*tc
,
134 struct pipe_surface
*ps
)
137 struct pipe_screen
*screen
= tc
->transfer
->texture
->screen
;
139 if (ps
== tc
->surface
)
142 if (tc
->transfer_map
) {
143 screen
->transfer_unmap(screen
, tc
->transfer
);
144 tc
->transfer_map
= NULL
;
147 screen
->tex_transfer_destroy(tc
->transfer
);
154 struct pipe_screen
*screen
= ps
->texture
->screen
;
157 tc
->transfer
= screen
->get_tex_transfer(screen
, ps
->texture
, ps
->face
,
158 ps
->level
, ps
->zslice
,
159 PIPE_TRANSFER_READ_WRITE
,
160 0, 0, ps
->width
, ps
->height
);
162 for (y
= 0; y
< ps
->height
; y
+= TILE_SIZE
) {
163 for (x
= 0; x
< ps
->width
; x
+= TILE_SIZE
) {
164 struct llvmpipe_cached_tile
*tile
= &tc
->entries
[y
/TILE_SIZE
][x
/TILE_SIZE
];
166 tile
->status
= LP_TILE_STATUS_UNDEFINED
;
169 tile
->color
= align_malloc( TILE_SIZE
*TILE_SIZE
*NUM_CHANNELS
, 16 );
177 * Return the transfer being cached.
179 struct pipe_surface
*
180 lp_tile_cache_get_surface(struct llvmpipe_tile_cache
*tc
)
187 lp_tile_cache_map_transfers(struct llvmpipe_tile_cache
*tc
)
189 if (tc
->transfer
&& !tc
->transfer_map
)
190 tc
->transfer_map
= tc
->screen
->transfer_map(tc
->screen
, tc
->transfer
);
195 lp_tile_cache_unmap_transfers(struct llvmpipe_tile_cache
*tc
)
197 if (tc
->transfer_map
) {
198 tc
->screen
->transfer_unmap(tc
->screen
, tc
->transfer
);
199 tc
->transfer_map
= NULL
;
205 * Set a tile to a solid color.
208 clear_tile(struct llvmpipe_cached_tile
*tile
,
209 uint8_t clear_color
[4])
211 if (clear_color
[0] == clear_color
[1] &&
212 clear_color
[1] == clear_color
[2] &&
213 clear_color
[2] == clear_color
[3]) {
214 memset(tile
->color
, clear_color
[0], TILE_SIZE
* TILE_SIZE
* 4);
218 for (y
= 0; y
< TILE_SIZE
; y
++)
219 for (x
= 0; x
< TILE_SIZE
; x
++)
220 for (chan
= 0; chan
< 4; ++chan
)
221 TILE_PIXEL(tile
->color
, x
, y
, chan
) = clear_color
[chan
];
227 * Flush the tile cache: write all dirty tiles back to the transfer.
228 * any tiles "flagged" as cleared will be "really" cleared.
231 lp_flush_tile_cache(struct llvmpipe_tile_cache
*tc
)
233 struct pipe_transfer
*pt
= tc
->transfer
;
239 assert(tc
->transfer_map
);
241 /* push the tile to all positions marked as clear */
242 for (y
= 0; y
< pt
->height
; y
+= TILE_SIZE
) {
243 for (x
= 0; x
< pt
->width
; x
+= TILE_SIZE
) {
244 struct llvmpipe_cached_tile
*tile
= &tc
->entries
[y
/TILE_SIZE
][x
/TILE_SIZE
];
246 if(tile
->status
!= LP_TILE_STATUS_UNDEFINED
) {
247 unsigned w
= TILE_SIZE
;
248 unsigned h
= TILE_SIZE
;
250 if (!pipe_clip_tile(x
, y
, &w
, &h
, pt
)) {
251 switch(tile
->status
) {
252 case LP_TILE_STATUS_CLEAR
:
253 /* Actually clear the tiles which were flagged as being in a
255 util_fill_rect(tc
->transfer_map
, pt
->texture
->format
, pt
->stride
,
260 case LP_TILE_STATUS_DEFINED
:
261 lp_tile_write_4ub(pt
->texture
->format
,
263 tc
->transfer_map
, pt
->stride
,
273 tile
->status
= LP_TILE_STATUS_UNDEFINED
;
281 * Get a tile from the cache.
282 * \param x, y position of tile, in pixels
285 lp_get_cached_tile(struct llvmpipe_tile_cache
*tc
,
286 unsigned x
, unsigned y
)
288 struct llvmpipe_cached_tile
*tile
= &tc
->entries
[y
/TILE_SIZE
][x
/TILE_SIZE
];
289 struct pipe_transfer
*pt
= tc
->transfer
;
292 assert(tc
->transfer
);
294 if(!tc
->transfer_map
)
295 lp_tile_cache_map_transfers(tc
);
297 assert(tc
->transfer_map
);
299 switch(tile
->status
) {
300 case LP_TILE_STATUS_CLEAR
:
301 /* don't get tile from framebuffer, just clear it */
302 clear_tile(tile
, tc
->clear_color
);
303 tile
->status
= LP_TILE_STATUS_DEFINED
;
306 case LP_TILE_STATUS_UNDEFINED
: {
307 unsigned w
= TILE_SIZE
;
308 unsigned h
= TILE_SIZE
;
310 x
&= ~(TILE_SIZE
- 1);
311 y
&= ~(TILE_SIZE
- 1);
313 if (!pipe_clip_tile(x
, y
, &w
, &h
, tc
->transfer
))
314 lp_tile_read_4ub(pt
->texture
->format
,
316 tc
->transfer_map
, tc
->transfer
->stride
,
319 tile
->status
= LP_TILE_STATUS_DEFINED
;
323 case LP_TILE_STATUS_DEFINED
:
333 * When a whole surface is being cleared to a value we can avoid
334 * fetching tiles above.
335 * Save the color and set a 'clearflag' for each tile of the screen.
338 lp_tile_cache_clear(struct llvmpipe_tile_cache
*tc
, const float *rgba
,
341 struct pipe_transfer
*pt
= tc
->transfer
;
342 const unsigned w
= pt
->width
;
343 const unsigned h
= pt
->height
;
346 for(chan
= 0; chan
< 4; ++chan
)
347 tc
->clear_color
[chan
] = float_to_ubyte(rgba
[chan
]);
349 tc
->clear_val
= clearValue
;
351 /* push the tile to all positions marked as clear */
352 for (y
= 0; y
< h
; y
+= TILE_SIZE
) {
353 for (x
= 0; x
< w
; x
+= TILE_SIZE
) {
354 struct llvmpipe_cached_tile
*tile
= &tc
->entries
[y
/TILE_SIZE
][x
/TILE_SIZE
];
355 tile
->status
= LP_TILE_STATUS_CLEAR
;