287 lines
9.1 KiB
C++
287 lines
9.1 KiB
C++
// Copyright (c) Wojciech Figat. All rights reserved.
|
|
|
|
#if GRAPHICS_API_WEBGPU
|
|
|
|
#include "GPUTextureWebGPU.h"
|
|
#include "RenderToolsWebGPU.h"
|
|
#include "Engine/Core/Log.h"
|
|
#include "Engine/Graphics/PixelFormatExtensions.h"
|
|
|
|
void GPUTextureViewWebGPU::Create(WGPUTexture texture, WGPUTextureViewDescriptor const* desc)
|
|
{
|
|
if (View)
|
|
wgpuTextureViewRelease(View);
|
|
Texture = texture;
|
|
View = wgpuTextureCreateView(texture, desc);
|
|
if (!View)
|
|
{
|
|
#if GPU_ENABLE_RESOURCE_NAMING
|
|
LOG(Error, "Failed to create a view for texture '{}'", GetParent() ? GetParent()->GetName() : StringView::Empty);
|
|
#endif
|
|
}
|
|
}
|
|
|
|
void GPUTextureViewWebGPU::Release()
|
|
{
|
|
if (View)
|
|
{
|
|
wgpuTextureViewRelease(View);
|
|
View = nullptr;
|
|
}
|
|
Texture = nullptr;
|
|
}
|
|
|
|
bool GPUTextureWebGPU::OnInit()
|
|
{
|
|
// Create texture
|
|
WGPUTextureDescriptor textureDesc = WGPU_TEXTURE_DESCRIPTOR_INIT;
|
|
#if GPU_ENABLE_RESOURCE_NAMING
|
|
_name.Set(_namePtr, _nameSize);
|
|
textureDesc.label = { _name.Get(), (size_t)_name.Length() };
|
|
#endif
|
|
if (!IsDepthStencil())
|
|
textureDesc.usage |= WGPUTextureUsage_CopyDst;
|
|
if (IsStaging())
|
|
textureDesc.usage |= WGPUTextureUsage_CopySrc | WGPUTextureUsage_CopyDst;
|
|
if (IsShaderResource())
|
|
textureDesc.usage |= WGPUTextureUsage_TextureBinding;
|
|
if (IsUnorderedAccess())
|
|
textureDesc.usage |= WGPUTextureUsage_StorageBinding;
|
|
if (IsRenderTarget() || IsDepthStencil())
|
|
textureDesc.usage |= WGPUTextureUsage_RenderAttachment;
|
|
textureDesc.size.width = _desc.Width;
|
|
textureDesc.size.height = _desc.Height;
|
|
textureDesc.size.depthOrArrayLayers = _desc.Depth;
|
|
switch (_desc.Dimensions)
|
|
{
|
|
case TextureDimensions::Texture:
|
|
_viewDimension = IsArray() ? WGPUTextureViewDimension_2DArray : WGPUTextureViewDimension_2D;
|
|
textureDesc.dimension = WGPUTextureDimension_2D;
|
|
break;
|
|
case TextureDimensions::VolumeTexture:
|
|
_viewDimension = WGPUTextureViewDimension_3D;
|
|
textureDesc.dimension = WGPUTextureDimension_3D;
|
|
break;
|
|
case TextureDimensions::CubeTexture:
|
|
_viewDimension = IsArray() ? WGPUTextureViewDimension_CubeArray : WGPUTextureViewDimension_Cube;
|
|
textureDesc.dimension = WGPUTextureDimension_2D;
|
|
textureDesc.size.depthOrArrayLayers *= 6; // Each cubemap uses 6 array slices
|
|
break;
|
|
}
|
|
textureDesc.format = RenderToolsWebGPU::ToTextureFormat(Format());
|
|
textureDesc.mipLevelCount = _desc.MipLevels;
|
|
textureDesc.sampleCount = (uint32_t)_desc.MultiSampleLevel;
|
|
textureDesc.viewFormats = &textureDesc.format;
|
|
textureDesc.viewFormatCount = 1;
|
|
_format = textureDesc.format;
|
|
_usage = textureDesc.usage;
|
|
Texture = wgpuDeviceCreateTexture(_device->Device, &textureDesc);
|
|
if (!Texture)
|
|
return true;
|
|
|
|
// Update memory usage
|
|
_memoryUsage = calculateMemoryUsage();
|
|
|
|
// Initialize handles to the resource
|
|
if (IsRegularTexture())
|
|
{
|
|
// 'Regular' texture is using only one handle (texture/cubemap)
|
|
_handlesPerSlice.Resize(1, false);
|
|
}
|
|
else
|
|
{
|
|
// Create all handles
|
|
InitHandles();
|
|
}
|
|
|
|
// Setup metadata for the views
|
|
bool hasStencil = PixelFormatExtensions::HasStencil(Format());
|
|
if (hasStencil)
|
|
{
|
|
_handleArray.HasStencil = hasStencil;
|
|
_handleVolume.HasStencil = hasStencil;
|
|
_handleReadOnlyDepth.HasStencil = hasStencil;
|
|
_handleStencil.HasStencil = hasStencil;
|
|
for (auto& e : _handlesPerSlice)
|
|
e.HasStencil = hasStencil;
|
|
for (auto& q : _handlesPerMip)
|
|
for (auto& e : q)
|
|
e.HasStencil = hasStencil;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void GPUTextureWebGPU::OnResidentMipsChanged()
|
|
{
|
|
// Update the view to handle base mip level as highest resident mip
|
|
WGPUTextureViewDescriptor viewDesc = WGPU_TEXTURE_VIEW_DESCRIPTOR_INIT;
|
|
viewDesc.format = _format;
|
|
viewDesc.usage = _usage;
|
|
viewDesc.dimension = _viewDimension;
|
|
viewDesc.baseMipLevel = MipLevels() - ResidentMipLevels();
|
|
viewDesc.mipLevelCount = ResidentMipLevels();
|
|
viewDesc.arrayLayerCount = ArraySize();
|
|
viewDesc.aspect = WGPUTextureAspect_All;
|
|
GPUTextureViewWebGPU& view = IsVolume() ? _handleVolume : _handlesPerSlice[0];
|
|
if (view.GetParent() == nullptr)
|
|
view.Init(this, _desc.Format, _desc.MultiSampleLevel);
|
|
view.Create(Texture, &viewDesc);
|
|
}
|
|
|
|
void GPUTextureWebGPU::OnReleaseGPU()
|
|
{
|
|
_handlesPerMip.Resize(0, false);
|
|
_handlesPerSlice.Resize(0, false);
|
|
_handleArray.Release();
|
|
_handleVolume.Release();
|
|
_handleReadOnlyDepth.Release();
|
|
_handleStencil.Release();
|
|
if (Texture)
|
|
{
|
|
wgpuTextureDestroy(Texture);
|
|
wgpuTextureRelease(Texture);
|
|
Texture = nullptr;
|
|
}
|
|
#if GPU_ENABLE_RESOURCE_NAMING
|
|
_name.Clear();
|
|
#endif
|
|
|
|
// Base
|
|
GPUTexture::OnReleaseGPU();
|
|
}
|
|
|
|
void GPUTextureWebGPU::InitHandles()
|
|
{
|
|
WGPUTextureViewDescriptor viewDesc = WGPU_TEXTURE_VIEW_DESCRIPTOR_INIT;
|
|
#if GPU_ENABLE_RESOURCE_NAMING
|
|
viewDesc.label = { _name.Get(), (size_t)_name.Length() };
|
|
#endif
|
|
viewDesc.format = _format;
|
|
viewDesc.usage = _usage;
|
|
viewDesc.dimension = _viewDimension;
|
|
viewDesc.mipLevelCount = MipLevels();
|
|
viewDesc.arrayLayerCount = ArraySize();
|
|
viewDesc.aspect = WGPUTextureAspect_All;
|
|
|
|
auto format = Format();
|
|
auto msaa = MultiSampleLevel();
|
|
|
|
if (IsVolume())
|
|
{
|
|
// Create handle for whole 3d texture
|
|
{
|
|
auto& view = _handleVolume;
|
|
view.Init(this, format, msaa);
|
|
view.Create(Texture, &viewDesc);
|
|
}
|
|
|
|
// Init per slice views
|
|
_handlesPerSlice.Resize(Depth(), false);
|
|
viewDesc.dimension = WGPUTextureViewDimension_2D;
|
|
if (_desc.HasPerSliceViews() && IsRenderTarget())
|
|
{
|
|
for (int32 sliceIndex = 0; sliceIndex < Depth(); sliceIndex++)
|
|
{
|
|
auto& view = _handlesPerSlice[sliceIndex];
|
|
view.Init(this, format, msaa);
|
|
view.Create(Texture, &viewDesc);
|
|
view.DepthSlice = sliceIndex;
|
|
}
|
|
}
|
|
viewDesc.dimension = _viewDimension;
|
|
}
|
|
else if (IsArray())
|
|
{
|
|
// Create whole array handle
|
|
{
|
|
auto& view = _handleArray;
|
|
view.Init(this, format, msaa);
|
|
view.Create(Texture, &viewDesc);
|
|
}
|
|
|
|
// Create per array slice handles
|
|
_handlesPerSlice.Resize(ArraySize(), false);
|
|
viewDesc.dimension = WGPUTextureViewDimension_2D;
|
|
for (int32 arrayIndex = 0; arrayIndex < _handlesPerSlice.Count(); arrayIndex++)
|
|
{
|
|
viewDesc.baseArrayLayer = arrayIndex;
|
|
viewDesc.arrayLayerCount = 1;
|
|
auto& view = _handlesPerSlice[arrayIndex];
|
|
view.Init(this, format, msaa);
|
|
view.Create(Texture, &viewDesc);
|
|
}
|
|
viewDesc.baseArrayLayer = 0;
|
|
viewDesc.arrayLayerCount = MipLevels();
|
|
viewDesc.dimension = _viewDimension;
|
|
}
|
|
else
|
|
{
|
|
// Create single handle for the whole texture
|
|
_handlesPerSlice.Resize(1, false);
|
|
auto& view = _handlesPerSlice[0];
|
|
view.Init(this, format, msaa);
|
|
view.Create(Texture, &viewDesc);
|
|
}
|
|
|
|
// Init per mip map handles
|
|
if (HasPerMipViews())
|
|
{
|
|
// Init handles
|
|
_handlesPerMip.Resize(ArraySize(), false);
|
|
viewDesc.dimension = WGPUTextureViewDimension_2D;
|
|
for (int32 arrayIndex = 0; arrayIndex < _handlesPerMip.Count(); arrayIndex++)
|
|
{
|
|
auto& slice = _handlesPerMip[arrayIndex];
|
|
slice.Resize(MipLevels(), false);
|
|
viewDesc.baseArrayLayer = arrayIndex;
|
|
viewDesc.arrayLayerCount = 1;
|
|
viewDesc.mipLevelCount = 1;
|
|
for (int32 mipIndex = 0; mipIndex < slice.Count(); mipIndex++)
|
|
{
|
|
auto& view = slice[mipIndex];
|
|
viewDesc.baseMipLevel = mipIndex;
|
|
view.Init(this, format, msaa);
|
|
view.Create(Texture, &viewDesc);
|
|
}
|
|
}
|
|
viewDesc.dimension = _viewDimension;
|
|
}
|
|
|
|
// Read-only depth-stencil
|
|
if (EnumHasAnyFlags(_desc.Flags, GPUTextureFlags::ReadOnlyDepthView))
|
|
{
|
|
auto& view = _handleReadOnlyDepth;
|
|
view.Init(this, format, msaa);
|
|
view.Create(Texture, &viewDesc);
|
|
view.ReadOnly = true;
|
|
}
|
|
|
|
// Stencil view
|
|
if (IsDepthStencil() && IsShaderResource() && PixelFormatExtensions::HasStencil(format))
|
|
{
|
|
PixelFormat stencilFormat = format;
|
|
switch (format)
|
|
{
|
|
case PixelFormat::D24_UNorm_S8_UInt:
|
|
stencilFormat = PixelFormat::X24_Typeless_G8_UInt;
|
|
break;
|
|
case PixelFormat::D32_Float_S8X24_UInt:
|
|
stencilFormat = PixelFormat::X32_Typeless_G8X24_UInt;
|
|
break;
|
|
}
|
|
viewDesc.aspect = WGPUTextureAspect_StencilOnly;
|
|
viewDesc.format = WGPUTextureFormat_Stencil8;
|
|
_handleStencil.Init(this, stencilFormat, msaa);
|
|
_handleStencil.Create(Texture, &viewDesc);
|
|
}
|
|
}
|
|
|
|
bool GPUTextureWebGPU::GetData(int32 arrayIndex, int32 mipMapIndex, TextureMipData& data, uint32 mipRowPitch)
|
|
{
|
|
// TODO: no implemented
|
|
return true;
|
|
}
|
|
|
|
#endif
|