diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d86f9b06b0f91..2d3922ac344d3f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1495,56 +1495,6 @@ elseif(EMSCRIPTEN) if(SDL_GPU) set(SDL_WEBGPU ON) set(SDL_RENDER_WEBGPU ON) - set(SPIRV_CROSS_EMSC ${SDL3_SOURCE_DIR}/SPIRV-Cross/build) - - if (NOT EXISTS ${SDL3_SOURCE_DIR}/SPIRV-Cross/build) - file(MAKE_DIRECTORY ${SDL3_SOURCE_DIR}/SPIRV-Cross/build) - endif() - - if (NOT EXISTS ${SDL3_SOURCE_DIR}/SPIRV-Cross/build/CMakeCache.txt) - execute_process( - COMMAND emcmake cmake .. - WORKING_DIRECTORY ${SDL3_SOURCE_DIR}/SPIRV-Cross/build - ) - endif() - - if (NOT EXISTS ${SDL3_SOURCE_DIR}/SPIRV-Cross/build/libspirv-cross-c.a) - execute_process( - COMMAND emmake make - WORKING_DIRECTORY ${SDL3_SOURCE_DIR}/SPIRV-Cross/build - ) - endif() - - add_subdirectory("${SDL3_SOURCE_DIR}/SPIRV-Cross" EXCLUDE_FROM_ALL) - - # We must link against libspirv-cross for Shader reflection - set(SPIRV_CROSS_LIBRARIES - ${SPIRV_CROSS_EMSC}/libspirv-cross-c.a - ${SPIRV_CROSS_EMSC}/libspirv-cross-cpp.a - ${SPIRV_CROSS_EMSC}/libspirv-cross-core.a - ${SPIRV_CROSS_EMSC}/libspirv-cross-glsl.a - ${SPIRV_CROSS_EMSC}/libspirv-cross-hlsl.a - ${SPIRV_CROSS_EMSC}/libspirv-cross-msl.a - ${SPIRV_CROSS_EMSC}/libspirv-cross-reflect.a - ${SPIRV_CROSS_EMSC}/libspirv-cross-util.a - ) - - # Link against SPIRV-Cross - sdl_link_dependency(spirv-cross-c LIBS ${SPIRV_CROSS_LIBRARIES}) - sdl_include_directories(PRIVATE ${SDL3_SOURCE_DIR}/SPIRV-Cross) - link_directories(${SPIRV_CROSS_LIBRARY_DIRS}) - - sdl_include_directories(PRIVATE /usr/include/c++/11/) - sdl_include_directories(PRIVATE /usr/include/x86_64-linux-gnu/c++/11/) - sdl_link_dependency(stdc++ LIBS stdc++) - - # Link against Tint for SPIR-V to WGSL conversion - set(TINT_DIR ${SDL3_SOURCE_DIR}/src/gpu/webgpu/tint-wasm/) - set(TINT_WASM ${TINT_DIR}/libtint_wasm.a) - sdl_link_dependency(tint LIBS ${TINT_WASM}) - sdl_include_directories(PRIVATE ${TINT_DIR}) - link_directories(${TINT_DIR}) - set(HAVE_WEBGPU TRUE) set(HAVE_RENDER_WEBGPU TRUE) endif() diff --git a/src/gpu/SDL_gpu.c b/src/gpu/SDL_gpu.c index cb859abfe1cba8..d54d525ad65b2c 100644 --- a/src/gpu/SDL_gpu.c +++ b/src/gpu/SDL_gpu.c @@ -419,7 +419,11 @@ static const SDL_GPUBootstrap *SDL_GPUSelectBackend(SDL_PropertiesID props) if (gpudriver != NULL) { for (i = 0; backends[i]; i += 1) { if (SDL_strcasecmp(gpudriver, backends[i]->name) == 0) { - if (!(backends[i]->shader_formats & format_flags)) { + if (!(backends[i]->shader_formats | format_flags)) { + SDL_Log("Selected GPU driver: %s", gpudriver); + SDL_Log("Expected Flags: %u", format_flags); + SDL_Log("WGSL Flag: %u", SDL_GPU_SHADERFORMAT_WGSL); + SDL_Log("Backend Flags: %u", backends[i]->shader_formats); SDL_LogError(SDL_LOG_CATEGORY_GPU, "Required shader format for backend %s not provided!", gpudriver); return NULL; } @@ -451,127 +455,12 @@ static const SDL_GPUBootstrap *SDL_GPUSelectBackend(SDL_PropertiesID props) return NULL; } -/*SDL_GPUDevice *SDL_CreateGPUDevice(*/ -/* SDL_GPUShaderFormat formatFlags,*/ -/* bool debugMode,*/ -/* const char *name)*/ -/*{*/ -/* SDL_GPUDevice *result;*/ -/*#ifdef __EMSCRIPTEN__*/ -/* SDL_SetHint(SDL_HINT_GPU_DRIVER, "webgpu");*/ -/*#endif*/ -/* SDL_PropertiesID props = SDL_CreateProperties();*/ -/* if (formatFlags & SDL_GPU_SHADERFORMAT_PRIVATE) {*/ -/* SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOL, true);*/ -/* }*/ -/* if (formatFlags & SDL_GPU_SHADERFORMAT_SPIRV) {*/ -/* SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOL, true);*/ -/* }*/ -/* if (formatFlags & SDL_GPU_SHADERFORMAT_DXBC) {*/ -/* SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOL, true);*/ -/* }*/ -/* if (formatFlags & SDL_GPU_SHADERFORMAT_DXIL) {*/ -/* SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOL, true);*/ -/* }*/ -/* if (formatFlags & SDL_GPU_SHADERFORMAT_MSL) {*/ -/* SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOL, true);*/ -/* }*/ -/* if (formatFlags & SDL_GPU_SHADERFORMAT_METALLIB) {*/ -/* SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOL, true);*/ -/* }*/ -/* SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOL, debugMode);*/ -/* SDL_SetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING, name);*/ -/* result = SDL_CreateGPUDeviceWithProperties(props);*/ -/* SDL_DestroyProperties(props);*/ -/* SDL_Log("SDL_CreateGPUDevice: %s", result ? "success" : "failure");*/ -/* return result;*/ -/*}*/ - -/*SDL_GPUDevice *SDL_CreateGPUDeviceWithProperties(SDL_PropertiesID props)*/ -/*{*/ -/* SDL_GPUShaderFormat formatFlags = 0;*/ -/* bool debugMode;*/ -/* bool preferLowPower;*/ -/**/ -/* const char *gpudriver;*/ -/* SDL_VideoDevice *_this = SDL_GetVideoDevice();*/ -/**/ -/* if (_this == NULL) {*/ -/* SDL_SetError("Video subsystem not initialized");*/ -/* return NULL;*/ -/* }*/ -/**/ -/* if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOL, false)) {*/ -/* formatFlags |= SDL_GPU_SHADERFORMAT_PRIVATE;*/ -/* }*/ -/* if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOL, false)) {*/ -/* formatFlags |= SDL_GPU_SHADERFORMAT_SPIRV;*/ -/* }*/ -/* if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOL, false)) {*/ -/* formatFlags |= SDL_GPU_SHADERFORMAT_DXBC;*/ -/* }*/ -/* if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOL, false)) {*/ -/* formatFlags |= SDL_GPU_SHADERFORMAT_DXIL;*/ -/* }*/ -/* if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOL, false)) {*/ -/* formatFlags |= SDL_GPU_SHADERFORMAT_MSL;*/ -/* }*/ -/* if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOL, false)) {*/ -/* formatFlags |= SDL_GPU_SHADERFORMAT_METALLIB;*/ -/* }*/ -/* if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_WGSL_BOOL, false)) {*/ -/* formatFlags |= SDL_GPU_SHADERFORMAT_WGSL;*/ -/* }*/ -/**/ -/* gpudriver = SDL_GetHint(SDL_HINT_GPU_DRIVER);*/ -/* if (gpudriver == NULL) {*/ -/*#ifdef __EMSCRIPTEN__*/ -/* gpudriver = SDL_SetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING, "webgpu");*/ -/*#else*/ -/* gpudriver = SDL_SetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING, NULL);*/ -/*#endif*/ -/* }*/ -/**/ -/* selectedBackend = SDL_GPUSelectBackend(props);*/ -/* if (selectedBackend != SDL_GPU_DRIVER_INVALID) {*/ -/* for (size_t i = 0; backends[i]; i += 1) {*/ -/* if (backends[i]->backendflag == selectedBackend) {*/ -/* result = backends[i]->CreateDevice(debugMode, preferLowPower, props);*/ -/* if (result != NULL) {*/ -/* result->backend = backends[i]->backendflag;*/ -/* result->shaderFormats = backends[i]->shaderFormats;*/ -/* result->debugMode = debugMode;*/ -/* break;*/ -/* }*/ -/* }*/ -/* }*/ -/**/ -/* SDL_SetError("SDL_HINT_GPU_DRIVER %s unsupported!", gpudriver);*/ -/* return NULL;*/ -/* }*/ -/**/ -/* for (size_t i = 0; backends[i]; i += 1) {*/ -/* if ((backends[i]->shader_formats & formatFlags) == 0) {*/ -/* // Don't select a backend which doesn't support the app's shaders.*/ -/* continue;*/ -/* }*/ -/* if (backends[i]->PrepareDriver(_this)) {*/ -/* return backends[i];*/ -/* }*/ -/* }*/ -/**/ -/* SDL_SetError("No supported SDL_GPU backend found!");*/ -/* return NULL;*/ -/*}*/ - static void SDL_GPU_FillProperties( SDL_PropertiesID props, SDL_GPUShaderFormat formatFlags, bool debug_mode, const char *name) { - - SDL_GPUDevice *result; #ifdef __EMSCRIPTEN__ SDL_SetHint(SDL_HINT_GPU_DRIVER, "webgpu"); #endif @@ -594,6 +483,9 @@ static void SDL_GPU_FillProperties( if (formatFlags & SDL_GPU_SHADERFORMAT_METALLIB) { SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOL, true); } + if (formatFlags & SDL_GPU_SHADERFORMAT_WGSL) { + SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_WGSL_BOOL, true); + } SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOL, debug_mode); SDL_SetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING, name); } diff --git a/src/gpu/webgpu/SDL_gpu_webgpu.c b/src/gpu/webgpu/SDL_gpu_webgpu.c index 4c59f149ee9666..c84da54471abfa 100644 --- a/src/gpu/webgpu/SDL_gpu_webgpu.c +++ b/src/gpu/webgpu/SDL_gpu_webgpu.c @@ -15,14 +15,14 @@ #include #include #include -#include +/*#include */ #include #include /* Tint WASM exported functions START */ -void tint_initialize(void); -const char *tint_spv_to_wgsl(const void *shader_data, const size_t shader_size); +/*void tint_initialize(void);*/ +/*const char *tint_spv_to_wgsl(const void *shader_data, const size_t shader_size);*/ /* Tint WASM exported functions END */ @@ -105,24 +105,6 @@ typedef enum WebGPUBindingType WGPUBindingType_ReadWriteStorageTexture = 0x00000046, } WebGPUBindingType; -static WebGPUBindingType SPIRVToWebGPUBindingType(spvc_resource_type type) -{ - switch (type) { - case SPVC_RESOURCE_TYPE_UNIFORM_BUFFER: - return WGPUBindingType_UniformBuffer; - case SPVC_RESOURCE_TYPE_STORAGE_BUFFER: - return WGPUBindingType_StorageBuffer; - case SPVC_RESOURCE_TYPE_SEPARATE_SAMPLERS: - return WGPUBindingType_Sampler; - case SPVC_RESOURCE_TYPE_SAMPLED_IMAGE: - return WGPUBindingType_Texture; - case SPVC_RESOURCE_TYPE_STORAGE_IMAGE: - return WGPUBindingType_StorageTexture; - default: - return WGPUBindingType_Undefined; - } -} - typedef enum WebGPUBufferType { WEBGPU_BUFFER_TYPE_GPU, @@ -833,171 +815,8 @@ static WGPUPresentMode SDLToWGPUPresentMode(SDL_GPUPresentMode presentMode) } } +// WGPU Bind Group Layout Functions // --------------------------------------------------- - -// SPIRV-Reflection Functions: -// --------------------------------------------------- -static void ReflectSPIRVShaderBindings_INTERNAL(spvc_compiler *compiler, - spvc_resources *resources, - spvc_resource_type type, - const spvc_reflected_resource *reflectedResources, - ReflectedBindGroup *bindGroups, - uint32_t *maxSet, - WGPUShaderStageFlags stageFlags) -{ - if (compiler == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Invalid SPIRV compiler."); - return; - } - - if (resources == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Invalid SPIRV resources."); - return; - } - - if (maxSet == NULL) { - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Invalid max set pointer."); - return; - } - - size_t reflectedCount; - - // Get the resources for the specified type - spvc_resources_get_resource_list_for_type(*resources, type, &reflectedResources, &reflectedCount); - - if (reflectedCount == 0) { - return; - } - - SDL_Log("Reflected %zu resource(s) of type %d", reflectedCount, type); - - for (size_t i = 0; i < reflectedCount; i += 1) { - // Get the descriptor set and binding - uint32_t set = spvc_compiler_get_decoration(*compiler, reflectedResources[i].id, SpvDecorationDescriptorSet); - uint32_t binding = spvc_compiler_get_decoration(*compiler, reflectedResources[i].id, SpvDecorationBinding); - - // Update the max set value within the pointer - if (set > *maxSet) { - *maxSet = set; - } - - // Calloc enough memory for the bindgroups if it hasn't been allocated yet - // The individual bindgroups are resized as needed - if (!bindGroups) { - bindGroups = SDL_calloc((size_t)set + 1, sizeof(ReflectedBindGroup)); - bindGroups[0].bindingCount = 0; - } - - ReflectedBinding *newBinding = SDL_realloc(bindGroups[set].bindings, - (bindGroups[set].bindingCount + 1) * sizeof(ReflectedBinding)); - if (!newBinding) { - SDL_free(bindGroups); - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to allocate memory for reflected bindings."); - return; - } - - bindGroups[set].bindings = newBinding; - bindGroups[set].bindings[bindGroups[set].bindingCount] = (ReflectedBinding){ - .set = set, - .binding = binding, - .type = SPIRVToWebGPUBindingType(type), - .stages = stageFlags, - }; - bindGroups[set].bindingCount += 1; - } - - SDL_free((void *)reflectedResources); -} - -static ReflectedBindGroup *ReflectSPIRVShaderBindings( - const uint32_t *spirv, - size_t spirvSize, - WGPUShaderStageFlags stageFlags, - uint32_t *outBindGroupCount) -{ - spvc_context context; - spvc_parsed_ir ir; - spvc_compiler compiler; - spvc_resources resources; - - const spvc_reflected_resource *reflectedResources = NULL; - - // Initialize SPIRV-Cross - spvc_context_create(&context); - spvc_context_parse_spirv(context, spirv, spirvSize / sizeof(uint32_t), &ir); - spvc_context_create_compiler(context, SPVC_BACKEND_NONE, ir, SPVC_CAPTURE_MODE_TAKE_OWNERSHIP, &compiler); - - // Create spirv shader resources - spvc_compiler_create_shader_resources(compiler, &resources); - if (!resources) { - spvc_context_destroy(context); - SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create shader resources."); - return NULL; - } - - // Reflected bind groups - ReflectedBindGroup *bindGroups = NULL; - uint32_t maxSet = 0; - - // Reflect gl variables - SDL_Log("Reflecting gl uniforms..."); - ReflectSPIRVShaderBindings_INTERNAL(&compiler, &resources, - SPVC_RESOURCE_TYPE_GL_PLAIN_UNIFORM, - reflectedResources, bindGroups, &maxSet, stageFlags); - - // Reflect Vertex attributes - SDL_Log("Reflecting vertex attributes..."); - ReflectSPIRVShaderBindings_INTERNAL(&compiler, &resources, - SPVC_RESOURCE_TYPE_STAGE_INPUT, - reflectedResources, bindGroups, &maxSet, stageFlags); - - // Reflect uniform buffers - SDL_Log("Reflecting uniform buffers..."); - ReflectSPIRVShaderBindings_INTERNAL(&compiler, &resources, - SPVC_RESOURCE_TYPE_UNIFORM_BUFFER, - reflectedResources, bindGroups, &maxSet, stageFlags); - - // Reflect storage buffers - SDL_Log("Reflecting storage buffers..."); - ReflectSPIRVShaderBindings_INTERNAL(&compiler, &resources, - SPVC_RESOURCE_TYPE_STORAGE_BUFFER, - reflectedResources, bindGroups, &maxSet, stageFlags); - - // Store textures - SDL_Log("Reflecting textures..."); - ReflectSPIRVShaderBindings_INTERNAL(&compiler, &resources, - SPVC_RESOURCE_TYPE_SEPARATE_IMAGE, - reflectedResources, bindGroups, &maxSet, stageFlags); - - // Reflect storage images - SDL_Log("Reflecting storage textures..."); - ReflectSPIRVShaderBindings_INTERNAL(&compiler, &resources, - SPVC_RESOURCE_TYPE_STORAGE_IMAGE, - reflectedResources, bindGroups, &maxSet, stageFlags); - - // Reflect sampled images - SDL_Log("Reflecting sampled texture..."); - ReflectSPIRVShaderBindings_INTERNAL(&compiler, &resources, - SPVC_RESOURCE_TYPE_SAMPLED_IMAGE, - reflectedResources, bindGroups, &maxSet, stageFlags); - - // Reflect samplers - SDL_Log("Reflecting reflecting samplers..."); - ReflectSPIRVShaderBindings_INTERNAL(&compiler, &resources, - SPVC_RESOURCE_TYPE_SEPARATE_SAMPLERS, - reflectedResources, bindGroups, &maxSet, stageFlags); - - SDL_Log("Max set: %d", maxSet); - - // Free resources - spvc_context_destroy(context); - SDL_free((void *)reflectedResources); - - // Set the output bind group count - *outBindGroupCount = maxSet; - return bindGroups; -} - static void WebGPU_CreateBindingLayout(WGPUBindGroupLayoutEntry *entry, ReflectedBinding *binding) { switch (binding->type) { @@ -1626,9 +1445,7 @@ SDL_GPUShader *WebGPU_CreateShader( WebGPURenderer *renderer = (WebGPURenderer *)driverData; WebGPUShader *shader = SDL_calloc(1, sizeof(WebGPUShader)); - const char *wgsl = tint_spv_to_wgsl(shaderCreateInfo->code, shaderCreateInfo->code_size); - - printf("WGSL: %s", wgsl); + const char *wgsl = (const char *)shaderCreateInfo->code; WGPUShaderModuleWGSLDescriptor wgsl_desc = { .chain = { @@ -1722,12 +1539,15 @@ static SDL_GPUGraphicsPipeline *WebGPU_CreateGraphicsPipeline( // though bind groups aren't a thing in SPIRV, they use sets and bindings instead from my understanding. uint32_t vertexBindGroupCount = 0; uint32_t fragmentBindGroupCount = 0; - ReflectedBindGroup *vertexBindGroups = ReflectSPIRVShaderBindings(vertShader->spirv, - vertShader->spirvSize, - WGPUShaderStage_Vertex, &vertexBindGroupCount); - ReflectedBindGroup *fragmentBindGroups = ReflectSPIRVShaderBindings(fragShader->spirv, - fragShader->spirvSize, - WGPUShaderStage_Fragment, &fragmentBindGroupCount); + ReflectedBindGroup *vertexBindGroups = NULL; + ReflectedBindGroup *fragmentBindGroups = NULL; + + /*ReflectedBindGroup *vertexBindGroups = ReflectSPIRVShaderBindings(vertShader->spirv,*/ + /* vertShader->spirvSize,*/ + /* WGPUShaderStage_Vertex, &vertexBindGroupCount);*/ + /*ReflectedBindGroup *fragmentBindGroups = ReflectSPIRVShaderBindings(fragShader->spirv,*/ + /* fragShader->spirvSize,*/ + /* WGPUShaderStage_Fragment, &fragmentBindGroupCount);*/ WebGPUPipelineResourceLayout *resourceLayout = CreateResourceLayoutFromReflection(renderer, vertexBindGroups, @@ -2112,7 +1932,7 @@ static SDL_GPUDevice *WebGPU_CreateDevice(bool debug, bool preferLowPower, SDL_P result = (SDL_GPUDevice *)SDL_malloc(sizeof(SDL_GPUDevice)); // Initialize Tint for SPIRV to WGSL conversion - tint_initialize(); + /*tint_initialize();*/ /* TODO: Ensure that all function signatures for the driver are correct so that the following line compiles @@ -2157,7 +1977,7 @@ static SDL_GPUDevice *WebGPU_CreateDevice(bool debug, bool preferLowPower, SDL_P SDL_GPUBootstrap WebGPUDriver = { "webgpu", - SDL_GPU_SHADERFORMAT_WGSL | SDL_GPU_SHADERFORMAT_SPIRV, + SDL_GPU_SHADERFORMAT_WGSL, WebGPU_PrepareDriver, WebGPU_CreateDevice, }; diff --git a/src/gpu/webgpu/tint-wasm/libtint_wasm.a b/src/gpu/webgpu/tint-wasm/libtint_wasm.a deleted file mode 100644 index 8ffa7cb8ec9a00..00000000000000 Binary files a/src/gpu/webgpu/tint-wasm/libtint_wasm.a and /dev/null differ diff --git a/src/gpu/webgpu/tint-wasm/tint_sdl.cpp b/src/gpu/webgpu/tint-wasm/tint_sdl.cpp deleted file mode 100644 index 21220d61372331..00000000000000 --- a/src/gpu/webgpu/tint-wasm/tint_sdl.cpp +++ /dev/null @@ -1,136 +0,0 @@ -// File: tint_sdl.cpp -// Author: Kyle Lukaszek -// Email: kylelukaszek [at] gmail [dot] com -// Date: 2024-09-26 -// ------------------------------------------------------------- -// Special thanks to the Tint contributors for their work on the Tint compiler. -// ------------------------------------------------------------- -// -// License: Apache 2.0 (Follows the same license as Tint) -// -// Description: -// This file is a simple C++ wrapper around the Tint compiler for converting SPIR-V to WGSL. -// The main function is tint_spv_to_wgsl which takes in a SPIR-V shader as a uint8_t array from -// SDL and returns a char* to the WGSL shader. -// -// This .cpp file is meant to be assigned as an extension to libtint.a which can be found -// at https://www.github.com/klukaszek/tint-wasm. -// -// This has already been done to the included libtint_wasm.a file in this directory. -// -// MAKING CHANGES: -// -// If you make any changes to this file, it is important that we update the object files -// in the libtint_wasm.a static library. -// -// To update libtint_wasm.a, you can use the following command: -// -> em++ -sWASM=0 -I./ tint_sdl.cpp -L. -ltint -c -// -> cp /libtint.a ./libtint_wasm.a -// -> emar rcs libtint_wasm.a tint_sdl.o -// -// Where is the path to the tint-wasm repo with the precompiled static library. -// -// The static library will already be included with SDL3 WebGPU along with the tint_sdl.cpp file. -// -// If you make any changes to this file, it is important to update libtint_wasm.a using the emar -// command above. This will overwrite the existing symbols with the new ones. -// --------------------------------------------------------------- - -#include "api/tint.h" -#include "lang/wgsl/common/allowed_features.h" -#include "spirv-tools/libspirv.h" -#include "utils/diagnostic/formatter.h" -#include -#define TINT_BUILD_WGSL_WRITER 1 -#define TINT_BUILD_WGSL_READER 1 -#define TINT_BUILD_SPV_READER 1 -#define TINT_BUILD_SPV_WRITER 1 - -#include "cmd/common/helper.h" -#include "spirv-tools/libspirv.hpp" -#include "tint.h" -#include "utils/diagnostic/source.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -std::vector convertUint8ArrayToUint32Array(const uint8_t *data, size_t size) -{ - std::vector result; - result.reserve((size / 4)); - for (size_t i = 0; i < size; i += 4) { - uint32_t word = 0; - word |= data[i + 0] << 0; - word |= data[i + 1] << 8; - word |= data[i + 2] << 16; - word |= data[i + 3] << 24; - result.push_back(word); - } - return result; -} - -tint::cmd::ProgramInfo LoadProgramInfo(const tint::cmd::LoadProgramOptions &opts, const std::vector shader_code) -{ - auto load = [&]() -> tint::cmd::ProgramInfo { - return tint::cmd::ProgramInfo{ - /* program */ tint::spirv::reader::Read(shader_code, {}), - /* source_file */ nullptr, - }; - }; - - tint::cmd::ProgramInfo info = load(); - - if (info.program.Diagnostics().Count() > 0) { - - std::cerr << info.program.Diagnostics().Str() << std::endl; - - fflush(stderr); - } - - if (!info.program.IsValid()) { - std::cerr << "Program is not valid." << std::endl; - return info; - } - - return info; -} - -extern "C" { - -void tint_initialize(void) -{ - tint::Initialize(); -} - -char *tint_spv_to_wgsl(const uint8_t *shader_data, const size_t shader_size) -{ - tint::cmd::LoadProgramOptions opts; - - opts.filename = "spv-shader"; - opts.use_ir = false; - opts.printer = nullptr; - - // Properly convert SDL's uint8_t SPIRV array to a uint32_t array - std::vector shader_code = convertUint8ArrayToUint32Array(shader_data, shader_size); - - auto info = LoadProgramInfo(opts, shader_code); - - tint::wgsl::writer::Options options; - auto result = tint::wgsl::writer::Generate(info.program, options); - - // Malloc the "str" pointer to the size of the WGSL string - char *wgsl = (char *)malloc(result->wgsl.size() + 1); - - // Copy the WGSL string to the provided buffer - std::strcpy(wgsl, result->wgsl.c_str()); - - return wgsl; -} -}