Cache retained primitives and fix backend submission parity

This commit is contained in:
西风逍遥游 committed 2026-09-09 16:27:12 +08:00
1 parent 0a9405b78a
commit dc52a28b9a
12 files changed
+490 -214

No files matched your search

-94
View File
@@ -1148,52 +1148,6 @@ wgpu::RenderPipeline Graphics::getMesh3DPipeline(BlendMode blend, bool depthWrit
return pipeline;
}
wgpu::RenderPipeline Graphics::getPrimitive3DPipeline(PrimitiveDepthMode depth, BlendMode blend, PrimitiveCullMode cull,
WGPUTextureFormat format, uint32_t sampleCount) {
const uint64_t key = static_cast<uint64_t>(depth) | (static_cast<uint64_t>(blend) << 2u) |
(static_cast<uint64_t>(cull) << 5u) | (static_cast<uint64_t>(uint32_t(format)) << 8u) |
(static_cast<uint64_t>(sampleCount) << 40u);
if (auto found = primitive3DPipelines.find(key); found != primitive3DPipelines.end()) return found->second;
static constexpr const char *kPrimitiveVert = R"wgsl(
struct VSIn { @location(0) clipPosition: vec4f, @location(1) color: vec4f };
struct VSOut { @builtin(position) position: vec4f, @location(0) color: vec4f };
@vertex fn vs_main(input: VSIn) -> VSOut {
var output: VSOut;
output.position = input.clipPosition;
output.color = input.color;
return output;
}
)wgsl";
static constexpr const char *kPrimitiveFrag = R"wgsl(
@fragment fn fs_main(@location(0) color: vec4f) -> @location(0) vec4f { return color; }
)wgsl";
wgpu::VertexAttribute attributes[2]{};
attributes[0].format = wgpu::VertexFormat::Float32x4;
attributes[0].offset = offsetof(Primitive3DVertex, clipPosition);
attributes[0].shaderLocation = 0;
attributes[1].format = wgpu::VertexFormat::Float32x4;
attributes[1].offset = offsetof(Primitive3DVertex, color);
attributes[1].shaderLocation = 1;
PipelineBuilder builder;
builder.label("eve_primitive3d")
.vertexLayout(sizeof(Primitive3DVertex), wgpu::VertexStepMode::Vertex, attributes, 2)
.shader(makeWgslModule(device, kPrimitiveVert), "vs_main", makeWgslModule(device, kPrimitiveFrag), "fs_main")
.colorTarget(format, blend)
.depth(WGPUTextureFormat_Depth32Float,
depth == PrimitiveDepthMode::Ignore ? static_cast<wgpu::CompareFunction>(WGPUCompareFunction_Always)
: wgpu::CompareFunction::LessEqual,
depth == PrimitiveDepthMode::TestAndWrite)
.sampleCount(sampleCount)
.frontFace(wgpu::FrontFace::CCW)
.cull(cull == PrimitiveCullMode::Back
? wgpu::CullMode::Back
: (cull == PrimitiveCullMode::Front ? wgpu::CullMode::Front
: static_cast<wgpu::CullMode>(WGPUCullMode_None)));
wgpu::RenderPipeline pipeline = builder.build(device);
primitive3DPipelines.emplace(key, pipeline);
return pipeline;
}
void Graphics::createMesh3DClusteredPipeline() {
mesh3dClusteredSetLayout = makeMesh3DClusteredBindGroupLayout();
@@ -3598,24 +3552,6 @@ void Graphics::begin3DFrame() {
rebuildSwapchainIfNeeded();
}
void Graphics::drawPrimitiveScene(const PrimitiveSceneCanvas3D &canvas) {
if (!frame3DStarted) throw Exception("drawPrimitiveScene: call begin3DFrame first");
const ResolvedPrimitiveTriangles resolved = resolvePrimitiveStrokes3D(canvas);
if (resolved.vertices.empty()) return;
const std::size_t firstSequence = primitive3DDraws.size();
primitive3DDraws.reserve(firstSequence + resolved.batches3D.size());
for (const ResolvedPrimitiveBatch3D &batch : resolved.batches3D) {
Primitive3DDraw draw;
draw.paint = batch.paint;
draw.averageDepth = batch.averageDepth;
draw.sequence = firstSequence + batch.sequence;
draw.vertices.reserve(batch.vertexCount);
for (std::size_t vertex = batch.firstVertex; vertex < batch.firstVertex + batch.vertexCount; ++vertex)
draw.vertices.push_back({resolved.vertices[vertex].clipPosition, resolved.vertices[vertex].color});
primitive3DDraws.push_back(std::move(draw));
}
}
void Graphics::begin3DFrameToCanvas(Canvas *canvas) {
if (!canvas) throw Exception("begin3DFrameToCanvas: null canvas");
@@ -4390,36 +4326,6 @@ void Graphics::destroyDecalResources() {
// Flush helpers
// ---------------------------------------------------------------------------
void Graphics::flushPrimitive3D(wgpu::RenderPassEncoder pass, WGPUTextureFormat format, uint32_t sampleCount) {
if (primitive3DDraws.empty()) return;
std::stable_sort(primitive3DDraws.begin(), primitive3DDraws.end(),
[](const Primitive3DDraw &a, const Primitive3DDraw &b) {
const bool ignoreA = a.paint.depth == PrimitiveDepthMode::Ignore;
const bool ignoreB = b.paint.depth == PrimitiveDepthMode::Ignore;
if (ignoreA != ignoreB) return !ignoreA;
if (a.paint.layer != b.paint.layer) return a.paint.layer < b.paint.layer;
const bool transparentA = a.paint.blend != BlendMode::Opaque || a.paint.color.a < 1.f;
const bool transparentB = b.paint.blend != BlendMode::Opaque || b.paint.color.a < 1.f;
if (transparentA != transparentB) return !transparentA;
if (transparentA && a.averageDepth != b.averageDepth) return a.averageDepth > b.averageDepth;
return a.sequence < b.sequence;
});
auto &arena = currentVertexArena();
std::size_t totalBytes = 0;
for (const Primitive3DDraw &draw : primitive3DDraws) totalBytes += draw.vertices.size() * sizeof(Primitive3DVertex);
ensureVertexArena(arena, arena.used + totalBytes);
for (const Primitive3DDraw &draw : primitive3DDraws) {
if (draw.vertices.empty()) continue;
const uint64_t bytes = draw.vertices.size() * sizeof(Primitive3DVertex);
const uint64_t offset = arena.alloc(bytes);
queue.WriteBuffer(arena.buffer, offset, draw.vertices.data(), bytes);
pass.SetPipeline(
getPrimitive3DPipeline(draw.paint.depth, draw.paint.blend, draw.paint.cull, format, sampleCount));
pass.SetVertexBuffer(0, arena.buffer, offset, bytes);
pass.Draw(static_cast<uint32_t>(draw.vertices.size()), 1, 0, 0);
}
primitive3DDraws.clear();
}
void Graphics::flushMesh3D(wgpu::RenderPassEncoder pass, WGPUTextureFormat format,
bool canvasTarget) {