6a984b40d9
refactor world shader vertex position calculation
1096 lines
43 KiB
C
1096 lines
43 KiB
C
#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;
|
|
|
|
bool multisampled;
|
|
R_Texture_Format format;
|
|
} R_Texture_Impl;
|
|
|
|
R_Texture R_surface;
|
|
|
|
static bool init_done;
|
|
|
|
static SDL_Window *window;
|
|
static WGPUInstance instance;
|
|
static WGPUDevice device;
|
|
static WGPUQueue queue;
|
|
static WGPUSurface surface;
|
|
|
|
static WGPUSurfaceConfiguration surface_configuration;
|
|
static R_Texture_Impl surface_texture;
|
|
|
|
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_TextureBinding,
|
|
[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, bool multisampled, 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 = multisampled ? 4 : 1,
|
|
.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,
|
|
|
|
.multisampled = multisampled,
|
|
.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);
|
|
}
|
|
|
|
Uint32 renderer_texture_get_width(R_Texture texture) {
|
|
return texture->width;
|
|
}
|
|
|
|
Uint32 renderer_texture_get_height(R_Texture texture) {
|
|
return texture->height;
|
|
}
|
|
|
|
bool renderer_texture_get_multisampled(R_Texture texture) {
|
|
return texture->multisampled;
|
|
}
|
|
|
|
R_Texture_Format renderer_texture_get_format(R_Texture texture) {
|
|
return texture->format;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
Uint32 renderer_buffer_get_size(R_Buffer buffer) {
|
|
return buffer->num_bytes;
|
|
}
|
|
|
|
R_Buffer_Usage renderer_buffer_get_usage(R_Buffer buffer){
|
|
return buffer->usage;
|
|
}
|
|
|
|
void renderer_frame_begin() {
|
|
SDL_assert(command_encoder == NULL);
|
|
SDL_assert(R_surface == 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);
|
|
}
|
|
|
|
WGPUSurfaceTexture wgpu_surface_texture;
|
|
wgpuSurfaceGetCurrentTexture(surface, &wgpu_surface_texture);
|
|
if (wgpu_surface_texture.status != WGPUSurfaceGetCurrentTextureStatus_SuccessOptimal && wgpu_surface_texture.status != WGPUSurfaceGetCurrentTextureStatus_SuccessSuboptimal) {
|
|
SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to get current surface texture (%x). Exiting.", wgpu_surface_texture.status);
|
|
SDL_assert_always(false); // TODO: recovery on outdated or device loss
|
|
return;
|
|
}
|
|
surface_texture.texture = wgpu_surface_texture.texture;
|
|
surface_texture.view = wgpuTextureCreateView(wgpu_surface_texture.texture, NULL);
|
|
surface_texture.width = surface_configuration.width;
|
|
surface_texture.height = surface_configuration.height;
|
|
|
|
command_encoder = wgpuDeviceCreateCommandEncoder(device, NULL);
|
|
R_surface = &surface_texture;
|
|
}
|
|
|
|
void renderer_frame_end() {
|
|
SDL_assert(command_encoder);
|
|
SDL_assert(R_surface);
|
|
|
|
if (pass_encoder) {
|
|
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_surface = 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_sampled_textures || resources->num_vertex_storage_textures || resources->num_vertex_storage_buffers) {
|
|
WGPUBindGroupEntry *entries = SDL_stack_alloc(WGPUBindGroupEntry, resources->num_vertex_sampled_textures + resources->num_vertex_storage_textures + resources->num_vertex_storage_buffers);
|
|
|
|
for (int i = 0; i < resources->num_vertex_sampled_textures; i++) {
|
|
entries[i] = (WGPUBindGroupEntry){
|
|
.binding = i,
|
|
.textureView = resources->vertex_sampled_textures[i]->view,
|
|
};
|
|
}
|
|
Uint32 entry_offset = resources->num_vertex_sampled_textures;
|
|
|
|
for (int i = 0; i < resources->num_vertex_storage_textures; i++) {
|
|
entries[i] = (WGPUBindGroupEntry){
|
|
.binding = i,
|
|
.textureView = resources->vertex_storage_textures[i]->view,
|
|
};
|
|
}
|
|
entry_offset += resources->num_vertex_storage_textures;
|
|
|
|
for (int i = 0; i < resources->num_vertex_storage_buffers; i++) {
|
|
entries[entry_offset + i] = (WGPUBindGroupEntry){
|
|
.binding = entry_offset + 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_sampled_textures + resources->num_vertex_storage_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_sampled_textures || resources->num_fragment_storage_textures || resources->num_fragment_storage_buffers) {
|
|
WGPUBindGroupEntry *entries = SDL_stack_alloc(WGPUBindGroupEntry, resources->num_fragment_sampled_textures * 2 + resources->num_fragment_storage_textures + resources->num_fragment_storage_buffers);
|
|
|
|
for (int i = 0; i < resources->num_fragment_sampled_textures; i++) {
|
|
entries[i * 2] = (WGPUBindGroupEntry){
|
|
.binding = i * 2,
|
|
.textureView = resources->fragment_sampled_textures[i]->view,
|
|
};
|
|
|
|
entries[i * 2 + 1] = (WGPUBindGroupEntry){
|
|
.binding = i * 2 + 1,
|
|
.sampler = bilinear_sampler,
|
|
};
|
|
}
|
|
Uint32 entry_offset = resources->num_fragment_sampled_textures * 2;
|
|
|
|
for (int i = 0; i < resources->num_fragment_storage_textures; i++) {
|
|
entries[entry_offset + i] = (WGPUBindGroupEntry){
|
|
.binding = entry_offset + i,
|
|
.textureView = resources->fragment_storage_textures[i]->view,
|
|
};
|
|
}
|
|
entry_offset += resources->num_fragment_storage_textures;
|
|
|
|
for (int i = 0; i < resources->num_fragment_storage_buffers; i++) {
|
|
entries[entry_offset + i] = (WGPUBindGroupEntry){
|
|
.binding = entry_offset + 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_sampled_textures * 2 + resources->num_fragment_storage_textures + 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, vertex_buffer ? 1 : 0, 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_texture.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,
|
|
};
|
|
|
|
// Shaders
|
|
{ // Character
|
|
const char shader_source[] = {
|
|
#embed "shaders/wgsl/character.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 = "character shader", .length = WGPU_STRLEN }
|
|
});
|
|
|
|
shaders[R_SHADER_CHARACTER] = wgpuDeviceCreateRenderPipeline(device, &(WGPURenderPipelineDescriptor){
|
|
.label = { .data = "character render_pipeline", .length = WGPU_STRLEN },
|
|
|
|
.layout = wgpuDeviceCreatePipelineLayout(device, &(WGPUPipelineLayoutDescriptor){
|
|
.label = { .data = "character 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 = 1,
|
|
.buffers = (WGPUVertexBufferLayout[]){
|
|
{
|
|
.stepMode = WGPUVertexStepMode_Instance,
|
|
.arrayStride = 12,
|
|
.attributeCount = 2,
|
|
.attributes = (WGPUVertexAttribute[]){
|
|
{
|
|
.format = WGPUVertexFormat_Float32x2,
|
|
.offset = 0,
|
|
.shaderLocation = 2,
|
|
},
|
|
{
|
|
.format = WGPUVertexFormat_Uint32,
|
|
.offset = 8,
|
|
.shaderLocation = 3,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
.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);
|
|
}
|
|
|
|
{ // Character Shadow
|
|
const char shader_source[] = {
|
|
#embed "shaders/wgsl/character_shadow.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 = "character_shadow shader", .length = WGPU_STRLEN }
|
|
});
|
|
|
|
shaders[R_SHADER_CHARACTER_SHADOW] = wgpuDeviceCreateRenderPipeline(device, &(WGPURenderPipelineDescriptor){
|
|
.label = { .data = "character_shadow render_pipeline", .length = WGPU_STRLEN },
|
|
|
|
.layout = wgpuDeviceCreatePipelineLayout(device, &(WGPUPipelineLayoutDescriptor){
|
|
.label = { .data = "character_shadow 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 = 1,
|
|
.buffers = (WGPUVertexBufferLayout[]){
|
|
{
|
|
.stepMode = WGPUVertexStepMode_Instance,
|
|
.arrayStride = 12,
|
|
.attributeCount = 2,
|
|
.attributes = (WGPUVertexAttribute[]){
|
|
{
|
|
.format = WGPUVertexFormat_Float32x2,
|
|
.offset = 0,
|
|
.shaderLocation = 2,
|
|
},
|
|
{
|
|
.format = WGPUVertexFormat_Uint32,
|
|
.offset = 8,
|
|
.shaderLocation = 3,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
|
|
.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 = 0,
|
|
.buffers = NULL,
|
|
},
|
|
|
|
.primitive = {
|
|
.topology = WGPUPrimitiveTopology_LineList,
|
|
.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);
|
|
}
|
|
|
|
for (int i = 0; i < R_SHADER_COUNT; i++) {
|
|
SDL_assert(shaders[i]);
|
|
}
|
|
|
|
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;
|
|
}
|