fix texture free asan
This commit is contained in:
79
gpu.c
79
gpu.c
@@ -4,6 +4,21 @@
|
||||
#include <SDL3/SDL_gpu.h>
|
||||
#include "cell.h"
|
||||
|
||||
// Shared flag so GPU resource wrappers know if the device is still alive.
|
||||
// Allocated once per device; all wrappers hold a pointer to it.
|
||||
// The device finalizer sets alive = 0 before calling SDL_DestroyGPUDevice,
|
||||
// so wrapper finalizers that run later (arbitrary GC order) skip SDL_Release.
|
||||
// Reference counted so the last user frees it.
|
||||
typedef struct {
|
||||
int alive;
|
||||
int refcount;
|
||||
} gpu_device_state;
|
||||
|
||||
static void gpu_device_state_ref(gpu_device_state *s) { if (s) s->refcount++; }
|
||||
static void gpu_device_state_unref(gpu_device_state *s) {
|
||||
if (s && --s->refcount <= 0) free(s);
|
||||
}
|
||||
|
||||
// Macro for GPU wrapper classes that need cleanup
|
||||
#define QJSCLASSGPUWRAPPER(WRAPPERTYPE, SDLTYPE) \
|
||||
typedef struct { \
|
||||
@@ -11,13 +26,17 @@ typedef struct { \
|
||||
JSValue js_device; \
|
||||
SDL_##SDLTYPE *type; \
|
||||
int owned; \
|
||||
gpu_device_state *state; \
|
||||
} WRAPPERTYPE; \
|
||||
JSClassID js_SDL_##SDLTYPE##_id; \
|
||||
static void js_SDL_##SDLTYPE##_finalizer(JSRuntime *rt, JSValue val) { \
|
||||
WRAPPERTYPE *wrapper = JS_GetOpaque(val, js_SDL_##SDLTYPE##_id); \
|
||||
JS_FreeValueRT(rt, wrapper->js_device); \
|
||||
if (wrapper && wrapper->device && wrapper->type && wrapper->owned) \
|
||||
if (!wrapper) return; \
|
||||
if (wrapper->state && wrapper->state->alive && \
|
||||
wrapper->device && wrapper->type && wrapper->owned) \
|
||||
SDL_Release##SDLTYPE(wrapper->device, wrapper->type); \
|
||||
gpu_device_state_unref(wrapper->state); \
|
||||
JS_FreeValueRT(rt, wrapper->js_device); \
|
||||
free(wrapper); \
|
||||
} \
|
||||
static JSClassDef js_SDL_##SDLTYPE##_class = { \
|
||||
@@ -35,6 +54,8 @@ JSValue SDL_##SDLTYPE##2js(JSContext *js, JSValue device, SDL_##SDLTYPE *member)
|
||||
wrapper->device = js2SDL_GPUDevice(js, device); \
|
||||
wrapper->type = member; \
|
||||
wrapper->owned = 1; \
|
||||
wrapper->state = js2gpu_device_state(js, device); \
|
||||
gpu_device_state_ref(wrapper->state); \
|
||||
JSValue j = JS_NewObjectClass(js, js_SDL_##SDLTYPE##_id); \
|
||||
JS_SetOpaque(j, wrapper); \
|
||||
return j; \
|
||||
@@ -47,11 +68,6 @@ const char *js2cstring(JSContext *js, JSValue v)
|
||||
}
|
||||
|
||||
// GPU Free functions
|
||||
void SDL_GPUDevice_free(JSRuntime *rt, SDL_GPUDevice *d)
|
||||
{
|
||||
SDL_DestroyGPUDevice(d);
|
||||
}
|
||||
|
||||
void SDL_GPUCommandBuffer_free(JSRuntime *rt, void *w)
|
||||
{
|
||||
}
|
||||
@@ -66,8 +82,52 @@ void SDL_GPUComputePass_free(JSRuntime *rt, SDL_GPUComputePass *c) { }
|
||||
void SDL_GPUCopyPass_free(JSRuntime *rt, SDL_GPUCopyPass *c) { }
|
||||
void SDL_GPURenderPass_free(JSRuntime *rt, SDL_GPURenderPass *c) { }
|
||||
|
||||
// GPU Class definitions
|
||||
QJSCLASS(SDL_GPUDevice,)
|
||||
// GPU Device: custom implementation with shared alive flag
|
||||
typedef struct {
|
||||
SDL_GPUDevice *device;
|
||||
gpu_device_state *state;
|
||||
} gpu_device_handle;
|
||||
|
||||
JSClassID js_SDL_GPUDevice_id;
|
||||
|
||||
static void js_SDL_GPUDevice_finalizer(JSRuntime *rt, JSValue val) {
|
||||
gpu_device_handle *h = JS_GetOpaque(val, js_SDL_GPUDevice_id);
|
||||
if (h) {
|
||||
if (h->state) h->state->alive = 0;
|
||||
if (h->device) SDL_DestroyGPUDevice(h->device);
|
||||
gpu_device_state_unref(h->state);
|
||||
free(h);
|
||||
}
|
||||
}
|
||||
|
||||
static JSClassDef js_SDL_GPUDevice_class = {
|
||||
.class_name = "SDL_GPUDevice",
|
||||
.finalizer = js_SDL_GPUDevice_finalizer,
|
||||
};
|
||||
|
||||
SDL_GPUDevice *js2SDL_GPUDevice(JSContext *js, JSValue val) {
|
||||
if (JS_GetClassID(val) != js_SDL_GPUDevice_id) return NULL;
|
||||
gpu_device_handle *h = JS_GetOpaque(val, js_SDL_GPUDevice_id);
|
||||
return h ? h->device : NULL;
|
||||
}
|
||||
|
||||
gpu_device_state *js2gpu_device_state(JSContext *js, JSValue val) {
|
||||
if (JS_GetClassID(val) != js_SDL_GPUDevice_id) return NULL;
|
||||
gpu_device_handle *h = JS_GetOpaque(val, js_SDL_GPUDevice_id);
|
||||
return h ? h->state : NULL;
|
||||
}
|
||||
|
||||
JSValue SDL_GPUDevice2js(JSContext *js, SDL_GPUDevice *d) {
|
||||
gpu_device_handle *h = malloc(sizeof(gpu_device_handle));
|
||||
h->device = d;
|
||||
h->state = malloc(sizeof(gpu_device_state));
|
||||
h->state->alive = 1;
|
||||
h->state->refcount = 1;
|
||||
JSValue j = JS_NewObjectClass(js, js_SDL_GPUDevice_id);
|
||||
JS_SetOpaque(j, h);
|
||||
return j;
|
||||
}
|
||||
|
||||
QJSCLASSGPUWRAPPER(gpu_buffer_wrapper, GPUBuffer)
|
||||
QJSCLASSGPUWRAPPER(gpu_compute_pipeline_wrapper, GPUComputePipeline)
|
||||
QJSCLASSGPUWRAPPER(gpu_graphics_pipeline_wrapper, GPUGraphicsPipeline)
|
||||
@@ -1452,6 +1512,7 @@ JSC_CCALL(cmd_acquire_swapchain_texture,
|
||||
wrapper->device = NULL; // We don't need the device pointer as we don't release
|
||||
wrapper->type = swapchainTexture;
|
||||
wrapper->owned = 0; // CRITICAL: Do not release this texture
|
||||
wrapper->state = NULL; // No device state needed for non-owned textures
|
||||
|
||||
JS_FRAME(js);
|
||||
JS_LOCAL(jstex, JS_NewObjectClass(js, js_SDL_GPUTexture_id));
|
||||
|
||||
Reference in New Issue
Block a user