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;