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] w The width 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::NonSupport In case the wg engine is not supported.
|
||||
*
|
||||
|
@ -1754,7 +1754,7 @@ public:
|
|||
* @see Canvas::viewport()
|
||||
* @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.
|
||||
|
|
|
@ -50,11 +50,14 @@ WgCanvas::WgCanvas() : Canvas(nullptr), pImpl(nullptr)
|
|||
|
||||
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
|
||||
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);
|
||||
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};
|
||||
renderer->viewport(Canvas::pImpl->vport);
|
||||
|
||||
|
|
|
@ -25,43 +25,16 @@
|
|||
#endif
|
||||
#include "tvgWgCommon.h"
|
||||
#include "tvgArray.h"
|
||||
#include <iostream>
|
||||
|
||||
void WgContext::initialize(WGPUInstance instance, WGPUSurface surface)
|
||||
void WgContext::initialize(WGPUInstance instance, WGPUDevice device)
|
||||
{
|
||||
assert(instance);
|
||||
assert(surface);
|
||||
assert(device);
|
||||
|
||||
// store global instance and surface
|
||||
this->instance = instance;
|
||||
this->surface = surface;
|
||||
|
||||
// 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);
|
||||
this->device = device;
|
||||
this->preferredFormat = WGPUTextureFormat_BGRA8Unorm;
|
||||
|
||||
// get current queue
|
||||
queue = wgpuDeviceGetQueue(device);
|
||||
|
@ -87,8 +60,6 @@ void WgContext::release()
|
|||
releaseSampler(samplerLinearRepeat);
|
||||
releaseSampler(samplerNearestRepeat);
|
||||
releaseBuffer(bufferIndexFan);
|
||||
wgpuDeviceRelease(device);
|
||||
wgpuAdapterRelease(adapter);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -34,10 +34,9 @@ class WgPipelines;
|
|||
struct WgContext {
|
||||
// external webgpu handles
|
||||
WGPUInstance instance{};
|
||||
WGPUSurface surface{};
|
||||
// common webgpu handles
|
||||
WGPUAdapter adapter{};
|
||||
WGPUDevice device{};
|
||||
// common webgpu handles
|
||||
WGPUQueue queue{};
|
||||
WGPUTextureFormat preferredFormat{};
|
||||
// external handles (do not release)
|
||||
|
@ -49,7 +48,7 @@ struct WgContext {
|
|||
WGPUSampler samplerLinearMirror{};
|
||||
WGPUSampler samplerLinearClamp{};
|
||||
|
||||
void initialize(WGPUInstance instance, WGPUSurface surface);
|
||||
void initialize(WGPUInstance instance, WGPUDevice device);
|
||||
void release();
|
||||
|
||||
// create common objects
|
||||
|
|
|
@ -56,6 +56,13 @@ void WgRenderer::release()
|
|||
mCompositorStack.clear();
|
||||
mRenderStorageStack.clear();
|
||||
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()
|
||||
{
|
||||
disposeObjects();
|
||||
if (!surface) return false;
|
||||
// get current texture
|
||||
WGPUSurfaceTexture surfaceTexture{};
|
||||
wgpuSurfaceGetCurrentTexture(mContext.surface, &surfaceTexture);
|
||||
wgpuSurfaceGetCurrentTexture(surface, &surfaceTexture);
|
||||
WGPUTextureView dstView = mContext.createTextureView(surfaceTexture.texture);
|
||||
|
||||
// create command encoder
|
||||
|
@ -271,14 +279,44 @@ bool WgRenderer::sync()
|
|||
|
||||
|
||||
// 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
|
||||
mTargetSurface.stride = w;
|
||||
mTargetSurface.w = w > 0 ? w : 1;
|
||||
mTargetSurface.h = h > 0 ? h : 1;
|
||||
gpuOwner = false;
|
||||
this->device = device;
|
||||
if (!this->device) {
|
||||
// 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 {
|
||||
.device = mContext.device,
|
||||
|
@ -292,10 +330,7 @@ bool WgRenderer::target(WGPUInstance instance, WGPUSurface surface, uint32_t w,
|
|||
#endif
|
||||
};
|
||||
wgpuSurfaceConfigure(surface, &surfaceConfiguration);
|
||||
initialize();
|
||||
mRenderStoragePool.initialize(mContext, w, h);
|
||||
mStorageRoot.initialize(mContext, w, h);
|
||||
mCompositor.initialize(mContext, w, h);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,7 +45,8 @@ public:
|
|||
bool clear() 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;
|
||||
bool beginComposite(Compositor* cmp, CompositeMethod method, uint8_t opacity) override;
|
||||
|
@ -55,6 +56,8 @@ public:
|
|||
static bool init(uint32_t threads);
|
||||
static bool term();
|
||||
|
||||
WGPUSurface surface{}; // external handle
|
||||
|
||||
private:
|
||||
WgRenderer();
|
||||
~WgRenderer();
|
||||
|
@ -81,6 +84,10 @@ private:
|
|||
|
||||
Array<RenderData> mDisposeRenderDatas{};
|
||||
Key mDisposeKey{};
|
||||
|
||||
WGPUAdapter adapter{};
|
||||
WGPUDevice device{};
|
||||
bool gpuOwner{};
|
||||
};
|
||||
|
||||
#endif /* _TVG_WG_RENDERER_H_ */
|
||||
|
|
Loading…
Add table
Reference in a new issue