diff options
| -rw-r--r-- | src/3d/renderer.cc | 250 | ||||
| -rw-r--r-- | src/gpu/effect.cc | 6 | ||||
| -rw-r--r-- | src/gpu/effects/shader_composer.cc | 10 | ||||
| -rw-r--r-- | src/gpu/effects/shader_composer.h | 5 | ||||
| -rw-r--r-- | src/gpu/gpu.cc | 111 | ||||
| -rw-r--r-- | src/gpu/texture_manager.cc | 17 | ||||
| -rw-r--r-- | src/platform/platform.cc | 87 | ||||
| -rw-r--r-- | src/platform/platform.h | 84 | ||||
| -rw-r--r-- | src/util/mesh_utils.h | 13 |
9 files changed, 456 insertions, 127 deletions
diff --git a/src/3d/renderer.cc b/src/3d/renderer.cc index e08a0d0..0bc8812 100644 --- a/src/3d/renderer.cc +++ b/src/3d/renderer.cc @@ -5,6 +5,7 @@ #include "generated/assets.h" #include "gpu/effects/shader_composer.h" #include "util/asset_manager.h" +#include "util/mesh_utils.h" #include <algorithm> #include <cassert> #include <cstring> @@ -124,7 +125,254 @@ void Renderer3D::create_default_resources() { WGPUBufferUsage_Storage | WGPUBufferUsage_CopyDst, nullptr) .buffer; } +void Renderer3D::create_pipeline() { + // Shader Modules + std::string sdf_shader_source = + ShaderComposer::Get().Compose(std::vector<std::string>{}, AssetId::ASSET_SHADER_RENDER_SCENE_QUERY_BVH); + WGPUShaderModuleDescriptor sdf_shader_desc = + platform_create_shader_module_descriptor(sdf_shader_source.c_str()); + WGPUShaderModule sdf_shader_module = + wgpuDeviceCreateShaderModule(device_, &sdf_shader_desc); + std::string sdf_no_bvh_shader_source = + ShaderComposer::Get().Compose(std::vector<std::string>{}, AssetId::ASSET_SHADER_RENDER_SCENE_QUERY_LINEAR); + WGPUShaderModuleDescriptor sdf_no_bvh_shader_desc = + platform_create_shader_module_descriptor( + sdf_no_bvh_shader_source.c_str()); + WGPUShaderModule sdf_no_bvh_shader_module = + wgpuDeviceCreateShaderModule(device_, &sdf_no_bvh_shader_desc); + + // Mesh Shader Module + std::string mesh_shader_source = + ShaderComposer::Get().Compose(std::vector<std::string>{}, AssetId::ASSET_SHADER_RENDER_SHADOWS); // Use SHADOWS shader + WGPUShaderModuleDescriptor mesh_shader_desc = + platform_create_shader_module_descriptor(mesh_shader_source.c_str()); + WGPUShaderModule mesh_shader_module = + wgpuDeviceCreateShaderModule(device_, &mesh_shader_desc); + + // Bind Group Layouts and Pipelines (SDF) + std::vector<WGPUBindGroupLayoutEntry> bgl_entries; + // Uniforms + bgl_entries.push_back({.binding = 0, + .visibility = WGPUShaderStage_Vertex | + WGPUShaderStage_Fragment, + .buffer = {.type = WGPUBufferBindingType_Uniform, + .hasDynamicOffset = false, + .minBindingSize = sizeof(GlobalUniforms)}}); + // Object Storage + bgl_entries.push_back( + {.binding = 1, + .visibility = WGPUShaderStage_Vertex | WGPUShaderStage_Fragment, + .buffer = {.type = WGPUBufferBindingType_ReadOnlyStorage, + .hasDynamicOffset = false, + .minBindingSize = sizeof(ObjectData) * kMaxObjects}}); + + // BVH Storage (Conditional for BVH pipeline) + bgl_entries.push_back( + {.binding = 2, + .visibility = WGPUShaderStage_Vertex | WGPUShaderStage_Fragment, + .buffer = {.type = WGPUBufferBindingType_ReadOnlyStorage, + .hasDynamicOffset = false, + .minBindingSize = sizeof(BVHNode) * kMaxObjects * 2}}); + + // Noise Texture + bgl_entries.push_back({.binding = 3, + .visibility = WGPUShaderStage_Fragment, + .texture = {.sampleType = WGPUTextureSampleType_Float, + .viewDimension = WGPUTextureViewDimension_2D, + .multisampled = false}}); + // Default Sampler + bgl_entries.push_back({.binding = 4, + .visibility = WGPUShaderStage_Fragment, + .sampler = {.type = WGPUSamplerBindingType_Filtering}}); + // Skybox Texture + bgl_entries.push_back({.binding = 5, + .visibility = WGPUShaderStage_Fragment, + .texture = {.sampleType = WGPUTextureSampleType_Float, + .viewDimension = WGPUTextureViewDimension_2D, + .multisampled = false}}); + + WGPUBindGroupLayoutDescriptor bgl_desc = {}; + bgl_desc.entryCount = (uint32_t)bgl_entries.size(); + bgl_desc.entries = bgl_entries.data(); + + WGPUBindGroupLayout bind_group_layout = + wgpuDeviceCreateBindGroupLayout(device_, &bgl_desc); + + WGPUPipelineLayoutDescriptor pl_desc = {}; + pl_desc.bindGroupLayoutCount = 1; + pl_desc.bindGroupLayouts = &bind_group_layout; + WGPUPipelineLayout pipeline_layout = + wgpuDeviceCreatePipelineLayout(device_, &pl_desc); + + // Depth Stencil State + WGPUDepthStencilState depth_stencil = {}; + depth_stencil.format = WGPUTextureFormat_Depth24Plus; + depth_stencil.depthWriteEnabled = WGPUOptionalBool_True; + depth_stencil.depthCompare = WGPUCompareFunction_Less; + + // Configure common color target state + WGPUColorTargetState color_target = {}; + color_target.format = format_; + color_target.writeMask = WGPUColorWriteMask_All; + // Alpha blending for meshes/particles, but not SDFs + color_target.blend = nullptr; // Explicitly set to nullptr + + WGPUFragmentState fragment_state = {}; + fragment_state.module = sdf_shader_module; + fragment_state.entryPoint = str_view("fs_main"); + fragment_state.targetCount = 1; + fragment_state.targets = &color_target; + + // Create SDF pipeline (with BVH) + WGPURenderPipelineDescriptor pipeline_desc = {}; + pipeline_desc.layout = pipeline_layout; + pipeline_desc.vertex.module = sdf_shader_module; + pipeline_desc.vertex.entryPoint = str_view("vs_main"); + pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList; + pipeline_desc.multisample.count = 1; + pipeline_desc.multisample.mask = 0xFFFFFFFF; + pipeline_desc.fragment = &fragment_state; + PLATFORM_SET_PIPELINE_DEPTH_STENCIL(pipeline_desc, &depth_stencil); + pipeline_ = wgpuDeviceCreateRenderPipeline(device_, &pipeline_desc); + + // Create SDF pipeline (without BVH) + fragment_state.module = sdf_no_bvh_shader_module; // Use linear shader + WGPURenderPipelineDescriptor pipeline_no_bvh_desc = pipeline_desc; + pipeline_no_bvh_desc.vertex.module = sdf_no_bvh_shader_module; + pipeline_no_bvh_desc.fragment = &fragment_state; + PLATFORM_SET_PIPELINE_DEPTH_STENCIL(pipeline_no_bvh_desc, &depth_stencil); + pipeline_no_bvh_ = wgpuDeviceCreateRenderPipeline(device_, &pipeline_no_bvh_desc); + + // Configure blend state for mesh/particle pipeline + WGPUBlendState mesh_blend_state = {}; + mesh_blend_state.color.srcFactor = WGPUBlendFactor_SrcAlpha; + mesh_blend_state.color.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha; + mesh_blend_state.color.operation = WGPUBlendOperation_Add; + mesh_blend_state.alpha.srcFactor = WGPUBlendFactor_One; + mesh_blend_state.alpha.dstFactor = WGPUBlendFactor_OneMinusSrcAlpha; + mesh_blend_state.alpha.operation = WGPUBlendOperation_Add; + color_target.blend = &mesh_blend_state; // Enable blending for meshes + + // Create Mesh pipeline + WGPURenderPipelineDescriptor mesh_pipeline_desc = {}; + mesh_pipeline_desc.layout = pipeline_layout; + mesh_pipeline_desc.vertex.module = mesh_shader_module; + mesh_pipeline_desc.vertex.entryPoint = str_view("vs_main"); + mesh_pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList; + mesh_pipeline_desc.multisample.count = 1; + mesh_pipeline_desc.multisample.mask = 0xFFFFFFFF; + mesh_pipeline_desc.fragment = &fragment_state; // Reuse fragment state + // Override fragment module to mesh_shader_module + fragment_state.module = mesh_shader_module; + mesh_pipeline_desc.fragment = &fragment_state; + PLATFORM_SET_PIPELINE_DEPTH_STENCIL(mesh_pipeline_desc, &depth_stencil); + + // Vertex attributes for mesh + WGPUVertexAttribute vert_attrs[3] = {}; + // Position + vert_attrs[0].shaderLocation = 0; + vert_attrs[0].offset = 0; + vert_attrs[0].format = WGPUVertexFormat_Float32x3; + // Normal + vert_attrs[1].shaderLocation = 1; + vert_attrs[1].offset = sizeof(vec3); + vert_attrs[1].format = WGPUVertexFormat_Float32x3; + // UV + vert_attrs[2].shaderLocation = 2; + vert_attrs[2].offset = sizeof(vec3) * 2; + vert_attrs[2].format = WGPUVertexFormat_Float32x2; + + WGPUVertexBufferLayout vert_buffer_layout = {}; + vert_buffer_layout.arrayStride = sizeof(MeshVertex); + vert_buffer_layout.stepMode = WGPUVertexStepMode_Vertex; + vert_buffer_layout.attributeCount = 3; + vert_buffer_layout.attributes = vert_attrs; + + mesh_pipeline_desc.vertex.bufferCount = 1; + mesh_pipeline_desc.vertex.buffers = &vert_buffer_layout; + + mesh_pipeline_ = wgpuDeviceCreateRenderPipeline(device_, &mesh_pipeline_desc); + + // Release shader modules as they are now part of the pipelines + wgpuShaderModuleRelease(sdf_shader_module); + wgpuShaderModuleRelease(sdf_no_bvh_shader_module); + wgpuShaderModuleRelease(mesh_shader_module); + wgpuPipelineLayoutRelease(pipeline_layout); + wgpuBindGroupLayoutRelease(bind_group_layout); +} + +void Renderer3D::create_skybox_pipeline() { + std::string skybox_shader_source = + ShaderComposer::Get().Compose(std::vector<std::string>{}, AssetId::ASSET_SHADER_RENDER_SHADOWS); // Use SHADOWS shader + WGPUShaderModuleDescriptor skybox_shader_desc = + platform_create_shader_module_descriptor(skybox_shader_source.c_str()); + WGPUShaderModule skybox_shader_module = + wgpuDeviceCreateShaderModule(device_, &skybox_shader_desc); + + WGPUBindGroupLayoutEntry bgl_entries[3] = {}; + // Skybox Texture + bgl_entries[0].binding = 0; + bgl_entries[0].visibility = WGPUShaderStage_Fragment; + bgl_entries[0].texture = {.sampleType = WGPUTextureSampleType_Float, + .viewDimension = WGPUTextureViewDimension_2D, + .multisampled = false}; + // Sampler + bgl_entries[1].binding = 1; + bgl_entries[1].visibility = WGPUShaderStage_Fragment; + bgl_entries[1].sampler = {.type = WGPUSamplerBindingType_Filtering}; + // Global Uniforms + bgl_entries[2].binding = 2; + bgl_entries[2].visibility = WGPUShaderStage_Vertex; + bgl_entries[2].buffer = {.type = WGPUBufferBindingType_Uniform, + .hasDynamicOffset = false, + .minBindingSize = sizeof(GlobalUniforms)}; + + WGPUBindGroupLayoutDescriptor bgl_desc = {}; + bgl_desc.entryCount = 3; + bgl_desc.entries = bgl_entries; + WGPUBindGroupLayout bind_group_layout = + wgpuDeviceCreateBindGroupLayout(device_, &bgl_desc); + + WGPUPipelineLayoutDescriptor pl_desc = {}; + pl_desc.bindGroupLayoutCount = 1; + pl_desc.bindGroupLayouts = &bind_group_layout; + WGPUPipelineLayout pipeline_layout = + wgpuDeviceCreatePipelineLayout(device_, &pl_desc); + + WGPUColorTargetState color_target = {}; + color_target.format = format_; + color_target.writeMask = WGPUColorWriteMask_All; + color_target.blend = nullptr; // No blending for skybox + + WGPUFragmentState fragment_state = {}; + fragment_state.module = skybox_shader_module; + fragment_state.entryPoint = str_view("fs_main"); + fragment_state.targetCount = 1; + fragment_state.targets = &color_target; + + WGPURenderPipelineDescriptor pipeline_desc = {}; + pipeline_desc.layout = pipeline_layout; + pipeline_desc.vertex.module = skybox_shader_module; + pipeline_desc.vertex.entryPoint = str_view("vs_main"); + pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList; + pipeline_desc.multisample.count = 1; + pipeline_desc.multisample.mask = 0xFFFFFFFF; + pipeline_desc.fragment = &fragment_state; + + // Skybox depth state (clear and write depth for objects) + WGPUDepthStencilState depth_stencil = {}; + depth_stencil.format = WGPUTextureFormat_Depth24Plus; + depth_stencil.depthWriteEnabled = WGPUOptionalBool_False; + depth_stencil.depthCompare = WGPUCompareFunction_Always; + PLATFORM_SET_PIPELINE_DEPTH_STENCIL(pipeline_desc, &depth_stencil); + + skybox_pipeline_ = wgpuDeviceCreateRenderPipeline(device_, &pipeline_desc); + + wgpuShaderModuleRelease(skybox_shader_module); + wgpuPipelineLayoutRelease(pipeline_layout); + wgpuBindGroupLayoutRelease(bind_group_layout); +} void Renderer3D::set_noise_texture(WGPUTextureView noise_view) { noise_texture_view_ = noise_view; } @@ -450,4 +698,4 @@ void Renderer3D::render(const Scene& scene, const Camera& camera, float time, wgpuCommandBufferRelease(commands); wgpuCommandEncoderRelease(encoder); -}
\ No newline at end of file +} diff --git a/src/gpu/effect.cc b/src/gpu/effect.cc index a1b45f1..9e769eb 100644 --- a/src/gpu/effect.cc +++ b/src/gpu/effect.cc @@ -260,9 +260,7 @@ void MainSequence::render_frame(float global_time, float beat, float peak, scene_attachment.loadOp = WGPULoadOp_Clear; scene_attachment.storeOp = WGPUStoreOp_Store; scene_attachment.clearValue = {0, 0, 0, 1}; -#if !defined(DEMO_CROSS_COMPILE_WIN32) scene_attachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED; -#endif /* !defined(DEMO_CROSS_COMPILE_WIN32) */ WGPURenderPassDepthStencilAttachment depth_attachment = {}; depth_attachment.view = depth_view_; @@ -302,9 +300,7 @@ void MainSequence::render_frame(float global_time, float beat, float peak, final_attachment.resolveTarget = nullptr; final_attachment.loadOp = WGPULoadOp_Load; final_attachment.storeOp = WGPUStoreOp_Store; -#if !defined(DEMO_CROSS_COMPILE_WIN32) final_attachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED; -#endif /* !defined(DEMO_CROSS_COMPILE_WIN32) */ WGPURenderPassDescriptor final_desc = { .colorAttachmentCount = 1, .colorAttachments = &final_attachment}; WGPURenderPassEncoder final_pass = @@ -338,9 +334,7 @@ void MainSequence::render_frame(float global_time, float beat, float peak, pp_attachment.resolveTarget = nullptr; pp_attachment.loadOp = WGPULoadOp_Load; pp_attachment.storeOp = WGPUStoreOp_Store; -#if !defined(DEMO_CROSS_COMPILE_WIN32) pp_attachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED; -#endif /* !defined(DEMO_CROSS_COMPILE_WIN32) */ WGPURenderPassDescriptor pp_desc = {.colorAttachmentCount = 1, .colorAttachments = &pp_attachment}; WGPURenderPassEncoder pp_pass = diff --git a/src/gpu/effects/shader_composer.cc b/src/gpu/effects/shader_composer.cc index b746f8b..5cd8699 100644 --- a/src/gpu/effects/shader_composer.cc +++ b/src/gpu/effects/shader_composer.cc @@ -2,6 +2,7 @@ // It implements the ShaderComposer class. #include "gpu/effects/shader_composer.h" +#include "util/asset_manager.h" #include <set> #include <sstream> @@ -86,3 +87,12 @@ ShaderComposer::Compose(const std::vector<std::string>& dependencies, return ss.str(); } + +std::string +ShaderComposer::Compose(const std::vector<std::string>& dependencies, + AssetId main_code_asset_id, + const CompositionMap& substitutions) { + size_t size; + const char* main_code = reinterpret_cast<const char*>(GetAsset(main_code_asset_id, &size)); + return Compose(dependencies, std::string(main_code, size), substitutions); +} diff --git a/src/gpu/effects/shader_composer.h b/src/gpu/effects/shader_composer.h index 9eb43f4..961ffcb 100644 --- a/src/gpu/effects/shader_composer.h +++ b/src/gpu/effects/shader_composer.h @@ -3,6 +3,7 @@ #pragma once +#include "generated/assets.h" // For AssetId #include <map> #include <set> #include <string> @@ -23,6 +24,10 @@ class ShaderComposer { std::string Compose(const std::vector<std::string>& dependencies, const std::string& main_code, const CompositionMap& substitutions = {}); + + std::string Compose(const std::vector<std::string>& dependencies, + AssetId main_code_asset_id, + const CompositionMap& substitutions = {}); private: ShaderComposer() = default; diff --git a/src/gpu/gpu.cc b/src/gpu/gpu.cc index 9776eac..c61c605 100644 --- a/src/gpu/gpu.cc +++ b/src/gpu/gpu.cc @@ -57,11 +57,7 @@ RenderPass gpu_create_render_pass(WGPUDevice device, WGPUTextureFormat format, RenderPass pass = {}; // Create Shader Module - WGPUShaderSourceWGSL wgsl_src = {}; - wgsl_src.chain.sType = WGPUSType_ShaderSourceWGSL; - wgsl_src.code = str_view(shader_code); - WGPUShaderModuleDescriptor shader_desc = {}; - shader_desc.nextInChain = &wgsl_src.chain; + WGPUShaderModuleDescriptor shader_desc = platform_create_shader_module_descriptor(shader_code); WGPUShaderModule shader_module = wgpuDeviceCreateShaderModule(device, &shader_desc); @@ -145,7 +141,7 @@ RenderPass gpu_create_render_pass(WGPUDevice device, WGPUTextureFormat format, depth_stencil.format = WGPUTextureFormat_Depth24Plus; depth_stencil.depthWriteEnabled = WGPUOptionalBool_False; depth_stencil.depthCompare = WGPUCompareFunction_Always; - pipeline_desc.depthStencil = &depth_stencil; + PLATFORM_SET_PIPELINE_DEPTH_STENCIL(pipeline_desc, &depth_stencil); pass.pipeline = wgpuDeviceCreateRenderPipeline(device, &pipeline_desc); @@ -157,11 +153,7 @@ ComputePass gpu_create_compute_pass(WGPUDevice device, const char* shader_code, int num_bindings) { ComputePass pass = {}; - WGPUShaderSourceWGSL wgsl_src = {}; - wgsl_src.chain.sType = WGPUSType_ShaderSourceWGSL; - wgsl_src.code = str_view(shader_code); - WGPUShaderModuleDescriptor shader_desc = {}; - shader_desc.nextInChain = &wgsl_src.chain; + WGPUShaderModuleDescriptor shader_desc = platform_create_shader_module_descriptor(shader_code); WGPUShaderModule shader_module = wgpuDeviceCreateShaderModule(device, &shader_desc); @@ -214,49 +206,11 @@ ComputePass gpu_create_compute_pass(WGPUDevice device, const char* shader_code, #if !defined(STRIP_ALL) #if defined(DEMO_CROSS_COMPILE_WIN32) -static void handle_request_adapter(WGPURequestAdapterStatus status, - WGPUAdapter adapter, const char* message, - void* userdata) { - if (status == WGPURequestAdapterStatus_Success) { - *((WGPUAdapter*)userdata) = adapter; - } else { - printf("Request adapter failed: %s\n", message ? message : "Unknown"); - } -} -static void handle_request_device(WGPURequestDeviceStatus status, - WGPUDevice device, const char* message, - void* userdata) { - if (status == WGPURequestDeviceStatus_Success) { - *((WGPUDevice*)userdata) = device; - } else { - printf("Request device failed: %s\n", message ? message : "Unknown"); - } -} static void handle_device_error(WGPUErrorType type, const char* message, void* userdata) { printf("WebGPU Error: %s\n", message ? message : "Unknown"); } #else -static void handle_request_adapter(WGPURequestAdapterStatus status, - WGPUAdapter adapter, WGPUStringView message, - void* userdata, void* userdata2) { - (void)userdata2; - if (status == WGPURequestAdapterStatus_Success) { - *((WGPUAdapter*)userdata) = adapter; - } else { - printf("Request adapter failed: %.*s\n", (int)message.length, message.data); - } -} -static void handle_request_device(WGPURequestDeviceStatus status, - WGPUDevice device, WGPUStringView message, - void* userdata, void* userdata2) { - (void)userdata2; - if (status == WGPURequestDeviceStatus_Success) { - *((WGPUDevice*)userdata) = device; - } else { - printf("Request device failed: %.*s\n", (int)message.length, message.data); - } -} static void handle_device_error(const WGPUDevice* device, WGPUErrorType type, WGPUStringView message, void* userdata, void* userdata2) { @@ -266,41 +220,6 @@ static void handle_device_error(const WGPUDevice* device, WGPUErrorType type, printf("WebGPU Error: %.*s\n", (int)message.length, message.data); } #endif /* defined(DEMO_CROSS_COMPILE_WIN32) */ -#else -// STRIP_ALL versions -#if defined(DEMO_CROSS_COMPILE_WIN32) -static void handle_request_adapter(WGPURequestAdapterStatus status, - WGPUAdapter adapter, const char* message, - void* userdata) { - if (status == WGPURequestAdapterStatus_Success) { - *((WGPUAdapter*)userdata) = adapter; - } -} -static void handle_request_device(WGPURequestDeviceStatus status, - WGPUDevice device, const char* message, - void* userdata) { - if (status == WGPURequestDeviceStatus_Success) { - *((WGPUDevice*)userdata) = device; - } -} -#else -static void handle_request_adapter(WGPURequestAdapterStatus status, - WGPUAdapter adapter, WGPUStringView message, - void* userdata, void* userdata2) { - (void)userdata2; - if (status == WGPURequestAdapterStatus_Success) { - *((WGPUAdapter*)userdata) = adapter; - } -} -static void handle_request_device(WGPURequestDeviceStatus status, - WGPUDevice device, WGPUStringView message, - void* userdata, void* userdata2) { - (void)userdata2; - if (status == WGPURequestDeviceStatus_Success) { - *((WGPUDevice*)userdata) = device; - } -} -#endif /* defined(DEMO_CROSS_COMPILE_WIN32) */ #endif /* !defined(STRIP_ALL) */ void gpu_init(PlatformState* platform_state) { @@ -311,16 +230,8 @@ void gpu_init(PlatformState* platform_state) { adapter_opts.compatibleSurface = g_surface; adapter_opts.powerPreference = WGPUPowerPreference_HighPerformance; -#if defined(DEMO_CROSS_COMPILE_WIN32) - wgpuInstanceRequestAdapter(g_instance, &adapter_opts, handle_request_adapter, - &g_adapter); -#else - WGPURequestAdapterCallbackInfo adapter_cb = {}; - adapter_cb.mode = WGPUCallbackMode_WaitAnyOnly; - adapter_cb.callback = handle_request_adapter; - adapter_cb.userdata1 = &g_adapter; - wgpuInstanceRequestAdapter(g_instance, &adapter_opts, adapter_cb); -#endif /* defined(DEMO_CROSS_COMPILE_WIN32) */ + platform_wgpu_request_adapter(g_instance, &adapter_opts, &g_adapter); + while (!g_adapter) platform_wgpu_wait_any(g_instance); @@ -331,16 +242,8 @@ void gpu_init(PlatformState* platform_state) { #endif /* !defined(DEMO_CROSS_COMPILE_WIN32) */ #endif /* !defined(STRIP_ALL) */ -#if defined(DEMO_CROSS_COMPILE_WIN32) - wgpuAdapterRequestDevice(g_adapter, &device_desc, handle_request_device, - &g_device); -#else - WGPURequestDeviceCallbackInfo device_cb = {}; - device_cb.mode = WGPUCallbackMode_WaitAnyOnly; - device_cb.callback = handle_request_device; - device_cb.userdata1 = &g_device; - wgpuAdapterRequestDevice(g_adapter, &device_desc, device_cb); -#endif /* defined(DEMO_CROSS_COMPILE_WIN32) */ + platform_wgpu_request_device(g_adapter, &device_desc, &g_device); + while (!g_device) platform_wgpu_wait_any(g_instance); diff --git a/src/gpu/texture_manager.cc b/src/gpu/texture_manager.cc index 0c30c94..e69425f 100644 --- a/src/gpu/texture_manager.cc +++ b/src/gpu/texture_manager.cc @@ -2,19 +2,10 @@ // It implements the TextureManager. #include "gpu/texture_manager.h" +#include "platform/platform.h" // Include for WGPU_TEX_COPY_INFO and WGPU_TEX_DATA_LAYOUT #include <cstdio> #include <vector> -#if defined(DEMO_CROSS_COMPILE_WIN32) -// Old API -#define WGPU_TEX_COPY_INFO WGPUImageCopyTexture -#define WGPU_TEX_DATA_LAYOUT WGPUTextureDataLayout -#else -// New API -#define WGPU_TEX_COPY_INFO WGPUTexelCopyTextureInfo -#define WGPU_TEX_DATA_LAYOUT WGPUTexelCopyBufferLayout -#endif - void TextureManager::init(WGPUDevice device, WGPUQueue queue) { device_ = device; queue_ = queue; @@ -60,11 +51,7 @@ void TextureManager::create_texture(const std::string& name, int width, tex_desc.format = WGPUTextureFormat_RGBA8Unorm; tex_desc.mipLevelCount = 1; tex_desc.sampleCount = 1; -#if defined(DEMO_CROSS_COMPILE_WIN32) - tex_desc.label = nullptr; -#else - tex_desc.label = {nullptr, 0}; -#endif + tex_desc.label = label_view(name.c_str()); WGPUTexture texture = wgpuDeviceCreateTexture(device_, &tex_desc); diff --git a/src/platform/platform.cc b/src/platform/platform.cc index 29b3af3..2b8529a 100644 --- a/src/platform/platform.cc +++ b/src/platform/platform.cc @@ -5,6 +5,7 @@ #include "platform/platform.h" #include "glfw3webgpu.h" #include <GLFW/glfw3.h> +#include <cstdio> // --- Callbacks --- @@ -128,4 +129,88 @@ WGPUSurface platform_create_wgpu_surface(WGPUInstance instance, double platform_get_time() { return glfwGetTime(); -}
\ No newline at end of file +} + +// --- WebGPU Request Helpers --- + +#if defined(DEMO_CROSS_COMPILE_WIN32) +static void _platform_adapter_cb_win32(WGPURequestAdapterStatus status, + WGPUAdapter adapter, const char* message, + void* userdata) { + if (status == WGPURequestAdapterStatus_Success) { + *((WGPUAdapter*)userdata) = adapter; + } else { + printf("Request adapter failed: %s\n", message ? message : "Unknown"); + } +} + +void platform_wgpu_request_adapter(WGPUInstance instance, + const WGPURequestAdapterOptions* options, + WGPUAdapter* out_adapter) { + wgpuInstanceRequestAdapter(instance, options, _platform_adapter_cb_win32, + out_adapter); +} + +static void _platform_device_cb_win32(WGPURequestDeviceStatus status, + WGPUDevice device, const char* message, + void* userdata) { + if (status == WGPURequestDeviceStatus_Success) { + *((WGPUDevice*)userdata) = device; + } else { + printf("Request device failed: %s\n", message ? message : "Unknown"); + } +} + +void platform_wgpu_request_device(WGPUAdapter adapter, + const WGPUDeviceDescriptor* descriptor, + WGPUDevice* out_device) { + wgpuAdapterRequestDevice(adapter, descriptor, _platform_device_cb_win32, + out_device); +} + +#else + +static void _platform_adapter_cb_native(WGPURequestAdapterStatus status, + WGPUAdapter adapter, + WGPUStringView message, void* userdata, + void* userdata2) { + (void)userdata2; + if (status == WGPURequestAdapterStatus_Success) { + *((WGPUAdapter*)userdata) = adapter; + } else { + printf("Request adapter failed: %.*s\n", (int)message.length, message.data); + } +} + +void platform_wgpu_request_adapter(WGPUInstance instance, + const WGPURequestAdapterOptions* options, + WGPUAdapter* out_adapter) { + WGPURequestAdapterCallbackInfo cb = {}; + cb.mode = WGPUCallbackMode_WaitAnyOnly; + cb.callback = _platform_adapter_cb_native; + cb.userdata1 = out_adapter; + wgpuInstanceRequestAdapter(instance, options, cb); +} + +static void _platform_device_cb_native(WGPURequestDeviceStatus status, + WGPUDevice device, + WGPUStringView message, void* userdata, + void* userdata2) { + (void)userdata2; + if (status == WGPURequestDeviceStatus_Success) { + *((WGPUDevice*)userdata) = device; + } else { + printf("Request device failed: %.*s\n", (int)message.length, message.data); + } +} + +void platform_wgpu_request_device(WGPUAdapter adapter, + const WGPUDeviceDescriptor* descriptor, + WGPUDevice* out_device) { + WGPURequestDeviceCallbackInfo cb = {}; + cb.mode = WGPUCallbackMode_WaitAnyOnly; + cb.callback = _platform_device_cb_native; + cb.userdata1 = out_device; + wgpuAdapterRequestDevice(adapter, descriptor, cb); +} +#endif diff --git a/src/platform/platform.h b/src/platform/platform.h index 0a98850..ddea7af 100644 --- a/src/platform/platform.h +++ b/src/platform/platform.h @@ -22,6 +22,9 @@ #define WGPUCallbackMode_WaitAnyOnly 0 typedef WGPUShaderModuleWGSLDescriptor WGPUShaderSourceWGSL; +// Texture compatibility typedefs +typedef WGPUImageCopyTexture WGPU_TEX_COPY_INFO; +typedef WGPUTextureDataLayout WGPU_TEX_DATA_LAYOUT; static inline const char* str_view(const char* str) { return str; @@ -39,10 +42,44 @@ platform_wgpu_set_error_callback(WGPUDevice device, wgpuDeviceSetUncapturedErrorCallback(device, callback, nullptr); } +// Helper to create a WGPUShaderModuleDescriptor with platform-specific chain +static inline WGPUShaderModuleDescriptor platform_create_shader_module_descriptor( + const char* shader_code) { + WGPUShaderSourceWGSL* wgsl_src = new WGPUShaderSourceWGSL(); + wgsl_src->chain.sType = WGPUSType_ShaderSourceWGSL; + wgsl_src->code = str_view(shader_code); + + WGPUShaderModuleDescriptor shader_desc = {}; + shader_desc.nextInChain = &wgsl_src->chain; + shader_desc.label = label_view(nullptr); // Use label_view for cross-platform compatibility + + return shader_desc; +} + +// Macro to set the depth stencil state for render pipelines +#define PLATFORM_SET_PIPELINE_DEPTH_STENCIL(pipeline_desc, depth_stencil_state_ptr) \ + _Pragma("clang diagnostic push") \ + _Pragma("clang diagnostic ignored \"-Wuninitialized\"") \ + _Pragma("clang diagnostic ignored \"-Wmissing-field-initializers\"") \ + do { \ + if (depth_stencil_state_ptr) { \ + if (defined(DEMO_CROSS_COMPILE_WIN32)) { \ + (pipeline_desc).depthStencilState = *(depth_stencil_state_ptr); \ + } else { \ + (pipeline_desc).depthStencil = (depth_stencil_state_ptr); \ + } \ + } \ + } while (0) \ + _Pragma("clang diagnostic pop") + #else #include <webgpu.h> #include <wgpu.h> +// Texture compatibility typedefs +typedef WGPUTexelCopyTextureInfo WGPU_TEX_COPY_INFO; +typedef WGPUTexelCopyBufferLayout WGPU_TEX_DATA_LAYOUT; + static inline WGPUStringView str_view(const char* str) { if (!str) return {nullptr, 0}; @@ -69,8 +106,55 @@ platform_wgpu_set_error_callback(WGPUDevice device, // Handled in descriptor for new API, but provided for compatibility if needed // elsewhere } + +// Helper to create a WGPUShaderModuleDescriptor with platform-specific chain +static inline WGPUShaderModuleDescriptor platform_create_shader_module_descriptor( + const char* shader_code) { + WGPUShaderModuleDescriptor shader_desc = {}; + // Need to dynamically allocate wgsl_src, as it needs to persist for the lifetime of shader_desc. + WGPUShaderSourceWGSL* wgsl_src = new WGPUShaderSourceWGSL(); + wgsl_src->chain.sType = WGPUSType_ShaderSourceWGSL; + wgsl_src->code = str_view(shader_code); + + shader_desc.nextInChain = &wgsl_src->chain; + shader_desc.label = label_view(nullptr); + return shader_desc; +} + +// Macro to set the depth stencil state for render pipelines +#define PLATFORM_SET_PIPELINE_DEPTH_STENCIL(pipeline_desc, depth_stencil_state_ptr) \ + do { \ + (pipeline_desc).depthStencil = (depth_stencil_state_ptr); \ + } while (0) #endif +// Helper to extract error message from platform-specific string type +static inline const char* platform_wgpu_get_error_message( +#if defined(DEMO_CROSS_COMPILE_WIN32) + const char* message +#else + WGPUStringView message +#endif +) { +#if defined(DEMO_CROSS_COMPILE_WIN32) + return message ? message : "Unknown"; +#else + // Warning: Returns raw pointer to view data, typically not null-terminated! + // Use '%.*s' printf format with message.length if possible. + // This helper is best effort. + return message.data; +#endif +} + +// Platform-agnostic WebGPU request helpers +void platform_wgpu_request_adapter(WGPUInstance instance, + const WGPURequestAdapterOptions* options, + WGPUAdapter* out_adapter); + +void platform_wgpu_request_device(WGPUAdapter adapter, + const WGPUDeviceDescriptor* descriptor, + WGPUDevice* out_device); + // Forward declare GLFWwindow to avoid including the full header here. struct GLFWwindow; diff --git a/src/util/mesh_utils.h b/src/util/mesh_utils.h new file mode 100644 index 0000000..df203ed --- /dev/null +++ b/src/util/mesh_utils.h @@ -0,0 +1,13 @@ +// This file is part of the 64k demo project. +// It defines utility structures and functions for mesh processing. + +#pragma once + +#include "util/mini_math.h" + +// Vertex structure for meshes +struct MeshVertex { + vec3 position; + vec3 normal; + vec2 uv; +}; |
