sokol: update sokol_gfx.h to the LAST version, and fix example 06 (#13100)

pull/13102/head
penguindark 2022-01-08 19:29:29 +01:00 committed by GitHub
parent 64c8fb061d
commit 22fce6a525
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 311 additions and 52 deletions

View File

@ -10,11 +10,11 @@ uniform vs_params {
in vec4 a_Position; // Per-vertex position information we will pass in.
in vec3 a_Normal; // Per-vertex normal information we will pass in.
in vec4 a_Color; // Per-vertex color information we will pass in.
//in vec4 a_Color; // Per-vertex color information we will pass in.
in vec2 a_Texcoord0;
out vec3 v_Position; // This will be passed into the fragment shader.
out vec4 v_Color; // This will be passed into the fragment shader.
//out vec4 v_Color; // This will be passed into the fragment shader.
out vec3 v_Normal; // This will be passed into the fragment shader.
out vec3 v_Normal1;
out vec2 uv; // This will be passed into the fragment shader.
@ -25,7 +25,7 @@ void main()
// Transform the vertex into eye space.
v_Position = vec3(u_MVMatrix * a_Position);
// Pass through the color.
v_Color = a_Color;
//v_Color = a_Color;
// calc eye space normal
v_Normal = vec3(u_NMatrix * vec4(a_Normal, 1.0));
// texture coord
@ -51,7 +51,7 @@ uniform fs_params {
};
in vec3 v_Position; // Interpolated position for this fragment.
in vec4 v_Color; // This is the color from the vertex shader interpolated across the triangle per fragment.
//in vec4 v_Color; // This is the color from the vertex shader interpolated across the triangle per fragment.
in vec3 v_Normal; // Interpolated normal for this fragment.
in vec3 v_Normal1;
in vec2 uv;

View File

@ -106,7 +106,7 @@ pub fn (mut obj_part ObjPart) create_pipeline(in_part []int, shader gfx.Shader,
// the constants [C.ATTR_vs_a_Position, C.ATTR_vs_a_Color, C.ATTR_vs_a_Texcoord0] are generated by sokol-shdc
pipdesc.layout.attrs[C.ATTR_vs_a_Position].format = .float3 // x,y,z as f32
pipdesc.layout.attrs[C.ATTR_vs_a_Normal].format = .float3 // x,y,z as f32
pipdesc.layout.attrs[C.ATTR_vs_a_Color].format = .ubyte4n // color as u32
// pipdesc.layout.attrs[C.ATTR_vs_a_Color].format = .ubyte4n // color as u32
pipdesc.layout.attrs[C.ATTR_vs_a_Texcoord0].format = .float2 // u,v as f32
// pipdesc.layout.attrs[C.ATTR_vs_a_Texcoord0].format = .short2n // u,v as u16
pipdesc.index_type = .uint32

View File

@ -129,7 +129,10 @@
--- optionally update shader uniform data with:
sg_apply_uniforms(sg_shader_stage stage, int ub_index, const void* data, int num_bytes)
sg_apply_uniforms(sg_shader_stage stage, int ub_index, const sg_range* data)
Read the section 'UNIFORM DATA LAYOUT' to learn about the expected memory layout
of the uniform data passed into sg_apply_uniforms().
--- kick off a draw call with:
@ -335,29 +338,128 @@
with context information provided by sokol_app.h
See the documention block of the sg_desc struct below for more information.
UNIFORM DATA LAYOUT:
====================
NOTE: if you use the sokol-shdc shader compiler tool, you don't need to worry
about the following details.
The data that's passed into the sg_apply_uniforms() function must adhere to
specific layout rules so that the GPU shader finds the uniform block
items at the right offset.
For the D3D11 and Metal backends, sokol-gfx only cares about the size of uniform
blocks, but not about the internal layout. The data will just be copied into
a uniform/constant buffer in a single operation and it's up you to arrange the
CPU-side layout so that it matches the GPU side layout. This also means that with
the D3D11 and Metal backends you are not limited to a 'cross-platform' subset
of uniform variable types.
If you ever only use one of the D3D11, Metal *or* WebGPU backend, you can stop reading here.
For the GL backends, the internal layout of uniform blocks matters though,
and you are limited to a small number of uniform variable types. This is
because sokol-gfx must be able to locate the uniform block members in order
to upload them to the GPU with glUniformXXX() calls.
To describe the uniform block layout to sokol-gfx, the following information
must be passed to the sg_make_shader() call in the sg_shader_desc struct:
- a hint about the used packing rule (either SG_UNIFORMLAYOUT_NATIVE or
SG_UNIFORMLAYOUT_STD140)
- a list of the uniform block members types in the correct order they
appear on the CPU side
For example if the GLSL shader has the following uniform declarations:
uniform mat4 mvp;
uniform vec2 offset0;
uniform vec2 offset1;
uniform vec2 offset2;
...and on the CPU side, there's a similar C struct:
typedef struct {
float mvp[16];
float offset0[2];
float offset1[2];
float offset2[2];
} params_t;
...the uniform block description in the sg_shader_desc must look like this:
sg_shader_desc desc = {
.vs.uniform_blocks[0] = {
.size = sizeof(params_t),
.layout = SG_UNIFORMLAYOUT_NATIVE, // this is the default and can be omitted
.uniforms = {
// order must be the same as in 'params_t':
[0] = { .name = "mvp", .type = SG_UNIFORMTYPE_MAT4 },
[1] = { .name = "offset0", .type = SG_UNIFORMTYPE_VEC2 },
[2] = { .name = "offset1", .type = SG_UNIFORMTYPE_VEC2 },
[3] = { .name = "offset2", .type = SG_UNIFORMTYPE_VEC2 },
}
}
};
With this information sokol-gfx can now compute the correct offsets of the data items
within the uniform block struct.
The SG_UNIFORMLAYOUT_NATIVE packing rule works fine if only the GL backends are used,
but for proper D3D11/Metal/GL a subset of the std140 layout must be used which is
described in the next section:
CROSS-BACKEND COMMON UNIFORM DATA LAYOUT
========================================
For cross-platform / cross-3D-backend code it is important that the same uniform block
layout on the CPU side can be used for all sokol-gfx backends. To achieve this,
a common subset of the std140 layout must be used:
- The uniform block layout hint in sg_shader_desc must be explicitely set to
SG_UNIFORMLAYOUT_STD140.
- Only the following GLSL uniform types can be used (with their associated sokol-gfx enums):
- float => SG_UNIFORMTYPE_FLOAT
- vec2 => SG_UNIFORMTYPE_FLOAT2
- vec3 => SG_UNIFORMTYPE_FLOAT3
- vec4 => SG_UNIFORMTYPE_FLOAT4
- int => SG_UNIFORMTYPE_INT
- ivec2 => SG_UNIFORMTYPE_INT2
- ivec3 => SG_UNIFORMTYPE_INT3
- ivec4 => SG_UNIFORMTYPE_INT4
- mat4 => SG_UNIFORMTYPE_MAT4
- Alignment for those types must be as follows (in bytes):
- float => 4
- vec2 => 8
- vec3 => 16
- vec4 => 16
- int => 4
- ivec2 => 8
- ivec3 => 16
- ivec4 => 16
- mat4 => 16
- Arrays are only allowed for the following types: vec4, int4, mat4.
Note that the HLSL cbuffer layout rules are slightly different from the
std140 layout rules, this means that the cbuffer declarations in HLSL code
must be tweaked so that the layout is compatible with std140.
The by far easiest way to tacke the common uniform block layout problem is
to use the sokol-shdc shader cross-compiler tool!
BACKEND-SPECIFIC TOPICS:
========================
--- the GL backends need to know about the internal structure of uniform
blocks, and the texture sampler-name and -type:
typedef struct {
float mvp[16]; // model-view-projection matrix
float offset0[2]; // some 2D vectors
float offset1[2];
float offset2[2];
} params_t;
--- The GL backends need to know about the internal structure of uniform
blocks, and the texture sampler-name and -type. The uniform layout details
are described in the UNIFORM DATA LAYOUT section above.
// uniform block structure and texture image definition in sg_shader_desc:
sg_shader_desc desc = {
// uniform block description (size and internal structure)
.vs.uniform_blocks[0] = {
.size = sizeof(params_t),
.uniforms = {
[0] = { .name="mvp", .type=SG_UNIFORMTYPE_MAT4 },
[1] = { .name="offset0", .type=SG_UNIFORMTYPE_VEC2 },
...
}
...
},
// one texture on the fragment-shader-stage, GLES2/WebGL needs name and image type
.fs.images[0] = { .name="tex", .type=SG_IMAGETYPE_ARRAY }
@ -1208,11 +1310,57 @@ typedef enum sg_uniform_type {
SG_UNIFORMTYPE_FLOAT2,
SG_UNIFORMTYPE_FLOAT3,
SG_UNIFORMTYPE_FLOAT4,
SG_UNIFORMTYPE_INT,
SG_UNIFORMTYPE_INT2,
SG_UNIFORMTYPE_INT3,
SG_UNIFORMTYPE_INT4,
SG_UNIFORMTYPE_MAT4,
_SG_UNIFORMTYPE_NUM,
_SG_UNIFORMTYPE_FORCE_U32 = 0x7FFFFFFF
} sg_uniform_type;
/*
sg_uniform_layout
A hint for the interior memory layout of uniform blocks. This is
only really relevant for the GL backend where the internal layout
of uniform blocks must be known to sokol-gfx. For all other backends the
internal memory layout of uniform blocks doesn't matter, sokol-gfx
will just pass uniform data as a single memory blob to the
3D backend.
SG_UNIFORMLAYOUT_NATIVE (default)
Native layout means that a 'backend-native' memory layout
is used. For the GL backend this means that uniforms
are packed tightly in memory (e.g. there are no padding
bytes).
SG_UNIFORMLAYOUT_STD140
The memory layout is a subset of std140. Arrays are only
allowed for the FLOAT4, INT4 and MAT4. Alignment is as
is as follows:
FLOAT, INT: 4 byte alignment
FLOAT2, INT2: 8 byte alignment
FLOAT3, INT3: 16 byte alignment(!)
FLOAT4, INT4: 16 byte alignment
MAT4: 16 byte alignment
FLOAT4[], INT4[]: 16 byte alignment
The overall size of the uniform block must be a multiple
of 16.
For more information search for 'UNIFORM DATA LAYOUT' in the documentation block
at the start of the header.
*/
typedef enum sg_uniform_layout {
_SG_UNIFORMLAYOUT_DEFAULT, /* value 0 reserved for default-init */
SG_UNIFORMLAYOUT_NATIVE, /* default: layout depends on currently active backend */
SG_UNIFORMLAYOUT_STD140, /* std140: memory layout according to std140 */
_SG_UNIFORMLAYOUT_NUM,
_SG_UNIFORMLAYOUT_FORCE_U32 = 0x7FFFFFFF
} sg_uniform_layout;
/*
sg_cull_mode
@ -1714,6 +1862,7 @@ typedef struct sg_image_desc {
defaults are "vs_4_0" and "ps_4_0")
- reflection info for each uniform block used by the shader stage:
- the size of the uniform block in bytes
- a memory layout hint (native vs std140, only required for GL backends)
- reflection info for each uniform block member (only required for GL backends):
- member name
- member type (SG_UNIFORMTYPE_xxx)
@ -1746,6 +1895,7 @@ typedef struct sg_shader_uniform_desc {
typedef struct sg_shader_uniform_block_desc {
size_t size;
sg_uniform_layout layout;
sg_shader_uniform_desc uniforms[SG_MAX_UB_MEMBERS];
} sg_shader_uniform_block_desc;
@ -3945,6 +4095,8 @@ typedef enum {
_SG_VALIDATE_SHADERDESC_NO_UB_MEMBERS,
_SG_VALIDATE_SHADERDESC_UB_MEMBER_NAME,
_SG_VALIDATE_SHADERDESC_UB_SIZE_MISMATCH,
_SG_VALIDATE_SHADERDESC_UB_ARRAY_COUNT,
_SG_VALIDATE_SHADERDESC_UB_STD140_ARRAY_TYPE,
_SG_VALIDATE_SHADERDESC_IMG_NAME,
_SG_VALIDATE_SHADERDESC_ATTR_NAMES,
_SG_VALIDATE_SHADERDESC_ATTR_SEMANTICS,
@ -4090,6 +4242,11 @@ _SOKOL_PRIVATE void _sg_strcpy(_sg_str_t* dst, const char* src) {
}
}
_SOKOL_PRIVATE uint32_t _sg_align_u32(uint32_t val, uint32_t align) {
SOKOL_ASSERT((align > 0) && ((align & (align - 1)) == 0));
return (val + (align - 1)) & ~(align - 1);
}
/* return byte size of a vertex format */
_SOKOL_PRIVATE int _sg_vertexformat_bytesize(sg_vertex_format fmt) {
switch (fmt) {
@ -4115,18 +4272,78 @@ _SOKOL_PRIVATE int _sg_vertexformat_bytesize(sg_vertex_format fmt) {
}
}
/* return the byte size of a shader uniform */
_SOKOL_PRIVATE int _sg_uniform_size(sg_uniform_type type, int count) {
switch (type) {
case SG_UNIFORMTYPE_INVALID: return 0;
case SG_UNIFORMTYPE_FLOAT: return 4 * count;
case SG_UNIFORMTYPE_FLOAT2: return 8 * count;
case SG_UNIFORMTYPE_FLOAT3: return 12 * count; /* FIXME: std140??? */
case SG_UNIFORMTYPE_FLOAT4: return 16 * count;
case SG_UNIFORMTYPE_MAT4: return 64 * count;
default:
SOKOL_UNREACHABLE;
return -1;
_SOKOL_PRIVATE uint32_t _sg_uniform_alignment(sg_uniform_type type, int array_count, sg_uniform_layout ub_layout) {
if (ub_layout == SG_UNIFORMLAYOUT_NATIVE) {
return 1;
}
else {
SOKOL_ASSERT(array_count > 0);
if (array_count == 1) {
switch (type) {
case SG_UNIFORMTYPE_FLOAT:
case SG_UNIFORMTYPE_INT:
return 4;
case SG_UNIFORMTYPE_FLOAT2:
case SG_UNIFORMTYPE_INT2:
return 8;
case SG_UNIFORMTYPE_FLOAT3:
case SG_UNIFORMTYPE_FLOAT4:
case SG_UNIFORMTYPE_INT3:
case SG_UNIFORMTYPE_INT4:
return 16;
case SG_UNIFORMTYPE_MAT4:
return 16;
default:
SOKOL_UNREACHABLE;
return 1;
}
}
else {
return 16;
}
}
}
_SOKOL_PRIVATE uint32_t _sg_uniform_size(sg_uniform_type type, int array_count) {
SOKOL_ASSERT(array_count > 0);
if (array_count == 1) {
switch (type) {
case SG_UNIFORMTYPE_FLOAT:
case SG_UNIFORMTYPE_INT:
return 4;
case SG_UNIFORMTYPE_FLOAT2:
case SG_UNIFORMTYPE_INT2:
return 8;
case SG_UNIFORMTYPE_FLOAT3:
case SG_UNIFORMTYPE_INT3:
return 12;
case SG_UNIFORMTYPE_FLOAT4:
case SG_UNIFORMTYPE_INT4:
return 16;
case SG_UNIFORMTYPE_MAT4:
return 64;
default:
SOKOL_UNREACHABLE;
return 0;
}
}
else {
switch (type) {
case SG_UNIFORMTYPE_FLOAT:
case SG_UNIFORMTYPE_FLOAT2:
case SG_UNIFORMTYPE_FLOAT3:
case SG_UNIFORMTYPE_FLOAT4:
case SG_UNIFORMTYPE_INT:
case SG_UNIFORMTYPE_INT2:
case SG_UNIFORMTYPE_INT3:
case SG_UNIFORMTYPE_INT4:
return 16 * (uint32_t)array_count;
case SG_UNIFORMTYPE_MAT4:
return 64 * (uint32_t)array_count;
default:
SOKOL_UNREACHABLE;
return 0;
}
}
}
@ -4685,8 +4902,15 @@ _SOKOL_PRIVATE void _sg_dummy_update_image(_sg_image_t* img, const sg_image_data
_SG_XMACRO(glClearBufferuiv, void, (GLenum buffer, GLint drawbuffer, const GLuint * value)) \
_SG_XMACRO(glClearBufferiv, void, (GLenum buffer, GLint drawbuffer, const GLint * value)) \
_SG_XMACRO(glDeleteRenderbuffers, void, (GLsizei n, const GLuint * renderbuffers)) \
_SG_XMACRO(glUniform4fv, void, (GLint location, GLsizei count, const GLfloat * value)) \
_SG_XMACRO(glUniform1fv, void, (GLint location, GLsizei count, const GLfloat * value)) \
_SG_XMACRO(glUniform2fv, void, (GLint location, GLsizei count, const GLfloat * value)) \
_SG_XMACRO(glUniform3fv, void, (GLint location, GLsizei count, const GLfloat * value)) \
_SG_XMACRO(glUniform4fv, void, (GLint location, GLsizei count, const GLfloat * value)) \
_SG_XMACRO(glUniform1iv, void, (GLint location, GLsizei count, const GLint * value)) \
_SG_XMACRO(glUniform2iv, void, (GLint location, GLsizei count, const GLint * value)) \
_SG_XMACRO(glUniform3iv, void, (GLint location, GLsizei count, const GLint * value)) \
_SG_XMACRO(glUniform4iv, void, (GLint location, GLsizei count, const GLint * value)) \
_SG_XMACRO(glUniformMatrix4fv, void, (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)) \
_SG_XMACRO(glUseProgram, void, (GLuint program)) \
_SG_XMACRO(glShaderSource, void, (GLuint shader, GLsizei count, const GLchar *const* string, const GLint * length)) \
_SG_XMACRO(glLinkProgram, void, (GLuint program)) \
@ -4711,7 +4935,6 @@ _SOKOL_PRIVATE void _sg_dummy_update_image(_sg_image_t* img, const sg_image_data
_SG_XMACRO(glCompressedTexImage3D, void, (GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLint border, GLsizei imageSize, const void * data)) \
_SG_XMACRO(glActiveTexture, void, (GLenum texture)) \
_SG_XMACRO(glTexSubImage3D, void, (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint zoffset, GLsizei width, GLsizei height, GLsizei depth, GLenum format, GLenum type, const void * pixels)) \
_SG_XMACRO(glUniformMatrix4fv, void, (GLint location, GLsizei count, GLboolean transpose, const GLfloat * value)) \
_SG_XMACRO(glRenderbufferStorage, void, (GLenum target, GLenum internalformat, GLsizei width, GLsizei height)) \
_SG_XMACRO(glGenTextures, void, (GLsizei n, GLuint * textures)) \
_SG_XMACRO(glPolygonOffset, void, (GLfloat factor, GLfloat units)) \
@ -4742,7 +4965,6 @@ _SOKOL_PRIVATE void _sg_dummy_update_image(_sg_image_t* img, const sg_image_data
_SG_XMACRO(glDrawArraysInstanced, void, (GLenum mode, GLint first, GLsizei count, GLsizei instancecount)) \
_SG_XMACRO(glClearStencil, void, (GLint s)) \
_SG_XMACRO(glScissor, void, (GLint x, GLint y, GLsizei width, GLsizei height)) \
_SG_XMACRO(glUniform3fv, void, (GLint location, GLsizei count, const GLfloat * value)) \
_SG_XMACRO(glGenRenderbuffers, void, (GLsizei n, GLuint * renderbuffers)) \
_SG_XMACRO(glBufferData, void, (GLenum target, GLsizeiptr size, const void * data, GLenum usage)) \
_SG_XMACRO(glBlendFuncSeparate, void, (GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorAlpha, GLenum dfactorAlpha)) \
@ -4763,7 +4985,6 @@ _SOKOL_PRIVATE void _sg_dummy_update_image(_sg_image_t* img, const sg_image_data
_SG_XMACRO(glStencilFunc, void, (GLenum func, GLint ref, GLuint mask)) \
_SG_XMACRO(glEnableVertexAttribArray, void, (GLuint index)) \
_SG_XMACRO(glBlendFunc, void, (GLenum sfactor, GLenum dfactor)) \
_SG_XMACRO(glUniform1fv, void, (GLint location, GLsizei count, const GLfloat * value)) \
_SG_XMACRO(glReadBuffer, void, (GLenum src)) \
_SG_XMACRO(glReadPixels, void, (GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, void * data)) \
_SG_XMACRO(glClear, void, (GLbitfield mask)) \
@ -6490,17 +6711,20 @@ _SOKOL_PRIVATE sg_resource_state _sg_gl_create_shader(_sg_shader_t* shd, const s
SOKOL_ASSERT(ub_desc->size > 0);
_sg_gl_uniform_block_t* ub = &gl_stage->uniform_blocks[ub_index];
SOKOL_ASSERT(ub->num_uniforms == 0);
int cur_uniform_offset = 0;
uint32_t cur_uniform_offset = 0;
for (int u_index = 0; u_index < SG_MAX_UB_MEMBERS; u_index++) {
const sg_shader_uniform_desc* u_desc = &ub_desc->uniforms[u_index];
if (u_desc->type == SG_UNIFORMTYPE_INVALID) {
break;
}
const uint32_t u_align = _sg_uniform_alignment(u_desc->type, u_desc->array_count, ub_desc->layout);
const uint32_t u_size = _sg_uniform_size(u_desc->type, u_desc->array_count);
cur_uniform_offset = _sg_align_u32(cur_uniform_offset, u_align);
_sg_gl_uniform_t* u = &ub->uniforms[u_index];
u->type = u_desc->type;
u->count = (uint16_t) u_desc->array_count;
u->offset = (uint16_t) cur_uniform_offset;
cur_uniform_offset += _sg_uniform_size(u->type, u->count);
cur_uniform_offset += u_size;
if (u_desc->name) {
u->gl_loc = glGetUniformLocation(gl_prog, u_desc->name);
}
@ -7331,24 +7555,37 @@ _SOKOL_PRIVATE void _sg_gl_apply_uniforms(sg_shader_stage stage_index, int ub_in
if (u->gl_loc == -1) {
continue;
}
GLfloat* ptr = (GLfloat*) (((uint8_t*)data->ptr) + u->offset);
GLfloat* fptr = (GLfloat*) (((uint8_t*)data->ptr) + u->offset);
GLint* iptr = (GLint*) (((uint8_t*)data->ptr) + u->offset);
switch (u->type) {
case SG_UNIFORMTYPE_INVALID:
break;
case SG_UNIFORMTYPE_FLOAT:
glUniform1fv(u->gl_loc, u->count, ptr);
glUniform1fv(u->gl_loc, u->count, fptr);
break;
case SG_UNIFORMTYPE_FLOAT2:
glUniform2fv(u->gl_loc, u->count, ptr);
glUniform2fv(u->gl_loc, u->count, fptr);
break;
case SG_UNIFORMTYPE_FLOAT3:
glUniform3fv(u->gl_loc, u->count, ptr);
glUniform3fv(u->gl_loc, u->count, fptr);
break;
case SG_UNIFORMTYPE_FLOAT4:
glUniform4fv(u->gl_loc, u->count, ptr);
glUniform4fv(u->gl_loc, u->count, fptr);
break;
case SG_UNIFORMTYPE_INT:
glUniform1iv(u->gl_loc, u->count, iptr);
break;
case SG_UNIFORMTYPE_INT2:
glUniform2iv(u->gl_loc, u->count, iptr);
break;
case SG_UNIFORMTYPE_INT3:
glUniform3iv(u->gl_loc, u->count, iptr);
break;
case SG_UNIFORMTYPE_INT4:
glUniform4iv(u->gl_loc, u->count, iptr);
break;
case SG_UNIFORMTYPE_MAT4:
glUniformMatrix4fv(u->gl_loc, u->count, GL_FALSE, ptr);
glUniformMatrix4fv(u->gl_loc, u->count, GL_FALSE, fptr);
break;
default:
SOKOL_UNREACHABLE;
@ -13671,6 +13908,9 @@ _SOKOL_PRIVATE const char* _sg_validate_string(_sg_validate_error_t err) {
case _SG_VALIDATE_SHADERDESC_NO_UB_MEMBERS: return "GL backend requires uniform block member declarations";
case _SG_VALIDATE_SHADERDESC_UB_MEMBER_NAME: return "uniform block member name missing";
case _SG_VALIDATE_SHADERDESC_UB_SIZE_MISMATCH: return "size of uniform block members doesn't match uniform block size";
case _SG_VALIDATE_SHADERDESC_UB_ARRAY_COUNT: return "uniform array count must be >= 1";
case _SG_VALIDATE_SHADERDESC_UB_STD140_ARRAY_TYPE: return "uniform arrays only allowed for FLOAT4, INT4, MAT4 in std140 layout";
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";
@ -13960,8 +14200,9 @@ _SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) {
const sg_shader_uniform_block_desc* ub_desc = &stage_desc->uniform_blocks[ub_index];
if (ub_desc->size > 0) {
SOKOL_VALIDATE(uniform_blocks_continuous, _SG_VALIDATE_SHADERDESC_NO_CONT_UBS);
#if defined(_SOKOL_ANY_GL)
bool uniforms_continuous = true;
int uniform_offset = 0;
uint32_t uniform_offset = 0;
int num_uniforms = 0;
for (int u_index = 0; u_index < SG_MAX_UB_MEMBERS; u_index++) {
const sg_shader_uniform_desc* u_desc = &ub_desc->uniforms[u_index];
@ -13971,19 +14212,28 @@ _SOKOL_PRIVATE bool _sg_validate_shader_desc(const sg_shader_desc* desc) {
SOKOL_VALIDATE(0 != u_desc->name, _SG_VALIDATE_SHADERDESC_UB_MEMBER_NAME);
#endif
const int array_count = u_desc->array_count;
uniform_offset += _sg_uniform_size(u_desc->type, array_count);
SOKOL_VALIDATE(array_count > 0, _SG_VALIDATE_SHADERDESC_UB_ARRAY_COUNT);
const uint32_t u_align = _sg_uniform_alignment(u_desc->type, array_count, ub_desc->layout);
const uint32_t u_size = _sg_uniform_size(u_desc->type, array_count);
uniform_offset = _sg_align_u32(uniform_offset, u_align);
uniform_offset += u_size;
num_uniforms++;
// with std140, arrays are only allowed for FLOAT4, INT4, MAT4
if (ub_desc->layout == SG_UNIFORMLAYOUT_STD140) {
if (array_count > 1) {
SOKOL_VALIDATE((u_desc->type == SG_UNIFORMTYPE_FLOAT4) || (u_desc->type == SG_UNIFORMTYPE_INT4) || (u_desc->type == SG_UNIFORMTYPE_MAT4), _SG_VALIDATE_SHADERDESC_UB_STD140_ARRAY_TYPE);
}
}
}
else {
uniforms_continuous = false;
}
}
#if defined(SOKOL_GLCORE33) || defined(SOKOL_GLES2) || defined(SOKOL_GLES3)
if (ub_desc->layout == SG_UNIFORMLAYOUT_STD140) {
uniform_offset = _sg_align_u32(uniform_offset, 16);
}
SOKOL_VALIDATE((size_t)uniform_offset == ub_desc->size, _SG_VALIDATE_SHADERDESC_UB_SIZE_MISMATCH);
SOKOL_VALIDATE(num_uniforms > 0, _SG_VALIDATE_SHADERDESC_NO_UB_MEMBERS);
#else
_SOKOL_UNUSED(uniform_offset);
_SOKOL_UNUSED(num_uniforms);
#endif
}
else {
@ -14425,6 +14675,7 @@ _SOKOL_PRIVATE sg_shader_desc _sg_shader_desc_defaults(const sg_shader_desc* des
if (0 == ub_desc->size) {
break;
}
ub_desc->layout = _sg_def(ub_desc->layout, SG_UNIFORMLAYOUT_NATIVE);
for (int u_index = 0; u_index < SG_MAX_UB_MEMBERS; u_index++) {
sg_shader_uniform_desc* u_desc = &ub_desc->uniforms[u_index];
if (u_desc->type == SG_UNIFORMTYPE_INVALID) {

View File

@ -297,3 +297,10 @@ pub enum Action {
dontcare
_num
}
pub enum UniformLayout {
uniformlayout_default = 0 // value 0 reserved for default-init
uniformlayout_native // default: layout depends on currently active backend
uniformlayout_std140 // std140: memory layout according to std140
_num
}

View File

@ -260,6 +260,7 @@ pub fn (mut desc ShaderStageDesc) set_image(index int, name string) ShaderStageD
struct C.sg_shader_uniform_block_desc {
pub mut:
size usize
layout UniformLayout
uniforms [16]ShaderUniformDesc
}