Add initial base implementation for WebGPU rendering backend
This commit is contained in:
179
Source/Engine/GraphicsDevice/WebGPU/GPUSwapChainWebGPU.cpp
Normal file
179
Source/Engine/GraphicsDevice/WebGPU/GPUSwapChainWebGPU.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
// Copyright (c) Wojciech Figat. All rights reserved.
|
||||
|
||||
#if GRAPHICS_API_WEBGPU
|
||||
|
||||
#include "GPUSwapChainWebGPU.h"
|
||||
#include "GPUAdapterWebGPU.h"
|
||||
#include "RenderToolsWebGPU.h"
|
||||
#include "Engine/Core/Log.h"
|
||||
#include "Engine/Core/Types/Span.h"
|
||||
#include "Engine/Platform/Window.h"
|
||||
#include "Engine/Graphics/RenderTools.h"
|
||||
#include "Engine/Profiler/ProfilerCPU.h"
|
||||
#include "Engine/Profiler/ProfilerMemory.h"
|
||||
#include "Engine/Scripting/Enums.h"
|
||||
|
||||
GPUSwapChainWebGPU::GPUSwapChainWebGPU(GPUDeviceWebGPU* device, Window* window)
|
||||
: GPUResourceWebGPU(device, StringView::Empty)
|
||||
{
|
||||
_window = window;
|
||||
}
|
||||
|
||||
void GPUSwapChainWebGPU::OnReleaseGPU()
|
||||
{
|
||||
// Release data
|
||||
PROFILE_MEM_DEC(Graphics, _memoryUsage);
|
||||
auto surfaceTexture = _surfaceView.Texture;
|
||||
_surfaceView.Release();
|
||||
if (surfaceTexture)
|
||||
{
|
||||
wgpuTextureRelease(surfaceTexture);
|
||||
}
|
||||
if (Surface)
|
||||
{
|
||||
wgpuSurfaceRelease(Surface);
|
||||
Surface = nullptr;
|
||||
}
|
||||
_width = _height = 0;
|
||||
_memoryUsage = 0;
|
||||
}
|
||||
|
||||
bool GPUSwapChainWebGPU::IsFullscreen()
|
||||
{
|
||||
return _window->IsFullscreen();
|
||||
}
|
||||
|
||||
void GPUSwapChainWebGPU::SetFullscreen(bool isFullscreen)
|
||||
{
|
||||
_window->SetIsFullscreen(true);
|
||||
}
|
||||
|
||||
GPUTextureView* GPUSwapChainWebGPU::GetBackBufferView()
|
||||
{
|
||||
if (!_surfaceView.Texture)
|
||||
{
|
||||
// Get current texture for the surface
|
||||
WGPUSurfaceTexture surfaceTexture = WGPU_SURFACE_TEXTURE_INIT;
|
||||
wgpuSurfaceGetCurrentTexture(Surface, &surfaceTexture);
|
||||
bool hasSurfaceTexture = surfaceTexture.status == WGPUSurfaceGetCurrentTextureStatus_SuccessOptimal || surfaceTexture.status == WGPUSurfaceGetCurrentTextureStatus_SuccessSuboptimal;
|
||||
ASSERT(hasSurfaceTexture);
|
||||
_surfaceView.Texture = surfaceTexture.texture;
|
||||
|
||||
// Create view
|
||||
WGPUTextureViewDescriptor viewDesc = WGPU_TEXTURE_VIEW_DESCRIPTOR_INIT;
|
||||
#if GPU_ENABLE_RESOURCE_NAMING
|
||||
viewDesc.label = WEBGPU_STR("Flax Surface");
|
||||
#endif
|
||||
viewDesc.format = wgpuTextureGetFormat(surfaceTexture.texture);
|
||||
viewDesc.dimension = WGPUTextureViewDimension_2D;
|
||||
viewDesc.mipLevelCount = 1;
|
||||
viewDesc.arrayLayerCount = 1;
|
||||
viewDesc.aspect = WGPUTextureAspect_All;
|
||||
viewDesc.usage = wgpuTextureGetUsage(surfaceTexture.texture);
|
||||
_surfaceView.Create(surfaceTexture.texture, &viewDesc);
|
||||
}
|
||||
return &_surfaceView;
|
||||
}
|
||||
|
||||
void GPUSwapChainWebGPU::Present(bool vsync)
|
||||
{
|
||||
PROFILE_CPU();
|
||||
ZoneColor(TracyWaitZoneColor);
|
||||
|
||||
#if !PLATFORM_WEB
|
||||
// Present frame
|
||||
wgpuSurfacePresent(Surface);
|
||||
#endif
|
||||
|
||||
// Release the texture
|
||||
auto surfaceTexture = _surfaceView.Texture;
|
||||
ASSERT(surfaceTexture);
|
||||
_surfaceView.Release();
|
||||
wgpuTextureRelease(surfaceTexture);
|
||||
|
||||
// Base
|
||||
GPUSwapChain::Present(vsync);
|
||||
}
|
||||
|
||||
bool GPUSwapChainWebGPU::Resize(int32 width, int32 height)
|
||||
{
|
||||
if (width == _width && height == _height)
|
||||
return false;
|
||||
_device->WaitForGPU();
|
||||
GPUDeviceLock lock(_device);
|
||||
#if GPU_ENABLE_DIAGNOSTICS
|
||||
LOG(Info, "Resizing WebGPU surface to: {}x{}", width, height);
|
||||
#endif
|
||||
|
||||
// Ensure to have a surface
|
||||
if (!Surface)
|
||||
{
|
||||
WGPUEmscriptenSurfaceSourceCanvasHTMLSelector canvasDesc = WGPU_EMSCRIPTEN_SURFACE_SOURCE_CANVAS_HTML_SELECTOR_INIT;
|
||||
canvasDesc.selector = WEBGPU_STR(WEB_CANVAS_ID);
|
||||
WGPUSurfaceDescriptor surfaceDesc = WGPU_SURFACE_DESCRIPTOR_INIT;
|
||||
surfaceDesc.nextInChain = &canvasDesc.chain;
|
||||
#if GPU_ENABLE_RESOURCE_NAMING
|
||||
surfaceDesc.label = WEBGPU_STR("Flax Surface");
|
||||
#endif
|
||||
Surface = wgpuInstanceCreateSurface(_device->WebGPUInstance, &surfaceDesc);
|
||||
if (!Surface)
|
||||
{
|
||||
LOG(Fatal, "Failed to create WebGPU surface for the HTML selector '{}'", TEXT(WEB_CANVAS_ID));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup surface configuration (based on capabilities)
|
||||
WGPUSurfaceCapabilities capabilities = WGPU_SURFACE_CAPABILITIES_INIT;
|
||||
wgpuSurfaceGetCapabilities(Surface, _device->Adapter->Adapter, &capabilities);
|
||||
auto formats = ToSpan(capabilities.formats, capabilities.formatCount);
|
||||
auto presentModes = ToSpan(capabilities.presentModes, capabilities.presentModeCount);
|
||||
auto alphaModes = ToSpan(capabilities.alphaModes, capabilities.alphaModeCount);
|
||||
WGPUSurfaceConfiguration configuration = WGPU_SURFACE_CONFIGURATION_INIT;
|
||||
configuration.device = _device->Device;
|
||||
configuration.usage = WGPUTextureUsage_RenderAttachment;
|
||||
#if GPU_USE_WINDOW_SRV
|
||||
configuration.usage |= WGPUTextureUsage_TextureBinding;
|
||||
#endif
|
||||
configuration.width = width;
|
||||
configuration.height = height;
|
||||
configuration.format = WGPUTextureFormat_RGBA8Unorm;
|
||||
configuration.viewFormats = &configuration.format;
|
||||
configuration.viewFormatCount = 1;
|
||||
_format = PixelFormat::R8G8B8A8_UNorm;
|
||||
if (SpanContains(formats, RenderToolsWebGPU::ToTextureFormat(GPU_BACK_BUFFER_PIXEL_FORMAT)))
|
||||
{
|
||||
_format = GPU_BACK_BUFFER_PIXEL_FORMAT;
|
||||
configuration.format = RenderToolsWebGPU::ToTextureFormat(_format);
|
||||
}
|
||||
else if (formats.Length() != 0)
|
||||
{
|
||||
configuration.format = formats[0];
|
||||
_format = RenderToolsWebGPU::ToPixelFormat(configuration.format);
|
||||
}
|
||||
if (_window->GetSettings().SupportsTransparency && SpanContains(alphaModes, WGPUCompositeAlphaMode_Premultiplied))
|
||||
configuration.alphaMode = WGPUCompositeAlphaMode_Premultiplied;
|
||||
else if (SpanContains(alphaModes, WGPUCompositeAlphaMode_Opaque))
|
||||
configuration.alphaMode = WGPUCompositeAlphaMode_Opaque;
|
||||
if (SpanContains(presentModes, WGPUPresentMode_Mailbox))
|
||||
configuration.presentMode = WGPUPresentMode_Mailbox;
|
||||
if (SpanContains(presentModes, WGPUPresentMode_Fifo))
|
||||
configuration.presentMode = WGPUPresentMode_Fifo;
|
||||
else if (presentModes.Length() != 0)
|
||||
configuration.presentMode = presentModes[0];
|
||||
wgpuSurfaceCapabilitiesFreeMembers(capabilities);
|
||||
|
||||
// Configure surface
|
||||
wgpuSurfaceConfigure(Surface, &configuration);
|
||||
|
||||
// Init
|
||||
_surfaceView.Init(this, _format, MSAALevel::None);
|
||||
_width = width;
|
||||
_height = height;
|
||||
_memoryUsage = RenderTools::CalculateTextureMemoryUsage(_format, _width, _height, 1);
|
||||
PROFILE_MEM_INC(Graphics, _memoryUsage);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user