00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00035 #include "pipe/p_inlines.h"
00036 #include "util/u_memory.h"
00037 #include "util/u_tile.h"
00038 #include "sp_context.h"
00039 #include "sp_surface.h"
00040 #include "sp_texture.h"
00041 #include "sp_tile_cache.h"
00042
00043 #define NUM_ENTRIES 50
00044
00045
00047 #define MAX_WIDTH 2048
00048 #define MAX_HEIGHT 2048
00049
00050
00051 struct softpipe_tile_cache
00052 {
00053 struct pipe_screen *screen;
00054 struct pipe_surface *surface;
00055 void *surface_map;
00056 struct pipe_texture *texture;
00057 struct softpipe_cached_tile entries[NUM_ENTRIES];
00058 uint clear_flags[(MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32];
00059 float clear_color[4];
00060 uint clear_val;
00061 boolean depth_stencil;
00063 struct pipe_surface *tex_surf;
00064 void *tex_surf_map;
00065 int tex_face, tex_level, tex_z;
00066
00067 struct softpipe_cached_tile tile;
00068 };
00069
00070
00077 #define CACHE_POS(x, y) \
00078 (((x) / TILE_SIZE + ((y) / TILE_SIZE) * 5) % NUM_ENTRIES)
00079
00080
00081
00085 static INLINE uint
00086 is_clear_flag_set(const uint *bitvec, int x, int y)
00087 {
00088 int pos, bit;
00089 x /= TILE_SIZE;
00090 y /= TILE_SIZE;
00091 pos = y * (MAX_WIDTH / TILE_SIZE) + x;
00092 assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
00093 bit = bitvec[pos / 32] & (1 << (pos & 31));
00094 return bit;
00095 }
00096
00097
00101 static INLINE void
00102 clear_clear_flag(uint *bitvec, int x, int y)
00103 {
00104 int pos;
00105 x /= TILE_SIZE;
00106 y /= TILE_SIZE;
00107 pos = y * (MAX_WIDTH / TILE_SIZE) + x;
00108 assert(pos / 32 < (MAX_WIDTH / TILE_SIZE) * (MAX_HEIGHT / TILE_SIZE) / 32);
00109 bitvec[pos / 32] &= ~(1 << (pos & 31));
00110 }
00111
00112
00113 struct softpipe_tile_cache *
00114 sp_create_tile_cache( struct pipe_screen *screen )
00115 {
00116 struct softpipe_tile_cache *tc;
00117 uint pos;
00118
00119 tc = CALLOC_STRUCT( softpipe_tile_cache );
00120 if (tc) {
00121 tc->screen = screen;
00122 for (pos = 0; pos < NUM_ENTRIES; pos++) {
00123 tc->entries[pos].x =
00124 tc->entries[pos].y = -1;
00125 }
00126 }
00127 return tc;
00128 }
00129
00130
00131 void
00132 sp_destroy_tile_cache(struct softpipe_tile_cache *tc)
00133 {
00134 uint pos;
00135
00136 for (pos = 0; pos < NUM_ENTRIES; pos++) {
00137
00138 }
00139 if (tc->surface) {
00140 pipe_surface_reference(&tc->surface, NULL);
00141 }
00142 if (tc->tex_surf) {
00143 pipe_surface_reference(&tc->tex_surf, NULL);
00144 }
00145
00146 FREE( tc );
00147 }
00148
00149
00153 void
00154 sp_tile_cache_set_surface(struct softpipe_tile_cache *tc,
00155 struct pipe_surface *ps)
00156 {
00157 assert(!tc->texture);
00158
00159 if (tc->surface_map) {
00160 tc->screen->surface_unmap(tc->screen, tc->surface);
00161 tc->surface_map = NULL;
00162 }
00163
00164 pipe_surface_reference(&tc->surface, ps);
00165
00166 if (tc->surface) {
00167 if (tc->surface_map)
00168 tc->surface_map = tc->screen->surface_map(tc->screen, tc->surface,
00169 PIPE_BUFFER_USAGE_CPU_READ |
00170 PIPE_BUFFER_USAGE_CPU_WRITE);
00171
00172 tc->depth_stencil = (ps->format == PIPE_FORMAT_S8Z24_UNORM ||
00173 ps->format == PIPE_FORMAT_X8Z24_UNORM ||
00174 ps->format == PIPE_FORMAT_Z24S8_UNORM ||
00175 ps->format == PIPE_FORMAT_Z24X8_UNORM ||
00176 ps->format == PIPE_FORMAT_Z16_UNORM ||
00177 ps->format == PIPE_FORMAT_Z32_UNORM ||
00178 ps->format == PIPE_FORMAT_S8_UNORM);
00179 }
00180 }
00181
00182
00186 struct pipe_surface *
00187 sp_tile_cache_get_surface(struct softpipe_tile_cache *tc)
00188 {
00189 return tc->surface;
00190 }
00191
00192
00193 void
00194 sp_tile_cache_map_surfaces(struct softpipe_tile_cache *tc)
00195 {
00196 if (tc->surface && !tc->surface_map)
00197 tc->surface_map = tc->screen->surface_map(tc->screen, tc->surface,
00198 PIPE_BUFFER_USAGE_CPU_WRITE |
00199 PIPE_BUFFER_USAGE_CPU_READ);
00200
00201 if (tc->tex_surf && !tc->tex_surf_map)
00202 tc->tex_surf_map = tc->screen->surface_map(tc->screen, tc->tex_surf,
00203 PIPE_BUFFER_USAGE_CPU_READ);
00204 }
00205
00206
00207 void
00208 sp_tile_cache_unmap_surfaces(struct softpipe_tile_cache *tc)
00209 {
00210 if (tc->surface_map) {
00211 tc->screen->surface_unmap(tc->screen, tc->surface);
00212 tc->surface_map = NULL;
00213 }
00214
00215 if (tc->tex_surf_map) {
00216 tc->screen->surface_unmap(tc->screen, tc->tex_surf);
00217 tc->tex_surf_map = NULL;
00218 }
00219 }
00220
00221
00225 void
00226 sp_tile_cache_set_texture(struct pipe_context *pipe,
00227 struct softpipe_tile_cache *tc,
00228 struct pipe_texture *texture)
00229 {
00230 uint i;
00231
00232 assert(!tc->surface);
00233
00234 pipe_texture_reference(&tc->texture, texture);
00235
00236 if (tc->tex_surf_map) {
00237 tc->screen->surface_unmap(tc->screen, tc->tex_surf);
00238 tc->tex_surf_map = NULL;
00239 }
00240 pipe_surface_reference(&tc->tex_surf, NULL);
00241
00242
00243
00244 for (i = 0; i < NUM_ENTRIES; i++) {
00245 tc->entries[i].x = -1;
00246 }
00247
00248 tc->tex_face = -1;
00249 }
00250
00251
00255 static void
00256 clear_tile_rgba(struct softpipe_cached_tile *tile,
00257 enum pipe_format format,
00258 const float clear_value[4])
00259 {
00260 if (clear_value[0] == 0.0 &&
00261 clear_value[1] == 0.0 &&
00262 clear_value[2] == 0.0 &&
00263 clear_value[3] == 0.0) {
00264 memset(tile->data.color, 0, sizeof(tile->data.color));
00265 }
00266 else {
00267 uint i, j;
00268 for (i = 0; i < TILE_SIZE; i++) {
00269 for (j = 0; j < TILE_SIZE; j++) {
00270 tile->data.color[i][j][0] = clear_value[0];
00271 tile->data.color[i][j][1] = clear_value[1];
00272 tile->data.color[i][j][2] = clear_value[2];
00273 tile->data.color[i][j][3] = clear_value[3];
00274 }
00275 }
00276 }
00277 }
00278
00279
00283 static void
00284 clear_tile(struct softpipe_cached_tile *tile,
00285 enum pipe_format format,
00286 uint clear_value)
00287 {
00288 uint i, j;
00289
00290 switch (pf_get_size(format)) {
00291 case 1:
00292 memset(tile->data.any, 0, TILE_SIZE * TILE_SIZE);
00293 break;
00294 case 2:
00295 if (clear_value == 0) {
00296 memset(tile->data.any, 0, 2 * TILE_SIZE * TILE_SIZE);
00297 }
00298 else {
00299 for (i = 0; i < TILE_SIZE; i++) {
00300 for (j = 0; j < TILE_SIZE; j++) {
00301 tile->data.depth16[i][j] = (ushort) clear_value;
00302 }
00303 }
00304 }
00305 break;
00306 case 4:
00307 if (clear_value == 0) {
00308 memset(tile->data.any, 0, 4 * TILE_SIZE * TILE_SIZE);
00309 }
00310 else {
00311 for (i = 0; i < TILE_SIZE; i++) {
00312 for (j = 0; j < TILE_SIZE; j++) {
00313 tile->data.color32[i][j] = clear_value;
00314 }
00315 }
00316 }
00317 break;
00318 default:
00319 assert(0);
00320 }
00321 }
00322
00323
00327 static void
00328 sp_tile_cache_flush_clear(struct pipe_context *pipe,
00329 struct softpipe_tile_cache *tc)
00330 {
00331 struct pipe_surface *ps = tc->surface;
00332 const uint w = tc->surface->width;
00333 const uint h = tc->surface->height;
00334 uint x, y;
00335 uint numCleared = 0;
00336
00337
00338 clear_tile(&tc->tile, ps->format, tc->clear_val);
00339
00340
00341 for (y = 0; y < h; y += TILE_SIZE) {
00342 for (x = 0; x < w; x += TILE_SIZE) {
00343 if (is_clear_flag_set(tc->clear_flags, x, y)) {
00344 pipe_put_tile_raw(ps,
00345 x, y, TILE_SIZE, TILE_SIZE,
00346 tc->tile.data.color32, 0);
00347
00348
00349 clear_clear_flag(tc->clear_flags, x, y);
00350
00351 numCleared++;
00352 }
00353 }
00354 }
00355 #if 0
00356 debug_printf("num cleared: %u\n", numCleared);
00357 #endif
00358 }
00359
00360
00365 void
00366 sp_flush_tile_cache(struct softpipe_context *softpipe,
00367 struct softpipe_tile_cache *tc)
00368 {
00369 struct pipe_surface *ps = tc->surface;
00370 int inuse = 0, pos;
00371
00372 if (ps && ps->buffer) {
00373
00374 for (pos = 0; pos < NUM_ENTRIES; pos++) {
00375 struct softpipe_cached_tile *tile = tc->entries + pos;
00376 if (tile->x >= 0) {
00377 if (tc->depth_stencil) {
00378 pipe_put_tile_raw(ps,
00379 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
00380 tile->data.depth32, 0);
00381 }
00382 else {
00383 pipe_put_tile_rgba(ps,
00384 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
00385 (float *) tile->data.color);
00386 }
00387 tile->x = tile->y = -1;
00388 inuse++;
00389 }
00390 }
00391
00392 #if TILE_CLEAR_OPTIMIZATION
00393 sp_tile_cache_flush_clear(&softpipe->pipe, tc);
00394 #endif
00395 }
00396 else if (tc->texture) {
00397
00398 for (pos = 0; pos < NUM_ENTRIES; pos++) {
00399 tc->entries[pos].x = -1;
00400 }
00401 tc->tex_face = -1;
00402 }
00403
00404 #if 0
00405 debug_printf("flushed tiles in use: %d\n", inuse);
00406 #endif
00407 }
00408
00409
00414 struct softpipe_cached_tile *
00415 sp_get_cached_tile(struct softpipe_context *softpipe,
00416 struct softpipe_tile_cache *tc, int x, int y)
00417 {
00418 struct pipe_surface *ps = tc->surface;
00419
00420
00421 const int tile_x = x & ~(TILE_SIZE - 1);
00422 const int tile_y = y & ~(TILE_SIZE - 1);
00423
00424
00425 const int pos = CACHE_POS(x, y);
00426 struct softpipe_cached_tile *tile = tc->entries + pos;
00427
00428 if (tile_x != tile->x ||
00429 tile_y != tile->y) {
00430
00431 if (tile->x != -1) {
00432
00433 if (tc->depth_stencil) {
00434 pipe_put_tile_raw(ps,
00435 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
00436 tile->data.depth32, 0);
00437 }
00438 else {
00439 pipe_put_tile_rgba(ps,
00440 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
00441 (float *) tile->data.color);
00442 }
00443 }
00444
00445 tile->x = tile_x;
00446 tile->y = tile_y;
00447
00448 if (is_clear_flag_set(tc->clear_flags, x, y)) {
00449
00450 if (tc->depth_stencil) {
00451 clear_tile(tile, ps->format, tc->clear_val);
00452 }
00453 else {
00454 clear_tile_rgba(tile, ps->format, tc->clear_color);
00455 }
00456 clear_clear_flag(tc->clear_flags, x, y);
00457 }
00458 else {
00459
00460 if (tc->depth_stencil) {
00461 pipe_get_tile_raw(ps,
00462 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
00463 tile->data.depth32, 0);
00464 }
00465 else {
00466 pipe_get_tile_rgba(ps,
00467 tile->x, tile->y, TILE_SIZE, TILE_SIZE,
00468 (float *) tile->data.color);
00469 }
00470 }
00471 }
00472
00473 return tile;
00474 }
00475
00476
00484 static INLINE uint
00485 tex_cache_pos(int x, int y, int z, int face, int level)
00486 {
00487 uint entry = x + y * 9 + z * 3 + face + level * 7;
00488 return entry % NUM_ENTRIES;
00489 }
00490
00491
00496 const struct softpipe_cached_tile *
00497 sp_get_cached_tile_tex(struct pipe_context *pipe,
00498 struct softpipe_tile_cache *tc, int x, int y, int z,
00499 int face, int level)
00500 {
00501 struct pipe_screen *screen = pipe->screen;
00502
00503 const int tile_x = x & ~(TILE_SIZE - 1);
00504 const int tile_y = y & ~(TILE_SIZE - 1);
00505
00506 const uint pos = tex_cache_pos(x / TILE_SIZE, y / TILE_SIZE, z,
00507 face, level);
00508 struct softpipe_cached_tile *tile = tc->entries + pos;
00509
00510 if (tc->texture) {
00511 struct softpipe_texture *spt = softpipe_texture(tc->texture);
00512 if (spt->modified) {
00513
00514 uint p;
00515 for (p = 0; p < NUM_ENTRIES; p++) {
00516 tile = tc->entries + p;
00517 tile->x = -1;
00518 }
00519 spt->modified = FALSE;
00520 }
00521 }
00522
00523 if (tile_x != tile->x ||
00524 tile_y != tile->y ||
00525 z != tile->z ||
00526 face != tile->face ||
00527 level != tile->level) {
00528
00529
00530 #if 0
00531 printf("miss at %u x=%d y=%d z=%d face=%d level=%d\n", pos,
00532 x/TILE_SIZE, y/TILE_SIZE, z, face, level);
00533 #endif
00534
00535 if (!tc->tex_surf ||
00536 tc->tex_face != face ||
00537 tc->tex_level != level ||
00538 tc->tex_z != z) {
00539
00540
00541 if (tc->tex_surf_map)
00542 tc->screen->surface_unmap(tc->screen, tc->tex_surf);
00543
00544 tc->tex_surf = screen->get_tex_surface(screen, tc->texture, face, level, z,
00545 PIPE_BUFFER_USAGE_CPU_READ);
00546 tc->tex_surf_map = screen->surface_map(screen, tc->tex_surf,
00547 PIPE_BUFFER_USAGE_CPU_READ);
00548
00549 tc->tex_face = face;
00550 tc->tex_level = level;
00551 tc->tex_z = z;
00552 }
00553
00554
00555 pipe_get_tile_rgba(tc->tex_surf,
00556 tile_x, tile_y, TILE_SIZE, TILE_SIZE,
00557 (float *) tile->data.color);
00558 tile->x = tile_x;
00559 tile->y = tile_y;
00560 tile->z = z;
00561 tile->face = face;
00562 tile->level = level;
00563 }
00564
00565 return tile;
00566 }
00567
00568
00574 void
00575 sp_tile_cache_clear(struct softpipe_tile_cache *tc, uint clearValue)
00576 {
00577 uint r, g, b, a;
00578 uint pos;
00579
00580 tc->clear_val = clearValue;
00581
00582 switch (tc->surface->format) {
00583 case PIPE_FORMAT_R8G8B8A8_UNORM:
00584 case PIPE_FORMAT_R8G8B8X8_UNORM:
00585 r = (clearValue >> 24) & 0xff;
00586 g = (clearValue >> 16) & 0xff;
00587 b = (clearValue >> 8) & 0xff;
00588 a = (clearValue ) & 0xff;
00589 break;
00590 case PIPE_FORMAT_A8R8G8B8_UNORM:
00591 case PIPE_FORMAT_X8R8G8B8_UNORM:
00592 r = (clearValue >> 16) & 0xff;
00593 g = (clearValue >> 8) & 0xff;
00594 b = (clearValue ) & 0xff;
00595 a = (clearValue >> 24) & 0xff;
00596 break;
00597 case PIPE_FORMAT_B8G8R8A8_UNORM:
00598 case PIPE_FORMAT_B8G8R8X8_UNORM:
00599 r = (clearValue >> 8) & 0xff;
00600 g = (clearValue >> 16) & 0xff;
00601 b = (clearValue >> 24) & 0xff;
00602 a = (clearValue ) & 0xff;
00603 break;
00604 default:
00605 r = g = b = a = 0;
00606 }
00607
00608 tc->clear_color[0] = r / 255.0f;
00609 tc->clear_color[1] = g / 255.0f;
00610 tc->clear_color[2] = b / 255.0f;
00611 tc->clear_color[3] = a / 255.0f;
00612
00613 #if TILE_CLEAR_OPTIMIZATION
00614
00615 memset(tc->clear_flags, 255, sizeof(tc->clear_flags));
00616 #else
00617
00618 memset(tc->clear_flags, 0, sizeof(tc->clear_flags));
00619 #endif
00620
00621 for (pos = 0; pos < NUM_ENTRIES; pos++) {
00622 struct softpipe_cached_tile *tile = tc->entries + pos;
00623 tile->x = tile->y = -1;
00624 }
00625 }