From 1a6571f596b738849e5dc2d0673ec0d638335b85 Mon Sep 17 00:00:00 2001 From: Sergii Liebodkin Date: Mon, 18 Dec 2023 21:56:21 +0200 Subject: [PATCH] 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 --- src/renderer/wg_engine/meson.build | 2 + src/renderer/wg_engine/tvgWgRenderTarget.cpp | 245 +++++++++++++++++++ src/renderer/wg_engine/tvgWgRenderTarget.h | 56 +++++ src/renderer/wg_engine/tvgWgRenderer.cpp | 197 ++------------- src/renderer/wg_engine/tvgWgRenderer.h | 9 +- 5 files changed, 329 insertions(+), 180 deletions(-) create mode 100644 src/renderer/wg_engine/tvgWgRenderTarget.cpp create mode 100644 src/renderer/wg_engine/tvgWgRenderTarget.h diff --git a/src/renderer/wg_engine/meson.build b/src/renderer/wg_engine/meson.build index 5e33e2f5..5c1c23f7 100644 --- a/src/renderer/wg_engine/meson.build +++ b/src/renderer/wg_engine/meson.build @@ -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' ] diff --git a/src/renderer/wg_engine/tvgWgRenderTarget.cpp b/src/renderer/wg_engine/tvgWgRenderTarget.cpp new file mode 100644 index 00000000..6b1251c3 --- /dev/null +++ b/src/renderer/wg_engine/tvgWgRenderTarget.cpp @@ -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); + } + } +} diff --git a/src/renderer/wg_engine/tvgWgRenderTarget.h b/src/renderer/wg_engine/tvgWgRenderTarget.h new file mode 100644 index 00000000..daf9356d --- /dev/null +++ b/src/renderer/wg_engine/tvgWgRenderTarget.h @@ -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 diff --git a/src/renderer/wg_engine/tvgWgRenderer.cpp b/src/renderer/wg_engine/tvgWgRenderer.cpp index 51d11e1e..82bf48a1 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.cpp +++ b/src/renderer/wg_engine/tvgWgRenderer.cpp @@ -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; } diff --git a/src/renderer/wg_engine/tvgWgRenderer.h b/src/renderer/wg_engine/tvgWgRenderer.h index c2ba83c1..2f505b15 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.h +++ b/src/renderer/wg_engine/tvgWgRenderer.h @@ -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 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; };