diff options
| author | Andre Weissflog <floooh@gmail.com> | 2019-04-26 18:05:17 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2019-04-26 18:05:17 +0200 |
| commit | eaae3947d8171ba6b842d46629df48c027f97822 (patch) | |
| tree | 41302371aba9ed7b4c39f2fe03cb5957017cb45f /sokol_gfx.h | |
| parent | 339bf9b4833361d7b47549b98c37c0a6a2b7cb6c (diff) | |
Move vertex-attr names/semantics from sg_pipeline_desc to sg_shader_desc (#146)
* sokol_gfx.h: start working moving vertex attr names into sg_shader_desc
* sokol_gfx.h: move vertex attribute names into shader desc
* sokol_gfx.h: D3D11 backend fixes
* fix typo in GLES2 shader-attr validation
* add shader-attribute change to README update section
* remove unused _sg_make_str function
Diffstat (limited to 'sokol_gfx.h')
| -rw-r--r-- | sokol_gfx.h | 137 |
1 files changed, 108 insertions, 29 deletions
diff --git a/sokol_gfx.h b/sokol_gfx.h index 53cb3ef6..82bea326 100644 --- a/sokol_gfx.h +++ b/sokol_gfx.h @@ -284,32 +284,34 @@ ... }; - --- when creating a pipeline object, GLES2/WebGL need to know the vertex - attribute names as used in the vertex shader when describing vertex - layouts: + --- when creating a shader object, GLES2/WebGL need to know the vertex + attribute names as used in the vertex shader: - sg_pipeline_desc desc = { - .layout = { - .attrs = { - [0] = { .name="position", .format=SG_VERTEXFORMAT_FLOAT3 }, - [1] = { .name="color1", .format=SG_VERTEXFORMAT_FLOAT4 } - } + sg_shader_desc desc = { + .attrs = { + [0] = { .name="position" }, + [1] = { .name="color1" } } }; + The vertex attribute names provided when creating a shader will be + used later in sg_create_pipeline() for matching the vertex layout + to vertex shader inputs. + --- on D3D11 you need to provide a semantic name and semantic index in the - vertex attribute definition instead (see the D3D11 documentation on + shader description struct instead (see the D3D11 documentation on D3D11_INPUT_ELEMENT_DESC for details): - sg_pipeline_desc desc = { - .layout = { - .attrs = { - [0] = { .sem_name="POSITION", .sem_index=0, .format=SG_VERTEXFORMAT_FLOAT3 }, - [1] = { .sem_name="COLOR", .sem_index=1, .format=SG_VERTEXFORMAT_FLOAT4 } - } + sg_shader_desc desc = { + .attrs = { + [0] = { .sem_name="POSITION", .sem_index=0 } + [1] = { .sem_name="COLOR", .sem_index=1 } } }; + The provided semantic information will be used later in sg_create_pipeline() + to match the vertex layout to vertex shader inputs. + --- on Metal, GL 3.3 or GLES3/WebGL2, you don't need to provide an attribute name or semantic name, since vertex attributes can be bound by their slot index (this is mandatory in Metal, and optional in GL): @@ -1283,10 +1285,17 @@ typedef struct sg_image_desc { sg_shader_desc The structure sg_shader_desc describes the shaders, uniform blocks - and texture images on the vertex- and fragment-shader stage. + texture images and vertex-attribute-names/semantics (required + for GLES2 and D3D11) of a shader stage. TODO: source code vs byte code, 3D backend API specifics. */ +typedef struct sg_shader_attr_desc { + const char* name; /* GLSL vertex attribute name (only required for GLES2) */ + const char* sem_name; /* HLSL semantic name */ + int sem_index; /* HLSL semantic index */ +} sg_shader_attr_desc; + typedef struct sg_shader_uniform_desc { const char* name; sg_uniform_type type; @@ -1314,6 +1323,7 @@ typedef struct sg_shader_stage_desc { typedef struct sg_shader_desc { uint32_t _start_canary; + sg_shader_attr_desc attrs[SG_MAX_VERTEX_ATTRIBUTES]; sg_shader_stage_desc vs; sg_shader_stage_desc fs; const char* label; @@ -1401,9 +1411,6 @@ typedef struct sg_buffer_layout_desc { } sg_buffer_layout_desc; typedef struct sg_vertex_attr_desc { - const char* name; - const char* sem_name; - int sem_index; int buffer_index; int offset; sg_vertex_format format; @@ -2039,6 +2046,7 @@ typedef struct { /* constants */ enum { + _SG_STRING_SIZE = 16, _SG_SLOT_SHIFT = 16, _SG_SLOT_MASK = (1<<_SG_SLOT_SHIFT)-1, _SG_MAX_POOL_SIZE = (1<<_SG_SLOT_SHIFT), @@ -2052,6 +2060,11 @@ enum { _SG_MTL_DEFAULT_SAMPLER_CACHE_CAPACITY = 64, }; +/* fixed-size string */ +typedef struct { + char buf[_SG_STRING_SIZE]; +} _sg_str_t; + /* helper macros */ #define _sg_def(val, def) (((val) == 0) ? (def) : (val)) #define _sg_def_flt(val, def) (((val) == 0.0f) ? (def) : (val)) @@ -2215,6 +2228,10 @@ typedef struct { } _sg_shader_image_t; typedef struct { + _sg_str_t name; +} _sg_shader_attr_t; + +typedef struct { int num_uniform_blocks; int num_images; _sg_uniform_block_t uniform_blocks[SG_MAX_SHADERSTAGE_UBS]; @@ -2224,6 +2241,7 @@ typedef struct { typedef struct { _sg_slot_t slot; GLuint gl_prog; + _sg_shader_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES]; _sg_shader_stage_t stage[SG_NUM_SHADER_STAGES]; } _sg_shader_t; @@ -2364,8 +2382,14 @@ typedef struct { } _sg_shader_image_t; typedef struct { + _sg_str_t sem_name; + int sem_index; +} _sg_shader_attr_t; + +typedef struct { int num_uniform_blocks; int num_images; + _sg_shader_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES]; _sg_uniform_block_t uniform_blocks[SG_MAX_SHADERSTAGE_UBS]; _sg_shader_image_t images[SG_MAX_SHADERSTAGE_IMAGES]; ID3D11Buffer* d3d11_cbs[SG_MAX_SHADERSTAGE_UBS]; @@ -2373,6 +2397,7 @@ typedef struct { typedef struct { _sg_slot_t slot; + _sg_shader_attr_t attrs[SG_MAX_VERTEX_ATTRIBUTES]; _sg_shader_stage_t stage[SG_NUM_SHADER_STAGES]; ID3D11VertexShader* d3d11_vs; ID3D11PixelShader* d3d11_fs; @@ -2711,6 +2736,9 @@ typedef enum { _SG_VALIDATE_SHADERDESC_UB_MEMBER_NAME, _SG_VALIDATE_SHADERDESC_UB_SIZE_MISMATCH, _SG_VALIDATE_SHADERDESC_IMG_NAME, + _SG_VALIDATE_SHADERDESC_ATTR_NAMES, + _SG_VALIDATE_SHADERDESC_ATTR_SEMANTICS, + _SG_VALIDATE_SHADERDESC_ATTR_STRING_TOO_LONG, /* pipeline creation */ _SG_VALIDATE_PIPELINEDESC_CANARY, @@ -2826,6 +2854,29 @@ static _sg_state_t _sg; /*-- helper functions --------------------------------------------------------*/ +_SOKOL_PRIVATE bool _sg_strempty(const _sg_str_t* str) { + return 0 == str->buf[0]; +} + +_SOKOL_PRIVATE const char* _sg_strptr(const _sg_str_t* str) { + return &str->buf[0]; +} + +_SOKOL_PRIVATE void _sg_strcpy(_sg_str_t* dst, const char* src) { + SOKOL_ASSERT(dst); + if (src) { + #if defined(_MSC_VER) + strncpy_s(dst->buf, _SG_STRING_SIZE, src, (_SG_STRING_SIZE-1)); + #else + strncpy(dst->buf, src, _SG_STRING_SIZE); + #endif + dst->buf[_SG_STRING_SIZE-1] = 0; + } + else { + memset(dst->buf, 0, _SG_STRING_SIZE); + } +} + /* return byte size of a vertex format */ _SOKOL_PRIVATE int _sg_vertexformat_bytesize(sg_vertex_format fmt) { switch (fmt) { @@ -4246,6 +4297,12 @@ _SOKOL_PRIVATE sg_resource_state _sg_create_shader(_sg_shader_t* shd, const sg_s SOKOL_ASSERT(shd && desc); SOKOL_ASSERT(!shd->gl_prog); _SG_GL_CHECK_ERROR(); + + /* copy vertex attribute names over, these are required for GLES2, and optional for GLES3 and GL3.x */ + for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { + _sg_strcpy(&shd->attrs[i].name, desc->attrs[i].name); + } + GLuint gl_vs = _sg_gl_compile_shader(SG_SHADERSTAGE_VS, desc->vs.source); GLuint gl_fs = _sg_gl_compile_shader(SG_SHADERSTAGE_FS, desc->fs.source); if (!(gl_vs && gl_fs)) { @@ -4384,8 +4441,8 @@ _SOKOL_PRIVATE sg_resource_state _sg_create_pipeline(_sg_pipeline_t* pip, _sg_sh const sg_vertex_step step_func = l_desc->step_func; const int step_rate = l_desc->step_rate; GLint attr_loc = attr_index; - if (a_desc->name) { - attr_loc = glGetAttribLocation(pip->shader->gl_prog, a_desc->name); + if (!_sg_strempty(&shd->attrs[attr_index].name)) { + attr_loc = glGetAttribLocation(pip->shader->gl_prog, _sg_strptr(&shd->attrs[attr_index].name)); } SOKOL_ASSERT(attr_loc < SG_MAX_VERTEX_ATTRIBUTES); if (attr_loc != -1) { @@ -4408,7 +4465,7 @@ _SOKOL_PRIVATE sg_resource_state _sg_create_pipeline(_sg_pipeline_t* pip, _sg_sh } else { SOKOL_LOG("Vertex attribute not found in shader: "); - SOKOL_LOG(a_desc->name); + SOKOL_LOG(_sg_strptr(&shd->attrs[attr_index].name)); } } return SG_RESOURCESTATE_VALID; @@ -5874,6 +5931,12 @@ _SOKOL_PRIVATE sg_resource_state _sg_create_shader(_sg_shader_t* shd, const sg_s HRESULT hr; sg_resource_state result = SG_RESOURCESTATE_FAILED; + /* copy vertex attribute semantic names and indices */ + for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { + _sg_strcpy(&shd->attrs[i].sem_name, desc->attrs[i].sem_name); + shd->attrs[i].sem_index = desc->attrs[i].sem_index; + } + /* shader stage uniform blocks and image slots */ for (int stage_index = 0; stage_index < SG_NUM_SHADER_STAGES; stage_index++) { const sg_shader_stage_desc* stage_desc = (stage_index == SG_SHADERSTAGE_VS) ? &desc->vs : &desc->fs; @@ -6018,8 +6081,8 @@ _SOKOL_PRIVATE sg_resource_state _sg_create_pipeline(_sg_pipeline_t* pip, _sg_sh const sg_vertex_step step_func = l_desc->step_func; const int step_rate = l_desc->step_rate; D3D11_INPUT_ELEMENT_DESC* d3d11_comp = &d3d11_comps[attr_index]; - d3d11_comp->SemanticName = a_desc->sem_name; - d3d11_comp->SemanticIndex = a_desc->sem_index; + d3d11_comp->SemanticName = _sg_strptr(&shd->attrs[attr_index].sem_name); + d3d11_comp->SemanticIndex = shd->attrs[attr_index].sem_index; d3d11_comp->Format = _sg_d3d11_vertex_format(a_desc->format); d3d11_comp->InputSlot = a_desc->buffer_index; d3d11_comp->AlignedByteOffset = a_desc->offset; @@ -8506,14 +8569,17 @@ _SOKOL_PRIVATE const char* _sg_validate_string(_sg_validate_error_t err) { case _SG_VALIDATE_SHADERDESC_UB_SIZE_MISMATCH: return "size of uniform block members doesn't match uniform block size"; case _SG_VALIDATE_SHADERDESC_NO_CONT_IMGS: return "shader images must occupy continuous slots"; case _SG_VALIDATE_SHADERDESC_IMG_NAME: return "GL backend requires uniform block member names"; + case _SG_VALIDATE_SHADERDESC_ATTR_NAMES: return "GLES2 backend requires vertex attribute names"; + case _SG_VALIDATE_SHADERDESC_ATTR_SEMANTICS: return "D3D11 backend requires vertex attribute semantics"; + case _SG_VALIDATE_SHADERDESC_ATTR_STRING_TOO_LONG: return "vertex attribute name/semantic string too long (max len 16)"; /* pipeline creation */ case _SG_VALIDATE_PIPELINEDESC_CANARY: return "sg_pipeline_desc not initialized"; case _SG_VALIDATE_PIPELINEDESC_SHADER: return "sg_pipeline_desc.shader missing or invalid"; case _SG_VALIDATE_PIPELINEDESC_NO_ATTRS: return "sg_pipeline_desc.layout.attrs is empty or not continuous"; case _SG_VALIDATE_PIPELINEDESC_LAYOUT_STRIDE4: return "sg_pipeline_desc.layout.buffers[].stride must be multiple of 4"; - case _SG_VALIDATE_PIPELINEDESC_ATTR_NAME: return "GLES2/WebGL vertex layouts must have attribute names"; - case _SG_VALIDATE_PIPELINEDESC_ATTR_SEMANTICS: return "D3D11 vertex layouts must have attribute semantics (sem_name and sem_index)"; + case _SG_VALIDATE_PIPELINEDESC_ATTR_NAME: return "GLES2/WebGL missing vertex attribute name in shader"; + case _SG_VALIDATE_PIPELINEDESC_ATTR_SEMANTICS: return "D3D11 missing vertex attribute semantics in shader"; /* pass creation */ case _SG_VALIDATE_PASSDESC_CANARY: return "sg_pass_desc not initialized"; @@ -8705,6 +8771,11 @@ _SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) { SOKOL_VALIDATE_BEGIN(); SOKOL_VALIDATE(desc->_start_canary == 0, _SG_VALIDATE_SHADERDESC_CANARY); SOKOL_VALIDATE(desc->_end_canary == 0, _SG_VALIDATE_SHADERDESC_CANARY); + #if defined(SOKOL_GLES2) + SOKOL_VALIDATE(0 != desc->attrs[0].name, _SG_VALIDATE_SHADERDESC_ATTR_NAMES); + #elif defined(SOKOL_D3D11) + SOKOL_VALIDATE(0 != desc->attrs[0].sem_name, _SG_VALIDATE_SHADERDESC_ATTR_SEMANTICS); + #endif #if defined(SOKOL_GLCORE33) || defined(SOKOL_GLES2) || defined(SOKOL_GLES3) /* on GL, must provide shader source code */ SOKOL_VALIDATE(0 != desc->vs.source, _SG_VALIDATE_SHADERDESC_SOURCE); @@ -8720,6 +8791,14 @@ _SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) { #else /* Dummy Backend, don't require source or bytecode */ #endif + for (int i = 0; i < SG_MAX_VERTEX_ATTRIBUTES; i++) { + if (desc->attrs[i].name) { + SOKOL_VALIDATE(strlen(desc->attrs[i].name) < _SG_STRING_SIZE, _SG_VALIDATE_SHADERDESC_ATTR_STRING_TOO_LONG); + } + if (desc->attrs[i].sem_name) { + SOKOL_VALIDATE(strlen(desc->attrs[i].sem_name) < _SG_STRING_SIZE, _SG_VALIDATE_SHADERDESC_ATTR_STRING_TOO_LONG); + } + } /* if shader byte code, the size must also be provided */ if (0 != desc->vs.byte_code) { SOKOL_VALIDATE(desc->vs.byte_code_size > 0, _SG_VALIDATE_SHADERDESC_NO_BYTECODE_SIZE); @@ -8810,10 +8889,10 @@ _SOKOL_PRIVATE bool _sg_validate_pipeline_desc(const sg_pipeline_desc* desc) { SOKOL_ASSERT(a_desc->buffer_index < SG_MAX_SHADERSTAGE_BUFFERS); #if defined(SOKOL_GLES2) /* on GLES2, vertex attribute names must be provided */ - SOKOL_VALIDATE((0 != a_desc->name), _SG_VALIDATE_PIPELINEDESC_ATTR_NAME); + SOKOL_VALIDATE(!_sg_strempty(&shd->attrs[attr_index].name), _SG_VALIDATE_PIPELINEDESC_ATTR_NAME); #elif defined(SOKOL_D3D11) /* on D3D11, semantic names (and semantic indices) must be provided */ - SOKOL_VALIDATE((0 != a_desc->sem_name), _SG_VALIDATE_PIPELINEDESC_ATTR_SEMANTICS); + SOKOL_VALIDATE(!_sg_strempty(&shd->attrs[attr_index].sem_name), _SG_VALIDATE_PIPELINEDESC_ATTR_SEMANTICS); #endif } return SOKOL_VALIDATE_END(); |