add renderer abstraction
This commit is contained in:
@@ -0,0 +1,992 @@
|
||||
#include "renderer.h"
|
||||
#include <webgpu/webgpu.h>
|
||||
#include <dcimgui_impl_wgpu.h>
|
||||
|
||||
typedef struct R_Buffer_Impl {
|
||||
WGPUBuffer buffer;
|
||||
|
||||
Uint32 num_bytes;
|
||||
R_Buffer_Usage usage;
|
||||
} R_Buffer_Impl;
|
||||
|
||||
typedef struct R_Texture_Impl {
|
||||
WGPUTexture texture;
|
||||
WGPUTextureView view;
|
||||
|
||||
Uint32 width;
|
||||
Uint32 height;
|
||||
|
||||
Uint32 sample_count;
|
||||
R_Texture_Format format;
|
||||
} R_Texture_Impl;
|
||||
|
||||
R_Texture R_framebuffer;
|
||||
|
||||
static bool init_done;
|
||||
|
||||
static SDL_Window *window;
|
||||
static WGPUInstance instance;
|
||||
static WGPUDevice device;
|
||||
static WGPUQueue queue;
|
||||
static WGPUSurface surface;
|
||||
|
||||
static R_Texture_Format surface_format;
|
||||
static WGPUSurfaceConfiguration surface_configuration;
|
||||
static WGPUSurfaceTexture surface_texture;
|
||||
static WGPUTextureView surface_texture_view;
|
||||
|
||||
static R_Texture framebuffer;
|
||||
|
||||
static WGPUCommandEncoder command_encoder;
|
||||
static WGPURenderPassEncoder pass_encoder;
|
||||
|
||||
static WGPURenderPipeline shaders[R_SHADER_COUNT];
|
||||
static R_Shader current_shader;
|
||||
|
||||
static WGPUSampler bilinear_sampler;
|
||||
|
||||
static WGPUTextureFormat texture_formats[] = {
|
||||
[R_TEXTURE_FORMAT_R8_UNORM] = WGPUTextureFormat_R8Unorm,
|
||||
[R_TEXTURE_FORMAT_R16_UINT] = WGPUTextureFormat_R16Uint,
|
||||
[R_TEXTURE_FORMAT_RGBA8_UNORM] = WGPUTextureFormat_RGBA8Unorm,
|
||||
[R_TEXTURE_FORMAT_RGBA8_UNORM_SRGB] = WGPUTextureFormat_RGBA8UnormSrgb,
|
||||
[R_TEXTURE_FORMAT_BGRA8_UNORM] = WGPUTextureFormat_BGRA8Unorm,
|
||||
[R_TEXTURE_FORMAT_BGRA8_UNORM_SRGB] = WGPUTextureFormat_BGRA8UnormSrgb,
|
||||
};
|
||||
static_assert(SDL_arraysize(texture_formats) == R_TEXTURE_FORMAT_COUNT);
|
||||
|
||||
static Uint32 texel_sizes[] = {
|
||||
[R_TEXTURE_FORMAT_R8_UNORM] = 1,
|
||||
[R_TEXTURE_FORMAT_R16_UINT] = 2,
|
||||
[R_TEXTURE_FORMAT_RGBA8_UNORM] = 4,
|
||||
[R_TEXTURE_FORMAT_RGBA8_UNORM_SRGB] = 4,
|
||||
[R_TEXTURE_FORMAT_BGRA8_UNORM] = 4,
|
||||
[R_TEXTURE_FORMAT_BGRA8_UNORM_SRGB] = 4,
|
||||
};
|
||||
static_assert(SDL_arraysize(texel_sizes) == R_TEXTURE_FORMAT_COUNT);
|
||||
|
||||
static WGPUTextureUsage texture_usages[] = {
|
||||
[R_TEXTURE_USAGE_SAMPLED] = WGPUTextureUsage_TextureBinding,
|
||||
[R_TEXTURE_USAGE_STORAGE] = WGPUTextureUsage_StorageBinding,
|
||||
[R_TEXTURE_USAGE_TARGET] = WGPUTextureUsage_RenderAttachment,
|
||||
};
|
||||
static_assert(SDL_arraysize(texture_usages) == R_TEXTURE_USAGE_COUNT);
|
||||
|
||||
static WGPUBufferUsage buffer_usages[] = {
|
||||
[R_BUFFER_USAGE_UNIFORM] = WGPUBufferUsage_Uniform,
|
||||
[R_BUFFER_USAGE_STORAGE] = WGPUBufferUsage_Storage,
|
||||
[R_BUFFER_USAGE_VERTEX] = WGPUBufferUsage_Vertex,
|
||||
[R_BUFFER_USAGE_INDEX] = WGPUBufferUsage_Index,
|
||||
};
|
||||
static_assert(SDL_arraysize(buffer_usages) == R_BUFFER_USAGE_COUNT);
|
||||
|
||||
static WGPULoadOp load_ops[] = {
|
||||
[R_LOAD_OP_LOAD] = WGPULoadOp_Load,
|
||||
[R_LOAD_OP_CLEAR] = WGPULoadOp_Clear,
|
||||
};
|
||||
static_assert(SDL_arraysize(load_ops) == R_LOAD_OP_COUNT);
|
||||
|
||||
static WGPUStoreOp store_ops[] = {
|
||||
[R_STORE_OP_STORE] = WGPUStoreOp_Store,
|
||||
[R_STORE_OP_DISCARD] = WGPUStoreOp_Discard,
|
||||
};
|
||||
static_assert(SDL_arraysize(store_ops) == R_STORE_OP_COUNT);
|
||||
|
||||
R_Texture renderer_texture_create(R_Texture_Format format, R_Texture_Usage usage, Uint32 sample_count, Uint32 width, Uint32 height, void *data, const char *debug_name) {
|
||||
WGPUTextureDescriptor descriptor = {
|
||||
.label = { .data = debug_name, .length = WGPU_STRLEN },
|
||||
.usage = texture_usages[usage] | WGPUTextureUsage_CopyDst,
|
||||
.dimension = WGPUTextureDimension_2D,
|
||||
.size = { .width = width, .height = height, .depthOrArrayLayers = 1 },
|
||||
.format = texture_formats[format],
|
||||
.mipLevelCount = 1,
|
||||
.sampleCount = sample_count,
|
||||
.viewFormatCount = 0,
|
||||
.viewFormats = NULL,
|
||||
};
|
||||
|
||||
WGPUTexture texture = wgpuDeviceCreateTexture(device, &descriptor);
|
||||
if (!texture) return NULL;
|
||||
|
||||
WGPUTextureView view = wgpuTextureCreateView(texture, NULL);
|
||||
if (!view) {
|
||||
wgpuTextureRelease(texture);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (data) {
|
||||
Uint32 texel_size = texel_sizes[format];
|
||||
|
||||
WGPUTexelCopyTextureInfo destination = {
|
||||
.texture = texture,
|
||||
.mipLevel = 0,
|
||||
.origin = { .x = 0, .y = 0, .z = 0 },
|
||||
.aspect = WGPUTextureAspect_All,
|
||||
};
|
||||
|
||||
WGPUTexelCopyBufferLayout data_layout = {
|
||||
.offset = 0,
|
||||
.bytesPerRow = width * texel_size,
|
||||
.rowsPerImage = height,
|
||||
};
|
||||
|
||||
WGPUExtent3D extent = {
|
||||
.width = width,
|
||||
.height = height,
|
||||
.depthOrArrayLayers = 1,
|
||||
};
|
||||
|
||||
wgpuQueueWriteTexture(queue, &destination, data, width * height * texel_size, &data_layout, &extent);
|
||||
}
|
||||
|
||||
R_Texture_Impl *result = SDL_calloc(1, sizeof(R_Texture_Impl));
|
||||
if (!result) {
|
||||
wgpuTextureViewRelease(view);
|
||||
wgpuTextureRelease(texture);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*result = (R_Texture_Impl){
|
||||
.texture = texture,
|
||||
.view = view,
|
||||
|
||||
.width = width,
|
||||
.height = height,
|
||||
|
||||
.sample_count = sample_count,
|
||||
.format = format,
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void renderer_texture_update(R_Texture texture, Uint32 offset_x, Uint32 offset_y, Uint32 width, Uint32 height, void *data, Uint32 bytes_per_row) {
|
||||
WGPUTexelCopyTextureInfo info = {
|
||||
.texture = texture->texture,
|
||||
.mipLevel = 0,
|
||||
.origin = { offset_x, offset_y, 0 },
|
||||
.aspect = WGPUTextureAspect_All,
|
||||
};
|
||||
|
||||
WGPUTexelCopyBufferLayout data_layout = {
|
||||
.offset = 0,
|
||||
.bytesPerRow = bytes_per_row,
|
||||
.rowsPerImage = height,
|
||||
};
|
||||
|
||||
WGPUExtent3D extent = { width, height, 1 };
|
||||
|
||||
wgpuQueueWriteTexture(queue, &info, data, data_layout.bytesPerRow * data_layout.rowsPerImage, &data_layout, &extent);
|
||||
}
|
||||
|
||||
void renderer_texture_destroy(R_Texture texture) {
|
||||
wgpuTextureViewRelease(texture->view);
|
||||
wgpuTextureRelease(texture->texture);
|
||||
SDL_free(texture);
|
||||
}
|
||||
|
||||
R_Buffer renderer_buffer_create(R_Buffer_Usage usage, Uint32 num_bytes, void *data, const char *debug_name) {
|
||||
WGPUBufferDescriptor descriptor = {
|
||||
.label = { .data = debug_name, .length = WGPU_STRLEN },
|
||||
.usage = buffer_usages[usage] | WGPUBufferUsage_CopyDst,
|
||||
.size = num_bytes,
|
||||
.mappedAtCreation = data != NULL,
|
||||
};
|
||||
|
||||
WGPUBuffer buffer = wgpuDeviceCreateBuffer(device, &descriptor);
|
||||
if (!buffer) return NULL;
|
||||
|
||||
if (data) {
|
||||
void *mapped_data = wgpuBufferGetMappedRange(buffer, 0, num_bytes);
|
||||
memcpy(mapped_data, data, num_bytes);
|
||||
wgpuBufferUnmap(buffer);
|
||||
}
|
||||
|
||||
R_Buffer_Impl *result = SDL_calloc(1, sizeof(R_Buffer_Impl));
|
||||
if (!result) {
|
||||
wgpuBufferRelease(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
*result = (R_Buffer_Impl){
|
||||
.buffer = buffer,
|
||||
|
||||
.num_bytes = num_bytes,
|
||||
.usage = usage,
|
||||
};
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void renderer_buffer_update(R_Buffer buffer, Uint32 offset, Uint32 num_bytes, void *data) {
|
||||
wgpuQueueWriteBuffer(queue, buffer->buffer, offset, data, num_bytes);
|
||||
}
|
||||
|
||||
void renderer_buffer_destroy(R_Buffer buffer) {
|
||||
wgpuBufferRelease(buffer->buffer);
|
||||
SDL_free(buffer);
|
||||
}
|
||||
|
||||
void renderer_frame_begin() {
|
||||
SDL_assert(command_encoder == NULL);
|
||||
SDL_assert(R_framebuffer == NULL);
|
||||
|
||||
Sint32 window_width = 0, window_height = 0;
|
||||
SDL_GetWindowSizeInPixels(window, &window_width, &window_height);
|
||||
|
||||
if (surface_configuration.width != window_width || surface_configuration.height != window_height) {
|
||||
surface_configuration.width = window_width;
|
||||
surface_configuration.height = window_height;
|
||||
wgpuSurfaceConfigure(surface, &surface_configuration);
|
||||
}
|
||||
|
||||
wgpuSurfaceGetCurrentTexture(surface, &surface_texture);
|
||||
if (surface_texture.status != WGPUSurfaceGetCurrentTextureStatus_SuccessOptimal && surface_texture.status != WGPUSurfaceGetCurrentTextureStatus_SuccessSuboptimal) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to get current surface texture (%x). Exiting.", surface_texture.status);
|
||||
SDL_assert_always(false); // TODO: recovery on outdated or device loss
|
||||
return;
|
||||
}
|
||||
surface_texture_view = wgpuTextureCreateView(surface_texture.texture, NULL);
|
||||
|
||||
if (!framebuffer || framebuffer->width != surface_configuration.width || framebuffer->height != surface_configuration.height) {
|
||||
if (framebuffer) {
|
||||
renderer_texture_destroy(framebuffer);
|
||||
framebuffer = NULL;
|
||||
}
|
||||
|
||||
framebuffer = renderer_texture_create(surface_format, R_TEXTURE_USAGE_TARGET, 4, surface_configuration.width, surface_configuration.height, NULL, "R_framebuffer");
|
||||
}
|
||||
|
||||
command_encoder = wgpuDeviceCreateCommandEncoder(device, NULL);
|
||||
R_framebuffer = framebuffer;
|
||||
}
|
||||
|
||||
void renderer_frame_end() {
|
||||
SDL_assert(command_encoder);
|
||||
SDL_assert(R_framebuffer);
|
||||
|
||||
if (pass_encoder) {
|
||||
wgpuRenderPassEncoderEnd(pass_encoder);
|
||||
wgpuRenderPassEncoderRelease(pass_encoder);
|
||||
pass_encoder = NULL;
|
||||
}
|
||||
|
||||
pass_encoder = wgpuCommandEncoderBeginRenderPass(command_encoder, &(WGPURenderPassDescriptor){
|
||||
.colorAttachmentCount = 1,
|
||||
.colorAttachments = &(WGPURenderPassColorAttachment) {
|
||||
.view = framebuffer->view,
|
||||
.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED,
|
||||
.resolveTarget = surface_texture_view,
|
||||
.loadOp = WGPULoadOp_Load,
|
||||
.storeOp = WGPUStoreOp_Discard,
|
||||
.clearValue = { .r = 0.0f, .g = 0.0f, .b = 0.0f, .a = 0.0f },
|
||||
},
|
||||
});
|
||||
wgpuRenderPassEncoderEnd(pass_encoder);
|
||||
wgpuRenderPassEncoderRelease(pass_encoder);
|
||||
pass_encoder = NULL;
|
||||
|
||||
wgpuTextureViewRelease(surface_texture_view);
|
||||
surface_texture_view = NULL;
|
||||
|
||||
WGPUCommandBuffer command_buffer = wgpuCommandEncoderFinish(command_encoder, NULL);
|
||||
wgpuCommandEncoderRelease(command_encoder);
|
||||
command_encoder = NULL;
|
||||
|
||||
wgpuQueueSubmit(queue, 1, &command_buffer);
|
||||
wgpuCommandBufferRelease(command_buffer);
|
||||
|
||||
wgpuSurfacePresent(surface);
|
||||
wgpuTextureRelease(surface_texture.texture);
|
||||
surface_texture.texture = NULL;
|
||||
|
||||
R_framebuffer = NULL;
|
||||
}
|
||||
|
||||
void renderer_frame_set_target(R_Texture target, R_Texture resolve_target, R_Load_Op load_op, R_Store_Op store_op, R_Color clear_color) {
|
||||
SDL_assert(command_encoder);
|
||||
|
||||
if (pass_encoder) {
|
||||
wgpuRenderPassEncoderEnd(pass_encoder);
|
||||
wgpuRenderPassEncoderRelease(pass_encoder);
|
||||
}
|
||||
|
||||
pass_encoder = wgpuCommandEncoderBeginRenderPass(command_encoder, &(WGPURenderPassDescriptor){
|
||||
.colorAttachmentCount = 1,
|
||||
.colorAttachments = &(WGPURenderPassColorAttachment) {
|
||||
.view = target->view,
|
||||
.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED,
|
||||
.resolveTarget = resolve_target ? resolve_target->view : NULL,
|
||||
.loadOp = load_ops[load_op],
|
||||
.storeOp = store_ops[store_op],
|
||||
.clearValue = { .r = clear_color.r, .g = clear_color.g, .b = clear_color.b, .a = clear_color.a },
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
void renderer_frame_set_shader(R_Shader shader) {
|
||||
wgpuRenderPassEncoderSetPipeline(pass_encoder, shaders[shader]);
|
||||
current_shader = shader;
|
||||
}
|
||||
|
||||
void renderer_frame_draw(R_Buffer vertex_buffer, R_Buffer index_buffer, R_Buffer instance_buffer, Uint32 num_indices, Uint32 num_instances, const R_Draw_Resources *resources) {
|
||||
SDL_assert(pass_encoder);
|
||||
|
||||
if (resources->num_vertex_textures || resources->num_vertex_storage_buffers) {
|
||||
WGPUBindGroupEntry *entries = SDL_stack_alloc(WGPUBindGroupEntry, resources->num_vertex_textures + resources->num_vertex_storage_buffers);
|
||||
|
||||
for (int i = 0; i < resources->num_vertex_textures; i++) {
|
||||
entries[i] = (WGPUBindGroupEntry){
|
||||
.binding = i,
|
||||
.textureView = resources->vertex_textures[i]->view,
|
||||
};
|
||||
}
|
||||
|
||||
for (int i = 0; i < resources->num_vertex_storage_buffers; i++) {
|
||||
entries[resources->num_vertex_textures + i] = (WGPUBindGroupEntry){
|
||||
.binding = resources->num_vertex_textures + i,
|
||||
.buffer = resources->vertex_storage_buffers[i]->buffer,
|
||||
.offset = 0,
|
||||
.size = WGPU_WHOLE_SIZE,
|
||||
};
|
||||
}
|
||||
|
||||
WGPUBindGroup bind_group = wgpuDeviceCreateBindGroup(device, &(WGPUBindGroupDescriptor){
|
||||
.layout = wgpuRenderPipelineGetBindGroupLayout(shaders[current_shader], 0),
|
||||
.entryCount = resources->num_vertex_textures + resources->num_vertex_storage_buffers,
|
||||
.entries = entries,
|
||||
});
|
||||
|
||||
SDL_stack_free(entries);
|
||||
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 0, bind_group, 0, NULL);
|
||||
wgpuBindGroupRelease(bind_group);
|
||||
} else {
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 0, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
if (resources->num_vertex_uniform_buffers) {
|
||||
WGPUBindGroupEntry *entries = SDL_stack_alloc(WGPUBindGroupEntry, resources->num_vertex_uniform_buffers);
|
||||
|
||||
for (int i = 0; i < resources->num_vertex_uniform_buffers; i++) {
|
||||
entries[i] = (WGPUBindGroupEntry){
|
||||
.binding = i,
|
||||
.buffer = resources->vertex_uniform_buffers[i]->buffer,
|
||||
.offset = 0,
|
||||
.size = WGPU_WHOLE_SIZE,
|
||||
};
|
||||
}
|
||||
|
||||
WGPUBindGroup bind_group = wgpuDeviceCreateBindGroup(device, &(WGPUBindGroupDescriptor){
|
||||
.layout = wgpuRenderPipelineGetBindGroupLayout(shaders[current_shader], 1),
|
||||
.entryCount = resources->num_vertex_uniform_buffers,
|
||||
.entries = entries,
|
||||
});
|
||||
|
||||
SDL_stack_free(entries);
|
||||
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, bind_group, 0, NULL);
|
||||
wgpuBindGroupRelease(bind_group);
|
||||
} else {
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 1, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
if (resources->num_fragment_textures || resources->num_fragment_storage_buffers) {
|
||||
WGPUBindGroupEntry *entries = SDL_stack_alloc(WGPUBindGroupEntry, resources->num_fragment_textures * 2 + resources->num_fragment_storage_buffers);
|
||||
|
||||
for (int i = 0; i < resources->num_fragment_textures; i++) {
|
||||
entries[i * 2] = (WGPUBindGroupEntry){
|
||||
.binding = i * 2,
|
||||
.textureView = resources->fragment_textures[i]->view,
|
||||
};
|
||||
|
||||
entries[i * 2 + 1] = (WGPUBindGroupEntry){
|
||||
.binding = i * 2 + 1,
|
||||
.sampler = bilinear_sampler,
|
||||
};
|
||||
}
|
||||
|
||||
for (int i = 0; i < resources->num_fragment_storage_buffers; i++) {
|
||||
entries[resources->num_fragment_textures * 2 + i] = (WGPUBindGroupEntry){
|
||||
.binding = resources->num_fragment_textures * 2 + i,
|
||||
.buffer = resources->fragment_storage_buffers[i]->buffer,
|
||||
.offset = 0,
|
||||
.size = WGPU_WHOLE_SIZE,
|
||||
};
|
||||
}
|
||||
|
||||
WGPUBindGroup bind_group = wgpuDeviceCreateBindGroup(device, &(WGPUBindGroupDescriptor){
|
||||
.layout = wgpuRenderPipelineGetBindGroupLayout(shaders[current_shader], 2),
|
||||
.entryCount = resources->num_fragment_textures * 2 + resources->num_fragment_storage_buffers,
|
||||
.entries = entries,
|
||||
});
|
||||
|
||||
SDL_stack_free(entries);
|
||||
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 2, bind_group, 0, NULL);
|
||||
wgpuBindGroupRelease(bind_group);
|
||||
} else {
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 2, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
if (resources->num_fragment_uniform_buffers) {
|
||||
WGPUBindGroupEntry *entries = SDL_stack_alloc(WGPUBindGroupEntry, resources->num_fragment_uniform_buffers);
|
||||
|
||||
for (int i = 0; i < resources->num_fragment_uniform_buffers; i++) {
|
||||
entries[i] = (WGPUBindGroupEntry){
|
||||
.binding = i,
|
||||
.buffer = resources->fragment_uniform_buffers[i]->buffer,
|
||||
.offset = 0,
|
||||
.size = WGPU_WHOLE_SIZE,
|
||||
};
|
||||
}
|
||||
|
||||
WGPUBindGroup bind_group = wgpuDeviceCreateBindGroup(device, &(WGPUBindGroupDescriptor){
|
||||
.layout = wgpuRenderPipelineGetBindGroupLayout(shaders[current_shader], 3),
|
||||
.entryCount = resources->num_fragment_uniform_buffers,
|
||||
.entries = entries,
|
||||
});
|
||||
|
||||
SDL_stack_free(entries);
|
||||
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 3, bind_group, 0, NULL);
|
||||
wgpuBindGroupRelease(bind_group);
|
||||
} else {
|
||||
wgpuRenderPassEncoderSetBindGroup(pass_encoder, 3, NULL, 0, NULL);
|
||||
}
|
||||
|
||||
if (vertex_buffer) wgpuRenderPassEncoderSetVertexBuffer(pass_encoder, 0, vertex_buffer->buffer, 0, WGPU_WHOLE_SIZE);
|
||||
if (instance_buffer) wgpuRenderPassEncoderSetVertexBuffer(pass_encoder, 1, instance_buffer->buffer, 0, WGPU_WHOLE_SIZE);
|
||||
|
||||
if (index_buffer) {
|
||||
wgpuRenderPassEncoderSetIndexBuffer(pass_encoder, index_buffer->buffer, WGPUIndexFormat_Uint16, 0, WGPU_WHOLE_SIZE);
|
||||
wgpuRenderPassEncoderDrawIndexed(pass_encoder, num_indices, num_instances, 0, 0, 0);
|
||||
} else {
|
||||
wgpuRenderPassEncoderDraw(pass_encoder, num_indices, num_instances, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static WGPUSurface create_wgpu_surface_for_SDL_window(SDL_Window *window) {
|
||||
SDL_PropertiesID properties = SDL_GetWindowProperties(window);
|
||||
|
||||
#if defined(SDL_PLATFORM_LINUX)
|
||||
const char *display_system = SDL_GetCurrentVideoDriver();
|
||||
|
||||
if (SDL_strcmp(display_system, "wayland") == 0) {
|
||||
void *display = SDL_GetPointerProperty(properties, SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER, NULL);
|
||||
void *surface = SDL_GetPointerProperty(properties, SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER, NULL);
|
||||
if (!display || !surface) return NULL;
|
||||
|
||||
WGPUSurfaceSourceWaylandSurface surface_source = {
|
||||
.chain = { .next = NULL, .sType = WGPUSType_SurfaceSourceWaylandSurface },
|
||||
.display = display,
|
||||
.surface = surface,
|
||||
};
|
||||
|
||||
WGPUSurfaceDescriptor descriptor = {
|
||||
.nextInChain = &surface_source.chain,
|
||||
.label = { .data = NULL, .length = WGPU_STRLEN },
|
||||
};
|
||||
|
||||
return wgpuInstanceCreateSurface(instance, &descriptor);
|
||||
} else if (SDL_strcmp(display_system, "x11") == 0) {
|
||||
void *display = SDL_GetPointerProperty(properties, SDL_PROP_WINDOW_X11_DISPLAY_POINTER, NULL);
|
||||
uint64_t xlib_window = SDL_GetNumberProperty (properties, SDL_PROP_WINDOW_X11_WINDOW_NUMBER, 0);
|
||||
if (!display || !xlib_window) return NULL;
|
||||
|
||||
WGPUSurfaceSourceXlibWindow surface_source = {
|
||||
.chain = { .next = NULL, .sType = WGPUSType_SurfaceSourceXlibWindow },
|
||||
.display = display,
|
||||
.window = xlib_window,
|
||||
};
|
||||
|
||||
WGPUSurfaceDescriptor descriptor = {
|
||||
.nextInChain = &surface_source.chain,
|
||||
.label = { .data = NULL, .length = WGPU_STRLEN },
|
||||
};
|
||||
|
||||
return wgpuInstanceCreateSurface(instance, &descriptor);
|
||||
} else {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_GPU, "create_wgpu_surface_for_SDL_window is not implemented for this display system (%s).", display_system);
|
||||
return NULL;
|
||||
}
|
||||
#elif defined(SDL_PLATFORM_WINDOWS)
|
||||
void *hinstance = SDL_GetPointerProperty(properties, SDL_PROP_WINDOW_WIN32_INSTANCE_POINTER, NULL);
|
||||
void *hwnd = SDL_GetPointerProperty(properties, SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
|
||||
if (!hinstance || !hwnd) return NULL;
|
||||
|
||||
WGPUSurfaceSourceWindowsHWND surface_source = {
|
||||
.chain = { .next = NULL, .sType = WGPUSType_SurfaceSourceWindowsHWND },
|
||||
.hinstance = hinstance,
|
||||
.hwnd = hwnd,
|
||||
};
|
||||
|
||||
WGPUSurfaceDescriptor descriptor = {
|
||||
.nextInChain = &surface_source.chain,
|
||||
.label = { .data = NULL, .length = WGPU_STRLEN },
|
||||
};
|
||||
|
||||
return wgpuInstanceCreateSurface(instance, &descriptor);
|
||||
#else
|
||||
static_assert(false, "create_wgpu_surface_for_SDL_window is not implemented for this platform.");
|
||||
#endif
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void device_request_callback(WGPURequestDeviceStatus status, WGPUDevice device_, WGPUStringView message, void *userdata1, void *userdata2) {
|
||||
if (status != WGPURequestDeviceStatus_Success) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to request webgpu device.");
|
||||
init_done = true;
|
||||
return;
|
||||
}
|
||||
|
||||
device = device_;
|
||||
queue = wgpuDeviceGetQueue(device);
|
||||
init_done = true;
|
||||
}
|
||||
|
||||
static void adapter_request_callback(WGPURequestAdapterStatus status, WGPUAdapter adapter, WGPUStringView message, void *userdata1, void *userdata2) {
|
||||
if (status != WGPURequestAdapterStatus_Success) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to request webgpu adapter.");
|
||||
init_done = true;
|
||||
return;
|
||||
}
|
||||
|
||||
WGPURequestDeviceCallbackInfo request_device_callback_info = {
|
||||
.mode = WGPUCallbackMode_AllowProcessEvents,
|
||||
.callback = device_request_callback,
|
||||
};
|
||||
|
||||
WGPUDeviceDescriptor device_descriptor = {
|
||||
.label = {},
|
||||
.requiredFeatureCount = 0,
|
||||
.requiredFeatures = NULL,
|
||||
.requiredLimits = NULL,
|
||||
.defaultQueue = {},
|
||||
.deviceLostCallbackInfo = {},
|
||||
.uncapturedErrorCallbackInfo = {},
|
||||
};
|
||||
|
||||
wgpuAdapterRequestDevice(adapter, &device_descriptor, request_device_callback_info);
|
||||
}
|
||||
|
||||
bool renderer_init(SDL_Window *window_) {
|
||||
window = window_;
|
||||
|
||||
instance = wgpuCreateInstance(NULL);
|
||||
if (!instance) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create webgpu instance.");
|
||||
return false;
|
||||
}
|
||||
|
||||
surface = create_wgpu_surface_for_SDL_window(window);
|
||||
if (!surface) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create webgpu surface for SDL window.");
|
||||
return false;
|
||||
}
|
||||
|
||||
WGPURequestAdapterCallbackInfo request_adapter_callback_info = {
|
||||
.mode = WGPUCallbackMode_AllowProcessEvents,
|
||||
.callback = adapter_request_callback,
|
||||
};
|
||||
|
||||
WGPURequestAdapterOptions request_adapter_options = {
|
||||
.featureLevel = WGPUFeatureLevel_Core,
|
||||
.powerPreference = WGPUPowerPreference_HighPerformance,
|
||||
.forceFallbackAdapter = false,
|
||||
.backendType = WGPUBackendType_Vulkan,
|
||||
.compatibleSurface = surface,
|
||||
};
|
||||
|
||||
wgpuInstanceRequestAdapter(instance, &request_adapter_options, request_adapter_callback_info);
|
||||
|
||||
while (!init_done) {
|
||||
wgpuInstanceProcessEvents(instance);
|
||||
}
|
||||
|
||||
if (!device) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to get webgpu device.");
|
||||
return false;
|
||||
}
|
||||
|
||||
surface_format = R_TEXTURE_FORMAT_BGRA8_UNORM_SRGB;
|
||||
surface_configuration = (WGPUSurfaceConfiguration){
|
||||
.device = device,
|
||||
.format = WGPUTextureFormat_BGRA8UnormSrgb,
|
||||
.usage = WGPUTextureUsage_RenderAttachment,
|
||||
.width = 1280,
|
||||
.height = 720,
|
||||
.viewFormatCount = 0,
|
||||
.viewFormats = NULL,
|
||||
.alphaMode = WGPUCompositeAlphaMode_Opaque,
|
||||
.presentMode = WGPUPresentMode_Fifo,
|
||||
};
|
||||
|
||||
wgpuSurfaceConfigure(surface, &surface_configuration);
|
||||
|
||||
WGPUSamplerDescriptor bilinear_sampler_descriptor = {
|
||||
.label = { .data = "bilinear_sampler", .length = WGPU_STRLEN },
|
||||
|
||||
.addressModeU = WGPUAddressMode_ClampToEdge,
|
||||
.addressModeV = WGPUAddressMode_ClampToEdge,
|
||||
.addressModeW = WGPUAddressMode_ClampToEdge,
|
||||
|
||||
.magFilter = WGPUFilterMode_Linear,
|
||||
.minFilter = WGPUFilterMode_Linear,
|
||||
.mipmapFilter = WGPUMipmapFilterMode_Nearest,
|
||||
|
||||
.maxAnisotropy = 1,
|
||||
};
|
||||
|
||||
bilinear_sampler = wgpuDeviceCreateSampler(device, &bilinear_sampler_descriptor);
|
||||
|
||||
WGPUBlendState blend_state = {
|
||||
.color = { .operation = WGPUBlendOperation_Add, .srcFactor = WGPUBlendFactor_SrcAlpha, .dstFactor = WGPUBlendFactor_OneMinusSrcAlpha },
|
||||
.alpha = { .operation = WGPUBlendOperation_Add, .srcFactor = WGPUBlendFactor_SrcAlpha, .dstFactor = WGPUBlendFactor_OneMinusSrcAlpha },
|
||||
};
|
||||
|
||||
WGPUColorTargetState color_target_state = {
|
||||
.format = surface_configuration.format,
|
||||
.blend = &blend_state,
|
||||
.writeMask = WGPUColorWriteMask_All,
|
||||
};
|
||||
|
||||
// Shader
|
||||
{ // Basic
|
||||
const char shader_source[] = {
|
||||
#embed "shaders/wgsl/basic.wgsl"
|
||||
};
|
||||
|
||||
WGPUShaderModule shader = wgpuDeviceCreateShaderModule(device, &(WGPUShaderModuleDescriptor){
|
||||
.nextInChain = (WGPUChainedStruct *)&(WGPUShaderSourceWGSL){
|
||||
.chain = { .next = NULL, .sType = WGPUSType_ShaderSourceWGSL },
|
||||
.code = { .data = shader_source, .length = SDL_arraysize(shader_source) },
|
||||
},
|
||||
.label = { .data = "basic shader", .length = WGPU_STRLEN }
|
||||
});
|
||||
|
||||
shaders[R_SHADER_BASIC] = wgpuDeviceCreateRenderPipeline(device, &(WGPURenderPipelineDescriptor){
|
||||
.label = { .data = "basic render_pipeline", .length = WGPU_STRLEN },
|
||||
|
||||
.layout = wgpuDeviceCreatePipelineLayout(device, &(WGPUPipelineLayoutDescriptor){
|
||||
.label = { .data = "basic pipeline_layout", .length = WGPU_STRLEN },
|
||||
.bindGroupLayoutCount = 4,
|
||||
.bindGroupLayouts = (WGPUBindGroupLayout[]){
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 0,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 1,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
{ .binding = 0, .visibility = WGPUShaderStage_Vertex, .buffer = { .type = WGPUBufferBindingType_Uniform } },
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 2,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
{ .binding = 0, .visibility = WGPUShaderStage_Fragment, .texture = { .sampleType = WGPUTextureSampleType_Float, .viewDimension = WGPUTextureViewDimension_2D } },
|
||||
{ .binding = 1, .visibility = WGPUShaderStage_Fragment, .sampler = { .type = WGPUSamplerBindingType_Filtering } },
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 1,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
{ .binding = 0, .visibility = WGPUShaderStage_Fragment, .buffer = { .type = WGPUBufferBindingType_Uniform } },
|
||||
},
|
||||
}),
|
||||
},
|
||||
}),
|
||||
|
||||
.vertex = {
|
||||
.module = shader,
|
||||
.entryPoint = { .data = "main_vertex", .length = WGPU_STRLEN },
|
||||
.constantCount = 0,
|
||||
.constants = NULL,
|
||||
.bufferCount = 2,
|
||||
.buffers = (WGPUVertexBufferLayout[]){
|
||||
{
|
||||
.stepMode = WGPUVertexStepMode_Vertex,
|
||||
.arrayStride = 20,
|
||||
.attributeCount = 2,
|
||||
.attributes = (WGPUVertexAttribute[]){
|
||||
{
|
||||
.format = WGPUVertexFormat_Float32x3,
|
||||
.offset = 0,
|
||||
.shaderLocation = 0,
|
||||
},
|
||||
{
|
||||
.format = WGPUVertexFormat_Float32x2,
|
||||
.offset = 12,
|
||||
.shaderLocation = 1,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
.stepMode = WGPUVertexStepMode_Instance,
|
||||
.arrayStride = 8,
|
||||
.attributeCount = 1,
|
||||
.attributes = (WGPUVertexAttribute[]){
|
||||
{
|
||||
.format = WGPUVertexFormat_Float32x2,
|
||||
.offset = 0,
|
||||
.shaderLocation = 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
.primitive = {
|
||||
.topology = WGPUPrimitiveTopology_TriangleList,
|
||||
.stripIndexFormat = WGPUIndexFormat_Undefined,
|
||||
.frontFace = WGPUFrontFace_CCW,
|
||||
.cullMode = WGPUCullMode_Back,
|
||||
.unclippedDepth = false,
|
||||
},
|
||||
|
||||
.depthStencil = NULL,
|
||||
|
||||
.multisample = {
|
||||
.count = 4,
|
||||
.mask = ~0u,
|
||||
.alphaToCoverageEnabled = false,
|
||||
},
|
||||
|
||||
.fragment = &(WGPUFragmentState){
|
||||
.module = shader,
|
||||
.entryPoint = { .data = "main_fragment", .length = WGPU_STRLEN },
|
||||
.constantCount = 0,
|
||||
.constants = NULL,
|
||||
.targetCount = 1,
|
||||
.targets = &color_target_state,
|
||||
},
|
||||
});
|
||||
|
||||
wgpuShaderModuleRelease(shader);
|
||||
}
|
||||
|
||||
{ // World
|
||||
const char shader_source[] = {
|
||||
#embed "shaders/wgsl/world.wgsl"
|
||||
};
|
||||
|
||||
WGPUShaderModule shader = wgpuDeviceCreateShaderModule(device, &(WGPUShaderModuleDescriptor){
|
||||
.nextInChain = (WGPUChainedStruct *)&(WGPUShaderSourceWGSL){
|
||||
.chain = { .next = NULL, .sType = WGPUSType_ShaderSourceWGSL },
|
||||
.code = { .data = shader_source, .length = SDL_arraysize(shader_source) },
|
||||
},
|
||||
.label = { .data = "world shader", .length = WGPU_STRLEN }
|
||||
});
|
||||
|
||||
shaders[R_SHADER_WORLD] = wgpuDeviceCreateRenderPipeline(device, &(WGPURenderPipelineDescriptor){
|
||||
.label = { .data = "world render_pipeline", .length = WGPU_STRLEN },
|
||||
|
||||
.layout = wgpuDeviceCreatePipelineLayout(device, &(WGPUPipelineLayoutDescriptor){
|
||||
.label = { .data = "world pipeline_layout", .length = WGPU_STRLEN },
|
||||
.bindGroupLayoutCount = 4,
|
||||
.bindGroupLayouts = (WGPUBindGroupLayout[]){
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 1,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
{ .binding = 0, .visibility = WGPUShaderStage_Vertex, .texture = { .sampleType = WGPUTextureSampleType_Uint, .viewDimension = WGPUTextureViewDimension_2D } },
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 2,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
{ .binding = 0, .visibility = WGPUShaderStage_Vertex, .buffer = { .type = WGPUBufferBindingType_Uniform } },
|
||||
{ .binding = 1, .visibility = WGPUShaderStage_Vertex, .buffer = { .type = WGPUBufferBindingType_Uniform } },
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 3,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
{ .binding = 0, .visibility = WGPUShaderStage_Fragment, .texture = { .sampleType = WGPUTextureSampleType_Float, .viewDimension = WGPUTextureViewDimension_2D } },
|
||||
{ .binding = 1, .visibility = WGPUShaderStage_Fragment, .sampler = { .type = WGPUSamplerBindingType_Filtering } },
|
||||
{ .binding = 2, .visibility = WGPUShaderStage_Fragment, .buffer = { .type = WGPUBufferBindingType_ReadOnlyStorage } },
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 1,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
{ .binding = 0, .visibility = WGPUShaderStage_Fragment, .buffer = { .type = WGPUBufferBindingType_Uniform } },
|
||||
},
|
||||
}),
|
||||
},
|
||||
}),
|
||||
|
||||
.vertex = {
|
||||
.module = shader,
|
||||
.entryPoint = { .data = "main_vertex", .length = WGPU_STRLEN },
|
||||
.constantCount = 0,
|
||||
.constants = NULL,
|
||||
.bufferCount = 0,
|
||||
.buffers = (WGPUVertexBufferLayout[]){
|
||||
|
||||
},
|
||||
},
|
||||
|
||||
.primitive = {
|
||||
.topology = WGPUPrimitiveTopology_TriangleList,
|
||||
.stripIndexFormat = WGPUIndexFormat_Undefined,
|
||||
.frontFace = WGPUFrontFace_CCW,
|
||||
.cullMode = WGPUCullMode_Back,
|
||||
.unclippedDepth = false,
|
||||
},
|
||||
|
||||
.depthStencil = NULL,
|
||||
|
||||
.multisample = {
|
||||
.count = 4,
|
||||
.mask = ~0u,
|
||||
.alphaToCoverageEnabled = false,
|
||||
},
|
||||
|
||||
.fragment = &(WGPUFragmentState){
|
||||
.module = shader,
|
||||
.entryPoint = { .data = "main_fragment", .length = WGPU_STRLEN },
|
||||
.constantCount = 0,
|
||||
.constants = NULL,
|
||||
.targetCount = 1,
|
||||
.targets = &color_target_state,
|
||||
},
|
||||
});
|
||||
|
||||
wgpuShaderModuleRelease(shader);
|
||||
}
|
||||
|
||||
{ // Grid
|
||||
const char shader_source[] = {
|
||||
#embed "shaders/wgsl/grid.wgsl"
|
||||
};
|
||||
|
||||
WGPUShaderModule shader = wgpuDeviceCreateShaderModule(device, &(WGPUShaderModuleDescriptor){
|
||||
.nextInChain = (WGPUChainedStruct *)&(WGPUShaderSourceWGSL){
|
||||
.chain = { .next = NULL, .sType = WGPUSType_ShaderSourceWGSL },
|
||||
.code = { .data = shader_source, .length = SDL_arraysize(shader_source) },
|
||||
},
|
||||
.label = { .data = "grid shader", .length = WGPU_STRLEN }
|
||||
});
|
||||
|
||||
shaders[R_SHADER_GRID] = wgpuDeviceCreateRenderPipeline(device, &(WGPURenderPipelineDescriptor){
|
||||
.label = { .data = "grid render_pipeline", .length = WGPU_STRLEN },
|
||||
|
||||
.layout = wgpuDeviceCreatePipelineLayout(device, &(WGPUPipelineLayoutDescriptor){
|
||||
.label = { .data = "grid pipeline_layout", .length = WGPU_STRLEN },
|
||||
.bindGroupLayoutCount = 4,
|
||||
.bindGroupLayouts = (WGPUBindGroupLayout[]){
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 0,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 2,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
{ .binding = 0, .visibility = WGPUShaderStage_Vertex, .buffer = { .type = WGPUBufferBindingType_Uniform } },
|
||||
{ .binding = 1, .visibility = WGPUShaderStage_Vertex, .buffer = { .type = WGPUBufferBindingType_Uniform } },
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 0,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
|
||||
},
|
||||
}),
|
||||
wgpuDeviceCreateBindGroupLayout(device, &(WGPUBindGroupLayoutDescriptor){
|
||||
.entryCount = 0,
|
||||
.entries = (WGPUBindGroupLayoutEntry[]){
|
||||
|
||||
},
|
||||
}),
|
||||
},
|
||||
}),
|
||||
|
||||
.vertex = {
|
||||
.module = shader,
|
||||
.entryPoint = { .data = "main_vertex", .length = WGPU_STRLEN },
|
||||
.constantCount = 0,
|
||||
.constants = NULL,
|
||||
.bufferCount = 1,
|
||||
.buffers = (WGPUVertexBufferLayout[]){
|
||||
{
|
||||
.stepMode = WGPUVertexStepMode_Vertex,
|
||||
.arrayStride = 20,
|
||||
.attributeCount = 1,
|
||||
.attributes = (WGPUVertexAttribute[]){
|
||||
{
|
||||
.format = WGPUVertexFormat_Float32x3,
|
||||
.offset = 0,
|
||||
.shaderLocation = 0,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
.primitive = {
|
||||
.topology = WGPUPrimitiveTopology_TriangleList,
|
||||
.stripIndexFormat = WGPUIndexFormat_Undefined,
|
||||
.frontFace = WGPUFrontFace_CCW,
|
||||
.cullMode = WGPUCullMode_Back,
|
||||
.unclippedDepth = false,
|
||||
},
|
||||
|
||||
.depthStencil = NULL,
|
||||
|
||||
.multisample = {
|
||||
.count = 4,
|
||||
.mask = ~0u,
|
||||
.alphaToCoverageEnabled = false,
|
||||
},
|
||||
|
||||
.fragment = &(WGPUFragmentState){
|
||||
.module = shader,
|
||||
.entryPoint = { .data = "main_fragment", .length = WGPU_STRLEN },
|
||||
.constantCount = 0,
|
||||
.constants = NULL,
|
||||
.targetCount = 1,
|
||||
.targets = &color_target_state,
|
||||
},
|
||||
});
|
||||
|
||||
wgpuShaderModuleRelease(shader);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_ImplRenderer_Init() {
|
||||
cImGui_ImplWGPU_Init(&(ImGui_ImplWGPU_InitInfo){
|
||||
.Device = device,
|
||||
.NumFramesInFlight = 3,
|
||||
.RenderTargetFormat = surface_configuration.format,
|
||||
|
||||
.PipelineMultisampleState = {
|
||||
.count = 4,
|
||||
.mask = ~0,
|
||||
.alphaToCoverageEnabled = false,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
void ImGui_ImplRenderer_NewFrame() {
|
||||
cImGui_ImplWGPU_NewFrame();
|
||||
}
|
||||
|
||||
void ImGui_ImplRenderer_Shutdown() {
|
||||
cImGui_ImplWGPU_Shutdown();
|
||||
}
|
||||
|
||||
void ImGui_ImplRenderer_RenderDrawData(void* draw_data) {
|
||||
cImGui_ImplWGPU_RenderDrawData(draw_data, pass_encoder);
|
||||
}
|
||||
|
||||
Uint64 ImGui_ImplRenderer_GetTextureID(R_Texture texture) {
|
||||
return (Uint64)texture->view;
|
||||
}
|
||||
Reference in New Issue
Block a user