From e7ad1d36ba7bbc1345bf83a1a912df7f4ccfdd36 Mon Sep 17 00:00:00 2001 From: Sven Balzer <4653051+Kyuusokuna@users.noreply.github.com> Date: Fri, 3 Jul 2026 14:19:41 +0200 Subject: [PATCH] add sdlgpu renderer --- CMakeLists.txt | 60 +- src/main.cpp | 50 +- src/renderer.h | 12 +- src/renderer_sdlgpu.c | 879 ++++++++++++++++++++++++++ src/renderer_wgpu.c | 50 +- src/shaders/compile_shaders.sh | 9 + src/shaders/spirv/basic.spv | Bin 0 -> 2488 bytes src/shaders/spirv/grid.spv | Bin 0 -> 2840 bytes src/shaders/spirv/world.spv | Bin 0 -> 5224 bytes src/shaders/src/basic.slang | 17 +- src/shaders/src/grid.slang | 8 +- src/shaders/src/wgsl_workaround.slang | 51 ++ src/shaders/src/world.slang | 61 +- src/shaders/wgsl/basic.wgsl | 8 +- src/shaders/wgsl/grid.wgsl | 11 +- src/shaders/wgsl/world.wgsl | 70 +- 16 files changed, 1161 insertions(+), 125 deletions(-) create mode 100644 src/renderer_sdlgpu.c create mode 100644 src/shaders/compile_shaders.sh create mode 100644 src/shaders/spirv/basic.spv create mode 100644 src/shaders/spirv/grid.spv create mode 100644 src/shaders/spirv/world.spv create mode 100644 src/shaders/src/wgsl_workaround.slang diff --git a/CMakeLists.txt b/CMakeLists.txt index a0a3031..7d6b11c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -46,27 +46,40 @@ add_library(imgui STATIC libs/imgui/imgui_tables.cpp libs/imgui/imgui_widgets.cpp libs/imgui/backends/imgui_impl_sdl3.cpp - libs/imgui/backends/imgui_impl_wgpu.cpp -) -target_include_directories(imgui PUBLIC - libs/imgui - libs/imgui/backends -) -target_link_libraries(imgui PRIVATE SDL3::SDL3 wgpu) -target_compile_definitions(imgui PRIVATE IMGUI_IMPL_WEBGPU_BACKEND_WGPU=1) -# Dear ImGui C bindings -add_library(dcimgui STATIC libs/dcimgui/dcimgui.cpp libs/dcimgui/dcimgui_internal.cpp libs/dcimgui/backends/dcimgui_impl_sdl3.cpp +) +target_include_directories(imgui PUBLIC + libs/imgui + libs/dcimgui + libs/imgui/backends +) +target_link_libraries(imgui PRIVATE SDL3::SDL3) + +# Dear ImGui WGPU backend +add_library(imgui_wgpu STATIC + libs/imgui/backends/imgui_impl_wgpu.cpp libs/dcimgui/backends/dcimgui_impl_wgpu.cpp ) -target_include_directories(dcimgui PUBLIC - libs/dcimgui +target_include_directories(imgui_wgpu PUBLIC + libs/imgui/backends libs/dcimgui/backends ) -target_link_libraries(dcimgui PRIVATE imgui SDL3::SDL3 wgpu) +target_link_libraries(imgui_wgpu PRIVATE imgui wgpu) +target_compile_definitions(imgui_wgpu PRIVATE IMGUI_IMPL_WEBGPU_BACKEND_WGPU=1) + +# Dear ImGui SDLGPU backend +add_library(imgui_sdlgpu STATIC + libs/imgui/backends/imgui_impl_sdlgpu3.cpp + libs/dcimgui/backends/dcimgui_impl_sdlgpu3.cpp +) +target_include_directories(imgui_sdlgpu PUBLIC + libs/imgui/backends + libs/dcimgui/backends +) +target_link_libraries(imgui_sdlgpu PRIVATE imgui SDL3::SDL3) # stb_image add_library(stb_image STATIC libs/stb/stb_image.c) @@ -90,7 +103,26 @@ target_link_libraries(mikemon SDL3_mixer::SDL3_mixer stb_image imgui - dcimgui + imgui_wgpu + TracyClient + wgpu +) + +add_executable(mikemon-sdlgpu + src/smol-atlas.cpp + src/change_directory.c + src/shaders/shaders.c + src/renderer_sdlgpu.c + src/main.cpp +) +target_link_libraries(mikemon-sdlgpu + PRIVATE + glm + SDL3::SDL3 + SDL3_mixer::SDL3_mixer + stb_image + imgui + imgui_sdlgpu TracyClient wgpu ) diff --git a/src/main.cpp b/src/main.cpp index 7c134e1..dfd55c1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -579,7 +579,7 @@ static bool load_map(const char *name, Map *result) { char buffer_name[256] = "Map "; SDL_strlcat(buffer_name, result->name, SDL_arraysize(buffer_name)); - result->texture = renderer_texture_create(R_TEXTURE_FORMAT_R16_UINT, R_TEXTURE_USAGE_SAMPLED, 1, result->size.x, result->size.y, result->tiles, "map_texture"); + result->texture = renderer_texture_create(R_TEXTURE_FORMAT_R16_UINT, R_TEXTURE_USAGE_STORAGE, 1, result->size.x, result->size.y, result->tiles, "map_texture"); SDL_Log("Loaded map file."); return true; @@ -1376,19 +1376,19 @@ static void render_editor() { ZoneScopedN("Draw Map"); renderer_frame_set_shader(R_SHADER_WORLD); renderer_frame_draw(NULL, NULL, NULL, 6, current_map.size.y * current_map.size.x, &(R_Draw_Resources){ - .vertex_textures = (R_Texture[]){ current_map.texture }, - .vertex_uniform_buffers = (R_Buffer[]){ view_projection_matrix_buffer, per_frame_buffer }, + .vertex_storage_textures = (R_Texture[]){ current_map.texture }, + .vertex_uniform_buffers = (R_Buffer[]){ view_projection_matrix_buffer, per_frame_buffer }, - .num_vertex_textures = 1, - .num_vertex_uniform_buffers = 2, + .num_vertex_storage_textures = 1, + .num_vertex_uniform_buffers = 2, - .fragment_textures = (R_Texture[]){ tile_textures_atlas }, - .fragment_storage_buffers = (R_Buffer[]){ tile_uvs_buffer }, - .fragment_uniform_buffers = (R_Buffer[]){ tint_color_buffer }, + .fragment_sampled_textures = (R_Texture[]){ tile_textures_atlas }, + .fragment_storage_buffers = (R_Buffer[]){ tile_uvs_buffer }, + .fragment_uniform_buffers = (R_Buffer[]){ tint_color_buffer }, - .num_fragment_textures = 1, - .num_fragment_storage_buffers = 1, - .num_fragment_uniform_buffers = 1, + .num_fragment_sampled_textures = 1, + .num_fragment_storage_buffers = 1, + .num_fragment_uniform_buffers = 1, }); } @@ -1532,19 +1532,19 @@ static void render_game() { ZoneScopedN("Draw Map"); renderer_frame_set_shader(R_SHADER_WORLD); renderer_frame_draw(NULL, NULL, NULL, 6, current_map.size.y * current_map.size.x, &(R_Draw_Resources){ - .vertex_textures = (R_Texture[]){ current_map.texture }, - .vertex_uniform_buffers = (R_Buffer[]){ view_projection_matrix_buffer, per_frame_buffer }, + .vertex_storage_textures = (R_Texture[]){ current_map.texture }, + .vertex_uniform_buffers = (R_Buffer[]){ view_projection_matrix_buffer, per_frame_buffer }, - .num_vertex_textures = 1, - .num_vertex_uniform_buffers = 2, + .num_vertex_storage_textures = 1, + .num_vertex_uniform_buffers = 2, - .fragment_textures = (R_Texture[]){ tile_textures_atlas }, - .fragment_storage_buffers = (R_Buffer[]){ tile_uvs_buffer }, - .fragment_uniform_buffers = (R_Buffer[]){ tint_color_buffer }, + .fragment_sampled_textures = (R_Texture[]){ tile_textures_atlas }, + .fragment_storage_buffers = (R_Buffer[]){ tile_uvs_buffer }, + .fragment_uniform_buffers = (R_Buffer[]){ tint_color_buffer }, - .num_fragment_textures = 1, - .num_fragment_storage_buffers = 1, - .num_fragment_uniform_buffers = 1, + .num_fragment_sampled_textures = 1, + .num_fragment_storage_buffers = 1, + .num_fragment_uniform_buffers = 1, }); } @@ -1556,11 +1556,11 @@ static void render_game() { .num_vertex_uniform_buffers = 1, - .fragment_textures = (R_Texture[]){ player_texture }, - .fragment_uniform_buffers = (R_Buffer[]){ tint_color_buffer }, + .fragment_sampled_textures = (R_Texture[]){ player_texture }, + .fragment_uniform_buffers = (R_Buffer[]){ tint_color_buffer }, - .num_fragment_textures = 1, - .num_fragment_uniform_buffers = 1, + .num_fragment_sampled_textures = 1, + .num_fragment_uniform_buffers = 1, }); } } diff --git a/src/renderer.h b/src/renderer.h index f5a17b0..5b7c633 100644 --- a/src/renderer.h +++ b/src/renderer.h @@ -62,19 +62,23 @@ typedef struct R_Buffer_Impl *R_Buffer; typedef struct R_Texture_Impl *R_Texture; typedef struct R_Draw_Resources { - R_Texture *vertex_textures; + R_Texture *vertex_sampled_textures; + R_Texture *vertex_storage_textures; R_Buffer *vertex_storage_buffers; R_Buffer *vertex_uniform_buffers; - Uint16 num_vertex_textures; + Uint16 num_vertex_sampled_textures; + Uint16 num_vertex_storage_textures; Uint16 num_vertex_storage_buffers; Uint16 num_vertex_uniform_buffers; - R_Texture *fragment_textures; + R_Texture *fragment_sampled_textures; + R_Texture *fragment_storage_textures; R_Buffer *fragment_storage_buffers; R_Buffer *fragment_uniform_buffers; - Uint16 num_fragment_textures; + Uint16 num_fragment_sampled_textures; + Uint16 num_fragment_storage_textures; Uint16 num_fragment_storage_buffers; Uint16 num_fragment_uniform_buffers; } R_Draw_Resources; diff --git a/src/renderer_sdlgpu.c b/src/renderer_sdlgpu.c new file mode 100644 index 0000000..5fe422b --- /dev/null +++ b/src/renderer_sdlgpu.c @@ -0,0 +1,879 @@ +#include "renderer.h" +#include + +static bool enable_debug_mode = false; + +typedef struct R_Buffer_Impl { + SDL_GPUBuffer *buffer; + void *cpu_uniform_data; + + Uint32 num_bytes; + R_Buffer_Usage usage; +} R_Buffer_Impl; + +typedef struct R_Texture_Impl { + SDL_GPUTexture *texture; + + Uint32 width; + Uint32 height; + + Uint32 sample_count; + R_Texture_Format format; +} R_Texture_Impl; + +R_Texture R_framebuffer; + +static SDL_Window *window; +static SDL_GPUDevice *device; + +static R_Texture_Format surface_format; +static SDL_GPUTexture *surface_texture; + +static R_Texture framebuffer; + +static SDL_GPUTransferBuffer *transfer_buffer; + +static SDL_GPUCommandBuffer *copy_command_buffer; +static SDL_GPUCopyPass *copy_pass; + +static SDL_GPUCommandBuffer *render_command_buffer; +static SDL_GPURenderPass *render_pass; + +static SDL_GPUSampler *bilinear_sampler; + +static SDL_GPUGraphicsPipeline *shaders[R_SHADER_COUNT]; + +static SDL_GPUTextureFormat texture_formats[] = { + [R_TEXTURE_FORMAT_R8_UNORM] = SDL_GPU_TEXTUREFORMAT_R8_UNORM, + [R_TEXTURE_FORMAT_R16_UINT] = SDL_GPU_TEXTUREFORMAT_R16_UINT, + [R_TEXTURE_FORMAT_RGBA8_UNORM] = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM, + [R_TEXTURE_FORMAT_RGBA8_UNORM_SRGB] = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB, + [R_TEXTURE_FORMAT_BGRA8_UNORM] = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM, + [R_TEXTURE_FORMAT_BGRA8_UNORM_SRGB] = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB, +}; +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 SDL_GPUTextureUsageFlags texture_usages[] = { + [R_TEXTURE_USAGE_SAMPLED] = SDL_GPU_TEXTUREUSAGE_SAMPLER, + [R_TEXTURE_USAGE_STORAGE] = SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ, + [R_TEXTURE_USAGE_TARGET] = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET, +}; +static_assert(SDL_arraysize(texture_usages) == R_TEXTURE_USAGE_COUNT); + +static SDL_GPUBufferUsageFlags buffer_usages[] = { + [R_BUFFER_USAGE_UNIFORM] = 0, + [R_BUFFER_USAGE_STORAGE] = SDL_GPU_BUFFERUSAGE_GRAPHICS_STORAGE_READ, + [R_BUFFER_USAGE_VERTEX] = SDL_GPU_BUFFERUSAGE_VERTEX, + [R_BUFFER_USAGE_INDEX] = SDL_GPU_BUFFERUSAGE_INDEX, +}; +static_assert(SDL_arraysize(buffer_usages) == R_BUFFER_USAGE_COUNT); + +static SDL_GPULoadOp load_ops[] = { + [R_LOAD_OP_LOAD] = SDL_GPU_LOADOP_LOAD, + [R_LOAD_OP_CLEAR] = SDL_GPU_LOADOP_CLEAR, +}; +static_assert(SDL_arraysize(load_ops) == R_LOAD_OP_COUNT); + +static SDL_GPUStoreOp store_ops[] = { + [R_STORE_OP_STORE] = SDL_GPU_STOREOP_STORE, + [R_STORE_OP_DISCARD] = SDL_GPU_STOREOP_DONT_CARE, +}; +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) { + SDL_PropertiesID properties = SDL_CreateProperties(); + SDL_SetStringProperty(properties, SDL_PROP_GPU_TEXTURE_CREATE_NAME_STRING, debug_name); + + SDL_GPUTexture *texture = SDL_CreateGPUTexture(device, &(SDL_GPUTextureCreateInfo){ + .type = SDL_GPU_TEXTURETYPE_2D, + .format = texture_formats[format], + .usage = texture_usages[usage], + .width = width, + .height = height, + .layer_count_or_depth = 1, + .num_levels = 1, + .sample_count = sample_count == 1 ? SDL_GPU_SAMPLECOUNT_1 : SDL_GPU_SAMPLECOUNT_8, + .props = properties, + }); + SDL_DestroyProperties(properties); + if (!texture) return NULL; + + R_Texture_Impl *result = SDL_calloc(1, sizeof(R_Texture_Impl)); + if (!result) { + SDL_ReleaseGPUTexture(device, texture); + return NULL; + } + + *result = (R_Texture_Impl){ + .texture = texture, + + .width = width, + .height = height, + + .sample_count = sample_count, + .format = format, + }; + + if (data) { + renderer_texture_update(result, 0, 0, width, height, data, width * texel_sizes[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) { + void *gpu_mem = SDL_MapGPUTransferBuffer(device, transfer_buffer, true); + SDL_memcpy(gpu_mem, data, bytes_per_row * height); + SDL_UnmapGPUTransferBuffer(device, transfer_buffer); + + SDL_UploadToGPUTexture(copy_pass, + &(SDL_GPUTextureTransferInfo){ + .transfer_buffer = transfer_buffer, + .offset = 0, + .pixels_per_row = width, + .rows_per_layer = height, + }, + &(SDL_GPUTextureRegion){ + .texture = texture->texture, + .mip_level = 0, + .layer = 0, + + .x = offset_x, + .y = offset_y, + .z = 0, + + .w = width, + .h = height, + .d = 1, + }, + false + ); +} + +void renderer_texture_destroy(R_Texture texture) { + SDL_ReleaseGPUTexture(device, texture->texture); + SDL_free(texture); +} + +R_Buffer renderer_buffer_create(R_Buffer_Usage usage, Uint32 num_bytes, void *data, const char *debug_name) { + R_Buffer_Impl *result = SDL_calloc(1, sizeof(R_Buffer_Impl)); + if (!result) return NULL; + + if (usage == R_BUFFER_USAGE_UNIFORM) { + *result = (R_Buffer_Impl){ + .cpu_uniform_data = SDL_calloc(1, num_bytes), + + .num_bytes = num_bytes, + .usage = usage, + }; + + if (!result->cpu_uniform_data) { + SDL_free(result); + return NULL; + } + + if (data) { + renderer_buffer_update(result, 0, num_bytes, data); + } + } else { + SDL_PropertiesID properties = SDL_CreateProperties(); + SDL_SetStringProperty(properties, SDL_PROP_GPU_BUFFER_CREATE_NAME_STRING, debug_name); + + SDL_GPUBuffer *buffer = SDL_CreateGPUBuffer(device, &(SDL_GPUBufferCreateInfo){ + .usage = buffer_usages[usage], + .size = num_bytes, + .props = properties, + }); + SDL_DestroyProperties(properties); + if (!buffer) { + SDL_free(result); + return NULL; + } + + *result = (R_Buffer_Impl){ + .buffer = buffer, + + .num_bytes = num_bytes, + .usage = usage, + }; + + if (data) { + renderer_buffer_update(result, 0, num_bytes, data); + } + } + + return result; +} + +void renderer_buffer_update(R_Buffer buffer, Uint32 offset, Uint32 num_bytes, void *data) { + SDL_assert(offset + num_bytes <= buffer->num_bytes); + + if (buffer->usage == R_BUFFER_USAGE_UNIFORM) { + memcpy(buffer->cpu_uniform_data, data + offset, num_bytes); + } else { + void *gpu_mem = SDL_MapGPUTransferBuffer(device, transfer_buffer, true); + SDL_memcpy(gpu_mem, data, num_bytes); + SDL_UnmapGPUTransferBuffer(device, transfer_buffer); + + SDL_UploadToGPUBuffer(copy_pass, + &(SDL_GPUTransferBufferLocation) { + .transfer_buffer = transfer_buffer, + .offset = 0, + }, + &(SDL_GPUBufferRegion){ + .buffer = buffer->buffer, + .offset = offset, + .size = num_bytes, + }, + false + ); + } +} + +void renderer_buffer_destroy(R_Buffer buffer) { + if (buffer->buffer) SDL_ReleaseGPUBuffer(device, buffer->buffer); + if (buffer->cpu_uniform_data) SDL_free(buffer->cpu_uniform_data); + SDL_free(buffer); +} + +void renderer_frame_begin() { + SDL_assert(R_framebuffer == NULL); + + Uint32 surface_width = 0, surface_height = 0; + SDL_WaitAndAcquireGPUSwapchainTexture(render_command_buffer, window, &surface_texture, &surface_width, &surface_height); + + if (!framebuffer || framebuffer->width != surface_width || framebuffer->height != surface_height) { + if (framebuffer) { + renderer_texture_destroy(framebuffer); + framebuffer = NULL; + } + + framebuffer = renderer_texture_create(surface_format, R_TEXTURE_USAGE_TARGET, 8, surface_width, surface_height, NULL, "R_framebuffer"); + } + + R_framebuffer = framebuffer; +} + +void renderer_frame_end() { + SDL_EndGPUCopyPass(copy_pass); + SDL_SubmitGPUCommandBuffer(copy_command_buffer); + + if (render_pass) { + SDL_EndGPURenderPass(render_pass); + render_pass = NULL; + } + + render_pass = SDL_BeginGPURenderPass(render_command_buffer, + &(SDL_GPUColorTargetInfo){ + .texture = framebuffer->texture, + .mip_level = 0, + .layer_or_depth_plane = 0, + + .clear_color = { 0.0f, 0.0f, 0.0f, 0.0f }, + .load_op = SDL_GPU_LOADOP_LOAD, + .store_op = SDL_GPU_STOREOP_RESOLVE, + + .resolve_texture = surface_texture, + .resolve_mip_level = 0, + .resolve_layer = 0, + + .cycle = false, + .cycle_resolve_texture = false, + }, + 1, + NULL + ); + SDL_EndGPURenderPass(render_pass); + render_pass = NULL; + + SDL_GPUFence *frame_fence = SDL_SubmitGPUCommandBufferAndAcquireFence(render_command_buffer); + SDL_WaitForGPUFences(device, true, &frame_fence, 1); + + copy_command_buffer = SDL_AcquireGPUCommandBuffer(device); + render_command_buffer = SDL_AcquireGPUCommandBuffer(device); + + R_framebuffer = NULL; + + copy_pass = SDL_BeginGPUCopyPass(copy_command_buffer); +} + +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) { + if (render_pass) { + SDL_EndGPURenderPass(render_pass); + render_pass = NULL; + } + + render_pass = SDL_BeginGPURenderPass(render_command_buffer, + &(SDL_GPUColorTargetInfo){ + .texture = target->texture, + .mip_level = 0, + .layer_or_depth_plane = 0, + + .clear_color = { clear_color.r, clear_color.g, clear_color.b, clear_color.a }, + .load_op = load_ops[load_op], + .store_op = resolve_target ? (store_op == R_STORE_OP_STORE ? SDL_GPU_STOREOP_RESOLVE_AND_STORE : SDL_GPU_STOREOP_RESOLVE) : store_ops[store_op], + + .resolve_texture = resolve_target ? resolve_target->texture : NULL, + .resolve_mip_level = 0, + .resolve_layer = 0, + + .cycle = false, + .cycle_resolve_texture = false, + }, + 1, + NULL + ); +} + +void renderer_frame_set_shader(R_Shader shader) { + SDL_BindGPUGraphicsPipeline(render_pass, shaders[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(render_pass); + + + for (int i = 0; i < resources->num_vertex_sampled_textures; i++) SDL_BindGPUVertexSamplers(render_pass, i, &(SDL_GPUTextureSamplerBinding){ .texture = resources->vertex_sampled_textures[i]->texture, .sampler = bilinear_sampler }, 1); + for (int i = 0; i < resources->num_vertex_storage_textures; i++) SDL_BindGPUVertexStorageTextures(render_pass, i, &resources->vertex_storage_textures[i]->texture, 1); + for (int i = 0; i < resources->num_vertex_storage_buffers; i++) SDL_BindGPUVertexStorageBuffers(render_pass, i, &resources->vertex_storage_buffers[i]->buffer, 1); + for (int i = 0; i < resources->num_vertex_uniform_buffers; i++) SDL_PushGPUVertexUniformData(render_command_buffer, i, resources->vertex_uniform_buffers[i]->cpu_uniform_data, resources->vertex_uniform_buffers[i]->num_bytes); + + for (int i = 0; i < resources->num_fragment_sampled_textures; i++) SDL_BindGPUFragmentSamplers(render_pass, i, &(SDL_GPUTextureSamplerBinding){ .texture = resources->fragment_sampled_textures[i]->texture, .sampler = bilinear_sampler }, 1); + for (int i = 0; i < resources->num_fragment_storage_textures; i++) SDL_BindGPUFragmentStorageTextures(render_pass, i, &resources->fragment_storage_textures[i]->texture, 1); + for (int i = 0; i < resources->num_fragment_storage_buffers; i++) SDL_BindGPUFragmentStorageBuffers(render_pass, i, &resources->fragment_storage_buffers[i]->buffer, 1); + for (int i = 0; i < resources->num_fragment_uniform_buffers; i++) SDL_PushGPUFragmentUniformData(render_command_buffer, i, resources->fragment_uniform_buffers[i]->cpu_uniform_data, resources->fragment_uniform_buffers[i]->num_bytes); + + if (vertex_buffer) SDL_BindGPUVertexBuffers(render_pass, 0, &(SDL_GPUBufferBinding){ .buffer = vertex_buffer->buffer, .offset = 0 }, 1); + if (instance_buffer) SDL_BindGPUVertexBuffers(render_pass, 1, &(SDL_GPUBufferBinding){ .buffer = instance_buffer->buffer, .offset = 0 }, 1); + + if (index_buffer) { + SDL_BindGPUIndexBuffer(render_pass, &(SDL_GPUBufferBinding){ .buffer = index_buffer->buffer, .offset = 0 }, SDL_GPU_INDEXELEMENTSIZE_16BIT); + SDL_DrawGPUIndexedPrimitives(render_pass, num_indices, num_instances, 0, 0, 0); + } else { + SDL_DrawGPUPrimitives(render_pass, num_indices, num_instances, 0, 0); + } +} + +static R_Texture_Format R_Texture_Format_from_SDL_GPUTextureFormat(SDL_GPUTextureFormat format) { + switch (format) { + case SDL_GPU_TEXTUREFORMAT_R8_UNORM: return R_TEXTURE_FORMAT_R8_UNORM; + case SDL_GPU_TEXTUREFORMAT_R16_UINT: return R_TEXTURE_FORMAT_R16_UINT; + case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM: return R_TEXTURE_FORMAT_RGBA8_UNORM; + case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB: return R_TEXTURE_FORMAT_RGBA8_UNORM_SRGB; + case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM: return R_TEXTURE_FORMAT_BGRA8_UNORM; + case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB: return R_TEXTURE_FORMAT_BGRA8_UNORM_SRGB; + + default: { + SDL_assert_always(false); + return R_TEXTURE_FORMAT_BGRA8_UNORM_SRGB; + }; + }; +} + +bool renderer_init(SDL_Window *window_) { + window = window_; + + device = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_SPIRV, enable_debug_mode, NULL); + if (!device) { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create gpu device."); + return false; + } + + if (!SDL_ClaimWindowForGPUDevice(device, window)) { + SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to claim window for gpu device."); + SDL_DestroyGPUDevice(device); + return false; + } + + SDL_SetGPUSwapchainParameters(device, window, SDL_GPU_SWAPCHAINCOMPOSITION_SDR_LINEAR, SDL_GPU_PRESENTMODE_VSYNC); + + surface_format = R_Texture_Format_from_SDL_GPUTextureFormat(SDL_GetGPUSwapchainTextureFormat(device, window)); + + bilinear_sampler = SDL_CreateGPUSampler(device, &(SDL_GPUSamplerCreateInfo){ + .min_filter = SDL_GPU_FILTER_LINEAR, + .mag_filter = SDL_GPU_FILTER_LINEAR, + .mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST, + + .address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE, + .address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE, + .address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE, + + .mip_lod_bias = 0.0f, + .max_anisotropy = 1.0f, + .compare_op = SDL_GPU_COMPAREOP_INVALID, + + .min_lod = 0.0f, + .max_lod = 0.0f, + + .enable_anisotropy = false, + .enable_compare = false, + }); + + // Shaders + { // Basic + const Uint8 shader_source[] = { + #embed "shaders/spirv/basic.spv" + }; + + SDL_GPUShader *vertex_shader = SDL_CreateGPUShader(device, &(SDL_GPUShaderCreateInfo){ + .code_size = sizeof(shader_source), + .code = shader_source, + .entrypoint = "main_vertex", + + .format = SDL_GPU_SHADERFORMAT_SPIRV, + .stage = SDL_GPU_SHADERSTAGE_VERTEX, + + .num_samplers = 0, + .num_storage_textures = 0, + .num_storage_buffers = 0, + .num_uniform_buffers = 1, + }); + + SDL_GPUShader *fragment_shader = SDL_CreateGPUShader(device, &(SDL_GPUShaderCreateInfo){ + .code_size = sizeof(shader_source), + .code = shader_source, + .entrypoint = "main_fragment", + + .format = SDL_GPU_SHADERFORMAT_SPIRV, + .stage = SDL_GPU_SHADERSTAGE_FRAGMENT, + + .num_samplers = 1, + .num_storage_textures = 0, + .num_storage_buffers = 0, + .num_uniform_buffers = 1, + }); + + SDL_PropertiesID properties = SDL_CreateProperties(); + SDL_SetStringProperty(properties, SDL_PROP_GPU_BUFFER_CREATE_NAME_STRING, "R_SHADER basic"); + + shaders[R_SHADER_BASIC] = SDL_CreateGPUGraphicsPipeline(device, &(SDL_GPUGraphicsPipelineCreateInfo){ + .vertex_shader = vertex_shader, + .fragment_shader = fragment_shader, + + .vertex_input_state = { + .vertex_buffer_descriptions = (SDL_GPUVertexBufferDescription[]){ + { + .slot = 0, + .pitch = 20, + .input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX, + + .instance_step_rate = 0, + }, + { + .slot = 1, + .pitch = 8, + .input_rate = SDL_GPU_VERTEXINPUTRATE_INSTANCE, + + .instance_step_rate = 0, + }, + }, + .num_vertex_buffers = 2, + + .vertex_attributes = (SDL_GPUVertexAttribute[]){ + { + .location = 0, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, + .offset = 0, + }, + { + .location = 1, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2, + .offset = 12, + }, + { + .location = 2, + .buffer_slot = 1, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT2, + .offset = 0, + }, + }, + .num_vertex_attributes = 3, + }, + + .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, + + .rasterizer_state = { + .fill_mode = SDL_GPU_FILLMODE_FILL, + .cull_mode = SDL_GPU_CULLMODE_BACK, + .front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE, + + .depth_bias_constant_factor = 0.0f, + .depth_bias_clamp = 0.0f, + .depth_bias_slope_factor = 0.0f, + + .enable_depth_bias = false, + .enable_depth_clip = false, + }, + + .multisample_state = { + .sample_count = SDL_GPU_SAMPLECOUNT_8, + .sample_mask = 0, + .enable_mask = 0, + + .enable_alpha_to_coverage = false, + }, + + .depth_stencil_state = { + .compare_op = SDL_GPU_COMPAREOP_GREATER_OR_EQUAL, + + .back_stencil_state = { .fail_op = SDL_GPU_STENCILOP_INVALID, .pass_op = SDL_GPU_STENCILOP_INVALID, .depth_fail_op = SDL_GPU_STENCILOP_INVALID, .compare_op = SDL_GPU_COMPAREOP_INVALID, }, + .front_stencil_state = { .fail_op = SDL_GPU_STENCILOP_INVALID, .pass_op = SDL_GPU_STENCILOP_INVALID, .depth_fail_op = SDL_GPU_STENCILOP_INVALID, .compare_op = SDL_GPU_COMPAREOP_INVALID, }, + + .compare_mask = 0, + .write_mask = 0, + + .enable_depth_test = false, + .enable_depth_write = false, + .enable_stencil_test = false, + }, + + .target_info = { + .color_target_descriptions = (SDL_GPUColorTargetDescription[]){ + { + .format = texture_formats[surface_format], + .blend_state = { + .src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA, + .dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, + .color_blend_op = SDL_GPU_BLENDOP_ADD, + + .src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA, + .dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, + .alpha_blend_op = SDL_GPU_BLENDOP_ADD, + + .color_write_mask = 0, + + .enable_blend = true, + .enable_color_write_mask = false, + }, + } + }, + + .num_color_targets = 1, + + .depth_stencil_format = SDL_GPU_TEXTUREFORMAT_INVALID, + .has_depth_stencil_target = false, + }, + }); + SDL_DestroyProperties(properties); + SDL_ReleaseGPUShader(device, vertex_shader); + SDL_ReleaseGPUShader(device, fragment_shader); + } + + { // World + const Uint8 shader_source[] = { + #embed "shaders/spirv/world.spv" + }; + + SDL_GPUShader *vertex_shader = SDL_CreateGPUShader(device, &(SDL_GPUShaderCreateInfo){ + .code_size = sizeof(shader_source), + .code = shader_source, + .entrypoint = "main_vertex", + + .format = SDL_GPU_SHADERFORMAT_SPIRV, + .stage = SDL_GPU_SHADERSTAGE_VERTEX, + + .num_samplers = 0, + .num_storage_textures = 1, + .num_storage_buffers = 0, + .num_uniform_buffers = 2, + }); + + SDL_GPUShader *fragment_shader = SDL_CreateGPUShader(device, &(SDL_GPUShaderCreateInfo){ + .code_size = sizeof(shader_source), + .code = shader_source, + .entrypoint = "main_fragment", + + .format = SDL_GPU_SHADERFORMAT_SPIRV, + .stage = SDL_GPU_SHADERSTAGE_FRAGMENT, + + .num_samplers = 1, + .num_storage_textures = 0, + .num_storage_buffers = 1, + .num_uniform_buffers = 1, + }); + + SDL_PropertiesID properties = SDL_CreateProperties(); + SDL_SetStringProperty(properties, SDL_PROP_GPU_BUFFER_CREATE_NAME_STRING, "R_SHADER world"); + + shaders[R_SHADER_WORLD] = SDL_CreateGPUGraphicsPipeline(device, &(SDL_GPUGraphicsPipelineCreateInfo){ + .vertex_shader = vertex_shader, + .fragment_shader = fragment_shader, + + .vertex_input_state = { + .vertex_buffer_descriptions = (SDL_GPUVertexBufferDescription[]){ + { + .slot = 0, + .pitch = 20, + .input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX, + + .instance_step_rate = 0, + }, + }, + .num_vertex_buffers = 1, + + .vertex_attributes = (SDL_GPUVertexAttribute[]){ + { + .location = 0, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, + .offset = 0, + }, + }, + .num_vertex_attributes = 1, + }, + + .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, + + .rasterizer_state = { + .fill_mode = SDL_GPU_FILLMODE_FILL, + .cull_mode = SDL_GPU_CULLMODE_BACK, + .front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE, + + .depth_bias_constant_factor = 0.0f, + .depth_bias_clamp = 0.0f, + .depth_bias_slope_factor = 0.0f, + + .enable_depth_bias = false, + .enable_depth_clip = false, + }, + + .multisample_state = { + .sample_count = SDL_GPU_SAMPLECOUNT_8, + .sample_mask = 0, + .enable_mask = 0, + + .enable_alpha_to_coverage = false, + }, + + .depth_stencil_state = { + .compare_op = SDL_GPU_COMPAREOP_GREATER_OR_EQUAL, + + .back_stencil_state = { .fail_op = SDL_GPU_STENCILOP_INVALID, .pass_op = SDL_GPU_STENCILOP_INVALID, .depth_fail_op = SDL_GPU_STENCILOP_INVALID, .compare_op = SDL_GPU_COMPAREOP_INVALID, }, + .front_stencil_state = { .fail_op = SDL_GPU_STENCILOP_INVALID, .pass_op = SDL_GPU_STENCILOP_INVALID, .depth_fail_op = SDL_GPU_STENCILOP_INVALID, .compare_op = SDL_GPU_COMPAREOP_INVALID, }, + + .compare_mask = 0, + .write_mask = 0, + + .enable_depth_test = false, + .enable_depth_write = false, + .enable_stencil_test = false, + }, + + .target_info = { + .color_target_descriptions = (SDL_GPUColorTargetDescription[]){ + { + .format = texture_formats[surface_format], + .blend_state = { + .src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA, + .dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, + .color_blend_op = SDL_GPU_BLENDOP_ADD, + + .src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA, + .dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, + .alpha_blend_op = SDL_GPU_BLENDOP_ADD, + + .color_write_mask = 0, + + .enable_blend = true, + .enable_color_write_mask = false, + }, + } + }, + + .num_color_targets = 1, + + .depth_stencil_format = SDL_GPU_TEXTUREFORMAT_INVALID, + .has_depth_stencil_target = false, + }, + }); + SDL_DestroyProperties(properties); + SDL_ReleaseGPUShader(device, vertex_shader); + SDL_ReleaseGPUShader(device, fragment_shader); + } + + { // Grid + const Uint8 shader_source[] = { + #embed "shaders/spirv/grid.spv" + }; + + SDL_GPUShader *vertex_shader = SDL_CreateGPUShader(device, &(SDL_GPUShaderCreateInfo){ + .code_size = sizeof(shader_source), + .code = shader_source, + .entrypoint = "main_vertex", + + .format = SDL_GPU_SHADERFORMAT_SPIRV, + .stage = SDL_GPU_SHADERSTAGE_VERTEX, + + .num_samplers = 0, + .num_storage_textures = 0, + .num_storage_buffers = 0, + .num_uniform_buffers = 2, + }); + + SDL_GPUShader *fragment_shader = SDL_CreateGPUShader(device, &(SDL_GPUShaderCreateInfo){ + .code_size = sizeof(shader_source), + .code = shader_source, + .entrypoint = "main_fragment", + + .format = SDL_GPU_SHADERFORMAT_SPIRV, + .stage = SDL_GPU_SHADERSTAGE_FRAGMENT, + + .num_samplers = 0, + .num_storage_textures = 0, + .num_storage_buffers = 0, + .num_uniform_buffers = 0, + }); + + SDL_PropertiesID properties = SDL_CreateProperties(); + SDL_SetStringProperty(properties, SDL_PROP_GPU_BUFFER_CREATE_NAME_STRING, "R_SHADER grid"); + + shaders[R_SHADER_GRID] = SDL_CreateGPUGraphicsPipeline(device, &(SDL_GPUGraphicsPipelineCreateInfo){ + .vertex_shader = vertex_shader, + .fragment_shader = fragment_shader, + + .vertex_input_state = { + .vertex_buffer_descriptions = (SDL_GPUVertexBufferDescription[]){ + { + .slot = 0, + .pitch = 20, + .input_rate = SDL_GPU_VERTEXINPUTRATE_VERTEX, + + .instance_step_rate = 0, + }, + }, + .num_vertex_buffers = 1, + + .vertex_attributes = (SDL_GPUVertexAttribute[]){ + { + .location = 0, + .buffer_slot = 0, + .format = SDL_GPU_VERTEXELEMENTFORMAT_FLOAT3, + .offset = 0, + }, + }, + .num_vertex_attributes = 1, + }, + + .primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST, + + .rasterizer_state = { + .fill_mode = SDL_GPU_FILLMODE_FILL, + .cull_mode = SDL_GPU_CULLMODE_BACK, + .front_face = SDL_GPU_FRONTFACE_COUNTER_CLOCKWISE, + + .depth_bias_constant_factor = 0.0f, + .depth_bias_clamp = 0.0f, + .depth_bias_slope_factor = 0.0f, + + .enable_depth_bias = false, + .enable_depth_clip = false, + }, + + .multisample_state = { + .sample_count = SDL_GPU_SAMPLECOUNT_8, + .sample_mask = 0, + .enable_mask = 0, + + .enable_alpha_to_coverage = false, + }, + + .depth_stencil_state = { + .compare_op = SDL_GPU_COMPAREOP_GREATER_OR_EQUAL, + + .back_stencil_state = { .fail_op = SDL_GPU_STENCILOP_INVALID, .pass_op = SDL_GPU_STENCILOP_INVALID, .depth_fail_op = SDL_GPU_STENCILOP_INVALID, .compare_op = SDL_GPU_COMPAREOP_INVALID, }, + .front_stencil_state = { .fail_op = SDL_GPU_STENCILOP_INVALID, .pass_op = SDL_GPU_STENCILOP_INVALID, .depth_fail_op = SDL_GPU_STENCILOP_INVALID, .compare_op = SDL_GPU_COMPAREOP_INVALID, }, + + .compare_mask = 0, + .write_mask = 0, + + .enable_depth_test = false, + .enable_depth_write = false, + .enable_stencil_test = false, + }, + + .target_info = { + .color_target_descriptions = (SDL_GPUColorTargetDescription[]){ + { + .format = texture_formats[surface_format], + .blend_state = { + .src_color_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA, + .dst_color_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, + .color_blend_op = SDL_GPU_BLENDOP_ADD, + + .src_alpha_blendfactor = SDL_GPU_BLENDFACTOR_SRC_ALPHA, + .dst_alpha_blendfactor = SDL_GPU_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, + .alpha_blend_op = SDL_GPU_BLENDOP_ADD, + + .color_write_mask = 0, + + .enable_blend = true, + .enable_color_write_mask = false, + }, + } + }, + + .num_color_targets = 1, + + .depth_stencil_format = SDL_GPU_TEXTUREFORMAT_INVALID, + .has_depth_stencil_target = false, + }, + }); + SDL_DestroyProperties(properties); + SDL_ReleaseGPUShader(device, vertex_shader); + SDL_ReleaseGPUShader(device, fragment_shader); + } + + transfer_buffer = SDL_CreateGPUTransferBuffer(device, &(SDL_GPUTransferBufferCreateInfo){ + .usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD, + .size = 64 * 1024, + }); + + copy_command_buffer = SDL_AcquireGPUCommandBuffer(device); + render_command_buffer = SDL_AcquireGPUCommandBuffer(device); + + copy_pass = SDL_BeginGPUCopyPass(copy_command_buffer); + + return true; +} + +void ImGui_ImplRenderer_Init() { + cImGui_ImplSDLGPU3_Init(&(ImGui_ImplSDLGPU3_InitInfo){ + .Device = device, + .ColorTargetFormat = texture_formats[surface_format], + .MSAASamples = SDL_GPU_SAMPLECOUNT_8, + .SwapchainComposition = SDL_GPU_SWAPCHAINCOMPOSITION_SDR, + .PresentMode = SDL_GPU_PRESENTMODE_VSYNC, + }); +} + +void ImGui_ImplRenderer_NewFrame() { + cImGui_ImplSDLGPU3_NewFrame(); +} + +void ImGui_ImplRenderer_Shutdown() { + cImGui_ImplSDLGPU3_Shutdown(); +} + +void ImGui_ImplRenderer_RenderDrawData(void* draw_data) { + SDL_EndGPUCopyPass(copy_pass); + cImGui_ImplSDLGPU3_PrepareDrawData(draw_data, copy_command_buffer); + copy_pass = SDL_BeginGPUCopyPass(copy_command_buffer); + + cImGui_ImplSDLGPU3_RenderDrawData(draw_data, render_command_buffer, render_pass); +} + +Uint64 ImGui_ImplRenderer_GetTextureID(R_Texture texture) { + return (Uint64)texture->texture; +} diff --git a/src/renderer_wgpu.c b/src/renderer_wgpu.c index f7c4e05..ac5d582 100644 --- a/src/renderer_wgpu.c +++ b/src/renderer_wgpu.c @@ -67,7 +67,7 @@ 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_STORAGE] = WGPUTextureUsage_TextureBinding, [R_TEXTURE_USAGE_TARGET] = WGPUTextureUsage_RenderAttachment, }; static_assert(SDL_arraysize(texture_usages) == R_TEXTURE_USAGE_COUNT); @@ -332,19 +332,28 @@ void renderer_frame_set_shader(R_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); + 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_textures; i++) { + for (int i = 0; i < resources->num_vertex_sampled_textures; i++) { entries[i] = (WGPUBindGroupEntry){ .binding = i, - .textureView = resources->vertex_textures[i]->view, + .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[resources->num_vertex_textures + i] = (WGPUBindGroupEntry){ - .binding = resources->num_vertex_textures + i, + entries[entry_offset + i] = (WGPUBindGroupEntry){ + .binding = entry_offset + i, .buffer = resources->vertex_storage_buffers[i]->buffer, .offset = 0, .size = WGPU_WHOLE_SIZE, @@ -353,7 +362,7 @@ void renderer_frame_draw(R_Buffer vertex_buffer, R_Buffer index_buffer, R_Buffer WGPUBindGroup bind_group = wgpuDeviceCreateBindGroup(device, &(WGPUBindGroupDescriptor){ .layout = wgpuRenderPipelineGetBindGroupLayout(shaders[current_shader], 0), - .entryCount = resources->num_vertex_textures + resources->num_vertex_storage_buffers, + .entryCount = resources->num_vertex_sampled_textures + resources->num_vertex_storage_textures + resources->num_vertex_storage_buffers, .entries = entries, }); @@ -391,13 +400,13 @@ void renderer_frame_draw(R_Buffer vertex_buffer, R_Buffer index_buffer, R_Buffer 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); + 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_textures; i++) { + for (int i = 0; i < resources->num_fragment_sampled_textures; i++) { entries[i * 2] = (WGPUBindGroupEntry){ .binding = i * 2, - .textureView = resources->fragment_textures[i]->view, + .textureView = resources->fragment_sampled_textures[i]->view, }; entries[i * 2 + 1] = (WGPUBindGroupEntry){ @@ -405,10 +414,19 @@ void renderer_frame_draw(R_Buffer vertex_buffer, R_Buffer index_buffer, R_Buffer .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[resources->num_fragment_textures * 2 + i] = (WGPUBindGroupEntry){ - .binding = resources->num_fragment_textures * 2 + i, + entries[entry_offset + i] = (WGPUBindGroupEntry){ + .binding = entry_offset + i, .buffer = resources->fragment_storage_buffers[i]->buffer, .offset = 0, .size = WGPU_WHOLE_SIZE, @@ -417,7 +435,7 @@ void renderer_frame_draw(R_Buffer vertex_buffer, R_Buffer index_buffer, R_Buffer WGPUBindGroup bind_group = wgpuDeviceCreateBindGroup(device, &(WGPUBindGroupDescriptor){ .layout = wgpuRenderPipelineGetBindGroupLayout(shaders[current_shader], 2), - .entryCount = resources->num_fragment_textures * 2 + resources->num_fragment_storage_buffers, + .entryCount = resources->num_fragment_sampled_textures * 2 + resources->num_fragment_storage_textures + resources->num_fragment_storage_buffers, .entries = entries, }); @@ -652,7 +670,7 @@ bool renderer_init(SDL_Window *window_) { .writeMask = WGPUColorWriteMask_All, }; - // Shader + // Shaders { // Basic const char shader_source[] = { #embed "shaders/wgsl/basic.wgsl" diff --git a/src/shaders/compile_shaders.sh b/src/shaders/compile_shaders.sh new file mode 100644 index 0000000..a3f2f0a --- /dev/null +++ b/src/shaders/compile_shaders.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +slangc src/basic.slang -target wgsl -D__wgsl__ -o wgsl/basic.wgsl +slangc src/world.slang -target wgsl -D__wgsl__ -o wgsl/world.wgsl +slangc src/grid.slang -target wgsl -D__wgsl__ -o wgsl/grid.wgsl + +slangc src/basic.slang -target spirv -profile spirv_1_0 -o spirv/basic.spv +slangc src/world.slang -target spirv -profile spirv_1_0 -o spirv/world.spv +slangc src/grid.slang -target spirv -profile spirv_1_0 -o spirv/grid.spv diff --git a/src/shaders/spirv/basic.spv b/src/shaders/spirv/basic.spv new file mode 100644 index 0000000000000000000000000000000000000000..7ca8a50aaa6b0137e4e25f3c8996cd98ee2624ef GIT binary patch literal 2488 zcmZvc+iz4=6o+>&Gg53Uh}=YBT4HQsop>3Hu?q32K9JC&1m7k@JB2ZwInC*5!6%1S z6dz3V4^W93<0bJ139pzKefGcc#f0xWvo{QemHcMyb=_;Nz0Qn{9)Bc+kr2Xc_?us8 zZx{_PMXu%1Pz{&h3#Z>cUEe5H>WvdGAcn`nn5>MR!b=(j-Bzd9+-m1V`$~8o`9-iF z%!0jODoliNcmtHat9k2Ux7{m{KLzt(54p8d9H+4|yR}rP#T=d9`esqToaJjP&Gl>p zeWko(pjV^sL^uLpzOcEv+RmHZR*`qEyuP}YwTijMT;pW3AX~Nc!7VhK-FEjvJGZ$? z*cFb#w>s_1&GkHcuf1G!vR=%gy;AlwxNmdI_)6Ga_DU!D`-@qpS1h*jR+pH2^Qh}- z?EmMa&b}YaR|)6PF~?#vZ#zc3CPE*cdfK9{ERQ|CY)7H&NgwIKp2ovAx`N8IRhX*t zerUbvP3p_pT9)Hmedv2F@RGiVv$7{;-&$E(;O%?^ZEumqvvhpG(2d{Ixf8=azWp9x zPV-FzDakXO-3euPOP?gWcY}=_*d5;en#Rjn56jMZIKQ&_2R)6IGfzGA(MzcZ@83oq zj#r)mej(bObGmOIS*>%r-0VTk2RK*J)xbgg?OoZKDDR50HS9;Ww;C|db5Wk;EY*;m zn>OQ&e;jT;>(TxMT)TSXwH*dhlAkQ4{;5OQpWdOg9}*}0pa0q;q?`~5pmpL}j|Hg*IgpIe;OpC!V% z{|StS^`dy${@o<}d&N literal 0 HcmV?d00001 diff --git a/src/shaders/spirv/grid.spv b/src/shaders/spirv/grid.spv new file mode 100644 index 0000000000000000000000000000000000000000..ca11d4d8a1a7ee01bb169032eac095bc93fd2e52 GIT binary patch literal 2840 zcmZvdTW?fV7>0K{?Eq3*kVEUKPN@okI*JxVp(O~kMXNMmG$GN+bh@Wb?Ht_QEj5y; zX+q@EYkz_9!VCTe{vHpBiO;jU7u_MO=I#2<>s{Zsc3bM7+!sZCQ52ny9`f6DBRC3E=Mxy63xu4(ddaG00ijy?njvDBz;3#+pj6?^b z0roYJ#Wj=qYCG*2qBfCgX}UJjP^$-*q7p@HkZ`faqW6Nt=C|5ZdyWR ze)PLmD2u0_P`FH{c5Ae|n;S8Eh?VbZ(psr?o6U_lePZ`!nf+dCCH;CYUheIBua=vs zJQ%%*tp_Kr(zdoX@7n70Hq&aayOG%rL>Ji`%bU$6vF&=Aw6-rd*Sqy}YI%_+G7-bl2iW+Uj=l8v2K_9@E9-yQOZclP=Yvg8#`JsvGe- zS@DXs<@fZQ2D!Pt-{rg)JxKSR%QI_-*;O0e^=?Ad@-yc;&%~X-b36;?nW^)T!va}h zW|QcyU~^vD_7`mCXggf6m2%ry!RDNddl`7XGnxR_4Eo7}?!3lQEJOeUB1WpZBHw}ejFoT9u@3E?8XNDd1PaZH}4pG1-Ps`%C65|sgJRHj`}#2 zoUJiJpZU8r2BH^`jWgyfxz>3Jlz?2Eoqpqk{}i%I|7mu)ir_zkY>s~4nzHB0?Jah> zh5F}^`+#=y^<4n2pud-CKVBKb|30#3*~4+FICE{D^#QwQX;Z(P>%l*l>-HgVy@~Ak za=XoL&#iHW+RAr?P8nQ9kL(SKbwJ#Cl`+NgbfOh%%cBg=Rebd%9?oFWm zr#!EUY_4`=e9QjNa89@AmO1a{HtnuH5b~#ytzpa(x3$0Lf%fp0HAk)fa&rtYg0Z5c>(T=LG#zamt&KJnq?eQUY^?%5-ruo(h zzPnHPjPXA5`4X7_8}slR`YN~Cuh7?h$Ug&TY0XBiE3YD(^B)tu2*P)~hRsz1^7)26 ze8*j6Ys$ehQ?Lns=e}~<%59!+pAvSLebUzh-va9@%fp)6z#bT{&zRuzZ(h-7jOWYa N2VlOjJGmb2^FN10^OXPq literal 0 HcmV?d00001 diff --git a/src/shaders/spirv/world.spv b/src/shaders/spirv/world.spv new file mode 100644 index 0000000000000000000000000000000000000000..864ab7e7b6d146fb880f688d9e6152b100c7b0fd GIT binary patch literal 5224 zcmaKv>yMpN6o+3OGrj7?DC$x}i&n?c%czFZR!WQ3OqHsToSd0CGY)g+j5BA(B}5UT ziMS*__~4TGLPDYmUtD`pABp}2{)F}$A`;K@p1pV-jm^qh>$lfl`?uF#?>^J6IjiPo z**RI3t;rryF_vX>vJFXZOxmf1Sx@#0de@%)drH%-(bB+;>v6NiS(hr$vV|^{-kt4`0$VJGKY(aJ|`g0_Y9cxy`>($8?{t7ny8vPxzl>Ej(6ss%W zK|bBtyle$}sM;*w*{sy7<(-vQr3|wT0}|`uKj$5zq-LhlBzX@j#m!M~%uH9&5i9TU zW^J_G7#o|ew*JOFVU9mp8*M%MPrUr=m8o)q$vii^3~YF!G4l9^(iGGz0zvdp4vJ#(Wtcg2l@wYE4R5B z<0zNw)%tL?>AAb9>mWLDn5|WxEKfBXk5xxnwZ>#hmEyb;D&Bm0s8O424OQSuz~A>) znwd4QM z;=J$7Kl5FAZ!QLN?Fn=b(&o~Y_o#K0>v6Or&SSj&DA(9aU#`}``_#Ao#@eICI>Il; z+Iy~Zujs?#UiM&dy}s+^XFmHe&e=;QT;hF2+x#xX@@##`MZ{ZkeeXiwe$to2a{T$| zKE$Da0lE({Zy)}J$rgA0C1`EeuOz$uE2fy+eC?d)W|v|cXUw{k`*Li#nA>wWZ@js$ zNw%2tYtizLdA}cR&uTvH>k)_ROK7<{zk*qR>x}U%=8U25UhXlFKx56Z8SNT52Ip3%zOny7Z1+VJhk2Z{M_lOOX(@jbWsE+_MeWLux(*!t%A9&MbMcm5;VJ2AI-41LF?tp5pZ zoa=uUWQavwPGfi0?+jSf%05{@Lih2^a`IaiGv|3|_ZHJ%l6>cH!S|c;Hvu>I{Z4$N zUE{nx=^N~bc;DcNwvz4llw%D)4_M#ns@Gk@LMY)${=b`1e7;(QPhfiV)l4&tKf@wavKKgh%cOTrI!7g%p4qvQzr_bYy zcXB%f*2(P!F!A8_BDR=0f}2=y^Ea@_Z5e)WJB(fA_8Puev2L&9i+6H+1FVzVn_%L> z?JaCEa|AcB;O1{}k(=L0aC-+^ZgGF_VvBY1cn_?T$NOO7!Q%sLF>?eDvEcC`c9BOf ze!O*q^pNj_zTf1%*nTVebMg0L`yH9f-z|OZPgAV+5p47P$xE>XiQj_H!5zLAz6D>P zbt=lhtoP7h%lBkqV?*WjB=IC5Q!BOYrX z#uhUN|L65Ix46F(=3j&D*%XIyF}JobHwWDME@GAIu4C>ObO|wsvDS7`;=L}-M{MBz z315(MoJ#$$1KgaiQY+V#u#FXuJ$GWer@w*DpGKcS;+<950i@_+G?)jI+P&%L}mG X(>wR?4mmEzH`Y17NB_PPi|_F-x6#rB literal 0 HcmV?d00001 diff --git a/src/shaders/src/basic.slang b/src/shaders/src/basic.slang index 1c4d19a..d39c65b 100644 --- a/src/shaders/src/basic.slang +++ b/src/shaders/src/basic.slang @@ -1,7 +1,7 @@ #language 2026 struct VertexShaderInput { - uint32_t vertex_index : SV_VertexID; + uint32_t vertex_index : SV_VulkanVertexID; [vk::location(0)] float3 pos; [vk::location(1)] float2 uv; @@ -46,9 +46,20 @@ FragmentShaderOutput main_fragment(VertexShaderOutput input) { return output; } +void GetDimensions(Sampler2D texture, out float width, out float height) { + __target_switch { + case wgsl: { + texture.__getTexture().GetDimensions(width, height); + } break; + default: { + texture.GetDimensions(width, height); + } break; + } +} + float4 pixel_art_sample(Sampler2D input_texture, float2 input_uv) { - var dimensions: float2; - input_texture.__getTexture().GetDimensions(dimensions.x, dimensions.y); + var dimensions : float2; + GetDimensions(input_texture, dimensions.x, dimensions.y); let texture_uv = input_uv * dimensions.xy; let sample_uv = (floor(texture_uv) + min(fract(texture_uv) / fwidth(texture_uv), float2(1.0, 1.0)) - 0.5) / dimensions.xy; diff --git a/src/shaders/src/grid.slang b/src/shaders/src/grid.slang index 519dc8e..83fbbca 100644 --- a/src/shaders/src/grid.slang +++ b/src/shaders/src/grid.slang @@ -1,8 +1,8 @@ #language 2026 struct VertexShaderInput { - uint32_t vertex_index : SV_VertexID; - uint32_t instance_index : SV_InstanceID; + uint32_t vertex_index : SV_VulkanVertexID; + uint32_t instance_index : SV_VulkanInstanceID; [vk::location(0)] float3 pos; }; @@ -26,7 +26,7 @@ struct Per_Frame_Data { }; [vk::binding(0, 1)] ConstantBuffer view_projection_matrix : register(b0, space1); -[vk::binding(1, 1)] ConstantBuffer per_frame : register(b1, space1); +[vk::binding(1, 1)] ConstantBuffer per_frame : register(b1, space1); [shader("vertex")] VertexShaderOutput main_vertex(VertexShaderInput input) { @@ -50,7 +50,7 @@ static const float4 selected_color = float4(1.0, 0.0, 1.0, 1.0); FragmentShaderOutput main_fragment(VertexShaderOutput input) { var output: FragmentShaderOutput; - output.color = select(input.selected != 0, selected_color, color); + output.color = input.selected != 0 ? selected_color : color; return output; } diff --git a/src/shaders/src/wgsl_workaround.slang b/src/shaders/src/wgsl_workaround.slang new file mode 100644 index 0000000..92ad1b0 --- /dev/null +++ b/src/shaders/src/wgsl_workaround.slang @@ -0,0 +1,51 @@ +struct CombinedTextureSampler { + #if !defined(__wgsl__) + private Sampler2D combined; + #else + private Texture2D texture; + private SamplerState sampler; + #endif + + Texture2D getTexture() { + #if !defined(__wgsl__) + return combined.__getTexture(); + #else + return texture; + #endif + } + + float4 Sample(float2 location, constexpr int2 offset, float clamp, out uint status) { + #if !defined(__wgsl__) + return combined.Sample(location, offset, clamp, status); + #else + return texture.Sample(sampler, location, offset, clamp, status); + #endif + } + + float4 Sample(float2 location, constexpr int2 offset, float clamp) { + #if !defined(__wgsl__) + return combined.Sample(location, offset, clamp); + #else + return texture.Sample(sampler, location, offset, clamp); + #endif + } + + float4 Sample(float2 location, constexpr int2 offset) { + #if !defined(__wgsl__) + return combined.Sample(location, offset); + #else + return texture.Sample(sampler, location, offset); + #endif + } + + float4 Sample(float2 location) { + #if !defined(__wgsl__) + return combined.Sample(location); + #else + return texture.Sample(sampler, location); + #endif + } + +}; + + diff --git a/src/shaders/src/world.slang b/src/shaders/src/world.slang index e3eabfd..6bb9cea 100644 --- a/src/shaders/src/world.slang +++ b/src/shaders/src/world.slang @@ -1,8 +1,10 @@ #language 2026 +#include "wgsl_workaround.slang" + struct VertexShaderInput { - uint32_t vertex_index : SV_VertexID; - uint32_t instance_index : SV_InstanceID; + uint32_t vertex_index : SV_VulkanVertexID; + uint32_t instance_index : SV_VulkanInstanceID; }; struct VertexShaderOutput { @@ -24,51 +26,64 @@ struct Per_Frame_Data { uint32_t map_width; }; -[vk::binding(0, 1)] ConstantBuffer view_projection_matrix : register(b0, space1); -[vk::binding(1, 1)] ConstantBuffer per_frame : register(b1, space1); +struct Block0 { + [format("r16ui")] + Texture2D map_texture; +}; -[vk::binding(0, 0)] Texture2D map_texture : register(t0, space0); +struct Block1 { + ConstantBuffer view_projection_matrix; + ConstantBuffer per_frame; +}; + +ParameterBlock block0; +ParameterBlock block1; [shader("vertex")] VertexShaderOutput main_vertex(VertexShaderInput input) { var output: VertexShaderOutput; - let tile_pos = uint32_t2(input.instance_index % per_frame.map_width, input.instance_index / per_frame.map_width); - output.tile = map_texture.Load(uint32_t3(tile_pos, 0)); + let tile_pos = uint32_t2(input.instance_index % block1.per_frame.map_width, input.instance_index / block1.per_frame.map_width); + output.tile = block0.map_texture.Load(uint32_t3(tile_pos, 0)); switch (input.vertex_index) { - case 0: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2(-0.5, 0.5), 0, 1), view_projection_matrix); output.uv = float2(0, 0); } break; - case 1: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2(-0.5, -0.5), 0, 1), view_projection_matrix); output.uv = float2(0, 1); } break; - case 2: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2( 0.5, -0.5), 0, 1), view_projection_matrix); output.uv = float2(1, 1); } break; - case 3: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2(-0.5, 0.5), 0, 1), view_projection_matrix); output.uv = float2(0, 0); } break; - case 4: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2( 0.5, -0.5), 0, 1), view_projection_matrix); output.uv = float2(1, 1); } break; - case 5: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2( 0.5, 0.5), 0, 1), view_projection_matrix); output.uv = float2(1, 0); } break; + case 0: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2(-0.5, 0.5), 0, 1), block1.view_projection_matrix); output.uv = float2(0, 0); } break; + case 1: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2(-0.5, -0.5), 0, 1), block1.view_projection_matrix); output.uv = float2(0, 1); } break; + case 2: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2( 0.5, -0.5), 0, 1), block1.view_projection_matrix); output.uv = float2(1, 1); } break; + case 3: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2(-0.5, 0.5), 0, 1), block1.view_projection_matrix); output.uv = float2(0, 0); } break; + case 4: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2( 0.5, -0.5), 0, 1), block1.view_projection_matrix); output.uv = float2(1, 1); } break; + case 5: { output.pos = mul(float4(float2(tile_pos) - float2(0.5, 0.5) + float2( 0.5, 0.5), 0, 1), block1.view_projection_matrix); output.uv = float2(1, 0); } break; default: {} } return output; } -[vk::binding(0, 2)] Sampler2D tile_atlas : register(t0, space2); -[vk::binding(2, 2)] StructuredBuffer tile_uvs : register(t1, space2); +struct Block2 { + CombinedTextureSampler tile_atlas; + StructuredBuffer tile_uvs; +}; -[vk::binding(0, 3)] ConstantBuffer tint : register(b0, space3); +struct Block3 { + ConstantBuffer tint; +}; + +ParameterBlock block2; +ParameterBlock block3; [shader("pixel")] FragmentShaderOutput main_fragment(VertexShaderOutput input) { var output: FragmentShaderOutput; - output.color = pixel_art_sample(tile_atlas, input.uv, input.tile); - output.color = float4(output.color.rgb * tint.rgb, output.color.a); + output.color = pixel_art_sample(block2.tile_atlas, input.uv, block2.tile_uvs[input.tile]); + output.color = float4(output.color.rgb * block3.tint.rgb, output.color.a); return output; } -float4 pixel_art_sample(Sampler2D input_texture, float2 input_uv, uint32_t tile) { - var dimensions: float2; - input_texture.__getTexture().GetDimensions(dimensions.x, dimensions.y); - - let tile_uv = tile_uvs[tile]; +float4 pixel_art_sample(CombinedTextureSampler input_texture, float2 input_uv, float4 tile_uv) { + var dimensions : float2; + input_texture.getTexture().GetDimensions(dimensions.x, dimensions.y); let texture_uv = lerp(tile_uv.xy, tile_uv.zw, input_uv); let sample_uv = (floor(texture_uv) + saturate(fract(texture_uv) / fwidth(texture_uv)) - 0.5) / dimensions; diff --git a/src/shaders/wgsl/basic.wgsl b/src/shaders/wgsl/basic.wgsl index ef8d547..1291d0e 100644 --- a/src/shaders/wgsl/basic.wgsl +++ b/src/shaders/wgsl/basic.wgsl @@ -31,12 +31,18 @@ fn main_vertex( _S1 : vertexInput_0, @builtin(vertex_index) vertex_index_0 : u32 return output_0; } +fn GetDimensions_0( texture_texture_0 : texture_2d, texture_sampler_0 : sampler, width_0 : ptr, height_0 : ptr) +{ + {var dim = textureDimensions((texture_texture_0));(((*width_0))) = f32(dim.x);(((*height_0))) = f32(dim.y);}; + return; +} + fn pixel_art_sample_0( input_texture_texture_0 : texture_2d, input_texture_sampler_0 : sampler, input_uv_0 : vec2) -> vec4 { var dimensions_0 : vec2; var _S2 : f32 = dimensions_0[i32(0)]; var _S3 : f32 = dimensions_0[i32(1)]; - {var dim = textureDimensions((input_texture_texture_0));((_S2)) = f32(dim.x);((_S3)) = f32(dim.y);}; + GetDimensions_0(input_texture_texture_0, input_texture_sampler_0, &(_S2), &(_S3)); dimensions_0[i32(0)] = _S2; dimensions_0[i32(1)] = _S3; var _S4 : vec2 = input_uv_0 * dimensions_0.xy; diff --git a/src/shaders/wgsl/grid.wgsl b/src/shaders/wgsl/grid.wgsl index 355047b..097a851 100644 --- a/src/shaders/wgsl/grid.wgsl +++ b/src/shaders/wgsl/grid.wgsl @@ -63,7 +63,16 @@ struct pixelInput_0 fn main_fragment( _S9 : pixelInput_0, @builtin(position) pos_2 : vec4) -> FragmentShaderOutput_0 { var output_1 : FragmentShaderOutput_0; - output_1.color_0 = select(vec4(1.0f, 1.0f, 1.0f, 0.10000000149011612f), vec4(1.0f, 0.0f, 1.0f, 1.0f), (_S9.selected_1) != i32(0)); + var _S10 : vec4; + if((_S9.selected_1) != i32(0)) + { + _S10 = vec4(1.0f, 0.0f, 1.0f, 1.0f); + } + else + { + _S10 = vec4(1.0f, 1.0f, 1.0f, 0.10000000149011612f); + } + output_1.color_0 = _S10; return output_1; } diff --git a/src/shaders/wgsl/world.wgsl b/src/shaders/wgsl/world.wgsl index 2291db7..17dd769 100644 --- a/src/shaders/wgsl/world.wgsl +++ b/src/shaders/wgsl/world.wgsl @@ -1,3 +1,9 @@ +struct _MatrixStorage_float4x4_ColMajorstd140_0 +{ + @align(16) data_0 : array, i32(4)>, +}; + +@binding(0) @group(1) var block1_view_projection_matrix_0 : _MatrixStorage_float4x4_ColMajorstd140_0; struct Per_Frame_Data_std140_0 { @align(16) drag_start_0 : vec2, @@ -7,22 +13,16 @@ struct Per_Frame_Data_std140_0 @align(4) map_width_0 : u32, }; -@binding(1) @group(1) var per_frame_0 : Per_Frame_Data_std140_0; -@binding(0) @group(0) var map_texture_0 : texture_2d; +@binding(1) @group(1) var block1_per_frame_0 : Per_Frame_Data_std140_0; +@binding(0) @group(0) var block0_map_texture_0 : texture_2d; -struct _MatrixStorage_float4x4_ColMajorstd140_0 -{ - @align(16) data_0 : array, i32(4)>, -}; +@binding(0) @group(2) var block2_tile_atlas_texture_0 : texture_2d; -@binding(0) @group(1) var view_projection_matrix_0 : _MatrixStorage_float4x4_ColMajorstd140_0; -@binding(2) @group(2) var tile_uvs_0 : array>; +@binding(1) @group(2) var block2_tile_atlas_sampler_0 : sampler; -@binding(0) @group(2) var tile_atlas_texture_0 : texture_2d; +@binding(2) @group(2) var block2_tile_uvs_0 : array>; -@binding(1) @group(2) var tile_atlas_sampler_0 : sampler; - -@binding(0) @group(3) var tint_0 : vec3; +@binding(0) @group(3) var block3_tint_0 : vec3; struct VertexShaderOutput_0 { @builtin(position) pos_0 : vec4, @@ -33,48 +33,48 @@ struct VertexShaderOutput_0 @vertex fn main_vertex(@builtin(vertex_index) vertex_index_0 : u32, @builtin(instance_index) instance_index_0 : u32) -> VertexShaderOutput_0 { - var _S1 : u32 = instance_index_0 % per_frame_0.map_width_0; - var _S2 : u32 = instance_index_0 / per_frame_0.map_width_0; + var _S1 : u32 = instance_index_0 % block1_per_frame_0.map_width_0; + var _S2 : u32 = instance_index_0 / block1_per_frame_0.map_width_0; var _S3 : vec2 = vec2(_S1, _S2); var output_0 : VertexShaderOutput_0; var _S4 : vec3 = vec3(vec3(_S3, u32(0))); - output_0.tile_0 = (textureLoad((map_texture_0), ((_S4)).xy, ((_S4)).z).x); + output_0.tile_0 = (textureLoad((block0_map_texture_0), ((_S4)).xy, ((_S4)).z).x); switch(vertex_index_0) { case u32(0): { - output_0.pos_0 = (((mat4x4(view_projection_matrix_0.data_0[i32(0)][i32(0)], view_projection_matrix_0.data_0[i32(1)][i32(0)], view_projection_matrix_0.data_0[i32(2)][i32(0)], view_projection_matrix_0.data_0[i32(3)][i32(0)], view_projection_matrix_0.data_0[i32(0)][i32(1)], view_projection_matrix_0.data_0[i32(1)][i32(1)], view_projection_matrix_0.data_0[i32(2)][i32(1)], view_projection_matrix_0.data_0[i32(3)][i32(1)], view_projection_matrix_0.data_0[i32(0)][i32(2)], view_projection_matrix_0.data_0[i32(1)][i32(2)], view_projection_matrix_0.data_0[i32(2)][i32(2)], view_projection_matrix_0.data_0[i32(3)][i32(2)], view_projection_matrix_0.data_0[i32(0)][i32(3)], view_projection_matrix_0.data_0[i32(1)][i32(3)], view_projection_matrix_0.data_0[i32(2)][i32(3)], view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4(vec2(_S3) - vec2(0.5f, 0.5f) + vec2(-0.5f, 0.5f), 0.0f, 1.0f)))); + output_0.pos_0 = (((mat4x4(block1_view_projection_matrix_0.data_0[i32(0)][i32(0)], block1_view_projection_matrix_0.data_0[i32(1)][i32(0)], block1_view_projection_matrix_0.data_0[i32(2)][i32(0)], block1_view_projection_matrix_0.data_0[i32(3)][i32(0)], block1_view_projection_matrix_0.data_0[i32(0)][i32(1)], block1_view_projection_matrix_0.data_0[i32(1)][i32(1)], block1_view_projection_matrix_0.data_0[i32(2)][i32(1)], block1_view_projection_matrix_0.data_0[i32(3)][i32(1)], block1_view_projection_matrix_0.data_0[i32(0)][i32(2)], block1_view_projection_matrix_0.data_0[i32(1)][i32(2)], block1_view_projection_matrix_0.data_0[i32(2)][i32(2)], block1_view_projection_matrix_0.data_0[i32(3)][i32(2)], block1_view_projection_matrix_0.data_0[i32(0)][i32(3)], block1_view_projection_matrix_0.data_0[i32(1)][i32(3)], block1_view_projection_matrix_0.data_0[i32(2)][i32(3)], block1_view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4(vec2(_S3) - vec2(0.5f, 0.5f) + vec2(-0.5f, 0.5f), 0.0f, 1.0f)))); output_0.uv_0 = vec2(0.0f, 0.0f); break; } case u32(1): { - output_0.pos_0 = (((mat4x4(view_projection_matrix_0.data_0[i32(0)][i32(0)], view_projection_matrix_0.data_0[i32(1)][i32(0)], view_projection_matrix_0.data_0[i32(2)][i32(0)], view_projection_matrix_0.data_0[i32(3)][i32(0)], view_projection_matrix_0.data_0[i32(0)][i32(1)], view_projection_matrix_0.data_0[i32(1)][i32(1)], view_projection_matrix_0.data_0[i32(2)][i32(1)], view_projection_matrix_0.data_0[i32(3)][i32(1)], view_projection_matrix_0.data_0[i32(0)][i32(2)], view_projection_matrix_0.data_0[i32(1)][i32(2)], view_projection_matrix_0.data_0[i32(2)][i32(2)], view_projection_matrix_0.data_0[i32(3)][i32(2)], view_projection_matrix_0.data_0[i32(0)][i32(3)], view_projection_matrix_0.data_0[i32(1)][i32(3)], view_projection_matrix_0.data_0[i32(2)][i32(3)], view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4(vec2(_S3) - vec2(0.5f, 0.5f) + vec2(-0.5f, -0.5f), 0.0f, 1.0f)))); + output_0.pos_0 = (((mat4x4(block1_view_projection_matrix_0.data_0[i32(0)][i32(0)], block1_view_projection_matrix_0.data_0[i32(1)][i32(0)], block1_view_projection_matrix_0.data_0[i32(2)][i32(0)], block1_view_projection_matrix_0.data_0[i32(3)][i32(0)], block1_view_projection_matrix_0.data_0[i32(0)][i32(1)], block1_view_projection_matrix_0.data_0[i32(1)][i32(1)], block1_view_projection_matrix_0.data_0[i32(2)][i32(1)], block1_view_projection_matrix_0.data_0[i32(3)][i32(1)], block1_view_projection_matrix_0.data_0[i32(0)][i32(2)], block1_view_projection_matrix_0.data_0[i32(1)][i32(2)], block1_view_projection_matrix_0.data_0[i32(2)][i32(2)], block1_view_projection_matrix_0.data_0[i32(3)][i32(2)], block1_view_projection_matrix_0.data_0[i32(0)][i32(3)], block1_view_projection_matrix_0.data_0[i32(1)][i32(3)], block1_view_projection_matrix_0.data_0[i32(2)][i32(3)], block1_view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4(vec2(_S3) - vec2(0.5f, 0.5f) + vec2(-0.5f, -0.5f), 0.0f, 1.0f)))); output_0.uv_0 = vec2(0.0f, 1.0f); break; } case u32(2): { - output_0.pos_0 = (((mat4x4(view_projection_matrix_0.data_0[i32(0)][i32(0)], view_projection_matrix_0.data_0[i32(1)][i32(0)], view_projection_matrix_0.data_0[i32(2)][i32(0)], view_projection_matrix_0.data_0[i32(3)][i32(0)], view_projection_matrix_0.data_0[i32(0)][i32(1)], view_projection_matrix_0.data_0[i32(1)][i32(1)], view_projection_matrix_0.data_0[i32(2)][i32(1)], view_projection_matrix_0.data_0[i32(3)][i32(1)], view_projection_matrix_0.data_0[i32(0)][i32(2)], view_projection_matrix_0.data_0[i32(1)][i32(2)], view_projection_matrix_0.data_0[i32(2)][i32(2)], view_projection_matrix_0.data_0[i32(3)][i32(2)], view_projection_matrix_0.data_0[i32(0)][i32(3)], view_projection_matrix_0.data_0[i32(1)][i32(3)], view_projection_matrix_0.data_0[i32(2)][i32(3)], view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4(vec2(_S3) - vec2(0.5f, 0.5f) + vec2(0.5f, -0.5f), 0.0f, 1.0f)))); + output_0.pos_0 = (((mat4x4(block1_view_projection_matrix_0.data_0[i32(0)][i32(0)], block1_view_projection_matrix_0.data_0[i32(1)][i32(0)], block1_view_projection_matrix_0.data_0[i32(2)][i32(0)], block1_view_projection_matrix_0.data_0[i32(3)][i32(0)], block1_view_projection_matrix_0.data_0[i32(0)][i32(1)], block1_view_projection_matrix_0.data_0[i32(1)][i32(1)], block1_view_projection_matrix_0.data_0[i32(2)][i32(1)], block1_view_projection_matrix_0.data_0[i32(3)][i32(1)], block1_view_projection_matrix_0.data_0[i32(0)][i32(2)], block1_view_projection_matrix_0.data_0[i32(1)][i32(2)], block1_view_projection_matrix_0.data_0[i32(2)][i32(2)], block1_view_projection_matrix_0.data_0[i32(3)][i32(2)], block1_view_projection_matrix_0.data_0[i32(0)][i32(3)], block1_view_projection_matrix_0.data_0[i32(1)][i32(3)], block1_view_projection_matrix_0.data_0[i32(2)][i32(3)], block1_view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4(vec2(_S3) - vec2(0.5f, 0.5f) + vec2(0.5f, -0.5f), 0.0f, 1.0f)))); output_0.uv_0 = vec2(1.0f, 1.0f); break; } case u32(3): { - output_0.pos_0 = (((mat4x4(view_projection_matrix_0.data_0[i32(0)][i32(0)], view_projection_matrix_0.data_0[i32(1)][i32(0)], view_projection_matrix_0.data_0[i32(2)][i32(0)], view_projection_matrix_0.data_0[i32(3)][i32(0)], view_projection_matrix_0.data_0[i32(0)][i32(1)], view_projection_matrix_0.data_0[i32(1)][i32(1)], view_projection_matrix_0.data_0[i32(2)][i32(1)], view_projection_matrix_0.data_0[i32(3)][i32(1)], view_projection_matrix_0.data_0[i32(0)][i32(2)], view_projection_matrix_0.data_0[i32(1)][i32(2)], view_projection_matrix_0.data_0[i32(2)][i32(2)], view_projection_matrix_0.data_0[i32(3)][i32(2)], view_projection_matrix_0.data_0[i32(0)][i32(3)], view_projection_matrix_0.data_0[i32(1)][i32(3)], view_projection_matrix_0.data_0[i32(2)][i32(3)], view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4(vec2(_S3) - vec2(0.5f, 0.5f) + vec2(-0.5f, 0.5f), 0.0f, 1.0f)))); + output_0.pos_0 = (((mat4x4(block1_view_projection_matrix_0.data_0[i32(0)][i32(0)], block1_view_projection_matrix_0.data_0[i32(1)][i32(0)], block1_view_projection_matrix_0.data_0[i32(2)][i32(0)], block1_view_projection_matrix_0.data_0[i32(3)][i32(0)], block1_view_projection_matrix_0.data_0[i32(0)][i32(1)], block1_view_projection_matrix_0.data_0[i32(1)][i32(1)], block1_view_projection_matrix_0.data_0[i32(2)][i32(1)], block1_view_projection_matrix_0.data_0[i32(3)][i32(1)], block1_view_projection_matrix_0.data_0[i32(0)][i32(2)], block1_view_projection_matrix_0.data_0[i32(1)][i32(2)], block1_view_projection_matrix_0.data_0[i32(2)][i32(2)], block1_view_projection_matrix_0.data_0[i32(3)][i32(2)], block1_view_projection_matrix_0.data_0[i32(0)][i32(3)], block1_view_projection_matrix_0.data_0[i32(1)][i32(3)], block1_view_projection_matrix_0.data_0[i32(2)][i32(3)], block1_view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4(vec2(_S3) - vec2(0.5f, 0.5f) + vec2(-0.5f, 0.5f), 0.0f, 1.0f)))); output_0.uv_0 = vec2(0.0f, 0.0f); break; } case u32(4): { - output_0.pos_0 = (((mat4x4(view_projection_matrix_0.data_0[i32(0)][i32(0)], view_projection_matrix_0.data_0[i32(1)][i32(0)], view_projection_matrix_0.data_0[i32(2)][i32(0)], view_projection_matrix_0.data_0[i32(3)][i32(0)], view_projection_matrix_0.data_0[i32(0)][i32(1)], view_projection_matrix_0.data_0[i32(1)][i32(1)], view_projection_matrix_0.data_0[i32(2)][i32(1)], view_projection_matrix_0.data_0[i32(3)][i32(1)], view_projection_matrix_0.data_0[i32(0)][i32(2)], view_projection_matrix_0.data_0[i32(1)][i32(2)], view_projection_matrix_0.data_0[i32(2)][i32(2)], view_projection_matrix_0.data_0[i32(3)][i32(2)], view_projection_matrix_0.data_0[i32(0)][i32(3)], view_projection_matrix_0.data_0[i32(1)][i32(3)], view_projection_matrix_0.data_0[i32(2)][i32(3)], view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4(vec2(_S3) - vec2(0.5f, 0.5f) + vec2(0.5f, -0.5f), 0.0f, 1.0f)))); + output_0.pos_0 = (((mat4x4(block1_view_projection_matrix_0.data_0[i32(0)][i32(0)], block1_view_projection_matrix_0.data_0[i32(1)][i32(0)], block1_view_projection_matrix_0.data_0[i32(2)][i32(0)], block1_view_projection_matrix_0.data_0[i32(3)][i32(0)], block1_view_projection_matrix_0.data_0[i32(0)][i32(1)], block1_view_projection_matrix_0.data_0[i32(1)][i32(1)], block1_view_projection_matrix_0.data_0[i32(2)][i32(1)], block1_view_projection_matrix_0.data_0[i32(3)][i32(1)], block1_view_projection_matrix_0.data_0[i32(0)][i32(2)], block1_view_projection_matrix_0.data_0[i32(1)][i32(2)], block1_view_projection_matrix_0.data_0[i32(2)][i32(2)], block1_view_projection_matrix_0.data_0[i32(3)][i32(2)], block1_view_projection_matrix_0.data_0[i32(0)][i32(3)], block1_view_projection_matrix_0.data_0[i32(1)][i32(3)], block1_view_projection_matrix_0.data_0[i32(2)][i32(3)], block1_view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4(vec2(_S3) - vec2(0.5f, 0.5f) + vec2(0.5f, -0.5f), 0.0f, 1.0f)))); output_0.uv_0 = vec2(1.0f, 1.0f); break; } case u32(5): { const _S5 : vec2 = vec2(0.5f, 0.5f); - output_0.pos_0 = (((mat4x4(view_projection_matrix_0.data_0[i32(0)][i32(0)], view_projection_matrix_0.data_0[i32(1)][i32(0)], view_projection_matrix_0.data_0[i32(2)][i32(0)], view_projection_matrix_0.data_0[i32(3)][i32(0)], view_projection_matrix_0.data_0[i32(0)][i32(1)], view_projection_matrix_0.data_0[i32(1)][i32(1)], view_projection_matrix_0.data_0[i32(2)][i32(1)], view_projection_matrix_0.data_0[i32(3)][i32(1)], view_projection_matrix_0.data_0[i32(0)][i32(2)], view_projection_matrix_0.data_0[i32(1)][i32(2)], view_projection_matrix_0.data_0[i32(2)][i32(2)], view_projection_matrix_0.data_0[i32(3)][i32(2)], view_projection_matrix_0.data_0[i32(0)][i32(3)], view_projection_matrix_0.data_0[i32(1)][i32(3)], view_projection_matrix_0.data_0[i32(2)][i32(3)], view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4(vec2(_S3) - _S5 + _S5, 0.0f, 1.0f)))); + output_0.pos_0 = (((mat4x4(block1_view_projection_matrix_0.data_0[i32(0)][i32(0)], block1_view_projection_matrix_0.data_0[i32(1)][i32(0)], block1_view_projection_matrix_0.data_0[i32(2)][i32(0)], block1_view_projection_matrix_0.data_0[i32(3)][i32(0)], block1_view_projection_matrix_0.data_0[i32(0)][i32(1)], block1_view_projection_matrix_0.data_0[i32(1)][i32(1)], block1_view_projection_matrix_0.data_0[i32(2)][i32(1)], block1_view_projection_matrix_0.data_0[i32(3)][i32(1)], block1_view_projection_matrix_0.data_0[i32(0)][i32(2)], block1_view_projection_matrix_0.data_0[i32(1)][i32(2)], block1_view_projection_matrix_0.data_0[i32(2)][i32(2)], block1_view_projection_matrix_0.data_0[i32(3)][i32(2)], block1_view_projection_matrix_0.data_0[i32(0)][i32(3)], block1_view_projection_matrix_0.data_0[i32(1)][i32(3)], block1_view_projection_matrix_0.data_0[i32(2)][i32(3)], block1_view_projection_matrix_0.data_0[i32(3)][i32(3)])) * (vec4(vec2(_S3) - _S5 + _S5, 0.0f, 1.0f)))); output_0.uv_0 = vec2(1.0f, 0.0f); break; } @@ -86,7 +86,12 @@ fn main_vertex(@builtin(vertex_index) vertex_index_0 : u32, @builtin(instance_in return output_0; } -fn pixel_art_sample_0( input_texture_texture_0 : texture_2d, input_texture_sampler_0 : sampler, input_uv_0 : vec2, tile_1 : u32) -> vec4 +fn CombinedTextureSampler_Sample_0( this_texture_0 : texture_2d, this_sampler_0 : sampler, location_0 : vec2) -> vec4 +{ + return (textureSample((this_texture_0), (this_sampler_0), (location_0))); +} + +fn pixel_art_sample_0( input_texture_texture_0 : texture_2d, input_texture_sampler_0 : sampler, input_uv_0 : vec2, tile_uv_0 : vec4) -> vec4 { var dimensions_0 : vec2; var _S6 : f32 = dimensions_0[i32(0)]; @@ -94,14 +99,11 @@ fn pixel_art_sample_0( input_texture_texture_0 : texture_2d, input_texture {var dim = textureDimensions((input_texture_texture_0));((_S6)) = f32(dim.x);((_S7)) = f32(dim.y);}; dimensions_0[i32(0)] = _S6; dimensions_0[i32(1)] = _S7; - var _S8 : vec4 = tile_uvs_0[tile_1]; - var _S9 : vec2 = _S8.xy; - var _S10 : vec2 = _S8.zw; - var _S11 : vec2 = mix(_S9, _S10, input_uv_0); - var _S12 : vec2 = vec2(0.5f); - var _S13 : vec2 = clamp((floor(_S11) + saturate(fract(_S11) / (fwidth((_S11)))) - _S12) / dimensions_0, (_S9 + _S12) / dimensions_0, (_S10 - _S12) / dimensions_0); - ; - return (textureSample((input_texture_texture_0), (input_texture_sampler_0), (_S13))); + var _S8 : vec2 = tile_uv_0.xy; + var _S9 : vec2 = tile_uv_0.zw; + var _S10 : vec2 = mix(_S8, _S9, input_uv_0); + var _S11 : vec2 = vec2(0.5f); + return CombinedTextureSampler_Sample_0(input_texture_texture_0, input_texture_sampler_0, clamp((floor(_S10) + saturate(fract(_S10) / (fwidth((_S10)))) - _S11) / dimensions_0, (_S8 + _S11) / dimensions_0, (_S9 - _S11) / dimensions_0)); } struct FragmentShaderOutput_0 @@ -112,15 +114,15 @@ struct FragmentShaderOutput_0 struct pixelInput_0 { @location(0) uv_1 : vec2, - @location(1) tile_2 : u32, + @location(1) tile_1 : u32, }; @fragment -fn main_fragment( _S14 : pixelInput_0, @builtin(position) pos_1 : vec4) -> FragmentShaderOutput_0 +fn main_fragment( _S12 : pixelInput_0, @builtin(position) pos_1 : vec4) -> FragmentShaderOutput_0 { var output_1 : FragmentShaderOutput_0; - var _S15 : vec4 = pixel_art_sample_0(tile_atlas_texture_0, tile_atlas_sampler_0, _S14.uv_1, _S14.tile_2); - output_1.color_0 = vec4(_S15.xyz * tint_0.xyz, _S15.w); + var _S13 : vec4 = pixel_art_sample_0(block2_tile_atlas_texture_0, block2_tile_atlas_sampler_0, _S12.uv_1, block2_tile_uvs_0[_S12.tile_1]); + output_1.color_0 = vec4(_S13.xyz * block3_tint_0.xyz, _S13.w); return output_1; }