cso_context.c revision 7d95efde0a0e13e13c59444703bc47eb13926385
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 /* Wrap the cso cache & hash mechanisms in a simplified 29 * pipe-driver-specific interface. 30 * 31 * Authors: 32 * Zack Rusin <zack@tungstengraphics.com> 33 * Keith Whitwell <keith@tungstengraphics.com> 34 */ 35 36#include "pipe/p_state.h" 37#include "pipe/p_util.h" 38 39#include "cso_cache/cso_context.h" 40#include "cso_cache/cso_cache.h" 41#include "cso_cache/cso_hash.h" 42 43struct cso_context { 44 struct pipe_context *pipe; 45 struct cso_cache *cache; 46 47 struct { 48 void *samplers[PIPE_MAX_SAMPLERS]; 49 unsigned nr_samplers; 50 } hw; 51 52 void *samplers[PIPE_MAX_SAMPLERS]; 53 unsigned nr_samplers; 54 55 void *samplers_saved[PIPE_MAX_SAMPLERS]; 56 unsigned nr_samplers_saved; 57 58 struct pipe_texture *textures[PIPE_MAX_SAMPLERS]; 59 uint nr_textures; 60 61 struct pipe_texture *textures_saved[PIPE_MAX_SAMPLERS]; 62 uint nr_textures_saved; 63 64 /** Current and saved state. 65 * The saved state is used as a 1-deep stack. 66 */ 67 void *blend, *blend_saved; 68 void *depth_stencil, *depth_stencil_saved; 69 void *rasterizer, *rasterizer_saved; 70 void *fragment_shader, *fragment_shader_saved; 71 void *vertex_shader, *vertex_shader_saved; 72 73 struct pipe_framebuffer_state fb, fb_saved; 74 struct pipe_viewport_state vp, vp_saved; 75 struct pipe_blend_color blend_color; 76}; 77 78 79struct cso_context *cso_create_context( struct pipe_context *pipe ) 80{ 81 struct cso_context *ctx = CALLOC_STRUCT(cso_context); 82 if (ctx == NULL) 83 goto out; 84 85 ctx->cache = cso_cache_create(); 86 if (ctx->cache == NULL) 87 goto out; 88 89 ctx->pipe = pipe; 90 91 /* Enable for testing: */ 92 if (0) cso_set_maximum_cache_size( ctx->cache, 4 ); 93 94 return ctx; 95 96out: 97 cso_destroy_context( ctx ); 98 return NULL; 99} 100 101static void cso_release_all( struct cso_context *ctx ) 102{ 103 if (ctx->pipe) { 104 ctx->pipe->bind_blend_state( ctx->pipe, NULL ); 105 ctx->pipe->bind_rasterizer_state( ctx->pipe, NULL ); 106 ctx->pipe->bind_sampler_states( ctx->pipe, 0, NULL ); 107 ctx->pipe->bind_depth_stencil_alpha_state( ctx->pipe, NULL ); 108 ctx->pipe->bind_fs_state( ctx->pipe, NULL ); 109 ctx->pipe->bind_vs_state( ctx->pipe, NULL ); 110 } 111 112 if (ctx->cache) { 113 cso_cache_delete( ctx->cache ); 114 ctx->cache = NULL; 115 } 116} 117 118 119void cso_destroy_context( struct cso_context *ctx ) 120{ 121 if (ctx) 122 cso_release_all( ctx ); 123 124 FREE( ctx ); 125} 126 127 128/* Those function will either find the state of the given template 129 * in the cache or they will create a new state from the given 130 * template, insert it in the cache and return it. 131 */ 132 133/* 134 * If the driver returns 0 from the create method then they will assign 135 * the data member of the cso to be the template itself. 136 */ 137 138void cso_set_blend(struct cso_context *ctx, 139 const struct pipe_blend_state *templ) 140{ 141 unsigned hash_key = cso_construct_key((void*)templ, sizeof(struct pipe_blend_state)); 142 struct cso_hash_iter iter = cso_find_state_template(ctx->cache, 143 hash_key, CSO_BLEND, 144 (void*)templ); 145 void *handle; 146 147 if (cso_hash_iter_is_null(iter)) { 148 struct cso_blend *cso = MALLOC(sizeof(struct cso_blend)); 149 150 cso->state = *templ; 151 cso->data = ctx->pipe->create_blend_state(ctx->pipe, &cso->state); 152 cso->delete_state = (cso_state_callback)ctx->pipe->delete_blend_state; 153 cso->context = ctx->pipe; 154 155 iter = cso_insert_state(ctx->cache, hash_key, CSO_BLEND, cso); 156 handle = cso->data; 157 } 158 else { 159 handle = ((struct cso_blend *)cso_hash_iter_data(iter))->data; 160 } 161 162 if (ctx->blend != handle) { 163 ctx->blend = handle; 164 ctx->pipe->bind_blend_state(ctx->pipe, handle); 165 } 166} 167 168void cso_save_blend(struct cso_context *ctx) 169{ 170 assert(!ctx->blend_saved); 171 ctx->blend_saved = ctx->blend; 172} 173 174void cso_restore_blend(struct cso_context *ctx) 175{ 176 if (ctx->blend != ctx->blend_saved) { 177 ctx->blend = ctx->blend_saved; 178 ctx->pipe->bind_blend_state(ctx->pipe, ctx->blend_saved); 179 } 180 ctx->blend_saved = NULL; 181} 182 183 184 185void cso_single_sampler(struct cso_context *ctx, 186 unsigned idx, 187 const struct pipe_sampler_state *templ) 188{ 189 void *handle = NULL; 190 191 if (templ != NULL) { 192 unsigned hash_key = cso_construct_key((void*)templ, sizeof(struct pipe_sampler_state)); 193 struct cso_hash_iter iter = cso_find_state_template(ctx->cache, 194 hash_key, CSO_SAMPLER, 195 (void*)templ); 196 197 if (cso_hash_iter_is_null(iter)) { 198 struct cso_sampler *cso = MALLOC(sizeof(struct cso_sampler)); 199 200 cso->state = *templ; 201 cso->data = ctx->pipe->create_sampler_state(ctx->pipe, &cso->state); 202 cso->delete_state = (cso_state_callback)ctx->pipe->delete_sampler_state; 203 cso->context = ctx->pipe; 204 205 iter = cso_insert_state(ctx->cache, hash_key, CSO_SAMPLER, cso); 206 handle = cso->data; 207 } 208 else { 209 handle = ((struct cso_sampler *)cso_hash_iter_data(iter))->data; 210 } 211 } 212 213 ctx->samplers[idx] = handle; 214} 215 216void cso_single_sampler_done( struct cso_context *ctx ) 217{ 218 unsigned i; 219 220 for (i = 0; i < 8; i++) 221 if (ctx->samplers[i] == NULL) 222 break; 223 224 ctx->nr_samplers = i; 225 226 if (ctx->hw.nr_samplers != ctx->nr_samplers || 227 memcmp(ctx->hw.samplers, 228 ctx->samplers, 229 ctx->nr_samplers * sizeof(void *)) != 0) 230 { 231 memcpy(ctx->hw.samplers, ctx->samplers, ctx->nr_samplers * sizeof(void *)); 232 ctx->hw.nr_samplers = ctx->nr_samplers; 233 234 ctx->pipe->bind_sampler_states(ctx->pipe, ctx->nr_samplers, ctx->samplers); 235 } 236} 237 238void cso_set_samplers( struct cso_context *ctx, 239 unsigned nr, 240 const struct pipe_sampler_state **templates ) 241{ 242 unsigned i; 243 244 /* TODO: fastpath 245 */ 246 247 for (i = 0; i < nr; i++) 248 cso_single_sampler( ctx, i, templates[i] ); 249 250 for ( ; i < ctx->nr_samplers; i++) 251 cso_single_sampler( ctx, i, NULL ); 252 253 cso_single_sampler_done( ctx ); 254} 255 256void cso_save_samplers(struct cso_context *ctx) 257{ 258 ctx->nr_samplers_saved = ctx->nr_samplers; 259 memcpy(ctx->samplers_saved, ctx->samplers, sizeof(ctx->samplers)); 260} 261 262void cso_restore_samplers(struct cso_context *ctx) 263{ 264 cso_set_samplers(ctx, ctx->nr_samplers_saved, 265 (const struct pipe_sampler_state **) ctx->samplers_saved); 266} 267 268 269void cso_set_sampler_textures( struct cso_context *ctx, 270 uint count, 271 struct pipe_texture **textures ) 272{ 273 uint i; 274 275 ctx->nr_textures = count; 276 277 for (i = 0; i < count; i++) 278 ctx->textures[i] = textures[i]; 279 for ( ; i < PIPE_MAX_SAMPLERS; i++) 280 ctx->textures[i] = NULL; 281 282 ctx->pipe->set_sampler_textures(ctx->pipe, count, textures); 283} 284 285void cso_save_sampler_textures( struct cso_context *ctx ) 286{ 287 ctx->nr_textures_saved = ctx->nr_textures; 288 memcpy(ctx->textures_saved, ctx->textures, sizeof(ctx->textures)); 289} 290 291void cso_restore_sampler_textures( struct cso_context *ctx ) 292{ 293 cso_set_sampler_textures(ctx, ctx->nr_textures_saved, ctx->textures_saved); 294 ctx->nr_textures_saved = 0; 295} 296 297 298 299 300void cso_set_depth_stencil_alpha(struct cso_context *ctx, 301 const struct pipe_depth_stencil_alpha_state *templ) 302{ 303 unsigned hash_key = cso_construct_key((void*)templ, 304 sizeof(struct pipe_depth_stencil_alpha_state)); 305 struct cso_hash_iter iter = cso_find_state_template(ctx->cache, 306 hash_key, 307 CSO_DEPTH_STENCIL_ALPHA, 308 (void*)templ); 309 void *handle; 310 311 if (cso_hash_iter_is_null(iter)) { 312 struct cso_depth_stencil_alpha *cso = MALLOC(sizeof(struct cso_depth_stencil_alpha)); 313 314 cso->state = *templ; 315 cso->data = ctx->pipe->create_depth_stencil_alpha_state(ctx->pipe, &cso->state); 316 cso->delete_state = (cso_state_callback)ctx->pipe->delete_depth_stencil_alpha_state; 317 cso->context = ctx->pipe; 318 319 cso_insert_state(ctx->cache, hash_key, CSO_DEPTH_STENCIL_ALPHA, cso); 320 handle = cso->data; 321 } 322 else { 323 handle = ((struct cso_depth_stencil_alpha *)cso_hash_iter_data(iter))->data; 324 } 325 326 if (ctx->depth_stencil != handle) { 327 ctx->depth_stencil = handle; 328 ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, handle); 329 } 330} 331 332void cso_save_depth_stencil_alpha(struct cso_context *ctx) 333{ 334 assert(!ctx->depth_stencil_saved); 335 ctx->depth_stencil_saved = ctx->depth_stencil; 336} 337 338void cso_restore_depth_stencil_alpha(struct cso_context *ctx) 339{ 340 if (ctx->depth_stencil != ctx->depth_stencil_saved) { 341 ctx->depth_stencil = ctx->depth_stencil_saved; 342 ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, ctx->depth_stencil_saved); 343 } 344 ctx->depth_stencil_saved = NULL; 345} 346 347 348 349void cso_set_rasterizer(struct cso_context *ctx, 350 const struct pipe_rasterizer_state *templ) 351{ 352 unsigned hash_key = cso_construct_key((void*)templ, 353 sizeof(struct pipe_rasterizer_state)); 354 struct cso_hash_iter iter = cso_find_state_template(ctx->cache, 355 hash_key, CSO_RASTERIZER, 356 (void*)templ); 357 void *handle = NULL; 358 359 if (cso_hash_iter_is_null(iter)) { 360 struct cso_rasterizer *cso = MALLOC(sizeof(struct cso_rasterizer)); 361 362 cso->state = *templ; 363 cso->data = ctx->pipe->create_rasterizer_state(ctx->pipe, &cso->state); 364 cso->delete_state = (cso_state_callback)ctx->pipe->delete_rasterizer_state; 365 cso->context = ctx->pipe; 366 367 cso_insert_state(ctx->cache, hash_key, CSO_RASTERIZER, cso); 368 handle = cso->data; 369 } 370 else { 371 handle = ((struct cso_rasterizer *)cso_hash_iter_data(iter))->data; 372 } 373 374 if (ctx->rasterizer != handle) { 375 ctx->rasterizer = handle; 376 ctx->pipe->bind_rasterizer_state(ctx->pipe, handle); 377 } 378} 379 380void cso_save_rasterizer(struct cso_context *ctx) 381{ 382 assert(!ctx->rasterizer_saved); 383 ctx->rasterizer_saved = ctx->rasterizer; 384} 385 386void cso_restore_rasterizer(struct cso_context *ctx) 387{ 388 if (ctx->rasterizer != ctx->rasterizer_saved) { 389 ctx->rasterizer = ctx->rasterizer_saved; 390 ctx->pipe->bind_rasterizer_state(ctx->pipe, ctx->rasterizer_saved); 391 } 392 ctx->rasterizer_saved = NULL; 393} 394 395 396void cso_set_fragment_shader(struct cso_context *ctx, 397 const struct pipe_shader_state *templ) 398{ 399 unsigned hash_key = cso_construct_key((void*)templ, 400 sizeof(struct pipe_shader_state)); 401 struct cso_hash_iter iter = cso_find_state_template(ctx->cache, 402 hash_key, CSO_FRAGMENT_SHADER, 403 (void*)templ); 404 void *handle = NULL; 405 406 if (cso_hash_iter_is_null(iter)) { 407 struct cso_fragment_shader *cso = MALLOC(sizeof(struct cso_fragment_shader)); 408 409 cso->state = *templ; 410 cso->data = ctx->pipe->create_fs_state(ctx->pipe, &cso->state); 411 cso->delete_state = (cso_state_callback)ctx->pipe->delete_fs_state; 412 cso->context = ctx->pipe; 413 414 iter = cso_insert_state(ctx->cache, hash_key, CSO_FRAGMENT_SHADER, cso); 415 handle = cso->data; 416 } 417 else { 418 handle = ((struct cso_fragment_shader *)cso_hash_iter_data(iter))->data; 419 } 420 421 if (ctx->fragment_shader != handle) { 422 ctx->fragment_shader = handle; 423 ctx->pipe->bind_fs_state(ctx->pipe, handle); 424 } 425} 426 427void cso_save_fragment_shader(struct cso_context *ctx) 428{ 429 assert(!ctx->fragment_shader_saved); 430 ctx->fragment_shader_saved = ctx->fragment_shader; 431} 432 433void cso_restore_fragment_shader(struct cso_context *ctx) 434{ 435 assert(ctx->fragment_shader_saved); 436 if (ctx->fragment_shader_saved != ctx->fragment_shader) { 437 ctx->pipe->bind_fs_state(ctx->pipe, ctx->fragment_shader_saved); 438 ctx->fragment_shader = ctx->fragment_shader_saved; 439 } 440 ctx->fragment_shader_saved = NULL; 441} 442 443 444 445void cso_set_vertex_shader(struct cso_context *ctx, 446 const struct pipe_shader_state *templ) 447{ 448 unsigned hash_key = cso_construct_key((void*)templ, 449 sizeof(struct pipe_shader_state)); 450 struct cso_hash_iter iter = cso_find_state_template(ctx->cache, 451 hash_key, CSO_VERTEX_SHADER, 452 (void*)templ); 453 void *handle = NULL; 454 455 if (cso_hash_iter_is_null(iter)) { 456 struct cso_vertex_shader *cso = MALLOC(sizeof(struct cso_vertex_shader)); 457 458 cso->state = *templ; 459 cso->data = ctx->pipe->create_vs_state(ctx->pipe, &cso->state); 460 cso->delete_state = (cso_state_callback)ctx->pipe->delete_vs_state; 461 cso->context = ctx->pipe; 462 463 iter = cso_insert_state(ctx->cache, hash_key, CSO_VERTEX_SHADER, cso); 464 handle = cso->data; 465 } 466 else { 467 handle = ((struct cso_vertex_shader *)cso_hash_iter_data(iter))->data; 468 } 469 470 if (ctx->vertex_shader != handle) { 471 ctx->vertex_shader = handle; 472 ctx->pipe->bind_vs_state(ctx->pipe, handle); 473 } 474} 475 476void cso_save_vertex_shader(struct cso_context *ctx) 477{ 478 assert(!ctx->vertex_shader_saved); 479 ctx->vertex_shader_saved = ctx->vertex_shader; 480} 481 482void cso_restore_vertex_shader(struct cso_context *ctx) 483{ 484 assert(ctx->vertex_shader_saved); 485 if (ctx->vertex_shader_saved != ctx->vertex_shader) { 486 ctx->pipe->bind_fs_state(ctx->pipe, ctx->vertex_shader_saved); 487 ctx->vertex_shader = ctx->vertex_shader_saved; 488 } 489 ctx->vertex_shader_saved = NULL; 490} 491 492 493 494void cso_set_framebuffer(struct cso_context *ctx, 495 const struct pipe_framebuffer_state *fb) 496{ 497 if (memcmp(&ctx->fb, fb, sizeof(*fb))) { 498 ctx->fb = *fb; 499 ctx->pipe->set_framebuffer_state(ctx->pipe, fb); 500 } 501} 502 503void cso_save_framebuffer(struct cso_context *ctx) 504{ 505 ctx->fb_saved = ctx->fb; 506} 507 508void cso_restore_framebuffer(struct cso_context *ctx) 509{ 510 if (memcmp(&ctx->fb, &ctx->fb_saved, sizeof(ctx->fb))) { 511 ctx->fb = ctx->fb_saved; 512 ctx->pipe->set_framebuffer_state(ctx->pipe, &ctx->fb); 513 } 514} 515 516 517void cso_set_viewport(struct cso_context *ctx, 518 const struct pipe_viewport_state *vp) 519{ 520 if (memcmp(&ctx->vp, vp, sizeof(*vp))) { 521 ctx->vp = *vp; 522 ctx->pipe->set_viewport_state(ctx->pipe, vp); 523 } 524} 525 526void cso_save_viewport(struct cso_context *ctx) 527{ 528 ctx->vp_saved = ctx->vp; 529} 530 531 532void cso_restore_viewport(struct cso_context *ctx) 533{ 534 if (memcmp(&ctx->vp, &ctx->vp_saved, sizeof(ctx->vp))) { 535 ctx->vp = ctx->vp_saved; 536 ctx->pipe->set_viewport_state(ctx->pipe, &ctx->vp); 537 } 538} 539 540 541 542 543void cso_set_blend_color(struct cso_context *ctx, 544 const struct pipe_blend_color *bc) 545{ 546 if (memcmp(&ctx->blend_color, bc, sizeof(ctx->blend_color))) { 547 ctx->blend_color = *bc; 548 ctx->pipe->set_blend_color(ctx->pipe, bc); 549 } 550} 551