From c97117b91600342fda157166aecda923f3e90747 Mon Sep 17 00:00:00 2001 From: Christian Nieves Date: Mon, 15 Dec 2025 22:32:50 -0600 Subject: [PATCH 1/7] Null check --- src/backend_wgpu.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/backend_wgpu.c b/src/backend_wgpu.c index 0d4dd9367..a0523e3c1 100644 --- a/src/backend_wgpu.c +++ b/src/backend_wgpu.c @@ -669,6 +669,11 @@ void UpdateBindGroup(DescribedBindGroup *bg) { desc.entries = aswgpu; desc.entryCount = bg->entryCount; + if (bg->layout == NULL) { + TRACELOG(LOG_ERROR, "UpdateBindGroup: bind group layout is NULL. Skipping bind group creation."); + RL_FREE(aswgpu); + return; + } desc.layout = bg->layout->layout; bg->bindGroup = wgpuDeviceCreateBindGroup(GetDevice(), &desc); bg->needsUpdate = false; From 45481709e3c46aeb410392e99edf8ce8c18e490d Mon Sep 17 00:00:00 2001 From: Christian Nieves Date: Mon, 15 Dec 2025 22:41:32 -0600 Subject: [PATCH 2/7] Fix resource lifetime --- src/backend_wgpu.c | 29 +++++++++++++++++++++++++++-- src/raygpu.c | 13 ++++++++++++- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/src/backend_wgpu.c b/src/backend_wgpu.c index a0523e3c1..3c9e7e77d 100644 --- a/src/backend_wgpu.c +++ b/src/backend_wgpu.c @@ -710,6 +710,9 @@ void UpdateBindGroupEntry(DescribedBindGroup *bg, size_t index, ResourceDescript if (entry.textureView) { wgpuTextureViewAddRef((WGPUTextureView)entry.textureView); } + if (entry.sampler) { + wgpuSamplerAddRef((WGPUSampler)entry.sampler); + } if (bg->entries[index].buffer) { wgpuBufferRelease((WGPUBuffer)bg->entries[index].buffer); @@ -719,6 +722,10 @@ void UpdateBindGroupEntry(DescribedBindGroup *bg, size_t index, ResourceDescript wgpuTextureViewRelease((WGPUTextureView)bg->entries[index].textureView); bg->entries[index].textureView = 0; } + if (bg->entries[index].sampler) { + wgpuSamplerRelease((WGPUSampler)bg->entries[index].sampler); + bg->entries[index].sampler = 0; + } bg->entries[index] = entry; bg->descriptorHash ^= bgEntryHashRD(bg->entries[index]); @@ -2846,8 +2853,26 @@ EntryPointSet getEntryPointsSPIRV(const uint32_t *shaderSourceSPIRV, uint32_t wo } void UnloadBindGroup(DescribedBindGroup *bg) { - free(bg->entries); - wgpuBindGroupRelease((WGPUBindGroup)bg->bindGroup); + if (bg->entries) { + for (uint32_t i = 0; i < bg->entryCount; i++) { + if (bg->entries[i].buffer) { + wgpuBufferRelease((WGPUBuffer)bg->entries[i].buffer); + } + if (bg->entries[i].textureView) { + wgpuTextureViewRelease((WGPUTextureView)bg->entries[i].textureView); + } + if (bg->entries[i].sampler) { + wgpuSamplerRelease((WGPUSampler)bg->entries[i].sampler); + } + } + free(bg->entries); + } + if (bg->bindGroup) { + wgpuBindGroupRelease((WGPUBindGroup)bg->bindGroup); + } + bg->bindGroup = NULL; + bg->entries = NULL; + bg->entryCount = 0; } void UnloadBindGroupLayout(DescribedBindGroupLayout *bglayout) { free(bglayout->entries); diff --git a/src/raygpu.c b/src/raygpu.c index b23be9f75..9583c529d 100644 --- a/src/raygpu.c +++ b/src/raygpu.c @@ -2453,7 +2453,18 @@ DescribedBindGroup LoadBindGroup(const DescribedBindGroupLayout* bglayout, const DescribedBindGroup ret = {0}; if(entryCount > 0){ ret.entries = (ResourceDescriptor*)RL_CALLOC(entryCount, sizeof(ResourceDescriptor)); - memcpy(ret.entries, entries, entryCount * sizeof(ResourceDescriptor)); + for (uint32_t i = 0; i < entryCount; i++) { + ret.entries[i] = entries[i]; + if (entries[i].buffer) { + wgpuBufferAddRef((WGPUBuffer)entries[i].buffer); + } + if (entries[i].textureView) { + wgpuTextureViewAddRef((WGPUTextureView)entries[i].textureView); + } + if (entries[i].sampler) { + wgpuSamplerAddRef((WGPUSampler)entries[i].sampler); + } + } } ret.entryCount = entryCount; ret.layout = bglayout; From 8177b1b3a6d3a0d09f58c25baa5cc6b670d778a7 Mon Sep 17 00:00:00 2001 From: Christian Nieves Date: Mon, 15 Dec 2025 23:02:40 -0600 Subject: [PATCH 3/7] Prevent bind group leak on update --- src/backend_wgpu.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/backend_wgpu.c b/src/backend_wgpu.c index 3c9e7e77d..1fe1ac273 100644 --- a/src/backend_wgpu.c +++ b/src/backend_wgpu.c @@ -654,6 +654,10 @@ void UpdateBindGroup(DescribedBindGroup *bg) { // std::cout << "Updating bindgroup with " << bg->desc.entryCount << " entries" << std::endl; // std::cout << "Updating bindgroup with " << bg->desc.entries[1].binding << " entries" << std::endl; if (bg->needsUpdate) { + if (bg->bindGroup) { + wgpuBindGroupRelease((WGPUBindGroup)bg->bindGroup); + bg->bindGroup = NULL; + } WGPUBindGroupDescriptor desc = {0}; WGPUBindGroupEntry* aswgpu = (WGPUBindGroupEntry*)RL_CALLOC(bg->entryCount, sizeof(WGPUBindGroupEntry)); for (uint32_t i = 0; i < bg->entryCount; i++) { From b628ee7af027aa910f8bfa415c88f6b9d746aff2 Mon Sep 17 00:00:00 2001 From: Christian Nieves Date: Mon, 15 Dec 2025 23:53:56 -0600 Subject: [PATCH 4/7] Use correct binding idx --- src/backend_wgpu.c | 15 +++++++-------- src/raygpu.c | 12 +++++++++++- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/backend_wgpu.c b/src/backend_wgpu.c index 1fe1ac273..8d53d5596 100644 --- a/src/backend_wgpu.c +++ b/src/backend_wgpu.c @@ -1619,11 +1619,11 @@ void SetBindgroupUniformBufferData(DescribedBindGroup *bg, uint32_t index, const }; WGPUBuffer uniformBuffer = wgpuDeviceCreateBuffer((WGPUDevice)GetDevice(), &bufferDesc); wgpuQueueWriteBuffer((WGPUQueue)GetQueue(), uniformBuffer, 0, data, size); + // Use the existing binding index from the bind group layout if available + uint32_t bindingIdx = (bg->entries && index < bg->entryCount) ? bg->entries[index].binding : index; + const ResourceDescriptor entry = { - .binding = index, - .buffer = uniformBuffer, - .size = size, - }; + .binding = bindingIdx, .buffer = uniformBuffer, .size = size, .offset = 0, .sampler = 0, .textureView = 0}; UpdateBindGroupEntry(bg, index, entry); wgpuBufferRelease(uniformBuffer); @@ -1638,11 +1638,10 @@ void SetBindgroupStorageBufferData(DescribedBindGroup *bg, uint32_t index, const }; WGPUBuffer storageBuffer = wgpuDeviceCreateBuffer((WGPUDevice)GetDevice(), &bufferDesc); wgpuQueueWriteBuffer((WGPUQueue)GetQueue(), storageBuffer, 0, data, size); + uint32_t bindingIdx = (bg->entries && index < bg->entryCount) ? bg->entries[index].binding : index; + const ResourceDescriptor entry = { - .binding = index, - .buffer = storageBuffer, - .size = size, - }; + .binding = bindingIdx, .buffer = storageBuffer, .size = size, .offset = 0, .sampler = 0, .textureView = 0}; UpdateBindGroupEntry(bg, index, entry); diff --git a/src/raygpu.c b/src/raygpu.c index 9583c529d..26d54d45d 100644 --- a/src/raygpu.c +++ b/src/raygpu.c @@ -3671,18 +3671,28 @@ RGAPI ShaderImpl* GetShaderImplByID(uint32_t id){ RGAPI ShaderImpl* GetShaderImpl(Shader shader){ return GetShaderImplByID(shader.id); } + RGAPI uint32_t getNextShaderID_shc(){ if(nextShaderID_shc >= capacity_shc){ uint32_t newCapacity = capacity_shc * 2 + (capacity_shc == 0) * 8; ShaderImpl* newAllocatedShaderIDs_shc = (ShaderImpl*)RL_CALLOC(newCapacity, sizeof(ShaderImpl)); if(capacity_shc){ memcpy(newAllocatedShaderIDs_shc, allocatedShaderIDs_shc, capacity_shc * sizeof(ShaderImpl)); + + // Fixup self-referential pointers after move + for (uint32_t i = 0; i < capacity_shc; i++) { + ShaderImpl* oldPtr = allocatedShaderIDs_shc + i; + ShaderImpl* newPtr = newAllocatedShaderIDs_shc + i; + if (newPtr->bindGroup.layout == &oldPtr->bglayout) { + newPtr->bindGroup.layout = &newPtr->bglayout; + } + } } if(allocatedShaderIDs_shc){ RL_FREE(allocatedShaderIDs_shc); } capacity_shc = newCapacity; - allocatedShaderIDs_shc = newAllocatedShaderIDs_shc; + allocatedShaderIDs_shc = newAllocatedShaderIDs_shc; } return nextShaderID_shc++; } From 4ac852312fb0b2944be4f42fce501337f1e990c6 Mon Sep 17 00:00:00 2001 From: Christian Nieves Date: Mon, 15 Dec 2025 23:56:58 -0600 Subject: [PATCH 5/7] Safety checks --- src/backend_wgpu.c | 7 ++++--- src/internal_include/internals.h | 4 ++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/backend_wgpu.c b/src/backend_wgpu.c index 8d53d5596..f03794270 100644 --- a/src/backend_wgpu.c +++ b/src/backend_wgpu.c @@ -259,8 +259,10 @@ void BindShaderWithSettings(Shader shader, PrimitiveType drawMode, RenderSetting impl->state.settings = settings; impl->state.colorAttachmentState = GetActiveRenderPass()->colorAttachmentState; WGPURenderPipeline activePipeline = PipelineHashMap_getOrCreate(&impl->pipelineCache, &impl->state, &impl->shaderModule, &impl->bglayout, &impl->layout); - wgpuRenderPassEncoderSetPipeline(g_renderstate.activeRenderpass->rpEncoder, activePipeline); - wgpuRenderPassEncoderSetBindGroup(g_renderstate.activeRenderpass->rpEncoder, 0, UpdateAndGetNativeBindGroup(&impl->bindGroup), 0, NULL); + if (activePipeline) { + wgpuRenderPassEncoderSetPipeline(g_renderstate.activeRenderpass->rpEncoder, activePipeline); + wgpuRenderPassEncoderSetBindGroup(g_renderstate.activeRenderpass->rpEncoder, 0, UpdateAndGetNativeBindGroup(&impl->bindGroup), 0, NULL); + } } void BindShader(Shader shader, PrimitiveType drawMode) { @@ -1611,7 +1613,6 @@ DescribedSampler LoadSamplerEx(TextureWrap amode, TextureFilter fmode, TextureFi return ret; } void SetBindgroupUniformBufferData(DescribedBindGroup *bg, uint32_t index, const void *data, size_t size) { - const WGPUBufferDescriptor bufferDesc = { .size = size, .usage = WGPUBufferUsage_CopySrc | WGPUBufferUsage_CopyDst | WGPUBufferUsage_Uniform, diff --git a/src/internal_include/internals.h b/src/internal_include/internals.h index bea17811f..689a169f5 100644 --- a/src/internal_include/internals.h +++ b/src/internal_include/internals.h @@ -866,6 +866,10 @@ static WGPURenderPipeline PipelineHashMap_getOrCreate(PipelineHashMap* cacheMap, } else{ WGPURenderPipeline toEmplace = createSingleRenderPipe(mst, shaderModule, bglayout, pllayout); + if (!toEmplace) { + TRACELOG(LOG_ERROR, "Failed to create render pipeline, likely due to a shader compilation/translation error."); + return NULL; + } PipelineHashMap_put(cacheMap, *mst, toEmplace); return toEmplace; } From ac7c85813636b7fbe6aed5c785755f5e5c245f7b Mon Sep 17 00:00:00 2001 From: Christian Nieves Date: Wed, 17 Dec 2025 02:03:42 -0600 Subject: [PATCH 6/7] Assign default bind group entries(yay fixes crash) --- src/backend_wgpu.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/backend_wgpu.c b/src/backend_wgpu.c index f03794270..4023f3126 100644 --- a/src/backend_wgpu.c +++ b/src/backend_wgpu.c @@ -671,6 +671,20 @@ void UpdateBindGroup(DescribedBindGroup *bg) { to->size = from->size; to->sampler = from->sampler; to->textureView = from->textureView; + + if(bg->layout && bg->layout->entries){ + if(to->sampler == NULL && bg->layout->entries[i].type == texture_sampler){ + to->sampler = (WGPUSampler)g_renderstate.defaultSampler.sampler; + } + if(to->textureView == NULL && bg->layout->entries[i].type == texture2d){ + to->textureView = (WGPUTextureView)g_renderstate.whitePixel.view; + } + if(to->buffer == NULL && (bg->layout->entries[i].type == uniform_buffer || bg->layout->entries[i].type == storage_buffer)){ + to->buffer = (WGPUBuffer)g_renderstate.identityMatrix->buffer; + to->offset = 0; + to->size = 64; // sizeof(Matrix) + } + } } desc.entries = aswgpu; From df51058cf730e98cba3e8a8b09a76207c934face Mon Sep 17 00:00:00 2001 From: Christian Nieves Date: Thu, 18 Dec 2025 02:23:28 -0600 Subject: [PATCH 7/7] Dont access bg->entries[index] if oob --- src/backend_wgpu.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend_wgpu.c b/src/backend_wgpu.c index 4023f3126..6db046ec7 100644 --- a/src/backend_wgpu.c +++ b/src/backend_wgpu.c @@ -712,9 +712,9 @@ static inline uint64_t bgEntryHashRD(const ResourceDescriptor bge) { } void UpdateBindGroupEntry(DescribedBindGroup *bg, size_t index, ResourceDescriptor entry) { - if (index >= bg->entryCount) { + if (bg->entries == NULL || index >= bg->entryCount) { TRACELOG(LOG_WARNING, "Trying to set entry %d on a BindGroup with only %d entries", (int)index, (int)bg->entryCount); - // return; + return; } WGPUBuffer newpuffer = entry.buffer; WGPUTextureView newtexture = entry.textureView;