[General] Update to emscripten 4.0.13's emdawnwebgpu

[General] First triangle!
This commit is contained in:
jstefanelli 2025-08-31 17:09:25 +02:00
parent f1e3a25f3a
commit cf374cd368
Signed by: jstefanelli
GPG key ID: 60EDE2437640D2AA
3 changed files with 28 additions and 17 deletions

View file

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 4.0)
project(wgpu-wasm LANGUAGES C CXX) project(wgpu-wasm LANGUAGES C CXX)
set(GLM_BUILD_LIBRARY FALSE) set(GLM_BUILD_LIBRARY FALSE CACHE BOOL "")
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/contrib/glm) add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/contrib/glm)
add_custom_target(${CMAKE_PROJECT_NAME}_html COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/assets/index.html ${CMAKE_CURRENT_BINARY_DIR}/index.html add_custom_target(${CMAKE_PROJECT_NAME}_html COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/assets/index.html ${CMAKE_CURRENT_BINARY_DIR}/index.html
@ -27,6 +27,7 @@ function(compile_and_package_shader SHADER_NAME TARGET)
#TODO: Add deptfile generation via slang for recompilation when embedded files change #TODO: Add deptfile generation via slang for recompilation when embedded files change
add_dependencies(${TARGET} ${TARGET}_shader_${SHADER_NAME}) add_dependencies(${TARGET} ${TARGET}_shader_${SHADER_NAME})
target_link_options(${TARGET} PRIVATE --embed-file ${CMAKE_CURRENT_BINARY_DIR}/shaders/${SHADER_NAME}.wgsl@/shaders/${SHADER_NAME}.wgsl) target_link_options(${TARGET} PRIVATE --embed-file ${CMAKE_CURRENT_BINARY_DIR}/shaders/${SHADER_NAME}.wgsl@/shaders/${SHADER_NAME}.wgsl)
set_target_properties(${TARGET} PROPERTIES LINK_DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/shaders/${SHADER_NAME}.wgsl)
endfunction() endfunction()
compile_and_package_shader(shaders ${CMAKE_PROJECT_NAME}) compile_and_package_shader(shaders ${CMAKE_PROJECT_NAME})

View file

@ -1,4 +1,3 @@
struct STDVertex { struct STDVertex {
float3 pos; float3 pos;
float4 col; float4 col;
@ -9,15 +8,17 @@ struct VertexOut {
float4 col; float4 col;
}; };
struct STDCamera { struct STDCamera {
float4x4 mvp; float4x4 mvp;
float3 position; float3 position;
float3 direction; float3 direction;
}; };
[vk::binding(0, 0)]
uniform ConstantBuffer<STDCamera> camera;
[shader("vertex")] [shader("vertex")]
VertexOut vsMain(uint vertex_id: SV_VertexID, uint instance_id: SV_InstanceID, StructuredBuffer<STDVertex> vertices, uniform STDCamera camera) { VertexOut vsMain(uint vertex_id: SV_VertexID, uint instance_id: SV_InstanceID, [vk::binding(1, 0)] StructuredBuffer<STDVertex> vertices) {
return VertexOut(mul(camera.mvp, float4(vertices[vertex_id].pos, 1.0)), vertices[vertex_id].col); return VertexOut(mul(camera.mvp, float4(vertices[vertex_id].pos, 1.0)), vertices[vertex_id].col);
} }

View file

@ -1,16 +1,20 @@
#include "glm/ext/matrix_clip_space.hpp" #include "glm/ext/matrix_transform.hpp"
#include "glm/trigonometric.hpp"
#include "webgpu/webgpu_cpp.h" #include "webgpu/webgpu_cpp.h"
#include <webgpu/webgpu.h>
#ifdef EMSCRIPTEN #ifdef EMSCRIPTEN
#include "emscripten/emscripten.h" #include "emscripten/emscripten.h"
#endif #endif
#define GLM_FORCE_ALIGNED_GENTYPES
#include <iostream> #include <iostream>
#include <stdexcept> #include <stdexcept>
#include <filesystem> #include <filesystem>
#include <fstream> #include <fstream>
#include <iterator> #include <iterator>
#include <glm/glm.hpp> #include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/ext/matrix_clip_space.hpp>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/gtx/string_cast.hpp>
#ifdef EMSCRIPTEN #ifdef EMSCRIPTEN
#define SHADERS_ROOT "/shaders/" #define SHADERS_ROOT "/shaders/"
@ -85,9 +89,12 @@ wgpu::BindGroup basic_bind_group;
void request_adapter() { void request_adapter() {
std::cout << "[WGPU] request_adapter()" << std::endl; std::cout << "[WGPU] request_adapter()" << std::endl;
wgpu::InstanceFeatureName feature = wgpu::InstanceFeatureName::TimedWaitAny;
wgpu::InstanceDescriptor instance_desc{}; wgpu::InstanceDescriptor instance_desc{};
instance_desc.capabilities.timedWaitAnyEnable = true; instance_desc.requiredFeatureCount = 1;
instance_desc.capabilities.timedWaitAnyMaxCount = 1; instance_desc.requiredFeatures = &feature;
gpu_instance = wgpu::CreateInstance(&instance_desc); gpu_instance = wgpu::CreateInstance(&instance_desc);
@ -200,7 +207,7 @@ std::string load_shader_source(const std::string_view& shader_name) {
} }
std::ifstream stream(path); std::ifstream stream(path);
std::istream_iterator<char> start(stream), end{}; std::istreambuf_iterator<char> start(stream), end{};
return std::string(start, end); return std::string(start, end);
} }
@ -250,9 +257,11 @@ wgpu::PipelineLayout load_basic_pipeline_layout() {
layout_entries[0].binding = 1; layout_entries[0].binding = 1;
layout_entries[0].buffer.minBindingSize = sizeof(float) * 8 * 3; //At least 3 STDVertex entries layout_entries[0].buffer.minBindingSize = sizeof(float) * 8 * 3; //At least 3 STDVertex entries
layout_entries[0].buffer.type = wgpu::BufferBindingType::ReadOnlyStorage; layout_entries[0].buffer.type = wgpu::BufferBindingType::ReadOnlyStorage;
layout_entries[0].visibility = wgpu::ShaderStage::Vertex;
layout_entries[1].binding = 0; layout_entries[1].binding = 0;
layout_entries[1].buffer.minBindingSize = sizeof(float) * 24; //1 STDCamera entry layout_entries[1].buffer.minBindingSize = sizeof(float) * 24; //1 STDCamera entry
layout_entries[1].buffer.type = wgpu::BufferBindingType::Uniform; layout_entries[1].buffer.type = wgpu::BufferBindingType::Uniform;
layout_entries[1].visibility = wgpu::ShaderStage::Vertex;
wgpu::BindGroupLayoutDescriptor group_desc{}; wgpu::BindGroupLayoutDescriptor group_desc{};
group_desc.entryCount = 2; group_desc.entryCount = 2;
@ -337,8 +346,7 @@ void fill_buffers() {
staging_buffer.WriteMappedRange(0, sample_triangle.data(), sample_triangle.size() * sizeof(STDVertex)); staging_buffer.WriteMappedRange(0, sample_triangle.data(), sample_triangle.size() * sizeof(STDVertex));
STDCamera cam{}; STDCamera cam{};
//cam.mvp = glm::perspectiveFov(glm::radians(90.0f), 1280.0f, 720.0f, 0.001f, 100.0f); cam.mvp = glm::perspectiveRH(glm::radians(90.0f), 1280.0f / 720.0f, 0.001f, 100.0f) * glm::lookAtRH(glm::vec3(0, 0, 0), glm::vec3(0, 0, -1), glm::vec3(0, 1, 0));
cam.mvp = glm::mat4(1.0f);
staging_buffer.WriteMappedRange(sizeof(STDVertex) * 3, &cam, sizeof(STDCamera)); staging_buffer.WriteMappedRange(sizeof(STDVertex) * 3, &cam, sizeof(STDCamera));
staging_buffer.Unmap(); staging_buffer.Unmap();
@ -357,9 +365,9 @@ void fill_buffers() {
gpu_device.GetQueue().Submit(1, &cmd); gpu_device.GetQueue().Submit(1, &cmd);
auto f = gpu_device.GetQueue().OnSubmittedWorkDone(wgpu::CallbackMode::WaitAnyOnly, [](wgpu::QueueWorkDoneStatus status) -> void { auto f = gpu_device.GetQueue().OnSubmittedWorkDone(wgpu::CallbackMode::WaitAnyOnly, [](wgpu::QueueWorkDoneStatus status, std::string_view error) -> void {
if (status != wgpu::QueueWorkDoneStatus::Success) { if (status != wgpu::QueueWorkDoneStatus::Success) {
std::cout << "WAAAA x2" << std::endl; std::cout << "[WGPU] Initial copy error: " << error << std::endl;
} }
}); });
@ -424,14 +432,15 @@ EM_JS(void, resize_canvas, (const char* canvas_id, int width, int height), {
}); });
void update_camera(int width, int height) { void update_camera(int width, int height) {
std::cout << "[WGPU] Updating camera " << width << "x" << height << std::endl;
auto map_future = staging_buffer.MapAsync(wgpu::MapMode::Write, 0, sizeof(STDCamera), wgpu::CallbackMode::WaitAnyOnly, [width, height](wgpu::MapAsyncStatus status, std::string_view error) -> void { auto map_future = staging_buffer.MapAsync(wgpu::MapMode::Write, 0, sizeof(STDCamera), wgpu::CallbackMode::WaitAnyOnly, [width, height](wgpu::MapAsyncStatus status, std::string_view error) -> void {
if (status != wgpu::MapAsyncStatus::Success) { if (status != wgpu::MapAsyncStatus::Success) {
std::cerr << "[WGPU] Map failure: " << error << std::endl; std::cerr << "[WGPU] Map failure: " << error << std::endl;
throw std::runtime_error("Staging buffer map failure"); throw std::runtime_error("Staging buffer map failure");
} }
STDCamera camera{}; STDCamera camera{};
camera.mvp = glm::perspectiveFov(glm::radians(90.0f), static_cast<float>(width), static_cast<float>(height), 0.001f, 100.0f); camera.mvp = glm::perspectiveRH(glm::radians(90.0f), static_cast<float>(width) / height, 0.01f, 10.0f) * glm::lookAtRH(glm::vec3(0, 0, 0), glm::vec3(0, 0, -1), glm::vec3(0, 1, 0));
camera.mvp = glm::mat4(1.0f);
staging_buffer.WriteMappedRange(0, &camera, sizeof(STDCamera)); staging_buffer.WriteMappedRange(0, &camera, sizeof(STDCamera));
staging_buffer.Unmap(); staging_buffer.Unmap();
@ -445,7 +454,7 @@ void update_camera(int width, int height) {
gpu_device.GetQueue().Submit(1, &cmd); gpu_device.GetQueue().Submit(1, &cmd);
auto copy_future = gpu_device.GetQueue().OnSubmittedWorkDone(wgpu::CallbackMode::WaitAnyOnly, [](wgpu::QueueWorkDoneStatus) -> void { auto copy_future = gpu_device.GetQueue().OnSubmittedWorkDone(wgpu::CallbackMode::WaitAnyOnly, [](wgpu::QueueWorkDoneStatus, std::string_view) -> void {
}); });