From 93f0e493ac6b8c9a5d1d082b99616fcadc345446 Mon Sep 17 00:00:00 2001 From: Sergii Liebodkin Date: Tue, 19 Dec 2023 23:56:14 +0200 Subject: [PATCH] wg_engine: refactor context handles New approach provide: - instance, adaptor, device and default queue - device capabilitieas - command buffer executor - error handling --- src/renderer/wg_engine/tvgWgCommon.cpp | 90 +++++++++++++++++ src/renderer/wg_engine/tvgWgCommon.h | 16 +++ src/renderer/wg_engine/tvgWgRenderer.cpp | 119 ++++------------------- src/renderer/wg_engine/tvgWgRenderer.h | 16 +-- 4 files changed, 131 insertions(+), 110 deletions(-) diff --git a/src/renderer/wg_engine/tvgWgCommon.cpp b/src/renderer/wg_engine/tvgWgCommon.cpp index 54584e31..d8114011 100644 --- a/src/renderer/wg_engine/tvgWgCommon.cpp +++ b/src/renderer/wg_engine/tvgWgCommon.cpp @@ -21,6 +21,96 @@ */ #include "tvgWgCommon.h" +#include + +//***************************************************************************** +// context +//***************************************************************************** + +void WgContext::initialize() +{ + // create instance + WGPUInstanceDescriptor instanceDesc{}; + instanceDesc.nextInChain = nullptr; + instance = wgpuCreateInstance(&instanceDesc); + assert(instance); + + // request adapter options + WGPURequestAdapterOptions requestAdapterOptions{}; + requestAdapterOptions.nextInChain = nullptr; + requestAdapterOptions.compatibleSurface = nullptr; + requestAdapterOptions.powerPreference = WGPUPowerPreference_HighPerformance; + requestAdapterOptions.forceFallbackAdapter = false; + // on adapter request ended function + auto onAdapterRequestEnded = [](WGPURequestAdapterStatus status, WGPUAdapter adapter, char const * message, void * pUserData) { + if (status != WGPURequestAdapterStatus_Success) + TVGERR("WG_RENDERER", "Adapter request: %s", message); + *((WGPUAdapter*)pUserData) = adapter; + }; + // request adapter + wgpuInstanceRequestAdapter(instance, &requestAdapterOptions, onAdapterRequestEnded, &adapter); + assert(adapter); + + // adapter enumarate fueatures + size_t featuresCount = wgpuAdapterEnumerateFeatures(adapter, featureNames); + wgpuAdapterGetProperties(adapter, &adapterProperties); + wgpuAdapterGetLimits(adapter, &supportedLimits); + + // reguest device + WGPUDeviceDescriptor deviceDesc{}; + deviceDesc.nextInChain = nullptr; + deviceDesc.label = "The device"; + deviceDesc.requiredFeaturesCount = featuresCount; + deviceDesc.requiredFeatures = featureNames; + deviceDesc.requiredLimits = nullptr; + deviceDesc.defaultQueue.nextInChain = nullptr; + deviceDesc.defaultQueue.label = "The default queue"; + deviceDesc.deviceLostCallback = nullptr; + deviceDesc.deviceLostUserdata = nullptr; + // on device request ended function + auto onDeviceRequestEnded = [](WGPURequestDeviceStatus status, WGPUDevice device, char const * message, void * pUserData) { + if (status != WGPURequestDeviceStatus_Success) + TVGERR("WG_RENDERER", "Device request: %s", message); + *((WGPUDevice*)pUserData) = device; + }; + // request device + wgpuAdapterRequestDevice(adapter, &deviceDesc, onDeviceRequestEnded, &device); + assert(device); + + // on device error function + auto onDeviceError = [](WGPUErrorType type, char const* message, void* pUserData) { + TVGERR("WG_RENDERER", "Uncaptured device error: %s", message); + // TODO: remove direct error message + std::cout << message << std::endl; + }; + // set device error handling + wgpuDeviceSetUncapturedErrorCallback(device, onDeviceError, nullptr); + + queue = wgpuDeviceGetQueue(device); + assert(queue); +} + +void WgContext::release() +{ + if (device) { + wgpuDeviceDestroy(device); + wgpuDeviceRelease(device); + } + if (adapter) wgpuAdapterRelease(adapter); + if (instance) wgpuInstanceRelease(instance); +} + +void WgContext::executeCommandEncoder(WGPUCommandEncoder commandEncoder) +{ + // command buffer descriptor + WGPUCommandBufferDescriptor commandBufferDesc{}; + commandBufferDesc.nextInChain = nullptr; + commandBufferDesc.label = "The command buffer"; + WGPUCommandBuffer commandsBuffer = nullptr; + commandsBuffer = wgpuCommandEncoderFinish(commandEncoder, &commandBufferDesc); + wgpuQueueSubmit(queue, 1, &commandsBuffer); + wgpuCommandBufferRelease(commandsBuffer); +} //***************************************************************************** // bind group diff --git a/src/renderer/wg_engine/tvgWgCommon.h b/src/renderer/wg_engine/tvgWgCommon.h index b7808c5f..e4ed397e 100644 --- a/src/renderer/wg_engine/tvgWgCommon.h +++ b/src/renderer/wg_engine/tvgWgCommon.h @@ -28,6 +28,22 @@ #include "tvgCommon.h" #include "tvgRender.h" +struct WgContext { + WGPUInstance instance{}; + WGPUAdapter adapter{}; + WGPUDevice device{}; + WGPUQueue queue{}; + + WGPUFeatureName featureNames[32]{}; + WGPUAdapterProperties adapterProperties{}; + WGPUSupportedLimits supportedLimits{}; + + void initialize(); + void release(); + + void executeCommandEncoder(WGPUCommandEncoder commandEncoder); +}; + struct WgBindGroup { WGPUBindGroup mBindGroup{}; diff --git a/src/renderer/wg_engine/tvgWgRenderer.cpp b/src/renderer/wg_engine/tvgWgRenderer.cpp index 82bf48a1..91e0ecc2 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.cpp +++ b/src/renderer/wg_engine/tvgWgRenderer.cpp @@ -22,13 +22,10 @@ #include "tvgWgRenderer.h" -#include #ifdef _WIN32 // TODO: cross-platform realization #include #endif -#include "tvgWgRenderData.h" -#include "tvgWgShaderSrc.h" WgRenderer::WgRenderer() { @@ -44,84 +41,18 @@ WgRenderer::~WgRenderer() void WgRenderer::initialize() { - // create instance - WGPUInstanceDescriptor instanceDesc{}; - instanceDesc.nextInChain = nullptr; - mInstance = wgpuCreateInstance(&instanceDesc); - assert(mInstance); - - // request adapter options - WGPURequestAdapterOptions requestAdapterOptions{}; - requestAdapterOptions.nextInChain = nullptr; - requestAdapterOptions.compatibleSurface = nullptr; - requestAdapterOptions.powerPreference = WGPUPowerPreference_HighPerformance; - requestAdapterOptions.forceFallbackAdapter = false; - // on adapter request ended function - auto onAdapterRequestEnded = [](WGPURequestAdapterStatus status, WGPUAdapter adapter, char const * message, void * pUserData) { - if (status != WGPURequestAdapterStatus_Success) - TVGERR("WG_RENDERER", "Adapter request: %s", message); - *((WGPUAdapter*)pUserData) = adapter; - }; - // request adapter - wgpuInstanceRequestAdapter(mInstance, &requestAdapterOptions, onAdapterRequestEnded, &mAdapter); - assert(mAdapter); - - // adapter enumarate fueatures - WGPUFeatureName featureNames[32]{}; - size_t featuresCount = wgpuAdapterEnumerateFeatures(mAdapter, featureNames); - WGPUAdapterProperties adapterProperties{}; - wgpuAdapterGetProperties(mAdapter, &adapterProperties); - WGPUSupportedLimits supportedLimits{}; - wgpuAdapterGetLimits(mAdapter, &supportedLimits); - - // reguest device - WGPUDeviceDescriptor deviceDesc{}; - deviceDesc.nextInChain = nullptr; - deviceDesc.label = "The device"; - deviceDesc.requiredFeaturesCount = featuresCount; - deviceDesc.requiredFeatures = featureNames; - deviceDesc.requiredLimits = nullptr; - deviceDesc.defaultQueue.nextInChain = nullptr; - deviceDesc.defaultQueue.label = "The default queue"; - deviceDesc.deviceLostCallback = nullptr; - deviceDesc.deviceLostUserdata = nullptr; - // on device request ended function - auto onDeviceRequestEnded = [](WGPURequestDeviceStatus status, WGPUDevice device, char const * message, void * pUserData) { - if (status != WGPURequestDeviceStatus_Success) - TVGERR("WG_RENDERER", "Device request: %s", message); - *((WGPUDevice*)pUserData) = device; - }; - // request device - wgpuAdapterRequestDevice(mAdapter, &deviceDesc, onDeviceRequestEnded, &mDevice); - assert(mDevice); - - // on device error function - auto onDeviceError = [](WGPUErrorType type, char const* message, void* pUserData) { - TVGERR("WG_RENDERER", "Uncaptured device error: %s", message); - // TODO: remove direct error message - std::cout << message << std::endl; - }; - // set device error handling - wgpuDeviceSetUncapturedErrorCallback(mDevice, onDeviceError, nullptr); - - mQueue = wgpuDeviceGetQueue(mDevice); - assert(mQueue); - - // create pipelines - mPipelines.initialize(mDevice); + mContext.initialize(); + mPipelines.initialize(mContext.device); } void WgRenderer::release() { - mRenderTarget.release(); mPipelines.release(); - if (mDevice) { - wgpuDeviceDestroy(mDevice); - wgpuDeviceRelease(mDevice); - } - if (mAdapter) wgpuAdapterRelease(mAdapter); - if (mInstance) wgpuInstanceRelease(mInstance); + if (mSwapChain) wgpuSwapChainRelease(mSwapChain); + if (mSurface) wgpuSurfaceRelease(mSurface); + mPipelines.release(); + mContext.release(); } @@ -131,27 +62,27 @@ RenderData WgRenderer::prepare(const RenderShape& rshape, RenderData data, const auto renderDataShape = (WgRenderDataShape*)data; if (!renderDataShape) { renderDataShape = new WgRenderDataShape(); - renderDataShape->initialize(mDevice); + renderDataShape->initialize(mContext.device); } // update geometry if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Stroke)) { renderDataShape->releaseRenderData(); - renderDataShape->tesselate(mDevice, mQueue, rshape); - renderDataShape->stroke(mDevice, mQueue, rshape); + renderDataShape->tesselate(mContext.device, mContext.queue, rshape); + renderDataShape->stroke(mContext.device, mContext.queue, rshape); } // update paint settings if (flags & (RenderUpdateFlag::Transform | RenderUpdateFlag::Blend)) { WgShaderTypeMat4x4f modelMat(transform); WgShaderTypeBlendSettings blendSettings(mTargetSurface.cs); - renderDataShape->mBindGroupPaint.initialize(mDevice, mQueue, modelMat, blendSettings); + renderDataShape->mBindGroupPaint.initialize(mContext.device, mContext.queue, modelMat, blendSettings); } // setup fill settings - renderDataShape->mRenderSettingsShape.update(mDevice, mQueue, rshape.fill, rshape.color, flags); + renderDataShape->mRenderSettingsShape.update(mContext.device, mContext.queue, rshape.fill, rshape.color, flags); if (rshape.stroke) - renderDataShape->mRenderSettingsStroke.update(mDevice, mQueue, rshape.stroke->fill, rshape.stroke->color, flags); + renderDataShape->mRenderSettingsStroke.update(mContext.device, mContext.queue, rshape.stroke->fill, rshape.stroke->color, flags); return renderDataShape; } @@ -169,22 +100,22 @@ RenderData WgRenderer::prepare(Surface* surface, const RenderMesh* mesh, RenderD auto renderDataShape = (WgRenderDataShape*)data; if (!renderDataShape) { renderDataShape = new WgRenderDataShape(); - renderDataShape->initialize(mDevice); + renderDataShape->initialize(mContext.device); } // update paint settings if (flags & (RenderUpdateFlag::Transform | RenderUpdateFlag::Blend)) { WgShaderTypeMat4x4f modelMat(transform); WgShaderTypeBlendSettings blendSettings(surface->cs); - renderDataShape->mBindGroupPaint.initialize(mDevice, mQueue, modelMat, blendSettings); + renderDataShape->mBindGroupPaint.initialize(mContext.device, mContext.queue, modelMat, blendSettings); } // update image data if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Image)) { renderDataShape->releaseRenderData(); - renderDataShape->tesselate(mDevice, mQueue, surface, mesh); + renderDataShape->tesselate(mContext.device, mContext.queue, surface, mesh); renderDataShape->mBindGroupPicture.initialize( - mDevice, mQueue, + mContext.device, mContext.queue, renderDataShape->mImageData.mSampler, renderDataShape->mImageData.mTextureView); } @@ -258,7 +189,6 @@ ColorSpace WgRenderer::colorSpace() bool WgRenderer::clear() { - mClearBuffer = true; return true; } @@ -271,7 +201,7 @@ bool WgRenderer::sync() WGPUCommandEncoderDescriptor commandEncoderDesc{}; commandEncoderDesc.nextInChain = nullptr; commandEncoderDesc.label = "The command encoder"; - WGPUCommandEncoder commandEncoder = wgpuDeviceCreateCommandEncoder(mDevice, &commandEncoderDesc); + WGPUCommandEncoder commandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc); // render datas mRenderTarget.beginRenderPass(commandEncoder, backBufferView); @@ -283,14 +213,7 @@ bool WgRenderer::sync() } mRenderTarget.endRenderPass(); - // execute command encoder - WGPUCommandBufferDescriptor commandBufferDesc{}; - commandBufferDesc.nextInChain = nullptr; - commandBufferDesc.label = "The command buffer"; - WGPUCommandBuffer commandsBuffer{}; - commandsBuffer = wgpuCommandEncoderFinish(commandEncoder, &commandBufferDesc); - wgpuQueueSubmit(mQueue, 1, &commandsBuffer); - wgpuCommandBufferRelease(commandsBuffer); + mContext.executeCommandEncoder(commandEncoder); wgpuCommandEncoderRelease(commandEncoder); // go to the next frame @@ -333,7 +256,7 @@ bool WgRenderer::target(void* window, uint32_t w, uint32_t h) WGPUSurfaceDescriptor surfaceDesc{}; surfaceDesc.nextInChain = (const WGPUChainedStruct*)&surfaceDescHwnd; surfaceDesc.label = "The surface"; - mSurface = wgpuInstanceCreateSurface(mInstance, &surfaceDesc); + mSurface = wgpuInstanceCreateSurface(mContext.instance, &surfaceDesc); assert(mSurface); // get preferred format @@ -347,10 +270,10 @@ bool WgRenderer::target(void* window, uint32_t w, uint32_t h) swapChainDesc.width = mTargetSurface.w; swapChainDesc.height = mTargetSurface.h; swapChainDesc.presentMode = WGPUPresentMode_Mailbox; - mSwapChain = wgpuDeviceCreateSwapChain(mDevice, mSurface, &swapChainDesc); + mSwapChain = wgpuDeviceCreateSwapChain(mContext.device, mSurface, &swapChainDesc); assert(mSwapChain); - mRenderTarget.initialize(mDevice, mQueue, mPipelines, w, h); + mRenderTarget.initialize(mContext.device, mContext.queue, mPipelines, w, h); return true; } diff --git a/src/renderer/wg_engine/tvgWgRenderer.h b/src/renderer/wg_engine/tvgWgRenderer.h index 2f505b15..fe31becd 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.h +++ b/src/renderer/wg_engine/tvgWgRenderer.h @@ -62,20 +62,12 @@ public: private: Array mRenderDatas{}; - - Surface mTargetSurface = { nullptr, 0, 0, 0, ColorSpace::Unsupported, true }; - // basic webgpu instances (TODO: create separated entity) - WGPUInstance mInstance{}; - WGPUAdapter mAdapter{}; - WGPUDevice mDevice{}; - WGPUQueue mQueue{}; - // webgpu surface handles (TODO: create separated entity) - WGPUSurface mSurface{}; - WGPUSwapChain mSwapChain{}; + WgContext mContext; WgPipelines mPipelines; WgRenderTarget mRenderTarget; - - bool mClearBuffer; + WGPUSurface mSurface{}; + WGPUSwapChain mSwapChain{}; + Surface mTargetSurface = { nullptr, 0, 0, 0, ColorSpace::Unsupported, true }; }; #endif /* _TVG_WG_RENDERER_H_ */