mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-08 13:43:43 +00:00
wg_engine: external device handles (web integration)
move instance, adapter and device creation from renderer to application its necessary for web integration, because browser have its own mechanics to create hardware handles this changes makes webgpu canvas more universal to use in case of system and web applications issue: https://github.com/thorvg/thorvg/issues/2410
This commit is contained in:
parent
d807ac91ea
commit
e2e4fc6964
7 changed files with 69 additions and 54 deletions
|
@ -1745,7 +1745,7 @@ public:
|
||||||
* @param[in] surface WGPUSurface, handle to a presentable surface.
|
* @param[in] surface WGPUSurface, handle to a presentable surface.
|
||||||
* @param[in] w The width of the surface.
|
* @param[in] w The width of the surface.
|
||||||
* @param[in] h The height of the surface.
|
* @param[in] h The height of the surface.
|
||||||
*
|
* @param[in] device WGPUDevice: desired handle for the WebGPU device. If it is nullptr, ThorVG will assign an appropriate device internally.
|
||||||
* @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.
|
||||||
*
|
*
|
||||||
|
@ -1754,7 +1754,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) noexcept;
|
Result target(void* instance, void* surface, uint32_t w, uint32_t h, void* device = nullptr) noexcept;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates a new WgCanvas object.
|
* @brief Creates a new WgCanvas object.
|
||||||
|
|
|
@ -50,11 +50,14 @@ WgCanvas::WgCanvas() : Canvas(nullptr), pImpl(nullptr)
|
||||||
|
|
||||||
WgCanvas::~WgCanvas()
|
WgCanvas::~WgCanvas()
|
||||||
{
|
{
|
||||||
delete pImpl;
|
#ifdef THORVG_WG_RASTER_SUPPORT
|
||||||
|
auto renderer = static_cast<WgRenderer*>(Canvas::pImpl->renderer);
|
||||||
|
renderer->target(nullptr, 0, 0);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Result WgCanvas::target(void* instance, void* surface, uint32_t w, uint32_t h) noexcept
|
Result WgCanvas::target(void* instance, void* surface, uint32_t w, uint32_t h, void* device) 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) {
|
||||||
|
@ -67,7 +70,7 @@ Result WgCanvas::target(void* instance, void* surface, uint32_t w, uint32_t h) n
|
||||||
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)) return Result::Unknown;
|
if (!renderer->target((WGPUInstance)instance, (WGPUSurface)surface, w, h, (WGPUDevice)device)) 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);
|
||||||
|
|
||||||
|
|
|
@ -25,43 +25,16 @@
|
||||||
#endif
|
#endif
|
||||||
#include "tvgWgCommon.h"
|
#include "tvgWgCommon.h"
|
||||||
#include "tvgArray.h"
|
#include "tvgArray.h"
|
||||||
#include <iostream>
|
|
||||||
|
|
||||||
void WgContext::initialize(WGPUInstance instance, WGPUSurface surface)
|
void WgContext::initialize(WGPUInstance instance, WGPUDevice device)
|
||||||
{
|
{
|
||||||
assert(instance);
|
assert(instance);
|
||||||
assert(surface);
|
assert(device);
|
||||||
|
|
||||||
// store global instance and surface
|
// store global instance and surface
|
||||||
this->instance = instance;
|
this->instance = instance;
|
||||||
this->surface = surface;
|
this->device = device;
|
||||||
|
this->preferredFormat = WGPUTextureFormat_BGRA8Unorm;
|
||||||
// request adapter
|
|
||||||
const WGPURequestAdapterOptions requestAdapterOptions { .nextInChain = nullptr, .compatibleSurface = surface, .powerPreference = WGPUPowerPreference_HighPerformance, .forceFallbackAdapter = false };
|
|
||||||
auto onAdapterRequestEnded = [](WGPURequestAdapterStatus status, WGPUAdapter adapter, char const * message, void * pUserData) { *((WGPUAdapter*)pUserData) = adapter; };
|
|
||||||
wgpuInstanceRequestAdapter(instance, &requestAdapterOptions, onAdapterRequestEnded, &adapter);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
while (!adapter) emscripten_sleep(10);
|
|
||||||
#endif
|
|
||||||
assert(adapter);
|
|
||||||
|
|
||||||
// get adapter and surface properties
|
|
||||||
WGPUFeatureName featureNames[32]{};
|
|
||||||
size_t featuresCount = wgpuAdapterEnumerateFeatures(adapter, featureNames);
|
|
||||||
preferredFormat = WGPUTextureFormat_BGRA8Unorm;
|
|
||||||
|
|
||||||
// request device
|
|
||||||
const WGPUDeviceDescriptor deviceDesc { .nextInChain = nullptr, .label = "The device", .requiredFeatureCount = featuresCount, .requiredFeatures = featureNames };
|
|
||||||
auto onDeviceRequestEnded = [](WGPURequestDeviceStatus status, WGPUDevice device, char const * message, void * pUserData) { *((WGPUDevice*)pUserData) = device; };
|
|
||||||
wgpuAdapterRequestDevice(adapter, &deviceDesc, onDeviceRequestEnded, &device);
|
|
||||||
#ifdef __EMSCRIPTEN__
|
|
||||||
while (!device) emscripten_sleep(10);
|
|
||||||
#endif
|
|
||||||
assert(device);
|
|
||||||
|
|
||||||
// device uncaptured error callback
|
|
||||||
auto onDeviceError = [](WGPUErrorType type, char const* message, void* pUserData) { std::cout << message << std::endl; };
|
|
||||||
wgpuDeviceSetUncapturedErrorCallback(device, onDeviceError, nullptr);
|
|
||||||
|
|
||||||
// get current queue
|
// get current queue
|
||||||
queue = wgpuDeviceGetQueue(device);
|
queue = wgpuDeviceGetQueue(device);
|
||||||
|
@ -87,8 +60,6 @@ void WgContext::release()
|
||||||
releaseSampler(samplerLinearRepeat);
|
releaseSampler(samplerLinearRepeat);
|
||||||
releaseSampler(samplerNearestRepeat);
|
releaseSampler(samplerNearestRepeat);
|
||||||
releaseBuffer(bufferIndexFan);
|
releaseBuffer(bufferIndexFan);
|
||||||
wgpuDeviceRelease(device);
|
|
||||||
wgpuAdapterRelease(adapter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -34,10 +34,9 @@ class WgPipelines;
|
||||||
struct WgContext {
|
struct WgContext {
|
||||||
// external webgpu handles
|
// external webgpu handles
|
||||||
WGPUInstance instance{};
|
WGPUInstance instance{};
|
||||||
WGPUSurface surface{};
|
|
||||||
// common webgpu handles
|
|
||||||
WGPUAdapter adapter{};
|
WGPUAdapter adapter{};
|
||||||
WGPUDevice device{};
|
WGPUDevice device{};
|
||||||
|
// common webgpu handles
|
||||||
WGPUQueue queue{};
|
WGPUQueue queue{};
|
||||||
WGPUTextureFormat preferredFormat{};
|
WGPUTextureFormat preferredFormat{};
|
||||||
// external handles (do not release)
|
// external handles (do not release)
|
||||||
|
@ -49,7 +48,7 @@ struct WgContext {
|
||||||
WGPUSampler samplerLinearMirror{};
|
WGPUSampler samplerLinearMirror{};
|
||||||
WGPUSampler samplerLinearClamp{};
|
WGPUSampler samplerLinearClamp{};
|
||||||
|
|
||||||
void initialize(WGPUInstance instance, WGPUSurface surface);
|
void initialize(WGPUInstance instance, WGPUDevice device);
|
||||||
void release();
|
void release();
|
||||||
|
|
||||||
// create common objects
|
// create common objects
|
||||||
|
|
|
@ -56,6 +56,13 @@ void WgRenderer::release()
|
||||||
mCompositorStack.clear();
|
mCompositorStack.clear();
|
||||||
mRenderStorageStack.clear();
|
mRenderStorageStack.clear();
|
||||||
mPipelines.release(mContext);
|
mPipelines.release(mContext);
|
||||||
|
if (gpuOwner) {
|
||||||
|
if (device) wgpuDeviceRelease(device);
|
||||||
|
device = nullptr;
|
||||||
|
if (adapter) wgpuAdapterRelease(adapter);
|
||||||
|
adapter = nullptr;
|
||||||
|
gpuOwner = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -246,9 +253,10 @@ bool WgRenderer::clear()
|
||||||
bool WgRenderer::sync()
|
bool WgRenderer::sync()
|
||||||
{
|
{
|
||||||
disposeObjects();
|
disposeObjects();
|
||||||
|
if (!surface) return false;
|
||||||
// get current texture
|
// get current texture
|
||||||
WGPUSurfaceTexture surfaceTexture{};
|
WGPUSurfaceTexture surfaceTexture{};
|
||||||
wgpuSurfaceGetCurrentTexture(mContext.surface, &surfaceTexture);
|
wgpuSurfaceGetCurrentTexture(surface, &surfaceTexture);
|
||||||
WGPUTextureView dstView = mContext.createTextureView(surfaceTexture.texture);
|
WGPUTextureView dstView = mContext.createTextureView(surfaceTexture.texture);
|
||||||
|
|
||||||
// create command encoder
|
// create command encoder
|
||||||
|
@ -271,14 +279,44 @@ bool WgRenderer::sync()
|
||||||
|
|
||||||
|
|
||||||
// target for native window handle
|
// target for native window handle
|
||||||
bool WgRenderer::target(WGPUInstance instance, WGPUSurface surface, uint32_t w, uint32_t h)
|
bool WgRenderer::target(WGPUInstance instance, WGPUSurface surface, uint32_t w, uint32_t h, WGPUDevice device)
|
||||||
{
|
{
|
||||||
// store target surface properties
|
gpuOwner = false;
|
||||||
mTargetSurface.stride = w;
|
this->device = device;
|
||||||
mTargetSurface.w = w > 0 ? w : 1;
|
if (!this->device) {
|
||||||
mTargetSurface.h = h > 0 ? h : 1;
|
// request adapter
|
||||||
|
const WGPURequestAdapterOptions requestAdapterOptions { .nextInChain = nullptr, .compatibleSurface = surface, .powerPreference = WGPUPowerPreference_HighPerformance, .forceFallbackAdapter = false };
|
||||||
|
auto onAdapterRequestEnded = [](WGPURequestAdapterStatus status, WGPUAdapter adapter, char const * message, void * pUserData) { *((WGPUAdapter*)pUserData) = adapter; };
|
||||||
|
wgpuInstanceRequestAdapter(instance, &requestAdapterOptions, onAdapterRequestEnded, &this->adapter);
|
||||||
|
|
||||||
mContext.initialize(instance, surface);
|
// get adapter and surface properties
|
||||||
|
WGPUFeatureName featureNames[32]{};
|
||||||
|
size_t featuresCount = wgpuAdapterEnumerateFeatures(this->adapter, featureNames);
|
||||||
|
|
||||||
|
// request device
|
||||||
|
const WGPUDeviceDescriptor deviceDesc { .nextInChain = nullptr, .label = "The 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool WgRenderer::target(WGPUSurface surface, uint32_t w, uint32_t h) {
|
||||||
|
// 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;
|
||||||
|
|
||||||
WGPUSurfaceConfiguration surfaceConfiguration {
|
WGPUSurfaceConfiguration surfaceConfiguration {
|
||||||
.device = mContext.device,
|
.device = mContext.device,
|
||||||
|
@ -292,10 +330,7 @@ bool WgRenderer::target(WGPUInstance instance, WGPUSurface surface, uint32_t w,
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
wgpuSurfaceConfigure(surface, &surfaceConfiguration);
|
wgpuSurfaceConfigure(surface, &surfaceConfiguration);
|
||||||
initialize();
|
|
||||||
mRenderStoragePool.initialize(mContext, w, h);
|
|
||||||
mStorageRoot.initialize(mContext, w, h);
|
|
||||||
mCompositor.initialize(mContext, w, h);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -45,7 +45,8 @@ 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);
|
bool target(WGPUInstance instance, WGPUSurface surface, uint32_t w, uint32_t h, WGPUDevice device);
|
||||||
|
bool target(WGPUSurface surface, uint32_t w, uint32_t h);
|
||||||
|
|
||||||
Compositor* target(const RenderRegion& region, ColorSpace cs) override;
|
Compositor* target(const RenderRegion& region, ColorSpace cs) override;
|
||||||
bool beginComposite(Compositor* cmp, CompositeMethod method, uint8_t opacity) override;
|
bool beginComposite(Compositor* cmp, CompositeMethod method, uint8_t opacity) override;
|
||||||
|
@ -55,6 +56,8 @@ 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();
|
||||||
|
@ -81,6 +84,10 @@ private:
|
||||||
|
|
||||||
Array<RenderData> mDisposeRenderDatas{};
|
Array<RenderData> mDisposeRenderDatas{};
|
||||||
Key mDisposeKey{};
|
Key mDisposeKey{};
|
||||||
|
|
||||||
|
WGPUAdapter adapter{};
|
||||||
|
WGPUDevice device{};
|
||||||
|
bool gpuOwner{};
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* _TVG_WG_RENDERER_H_ */
|
#endif /* _TVG_WG_RENDERER_H_ */
|
||||||
|
|
Loading…
Add table
Reference in a new issue