Skip to content

Commit

Permalink
WebGPU: Implemented texture uploader (close #556)
Browse files Browse the repository at this point in the history
  • Loading branch information
MikhailGorobets authored and TheMostDiligent committed Jul 24, 2024
1 parent 1ecb9ec commit fb1cb7a
Show file tree
Hide file tree
Showing 6 changed files with 607 additions and 40 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/build-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ jobs:
uses: DiligentGraphics/github-action/run-core-gpu-tests@v1
with:
mode: wgpu
args: --gtest_filter=-ShaderResourceLayout.VariableAccess:QueryTest.*:TextureUploaderTest*
args: --gtest_filter=-ShaderResourceLayout.VariableAccess:QueryTest.*

- name: Upload artifact
uses: actions/upload-artifact@v3
Expand Down
107 changes: 69 additions & 38 deletions Graphics/GraphicsEngineWebGPU/src/DeviceContextWebGPUImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -783,59 +783,90 @@ void DeviceContextWebGPUImpl::UpdateTexture(ITexture* pText
{
TDeviceContextBase::UpdateTexture(pTexture, MipLevel, Slice, DstBox, SubresData, SrcBufferStateTransitionMode, DstTextureStateTransitionMode);

EndCommandEncoders();

if (SubresData.pSrcBuffer != nullptr)
{
UNSUPPORTED("Copy buffer to texture is not implemented");
return;
}
auto* const pDstTextureWebGPU = ClassPtrCast<TextureWebGPUImpl>(pTexture);
auto* const pSrcBufferWebGPU = ClassPtrCast<BufferWebGPUImpl>(SubresData.pSrcBuffer);

EndCommandEncoders();
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;

auto* const pTextureWebGPU = ClassPtrCast<TextureWebGPUImpl>(pTexture);
const auto& FmtAttribs = GetTextureFormatAttribs(pDstTextureWebGPU->GetDesc().Format);

WGPUExtent3D wgpuCopySize{};
wgpuCopySize.width = DstBox.Width();
wgpuCopySize.height = DstBox.Height();
wgpuCopySize.depthOrArrayLayers = DstBox.Depth();

const auto& TexDesc = pTextureWebGPU->GetDesc();
const auto CopyInfo = GetBufferToTextureCopyInfo(TexDesc.Format, DstBox, TextureWebGPUImpl::ImageCopyBufferRowAlignment);
if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED)
{
wgpuCopySize.width = AlignUp(wgpuCopySize.width, FmtAttribs.BlockWidth);
wgpuCopySize.height = AlignUp(wgpuCopySize.height, FmtAttribs.BlockHeight);
}

const auto DynAllocation = AllocateUploadMemory(CopyInfo.MemorySize);
WGPUImageCopyBuffer wgpuImageCopySrc{};
wgpuImageCopySrc.buffer = pSrcBufferWebGPU->GetWebGPUBuffer();
wgpuImageCopySrc.layout.offset = SubresData.SrcOffset;
wgpuImageCopySrc.layout.bytesPerRow = static_cast<Uint32>(SubresData.Stride);
wgpuImageCopySrc.layout.rowsPerImage = wgpuCopySize.height;

for (Uint32 LayerIdx = 0; LayerIdx < CopyInfo.Region.Depth(); ++LayerIdx)
wgpuCommandEncoderCopyBufferToTexture(GetCommandEncoder(), &wgpuImageCopySrc, &wgpuImageCopyDst, &wgpuCopySize);
}
else
{
for (Uint32 RawIdx = 0; RawIdx < CopyInfo.RowCount; ++RawIdx)
auto* const pTextureWebGPU = ClassPtrCast<TextureWebGPUImpl>(pTexture);

const auto& TexDesc = pTextureWebGPU->GetDesc();
const auto CopyInfo = GetBufferToTextureCopyInfo(TexDesc.Format, DstBox, TextureWebGPUImpl::ImageCopyBufferRowAlignment);

const auto DynAllocation = AllocateUploadMemory(CopyInfo.MemorySize);

for (Uint32 LayerIdx = 0; LayerIdx < CopyInfo.Region.Depth(); ++LayerIdx)
{
const auto SrcOffset = RawIdx * SubresData.Stride + LayerIdx * SubresData.DepthStride;
const auto DstOffset = RawIdx * CopyInfo.RowStride + LayerIdx * CopyInfo.DepthStride;
memcpy(DynAllocation.pData + DstOffset, static_cast<const uint8_t*>(SubresData.pData) + SrcOffset, StaticCast<size_t>(CopyInfo.RowSize));
for (Uint32 RawIdx = 0; RawIdx < CopyInfo.RowCount; ++RawIdx)
{
const auto SrcOffset = RawIdx * SubresData.Stride + LayerIdx * SubresData.DepthStride;
const auto DstOffset = RawIdx * CopyInfo.RowStride + LayerIdx * CopyInfo.DepthStride;
memcpy(DynAllocation.pData + DstOffset, static_cast<const uint8_t*>(SubresData.pData) + SrcOffset, StaticCast<size_t>(CopyInfo.RowSize));
}
}
}

WGPUImageCopyBuffer wgpuImageCopySrc{};
wgpuImageCopySrc.buffer = DynAllocation.wgpuBuffer;
wgpuImageCopySrc.layout.offset = DynAllocation.Offset;
wgpuImageCopySrc.layout.bytesPerRow = static_cast<Uint32>(CopyInfo.RowStride);
wgpuImageCopySrc.layout.rowsPerImage = static_cast<Uint32>(CopyInfo.DepthStride);
WGPUImageCopyBuffer wgpuImageCopySrc{};
wgpuImageCopySrc.buffer = DynAllocation.wgpuBuffer;
wgpuImageCopySrc.layout.offset = DynAllocation.Offset;
wgpuImageCopySrc.layout.bytesPerRow = static_cast<Uint32>(CopyInfo.RowStride);
wgpuImageCopySrc.layout.rowsPerImage = static_cast<Uint32>(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;
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;

const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format);
const auto& FmtAttribs = GetTextureFormatAttribs(TexDesc.Format);

WGPUExtent3D wgpuCopySize{};
wgpuCopySize.width = DstBox.Width();
wgpuCopySize.height = DstBox.Height();
wgpuCopySize.depthOrArrayLayers = DstBox.Depth();
WGPUExtent3D wgpuCopySize{};
wgpuCopySize.width = DstBox.Width();
wgpuCopySize.height = DstBox.Height();
wgpuCopySize.depthOrArrayLayers = DstBox.Depth();

if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED)
{
wgpuCopySize.width = AlignUp(wgpuCopySize.width, FmtAttribs.BlockWidth);
wgpuCopySize.height = AlignUp(wgpuCopySize.height, FmtAttribs.BlockHeight);
}
if (FmtAttribs.ComponentType == COMPONENT_TYPE_COMPRESSED)
{
wgpuCopySize.width = AlignUp(wgpuCopySize.width, FmtAttribs.BlockWidth);
wgpuCopySize.height = AlignUp(wgpuCopySize.height, FmtAttribs.BlockHeight);
}

wgpuCommandEncoderCopyBufferToTexture(GetCommandEncoder(), &wgpuImageCopySrc, &wgpuImageCopyDst, &wgpuCopySize);
wgpuCommandEncoderCopyBufferToTexture(GetCommandEncoder(), &wgpuImageCopySrc, &wgpuImageCopyDst, &wgpuCopySize);
}
}

void DeviceContextWebGPUImpl::CopyTexture(const CopyTextureAttribs& CopyAttribs)
Expand Down Expand Up @@ -1097,7 +1128,7 @@ void DeviceContextWebGPUImpl::UnmapTextureSubresource(ITexture* pTexture, Uint32
wgpuImageCopySrc.buffer = Allocation.wgpuBuffer;
wgpuImageCopySrc.layout.offset = Allocation.Offset;
wgpuImageCopySrc.layout.bytesPerRow = static_cast<Uint32>(CopyInfo.RowStride);
wgpuImageCopySrc.layout.rowsPerImage = static_cast<Uint32>(CopyInfo.DepthStride);
wgpuImageCopySrc.layout.rowsPerImage = static_cast<Uint32>(CopyInfo.DepthStride / CopyInfo.RowStride);

WGPUImageCopyTexture wgpuImageCopyDst{};
wgpuImageCopyDst.texture = pTextureWebGPU->GetWebGPUTexture();
Expand Down
9 changes: 9 additions & 0 deletions Graphics/GraphicsTools/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,15 @@ if(GL_SUPPORTED OR GLES_SUPPORTED)
list(APPEND DEPENDENCIES Diligent-GraphicsEngineOpenGLInterface)
endif()

if(WEBGPU_SUPPORTED)
list(APPEND SOURCE src/TextureUploaderWebGPU.cpp)
list(APPEND INTERFACE interface/TextureUploaderWebGPU.hpp)
list(APPEND DEPENDENCIES Diligent-GraphicsEngineWebGPUInterface)
if (NOT PLATFORM_EMSCRIPTEN)
list(APPEND DEPENDENCIES dawn_proc)
endif()
endif()

if(METAL_SUPPORTED)
list(APPEND SOURCE src/GraphicsUtilitiesMtl.mm)
list(APPEND DEPENDENCIES Diligent-GraphicsEngineMetalInterface)
Expand Down
63 changes: 63 additions & 0 deletions Graphics/GraphicsTools/interface/TextureUploaderWebGPU.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* Copyright 2024 Diligent Graphics LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* In no event and under no legal theory, whether in tort (including negligence),
* contract, or otherwise, unless required by applicable law (such as deliberate
* and grossly negligent acts) or agreed to in writing, shall any Contributor be
* liable for any damages, including any direct, indirect, special, incidental,
* or consequential damages of any character arising as a result of this License or
* out of the use or inability to use the software (including but not limited to damages
* for loss of goodwill, work stoppage, computer failure or malfunction, or any and
* all other commercial damages or losses), even if such Contributor has been advised
* of the possibility of such damages.
*/

#pragma once

#include "TextureUploaderBase.hpp"

namespace Diligent
{

class TextureUploaderWebGPU : public TextureUploaderBase
{
public:
TextureUploaderWebGPU(IReferenceCounters* pRefCounters,
IRenderDevice* pDevice,
const TextureUploaderDesc Desc);
~TextureUploaderWebGPU();

virtual void RenderThreadUpdate(IDeviceContext* pContext) override final;

virtual void AllocateUploadBuffer(IDeviceContext* pContext,
const UploadBufferDesc& Desc,
IUploadBuffer** ppBuffer) override final;

virtual void ScheduleGPUCopy(IDeviceContext* pContext,
ITexture* pDstTexture,
Uint32 ArraySlice,
Uint32 MipLevel,
IUploadBuffer* pUploadBuffer) override final;

virtual void RecycleBuffer(IUploadBuffer* pUploadBuffer) override final;

virtual TextureUploaderStats GetStats() override final;

private:
struct InternalData;
std::unique_ptr<InternalData> m_pInternalData;
};

} // namespace Diligent
11 changes: 10 additions & 1 deletion Graphics/GraphicsTools/src/TextureUploader.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2019-2022 Diligent Graphics LLC
* Copyright 2019-2024 Diligent Graphics LLC
* Copyright 2015-2019 Egor Yusov
*
* Licensed under the Apache License, Version 2.0 (the "License");
Expand Down Expand Up @@ -40,6 +40,10 @@
# include "TextureUploaderGL.hpp"
#endif

#if WEBGPU_SUPPORTED
# include "TextureUploaderWebGPU.hpp"
#endif

namespace Diligent
{

Expand Down Expand Up @@ -68,6 +72,11 @@ void CreateTextureUploader(IRenderDevice* pDevice, const TextureUploaderDesc& De
break;
#endif

#if WEBGPU_SUPPORTED
case RENDER_DEVICE_TYPE_WEBGPU:
*ppUploader = MakeNewRCObj<TextureUploaderWebGPU>()(pDevice, Desc);
break;
#endif
default:
UNEXPECTED("Unsupported device type");
}
Expand Down
Loading

0 comments on commit fb1cb7a

Please sign in to comment.