mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-14 12:04:29 +00:00
wg_engine: refactor render targets handling
For further development of features, we need to create off-screen buffers that will allow us to implement functionality related to composition and blending, as well as for loading data to system memory from the framebuffer. Separating the framebuffer into a separate entity allows you to create several instances of them, switch between them, and blend them according to given rules. For current time we have only a single render target instance, that have a handle to drawing into surface surface, like a native window. New approach allows: - offscreen rendering - render pass handling - switching between render targets - ability to render images, strokes and shapes into independent render targets
This commit is contained in:
parent
51a69880fd
commit
1a6571f596
5 changed files with 329 additions and 180 deletions
|
@ -5,6 +5,7 @@ source_file = [
|
||||||
'tvgWgPipelines.h',
|
'tvgWgPipelines.h',
|
||||||
'tvgWgRenderData.h',
|
'tvgWgRenderData.h',
|
||||||
'tvgWgRenderer.h',
|
'tvgWgRenderer.h',
|
||||||
|
'tvgWgRenderTarget.h',
|
||||||
'tvgWgShaderSrc.h',
|
'tvgWgShaderSrc.h',
|
||||||
'tvgWgShaderTypes.h'
|
'tvgWgShaderTypes.h'
|
||||||
'tvgWgBindGroups.cpp',
|
'tvgWgBindGroups.cpp',
|
||||||
|
@ -13,6 +14,7 @@ source_file = [
|
||||||
'tvgWgPipelines.cpp',
|
'tvgWgPipelines.cpp',
|
||||||
'tvgWgRenderData.cpp',
|
'tvgWgRenderData.cpp',
|
||||||
'tvgWgRenderer.cpp',
|
'tvgWgRenderer.cpp',
|
||||||
|
'tvgWgRenderTarget.cpp',
|
||||||
'tvgWgShaderSrc.cpp',
|
'tvgWgShaderSrc.cpp',
|
||||||
'tvgWgShaderTypes.cpp'
|
'tvgWgShaderTypes.cpp'
|
||||||
]
|
]
|
||||||
|
|
245
src/renderer/wg_engine/tvgWgRenderTarget.cpp
Normal file
245
src/renderer/wg_engine/tvgWgRenderTarget.cpp
Normal file
|
@ -0,0 +1,245 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 the ThorVG project. All rights reserved.
|
||||||
|
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "tvgWgRenderTarget.h"
|
||||||
|
|
||||||
|
void WgRenderTarget::initialize(WGPUDevice device, WGPUQueue queue, WgPipelines& pipelines, uint32_t w, uint32_t h)
|
||||||
|
{
|
||||||
|
release();
|
||||||
|
// sampler descriptor
|
||||||
|
WGPUSamplerDescriptor samplerDesc{};
|
||||||
|
samplerDesc.nextInChain = nullptr;
|
||||||
|
samplerDesc.label = "The target sampler";
|
||||||
|
samplerDesc.addressModeU = WGPUAddressMode_ClampToEdge;
|
||||||
|
samplerDesc.addressModeV = WGPUAddressMode_ClampToEdge;
|
||||||
|
samplerDesc.addressModeW = WGPUAddressMode_ClampToEdge;
|
||||||
|
samplerDesc.magFilter = WGPUFilterMode_Nearest;
|
||||||
|
samplerDesc.minFilter = WGPUFilterMode_Nearest;
|
||||||
|
samplerDesc.mipmapFilter = WGPUMipmapFilterMode_Nearest;
|
||||||
|
samplerDesc.lodMinClamp = 0.0f;
|
||||||
|
samplerDesc.lodMaxClamp = 32.0f;
|
||||||
|
samplerDesc.compare = WGPUCompareFunction_Undefined;
|
||||||
|
samplerDesc.maxAnisotropy = 1;
|
||||||
|
mSampler = wgpuDeviceCreateSampler(device, &samplerDesc);
|
||||||
|
assert(mSampler);
|
||||||
|
// texture descriptor
|
||||||
|
WGPUTextureDescriptor textureDescColor{};
|
||||||
|
textureDescColor.nextInChain = nullptr;
|
||||||
|
textureDescColor.label = "The target texture color";
|
||||||
|
textureDescColor.usage = WGPUTextureUsage_RenderAttachment | WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst;
|
||||||
|
textureDescColor.dimension = WGPUTextureDimension_2D;
|
||||||
|
textureDescColor.size = { w, h, 1 };
|
||||||
|
textureDescColor.format = WGPUTextureFormat_RGBA8Unorm;
|
||||||
|
textureDescColor.mipLevelCount = 1;
|
||||||
|
textureDescColor.sampleCount = 1;
|
||||||
|
textureDescColor.viewFormatCount = 0;
|
||||||
|
textureDescColor.viewFormats = nullptr;
|
||||||
|
mTextureColor = wgpuDeviceCreateTexture(device, &textureDescColor);
|
||||||
|
assert(mTextureColor);
|
||||||
|
// texture view descriptor
|
||||||
|
WGPUTextureViewDescriptor textureViewDescColor{};
|
||||||
|
textureViewDescColor.nextInChain = nullptr;
|
||||||
|
textureViewDescColor.label = "The target texture view color";
|
||||||
|
textureViewDescColor.format = WGPUTextureFormat_RGBA8Unorm;
|
||||||
|
textureViewDescColor.dimension = WGPUTextureViewDimension_2D;
|
||||||
|
textureViewDescColor.baseMipLevel = 0;
|
||||||
|
textureViewDescColor.mipLevelCount = 1;
|
||||||
|
textureViewDescColor.baseArrayLayer = 0;
|
||||||
|
textureViewDescColor.arrayLayerCount = 1;
|
||||||
|
textureViewDescColor.aspect = WGPUTextureAspect_All;
|
||||||
|
mTextureViewColor = wgpuTextureCreateView(mTextureColor, &textureViewDescColor);
|
||||||
|
assert(mTextureViewColor);
|
||||||
|
// stencil texture
|
||||||
|
WGPUTextureDescriptor textureDescStencil{};
|
||||||
|
textureDescStencil.nextInChain = nullptr;
|
||||||
|
textureDescStencil.label = "The target texture stencil";
|
||||||
|
textureDescStencil.usage = WGPUTextureUsage_RenderAttachment;
|
||||||
|
textureDescStencil.dimension = WGPUTextureDimension_2D;
|
||||||
|
textureDescStencil.size = { w, h, 1 };
|
||||||
|
textureDescStencil.format = WGPUTextureFormat_Stencil8;
|
||||||
|
textureDescStencil.mipLevelCount = 1;
|
||||||
|
textureDescStencil.sampleCount = 1;
|
||||||
|
textureDescStencil.viewFormatCount = 0;
|
||||||
|
textureDescStencil.viewFormats = nullptr;
|
||||||
|
mTextureStencil = wgpuDeviceCreateTexture(device, &textureDescStencil);
|
||||||
|
assert(mTextureStencil);
|
||||||
|
// texture view descriptor
|
||||||
|
WGPUTextureViewDescriptor textureViewDescStencil{};
|
||||||
|
textureViewDescStencil.nextInChain = nullptr;
|
||||||
|
textureViewDescStencil.label = "The target texture view stncil";
|
||||||
|
textureViewDescStencil.format = WGPUTextureFormat_Stencil8;
|
||||||
|
textureViewDescStencil.dimension = WGPUTextureViewDimension_2D;
|
||||||
|
textureViewDescStencil.baseMipLevel = 0;
|
||||||
|
textureViewDescStencil.mipLevelCount = 1;
|
||||||
|
textureViewDescStencil.baseArrayLayer = 0;
|
||||||
|
textureViewDescStencil.arrayLayerCount = 1;
|
||||||
|
textureViewDescStencil.aspect = WGPUTextureAspect_All;
|
||||||
|
mTextureViewStencil = wgpuTextureCreateView(mTextureStencil, &textureViewDescStencil);
|
||||||
|
assert(mTextureViewStencil);
|
||||||
|
// initialize window binding groups
|
||||||
|
WgShaderTypeMat4x4f viewMat(w, h);
|
||||||
|
mBindGroupCanvasWnd.initialize(device, queue, viewMat);
|
||||||
|
WgShaderTypeMat4x4f modelMat;
|
||||||
|
WgShaderTypeBlendSettings blendSettings(ColorSpace::ABGR8888);
|
||||||
|
mBindGroupPaintWnd.initialize(device, queue, modelMat, blendSettings);
|
||||||
|
// update pipeline geometry data
|
||||||
|
WgVertexList wnd;
|
||||||
|
wnd.appendRect(WgPoint(0.0f, 0.0f), WgPoint(w, 0.0f), WgPoint(0.0f, h), WgPoint(w, h));
|
||||||
|
mGeometryDataWnd.update(device, queue, &wnd);
|
||||||
|
mPipelines = &pipelines;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WgRenderTarget::release()
|
||||||
|
{
|
||||||
|
mBindGroupCanvasWnd.release();
|
||||||
|
mBindGroupPaintWnd.release();
|
||||||
|
mGeometryDataWnd.release();
|
||||||
|
if (mTextureStencil) {
|
||||||
|
wgpuTextureDestroy(mTextureStencil);
|
||||||
|
wgpuTextureRelease(mTextureStencil);
|
||||||
|
mTextureStencil = nullptr;
|
||||||
|
}
|
||||||
|
if (mTextureViewStencil) wgpuTextureViewRelease(mTextureViewStencil);
|
||||||
|
mTextureViewStencil = nullptr;
|
||||||
|
if (mTextureColor) {
|
||||||
|
wgpuTextureDestroy(mTextureColor);
|
||||||
|
wgpuTextureRelease(mTextureColor);
|
||||||
|
mTextureColor = nullptr;
|
||||||
|
}
|
||||||
|
if (mTextureViewColor) wgpuTextureViewRelease(mTextureViewColor);
|
||||||
|
mTextureViewColor = nullptr;
|
||||||
|
if (mSampler) wgpuSamplerRelease(mSampler);
|
||||||
|
mSampler = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WgRenderTarget::beginRenderPass(WGPUCommandEncoder commandEncoder)
|
||||||
|
{
|
||||||
|
beginRenderPass(commandEncoder, mTextureViewColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WgRenderTarget::beginRenderPass(WGPUCommandEncoder commandEncoder, WGPUTextureView colorAttachement)
|
||||||
|
{
|
||||||
|
assert(!mRenderPassEncoder);
|
||||||
|
// render pass depth stencil attachment
|
||||||
|
WGPURenderPassDepthStencilAttachment depthStencilAttachment{};
|
||||||
|
depthStencilAttachment.view = mTextureViewStencil;
|
||||||
|
depthStencilAttachment.depthLoadOp = WGPULoadOp_Clear;
|
||||||
|
depthStencilAttachment.depthStoreOp = WGPUStoreOp_Store;
|
||||||
|
depthStencilAttachment.depthClearValue = 1.0f;
|
||||||
|
depthStencilAttachment.depthReadOnly = false;
|
||||||
|
depthStencilAttachment.stencilLoadOp = WGPULoadOp_Clear;
|
||||||
|
depthStencilAttachment.stencilStoreOp = WGPUStoreOp_Store;
|
||||||
|
depthStencilAttachment.stencilClearValue = 0;
|
||||||
|
depthStencilAttachment.stencilReadOnly = false;
|
||||||
|
// render pass color attachment
|
||||||
|
WGPURenderPassColorAttachment colorAttachment{};
|
||||||
|
colorAttachment.view = colorAttachement;
|
||||||
|
colorAttachment.resolveTarget = nullptr;
|
||||||
|
colorAttachment.loadOp = WGPULoadOp_Clear;
|
||||||
|
colorAttachment.clearValue = {0, 0, 0, 0};
|
||||||
|
colorAttachment.storeOp = WGPUStoreOp_Store;
|
||||||
|
// render pass descriptor
|
||||||
|
WGPURenderPassDescriptor renderPassDesc{};
|
||||||
|
renderPassDesc.nextInChain = nullptr;
|
||||||
|
renderPassDesc.label = "The render pass";
|
||||||
|
renderPassDesc.colorAttachmentCount = 1;
|
||||||
|
renderPassDesc.colorAttachments = &colorAttachment;
|
||||||
|
renderPassDesc.depthStencilAttachment = &depthStencilAttachment;
|
||||||
|
//renderPassDesc.depthStencilAttachment = nullptr;
|
||||||
|
renderPassDesc.occlusionQuerySet = nullptr;
|
||||||
|
renderPassDesc.timestampWriteCount = 0;
|
||||||
|
renderPassDesc.timestampWrites = nullptr;
|
||||||
|
// begin render pass
|
||||||
|
mRenderPassEncoder = wgpuCommandEncoderBeginRenderPass(commandEncoder, &renderPassDesc);
|
||||||
|
}
|
||||||
|
|
||||||
|
void WgRenderTarget::endRenderPass()
|
||||||
|
{
|
||||||
|
assert(mRenderPassEncoder);
|
||||||
|
wgpuRenderPassEncoderEnd(mRenderPassEncoder);
|
||||||
|
wgpuRenderPassEncoderRelease(mRenderPassEncoder);
|
||||||
|
mRenderPassEncoder = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WgRenderTarget::renderShape(WgRenderDataShape* renderData)
|
||||||
|
{
|
||||||
|
assert(renderData);
|
||||||
|
assert(mRenderPassEncoder);
|
||||||
|
// draw shape geometry
|
||||||
|
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
|
||||||
|
for (uint32_t i = 0; i < renderData->mGeometryDataShape.count; i++) {
|
||||||
|
// draw to stencil (first pass)
|
||||||
|
mPipelines->mPipelineFillShape.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->mBindGroupPaint);
|
||||||
|
renderData->mGeometryDataShape[i]->draw(mRenderPassEncoder);
|
||||||
|
// fill shape (second pass)
|
||||||
|
WgRenderDataShapeSettings& settings = renderData->mRenderSettingsShape;
|
||||||
|
if (settings.mFillType == WgRenderDataShapeFillType::Solid)
|
||||||
|
mPipelines->mPipelineSolid.use(mRenderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupSolid);
|
||||||
|
else if (settings.mFillType == WgRenderDataShapeFillType::Linear)
|
||||||
|
mPipelines->mPipelineLinear.use(mRenderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupLinear);
|
||||||
|
else if (settings.mFillType == WgRenderDataShapeFillType::Radial)
|
||||||
|
mPipelines->mPipelineRadial.use(mRenderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupRadial);
|
||||||
|
mGeometryDataWnd.draw(mRenderPassEncoder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WgRenderTarget::renderStroke(WgRenderDataShape* renderData)
|
||||||
|
{
|
||||||
|
assert(renderData);
|
||||||
|
assert(mRenderPassEncoder);
|
||||||
|
// draw stroke geometry
|
||||||
|
if (renderData->mGeometryDataStroke.count > 0) {
|
||||||
|
// draw strokes to stencil (first pass)
|
||||||
|
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 255);
|
||||||
|
for (uint32_t i = 0; i < renderData->mGeometryDataStroke.count; i++) {
|
||||||
|
mPipelines->mPipelineFillStroke.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->mBindGroupPaint);
|
||||||
|
renderData->mGeometryDataStroke[i]->draw(mRenderPassEncoder);
|
||||||
|
}
|
||||||
|
// fill shape (second pass)
|
||||||
|
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
|
||||||
|
WgRenderDataShapeSettings& settings = renderData->mRenderSettingsStroke;
|
||||||
|
if (settings.mFillType == WgRenderDataShapeFillType::Solid)
|
||||||
|
mPipelines->mPipelineSolid.use(mRenderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupSolid);
|
||||||
|
else if (settings.mFillType == WgRenderDataShapeFillType::Linear)
|
||||||
|
mPipelines->mPipelineLinear.use(mRenderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupLinear);
|
||||||
|
else if (settings.mFillType == WgRenderDataShapeFillType::Radial)
|
||||||
|
mPipelines->mPipelineRadial.use(mRenderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupRadial);
|
||||||
|
mGeometryDataWnd.draw(mRenderPassEncoder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void WgRenderTarget::renderImage(WgRenderDataShape* renderData)
|
||||||
|
{
|
||||||
|
assert(renderData);
|
||||||
|
assert(mRenderPassEncoder);
|
||||||
|
if (renderData->mGeometryDataImage.count > 0) {
|
||||||
|
wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0);
|
||||||
|
for (uint32_t j = 0; j < renderData->mGeometryDataImage.count; j++) {
|
||||||
|
mPipelines->mPipelineImage.use(
|
||||||
|
mRenderPassEncoder,
|
||||||
|
mBindGroupCanvasWnd,
|
||||||
|
renderData->mBindGroupPaint,
|
||||||
|
renderData->mBindGroupPicture);
|
||||||
|
renderData->mGeometryDataImage[j]->drawImage(mRenderPassEncoder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
56
src/renderer/wg_engine/tvgWgRenderTarget.h
Normal file
56
src/renderer/wg_engine/tvgWgRenderTarget.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 the ThorVG project. All rights reserved.
|
||||||
|
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
* The above copyright notice and this permission notice shall be included in all
|
||||||
|
* copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
* SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _TVG_WG_RENDER_TARGET_H_
|
||||||
|
#define _TVG_WG_RENDER_TARGET_H_
|
||||||
|
|
||||||
|
#include "tvgWgRenderData.h"
|
||||||
|
|
||||||
|
class WgRenderTarget {
|
||||||
|
private:
|
||||||
|
// command buffer
|
||||||
|
WGPURenderPassEncoder mRenderPassEncoder{};
|
||||||
|
// fill and blit data
|
||||||
|
WgBindGroupCanvas mBindGroupCanvasWnd;
|
||||||
|
WgBindGroupPaint mBindGroupPaintWnd;
|
||||||
|
WgGeometryData mGeometryDataWnd;
|
||||||
|
// gpu buffers
|
||||||
|
WGPUSampler mSampler{};
|
||||||
|
WGPUTexture mTextureColor{};
|
||||||
|
WGPUTexture mTextureStencil{};
|
||||||
|
WGPUTextureView mTextureViewColor{};
|
||||||
|
WGPUTextureView mTextureViewStencil{};
|
||||||
|
WgPipelines* mPipelines{}; // external handle
|
||||||
|
public:
|
||||||
|
void initialize(WGPUDevice device, WGPUQueue queue, WgPipelines& pipelines, uint32_t w, uint32_t h);
|
||||||
|
void release();
|
||||||
|
|
||||||
|
void beginRenderPass(WGPUCommandEncoder commandEncoder, WGPUTextureView colorAttachement);
|
||||||
|
void beginRenderPass(WGPUCommandEncoder commandEncoder);
|
||||||
|
void endRenderPass();
|
||||||
|
|
||||||
|
void renderShape(WgRenderDataShape* renderData);
|
||||||
|
void renderStroke(WgRenderDataShape* renderData);
|
||||||
|
void renderImage(WgRenderDataShape* renderData);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -114,16 +114,7 @@ void WgRenderer::initialize()
|
||||||
|
|
||||||
void WgRenderer::release()
|
void WgRenderer::release()
|
||||||
{
|
{
|
||||||
if (mStencilTex) {
|
mRenderTarget.release();
|
||||||
wgpuTextureDestroy(mStencilTex);
|
|
||||||
wgpuTextureRelease(mStencilTex);
|
|
||||||
}
|
|
||||||
if (mStencilTexView) wgpuTextureViewRelease(mStencilTexView);
|
|
||||||
if (mSwapChain) wgpuSwapChainRelease(mSwapChain);
|
|
||||||
if (mSurface) wgpuSurfaceRelease(mSurface);
|
|
||||||
mBindGroupCanvasWnd.release();
|
|
||||||
mBindGroupPaintWnd.release();
|
|
||||||
mGeometryDataWnd.release();
|
|
||||||
mPipelines.release();
|
mPipelines.release();
|
||||||
if (mDevice) {
|
if (mDevice) {
|
||||||
wgpuDeviceDestroy(mDevice);
|
wgpuDeviceDestroy(mDevice);
|
||||||
|
@ -276,127 +267,38 @@ bool WgRenderer::sync()
|
||||||
{
|
{
|
||||||
WGPUTextureView backBufferView = wgpuSwapChainGetCurrentTextureView(mSwapChain);
|
WGPUTextureView backBufferView = wgpuSwapChainGetCurrentTextureView(mSwapChain);
|
||||||
|
|
||||||
// command buffer descriptor
|
// command encoder descriptor
|
||||||
|
WGPUCommandEncoderDescriptor commandEncoderDesc{};
|
||||||
|
commandEncoderDesc.nextInChain = nullptr;
|
||||||
|
commandEncoderDesc.label = "The command encoder";
|
||||||
|
WGPUCommandEncoder commandEncoder = wgpuDeviceCreateCommandEncoder(mDevice, &commandEncoderDesc);
|
||||||
|
|
||||||
|
// render datas
|
||||||
|
mRenderTarget.beginRenderPass(commandEncoder, backBufferView);
|
||||||
|
for (size_t i = 0; i < mRenderDatas.count; i++) {
|
||||||
|
WgRenderDataShape* renderData = (WgRenderDataShape*)(mRenderDatas[i]);
|
||||||
|
mRenderTarget.renderShape(renderData);
|
||||||
|
mRenderTarget.renderStroke(renderData);
|
||||||
|
mRenderTarget.renderImage(renderData);
|
||||||
|
}
|
||||||
|
mRenderTarget.endRenderPass();
|
||||||
|
|
||||||
|
// execute command encoder
|
||||||
WGPUCommandBufferDescriptor commandBufferDesc{};
|
WGPUCommandBufferDescriptor commandBufferDesc{};
|
||||||
commandBufferDesc.nextInChain = nullptr;
|
commandBufferDesc.nextInChain = nullptr;
|
||||||
commandBufferDesc.label = "The command buffer";
|
commandBufferDesc.label = "The command buffer";
|
||||||
WGPUCommandBuffer commandsBuffer = nullptr; {
|
WGPUCommandBuffer commandsBuffer{};
|
||||||
// command encoder descriptor
|
commandsBuffer = wgpuCommandEncoderFinish(commandEncoder, &commandBufferDesc);
|
||||||
WGPUCommandEncoderDescriptor commandEncoderDesc{};
|
|
||||||
commandEncoderDesc.nextInChain = nullptr;
|
|
||||||
commandEncoderDesc.label = "The command encoder";
|
|
||||||
// begin render pass
|
|
||||||
WGPUCommandEncoder commandEncoder = wgpuDeviceCreateCommandEncoder(mDevice, &commandEncoderDesc); {
|
|
||||||
// render pass depth stencil attachment
|
|
||||||
WGPURenderPassDepthStencilAttachment depthStencilAttachment{};
|
|
||||||
depthStencilAttachment.view = mStencilTexView;
|
|
||||||
depthStencilAttachment.depthLoadOp = WGPULoadOp_Clear;
|
|
||||||
depthStencilAttachment.depthStoreOp = WGPUStoreOp_Store;
|
|
||||||
depthStencilAttachment.depthClearValue = 1.0f;
|
|
||||||
depthStencilAttachment.depthReadOnly = false;
|
|
||||||
depthStencilAttachment.stencilLoadOp = WGPULoadOp_Clear;
|
|
||||||
depthStencilAttachment.stencilStoreOp = WGPUStoreOp_Store;
|
|
||||||
depthStencilAttachment.stencilClearValue = 0;
|
|
||||||
depthStencilAttachment.stencilReadOnly = false;
|
|
||||||
// render pass color attachment
|
|
||||||
WGPURenderPassColorAttachment colorAttachment{};
|
|
||||||
colorAttachment.view = backBufferView;
|
|
||||||
colorAttachment.resolveTarget = nullptr;
|
|
||||||
if (mClearBuffer) {
|
|
||||||
colorAttachment.loadOp = WGPULoadOp_Clear;
|
|
||||||
colorAttachment.clearValue = {0, 0, 0, 0};
|
|
||||||
} else {
|
|
||||||
colorAttachment.loadOp = WGPULoadOp_Load;
|
|
||||||
}
|
|
||||||
colorAttachment.storeOp = WGPUStoreOp_Store;
|
|
||||||
// render pass descriptor
|
|
||||||
WGPURenderPassDescriptor renderPassDesc{};
|
|
||||||
renderPassDesc.nextInChain = nullptr;
|
|
||||||
renderPassDesc.label = "The render pass";
|
|
||||||
renderPassDesc.colorAttachmentCount = 1;
|
|
||||||
renderPassDesc.colorAttachments = &colorAttachment;
|
|
||||||
renderPassDesc.depthStencilAttachment = &depthStencilAttachment;
|
|
||||||
//renderPassDesc.depthStencilAttachment = nullptr;
|
|
||||||
renderPassDesc.occlusionQuerySet = nullptr;
|
|
||||||
renderPassDesc.timestampWriteCount = 0;
|
|
||||||
renderPassDesc.timestampWrites = nullptr;
|
|
||||||
// begin render pass
|
|
||||||
WGPURenderPassEncoder renderPassEncoder = wgpuCommandEncoderBeginRenderPass(commandEncoder, &renderPassDesc); {
|
|
||||||
// iterate render data
|
|
||||||
for (size_t i = 0; i < mRenderDatas.count; i++) {
|
|
||||||
WgRenderDataShape* renderData = (WgRenderDataShape*)(mRenderDatas[i]);
|
|
||||||
|
|
||||||
// draw shape geometry
|
|
||||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
|
||||||
for (uint32_t j = 0; j < renderData->mGeometryDataShape.count; j++) {
|
|
||||||
// draw to stencil (first pass)
|
|
||||||
mPipelines.mPipelineFillShape.use(renderPassEncoder, mBindGroupCanvasWnd, renderData->mBindGroupPaint);
|
|
||||||
renderData->mGeometryDataShape[j]->draw(renderPassEncoder);
|
|
||||||
// fill shape (second pass)
|
|
||||||
WgRenderDataShapeSettings& settings = renderData->mRenderSettingsShape;
|
|
||||||
if (settings.mFillType == WgRenderDataShapeFillType::Solid)
|
|
||||||
mPipelines.mPipelineSolid.use(renderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupSolid);
|
|
||||||
else if (settings.mFillType == WgRenderDataShapeFillType::Linear)
|
|
||||||
mPipelines.mPipelineLinear.use(renderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupLinear);
|
|
||||||
else if (settings.mFillType == WgRenderDataShapeFillType::Radial)
|
|
||||||
mPipelines.mPipelineRadial.use(renderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupRadial);
|
|
||||||
mGeometryDataWnd.draw(renderPassEncoder);
|
|
||||||
}
|
|
||||||
|
|
||||||
// draw stroke geometry
|
|
||||||
if (renderData->mGeometryDataStroke.count > 0) {
|
|
||||||
// draw strokes to stencil (first pass)
|
|
||||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 255);
|
|
||||||
for (uint32_t j = 0; j < renderData->mGeometryDataStroke.count; j++) {
|
|
||||||
mPipelines.mPipelineFillStroke.use(renderPassEncoder, mBindGroupCanvasWnd, renderData->mBindGroupPaint);
|
|
||||||
renderData->mGeometryDataStroke[j]->draw(renderPassEncoder);
|
|
||||||
}
|
|
||||||
// fill shape (second pass)
|
|
||||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
|
||||||
WgRenderDataShapeSettings& settings = renderData->mRenderSettingsStroke;
|
|
||||||
if (settings.mFillType == WgRenderDataShapeFillType::Solid)
|
|
||||||
mPipelines.mPipelineSolid.use(renderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupSolid);
|
|
||||||
else if (settings.mFillType == WgRenderDataShapeFillType::Linear)
|
|
||||||
mPipelines.mPipelineLinear.use(renderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupLinear);
|
|
||||||
else if (settings.mFillType == WgRenderDataShapeFillType::Radial)
|
|
||||||
mPipelines.mPipelineRadial.use(renderPassEncoder, mBindGroupCanvasWnd, mBindGroupPaintWnd, settings.mBindGroupRadial);
|
|
||||||
mGeometryDataWnd.draw(renderPassEncoder);
|
|
||||||
}
|
|
||||||
|
|
||||||
// render image
|
|
||||||
if (renderData->mGeometryDataImage.count > 0) {
|
|
||||||
wgpuRenderPassEncoderSetStencilReference(renderPassEncoder, 0);
|
|
||||||
for (uint32_t j = 0; j < renderData->mGeometryDataImage.count; j++) {
|
|
||||||
mPipelines.mPipelineImage.use(
|
|
||||||
renderPassEncoder,
|
|
||||||
mBindGroupCanvasWnd,
|
|
||||||
renderData->mBindGroupPaint,
|
|
||||||
renderData->mBindGroupPicture);
|
|
||||||
renderData->mGeometryDataImage[j]->drawImage(renderPassEncoder);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// end render pass
|
|
||||||
wgpuRenderPassEncoderEnd(renderPassEncoder);
|
|
||||||
wgpuRenderPassEncoderRelease(renderPassEncoder);
|
|
||||||
|
|
||||||
// release backbuffer and present
|
|
||||||
wgpuTextureViewRelease(backBufferView);
|
|
||||||
}
|
|
||||||
commandsBuffer = wgpuCommandEncoderFinish(commandEncoder, &commandBufferDesc);
|
|
||||||
wgpuCommandEncoderRelease(commandEncoder);
|
|
||||||
}
|
|
||||||
wgpuQueueSubmit(mQueue, 1, &commandsBuffer);
|
wgpuQueueSubmit(mQueue, 1, &commandsBuffer);
|
||||||
wgpuCommandBufferRelease(commandsBuffer);
|
wgpuCommandBufferRelease(commandsBuffer);
|
||||||
|
wgpuCommandEncoderRelease(commandEncoder);
|
||||||
|
|
||||||
// go to the next frame
|
// go to the next frame
|
||||||
|
wgpuTextureViewRelease(backBufferView);
|
||||||
wgpuSwapChainPresent(mSwapChain);
|
wgpuSwapChainPresent(mSwapChain);
|
||||||
|
|
||||||
mRenderDatas.clear();
|
mRenderDatas.clear();
|
||||||
|
|
||||||
mClearBuffer = false;
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -408,12 +310,6 @@ bool WgRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
|
||||||
mTargetSurface.w = w;
|
mTargetSurface.w = w;
|
||||||
mTargetSurface.h = h;
|
mTargetSurface.h = h;
|
||||||
|
|
||||||
// update view matrix
|
|
||||||
mViewMatrix[0] = +2.0f / w; mViewMatrix[1] = +0.0f; mViewMatrix[2] = +0.0f; mViewMatrix[3] = +0.0f;
|
|
||||||
mViewMatrix[4] = +0.0f; mViewMatrix[5] = -2.0f / h; mViewMatrix[6] = +0.0f; mViewMatrix[7] = +0.0f;
|
|
||||||
mViewMatrix[8] = +0.0f; mViewMatrix[9] = +0.0f; mViewMatrix[10] = -1.0f; mViewMatrix[11] = +0.0f;
|
|
||||||
mViewMatrix[12] = -1.0f; mViewMatrix[13] = +1.0f; mViewMatrix[14] = +0.0f; mViewMatrix[15] = +1.0f;
|
|
||||||
|
|
||||||
// TODO: Add ability to render into offscreen buffer
|
// TODO: Add ability to render into offscreen buffer
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -427,12 +323,6 @@ bool WgRenderer::target(void* window, uint32_t w, uint32_t h)
|
||||||
mTargetSurface.w = w > 0 ? w : 1;
|
mTargetSurface.w = w > 0 ? w : 1;
|
||||||
mTargetSurface.h = h > 0 ? h : 1;
|
mTargetSurface.h = h > 0 ? h : 1;
|
||||||
|
|
||||||
// update view matrix
|
|
||||||
mViewMatrix[0] = +2.0f / w; mViewMatrix[1] = +0.0f; mViewMatrix[2] = +0.0f; mViewMatrix[3] = +0.0f;
|
|
||||||
mViewMatrix[4] = +0.0f; mViewMatrix[5] = -2.0f / h; mViewMatrix[6] = +0.0f; mViewMatrix[7] = +0.0f;
|
|
||||||
mViewMatrix[8] = +0.0f; mViewMatrix[9] = +0.0f; mViewMatrix[10] = -1.0f; mViewMatrix[11] = +0.0f;
|
|
||||||
mViewMatrix[12] = -1.0f; mViewMatrix[13] = +1.0f; mViewMatrix[14] = +0.0f; mViewMatrix[15] = +1.0f;
|
|
||||||
|
|
||||||
// TODO: replace solution to cross-platform realization
|
// TODO: replace solution to cross-platform realization
|
||||||
// surface descriptor from windows hwnd
|
// surface descriptor from windows hwnd
|
||||||
WGPUSurfaceDescriptorFromWindowsHWND surfaceDescHwnd{};
|
WGPUSurfaceDescriptorFromWindowsHWND surfaceDescHwnd{};
|
||||||
|
@ -460,46 +350,7 @@ bool WgRenderer::target(void* window, uint32_t w, uint32_t h)
|
||||||
mSwapChain = wgpuDeviceCreateSwapChain(mDevice, mSurface, &swapChainDesc);
|
mSwapChain = wgpuDeviceCreateSwapChain(mDevice, mSurface, &swapChainDesc);
|
||||||
assert(mSwapChain);
|
assert(mSwapChain);
|
||||||
|
|
||||||
// depth-stencil texture
|
mRenderTarget.initialize(mDevice, mQueue, mPipelines, w, h);
|
||||||
WGPUTextureDescriptor textureDesc{};
|
|
||||||
textureDesc.nextInChain = nullptr;
|
|
||||||
textureDesc.label = "The depth-stencil texture";
|
|
||||||
textureDesc.usage = WGPUTextureUsage_RenderAttachment;
|
|
||||||
textureDesc.dimension = WGPUTextureDimension_2D;
|
|
||||||
textureDesc.size = { swapChainDesc.width, swapChainDesc.height, 1 }; // window size
|
|
||||||
textureDesc.format = WGPUTextureFormat_Stencil8;
|
|
||||||
textureDesc.mipLevelCount = 1;
|
|
||||||
textureDesc.sampleCount = 1;
|
|
||||||
textureDesc.viewFormatCount = 0;
|
|
||||||
textureDesc.viewFormats = nullptr;
|
|
||||||
mStencilTex = wgpuDeviceCreateTexture(mDevice, &textureDesc);
|
|
||||||
assert(mStencilTex);
|
|
||||||
|
|
||||||
// depth-stencil texture view
|
|
||||||
WGPUTextureViewDescriptor textureViewDesc{};
|
|
||||||
textureViewDesc.nextInChain = nullptr;
|
|
||||||
textureViewDesc.label = "The depth-stencil texture view";
|
|
||||||
textureViewDesc.format = WGPUTextureFormat_Stencil8;
|
|
||||||
textureViewDesc.dimension = WGPUTextureViewDimension_2D;
|
|
||||||
textureViewDesc.baseMipLevel = 0;
|
|
||||||
textureViewDesc.mipLevelCount = 1;
|
|
||||||
textureViewDesc.baseArrayLayer = 0;
|
|
||||||
textureViewDesc.arrayLayerCount = 1;
|
|
||||||
textureViewDesc.aspect = WGPUTextureAspect_All;
|
|
||||||
mStencilTexView = wgpuTextureCreateView(mStencilTex, &textureViewDesc);
|
|
||||||
assert(mStencilTexView);
|
|
||||||
|
|
||||||
// initialize window binding groups
|
|
||||||
WgShaderTypeMat4x4f viewMat(w, h);
|
|
||||||
mBindGroupCanvasWnd.initialize(mDevice, mQueue, viewMat);
|
|
||||||
WgShaderTypeMat4x4f modelMat;
|
|
||||||
WgShaderTypeBlendSettings blendSettings(ColorSpace::ABGR8888);
|
|
||||||
mBindGroupPaintWnd.initialize(mDevice, mQueue, modelMat, blendSettings);
|
|
||||||
// update pipeline geometry data
|
|
||||||
WgVertexList wnd;
|
|
||||||
wnd.appendRect(WgPoint(0.0f, 0.0f), WgPoint(w, 0.0f), WgPoint(0.0f, h), WgPoint(w, h));
|
|
||||||
mGeometryDataWnd.update(mDevice, mQueue, &wnd);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#ifndef _TVG_WG_RENDERER_H_
|
#ifndef _TVG_WG_RENDERER_H_
|
||||||
#define _TVG_WG_RENDERER_H_
|
#define _TVG_WG_RENDERER_H_
|
||||||
|
|
||||||
#include "tvgWgRenderData.h"
|
#include "tvgWgRenderTarget.h"
|
||||||
|
|
||||||
class WgRenderer : public RenderMethod
|
class WgRenderer : public RenderMethod
|
||||||
{
|
{
|
||||||
|
@ -64,7 +64,6 @@ private:
|
||||||
Array<RenderData> mRenderDatas{};
|
Array<RenderData> mRenderDatas{};
|
||||||
|
|
||||||
Surface mTargetSurface = { nullptr, 0, 0, 0, ColorSpace::Unsupported, true };
|
Surface mTargetSurface = { nullptr, 0, 0, 0, ColorSpace::Unsupported, true };
|
||||||
float mViewMatrix[16]{};
|
|
||||||
// basic webgpu instances (TODO: create separated entity)
|
// basic webgpu instances (TODO: create separated entity)
|
||||||
WGPUInstance mInstance{};
|
WGPUInstance mInstance{};
|
||||||
WGPUAdapter mAdapter{};
|
WGPUAdapter mAdapter{};
|
||||||
|
@ -73,12 +72,8 @@ private:
|
||||||
// webgpu surface handles (TODO: create separated entity)
|
// webgpu surface handles (TODO: create separated entity)
|
||||||
WGPUSurface mSurface{};
|
WGPUSurface mSurface{};
|
||||||
WGPUSwapChain mSwapChain{};
|
WGPUSwapChain mSwapChain{};
|
||||||
WGPUTexture mStencilTex{};
|
|
||||||
WGPUTextureView mStencilTexView{};
|
|
||||||
WgBindGroupCanvas mBindGroupCanvasWnd;
|
|
||||||
WgBindGroupPaint mBindGroupPaintWnd;
|
|
||||||
WgGeometryData mGeometryDataWnd;
|
|
||||||
WgPipelines mPipelines;
|
WgPipelines mPipelines;
|
||||||
|
WgRenderTarget mRenderTarget;
|
||||||
|
|
||||||
bool mClearBuffer;
|
bool mClearBuffer;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue