wg_engine: refactor context handles

New approach provide:
- instance, adaptor, device and default queue
- device capabilitieas
- command buffer executor
- error handling
This commit is contained in:
Sergii Liebodkin 2023-12-19 23:56:14 +02:00 committed by Hermet Park
parent e797cf63f4
commit 003464b7e5
4 changed files with 131 additions and 110 deletions

View file

@ -21,6 +21,96 @@
*/
#include "tvgWgCommon.h"
#include <iostream>
//*****************************************************************************
// 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

View file

@ -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{};

View file

@ -22,13 +22,10 @@
#include "tvgWgRenderer.h"
#include <iostream>
#ifdef _WIN32
// TODO: cross-platform realization
#include <windows.h>
#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;
}

View file

@ -62,20 +62,12 @@ public:
private:
Array<RenderData> 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_ */