diff options
| author | Stuart Adams <stuartdadams@gmail.com> | 2021-07-25 17:34:20 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-07-25 17:34:20 +0100 |
| commit | 36e9b36b923f27c7112d05965c04ba190d50e4c0 (patch) | |
| tree | e041a5407ca7d48db9d15aec14eac3689e01e2af /util | |
| parent | 158077fd793e1a8da6c73b581aa78af0f99e8f84 (diff) | |
sbatch_pipeline API
the sbatch_pipeline helps users make a pipeline object that is correct and usable for the sbatch rendering API.
Diffstat (limited to 'util')
| -rw-r--r-- | util/sokol_spritebatch.h | 213 |
1 files changed, 171 insertions, 42 deletions
diff --git a/util/sokol_spritebatch.h b/util/sokol_spritebatch.h index c95d57ba..6def5e33 100644 --- a/util/sokol_spritebatch.h +++ b/util/sokol_spritebatch.h @@ -70,6 +70,7 @@ extern "C" { typedef struct sbatch_desc { int context_pool_size; + int pipeline_pool_size; sg_pixel_format color_format; sg_pixel_format depth_format; int sample_count; @@ -79,17 +80,15 @@ extern "C" { uint32_t id; } sbatch_context; - enum - { - SBATCH_MAX_SPRITES = (1 << 16) / 4, - SBATCH_DEFAULT_SPRITES = SBATCH_MAX_SPRITES / 4 - }; + typedef struct sbatch_pipeline { + uint32_t id; + } sbatch_pipeline; typedef struct sbatch_context_desc { int canvas_width; int canvas_height; int max_sprites; - sg_pipeline pipeline; + sbatch_pipeline pipeline; const char* label; } sbatch_context_desc; @@ -97,6 +96,9 @@ extern "C" { SOKOL_SPRITEBATCH_API_DECL void sbatch_shutdown(void); SOKOL_SPRITEBATCH_API_DECL int sbatch_frame(); + SOKOL_SPRITEBATCH_API_DECL sbatch_pipeline sbatch_make_pipeline(const sg_pipeline_desc* desc); + SOKOL_SPRITEBATCH_API_DECL void sbatch_destroy_pipeline(sbatch_pipeline context); + SOKOL_SPRITEBATCH_API_DECL sbatch_context sbatch_make_context(const sbatch_context_desc* desc); SOKOL_SPRITEBATCH_API_DECL void sbatch_destroy_context(sbatch_context context); @@ -199,7 +201,7 @@ typedef struct { _sbatch_vertex* vertices; sg_image* images; sg_buffer vertex_buffer; - sg_pipeline pipeline; + sbatch_pipeline pipeline; int update_frame_index; _sbatch_fs_uniform_state fs_uniform_state; } _sbatch_context; @@ -217,6 +219,18 @@ typedef struct { } _sbatch_context_pool; typedef struct { + _sbatch_str label; + _sbatch_slot slot; + sg_pipeline_desc desc; + sg_pipeline pipeline; +} _sbatch_pipeline; + +typedef struct { + _sbatch_pool pool; + _sbatch_pipeline* pipelines; +} _sbatch_pipeline_pool; + +typedef struct { sg_image image; int width; int height; @@ -234,9 +248,10 @@ typedef struct { _sbatch_slot slot; sg_bindings bindings; sg_shader shader; - sg_pipeline pipeline; + sbatch_pipeline pipeline; sbatch_context ctx_id; _sbatch_context_pool context_pool; + _sbatch_pipeline_pool pipeline_pool; _sbatch_sprite_pool sprite_pool; sg_buffer index_buffer; int frame_index; @@ -402,7 +417,6 @@ static _sbatch_str _sbatch_make_str(const char* str) { return res; } -/*=== CONTEXT POOL ===========================================================*/ static void _sbatch_init_pool(_sbatch_pool* pool, int num) { SOKOL_ASSERT(pool && (num >= 1)); /* slot 0 is reserved for the 'invalid id', so bump the pool size by 1 */ @@ -461,24 +475,6 @@ static void _sbatch_pool_free_index(_sbatch_pool* pool, int slot_index) { SOKOL_ASSERT(pool->queue_top <= (pool->size - 1)); } -static void _sbatch_setup_context_pool(const sbatch_desc* desc) { - SOKOL_ASSERT(desc); - /* note: the pool will have an additional item, since slot 0 is reserved */ - SOKOL_ASSERT((desc->context_pool_size > 0) && (desc->context_pool_size < _SBATCH_MAX_POOL_SIZE)); - _sbatch_init_pool(&_sbatch.context_pool.pool, desc->context_pool_size); - const size_t pool_byte_size = sizeof(_sbatch_context) * (size_t)_sbatch.context_pool.pool.size; - _sbatch.context_pool.contexts = (_sbatch_context*)SOKOL_MALLOC(pool_byte_size); - SOKOL_ASSERT(_sbatch.context_pool.contexts); - memset(_sbatch.context_pool.contexts, 0, pool_byte_size); -} - -static void _sbatch_discard_context_pool(void) { - SOKOL_ASSERT(_sbatch.context_pool.contexts); - SOKOL_FREE(_sbatch.context_pool.contexts); - _sbatch.context_pool.contexts = 0; - _sbatch_discard_pool(&_sbatch.context_pool.pool); -} - /* allocate the slot at slot_index: - bump the slot's generation counter - create a resource id from the generation counter and slot index @@ -507,6 +503,24 @@ static int _sbatch_slot_index(uint32_t id) { return slot_index; } +static void _sbatch_setup_context_pool(const sbatch_desc* desc) { + SOKOL_ASSERT(desc); + /* note: the pool will have an additional item, since slot 0 is reserved */ + SOKOL_ASSERT((desc->context_pool_size > 0) && (desc->context_pool_size < _SBATCH_MAX_POOL_SIZE)); + _sbatch_init_pool(&_sbatch.context_pool.pool, desc->context_pool_size); + const size_t pool_byte_size = sizeof(_sbatch_context) * (size_t)_sbatch.context_pool.pool.size; + _sbatch.context_pool.contexts = (_sbatch_context*)SOKOL_MALLOC(pool_byte_size); + SOKOL_ASSERT(_sbatch.context_pool.contexts); + memset(_sbatch.context_pool.contexts, 0, pool_byte_size); +} + +static void _sbatch_discard_context_pool(void) { + SOKOL_ASSERT(_sbatch.context_pool.contexts); + SOKOL_FREE(_sbatch.context_pool.contexts); + _sbatch.context_pool.contexts = 0; + _sbatch_discard_pool(&_sbatch.context_pool.pool); +} + /* get context pointer without id-check */ static _sbatch_context* _sbatch_context_at(uint32_t ctx_id) { SOKOL_ASSERT(SG_INVALID_ID != ctx_id); @@ -546,6 +560,65 @@ static sbatch_context _sbatch_alloc_context(void) { return ctx_id; } +/////////////////////////////// + +static void _sbatch_setup_pipeline_pool(const sbatch_desc* desc) { + SOKOL_ASSERT(desc); + /* note: the pool will have an additional item, since slot 0 is reserved */ + SOKOL_ASSERT((desc->pipeline_pool_size > 0) && (desc->pipeline_pool_size < _SBATCH_MAX_POOL_SIZE)); + _sbatch_init_pool(&_sbatch.pipeline_pool.pool, desc->pipeline_pool_size); + const size_t pool_byte_size = sizeof(_sbatch_pipeline) * (size_t)_sbatch.pipeline_pool.pool.size; + _sbatch.pipeline_pool.pipelines = (_sbatch_pipeline*)SOKOL_MALLOC(pool_byte_size); + SOKOL_ASSERT(_sbatch.pipeline_pool.pipelines); + memset(_sbatch.pipeline_pool.pipelines, 0, pool_byte_size); +} + +static void _sbatch_discard_pipeline_pool(void) { + SOKOL_ASSERT(_sbatch.pipeline_pool.pipelines); + SOKOL_FREE(_sbatch.pipeline_pool.pipelines); + _sbatch.pipeline_pool.pipelines = 0; + _sbatch_discard_pool(&_sbatch.pipeline_pool.pool); +} + +/* get pipeline pointer without id-check */ +static _sbatch_pipeline* _sbatch_pipeline_at(uint32_t pip_id) { + SOKOL_ASSERT(SG_INVALID_ID != pip_id); + const int slot_index = _sbatch_slot_index(pip_id); + SOKOL_ASSERT((slot_index > _SBATCH_INVALID_SLOT_INDEX) && (slot_index < _sbatch.pipeline_pool.pool.size)); + return &_sbatch.pipeline_pool.pipelines[slot_index]; +} + +/* get pipeline pointer with id-check, returns 0 if no match */ +static _sbatch_pipeline* _sbatch_lookup_pipeline(uint32_t pip_id) { + if (SG_INVALID_ID != pip_id) { + _sbatch_pipeline* pip = _sbatch_pipeline_at(pip_id); + if (pip->slot.id == pip_id) { + return pip; + } + } + return NULL; +} + +/* make pipeline handle from raw uint32_t id */ +static sbatch_pipeline _sbatch_make_pip_id(uint32_t pip_id) { + sbatch_pipeline pip; + pip.id = pip_id; + return pip; +} + +static sbatch_pipeline _sbatch_alloc_pipeline(void) { + sbatch_pipeline pip_id; + const int slot_index = _sbatch_pool_alloc_index(&_sbatch.pipeline_pool.pool); + if (_SBATCH_INVALID_SLOT_INDEX != slot_index) { + pip_id = _sbatch_make_pip_id(_sbatch_slot_alloc(&_sbatch.pipeline_pool.pool, &_sbatch.pipeline_pool.pipelines[slot_index].slot, slot_index)); + } + else { + /* pool is exhausted */ + pip_id = _sbatch_make_pip_id(SG_INVALID_ID); + } + return pip_id; +} + static sbatch_context_desc _sbatch_context_desc_defaults(const sbatch_context_desc* desc) { sbatch_context_desc res = *desc; res.max_sprites = _SBATCH_DEFAULT(res.max_sprites, 4096); @@ -598,7 +671,6 @@ static void _sbatch_init_context(sbatch_context ctx_id, const sbatch_context_des static void _sbatch_destroy_context(sbatch_context ctx_id) { _sbatch_context* ctx = _sbatch_lookup_context(ctx_id.id); if (ctx) { - ctx->sprite_count = 0; if (ctx->vertices) { SOKOL_FREE(ctx->vertices); } @@ -613,6 +685,59 @@ static void _sbatch_destroy_context(sbatch_context ctx_id) { } } + +static sg_pipeline_desc _sbatch_pipeline_desc_defaults(const sg_pipeline_desc* desc) { + sg_pipeline_desc pipeline_desc = *desc; + + pipeline_desc.color_count = _SBATCH_DEFAULT(pipeline_desc.color_count, 1); + if (pipeline_desc.color_count == 1) { + pipeline_desc.colors[0].blend.enabled = _SBATCH_DEFAULT(desc->colors[0].blend.enabled, true); + pipeline_desc.colors[0].blend.src_factor_rgb = _SBATCH_DEFAULT(desc->colors[0].blend.src_factor_rgb, SG_BLENDFACTOR_ONE); + pipeline_desc.colors[0].blend.src_factor_alpha = _SBATCH_DEFAULT(desc->colors[0].blend.src_factor_rgb, SG_BLENDFACTOR_ONE); + pipeline_desc.colors[0].blend.dst_factor_rgb = _SBATCH_DEFAULT(desc->colors[0].blend.src_factor_rgb, SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA); + pipeline_desc.colors[0].blend.dst_factor_alpha = _SBATCH_DEFAULT(desc->colors[0].blend.src_factor_rgb, SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA); + } + + pipeline_desc.shader.id = _SBATCH_DEFAULT(desc->shader.id, _sbatch.shader.id); + pipeline_desc.index_type = SG_INDEXTYPE_UINT16; + pipeline_desc.layout.attrs[0].format = SG_VERTEXFORMAT_FLOAT3; + pipeline_desc.layout.attrs[1].format = SG_VERTEXFORMAT_FLOAT2; + pipeline_desc.layout.attrs[2].format = SG_VERTEXFORMAT_UBYTE4N; + pipeline_desc.label = _SBATCH_DEFAULT(desc->label, "sokol-spritebatch-pipline"); + return pipeline_desc; +} + +static void _sbatch_init_pipeline(sbatch_pipeline pip_id, const sg_pipeline_desc* in_desc) { + sg_push_debug_group("sokol-spritebatch"); + + SOKOL_ASSERT((pip_id.id != SG_INVALID_ID) && in_desc); + + _sbatch_pipeline* pip = _sbatch_lookup_pipeline(pip_id.id); + SOKOL_ASSERT(pip); + + pip->desc = _sbatch_pipeline_desc_defaults(in_desc); + + pip->label = _sbatch_make_str(pip->desc.label); + + pip->desc.label = NULL; + + pip->pipeline = sg_make_pipeline(&pip->desc); + SOKOL_ASSERT(pip->pipeline.id != SG_INVALID_ID); + + sg_pop_debug_group(); +} + +static void _sbatch_destroy_pipeline(sbatch_pipeline pip_id) { + _sbatch_pipeline* pip = _sbatch_lookup_pipeline(pip_id.id); + if (pip) { + sg_push_debug_group("sokol-spritebatch"); + sg_destroy_pipeline(pip->pipeline); + sg_pop_debug_group(); + memset(pip, 0, sizeof(*pip)); + _sbatch_pool_free_index(&_sbatch.pipeline_pool.pool, _sbatch_slot_index(pip_id.id)); + } +} + static uint32_t _sbatch_pack_color_bytes(uint8_t r, uint8_t g, uint8_t b, uint8_t a) { return (uint32_t)a << 24 | (uint32_t)b << 16 | (uint32_t)g << 8 | (uint32_t)r; } @@ -774,39 +899,42 @@ SOKOL_API_IMPL void sbatch_setup(const sbatch_desc* desc) { sbatch_desc batch_desc = *desc; batch_desc.context_pool_size = _SBATCH_DEFAULT(batch_desc.context_pool_size, 32); + batch_desc.pipeline_pool_size = _SBATCH_DEFAULT(batch_desc.pipeline_pool_size, 32); _sbatch_setup_context_pool(&batch_desc); + _sbatch_setup_pipeline_pool(&batch_desc); _sbatch_setup_sprite_pool(); _sbatch.shader = sg_make_shader(spritebatch_shader_desc(sg_query_backend())); sg_pipeline_desc pipeline_desc; memset(&pipeline_desc, 0, sizeof(sg_pipeline_desc)); - pipeline_desc.color_count = 1; - pipeline_desc.colors[0].blend.enabled = true; - pipeline_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_ONE; - pipeline_desc.colors[0].blend.src_factor_alpha = SG_BLENDFACTOR_ONE; - pipeline_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; - pipeline_desc.colors[0].blend.dst_factor_alpha = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; pipeline_desc.shader = _sbatch.shader; - pipeline_desc.index_type = SG_INDEXTYPE_UINT16; - pipeline_desc.layout.attrs[0].format = SG_VERTEXFORMAT_FLOAT3; - pipeline_desc.layout.attrs[1].format = SG_VERTEXFORMAT_FLOAT2; - pipeline_desc.layout.attrs[2].format = SG_VERTEXFORMAT_UBYTE4N; pipeline_desc.label = "spritebatch-default-pipeline"; - - _sbatch.pipeline = sg_make_pipeline(&pipeline_desc); + _sbatch.pipeline = sbatch_make_pipeline(&pipeline_desc); _sbatch_init_index_buffer(); } SOKOL_API_IMPL void sbatch_shutdown(void) { sg_destroy_buffer(_sbatch.index_buffer); - sg_destroy_pipeline(_sbatch.pipeline); + sbatch_destroy_pipeline(_sbatch.pipeline); sg_destroy_shader(_sbatch.shader); _sbatch_discard_context_pool(); SOKOL_FREE(_sbatch.sprite_pool.data); } +SOKOL_SPRITEBATCH_API_DECL sbatch_pipeline sbatch_make_pipeline(const sg_pipeline_desc* desc) { + SOKOL_ASSERT(desc); + const sbatch_pipeline result = _sbatch_alloc_pipeline(); + _sbatch_init_pipeline(result, desc); + return result; +} + +SOKOL_SPRITEBATCH_API_DECL void sbatch_destroy_pipeline(sbatch_pipeline pipeline) { + SOKOL_ASSERT(pipeline.id != SG_INVALID_ID); + _sbatch_destroy_pipeline(pipeline); +} + SOKOL_API_IMPL sbatch_context sbatch_make_context(const sbatch_context_desc* desc) { SOKOL_ASSERT(desc); const sbatch_context result = _sbatch_alloc_context(); @@ -1085,7 +1213,8 @@ void sbatch_end(void) { int base_element = 0; sg_image current_image = ctx->images[0]; - sg_apply_pipeline(ctx->pipeline); + const _sbatch_pipeline* pipeline = _sbatch_pipeline_at(ctx->pipeline.id); + sg_apply_pipeline(pipeline->pipeline); _sbatch_mat4x4 matrix = _sbatch_orthographic_off_center(0.0f, (float)ctx->desc.canvas_width, (float)ctx->desc.canvas_height, 0.0f, 0.0f, 1000.0f); |