diff --git a/filament/backend/include/backend/DriverEnums.h b/filament/backend/include/backend/DriverEnums.h index f0561be709..bcf74e0cc1 100644 --- a/filament/backend/include/backend/DriverEnums.h +++ b/filament/backend/include/backend/DriverEnums.h @@ -182,6 +182,7 @@ enum class ShaderLanguage { SPIRV = 2, MSL = 3, METAL_LIBRARY = 4, + WGSL = 5, }; static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguage) { @@ -196,6 +197,8 @@ static constexpr const char* shaderLanguageToString(ShaderLanguage shaderLanguag return "MSL"; case ShaderLanguage::METAL_LIBRARY: return "Metal precompiled library"; + case ShaderLanguage::WGSL: + return "WGSL"; } } diff --git a/filament/backend/src/metal/MetalShaderCompiler.mm b/filament/backend/src/metal/MetalShaderCompiler.mm index 0a5f9e345c..c23b3109d3 100644 --- a/filament/backend/src/metal/MetalShaderCompiler.mm +++ b/filament/backend/src/metal/MetalShaderCompiler.mm @@ -138,6 +138,7 @@ bool MetalShaderCompiler::isParallelShaderCompileSupported() const noexcept { case ShaderLanguage::ESSL1: case ShaderLanguage::ESSL3: case ShaderLanguage::SPIRV: + case ShaderLanguage::WGSL: break; } diff --git a/filament/backend/src/webgpu/WebGPUDriver.cpp b/filament/backend/src/webgpu/WebGPUDriver.cpp index e10d1f43fd..1dc81f349a 100644 --- a/filament/backend/src/webgpu/WebGPUDriver.cpp +++ b/filament/backend/src/webgpu/WebGPUDriver.cpp @@ -45,7 +45,7 @@ ShaderModel WebGPUDriver::getShaderModel() const noexcept { } ShaderLanguage WebGPUDriver::getShaderLanguage() const noexcept { - return ShaderLanguage::ESSL3; + return ShaderLanguage::WGSL; } // explicit instantiation of the Dispatcher diff --git a/filament/backend/test/PlatformRunner.h b/filament/backend/test/PlatformRunner.h index 0e0d30075c..3cd5c2c35a 100644 --- a/filament/backend/test/PlatformRunner.h +++ b/filament/backend/test/PlatformRunner.h @@ -30,7 +30,8 @@ enum class Backend : uint8_t { OPENGL = 1, VULKAN = 2, METAL = 3, - NOOP = 4, + WEBGPU = 4, + NOOP = 5, }; struct NativeView { diff --git a/filament/backend/test/ShaderGenerator.cpp b/filament/backend/test/ShaderGenerator.cpp index 545a6f9708..e493c444af 100644 --- a/filament/backend/test/ShaderGenerator.cpp +++ b/filament/backend/test/ShaderGenerator.cpp @@ -90,6 +90,9 @@ ShaderGenerator::ShaderGenerator(std::string vertex, std::string fragment, Backe case Backend::METAL: mShaderLanguage = filament::backend::ShaderLanguage::MSL; break; + case Backend::WEBGPU: + mShaderLanguage = filament::backend::ShaderLanguage::WGSL; + break; case Backend::NOOP: mShaderLanguage = filament::backend::ShaderLanguage::ESSL3; break; @@ -115,6 +118,8 @@ ShaderGenerator::Blob ShaderGenerator::transpileShader(ShaderStage stage, std::s shader.insert(pos, "#define TARGET_METAL_ENVIRONMENT\n"); } else if (backend == Backend::VULKAN) { shader.insert(pos, "#define TARGET_VULKAN_ENVIRONMENT\n"); + } else if (backend == Backend::WEBGPU) { + shader.insert(pos, "#define TARGET_VULKAN_ENVIRONMENT\n"); } const char* shaderCString = shader.c_str(); @@ -150,7 +155,8 @@ ShaderGenerator::Blob ShaderGenerator::transpileShader(ShaderStage stage, std::s assert_invariant(backend == Backend::OPENGL || backend == Backend::METAL || - backend == Backend::VULKAN); + backend == Backend::VULKAN || + backend == Backend::WEBGPU); if (backend == Backend::OPENGL) { if (isMobile) { @@ -166,6 +172,8 @@ ShaderGenerator::Blob ShaderGenerator::transpileShader(ShaderStage stage, std::s return { result.c_str(), result.c_str() + result.length() + 1 }; } else if (backend == Backend::VULKAN) { return { (uint8_t*)spirv.data(), (uint8_t*)(spirv.data() + spirv.size()) }; + } else if (backend == Backend::WEBGPU){ + filamat::GLSLPostProcessor::spirvToWgsl(&spirv, &result); } return {}; diff --git a/filament/src/MaterialParser.cpp b/filament/src/MaterialParser.cpp index 400e8e18d0..c217f6c911 100644 --- a/filament/src/MaterialParser.cpp +++ b/filament/src/MaterialParser.cpp @@ -62,6 +62,8 @@ constexpr std::pair shaderLanguageToTags(ShaderLanguage co return { MaterialEssl1, DictionaryText }; case ShaderLanguage::MSL: return { MaterialMetal, DictionaryText }; + case ShaderLanguage::WGSL: + return { MaterialWgsl, DictionaryText }; case ShaderLanguage::SPIRV: return { MaterialSpirv, DictionarySpirv }; case ShaderLanguage::METAL_LIBRARY: diff --git a/libs/filabridge/include/filament/MaterialChunkType.h b/libs/filabridge/include/filament/MaterialChunkType.h index 4d9f6a7deb..4ca08f4c68 100644 --- a/libs/filabridge/include/filament/MaterialChunkType.h +++ b/libs/filabridge/include/filament/MaterialChunkType.h @@ -45,6 +45,7 @@ enum UTILS_PUBLIC ChunkType : uint64_t { MaterialEssl1 = charTo64bitNum("MAT_ESS1"), MaterialSpirv = charTo64bitNum("MAT_SPIR"), MaterialMetal = charTo64bitNum("MAT_METL"), + MaterialWgsl = charTo64bitNum("MAT_WGSL"), MaterialMetalLibrary = charTo64bitNum("MAT_MLIB"), MaterialShaderModels = charTo64bitNum("MAT_SMDL"), MaterialBindingUniformInfo = charTo64bitNum("MAT_UFRM"), diff --git a/libs/filaflat/src/MaterialChunk.cpp b/libs/filaflat/src/MaterialChunk.cpp index b69af9abd0..85bc06414f 100644 --- a/libs/filaflat/src/MaterialChunk.cpp +++ b/libs/filaflat/src/MaterialChunk.cpp @@ -183,6 +183,7 @@ bool MaterialChunk::getShader(ShaderContent& shaderContent, BlobDictionary const switch (mMaterialTag) { case filamat::ChunkType::MaterialGlsl: case filamat::ChunkType::MaterialEssl1: + case filamat::ChunkType::MaterialWgsl: case filamat::ChunkType::MaterialMetal: return getTextShader(mUnflattener, dictionary, shaderContent, shaderModel, variant, stage); case filamat::ChunkType::MaterialSpirv: diff --git a/libs/filamat/include/filamat/MaterialBuilder.h b/libs/filamat/include/filamat/MaterialBuilder.h index c9ff548880..2d868b281e 100644 --- a/libs/filamat/include/filamat/MaterialBuilder.h +++ b/libs/filamat/include/filamat/MaterialBuilder.h @@ -81,7 +81,11 @@ public: VULKAN = 0x02u, METAL = 0x04u, WEBGPU = 0x08u, +#ifdef FILAMENT_SUPPORTS_WEBGPU ALL = OPENGL | VULKAN | METAL | WEBGPU +#else + ALL = OPENGL | VULKAN | METAL +#endif }; /* diff --git a/libs/filamat/src/GLSLPostProcessor.cpp b/libs/filamat/src/GLSLPostProcessor.cpp index 54c8f0645e..794425ee00 100644 --- a/libs/filamat/src/GLSLPostProcessor.cpp +++ b/libs/filamat/src/GLSLPostProcessor.cpp @@ -527,11 +527,14 @@ bool GLSLPostProcessor::spirvToWgsl(const SpirvBlob *spirv, std::string *outWsl) tint::Program tintRead = tint::spirv::reader::Read(*spirv, readerOpts); if (tintRead.Diagnostics().ContainsErrors()) { - slog.w << "This tint reader error is currently ignored during WebGPU bringup:" << tintRead.Diagnostics().Str() << io::endl; - - //TODO: We should actually return false here, but for initial debugging - // let it slide until combined image sampler is resolved - // return false; + //TODO remove this if block once combined image sampler conversion works. + if (tintRead.Diagnostics().Str().rfind("error: WGSL does not support combined image-samplers") != std::string::npos) { + slog.w << "This tint reader error is currently ignored during WebGPU bringup: " << tintRead.Diagnostics().Str() << io::endl; + } + else { + slog.e << "Tint Reader Error: " << tintRead.Diagnostics().Str() << io::endl; + return false; + } } tint::Result wgslOut = tint::wgsl::writer::Generate(tintRead,writerOpts); @@ -539,10 +542,8 @@ bool GLSLPostProcessor::spirvToWgsl(const SpirvBlob *spirv, std::string *outWsl) tint::SuccessType tintSuccess; if (wgslOut != tintSuccess) { - slog.w << "This tint writer error is currently ignored during WebGPU bringup:" << wgslOut.Failure().reason.Str() << io::endl; - //TODO: We should actually return false here, but for initial debugging - // let it slide until combined image sampler is resolved - // return false; + slog.e << "Tint writer error: " << wgslOut.Failure().reason.Str() << io::endl; + return false; } *outWsl = wgslOut->wgsl; return true; diff --git a/libs/filamat/src/MaterialBuilder.cpp b/libs/filamat/src/MaterialBuilder.cpp index 300ebd7cfc..b15b1e73f1 100644 --- a/libs/filamat/src/MaterialBuilder.cpp +++ b/libs/filamat/src/MaterialBuilder.cpp @@ -179,6 +179,14 @@ void MaterialBuilderBase::prepare(bool vulkanSemantics, effectiveFeatureLevel, }); } + if (any(mTargetApi & TargetApi::WEBGPU)) { + mCodeGenPermutations.push_back({ + shaderModel, + TargetApi::WEBGPU, + TargetLanguage::SPIRV, + effectiveFeatureLevel, + }); + } } } @@ -836,6 +844,7 @@ static void showErrorMessage(const char* materialName, filament::Variant variant break; case TargetApi::WEBGPU: targetApiString = "WebGPU.\n"; + break; case TargetApi::ALL: assert(0); // Unreachable. break; @@ -879,6 +888,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector essl1Entries; std::vector spirvEntries; std::vector metalEntries; + std::vector wgslEntries; LineDictionary textDictionary; BlobDictionary spirvDictionary; // End: must be protected by lock @@ -907,7 +917,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector 0); + wgslEntry.stage = v.stage; + wgslEntry.shader = wgsl; + wgslEntries.push_back(wgslEntry); + break; case TargetApi::ALL: // should never happen break; @@ -1099,6 +1118,7 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector( @@ -1144,6 +1167,12 @@ bool MaterialBuilder::generateShaders(JobSystem& jobSystem, const std::vector(std::move(wgslEntries), + dictionaryChunk.getDictionary(), ChunkType::MaterialWgsl); + } + return true; } diff --git a/libs/filamat/src/sca/GLSLTools.cpp b/libs/filamat/src/sca/GLSLTools.cpp index da9c6495f0..c03b9f295a 100644 --- a/libs/filamat/src/sca/GLSLTools.cpp +++ b/libs/filamat/src/sca/GLSLTools.cpp @@ -525,6 +525,11 @@ EShMessages GLSLTools::glslangFlagsFromTargetApi( // choke on gl_VertexIndex. msg |= (Type)EShMessages::EShMsgVulkanRules; } + if (targetApi == TargetApi::WEBGPU) { + // FIXME: We have to use EShMsgVulkanRules for WEBGPU, otherwise compilation will + // choke on gl_VertexIndex. + msg |= (Type)EShMessages::EShMsgVulkanRules; + } return (EShMessages)msg; } } @@ -540,13 +545,13 @@ void GLSLTools::prepareShaderParser(MaterialBuilder::TargetApi targetApi, shader.setEnvInput(EShSourceGlsl, stage, EShClientOpenGL, version); shader.setEnvClient(EShClientOpenGL, EShTargetOpenGL_450); break; + case MaterialBuilderBase::TargetApi::WEBGPU: case MaterialBuilderBase::TargetApi::VULKAN: case MaterialBuilderBase::TargetApi::METAL: shader.setEnvInput(EShSourceGlsl, stage, EShClientVulkan, version); shader.setEnvClient(EShClientVulkan, EShTargetVulkan_1_1); break; // TODO: Handle webgpu here - case MaterialBuilderBase::TargetApi::WEBGPU: case MaterialBuilderBase::TargetApi::ALL: // can't happen break; diff --git a/libs/filamat/src/shaders/CodeGenerator.cpp b/libs/filamat/src/shaders/CodeGenerator.cpp index 37e14a77f7..67fd6d09d2 100644 --- a/libs/filamat/src/shaders/CodeGenerator.cpp +++ b/libs/filamat/src/shaders/CodeGenerator.cpp @@ -175,6 +175,10 @@ utils::io::sstream& CodeGenerator::generateCommonProlog(utils::io::sstream& out, break; // TODO: Handle webgpu here case TargetApi::WEBGPU: + //For now, no differences so inherit the same changes. + // TODO Define a separte environment, OR relevant checks + out << "#define TARGET_VULKAN_ENVIRONMENT\n"; + break; case TargetApi::ALL: // invalid should never happen break; @@ -190,6 +194,7 @@ utils::io::sstream& CodeGenerator::generateCommonProlog(utils::io::sstream& out, } if (mTargetApi == TargetApi::VULKAN || + mTargetApi == TargetApi::WEBGPU || mTargetApi == TargetApi::METAL || (mTargetApi == TargetApi::OPENGL && mShaderModel == ShaderModel::DESKTOP) || mFeatureLevel >= FeatureLevel::FEATURE_LEVEL_2) { @@ -725,6 +730,8 @@ io::sstream& CodeGenerator::generateBufferInterfaceBlock(io::sstream& out, Shade break; // TODO: Handle webgpu here case TargetApi::WEBGPU: + out << "set = " << +set << ", binding = " << +binding << ", "; + break; case TargetApi::ALL: // nonsensical, shouldn't happen. break; @@ -813,6 +820,8 @@ io::sstream& CodeGenerator::generateCommonSamplers(utils::io::sstream& out, break; // TODO: Handle webgpu here case TargetApi::WEBGPU: + out << "layout(binding = " << +info.binding << ", set = " << +set << ") "; + break; case TargetApi::ALL: // should not happen break; diff --git a/libs/matdbg/src/JsonWriter.cpp b/libs/matdbg/src/JsonWriter.cpp index 7a5409927b..2dd65302af 100644 --- a/libs/matdbg/src/JsonWriter.cpp +++ b/libs/matdbg/src/JsonWriter.cpp @@ -254,6 +254,10 @@ bool JsonWriter::writeActiveInfo(const filaflat::ChunkContainer& package, json << "metal"; chunkType = ChunkType::MaterialMetal; break; + case ShaderLanguage::WGSL: + json << "webgpu"; + chunkType = ChunkType::MaterialWgsl; + break; default: return false; } diff --git a/libs/matdbg/src/ShaderExtractor.cpp b/libs/matdbg/src/ShaderExtractor.cpp index 22ba82c211..5103ca2706 100644 --- a/libs/matdbg/src/ShaderExtractor.cpp +++ b/libs/matdbg/src/ShaderExtractor.cpp @@ -57,6 +57,10 @@ ShaderExtractor::ShaderExtractor(backend::ShaderLanguage target, const void* dat mMaterialTag = ChunkType::MaterialMetalLibrary; mDictionaryTag = ChunkType::DictionaryMetalLibrary; break; + case backend::ShaderLanguage::WGSL: + mMaterialTag = ChunkType::MaterialWgsl; + mDictionaryTag = ChunkType::DictionaryText; + break; case backend::ShaderLanguage::SPIRV: mMaterialTag = ChunkType::MaterialSpirv; mDictionaryTag = ChunkType::DictionarySpirv; diff --git a/libs/matdbg/src/ShaderReplacer.cpp b/libs/matdbg/src/ShaderReplacer.cpp index 5c1e97f9bd..8537b4a13c 100644 --- a/libs/matdbg/src/ShaderReplacer.cpp +++ b/libs/matdbg/src/ShaderReplacer.cpp @@ -135,6 +135,10 @@ ShaderReplacer::ShaderReplacer(Backend backend, ShaderLanguage language, mMaterialTag = ChunkType::MaterialMetal; mDictionaryTag = ChunkType::DictionaryText; break; + case backend::ShaderLanguage::WGSL: + mMaterialTag = ChunkType::MaterialWgsl; + mDictionaryTag = ChunkType::DictionaryText; + break; case backend::ShaderLanguage::SPIRV: mMaterialTag = ChunkType::MaterialSpirv; mDictionaryTag = ChunkType::DictionarySpirv; diff --git a/libs/matdbg/src/TextWriter.cpp b/libs/matdbg/src/TextWriter.cpp index baa189a1b8..bb9a200b95 100644 --- a/libs/matdbg/src/TextWriter.cpp +++ b/libs/matdbg/src/TextWriter.cpp @@ -429,7 +429,10 @@ static bool printShaderInfo(ostream& text, const ChunkContainer& container, Chun break; case ChunkType::MaterialMetalLibrary: text << "Metal precompiled shader libraries:" << endl; - break; + break; + case ChunkType::MaterialWgsl: + text << "WGSL precompiled shader libraries:" << endl; + break; default: assert(false && "Invalid shader ChunkType"); break; @@ -467,6 +470,9 @@ bool TextWriter::writeMaterialInfo(const filaflat::ChunkContainer& container) { if (!printShaderInfo(text, container, ChunkType::MaterialMetalLibrary)) { return false; } + if (!printShaderInfo(text, container, ChunkType::MaterialWgsl)) { + return false; + } printChunks(text, container); diff --git a/tools/matc/src/matc/CommandlineConfig.cpp b/tools/matc/src/matc/CommandlineConfig.cpp index 6ca63158c6..4ff45f73d0 100644 --- a/tools/matc/src/matc/CommandlineConfig.cpp +++ b/tools/matc/src/matc/CommandlineConfig.cpp @@ -262,6 +262,8 @@ bool CommandlineConfig::parse() { mTargetApi |= TargetApi::VULKAN; } else if (arg == "metal") { mTargetApi |= TargetApi::METAL; + } else if (arg == "webgpu") { + mTargetApi |= TargetApi::WEBGPU; } else if (arg == "all") { mTargetApi |= TargetApi::ALL; } else { diff --git a/tools/matinfo/src/main.cpp b/tools/matinfo/src/main.cpp index c96604f184..1443d3bb0b 100644 --- a/tools/matinfo/src/main.cpp +++ b/tools/matinfo/src/main.cpp @@ -532,7 +532,7 @@ static bool parseChunks(Config config, void* data, size_t size) { return true; } - + //TODO Include a printWgsl logic here if (config.printMetal) { const filament::backend::ShaderLanguage language = config.binary ? filament::backend::ShaderLanguage::METAL_LIBRARY