mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-07 21:23:32 +00:00
wg_engine: multicanvas support
Added multicanas support Issue https://github.com/thorvg/thorvg/issues/2745
This commit is contained in:
parent
57fcada8cc
commit
3805f26aff
14 changed files with 181 additions and 126 deletions
|
@ -425,14 +425,14 @@ struct WgWindow : Window
|
|||
|
||||
virtual ~WgWindow()
|
||||
{
|
||||
wgpuSurfaceRelease(surface);
|
||||
//wgpuSurfaceRelease(surface);
|
||||
wgpuInstanceRelease(instance);
|
||||
}
|
||||
|
||||
void resize() override
|
||||
{
|
||||
//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
|
||||
|
|
11
inc/thorvg.h
11
inc/thorvg.h
|
@ -1774,11 +1774,12 @@ public:
|
|||
/**
|
||||
* @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] 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::NonSupport In case the wg engine is not supported.
|
||||
|
@ -1788,7 +1789,7 @@ public:
|
|||
* @see Canvas::viewport()
|
||||
* @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.
|
||||
|
|
|
@ -560,11 +560,12 @@ TVG_API Tvg_Canvas* tvg_wgcanvas_create(void);
|
|||
/*!
|
||||
* \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
|
||||
*
|
||||
* \return Tvg_Result enumeration.
|
||||
* \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
|
||||
*/
|
||||
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
|
||||
|
||||
|
|
|
@ -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;
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -150,7 +150,7 @@ struct TvgWgEngine : TvgEngineMethod
|
|||
void resize(Canvas* canvas, int w, int h) override
|
||||
{
|
||||
#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
|
||||
}
|
||||
};
|
||||
|
|
|
@ -52,25 +52,23 @@ WgCanvas::~WgCanvas()
|
|||
{
|
||||
#ifdef THORVG_WG_RASTER_SUPPORT
|
||||
auto renderer = static_cast<WgRenderer*>(Canvas::pImpl->renderer);
|
||||
renderer->target(nullptr, 0, 0);
|
||||
renderer->target(nullptr, nullptr, nullptr, 0, 0);
|
||||
#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
|
||||
if (Canvas::pImpl->status != Status::Damaged && Canvas::pImpl->status != Status::Synced) {
|
||||
return Result::InsufficientCondition;
|
||||
}
|
||||
|
||||
if (!instance || !surface || (w == 0) || (h == 0)) return Result::InvalidArguments;
|
||||
|
||||
//We know renderer type, avoid dynamic_cast for performance.
|
||||
auto renderer = static_cast<WgRenderer*>(Canvas::pImpl->renderer);
|
||||
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};
|
||||
renderer->viewport(Canvas::pImpl->vport);
|
||||
|
||||
|
|
|
@ -140,6 +140,12 @@ void WgBindGroupLayouts::releaseBindGroup(WGPUBindGroup& bindGroup)
|
|||
bindGroup = nullptr;
|
||||
}
|
||||
|
||||
void WgBindGroupLayouts::releaseBindGroupLayout(WGPUBindGroupLayout& bindGroupLayout)
|
||||
{
|
||||
if (bindGroupLayout) wgpuBindGroupLayoutRelease(bindGroupLayout);
|
||||
bindGroupLayout = nullptr;
|
||||
}
|
||||
|
||||
|
||||
void WgBindGroupLayouts::initialize(WgContext& context)
|
||||
{
|
||||
|
@ -262,14 +268,15 @@ void WgBindGroupLayouts::initialize(WgContext& context)
|
|||
|
||||
void WgBindGroupLayouts::release(WgContext& context)
|
||||
{
|
||||
wgpuBindGroupLayoutRelease(layoutBuffer3Un);
|
||||
wgpuBindGroupLayoutRelease(layoutBuffer2Un);
|
||||
wgpuBindGroupLayoutRelease(layoutBuffer1Un);
|
||||
wgpuBindGroupLayoutRelease(layoutTexStrorage3RO);
|
||||
wgpuBindGroupLayoutRelease(layoutTexStrorage2RO);
|
||||
wgpuBindGroupLayoutRelease(layoutTexStrorage1RO);
|
||||
wgpuBindGroupLayoutRelease(layoutTexStrorage1WO);
|
||||
wgpuBindGroupLayoutRelease(layoutTexSampledBuff1Un);
|
||||
wgpuBindGroupLayoutRelease(layoutTexSampled);
|
||||
releaseBindGroupLayout(layoutBuffer3Un);
|
||||
releaseBindGroupLayout(layoutBuffer2Un);
|
||||
releaseBindGroupLayout(layoutBuffer1Un);
|
||||
releaseBindGroupLayout(layoutTexStrorage3RO);
|
||||
releaseBindGroupLayout(layoutTexStrorage2RO);
|
||||
releaseBindGroupLayout(layoutTexStrorage1RO);
|
||||
releaseBindGroupLayout(layoutTexStrorage1WO);
|
||||
releaseBindGroupLayout(layoutTexSampledBuff1Un);
|
||||
releaseBindGroupLayout(layoutTexSampledBuff2Un);
|
||||
releaseBindGroupLayout(layoutTexSampled);
|
||||
device = nullptr;
|
||||
}
|
||||
|
|
|
@ -51,6 +51,7 @@ public:
|
|||
WGPUBindGroup createBindGroupBuffer2Un(WGPUBuffer buff0, WGPUBuffer buff1);
|
||||
WGPUBindGroup createBindGroupBuffer3Un(WGPUBuffer buff0, WGPUBuffer buff1, WGPUBuffer buff2);
|
||||
void releaseBindGroup(WGPUBindGroup& bindGroup);
|
||||
void releaseBindGroupLayout(WGPUBindGroupLayout& bindGroupLayout);
|
||||
public:
|
||||
void initialize(WgContext& context);
|
||||
void release(WgContext& context);
|
||||
|
|
|
@ -260,7 +260,7 @@ void WgContext::releaseBuffer(WGPUBuffer& buffer)
|
|||
}
|
||||
}
|
||||
|
||||
void WgContext::releaseQueue(WGPUQueue queue)
|
||||
void WgContext::releaseQueue(WGPUQueue& queue)
|
||||
{
|
||||
if (queue) {
|
||||
wgpuQueueRelease(queue);
|
||||
|
|
|
@ -63,7 +63,7 @@ struct WgContext {
|
|||
void releaseTextureView(WGPUTextureView& textureView);
|
||||
void releaseTexture(WGPUTexture& texture);
|
||||
void releaseSampler(WGPUSampler& sampler);
|
||||
void releaseQueue(WGPUQueue queue);
|
||||
void releaseQueue(WGPUQueue& queue);
|
||||
|
||||
// create buffer objects (return true, if buffer handle was changed)
|
||||
bool allocateBufferUniform(WGPUBuffer& buffer, const void* data, uint64_t size);
|
||||
|
|
|
@ -165,7 +165,8 @@ void WgMeshDataPool::release(WgContext& context)
|
|||
mList.clear();
|
||||
}
|
||||
|
||||
WgMeshDataPool* WgMeshDataGroup::gMeshDataPool = nullptr;
|
||||
WgMeshDataPool gMeshDataPoolInstance;
|
||||
WgMeshDataPool* WgMeshDataPool::gMeshDataPool = &gMeshDataPoolInstance;
|
||||
|
||||
//***********************************************************************
|
||||
// WgMeshDataGroup
|
||||
|
@ -174,7 +175,7 @@ WgMeshDataPool* WgMeshDataGroup::gMeshDataPool = nullptr;
|
|||
void WgMeshDataGroup::append(WgContext& context, const WgVertexBuffer& vertexBuffer)
|
||||
{
|
||||
assert(vertexBuffer.vcount >= 3);
|
||||
meshes.push(gMeshDataPool->allocate(context));
|
||||
meshes.push(WgMeshDataPool::gMeshDataPool->allocate(context));
|
||||
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)
|
||||
{
|
||||
assert(vertexBufferInd.vcount >= 3);
|
||||
meshes.push(gMeshDataPool->allocate(context));
|
||||
meshes.push(WgMeshDataPool::gMeshDataPool->allocate(context));
|
||||
meshes.last()->update(context, vertexBufferInd);
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -197,7 +198,7 @@ void WgMeshDataGroup::append(WgContext& context, const Point pmin, const Point p
|
|||
void WgMeshDataGroup::release(WgContext& context)
|
||||
{
|
||||
for (uint32_t i = 0; i < meshes.count; i++)
|
||||
gMeshDataPool->free(context, meshes[i]);
|
||||
WgMeshDataPool::gMeshDataPool->free(context, meshes[i]);
|
||||
meshes.clear();
|
||||
};
|
||||
|
||||
|
@ -298,8 +299,6 @@ void WgRenderSettings::release(WgContext& context)
|
|||
// WgRenderDataPaint
|
||||
//***********************************************************************
|
||||
|
||||
WgVertexBufferInd* WgRenderDataPaint::gStrokesGenerator = nullptr;
|
||||
|
||||
void WgRenderDataPaint::release(WgContext& context)
|
||||
{
|
||||
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)
|
||||
{
|
||||
assert(rstroke);
|
||||
gStrokesGenerator->reset(buff.tscale);
|
||||
static WgVertexBufferInd strokesGenerator;
|
||||
strokesGenerator.reset(buff.tscale);
|
||||
// trim -> dash -> stroke
|
||||
if ((tbeg != 0.0f) || (tend != 1.0f)) {
|
||||
if (tbeg == tend) return;
|
||||
|
@ -464,17 +464,17 @@ void WgRenderDataShape::proceedStrokes(WgContext context, const RenderStroke* rs
|
|||
trimed_buff.trim(buff, tbeg, tend);
|
||||
trimed_buff.updateDistances();
|
||||
// trim ->dash -> stroke
|
||||
if (rstroke->dashPattern) gStrokesGenerator->appendStrokesDashed(trimed_buff, rstroke);
|
||||
if (rstroke->dashPattern) strokesGenerator.appendStrokesDashed(trimed_buff, rstroke);
|
||||
// trim -> stroke
|
||||
else gStrokesGenerator->appendStrokes(trimed_buff, rstroke);
|
||||
else strokesGenerator.appendStrokes(trimed_buff, rstroke);
|
||||
} else
|
||||
// dash -> stroke
|
||||
if (rstroke->dashPattern) {
|
||||
gStrokesGenerator->appendStrokesDashed(buff, rstroke);
|
||||
strokesGenerator.appendStrokesDashed(buff, rstroke);
|
||||
// stroke
|
||||
} else
|
||||
gStrokesGenerator->appendStrokes(buff, rstroke);
|
||||
appendStroke(context, *gStrokesGenerator);
|
||||
strokesGenerator.appendStrokes(buff, rstroke);
|
||||
appendStroke(context, strokesGenerator);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -50,14 +50,13 @@ private:
|
|||
Array<WgMeshData*> mPool;
|
||||
Array<WgMeshData*> mList;
|
||||
public:
|
||||
static WgMeshDataPool* gMeshDataPool;
|
||||
WgMeshData* allocate(WgContext& context);
|
||||
void free(WgContext& context, WgMeshData* meshData);
|
||||
void release(WgContext& context);
|
||||
};
|
||||
|
||||
struct WgMeshDataGroup {
|
||||
static WgMeshDataPool* gMeshDataPool;
|
||||
|
||||
Array<WgMeshData*> meshes{};
|
||||
|
||||
void append(WgContext& context, const WgVertexBuffer& vertexBuffer);
|
||||
|
@ -96,9 +95,6 @@ struct WgRenderSettings
|
|||
|
||||
struct WgRenderDataPaint
|
||||
{
|
||||
// global strokes generator. single instance
|
||||
static WgVertexBufferInd* gStrokesGenerator;
|
||||
|
||||
WGPUBuffer bufferModelMat{};
|
||||
WGPUBuffer bufferBlendSettings{};
|
||||
WGPUBindGroup bindGroupPaint{};
|
||||
|
|
|
@ -30,47 +30,45 @@ WgRenderer::WgRenderer()
|
|||
WgRenderer::~WgRenderer()
|
||||
{
|
||||
release();
|
||||
mContext.release();
|
||||
}
|
||||
|
||||
|
||||
void WgRenderer::initialize()
|
||||
{
|
||||
mPipelines.initialize(mContext);
|
||||
WgMeshDataGroup::gMeshDataPool = new WgMeshDataPool();
|
||||
WgRenderDataShape::gStrokesGenerator = new WgVertexBufferInd();
|
||||
}
|
||||
|
||||
|
||||
void WgRenderer::release()
|
||||
{
|
||||
// check for general context availability
|
||||
if (!mContext.queue) return;
|
||||
|
||||
// dispose stored objects
|
||||
disposeObjects();
|
||||
mStorageRoot.release(mContext);
|
||||
mRenderStoragePool.release(mContext);
|
||||
mRenderDataShapePool.release(mContext);
|
||||
delete WgRenderDataShape::gStrokesGenerator;
|
||||
WgMeshDataGroup::gMeshDataPool->release(mContext);
|
||||
delete WgMeshDataGroup::gMeshDataPool;
|
||||
|
||||
// clear rendering tree stacks
|
||||
mCompositorStack.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);
|
||||
if (gpuOwner) {
|
||||
if (device) wgpuDeviceRelease(device);
|
||||
device = nullptr;
|
||||
if (adapter) wgpuAdapterRelease(adapter);
|
||||
adapter = nullptr;
|
||||
gpuOwner = false;
|
||||
}
|
||||
releaseSurfaceTexture();
|
||||
mContext.release();
|
||||
|
||||
// release gpu handles
|
||||
clearTargets();
|
||||
releaseDevice();
|
||||
}
|
||||
|
||||
|
||||
void WgRenderer::disposeObjects()
|
||||
{
|
||||
if (mDisposeRenderDatas.count == 0) return;
|
||||
|
||||
for (auto p = mDisposeRenderDatas.begin(); p < mDisposeRenderDatas.end(); p++) {
|
||||
auto renderData = (WgRenderDataPaint*)(*p);
|
||||
for (uint32_t i = 0; i < mDisposeRenderDatas.count; i++) {
|
||||
WgRenderDataPaint* renderData = (WgRenderDataPaint*)mDisposeRenderDatas[i];
|
||||
if (renderData->type() == Type::Shape) {
|
||||
mRenderDataShapePool.free(mContext, (WgRenderDataShape*)renderData);
|
||||
} else {
|
||||
|
@ -260,20 +258,26 @@ void WgRenderer::releaseSurfaceTexture()
|
|||
bool WgRenderer::sync()
|
||||
{
|
||||
disposeObjects();
|
||||
if (!surface) return false;
|
||||
|
||||
// if texture buffer used
|
||||
WGPUTexture dstTexture = targetTexture;
|
||||
if (surface) {
|
||||
releaseSurfaceTexture();
|
||||
|
||||
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
|
||||
const WGPUCommandEncoderDescriptor commandEncoderDesc{};
|
||||
WGPUCommandEncoder commandEncoder = wgpuDeviceCreateCommandEncoder(mContext.device, &commandEncoderDesc);
|
||||
|
||||
// show root offscreen buffer
|
||||
mCompositor.blit(mContext, commandEncoder, &mStorageRoot, dstView);
|
||||
mCompositor.blit(mContext, commandEncoder, &mStorageRoot, dstTextureView);
|
||||
|
||||
// release command encoder
|
||||
const WGPUCommandBufferDescriptor commandBufferDesc{};
|
||||
|
@ -281,20 +285,54 @@ bool WgRenderer::sync()
|
|||
wgpuQueueSubmit(mContext.queue, 1, &commandsBuffer);
|
||||
wgpuCommandBufferRelease(commandsBuffer);
|
||||
wgpuCommandEncoderRelease(commandEncoder);
|
||||
mContext.releaseTextureView(dstView);
|
||||
|
||||
// release dest buffer view
|
||||
mContext.releaseTextureView(dstTextureView);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// target for native window handle
|
||||
bool WgRenderer::target(WGPUInstance instance, WGPUSurface surface, uint32_t w, uint32_t h, WGPUDevice device)
|
||||
// render target handle
|
||||
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;
|
||||
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
|
||||
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; };
|
||||
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);
|
||||
|
||||
// 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; };
|
||||
wgpuAdapterRequestDevice(this->adapter, &deviceDesc, onDeviceRequestEnded, &this->device);
|
||||
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;
|
||||
|
||||
void WgRenderer::releaseDevice()
|
||||
{
|
||||
if (!gpuOwner) return;
|
||||
wgpuDeviceRelease(device);
|
||||
wgpuDeviceDestroy(device);
|
||||
wgpuAdapterRelease(adapter);
|
||||
device = nullptr;
|
||||
adapter = nullptr;
|
||||
gpuOwner = false;
|
||||
}
|
||||
|
||||
bool WgRenderer::target(WGPUSurface surface, uint32_t w, uint32_t h) {
|
||||
|
||||
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
|
||||
this->surface = surface;
|
||||
mTargetSurface.stride = w;
|
||||
mTargetSurface.w = w;
|
||||
mTargetSurface.h = h;
|
||||
if (w == 0 || h == 0) return false;
|
||||
if (!surface) return true;
|
||||
if (width == 0 || height == 0 || !surface) return false;
|
||||
|
||||
// setup surface configuration
|
||||
WGPUSurfaceConfiguration surfaceConfiguration {
|
||||
.device = mContext.device,
|
||||
.format = mContext.preferredFormat,
|
||||
.device = context.device,
|
||||
.format = context.preferredFormat,
|
||||
.usage = WGPUTextureUsage_RenderAttachment,
|
||||
#ifdef __EMSCRIPTEN__
|
||||
.alphaMode = WGPUCompositeAlphaMode_Premultiplied,
|
||||
#endif
|
||||
.width = w, .height = h,
|
||||
#ifdef __EMSCRIPTEN__
|
||||
.width = width,
|
||||
.height = height,
|
||||
#ifndef __EMSCRIPTEN__
|
||||
.presentMode = WGPUPresentMode_Fifo,
|
||||
#else
|
||||
.presentMode = WGPUPresentMode_Immediate
|
||||
#endif
|
||||
};
|
||||
wgpuSurfaceConfigure(surface, &surfaceConfiguration);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -369,7 +414,7 @@ bool WgRenderer::beginComposite(RenderCompositor* cmp, MaskMethod method, uint8_
|
|||
mRenderStorageStack.push(storage);
|
||||
// begin newly added render pass
|
||||
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);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -45,8 +45,7 @@ public:
|
|||
bool clear() override;
|
||||
bool sync() override;
|
||||
|
||||
bool target(WGPUInstance instance, WGPUSurface surface, uint32_t w, uint32_t h, WGPUDevice device);
|
||||
bool target(WGPUSurface surface, uint32_t w, uint32_t h);
|
||||
bool target(WGPUDevice device, WGPUInstance instance, void* target, uint32_t width, uint32_t height, int type = 0);
|
||||
|
||||
RenderCompositor* target(const RenderRegion& region, ColorSpace cs) override;
|
||||
bool beginComposite(RenderCompositor* cmp, MaskMethod method, uint8_t opacity) override;
|
||||
|
@ -59,8 +58,6 @@ public:
|
|||
static bool init(uint32_t threads);
|
||||
static bool term();
|
||||
|
||||
WGPUSurface surface{}; // external handle
|
||||
|
||||
private:
|
||||
WgRenderer();
|
||||
~WgRenderer();
|
||||
|
@ -69,28 +66,37 @@ private:
|
|||
void disposeObjects();
|
||||
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{};
|
||||
WgRenderDataShapePool mRenderDataShapePool;
|
||||
|
||||
// render tree stacks
|
||||
// render tree stacks and pools
|
||||
WgRenderStorage mStorageRoot;
|
||||
Array<WgCompose*> mCompositorStack;
|
||||
Array<WgRenderStorage*> mRenderStorageStack;
|
||||
WgRenderStoragePool mRenderStoragePool;
|
||||
WgRenderDataShapePool mRenderDataShapePool;
|
||||
|
||||
// rendering context
|
||||
WgContext mContext;
|
||||
WgPipelines mPipelines;
|
||||
WgCompositor mCompositor;
|
||||
|
||||
// rendering states
|
||||
RenderSurface mTargetSurface;
|
||||
BlendMethod mBlendMethod{};
|
||||
RenderRegion mViewport{};
|
||||
|
||||
// disposable data list
|
||||
Array<RenderData> mDisposeRenderDatas{};
|
||||
Key mDisposeKey{};
|
||||
|
||||
// gpu handles
|
||||
WGPUCommandEncoder mCommandEncoder{};
|
||||
WGPUTexture targetTexture{}; // external handle
|
||||
WGPUSurfaceTexture surfaceTexture{};
|
||||
WGPUSurface surface{}; // external handle
|
||||
WGPUAdapter adapter{};
|
||||
WGPUDevice device{};
|
||||
bool gpuOwner{};
|
||||
|
|
Loading…
Add table
Reference in a new issue