Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/cute_shader_bytecode.h
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,8 @@ typedef struct CF_ShaderInfo
int num_images;
/* @member Name of each images. */
const char** image_names;
/* @member Binding slot index of each image. */
const int* image_binding_slots;
Copy link
Contributor

@bullno1 bullno1 Aug 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I only meant the global variable generated by the shader compiler.
Because they get used by the static initializer later.
This doesn't have to be const.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It actually has to, as otherwise the generated values cannot be assigned to the struct member:

static const char** const s_backbuffer_fs_bytecode_image_names = NULL;
static const int* const s_backbuffer_fs_bytecode_image_binding_slots = NULL;
static CF_ShaderUniformInfo* const s_backbuffer_fs_bytecode_uniforms = NULL;
static CF_ShaderUniformMemberInfo* const s_backbuffer_fs_bytecode_uniform_members = NULL;
static CF_ShaderInputInfo* const s_backbuffer_fs_bytecode_inputs = NULL;
static const CF_ShaderBytecode s_backbuffer_fs_bytecode = {
    .content = s_backbuffer_fs_bytecode_content,
    .size = 408,
    .shader_info = {
        .num_samplers = 0,
        .num_storage_textures = 0,
        .num_storage_buffers = 0,
        .num_images = 0,
        .image_names = s_backbuffer_fs_bytecode_image_names,
        .image_binding_slots = s_backbuffer_fs_bytecode_image_binding_slots,
        .num_uniforms = 0,
        .uniforms = s_backbuffer_fs_bytecode_uniforms,
        .num_uniform_members = 0,
        .uniform_members = s_backbuffer_fs_bytecode_uniform_members,
        .num_inputs = 0,
        .inputs = s_backbuffer_fs_bytecode_inputs,
    },
};

This is what it's generated as: static const int* const s_backbuffer_fs_bytecode_image_binding_slots = NULL;

And here it's being assigned:

.image_binding_slots = s_backbuffer_fs_bytecode_image_binding_slots,

So unless there's a better way of doing it, it has to stay as is?

Copy link
Contributor

@bullno1 bullno1 Aug 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean the problem is not in the generated code.

The declaration in the struct member does not have to be const int*.
It can just be int* image_binding_slots.

It's only const int* const in the generated code because some compilers in C mode complains that static initializer has to be constant expression.


/* @member Number of uniform blocks. */
int num_uniforms;
Expand Down
18 changes: 14 additions & 4 deletions src/cute_graphics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,7 @@ static SDL_GPUShader* s_compile(CF_ShaderInternal* shader_internal, CF_ShaderByt

for (int i = 0; i < shader_info->num_images; ++i) {
shader_internal->image_names.add(sintern(shader_info->image_names[i]));
shader_internal->image_binding_slots.add(shader_info->image_binding_slots[i]);
}

if (stage == CF_SHADER_STAGE_VERTEX) {
Expand Down Expand Up @@ -1468,20 +1469,29 @@ void cf_apply_shader(CF_Shader shader_handle, CF_Material material_handle)

// Bind images to all their respective slots.
int sampler_count = shader->image_names.count();
SDL_GPUTextureSamplerBinding* sampler_bindings = SDL_stack_alloc(SDL_GPUTextureSamplerBinding, sampler_count);
int max_binding_slot = 0;
// Find the maximum binding slot to allocate the correct size array
for (int i = 0; i < shader->image_binding_slots.size(); ++i) {
if (shader->image_binding_slots[i] > max_binding_slot) {
max_binding_slot = shader->image_binding_slots[i];
}
}
SDL_GPUTextureSamplerBinding* sampler_bindings = SDL_stack_alloc(SDL_GPUTextureSamplerBinding, max_binding_slot + 1);
CF_MEMSET(sampler_bindings, 0, sizeof(SDL_GPUTextureSamplerBinding) * (max_binding_slot + 1));
int found_image_count = 0;
for (int i = 0; found_image_count < sampler_count && i < material->fs.textures.count(); ++i) {
const char* image_name = material->fs.textures[i].name;
for (int j = 0; j < shader->image_names.size(); ++j) {
if (shader->image_names[j] == image_name) {
sampler_bindings[j].sampler = ((CF_TextureInternal*)material->fs.textures[i].handle.id)->sampler;
sampler_bindings[j].texture = ((CF_TextureInternal*)material->fs.textures[i].handle.id)->tex;
int binding_slot = shader->image_binding_slots[j];
sampler_bindings[binding_slot].sampler = ((CF_TextureInternal*)material->fs.textures[i].handle.id)->sampler;
sampler_bindings[binding_slot].texture = ((CF_TextureInternal*)material->fs.textures[i].handle.id)->tex;
found_image_count++;
}
}
}
CF_ASSERT(found_image_count == sampler_count);
SDL_BindGPUFragmentSamplers(pass, 0, sampler_bindings, (Uint32)found_image_count);
SDL_BindGPUFragmentSamplers(pass, 0, sampler_bindings, (Uint32)(max_binding_slot + 1));

// Copy over uniform data.
s_copy_uniforms(cmd, &material->block_arena, shader, &material->vs, true);
Expand Down
7 changes: 7 additions & 0 deletions src/cute_shader/cute_shader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -369,9 +369,11 @@ CF_ShaderCompilerResult cute_shader_compile(const char* source, CF_ShaderCompile
int num_uniform_members;
CF_ShaderUniformMemberInfo* uniform_members = NULL;
uint32_t num_inputs = 0;
int* image_binding_slots = NULL;
CF_ShaderInputInfo* inputs = NULL;
{
std::vector<const char*> image_names_vec;
std::vector<int> image_binding_slots_vec;
std::vector<CF_ShaderUniformInfo> uniforms_vec;
std::vector<CF_ShaderUniformMemberInfo> uniform_members_vec;

Expand All @@ -389,6 +391,7 @@ CF_ShaderCompilerResult cute_shader_compile(const char* source, CF_ShaderCompile
case SPV_REFLECT_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER:
{
image_names_vec.push_back(strdup(binding->name));
image_binding_slots_vec.push_back(binding->binding);
} // Fall-thru.
case SPV_REFLECT_DESCRIPTOR_TYPE_SAMPLER: ++num_samplers; break;
case SPV_REFLECT_DESCRIPTOR_TYPE_STORAGE_IMAGE: ++num_storage_textures; break;
Expand Down Expand Up @@ -432,6 +435,8 @@ CF_ShaderCompilerResult cute_shader_compile(const char* source, CF_ShaderCompile
if (num_images > 0) {
image_names = (const char**)malloc(sizeof(char*) * num_images);
memcpy(image_names, image_names_vec.data(), sizeof(char*) * num_images);
image_binding_slots = (int*)malloc(sizeof(int) * num_images);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be freed in cute_shader_free_result

memcpy(image_binding_slots, image_binding_slots_vec.data(), sizeof(int) * num_images);
}

num_uniforms = (int)uniforms_vec.size();
Expand Down Expand Up @@ -480,6 +485,7 @@ CF_ShaderCompilerResult cute_shader_compile(const char* source, CF_ShaderCompile

.num_images = num_images,
.image_names = image_names,
.image_binding_slots = image_binding_slots,

.num_uniforms = num_uniforms,
.uniforms = uniforms,
Expand Down Expand Up @@ -520,6 +526,7 @@ void cute_shader_free_result(CF_ShaderCompilerResult result)
free((char*)shader_info->image_names[i]);
}
free(shader_info->image_names);
free((int*)shader_info->image_binding_slots);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So the cast to free is not necessary if it wasn't const in the struct in the first place.


free((void*)result.bytecode.content);
free((char*)result.preprocessed_source);
Expand Down
7 changes: 7 additions & 0 deletions src/cute_shader/cute_shaderc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,8 +106,14 @@ static bool write_bytecode_struct(
fprintf(file, " \"%s\",", shader_info->image_names[i]);
}
fprintf(file, "\n};\n");
fprintf(file, "static const int %s%s_image_binding_slots[%d] = {\n ", var_name, suffix, shader_info->num_images);
for (int i = 0; i < shader_info->num_images; ++i) {
fprintf(file, " %d,", shader_info->image_binding_slots[i]);
}
fprintf(file, "\n};\n");
} else {
fprintf(file, "static const char** const %s%s_image_names = NULL;\n", var_name, suffix);
fprintf(file, "static const int* const %s%s_image_binding_slots = NULL;\n", var_name, suffix);
}

if (shader_info->num_uniforms > 0) {
Expand Down Expand Up @@ -164,6 +170,7 @@ static bool write_bytecode_struct(
fprintf(file, " .num_storage_buffers = %d,\n", shader_info->num_storage_buffers);
fprintf(file, " .num_images = %d,\n", shader_info->num_images);
fprintf(file, " .image_names = %s%s_image_names,\n", var_name, suffix);
fprintf(file, " .image_binding_slots = %s%s_image_binding_slots,\n", var_name, suffix);
fprintf(file, " .num_uniforms = %d,\n", shader_info->num_uniforms);
fprintf(file, " .uniforms = %s%s_uniforms,\n", var_name, suffix);
fprintf(file, " .num_uniform_members = %d,\n", shader_info->num_uniform_members);
Expand Down
20 changes: 20 additions & 0 deletions src/data/builtin_shaders_bytecode.h
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ static const uint8_t s_draw_vs_bytecode_content[3176] = {
0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};
static const char** const s_draw_vs_bytecode_image_names = NULL;
static const int* const s_draw_vs_bytecode_image_binding_slots = NULL;
static CF_ShaderUniformInfo* const s_draw_vs_bytecode_uniforms = NULL;
static CF_ShaderUniformMemberInfo* const s_draw_vs_bytecode_uniform_members = NULL;
static CF_ShaderInputInfo s_draw_vs_bytecode_inputs[14] = {
Expand Down Expand Up @@ -348,6 +349,7 @@ static const CF_ShaderBytecode s_draw_vs_bytecode = {
.num_storage_buffers = 0,
.num_images = 0,
.image_names = s_draw_vs_bytecode_image_names,
.image_binding_slots = s_draw_vs_bytecode_image_binding_slots,
.num_uniforms = 0,
.uniforms = s_draw_vs_bytecode_uniforms,
.num_uniform_members = 0,
Expand Down Expand Up @@ -1972,6 +1974,9 @@ static const uint8_t s_draw_fs_bytecode_content[20720] = {
static const char* s_draw_fs_bytecode_image_names[1] = {
"u_image",
};
static const int s_draw_fs_bytecode_image_binding_slots[1] = {
0,
};
static CF_ShaderUniformInfo s_draw_fs_bytecode_uniforms[1] = {
{
.block_name = "uniform_block",
Expand Down Expand Up @@ -2004,6 +2009,7 @@ static const CF_ShaderBytecode s_draw_fs_bytecode = {
.num_storage_buffers = 0,
.num_images = 1,
.image_names = s_draw_fs_bytecode_image_names,
.image_binding_slots = s_draw_fs_bytecode_image_binding_slots,
.num_uniforms = 1,
.uniforms = s_draw_fs_bytecode_uniforms,
.num_uniform_members = 2,
Expand Down Expand Up @@ -2084,6 +2090,7 @@ static const uint8_t s_basic_vs_bytecode_content[896] = {
0x1A, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};
static const char** const s_basic_vs_bytecode_image_names = NULL;
static const int* const s_basic_vs_bytecode_image_binding_slots = NULL;
static CF_ShaderUniformInfo* const s_basic_vs_bytecode_uniforms = NULL;
static CF_ShaderUniformMemberInfo* const s_basic_vs_bytecode_uniform_members = NULL;
static CF_ShaderInputInfo s_basic_vs_bytecode_inputs[1] = {
Expand All @@ -2102,6 +2109,7 @@ static const CF_ShaderBytecode s_basic_vs_bytecode = {
.num_storage_buffers = 0,
.num_images = 0,
.image_names = s_basic_vs_bytecode_image_names,
.image_binding_slots = s_basic_vs_bytecode_image_binding_slots,
.num_uniforms = 0,
.uniforms = s_basic_vs_bytecode_uniforms,
.num_uniform_members = 0,
Expand Down Expand Up @@ -2152,6 +2160,7 @@ static const uint8_t s_basic_fs_bytecode_content[408] = {
0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};
static const char** const s_basic_fs_bytecode_image_names = NULL;
static const int* const s_basic_fs_bytecode_image_binding_slots = NULL;
static CF_ShaderUniformInfo* const s_basic_fs_bytecode_uniforms = NULL;
static CF_ShaderUniformMemberInfo* const s_basic_fs_bytecode_uniform_members = NULL;
static CF_ShaderInputInfo* const s_basic_fs_bytecode_inputs = NULL;
Expand All @@ -2164,6 +2173,7 @@ static const CF_ShaderBytecode s_basic_fs_bytecode = {
.num_storage_buffers = 0,
.num_images = 0,
.image_names = s_basic_fs_bytecode_image_names,
.image_binding_slots = s_basic_fs_bytecode_image_binding_slots,
.num_uniforms = 0,
.uniforms = s_basic_fs_bytecode_uniforms,
.num_uniform_members = 0,
Expand Down Expand Up @@ -2244,6 +2254,7 @@ static const uint8_t s_backbuffer_vs_bytecode_content[896] = {
0x1A, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};
static const char** const s_backbuffer_vs_bytecode_image_names = NULL;
static const int* const s_backbuffer_vs_bytecode_image_binding_slots = NULL;
static CF_ShaderUniformInfo* const s_backbuffer_vs_bytecode_uniforms = NULL;
static CF_ShaderUniformMemberInfo* const s_backbuffer_vs_bytecode_uniform_members = NULL;
static CF_ShaderInputInfo s_backbuffer_vs_bytecode_inputs[1] = {
Expand All @@ -2262,6 +2273,7 @@ static const CF_ShaderBytecode s_backbuffer_vs_bytecode = {
.num_storage_buffers = 0,
.num_images = 0,
.image_names = s_backbuffer_vs_bytecode_image_names,
.image_binding_slots = s_backbuffer_vs_bytecode_image_binding_slots,
.num_uniforms = 0,
.uniforms = s_backbuffer_vs_bytecode_uniforms,
.num_uniform_members = 0,
Expand Down Expand Up @@ -2312,6 +2324,7 @@ static const uint8_t s_backbuffer_fs_bytecode_content[408] = {
0xFD, 0x00, 0x01, 0x00, 0x38, 0x00, 0x01, 0x00,
};
static const char** const s_backbuffer_fs_bytecode_image_names = NULL;
static const int* const s_backbuffer_fs_bytecode_image_binding_slots = NULL;
static CF_ShaderUniformInfo* const s_backbuffer_fs_bytecode_uniforms = NULL;
static CF_ShaderUniformMemberInfo* const s_backbuffer_fs_bytecode_uniform_members = NULL;
static CF_ShaderInputInfo* const s_backbuffer_fs_bytecode_inputs = NULL;
Expand All @@ -2324,6 +2337,7 @@ static const CF_ShaderBytecode s_backbuffer_fs_bytecode = {
.num_storage_buffers = 0,
.num_images = 0,
.image_names = s_backbuffer_fs_bytecode_image_names,
.image_binding_slots = s_backbuffer_fs_bytecode_image_binding_slots,
.num_uniforms = 0,
.uniforms = s_backbuffer_fs_bytecode_uniforms,
.num_uniform_members = 0,
Expand Down Expand Up @@ -2448,6 +2462,7 @@ static const uint8_t s_blit_vs_bytecode_content[1412] = {
0x38, 0x00, 0x01, 0x00,
};
static const char** const s_blit_vs_bytecode_image_names = NULL;
static const int* const s_blit_vs_bytecode_image_binding_slots = NULL;
static CF_ShaderUniformInfo* const s_blit_vs_bytecode_uniforms = NULL;
static CF_ShaderUniformMemberInfo* const s_blit_vs_bytecode_uniform_members = NULL;
static CF_ShaderInputInfo s_blit_vs_bytecode_inputs[4] = {
Expand Down Expand Up @@ -2481,6 +2496,7 @@ static const CF_ShaderBytecode s_blit_vs_bytecode = {
.num_storage_buffers = 0,
.num_images = 0,
.image_names = s_blit_vs_bytecode_image_names,
.image_binding_slots = s_blit_vs_bytecode_image_binding_slots,
.num_uniforms = 0,
.uniforms = s_blit_vs_bytecode_uniforms,
.num_uniform_members = 0,
Expand Down Expand Up @@ -2731,6 +2747,9 @@ static const uint8_t s_blit_fs_bytecode_content[3052] = {
static const char* s_blit_fs_bytecode_image_names[1] = {
"u_image",
};
static const int s_blit_fs_bytecode_image_binding_slots[1] = {
0,
};
static CF_ShaderUniformInfo s_blit_fs_bytecode_uniforms[1] = {
{
.block_name = "uniform_block",
Expand Down Expand Up @@ -2763,6 +2782,7 @@ static const CF_ShaderBytecode s_blit_fs_bytecode = {
.num_storage_buffers = 0,
.num_images = 1,
.image_names = s_blit_fs_bytecode_image_names,
.image_binding_slots = s_blit_fs_bytecode_image_binding_slots,
.num_uniforms = 1,
.uniforms = s_blit_fs_bytecode_uniforms,
.num_uniform_members = 2,
Expand Down
1 change: 1 addition & 0 deletions src/internal/cute_graphics_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@ struct CF_ShaderInternal
Cute::Array<CF_UniformBlockMember> fs_uniform_block_members[CF_MAX_UNIFORM_BLOCK_COUNT];
Cute::Array<CF_UniformBlockMember> vs_uniform_block_members[CF_MAX_UNIFORM_BLOCK_COUNT];
Cute::Array<const char*> image_names;
Cute::Array<int> image_binding_slots;
Cute::Array<CF_Pipeline> pip_cache;

CF_INLINE int get_input_index(const char* name)
Expand Down