wg_engine: multicanvas support

Added multicanas support
Issue https://github.com/thorvg/thorvg/issues/2745
This commit is contained in:
Sergii Liebodkin 2024-11-21 14:52:42 +00:00 committed by Hermet Park
parent 57fcada8cc
commit 3805f26aff
14 changed files with 181 additions and 126 deletions

View file

@ -425,14 +425,14 @@ struct WgWindow : Window
virtual ~WgWindow() virtual ~WgWindow()
{ {
wgpuSurfaceRelease(surface); //wgpuSurfaceRelease(surface);
wgpuInstanceRelease(instance); wgpuInstanceRelease(instance);
} }
void resize() override void resize() override
{ {
//Set the canvas target and draw on it. //Set the canvas target and draw on it.
verify(static_cast<tvg::WgCanvas*>(canvas)->target(instance, surface, width, height)); verify(static_cast<tvg::WgCanvas*>(canvas)->target(nullptr, instance, surface, width, height));
} }
void refresh() override void refresh() override

View file

@ -1774,11 +1774,12 @@ public:
/** /**
* @brief Sets the drawing target for the rasterization. * @brief Sets the drawing target for the rasterization.
* *
* @param[in] instance WGPUInstance, context for all other wgpu objects.
* @param[in] surface WGPUSurface, handle to a presentable surface.
* @param[in] w The width of the surface.
* @param[in] h The height of the surface.
* @param[in] device WGPUDevice, a desired handle for the wgpu device. If it is @c nullptr, ThorVG will assign an appropriate device internally. * @param[in] device WGPUDevice, a desired handle for the wgpu device. If it is @c nullptr, ThorVG will assign an appropriate device internally.
* @param[in] instance WGPUInstance, context for all other wgpu objects.
* @param[in] target Either WGPUSurface or WGPUTexture, serving as handles to a presentable surface or texture
* @param[in] w The width of the target.
* @param[in] h The height of the target.
* @param[in] type 0: surface, 1: texture are used as pesentable target
* *
* @retval Result::InsufficientCondition if the canvas is performing rendering. Please ensure the canvas is synced. * @retval Result::InsufficientCondition if the canvas is performing rendering. Please ensure the canvas is synced.
* @retval Result::NonSupport In case the wg engine is not supported. * @retval Result::NonSupport In case the wg engine is not supported.
@ -1788,7 +1789,7 @@ public:
* @see Canvas::viewport() * @see Canvas::viewport()
* @see Canvas::sync() * @see Canvas::sync()
*/ */
Result target(void* instance, void* surface, uint32_t w, uint32_t h, void* device = nullptr) noexcept; Result target(void* device, void* instance, void* target, uint32_t w, uint32_t h, int type = 0) noexcept;
/** /**
* @brief Creates a new WgCanvas object. * @brief Creates a new WgCanvas object.

View file

@ -560,11 +560,12 @@ TVG_API Tvg_Canvas* tvg_wgcanvas_create(void);
/*! /*!
* \brief Sets the drawing target for the rasterization. * \brief Sets the drawing target for the rasterization.
* *
* \param[in] instance WGPUInstance, context for all other wgpu objects. * @param[in] device WGPUDevice, a desired handle for the wgpu device. If it is @c nullptr, ThorVG will assign an appropriate device internally.
* \param[in] surface WGPUSurface, handle to a presentable surface. * @param[in] instance WGPUInstance, context for all other wgpu objects.
* \param[in] w The width of the surface. * @param[in] target Either WGPUSurface or WGPUTexture, serving as handles to a presentable surface or texture
* \param[in] h The height of the surface. * @param[in] w The width of the target.
* \param[in] device WGPUDevice, a desired handle for the wgpu device. If it is @c nullptr, ThorVG will assign an appropriate device internally. * @param[in] h The height of the target.
* @param[in] type 0: surface, 1: texture are used as pesentable target
* *
* \return Tvg_Result enumeration. * \return Tvg_Result enumeration.
* \retval TVG_RESULT_INSUFFICIENT_CONDITION if the canvas is performing rendering. Please ensure the canvas is synced. * \retval TVG_RESULT_INSUFFICIENT_CONDITION if the canvas is performing rendering. Please ensure the canvas is synced.
@ -572,7 +573,7 @@ TVG_API Tvg_Canvas* tvg_wgcanvas_create(void);
* *
* \note Experimental API * \note Experimental API
*/ */
TVG_API Tvg_Result tvg_wgcanvas_set_target(Tvg_Canvas* canvas, void* instance, void* surface, uint32_t w, uint32_t h, void* device); TVG_API Tvg_Result tvg_wgcanvas_set_target(Tvg_Canvas* canvas, void* device, void* instance, void* target, uint32_t w, uint32_t h, int type = 0);
/** \} */ // end defgroup ThorVGCapi_WgCanvas /** \} */ // end defgroup ThorVGCapi_WgCanvas

View file

@ -109,10 +109,10 @@ TVG_API Tvg_Result tvg_glcanvas_set_target(Tvg_Canvas* canvas, int32_t id, uint3
} }
TVG_API Tvg_Result tvg_wgcanvas_set_target(Tvg_Canvas* canvas, void* instance, void* surface, uint32_t w, uint32_t h, void* device) TVG_API Tvg_Result tvg_wgcanvas_set_target(Tvg_Canvas* canvas, void* device, void* instance, void* target, uint32_t w, uint32_t h, int type)
{ {
if (!canvas) return TVG_RESULT_INVALID_ARGUMENT; if (!canvas) return TVG_RESULT_INVALID_ARGUMENT;
return (Tvg_Result) reinterpret_cast<WgCanvas*>(canvas)->target(instance, surface, w, h, device); return (Tvg_Result) reinterpret_cast<WgCanvas*>(canvas)->target(device, instance, target, w, h, type);
} }

View file

@ -150,7 +150,7 @@ struct TvgWgEngine : TvgEngineMethod
void resize(Canvas* canvas, int w, int h) override void resize(Canvas* canvas, int w, int h) override
{ {
#ifdef THORVG_WG_RASTER_SUPPORT #ifdef THORVG_WG_RASTER_SUPPORT
static_cast<WgCanvas*>(canvas)->target(instance, surface, w, h, device); static_cast<WgCanvas*>(canvas)->target(device, instance, surface, w, h);
#endif #endif
} }
}; };

View file

@ -52,25 +52,23 @@ WgCanvas::~WgCanvas()
{ {
#ifdef THORVG_WG_RASTER_SUPPORT #ifdef THORVG_WG_RASTER_SUPPORT
auto renderer = static_cast<WgRenderer*>(Canvas::pImpl->renderer); auto renderer = static_cast<WgRenderer*>(Canvas::pImpl->renderer);
renderer->target(nullptr, 0, 0); renderer->target(nullptr, nullptr, nullptr, 0, 0);
#endif #endif
} }
Result WgCanvas::target(void* instance, void* surface, uint32_t w, uint32_t h, void* device) noexcept Result WgCanvas::target(void* device, void* instance, void* target, uint32_t w, uint32_t h, int type) noexcept
{ {
#ifdef THORVG_WG_RASTER_SUPPORT #ifdef THORVG_WG_RASTER_SUPPORT
if (Canvas::pImpl->status != Status::Damaged && Canvas::pImpl->status != Status::Synced) { if (Canvas::pImpl->status != Status::Damaged && Canvas::pImpl->status != Status::Synced) {
return Result::InsufficientCondition; return Result::InsufficientCondition;
} }
if (!instance || !surface || (w == 0) || (h == 0)) return Result::InvalidArguments;
//We know renderer type, avoid dynamic_cast for performance. //We know renderer type, avoid dynamic_cast for performance.
auto renderer = static_cast<WgRenderer*>(Canvas::pImpl->renderer); auto renderer = static_cast<WgRenderer*>(Canvas::pImpl->renderer);
if (!renderer) return Result::MemoryCorruption; if (!renderer) return Result::MemoryCorruption;
if (!renderer->target((WGPUInstance)instance, (WGPUSurface)surface, w, h, (WGPUDevice)device)) return Result::Unknown; if (!renderer->target((WGPUDevice)device, (WGPUInstance)instance, target, w, h, type)) return Result::Unknown;
Canvas::pImpl->vport = {0, 0, (int32_t)w, (int32_t)h}; Canvas::pImpl->vport = {0, 0, (int32_t)w, (int32_t)h};
renderer->viewport(Canvas::pImpl->vport); renderer->viewport(Canvas::pImpl->vport);

View file

@ -140,6 +140,12 @@ void WgBindGroupLayouts::releaseBindGroup(WGPUBindGroup& bindGroup)
bindGroup = nullptr; bindGroup = nullptr;
} }
void WgBindGroupLayouts::releaseBindGroupLayout(WGPUBindGroupLayout& bindGroupLayout)
{
if (bindGroupLayout) wgpuBindGroupLayoutRelease(bindGroupLayout);
bindGroupLayout = nullptr;
}
void WgBindGroupLayouts::initialize(WgContext& context) void WgBindGroupLayouts::initialize(WgContext& context)
{ {
@ -262,14 +268,15 @@ void WgBindGroupLayouts::initialize(WgContext& context)
void WgBindGroupLayouts::release(WgContext& context) void WgBindGroupLayouts::release(WgContext& context)
{ {
wgpuBindGroupLayoutRelease(layoutBuffer3Un); releaseBindGroupLayout(layoutBuffer3Un);
wgpuBindGroupLayoutRelease(layoutBuffer2Un); releaseBindGroupLayout(layoutBuffer2Un);
wgpuBindGroupLayoutRelease(layoutBuffer1Un); releaseBindGroupLayout(layoutBuffer1Un);
wgpuBindGroupLayoutRelease(layoutTexStrorage3RO); releaseBindGroupLayout(layoutTexStrorage3RO);
wgpuBindGroupLayoutRelease(layoutTexStrorage2RO); releaseBindGroupLayout(layoutTexStrorage2RO);
wgpuBindGroupLayoutRelease(layoutTexStrorage1RO); releaseBindGroupLayout(layoutTexStrorage1RO);
wgpuBindGroupLayoutRelease(layoutTexStrorage1WO); releaseBindGroupLayout(layoutTexStrorage1WO);
wgpuBindGroupLayoutRelease(layoutTexSampledBuff1Un); releaseBindGroupLayout(layoutTexSampledBuff1Un);
wgpuBindGroupLayoutRelease(layoutTexSampled); releaseBindGroupLayout(layoutTexSampledBuff2Un);
releaseBindGroupLayout(layoutTexSampled);
device = nullptr; device = nullptr;
} }

View file

@ -51,6 +51,7 @@ public:
WGPUBindGroup createBindGroupBuffer2Un(WGPUBuffer buff0, WGPUBuffer buff1); WGPUBindGroup createBindGroupBuffer2Un(WGPUBuffer buff0, WGPUBuffer buff1);
WGPUBindGroup createBindGroupBuffer3Un(WGPUBuffer buff0, WGPUBuffer buff1, WGPUBuffer buff2); WGPUBindGroup createBindGroupBuffer3Un(WGPUBuffer buff0, WGPUBuffer buff1, WGPUBuffer buff2);
void releaseBindGroup(WGPUBindGroup& bindGroup); void releaseBindGroup(WGPUBindGroup& bindGroup);
void releaseBindGroupLayout(WGPUBindGroupLayout& bindGroupLayout);
public: public:
void initialize(WgContext& context); void initialize(WgContext& context);
void release(WgContext& context); void release(WgContext& context);

View file

@ -260,7 +260,7 @@ void WgContext::releaseBuffer(WGPUBuffer& buffer)
} }
} }
void WgContext::releaseQueue(WGPUQueue queue) void WgContext::releaseQueue(WGPUQueue& queue)
{ {
if (queue) { if (queue) {
wgpuQueueRelease(queue); wgpuQueueRelease(queue);

View file

@ -63,7 +63,7 @@ struct WgContext {
void releaseTextureView(WGPUTextureView& textureView); void releaseTextureView(WGPUTextureView& textureView);
void releaseTexture(WGPUTexture& texture); void releaseTexture(WGPUTexture& texture);
void releaseSampler(WGPUSampler& sampler); void releaseSampler(WGPUSampler& sampler);
void releaseQueue(WGPUQueue queue); void releaseQueue(WGPUQueue& queue);
// create buffer objects (return true, if buffer handle was changed) // create buffer objects (return true, if buffer handle was changed)
bool allocateBufferUniform(WGPUBuffer& buffer, const void* data, uint64_t size); bool allocateBufferUniform(WGPUBuffer& buffer, const void* data, uint64_t size);

View file

@ -165,7 +165,8 @@ void WgMeshDataPool::release(WgContext& context)
mList.clear(); mList.clear();
} }
WgMeshDataPool* WgMeshDataGroup::gMeshDataPool = nullptr; WgMeshDataPool gMeshDataPoolInstance;
WgMeshDataPool* WgMeshDataPool::gMeshDataPool = &gMeshDataPoolInstance;
//*********************************************************************** //***********************************************************************
// WgMeshDataGroup // WgMeshDataGroup
@ -174,7 +175,7 @@ WgMeshDataPool* WgMeshDataGroup::gMeshDataPool = nullptr;
void WgMeshDataGroup::append(WgContext& context, const WgVertexBuffer& vertexBuffer) void WgMeshDataGroup::append(WgContext& context, const WgVertexBuffer& vertexBuffer)
{ {
assert(vertexBuffer.vcount >= 3); assert(vertexBuffer.vcount >= 3);
meshes.push(gMeshDataPool->allocate(context)); meshes.push(WgMeshDataPool::gMeshDataPool->allocate(context));
meshes.last()->update(context, vertexBuffer); meshes.last()->update(context, vertexBuffer);
} }
@ -182,14 +183,14 @@ void WgMeshDataGroup::append(WgContext& context, const WgVertexBuffer& vertexBuf
void WgMeshDataGroup::append(WgContext& context, const WgVertexBufferInd& vertexBufferInd) void WgMeshDataGroup::append(WgContext& context, const WgVertexBufferInd& vertexBufferInd)
{ {
assert(vertexBufferInd.vcount >= 3); assert(vertexBufferInd.vcount >= 3);
meshes.push(gMeshDataPool->allocate(context)); meshes.push(WgMeshDataPool::gMeshDataPool->allocate(context));
meshes.last()->update(context, vertexBufferInd); meshes.last()->update(context, vertexBufferInd);
} }
void WgMeshDataGroup::append(WgContext& context, const Point pmin, const Point pmax) void WgMeshDataGroup::append(WgContext& context, const Point pmin, const Point pmax)
{ {
meshes.push(gMeshDataPool->allocate(context)); meshes.push(WgMeshDataPool::gMeshDataPool->allocate(context));
meshes.last()->bbox(context, pmin, pmax); meshes.last()->bbox(context, pmin, pmax);
} }
@ -197,7 +198,7 @@ void WgMeshDataGroup::append(WgContext& context, const Point pmin, const Point p
void WgMeshDataGroup::release(WgContext& context) void WgMeshDataGroup::release(WgContext& context)
{ {
for (uint32_t i = 0; i < meshes.count; i++) for (uint32_t i = 0; i < meshes.count; i++)
gMeshDataPool->free(context, meshes[i]); WgMeshDataPool::gMeshDataPool->free(context, meshes[i]);
meshes.clear(); meshes.clear();
}; };
@ -298,8 +299,6 @@ void WgRenderSettings::release(WgContext& context)
// WgRenderDataPaint // WgRenderDataPaint
//*********************************************************************** //***********************************************************************
WgVertexBufferInd* WgRenderDataPaint::gStrokesGenerator = nullptr;
void WgRenderDataPaint::release(WgContext& context) void WgRenderDataPaint::release(WgContext& context)
{ {
context.pipelines->layouts.releaseBindGroup(bindGroupPaint); context.pipelines->layouts.releaseBindGroup(bindGroupPaint);
@ -455,7 +454,8 @@ void WgRenderDataShape::updateMeshes(WgContext &context, const RenderShape &rsha
void WgRenderDataShape::proceedStrokes(WgContext context, const RenderStroke* rstroke, float tbeg, float tend, const WgVertexBuffer& buff) void WgRenderDataShape::proceedStrokes(WgContext context, const RenderStroke* rstroke, float tbeg, float tend, const WgVertexBuffer& buff)
{ {
assert(rstroke); assert(rstroke);
gStrokesGenerator->reset(buff.tscale); static WgVertexBufferInd strokesGenerator;
strokesGenerator.reset(buff.tscale);
// trim -> dash -> stroke // trim -> dash -> stroke
if ((tbeg != 0.0f) || (tend != 1.0f)) { if ((tbeg != 0.0f) || (tend != 1.0f)) {
if (tbeg == tend) return; if (tbeg == tend) return;
@ -464,17 +464,17 @@ void WgRenderDataShape::proceedStrokes(WgContext context, const RenderStroke* rs
trimed_buff.trim(buff, tbeg, tend); trimed_buff.trim(buff, tbeg, tend);
trimed_buff.updateDistances(); trimed_buff.updateDistances();
// trim ->dash -> stroke // trim ->dash -> stroke
if (rstroke->dashPattern) gStrokesGenerator->appendStrokesDashed(trimed_buff, rstroke); if (rstroke->dashPattern) strokesGenerator.appendStrokesDashed(trimed_buff, rstroke);
// trim -> stroke // trim -> stroke
else gStrokesGenerator->appendStrokes(trimed_buff, rstroke); else strokesGenerator.appendStrokes(trimed_buff, rstroke);
} else } else
// dash -> stroke // dash -> stroke
if (rstroke->dashPattern) { if (rstroke->dashPattern) {
gStrokesGenerator->appendStrokesDashed(buff, rstroke); strokesGenerator.appendStrokesDashed(buff, rstroke);
// stroke // stroke
} else } else
gStrokesGenerator->appendStrokes(buff, rstroke); strokesGenerator.appendStrokes(buff, rstroke);
appendStroke(context, *gStrokesGenerator); appendStroke(context, strokesGenerator);
} }

View file

@ -50,14 +50,13 @@ private:
Array<WgMeshData*> mPool; Array<WgMeshData*> mPool;
Array<WgMeshData*> mList; Array<WgMeshData*> mList;
public: public:
static WgMeshDataPool* gMeshDataPool;
WgMeshData* allocate(WgContext& context); WgMeshData* allocate(WgContext& context);
void free(WgContext& context, WgMeshData* meshData); void free(WgContext& context, WgMeshData* meshData);
void release(WgContext& context); void release(WgContext& context);
}; };
struct WgMeshDataGroup { struct WgMeshDataGroup {
static WgMeshDataPool* gMeshDataPool;
Array<WgMeshData*> meshes{}; Array<WgMeshData*> meshes{};
void append(WgContext& context, const WgVertexBuffer& vertexBuffer); void append(WgContext& context, const WgVertexBuffer& vertexBuffer);
@ -96,9 +95,6 @@ struct WgRenderSettings
struct WgRenderDataPaint struct WgRenderDataPaint
{ {
// global strokes generator. single instance
static WgVertexBufferInd* gStrokesGenerator;
WGPUBuffer bufferModelMat{}; WGPUBuffer bufferModelMat{};
WGPUBuffer bufferBlendSettings{}; WGPUBuffer bufferBlendSettings{};
WGPUBindGroup bindGroupPaint{}; WGPUBindGroup bindGroupPaint{};

View file

@ -30,47 +30,45 @@ WgRenderer::WgRenderer()
WgRenderer::~WgRenderer() WgRenderer::~WgRenderer()
{ {
release(); release();
mContext.release();
} }
void WgRenderer::initialize() void WgRenderer::initialize()
{ {
mPipelines.initialize(mContext);
WgMeshDataGroup::gMeshDataPool = new WgMeshDataPool();
WgRenderDataShape::gStrokesGenerator = new WgVertexBufferInd();
} }
void WgRenderer::release() void WgRenderer::release()
{ {
// check for general context availability
if (!mContext.queue) return;
// dispose stored objects
disposeObjects(); disposeObjects();
mStorageRoot.release(mContext);
mRenderStoragePool.release(mContext); // clear rendering tree stacks
mRenderDataShapePool.release(mContext);
delete WgRenderDataShape::gStrokesGenerator;
WgMeshDataGroup::gMeshDataPool->release(mContext);
delete WgMeshDataGroup::gMeshDataPool;
mCompositorStack.clear(); mCompositorStack.clear();
mRenderStorageStack.clear(); mRenderStorageStack.clear();
mRenderStoragePool.release(mContext);
mRenderDataShapePool.release(mContext);
WgMeshDataPool::gMeshDataPool->release(mContext);
mStorageRoot.release(mContext);
// release context handles
mCompositor.release(mContext);
mPipelines.release(mContext); mPipelines.release(mContext);
if (gpuOwner) { mContext.release();
if (device) wgpuDeviceRelease(device);
device = nullptr; // release gpu handles
if (adapter) wgpuAdapterRelease(adapter); clearTargets();
adapter = nullptr; releaseDevice();
gpuOwner = false;
}
releaseSurfaceTexture();
} }
void WgRenderer::disposeObjects() void WgRenderer::disposeObjects()
{ {
if (mDisposeRenderDatas.count == 0) return; for (uint32_t i = 0; i < mDisposeRenderDatas.count; i++) {
WgRenderDataPaint* renderData = (WgRenderDataPaint*)mDisposeRenderDatas[i];
for (auto p = mDisposeRenderDatas.begin(); p < mDisposeRenderDatas.end(); p++) {
auto renderData = (WgRenderDataPaint*)(*p);
if (renderData->type() == Type::Shape) { if (renderData->type() == Type::Shape) {
mRenderDataShapePool.free(mContext, (WgRenderDataShape*)renderData); mRenderDataShapePool.free(mContext, (WgRenderDataShape*)renderData);
} else { } else {
@ -260,20 +258,26 @@ void WgRenderer::releaseSurfaceTexture()
bool WgRenderer::sync() bool WgRenderer::sync()
{ {
disposeObjects(); disposeObjects();
if (!surface) return false;
// if texture buffer used
WGPUTexture dstTexture = targetTexture;
if (surface) {
releaseSurfaceTexture(); releaseSurfaceTexture();
wgpuSurfaceGetCurrentTexture(surface, &surfaceTexture); wgpuSurfaceGetCurrentTexture(surface, &surfaceTexture);
dstTexture = surfaceTexture.texture;
}
// there is no external dest buffer
if (!dstTexture) return false;
WGPUTextureView dstView = mContext.createTextureView(surfaceTexture.texture); // get external dest buffer
WGPUTextureView dstTextureView = mContext.createTextureView(dstTexture);
// create command encoder // create command encoder
const WGPUCommandEncoderDescriptor commandEncoderDesc{}; const WGPUCommandEncoderDescriptor commandEncoderDesc{};
WGPUCommandEncoder commandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc); WGPUCommandEncoder commandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc);
// show root offscreen buffer // show root offscreen buffer
mCompositor.blit(mContext, commandEncoder, &mStorageRoot, dstView); mCompositor.blit(mContext, commandEncoder, &mStorageRoot, dstTextureView);
// release command encoder // release command encoder
const WGPUCommandBufferDescriptor commandBufferDesc{}; const WGPUCommandBufferDescriptor commandBufferDesc{};
@ -281,20 +285,54 @@ bool WgRenderer::sync()
wgpuQueueSubmit(mContext.queue, 1, &commandsBuffer); wgpuQueueSubmit(mContext.queue, 1, &commandsBuffer);
wgpuCommandBufferRelease(commandsBuffer); wgpuCommandBufferRelease(commandsBuffer);
wgpuCommandEncoderRelease(commandEncoder); wgpuCommandEncoderRelease(commandEncoder);
mContext.releaseTextureView(dstView);
// release dest buffer view
mContext.releaseTextureView(dstTextureView);
return true; return true;
} }
// target for native window handle // render target handle
bool WgRenderer::target(WGPUInstance instance, WGPUSurface surface, uint32_t w, uint32_t h, WGPUDevice device) bool WgRenderer::target(WGPUDevice device, WGPUInstance instance, void* target, uint32_t width, uint32_t height, int type)
{ {
gpuOwner = false; // release existing handles
release();
// can not initialize renderer, give up
if (!instance || !target || !width || !height) return false;
// store or regest gpu device
this->device = device; this->device = device;
if (!this->device) { if (!this->device)
reguestDevice(instance, (WGPUSurface)target);
// store target properties
mTargetSurface.stride = width;
mTargetSurface.w = width;
mTargetSurface.h = height;
// initialize rendering context
mContext.initialize(instance, this->device);
mPipelines.initialize(mContext);
// initialize render tree instances
mRenderStoragePool.initialize(mContext, width, height);
mStorageRoot.initialize(mContext, width, height);
mCompositor.initialize(mContext, width, height);
// configure surface (must be called after context creation)
if (type == 0) {
surface = (WGPUSurface)target;
surfaceConfigure(surface, mContext, width, height);
} else targetTexture = (WGPUTexture)target;
return true;
}
void WgRenderer::reguestDevice(WGPUInstance instance, WGPUSurface surface)
{
// request adapter // request adapter
const WGPURequestAdapterOptions requestAdapterOptions { .nextInChain = nullptr, .compatibleSurface = surface, .powerPreference = WGPUPowerPreference_HighPerformance, .forceFallbackAdapter = false }; const WGPURequestAdapterOptions requestAdapterOptions { .compatibleSurface = surface, .powerPreference = WGPUPowerPreference_HighPerformance };
auto onAdapterRequestEnded = [](WGPURequestAdapterStatus status, WGPUAdapter adapter, char const * message, void * pUserData) { *((WGPUAdapter*)pUserData) = adapter; }; auto onAdapterRequestEnded = [](WGPURequestAdapterStatus status, WGPUAdapter adapter, char const * message, void * pUserData) { *((WGPUAdapter*)pUserData) = adapter; };
wgpuInstanceRequestAdapter(instance, &requestAdapterOptions, onAdapterRequestEnded, &this->adapter); wgpuInstanceRequestAdapter(instance, &requestAdapterOptions, onAdapterRequestEnded, &this->adapter);
@ -303,46 +341,53 @@ bool WgRenderer::target(WGPUInstance instance, WGPUSurface surface, uint32_t w,
size_t featuresCount = wgpuAdapterEnumerateFeatures(this->adapter, featureNames); size_t featuresCount = wgpuAdapterEnumerateFeatures(this->adapter, featureNames);
// request device // request device
const WGPUDeviceDescriptor deviceDesc { .nextInChain = nullptr, .label = "The device", .requiredFeatureCount = featuresCount, .requiredFeatures = featureNames }; const WGPUDeviceDescriptor deviceDesc { .label = "The owned device", .requiredFeatureCount = featuresCount, .requiredFeatures = featureNames };
auto onDeviceRequestEnded = [](WGPURequestDeviceStatus status, WGPUDevice device, char const * message, void * pUserData) { *((WGPUDevice*)pUserData) = device; }; auto onDeviceRequestEnded = [](WGPURequestDeviceStatus status, WGPUDevice device, char const * message, void * pUserData) { *((WGPUDevice*)pUserData) = device; };
wgpuAdapterRequestDevice(this->adapter, &deviceDesc, onDeviceRequestEnded, &this->device); wgpuAdapterRequestDevice(this->adapter, &deviceDesc, onDeviceRequestEnded, &this->device);
gpuOwner = true; gpuOwner = true;
}
mContext.initialize(instance, this->device);
initialize();
target(surface, w, h);
mRenderStoragePool.initialize(mContext, w, h);
mStorageRoot.initialize(mContext, w, h);
mCompositor.initialize(mContext, w, h);
return true;
} }
bool WgRenderer::target(WGPUSurface surface, uint32_t w, uint32_t h) {
void WgRenderer::releaseDevice()
{
if (!gpuOwner) return;
wgpuDeviceRelease(device);
wgpuDeviceDestroy(device);
wgpuAdapterRelease(adapter);
device = nullptr;
adapter = nullptr;
gpuOwner = false;
}
void WgRenderer::clearTargets() {
releaseSurfaceTexture();
targetTexture = nullptr;
surface = nullptr;
}
bool WgRenderer::surfaceConfigure(WGPUSurface surface, WgContext& context, uint32_t width, uint32_t height)
{
// store target surface properties // store target surface properties
this->surface = surface; this->surface = surface;
mTargetSurface.stride = w; if (width == 0 || height == 0 || !surface) return false;
mTargetSurface.w = w;
mTargetSurface.h = h;
if (w == 0 || h == 0) return false;
if (!surface) return true;
// setup surface configuration
WGPUSurfaceConfiguration surfaceConfiguration { WGPUSurfaceConfiguration surfaceConfiguration {
.device = mContext.device, .device = context.device,
.format = mContext.preferredFormat, .format = context.preferredFormat,
.usage = WGPUTextureUsage_RenderAttachment, .usage = WGPUTextureUsage_RenderAttachment,
#ifdef __EMSCRIPTEN__ #ifdef __EMSCRIPTEN__
.alphaMode = WGPUCompositeAlphaMode_Premultiplied, .alphaMode = WGPUCompositeAlphaMode_Premultiplied,
#endif #endif
.width = w, .height = h, .width = width,
#ifdef __EMSCRIPTEN__ .height = height,
#ifndef __EMSCRIPTEN__
.presentMode = WGPUPresentMode_Fifo, .presentMode = WGPUPresentMode_Fifo,
#else
.presentMode = WGPUPresentMode_Immediate
#endif #endif
}; };
wgpuSurfaceConfigure(surface, &surfaceConfiguration); wgpuSurfaceConfigure(surface, &surfaceConfiguration);
return true; return true;
} }
@ -369,7 +414,7 @@ bool WgRenderer::beginComposite(RenderCompositor* cmp, MaskMethod method, uint8_
mRenderStorageStack.push(storage); mRenderStorageStack.push(storage);
// begin newly added render pass // begin newly added render pass
WGPUColor color{}; WGPUColor color{};
if ((method == MaskMethod::None) && (opacity != 255)) color = {1.0f, 1.0f, 1.0f, 0.0f}; if ((method == MaskMethod::None) && (opacity != 255)) color = { 1.0, 1.0, 1.0, 0.0 };
mCompositor.beginRenderPass(mCommandEncoder, mRenderStorageStack.last(), true, color); mCompositor.beginRenderPass(mCommandEncoder, mRenderStorageStack.last(), true, color);
return true; return true;
} }

View file

@ -45,8 +45,7 @@ public:
bool clear() override; bool clear() override;
bool sync() override; bool sync() override;
bool target(WGPUInstance instance, WGPUSurface surface, uint32_t w, uint32_t h, WGPUDevice device); bool target(WGPUDevice device, WGPUInstance instance, void* target, uint32_t width, uint32_t height, int type = 0);
bool target(WGPUSurface surface, uint32_t w, uint32_t h);
RenderCompositor* target(const RenderRegion& region, ColorSpace cs) override; RenderCompositor* target(const RenderRegion& region, ColorSpace cs) override;
bool beginComposite(RenderCompositor* cmp, MaskMethod method, uint8_t opacity) override; bool beginComposite(RenderCompositor* cmp, MaskMethod method, uint8_t opacity) override;
@ -59,8 +58,6 @@ public:
static bool init(uint32_t threads); static bool init(uint32_t threads);
static bool term(); static bool term();
WGPUSurface surface{}; // external handle
private: private:
WgRenderer(); WgRenderer();
~WgRenderer(); ~WgRenderer();
@ -69,28 +66,37 @@ private:
void disposeObjects(); void disposeObjects();
void releaseSurfaceTexture(); void releaseSurfaceTexture();
WGPUSurfaceTexture surfaceTexture{}; void reguestDevice(WGPUInstance instance, WGPUSurface surface);
void releaseDevice();
void clearTargets();
bool surfaceConfigure(WGPUSurface surface, WgContext& context, uint32_t width, uint32_t height);
WGPUCommandEncoder mCommandEncoder{}; // render tree stacks and pools
WgRenderDataShapePool mRenderDataShapePool;
// render tree stacks
WgRenderStorage mStorageRoot; WgRenderStorage mStorageRoot;
Array<WgCompose*> mCompositorStack; Array<WgCompose*> mCompositorStack;
Array<WgRenderStorage*> mRenderStorageStack; Array<WgRenderStorage*> mRenderStorageStack;
WgRenderStoragePool mRenderStoragePool; WgRenderStoragePool mRenderStoragePool;
WgRenderDataShapePool mRenderDataShapePool;
// rendering context
WgContext mContext; WgContext mContext;
WgPipelines mPipelines; WgPipelines mPipelines;
WgCompositor mCompositor; WgCompositor mCompositor;
// rendering states
RenderSurface mTargetSurface; RenderSurface mTargetSurface;
BlendMethod mBlendMethod{}; BlendMethod mBlendMethod{};
RenderRegion mViewport{}; RenderRegion mViewport{};
// disposable data list
Array<RenderData> mDisposeRenderDatas{}; Array<RenderData> mDisposeRenderDatas{};
Key mDisposeKey{}; Key mDisposeKey{};
// gpu handles
WGPUCommandEncoder mCommandEncoder{};
WGPUTexture targetTexture{}; // external handle
WGPUSurfaceTexture surfaceTexture{};
WGPUSurface surface{}; // external handle
WGPUAdapter adapter{}; WGPUAdapter adapter{};
WGPUDevice device{}; WGPUDevice device{};
bool gpuOwner{}; bool gpuOwner{};