From 8553044875d17d65f523c24c7ea06b8d06bf4267 Mon Sep 17 00:00:00 2001 From: Sergii Liebodkin Date: Fri, 22 Dec 2023 03:01:11 +0200 Subject: [PATCH] wg_engine: shape bbox based rendering (optimization) Before the current changes, all surfaces were painted using a full-screen overlay, no matter how large the object was rendered. This approach is redundant and required reorganization. At the moment, all objects are rendered using an overlay equal to the box of the object itself, which reduces the cost of filling the surface. Also surfaces and images were divided into different entities, which reduces the pressure on memory. Also geometry data for rendering and geometry data for calculations in system memory were logically separated. --- src/renderer/wg_engine/tvgWgCommon.cpp | 3 + src/renderer/wg_engine/tvgWgGeometry.cpp | 403 ++++++++++-- src/renderer/wg_engine/tvgWgGeometry.h | 31 +- src/renderer/wg_engine/tvgWgRenderData.cpp | 635 ++++++------------- src/renderer/wg_engine/tvgWgRenderData.h | 127 ++-- src/renderer/wg_engine/tvgWgRenderTarget.cpp | 94 ++- src/renderer/wg_engine/tvgWgRenderTarget.h | 8 +- src/renderer/wg_engine/tvgWgRenderer.cpp | 61 +- 8 files changed, 717 insertions(+), 645 deletions(-) diff --git a/src/renderer/wg_engine/tvgWgCommon.cpp b/src/renderer/wg_engine/tvgWgCommon.cpp index d8114011..68956f86 100644 --- a/src/renderer/wg_engine/tvgWgCommon.cpp +++ b/src/renderer/wg_engine/tvgWgCommon.cpp @@ -90,6 +90,7 @@ void WgContext::initialize() assert(queue); } + void WgContext::release() { if (device) { @@ -100,6 +101,7 @@ void WgContext::release() if (instance) wgpuInstanceRelease(instance); } + void WgContext::executeCommandEncoder(WGPUCommandEncoder commandEncoder) { // command buffer descriptor @@ -112,6 +114,7 @@ void WgContext::executeCommandEncoder(WGPUCommandEncoder commandEncoder) wgpuCommandBufferRelease(commandsBuffer); } + //***************************************************************************** // bind group //***************************************************************************** diff --git a/src/renderer/wg_engine/tvgWgGeometry.cpp b/src/renderer/wg_engine/tvgWgGeometry.cpp index b8791d7c..6641fde3 100644 --- a/src/renderer/wg_engine/tvgWgGeometry.cpp +++ b/src/renderer/wg_engine/tvgWgGeometry.cpp @@ -22,21 +22,25 @@ #include "tvgWgGeometry.h" -void WgVertexList::computeTriFansIndexes() +//*********************************************************************** +// WgGeometryData +//*********************************************************************** + +void WgGeometryData::computeTriFansIndexes() { - assert(mVertexList.count > 2); - mIndexList.reserve((mVertexList.count - 2) * 3); - for (size_t i = 0; i < mVertexList.count - 2; i++) { - mIndexList.push(0); - mIndexList.push(i + 1); - mIndexList.push(i + 2); + if (positions.count <= 2) return; + indexes.reserve((positions.count - 2) * 3); + for (size_t i = 0; i < positions.count - 2; i++) { + indexes.push(0); + indexes.push(i + 1); + indexes.push(i + 2); } -} +}; -void WgVertexList::appendCubic(WgPoint p1, WgPoint p2, WgPoint p3) +void WgGeometryData::appendCubic(WgPoint p1, WgPoint p2, WgPoint p3) { - WgPoint p0 = mVertexList.count > 0 ? mVertexList.last() : WgPoint(0.0f, 0.0f); + WgPoint p0 = positions.count > 0 ? positions.last() : WgPoint(0.0f, 0.0f); const size_t segs = 16; for (size_t i = 1; i <= segs; i++) { float t = i / (float)segs; @@ -45,51 +49,368 @@ void WgVertexList::appendCubic(WgPoint p1, WgPoint p2, WgPoint p3) float t1 = 3 * (1.0f - t) * (1.0f - t) * t; float t2 = 3 * (1.0f - t) * t * t; float t3 = 1 * t * t * t; - mVertexList.push(p0 * t0 + p1 * t1 + p2 * t2 + p3 * t3); + positions.push(p0 * t0 + p1 * t1 + p2 * t2 + p3 * t3); } -} +}; -void WgVertexList::appendRect(WgPoint p0, WgPoint p1, WgPoint p2, WgPoint p3) +void WgGeometryData::appendBox(WgPoint pmin, WgPoint pmax) { - uint32_t index = mVertexList.count; - mVertexList.push(p0); // +0 - mVertexList.push(p1); // +1 - mVertexList.push(p2); // +2 - mVertexList.push(p3); // +3 - mIndexList.push(index + 0); - mIndexList.push(index + 1); - mIndexList.push(index + 2); - mIndexList.push(index + 1); - mIndexList.push(index + 3); - mIndexList.push(index + 2); -} + appendRect( + { pmin.x, pmin.y}, + { pmax.x, pmin.y}, + { pmin.x, pmax.y}, + { pmax.x, pmax.y}); +}; -// TODO: optimize vertex and index count -void WgVertexList::appendCircle(WgPoint center, float radius) +void WgGeometryData::appendRect(WgPoint p0, WgPoint p1, WgPoint p2, WgPoint p3) { - uint32_t index = mVertexList.count; - uint32_t nSegments = 32; + uint32_t index = positions.count; + positions.push(p0); // +0 + positions.push(p1); // +1 + positions.push(p2); // +2 + positions.push(p3); // +3 + indexes.push(index + 0); + indexes.push(index + 1); + indexes.push(index + 2); + indexes.push(index + 1); + indexes.push(index + 3); + indexes.push(index + 2); +}; + + +// TODO: optimize vertex and index count +void WgGeometryData::appendCircle(WgPoint center, float radius) +{ + uint32_t index = positions.count; + uint32_t nSegments = std::trunc(radius); for (uint32_t i = 0; i < nSegments; i++) { - float angle0 = (float)(i + 0) / nSegments * 3.141593f * 2.0f; - float angle1 = (float)(i + 1) / nSegments * 3.141593f * 2.0f; + float angle0 = (float)(i + 0) / nSegments * (float)M_PI * 2.0f; + float angle1 = (float)(i + 1) / nSegments * (float)M_PI * 2.0f; WgPoint p0 = center + WgPoint(sin(angle0) * radius, cos(angle0) * radius); WgPoint p1 = center + WgPoint(sin(angle1) * radius, cos(angle1) * radius); - mVertexList.push(center); // +0 - mVertexList.push(p0); // +1 - mVertexList.push(p1); // +2 - mIndexList.push(index + 0); - mIndexList.push(index + 1); - mIndexList.push(index + 2); + positions.push(center); // +0 + positions.push(p0); // +1 + positions.push(p1); // +2 + indexes.push(index + 0); + indexes.push(index + 1); + indexes.push(index + 2); index += 3; } +}; + + +void WgGeometryData::appendImageBox(float w, float h) +{ + positions.push({ 0.0f, 0.0f }); + positions.push({ w , 0.0f }); + positions.push({ w , h }); + positions.push({ 0.0f, h }); + texCoords.push({ 0.0f, 0.0f }); + texCoords.push({ 1.0f, 0.0f }); + texCoords.push({ 1.0f, 1.0f }); + texCoords.push({ 0.0f, 1.0f }); + indexes.push(0); + indexes.push(1); + indexes.push(2); + indexes.push(0); + indexes.push(2); + indexes.push(3); +}; + + +void WgGeometryData::appendMesh(const RenderMesh* rmesh) +{ + assert(rmesh); + positions.reserve(rmesh->triangleCnt * 3); + texCoords.reserve(rmesh->triangleCnt * 3); + indexes.reserve(rmesh->triangleCnt * 3); + for (uint32_t i = 0; i < rmesh->triangleCnt; i++) { + positions.push(rmesh->triangles[i].vertex[0].pt); + positions.push(rmesh->triangles[i].vertex[1].pt); + positions.push(rmesh->triangles[i].vertex[2].pt); + texCoords.push(rmesh->triangles[i].vertex[0].uv); + texCoords.push(rmesh->triangles[i].vertex[1].uv); + texCoords.push(rmesh->triangles[i].vertex[2].uv); + indexes.push(i*3 + 0); + indexes.push(i*3 + 1); + indexes.push(i*3 + 2); + } +}; + + +void WgGeometryData::close() +{ + if (positions.count > 1) { + positions.push(positions[0]); + } +}; + +//*********************************************************************** +// WgGeometryDataGroup +//*********************************************************************** + +void WgGeometryDataGroup::getBBox(WgPoint& pmin, WgPoint& pmax) { + assert(geometries.count > 0); + assert(geometries[0]->positions.count > 0); + pmin = geometries[0]->positions[0]; + pmax = geometries[0]->positions[0]; + for (uint32_t i = 0; i < geometries.count; i++) { + for (uint32_t j = 0; j < geometries[i]->positions.count; j++) { + pmin.x = std::min(pmin.x, geometries[i]->positions[j].x); + pmin.y = std::min(pmin.y, geometries[i]->positions[j].y); + pmax.x = std::max(pmax.x, geometries[i]->positions[j].x); + pmax.y = std::max(pmax.y, geometries[i]->positions[j].y); + } + } } -void WgVertexList::close() +void WgGeometryDataGroup::tesselate(const RenderShape& rshape) { - if (mVertexList.count > 1) { - mVertexList.push(mVertexList[0]); + decodePath(rshape, this); + for (uint32_t i = 0; i < geometries.count; i++) + geometries[i]->computeTriFansIndexes(); +} + + +void WgGeometryDataGroup::stroke(const RenderShape& rshape) +{ + assert(rshape.stroke); + if (rshape.stroke->dashPattern) { + // first step: decode path data + WgGeometryDataGroup segments{}; + decodePath(rshape, &segments); + // second step: split path to segments using dash patterns + WgGeometryDataGroup outlines{}; + strokeSegments(rshape, &segments, &outlines); + // third step: create geometry for strokes + auto strokeData = new WgGeometryData; + strokeSublines(rshape, &outlines, strokeData); + // append strokes geometry data + geometries.push(strokeData); + } else { + // first step: decode path data + WgGeometryDataGroup outlines{}; + decodePath(rshape, &outlines); + // second step: create geometry for strokes + auto strokeData = new WgGeometryData; + strokeSublines(rshape, &outlines, strokeData); + // append strokes geometry data + geometries.push(strokeData); } -} \ No newline at end of file +} + + +void WgGeometryDataGroup::release() +{ + for (uint32_t i = 0; i < geometries.count; i++) + delete geometries[i]; + geometries.clear(); +} + + +void WgGeometryDataGroup::decodePath(const RenderShape& rshape, WgGeometryDataGroup* outlines) +{ + size_t pntIndex = 0; + for (uint32_t cmdIndex = 0; cmdIndex < rshape.path.cmds.count; cmdIndex++) { + PathCommand cmd = rshape.path.cmds[cmdIndex]; + if (cmd == PathCommand::MoveTo) { + outlines->geometries.push(new WgGeometryData); + auto outline = outlines->geometries.last(); + outline->positions.push(rshape.path.pts[pntIndex]); + pntIndex++; + } else if (cmd == PathCommand::LineTo) { + auto outline = outlines->geometries.last(); + if (outline) + outline->positions.push(rshape.path.pts[pntIndex]); + pntIndex++; + } else if (cmd == PathCommand::Close) { + auto outline = outlines->geometries.last(); + if ((outline) && (outline->positions.count > 0)) + outline->positions.push(outline->positions[0]); + } else if (cmd == PathCommand::CubicTo) { + auto outline = outlines->geometries.last(); + if ((outline) && (outline->positions.count > 0)) + outline->appendCubic( + rshape.path.pts[pntIndex + 0], + rshape.path.pts[pntIndex + 1], + rshape.path.pts[pntIndex + 2] + ); + pntIndex += 3; + } + } +} + + +void WgGeometryDataGroup::strokeSegments(const RenderShape& rshape, WgGeometryDataGroup* outlines, WgGeometryDataGroup* segments) +{ + for (uint32_t i = 0; i < outlines->geometries.count; i++) { + auto& vlist = outlines->geometries[i]->positions; + + // append single point segment + if (vlist.count == 1) { + auto segment = new WgGeometryData; + segment->positions.push(vlist.last()); + segments->geometries.push(segment); + } + + if (vlist.count >= 2) { + uint32_t icurr = 1; + uint32_t ipatt = 0; + WgPoint vcurr = vlist[0]; + while (icurr < vlist.count) { + if (ipatt % 2 == 0) { + segments->geometries.push(new WgGeometryData); + segments->geometries.last()->positions.push(vcurr); + } + float lcurr = rshape.stroke->dashPattern[ipatt]; + while ((icurr < vlist.count) && (vlist[icurr].dist(vcurr) < lcurr)) { + lcurr -= vlist[icurr].dist(vcurr); + vcurr = vlist[icurr]; + icurr++; + if (ipatt % 2 == 0) segments->geometries.last()->positions.push(vcurr); + } + if (icurr < vlist.count) { + vcurr = vcurr + (vlist[icurr] - vlist[icurr-1]).normal() * lcurr; + if (ipatt % 2 == 0) segments->geometries.last()->positions.push(vcurr); + } + ipatt = (ipatt + 1) % rshape.stroke->dashCnt; + } + } + } +} + + +void WgGeometryDataGroup::strokeSublines(const RenderShape& rshape, WgGeometryDataGroup* outlines, WgGeometryData* strokes) +{ + float wdt = rshape.stroke->width / 2; + for (uint32_t i = 0; i < outlines->geometries.count; i++) { + auto outline = outlines->geometries[i]; + + // single point sub-path + if (outline->positions.count == 1) { + if (rshape.stroke->cap == StrokeCap::Round) { + strokes->appendCircle(outline->positions[0], wdt); + } else if (rshape.stroke->cap == StrokeCap::Butt) { + // for zero length sub-paths no stroke is rendered + } else if (rshape.stroke->cap == StrokeCap::Square) { + strokes->appendRect( + outline->positions[0] + WgPoint(+wdt, +wdt), + outline->positions[0] + WgPoint(+wdt, -wdt), + outline->positions[0] + WgPoint(-wdt, +wdt), + outline->positions[0] + WgPoint(-wdt, -wdt) + ); + } + } + + // single line sub-path + if (outline->positions.count == 2) { + WgPoint v0 = outline->positions[0]; + WgPoint v1 = outline->positions[1]; + WgPoint dir0 = (v1 - v0).normal(); + WgPoint nrm0 = WgPoint{ -dir0.y, +dir0.x }; + if (rshape.stroke->cap == StrokeCap::Round) { + strokes->appendRect( + v0 - nrm0 * wdt, v0 + nrm0 * wdt, + v1 - nrm0 * wdt, v1 + nrm0 * wdt); + strokes->appendCircle(outline->positions[0], wdt); + strokes->appendCircle(outline->positions[1], wdt); + } else if (rshape.stroke->cap == StrokeCap::Butt) { + strokes->appendRect( + v0 - nrm0 * wdt, v0 + nrm0 * wdt, + v1 - nrm0 * wdt, v1 + nrm0 * wdt + ); + } else if (rshape.stroke->cap == StrokeCap::Square) { + strokes->appendRect( + v0 - nrm0 * wdt - dir0 * wdt, v0 + nrm0 * wdt - dir0 * wdt, + v1 - nrm0 * wdt + dir0 * wdt, v1 + nrm0 * wdt + dir0 * wdt + ); + } + } + + // multi-lined sub-path + if (outline->positions.count > 2) { + // append first cap + WgPoint v0 = outline->positions[0]; + WgPoint v1 = outline->positions[1]; + WgPoint dir0 = (v1 - v0).normal(); + WgPoint nrm0 = WgPoint{ -dir0.y, +dir0.x }; + if (rshape.stroke->cap == StrokeCap::Round) { + strokes->appendCircle(v0, wdt); + } else if (rshape.stroke->cap == StrokeCap::Butt) { + // no cap needed + } else if (rshape.stroke->cap == StrokeCap::Square) { + strokes->appendRect( + v0 - nrm0 * wdt - dir0 * wdt, + v0 + nrm0 * wdt - dir0 * wdt, + v0 - nrm0 * wdt, + v0 + nrm0 * wdt + ); + } + + // append last cap + v0 = outline->positions[outline->positions.count - 2]; + v1 = outline->positions[outline->positions.count - 1]; + dir0 = (v1 - v0).normal(); + nrm0 = WgPoint{ -dir0.y, +dir0.x }; + if (rshape.stroke->cap == StrokeCap::Round) { + strokes->appendCircle(v1, wdt); + } else if (rshape.stroke->cap == StrokeCap::Butt) { + // no cap needed + } else if (rshape.stroke->cap == StrokeCap::Square) { + strokes->appendRect( + v1 - nrm0 * wdt, + v1 + nrm0 * wdt, + v1 - nrm0 * wdt + dir0 * wdt, + v1 + nrm0 * wdt + dir0 * wdt + ); + } + + // append sub-lines + for (uint32_t j = 0; j < outline->positions.count - 1; j++) { + WgPoint v0 = outline->positions[j + 0]; + WgPoint v1 = outline->positions[j + 1]; + WgPoint dir = (v1 - v0).normal(); + WgPoint nrm { -dir.y, +dir.x }; + strokes->appendRect( + v0 - nrm * wdt, + v0 + nrm * wdt, + v1 - nrm * wdt, + v1 + nrm * wdt + ); + } + + // append joints (TODO: separate by joint types) + for (uint32_t j = 1; j < outline->positions.count - 1; j++) { + WgPoint v0 = outline->positions[j - 1]; + WgPoint v1 = outline->positions[j + 0]; + WgPoint v2 = outline->positions[j + 1]; + WgPoint dir0 = (v1 - v0).normal(); + WgPoint dir1 = (v1 - v2).normal(); + WgPoint nrm0 { -dir0.y, +dir0.x }; + WgPoint nrm1 { +dir1.y, -dir1.x }; + if (rshape.stroke->join == StrokeJoin::Round) { + strokes->appendCircle(v1, wdt); + } else if (rshape.stroke->join == StrokeJoin::Bevel) { + strokes->appendRect( + v1 - nrm0 * wdt, v1 - nrm1 * wdt, + v1 + nrm1 * wdt, v1 + nrm0 * wdt + ); + } else if (rshape.stroke->join == StrokeJoin::Miter) { + WgPoint nrm = (dir0 + dir1).normal(); + float cosine = nrm.dot(nrm0); + if ((cosine != 0.0f) && (abs(wdt / cosine) <= rshape.stroke->miterlimit * 2)) { + strokes->appendRect(v1 + nrm * (wdt / cosine), v1 + nrm0 * wdt, v1 + nrm1 * wdt, v1); + strokes->appendRect(v1 - nrm * (wdt / cosine), v1 - nrm0 * wdt, v1 - nrm1 * wdt, v1); + } else { + strokes->appendRect( + v1 - nrm0 * wdt, v1 - nrm1 * wdt, + v1 + nrm1 * wdt, v1 + nrm0 * wdt); + } + } + } + } + } +} diff --git a/src/renderer/wg_engine/tvgWgGeometry.h b/src/renderer/wg_engine/tvgWgGeometry.h index 4dc7e8ed..1e519988 100644 --- a/src/renderer/wg_engine/tvgWgGeometry.h +++ b/src/renderer/wg_engine/tvgWgGeometry.h @@ -25,7 +25,7 @@ #include #include "tvgMath.h" -#include "tvgCommon.h" +#include "tvgRender.h" #include "tvgArray.h" class WgPoint @@ -75,17 +75,38 @@ public: } }; -class WgVertexList +struct WgGeometryData { -public: - Array mVertexList; - Array mIndexList; + Array positions{}; + Array texCoords{}; + Array indexes{}; + // webgpu did not support triangle fans primitives type + // so we can emulate triangle fans using indexing void computeTriFansIndexes(); + void appendCubic(WgPoint p1, WgPoint p2, WgPoint p3); + void appendBox(WgPoint pmin, WgPoint pmax); void appendRect(WgPoint p0, WgPoint p1, WgPoint p2, WgPoint p3); void appendCircle(WgPoint center, float radius); + void appendImageBox(float w, float h); + void appendMesh(const RenderMesh* rmesh); void close(); }; +struct WgGeometryDataGroup +{ + Array geometries{}; + virtual ~WgGeometryDataGroup() { release(); } + + void getBBox(WgPoint& pmin, WgPoint& pmax); + void tesselate(const RenderShape& rshape); + void stroke(const RenderShape& rshape); + void release(); +private: + static void decodePath(const RenderShape& rshape, WgGeometryDataGroup* outlines); + static void strokeSegments(const RenderShape& rshape, WgGeometryDataGroup* outlines, WgGeometryDataGroup* segments); + static void strokeSublines(const RenderShape& rshape, WgGeometryDataGroup* outlines, WgGeometryData* strokes); +}; + #endif // _TVG_WG_GEOMETRY_H_ diff --git a/src/renderer/wg_engine/tvgWgRenderData.cpp b/src/renderer/wg_engine/tvgWgRenderData.cpp index 1f79a1fa..07d3a79e 100644 --- a/src/renderer/wg_engine/tvgWgRenderData.cpp +++ b/src/renderer/wg_engine/tvgWgRenderData.cpp @@ -1,3 +1,4 @@ + /* * Copyright (c) 2023 the ThorVG project. All rights reserved. @@ -20,111 +21,129 @@ * SOFTWARE. */ +#ifndef _TVG_WG_RENDER_DATA_H_ +#define _TVG_WG_RENDER_DATA_H_ + #include "tvgWgRenderData.h" //*********************************************************************** -// WgGeometryData +// WgMeshData //*********************************************************************** -void WgGeometryData::draw(WGPURenderPassEncoder renderPassEncoder) +void WgMeshData::draw(WGPURenderPassEncoder renderPassEncoder) { - wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, mBufferVertex, 0, mVertexCount * sizeof(float) * 2); - wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, mBufferIndex, WGPUIndexFormat_Uint32, 0, mIndexCount * sizeof(uint32_t)); - wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, mIndexCount, 1, 0, 0, 0); + wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, bufferPosition, 0, vertexCount * sizeof(float) * 2); + wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, bufferIndex, WGPUIndexFormat_Uint32, 0, indexCount * sizeof(uint32_t)); + wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, indexCount, 1, 0, 0, 0); } -void WgGeometryData::drawImage(WGPURenderPassEncoder renderPassEncoder) +void WgMeshData::drawImage(WGPURenderPassEncoder renderPassEncoder) { - wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, mBufferVertex, 0, mVertexCount * sizeof(float) * 2); - wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 1, mBufferTexCoords, 0, mVertexCount * sizeof(float) * 2); - wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, mBufferIndex, WGPUIndexFormat_Uint32, 0, mIndexCount * sizeof(uint32_t)); - wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, mIndexCount, 1, 0, 0, 0); -} + wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 0, bufferPosition, 0, vertexCount * sizeof(float) * 2); + wgpuRenderPassEncoderSetVertexBuffer(renderPassEncoder, 1, bufferTexCoord, 0, vertexCount * sizeof(float) * 2); + wgpuRenderPassEncoderSetIndexBuffer(renderPassEncoder, bufferIndex, WGPUIndexFormat_Uint32, 0, indexCount * sizeof(uint32_t)); + wgpuRenderPassEncoderDrawIndexed(renderPassEncoder, indexCount, 1, 0, 0, 0); +}; -void WgGeometryData::update(WGPUDevice device, WGPUQueue queue, WgVertexList* vertexList) -{ - update(device, queue, - (float *)vertexList->mVertexList.data, - vertexList->mVertexList.count, - vertexList->mIndexList.data, - vertexList->mIndexList.count); -} - - -void WgGeometryData::update(WGPUDevice device, WGPUQueue queue, float* vertexData, size_t vertexCount, uint32_t* indexData, size_t indexCount) -{ - release(); - +void WgMeshData::update(WgContext& context, WgGeometryData* geometryData){ + release(context); + assert(geometryData); + // buffer position data create and write + if(geometryData->positions.count > 0) { + vertexCount = geometryData->positions.count; + WGPUBufferDescriptor bufferDesc{}; + bufferDesc.nextInChain = nullptr; + bufferDesc.label = "Buffer position geometry data"; + bufferDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex; + bufferDesc.size = sizeof(float) * vertexCount * 2; // x, y + bufferDesc.mappedAtCreation = false; + bufferPosition = wgpuDeviceCreateBuffer(context.device, &bufferDesc); + assert(bufferPosition); + wgpuQueueWriteBuffer(context.queue, bufferPosition, 0, &geometryData->positions[0], vertexCount * sizeof(float) * 2); + } // buffer vertex data create and write - WGPUBufferDescriptor bufferVertexDesc{}; - bufferVertexDesc.nextInChain = nullptr; - bufferVertexDesc.label = "Buffer vertex geometry data"; - bufferVertexDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex; - bufferVertexDesc.size = sizeof(float) * vertexCount * 2; // x, y - bufferVertexDesc.mappedAtCreation = false; - mBufferVertex = wgpuDeviceCreateBuffer(device, &bufferVertexDesc); - assert(mBufferVertex); - wgpuQueueWriteBuffer(queue, mBufferVertex, 0, vertexData, vertexCount * sizeof(float) * 2); - mVertexCount = vertexCount; + if(geometryData->texCoords.count > 0) { + WGPUBufferDescriptor bufferDesc{}; + bufferDesc.nextInChain = nullptr; + bufferDesc.label = "Buffer tex coords geometry data"; + bufferDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex; + bufferDesc.size = sizeof(float) * vertexCount * 2; // u, v + bufferDesc.mappedAtCreation = false; + bufferTexCoord = wgpuDeviceCreateBuffer(context.device, &bufferDesc); + assert(bufferPosition); + wgpuQueueWriteBuffer(context.queue, bufferTexCoord, 0, &geometryData->texCoords[0], vertexCount * sizeof(float) * 2); + } // buffer index data create and write - WGPUBufferDescriptor bufferIndexDesc{}; - bufferIndexDesc.nextInChain = nullptr; - bufferIndexDesc.label = "Buffer index geometry data"; - bufferIndexDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Index; - bufferIndexDesc.size = sizeof(uint32_t) * indexCount; - bufferIndexDesc.mappedAtCreation = false; - mBufferIndex = wgpuDeviceCreateBuffer(device, &bufferIndexDesc); - assert(mBufferIndex); - wgpuQueueWriteBuffer(queue, mBufferIndex, 0, indexData, indexCount * sizeof(uint32_t)); - mIndexCount = indexCount; -} + if(geometryData->indexes.count > 0) { + indexCount = geometryData->indexes.count; + WGPUBufferDescriptor bufferDesc{}; + bufferDesc.nextInChain = nullptr; + bufferDesc.label = "Buffer index geometry data"; + bufferDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Index; + bufferDesc.size = sizeof(uint32_t) * indexCount; + bufferDesc.mappedAtCreation = false; + bufferIndex = wgpuDeviceCreateBuffer(context.device, &bufferDesc); + assert(bufferIndex); + wgpuQueueWriteBuffer(context.queue, bufferIndex, 0, &geometryData->indexes[0], indexCount * sizeof(uint32_t)); + } +}; -void WgGeometryData::update(WGPUDevice device, WGPUQueue queue, float* vertexData, float* texCoordsData, size_t vertexCount, uint32_t* indexData, size_t indexCount) { - update(device, queue, vertexData, vertexCount, indexData, indexCount); - // buffer tex coords data create and write - WGPUBufferDescriptor bufferTexCoordsDesc{}; - bufferTexCoordsDesc.nextInChain = nullptr; - bufferTexCoordsDesc.label = "Buffer tex coords geometry data"; - bufferTexCoordsDesc.usage = WGPUBufferUsage_CopyDst | WGPUBufferUsage_Vertex; - bufferTexCoordsDesc.size = sizeof(float) * vertexCount * 2; // u, v - bufferTexCoordsDesc.mappedAtCreation = false; - mBufferTexCoords = wgpuDeviceCreateBuffer(device, &bufferTexCoordsDesc); - assert(mBufferTexCoords); - wgpuQueueWriteBuffer(queue, mBufferTexCoords, 0, texCoordsData, vertexCount * sizeof(float) * 2); -} - - -void WgGeometryData::release() +void WgMeshData::release(WgContext& context) { - if (mBufferIndex) { - wgpuBufferDestroy(mBufferIndex); - wgpuBufferRelease(mBufferIndex); - mBufferIndex = nullptr; - mVertexCount = 0; + if (bufferIndex) { + wgpuBufferDestroy(bufferIndex); + wgpuBufferRelease(bufferIndex); + bufferIndex = nullptr; + indexCount = 0; } - if (mBufferTexCoords) { - wgpuBufferDestroy(mBufferTexCoords); - wgpuBufferRelease(mBufferTexCoords); - mBufferTexCoords = nullptr; + if (bufferTexCoord) { + wgpuBufferDestroy(bufferTexCoord); + wgpuBufferRelease(bufferTexCoord); + bufferTexCoord = nullptr; } - if (mBufferVertex) { - wgpuBufferDestroy(mBufferVertex); - wgpuBufferRelease(mBufferVertex); - mBufferVertex = nullptr; - mIndexCount = 0; + if (bufferPosition) { + wgpuBufferDestroy(bufferPosition); + wgpuBufferRelease(bufferPosition); + bufferPosition = nullptr; + bufferPosition = 0; } -} +}; + +//*********************************************************************** +// WgMeshDataGroup +//*********************************************************************** + +void WgMeshDataGroup::update(WgContext& context, WgGeometryDataGroup* geometryDataGroup) +{ + release(context); + assert(geometryDataGroup); + for (uint32_t i = 0; i < geometryDataGroup->geometries.count; i++) { + if (geometryDataGroup->geometries[i]->positions.count > 2) { + meshes.push(new WgMeshData()); + meshes.last()->update(context, geometryDataGroup->geometries[i]); + } + } +}; + + +void WgMeshDataGroup::release(WgContext& context) +{ + for (uint32_t i = 0; i < meshes.count; i++) + meshes[i]->release(context); + meshes.clear(); +}; //*********************************************************************** // WgImageData //*********************************************************************** -void WgImageData::update(WGPUDevice device, WGPUQueue queue, Surface* surface) +void WgImageData::update(WgContext& context, Surface* surface) { - release(); + release(context); + assert(surface); // sampler descriptor WGPUSamplerDescriptor samplerDesc{}; samplerDesc.nextInChain = nullptr; @@ -139,8 +158,8 @@ void WgImageData::update(WGPUDevice device, WGPUQueue queue, Surface* surface) samplerDesc.lodMaxClamp = 32.0f; samplerDesc.compare = WGPUCompareFunction_Undefined; samplerDesc.maxAnisotropy = 1; - mSampler = wgpuDeviceCreateSampler(device, &samplerDesc); - assert(mSampler); + sampler = wgpuDeviceCreateSampler(context.device, &samplerDesc); + assert(sampler); // texture descriptor WGPUTextureDescriptor textureDesc{}; textureDesc.nextInChain = nullptr; @@ -153,8 +172,8 @@ void WgImageData::update(WGPUDevice device, WGPUQueue queue, Surface* surface) textureDesc.sampleCount = 1; textureDesc.viewFormatCount = 0; textureDesc.viewFormats = nullptr; - mTexture = wgpuDeviceCreateTexture(device, &textureDesc); - assert(mTexture); + texture = wgpuDeviceCreateTexture(context.device, &textureDesc); + assert(texture); // texture view descriptor WGPUTextureViewDescriptor textureViewDesc{}; textureViewDesc.nextInChain = nullptr; @@ -166,12 +185,12 @@ void WgImageData::update(WGPUDevice device, WGPUQueue queue, Surface* surface) textureViewDesc.baseArrayLayer = 0; textureViewDesc.arrayLayerCount = 1; textureViewDesc.aspect = WGPUTextureAspect_All; - mTextureView = wgpuTextureCreateView(mTexture, &textureViewDesc); - assert(mTextureView); + textureView = wgpuTextureCreateView(texture, &textureViewDesc); + assert(textureView); // update texture data WGPUImageCopyTexture imageCopyTexture{}; imageCopyTexture.nextInChain = nullptr; - imageCopyTexture.texture = mTexture; + imageCopyTexture.texture = texture; imageCopyTexture.mipLevel = 0; imageCopyTexture.origin = { 0, 0, 0 }; imageCopyTexture.aspect = WGPUTextureAspect_All; @@ -184,403 +203,129 @@ void WgImageData::update(WGPUDevice device, WGPUQueue queue, Surface* surface) writeSize.width = surface->w; writeSize.height = surface->h; writeSize.depthOrArrayLayers = 1; - wgpuQueueWriteTexture(queue, &imageCopyTexture, surface->data, 4 * surface->w * surface->h, &textureDataLayout, &writeSize); -} + wgpuQueueWriteTexture(context.queue, &imageCopyTexture, surface->data, 4 * surface->w * surface->h, &textureDataLayout, &writeSize); +}; -void WgImageData::release() +void WgImageData::release(WgContext& context) { - if (mTexture) { - wgpuTextureDestroy(mTexture); - wgpuTextureRelease(mTexture); - mTexture = nullptr; + if (textureView) { + wgpuTextureViewRelease(textureView); + textureView = nullptr; + } + if (texture) { + wgpuTextureDestroy(texture); + wgpuTextureRelease(texture); + texture = nullptr; } - if (mTextureView) { - wgpuTextureViewRelease(mTextureView); - mTextureView = nullptr; + if (sampler) { + wgpuSamplerRelease(sampler); + sampler = nullptr; } - if (mSampler) { - wgpuSamplerRelease(mSampler); - mSampler = nullptr; - } -} +}; //*********************************************************************** -// WgRenderDataShapeSettings +// WgRenderSettings //*********************************************************************** -void WgRenderDataShapeSettings::update(WGPUDevice device, WGPUQueue queue, - const Fill* fill, const uint8_t* color, - const RenderUpdateFlag flags) +void WgRenderSettings::update(WgContext& context, const Fill* fill, const uint8_t* color, const RenderUpdateFlag flags) { // setup fill properties if ((flags & (RenderUpdateFlag::Gradient)) && fill) { // setup linear fill properties if (fill->identifier() == TVG_CLASS_ID_LINEAR) { WgShaderTypeLinearGradient linearGradient((LinearGradient*)fill); - mBindGroupLinear.initialize(device, queue, linearGradient); - mFillType = WgRenderDataShapeFillType::Linear; + bindGroupLinear.initialize(context.device, context.queue, linearGradient); + fillType = WgRenderSettingsType::Linear; } else if (fill->identifier() == TVG_CLASS_ID_RADIAL) { WgShaderTypeRadialGradient radialGradient((RadialGradient*)fill); - mBindGroupRadial.initialize(device, queue, radialGradient); - mFillType = WgRenderDataShapeFillType::Radial; + bindGroupRadial.initialize(context.device, context.queue, radialGradient); + fillType = WgRenderSettingsType::Radial; } } else if ((flags & (RenderUpdateFlag::Color)) && !fill) { WgShaderTypeSolidColor solidColor(color); - mBindGroupSolid.initialize(device, queue, solidColor); - mFillType = WgRenderDataShapeFillType::Solid; + bindGroupSolid.initialize(context.device, context.queue, solidColor); + fillType = WgRenderSettingsType::Solid; } -} +}; -void WgRenderDataShapeSettings::release() + +void WgRenderSettings::release(WgContext& context) { - mBindGroupSolid.release(); - mBindGroupLinear.release(); - mBindGroupRadial.release(); -} + bindGroupSolid.release(); + bindGroupLinear.release(); + bindGroupRadial.release(); +}; + +//*********************************************************************** +// WgRenderDataPaint +//*********************************************************************** + +void WgRenderDataPaint::release(WgContext& context) +{ + bindGroupPaint.release(); +}; //*********************************************************************** // WgRenderDataShape //*********************************************************************** -void WgRenderDataShape::release() +void WgRenderDataShape::updateMeshes(WgContext &context, const RenderShape &rshape) { - releaseRenderData(); - mImageData.release(); - mBindGroupPaint.release(); - mRenderSettingsShape.release(); - mRenderSettingsStroke.release(); - mBindGroupPicture.release(); -} - - -void WgRenderDataShape::releaseRenderData() -{ - for (uint32_t i = 0; i < mGeometryDataImage.count; i++) { - mGeometryDataImage[i]->release(); - delete mGeometryDataImage[i]; - } - for (uint32_t i = 0; i < mGeometryDataStroke.count; i++) { - mGeometryDataStroke[i]->release(); - delete mGeometryDataStroke[i]; - } - mGeometryDataStroke.clear(); - for (uint32_t i = 0; i < mGeometryDataShape.count; i++) { - mGeometryDataShape[i]->release(); - delete mGeometryDataShape[i]; - } - mGeometryDataShape.clear(); -} - - -void WgRenderDataShape::tesselate(WGPUDevice device, WGPUQueue queue, Surface* surface, const RenderMesh* mesh) -{ - // create image geometry data - Array vertexList; - Array texCoordsList; - Array indexList; - - if (mesh && mesh->triangleCnt) { - vertexList.reserve(mesh->triangleCnt * 3); - texCoordsList.reserve(mesh->triangleCnt * 3); - indexList.reserve(mesh->triangleCnt * 3); - for (uint32_t i = 0; i < mesh->triangleCnt; i++) { - vertexList.push(mesh->triangles[i].vertex[0].pt); - vertexList.push(mesh->triangles[i].vertex[1].pt); - vertexList.push(mesh->triangles[i].vertex[2].pt); - texCoordsList.push(mesh->triangles[i].vertex[0].uv); - texCoordsList.push(mesh->triangles[i].vertex[1].uv); - texCoordsList.push(mesh->triangles[i].vertex[2].uv); - indexList.push(i*3 + 0); - indexList.push(i*3 + 1); - indexList.push(i*3 + 2); - } - } else { - vertexList.push({ 0.0f, 0.0f }); - vertexList.push({ (float)surface->w, 0.0f }); - vertexList.push({ (float)surface->w, (float)surface->h }); - vertexList.push({ 0.0f, (float)surface->h }); - texCoordsList.push({0.0f, 0.0f}); - texCoordsList.push({1.0f, 0.0f}); - texCoordsList.push({1.0f, 1.0f}); - texCoordsList.push({0.0f, 1.0f}); - indexList.push(0); - indexList.push(1); - indexList.push(2); - indexList.push(0); - indexList.push(2); - indexList.push(3); - } - - // create geometry data for image - WgGeometryData* geometryData = new WgGeometryData(); - geometryData->update(device, queue, - (float *)vertexList.data, (float *)texCoordsList.data, vertexList.count, - indexList.data, indexList.count); - mGeometryDataImage.push(geometryData); - - // update image data - mImageData.update(device, queue, surface); -} - - -void WgRenderDataShape::tesselate(WGPUDevice device, WGPUQueue queue, const RenderShape& rshape) -{ - Array outlines{}; - decodePath(rshape, outlines); - - // create geometry data for fill for each outline - for (uint32_t i = 0; i < outlines.count; i++) { - auto outline = outlines[i]; - // append shape if it can create at least one triangle - if (outline->mVertexList.count > 2) { - outline->computeTriFansIndexes(); - - // create geometry data for fill using triangle fan indexes - WgGeometryData* geometryData = new WgGeometryData(); - geometryData->update(device, queue, outline); - mGeometryDataShape.push(geometryData); - } - } - - for (uint32_t i = 0; i < outlines.count; i++) - delete outlines[i]; -} - - -// TODO: separate to entity -void WgRenderDataShape::stroke(WGPUDevice device, WGPUQueue queue, const RenderShape& rshape) -{ - if (!rshape.stroke) return; - - // TODO: chnage to shared_ptrs - Array outlines{}; - decodePath(rshape, outlines); - - WgVertexList strokes; - if (rshape.stroke->dashPattern) { - Array segments; - strokeSegments(rshape, outlines, segments); - strokeSublines(rshape, segments, strokes); - for (uint32_t i = 0; i < segments.count; i++) - delete segments[i]; - } else - strokeSublines(rshape, outlines, strokes); - - // append shape if it can create at least one triangle - // TODO: create single geometry data for strokes pere shape - if (strokes.mIndexList.count > 2) { - WgGeometryData* geometryData = new WgGeometryData(); - geometryData->initialize(device); - geometryData->update(device, queue, &strokes); - mGeometryDataStroke.push(geometryData); - } - - for (uint32_t i = 0; i < outlines.count; i++) - delete outlines[i]; -} - - -void WgRenderDataShape::decodePath(const RenderShape& rshape, Array& outlines) -{ - size_t pntIndex = 0; - for (uint32_t cmdIndex = 0; cmdIndex < rshape.path.cmds.count; cmdIndex++) { - PathCommand cmd = rshape.path.cmds[cmdIndex]; - if (cmd == PathCommand::MoveTo) { - outlines.push(new WgVertexList); - auto outline = outlines.last(); - outline->mVertexList.push(rshape.path.pts[pntIndex]); - pntIndex++; - } else if (cmd == PathCommand::LineTo) { - auto outline = outlines.last(); - if (outline) - outline->mVertexList.push(rshape.path.pts[pntIndex]); - pntIndex++; - } else if (cmd == PathCommand::Close) { - auto outline = outlines.last(); - if ((outline) && (outline->mVertexList.count > 0)) - outline->mVertexList.push(outline->mVertexList[0]); - } else if (cmd == PathCommand::CubicTo) { - auto outline = outlines.last(); - if ((outline) && (outline->mVertexList.count > 0)) - outline->appendCubic( - rshape.path.pts[pntIndex + 0], - rshape.path.pts[pntIndex + 1], - rshape.path.pts[pntIndex + 2] - ); - pntIndex += 3; - } + releaseMeshes(context); + // update shapes geometry + WgGeometryDataGroup shapes; + shapes.tesselate(rshape); + meshGroupShapes.update(context, &shapes); + // update shapes bbox + WgPoint pmin{}, pmax{}; + shapes.getBBox(pmin, pmax); + WgGeometryData box; + box.appendBox(pmin, pmax); + meshBBoxShapes.update(context, &box); + // update strokes geometry + if (rshape.stroke) { + WgGeometryDataGroup strokes; + strokes.stroke(rshape); + strokes.getBBox(pmin, pmax); + meshGroupStrokes.update(context, &strokes); + // update strokes bbox + WgPoint pmin{}, pmax{}; + strokes.getBBox(pmin, pmax); + WgGeometryData box; + box.appendBox(pmin, pmax); + meshBBoxStrokes.update(context, &box); } } -void WgRenderDataShape::strokeSegments(const RenderShape& rshape, Array& outlines, Array& segments) +void WgRenderDataShape::releaseMeshes(WgContext &context) { - for (uint32_t i = 0; i < outlines.count; i++) { - auto& vlist = outlines[i]->mVertexList; - - // append single point segment - if (vlist.count == 1) { - auto segment = new WgVertexList(); - segment->mVertexList.push(vlist.last()); - segments.push(segment); - } - - if (vlist.count >= 2) { - uint32_t icurr = 1; - uint32_t ipatt = 0; - WgPoint vcurr = vlist[0]; - while (icurr < vlist.count) { - if (ipatt % 2 == 0) { - segments.push(new WgVertexList()); - segments.last()->mVertexList.push(vcurr); - } - float lcurr = rshape.stroke->dashPattern[ipatt]; - while ((icurr < vlist.count) && (vlist[icurr].dist(vcurr) < lcurr)) { - lcurr -= vlist[icurr].dist(vcurr); - vcurr = vlist[icurr]; - icurr++; - if (ipatt % 2 == 0) segments.last()->mVertexList.push(vcurr); - } - if (icurr < vlist.count) { - vcurr = vcurr + (vlist[icurr] - vlist[icurr-1]).normal() * lcurr; - if (ipatt % 2 == 0) segments.last()->mVertexList.push(vcurr); - } - ipatt = (ipatt + 1) % rshape.stroke->dashCnt; - } - } - } + meshBBoxStrokes.release(context); + meshBBoxShapes.release(context); + meshGroupStrokes.release(context); + meshGroupShapes.release(context); } -void WgRenderDataShape::strokeSublines(const RenderShape& rshape, Array& outlines, WgVertexList& strokes) +void WgRenderDataShape::release(WgContext& context) { - float wdt = rshape.stroke->width / 2; - for (uint32_t i = 0; i < outlines.count; i++) { - auto outline = outlines[i]; + releaseMeshes(context); + renderSettingsStroke.release(context); + renderSettingsShape.release(context); + WgRenderDataPaint::release(context); +}; - // single point sub-path - if (outline->mVertexList.count == 1) { - if (rshape.stroke->cap == StrokeCap::Round) { - strokes.appendCircle(outline->mVertexList[0], wdt); - } else if (rshape.stroke->cap == StrokeCap::Butt) { - // for zero length sub-paths no stroke is rendered - } else if (rshape.stroke->cap == StrokeCap::Square) { - strokes.appendRect( - outline->mVertexList[0] + WgPoint(+wdt, +wdt), - outline->mVertexList[0] + WgPoint(+wdt, -wdt), - outline->mVertexList[0] + WgPoint(-wdt, +wdt), - outline->mVertexList[0] + WgPoint(-wdt, -wdt) - ); - } - } +//*********************************************************************** +// WgRenderDataPicture +//*********************************************************************** - // single line sub-path - if (outline->mVertexList.count == 2) { - WgPoint v0 = outline->mVertexList[0]; - WgPoint v1 = outline->mVertexList[1]; - WgPoint dir0 = (v1 - v0).normal(); - WgPoint nrm0 = WgPoint{ -dir0.y, +dir0.x }; - if (rshape.stroke->cap == StrokeCap::Round) { - strokes.appendRect( - v0 - nrm0 * wdt, v0 + nrm0 * wdt, - v1 - nrm0 * wdt, v1 + nrm0 * wdt); - strokes.appendCircle(outline->mVertexList[0], wdt); - strokes.appendCircle(outline->mVertexList[1], wdt); - } else if (rshape.stroke->cap == StrokeCap::Butt) { - strokes.appendRect( - v0 - nrm0 * wdt, v0 + nrm0 * wdt, - v1 - nrm0 * wdt, v1 + nrm0 * wdt - ); - } else if (rshape.stroke->cap == StrokeCap::Square) { - strokes.appendRect( - v0 - nrm0 * wdt - dir0 * wdt, v0 + nrm0 * wdt - dir0 * wdt, - v1 - nrm0 * wdt + dir0 * wdt, v1 + nrm0 * wdt + dir0 * wdt - ); - } - } - - // multi-lined sub-path - if (outline->mVertexList.count > 2) { - // append first cap - WgPoint v0 = outline->mVertexList[0]; - WgPoint v1 = outline->mVertexList[1]; - WgPoint dir0 = (v1 - v0).normal(); - WgPoint nrm0 = WgPoint{ -dir0.y, +dir0.x }; - if (rshape.stroke->cap == StrokeCap::Round) { - strokes.appendCircle(v0, wdt); - } else if (rshape.stroke->cap == StrokeCap::Butt) { - // no cap needed - } else if (rshape.stroke->cap == StrokeCap::Square) { - strokes.appendRect( - v0 - nrm0 * wdt - dir0 * wdt, - v0 + nrm0 * wdt - dir0 * wdt, - v0 - nrm0 * wdt, - v0 + nrm0 * wdt - ); - } - - // append last cap - v0 = outline->mVertexList[outline->mVertexList.count - 2]; - v1 = outline->mVertexList[outline->mVertexList.count - 1]; - dir0 = (v1 - v0).normal(); - nrm0 = WgPoint{ -dir0.y, +dir0.x }; - if (rshape.stroke->cap == StrokeCap::Round) { - strokes.appendCircle(v1, wdt); - } else if (rshape.stroke->cap == StrokeCap::Butt) { - // no cap needed - } else if (rshape.stroke->cap == StrokeCap::Square) { - strokes.appendRect( - v1 - nrm0 * wdt, - v1 + nrm0 * wdt, - v1 - nrm0 * wdt + dir0 * wdt, - v1 + nrm0 * wdt + dir0 * wdt - ); - } - - // append sub-lines - for (uint32_t j = 0; j < outline->mVertexList.count - 1; j++) { - WgPoint v0 = outline->mVertexList[j + 0]; - WgPoint v1 = outline->mVertexList[j + 1]; - WgPoint dir = (v1 - v0).normal(); - WgPoint nrm { -dir.y, +dir.x }; - strokes.appendRect( - v0 - nrm * wdt, - v0 + nrm * wdt, - v1 - nrm * wdt, - v1 + nrm * wdt - ); - } - - // append joints (TODO: separate by joint types) - for (uint32_t j = 1; j < outline->mVertexList.count - 1; j++) { - WgPoint v0 = outline->mVertexList[j - 1]; - WgPoint v1 = outline->mVertexList[j + 0]; - WgPoint v2 = outline->mVertexList[j + 1]; - WgPoint dir0 = (v1 - v0).normal(); - WgPoint dir1 = (v1 - v2).normal(); - WgPoint nrm0 { -dir0.y, +dir0.x }; - WgPoint nrm1 { +dir1.y, -dir1.x }; - if (rshape.stroke->join == StrokeJoin::Round) { - strokes.appendCircle(v1, wdt); - } else if (rshape.stroke->join == StrokeJoin::Bevel) { - strokes.appendRect( - v1 - nrm0 * wdt, v1 - nrm1 * wdt, - v1 + nrm1 * wdt, v1 + nrm0 * wdt - ); - } else if (rshape.stroke->join == StrokeJoin::Miter) { - WgPoint nrm = (dir0 + dir1).normal(); - float cosine = nrm.dot(nrm0); - if ((cosine != 0.0f) && (abs(wdt / cosine) <= rshape.stroke->miterlimit * 2)) { - strokes.appendRect(v1 + nrm * (wdt / cosine), v1 + nrm0 * wdt, v1 + nrm1 * wdt, v1); - strokes.appendRect(v1 - nrm * (wdt / cosine), v1 - nrm0 * wdt, v1 - nrm1 * wdt, v1); - } else { - strokes.appendRect( - v1 - nrm0 * wdt, v1 - nrm1 * wdt, - v1 + nrm1 * wdt, v1 + nrm0 * wdt); - } - } - } - } - } +void WgRenderDataPicture::release(WgContext& context) +{ + meshData.release(context); + imageData.release(context); + bindGroupPicture.release(); + WgRenderDataPaint::release(context); } + +#endif //_TVG_WG_RENDER_DATA_H_ diff --git a/src/renderer/wg_engine/tvgWgRenderData.h b/src/renderer/wg_engine/tvgWgRenderData.h index e872e7a7..0e98a3ae 100644 --- a/src/renderer/wg_engine/tvgWgRenderData.h +++ b/src/renderer/wg_engine/tvgWgRenderData.h @@ -20,95 +20,82 @@ * SOFTWARE. */ -#ifndef _TVG_WG_RENDER_DATA_H_ -#define _TVG_WG_RENDER_DATA_H_ - #include "tvgWgPipelines.h" #include "tvgWgGeometry.h" -struct WgGeometryData -{ - WGPUBuffer mBufferVertex{}; - WGPUBuffer mBufferTexCoords{}; - WGPUBuffer mBufferIndex{}; - size_t mVertexCount{}; - size_t mIndexCount{}; +struct WgMeshData { + WGPUBuffer bufferPosition{}; + WGPUBuffer bufferTexCoord{}; + WGPUBuffer bufferIndex{}; + size_t vertexCount{}; + size_t indexCount{}; - WgGeometryData() {} - virtual ~WgGeometryData() { release(); } - - void initialize(WGPUDevice device) {}; void draw(WGPURenderPassEncoder renderPassEncoder); void drawImage(WGPURenderPassEncoder renderPassEncoder); - void update(WGPUDevice device, WGPUQueue queue, WgVertexList* vertexList); - void update(WGPUDevice device, WGPUQueue queue, float* vertexData, size_t vertexCount, uint32_t* indexData, size_t indexCount); - void update(WGPUDevice device, WGPUQueue queue, float* vertexData, float* texCoordsData, size_t vertexCount, uint32_t* indexData, size_t indexCount); - void release(); + + void update(WgContext& context, WgGeometryData* geometryData); + void release(WgContext& context); }; -struct WgImageData +struct WgMeshDataGroup { + Array meshes{}; + + void update(WgContext& context, WgGeometryDataGroup* geometryDataGroup); + void release(WgContext& context); +}; + +struct WgImageData { + WGPUSampler sampler{}; + WGPUTexture texture{}; + WGPUTextureView textureView{}; + + void update(WgContext& context, Surface* surface); + void release(WgContext& context); +}; + +enum class WgRenderSettingsType { None = 0, Solid = 1, Linear = 2, Radial = 3 }; + +struct WgRenderSettings { - WGPUSampler mSampler{}; - WGPUTexture mTexture{}; - WGPUTextureView mTextureView{}; + WgBindGroupSolidColor bindGroupSolid{}; + WgBindGroupLinearGradient bindGroupLinear{}; + WgBindGroupRadialGradient bindGroupRadial{}; + WgRenderSettingsType fillType{}; - WgImageData() {} - virtual ~WgImageData() { release(); } - - void initialize(WGPUDevice device) {}; - void update(WGPUDevice device, WGPUQueue queue, Surface* surface); - void release(); + void update(WgContext& context, const Fill* fill, const uint8_t* color, const RenderUpdateFlag flags); + void release(WgContext& context); }; -class WgRenderData +struct WgRenderDataPaint { -public: - virtual void initialize(WGPUDevice device) {}; - virtual void release() = 0; + WgBindGroupPaint bindGroupPaint{}; + + virtual void release(WgContext& context); + virtual uint32_t identifier() { return TVG_CLASS_ID_UNDEFINED; }; }; -enum class WgRenderDataShapeFillType { None = 0, Solid = 1, Linear = 2, Radial = 3 }; - -struct WgRenderDataShapeSettings +struct WgRenderDataShape: public WgRenderDataPaint { - WgBindGroupSolidColor mBindGroupSolid{}; - WgBindGroupLinearGradient mBindGroupLinear{}; - WgBindGroupRadialGradient mBindGroupRadial{}; - WgRenderDataShapeFillType mFillType{}; // Default: None + WgRenderSettings renderSettingsShape{}; + WgRenderSettings renderSettingsStroke{}; + WgMeshDataGroup meshGroupShapes{}; + WgMeshDataGroup meshGroupStrokes{}; + WgMeshData meshBBoxShapes{}; + WgMeshData meshBBoxStrokes{}; - // update render shape settings defined by flags and fill settings - void update(WGPUDevice device, WGPUQueue queue, - const Fill* fill, const uint8_t* color, const RenderUpdateFlag flags); - void release(); + void updateMeshes(WgContext& context, const RenderShape& rshape); + void releaseMeshes(WgContext& context); + void release(WgContext& context) override; + uint32_t identifier() override { return TVG_CLASS_ID_SHAPE; }; }; -class WgRenderDataShape: public WgRenderData +struct WgRenderDataPicture: public WgRenderDataPaint { -public: - // geometry data for shapes, strokes and image - Array mGeometryDataShape; - Array mGeometryDataStroke; - Array mGeometryDataImage; - WgImageData mImageData; + WgBindGroupPicture bindGroupPicture{}; + WgImageData imageData{}; + WgMeshData meshData{}; - // shader settings - WgBindGroupPaint mBindGroupPaint; - WgRenderDataShapeSettings mRenderSettingsShape; - WgRenderDataShapeSettings mRenderSettingsStroke; - WgBindGroupPicture mBindGroupPicture; -public: - WgRenderDataShape() {} - - void release() override; - void releaseRenderData(); - - void tesselate(WGPUDevice device, WGPUQueue queue, Surface* surface, const RenderMesh* mesh); - void tesselate(WGPUDevice device, WGPUQueue queue, const RenderShape& rshape); - void stroke(WGPUDevice device, WGPUQueue queue, const RenderShape& rshape); -private: - void decodePath(const RenderShape& rshape, Array& outlines); - void strokeSegments(const RenderShape& rshape, Array& outlines, Array& segments); - void strokeSublines(const RenderShape& rshape, Array& outlines, WgVertexList& strokes); + void update(WgContext& context); + void release(WgContext& context) override; + uint32_t identifier() override { return TVG_CLASS_ID_PICTURE; }; }; - -#endif //_TVG_WG_RENDER_DATA_H_ diff --git a/src/renderer/wg_engine/tvgWgRenderTarget.cpp b/src/renderer/wg_engine/tvgWgRenderTarget.cpp index 9cc06862..f39bd0d2 100644 --- a/src/renderer/wg_engine/tvgWgRenderTarget.cpp +++ b/src/renderer/wg_engine/tvgWgRenderTarget.cpp @@ -22,9 +22,9 @@ #include "tvgWgRenderTarget.h" -void WgRenderTarget::initialize(WGPUDevice device, WGPUQueue queue, WgPipelines& pipelines, uint32_t w, uint32_t h) +void WgRenderTarget::initialize(WgContext& context, WgPipelines& pipelines, uint32_t w, uint32_t h) { - release(); + release(context); // sampler descriptor WGPUSamplerDescriptor samplerDesc{}; samplerDesc.nextInChain = nullptr; @@ -39,7 +39,7 @@ void WgRenderTarget::initialize(WGPUDevice device, WGPUQueue queue, WgPipelines& samplerDesc.lodMaxClamp = 32.0f; samplerDesc.compare = WGPUCompareFunction_Undefined; samplerDesc.maxAnisotropy = 1; - mSampler = wgpuDeviceCreateSampler(device, &samplerDesc); + mSampler = wgpuDeviceCreateSampler(context.device, &samplerDesc); assert(mSampler); // texture descriptor WGPUTextureDescriptor textureDescColor{}; @@ -53,7 +53,7 @@ void WgRenderTarget::initialize(WGPUDevice device, WGPUQueue queue, WgPipelines& textureDescColor.sampleCount = 1; textureDescColor.viewFormatCount = 0; textureDescColor.viewFormats = nullptr; - mTextureColor = wgpuDeviceCreateTexture(device, &textureDescColor); + mTextureColor = wgpuDeviceCreateTexture(context.device, &textureDescColor); assert(mTextureColor); // texture view descriptor WGPUTextureViewDescriptor textureViewDescColor{}; @@ -80,7 +80,7 @@ void WgRenderTarget::initialize(WGPUDevice device, WGPUQueue queue, WgPipelines& textureDescStencil.sampleCount = 1; textureDescStencil.viewFormatCount = 0; textureDescStencil.viewFormats = nullptr; - mTextureStencil = wgpuDeviceCreateTexture(device, &textureDescStencil); + mTextureStencil = wgpuDeviceCreateTexture(context.device, &textureDescStencil); assert(mTextureStencil); // texture view descriptor WGPUTextureViewDescriptor textureViewDescStencil{}; @@ -97,22 +97,14 @@ void WgRenderTarget::initialize(WGPUDevice device, WGPUQueue queue, WgPipelines& assert(mTextureViewStencil); // initialize window binding groups WgShaderTypeMat4x4f viewMat(w, h); - mBindGroupCanvasWnd.initialize(device, queue, viewMat); - WgShaderTypeMat4x4f modelMat; - WgShaderTypeBlendSettings blendSettings(ColorSpace::ABGR8888, 255); - 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); + mBindGroupCanvasWnd.initialize(context.device, context.queue, viewMat); mPipelines = &pipelines; } -void WgRenderTarget::release() + +void WgRenderTarget::release(WgContext& context) { mBindGroupCanvasWnd.release(); - mBindGroupPaintWnd.release(); - mGeometryDataWnd.release(); if (mTextureStencil) { wgpuTextureDestroy(mTextureStencil); wgpuTextureRelease(mTextureStencil); @@ -131,11 +123,13 @@ void WgRenderTarget::release() mSampler = nullptr; } + void WgRenderTarget::beginRenderPass(WGPUCommandEncoder commandEncoder) { beginRenderPass(commandEncoder, mTextureViewColor); } + void WgRenderTarget::beginRenderPass(WGPUCommandEncoder commandEncoder, WGPUTextureView colorAttachement) { assert(!mRenderPassEncoder); @@ -172,6 +166,7 @@ void WgRenderTarget::beginRenderPass(WGPUCommandEncoder commandEncoder, WGPUText mRenderPassEncoder = wgpuCommandEncoderBeginRenderPass(commandEncoder, &renderPassDesc); } + void WgRenderTarget::endRenderPass() { assert(mRenderPassEncoder); @@ -180,66 +175,67 @@ void WgRenderTarget::endRenderPass() 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++) { + for (uint32_t i = 0; i < renderData->meshGroupShapes.meshes.count; i++) { // draw to stencil (first pass) - mPipelines->mPipelineFillShape.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->mBindGroupPaint); - renderData->mGeometryDataShape[i]->draw(mRenderPassEncoder); + mPipelines->mPipelineFillShape.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint); + renderData->meshGroupShapes.meshes[i]->draw(mRenderPassEncoder); // fill shape (second pass) - WgRenderDataShapeSettings& settings = renderData->mRenderSettingsShape; - if (settings.mFillType == WgRenderDataShapeFillType::Solid) - mPipelines->mPipelineSolid.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->mBindGroupPaint, settings.mBindGroupSolid); - else if (settings.mFillType == WgRenderDataShapeFillType::Linear) - mPipelines->mPipelineLinear.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->mBindGroupPaint, settings.mBindGroupLinear); - else if (settings.mFillType == WgRenderDataShapeFillType::Radial) - mPipelines->mPipelineRadial.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->mBindGroupPaint, settings.mBindGroupRadial); - mGeometryDataWnd.draw(mRenderPassEncoder); + WgRenderSettings& settings = renderData->renderSettingsShape; + if (settings.fillType == WgRenderSettingsType::Solid) + mPipelines->mPipelineSolid.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupSolid); + else if (settings.fillType == WgRenderSettingsType::Linear) + mPipelines->mPipelineLinear.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupLinear); + else if (settings.fillType == WgRenderSettingsType::Radial) + mPipelines->mPipelineRadial.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupRadial); + renderData->meshBBoxShapes.draw(mRenderPassEncoder); } } + void WgRenderTarget::renderStroke(WgRenderDataShape* renderData) { assert(renderData); assert(mRenderPassEncoder); // draw stroke geometry - if (renderData->mGeometryDataStroke.count > 0) { + if (renderData->meshGroupStrokes.meshes.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); + for (uint32_t i = 0; i < renderData->meshGroupStrokes.meshes.count; i++) { + mPipelines->mPipelineFillStroke.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint); + renderData->meshGroupStrokes.meshes[i]->draw(mRenderPassEncoder); } // fill shape (second pass) wgpuRenderPassEncoderSetStencilReference(mRenderPassEncoder, 0); - WgRenderDataShapeSettings& settings = renderData->mRenderSettingsStroke; - if (settings.mFillType == WgRenderDataShapeFillType::Solid) - mPipelines->mPipelineSolid.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->mBindGroupPaint, settings.mBindGroupSolid); - else if (settings.mFillType == WgRenderDataShapeFillType::Linear) - mPipelines->mPipelineLinear.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->mBindGroupPaint, settings.mBindGroupLinear); - else if (settings.mFillType == WgRenderDataShapeFillType::Radial) - mPipelines->mPipelineRadial.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->mBindGroupPaint, settings.mBindGroupRadial); - mGeometryDataWnd.draw(mRenderPassEncoder); + WgRenderSettings& settings = renderData->renderSettingsStroke; + if (settings.fillType == WgRenderSettingsType::Solid) + mPipelines->mPipelineSolid.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupSolid); + else if (settings.fillType == WgRenderSettingsType::Linear) + mPipelines->mPipelineLinear.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupLinear); + else if (settings.fillType == WgRenderSettingsType::Radial) + mPipelines->mPipelineRadial.use(mRenderPassEncoder, mBindGroupCanvasWnd, renderData->bindGroupPaint, settings.bindGroupRadial); + renderData->meshBBoxStrokes.draw(mRenderPassEncoder); } } -void WgRenderTarget::renderImage(WgRenderDataShape* renderData) + +void WgRenderTarget::renderPicture(WgRenderDataPicture* renderData) { assert(renderData); assert(mRenderPassEncoder); - if (renderData->mGeometryDataImage.count > 0) { + if (renderData->meshData.bufferTexCoord) { 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); - } + mPipelines->mPipelineImage.use( + mRenderPassEncoder, + mBindGroupCanvasWnd, + renderData->bindGroupPaint, + renderData->bindGroupPicture); + renderData->meshData.drawImage(mRenderPassEncoder); } } diff --git a/src/renderer/wg_engine/tvgWgRenderTarget.h b/src/renderer/wg_engine/tvgWgRenderTarget.h index daf9356d..ea46e92d 100644 --- a/src/renderer/wg_engine/tvgWgRenderTarget.h +++ b/src/renderer/wg_engine/tvgWgRenderTarget.h @@ -31,8 +31,6 @@ private: WGPURenderPassEncoder mRenderPassEncoder{}; // fill and blit data WgBindGroupCanvas mBindGroupCanvasWnd; - WgBindGroupPaint mBindGroupPaintWnd; - WgGeometryData mGeometryDataWnd; // gpu buffers WGPUSampler mSampler{}; WGPUTexture mTextureColor{}; @@ -41,8 +39,8 @@ private: WGPUTextureView mTextureViewStencil{}; WgPipelines* mPipelines{}; // external handle public: - void initialize(WGPUDevice device, WGPUQueue queue, WgPipelines& pipelines, uint32_t w, uint32_t h); - void release(); + void initialize(WgContext& context, WgPipelines& pipelines, uint32_t w, uint32_t h); + void release(WgContext& context); void beginRenderPass(WGPUCommandEncoder commandEncoder, WGPUTextureView colorAttachement); void beginRenderPass(WGPUCommandEncoder commandEncoder); @@ -50,7 +48,7 @@ public: void renderShape(WgRenderDataShape* renderData); void renderStroke(WgRenderDataShape* renderData); - void renderImage(WgRenderDataShape* renderData); + void renderPicture(WgRenderDataPicture* renderData); }; #endif diff --git a/src/renderer/wg_engine/tvgWgRenderer.cpp b/src/renderer/wg_engine/tvgWgRenderer.cpp index c8058d3f..39f7b31a 100644 --- a/src/renderer/wg_engine/tvgWgRenderer.cpp +++ b/src/renderer/wg_engine/tvgWgRenderer.cpp @@ -60,29 +60,24 @@ RenderData WgRenderer::prepare(const RenderShape& rshape, RenderData data, const { // get or create render data shape auto renderDataShape = (WgRenderDataShape*)data; - if (!renderDataShape) { + if (!renderDataShape) renderDataShape = new WgRenderDataShape(); - renderDataShape->initialize(mContext.device); - } // update geometry - if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Stroke)) { - renderDataShape->releaseRenderData(); - renderDataShape->tesselate(mContext.device, mContext.queue, rshape); - renderDataShape->stroke(mContext.device, mContext.queue, rshape); - } + if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Stroke)) + renderDataShape->updateMeshes(mContext, rshape); // update paint settings if (flags & (RenderUpdateFlag::Transform | RenderUpdateFlag::Blend)) { WgShaderTypeMat4x4f modelMat(transform); WgShaderTypeBlendSettings blendSettings(mTargetSurface.cs, opacity); - renderDataShape->mBindGroupPaint.initialize(mContext.device, mContext.queue, modelMat, blendSettings); + renderDataShape->bindGroupPaint.initialize(mContext.device, mContext.queue, modelMat, blendSettings); } // setup fill settings - renderDataShape->mRenderSettingsShape.update(mContext.device, mContext.queue, rshape.fill, rshape.color, flags); + renderDataShape->renderSettingsShape.update(mContext, rshape.fill, rshape.color, flags); if (rshape.stroke) - renderDataShape->mRenderSettingsStroke.update(mContext.device, mContext.queue, rshape.stroke->fill, rshape.stroke->color, flags); + renderDataShape->renderSettingsStroke.update(mContext, rshape.stroke->fill, rshape.stroke->color, flags); return renderDataShape; } @@ -97,30 +92,32 @@ RenderData WgRenderer::prepare(TVG_UNUSED const Array& scene, TVG_UN RenderData WgRenderer::prepare(Surface* surface, const RenderMesh* mesh, RenderData data, const RenderTransform* transform, Array& clips, uint8_t opacity, RenderUpdateFlag flags) { // get or create render data shape - auto renderDataShape = (WgRenderDataShape*)data; - if (!renderDataShape) { - renderDataShape = new WgRenderDataShape(); - renderDataShape->initialize(mContext.device); - } + auto renderDataPicture = (WgRenderDataPicture*)data; + if (!renderDataPicture) + renderDataPicture = new WgRenderDataPicture(); // update paint settings if (flags & (RenderUpdateFlag::Transform | RenderUpdateFlag::Blend)) { WgShaderTypeMat4x4f modelMat(transform); WgShaderTypeBlendSettings blendSettings(surface->cs, opacity); - renderDataShape->mBindGroupPaint.initialize(mContext.device, mContext.queue, modelMat, blendSettings); + renderDataPicture->bindGroupPaint.initialize(mContext.device, mContext.queue, modelMat, blendSettings); } // update image data if (flags & (RenderUpdateFlag::Path | RenderUpdateFlag::Image)) { - renderDataShape->releaseRenderData(); - renderDataShape->tesselate(mContext.device, mContext.queue, surface, mesh); - renderDataShape->mBindGroupPicture.initialize( + WgGeometryData geometryData; + if (mesh->triangleCnt == 0) geometryData.appendImageBox(surface->w, surface->h); + else geometryData.appendMesh(mesh); + renderDataPicture->meshData.release(mContext); + renderDataPicture->meshData.update(mContext, &geometryData); + renderDataPicture->imageData.update(mContext, surface); + renderDataPicture->bindGroupPicture.initialize( mContext.device, mContext.queue, - renderDataShape->mImageData.mSampler, - renderDataShape->mImageData.mTextureView); + renderDataPicture->imageData.sampler, + renderDataPicture->imageData.textureView); } - return renderDataShape; + return renderDataPicture; } @@ -152,8 +149,8 @@ bool WgRenderer::postRender() bool WgRenderer::dispose(RenderData data) { - auto renderData = (WgRenderData*)data; - if (renderData) renderData->release(); + auto renderData = (WgRenderDataPaint*)data; + if (renderData) renderData->release(mContext); return true; } @@ -206,10 +203,13 @@ bool WgRenderer::sync() // 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); + WgRenderDataPaint* renderData = (WgRenderDataShape*)(mRenderDatas[i]); + if (renderData->identifier() == TVG_CLASS_ID_SHAPE) { + mRenderTarget.renderShape((WgRenderDataShape *)renderData); + mRenderTarget.renderStroke((WgRenderDataShape *)renderData); + } else if (renderData->identifier() == TVG_CLASS_ID_PICTURE) { + mRenderTarget.renderPicture((WgRenderDataPicture *)renderData); + } } mRenderTarget.endRenderPass(); @@ -273,7 +273,7 @@ bool WgRenderer::target(void* window, uint32_t w, uint32_t h) mSwapChain = wgpuDeviceCreateSwapChain(mContext.device, mSurface, &swapChainDesc); assert(mSwapChain); - mRenderTarget.initialize(mContext.device, mContext.queue, mPipelines, w, h); + mRenderTarget.initialize(mContext, mPipelines, w, h); return true; } @@ -283,6 +283,7 @@ Compositor* WgRenderer::target(TVG_UNUSED const RenderRegion& region, TVG_UNUSED return nullptr; } + bool WgRenderer::beginComposite(TVG_UNUSED Compositor* cmp, TVG_UNUSED CompositeMethod method, TVG_UNUSED uint8_t opacity) { return false;