Files
FlaxEngine/Source/Engine/GraphicsDevice/WebGPU/GPUSwapChainWebGPU.cpp

180 lines
6.1 KiB
C++

// 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