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',
|
||||
'tvgWgRenderData.h',
|
||||
'tvgWgRenderer.h',
|
||||
'tvgWgRenderTarget.h',
|
||||
'tvgWgShaderSrc.h',
|
||||
'tvgWgShaderTypes.h'
|
||||
'tvgWgBindGroups.cpp',
|
||||
|
@ -13,6 +14,7 @@ source_file = [
|
|||
'tvgWgPipelines.cpp',
|
||||
'tvgWgRenderData.cpp',
|
||||
'tvgWgRenderer.cpp',
|
||||
'tvgWgRenderTarget.cpp',
|
||||
'tvgWgShaderSrc.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()
|
||||
{
|
||||
if (mStencilTex) {
|
||||
wgpuTextureDestroy(mStencilTex);
|
||||
wgpuTextureRelease(mStencilTex);
|
||||
}
|
||||
if (mStencilTexView) wgpuTextureViewRelease(mStencilTexView);
|
||||
if (mSwapChain) wgpuSwapChainRelease(mSwapChain);
|
||||
if (mSurface) wgpuSurfaceRelease(mSurface);
|
||||
mBindGroupCanvasWnd.release();
|
||||
mBindGroupPaintWnd.release();
|
||||
mGeometryDataWnd.release();
|
||||
mRenderTarget.release();
|
||||
mPipelines.release();
|
||||
if (mDevice) {
|
||||
wgpuDeviceDestroy(mDevice);
|
||||
|
@ -276,127 +267,38 @@ bool WgRenderer::sync()
|
|||
{
|
||||
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{};
|
||||
commandBufferDesc.nextInChain = nullptr;
|
||||
commandBufferDesc.label = "The command buffer";
|
||||
WGPUCommandBuffer commandsBuffer = nullptr; {
|
||||
// command encoder descriptor
|
||||
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);
|
||||
}
|
||||
WGPUCommandBuffer commandsBuffer{};
|
||||
commandsBuffer = wgpuCommandEncoderFinish(commandEncoder, &commandBufferDesc);
|
||||
wgpuQueueSubmit(mQueue, 1, &commandsBuffer);
|
||||
wgpuCommandBufferRelease(commandsBuffer);
|
||||
|
||||
wgpuCommandEncoderRelease(commandEncoder);
|
||||
|
||||
// go to the next frame
|
||||
wgpuTextureViewRelease(backBufferView);
|
||||
wgpuSwapChainPresent(mSwapChain);
|
||||
|
||||
mRenderDatas.clear();
|
||||
|
||||
mClearBuffer = false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -408,12 +310,6 @@ bool WgRenderer::target(uint32_t* buffer, uint32_t stride, uint32_t w, uint32_t
|
|||
mTargetSurface.w = w;
|
||||
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
|
||||
return true;
|
||||
}
|
||||
|
@ -427,12 +323,6 @@ bool WgRenderer::target(void* window, uint32_t w, uint32_t h)
|
|||
mTargetSurface.w = w > 0 ? w : 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
|
||||
// surface descriptor from windows hwnd
|
||||
WGPUSurfaceDescriptorFromWindowsHWND surfaceDescHwnd{};
|
||||
|
@ -460,46 +350,7 @@ bool WgRenderer::target(void* window, uint32_t w, uint32_t h)
|
|||
mSwapChain = wgpuDeviceCreateSwapChain(mDevice, mSurface, &swapChainDesc);
|
||||
assert(mSwapChain);
|
||||
|
||||
// depth-stencil texture
|
||||
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);
|
||||
|
||||
mRenderTarget.initialize(mDevice, mQueue, mPipelines, w, h);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
#ifndef _TVG_WG_RENDERER_H_
|
||||
#define _TVG_WG_RENDERER_H_
|
||||
|
||||
#include "tvgWgRenderData.h"
|
||||
#include "tvgWgRenderTarget.h"
|
||||
|
||||
class WgRenderer : public RenderMethod
|
||||
{
|
||||
|
@ -64,7 +64,6 @@ private:
|
|||
Array<RenderData> mRenderDatas{};
|
||||
|
||||
Surface mTargetSurface = { nullptr, 0, 0, 0, ColorSpace::Unsupported, true };
|
||||
float mViewMatrix[16]{};
|
||||
// basic webgpu instances (TODO: create separated entity)
|
||||
WGPUInstance mInstance{};
|
||||
WGPUAdapter mAdapter{};
|
||||
|
@ -73,12 +72,8 @@ private:
|
|||
// webgpu surface handles (TODO: create separated entity)
|
||||
WGPUSurface mSurface{};
|
||||
WGPUSwapChain mSwapChain{};
|
||||
WGPUTexture mStencilTex{};
|
||||
WGPUTextureView mStencilTexView{};
|
||||
WgBindGroupCanvas mBindGroupCanvasWnd;
|
||||
WgBindGroupPaint mBindGroupPaintWnd;
|
||||
WgGeometryData mGeometryDataWnd;
|
||||
WgPipelines mPipelines;
|
||||
WgRenderTarget mRenderTarget;
|
||||
|
||||
bool mClearBuffer;
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue