X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=src%2Fgallium%2Fauxiliary%2Fcso_cache%2Fcso_context.c;h=9ec7a2a9676108fbf0c9254b059d3966761da4e9;hb=76eefcc70cc62db7d226591de3f918ff102f6de3;hp=fdfb5faa59e4037b6cd4e2745fb82c6ab4671e1c;hpb=7b5ad23c7f7f9016f725cb1caa3cf8971aeedbc8;p=mesa.git diff --git a/src/gallium/auxiliary/cso_cache/cso_context.c b/src/gallium/auxiliary/cso_cache/cso_context.c index fdfb5faa59e..9ec7a2a9676 100644 --- a/src/gallium/auxiliary/cso_cache/cso_context.c +++ b/src/gallium/auxiliary/cso_cache/cso_context.c @@ -36,6 +36,10 @@ */ #include "pipe/p_state.h" +#include "util/u_draw.h" +#include "util/u_framebuffer.h" +#include "util/u_inlines.h" +#include "util/u_math.h" #include "util/u_memory.h" #include "tgsi/tgsi_parse.h" @@ -44,41 +48,54 @@ #include "cso_cache/cso_hash.h" #include "cso_context.h" -struct cso_context { - struct pipe_context *pipe; - struct cso_cache *cache; +/** + * Info related to samplers and sampler views. + * We have one of these for fragment samplers and another for vertex samplers. + */ +struct sampler_info +{ struct { void *samplers[PIPE_MAX_SAMPLERS]; unsigned nr_samplers; - - void *vertex_samplers[PIPE_MAX_VERTEX_SAMPLERS]; - unsigned nr_vertex_samplers; } hw; void *samplers[PIPE_MAX_SAMPLERS]; unsigned nr_samplers; - void *vertex_samplers[PIPE_MAX_VERTEX_SAMPLERS]; - unsigned nr_vertex_samplers; - - unsigned nr_samplers_saved; void *samplers_saved[PIPE_MAX_SAMPLERS]; + unsigned nr_samplers_saved; + + struct pipe_sampler_view *views[PIPE_MAX_SAMPLERS]; + unsigned nr_views; + + struct pipe_sampler_view *views_saved[PIPE_MAX_SAMPLERS]; + unsigned nr_views_saved; +}; + + + +struct cso_context { + struct pipe_context *pipe; + struct cso_cache *cache; + + boolean has_geometry_shader; + boolean has_streamout; - unsigned nr_vertex_samplers_saved; - void *vertex_samplers_saved[PIPE_MAX_VERTEX_SAMPLERS]; + struct sampler_info fragment_samplers; + struct sampler_info vertex_samplers; - struct pipe_texture *textures[PIPE_MAX_SAMPLERS]; - uint nr_textures; + uint nr_vertex_buffers; + struct pipe_vertex_buffer vertex_buffers[PIPE_MAX_ATTRIBS]; - struct pipe_texture *vertex_textures[PIPE_MAX_VERTEX_SAMPLERS]; - uint nr_vertex_textures; + uint nr_vertex_buffers_saved; + struct pipe_vertex_buffer vertex_buffers_saved[PIPE_MAX_ATTRIBS]; - uint nr_textures_saved; - struct pipe_texture *textures_saved[PIPE_MAX_SAMPLERS]; + unsigned nr_so_targets; + struct pipe_stream_output_target *so_targets[PIPE_MAX_SO_BUFFERS]; - uint nr_vertex_textures_saved; - struct pipe_texture *vertex_textures_saved[PIPE_MAX_SAMPLERS]; + unsigned nr_so_targets_saved; + struct pipe_stream_output_target *so_targets_saved[PIPE_MAX_SO_BUFFERS]; /** Current and saved state. * The saved state is used as a 1-deep stack. @@ -88,17 +105,19 @@ struct cso_context { void *rasterizer, *rasterizer_saved; void *fragment_shader, *fragment_shader_saved, *geometry_shader; void *vertex_shader, *vertex_shader_saved, *geometry_shader_saved; + void *velements, *velements_saved; + + struct pipe_clip_state clip; + struct pipe_clip_state clip_saved; struct pipe_framebuffer_state fb, fb_saved; struct pipe_viewport_state vp, vp_saved; struct pipe_blend_color blend_color; + unsigned sample_mask; + struct pipe_stencil_ref stencil_ref, stencil_ref_saved; }; -static void -free_framebuffer_state(struct pipe_framebuffer_state *fb); - - static boolean delete_blend_state(struct cso_context *ctx, void *state) { struct cso_blend *cso = (struct cso_blend *)state; @@ -147,26 +166,18 @@ static boolean delete_rasterizer_state(struct cso_context *ctx, void *state) return TRUE; } -static boolean delete_fs_state(struct cso_context *ctx, void *state) +static boolean delete_vertex_elements(struct cso_context *ctx, + void *state) { - struct cso_fragment_shader *cso = (struct cso_fragment_shader *)state; - if (ctx->fragment_shader == cso->data) + struct cso_velements *cso = (struct cso_velements *)state; + + if (ctx->velements == cso->data) return FALSE; - if (cso->delete_state) - cso->delete_state(cso->context, cso->data); - FREE(state); - return TRUE; -} -static boolean delete_vs_state(struct cso_context *ctx, void *state) -{ - struct cso_vertex_shader *cso = (struct cso_vertex_shader *)state; - if (ctx->vertex_shader == cso->data) - return TRUE; if (cso->delete_state) cso->delete_state(cso->context, cso->data); FREE(state); - return FALSE; + return TRUE; } @@ -186,11 +197,8 @@ static INLINE boolean delete_cso(struct cso_context *ctx, case CSO_RASTERIZER: return delete_rasterizer_state(ctx, state); break; - case CSO_FRAGMENT_SHADER: - return delete_fs_state(ctx, state); - break; - case CSO_VERTEX_SHADER: - return delete_vs_state(ctx, state); + case CSO_VELEMENTS: + return delete_vertex_elements(ctx, state); break; default: assert(0); @@ -230,6 +238,8 @@ struct cso_context *cso_create_context( struct pipe_context *pipe ) if (ctx == NULL) goto out; + assert(PIPE_MAX_SAMPLERS == PIPE_MAX_VERTEX_SAMPLERS); + ctx->cache = cso_cache_create(); if (ctx->cache == NULL) goto out; @@ -242,6 +252,15 @@ struct cso_context *cso_create_context( struct pipe_context *pipe ) /* Enable for testing: */ if (0) cso_set_maximum_cache_size( ctx->cache, 4 ); + if (pipe->screen->get_shader_param(pipe->screen, PIPE_SHADER_GEOMETRY, + PIPE_SHADER_CAP_MAX_INSTRUCTIONS) > 0) { + ctx->has_geometry_shader = TRUE; + } + if (pipe->screen->get_param(pipe->screen, + PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS) != 0) { + ctx->has_streamout = TRUE; + } + return ctx; out: @@ -256,7 +275,8 @@ out: void cso_release_all( struct cso_context *ctx ) { unsigned i; - + struct sampler_info *info; + if (ctx->pipe) { ctx->pipe->bind_blend_state( ctx->pipe, NULL ); ctx->pipe->bind_rasterizer_state( ctx->pipe, NULL ); @@ -266,20 +286,42 @@ void cso_release_all( struct cso_context *ctx ) ctx->pipe->bind_depth_stencil_alpha_state( ctx->pipe, NULL ); ctx->pipe->bind_fs_state( ctx->pipe, NULL ); ctx->pipe->bind_vs_state( ctx->pipe, NULL ); + ctx->pipe->bind_vertex_elements_state( ctx->pipe, NULL ); + ctx->pipe->set_fragment_sampler_views(ctx->pipe, 0, NULL); + if (ctx->pipe->set_vertex_sampler_views) + ctx->pipe->set_vertex_sampler_views(ctx->pipe, 0, NULL); + if (ctx->pipe->set_stream_output_targets) + ctx->pipe->set_stream_output_targets(ctx->pipe, 0, NULL, 0); } + /* free fragment samplers, views */ + info = &ctx->fragment_samplers; for (i = 0; i < PIPE_MAX_SAMPLERS; i++) { - pipe_texture_reference(&ctx->textures[i], NULL); - pipe_texture_reference(&ctx->textures_saved[i], NULL); + pipe_sampler_view_reference(&info->views[i], NULL); + pipe_sampler_view_reference(&info->views_saved[i], NULL); } - for (i = 0; i < PIPE_MAX_VERTEX_SAMPLERS; i++) { - pipe_texture_reference(&ctx->vertex_textures[i], NULL); - pipe_texture_reference(&ctx->vertex_textures_saved[i], NULL); + /* free vertex samplers, views */ + info = &ctx->vertex_samplers; + for (i = 0; i < PIPE_MAX_SAMPLERS; i++) { + pipe_sampler_view_reference(&info->views[i], NULL); + pipe_sampler_view_reference(&info->views_saved[i], NULL); } - free_framebuffer_state(&ctx->fb); - free_framebuffer_state(&ctx->fb_saved); + util_unreference_framebuffer_state(&ctx->fb); + util_unreference_framebuffer_state(&ctx->fb_saved); + + util_copy_vertex_buffers(ctx->vertex_buffers, + &ctx->nr_vertex_buffers, + NULL, 0); + util_copy_vertex_buffers(ctx->vertex_buffers_saved, + &ctx->nr_vertex_buffers_saved, + NULL, 0); + + for (i = 0; i < PIPE_MAX_SO_BUFFERS; i++) { + pipe_so_target_reference(&ctx->so_targets[i], NULL); + pipe_so_target_reference(&ctx->so_targets_saved[i], NULL); + } if (ctx->cache) { cso_cache_delete( ctx->cache ); @@ -288,10 +330,13 @@ void cso_release_all( struct cso_context *ctx ) } +/** + * Free the CSO context. NOTE: the state tracker should have previously called + * cso_release_all(). + */ void cso_destroy_context( struct cso_context *ctx ) { if (ctx) { - /*cso_release_all( ctx );*/ FREE( ctx ); } } @@ -310,18 +355,22 @@ void cso_destroy_context( struct cso_context *ctx ) enum pipe_error cso_set_blend(struct cso_context *ctx, const struct pipe_blend_state *templ) { - unsigned hash_key = cso_construct_key((void*)templ, sizeof(struct pipe_blend_state)); - struct cso_hash_iter iter = cso_find_state_template(ctx->cache, - hash_key, CSO_BLEND, - (void*)templ); + unsigned key_size, hash_key; + struct cso_hash_iter iter; void *handle; + key_size = templ->independent_blend_enable ? sizeof(struct pipe_blend_state) : + (char *)&(templ->rt[1]) - (char *)templ; + hash_key = cso_construct_key((void*)templ, key_size); + iter = cso_find_state_template(ctx->cache, hash_key, CSO_BLEND, (void*)templ, key_size); + if (cso_hash_iter_is_null(iter)) { struct cso_blend *cso = MALLOC(sizeof(struct cso_blend)); if (!cso) return PIPE_ERROR_OUT_OF_MEMORY; - memcpy(&cso->state, templ, sizeof(*templ)); + memset(&cso->state, 0, sizeof cso->state); + memcpy(&cso->state, templ, key_size); cso->data = ctx->pipe->create_blend_state(ctx->pipe, &cso->state); cso->delete_state = (cso_state_callback)ctx->pipe->delete_blend_state; cso->context = ctx->pipe; @@ -362,417 +411,401 @@ void cso_restore_blend(struct cso_context *ctx) -enum pipe_error cso_single_sampler(struct cso_context *ctx, - unsigned idx, - const struct pipe_sampler_state *templ) +enum pipe_error cso_set_depth_stencil_alpha(struct cso_context *ctx, + const struct pipe_depth_stencil_alpha_state *templ) { - void *handle = NULL; - - if (templ != NULL) { - unsigned hash_key = cso_construct_key((void*)templ, sizeof(struct pipe_sampler_state)); - struct cso_hash_iter iter = cso_find_state_template(ctx->cache, - hash_key, CSO_SAMPLER, - (void*)templ); - - if (cso_hash_iter_is_null(iter)) { - struct cso_sampler *cso = MALLOC(sizeof(struct cso_sampler)); - if (!cso) - return PIPE_ERROR_OUT_OF_MEMORY; + unsigned key_size = sizeof(struct pipe_depth_stencil_alpha_state); + unsigned hash_key = cso_construct_key((void*)templ, key_size); + struct cso_hash_iter iter = cso_find_state_template(ctx->cache, + hash_key, + CSO_DEPTH_STENCIL_ALPHA, + (void*)templ, key_size); + void *handle; - memcpy(&cso->state, templ, sizeof(*templ)); - cso->data = ctx->pipe->create_sampler_state(ctx->pipe, &cso->state); - cso->delete_state = (cso_state_callback)ctx->pipe->delete_sampler_state; - cso->context = ctx->pipe; + if (cso_hash_iter_is_null(iter)) { + struct cso_depth_stencil_alpha *cso = MALLOC(sizeof(struct cso_depth_stencil_alpha)); + if (!cso) + return PIPE_ERROR_OUT_OF_MEMORY; - iter = cso_insert_state(ctx->cache, hash_key, CSO_SAMPLER, cso); - if (cso_hash_iter_is_null(iter)) { - FREE(cso); - return PIPE_ERROR_OUT_OF_MEMORY; - } + memcpy(&cso->state, templ, sizeof(*templ)); + cso->data = ctx->pipe->create_depth_stencil_alpha_state(ctx->pipe, &cso->state); + cso->delete_state = (cso_state_callback)ctx->pipe->delete_depth_stencil_alpha_state; + cso->context = ctx->pipe; - handle = cso->data; - } - else { - handle = ((struct cso_sampler *)cso_hash_iter_data(iter))->data; + iter = cso_insert_state(ctx->cache, hash_key, CSO_DEPTH_STENCIL_ALPHA, cso); + if (cso_hash_iter_is_null(iter)) { + FREE(cso); + return PIPE_ERROR_OUT_OF_MEMORY; } + + handle = cso->data; + } + else { + handle = ((struct cso_depth_stencil_alpha *)cso_hash_iter_data(iter))->data; } - ctx->samplers[idx] = handle; + if (ctx->depth_stencil != handle) { + ctx->depth_stencil = handle; + ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, handle); + } return PIPE_OK; } -enum pipe_error -cso_single_vertex_sampler(struct cso_context *ctx, - unsigned idx, - const struct pipe_sampler_state *templ) +void cso_save_depth_stencil_alpha(struct cso_context *ctx) { - void *handle = NULL; - - if (templ != NULL) { - unsigned hash_key = cso_construct_key((void*)templ, sizeof(struct pipe_sampler_state)); - struct cso_hash_iter iter = cso_find_state_template(ctx->cache, - hash_key, CSO_SAMPLER, - (void*)templ); - - if (cso_hash_iter_is_null(iter)) { - struct cso_sampler *cso = MALLOC(sizeof(struct cso_sampler)); - if (!cso) - return PIPE_ERROR_OUT_OF_MEMORY; - - memcpy(&cso->state, templ, sizeof(*templ)); - cso->data = ctx->pipe->create_sampler_state(ctx->pipe, &cso->state); - cso->delete_state = (cso_state_callback)ctx->pipe->delete_sampler_state; - cso->context = ctx->pipe; - - iter = cso_insert_state(ctx->cache, hash_key, CSO_SAMPLER, cso); - if (cso_hash_iter_is_null(iter)) { - FREE(cso); - return PIPE_ERROR_OUT_OF_MEMORY; - } - - handle = cso->data; - } - else { - handle = ((struct cso_sampler *)cso_hash_iter_data(iter))->data; - } - } - - ctx->vertex_samplers[idx] = handle; - return PIPE_OK; + assert(!ctx->depth_stencil_saved); + ctx->depth_stencil_saved = ctx->depth_stencil; } -void cso_single_sampler_done( struct cso_context *ctx ) +void cso_restore_depth_stencil_alpha(struct cso_context *ctx) { - unsigned i; - - /* find highest non-null sampler */ - for (i = PIPE_MAX_SAMPLERS; i > 0; i--) { - if (ctx->samplers[i - 1] != NULL) - break; + if (ctx->depth_stencil != ctx->depth_stencil_saved) { + ctx->depth_stencil = ctx->depth_stencil_saved; + ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, ctx->depth_stencil_saved); } + ctx->depth_stencil_saved = NULL; +} - ctx->nr_samplers = i; - - if (ctx->hw.nr_samplers != ctx->nr_samplers || - memcmp(ctx->hw.samplers, - ctx->samplers, - ctx->nr_samplers * sizeof(void *)) != 0) - { - memcpy(ctx->hw.samplers, ctx->samplers, ctx->nr_samplers * sizeof(void *)); - ctx->hw.nr_samplers = ctx->nr_samplers; - ctx->pipe->bind_fragment_sampler_states(ctx->pipe, ctx->nr_samplers, ctx->samplers); - } -} -void -cso_single_vertex_sampler_done(struct cso_context *ctx) +enum pipe_error cso_set_rasterizer(struct cso_context *ctx, + const struct pipe_rasterizer_state *templ) { - unsigned i; + unsigned key_size = sizeof(struct pipe_rasterizer_state); + unsigned hash_key = cso_construct_key((void*)templ, key_size); + struct cso_hash_iter iter = cso_find_state_template(ctx->cache, + hash_key, CSO_RASTERIZER, + (void*)templ, key_size); + void *handle = NULL; - /* find highest non-null sampler */ - for (i = PIPE_MAX_VERTEX_SAMPLERS; i > 0; i--) { - if (ctx->vertex_samplers[i - 1] != NULL) - break; - } + if (cso_hash_iter_is_null(iter)) { + struct cso_rasterizer *cso = MALLOC(sizeof(struct cso_rasterizer)); + if (!cso) + return PIPE_ERROR_OUT_OF_MEMORY; - ctx->nr_vertex_samplers = i; + memcpy(&cso->state, templ, sizeof(*templ)); + cso->data = ctx->pipe->create_rasterizer_state(ctx->pipe, &cso->state); + cso->delete_state = (cso_state_callback)ctx->pipe->delete_rasterizer_state; + cso->context = ctx->pipe; - if (ctx->hw.nr_vertex_samplers != ctx->nr_vertex_samplers || - memcmp(ctx->hw.vertex_samplers, - ctx->vertex_samplers, - ctx->nr_vertex_samplers * sizeof(void *)) != 0) - { - memcpy(ctx->hw.vertex_samplers, - ctx->vertex_samplers, - ctx->nr_vertex_samplers * sizeof(void *)); - ctx->hw.nr_vertex_samplers = ctx->nr_vertex_samplers; + iter = cso_insert_state(ctx->cache, hash_key, CSO_RASTERIZER, cso); + if (cso_hash_iter_is_null(iter)) { + FREE(cso); + return PIPE_ERROR_OUT_OF_MEMORY; + } - ctx->pipe->bind_vertex_sampler_states(ctx->pipe, - ctx->nr_vertex_samplers, - ctx->vertex_samplers); + handle = cso->data; } -} - -/* - * If the function encouters any errors it will return the - * last one. Done to always try to set as many samplers - * as possible. - */ -enum pipe_error cso_set_samplers( struct cso_context *ctx, - unsigned nr, - const struct pipe_sampler_state **templates ) -{ - unsigned i; - enum pipe_error temp, error = PIPE_OK; - - /* TODO: fastpath - */ - - for (i = 0; i < nr; i++) { - temp = cso_single_sampler( ctx, i, templates[i] ); - if (temp != PIPE_OK) - error = temp; + else { + handle = ((struct cso_rasterizer *)cso_hash_iter_data(iter))->data; } - for ( ; i < ctx->nr_samplers; i++) { - temp = cso_single_sampler( ctx, i, NULL ); - if (temp != PIPE_OK) - error = temp; + if (ctx->rasterizer != handle) { + ctx->rasterizer = handle; + ctx->pipe->bind_rasterizer_state(ctx->pipe, handle); } - - cso_single_sampler_done( ctx ); - - return error; + return PIPE_OK; } -void cso_save_samplers(struct cso_context *ctx) +void cso_save_rasterizer(struct cso_context *ctx) { - ctx->nr_samplers_saved = ctx->nr_samplers; - memcpy(ctx->samplers_saved, ctx->samplers, sizeof(ctx->samplers)); + assert(!ctx->rasterizer_saved); + ctx->rasterizer_saved = ctx->rasterizer; } -void cso_restore_samplers(struct cso_context *ctx) +void cso_restore_rasterizer(struct cso_context *ctx) { - ctx->nr_samplers = ctx->nr_samplers_saved; - memcpy(ctx->samplers, ctx->samplers_saved, sizeof(ctx->samplers)); - cso_single_sampler_done( ctx ); + if (ctx->rasterizer != ctx->rasterizer_saved) { + ctx->rasterizer = ctx->rasterizer_saved; + ctx->pipe->bind_rasterizer_state(ctx->pipe, ctx->rasterizer_saved); + } + ctx->rasterizer_saved = NULL; } -/* - * If the function encouters any errors it will return the - * last one. Done to always try to set as many samplers - * as possible. - */ -enum pipe_error cso_set_vertex_samplers(struct cso_context *ctx, - unsigned nr, - const struct pipe_sampler_state **templates) -{ - unsigned i; - enum pipe_error temp, error = PIPE_OK; - /* TODO: fastpath - */ - for (i = 0; i < nr; i++) { - temp = cso_single_vertex_sampler( ctx, i, templates[i] ); - if (temp != PIPE_OK) - error = temp; +enum pipe_error cso_set_fragment_shader_handle(struct cso_context *ctx, + void *handle ) +{ + if (ctx->fragment_shader != handle) { + ctx->fragment_shader = handle; + ctx->pipe->bind_fs_state(ctx->pipe, handle); } + return PIPE_OK; +} - for ( ; i < ctx->nr_samplers; i++) { - temp = cso_single_vertex_sampler( ctx, i, NULL ); - if (temp != PIPE_OK) - error = temp; +void cso_delete_fragment_shader(struct cso_context *ctx, void *handle ) +{ + if (handle == ctx->fragment_shader) { + /* unbind before deleting */ + ctx->pipe->bind_fs_state(ctx->pipe, NULL); + ctx->fragment_shader = NULL; } - - cso_single_vertex_sampler_done( ctx ); - - return error; + ctx->pipe->delete_fs_state(ctx->pipe, handle); } -void -cso_save_vertex_samplers(struct cso_context *ctx) +void cso_save_fragment_shader(struct cso_context *ctx) { - ctx->nr_vertex_samplers_saved = ctx->nr_vertex_samplers; - memcpy(ctx->vertex_samplers_saved, ctx->vertex_samplers, sizeof(ctx->vertex_samplers)); + assert(!ctx->fragment_shader_saved); + ctx->fragment_shader_saved = ctx->fragment_shader; } -void -cso_restore_vertex_samplers(struct cso_context *ctx) +void cso_restore_fragment_shader(struct cso_context *ctx) { - ctx->nr_vertex_samplers = ctx->nr_vertex_samplers_saved; - memcpy(ctx->vertex_samplers, ctx->vertex_samplers_saved, sizeof(ctx->vertex_samplers)); - cso_single_vertex_sampler_done(ctx); + if (ctx->fragment_shader_saved != ctx->fragment_shader) { + ctx->pipe->bind_fs_state(ctx->pipe, ctx->fragment_shader_saved); + ctx->fragment_shader = ctx->fragment_shader_saved; + } + ctx->fragment_shader_saved = NULL; } -enum pipe_error cso_set_sampler_textures( struct cso_context *ctx, - uint count, - struct pipe_texture **textures ) +enum pipe_error cso_set_vertex_shader_handle(struct cso_context *ctx, + void *handle ) { - uint i; - - ctx->nr_textures = count; - - for (i = 0; i < count; i++) - pipe_texture_reference(&ctx->textures[i], textures[i]); - for ( ; i < PIPE_MAX_SAMPLERS; i++) - pipe_texture_reference(&ctx->textures[i], NULL); - - ctx->pipe->set_fragment_sampler_textures(ctx->pipe, count, textures); - + if (ctx->vertex_shader != handle) { + ctx->vertex_shader = handle; + ctx->pipe->bind_vs_state(ctx->pipe, handle); + } return PIPE_OK; } -void cso_save_sampler_textures( struct cso_context *ctx ) +void cso_delete_vertex_shader(struct cso_context *ctx, void *handle ) { - uint i; - - ctx->nr_textures_saved = ctx->nr_textures; - for (i = 0; i < ctx->nr_textures; i++) { - assert(!ctx->textures_saved[i]); - pipe_texture_reference(&ctx->textures_saved[i], ctx->textures[i]); + if (handle == ctx->vertex_shader) { + /* unbind before deleting */ + ctx->pipe->bind_vs_state(ctx->pipe, NULL); + ctx->vertex_shader = NULL; } + ctx->pipe->delete_vs_state(ctx->pipe, handle); } -void cso_restore_sampler_textures( struct cso_context *ctx ) +void cso_save_vertex_shader(struct cso_context *ctx) { - uint i; + assert(!ctx->vertex_shader_saved); + ctx->vertex_shader_saved = ctx->vertex_shader; +} - ctx->nr_textures = ctx->nr_textures_saved; +void cso_restore_vertex_shader(struct cso_context *ctx) +{ + if (ctx->vertex_shader_saved != ctx->vertex_shader) { + ctx->pipe->bind_vs_state(ctx->pipe, ctx->vertex_shader_saved); + ctx->vertex_shader = ctx->vertex_shader_saved; + } + ctx->vertex_shader_saved = NULL; +} - for (i = 0; i < ctx->nr_textures; i++) { - pipe_texture_reference(&ctx->textures[i], NULL); - ctx->textures[i] = ctx->textures_saved[i]; - ctx->textures_saved[i] = NULL; + +enum pipe_error cso_set_framebuffer(struct cso_context *ctx, + const struct pipe_framebuffer_state *fb) +{ + if (memcmp(&ctx->fb, fb, sizeof(*fb)) != 0) { + util_copy_framebuffer_state(&ctx->fb, fb); + ctx->pipe->set_framebuffer_state(ctx->pipe, fb); } - for ( ; i < PIPE_MAX_SAMPLERS; i++) - pipe_texture_reference(&ctx->textures[i], NULL); + return PIPE_OK; +} - ctx->pipe->set_fragment_sampler_textures(ctx->pipe, ctx->nr_textures, ctx->textures); +void cso_save_framebuffer(struct cso_context *ctx) +{ + util_copy_framebuffer_state(&ctx->fb_saved, &ctx->fb); +} - ctx->nr_textures_saved = 0; +void cso_restore_framebuffer(struct cso_context *ctx) +{ + if (memcmp(&ctx->fb, &ctx->fb_saved, sizeof(ctx->fb))) { + util_copy_framebuffer_state(&ctx->fb, &ctx->fb_saved); + ctx->pipe->set_framebuffer_state(ctx->pipe, &ctx->fb); + util_unreference_framebuffer_state(&ctx->fb_saved); + } } +enum pipe_error cso_set_viewport(struct cso_context *ctx, + const struct pipe_viewport_state *vp) +{ + if (memcmp(&ctx->vp, vp, sizeof(*vp))) { + ctx->vp = *vp; + ctx->pipe->set_viewport_state(ctx->pipe, vp); + } + return PIPE_OK; +} -enum pipe_error -cso_set_vertex_sampler_textures(struct cso_context *ctx, - uint count, - struct pipe_texture **textures) +void cso_save_viewport(struct cso_context *ctx) { - uint i; + ctx->vp_saved = ctx->vp; +} - ctx->nr_vertex_textures = count; - for (i = 0; i < count; i++) { - pipe_texture_reference(&ctx->vertex_textures[i], textures[i]); - } - for ( ; i < PIPE_MAX_VERTEX_SAMPLERS; i++) { - pipe_texture_reference(&ctx->vertex_textures[i], NULL); +void cso_restore_viewport(struct cso_context *ctx) +{ + if (memcmp(&ctx->vp, &ctx->vp_saved, sizeof(ctx->vp))) { + ctx->vp = ctx->vp_saved; + ctx->pipe->set_viewport_state(ctx->pipe, &ctx->vp); } +} - ctx->pipe->set_vertex_sampler_textures(ctx->pipe, count, textures); +enum pipe_error cso_set_blend_color(struct cso_context *ctx, + const struct pipe_blend_color *bc) +{ + if (memcmp(&ctx->blend_color, bc, sizeof(ctx->blend_color))) { + ctx->blend_color = *bc; + ctx->pipe->set_blend_color(ctx->pipe, bc); + } return PIPE_OK; } -void -cso_save_vertex_sampler_textures(struct cso_context *ctx) +enum pipe_error cso_set_sample_mask(struct cso_context *ctx, + unsigned sample_mask) { - uint i; + if (ctx->sample_mask != sample_mask) { + ctx->sample_mask = sample_mask; + ctx->pipe->set_sample_mask(ctx->pipe, sample_mask); + } + return PIPE_OK; +} - ctx->nr_vertex_textures_saved = ctx->nr_vertex_textures; - for (i = 0; i < ctx->nr_vertex_textures; i++) { - assert(!ctx->vertex_textures_saved[i]); - pipe_texture_reference(&ctx->vertex_textures_saved[i], ctx->vertex_textures[i]); +enum pipe_error cso_set_stencil_ref(struct cso_context *ctx, + const struct pipe_stencil_ref *sr) +{ + if (memcmp(&ctx->stencil_ref, sr, sizeof(ctx->stencil_ref))) { + ctx->stencil_ref = *sr; + ctx->pipe->set_stencil_ref(ctx->pipe, sr); } + return PIPE_OK; } -void -cso_restore_vertex_sampler_textures(struct cso_context *ctx) +void cso_save_stencil_ref(struct cso_context *ctx) { - uint i; + ctx->stencil_ref_saved = ctx->stencil_ref; +} - ctx->nr_vertex_textures = ctx->nr_vertex_textures_saved; - for (i = 0; i < ctx->nr_vertex_textures; i++) { - pipe_texture_reference(&ctx->vertex_textures[i], NULL); - ctx->vertex_textures[i] = ctx->vertex_textures_saved[i]; - ctx->vertex_textures_saved[i] = NULL; - } - for ( ; i < PIPE_MAX_VERTEX_SAMPLERS; i++) { - pipe_texture_reference(&ctx->vertex_textures[i], NULL); +void cso_restore_stencil_ref(struct cso_context *ctx) +{ + if (memcmp(&ctx->stencil_ref, &ctx->stencil_ref_saved, sizeof(ctx->stencil_ref))) { + ctx->stencil_ref = ctx->stencil_ref_saved; + ctx->pipe->set_stencil_ref(ctx->pipe, &ctx->stencil_ref); } - - ctx->pipe->set_vertex_sampler_textures(ctx->pipe, - ctx->nr_vertex_textures, - ctx->vertex_textures); - - ctx->nr_vertex_textures_saved = 0; } +enum pipe_error cso_set_geometry_shader_handle(struct cso_context *ctx, + void *handle) +{ + assert(ctx->has_geometry_shader || !handle); + if (ctx->has_geometry_shader && ctx->geometry_shader != handle) { + ctx->geometry_shader = handle; + ctx->pipe->bind_gs_state(ctx->pipe, handle); + } + return PIPE_OK; +} -enum pipe_error cso_set_depth_stencil_alpha(struct cso_context *ctx, - const struct pipe_depth_stencil_alpha_state *templ) +void cso_delete_geometry_shader(struct cso_context *ctx, void *handle) { - unsigned hash_key = cso_construct_key((void*)templ, - sizeof(struct pipe_depth_stencil_alpha_state)); - struct cso_hash_iter iter = cso_find_state_template(ctx->cache, - hash_key, - CSO_DEPTH_STENCIL_ALPHA, - (void*)templ); - void *handle; - - if (cso_hash_iter_is_null(iter)) { - struct cso_depth_stencil_alpha *cso = MALLOC(sizeof(struct cso_depth_stencil_alpha)); - if (!cso) - return PIPE_ERROR_OUT_OF_MEMORY; + if (handle == ctx->geometry_shader) { + /* unbind before deleting */ + ctx->pipe->bind_gs_state(ctx->pipe, NULL); + ctx->geometry_shader = NULL; + } + ctx->pipe->delete_gs_state(ctx->pipe, handle); +} - memcpy(&cso->state, templ, sizeof(*templ)); - cso->data = ctx->pipe->create_depth_stencil_alpha_state(ctx->pipe, &cso->state); - cso->delete_state = (cso_state_callback)ctx->pipe->delete_depth_stencil_alpha_state; - cso->context = ctx->pipe; +void cso_save_geometry_shader(struct cso_context *ctx) +{ + if (!ctx->has_geometry_shader) { + return; + } - iter = cso_insert_state(ctx->cache, hash_key, CSO_DEPTH_STENCIL_ALPHA, cso); - if (cso_hash_iter_is_null(iter)) { - FREE(cso); - return PIPE_ERROR_OUT_OF_MEMORY; - } + assert(!ctx->geometry_shader_saved); + ctx->geometry_shader_saved = ctx->geometry_shader; +} - handle = cso->data; - } - else { - handle = ((struct cso_depth_stencil_alpha *)cso_hash_iter_data(iter))->data; +void cso_restore_geometry_shader(struct cso_context *ctx) +{ + if (!ctx->has_geometry_shader) { + return; } - if (ctx->depth_stencil != handle) { - ctx->depth_stencil = handle; - ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, handle); + if (ctx->geometry_shader_saved != ctx->geometry_shader) { + ctx->pipe->bind_gs_state(ctx->pipe, ctx->geometry_shader_saved); + ctx->geometry_shader = ctx->geometry_shader_saved; } - return PIPE_OK; + ctx->geometry_shader_saved = NULL; } -void cso_save_depth_stencil_alpha(struct cso_context *ctx) +/* clip state */ + +static INLINE void +clip_state_cpy(struct pipe_clip_state *dst, + const struct pipe_clip_state *src) { - assert(!ctx->depth_stencil_saved); - ctx->depth_stencil_saved = ctx->depth_stencil; + memcpy(dst->ucp, src->ucp, sizeof(dst->ucp)); } -void cso_restore_depth_stencil_alpha(struct cso_context *ctx) +static INLINE int +clip_state_cmp(const struct pipe_clip_state *a, + const struct pipe_clip_state *b) { - if (ctx->depth_stencil != ctx->depth_stencil_saved) { - ctx->depth_stencil = ctx->depth_stencil_saved; - ctx->pipe->bind_depth_stencil_alpha_state(ctx->pipe, ctx->depth_stencil_saved); + return memcmp(a->ucp, b->ucp, sizeof(a->ucp)); +} + +void +cso_set_clip(struct cso_context *ctx, + const struct pipe_clip_state *clip) +{ + if (clip_state_cmp(&ctx->clip, clip)) { + clip_state_cpy(&ctx->clip, clip); + ctx->pipe->set_clip_state(ctx->pipe, clip); } - ctx->depth_stencil_saved = NULL; } +void +cso_save_clip(struct cso_context *ctx) +{ + clip_state_cpy(&ctx->clip_saved, &ctx->clip); +} +void +cso_restore_clip(struct cso_context *ctx) +{ + if (clip_state_cmp(&ctx->clip, &ctx->clip_saved)) { + clip_state_cpy(&ctx->clip, &ctx->clip_saved); + ctx->pipe->set_clip_state(ctx->pipe, &ctx->clip_saved); + } +} -enum pipe_error cso_set_rasterizer(struct cso_context *ctx, - const struct pipe_rasterizer_state *templ) +enum pipe_error cso_set_vertex_elements(struct cso_context *ctx, + unsigned count, + const struct pipe_vertex_element *states) { - unsigned hash_key = cso_construct_key((void*)templ, - sizeof(struct pipe_rasterizer_state)); - struct cso_hash_iter iter = cso_find_state_template(ctx->cache, - hash_key, CSO_RASTERIZER, - (void*)templ); - void *handle = NULL; + unsigned key_size, hash_key; + struct cso_hash_iter iter; + void *handle; + struct cso_velems_state velems_state; + + /* need to include the count into the stored state data too. + Otherwise first few count pipe_vertex_elements could be identical even if count + is different, and there's no guarantee the hash would be different in that + case neither */ + key_size = sizeof(struct pipe_vertex_element) * count + sizeof(unsigned); + velems_state.count = count; + memcpy(velems_state.velems, states, sizeof(struct pipe_vertex_element) * count); + hash_key = cso_construct_key((void*)&velems_state, key_size); + iter = cso_find_state_template(ctx->cache, hash_key, CSO_VELEMENTS, (void*)&velems_state, key_size); if (cso_hash_iter_is_null(iter)) { - struct cso_rasterizer *cso = MALLOC(sizeof(struct cso_rasterizer)); + struct cso_velements *cso = MALLOC(sizeof(struct cso_velements)); if (!cso) return PIPE_ERROR_OUT_OF_MEMORY; - memcpy(&cso->state, templ, sizeof(*templ)); - cso->data = ctx->pipe->create_rasterizer_state(ctx->pipe, &cso->state); - cso->delete_state = (cso_state_callback)ctx->pipe->delete_rasterizer_state; + memcpy(&cso->state, &velems_state, key_size); + cso->data = ctx->pipe->create_vertex_elements_state(ctx->pipe, count, &cso->state.velems[0]); + cso->delete_state = (cso_state_callback)ctx->pipe->delete_vertex_elements_state; cso->context = ctx->pipe; - iter = cso_insert_state(ctx->cache, hash_key, CSO_RASTERIZER, cso); + iter = cso_insert_state(ctx->cache, hash_key, CSO_VELEMENTS, cso); if (cso_hash_iter_is_null(iter)) { FREE(cso); return PIPE_ERROR_OUT_OF_MEMORY; @@ -781,317 +814,514 @@ enum pipe_error cso_set_rasterizer(struct cso_context *ctx, handle = cso->data; } else { - handle = ((struct cso_rasterizer *)cso_hash_iter_data(iter))->data; + handle = ((struct cso_velements *)cso_hash_iter_data(iter))->data; } - if (ctx->rasterizer != handle) { - ctx->rasterizer = handle; - ctx->pipe->bind_rasterizer_state(ctx->pipe, handle); + if (ctx->velements != handle) { + ctx->velements = handle; + ctx->pipe->bind_vertex_elements_state(ctx->pipe, handle); } return PIPE_OK; } -void cso_save_rasterizer(struct cso_context *ctx) +void cso_save_vertex_elements(struct cso_context *ctx) { - assert(!ctx->rasterizer_saved); - ctx->rasterizer_saved = ctx->rasterizer; + assert(!ctx->velements_saved); + ctx->velements_saved = ctx->velements; } -void cso_restore_rasterizer(struct cso_context *ctx) +void cso_restore_vertex_elements(struct cso_context *ctx) { - if (ctx->rasterizer != ctx->rasterizer_saved) { - ctx->rasterizer = ctx->rasterizer_saved; - ctx->pipe->bind_rasterizer_state(ctx->pipe, ctx->rasterizer_saved); + if (ctx->velements != ctx->velements_saved) { + ctx->velements = ctx->velements_saved; + ctx->pipe->bind_vertex_elements_state(ctx->pipe, ctx->velements_saved); } - ctx->rasterizer_saved = NULL; + ctx->velements_saved = NULL; } +/* vertex buffers */ - -enum pipe_error cso_set_fragment_shader_handle(struct cso_context *ctx, - void *handle ) +void cso_set_vertex_buffers(struct cso_context *ctx, + unsigned count, + const struct pipe_vertex_buffer *buffers) { - if (ctx->fragment_shader != handle) { - ctx->fragment_shader = handle; - ctx->pipe->bind_fs_state(ctx->pipe, handle); + if (count != ctx->nr_vertex_buffers || + memcmp(buffers, ctx->vertex_buffers, + sizeof(struct pipe_vertex_buffer) * count) != 0) { + util_copy_vertex_buffers(ctx->vertex_buffers, &ctx->nr_vertex_buffers, + buffers, count); + ctx->pipe->set_vertex_buffers(ctx->pipe, count, buffers); } - return PIPE_OK; } -void cso_delete_fragment_shader(struct cso_context *ctx, void *handle ) +void cso_save_vertex_buffers(struct cso_context *ctx) { - if (handle == ctx->fragment_shader) { - /* unbind before deleting */ - ctx->pipe->bind_fs_state(ctx->pipe, NULL); - ctx->fragment_shader = NULL; + util_copy_vertex_buffers(ctx->vertex_buffers_saved, + &ctx->nr_vertex_buffers_saved, + ctx->vertex_buffers, + ctx->nr_vertex_buffers); +} + +void cso_restore_vertex_buffers(struct cso_context *ctx) +{ + unsigned i; + + util_copy_vertex_buffers(ctx->vertex_buffers, + &ctx->nr_vertex_buffers, + ctx->vertex_buffers_saved, + ctx->nr_vertex_buffers_saved); + + for (i = 0; i < ctx->nr_vertex_buffers_saved; i++) { + pipe_resource_reference(&ctx->vertex_buffers_saved[i].buffer, NULL); } - ctx->pipe->delete_fs_state(ctx->pipe, handle); + ctx->nr_vertex_buffers_saved = 0; + + ctx->pipe->set_vertex_buffers(ctx->pipe, ctx->nr_vertex_buffers, + ctx->vertex_buffers); } -/* Not really working: - */ -#if 0 -enum pipe_error cso_set_fragment_shader(struct cso_context *ctx, - const struct pipe_shader_state *templ) -{ - const struct tgsi_token *tokens = templ->tokens; - unsigned num_tokens = tgsi_num_tokens(tokens); - size_t tokens_size = num_tokens*sizeof(struct tgsi_token); - unsigned hash_key = cso_construct_key((void*)tokens, tokens_size); - struct cso_hash_iter iter = cso_find_state_template(ctx->cache, - hash_key, - CSO_FRAGMENT_SHADER, - (void*)tokens); - void *handle = NULL; - if (cso_hash_iter_is_null(iter)) { - struct cso_fragment_shader *cso = MALLOC(sizeof(struct cso_fragment_shader) + tokens_size); - struct tgsi_token *cso_tokens = (struct tgsi_token *)((char *)cso + sizeof(*cso)); +/**************** fragment/vertex sampler view state *************************/ - if (!cso) - return PIPE_ERROR_OUT_OF_MEMORY; +static enum pipe_error +single_sampler(struct cso_context *ctx, + struct sampler_info *info, + unsigned idx, + const struct pipe_sampler_state *templ) +{ + void *handle = NULL; - memcpy(cso_tokens, tokens, tokens_size); - cso->state.tokens = cso_tokens; - cso->data = ctx->pipe->create_fs_state(ctx->pipe, &cso->state); - cso->delete_state = (cso_state_callback)ctx->pipe->delete_fs_state; - cso->context = ctx->pipe; + if (templ != NULL) { + unsigned key_size = sizeof(struct pipe_sampler_state); + unsigned hash_key = cso_construct_key((void*)templ, key_size); + struct cso_hash_iter iter = + cso_find_state_template(ctx->cache, + hash_key, CSO_SAMPLER, + (void *) templ, key_size); - iter = cso_insert_state(ctx->cache, hash_key, CSO_FRAGMENT_SHADER, cso); if (cso_hash_iter_is_null(iter)) { - FREE(cso); - return PIPE_ERROR_OUT_OF_MEMORY; - } + struct cso_sampler *cso = MALLOC(sizeof(struct cso_sampler)); + if (!cso) + return PIPE_ERROR_OUT_OF_MEMORY; - handle = cso->data; - } - else { - handle = ((struct cso_fragment_shader *)cso_hash_iter_data(iter))->data; + memcpy(&cso->state, templ, sizeof(*templ)); + cso->data = ctx->pipe->create_sampler_state(ctx->pipe, &cso->state); + cso->delete_state = (cso_state_callback)ctx->pipe->delete_sampler_state; + cso->context = ctx->pipe; + + iter = cso_insert_state(ctx->cache, hash_key, CSO_SAMPLER, cso); + if (cso_hash_iter_is_null(iter)) { + FREE(cso); + return PIPE_ERROR_OUT_OF_MEMORY; + } + + handle = cso->data; + } + else { + handle = ((struct cso_sampler *)cso_hash_iter_data(iter))->data; + } } - return cso_set_fragment_shader_handle( ctx, handle ); + info->samplers[idx] = handle; + + return PIPE_OK; } -#endif -void cso_save_fragment_shader(struct cso_context *ctx) +enum pipe_error +cso_single_sampler(struct cso_context *ctx, + unsigned idx, + const struct pipe_sampler_state *templ) { - assert(!ctx->fragment_shader_saved); - ctx->fragment_shader_saved = ctx->fragment_shader; + return single_sampler(ctx, &ctx->fragment_samplers, idx, templ); } -void cso_restore_fragment_shader(struct cso_context *ctx) +enum pipe_error +cso_single_vertex_sampler(struct cso_context *ctx, + unsigned idx, + const struct pipe_sampler_state *templ) { - if (ctx->fragment_shader_saved != ctx->fragment_shader) { - ctx->pipe->bind_fs_state(ctx->pipe, ctx->fragment_shader_saved); - ctx->fragment_shader = ctx->fragment_shader_saved; - } - ctx->fragment_shader_saved = NULL; + return single_sampler(ctx, &ctx->vertex_samplers, idx, templ); } -enum pipe_error cso_set_vertex_shader_handle(struct cso_context *ctx, - void *handle ) + +static void +single_sampler_done(struct cso_context *ctx, + struct sampler_info *info) { - if (ctx->vertex_shader != handle) { - ctx->vertex_shader = handle; - ctx->pipe->bind_vs_state(ctx->pipe, handle); + unsigned i; + + /* find highest non-null sampler */ + for (i = PIPE_MAX_SAMPLERS; i > 0; i--) { + if (info->samplers[i - 1] != NULL) + break; + } + + info->nr_samplers = i; + + if (info->hw.nr_samplers != info->nr_samplers || + memcmp(info->hw.samplers, + info->samplers, + info->nr_samplers * sizeof(void *)) != 0) + { + memcpy(info->hw.samplers, + info->samplers, + info->nr_samplers * sizeof(void *)); + info->hw.nr_samplers = info->nr_samplers; + + if (info == &ctx->fragment_samplers) { + ctx->pipe->bind_fragment_sampler_states(ctx->pipe, + info->nr_samplers, + info->samplers); + } + else if (info == &ctx->vertex_samplers) { + ctx->pipe->bind_vertex_sampler_states(ctx->pipe, + info->nr_samplers, + info->samplers); + } + else { + assert(0); + } } - return PIPE_OK; } -void cso_delete_vertex_shader(struct cso_context *ctx, void *handle ) +void +cso_single_sampler_done( struct cso_context *ctx ) { - if (handle == ctx->vertex_shader) { - /* unbind before deleting */ - ctx->pipe->bind_vs_state(ctx->pipe, NULL); - ctx->vertex_shader = NULL; - } - ctx->pipe->delete_vs_state(ctx->pipe, handle); + single_sampler_done(ctx, &ctx->fragment_samplers); +} + +void +cso_single_vertex_sampler_done(struct cso_context *ctx) +{ + single_sampler_done(ctx, &ctx->vertex_samplers); } -/* Not really working: +/* + * If the function encouters any errors it will return the + * last one. Done to always try to set as many samplers + * as possible. */ -#if 0 -enum pipe_error cso_set_vertex_shader(struct cso_context *ctx, - const struct pipe_shader_state *templ) +static enum pipe_error +set_samplers(struct cso_context *ctx, + struct sampler_info *info, + unsigned nr, + const struct pipe_sampler_state **templates) { - unsigned hash_key = cso_construct_key((void*)templ, - sizeof(struct pipe_shader_state)); - struct cso_hash_iter iter = cso_find_state_template(ctx->cache, - hash_key, CSO_VERTEX_SHADER, - (void*)templ); - void *handle = NULL; + unsigned i; + enum pipe_error temp, error = PIPE_OK; - if (cso_hash_iter_is_null(iter)) { - struct cso_vertex_shader *cso = MALLOC(sizeof(struct cso_vertex_shader)); + /* TODO: fastpath + */ - if (!cso) - return PIPE_ERROR_OUT_OF_MEMORY; + for (i = 0; i < nr; i++) { + temp = single_sampler(ctx, info, i, templates[i]); + if (temp != PIPE_OK) + error = temp; + } - memcpy(cso->state, templ, sizeof(*templ)); - cso->data = ctx->pipe->create_vs_state(ctx->pipe, &cso->state); - cso->delete_state = (cso_state_callback)ctx->pipe->delete_vs_state; - cso->context = ctx->pipe; + for ( ; i < info->nr_samplers; i++) { + temp = single_sampler(ctx, info, i, NULL); + if (temp != PIPE_OK) + error = temp; + } - iter = cso_insert_state(ctx->cache, hash_key, CSO_VERTEX_SHADER, cso); - if (cso_hash_iter_is_null(iter)) { - FREE(cso); - return PIPE_ERROR_OUT_OF_MEMORY; - } + single_sampler_done(ctx, info); - handle = cso->data; - } - else { - handle = ((struct cso_vertex_shader *)cso_hash_iter_data(iter))->data; - } + return error; +} - return cso_set_vertex_shader_handle( ctx, handle ); +enum pipe_error +cso_set_samplers(struct cso_context *ctx, + unsigned nr, + const struct pipe_sampler_state **templates) +{ + return set_samplers(ctx, &ctx->fragment_samplers, nr, templates); +} + +enum pipe_error +cso_set_vertex_samplers(struct cso_context *ctx, + unsigned nr, + const struct pipe_sampler_state **templates) +{ + return set_samplers(ctx, &ctx->vertex_samplers, nr, templates); } -#endif -void cso_save_vertex_shader(struct cso_context *ctx) +static void +save_samplers(struct cso_context *ctx, struct sampler_info *info) { - assert(!ctx->vertex_shader_saved); - ctx->vertex_shader_saved = ctx->vertex_shader; + info->nr_samplers_saved = info->nr_samplers; + memcpy(info->samplers_saved, info->samplers, sizeof(info->samplers)); } -void cso_restore_vertex_shader(struct cso_context *ctx) +void +cso_save_samplers(struct cso_context *ctx) { - if (ctx->vertex_shader_saved != ctx->vertex_shader) { - ctx->pipe->bind_vs_state(ctx->pipe, ctx->vertex_shader_saved); - ctx->vertex_shader = ctx->vertex_shader_saved; - } - ctx->vertex_shader_saved = NULL; + save_samplers(ctx, &ctx->fragment_samplers); } +void +cso_save_vertex_samplers(struct cso_context *ctx) +{ + save_samplers(ctx, &ctx->vertex_samplers); +} + + -/** - * Copy framebuffer state from src to dst with refcounting of surfaces. - */ static void -copy_framebuffer_state(struct pipe_framebuffer_state *dst, - const struct pipe_framebuffer_state *src) +restore_samplers(struct cso_context *ctx, struct sampler_info *info) { - uint i; + info->nr_samplers = info->nr_samplers_saved; + memcpy(info->samplers, info->samplers_saved, sizeof(info->samplers)); + single_sampler_done(ctx, info); +} - dst->width = src->width; - dst->height = src->height; - dst->nr_cbufs = src->nr_cbufs; - for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) { - pipe_surface_reference(&dst->cbufs[i], src->cbufs[i]); - } - pipe_surface_reference(&dst->zsbuf, src->zsbuf); +void +cso_restore_samplers(struct cso_context *ctx) +{ + restore_samplers(ctx, &ctx->fragment_samplers); +} + +void +cso_restore_vertex_samplers(struct cso_context *ctx) +{ + restore_samplers(ctx, &ctx->vertex_samplers); } + static void -free_framebuffer_state(struct pipe_framebuffer_state *fb) +set_sampler_views(struct cso_context *ctx, + struct sampler_info *info, + void (*set_views)(struct pipe_context *, + unsigned num_views, + struct pipe_sampler_view **), + uint count, + struct pipe_sampler_view **views) { uint i; - for (i = 0; i < PIPE_MAX_COLOR_BUFS; i++) { - pipe_surface_reference(&fb->cbufs[i], NULL); + /* reference new views */ + for (i = 0; i < count; i++) { + pipe_sampler_view_reference(&info->views[i], views[i]); } - pipe_surface_reference(&fb->zsbuf, NULL); + /* unref extra old views, if any */ + for (; i < info->nr_views; i++) { + pipe_sampler_view_reference(&info->views[i], NULL); + } + + info->nr_views = count; + + /* bind the new sampler views */ + set_views(ctx->pipe, count, info->views); } +void +cso_set_fragment_sampler_views(struct cso_context *ctx, + uint count, + struct pipe_sampler_view **views) +{ + set_sampler_views(ctx, &ctx->fragment_samplers, + ctx->pipe->set_fragment_sampler_views, + count, views); +} -enum pipe_error cso_set_framebuffer(struct cso_context *ctx, - const struct pipe_framebuffer_state *fb) +void +cso_set_vertex_sampler_views(struct cso_context *ctx, + uint count, + struct pipe_sampler_view **views) { - if (memcmp(&ctx->fb, fb, sizeof(*fb)) != 0) { - copy_framebuffer_state(&ctx->fb, fb); - ctx->pipe->set_framebuffer_state(ctx->pipe, fb); + set_sampler_views(ctx, &ctx->vertex_samplers, + ctx->pipe->set_vertex_sampler_views, + count, views); +} + + + +static void +save_sampler_views(struct cso_context *ctx, + struct sampler_info *info) +{ + uint i; + + info->nr_views_saved = info->nr_views; + + for (i = 0; i < info->nr_views; i++) { + assert(!info->views_saved[i]); + pipe_sampler_view_reference(&info->views_saved[i], info->views[i]); } - return PIPE_OK; } -void cso_save_framebuffer(struct cso_context *ctx) +void +cso_save_fragment_sampler_views(struct cso_context *ctx) { - copy_framebuffer_state(&ctx->fb_saved, &ctx->fb); + save_sampler_views(ctx, &ctx->fragment_samplers); } -void cso_restore_framebuffer(struct cso_context *ctx) +void +cso_save_vertex_sampler_views(struct cso_context *ctx) { - if (memcmp(&ctx->fb, &ctx->fb_saved, sizeof(ctx->fb))) { - copy_framebuffer_state(&ctx->fb, &ctx->fb_saved); - ctx->pipe->set_framebuffer_state(ctx->pipe, &ctx->fb); - free_framebuffer_state(&ctx->fb_saved); - } + save_sampler_views(ctx, &ctx->vertex_samplers); } -enum pipe_error cso_set_viewport(struct cso_context *ctx, - const struct pipe_viewport_state *vp) +static void +restore_sampler_views(struct cso_context *ctx, + struct sampler_info *info, + void (*set_views)(struct pipe_context *, + unsigned num_views, + struct pipe_sampler_view **)) { - if (memcmp(&ctx->vp, vp, sizeof(*vp))) { - ctx->vp = *vp; - ctx->pipe->set_viewport_state(ctx->pipe, vp); + uint i; + + for (i = 0; i < info->nr_views_saved; i++) { + pipe_sampler_view_reference(&info->views[i], NULL); + /* move the reference from one pointer to another */ + info->views[i] = info->views_saved[i]; + info->views_saved[i] = NULL; } - return PIPE_OK; + for (; i < info->nr_views; i++) { + pipe_sampler_view_reference(&info->views[i], NULL); + } + + /* bind the old/saved sampler views */ + set_views(ctx->pipe, info->nr_views_saved, info->views); + + info->nr_views = info->nr_views_saved; + info->nr_views_saved = 0; } -void cso_save_viewport(struct cso_context *ctx) +void +cso_restore_fragment_sampler_views(struct cso_context *ctx) { - ctx->vp_saved = ctx->vp; + restore_sampler_views(ctx, &ctx->fragment_samplers, + ctx->pipe->set_fragment_sampler_views); +} + +void +cso_restore_vertex_sampler_views(struct cso_context *ctx) +{ + restore_sampler_views(ctx, &ctx->vertex_samplers, + ctx->pipe->set_vertex_sampler_views); } -void cso_restore_viewport(struct cso_context *ctx) +void +cso_set_stream_outputs(struct cso_context *ctx, + unsigned num_targets, + struct pipe_stream_output_target **targets, + unsigned append_bitmask) { - if (memcmp(&ctx->vp, &ctx->vp_saved, sizeof(ctx->vp))) { - ctx->vp = ctx->vp_saved; - ctx->pipe->set_viewport_state(ctx->pipe, &ctx->vp); + struct pipe_context *pipe = ctx->pipe; + uint i; + + if (!ctx->has_streamout) { + assert(num_targets == 0); + return; } -} + if (ctx->nr_so_targets == 0 && num_targets == 0) { + /* Nothing to do. */ + return; + } + /* reference new targets */ + for (i = 0; i < num_targets; i++) { + pipe_so_target_reference(&ctx->so_targets[i], targets[i]); + } + /* unref extra old targets, if any */ + for (; i < ctx->nr_so_targets; i++) { + pipe_so_target_reference(&ctx->so_targets[i], NULL); + } + pipe->set_stream_output_targets(pipe, num_targets, targets, + append_bitmask); + ctx->nr_so_targets = num_targets; +} -enum pipe_error cso_set_blend_color(struct cso_context *ctx, - const struct pipe_blend_color *bc) +void +cso_save_stream_outputs(struct cso_context *ctx) { - if (memcmp(&ctx->blend_color, bc, sizeof(ctx->blend_color))) { - ctx->blend_color = *bc; - ctx->pipe->set_blend_color(ctx->pipe, bc); + uint i; + + if (!ctx->has_streamout) { + return; + } + + ctx->nr_so_targets_saved = ctx->nr_so_targets; + + for (i = 0; i < ctx->nr_so_targets; i++) { + assert(!ctx->so_targets_saved[i]); + pipe_so_target_reference(&ctx->so_targets_saved[i], ctx->so_targets[i]); } - return PIPE_OK; } -enum pipe_error cso_set_geometry_shader_handle(struct cso_context *ctx, - void *handle) +void +cso_restore_stream_outputs(struct cso_context *ctx) { - if (ctx->geometry_shader != handle) { - ctx->geometry_shader = handle; - ctx->pipe->bind_gs_state(ctx->pipe, handle); + struct pipe_context *pipe = ctx->pipe; + uint i; + + if (!ctx->has_streamout) { + return; } - return PIPE_OK; + + if (ctx->nr_so_targets == 0 && ctx->nr_so_targets_saved == 0) { + /* Nothing to do. */ + return; + } + + for (i = 0; i < ctx->nr_so_targets_saved; i++) { + pipe_so_target_reference(&ctx->so_targets[i], NULL); + /* move the reference from one pointer to another */ + ctx->so_targets[i] = ctx->so_targets_saved[i]; + ctx->so_targets_saved[i] = NULL; + } + for (; i < ctx->nr_so_targets; i++) { + pipe_so_target_reference(&ctx->so_targets[i], NULL); + } + + /* ~0 means append */ + pipe->set_stream_output_targets(pipe, ctx->nr_so_targets_saved, + ctx->so_targets, ~0); + + ctx->nr_so_targets = ctx->nr_so_targets_saved; + ctx->nr_so_targets_saved = 0; } -void cso_delete_geometry_shader(struct cso_context *ctx, void *handle) +/* drawing */ + +void +cso_set_index_buffer(struct cso_context *cso, + const struct pipe_index_buffer *ib) { - if (handle == ctx->geometry_shader) { - /* unbind before deleting */ - ctx->pipe->bind_gs_state(ctx->pipe, NULL); - ctx->geometry_shader = NULL; - } - ctx->pipe->delete_gs_state(ctx->pipe, handle); + struct pipe_context *pipe = cso->pipe; + pipe->set_index_buffer(pipe, ib); } -void cso_save_geometry_shader(struct cso_context *ctx) +void +cso_draw_vbo(struct cso_context *cso, + const struct pipe_draw_info *info) { - assert(!ctx->geometry_shader_saved); - ctx->geometry_shader_saved = ctx->geometry_shader; + struct pipe_context *pipe = cso->pipe; + pipe->draw_vbo(pipe, info); } -void cso_restore_geometry_shader(struct cso_context *ctx) +void +cso_draw_arrays(struct cso_context *cso, uint mode, uint start, uint count) { - if (ctx->geometry_shader_saved != ctx->geometry_shader) { - ctx->pipe->bind_gs_state(ctx->pipe, ctx->geometry_shader_saved); - ctx->geometry_shader = ctx->geometry_shader_saved; - } - ctx->geometry_shader_saved = NULL; + struct pipe_draw_info info; + + util_draw_init_info(&info); + + info.mode = mode; + info.start = start; + info.count = count; + info.min_index = start; + info.max_index = start + count - 1; + + cso_draw_vbo(cso, &info); }