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_tile_soa.h"
42 #include "lp_tile_cache.h"
45 #define MAX_WIDTH 4096
46 #define MAX_HEIGHT 4096
49 enum llvmpipe_tile_status
51 LP_TILE_STATUS_UNDEFINED
= 0,
52 LP_TILE_STATUS_CLEAR
= 1,
53 LP_TILE_STATUS_DEFINED
= 2
57 struct llvmpipe_cached_tile
59 enum llvmpipe_tile_status status
;
61 /** color in SOA format */
66 struct llvmpipe_tile_cache
68 struct pipe_screen
*screen
;
69 struct pipe_surface
*surface
; /**< the surface we're caching */
70 struct pipe_transfer
*transfer
;
73 struct llvmpipe_cached_tile entries
[MAX_WIDTH
/TILE_SIZE
][MAX_HEIGHT
/TILE_SIZE
];
75 uint8_t clear_color
[4]; /**< for color bufs */
76 uint clear_val
; /**< for z+stencil, or packed color clear value */
78 struct llvmpipe_cached_tile
*last_tile
; /**< most recently retrieved tile */
82 struct llvmpipe_tile_cache
*
83 lp_create_tile_cache( struct pipe_screen
*screen
)
85 struct llvmpipe_tile_cache
*tc
;
86 int maxLevels
, maxTexSize
;
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
);
93 tc
= CALLOC_STRUCT( llvmpipe_tile_cache
);
104 lp_destroy_tile_cache(struct llvmpipe_tile_cache
*tc
)
106 struct pipe_screen
*screen
;
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
];
114 align_free(tile
->color
);
119 screen
= tc
->transfer
->texture
->screen
;
120 screen
->tex_transfer_destroy(tc
->transfer
);
128 * Specify the surface to cache.
131 lp_tile_cache_set_surface(struct llvmpipe_tile_cache
*tc
,
132 struct pipe_surface
*ps
)
135 struct pipe_screen
*screen
= tc
->transfer
->texture
->screen
;
137 if (ps
== tc
->surface
)
140 if (tc
->transfer_map
) {
141 screen
->transfer_unmap(screen
, tc
->transfer
);
142 tc
->transfer_map
= NULL
;
145 screen
->tex_transfer_destroy(tc
->transfer
);
152 struct pipe_screen
*screen
= ps
->texture
->screen
;
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
);
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
];
164 tile
->status
= LP_TILE_STATUS_UNDEFINED
;
167 tile
->color
= align_malloc( TILE_SIZE
*TILE_SIZE
*NUM_CHANNELS
, 16 );
175 * Return the transfer being cached.
177 struct pipe_surface
*
178 lp_tile_cache_get_surface(struct llvmpipe_tile_cache
*tc
)
185 lp_tile_cache_map_transfers(struct llvmpipe_tile_cache
*tc
)
187 if (tc
->transfer
&& !tc
->transfer_map
)
188 tc
->transfer_map
= tc
->screen
->transfer_map(tc
->screen
, tc
->transfer
);
193 lp_tile_cache_unmap_transfers(struct llvmpipe_tile_cache
*tc
)
195 if (tc
->transfer_map
) {
196 tc
->screen
->transfer_unmap(tc
->screen
, tc
->transfer
);
197 tc
->transfer_map
= NULL
;
203 * Set a tile to a solid color.
206 clear_tile(struct llvmpipe_cached_tile
*tile
,
207 uint8_t clear_color
[4])
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);
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
];
225 * Flush the tile cache: write all dirty tiles back to the transfer.
226 * any tiles "flagged" as cleared will be "really" cleared.
229 lp_flush_tile_cache(struct llvmpipe_tile_cache
*tc
)
231 struct pipe_transfer
*pt
= tc
->transfer
;
237 assert(tc
->transfer_map
);
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
];
244 if(tile
->status
!= LP_TILE_STATUS_UNDEFINED
) {
245 unsigned w
= TILE_SIZE
;
246 unsigned h
= TILE_SIZE
;
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
253 util_fill_rect(tc
->transfer_map
, pt
->texture
->format
, pt
->stride
,
258 case LP_TILE_STATUS_DEFINED
:
259 lp_tile_write_4ub(pt
->texture
->format
,
261 tc
->transfer_map
, pt
->stride
,
271 tile
->status
= LP_TILE_STATUS_UNDEFINED
;
279 * Get a tile from the cache.
280 * \param x, y position of tile, in pixels
283 lp_get_cached_tile(struct llvmpipe_tile_cache
*tc
,
284 unsigned x
, unsigned y
)
286 struct llvmpipe_cached_tile
*tile
= &tc
->entries
[y
/TILE_SIZE
][x
/TILE_SIZE
];
287 struct pipe_transfer
*pt
= tc
->transfer
;
290 assert(tc
->transfer
);
292 if(!tc
->transfer_map
)
293 lp_tile_cache_map_transfers(tc
);
295 assert(tc
->transfer_map
);
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
;
304 case LP_TILE_STATUS_UNDEFINED
: {
305 unsigned w
= TILE_SIZE
;
306 unsigned h
= TILE_SIZE
;
308 x
&= ~(TILE_SIZE
- 1);
309 y
&= ~(TILE_SIZE
- 1);
311 if (!pipe_clip_tile(x
, y
, &w
, &h
, tc
->transfer
))
312 lp_tile_read_4ub(pt
->texture
->format
,
314 tc
->transfer_map
, tc
->transfer
->stride
,
317 tile
->status
= LP_TILE_STATUS_DEFINED
;
321 case LP_TILE_STATUS_DEFINED
:
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.
336 lp_tile_cache_clear(struct llvmpipe_tile_cache
*tc
, const float *rgba
,
339 struct pipe_transfer
*pt
= tc
->transfer
;
340 const unsigned w
= pt
->width
;
341 const unsigned h
= pt
->height
;
344 for(chan
= 0; chan
< 4; ++chan
)
345 tc
->clear_color
[chan
] = float_to_ubyte(rgba
[chan
]);
347 tc
->clear_val
= clearValue
;
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
;