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:
Sergii Liebodkin 2023-12-18 21:56:21 +02:00 committed by Hermet Park
parent 51a69880fd
commit 1a6571f596
5 changed files with 329 additions and 180 deletions

View file

@ -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'
] ]

View 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);
}
}
}

View 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

View file

@ -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;
} }

View file

@ -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;
}; };