From 26453ac99b187a64ac9df34fe647e79623e7ffdc Mon Sep 17 00:00:00 2001 From: MikhailGorobets Date: Fri, 5 Dec 2025 06:14:37 +0600 Subject: [PATCH 1/3] [WebGPU, Dawn]: Upgrade Dawn and new features for WebGPU --- BuildTools/CMake/BuildUtils.cmake | 44 +++-- Common/interface/ParsingTools.hpp | 1 - Graphics/GraphicsEngineWebGPU/CMakeLists.txt | 7 +- .../include/WebGPUStubs.hpp | 11 -- Graphics/GraphicsEngineWebGPU/include/pch.h | 42 +--- .../src/DeviceContextWebGPUImpl.cpp | 176 +++++++++-------- .../src/EngineFactoryWebGPU.cpp | 184 ++++++++---------- .../src/GenerateMipsHelperWebGPU.cpp | 21 +- .../src/PipelineStateWebGPUImpl.cpp | 80 +++----- .../src/RenderDeviceWebGPUImpl.cpp | 78 +++++--- .../src/ShaderWebGPUImpl.cpp | 9 +- .../src/SwapChainWebGPUImpl.cpp | 15 +- .../src/TextureWebGPUImpl.cpp | 13 +- .../src/WebGPUResourceBase.cpp | 20 +- .../src/WebGPUTypeConversions.cpp | 2 +- Graphics/ShaderTools/CMakeLists.txt | 10 +- .../ShaderTools/include/GLSLParsingTools.hpp | 64 ++++++ .../ShaderTools/include/HLSLParsingTools.hpp | 34 +++- Graphics/ShaderTools/include/SPIRVUtils.hpp | 36 +++- Graphics/ShaderTools/include/WGSLUtils.hpp | 3 + Graphics/ShaderTools/src/GLSLParsingTools.cpp | 12 ++ Graphics/ShaderTools/src/HLSLParsingTools.cpp | 112 ++++++++--- Graphics/ShaderTools/src/SPIRVUtils.cpp | 136 ++++++++++--- .../ShaderTools/src/WGSLShaderResources.cpp | 19 ++ Graphics/ShaderTools/src/WGSLUtils.cpp | 181 +++++++++++++---- .../RenderStateCache/ComputeShader.csh | 2 +- .../InlineShaders/ComputeShaderTestHLSL.h | 2 +- Tests/DiligentCoreAPITest/src/ArchiveTest.cpp | 2 +- Tests/DiligentCoreTest/CMakeLists.txt | 8 +- .../assets/shaders/WGSL/RWTextureArrays.psh | 12 +- .../assets/shaders/WGSL/RWTextures.psh | 24 +-- .../src/ShaderTools/GLSLParsingToolsTest.cpp | 36 ++++ .../src/ShaderTools/HLSLParsingToolsTest.cpp | 83 ++++++-- .../ShaderTools/WGSLShaderResourcesTest.cpp | 18 +- .../src/ShaderTools/WGSLUtilsTest.cpp | 1 + .../WebGPU/TestingEnvironmentWebGPU.hpp | 21 -- .../src/WebGPU/TestingEnvironmentWebGPU.cpp | 16 +- .../src/WebGPU/TestingSwapChainWebGPU.cpp | 64 +++--- Tests/IncludeTest/CMakeLists.txt | 6 +- ThirdParty/CMakeLists.txt | 8 - ThirdParty/abseil-cpp/CMakeLists.txt | 16 -- ThirdParty/dawn/CMakeLists.txt | 55 +++--- 42 files changed, 1057 insertions(+), 627 deletions(-) delete mode 100644 ThirdParty/abseil-cpp/CMakeLists.txt diff --git a/BuildTools/CMake/BuildUtils.cmake b/BuildTools/CMake/BuildUtils.cmake index ee394acabe..78e100d9c5 100644 --- a/BuildTools/CMake/BuildUtils.cmake +++ b/BuildTools/CMake/BuildUtils.cmake @@ -245,6 +245,21 @@ function(set_common_target_properties TARGET) custom_post_configure_target(${TARGET}) endif() + # Mark generated files as such to avoid "file not found" warnings in some IDEs in configuration stage + if (WEBGPU_SUPPORTED AND (NOT PLATFORM_WEB)) + set(DAWN_GENERATED_HEADERS + ${DAWN_BUILD_GEN_DIR}/include/dawn/webgpu.h + ${DAWN_BUILD_GEN_DIR}/include/dawn/webgpu_cpp.h + ${DAWN_BUILD_GEN_DIR}/include/dawn/webgpu_cpp_print.h + ${DAWN_BUILD_GEN_DIR}/include/dawn/wire/client/webgpu.h + ${DAWN_BUILD_GEN_DIR}/include/dawn/wire/client/webgpu_cpp.h + ${DAWN_BUILD_GEN_DIR}/include/dawn/wire/client/webgpu_cpp_print.h + ${DAWN_BUILD_GEN_DIR}/include/dawn/dawn_proc_table.h + ${DAWN_BUILD_GEN_DIR}/include/webgpu/webgpu_cpp_chained_struct.h + ) + set_source_files_properties(${DAWN_GENERATED_HEADERS} PROPERTIES GENERATED TRUE) + endif() + endfunction() function(find_targets_in_directory _RESULT _DIR) @@ -466,24 +481,29 @@ function(add_format_validation_target MODULE_NAME MODULE_ROOT_PATH IDE_FOLDER) endfunction() -# FetchContent's GIT_SHALLOW option is buggy and does not actually do a shallow -# clone. This macro takes care of it. -macro(FetchContent_DeclareShallowGit Name GIT_REPOSITORY GitRepository GIT_TAG GitTag) +# The GIT_SHALLOW option in FetchContent is buggy and does not actually perform +# a shallow clone. This macro fixes that. Also, we do not want to clone all +# submodules to reduce download time, therefore we add an option GIT_SUBMODULES +# to specify which submodules should be cloned (if any). +macro(FetchContent_DeclareShallowGit Name GIT_REPOSITORY GitRepository GIT_TAG GitTag GIT_SUBMODULES GitSubmodules) include(FetchContent) - FetchContent_Declare( - "${Name}" - # This is what it'd look like if GIT_SHALLOW was indeed working: - #GIT_REPOSITORY "${GitRepository}" - #GIT_TAG "${GitTag}" - #GIT_SHALLOW ON + # This is what it'd look like if GIT_SHALLOW was indeed working: + #GIT_REPOSITORY "${GitRepository}" + #GIT_TAG "${GitTag}" + #GIT_SHALLOW ON + #GIT_SUBMODULES "${GitSubmodules}" - # Manual download mode instead: + # Manual download mode instead: + FetchContent_Declare( + ${Name} DOWNLOAD_COMMAND cd "${FETCHCONTENT_BASE_DIR}/${Name}-src" && git init && - git fetch --depth=1 "${GitRepository}" "${GitTag}" && - git reset --hard FETCH_HEAD + git remote add origin "${GitRepository}" && + git fetch --depth=1 origin "${GitTag}" && + git checkout FETCH_HEAD && + git submodule update --init --recursive --depth=1 ${GitSubmodules} ) endmacro() diff --git a/Common/interface/ParsingTools.hpp b/Common/interface/ParsingTools.hpp index ee6c0f9727..19f36f8e3a 100644 --- a/Common/interface/ParsingTools.hpp +++ b/Common/interface/ParsingTools.hpp @@ -955,7 +955,6 @@ TokenIterType FindMatchingBracket(const TokenIterType& Start, ClosingBracketType = TokenType::OpenSquareBracket; SearchForward = false; break; - case TokenType::ClosingAngleBracket: ClosingBracketType = TokenType::OpenAngleBracket; SearchForward = false; diff --git a/Graphics/GraphicsEngineWebGPU/CMakeLists.txt b/Graphics/GraphicsEngineWebGPU/CMakeLists.txt index 0b8f2add2b..4e4458b5b6 100644 --- a/Graphics/GraphicsEngineWebGPU/CMakeLists.txt +++ b/Graphics/GraphicsEngineWebGPU/CMakeLists.txt @@ -179,7 +179,12 @@ PRIVATE ) if (PLATFORM_WEB) - target_link_options(Diligent-GraphicsEngineWebGPU-static PUBLIC "SHELL: -s USE_WEBGPU=1 -s USE_PTHREADS=1") + target_link_options(Diligent-GraphicsEngineWebGPU-static PUBLIC "SHELL: --use-port=emdawnwebgpu -s USE_PTHREADS=1") + target_compile_options(Diligent-GraphicsEngineWebGPU-static PUBLIC "--use-port=emdawnwebgpu") + # This is required only for IntelliSense to detect webgpu.h. + target_include_directories(Diligent-GraphicsEngineWebGPU-static PUBLIC + ${EMSCRIPTEN_ROOT_PATH}/cache/ports/emdawnwebgpu/emdawnwebgpu_pkg/webgpu/include + ) endif() target_compile_definitions(Diligent-GraphicsEngineWebGPU-shared PUBLIC DILIGENT_WEBGPU_SHARED=1) diff --git a/Graphics/GraphicsEngineWebGPU/include/WebGPUStubs.hpp b/Graphics/GraphicsEngineWebGPU/include/WebGPUStubs.hpp index d4dec4d798..939b2d6932 100644 --- a/Graphics/GraphicsEngineWebGPU/include/WebGPUStubs.hpp +++ b/Graphics/GraphicsEngineWebGPU/include/WebGPUStubs.hpp @@ -29,16 +29,5 @@ #if PLATFORM_WEB inline constexpr WGPUFeatureName WGPUFeatureName_ChromiumExperimentalTimestampQueryInsidePasses = static_cast(0x000003EE); -inline constexpr WGPUFeatureName WGPUFeatureName_Unorm16TextureFormats = static_cast(0x000003FB); -inline constexpr WGPUFeatureName WGPUFeatureName_Snorm16TextureFormats = static_cast(0x000003FC); - -inline constexpr WGPUTextureFormat WGPUTextureFormat_R16Unorm = static_cast(0x00000060); -inline constexpr WGPUTextureFormat WGPUTextureFormat_R16Snorm = static_cast(0x00000063); -inline constexpr WGPUTextureFormat WGPUTextureFormat_RG16Unorm = static_cast(0x00000061); -inline constexpr WGPUTextureFormat WGPUTextureFormat_RG16Snorm = static_cast(0x00000064); -inline constexpr WGPUTextureFormat WGPUTextureFormat_RGBA16Unorm = static_cast(0x00000062); -inline constexpr WGPUTextureFormat WGPUTextureFormat_RGBA16Snorm = static_cast(0x00000065); - -inline constexpr WGPUSurfaceGetCurrentTextureStatus WGPUSurfaceGetCurrentTextureStatus_Error = static_cast(0x00000007); #endif diff --git a/Graphics/GraphicsEngineWebGPU/include/pch.h b/Graphics/GraphicsEngineWebGPU/include/pch.h index 8ace9d3b41..dc9015e89f 100644 --- a/Graphics/GraphicsEngineWebGPU/include/pch.h +++ b/Graphics/GraphicsEngineWebGPU/include/pch.h @@ -37,45 +37,11 @@ #if PLATFORM_WEB -using WGPUOptionalBool = bool; -using WGPUShaderSourceWGSL = WGPUShaderModuleWGSLDescriptor; -using WGPUStringView = const char*; -using WGPUSurfaceSourceCanvasHTMLSelector_Emscripten = WGPUSurfaceDescriptorFromCanvasHTMLSelector; +using WGPUSurfaceSourceCanvasHTMLSelector_Emscripten = WGPUEmscriptenSurfaceSourceCanvasHTMLSelector; -constexpr bool WGPUOptionalBool_True = true; -constexpr bool WGPUOptionalBool_False = false; +constexpr WGPUSType WGPUSType_SurfaceSourceCanvasHTMLSelector_Emscripten = WGPUSType_EmscriptenSurfaceSourceCanvasHTMLSelector; -constexpr WGPUSType WGPUSType_ShaderSourceWGSL = WGPUSType_ShaderModuleWGSLDescriptor; -constexpr WGPUSType WGPUSType_SurfaceSourceCanvasHTMLSelector_Emscripten = WGPUSType_SurfaceDescriptorFromCanvasHTMLSelector; - -constexpr WGPUBufferBindingType WGPUBufferBindingType_BindingNotUsed = WGPUBufferBindingType_Undefined; -constexpr WGPUSamplerBindingType WGPUSamplerBindingType_BindingNotUsed = WGPUSamplerBindingType_Undefined; -constexpr WGPUTextureSampleType WGPUTextureSampleType_BindingNotUsed = WGPUTextureSampleType_Undefined; -constexpr WGPUStorageTextureAccess WGPUStorageTextureAccess_BindingNotUsed = WGPUStorageTextureAccess_Undefined; - -constexpr WGPUFeatureName WGPUFeatureName_DualSourceBlending = static_cast(0x00050008); - -inline bool WGPUStringViewValid(WGPUStringView Str) -{ - return Str != nullptr && Str[0] != '\0'; -} - -inline const char* WGPUStringViewToString(WGPUStringView Str) -{ - return Str; -} - -inline WGPUStringView GetWGPUStringView(const std::string& Str) -{ - return Str.c_str(); -} - -inline WGPUStringView GetWGPUStringView(const char* Str) -{ - return Str; -} - -#else +#endif inline bool WGPUStringViewValid(const WGPUStringView& Str) { @@ -102,5 +68,3 @@ inline WGPUStringView GetWGPUStringView(const char* Str) { return {Str, Str ? strlen(Str) : 0}; } - -#endif diff --git a/Graphics/GraphicsEngineWebGPU/src/DeviceContextWebGPUImpl.cpp b/Graphics/GraphicsEngineWebGPU/src/DeviceContextWebGPUImpl.cpp index 2ce32b2b19..59a779a5ac 100644 --- a/Graphics/GraphicsEngineWebGPU/src/DeviceContextWebGPUImpl.cpp +++ b/Graphics/GraphicsEngineWebGPU/src/DeviceContextWebGPUImpl.cpp @@ -896,13 +896,13 @@ void DeviceContextWebGPUImpl::UpdateTexture(ITexture* pText BufferWebGPUImpl* const pSrcBufferWebGPU = ClassPtrCast(SubresData.pSrcBuffer); const BufferDesc& SrcBuffDesc = pSrcBufferWebGPU->GetDesc(); - WGPUImageCopyTexture wgpuImageCopyDst{}; - wgpuImageCopyDst.texture = pDstTextureWebGPU->GetWebGPUTexture(); - wgpuImageCopyDst.aspect = WGPUTextureAspect_All; - wgpuImageCopyDst.origin.x = DstBox.MinX; - wgpuImageCopyDst.origin.y = DstBox.MinY; - wgpuImageCopyDst.origin.z = Slice != 0 ? Slice : DstBox.MinZ; - wgpuImageCopyDst.mipLevel = MipLevel; + WGPUTexelCopyTextureInfo wgpuTexelCopyDst{}; + wgpuTexelCopyDst.texture = pDstTextureWebGPU->GetWebGPUTexture(); + wgpuTexelCopyDst.aspect = WGPUTextureAspect_All; + wgpuTexelCopyDst.origin.x = DstBox.MinX; + wgpuTexelCopyDst.origin.y = DstBox.MinY; + wgpuTexelCopyDst.origin.z = Slice != 0 ? Slice : DstBox.MinZ; + wgpuTexelCopyDst.mipLevel = MipLevel; const TextureFormatAttribs& FmtAttribs = GetTextureFormatAttribs(pDstTextureWebGPU->GetDesc().Format); @@ -928,13 +928,13 @@ void DeviceContextWebGPUImpl::UpdateTexture(ITexture* pText } } - WGPUImageCopyBuffer wgpuImageCopySrc{}; - wgpuImageCopySrc.buffer = pSrcStagingBuffer != nullptr ? pSrcStagingBuffer->wgpuBuffer : pSrcBufferWebGPU->GetWebGPUBuffer(); - wgpuImageCopySrc.layout.offset = SubresData.SrcOffset; - wgpuImageCopySrc.layout.bytesPerRow = static_cast(SubresData.Stride); - wgpuImageCopySrc.layout.rowsPerImage = wgpuCopySize.height; + WGPUTexelCopyBufferInfo wgpuTexelCopySrc{}; + wgpuTexelCopySrc.buffer = pSrcStagingBuffer != nullptr ? pSrcStagingBuffer->wgpuBuffer : pSrcBufferWebGPU->GetWebGPUBuffer(); + wgpuTexelCopySrc.layout.offset = SubresData.SrcOffset; + wgpuTexelCopySrc.layout.bytesPerRow = static_cast(SubresData.Stride); + wgpuTexelCopySrc.layout.rowsPerImage = wgpuCopySize.height; - wgpuCommandEncoderCopyBufferToTexture(GetCommandEncoder(), &wgpuImageCopySrc, &wgpuImageCopyDst, &wgpuCopySize); + wgpuCommandEncoderCopyBufferToTexture(GetCommandEncoder(), &wgpuTexelCopySrc, &wgpuTexelCopyDst, &wgpuCopySize); if (pSrcStagingBuffer != nullptr) { @@ -965,19 +965,19 @@ void DeviceContextWebGPUImpl::UpdateTexture(ITexture* pText } } - WGPUImageCopyBuffer wgpuImageCopySrc{}; - wgpuImageCopySrc.buffer = UploadAlloc.wgpuBuffer; - wgpuImageCopySrc.layout.offset = UploadAlloc.Offset; - wgpuImageCopySrc.layout.bytesPerRow = static_cast(CopyInfo.RowStride); - wgpuImageCopySrc.layout.rowsPerImage = static_cast(CopyInfo.DepthStride / CopyInfo.RowStride); + WGPUTexelCopyBufferInfo wgpuTexelCopySrc{}; + wgpuTexelCopySrc.buffer = UploadAlloc.wgpuBuffer; + wgpuTexelCopySrc.layout.offset = UploadAlloc.Offset; + wgpuTexelCopySrc.layout.bytesPerRow = static_cast(CopyInfo.RowStride); + wgpuTexelCopySrc.layout.rowsPerImage = static_cast(CopyInfo.DepthStride / CopyInfo.RowStride); - WGPUImageCopyTexture wgpuImageCopyDst{}; - wgpuImageCopyDst.texture = pTextureWebGPU->GetWebGPUTexture(); - wgpuImageCopyDst.aspect = WGPUTextureAspect_All; - wgpuImageCopyDst.origin.x = DstBox.MinX; - wgpuImageCopyDst.origin.y = DstBox.MinY; - wgpuImageCopyDst.origin.z = Slice != 0 ? Slice : DstBox.MinZ; - wgpuImageCopyDst.mipLevel = MipLevel; + WGPUTexelCopyTextureInfo wgpuTexelCopyDst{}; + wgpuTexelCopyDst.texture = pTextureWebGPU->GetWebGPUTexture(); + wgpuTexelCopyDst.aspect = WGPUTextureAspect_All; + wgpuTexelCopyDst.origin.x = DstBox.MinX; + wgpuTexelCopyDst.origin.y = DstBox.MinY; + wgpuTexelCopyDst.origin.z = Slice != 0 ? Slice : DstBox.MinZ; + wgpuTexelCopyDst.mipLevel = MipLevel; const TextureFormatAttribs& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format); @@ -992,7 +992,7 @@ void DeviceContextWebGPUImpl::UpdateTexture(ITexture* pText wgpuCopySize.height = AlignUp(wgpuCopySize.height, FmtAttribs.BlockHeight); } - wgpuCommandEncoderCopyBufferToTexture(GetCommandEncoder(), &wgpuImageCopySrc, &wgpuImageCopyDst, &wgpuCopySize); + wgpuCommandEncoderCopyBufferToTexture(GetCommandEncoder(), &wgpuTexelCopySrc, &wgpuTexelCopyDst, &wgpuCopySize); } } @@ -1033,21 +1033,21 @@ void DeviceContextWebGPUImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) else wgpuAspectMask = WGPUTextureAspect_All; - WGPUImageCopyTexture wgpuImageCopySrc{}; - wgpuImageCopySrc.texture = pSrcTexWebGPU->GetWebGPUTexture(); - wgpuImageCopySrc.aspect = wgpuAspectMask; - wgpuImageCopySrc.origin.x = pSrcBox->MinX; - wgpuImageCopySrc.origin.y = pSrcBox->MinY; - wgpuImageCopySrc.origin.z = CopyAttribs.SrcSlice != 0 ? CopyAttribs.SrcSlice : pSrcBox->MinZ; - wgpuImageCopySrc.mipLevel = CopyAttribs.SrcMipLevel; - - WGPUImageCopyTexture wgpuImageCopyDst{}; - wgpuImageCopyDst.texture = pDstTexWebGPU->GetWebGPUTexture(); - wgpuImageCopyDst.aspect = wgpuAspectMask; - wgpuImageCopyDst.origin.x = CopyAttribs.DstX; - wgpuImageCopyDst.origin.y = CopyAttribs.DstY; - wgpuImageCopyDst.origin.z = CopyAttribs.DstSlice != 0 ? CopyAttribs.DstSlice : CopyAttribs.DstZ; - wgpuImageCopyDst.mipLevel = CopyAttribs.DstMipLevel; + WGPUTexelCopyTextureInfo wgpuTexelCopySrc{}; + wgpuTexelCopySrc.texture = pSrcTexWebGPU->GetWebGPUTexture(); + wgpuTexelCopySrc.aspect = wgpuAspectMask; + wgpuTexelCopySrc.origin.x = pSrcBox->MinX; + wgpuTexelCopySrc.origin.y = pSrcBox->MinY; + wgpuTexelCopySrc.origin.z = CopyAttribs.SrcSlice != 0 ? CopyAttribs.SrcSlice : pSrcBox->MinZ; + wgpuTexelCopySrc.mipLevel = CopyAttribs.SrcMipLevel; + + WGPUTexelCopyTextureInfo wgpuTexelCopyDst{}; + wgpuTexelCopyDst.texture = pDstTexWebGPU->GetWebGPUTexture(); + wgpuTexelCopyDst.aspect = wgpuAspectMask; + wgpuTexelCopyDst.origin.x = CopyAttribs.DstX; + wgpuTexelCopyDst.origin.y = CopyAttribs.DstY; + wgpuTexelCopyDst.origin.z = CopyAttribs.DstSlice != 0 ? CopyAttribs.DstSlice : CopyAttribs.DstZ; + wgpuTexelCopyDst.mipLevel = CopyAttribs.DstMipLevel; WGPUExtent3D wgpuCopySize{}; wgpuCopySize.width = std::max(pSrcBox->Width(), 1u); @@ -1060,7 +1060,7 @@ void DeviceContextWebGPUImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) wgpuCopySize.height = AlignUp(wgpuCopySize.height, DstFmtAttribs.BlockHeight); } - wgpuCommandEncoderCopyTextureToTexture(wgpuCmdEncoder, &wgpuImageCopySrc, &wgpuImageCopyDst, &wgpuCopySize); + wgpuCommandEncoderCopyTextureToTexture(wgpuCmdEncoder, &wgpuTexelCopySrc, &wgpuTexelCopyDst, &wgpuCopySize); } else if (SrcTexDesc.Usage == USAGE_STAGING && DstTexDesc.Usage != USAGE_STAGING) { @@ -1083,19 +1083,19 @@ void DeviceContextWebGPUImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) return; } - WGPUImageCopyBuffer wgpuImageCopySrc{}; - wgpuImageCopySrc.buffer = pSrcStagingBuffer->wgpuBuffer; - wgpuImageCopySrc.layout.offset = SrcBufferOffset; - wgpuImageCopySrc.layout.bytesPerRow = static_cast(AlignUp(SrcMipLevelAttribs.RowSize, TextureWebGPUImpl::ImageCopyBufferRowAlignment)); - wgpuImageCopySrc.layout.rowsPerImage = SrcMipLevelAttribs.StorageHeight / DstFmtAttribs.BlockHeight; + WGPUTexelCopyBufferInfo wgpuTexelCopySrc{}; + wgpuTexelCopySrc.buffer = pSrcStagingBuffer->wgpuBuffer; + wgpuTexelCopySrc.layout.offset = SrcBufferOffset; + wgpuTexelCopySrc.layout.bytesPerRow = static_cast(AlignUp(SrcMipLevelAttribs.RowSize, TextureWebGPUImpl::ImageCopyBufferRowAlignment)); + wgpuTexelCopySrc.layout.rowsPerImage = SrcMipLevelAttribs.StorageHeight / DstFmtAttribs.BlockHeight; - WGPUImageCopyTexture wgpuImageCopyDst{}; - wgpuImageCopyDst.texture = pDstTexWebGPU->GetWebGPUTexture(); - wgpuImageCopyDst.aspect = wgpuAspectMask; - wgpuImageCopyDst.origin.x = CopyAttribs.DstX; - wgpuImageCopyDst.origin.y = CopyAttribs.DstY; - wgpuImageCopyDst.origin.z = CopyAttribs.DstSlice != 0 ? CopyAttribs.DstSlice : CopyAttribs.DstZ; - wgpuImageCopyDst.mipLevel = CopyAttribs.DstMipLevel; + WGPUTexelCopyTextureInfo wgpuTexelCopyDst{}; + wgpuTexelCopyDst.texture = pDstTexWebGPU->GetWebGPUTexture(); + wgpuTexelCopyDst.aspect = wgpuAspectMask; + wgpuTexelCopyDst.origin.x = CopyAttribs.DstX; + wgpuTexelCopyDst.origin.y = CopyAttribs.DstY; + wgpuTexelCopyDst.origin.z = CopyAttribs.DstSlice != 0 ? CopyAttribs.DstSlice : CopyAttribs.DstZ; + wgpuTexelCopyDst.mipLevel = CopyAttribs.DstMipLevel; WGPUExtent3D wgpuCopySize{}; wgpuCopySize.width = std::max(pSrcBox->Width(), 1u); @@ -1108,7 +1108,7 @@ void DeviceContextWebGPUImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) wgpuCopySize.height = AlignUp(wgpuCopySize.height, DstFmtAttribs.BlockHeight); } - wgpuCommandEncoderCopyBufferToTexture(wgpuCmdEncoder, &wgpuImageCopySrc, &wgpuImageCopyDst, &wgpuCopySize); + wgpuCommandEncoderCopyBufferToTexture(wgpuCmdEncoder, &wgpuTexelCopySrc, &wgpuTexelCopyDst, &wgpuCopySize); m_PendingStagingWrites.emplace(pSrcStagingBuffer, RefCntAutoPtr{pSrcTexWebGPU}); } @@ -1133,19 +1133,19 @@ void DeviceContextWebGPUImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) return; } - WGPUImageCopyTexture wgpuImageCopySrc{}; - wgpuImageCopySrc.texture = pSrcTexWebGPU->GetWebGPUTexture(); - wgpuImageCopySrc.aspect = wgpuAspectMask; - wgpuImageCopySrc.origin.x = pSrcBox->MinX; - wgpuImageCopySrc.origin.y = pSrcBox->MinY; - wgpuImageCopySrc.origin.z = CopyAttribs.SrcSlice != 0 ? CopyAttribs.SrcSlice : pSrcBox->MinZ; - wgpuImageCopySrc.mipLevel = CopyAttribs.SrcMipLevel; + WGPUTexelCopyTextureInfo wgpuTexelCopySrc{}; + wgpuTexelCopySrc.texture = pSrcTexWebGPU->GetWebGPUTexture(); + wgpuTexelCopySrc.aspect = wgpuAspectMask; + wgpuTexelCopySrc.origin.x = pSrcBox->MinX; + wgpuTexelCopySrc.origin.y = pSrcBox->MinY; + wgpuTexelCopySrc.origin.z = CopyAttribs.SrcSlice != 0 ? CopyAttribs.SrcSlice : pSrcBox->MinZ; + wgpuTexelCopySrc.mipLevel = CopyAttribs.SrcMipLevel; - WGPUImageCopyBuffer wgpuImageCopyDst{}; - wgpuImageCopyDst.buffer = pDstStagingBuffer->wgpuBuffer; - wgpuImageCopyDst.layout.offset = DstBufferOffset; - wgpuImageCopyDst.layout.bytesPerRow = static_cast(AlignUp(DstMipLevelAttribs.RowSize, TextureWebGPUImpl::ImageCopyBufferRowAlignment)); - wgpuImageCopyDst.layout.rowsPerImage = DstMipLevelAttribs.StorageHeight / SrcFmtAttribs.BlockHeight; + WGPUTexelCopyBufferInfo wgpuTexelCopyDst{}; + wgpuTexelCopyDst.buffer = pDstStagingBuffer->wgpuBuffer; + wgpuTexelCopyDst.layout.offset = DstBufferOffset; + wgpuTexelCopyDst.layout.bytesPerRow = static_cast(AlignUp(DstMipLevelAttribs.RowSize, TextureWebGPUImpl::ImageCopyBufferRowAlignment)); + wgpuTexelCopyDst.layout.rowsPerImage = DstMipLevelAttribs.StorageHeight / SrcFmtAttribs.BlockHeight; WGPUExtent3D wgpuCopySize{}; wgpuCopySize.width = std::max(pSrcBox->Width(), 1u); @@ -1158,7 +1158,7 @@ void DeviceContextWebGPUImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs) wgpuCopySize.height = AlignUp(wgpuCopySize.height, SrcFmtAttribs.BlockHeight); } - wgpuCommandEncoderCopyTextureToBuffer(wgpuCmdEncoder, &wgpuImageCopySrc, &wgpuImageCopyDst, &wgpuCopySize); + wgpuCommandEncoderCopyTextureToBuffer(wgpuCmdEncoder, &wgpuTexelCopySrc, &wgpuTexelCopyDst, &wgpuCopySize); m_PendingStagingReads.emplace(pDstStagingBuffer, RefCntAutoPtr{pDstTexWebGPU}); } @@ -1277,19 +1277,19 @@ void DeviceContextWebGPUImpl::UnmapTextureSubresource(ITexture* pTexture, Uint32 const UploadMemoryManagerWebGPU::Allocation& Allocation = UploadSpaceIt->second.Allocation; const BufferToTextureCopyInfo& CopyInfo = UploadSpaceIt->second.CopyInfo; - WGPUImageCopyBuffer wgpuImageCopySrc{}; - wgpuImageCopySrc.buffer = Allocation.wgpuBuffer; - wgpuImageCopySrc.layout.offset = Allocation.Offset; - wgpuImageCopySrc.layout.bytesPerRow = static_cast(CopyInfo.RowStride); - wgpuImageCopySrc.layout.rowsPerImage = static_cast(CopyInfo.DepthStride / CopyInfo.RowStride); + WGPUTexelCopyBufferInfo wgpuTexelCopySrc{}; + wgpuTexelCopySrc.buffer = Allocation.wgpuBuffer; + wgpuTexelCopySrc.layout.offset = Allocation.Offset; + wgpuTexelCopySrc.layout.bytesPerRow = static_cast(CopyInfo.RowStride); + wgpuTexelCopySrc.layout.rowsPerImage = static_cast(CopyInfo.DepthStride / CopyInfo.RowStride); - WGPUImageCopyTexture wgpuImageCopyDst{}; - wgpuImageCopyDst.texture = pTextureWebGPU->GetWebGPUTexture(); - wgpuImageCopyDst.aspect = WGPUTextureAspect_All; - wgpuImageCopyDst.origin.x = CopyInfo.Region.MinX; - wgpuImageCopyDst.origin.y = CopyInfo.Region.MinY; - wgpuImageCopyDst.origin.z = CopyInfo.Region.MinZ; - wgpuImageCopyDst.mipLevel = UploadSpaceIt->first.MipLevel; + WGPUTexelCopyTextureInfo wgpuTexelCopyDst{}; + wgpuTexelCopyDst.texture = pTextureWebGPU->GetWebGPUTexture(); + wgpuTexelCopyDst.aspect = WGPUTextureAspect_All; + wgpuTexelCopyDst.origin.x = CopyInfo.Region.MinX; + wgpuTexelCopyDst.origin.y = CopyInfo.Region.MinY; + wgpuTexelCopyDst.origin.z = CopyInfo.Region.MinZ; + wgpuTexelCopyDst.mipLevel = UploadSpaceIt->first.MipLevel; WGPUExtent3D wgpuCopySize{}; wgpuCopySize.width = CopyInfo.Region.Width(); @@ -1302,7 +1302,7 @@ void DeviceContextWebGPUImpl::UnmapTextureSubresource(ITexture* pTexture, Uint32 wgpuCopySize.height = AlignUp(wgpuCopySize.height, FmtAttribs.BlockHeight); } - wgpuCommandEncoderCopyBufferToTexture(GetCommandEncoder(), &wgpuImageCopySrc, &wgpuImageCopyDst, &wgpuCopySize); + wgpuCommandEncoderCopyBufferToTexture(GetCommandEncoder(), &wgpuTexelCopySrc, &wgpuTexelCopyDst, &wgpuCopySize); m_MappedTextures.erase(UploadSpaceIt); } else @@ -1476,9 +1476,9 @@ void DeviceContextWebGPUImpl::Flush() if (m_wgpuCommandEncoder || !m_SignaledFences.empty()) { - auto WorkDoneCallback = [](WGPUQueueWorkDoneStatus Status, void* pUserData) { - VERIFY_EXPR(pUserData != nullptr); - SyncPointWebGPUImpl* pSyncPoint = static_cast(pUserData); + auto WorkDoneCallback = [](WGPUQueueWorkDoneStatus wgpuStatus, WGPUStringView Message, void* pUserData1, void* pUserData2) { + VERIFY_EXPR(pUserData1 != nullptr); + SyncPointWebGPUImpl* pSyncPoint = static_cast(pUserData1); pSyncPoint->Trigger(); pSyncPoint->Release(); }; @@ -1501,9 +1501,13 @@ void DeviceContextWebGPUImpl::Flush() WGPUCommandBufferDescriptor wgpuCmdBufferDesc{}; WebGPUCommandBufferWrapper wgpuCmdBuffer{wgpuCommandEncoderFinish(GetCommandEncoder(), &wgpuCmdBufferDesc)}; DEV_CHECK_ERR(wgpuCmdBuffer != nullptr, "Failed to finish command encoder"); - wgpuQueueSubmit(m_wgpuQueue, 1, &wgpuCmdBuffer.Get()); - wgpuQueueOnSubmittedWorkDone(m_wgpuQueue, WorkDoneCallback, pWorkDoneSyncPoint.Detach()); + + WGPUQueueWorkDoneCallbackInfo wgpuWorkDoneCallbackInfo{}; + wgpuWorkDoneCallbackInfo.callback = WorkDoneCallback; + wgpuWorkDoneCallbackInfo.mode = WGPUCallbackMode_AllowSpontaneous; + wgpuWorkDoneCallbackInfo.userdata1 = pWorkDoneSyncPoint.Detach(); + wgpuQueueOnSubmittedWorkDone(m_wgpuQueue, wgpuWorkDoneCallbackInfo); m_wgpuCommandEncoder.Reset(nullptr); for (auto& PendingReadIt : m_PendingStagingReads) diff --git a/Graphics/GraphicsEngineWebGPU/src/EngineFactoryWebGPU.cpp b/Graphics/GraphicsEngineWebGPU/src/EngineFactoryWebGPU.cpp index 1a584de3df..4590b6d677 100644 --- a/Graphics/GraphicsEngineWebGPU/src/EngineFactoryWebGPU.cpp +++ b/Graphics/GraphicsEngineWebGPU/src/EngineFactoryWebGPU.cpp @@ -147,19 +147,19 @@ std::vector FindCompatibleAdapters(WGPUInstance wgpuInstan struct CallbackUserData { - WGPUAdapter Adapter = nullptr; - WGPURequestAdapterStatus RequestStatus = {}; - String Message = {}; - bool IsReady = {}; + WGPUAdapter wgpuAdapter = nullptr; + WGPURequestAdapterStatus wgpuRequestStatus = {}; + String Message = {}; + bool IsReady = {}; }; - auto OnAdapterRequestEnded = [](WGPURequestAdapterStatus Status, WGPUAdapter Adapter, WGPUStringView Message, void* pCallbackUserData) { - if (pCallbackUserData != nullptr) + auto OnAdapterRequestEnded = [](WGPURequestAdapterStatus wgpuStatus, WGPUAdapter wgpuAdapter, WGPUStringView Message, void* pUserData1, void* pUserData2) { + if (pUserData1 != nullptr) { - CallbackUserData* pUserData = static_cast(pCallbackUserData); - pUserData->Adapter = Adapter; - pUserData->RequestStatus = Status; - pUserData->IsReady = true; + CallbackUserData* pUserData = static_cast(pUserData1); + pUserData->wgpuAdapter = wgpuAdapter; + pUserData->wgpuRequestStatus = wgpuStatus; + pUserData->IsReady = true; if (WGPUStringViewValid(Message)) pUserData->Message = WGPUStringViewToString(Message); } @@ -169,27 +169,31 @@ std::vector FindCompatibleAdapters(WGPUInstance wgpuInstan WGPUPowerPreference_HighPerformance, WGPUPowerPreference_LowPower}; - for (const WGPUPowerPreference& powerPreference : PowerPreferences) + for (const WGPUPowerPreference& PowerPreference : PowerPreferences) { CallbackUserData UserData{}; - WGPURequestAdapterOptions Options{}; - Options.powerPreference = powerPreference; - Options.backendType = WGPUBackendType_Undefined; - Options.forceFallbackAdapter = false; - Options.compatibilityMode = false; - wgpuInstanceRequestAdapter(wgpuInstance, &Options, OnAdapterRequestEnded, &UserData); + WGPURequestAdapterOptions wgpuAdapterRequestOptions{}; + wgpuAdapterRequestOptions.powerPreference = PowerPreference; + wgpuAdapterRequestOptions.backendType = WGPUBackendType_Undefined; + wgpuAdapterRequestOptions.forceFallbackAdapter = false; + + WGPURequestAdapterCallbackInfo wgpuAdapterRequestCallbackInfo{}; + wgpuAdapterRequestCallbackInfo.callback = OnAdapterRequestEnded; + wgpuAdapterRequestCallbackInfo.mode = WGPUCallbackMode_AllowSpontaneous; + wgpuAdapterRequestCallbackInfo.userdata1 = &UserData; + wgpuInstanceRequestAdapter(wgpuInstance, &wgpuAdapterRequestOptions, wgpuAdapterRequestCallbackInfo); while (!UserData.IsReady) InstancePoolEvents(wgpuInstance); - if (UserData.RequestStatus == WGPURequestAdapterStatus_Success) + if (UserData.wgpuRequestStatus == WGPURequestAdapterStatus_Success) { - auto adapter_it = std::find_if(wgpuAdapters.begin(), wgpuAdapters.end(), - [&](const auto& wgpuAdapter) { return wgpuAdapter.Get() == UserData.Adapter; }); + auto AdapterIter = std::find_if(wgpuAdapters.begin(), wgpuAdapters.end(), + [&](const auto& wgpuAdapter) { return wgpuAdapter.Get() == UserData.wgpuAdapter; }); - if (adapter_it == wgpuAdapters.end()) - wgpuAdapters.emplace_back(UserData.Adapter); + if (AdapterIter == wgpuAdapters.end()) + wgpuAdapters.emplace_back(UserData.wgpuAdapter); } else { @@ -200,47 +204,25 @@ std::vector FindCompatibleAdapters(WGPUInstance wgpuInstan return wgpuAdapters; } -static void DeviceLostCallback(WGPUDeviceLostReason Reason, +static void DeviceLostCallback(WGPUDevice const* wgpuDevice, + WGPUDeviceLostReason wgpuReason, WGPUStringView Message, - void* userdata) -{ - bool Expression = Reason != WGPUDeviceLostReason_Destroyed; -#if !PLATFORM_WEB - Expression &= (Reason != WGPUDeviceLostReason_InstanceDropped); -#endif - if (Expression && WGPUStringViewValid(Message)) - { - LOG_DEBUG_MESSAGE(DEBUG_MESSAGE_SEVERITY_ERROR, "WebGPU: ", WGPUStringViewToString(Message)); - } -} - -#if !PLATFORM_WEB -static void DeviceLostCallback2(WGPUDevice const* device, - WGPUDeviceLostReason Reason, - WGPUStringView Message, - void* userdata1, - void* userdata2) + void* userdata, + void* userdata2) { - DeviceLostCallback(Reason, Message, userdata1); -} + bool Expression = wgpuReason != WGPUDeviceLostReason_Destroyed; + Expression &= (wgpuReason != WGPUDeviceLostReason_CallbackCancelled); -static void UncapturedErrorCallback2(WGPUDevice const* device, - WGPUErrorType MessageType, - WGPUStringView Message, - void* userdata1, - void* userdata2) -{ - if (WGPUStringViewValid(Message)) + if (Expression && WGPUStringViewValid(Message)) { LOG_DEBUG_MESSAGE(DEBUG_MESSAGE_SEVERITY_ERROR, "WebGPU: ", WGPUStringViewToString(Message)); } } -#endif WebGPUDeviceWrapper CreateDeviceForAdapter(const DeviceFeatures& Features, WGPUInstance wgpuInstance, WGPUAdapter wgpuAdapter) { - WGPUSupportedLimits SupportedLimits{}; - wgpuAdapterGetLimits(wgpuAdapter, &SupportedLimits); + WGPULimits wgpuSupportedLimits{}; + wgpuAdapterGetLimits(wgpuAdapter, &wgpuSupportedLimits); std::vector wgpuFeatures{}; { @@ -271,33 +253,45 @@ WebGPUDeviceWrapper CreateDeviceForAdapter(const DeviceFeatures& Features, WGPUI if (wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_BGRA8UnormStorage)) wgpuFeatures.push_back(WGPUFeatureName_BGRA8UnormStorage); - if (wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_Unorm16TextureFormats)) - wgpuFeatures.push_back(WGPUFeatureName_Unorm16TextureFormats); + if (wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_TextureFormatsTier1)) + wgpuFeatures.push_back(WGPUFeatureName_TextureFormatsTier1); - if (wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_Snorm16TextureFormats)) - wgpuFeatures.push_back(WGPUFeatureName_Snorm16TextureFormats); + if (wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_TextureFormatsTier2)) + wgpuFeatures.push_back(WGPUFeatureName_TextureFormatsTier2); } struct CallbackUserData { - WGPUDevice Device = nullptr; - WGPURequestDeviceStatus RequestStatus = {}; - String Message = {}; - bool IsReady = {}; + WGPUDevice wgpuDevice = nullptr; + WGPURequestDeviceStatus wgpuRequestStatus = {}; + String Message = {}; + bool IsReady = {}; } UserData; - auto OnDeviceRequestEnded = [](WGPURequestDeviceStatus Status, WGPUDevice Device, WGPUStringView Message, void* pCallbackUserData) { - if (pCallbackUserData != nullptr) + auto OnDeviceRequestEnded = [](WGPURequestDeviceStatus wgpuStatus, WGPUDevice wgpuDevice, WGPUStringView Message, void* pUserData1, void* pUserData2) { + if (pUserData1 != nullptr) { - CallbackUserData* pUserData = static_cast(pCallbackUserData); - pUserData->Device = Device; - pUserData->RequestStatus = Status; - pUserData->IsReady = true; + CallbackUserData* pUserData = static_cast(pUserData1); + pUserData->wgpuDevice = wgpuDevice; + pUserData->wgpuRequestStatus = wgpuStatus; + pUserData->IsReady = true; if (WGPUStringViewValid(Message)) pUserData->Message = WGPUStringViewToString(Message); } }; + auto UncapturedErrorCallback = [](WGPUDevice const* wgpuDevice, WGPUErrorType wgpuTypeError, WGPUStringView Message, void* pUserdata1, void* pUserdata2) { + LOG_ERROR_MESSAGE("Uncaptured WebGPU error (type ", wgpuTypeError, "): ", WGPUStringViewToString(Message)); + }; + + WGPUDeviceDescriptor wgpuDeviceDesc{}; + wgpuDeviceDesc.requiredLimits = &wgpuSupportedLimits; + wgpuDeviceDesc.requiredFeatureCount = wgpuFeatures.size(); + wgpuDeviceDesc.requiredFeatures = wgpuFeatures.data(); + + wgpuDeviceDesc.uncapturedErrorCallbackInfo.callback = UncapturedErrorCallback; + wgpuDeviceDesc.deviceLostCallbackInfo.callback = DeviceLostCallback; + wgpuDeviceDesc.deviceLostCallbackInfo.mode = WGPUCallbackMode_AllowSpontaneous; #if !PLATFORM_WEB const char* ToggleNames[] = { "disable_timestamp_query_conversion", @@ -308,30 +302,24 @@ WebGPUDeviceWrapper CreateDeviceForAdapter(const DeviceFeatures& Features, WGPUI wgpuDawnTogglesDesc.chain.sType = WGPUSType_DawnTogglesDescriptor; wgpuDawnTogglesDesc.enabledToggleCount = _countof(ToggleNames); wgpuDawnTogglesDesc.enabledToggles = ToggleNames; -#endif - - WGPURequiredLimits RequiredLimits{nullptr, SupportedLimits.limits}; - WGPUDeviceDescriptor DeviceDesc{}; - DeviceDesc.requiredLimits = &RequiredLimits; - DeviceDesc.requiredFeatureCount = wgpuFeatures.size(); - DeviceDesc.requiredFeatures = wgpuFeatures.data(); -#if PLATFORM_WEB - DeviceDesc.deviceLostCallback = DeviceLostCallback; -#else - DeviceDesc.deviceLostCallbackInfo2 = {nullptr, WGPUCallbackMode_AllowSpontaneous, DeviceLostCallback2}; - DeviceDesc.uncapturedErrorCallbackInfo2 = {nullptr, UncapturedErrorCallback2}; - DeviceDesc.nextInChain = reinterpret_cast(&wgpuDawnTogglesDesc); + wgpuDeviceDesc.nextInChain = reinterpret_cast(&wgpuDawnTogglesDesc); #endif - wgpuAdapterRequestDevice(wgpuAdapter, &DeviceDesc, OnDeviceRequestEnded, &UserData); + + WGPURequestDeviceCallbackInfo wgpuDeviceRequestCallbackInfo{}; + wgpuDeviceRequestCallbackInfo.nextInChain = nullptr; + wgpuDeviceRequestCallbackInfo.mode = WGPUCallbackMode_AllowSpontaneous; + wgpuDeviceRequestCallbackInfo.callback = OnDeviceRequestEnded; + wgpuDeviceRequestCallbackInfo.userdata1 = &UserData; + wgpuAdapterRequestDevice(wgpuAdapter, &wgpuDeviceDesc, wgpuDeviceRequestCallbackInfo); while (!UserData.IsReady) InstancePoolEvents(wgpuInstance); - if (UserData.RequestStatus != WGPURequestDeviceStatus_Success) + if (UserData.wgpuRequestStatus != WGPURequestDeviceStatus_Success) LOG_ERROR_AND_THROW(UserData.Message); - return WebGPUDeviceWrapper{UserData.Device}; + return WebGPUDeviceWrapper{UserData.wgpuDevice}; } bool FeatureSupported(WGPUAdapter wgpuAdapter, WGPUDevice wgpuDevice, WGPUFeatureName Feature) @@ -454,7 +442,7 @@ GraphicsAdapterInfo GetGraphicsAdapterInfo(WGPUAdapter wgpuAdapter, WGPUDevice w AdapterInfo.Features = GetSupportedFeatures(wgpuAdapter, wgpuDevice); - WGPUSupportedLimits wgpuSupportedLimits{}; + WGPULimits wgpuSupportedLimits{}; if (wgpuAdapter) wgpuAdapterGetLimits(wgpuAdapter, &wgpuSupportedLimits); else @@ -491,16 +479,16 @@ GraphicsAdapterInfo GetGraphicsAdapterInfo(WGPUAdapter wgpuAdapter, WGPUDevice w { ComputeShaderProperties& ComputeShaderInfo{AdapterInfo.ComputeShader}; - ComputeShaderInfo.MaxThreadGroupSizeX = wgpuSupportedLimits.limits.maxComputeWorkgroupSizeX; - ComputeShaderInfo.MaxThreadGroupSizeY = wgpuSupportedLimits.limits.maxComputeWorkgroupSizeY; - ComputeShaderInfo.MaxThreadGroupSizeZ = wgpuSupportedLimits.limits.maxComputeWorkgroupSizeZ; + ComputeShaderInfo.MaxThreadGroupSizeX = wgpuSupportedLimits.maxComputeWorkgroupSizeX; + ComputeShaderInfo.MaxThreadGroupSizeY = wgpuSupportedLimits.maxComputeWorkgroupSizeY; + ComputeShaderInfo.MaxThreadGroupSizeZ = wgpuSupportedLimits.maxComputeWorkgroupSizeZ; - ComputeShaderInfo.MaxThreadGroupCountX = wgpuSupportedLimits.limits.maxComputeWorkgroupsPerDimension; - ComputeShaderInfo.MaxThreadGroupCountY = wgpuSupportedLimits.limits.maxComputeWorkgroupsPerDimension; - ComputeShaderInfo.MaxThreadGroupCountZ = wgpuSupportedLimits.limits.maxComputeWorkgroupsPerDimension; + ComputeShaderInfo.MaxThreadGroupCountX = wgpuSupportedLimits.maxComputeWorkgroupsPerDimension; + ComputeShaderInfo.MaxThreadGroupCountY = wgpuSupportedLimits.maxComputeWorkgroupsPerDimension; + ComputeShaderInfo.MaxThreadGroupCountZ = wgpuSupportedLimits.maxComputeWorkgroupsPerDimension; - ComputeShaderInfo.SharedMemorySize = wgpuSupportedLimits.limits.maxComputeWorkgroupStorageSize; - ComputeShaderInfo.MaxThreadGroupInvocations = wgpuSupportedLimits.limits.maxComputeInvocationsPerWorkgroup; + ComputeShaderInfo.SharedMemorySize = wgpuSupportedLimits.maxComputeWorkgroupStorageSize; + ComputeShaderInfo.MaxThreadGroupInvocations = wgpuSupportedLimits.maxComputeInvocationsPerWorkgroup; } // Set texture info @@ -508,11 +496,11 @@ GraphicsAdapterInfo GetGraphicsAdapterInfo(WGPUAdapter wgpuAdapter, WGPUDevice w TextureProperties& TextureInfo{AdapterInfo.Texture}; TextureInfo.MaxTexture1DArraySlices = 0; // Not supported in WebGPU - TextureInfo.MaxTexture2DArraySlices = wgpuSupportedLimits.limits.maxTextureArrayLayers; + TextureInfo.MaxTexture2DArraySlices = wgpuSupportedLimits.maxTextureArrayLayers; - TextureInfo.MaxTexture1DDimension = wgpuSupportedLimits.limits.maxTextureDimension1D; - TextureInfo.MaxTexture2DDimension = wgpuSupportedLimits.limits.maxTextureDimension2D; - TextureInfo.MaxTexture3DDimension = wgpuSupportedLimits.limits.maxTextureDimension3D; + TextureInfo.MaxTexture1DDimension = wgpuSupportedLimits.maxTextureDimension1D; + TextureInfo.MaxTexture2DDimension = wgpuSupportedLimits.maxTextureDimension2D; + TextureInfo.MaxTexture3DDimension = wgpuSupportedLimits.maxTextureDimension3D; TextureInfo.Texture2DMSSupported = True; TextureInfo.Texture2DMSArraySupported = False; @@ -524,8 +512,8 @@ GraphicsAdapterInfo GetGraphicsAdapterInfo(WGPUAdapter wgpuAdapter, WGPUDevice w // Set buffer info { BufferProperties& BufferInfo{AdapterInfo.Buffer}; - BufferInfo.ConstantBufferOffsetAlignment = wgpuSupportedLimits.limits.minUniformBufferOffsetAlignment; - BufferInfo.StructuredBufferOffsetAlignment = wgpuSupportedLimits.limits.minStorageBufferOffsetAlignment; + BufferInfo.ConstantBufferOffsetAlignment = wgpuSupportedLimits.minUniformBufferOffsetAlignment; + BufferInfo.StructuredBufferOffsetAlignment = wgpuSupportedLimits.minStorageBufferOffsetAlignment; } // Set sampler info diff --git a/Graphics/GraphicsEngineWebGPU/src/GenerateMipsHelperWebGPU.cpp b/Graphics/GraphicsEngineWebGPU/src/GenerateMipsHelperWebGPU.cpp index bb72acf8b5..2736d8689c 100644 --- a/Graphics/GraphicsEngineWebGPU/src/GenerateMipsHelperWebGPU.cpp +++ b/Graphics/GraphicsEngineWebGPU/src/GenerateMipsHelperWebGPU.cpp @@ -247,10 +247,24 @@ std::string_view ConvertWebGPUFormatToString(WGPUTextureFormat TexFmt) case WGPUTextureFormat_RGBA16Float: return "rgba16float"; + case WGPUTextureFormat_RGBA16Unorm: + return "rgba16unorm"; + case WGPUTextureFormat_RGBA16Snorm: + return "rgba16snorm"; + case WGPUTextureFormat_RG16Float: return "rg16float"; + case WGPUTextureFormat_RG16Unorm: + return "rg16unorm"; + case WGPUTextureFormat_RG16Snorm: + return "rg16snorm"; + case WGPUTextureFormat_R16Float: return "r16float"; + case WGPUTextureFormat_R16Unorm: + return "r16unorm"; + case WGPUTextureFormat_R16Snorm: + return "r16snorm"; case WGPUTextureFormat_RGBA32Float: return "rgba32float"; @@ -259,8 +273,13 @@ std::string_view ConvertWebGPUFormatToString(WGPUTextureFormat TexFmt) case WGPUTextureFormat_R32Float: return "r32float"; + case WGPUTextureFormat_RG11B10Ufloat: + return "rg11b10ufloat"; + case WGPUTextureFormat_RGB10A2Unorm: + return "rgb10a2unorm"; + default: - UNEXPECTED("Unsupported texture format"); + UNEXPECTED("Unsupported texture format: ", TexFmt); return "rgba8unorm"; } } diff --git a/Graphics/GraphicsEngineWebGPU/src/PipelineStateWebGPUImpl.cpp b/Graphics/GraphicsEngineWebGPU/src/PipelineStateWebGPUImpl.cpp index 70ca2924d0..4dea792aed 100644 --- a/Graphics/GraphicsEngineWebGPU/src/PipelineStateWebGPUImpl.cpp +++ b/Graphics/GraphicsEngineWebGPU/src/PipelineStateWebGPUImpl.cpp @@ -307,35 +307,19 @@ struct PipelineStateWebGPUImpl::AsyncPipelineBuilder : public ObjectBase(pUserData)->InitializePipelines(Status, Pipeline, nullptr, Message); - } - - static void CreateRenderPipelineCallback2(WGPUCreatePipelineAsyncStatus Status, - WGPURenderPipeline Pipeline, - WGPUStringView Message, - void* pUserData1, - void* pUserData2) - { - CreateRenderPipelineCallback(Status, Pipeline, Message, pUserData1); + static_cast(pUserData1)->InitializePipelines(Status, Pipeline, nullptr, Message); } static void CreateComputePipelineCallback(WGPUCreatePipelineAsyncStatus Status, WGPUComputePipeline Pipeline, WGPUStringView Message, - void* pUserData) - { - static_cast(pUserData)->InitializePipelines(Status, nullptr, Pipeline, Message); - } - - static void CreateComputePipelineCallback2(WGPUCreatePipelineAsyncStatus Status, - WGPUComputePipeline Pipeline, - WGPUStringView Message, - void* pUserData1, - void* pUserData2) + void* pUserData1, + void* pUserData2) { - CreateComputePipelineCallback(Status, Pipeline, Message, pUserData1); + static_cast(pUserData1)->InitializePipelines(Status, nullptr, Pipeline, Message); } }; @@ -444,7 +428,7 @@ void PipelineStateWebGPUImpl::InitializeWebGPURenderPipeline(const TShaderStages for (size_t Idx = 0; Idx < MaxBufferSlot + 1; ++Idx) { - wgpuVertexBufferLayouts[Idx].stepMode = !wgpuVertexAttributes[Idx].empty() ? wgpuVertexBufferLayouts[Idx].stepMode : WGPUVertexStepMode_VertexBufferNotUsed; + wgpuVertexBufferLayouts[Idx].stepMode = !wgpuVertexAttributes[Idx].empty() ? wgpuVertexBufferLayouts[Idx].stepMode : WGPUVertexStepMode_Undefined; wgpuVertexBufferLayouts[Idx].attributeCount = static_cast(wgpuVertexAttributes[Idx].size()); wgpuVertexBufferLayouts[Idx].attributes = wgpuVertexAttributes[Idx].data(); } @@ -520,9 +504,6 @@ void PipelineStateWebGPUImpl::InitializeWebGPURenderPipeline(const TShaderStages wgpuRenderPipelineDesc.depthStencil = &wgpuDepthStencilState; } -#if PLATFORM_WEB - WGPUPrimitiveDepthClipControl wgpuDepthClipControl{}; -#endif { const RasterizerStateDesc& RasterizerDesc = GraphicsPipeline.RasterizerDesc; @@ -544,13 +525,7 @@ void PipelineStateWebGPUImpl::InitializeWebGPURenderPipeline(const TShaderStages { if (m_pDevice->GetDeviceInfo().Features.DepthClamp) { -#if PLATFORM_WEB - wgpuDepthClipControl.chain.sType = WGPUSType_PrimitiveDepthClipControl; - wgpuDepthClipControl.unclippedDepth = true; - wgpuPrimitiveState.nextInChain = reinterpret_cast(&wgpuDepthClipControl); -#else wgpuPrimitiveState.unclippedDepth = true; -#endif } else { @@ -571,18 +546,14 @@ void PipelineStateWebGPUImpl::InitializeWebGPURenderPipeline(const TShaderStages { // The reference will be released from the callback. AsyncBuilder->AddRef(); -#if PLATFORM_WEB - wgpuDeviceCreateRenderPipelineAsync(m_pDevice->GetWebGPUDevice(), &wgpuRenderPipelineDesc, AsyncPipelineBuilder::CreateRenderPipelineCallback, AsyncBuilder); -#else - wgpuDeviceCreateRenderPipelineAsync2(m_pDevice->GetWebGPUDevice(), &wgpuRenderPipelineDesc, - { - nullptr, - WGPUCallbackMode_AllowSpontaneous, - AsyncPipelineBuilder::CreateRenderPipelineCallback2, - AsyncBuilder, - nullptr, - }); -#endif + wgpuDeviceCreateRenderPipelineAsync(m_pDevice->GetWebGPUDevice(), &wgpuRenderPipelineDesc, + { + nullptr, + WGPUCallbackMode_AllowSpontaneous, + AsyncPipelineBuilder::CreateRenderPipelineCallback, + AsyncBuilder, + nullptr, + }); } else { @@ -619,18 +590,15 @@ void PipelineStateWebGPUImpl::InitializeWebGPUComputePipeline(const TShaderStage { // The reference will be released from the callback. AsyncBuilder->AddRef(); -#if PLATFORM_WEB - wgpuDeviceCreateComputePipelineAsync(m_pDevice->GetWebGPUDevice(), &wgpuComputePipelineDesc, AsyncPipelineBuilder::CreateComputePipelineCallback, AsyncBuilder); -#else - wgpuDeviceCreateComputePipelineAsync2(m_pDevice->GetWebGPUDevice(), &wgpuComputePipelineDesc, - { - nullptr, - WGPUCallbackMode_AllowSpontaneous, - AsyncPipelineBuilder::CreateComputePipelineCallback2, - AsyncBuilder, - nullptr, - }); -#endif + + wgpuDeviceCreateComputePipelineAsync(m_pDevice->GetWebGPUDevice(), &wgpuComputePipelineDesc, + { + nullptr, + WGPUCallbackMode_AllowSpontaneous, + AsyncPipelineBuilder::CreateComputePipelineCallback, + AsyncBuilder, + nullptr, + }); } else { diff --git a/Graphics/GraphicsEngineWebGPU/src/RenderDeviceWebGPUImpl.cpp b/Graphics/GraphicsEngineWebGPU/src/RenderDeviceWebGPUImpl.cpp index 5500d7db3b..4d882707e0 100644 --- a/Graphics/GraphicsEngineWebGPU/src/RenderDeviceWebGPUImpl.cpp +++ b/Graphics/GraphicsEngineWebGPU/src/RenderDeviceWebGPUImpl.cpp @@ -67,14 +67,6 @@ class ShaderBindingTableWebGPUImpl class DeviceMemoryWebGPUImpl {}; -#if PLATFORM_WEB -static void DebugMessengerCallback(WGPUErrorType MessageType, const char* Message, void* pUserData) -{ - if (Message != nullptr) - LOG_DEBUG_MESSAGE(DEBUG_MESSAGE_SEVERITY_ERROR, "WebGPU: ", Message); -} -#endif - RenderDeviceWebGPUImpl::RenderDeviceWebGPUImpl(IReferenceCounters* pRefCounters, const CreateInfo& CI) : @@ -92,13 +84,8 @@ RenderDeviceWebGPUImpl::RenderDeviceWebGPUImpl(IReferenceCounters* pRefCounters, m_wgpuDevice{CI.wgpuDevice} // clang-format on { - WGPUSupportedLimits wgpuSupportedLimits{}; - wgpuDeviceGetLimits(m_wgpuDevice, &wgpuSupportedLimits); - m_wgpuLimits = wgpuSupportedLimits.limits; -#if PLATFORM_WEB - wgpuDeviceSetUncapturedErrorCallback(m_wgpuDevice, DebugMessengerCallback, nullptr); -#endif + wgpuDeviceGetLimits(m_wgpuDevice, &m_wgpuLimits); FindSupportedTextureFormats(); m_DeviceInfo.Type = RENDER_DEVICE_TYPE_WEBGPU; @@ -384,9 +371,12 @@ void RenderDeviceWebGPUImpl::FindSupportedTextureFormats() constexpr BIND_FLAGS BIND_SRU = BIND_SHADER_RESOURCE | BIND_RENDER_TARGET | BIND_UNORDERED_ACCESS; constexpr BIND_FLAGS BIND_SR = BIND_SHADER_RESOURCE | BIND_RENDER_TARGET; - constexpr BIND_FLAGS BIND_S = BIND_SHADER_RESOURCE; constexpr BIND_FLAGS BIND_SU = BIND_SHADER_RESOURCE | BIND_UNORDERED_ACCESS; + constexpr BIND_FLAGS BIND_S = BIND_SHADER_RESOURCE; + constexpr BIND_FLAGS BIND_R = BIND_RENDER_TARGET; constexpr BIND_FLAGS BIND_D = BIND_DEPTH_STENCIL; + constexpr BIND_FLAGS BIND_U = BIND_UNORDERED_ACCESS; + SAMPLE_COUNT SupportedSampleCounts = SAMPLE_COUNT_1 | SAMPLE_COUNT_4; // We can't query supported sample counts in WebGPU @@ -429,14 +419,24 @@ void RenderDeviceWebGPUImpl::FindSupportedTextureFormats() } }; + auto UpdateTexFormatInfo = [&](std::initializer_list Formats, BIND_FLAGS BindFlags, Uint32 FmtFlags) { + for (TEXTURE_FORMAT Fmt : Formats) + { + TextureFormatInfoExt& FmtInfo = m_TextureFormatsInfo[Fmt]; + VERIFY(FmtInfo.Supported, "The format hasn't been initialized"); + FmtInfo.BindFlags |= BindFlags; + FmtInfo.SampleCounts |= (FmtFlags & FMT_FLAG_MSAA) != 0 ? SupportedSampleCounts : SAMPLE_COUNT_1; + FmtInfo.Filterable |= (FmtFlags & FMT_FLAG_FILTER) != 0; + } + }; + const bool BGRA8UnormStorageSupported = wgpuDeviceHasFeature(m_wgpuDevice, WGPUFeatureName_BGRA8UnormStorage); const bool Float32FilterableSupported = wgpuDeviceHasFeature(m_wgpuDevice, WGPUFeatureName_Float32Filterable); const bool RG11B10UfloatRenderableSupported = wgpuDeviceHasFeature(m_wgpuDevice, WGPUFeatureName_RG11B10UfloatRenderable); const bool Depth32FloatStencil8Supported = wgpuDeviceHasFeature(m_wgpuDevice, WGPUFeatureName_Depth32FloatStencil8); const bool TextureCompressionBCSupported = wgpuDeviceHasFeature(m_wgpuDevice, WGPUFeatureName_TextureCompressionBC); const bool TextureCompressionETC2Supported = wgpuDeviceHasFeature(m_wgpuDevice, WGPUFeatureName_TextureCompressionETC2); - const bool R16UnormSupported = wgpuDeviceHasFeature(m_wgpuDevice, WGPUFeatureName_Unorm16TextureFormats); - const bool R16SnormSupported = wgpuDeviceHasFeature(m_wgpuDevice, WGPUFeatureName_Snorm16TextureFormats); + const bool TextureTier1Supported = wgpuDeviceHasFeature(m_wgpuDevice, WGPUFeatureName_TextureFormatsTier1); // https://www.w3.org/TR/webgpu/#texture-format-caps @@ -519,18 +519,40 @@ void RenderDeviceWebGPUImpl::FindSupportedTextureFormats() BIND_S, FMT_FLAG_FILTER); } - if (R16UnormSupported) - { - SetTexFormatInfo({TEX_FORMAT_R16_UNORM}, BIND_SR, FMT_FLAG_FILTER | FMT_FLAG_MSAA); - SetTexFormatInfo({TEX_FORMAT_RG16_UNORM}, BIND_SR, FMT_FLAG_FILTER | FMT_FLAG_MSAA); - SetTexFormatInfo({TEX_FORMAT_RGBA16_UNORM}, BIND_SR, FMT_FLAG_FILTER | FMT_FLAG_MSAA); - } - - if (R16SnormSupported) + if (TextureTier1Supported) { - SetTexFormatInfo({TEX_FORMAT_R16_SNORM}, BIND_SR, FMT_FLAG_FILTER | FMT_FLAG_MSAA); - SetTexFormatInfo({TEX_FORMAT_RG16_SNORM}, BIND_SR, FMT_FLAG_FILTER | FMT_FLAG_MSAA); - SetTexFormatInfo({TEX_FORMAT_RGBA16_SNORM}, BIND_SR, FMT_FLAG_FILTER | FMT_FLAG_MSAA); + // https://www.w3.org/TR/webgpu/#texture-formats-tier1 + SetTexFormatInfo({TEX_FORMAT_R16_UNORM, + TEX_FORMAT_R16_SNORM, + TEX_FORMAT_RG16_UNORM, + TEX_FORMAT_RG16_SNORM, + TEX_FORMAT_RGBA16_UNORM, + TEX_FORMAT_RGBA16_SNORM}, + BIND_SRU, FMT_FLAG_FILTER | FMT_FLAG_MSAA); + + UpdateTexFormatInfo({TEX_FORMAT_R8_SNORM, + TEX_FORMAT_RG8_SNORM, + TEX_FORMAT_RGBA8_SNORM}, + BIND_R, FMT_FLAG_MSAA); + + UpdateTexFormatInfo({TEX_FORMAT_R8_UNORM, + TEX_FORMAT_R8_SNORM, + TEX_FORMAT_R8_UINT, + TEX_FORMAT_R8_SINT, + TEX_FORMAT_RG8_UNORM, + TEX_FORMAT_RG8_SNORM, + TEX_FORMAT_RG8_UINT, + TEX_FORMAT_RG8_SINT, + TEX_FORMAT_R16_UINT, + TEX_FORMAT_R16_SINT, + TEX_FORMAT_R16_FLOAT, + TEX_FORMAT_RG16_UINT, + TEX_FORMAT_RG16_SINT, + TEX_FORMAT_RG16_FLOAT, + TEX_FORMAT_RGB10A2_UNORM, + TEX_FORMAT_RGB10A2_UINT, + TEX_FORMAT_R11G11B10_FLOAT}, + BIND_U, 0); } if (TextureCompressionETC2Supported) diff --git a/Graphics/GraphicsEngineWebGPU/src/ShaderWebGPUImpl.cpp b/Graphics/GraphicsEngineWebGPU/src/ShaderWebGPUImpl.cpp index ba431061eb..49b4d8c66e 100644 --- a/Graphics/GraphicsEngineWebGPU/src/ShaderWebGPUImpl.cpp +++ b/Graphics/GraphicsEngineWebGPU/src/ShaderWebGPUImpl.cpp @@ -92,12 +92,12 @@ std::vector CompileShaderToSPIRV(const ShaderCreateInfo& S const std::string HLSLSource = BuildHLSLSourceString(ShaderCI); if (!HLSLSource.empty()) { - // Extract image formats from special comments in HLSL code: - // Texture2D g_RWTexture; - const auto ImageFormats = Parsing::ExtractGLSLImageFormatsFromHLSL(HLSLSource); + // Extract image formats and access modes from special comments in HLSL code: + // Texture2D g_RWTexture; + const auto ImageFormats = Parsing::ExtractGLSLImageFormatsAndAccessModeFromHLSL(HLSLSource); if (!ImageFormats.empty()) { - SPIRV = PatchImageFormats(SPIRV, ImageFormats); + SPIRV = PatchImageFormatsAndAccessModes(SPIRV, ImageFormats); } } } @@ -203,6 +203,7 @@ void ShaderWebGPUImpl::Initialize(const ShaderCreateInfo& ShaderCI, LOG_ERROR_AND_THROW("Shader source must be provided through one of the 'Source', 'FilePath' or 'ByteCode' members"); } + StripGoogleHlslFunctionality(SPIRV); m_WGSL = ConvertSPIRVtoWGSL(SPIRV); if (m_WGSL.empty()) { diff --git a/Graphics/GraphicsEngineWebGPU/src/SwapChainWebGPUImpl.cpp b/Graphics/GraphicsEngineWebGPU/src/SwapChainWebGPUImpl.cpp index 90a7d74fca..1f61484416 100644 --- a/Graphics/GraphicsEngineWebGPU/src/SwapChainWebGPUImpl.cpp +++ b/Graphics/GraphicsEngineWebGPU/src/SwapChainWebGPUImpl.cpp @@ -229,10 +229,9 @@ class SwapChainWebGPUImpl::PresentCommand switch (wgpuSurfaceTexture.status) { - case WGPUSurfaceGetCurrentTextureStatus_Success: + case WGPUSurfaceGetCurrentTextureStatus_SuccessOptimal: + case WGPUSurfaceGetCurrentTextureStatus_SuccessSuboptimal: case WGPUSurfaceGetCurrentTextureStatus_Outdated: - break; - case WGPUSurfaceGetCurrentTextureStatus_Timeout: break; @@ -240,14 +239,6 @@ class SwapChainWebGPUImpl::PresentCommand LOG_WARNING_MESSAGE("Unable to present: swap chain surface is lost"); return wgpuSurfaceTexture.status; - case WGPUSurfaceGetCurrentTextureStatus_OutOfMemory: - LOG_ERROR_MESSAGE("Unable to present: out of memory"); - return wgpuSurfaceTexture.status; - - case WGPUSurfaceGetCurrentTextureStatus_DeviceLost: - LOG_ERROR_MESSAGE("Unable to present: device is lost"); - return wgpuSurfaceTexture.status; - case WGPUSurfaceGetCurrentTextureStatus_Error: LOG_ERROR_MESSAGE("Unable to present: unknown error"); return wgpuSurfaceTexture.status; @@ -455,7 +446,7 @@ void SwapChainWebGPUImpl::CreateSurface() #elif PLATFORM_WEB WGPUSurfaceSourceCanvasHTMLSelector_Emscripten wgpuSurfaceNativeDesc{}; wgpuSurfaceNativeDesc.chain = {nullptr, WGPUSType_SurfaceSourceCanvasHTMLSelector_Emscripten}; - wgpuSurfaceNativeDesc.selector = m_NativeWindow.pCanvasId; + wgpuSurfaceNativeDesc.selector = GetWGPUStringView(m_NativeWindow.pCanvasId); #endif WGPUSurfaceDescriptor wgpuSurfaceDesc{}; diff --git a/Graphics/GraphicsEngineWebGPU/src/TextureWebGPUImpl.cpp b/Graphics/GraphicsEngineWebGPU/src/TextureWebGPUImpl.cpp index 3162d2d9c3..716b76d172 100644 --- a/Graphics/GraphicsEngineWebGPU/src/TextureWebGPUImpl.cpp +++ b/Graphics/GraphicsEngineWebGPU/src/TextureWebGPUImpl.cpp @@ -138,7 +138,6 @@ WGPUTextureDescriptor TextureDescToWGPUTextureDescriptor(const TextureDesc& return wgpuTextureDesc; } -#if !PLATFORM_EMSCRIPTEN static WGPUTextureUsage TextureViewTypeToWGPUTextureUsage(TEXTURE_VIEW_TYPE ViewType) { static_assert(TEXTURE_VIEW_NUM_VIEWS == 7, "Please update the switch below to handle the new view type"); @@ -166,7 +165,6 @@ static WGPUTextureUsage TextureViewTypeToWGPUTextureUsage(TEXTURE_VIEW_TYPE View return WGPUTextureUsage_None; } } -#endif WGPUTextureViewDescriptor TextureViewDescToWGPUTextureViewDescriptor(const TextureDesc& TexDesc, TextureViewDesc& ViewDesc, @@ -229,14 +227,10 @@ WGPUTextureViewDescriptor TextureViewDescToWGPUTextureViewDescriptor(const Textu wgpuTextureViewDesc.aspect = WGPUTextureAspect_All; } - // TODO: enable this as soon as Emscripten adds the usage member to WGPUTextureViewDescriptor - // https://github.com/emscripten-core/emscripten/issues/23945 -#if !PLATFORM_EMSCRIPTEN - if (ViewDesc.Format != TexDesc.Format) + if (ViewDesc.Format != TexDesc.Format || (TexDesc.MiscFlags & TEXTURE_VIEW_FLAG_ALLOW_MIP_MAP_GENERATION)) { wgpuTextureViewDesc.usage = TextureViewTypeToWGPUTextureUsage(ViewDesc.ViewType); } -#endif return wgpuTextureViewDesc; } @@ -385,13 +379,14 @@ TextureWebGPUImpl::TextureWebGPUImpl(IReferenceCounters* pRefCounters, DstDepthStride // DstDepthStride ); - WGPUImageCopyBuffer wgpuSourceCopyInfo{}; + + WGPUTexelCopyBufferInfo wgpuSourceCopyInfo{}; wgpuSourceCopyInfo.layout.offset = DstSubResOffset; wgpuSourceCopyInfo.layout.bytesPerRow = static_cast(DstRawStride); wgpuSourceCopyInfo.layout.rowsPerImage = static_cast(DstDepthStride / DstRawStride); wgpuSourceCopyInfo.buffer = wgpuUploadBuffer.Get(); - WGPUImageCopyTexture wgpuDestinationCopyInfo{}; + WGPUTexelCopyTextureInfo wgpuDestinationCopyInfo{}; wgpuDestinationCopyInfo.texture = m_wgpuTexture.Get(); wgpuDestinationCopyInfo.mipLevel = MipIdx; wgpuDestinationCopyInfo.origin = {0, 0, LayerIdx}; diff --git a/Graphics/GraphicsEngineWebGPU/src/WebGPUResourceBase.cpp b/Graphics/GraphicsEngineWebGPU/src/WebGPUResourceBase.cpp index 588d660410..f6a7aa2e3b 100644 --- a/Graphics/GraphicsEngineWebGPU/src/WebGPUResourceBase.cpp +++ b/Graphics/GraphicsEngineWebGPU/src/WebGPUResourceBase.cpp @@ -183,11 +183,11 @@ void WebGPUResourceBase::FlushPendingWrites(StagingBufferInfo& Buffer) void WebGPUResourceBase::ProcessAsyncReadback(StagingBufferInfo& Buffer) { - auto MapAsyncCallback = [](WGPUBufferMapAsyncStatus MapStatus, void* pUserData) { - VERIFY_EXPR(pUserData != nullptr); - StagingBufferInfo& BufferInfo = *static_cast(pUserData); + auto MapAsyncCallback = [](WGPUMapAsyncStatus wgpuMapStatus, WGPUStringView Message, void* pUserData1, void* pUserData2) { + VERIFY_EXPR(pUserData1 != nullptr); + StagingBufferInfo& BufferInfo = *static_cast(pUserData1); - if (MapStatus == WGPUBufferMapAsyncStatus_Success) + if (wgpuMapStatus == WGPUMapAsyncStatus_Success) { // Do NOT use WGPU_WHOLE_MAP_SIZE due to https://github.com/emscripten-core/emscripten/issues/20538 const size_t MappedDataSize = BufferInfo.Resource.m_MappedData.size(); @@ -201,6 +201,10 @@ void WebGPUResourceBase::ProcessAsyncReadback(StagingBufferInfo& Buffer) } wgpuBufferUnmap(BufferInfo.wgpuBuffer.Get()); } + else + { + LOG_DEBUG_MESSAGE(DEBUG_MESSAGE_SEVERITY_ERROR, "WebGPU: ", WGPUStringViewToString(Message)); + } BufferInfo.pSyncPoint->Trigger(); @@ -211,8 +215,12 @@ void WebGPUResourceBase::ProcessAsyncReadback(StagingBufferInfo& Buffer) // Keep the resource alive until the callback is called m_Owner.AddRef(); // Do NOT use WGPU_WHOLE_MAP_SIZE due to https://github.com/emscripten-core/emscripten/issues/20538 - const size_t MappedDataSize = Buffer.Resource.m_MappedData.size(); - wgpuBufferMapAsync(Buffer.wgpuBuffer, WGPUMapMode_Read, 0, AlignUp(MappedDataSize, MappedRangeAlignment), MapAsyncCallback, &Buffer); + const size_t MappedDataSize = Buffer.Resource.m_MappedData.size(); + WGPUBufferMapCallbackInfo wgpuBufferMapCallbackInfo{}; + wgpuBufferMapCallbackInfo.callback = MapAsyncCallback; + wgpuBufferMapCallbackInfo.userdata1 = &Buffer; + wgpuBufferMapCallbackInfo.mode = WGPUCallbackMode_AllowSpontaneous; + wgpuBufferMapAsync(Buffer.wgpuBuffer, WGPUMapMode_Read, 0, AlignUp(MappedDataSize, MappedRangeAlignment), wgpuBufferMapCallbackInfo); } } // namespace Diligent diff --git a/Graphics/GraphicsEngineWebGPU/src/WebGPUTypeConversions.cpp b/Graphics/GraphicsEngineWebGPU/src/WebGPUTypeConversions.cpp index ffbff1b0bc..331a733a17 100644 --- a/Graphics/GraphicsEngineWebGPU/src/WebGPUTypeConversions.cpp +++ b/Graphics/GraphicsEngineWebGPU/src/WebGPUTypeConversions.cpp @@ -31,7 +31,7 @@ #include "DebugUtilities.hpp" #include "GraphicsAccessories.hpp" -#define WEBGPU_FORMAT_RANGE_SIZE (WGPUTextureFormat_RGBA16Snorm - WGPUTextureFormat_Undefined + 1) +#define WEBGPU_FORMAT_RANGE_SIZE (WGPUTextureFormat_ASTC12x12UnormSrgb - WGPUTextureFormat_Undefined + 1) namespace Diligent { diff --git a/Graphics/ShaderTools/CMakeLists.txt b/Graphics/ShaderTools/CMakeLists.txt index 2c988c0916..b6d512cf30 100644 --- a/Graphics/ShaderTools/CMakeLists.txt +++ b/Graphics/ShaderTools/CMakeLists.txt @@ -196,9 +196,7 @@ if(ENABLE_WGSL) target_link_libraries(Diligent-ShaderTools PRIVATE libtint - # We include this library because when building for Emscripten, libtint does not include this library in the dependency list - tint_lang_wgsl_inspector - ) + ) endif() set(HLSL_DEFINITIONS include/HLSLDefinitions.fxh) @@ -227,7 +225,11 @@ add_custom_command(OUTPUT ${HLSL_DEFINITIONS_INC} # We must use full path here! VERBATIM ) -set_common_target_properties(Diligent-ShaderTools 17) +if(ENABLE_WGSL) + set_common_target_properties(Diligent-ShaderTools 20) +else() + set_common_target_properties(Diligent-ShaderTools 17) +endif() source_group("src" FILES ${SOURCE}) source_group("include" FILES ${INCLUDE}) diff --git a/Graphics/ShaderTools/include/GLSLParsingTools.hpp b/Graphics/ShaderTools/include/GLSLParsingTools.hpp index 6ba4f85360..e63678c8e8 100644 --- a/Graphics/ShaderTools/include/GLSLParsingTools.hpp +++ b/Graphics/ShaderTools/include/GLSLParsingTools.hpp @@ -28,6 +28,7 @@ #include "ParsingTools.hpp" #include "GraphicsTypes.h" +#include "SPIRVUtils.hpp" namespace Diligent { @@ -111,6 +112,69 @@ std::string ExtractGLSLImageFormatFromComment(const InteratorType& Start, const /// \return Texture format, or TEXTURE_FORMAT_UNKNOWN if the format is not recognized. TEXTURE_FORMAT ParseGLSLImageFormat(const std::string& Format); + +/// Extracts GLSL access mode from the comment, e.g.: +/// /* access = read_write */ +/// ^ ^ +/// Start End +/// The function returns "read_write" +/// If the comment does not contain access mode specifier, the function returns an empty string. +/// /// \param[in] Start - iterator to the beginning of the comment +/// /// \param[in] End - iterator to the end of the comment +/// /// \return GLSL access mode +template +std::string ExtractGLSLAccessModeFromComment(const IteratorType& Start, const IteratorType& End) +{ + // /* access = read_write */ + // ^ + auto Pos = SkipDelimiters(Start, End); + if (Pos == End) + return {}; + // /* access = read_write */ + // ^ + if (*Pos != '/') + return {}; + ++Pos; + // /* access = read_write */ + // ^ + // // access = read_write + // ^ + if (Pos == End || (*Pos != '/' && *Pos != '*')) + return {}; + ++Pos; + // /* access = read_write */ + // ^ + Pos = SkipDelimiters(Pos, End); + if (Pos == End) + return {}; + // /* access = read_write */ + // ^ + if (!SkipString(Pos, End, "access", Pos)) + return {}; + // /* access = read_write */ + // ^ + Pos = SkipDelimiters(Pos, End); + if (Pos == End) + return {}; + // /* access = read_write */ + // ^ + if (*Pos != '=') + return {}; + ++Pos; + // /* access = read_write */ + // ^ + Pos = SkipDelimiters(Pos, End); + if (Pos == End) + return {}; + // /* access = read_write */ + // ^ + auto AccessModeEndPos = SkipIdentifier(Pos, End); + return {Pos, AccessModeEndPos}; +} + + +IMAGE_ACCESS_MODE ParseGLSLImageAccessMode(const std::string& AccessModeStr); + } // namespace Parsing } // namespace Diligent diff --git a/Graphics/ShaderTools/include/HLSLParsingTools.hpp b/Graphics/ShaderTools/include/HLSLParsingTools.hpp index c3d51c504c..0a0ba939a9 100644 --- a/Graphics/ShaderTools/include/HLSLParsingTools.hpp +++ b/Graphics/ShaderTools/include/HLSLParsingTools.hpp @@ -31,6 +31,7 @@ #include "ParsingTools.hpp" #include "GraphicsTypes.h" #include "HashUtils.hpp" +#include "SPIRVUtils.hpp" namespace Diligent { @@ -38,21 +39,36 @@ namespace Diligent namespace Parsing { -/// Parses HLSL source code and extracts image formats from RWTexture comments, for example: +/// Parses HLSL source code and extracts image formats and access modes +/// from RWTexture comments. Annotations are expected inside the RWTexture +/// template argument list, for example: +/// /// HLSL: -/// RWTexture2D g_Tex2D; -/// RWTexture3D g_Tex3D; +/// RWTexture2D g_Tex2D; +/// RWTexture3D g_Tex3D; +/// RWTexture2D g_Tex2D_Read; +/// /// Output: /// { -/// {"g_Tex2D", TEX_FORMAT_RGBA8_UNORM}, -/// {"g_Tex3D", TEX_FORMAT_RG16_FLOAT} -/// } +/// { "g_Tex2D", { TEX_FORMAT_RGBA8_UNORM, IMAGE_ACCESS_MODE_READ_WRITE } }, +/// { "g_Tex3D", { TEX_FORMAT_RG16_FLOAT, IMAGE_ACCESS_MODE_WRITE } }, +/// { "g_Tex2D_Read", { TEX_FORMAT_RGBA8_UNORM, IMAGE_ACCESS_MODE_READ } } +/// } +/// +/// The following comment patterns are recognized: +/// /*format=*/ +/// /*access=read*/ +/// /*access=write*/ +/// /*access=read_write*/ +/// +/// If no access comment is present, the access mode defaults to IMAGE_ACCESS_MODE_UNKNOWN. /// /// \param[in] HLSLSource - HLSL source code. -/// \return A map containing image formats extracted from RWTexture comments. +/// \return A map that associates RWTexture variable names with the image format +/// and access mode extracted from their comments. /// -/// \remarks Only texture declarations in global scope are processed. -std::unordered_map ExtractGLSLImageFormatsFromHLSL(const std::string& HLSLSource); +/// \remarks Only RWTexture declarations in global scope are processed. +std::unordered_map ExtractGLSLImageFormatsAndAccessModeFromHLSL(const std::string& HLSLSource); } // namespace Parsing diff --git a/Graphics/ShaderTools/include/SPIRVUtils.hpp b/Graphics/ShaderTools/include/SPIRVUtils.hpp index 8d9a2af3e6..7d7602d276 100644 --- a/Graphics/ShaderTools/include/SPIRVUtils.hpp +++ b/Graphics/ShaderTools/include/SPIRVUtils.hpp @@ -35,13 +35,45 @@ namespace Diligent { +/// Defines image access modes in HLSL. +enum IMAGE_ACCESS_MODE +{ + IMAGE_ACCESS_MODE_UNKNOWN, + IMAGE_ACCESS_MODE_READ, + IMAGE_ACCESS_MODE_WRITE, + IMAGE_ACCESS_MODE_READ_WRITE +}; + +/// Stores the image format and access mode for an RWTexture declared in HLSL. +struct ImageFormatAndAccess +{ + TEXTURE_FORMAT Format = TEX_FORMAT_UNKNOWN; + IMAGE_ACCESS_MODE AccessMode = IMAGE_ACCESS_MODE_UNKNOWN; + + ImageFormatAndAccess() noexcept = default; + + constexpr ImageFormatAndAccess(TEXTURE_FORMAT _Format, + IMAGE_ACCESS_MODE _AccessMode = IMAGE_ACCESS_MODE_UNKNOWN) noexcept : + Format{_Format}, AccessMode{_AccessMode} {} + + bool operator==(const ImageFormatAndAccess& rhs) const + { + return Format == rhs.Format && AccessMode == rhs.AccessMode; + } + + bool operator!=(const ImageFormatAndAccess& rhs) const + { + return !(*this == rhs); + } +}; + /// Patches image format declarations in the SPIRV code using the provided mapping. /// /// \param [in] SPIRV - SPIRV code. /// \param [in] ImageFormats - Mapping from image format names to texture formats. /// /// \return Patched SPIRV code. -std::vector PatchImageFormats(const std::vector& SPIRV, - const std::unordered_map& ImageFormats); +std::vector PatchImageFormatsAndAccessModes(const std::vector& SPIRV, + const std::unordered_map& ImageInfos); } // namespace Diligent diff --git a/Graphics/ShaderTools/include/WGSLUtils.hpp b/Graphics/ShaderTools/include/WGSLUtils.hpp index e4304a2a12..43f9ea1c70 100644 --- a/Graphics/ShaderTools/include/WGSLUtils.hpp +++ b/Graphics/ShaderTools/include/WGSLUtils.hpp @@ -56,6 +56,9 @@ std::string RemapWGSLResourceBindings(const std::string& WGSL, const WGSLResourceMapping& ResMapping, const char* EmulatedArrayIndexSuffix); +/// New version of Tint can't translate SPIR-V to WGSL with certain HLSL-specific functionality, +void StripGoogleHlslFunctionality(std::vector& SPIRV); + /// When WGSL is generated from SPIR-V, the names of resources may be mangled /// diff --git a/Graphics/ShaderTools/src/GLSLParsingTools.cpp b/Graphics/ShaderTools/src/GLSLParsingTools.cpp index c23dd0bb7e..6d4ec389df 100644 --- a/Graphics/ShaderTools/src/GLSLParsingTools.cpp +++ b/Graphics/ShaderTools/src/GLSLParsingTools.cpp @@ -236,6 +236,18 @@ TEXTURE_FORMAT ParseGLSLImageFormat(const std::string& Format) return TEX_FORMAT_UNKNOWN; } +IMAGE_ACCESS_MODE ParseGLSLImageAccessMode(const std::string& AccessMode) +{ + if (AccessMode == "read") + return IMAGE_ACCESS_MODE_READ; + else if (AccessMode == "write") + return IMAGE_ACCESS_MODE_WRITE; + else if (AccessMode == "read_write") + return IMAGE_ACCESS_MODE_READ_WRITE; + else + return IMAGE_ACCESS_MODE_UNKNOWN; +} + } // namespace Parsing } // namespace Diligent diff --git a/Graphics/ShaderTools/src/HLSLParsingTools.cpp b/Graphics/ShaderTools/src/HLSLParsingTools.cpp index f31da3c871..3518c53849 100644 --- a/Graphics/ShaderTools/src/HLSLParsingTools.cpp +++ b/Graphics/ShaderTools/src/HLSLParsingTools.cpp @@ -34,40 +34,79 @@ namespace Diligent namespace Parsing { -static std::pair ParseRWTextureDefinition(HLSLTokenizer::TokenListType::const_iterator& Token, - HLSLTokenizer::TokenListType::const_iterator End) + +static void ExtractAnnotationsFromDelimiter(const std::string& Delim, ImageFormatAndAccess& Info) +{ + size_t Pos = 0; + while (Pos < Delim.size()) + { + size_t Begin = Delim.find("/*", Pos); + if (Begin == std::string::npos) + break; + + size_t End = Delim.find("*/", Begin + 2); + if (End == std::string::npos) + break; + + auto CmtBeg = Delim.begin() + Begin; + auto CmtEnd = Delim.begin() + End + 2; + + + // Try to extract image format from a comment like: + // /*format=rg8*/ + if (Info.Format == TEX_FORMAT_UNKNOWN) + { + std::string Format = ExtractGLSLImageFormatFromComment(CmtBeg, CmtEnd); + if (!Format.empty()) + Info.Format = ParseGLSLImageFormat(Format); + } + + + // Try to extract access mode from a comment like: + // /*access=read*/ + // /*access=write*/ + // /*access=read_write*/ + std::string Access = ExtractGLSLAccessModeFromComment(CmtBeg, CmtEnd); + if (!Access.empty()) + Info.AccessMode = ParseGLSLImageAccessMode(Access); + + Pos = End + 2; + } +} + +static std::pair ParseRWTextureDefinition( + HLSLTokenizer::TokenListType::const_iterator& Token, + HLSLTokenizer::TokenListType::const_iterator End) { - // RWTexture2D g_RWTex; - // ^ + // RWTexture2D g_RWTex; + // ^ - RWTexture* keyword ++Token; - // RWTexture2D g_RWTex; - // ^ + // RWTexture2D g_RWTex; + // ^ - '<' after RWTexture* if (Token == End || Token->Literal != "<") return {}; - TEXTURE_FORMAT Fmt = TEX_FORMAT_UNKNOWN; + ImageFormatAndAccess Info; /// Format = UNKNOWN, AccessMode = UNKNOWN by default + + // Walk through all tokens inside the '<' ... '>' list and look for + // comments that annotate format and access mode. while (Token != End && Token->Literal != ">") { ++Token; if (Token != End) { - // RWTexture2D< /*format=rg8*/ unorm float4> g_RWTex; - // ^ - // RWTexture2D< unorm /*format=rg8*/ float4> g_RWTex; - // ^ - // RWTexture2D< unorm float4 /*format=rg8*/> g_RWTex; - // ^ - std::string FormatStr = ExtractGLSLImageFormatFromComment(Token->Delimiter.begin(), Token->Delimiter.end()); - if (!FormatStr.empty()) + /// Any comments preceding the current token are stored in Delimiter. + if (!Token->Delimiter.empty()) { - Fmt = ParseGLSLImageFormat(FormatStr); + ExtractAnnotationsFromDelimiter(Token->Delimiter, Info); } } } - // RWTexture2D g_RWTex; - // ^ + // RWTexture2D g_RWTex; + // ^ - '>' reached + if (Token == End) return {}; @@ -75,20 +114,21 @@ static std::pair ParseRWTextureDefinition(HLSLToken if (Token == End) return {}; - // RWTexture2D g_RWTex; - // ^ + // RWTexture2D g_RWTex; + // ^ - texture variable identifier if (Token->Type != HLSLTokenType::Identifier) return {}; - return {Token->Literal, Fmt}; + return {Token->Literal, Info}; } -std::unordered_map ExtractGLSLImageFormatsFromHLSL(const std::string& HLSLSource) + +std::unordered_map ExtractGLSLImageFormatsAndAccessModeFromHLSL(const std::string& HLSLSource) { HLSLTokenizer Tokenizer; const HLSLTokenizer::TokenListType Tokens = Tokenizer.Tokenize(HLSLSource); - std::unordered_map ImageFormats; + std::unordered_map ImageFormats; auto Token = Tokens.begin(); int ScopeLevel = 0; @@ -119,13 +159,29 @@ std::unordered_map ExtractGLSLImageFormatsFrom Token->Type == HLSLTokenType::kw_RWTexture2DArray || Token->Type == HLSLTokenType::kw_RWTexture3D)) { - auto NameAndFmt = ParseRWTextureDefinition(Token, Tokens.end()); - if (NameAndFmt.second != TEX_FORMAT_UNKNOWN) + auto NameAndInfo = ParseRWTextureDefinition(Token, Tokens.end()); + const auto& Name = NameAndInfo.first; + const auto& Info = NameAndInfo.second; + + const bool HasFormat = (Info.Format != TEX_FORMAT_UNKNOWN); + const bool HasNonDefaultAccess = (Info.AccessMode != IMAGE_ACCESS_MODE_UNKNOWN); + + if (HasFormat || HasNonDefaultAccess) { - auto it_inserted = ImageFormats.emplace(NameAndFmt); - if (!it_inserted.second && it_inserted.first->second != NameAndFmt.second) + auto InsertedIt = ImageFormats.emplace(Name, Info); + if (!InsertedIt.second) { - LOG_WARNING_MESSAGE("Different formats are specified for the same RWTexture '", NameAndFmt.first, "'. Note that the parser does not support preprocessing."); + const auto& Existing = InsertedIt.first->second; + + if (Existing.Format != Info.Format) + { + LOG_WARNING_MESSAGE("Different formats are specified for the same RWTexture '", Name, "'. Note that the parser does not support preprocessing."); + } + + if (Existing.AccessMode != Info.AccessMode) + { + LOG_WARNING_MESSAGE("Different access modes are specified for the same RWTexture '", Name, "'. Note that the parser does not support preprocessing."); + } } } } diff --git a/Graphics/ShaderTools/src/SPIRVUtils.cpp b/Graphics/ShaderTools/src/SPIRVUtils.cpp index 587a66422a..a66e4176dd 100644 --- a/Graphics/ShaderTools/src/SPIRVUtils.cpp +++ b/Graphics/ShaderTools/src/SPIRVUtils.cpp @@ -26,6 +26,7 @@ #include "SPIRVUtils.hpp" #include "SPIRVShaderResources.hpp" // required for diligent_spirv_cross +#include "HLSLParsingTools.hpp" #include "spirv_cross.hpp" @@ -95,63 +96,138 @@ static spv::ImageFormat TextureFormatToSpvImageFormat(TEXTURE_FORMAT Format) } } -std::vector PatchImageFormats(const std::vector& SPIRV, - const std::unordered_map& ImageFormats) -{ - diligent_spirv_cross::Compiler Compiler{SPIRV}; +std::vector PatchImageFormatsAndAccessModes(const std::vector& SPIRV, const std::unordered_map& ImageInfos) +{ + diligent_spirv_cross::Compiler Compiler{SPIRV}; diligent_spirv_cross::ShaderResources resources = Compiler.get_shader_resources(); std::unordered_map ImageTypeIdToFormat; - for (uint32_t i = 0; i < SPIRV.size(); ++i) + ImageTypeIdToFormat.reserve(resources.storage_images.size()); + + uint32_t FirstFunctionWordIndex = 0; + uint32_t LastDecorateEnd = 0; + + constexpr size_t SpirvHeaderSize = 5; + uint32_t InstructionPointer = static_cast(SpirvHeaderSize); + while (InstructionPointer < SPIRV.size()) { // OpTypeImage // 0 1 2 3 4 5 6 7 8 9 // | OpCode | Result | Sampled Type | Dim | Depth | Arrayed | MS | Sampled | Image Format | Access Qualifier constexpr uint32_t ImageFormatOffset = 8; - uint32_t OpCode = SPIRV[i] & 0xFFFF; - if (OpCode == spv::OpTypeImage && i + ImageFormatOffset < SPIRV.size()) + const uint32_t Instruction = SPIRV[InstructionPointer]; + const uint16_t WordCount = static_cast(Instruction >> 16); + const uint16_t OpCode = static_cast(Instruction & 0xFFFFu); + + if (WordCount == 0 || InstructionPointer + WordCount > SPIRV.size()) + break; + + if (OpCode == spv::OpTypeImage) + { + const uint32_t ImageTypeId = SPIRV[InstructionPointer + 1]; + if (WordCount > ImageFormatOffset) + ImageTypeIdToFormat[ImageTypeId] = InstructionPointer + ImageFormatOffset; + } + else if (OpCode == spv::OpFunction && FirstFunctionWordIndex == 0) { - const uint32_t ImageTypeId = SPIRV[i + 1]; - ImageTypeIdToFormat[ImageTypeId] = i + ImageFormatOffset; + FirstFunctionWordIndex = InstructionPointer; } + else if (OpCode == spv::OpDecorate) + { + LastDecorateEnd = InstructionPointer + WordCount; + } + + InstructionPointer += WordCount; } std::vector PatchedSPIRV = SPIRV; + + std::vector NewDecorations; + NewDecorations.reserve(resources.storage_images.size() * 3); + for (const diligent_spirv_cross::Resource& Img : resources.storage_images) { - const diligent_spirv_cross::SPIRType& type = Compiler.get_type(Img.type_id); - if (type.image.dim == spv::Dim1D || - type.image.dim == spv::Dim2D || - type.image.dim == spv::Dim3D) + const diligent_spirv_cross::SPIRType& SpvType = Compiler.get_type(Img.type_id); + if (SpvType.image.dim == spv::Dim1D || + SpvType.image.dim == spv::Dim2D || + SpvType.image.dim == spv::Dim3D) { - auto FormatIt = ImageFormats.find(HashMapStringKey{Img.name.c_str()}); - if (FormatIt != ImageFormats.end()) + auto InfoIt = ImageInfos.find(HashMapStringKey{Img.name.c_str()}); + if (InfoIt == ImageInfos.end()) + continue; + + const spv::ImageFormat SpvFormat = TextureFormatToSpvImageFormat(InfoIt->second.Format); + if (SpvFormat != spv::ImageFormatUnknown) { - spv::ImageFormat spvFormat = TextureFormatToSpvImageFormat(FormatIt->second); - if (spvFormat != spv::ImageFormatUnknown) + auto FormatOffsetIt = ImageTypeIdToFormat.find(Img.base_type_id); + if (FormatOffsetIt != ImageTypeIdToFormat.end() && + FormatOffsetIt->second < PatchedSPIRV.size()) { - auto FormatOffsetIt = ImageTypeIdToFormat.find(Img.base_type_id); - if (FormatOffsetIt != ImageTypeIdToFormat.end()) + const uint32_t ImageFormatOffset = FormatOffsetIt->second; + uint32_t& FormatWord = PatchedSPIRV[ImageFormatOffset]; + if (FormatWord != static_cast(SpvType.image.format) && + FormatWord != static_cast(SpvFormat)) { - const uint32_t ImageFormatOffset = FormatOffsetIt->second; - uint32_t& FormatWord = PatchedSPIRV[ImageFormatOffset]; - if (FormatWord != static_cast(type.image.format) && - FormatWord != static_cast(spvFormat)) - { - LOG_ERROR_MESSAGE("Inconsistent formats encountered while patching format for image '", Img.name, - "'.\nThis likely is the result of the same-format textures using inconsistent format specifiers in HLSL, for example:" - "\n RWTexture2D g_RWTex1;" - "\n RWTexture2D g_RWTex2;"); - } - FormatWord = spvFormat; + LOG_ERROR_MESSAGE("Inconsistent formats encountered while patching format for image '", Img.name, + "'.\nThis likely is the result of the same-format textures using inconsistent format specifiers in HLSL, for example:" + "\n RWTexture2D g_RWTex1;" + "\n RWTexture2D g_RWTex2;"); } + FormatWord = static_cast(SpvFormat); + } + } + + switch (InfoIt->second.AccessMode) + { + case IMAGE_ACCESS_MODE_READ: + { + constexpr uint32_t WordCount = 3; + constexpr uint32_t OpCode = static_cast(spv::OpDecorate); + + NewDecorations.push_back((WordCount << 16) | OpCode); + NewDecorations.push_back(Img.id); + NewDecorations.push_back(static_cast(spv::DecorationNonWritable)); + break; } + + case IMAGE_ACCESS_MODE_WRITE: + { + constexpr uint32_t WordCount = 3; + constexpr uint32_t OpCode = static_cast(spv::OpDecorate); + + NewDecorations.push_back((WordCount << 16) | OpCode); + NewDecorations.push_back(Img.id); + NewDecorations.push_back(static_cast(spv::DecorationNonReadable)); + break; + } + + case IMAGE_ACCESS_MODE_READ_WRITE: + case IMAGE_ACCESS_MODE_UNKNOWN: + default: + break; } } } + if (!NewDecorations.empty()) + { + size_t InsertPos = PatchedSPIRV.size(); + + if (LastDecorateEnd != 0 && LastDecorateEnd <= PatchedSPIRV.size()) + { + InsertPos = static_cast(LastDecorateEnd); + } + else if (FirstFunctionWordIndex != 0 && FirstFunctionWordIndex < PatchedSPIRV.size()) + { + InsertPos = static_cast(FirstFunctionWordIndex); + } + + PatchedSPIRV.insert(PatchedSPIRV.begin() + InsertPos, + NewDecorations.begin(), NewDecorations.end()); + } + return PatchedSPIRV; } diff --git a/Graphics/ShaderTools/src/WGSLShaderResources.cpp b/Graphics/ShaderTools/src/WGSLShaderResources.cpp index ca77db0709..ed191b1a8b 100644 --- a/Graphics/ShaderTools/src/WGSLShaderResources.cpp +++ b/Graphics/ShaderTools/src/WGSLShaderResources.cpp @@ -267,6 +267,8 @@ TEXTURE_FORMAT TintTexelFormatToTextureFormat(const tint::inspector::ResourceBin case TintTexelFormat::kRgba16Uint: return TEX_FORMAT_RGBA16_UINT; case TintTexelFormat::kRgba16Sint: return TEX_FORMAT_RGBA16_SINT; case TintTexelFormat::kRgba16Float: return TEX_FORMAT_RGBA16_FLOAT; + case TintTexelFormat::kRgba16Unorm: return TEX_FORMAT_RGBA16_UNORM; + case TintTexelFormat::kRgba16Snorm: return TEX_FORMAT_RGBA16_SNORM; case TintTexelFormat::kR32Uint: return TEX_FORMAT_R32_UINT; case TintTexelFormat::kR32Sint: return TEX_FORMAT_R32_SINT; case TintTexelFormat::kR32Float: return TEX_FORMAT_R32_FLOAT; @@ -277,6 +279,23 @@ TEXTURE_FORMAT TintTexelFormatToTextureFormat(const tint::inspector::ResourceBin case TintTexelFormat::kRgba32Sint: return TEX_FORMAT_RGBA32_SINT; case TintTexelFormat::kRgba32Float: return TEX_FORMAT_RGBA32_FLOAT; case TintTexelFormat::kR8Unorm: return TEX_FORMAT_R8_UNORM; + case TintTexelFormat::kR8Snorm: return TEX_FORMAT_R8_SNORM; + case TintTexelFormat::kR8Uint: return TEX_FORMAT_R8_UINT; + case TintTexelFormat::kR8Sint: return TEX_FORMAT_R8_SINT; + case TintTexelFormat::kRg8Unorm: return TEX_FORMAT_RG8_UNORM; + case TintTexelFormat::kRg8Snorm: return TEX_FORMAT_RG8_SNORM; + case TintTexelFormat::kRg8Uint: return TEX_FORMAT_RG8_UINT; + case TintTexelFormat::kRg8Sint: return TEX_FORMAT_RG8_SINT; + case TintTexelFormat::kR16Uint: return TEX_FORMAT_R16_UINT; + case TintTexelFormat::kR16Sint: return TEX_FORMAT_R16_SINT; + case TintTexelFormat::kR16Float: return TEX_FORMAT_R16_FLOAT; + case TintTexelFormat::kR16Unorm: return TEX_FORMAT_R16_UNORM; + case TintTexelFormat::kR16Snorm: return TEX_FORMAT_R16_SNORM; + case TintTexelFormat::kRg16Uint: return TEX_FORMAT_RG16_UINT; + case TintTexelFormat::kRg16Sint: return TEX_FORMAT_RG16_SINT; + case TintTexelFormat::kRg16Float: return TEX_FORMAT_RG16_FLOAT; + case TintTexelFormat::kRg16Unorm: return TEX_FORMAT_RG16_UNORM; + case TintTexelFormat::kRg16Snorm: return TEX_FORMAT_RG16_SNORM; case TintTexelFormat::kNone: return TEX_FORMAT_UNKNOWN; // clang-format on default: diff --git a/Graphics/ShaderTools/src/WGSLUtils.cpp b/Graphics/ShaderTools/src/WGSLUtils.cpp index f528f126f7..03d037e200 100644 --- a/Graphics/ShaderTools/src/WGSLUtils.cpp +++ b/Graphics/ShaderTools/src/WGSLUtils.cpp @@ -44,11 +44,15 @@ #include "src/tint/lang/core/type/atomic.h" #include "src/tint/lang/core/type/array.h" #include "src/tint/lang/core/type/struct.h" - +#include "src/tint/lang/core/ir/transform/binding_remapper.h" +#include "src/tint/lang/wgsl/inspector/inspector.h" +#include "src/tint/lang/wgsl/writer/ir_to_program/ir_to_program.h" +#include "src/tint/lang/wgsl/reader/program_to_ir/program_to_ir.h" #ifdef _MSC_VER # pragma warning(pop) #endif +#include namespace Diligent { @@ -89,25 +93,88 @@ WGSLEmulatedResourceArrayElement GetWGSLEmulatedArrayElement(const std::string& return {Name, -1}; } -std::string ConvertSPIRVtoWGSL(const std::vector& SPIRV) +std::string DecodeSpirvLiteralString(const std::vector& SPIRV, + size_t StartWord, + uint16_t WordCount) { - tint::spirv::reader::Options SPIRVReaderOptions{true, {tint::wgsl::AllowedFeatures::Everything()}}; - tint::Program Program = Read(SPIRV, SPIRVReaderOptions); + std::string Result; + Result.reserve(static_cast(WordCount) * 4); - if (!Program.IsValid()) + const size_t EndWord = StartWord + WordCount; + for (size_t Idx = StartWord; Idx < EndWord; ++Idx) { - LOG_ERROR_MESSAGE("Tint SPIR-V reader failure:\nParser: " + Program.Diagnostics().Str() + "\n"); - return {}; + uint32_t Word = SPIRV[Idx]; + + for (int32_t ByteIndex = 0; ByteIndex < 4; ++ByteIndex) + { + char c = static_cast((Word >> (8 * ByteIndex)) & 0xFF); + if (c == '\0') + return Result; + Result.push_back(c); + } } - auto GenerationResult = tint::wgsl::writer::Generate(Program, {}); - if (GenerationResult != tint::Success) + return Result; +} + +void StripGoogleHlslFunctionality(std::vector& SPIRV) +{ + if (SPIRV.size() <= 5) + return; + + constexpr uint16_t OpExtension = 10; + constexpr uint16_t OpDecorateStringGOOGLE = 5632; + constexpr uint16_t OpMemberDecorateStringGOOGLE = 5633; + + size_t InstructionPointer = 5; // Skip SPIR-V header + while (InstructionPointer < SPIRV.size()) { - LOG_ERROR_MESSAGE("Tint WGSL writer failure:\nGeneate: " + GenerationResult.Failure().reason.Str() + "\n"); + uint32_t Instruction = SPIRV[InstructionPointer]; + uint16_t WordCount = Instruction >> 16; + uint16_t OpCode = Instruction & 0xFFFF; + + if (WordCount == 0 || InstructionPointer + WordCount > SPIRV.size()) + break; + + auto EraseCurrent = [&](size_t count) { + SPIRV.erase(SPIRV.begin() + InstructionPointer, + SPIRV.begin() + InstructionPointer + count); + }; + + if (OpCode == OpExtension) + { + std::string Extension = DecodeSpirvLiteralString(SPIRV, InstructionPointer + 1, static_cast(WordCount - 1)); + + if (Extension == "SPV_GOOGLE_hlsl_functionality1") + { + EraseCurrent(WordCount); + continue; + } + } + else if (OpCode == OpDecorateStringGOOGLE || OpCode == OpMemberDecorateStringGOOGLE) + { + EraseCurrent(WordCount); + continue; + } + InstructionPointer += WordCount; + } +} + +std::string ConvertSPIRVtoWGSL(const std::vector& SPIRV) +{ + tint::wgsl::writer::Options WGSLWriterOptions{}; + WGSLWriterOptions.allow_non_uniform_derivatives = true; + WGSLWriterOptions.allowed_features = tint::wgsl::AllowedFeatures::Everything(); + WGSLWriterOptions.minify = false; + + auto Result = tint::SpirvToWgsl(SPIRV, WGSLWriterOptions); + if (Result != tint::Success) + { + LOG_ERROR_MESSAGE("Tint SPIR-V -> WGSL failed:\n" + Result.Failure().reason + "\n"); return {}; } - return GenerationResult->wgsl; + return Result.Get(); } static bool IsAtomic(const tint::core::type::Type* WGSLType) @@ -155,6 +222,24 @@ static bool IsAtomic(const tint::core::type::Type* WGSLType) } } +static std::string StripNumericSuffix(std::string Name) +{ + const auto UnderscorePos = Name.find_last_of('_'); + if (UnderscorePos == std::string::npos || UnderscorePos + 1 >= Name.length()) + return Name; + + const bool AllDigits = + std::all_of(Name.begin() + static_cast(UnderscorePos + 1), + Name.end(), + [](char c) { return c >= '0' && c <= '9'; }); + + if (!AllDigits) + return Name; + + Name.erase(UnderscorePos); + return Name; +} + std::string GetWGSLResourceAlternativeName(const tint::Program& Program, const tint::inspector::ResourceBinding& Binding) { if (Binding.resource_type != tint::inspector::ResourceBinding::ResourceType::kUniformBuffer && @@ -196,7 +281,7 @@ std::string GetWGSLResourceAlternativeName(const tint::Program& Program, const t // g_Data0 : vec4f, // } // @group(0) @binding(0) var x_13 : CB0; - return TypeName; + return StripNumericSuffix(std::move(TypeName)); } else { @@ -253,14 +338,14 @@ static WGSLResourceMapping::const_iterator FindResourceAsArrayElement(const WGSL if (WGSLEmulatedResourceArrayElement ArrayElem = GetWGSLEmulatedArrayElement(Name, EmulatedArrayIndexSuffix)) { - auto BindigIt = ResMapping.find(ArrayElem.Name); - if (BindigIt == ResMapping.end()) + auto BindingIt = ResMapping.find(ArrayElem.Name); + if (BindingIt == ResMapping.end()) return ResMapping.end(); - if (ArrayElem.Index < static_cast(BindigIt->second.ArraySize)) + if (ArrayElem.Index < static_cast(BindingIt->second.ArraySize)) { ArrayIndex = static_cast(ArrayElem.Index); - return BindigIt; + return BindingIt; } } @@ -271,47 +356,50 @@ std::string RemapWGSLResourceBindings(const std::string& WGSL, const WGSLResourceMapping& ResMapping, const char* EmulatedArrayIndexSuffix) { - tint::Source::File srcFile("", WGSL); - tint::Program Program = tint::wgsl::reader::Parse(&srcFile, {tint::wgsl::AllowedFeatures::Everything()}); + tint::Source::File SrcFile("", WGSL); + + tint::wgsl::reader::Options WGSLReaderOptions{}; + WGSLReaderOptions.allowed_features = tint::wgsl::AllowedFeatures::Everything(); + + tint::Program Program = tint::wgsl::reader::Parse(&SrcFile, WGSLReaderOptions); if (!Program.IsValid()) { - LOG_ERROR_MESSAGE("Tint WGSL reader failure:\nParser: ", Program.Diagnostics().Str(), "\n"); + LOG_ERROR_MESSAGE("Tint WGSL parse failed:\n", Program.Diagnostics().Str(), "\n"); return {}; } - tint::ast::transform::BindingRemapper::BindingPoints BindingPoints; - - tint::inspector::Inspector Inspector{Program}; + std::unordered_map BindingPoints; + tint::inspector::Inspector Inspector{Program}; for (tint::inspector::EntryPoint& EntryPoint : Inspector.GetEntryPoints()) { for (tint::inspector::ResourceBinding& Binding : Inspector.GetResourceBindings(EntryPoint.name)) { Uint32 ArrayIndex = 0; - auto DstBindigIt = ResMapping.find(Binding.variable_name); - if (EmulatedArrayIndexSuffix != nullptr && DstBindigIt == ResMapping.end()) + auto DstBindingIt = ResMapping.find(Binding.variable_name); + if (EmulatedArrayIndexSuffix != nullptr && DstBindingIt == ResMapping.end()) { - DstBindigIt = FindResourceAsArrayElement(ResMapping, EmulatedArrayIndexSuffix, Binding.variable_name, ArrayIndex); + DstBindingIt = FindResourceAsArrayElement(ResMapping, EmulatedArrayIndexSuffix, Binding.variable_name, ArrayIndex); } - if (DstBindigIt == ResMapping.end()) + if (DstBindingIt == ResMapping.end()) { const std::string AltName = GetWGSLResourceAlternativeName(Program, Binding); if (!AltName.empty()) { - DstBindigIt = ResMapping.find(AltName); - if (EmulatedArrayIndexSuffix != nullptr && DstBindigIt == ResMapping.end()) + DstBindingIt = ResMapping.find(AltName); + if (EmulatedArrayIndexSuffix != nullptr && DstBindingIt == ResMapping.end()) { - DstBindigIt = FindResourceAsArrayElement(ResMapping, EmulatedArrayIndexSuffix, AltName, ArrayIndex); + DstBindingIt = FindResourceAsArrayElement(ResMapping, EmulatedArrayIndexSuffix, AltName, ArrayIndex); } } } - if (DstBindigIt != ResMapping.end()) + if (DstBindingIt != ResMapping.end()) { - const WGSLResourceBindingInfo& DstBindig = DstBindigIt->second; - BindingPoints.emplace(tint::ast::transform::BindingPoint{Binding.bind_group, Binding.binding}, tint::ast::transform::BindingPoint{DstBindig.Group, DstBindig.Index + ArrayIndex}); + const WGSLResourceBindingInfo& DstBinding = DstBindingIt->second; + BindingPoints.emplace(tint::BindingPoint{Binding.bind_group, Binding.binding}, tint::BindingPoint{DstBinding.Group, DstBinding.Index + ArrayIndex}); } else { @@ -320,23 +408,32 @@ std::string RemapWGSLResourceBindings(const std::string& WGSL, } } - tint::ast::transform::Manager Manager; - tint::ast::transform::DataMap Inputs; - tint::ast::transform::DataMap Outputs; + auto Module = tint::wgsl::reader::ProgramToIR(Program); + if (Module != tint::Success) + { + LOG_ERROR_MESSAGE("Tint WGSL → IR failed:\n", Module.Failure().reason, "\n"); + return {}; + } - Inputs.Add(BindingPoints, tint::ast::transform::BindingRemapper::AccessControls{}, false); - Manager.Add(); - tint::ast::transform::Output TransformResult = Manager.Run(Program, Inputs, Outputs); + if (auto Result = tint::core::ir::transform::BindingRemapper(Module.Get(), BindingPoints); Result != tint::Success) + { + LOG_ERROR_MESSAGE("Tint binding remap failed:\n", Result.Failure().reason, "\n"); + return {}; + } - auto GenerationResult = tint::wgsl::writer::Generate(TransformResult.program, {}); + tint::wgsl::writer::Options WGSLWriterOptions{}; + WGSLWriterOptions.allow_non_uniform_derivatives = true; + WGSLWriterOptions.allowed_features = WGSLReaderOptions.allowed_features; + WGSLWriterOptions.minify = false; - if (GenerationResult != tint::Success) + auto Result = tint::wgsl::writer::WgslFromIR(Module.Get(), WGSLWriterOptions); + if (Result != tint::Success) { - LOG_ERROR_MESSAGE("Tint WGSL writer failure:\nGeneate: ", GenerationResult.Failure().reason.Str(), "\n"); + LOG_ERROR_MESSAGE("Tint IR -> WGSL failed:\n", Result.Failure().reason, "\n"); return {}; } - std::string PatchedWGSL = std::move(GenerationResult->wgsl); + std::string PatchedWGSL = std::move(Result->wgsl); // If original WGSL contains shader source language definition, append it to the patched WGSL SHADER_SOURCE_LANGUAGE SrcLang = ParseShaderSourceLanguageDefinition(WGSL); diff --git a/Tests/DiligentCoreAPITest/assets/shaders/RenderStateCache/ComputeShader.csh b/Tests/DiligentCoreAPITest/assets/shaders/RenderStateCache/ComputeShader.csh index a30e619bb3..d1bba70586 100644 --- a/Tests/DiligentCoreAPITest/assets/shaders/RenderStateCache/ComputeShader.csh +++ b/Tests/DiligentCoreAPITest/assets/shaders/RenderStateCache/ComputeShader.csh @@ -1,6 +1,6 @@ #include "Defines.h" -VK_IMAGE_FORMAT("rgba8") RWTexture2D g_tex2DUAV; +VK_IMAGE_FORMAT("rgba8") RWTexture2D g_tex2DUAV; #if INTERNAL_MACROS == 1 && EXTERNAL_MACROS == 2 [numthreads(16, 16, 1)] diff --git a/Tests/DiligentCoreAPITest/include/InlineShaders/ComputeShaderTestHLSL.h b/Tests/DiligentCoreAPITest/include/InlineShaders/ComputeShaderTestHLSL.h index 3b2baf66af..0fee5d6be9 100644 --- a/Tests/DiligentCoreAPITest/include/InlineShaders/ComputeShaderTestHLSL.h +++ b/Tests/DiligentCoreAPITest/include/InlineShaders/ComputeShaderTestHLSL.h @@ -125,7 +125,7 @@ cbuffer Constants float4 g_Color; }; -VK_IMAGE_FORMAT("rgba8") RWTexture2D g_tex2DUAV : register(u0); +VK_IMAGE_FORMAT("rgba8") RWTexture2D g_tex2DUAV : register(u0); void main(in VSOutput VSOut) { diff --git a/Tests/DiligentCoreAPITest/src/ArchiveTest.cpp b/Tests/DiligentCoreAPITest/src/ArchiveTest.cpp index 6185009456..8375c7affc 100644 --- a/Tests/DiligentCoreAPITest/src/ArchiveTest.cpp +++ b/Tests/DiligentCoreAPITest/src/ArchiveTest.cpp @@ -1298,7 +1298,7 @@ namespace HLSL // Test shader source as string const std::string ComputePSOTest_CS{R"( -VK_IMAGE_FORMAT("rgba8") RWTexture2D g_tex2DUAV : register(u0); +VK_IMAGE_FORMAT("rgba8") RWTexture2D g_tex2DUAV : register(u0); [numthreads(16, 16, 1)] void main(uint3 DTid : SV_DispatchThreadID) diff --git a/Tests/DiligentCoreTest/CMakeLists.txt b/Tests/DiligentCoreTest/CMakeLists.txt index d6fed71511..7a200238ad 100644 --- a/Tests/DiligentCoreTest/CMakeLists.txt +++ b/Tests/DiligentCoreTest/CMakeLists.txt @@ -32,7 +32,13 @@ if (CMAKE_CXX_COMPILER_ID MATCHES "Clang") endif() add_executable(DiligentCoreTest ${SOURCE} ${SHADERS}) -set_common_target_properties(DiligentCoreTest 17) + +if (WEBGPU_SUPPORTED) + set_common_target_properties(DiligentCoreTest 20) +else() + set_common_target_properties(DiligentCoreTest 17) +endif() + if (PLATFORM_WEB) set(RESOURCE_PATH "${PROJECT_SOURCE_DIR}/assets/") diff --git a/Tests/DiligentCoreTest/assets/shaders/WGSL/RWTextureArrays.psh b/Tests/DiligentCoreTest/assets/shaders/WGSL/RWTextureArrays.psh index 80ceac47d9..09eb9660a1 100644 --- a/Tests/DiligentCoreTest/assets/shaders/WGSL/RWTextureArrays.psh +++ b/Tests/DiligentCoreTest/assets/shaders/WGSL/RWTextureArrays.psh @@ -1,14 +1,14 @@ -RWTexture2D g_WOTex2DArr0_3; -RWTexture2D g_WOTex2DArr0_1; +RWTexture2D g_WOTex2DArr0_3; +RWTexture2D g_WOTex2DArr0_1; RWTexture2D g_RWTex2DArr0_2; RWTexture2D g_RWTex2DArr0_0; -RWTexture2D g_WOTex2DNotArr1_2; -RWTexture2D g_WOTex2DNotArr1_4; +RWTexture2D g_WOTex2DNotArr1_2; +RWTexture2D g_WOTex2DNotArr1_4; -RWTexture2D g_RWTex2DNotArr2_5; -RWTexture2D g_RWTex2DNotArr2_9; +RWTexture2D g_RWTex2DNotArr2_5; +RWTexture2D g_RWTex2DNotArr2_9; float4 main() : SV_Target { diff --git a/Tests/DiligentCoreTest/assets/shaders/WGSL/RWTextures.psh b/Tests/DiligentCoreTest/assets/shaders/WGSL/RWTextures.psh index f3e2a73220..da08cb61eb 100644 --- a/Tests/DiligentCoreTest/assets/shaders/WGSL/RWTextures.psh +++ b/Tests/DiligentCoreTest/assets/shaders/WGSL/RWTextures.psh @@ -1,17 +1,17 @@ -RWTexture1D g_WOTex1D; -RWTexture2D g_WOTex2D; -RWTexture2DArray g_WOTex2DArr; -RWTexture3D g_WOTex3D; +RWTexture1D g_WOTex1D; +RWTexture2D g_WOTex2D; +RWTexture2DArray g_WOTex2DArr; +RWTexture3D g_WOTex3D; -RWTexture1D g_ROTex1D; -RWTexture2D g_ROTex2D; -RWTexture2DArray g_ROTex2DArr; -RWTexture3D g_ROTex3D; +RWTexture1D g_ROTex1D; +RWTexture2D g_ROTex2D; +RWTexture2DArray g_ROTex2DArr; +RWTexture3D g_ROTex3D; -RWTexture1D g_RWTex1D; -RWTexture2D g_RWTex2D; -RWTexture2DArray g_RWTex2DArr; -RWTexture3D g_RWTex3D; +RWTexture1D g_RWTex1D; +RWTexture2D g_RWTex2D; +RWTexture2DArray g_RWTex2DArr; +RWTexture3D g_RWTex3D; float4 main() : SV_Target { diff --git a/Tests/DiligentCoreTest/src/ShaderTools/GLSLParsingToolsTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/GLSLParsingToolsTest.cpp index 6683c84c8b..7df5a62388 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/GLSLParsingToolsTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/GLSLParsingToolsTest.cpp @@ -73,6 +73,42 @@ TEST(GLSLParsingToolsTest, ExtractGLSLImageFormatFromComment) Test(" // format = rg16u\n", "rg16u"); } +TEST(GLSLParsingToolsTest, ExtractGLSLAccessModeFromComment) +{ + auto Test = [](const std::string& Str, const std::string& RefAccessMode) { + std::string AccessMode = Parsing::ExtractGLSLAccessModeFromComment(Str.begin(), Str.end()); + EXPECT_STREQ(AccessMode.c_str(), RefAccessMode.c_str()) << Str; + }; + Test("", ""); + Test(" ", ""); + Test(" access", ""); + Test(" /access", ""); + Test(" // ", ""); + Test(" /* ", ""); + Test(" // acce", ""); + Test(" /* acc", ""); + Test(" // acce ", ""); + Test(" /* acc ", ""); + Test(" // access", ""); + Test(" /* access", ""); + Test(" // access-", ""); + Test(" /* access:", ""); + Test(" // access=12", ""); + Test(" /* access=34", ""); + Test(" // access=read", "read"); + Test(" /* access=write", "write"); + Test(" // access=read_write ", "read_write"); + Test(" /* access=read */", "read"); + Test(" /* access= write*/", "write"); + Test(" /* access= read_write */", "read_write"); + Test(" /* access =write */", "write"); + Test(" // access = read\n", "read"); + Test(" /* access= write*/", "write"); + Test(" // access= read_write \n", "read_write"); + Test(" /* access = read*/", "read"); + Test(" // access = write\n", "write"); + Test(" /* access = read_write */", "read_write"); +} TEST(GLSLParsingToolsTest, ParseGLSLImageFormat) { diff --git a/Tests/DiligentCoreTest/src/ShaderTools/HLSLParsingToolsTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/HLSLParsingToolsTest.cpp index d25fda62aa..7cb21358c5 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/HLSLParsingToolsTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/HLSLParsingToolsTest.cpp @@ -35,7 +35,7 @@ using namespace Diligent::Testing; namespace { -static constexpr char g_TestHLSL[] = R"( +static constexpr char g_TestHLSL_Formats[] = R"( RWTexture1D g_rgba8; RWTexture2D g_rg8; RWTexture3D g_r8; @@ -103,7 +103,7 @@ void Function(RWTexture2D FunctionArg1, TEST(HLSLParsingTools, ExtractGLSLImageFormatsFromHLSL) { - std::unordered_map RefFormats; + std::unordered_map RefFormats; RefFormats.emplace("g_rgba8", TEX_FORMAT_RGBA8_UNORM); RefFormats.emplace("g_rg8", TEX_FORMAT_RG8_UNORM); RefFormats.emplace("g_r8", TEX_FORMAT_R8_UNORM); @@ -156,7 +156,7 @@ TEST(HLSLParsingTools, ExtractGLSLImageFormatsFromHLSL) RefFormats.emplace("g_rgb10_a2", TEX_FORMAT_RGB10A2_UNORM); RefFormats.emplace("g_rgb10_a2ui", TEX_FORMAT_RGB10A2_UINT); - std::unordered_map Formats = Parsing::ExtractGLSLImageFormatsFromHLSL(g_TestHLSL); + std::unordered_map Formats = Parsing::ExtractGLSLImageFormatsAndAccessModeFromHLSL(g_TestHLSL_Formats); EXPECT_EQ(Formats.size(), RefFormats.size()); for (const auto& RefFmtIt : RefFormats) { @@ -169,14 +169,75 @@ TEST(HLSLParsingTools, ExtractGLSLImageFormatsFromHLSL) } } - EXPECT_TRUE(Parsing::ExtractGLSLImageFormatsFromHLSL("").empty()); - EXPECT_TRUE(Parsing::ExtractGLSLImageFormatsFromHLSL("RWTexture2D").empty()); - EXPECT_TRUE(Parsing::ExtractGLSLImageFormatsFromHLSL("RWTexture2D<").empty()); - EXPECT_TRUE(Parsing::ExtractGLSLImageFormatsFromHLSL("RWTexture2D<>").empty()); - EXPECT_TRUE(Parsing::ExtractGLSLImageFormatsFromHLSL("RWTexture2D").empty()); - EXPECT_TRUE(Parsing::ExtractGLSLImageFormatsFromHLSL("RWTexture2D").empty()); - EXPECT_TRUE(Parsing::ExtractGLSLImageFormatsFromHLSL("RWTexture2D").empty()); - EXPECT_TRUE(Parsing::ExtractGLSLImageFormatsFromHLSL("RWTexture2D 123").empty()); + EXPECT_TRUE(Parsing::ExtractGLSLImageFormatsAndAccessModeFromHLSL("").empty()); + EXPECT_TRUE(Parsing::ExtractGLSLImageFormatsAndAccessModeFromHLSL("RWTexture2D").empty()); + EXPECT_TRUE(Parsing::ExtractGLSLImageFormatsAndAccessModeFromHLSL("RWTexture2D<").empty()); + EXPECT_TRUE(Parsing::ExtractGLSLImageFormatsAndAccessModeFromHLSL("RWTexture2D<>").empty()); + EXPECT_TRUE(Parsing::ExtractGLSLImageFormatsAndAccessModeFromHLSL("RWTexture2D").empty()); + EXPECT_TRUE(Parsing::ExtractGLSLImageFormatsAndAccessModeFromHLSL("RWTexture2D").empty()); + EXPECT_TRUE(Parsing::ExtractGLSLImageFormatsAndAccessModeFromHLSL("RWTexture2D").empty()); + EXPECT_TRUE(Parsing::ExtractGLSLImageFormatsAndAccessModeFromHLSL("RWTexture2D 123").empty()); +} + + +static constexpr char g_TestHLSL_AccessMode[] = R"( +RWTexture1D g_ReadOnly; +RWTexture1D g_WriteOnly; +RWTexture1D g_ReadWrite; + +RWTexture1D g_ReadWrite_1; +RWTexture1D g_ReadWrite_2; + +RWTexture1D g_ReadWriteFmt_01; +RWTexture1D g_ReadWriteFmt_02; +RWTexture1D g_ReadWriteFmt_03; +RWTexture1D g_ReadWriteFmt_04; +RWTexture1D g_ReadWriteFmt_05; +RWTexture1D g_ReadWriteFmt_06; + +RWTexture2D g_ReadWriteNoneVisible; + +void Function(RWTexture2D FunctionArg1, + RWTexture2D FunctionArg2, + RWTexture2D FunctionArg3) +{ + RWTexture2D LocalRWTex0; + RWTexture2D LocalRWTex1; + RWTexture2D LocalRWTex2; +} + +)"; + +TEST(HLSLParsingTools, ExtractGLSLAccessModeFromHLSL) +{ + std::unordered_map RefFormats; + RefFormats.emplace("g_ReadOnly", ImageFormatAndAccess{TEX_FORMAT_UNKNOWN, IMAGE_ACCESS_MODE_READ}); + RefFormats.emplace("g_WriteOnly", ImageFormatAndAccess{TEX_FORMAT_UNKNOWN, IMAGE_ACCESS_MODE_WRITE}); + RefFormats.emplace("g_ReadWrite", ImageFormatAndAccess{TEX_FORMAT_UNKNOWN, IMAGE_ACCESS_MODE_READ_WRITE}); + + RefFormats.emplace("g_ReadWrite_1", ImageFormatAndAccess{TEX_FORMAT_UNKNOWN, IMAGE_ACCESS_MODE_READ_WRITE}); + RefFormats.emplace("g_ReadWrite_2", ImageFormatAndAccess{TEX_FORMAT_UNKNOWN, IMAGE_ACCESS_MODE_READ_WRITE}); + + RefFormats.emplace("g_ReadWriteFmt_01", ImageFormatAndAccess{TEX_FORMAT_RGBA32_FLOAT, IMAGE_ACCESS_MODE_READ_WRITE}); + RefFormats.emplace("g_ReadWriteFmt_02", ImageFormatAndAccess{TEX_FORMAT_RGBA32_FLOAT, IMAGE_ACCESS_MODE_READ_WRITE}); + RefFormats.emplace("g_ReadWriteFmt_03", ImageFormatAndAccess{TEX_FORMAT_RGBA32_FLOAT, IMAGE_ACCESS_MODE_READ_WRITE}); + RefFormats.emplace("g_ReadWriteFmt_04", ImageFormatAndAccess{TEX_FORMAT_RGBA32_FLOAT, IMAGE_ACCESS_MODE_READ_WRITE}); + RefFormats.emplace("g_ReadWriteFmt_05", ImageFormatAndAccess{TEX_FORMAT_RGBA32_FLOAT, IMAGE_ACCESS_MODE_READ_WRITE}); + RefFormats.emplace("g_ReadWriteFmt_06", ImageFormatAndAccess{TEX_FORMAT_RGBA32_FLOAT, IMAGE_ACCESS_MODE_READ_WRITE}); + + + std::unordered_map Formats = Parsing::ExtractGLSLImageFormatsAndAccessModeFromHLSL(g_TestHLSL_AccessMode); + EXPECT_EQ(Formats.size(), RefFormats.size()); + for (const auto& RefFmtIt : RefFormats) + { + const auto& FmtIt = Formats.find(RefFmtIt.first); + if (FmtIt == Formats.end()) + ADD_FAILURE() << "Unable to find image format for resource " << RefFmtIt.first.GetStr(); + if (FmtIt != Formats.end()) + { + EXPECT_EQ(FmtIt->second, RefFmtIt.second) << "Incorrect format for resource " << RefFmtIt.first.GetStr(); + } + } } } // namespace diff --git a/Tests/DiligentCoreTest/src/ShaderTools/WGSLShaderResourcesTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/WGSLShaderResourcesTest.cpp index 21369f3fe2..b72ec93974 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/WGSLShaderResourcesTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/WGSLShaderResourcesTest.cpp @@ -30,6 +30,8 @@ #include "DefaultShaderSourceStreamFactory.h" #include "RefCntAutoPtr.hpp" #include "EngineMemory.h" +#include "HLSLParsingTools.hpp" +#include "ShaderToolsCommon.hpp" #include @@ -59,6 +61,14 @@ std::string HLSLtoWGLS(const char* FilePath) GLSLangUtils::InitializeGlslang(); auto SPIRV = GLSLangUtils::HLSLtoSPIRV(ShaderCI, GLSLangUtils::SpirvVersion::Vk100, nullptr, nullptr); + StripGoogleHlslFunctionality(SPIRV); + + const ShaderSourceFileData SourceData = ReadShaderSourceFile(ShaderCI); + + const auto ImageFormats = Parsing::ExtractGLSLImageFormatsAndAccessModeFromHLSL(std::string(SourceData.Source, SourceData.SourceLength)); + if (!ImageFormats.empty()) + SPIRV = PatchImageFormatsAndAccessModes(SPIRV, ImageFormats); + GLSLangUtils::FinalizeGlslang(); if (SPIRV.empty()) @@ -150,10 +160,10 @@ TEST(WGSLShaderResources, RWTextures) {"g_WOTex2DArr", WGSLResourceType::WOStorageTexture, 1, RESOURCE_DIM_TEX_2D_ARRAY, TEX_FORMAT_RGBA32_UINT, WGSLSampleType::UInt}, {"g_WOTex3D", WGSLResourceType::WOStorageTexture, 1, RESOURCE_DIM_TEX_3D, TEX_FORMAT_RGBA32_FLOAT, WGSLSampleType::Float}, - {"g_ROTex1D", WGSLResourceType::Texture, 1, RESOURCE_DIM_TEX_1D, TEX_FORMAT_UNKNOWN, WGSLSampleType::SInt}, - {"g_ROTex2D", WGSLResourceType::Texture, 1, RESOURCE_DIM_TEX_2D, TEX_FORMAT_UNKNOWN, WGSLSampleType::Float}, - {"g_ROTex2DArr", WGSLResourceType::Texture, 1, RESOURCE_DIM_TEX_2D_ARRAY, TEX_FORMAT_UNKNOWN, WGSLSampleType::UInt}, - {"g_ROTex3D", WGSLResourceType::Texture, 1, RESOURCE_DIM_TEX_3D, TEX_FORMAT_UNKNOWN, WGSLSampleType::Float}, + {"g_ROTex1D", WGSLResourceType::ROStorageTexture, 1, RESOURCE_DIM_TEX_1D, TEX_FORMAT_RG32_SINT, WGSLSampleType::SInt}, + {"g_ROTex2D", WGSLResourceType::ROStorageTexture, 1, RESOURCE_DIM_TEX_2D, TEX_FORMAT_RG32_FLOAT, WGSLSampleType::Float}, + {"g_ROTex2DArr", WGSLResourceType::ROStorageTexture, 1, RESOURCE_DIM_TEX_2D_ARRAY, TEX_FORMAT_RG32_UINT, WGSLSampleType::UInt}, + {"g_ROTex3D", WGSLResourceType::ROStorageTexture, 1, RESOURCE_DIM_TEX_3D, TEX_FORMAT_RG32_FLOAT, WGSLSampleType::Float}, {"g_RWTex1D", WGSLResourceType::RWStorageTexture, 1, RESOURCE_DIM_TEX_1D, TEX_FORMAT_R32_SINT, WGSLSampleType::SInt}, {"g_RWTex2D", WGSLResourceType::RWStorageTexture, 1, RESOURCE_DIM_TEX_2D, TEX_FORMAT_R32_FLOAT, WGSLSampleType::Float}, diff --git a/Tests/DiligentCoreTest/src/ShaderTools/WGSLUtilsTest.cpp b/Tests/DiligentCoreTest/src/ShaderTools/WGSLUtilsTest.cpp index 88430770f6..89514548d3 100644 --- a/Tests/DiligentCoreTest/src/ShaderTools/WGSLUtilsTest.cpp +++ b/Tests/DiligentCoreTest/src/ShaderTools/WGSLUtilsTest.cpp @@ -120,6 +120,7 @@ std::string HLSLtoWGLS(const char* FilePath) GLSLangUtils::InitializeGlslang(); auto SPIRV = GLSLangUtils::HLSLtoSPIRV(ShaderCI, GLSLangUtils::SpirvVersion::Vk100, nullptr, nullptr); + StripGoogleHlslFunctionality(SPIRV); GLSLangUtils::FinalizeGlslang(); if (SPIRV.empty()) diff --git a/Tests/GPUTestFramework/include/WebGPU/TestingEnvironmentWebGPU.hpp b/Tests/GPUTestFramework/include/WebGPU/TestingEnvironmentWebGPU.hpp index f71eaea3e8..5a6c05cede 100644 --- a/Tests/GPUTestFramework/include/WebGPU/TestingEnvironmentWebGPU.hpp +++ b/Tests/GPUTestFramework/include/WebGPU/TestingEnvironmentWebGPU.hpp @@ -59,25 +59,6 @@ class TestingEnvironmentWebGPU final : public GPUTestingEnvironment WGPUDevice m_wgpuDevice = nullptr; }; -#if PLATFORM_WEB - -using WGPUShaderSourceWGSL = WGPUShaderModuleWGSLDescriptor; -using WGPUStringView = const char*; - -constexpr WGPUSType WGPUSType_ShaderSourceWGSL = WGPUSType_ShaderModuleWGSLDescriptor; - -inline WGPUStringView GetWGPUStringView(const char* Str) -{ - return Str; -} - -inline WGPUStringView GetWGPUStringView(const std::string& Str) -{ - return Str.c_str(); -} - -#else - template WGPUStringView GetWGPUStringView(const char (&Str)[Size]) { @@ -89,8 +70,6 @@ inline WGPUStringView GetWGPUStringView(const std::string& Str) return {Str.c_str(), Str.length()}; } -#endif - } // namespace Testing } // namespace Diligent diff --git a/Tests/GPUTestFramework/src/WebGPU/TestingEnvironmentWebGPU.cpp b/Tests/GPUTestFramework/src/WebGPU/TestingEnvironmentWebGPU.cpp index 57cb8f9edf..c3823978c4 100644 --- a/Tests/GPUTestFramework/src/WebGPU/TestingEnvironmentWebGPU.cpp +++ b/Tests/GPUTestFramework/src/WebGPU/TestingEnvironmentWebGPU.cpp @@ -103,14 +103,18 @@ void TestingEnvironmentWebGPU::SubmitCommandEncoder(WGPUCommandEncoder wgpuCmdEn if (WaitForIdle) { bool IsWorkDone = false; - auto WorkDoneCallback = [](WGPUQueueWorkDoneStatus Status, void* pUserData) { - if (bool* pIsWorkDone = static_cast(pUserData)) - *pIsWorkDone = Status == WGPUQueueWorkDoneStatus_Success; - if (Status != WGPUQueueWorkDoneStatus_Success) - DEV_ERROR("Failed wgpuQueueOnSubmittedWorkDone: ", Status); + auto WorkDoneCallback = [](WGPUQueueWorkDoneStatus wgpuStatus, WGPUStringView Message, void* pUserData1, void* pUserData2) { + if (bool* pIsWorkDone = static_cast(pUserData1)) + *pIsWorkDone = wgpuStatus == WGPUQueueWorkDoneStatus_Success; + if (wgpuStatus != WGPUQueueWorkDoneStatus_Success) + DEV_ERROR("Failed wgpuQueueOnSubmittedWorkDone: ", wgpuStatus); }; - wgpuQueueOnSubmittedWorkDone(wgpuCmdQueue, WorkDoneCallback, &IsWorkDone); + WGPUQueueWorkDoneCallbackInfo wgpuQueueWorkDoneCallbackInfo{}; + wgpuQueueWorkDoneCallbackInfo.mode = WGPUCallbackMode_AllowSpontaneous; + wgpuQueueWorkDoneCallbackInfo.callback = WorkDoneCallback; + wgpuQueueWorkDoneCallbackInfo.userdata1 = &IsWorkDone; + wgpuQueueOnSubmittedWorkDone(wgpuCmdQueue, wgpuQueueWorkDoneCallbackInfo); while (!IsWorkDone) { diff --git a/Tests/GPUTestFramework/src/WebGPU/TestingSwapChainWebGPU.cpp b/Tests/GPUTestFramework/src/WebGPU/TestingSwapChainWebGPU.cpp index 987977182a..aef74b460a 100644 --- a/Tests/GPUTestFramework/src/WebGPU/TestingSwapChainWebGPU.cpp +++ b/Tests/GPUTestFramework/src/WebGPU/TestingSwapChainWebGPU.cpp @@ -165,23 +165,23 @@ void TestingSwapChainWebGPU::TakeSnapshot(ITexture* pCopyFrom) WGPUCommandEncoderDescriptor wgpuCmdEncoderDesc{}; WGPUCommandEncoder wgpuCmdEncoder = wgpuDeviceCreateCommandEncoder(m_wgpuDevice, &wgpuCmdEncoderDesc); - WGPUImageCopyTexture wgpuImageCopySrc{}; - wgpuImageCopySrc.mipLevel = 0; - wgpuImageCopySrc.texture = wgpuSrcTexture; - wgpuImageCopySrc.origin = {0, 0, 0}; + WGPUTexelCopyTextureInfo wgpuTexelCopySrc{}; + wgpuTexelCopySrc.mipLevel = 0; + wgpuTexelCopySrc.texture = wgpuSrcTexture; + wgpuTexelCopySrc.origin = {0, 0, 0}; - WGPUImageCopyBuffer wgpuImageCopyDst{}; - wgpuImageCopyDst.layout.offset = 0; - wgpuImageCopyDst.layout.bytesPerRow = 4 * m_SwapChainDesc.Width; - wgpuImageCopyDst.layout.rowsPerImage = m_SwapChainDesc.Height; - wgpuImageCopyDst.buffer = m_wgpuStagingBuffer; + WGPUTexelCopyBufferInfo wgpuTexelCopyDst{}; + wgpuTexelCopyDst.layout.offset = 0; + wgpuTexelCopyDst.layout.bytesPerRow = 4 * m_SwapChainDesc.Width; + wgpuTexelCopyDst.layout.rowsPerImage = m_SwapChainDesc.Height; + wgpuTexelCopyDst.buffer = m_wgpuStagingBuffer; WGPUExtent3D wgpuCopySize{}; wgpuCopySize.width = m_SwapChainDesc.Width; wgpuCopySize.height = m_SwapChainDesc.Height; wgpuCopySize.depthOrArrayLayers = 1; - wgpuCommandEncoderCopyTextureToBuffer(wgpuCmdEncoder, &wgpuImageCopySrc, &wgpuImageCopyDst, &wgpuCopySize); + wgpuCommandEncoderCopyTextureToBuffer(wgpuCmdEncoder, &wgpuTexelCopySrc, &wgpuTexelCopyDst, &wgpuCopySize); WGPUCommandBufferDescriptor wgpuCmdBufferDesc{}; WGPUCommandBuffer wgpuCmdBuffer = wgpuCommandEncoderFinish(wgpuCmdEncoder, &wgpuCmdBufferDesc); @@ -191,27 +191,31 @@ void TestingSwapChainWebGPU::TakeSnapshot(ITexture* pCopyFrom) wgpuCommandBufferRelease(wgpuCmdBuffer); const size_t DataSize = 4 * m_SwapChainDesc.Width * m_SwapChainDesc.Height; + + WGPUBufferMapCallbackInfo wgpuMapCallbackInfo{}; + wgpuMapCallbackInfo.userdata1 = this; + wgpuMapCallbackInfo.mode = WGPUCallbackMode_AllowSpontaneous; + wgpuMapCallbackInfo.callback = [](WGPUMapAsyncStatus wgpuMapStatus, WGPUStringView Message, void* pUserData1, void* pUserData2) { + if (wgpuMapStatus == WGPUMapAsyncStatus_Success) + { + const auto pThis = static_cast(pUserData1); + + pThis->m_ReferenceDataPitch = pThis->m_SwapChainDesc.Width * 4; + pThis->m_ReferenceData.resize(pThis->m_ReferenceDataPitch * pThis->m_SwapChainDesc.Height); + + const auto* pMappedData = static_cast(wgpuBufferGetConstMappedRange(pThis->m_wgpuStagingBuffer, 0, pThis->m_ReferenceData.size())); + VERIFY_EXPR(pMappedData != nullptr); + + memcpy(pThis->m_ReferenceData.data(), pMappedData, pThis->m_ReferenceData.size()); + wgpuBufferUnmap(pThis->m_wgpuStagingBuffer); + } + else + { + ADD_FAILURE() << "Failing to map staging buffer"; + } + }; wgpuBufferMapAsync( - m_wgpuStagingBuffer, WGPUMapMode_Read, 0, DataSize, [](WGPUBufferMapAsyncStatus MapStatus, void* pUserData) { - if (MapStatus == WGPUBufferMapAsyncStatus_Success) - { - const auto pThis = static_cast(pUserData); - - pThis->m_ReferenceDataPitch = pThis->m_SwapChainDesc.Width * 4; - pThis->m_ReferenceData.resize(pThis->m_ReferenceDataPitch * pThis->m_SwapChainDesc.Height); - - const auto* pMappedData = static_cast(wgpuBufferGetConstMappedRange(pThis->m_wgpuStagingBuffer, 0, pThis->m_ReferenceData.size())); - VERIFY_EXPR(pMappedData != nullptr); - - memcpy(pThis->m_ReferenceData.data(), pMappedData, pThis->m_ReferenceData.size()); - wgpuBufferUnmap(pThis->m_wgpuStagingBuffer); - } - else - { - ADD_FAILURE() << "Failing to map staging buffer"; - } - }, - this); + m_wgpuStagingBuffer, WGPUMapMode_Read, 0, DataSize, wgpuMapCallbackInfo); #if !PLATFORM_WEB wgpuDeviceTick(m_wgpuDevice); diff --git a/Tests/IncludeTest/CMakeLists.txt b/Tests/IncludeTest/CMakeLists.txt index 90b6c6e55d..15d9f20228 100644 --- a/Tests/IncludeTest/CMakeLists.txt +++ b/Tests/IncludeTest/CMakeLists.txt @@ -59,7 +59,11 @@ target_link_libraries(DiligentCore-IncludeTest PRIVATE Diligent-BuildSettings) set_common_target_properties(DiligentCore-IncludeTest) if (WEBGPU_SUPPORTED) - target_link_libraries(DiligentCore-IncludeTest PUBLIC dawn_headers) + if (PLATFORM_WEB) + target_compile_options(DiligentCore-IncludeTest PUBLIC "--use-port=emdawnwebgpu") + else() + target_link_libraries(DiligentCore-IncludeTest PUBLIC dawn_headers) + endif() endif() if(MSVC) diff --git a/ThirdParty/CMakeLists.txt b/ThirdParty/CMakeLists.txt index 88def6be84..d2eca119be 100644 --- a/ThirdParty/CMakeLists.txt +++ b/ThirdParty/CMakeLists.txt @@ -158,9 +158,6 @@ if (VULKAN_SUPPORTED AND (PLATFORM_WIN32 OR PLATFORM_LINUX OR PLATFORM_MACOS OR endif() if (WEBGPU_SUPPORTED) - add_subdirectory(abseil-cpp EXCLUDE_FROM_ALL) - set_directory_root_folder("abseil-cpp" "DiligentCore/ThirdParty") - add_subdirectory(dawn EXCLUDE_FROM_ALL) set_directory_root_folder("dawn" "DiligentCore/ThirdParty/dawn") endif() @@ -183,11 +180,6 @@ if ((${DILIGENT_BUILD_GOOGLE_TEST}) AND (NOT TARGET gtest)) get_target_property(GTEST_SOURCE_DIR gtest SOURCE_DIR) install(FILES "googletest/LICENSE" DESTINATION "Licenses/ThirdParty/${DILIGENT_CORE_DIR}" RENAME googletest-License.txt) - - if (PLATFORM_WEB) - find_targets_in_directory(GTEST_TARGETS ${GTEST_SOURCE_DIR}) - set_targets_emscripten_properties(${GTEST_TARGETS}) - endif() endif() if (NOT TARGET xxHash::xxhash) diff --git a/ThirdParty/abseil-cpp/CMakeLists.txt b/ThirdParty/abseil-cpp/CMakeLists.txt deleted file mode 100644 index cb88412fc2..0000000000 --- a/ThirdParty/abseil-cpp/CMakeLists.txt +++ /dev/null @@ -1,16 +0,0 @@ -cmake_minimum_required (VERSION 3.11) - -FetchContent_DeclareShallowGit( - abseil-cpp - GIT_REPOSITORY https://chromium.googlesource.com/chromium/src/third_party/abseil-cpp - GIT_TAG 54ea9e3a7fe017384713d773373761de7c4a1154 -) - -set(CMAKE_CXX_STANDARD 17) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) - -set(ABSL_PROPAGATE_CXX_STD ON CACHE BOOL "" FORCE) - -FetchContent_MakeAvailable(abseil-cpp) -install(FILES "${abseil-cpp_SOURCE_DIR}/LICENSE" DESTINATION "Licenses/ThirdParty/${DILIGENT_CORE_DIR}" RENAME abseil-cpp-License.txt) diff --git a/ThirdParty/dawn/CMakeLists.txt b/ThirdParty/dawn/CMakeLists.txt index 2a62f6f944..14b47899d5 100644 --- a/ThirdParty/dawn/CMakeLists.txt +++ b/ThirdParty/dawn/CMakeLists.txt @@ -1,26 +1,22 @@ cmake_minimum_required (VERSION 3.11) -find_package(Python3 REQUIRED) - -set(JINJA2_INSTALL_CMD ${Python3_EXECUTABLE} -m pip install --upgrade jinja2>=3.0) - -if(${Python3_VERSION} VERSION_GREATER_EQUAL "3.12") - set(JINJA2_INSTALL_CMD ${JINJA2_INSTALL_CMD} --break-system-packages) -endif() - -execute_process(COMMAND ${JINJA2_INSTALL_CMD} - RESULT_VARIABLE PYTHON_PIP_JINJIA_RESULT) -if(NOT PYTHON_PIP_JINJIA_RESULT EQUAL "0") - message(FATAL_ERROR "Command '${JINJA2_INSTALL_CMD}' failed with error code ${PYTHON_PIP_JINJIA_RESULT}") -endif() +set(DAWN_SUBMODULES + third_party/abseil-cpp + third_party/jinja2 + third_party/markupsafe + third_party/libprotobuf-mutator + third_party/protobuf + third_party/webgpu-headers +) FetchContent_DeclareShallowGit( dawn GIT_REPOSITORY https://dawn.googlesource.com/dawn - GIT_TAG db55f595741106be83b823a02ebdc58efbe997f1 + GIT_TAG d9daee7f75b60657aa3bc54b406882d10b693f89 + GIT_SUBMODULES "${DAWN_SUBMODULES}" ) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) @@ -29,10 +25,10 @@ if (PLATFORM_WEB) else() set(TINT_BUILD_AS_OTHER_OS OFF CACHE BOOL "" FORCE) endif() -set(TINT_BUILD_SPV_READER ON CACHE BOOL "" FORCE) -set(TINT_BUILD_WGSL_WRITER ON CACHE BOOL "" FORCE) -set(TINT_BUILD_WGSL_READER ON CACHE BOOL "" FORCE) -set(TINT_BUILD_IR ON CACHE BOOL "" FORCE) +set(TINT_BUILD_SPV_READER ON CACHE BOOL "" FORCE) +set(TINT_BUILD_WGSL_WRITER ON CACHE BOOL "" FORCE) +set(TINT_BUILD_WGSL_READER ON CACHE BOOL "" FORCE) +set(TINT_BUILD_IR_BINARY ON CACHE BOOL "" FORCE) if (PLATFORM_WEB) set(TINT_BUILD_HLSL_WRITER OFF CACHE BOOL "" FORCE) else() @@ -43,6 +39,7 @@ set(TINT_BUILD_GLSL_WRITER OFF CACHE BOOL "" FORCE) set(TINT_BUILD_MSL_WRITER OFF CACHE BOOL "" FORCE) set(TINT_BUILD_SPV_WRITER OFF CACHE BOOL "" FORCE) set(TINT_BUILD_GLSL_VALIDATOR OFF CACHE BOOL "" FORCE) +set(TINT_ENABLE_IR_VALIDATION OFF CACHE BOOL "" FORCE) set(TINT_BUILD_CMD_TOOLS OFF CACHE BOOL "" FORCE) set(TINT_BUILD_SAMPLES OFF CACHE BOOL "" FORCE) @@ -50,6 +47,7 @@ set(TINT_BUILD_DOCS OFF CACHE BOOL "" FORCE) set(TINT_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(DAWN_BUILD_SAMPLES OFF CACHE BOOL "" FORCE) +set(DAWN_BUILD_TESTS OFF CACHE BOOL "" FORCE) set(DAWN_USE_X11 OFF CACHE BOOL "" FORCE) set(DAWN_USE_WAYLAND OFF CACHE BOOL "" FORCE) @@ -57,7 +55,6 @@ set(DAWN_ENABLE_VULKAN OFF CACHE BOOL "" FORCE) set(DAWN_ENABLE_D3D11 OFF CACHE BOOL "" FORCE) set(DAWN_ENABLE_DESKTOP_GL OFF CACHE BOOL "" FORCE) set(DAWN_ENABLE_OPENGLES OFF CACHE BOOL "" FORCE) -set(DAWN_BUILD_TESTS OFF CACHE BOOL "" FORCE) # Dawn's CMake defines DAWN_EMSCRIPTEN_TOOLCHAIN through the option command, which # sets its default value to OFF instead of "" set(DAWN_EMSCRIPTEN_TOOLCHAIN "" CACHE STRING "" FORCE) @@ -67,16 +64,18 @@ else() set(DAWN_ENABLE_D3D12 ON CACHE BOOL "" FORCE) endif() -set(DAWN_USE_GLFW OFF CACHE BOOL "" FORCE) -set(DAWN_ENABLE_NULL OFF CACHE BOOL "" FORCE) -set(DAWN_USE_WINDOWS_UI OFF CACHE BOOL "" FORCE) -set(DAWN_ENABLE_SPIRV_VALIDATION OFF CACHE BOOL "" FORCE) +set(DAWN_USE_GLFW OFF CACHE BOOL "" FORCE) +set(DAWN_ENABLE_NULL OFF CACHE BOOL "" FORCE) +set(DAWN_USE_WINDOWS_UI OFF CACHE BOOL "" FORCE) +set(DAWN_ENABLE_SPIRV_VALIDATION OFF CACHE BOOL "" FORCE) +set(DAWN_BUILD_MONOLITHIC_LIBRARY OFF CACHE STRING "" FORCE) -set(DAWN_SPIRV_TOOLS_DIR "${spirv-tools_SOURCE_DIR}" CACHE STRING "Directory in which to find SPIRV-Tools" FORCE) -set(DAWN_SPIRV_HEADERS_DIR "${SPIRV-Headers_SOURCE_DIR}" CACHE STRING "Directory in which to find SPIRV-Headers" FORCE) -set(DAWN_ABSEIL_DIR "${abseil-cpp_SOURCE_DIR}" CACHE STRING "Directory in which to find Abseil" FORCE) +set(DAWN_SPIRV_TOOLS_DIR "${spirv-tools_SOURCE_DIR}" CACHE STRING "Directory in which to find SPIRV-Tools" FORCE) +set(DAWN_SPIRV_HEADERS_DIR "${SPIRV-Headers_SOURCE_DIR}" CACHE STRING "Directory in which to find SPIRV-Headers" FORCE) +set(DAWN_GOOGLETEST_DIR "${GTEST_SOURCE_DIR}" CACHE STRING "Directory in which to find GoogleTest" FORCE) -set(BUILD_SHARED_LIBS OFF) +set(BUILD_SAMPLES OFF CACHE BOOL "") +set(BUILD_SHARED_LIBS OFF CACHE BOOL "") FetchContent_MakeAvailable(dawn) From 3484ee98ce09ea49f14b6399c73251237bde21da Mon Sep 17 00:00:00 2001 From: Mikhail Gorobets Date: Sun, 21 Dec 2025 17:35:07 +0600 Subject: [PATCH 2/3] WebGPU: Activate Float32 Blendable Feature --- Graphics/GraphicsEngineWebGPU/src/EngineFactoryWebGPU.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Graphics/GraphicsEngineWebGPU/src/EngineFactoryWebGPU.cpp b/Graphics/GraphicsEngineWebGPU/src/EngineFactoryWebGPU.cpp index 4590b6d677..1b24fbd36f 100644 --- a/Graphics/GraphicsEngineWebGPU/src/EngineFactoryWebGPU.cpp +++ b/Graphics/GraphicsEngineWebGPU/src/EngineFactoryWebGPU.cpp @@ -244,6 +244,9 @@ WebGPUDeviceWrapper CreateDeviceForAdapter(const DeviceFeatures& Features, WGPUI if (wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_Float32Filterable)) wgpuFeatures.push_back(WGPUFeatureName_Float32Filterable); + if (wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_Float32Blendable)) + wgpuFeatures.push_back(WGPUFeatureName_Float32Blendable); + if (wgpuAdapterHasFeature(wgpuAdapter, WGPUFeatureName_IndirectFirstInstance)) wgpuFeatures.push_back(WGPUFeatureName_IndirectFirstInstance); From 017f804c6683a367609c5077305ea51aff73bef1 Mon Sep 17 00:00:00 2001 From: Mikhail Gorobets Date: Tue, 6 Jan 2026 18:55:13 +0600 Subject: [PATCH 3/3] [WebGPU, Dawn] Updated Dawn to support texture-tier-1 in the Tint converter --- .../src/ShaderWebGPUImpl.cpp | 1 + Graphics/ShaderTools/include/WGSLUtils.hpp | 2 + .../ShaderTools/src/WGSLShaderResources.cpp | 79 ++++++++++--------- Graphics/ShaderTools/src/WGSLUtils.cpp | 55 ++++++++++++- ThirdParty/dawn/CMakeLists.txt | 2 +- 5 files changed, 96 insertions(+), 43 deletions(-) diff --git a/Graphics/GraphicsEngineWebGPU/src/ShaderWebGPUImpl.cpp b/Graphics/GraphicsEngineWebGPU/src/ShaderWebGPUImpl.cpp index 49b4d8c66e..7125212f85 100644 --- a/Graphics/GraphicsEngineWebGPU/src/ShaderWebGPUImpl.cpp +++ b/Graphics/GraphicsEngineWebGPU/src/ShaderWebGPUImpl.cpp @@ -204,6 +204,7 @@ void ShaderWebGPUImpl::Initialize(const ShaderCreateInfo& ShaderCI, } StripGoogleHlslFunctionality(SPIRV); + AddStorageImageExtendedFormats(SPIRV); m_WGSL = ConvertSPIRVtoWGSL(SPIRV); if (m_WGSL.empty()) { diff --git a/Graphics/ShaderTools/include/WGSLUtils.hpp b/Graphics/ShaderTools/include/WGSLUtils.hpp index 43f9ea1c70..7b4a53c5d0 100644 --- a/Graphics/ShaderTools/include/WGSLUtils.hpp +++ b/Graphics/ShaderTools/include/WGSLUtils.hpp @@ -59,6 +59,8 @@ std::string RemapWGSLResourceBindings(const std::string& WGSL, /// New version of Tint can't translate SPIR-V to WGSL with certain HLSL-specific functionality, void StripGoogleHlslFunctionality(std::vector& SPIRV); +/// Ensures the module declares `OpCapability StorageImageExtendedFormats`, which is required when using extended storage image formats +void AddStorageImageExtendedFormats(std::vector& SPIRV); /// When WGSL is generated from SPIR-V, the names of resources may be mangled /// diff --git a/Graphics/ShaderTools/src/WGSLShaderResources.cpp b/Graphics/ShaderTools/src/WGSLShaderResources.cpp index ed191b1a8b..410c62e6d0 100644 --- a/Graphics/ShaderTools/src/WGSLShaderResources.cpp +++ b/Graphics/ShaderTools/src/WGSLShaderResources.cpp @@ -259,44 +259,47 @@ TEXTURE_FORMAT TintTexelFormatToTextureFormat(const tint::inspector::ResourceBin switch (TintBinding.image_format) { // clang-format off - case TintTexelFormat::kBgra8Unorm: return TEX_FORMAT_BGRA8_UNORM; - case TintTexelFormat::kRgba8Unorm: return TEX_FORMAT_RGBA8_UNORM; - case TintTexelFormat::kRgba8Snorm: return TEX_FORMAT_RGBA8_SNORM; - case TintTexelFormat::kRgba8Uint: return TEX_FORMAT_RGBA8_UINT; - case TintTexelFormat::kRgba8Sint: return TEX_FORMAT_RGBA8_SINT; - case TintTexelFormat::kRgba16Uint: return TEX_FORMAT_RGBA16_UINT; - case TintTexelFormat::kRgba16Sint: return TEX_FORMAT_RGBA16_SINT; - case TintTexelFormat::kRgba16Float: return TEX_FORMAT_RGBA16_FLOAT; - case TintTexelFormat::kRgba16Unorm: return TEX_FORMAT_RGBA16_UNORM; - case TintTexelFormat::kRgba16Snorm: return TEX_FORMAT_RGBA16_SNORM; - case TintTexelFormat::kR32Uint: return TEX_FORMAT_R32_UINT; - case TintTexelFormat::kR32Sint: return TEX_FORMAT_R32_SINT; - case TintTexelFormat::kR32Float: return TEX_FORMAT_R32_FLOAT; - case TintTexelFormat::kRg32Uint: return TEX_FORMAT_RG32_UINT; - case TintTexelFormat::kRg32Sint: return TEX_FORMAT_RG32_SINT; - case TintTexelFormat::kRg32Float: return TEX_FORMAT_RG32_FLOAT; - case TintTexelFormat::kRgba32Uint: return TEX_FORMAT_RGBA32_UINT; - case TintTexelFormat::kRgba32Sint: return TEX_FORMAT_RGBA32_SINT; - case TintTexelFormat::kRgba32Float: return TEX_FORMAT_RGBA32_FLOAT; - case TintTexelFormat::kR8Unorm: return TEX_FORMAT_R8_UNORM; - case TintTexelFormat::kR8Snorm: return TEX_FORMAT_R8_SNORM; - case TintTexelFormat::kR8Uint: return TEX_FORMAT_R8_UINT; - case TintTexelFormat::kR8Sint: return TEX_FORMAT_R8_SINT; - case TintTexelFormat::kRg8Unorm: return TEX_FORMAT_RG8_UNORM; - case TintTexelFormat::kRg8Snorm: return TEX_FORMAT_RG8_SNORM; - case TintTexelFormat::kRg8Uint: return TEX_FORMAT_RG8_UINT; - case TintTexelFormat::kRg8Sint: return TEX_FORMAT_RG8_SINT; - case TintTexelFormat::kR16Uint: return TEX_FORMAT_R16_UINT; - case TintTexelFormat::kR16Sint: return TEX_FORMAT_R16_SINT; - case TintTexelFormat::kR16Float: return TEX_FORMAT_R16_FLOAT; - case TintTexelFormat::kR16Unorm: return TEX_FORMAT_R16_UNORM; - case TintTexelFormat::kR16Snorm: return TEX_FORMAT_R16_SNORM; - case TintTexelFormat::kRg16Uint: return TEX_FORMAT_RG16_UINT; - case TintTexelFormat::kRg16Sint: return TEX_FORMAT_RG16_SINT; - case TintTexelFormat::kRg16Float: return TEX_FORMAT_RG16_FLOAT; - case TintTexelFormat::kRg16Unorm: return TEX_FORMAT_RG16_UNORM; - case TintTexelFormat::kRg16Snorm: return TEX_FORMAT_RG16_SNORM; - case TintTexelFormat::kNone: return TEX_FORMAT_UNKNOWN; + case TintTexelFormat::kBgra8Unorm: return TEX_FORMAT_BGRA8_UNORM; + case TintTexelFormat::kRgba8Unorm: return TEX_FORMAT_RGBA8_UNORM; + case TintTexelFormat::kRgba8Snorm: return TEX_FORMAT_RGBA8_SNORM; + case TintTexelFormat::kRgba8Uint: return TEX_FORMAT_RGBA8_UINT; + case TintTexelFormat::kRgba8Sint: return TEX_FORMAT_RGBA8_SINT; + case TintTexelFormat::kRgba16Uint: return TEX_FORMAT_RGBA16_UINT; + case TintTexelFormat::kRgba16Sint: return TEX_FORMAT_RGBA16_SINT; + case TintTexelFormat::kRgba16Float: return TEX_FORMAT_RGBA16_FLOAT; + case TintTexelFormat::kRgba16Unorm: return TEX_FORMAT_RGBA16_UNORM; + case TintTexelFormat::kRgba16Snorm: return TEX_FORMAT_RGBA16_SNORM; + case TintTexelFormat::kR32Uint: return TEX_FORMAT_R32_UINT; + case TintTexelFormat::kR32Sint: return TEX_FORMAT_R32_SINT; + case TintTexelFormat::kR32Float: return TEX_FORMAT_R32_FLOAT; + case TintTexelFormat::kRg32Uint: return TEX_FORMAT_RG32_UINT; + case TintTexelFormat::kRg32Sint: return TEX_FORMAT_RG32_SINT; + case TintTexelFormat::kRg32Float: return TEX_FORMAT_RG32_FLOAT; + case TintTexelFormat::kRgba32Uint: return TEX_FORMAT_RGBA32_UINT; + case TintTexelFormat::kRgba32Sint: return TEX_FORMAT_RGBA32_SINT; + case TintTexelFormat::kRgba32Float: return TEX_FORMAT_RGBA32_FLOAT; + case TintTexelFormat::kR8Unorm: return TEX_FORMAT_R8_UNORM; + case TintTexelFormat::kR8Snorm: return TEX_FORMAT_R8_SNORM; + case TintTexelFormat::kR8Uint: return TEX_FORMAT_R8_UINT; + case TintTexelFormat::kR8Sint: return TEX_FORMAT_R8_SINT; + case TintTexelFormat::kRg8Unorm: return TEX_FORMAT_RG8_UNORM; + case TintTexelFormat::kRg8Snorm: return TEX_FORMAT_RG8_SNORM; + case TintTexelFormat::kRg8Uint: return TEX_FORMAT_RG8_UINT; + case TintTexelFormat::kRg8Sint: return TEX_FORMAT_RG8_SINT; + case TintTexelFormat::kR16Uint: return TEX_FORMAT_R16_UINT; + case TintTexelFormat::kR16Sint: return TEX_FORMAT_R16_SINT; + case TintTexelFormat::kR16Float: return TEX_FORMAT_R16_FLOAT; + case TintTexelFormat::kR16Unorm: return TEX_FORMAT_R16_UNORM; + case TintTexelFormat::kR16Snorm: return TEX_FORMAT_R16_SNORM; + case TintTexelFormat::kRg16Uint: return TEX_FORMAT_RG16_UINT; + case TintTexelFormat::kRg16Sint: return TEX_FORMAT_RG16_SINT; + case TintTexelFormat::kRg16Float: return TEX_FORMAT_RG16_FLOAT; + case TintTexelFormat::kRg16Unorm: return TEX_FORMAT_RG16_UNORM; + case TintTexelFormat::kRg16Snorm: return TEX_FORMAT_RG16_SNORM; + case TintTexelFormat::kRg11B10Ufloat: return TEX_FORMAT_R11G11B10_FLOAT; + case TintTexelFormat::kRgb10A2Uint: return TEX_FORMAT_RGB10A2_UINT; + case TintTexelFormat::kRgb10A2Unorm: return TEX_FORMAT_RGB10A2_UNORM; + case TintTexelFormat::kNone: return TEX_FORMAT_UNKNOWN; // clang-format on default: UNEXPECTED("Unexpected texel format"); diff --git a/Graphics/ShaderTools/src/WGSLUtils.cpp b/Graphics/ShaderTools/src/WGSLUtils.cpp index 03d037e200..2bb3e5f774 100644 --- a/Graphics/ShaderTools/src/WGSLUtils.cpp +++ b/Graphics/ShaderTools/src/WGSLUtils.cpp @@ -117,6 +117,51 @@ std::string DecodeSpirvLiteralString(const std::vector& SPIRV, return Result; } +void AddStorageImageExtendedFormats(std::vector& SPIRV) +{ + if (SPIRV.size() <= 5) + return; + + constexpr uint16_t OpCapability = 17; + constexpr uint32_t StorageImageExtendedFormats = 49; + + bool HasCapability = false; + size_t InsertAfterCapability = 5; + + size_t InstructionPointer = 5; // Skip SPIR-V header + while (InstructionPointer < SPIRV.size()) + { + uint32_t Instruction = SPIRV[InstructionPointer]; + uint16_t WordCount = Instruction >> 16; + uint16_t OpCode = Instruction & 0xFFFF; + + if (WordCount == 0 || InstructionPointer + WordCount > SPIRV.size()) + break; + + if (OpCode == OpCapability) + { + InsertAfterCapability = InstructionPointer + WordCount; + + if (WordCount >= 2 && SPIRV[InstructionPointer + 1] == StorageImageExtendedFormats) + { + HasCapability = true; + break; + } + + InstructionPointer += WordCount; + continue; + } + break; + } + + if (HasCapability) + return; + + + const uint32_t FirstWord = (2u << 16) | uint32_t(OpCapability); + SPIRV.insert(SPIRV.begin() + InsertAfterCapability, {FirstWord, StorageImageExtendedFormats}); +} + void StripGoogleHlslFunctionality(std::vector& SPIRV) { if (SPIRV.size() <= 5) @@ -127,6 +172,12 @@ void StripGoogleHlslFunctionality(std::vector& SPIRV) constexpr uint16_t OpMemberDecorateStringGOOGLE = 5633; size_t InstructionPointer = 5; // Skip SPIR-V header + + auto EraseCurrent = [&](size_t Count) { + SPIRV.erase(SPIRV.begin() + InstructionPointer, + SPIRV.begin() + InstructionPointer + Count); + }; + while (InstructionPointer < SPIRV.size()) { uint32_t Instruction = SPIRV[InstructionPointer]; @@ -136,10 +187,6 @@ void StripGoogleHlslFunctionality(std::vector& SPIRV) if (WordCount == 0 || InstructionPointer + WordCount > SPIRV.size()) break; - auto EraseCurrent = [&](size_t count) { - SPIRV.erase(SPIRV.begin() + InstructionPointer, - SPIRV.begin() + InstructionPointer + count); - }; if (OpCode == OpExtension) { diff --git a/ThirdParty/dawn/CMakeLists.txt b/ThirdParty/dawn/CMakeLists.txt index 14b47899d5..b900fc16a8 100644 --- a/ThirdParty/dawn/CMakeLists.txt +++ b/ThirdParty/dawn/CMakeLists.txt @@ -12,7 +12,7 @@ set(DAWN_SUBMODULES FetchContent_DeclareShallowGit( dawn GIT_REPOSITORY https://dawn.googlesource.com/dawn - GIT_TAG d9daee7f75b60657aa3bc54b406882d10b693f89 + GIT_TAG 958dff171579e885fcfd02ec86fd6e0f5081a35f GIT_SUBMODULES "${DAWN_SUBMODULES}" )