Fix rendering various visuals on WebGPU
This commit is contained in:
@@ -60,6 +60,8 @@ GPUContextWebGPU::GPUContextWebGPU(GPUDeviceWebGPU* device)
|
||||
|
||||
GPUContextWebGPU::~GPUContextWebGPU()
|
||||
{
|
||||
if (Encoder)
|
||||
Flush();
|
||||
CHECK(Encoder == nullptr);
|
||||
}
|
||||
|
||||
@@ -120,6 +122,10 @@ void GPUContextWebGPU::FrameEnd()
|
||||
|
||||
void GPUContextWebGPU::EventBegin(const Char* name)
|
||||
{
|
||||
// Cannot insert commands in encoder during render pass
|
||||
if (_renderPass)
|
||||
EndRenderPass();
|
||||
|
||||
StringAsANSI<> nameAnsi(name);
|
||||
wgpuCommandEncoderPushDebugGroup(Encoder, { nameAnsi.Get(), (size_t)nameAnsi.Length() });
|
||||
}
|
||||
@@ -252,17 +258,19 @@ void GPUContextWebGPU::SetStencilRef(uint32 value)
|
||||
|
||||
void GPUContextWebGPU::ResetSR()
|
||||
{
|
||||
_bindGroupDirty = true;
|
||||
Platform::MemoryClear(_shaderResources, sizeof(_shaderResources));
|
||||
}
|
||||
|
||||
void GPUContextWebGPU::ResetUA()
|
||||
{
|
||||
_bindGroupDirty = true;
|
||||
Platform::MemoryClear(_storageResources, sizeof(_storageResources));
|
||||
}
|
||||
|
||||
void GPUContextWebGPU::ResetCB()
|
||||
{
|
||||
_bindGroupDirty = false;
|
||||
_bindGroupDirty = true;
|
||||
Platform::MemoryClear(_constantBuffers, sizeof(_constantBuffers));
|
||||
}
|
||||
|
||||
@@ -425,14 +433,14 @@ void GPUContextWebGPU::EndQuery(uint64 queryID)
|
||||
void GPUContextWebGPU::SetViewport(const Viewport& viewport)
|
||||
{
|
||||
_viewport = viewport;
|
||||
if (_renderPass)
|
||||
if (_renderPass && !_renderPassDirty)
|
||||
wgpuRenderPassEncoderSetViewport(_renderPass, viewport.X, viewport.Y, viewport.Width, viewport.Height, viewport.MinDepth, viewport.MaxDepth);
|
||||
}
|
||||
|
||||
void GPUContextWebGPU::SetScissor(const Rectangle& scissorRect)
|
||||
{
|
||||
_scissorRect = scissorRect;
|
||||
if (_renderPass)
|
||||
if (_renderPass && !_renderPassDirty)
|
||||
wgpuRenderPassEncoderSetScissorRect(_renderPass, (uint32_t)scissorRect.GetX(), (uint32_t)scissorRect.GetY(), (uint32_t)scissorRect.GetWidth(), (uint32_t)scissorRect.GetHeight());
|
||||
}
|
||||
|
||||
@@ -490,6 +498,7 @@ void GPUContextWebGPU::Flush()
|
||||
WGPUCommandBufferDescriptor commandBufferDesc = WGPU_COMMAND_BUFFER_DESCRIPTOR_INIT;
|
||||
WGPUCommandBuffer commandBuffer = wgpuCommandEncoderFinish(Encoder, &commandBufferDesc);
|
||||
wgpuCommandEncoderRelease(Encoder);
|
||||
Encoder = nullptr;
|
||||
if (commandBuffer)
|
||||
{
|
||||
wgpuQueueSubmit(_device->Queue, 1, &commandBuffer);
|
||||
@@ -567,8 +576,7 @@ void GPUContextWebGPU::CopyTexture(GPUTexture* dstResource, uint32 dstSubresourc
|
||||
ASSERT(dstResource && srcResource);
|
||||
auto srcTextureWebGPU = (GPUTextureWebGPU*)srcResource;
|
||||
auto dstTextureWebGPU = (GPUTextureWebGPU*)dstResource;
|
||||
ASSERT_LOW_LAYER(dstTextureWebGPU->Texture && wgpuTextureGetUsage(dstTextureWebGPU->Texture) & WGPUTextureUsage_CopyDst);
|
||||
ASSERT_LOW_LAYER(srcTextureWebGPU->Texture && wgpuTextureGetUsage(srcTextureWebGPU->Texture) & WGPUTextureUsage_CopySrc);
|
||||
ASSERT_LOW_LAYER(dstTextureWebGPU->Texture && srcTextureWebGPU->Texture);
|
||||
|
||||
const int32 srcMipIndex = srcSubresource % srcTextureWebGPU->MipLevels();
|
||||
const int32 dstMipIndex = dstSubresource % srcTextureWebGPU->MipLevels();
|
||||
@@ -578,18 +586,45 @@ void GPUContextWebGPU::CopyTexture(GPUTexture* dstResource, uint32 dstSubresourc
|
||||
int32 srcMipWidth, srcMipHeight, srcMipDepth;
|
||||
srcTextureWebGPU->GetMipSize(srcMipIndex, srcMipWidth, srcMipHeight, srcMipDepth);
|
||||
|
||||
WGPUTexelCopyTextureInfo srcInfo = WGPU_TEXEL_COPY_TEXTURE_INFO_INIT;
|
||||
srcInfo.texture = srcTextureWebGPU->Texture;
|
||||
srcInfo.mipLevel = srcMipIndex;
|
||||
srcInfo.origin.z = srcArrayIndex;
|
||||
srcInfo.aspect = WGPUTextureAspect_All;
|
||||
WGPUTexelCopyTextureInfo dstInfo = WGPU_TEXEL_COPY_TEXTURE_INFO_INIT;
|
||||
dstInfo.texture = dstTextureWebGPU->Texture;
|
||||
dstInfo.mipLevel = dstMipIndex;
|
||||
dstInfo.origin = { dstX, dstY, dstZ + dstArrayIndex };
|
||||
dstInfo.aspect = WGPUTextureAspect_All;
|
||||
WGPUExtent3D copySize = { (uint32_t)srcMipWidth, (uint32_t)srcMipHeight, (uint32_t)srcMipDepth };
|
||||
wgpuCommandEncoderCopyTextureToTexture(Encoder, &srcInfo, &dstInfo, ©Size);
|
||||
if (dstTextureWebGPU->Usage & WGPUTextureUsage_CopyDst && srcTextureWebGPU->Usage & WGPUTextureUsage_CopySrc)
|
||||
{
|
||||
// Direct copy
|
||||
WGPUTexelCopyTextureInfo srcInfo = WGPU_TEXEL_COPY_TEXTURE_INFO_INIT;
|
||||
srcInfo.texture = srcTextureWebGPU->Texture;
|
||||
srcInfo.mipLevel = srcMipIndex;
|
||||
srcInfo.origin.z = srcArrayIndex;
|
||||
srcInfo.aspect = WGPUTextureAspect_All;
|
||||
WGPUTexelCopyTextureInfo dstInfo = WGPU_TEXEL_COPY_TEXTURE_INFO_INIT;
|
||||
dstInfo.texture = dstTextureWebGPU->Texture;
|
||||
dstInfo.mipLevel = dstMipIndex;
|
||||
dstInfo.origin = { dstX, dstY, dstZ + dstArrayIndex };
|
||||
dstInfo.aspect = WGPUTextureAspect_All;
|
||||
WGPUExtent3D copySize = { (uint32_t)srcMipWidth, (uint32_t)srcMipHeight, (uint32_t)srcMipDepth };
|
||||
wgpuCommandEncoderCopyTextureToTexture(Encoder, &srcInfo, &dstInfo, ©Size);
|
||||
}
|
||||
else if (dstTextureWebGPU->Usage & WGPUTextureUsage_RenderAttachment && srcTextureWebGPU->Usage & WGPUTextureUsage_TextureBinding)
|
||||
{
|
||||
// Copy via drawing
|
||||
ResetRenderTarget();
|
||||
SetViewportAndScissors(srcMipWidth, srcMipHeight);
|
||||
SetState(_device->GetCopyLinearPS());
|
||||
if (srcSubresource == 0 && dstSubresource == 0)
|
||||
{
|
||||
SetRenderTarget(dstTextureWebGPU->View(0));
|
||||
BindSR(0, srcTextureWebGPU->View(0));
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(dstTextureWebGPU->HasPerMipViews() && srcResource->HasPerMipViews());
|
||||
SetRenderTarget(dstTextureWebGPU->View(dstArrayIndex, dstMipIndex));
|
||||
BindSR(0, srcTextureWebGPU->View(srcArrayIndex, srcMipIndex));
|
||||
}
|
||||
DrawFullscreenTriangle();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(Fatal, "Cannot copy texture {} to {}", srcTextureWebGPU->GetDescription().ToString(), dstTextureWebGPU->GetDescription().ToString());
|
||||
}
|
||||
}
|
||||
|
||||
void GPUContextWebGPU::ResetCounter(GPUBuffer* buffer)
|
||||
@@ -615,9 +650,15 @@ void GPUContextWebGPU::CopyResource(GPUResource* dstResource, GPUResource* srcRe
|
||||
{
|
||||
// Texture -> Texture
|
||||
ASSERT(srcTexture->MipLevels() == dstTexture->MipLevels());
|
||||
ASSERT(srcTexture->ArraySize() == 1); // TODO: implement copying texture arrays
|
||||
for (int32 mipLevel = 0; mipLevel < srcTexture->MipLevels(); mipLevel++)
|
||||
CopyTexture(dstTexture, mipLevel, 0, 0, 0, srcTexture, mipLevel);
|
||||
ASSERT(srcTexture->ArraySize() == dstTexture->ArraySize());
|
||||
for (int32 arraySlice = 0; arraySlice < srcTexture->ArraySize(); arraySlice++)
|
||||
{
|
||||
for (int32 mipLevel = 0; mipLevel < srcTexture->MipLevels(); mipLevel++)
|
||||
{
|
||||
uint32 subresource = arraySlice * srcTexture->MipLevels() + mipLevel;
|
||||
CopyTexture(dstTexture, subresource, 0, 0, 0, srcTexture, subresource);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (srcTexture)
|
||||
{
|
||||
@@ -751,7 +792,7 @@ void GPUContextWebGPU::OnDrawCall()
|
||||
}
|
||||
|
||||
// Check if need to start a new render pass
|
||||
if (_renderPassDirty)
|
||||
if (_renderPassDirty || !_renderPass)
|
||||
{
|
||||
FlushRenderPass();
|
||||
}
|
||||
@@ -815,13 +856,14 @@ void GPUContextWebGPU::FlushRenderPass()
|
||||
|
||||
// Start a new render pass
|
||||
WGPURenderPassColorAttachment colorAttachments[GPU_MAX_RT_BINDED];
|
||||
WGPURenderPassDepthStencilAttachment depthStencilAttachment = WGPU_RENDER_PASS_DEPTH_STENCIL_ATTACHMENT_INIT;
|
||||
WGPURenderPassDepthStencilAttachment depthStencilAttachment;
|
||||
WGPURenderPassDescriptor renderPassDesc = WGPU_RENDER_PASS_DESCRIPTOR_INIT;
|
||||
renderPassDesc.colorAttachmentCount = _renderTargetCount;
|
||||
renderPassDesc.colorAttachments = colorAttachments;
|
||||
PendingClear clear;
|
||||
_pipelineKey.MultiSampleCount = 1;
|
||||
_pipelineKey.RenderTargetCount = _renderTargetCount;
|
||||
GPUTextureViewSizeWebGPU attachmentSize;
|
||||
for (int32 i = 0; i < renderPassDesc.colorAttachmentCount; i++)
|
||||
{
|
||||
auto& colorAttachment = colorAttachments[i];
|
||||
@@ -838,43 +880,54 @@ void GPUContextWebGPU::FlushRenderPass()
|
||||
}
|
||||
_pipelineKey.MultiSampleCount = (int32)renderTarget->GetMSAA();
|
||||
_pipelineKey.RenderTargetFormats[i] = renderTarget->Format;
|
||||
attachmentSize.Set(renderTarget->RenderSize);
|
||||
}
|
||||
if (_depthStencil)
|
||||
{
|
||||
auto renderTarget = _depthStencil;
|
||||
renderPassDesc.depthStencilAttachment = &depthStencilAttachment;
|
||||
depthStencilAttachment.view = _depthStencil->ViewRender;
|
||||
depthStencilAttachment.depthLoadOp = WGPULoadOp_Load;
|
||||
depthStencilAttachment.depthStoreOp = _depthStencil->ReadOnly ? WGPUStoreOp_Discard : WGPUStoreOp_Store;
|
||||
depthStencilAttachment.depthReadOnly = _depthStencil->ReadOnly;
|
||||
if (_depthStencil->HasStencil)
|
||||
depthStencilAttachment = WGPU_RENDER_PASS_DEPTH_STENCIL_ATTACHMENT_INIT;
|
||||
depthStencilAttachment.view = renderTarget->ViewRender;
|
||||
depthStencilAttachment.depthLoadOp = renderTarget->ReadOnly ? WGPULoadOp_Undefined : WGPULoadOp_Load;
|
||||
depthStencilAttachment.depthStoreOp = renderTarget->ReadOnly ? WGPUStoreOp_Undefined : WGPUStoreOp_Store;
|
||||
depthStencilAttachment.depthReadOnly = renderTarget->ReadOnly;
|
||||
if (renderTarget->HasStencil)
|
||||
{
|
||||
depthStencilAttachment.stencilLoadOp = WGPULoadOp_Load;
|
||||
depthStencilAttachment.stencilStoreOp = _depthStencil->ReadOnly ? WGPUStoreOp_Discard : WGPUStoreOp_Store;
|
||||
depthStencilAttachment.depthReadOnly = _depthStencil->ReadOnly;
|
||||
depthStencilAttachment.stencilLoadOp = renderTarget->ReadOnly ? WGPULoadOp_Undefined : WGPULoadOp_Load;
|
||||
depthStencilAttachment.stencilStoreOp = renderTarget->ReadOnly ? WGPUStoreOp_Undefined : WGPUStoreOp_Store;
|
||||
depthStencilAttachment.depthReadOnly = renderTarget->ReadOnly;
|
||||
depthStencilAttachment.stencilReadOnly = renderTarget->ReadOnly;
|
||||
}
|
||||
else
|
||||
{
|
||||
depthStencilAttachment.stencilClearValue = 0;
|
||||
depthStencilAttachment.stencilLoadOp = WGPULoadOp_Clear;
|
||||
depthStencilAttachment.stencilStoreOp = WGPUStoreOp_Discard;
|
||||
depthStencilAttachment.stencilLoadOp = WGPULoadOp_Undefined;
|
||||
depthStencilAttachment.stencilStoreOp = WGPUStoreOp_Undefined;
|
||||
depthStencilAttachment.stencilReadOnly = true;
|
||||
}
|
||||
if (FindClear(_depthStencil, clear))
|
||||
if (!renderTarget->ReadOnly && FindClear(renderTarget, clear))
|
||||
{
|
||||
depthStencilAttachment.depthLoadOp = WGPULoadOp_Clear;
|
||||
depthStencilAttachment.depthClearValue = clear.Depth;
|
||||
if (_depthStencil->HasStencil)
|
||||
if (renderTarget->HasStencil)
|
||||
{
|
||||
depthStencilAttachment.stencilLoadOp = WGPULoadOp_Clear;
|
||||
depthStencilAttachment.stencilClearValue = clear.Stencil;
|
||||
}
|
||||
}
|
||||
_pipelineKey.DepthStencilFormat = _depthStencil->Format;
|
||||
else
|
||||
{
|
||||
depthStencilAttachment.depthClearValue = 0.0f;
|
||||
depthStencilAttachment.stencilClearValue = 0;
|
||||
}
|
||||
_pipelineKey.DepthStencilFormat = renderTarget->Format;
|
||||
attachmentSize.Set(renderTarget->RenderSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
_pipelineKey.DepthStencilFormat = WGPUTextureFormat_Undefined;
|
||||
}
|
||||
ASSERT(attachmentSize.Packed != 0);
|
||||
_renderPass = wgpuCommandEncoderBeginRenderPass(Encoder, &renderPassDesc);
|
||||
ASSERT(_renderPass);
|
||||
|
||||
@@ -885,11 +938,11 @@ void GPUContextWebGPU::FlushRenderPass()
|
||||
if (_stencilRef != 0)
|
||||
wgpuRenderPassEncoderSetStencilReference(_renderPass, _stencilRef);
|
||||
auto scissorRect = _scissorRect;
|
||||
// TODO: skip calling this if scissorRect is default (0, 0, attachment width, attachment height)
|
||||
wgpuRenderPassEncoderSetScissorRect(_renderPass, (uint32_t)scissorRect.GetX(), (uint32_t)scissorRect.GetY(), (uint32_t)scissorRect.GetWidth(), (uint32_t)scissorRect.GetHeight());
|
||||
if (scissorRect != Rectangle(0, 0, attachmentSize.Width, attachmentSize.Height))
|
||||
wgpuRenderPassEncoderSetScissorRect(_renderPass, (uint32_t)scissorRect.GetX(), (uint32_t)scissorRect.GetY(), (uint32_t)scissorRect.GetWidth(), (uint32_t)scissorRect.GetHeight());
|
||||
auto viewport = _viewport;
|
||||
// TODO: skip calling this if viewport is default (0, 0, attachment width, attachment height, 0, 1)
|
||||
wgpuRenderPassEncoderSetViewport(_renderPass, viewport.X, viewport.Y, viewport.Width, viewport.Height, viewport.MinDepth, viewport.MaxDepth);
|
||||
if (viewport != Viewport(Float2(attachmentSize.Width, attachmentSize.Height)))
|
||||
wgpuRenderPassEncoderSetViewport(_renderPass, viewport.X, viewport.Y, viewport.Width, viewport.Height, viewport.MinDepth, viewport.MaxDepth);
|
||||
|
||||
// Auto-dirty pipeline when new render pass starts
|
||||
if (_pipelineState)
|
||||
@@ -937,6 +990,7 @@ void GPUContextWebGPU::FlushBindGroup()
|
||||
break;
|
||||
}
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
||||
case VK_DESCRIPTOR_TYPE_STORAGE_IMAGE:
|
||||
{
|
||||
ASSERT_LOW_LAYER(descriptor.BindingType == SpirvShaderResourceBindingType::SRV);
|
||||
auto view = _shaderResources[descriptor.Slot];
|
||||
@@ -952,7 +1006,19 @@ void GPUContextWebGPU::FlushBindGroup()
|
||||
LOG(Error, "Missing resource {} at slot {} of binding space {}", (int32)descriptor.ResourceType, descriptor.Slot, (int32)descriptor.BindingType);
|
||||
CRASH;
|
||||
}
|
||||
view = defaultTexture->View(0);
|
||||
switch (descriptor.ResourceType)
|
||||
{
|
||||
case SpirvShaderResourceType::Texture3D:
|
||||
view = defaultTexture->ViewVolume();
|
||||
break;
|
||||
case SpirvShaderResourceType::Texture1DArray:
|
||||
case SpirvShaderResourceType::Texture2DArray:
|
||||
view = defaultTexture->ViewArray();
|
||||
break;
|
||||
default:
|
||||
view = defaultTexture->View(0);
|
||||
break;
|
||||
}
|
||||
ptr = (GPUResourceViewPtrWebGPU*)view->GetNativePtr();
|
||||
entry.textureView = ptr->TextureView->View;
|
||||
}
|
||||
@@ -976,6 +1042,7 @@ void GPUContextWebGPU::FlushBindGroup()
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
|
||||
{
|
||||
GPUConstantBufferWebGPU* uniform = _constantBuffers[descriptor.Slot];
|
||||
@@ -983,20 +1050,10 @@ void GPUContextWebGPU::FlushBindGroup()
|
||||
{
|
||||
entry.buffer = uniform->Allocation.Buffer;
|
||||
entry.size = uniform->AllocationSize;
|
||||
_dynamicOffsets.Add(uniform->Allocation.Offset);
|
||||
}
|
||||
else
|
||||
CRASH; // TODO: add dummy buffer as fallback
|
||||
break;
|
||||
}
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
||||
{
|
||||
GPUConstantBufferWebGPU* uniform = _constantBuffers[descriptor.Slot];
|
||||
if (uniform && uniform->Allocation.Buffer)
|
||||
{
|
||||
entry.buffer = uniform->Allocation.Buffer;
|
||||
entry.offset = uniform->Allocation.Offset;
|
||||
entry.size = uniform->AllocationSize;
|
||||
if (descriptor.DescriptorType == VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER)
|
||||
entry.offset = uniform->Allocation.Offset;
|
||||
else
|
||||
_dynamicOffsets.Add(uniform->Allocation.Offset);
|
||||
}
|
||||
else
|
||||
CRASH; // TODO: add dummy buffer as fallback
|
||||
@@ -1015,9 +1072,21 @@ void GPUContextWebGPU::FlushBindGroup()
|
||||
// Create a bind group
|
||||
bindGroupDesc.entryCount = _bindGroupEntries.Count();
|
||||
bindGroupDesc.entries = entriesPtr;
|
||||
#if BUILD_DEBUG
|
||||
for (int32 i = 0; i < bindGroupDesc.entryCount; i++)
|
||||
{
|
||||
auto& e = bindGroupDesc.entries[i];
|
||||
if ((e.buffer != nullptr) + (e.sampler != nullptr) + (e.textureView != nullptr) != 1)
|
||||
{
|
||||
LOG(Error, "Invalid binding in group {} at index {} ({})", groupIndex, i, _pipelineState->GetName());
|
||||
LOG(Error, " > sampler: {}", (uint32)e.sampler);
|
||||
LOG(Error, " > textureView: {}", (uint32)e.textureView);
|
||||
LOG(Error, " > buffer: {}", (uint32)e.buffer);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
WGPUBindGroup bindGroup = wgpuDeviceCreateBindGroup(_device->Device, &bindGroupDesc);
|
||||
_unusedBindGroups.Add(bindGroup);
|
||||
// TODO: cache and release them
|
||||
|
||||
// Bind group
|
||||
wgpuRenderPassEncoderSetBindGroup(_renderPass, groupIndex, bindGroup, _dynamicOffsets.Count(), _dynamicOffsets.Get());
|
||||
|
||||
@@ -28,22 +28,6 @@ GPUVertexLayoutWebGPU::GPUVertexLayoutWebGPU(GPUDeviceWebGPU* device, const Elem
|
||||
: GPUResourceBase<GPUDeviceWebGPU, GPUVertexLayout>(device, StringView::Empty)
|
||||
{
|
||||
SetElements(elements, explicitOffsets);
|
||||
Layout = WGPU_VERTEX_BUFFER_LAYOUT_INIT;
|
||||
Layout.stepMode = WGPUVertexStepMode_Vertex;
|
||||
Layout.arrayStride = GetStride();
|
||||
Layout.attributeCount = elements.Count();
|
||||
Layout.attributes = Attributes;
|
||||
const VertexElement* srcElements = GetElements().Get();
|
||||
for (int32 i = 0; i < elements.Count(); i++)
|
||||
{
|
||||
const VertexElement& src = srcElements[i];
|
||||
WGPUVertexAttribute& dst = Attributes[i];
|
||||
dst.nextInChain = nullptr;
|
||||
dst.format = RenderToolsWebGPU::ToVertexFormat(src.Format);
|
||||
dst.offset = src.Offset;
|
||||
if (src.PerInstance)
|
||||
Layout.stepMode = WGPUVertexStepMode_Instance;
|
||||
}
|
||||
}
|
||||
|
||||
GPUDataUploaderWebGPU::Allocation GPUDataUploaderWebGPU::Allocate(uint32 size, WGPUBufferUsage usage, uint32 alignment)
|
||||
@@ -183,6 +167,7 @@ bool GPUDeviceWebGPU::Init()
|
||||
if (wgpuAdapterGetLimits(Adapter->Adapter, &limits) == WGPUStatus_Success)
|
||||
{
|
||||
MinUniformBufferOffsetAlignment = limits.minUniformBufferOffsetAlignment;
|
||||
Limits.HasDrawIndirect = true;
|
||||
Limits.HasDepthAsSRV = true;
|
||||
Limits.HasReadOnlyDepth = true;
|
||||
Limits.HasDepthClip = features.Contains(WGPUFeatureName_DepthClipControl);
|
||||
@@ -431,6 +416,9 @@ bool GPUDeviceWebGPU::Init()
|
||||
{
|
||||
LOG(Info, "WebGPU: {}", WEBGPU_TO_STR(message));
|
||||
}
|
||||
static int32 LogSpamLeft = 20;
|
||||
if (LogSpamLeft-- < 0)
|
||||
CRASH; // Too many errors
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Graphics/PixelFormatExtensions.h"
|
||||
|
||||
#define WEBGPU_LOG_PSO 0
|
||||
|
||||
WGPUCompareFunction ToCompareFunction(ComparisonFunc value)
|
||||
{
|
||||
switch (value)
|
||||
@@ -158,10 +160,9 @@ void GPUPipelineStateWebGPU::OnReleaseGPU()
|
||||
|
||||
uint32 GetHash(const GPUPipelineStateWebGPU::Key& key)
|
||||
{
|
||||
static_assert(sizeof(GPUPipelineStateWebGPU::Key) == sizeof(uint64) * 3, "Invalid PSO key size.");
|
||||
static_assert(sizeof(GPUPipelineStateWebGPU::Key) == sizeof(uint64) * 2, "Invalid PSO key size.");
|
||||
uint32 hash = GetHash(key.Packed[0]);
|
||||
CombineHash(hash, GetHash(key.Packed[1]));
|
||||
CombineHash(hash, GetHash(key.Packed[2]));
|
||||
return hash;
|
||||
}
|
||||
|
||||
@@ -175,6 +176,9 @@ WGPURenderPipeline GPUPipelineStateWebGPU::GetPipeline(const Key& key, GPUResour
|
||||
#if GPU_ENABLE_RESOURCE_NAMING
|
||||
ZoneText(_debugName.Get(), _debugName.Count() - 1);
|
||||
#endif
|
||||
#if WEBGPU_LOG_PSO
|
||||
LOG(Info, "[WebGPU] GetPipeline: '{}'", String(_debugName.Get(), _debugName.Count() - 1));
|
||||
#endif
|
||||
|
||||
// Lazy-init layout (cannot do it during Init as texture samplers that access eg. depth need to explicitly use UnfilterableFloat)
|
||||
if (!PipelineDesc.layout)
|
||||
@@ -182,10 +186,14 @@ WGPURenderPipeline GPUPipelineStateWebGPU::GetPipeline(const Key& key, GPUResour
|
||||
|
||||
// Build final pipeline description
|
||||
_depthStencilDesc.format = (WGPUTextureFormat)key.DepthStencilFormat;
|
||||
PipelineDesc.depthStencil = key.DepthStencilFormat ? &_depthStencilDesc : nullptr; // Unbind depth stencil state when no debug buffer is bound
|
||||
PipelineDesc.multisample.count = key.MultiSampleCount;
|
||||
_fragmentDesc.targetCount = key.RenderTargetCount;
|
||||
for (int32 i = 0; i < _fragmentDesc.targetCount; i++)
|
||||
_colorTargets[i].format = (WGPUTextureFormat)key.RenderTargetFormats[i];
|
||||
if (PS)
|
||||
{
|
||||
_fragmentDesc.targetCount = key.RenderTargetCount;
|
||||
for (int32 i = 0; i < _fragmentDesc.targetCount; i++)
|
||||
_colorTargets[i].format = (WGPUTextureFormat)key.RenderTargetFormats[i];
|
||||
}
|
||||
WGPUVertexBufferLayout buffers[GPU_MAX_VB_BINDED];
|
||||
if (key.VertexLayout)
|
||||
{
|
||||
@@ -253,6 +261,10 @@ WGPURenderPipeline GPUPipelineStateWebGPU::GetPipeline(const Key& key, GPUResour
|
||||
|
||||
void GPUPipelineStateWebGPU::InitLayout(GPUResourceView* shaderResources[GPU_MAX_SR_BINDED])
|
||||
{
|
||||
#if WEBGPU_LOG_PSO
|
||||
// Debug log for PSOs with specific name
|
||||
const bool log = true;// StringAnsiView(_debugName.Get(), _debugName.Count() - 1).Contains("PS_HalfDepth");
|
||||
#endif
|
||||
|
||||
// Count the biggest bind group entries (for all shaders) to allocate reused memory
|
||||
int32 maxEntriesCount = 0;
|
||||
@@ -276,6 +288,11 @@ void GPUPipelineStateWebGPU::InitLayout(GPUResourceView* shaderResources[GPU_MAX
|
||||
int32 entriesCount = descriptors->DescriptorTypesCount;
|
||||
Platform::MemoryClear(entries.Get(), sizeof(WGPUBindGroupLayoutEntry) * entriesCount);
|
||||
auto visibility = groupIndex == 0 ? WGPUShaderStage_Vertex : WGPUShaderStage_Fragment;
|
||||
#if WEBGPU_LOG_PSO
|
||||
if (log)
|
||||
LOG(Info, " > group {} - {}", groupIndex, groupIndex == 0 ? TEXT("Vertex") : TEXT("Fragment"));
|
||||
const Char* samplerType = TEXT("?");
|
||||
#endif
|
||||
for (int32 index = 0; index < entriesCount; index++)
|
||||
{
|
||||
auto& descriptor = descriptors->DescriptorTypes[index];
|
||||
@@ -287,16 +304,87 @@ void GPUPipelineStateWebGPU::InitLayout(GPUResourceView* shaderResources[GPU_MAX
|
||||
{
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLER:
|
||||
entry.sampler.type = WGPUSamplerBindingType_Undefined;
|
||||
if (descriptor.Slot == 4 || descriptor.Slot == 5) // Hack for ShadowSampler and ShadowSamplerLinear (this could get binded samplers table just like for shaderResources)
|
||||
entry.sampler.type = WGPUSamplerBindingType_Comparison;
|
||||
#if WEBGPU_LOG_PSO
|
||||
switch (entry.sampler.type)
|
||||
{
|
||||
case WGPUSamplerBindingType_BindingNotUsed:
|
||||
samplerType = TEXT("BindingNotUsed");
|
||||
break;
|
||||
case WGPUSamplerBindingType_Undefined:
|
||||
samplerType = TEXT("Undefined");
|
||||
break;
|
||||
case WGPUSamplerBindingType_Filtering:
|
||||
samplerType = TEXT("Filtering");
|
||||
break;
|
||||
case WGPUSamplerBindingType_NonFiltering:
|
||||
samplerType = TEXT("NonFiltering");
|
||||
break;
|
||||
case WGPUSamplerBindingType_Comparison:
|
||||
samplerType = TEXT("Comparison");
|
||||
break;
|
||||
}
|
||||
if (log)
|
||||
LOG(Info, " > [{}] sampler ({})", entry.binding, samplerType);
|
||||
#endif
|
||||
break;
|
||||
case VK_DESCRIPTOR_TYPE_SAMPLED_IMAGE:
|
||||
entry.texture.sampleType = WGPUTextureSampleType_Undefined;
|
||||
if (shaderResources[descriptor.Slot])
|
||||
{
|
||||
// Hack to use the sample type directly from the view which allows to fix incorrect Depth Buffer reading that allows only manual Load when UnfilterableFloat is used (see SAMPLE_RT_LOAD)
|
||||
// Hack to use the sample type directly from the view which allows to fix incorrect Depth Buffer reading that allows only manual Load when UnfilterableFloat is used (see SAMPLE_RT_DEPTH)
|
||||
auto ptr = (GPUResourceViewPtrWebGPU*)shaderResources[descriptor.Slot]->GetNativePtr();
|
||||
if (ptr && ptr->TextureView)
|
||||
entry.texture.sampleType = ptr->TextureView->SampleType;
|
||||
}
|
||||
#if WEBGPU_LOG_PSO
|
||||
if (log)
|
||||
{
|
||||
switch (entry.texture.sampleType)
|
||||
{
|
||||
case WGPUTextureSampleType_BindingNotUsed:
|
||||
samplerType = TEXT("BindingNotUsed");
|
||||
break;
|
||||
case WGPUTextureSampleType_Undefined:
|
||||
samplerType = TEXT("Undefined");
|
||||
break;
|
||||
case WGPUTextureSampleType_Float:
|
||||
samplerType = TEXT("Float");
|
||||
break;
|
||||
case WGPUTextureSampleType_UnfilterableFloat:
|
||||
samplerType = TEXT("UnfilterableFloat");
|
||||
break;
|
||||
case WGPUTextureSampleType_Depth:
|
||||
samplerType = TEXT("Depth");
|
||||
break;
|
||||
case WGPUTextureSampleType_Sint:
|
||||
samplerType = TEXT("Sint");
|
||||
break;
|
||||
case WGPUTextureSampleType_Uint:
|
||||
samplerType = TEXT("Uint");
|
||||
break;
|
||||
}
|
||||
switch (descriptor.ResourceType)
|
||||
{
|
||||
case SpirvShaderResourceType::Texture1D:
|
||||
LOG(Info, " > [{}] texture 1D ({})", entry.binding, samplerType);
|
||||
break;
|
||||
case SpirvShaderResourceType::Texture2D:
|
||||
LOG(Info, " > [{}] texture 2D ({})", entry.binding, samplerType);
|
||||
break;
|
||||
case SpirvShaderResourceType::Texture3D:
|
||||
LOG(Info, " > [{}] texture 3D ({})", entry.binding, samplerType);
|
||||
break;
|
||||
case SpirvShaderResourceType::TextureCube:
|
||||
LOG(Info, " > [{}] texture Cube ({})", entry.binding, samplerType);
|
||||
break;
|
||||
case SpirvShaderResourceType::Texture2DArray:
|
||||
LOG(Info, " > [{}] texture 2D array ({})", entry.binding, samplerType);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
switch (descriptor.ResourceType)
|
||||
{
|
||||
case SpirvShaderResourceType::Texture1D:
|
||||
@@ -326,11 +414,19 @@ void GPUPipelineStateWebGPU::InitLayout(GPUResourceView* shaderResources[GPU_MAX
|
||||
entry.buffer.type = WGPUBufferBindingType_ReadOnlyStorage;
|
||||
else
|
||||
entry.buffer.type = WGPUBufferBindingType_Storage;
|
||||
#if WEBGPU_LOG_PSO
|
||||
if (log)
|
||||
LOG(Info, " > [{}] storage buffer (read-only = {}, dynamic = {})", entry.binding, entry.buffer.type == WGPUBufferBindingType_ReadOnlyStorage, entry.buffer.hasDynamicOffset);
|
||||
#endif
|
||||
break;
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC:
|
||||
entry.buffer.hasDynamicOffset = true;
|
||||
case VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER:
|
||||
entry.buffer.type = WGPUBufferBindingType_Uniform;
|
||||
#if WEBGPU_LOG_PSO
|
||||
if (log)
|
||||
LOG(Info, " > [{}] uniform buffer (dynamic = {})", entry.binding, entry.buffer.hasDynamicOffset);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
#if GPU_ENABLE_DIAGNOSTICS
|
||||
@@ -414,33 +510,33 @@ bool GPUPipelineStateWebGPU::Init(const Description& desc)
|
||||
}
|
||||
}
|
||||
PipelineDesc.multisample.alphaToCoverageEnabled = desc.BlendMode.AlphaToCoverageEnable;
|
||||
PipelineDesc.fragment = &_fragmentDesc;
|
||||
_fragmentDesc = WGPU_FRAGMENT_STATE_INIT;
|
||||
_fragmentDesc.targets = _colorTargets;
|
||||
Platform::MemoryClear(&_colorTargets, sizeof(_colorTargets));
|
||||
if (desc.BlendMode.BlendEnable)
|
||||
{
|
||||
_blendState = WGPU_BLEND_STATE_INIT;
|
||||
_blendState.color = ToBlendComponent(desc.BlendMode.BlendOp, desc.BlendMode.SrcBlend, desc.BlendMode.DestBlend);
|
||||
_blendState.alpha = ToBlendComponent(desc.BlendMode.BlendOpAlpha, desc.BlendMode.SrcBlendAlpha, desc.BlendMode.DestBlendAlpha);
|
||||
for (auto& e : _colorTargets)
|
||||
e.blend = &_blendState;
|
||||
}
|
||||
WGPUColorWriteMask writeMask = WGPUColorWriteMask_All;
|
||||
if (desc.BlendMode.RenderTargetWriteMask != BlendingMode::ColorWrite::All)
|
||||
{
|
||||
writeMask = 0;
|
||||
if (EnumHasAllFlags(desc.BlendMode.RenderTargetWriteMask, BlendingMode::ColorWrite::Red))
|
||||
writeMask |= WGPUColorWriteMask_Red;
|
||||
if (EnumHasAllFlags(desc.BlendMode.RenderTargetWriteMask, BlendingMode::ColorWrite::Green))
|
||||
writeMask |= WGPUColorWriteMask_Green;
|
||||
if (EnumHasAllFlags(desc.BlendMode.RenderTargetWriteMask, BlendingMode::ColorWrite::Blue))
|
||||
writeMask |= WGPUColorWriteMask_Blue;
|
||||
if (EnumHasAllFlags(desc.BlendMode.RenderTargetWriteMask, BlendingMode::ColorWrite::Alpha))
|
||||
writeMask |= WGPUColorWriteMask_Alpha;
|
||||
}
|
||||
if (desc.PS)
|
||||
{
|
||||
PipelineDesc.fragment = &_fragmentDesc;
|
||||
_fragmentDesc = WGPU_FRAGMENT_STATE_INIT;
|
||||
_fragmentDesc.targets = _colorTargets;
|
||||
Platform::MemoryClear(&_colorTargets, sizeof(_colorTargets));
|
||||
if (desc.BlendMode.BlendEnable)
|
||||
{
|
||||
_blendState = WGPU_BLEND_STATE_INIT;
|
||||
_blendState.color = ToBlendComponent(desc.BlendMode.BlendOp, desc.BlendMode.SrcBlend, desc.BlendMode.DestBlend);
|
||||
_blendState.alpha = ToBlendComponent(desc.BlendMode.BlendOpAlpha, desc.BlendMode.SrcBlendAlpha, desc.BlendMode.DestBlendAlpha);
|
||||
for (auto& e : _colorTargets)
|
||||
e.blend = &_blendState;
|
||||
}
|
||||
WGPUColorWriteMask writeMask = WGPUColorWriteMask_All;
|
||||
if (desc.BlendMode.RenderTargetWriteMask != BlendingMode::ColorWrite::All)
|
||||
{
|
||||
writeMask = 0;
|
||||
if (EnumHasAllFlags(desc.BlendMode.RenderTargetWriteMask, BlendingMode::ColorWrite::Red))
|
||||
writeMask |= WGPUColorWriteMask_Red;
|
||||
if (EnumHasAllFlags(desc.BlendMode.RenderTargetWriteMask, BlendingMode::ColorWrite::Green))
|
||||
writeMask |= WGPUColorWriteMask_Green;
|
||||
if (EnumHasAllFlags(desc.BlendMode.RenderTargetWriteMask, BlendingMode::ColorWrite::Blue))
|
||||
writeMask |= WGPUColorWriteMask_Blue;
|
||||
if (EnumHasAllFlags(desc.BlendMode.RenderTargetWriteMask, BlendingMode::ColorWrite::Alpha))
|
||||
writeMask |= WGPUColorWriteMask_Alpha;
|
||||
}
|
||||
uint16 outputsCount = desc.PS->GetBindings().OutputsCount;
|
||||
for (uint16 rtIndex = 0; rtIndex < outputsCount; rtIndex++)
|
||||
_colorTargets[rtIndex].writeMask = writeMask;
|
||||
|
||||
@@ -28,7 +28,7 @@ public:
|
||||
uint8 RenderTargetFormats[GPU_MAX_RT_BINDED];
|
||||
class GPUVertexLayoutWebGPU* VertexLayout;
|
||||
};
|
||||
uint64 Packed[3];
|
||||
uint64 Packed[2];
|
||||
};
|
||||
|
||||
FORCE_INLINE bool operator==(const Key& other) const
|
||||
|
||||
@@ -41,19 +41,19 @@ bool GPUSamplerWebGPU::OnInit()
|
||||
switch (_desc.Filter)
|
||||
{
|
||||
case GPUSamplerFilter::Point:
|
||||
samplerDesc.magFilter = samplerDesc.magFilter = WGPUFilterMode_Nearest;
|
||||
samplerDesc.magFilter = samplerDesc.minFilter = WGPUFilterMode_Nearest;
|
||||
samplerDesc.mipmapFilter = WGPUMipmapFilterMode_Nearest;
|
||||
break;
|
||||
case GPUSamplerFilter::Bilinear:
|
||||
samplerDesc.magFilter = samplerDesc.magFilter = WGPUFilterMode_Linear;
|
||||
samplerDesc.magFilter = samplerDesc.minFilter = WGPUFilterMode_Linear;
|
||||
samplerDesc.mipmapFilter = WGPUMipmapFilterMode_Nearest;
|
||||
break;
|
||||
case GPUSamplerFilter::Trilinear:
|
||||
samplerDesc.magFilter = samplerDesc.magFilter = WGPUFilterMode_Linear;
|
||||
samplerDesc.magFilter = samplerDesc.minFilter = WGPUFilterMode_Linear;
|
||||
samplerDesc.mipmapFilter = WGPUMipmapFilterMode_Linear;
|
||||
break;
|
||||
case GPUSamplerFilter::Anisotropic:
|
||||
samplerDesc.magFilter = samplerDesc.magFilter = WGPUFilterMode_Linear;
|
||||
samplerDesc.magFilter = samplerDesc.minFilter = WGPUFilterMode_Linear;
|
||||
samplerDesc.mipmapFilter = WGPUMipmapFilterMode_Linear;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ GPUTextureView* GPUSwapChainWebGPU::GetBackBufferView()
|
||||
viewDesc.arrayLayerCount = 1;
|
||||
viewDesc.aspect = WGPUTextureAspect_All;
|
||||
viewDesc.usage = wgpuTextureGetUsage(surfaceTexture.texture);
|
||||
_surfaceView.Create(surfaceTexture.texture, &viewDesc);
|
||||
_surfaceView.Create(surfaceTexture.texture, viewDesc);
|
||||
}
|
||||
return &_surfaceView;
|
||||
}
|
||||
|
||||
@@ -32,12 +32,38 @@ WGPUTextureFormat DropStencil(WGPUTextureFormat format)
|
||||
}
|
||||
}
|
||||
|
||||
void GPUTextureViewWebGPU::Create(WGPUTexture texture, WGPUTextureViewDescriptor const* desc)
|
||||
void SetWebGPUTextureViewSampler(GPUTextureView* view, uint32 samplerType)
|
||||
{
|
||||
((GPUTextureViewWebGPU*)view)->SampleType = (WGPUTextureSampleType)samplerType;
|
||||
}
|
||||
|
||||
void GPUTextureViewWebGPU::Create(WGPUTexture texture, const WGPUTextureViewDescriptor& desc)
|
||||
{
|
||||
if (View)
|
||||
wgpuTextureViewRelease(View);
|
||||
Texture = texture;
|
||||
View = wgpuTextureCreateView(texture, desc);
|
||||
|
||||
auto viewDesc = desc;
|
||||
auto renderDesc = desc;
|
||||
auto separateViews = false;
|
||||
|
||||
// Render views cannot have more than 1 mip levels count
|
||||
if (desc.usage & WGPUTextureUsage_RenderAttachment && renderDesc.mipLevelCount > 1)
|
||||
{
|
||||
renderDesc.mipLevelCount = 1;
|
||||
separateViews = true;
|
||||
}
|
||||
|
||||
// Depth-stencil textures expose depth-only when binding to shaders (unless via custom _handleStencil view) so make separate ViewRender for rendering with all components
|
||||
if (desc.aspect == WGPUTextureAspect_All && ::HasStencil(desc.format))
|
||||
{
|
||||
viewDesc.aspect = WGPUTextureAspect_DepthOnly;
|
||||
viewDesc.format = DropStencil(viewDesc.format);
|
||||
separateViews = true;
|
||||
}
|
||||
|
||||
// Create views
|
||||
View = wgpuTextureCreateView(texture, &viewDesc);
|
||||
if (!View)
|
||||
{
|
||||
#if GPU_ENABLE_RESOURCE_NAMING
|
||||
@@ -46,18 +72,13 @@ void GPUTextureViewWebGPU::Create(WGPUTexture texture, WGPUTextureViewDescriptor
|
||||
LOG(Error, "Failed to create a view for texture");
|
||||
#endif
|
||||
}
|
||||
ViewRender = View;
|
||||
if (separateViews)
|
||||
ViewRender = wgpuTextureCreateView(texture, &renderDesc);
|
||||
else
|
||||
ViewRender = View;
|
||||
|
||||
// Depth-stencil textures expose depth-only when binding to shaders (unless via custom _handleStencil view) so make separate ViewRender for rendering with all components
|
||||
if (desc && desc->aspect == WGPUTextureAspect_All && ::HasStencil(desc->format))
|
||||
{
|
||||
auto depthOnlyDesc = *desc;
|
||||
depthOnlyDesc.aspect = WGPUTextureAspect_DepthOnly;
|
||||
depthOnlyDesc.format = DropStencil(depthOnlyDesc.format);
|
||||
View = wgpuTextureCreateView(texture, &depthOnlyDesc);
|
||||
}
|
||||
|
||||
Format = desc ? desc->format : wgpuTextureGetFormat(texture);
|
||||
// Cache metadata
|
||||
Format = desc.format;
|
||||
switch (Format)
|
||||
{
|
||||
case WGPUTextureFormat_Depth16Unorm:
|
||||
@@ -76,6 +97,8 @@ void GPUTextureViewWebGPU::Create(WGPUTexture texture, WGPUTextureViewDescriptor
|
||||
SampleType = WGPUTextureSampleType_Undefined;
|
||||
break;
|
||||
}
|
||||
RenderSize.Width = Math::Max<uint16>(wgpuTextureGetWidth(Texture) >> renderDesc.baseMipLevel, 1);
|
||||
RenderSize.Height = Math::Max<uint16>(wgpuTextureGetHeight(Texture) >> renderDesc.baseMipLevel, 1);
|
||||
}
|
||||
|
||||
void GPUTextureViewWebGPU::Release()
|
||||
@@ -113,21 +136,22 @@ bool GPUTextureWebGPU::OnInit()
|
||||
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;
|
||||
textureDesc.size.depthOrArrayLayers = _desc.ArraySize;
|
||||
break;
|
||||
case TextureDimensions::VolumeTexture:
|
||||
_viewDimension = WGPUTextureViewDimension_3D;
|
||||
textureDesc.dimension = WGPUTextureDimension_3D;
|
||||
textureDesc.size.depthOrArrayLayers = _desc.Depth;
|
||||
break;
|
||||
case TextureDimensions::CubeTexture:
|
||||
_viewDimension = _desc.ArraySize > 6 ? WGPUTextureViewDimension_CubeArray : WGPUTextureViewDimension_Cube;
|
||||
textureDesc.dimension = WGPUTextureDimension_2D;
|
||||
textureDesc.size.depthOrArrayLayers *= 6; // Each cubemap uses 6 array slices
|
||||
textureDesc.size.depthOrArrayLayers = _desc.ArraySize;
|
||||
break;
|
||||
}
|
||||
textureDesc.format = RenderToolsWebGPU::ToTextureFormat(Format());
|
||||
@@ -136,7 +160,7 @@ bool GPUTextureWebGPU::OnInit()
|
||||
textureDesc.viewFormats = &textureDesc.format;
|
||||
textureDesc.viewFormatCount = 1;
|
||||
_format = textureDesc.format;
|
||||
_usage = textureDesc.usage;
|
||||
Usage = textureDesc.usage;
|
||||
Texture = wgpuDeviceCreateTexture(_device->Device, &textureDesc);
|
||||
if (!Texture)
|
||||
return true;
|
||||
@@ -179,7 +203,7 @@ 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.usage = Usage;
|
||||
viewDesc.dimension = _viewDimension;
|
||||
viewDesc.baseMipLevel = MipLevels() - ResidentMipLevels();
|
||||
viewDesc.mipLevelCount = ResidentMipLevels();
|
||||
@@ -188,7 +212,7 @@ void GPUTextureWebGPU::OnResidentMipsChanged()
|
||||
GPUTextureViewWebGPU& view = IsVolume() ? _handleVolume : _handlesPerSlice[0];
|
||||
if (view.GetParent() == nullptr)
|
||||
view.Init(this, _desc.Format, _desc.MultiSampleLevel);
|
||||
view.Create(Texture, &viewDesc);
|
||||
view.Create(Texture, viewDesc);
|
||||
}
|
||||
|
||||
void GPUTextureWebGPU::OnReleaseGPU()
|
||||
@@ -220,7 +244,7 @@ void GPUTextureWebGPU::InitHandles()
|
||||
viewDesc.label = { _name.Get(), (size_t)_name.Length() };
|
||||
#endif
|
||||
viewDesc.format = _format;
|
||||
viewDesc.usage = _usage;
|
||||
viewDesc.usage = Usage;
|
||||
viewDesc.dimension = _viewDimension;
|
||||
viewDesc.mipLevelCount = MipLevels();
|
||||
viewDesc.arrayLayerCount = ArraySize();
|
||||
@@ -235,7 +259,7 @@ void GPUTextureWebGPU::InitHandles()
|
||||
{
|
||||
auto& view = _handleVolume;
|
||||
view.Init(this, format, msaa);
|
||||
view.Create(Texture, &viewDesc);
|
||||
view.Create(Texture, viewDesc);
|
||||
}
|
||||
|
||||
// Init per slice views
|
||||
@@ -249,7 +273,7 @@ void GPUTextureWebGPU::InitHandles()
|
||||
//viewDesc.arrayLayerCount = 1;
|
||||
auto& view = _handlesPerSlice[sliceIndex];
|
||||
view.Init(this, format, msaa);
|
||||
view.Create(Texture, &viewDesc);
|
||||
view.Create(Texture, viewDesc);
|
||||
view.DepthSlice = sliceIndex;
|
||||
}
|
||||
}
|
||||
@@ -263,7 +287,7 @@ void GPUTextureWebGPU::InitHandles()
|
||||
{
|
||||
auto& view = _handleArray;
|
||||
view.Init(this, format, msaa);
|
||||
view.Create(Texture, &viewDesc);
|
||||
view.Create(Texture, viewDesc);
|
||||
}
|
||||
|
||||
// Create per array slice handles
|
||||
@@ -275,7 +299,7 @@ void GPUTextureWebGPU::InitHandles()
|
||||
viewDesc.arrayLayerCount = 1;
|
||||
auto& view = _handlesPerSlice[arrayIndex];
|
||||
view.Init(this, format, msaa);
|
||||
view.Create(Texture, &viewDesc);
|
||||
view.Create(Texture, viewDesc);
|
||||
}
|
||||
viewDesc.baseArrayLayer = 0;
|
||||
viewDesc.arrayLayerCount = MipLevels();
|
||||
@@ -287,7 +311,7 @@ void GPUTextureWebGPU::InitHandles()
|
||||
_handlesPerSlice.Resize(1, false);
|
||||
auto& view = _handlesPerSlice[0];
|
||||
view.Init(this, format, msaa);
|
||||
view.Create(Texture, &viewDesc);
|
||||
view.Create(Texture, viewDesc);
|
||||
}
|
||||
|
||||
// Init per mip map handles
|
||||
@@ -308,7 +332,7 @@ void GPUTextureWebGPU::InitHandles()
|
||||
auto& view = slice[mipIndex];
|
||||
viewDesc.baseMipLevel = mipIndex;
|
||||
view.Init(this, format, msaa);
|
||||
view.Create(Texture, &viewDesc);
|
||||
view.Create(Texture, viewDesc);
|
||||
}
|
||||
}
|
||||
viewDesc.dimension = _viewDimension;
|
||||
@@ -319,7 +343,7 @@ void GPUTextureWebGPU::InitHandles()
|
||||
{
|
||||
auto& view = _handleReadOnlyDepth;
|
||||
view.Init(this, format, msaa);
|
||||
view.Create(Texture, &viewDesc);
|
||||
view.Create(Texture, viewDesc);
|
||||
view.ReadOnly = true;
|
||||
}
|
||||
|
||||
@@ -339,7 +363,7 @@ void GPUTextureWebGPU::InitHandles()
|
||||
viewDesc.aspect = WGPUTextureAspect_StencilOnly;
|
||||
viewDesc.format = WGPUTextureFormat_Stencil8;
|
||||
_handleStencil.Init(this, stencilFormat, msaa);
|
||||
_handleStencil.Create(Texture, &viewDesc);
|
||||
_handleStencil.Create(Texture, viewDesc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,28 @@
|
||||
|
||||
#if GRAPHICS_API_WEBGPU
|
||||
|
||||
struct GPUTextureViewSizeWebGPU
|
||||
{
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint16 Width, Height;
|
||||
};
|
||||
uint32 Packed = 0;
|
||||
};
|
||||
|
||||
FORCE_INLINE void Set(GPUTextureViewSizeWebGPU other)
|
||||
{
|
||||
if (Packed == 0)
|
||||
Packed = other.Packed;
|
||||
else
|
||||
{
|
||||
ASSERT(Packed == other.Packed);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// The texture view for Web GPU backend.
|
||||
/// </summary>
|
||||
@@ -36,13 +58,14 @@ public:
|
||||
bool HasStencil = false;
|
||||
bool ReadOnly = false;
|
||||
uint32 DepthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
|
||||
GPUTextureViewSizeWebGPU RenderSize;
|
||||
WGPUTextureFormat Format = WGPUTextureFormat_Undefined;
|
||||
WGPUTextureSampleType SampleType = WGPUTextureSampleType_Undefined;
|
||||
GPUResourceViewPtrWebGPU Ptr;
|
||||
|
||||
public:
|
||||
using GPUTextureView::Init;
|
||||
void Create(WGPUTexture texture, WGPUTextureViewDescriptor const* desc = nullptr);
|
||||
void Create(WGPUTexture texture, const WGPUTextureViewDescriptor& desc);
|
||||
void Release();
|
||||
|
||||
public:
|
||||
@@ -70,7 +93,6 @@ private:
|
||||
#endif
|
||||
WGPUTextureFormat _format = WGPUTextureFormat_Undefined;
|
||||
WGPUTextureViewDimension _viewDimension = WGPUTextureViewDimension_Undefined;
|
||||
WGPUTextureUsage _usage = 0;
|
||||
|
||||
public:
|
||||
GPUTextureWebGPU(GPUDeviceWebGPU* device, const StringView& name)
|
||||
@@ -81,6 +103,8 @@ public:
|
||||
public:
|
||||
// Handle to the WebGPU texture object.
|
||||
WGPUTexture Texture = nullptr;
|
||||
// Usage flags fo the created texture.
|
||||
WGPUTextureUsage Usage = 0;
|
||||
|
||||
public:
|
||||
// [GPUTexture]
|
||||
|
||||
@@ -14,10 +14,6 @@ class GPUVertexLayoutWebGPU : public GPUResourceBase<GPUDeviceWebGPU, GPUVertexL
|
||||
{
|
||||
public:
|
||||
GPUVertexLayoutWebGPU(GPUDeviceWebGPU* device, const Elements& elements, bool explicitOffsets);
|
||||
|
||||
public:
|
||||
WGPUVertexBufferLayout Layout;
|
||||
WGPUVertexAttribute Attributes[GPU_MAX_VS_ELEMENTS];
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user