8void Graphics::flushToOffscreen(OffscreenCanvas *canvas) {
9 auto solid = std::move(solidBatches);
10 auto textured = std::move(texturedBatches);
11 auto lit = std::move(litBatches);
12 auto spans = std::move(overlaySpans);
15 const Color cc = canvas->pendingClearColor();
16 const bool needClear = canvas->takePendingClear();
17 bool hasSolid =
false;
18 for (
const auto &sb : solid)
19 if (!sb.batch.empty()) hasSolid = true;
20 if (!hasSolid && textured.empty() && lit.empty() && !needClear)
return;
27 auto recordOffscreen = [&](vk::CommandBuffer cb) {
28 canvas->colorImage().setLayout(cb, vk::ImageLayout::eColorAttachmentOptimal);
31 vk::ClearColorValue(std::array<float, 4>{cc.r, cc.g, cc.b, cc.a})};
32 vk::RenderPassBeginInfo rpBegin{};
33 rpBegin.renderPass = canvas->isHDR() ? hdrOffscreenRenderPass
34 : offscreenRenderPass;
35 rpBegin.framebuffer = canvas->framebuffer();
36 rpBegin.renderArea.extent =
37 vk::Extent2D{uint32_t(canvas->getWidth()), uint32_t(canvas->getHeight())};
38 rpBegin.clearValueCount = 1;
39 rpBegin.pClearValues = &cv;
40 canvas->colorImage().beginColorAttachment();
41 cb.beginRenderPass(rpBegin, vk::SubpassContents::eInline);
43 vk::ClearAttachment attachment{};
44 attachment.aspectMask = vk::ImageAspectFlagBits::eColor;
45 attachment.colorAttachment = 0;
46 attachment.clearValue = cv;
48 rect.rect = rpBegin.renderArea;
50 cb.clearAttachments(attachment, rect);
53 setViewportAndScissor(cb, uint32_t(canvas->getWidth()),
54 uint32_t(canvas->getHeight()));
56 std::vector<vkb::HostVertexBuffer> &solidBufs =
57 offscreenBuffers.solidBufs;
58 std::vector<vkb::HostVertexBuffer> &texBufs = offscreenBuffers.texBufs;
59 size_t texBufIndex = 0;
60 const int vw = canvas->getWidth();
61 const int vh = canvas->getHeight();
63 auto offscreenTexPipe = [&](
BlendMode mode) -> vk::Pipeline {
66 return offscreenAdditiveTexPipeline;
68 return offscreenPremultipliedTexPipeline;
70 return offscreenMultiplyTexPipeline;
72 return canvas->isHDR() ? hdrOffscreenOpaqueTexPipeline
73 : offscreenOpaqueTexPipeline;
76 return canvas->isHDR() ? hdrOffscreenTexPipeline
77 : offscreenTexPipeline;
80 auto offscreenSolidPipe = [&](
BlendMode mode) -> vk::Pipeline {
83 return offscreenAdditiveSolidPipeline;
85 return offscreenPremultipliedSolidPipeline;
87 return offscreenMultiplySolidPipeline;
89 return offscreenSolidAlphaPipeline;
92 return offscreenSolidPipeline;
96 auto drawOffscreenTextured = [&](TexturedBatch &
tb) {
97 if (
tb.batch.empty() || !
tb.texture || !
tb.texture->gpuHandle)
return;
98 auto *gpu =
static_cast<GpuTexture *
>(
tb.texture->gpuHandle);
99 vk::DescriptorSet texSet = gpu->descriptorSet;
100 if ((
tb.depth &&
tb.depth->gpuHandle) ||
101 (
tb.motion &&
tb.motion->gpuHandle) ||
102 (
tb.extra &&
tb.extra->gpuHandle)) {
103 auto *depthGpu =
tb.depth
104 ?
static_cast<GpuTexture *
>(
tb.depth->gpuHandle)
106 auto *motionGpu =
tb.motion
107 ?
static_cast<GpuTexture *
>(
tb.motion->gpuHandle)
109 auto *extraGpu =
tb.extra
110 ?
static_cast<GpuTexture *
>(
tb.extra->gpuHandle)
114 ?
static_cast<GpuTexture *
>(
tb.specular->gpuHandle)
116 if (vk::DescriptorSet combo =
117 post2SetFor(gpu, depthGpu, motionGpu, extraGpu,
121 Batcher ndc =
tb.batch;
123 std::vector<TexturedVertex> gpuVerts;
124 gpuVerts.reserve(ndc.vertices().size());
128 if (texBufIndex >= texBufs.size()) texBufs.emplace_back();
129 vkb::HostVertexBuffer &vb = texBufs[texBufIndex++];
130 vb.allocate<TexturedVertex>(frameToken(), device, gpuVerts);
132 if (
tb.shader &&
tb.shader->gpuHandle) {
134 ensureShaderHdrOffscreenPipeline(
tb.shader);
136 ensureShaderOffscreenPipeline(
tb.shader);
137 auto *gs =
static_cast<GpuShader *
>(
tb.shader->gpuHandle);
138 vk::Pipeline alphaPipe = canvas->isHDR()
139 ? gs->hdrOffscreenPipeline
140 : gs->offscreenPipeline;
141 vk::Pipeline opaquePipe =
142 canvas->isHDR() ? gs->hdrOffscreenOpaquePipeline
143 : gs->offscreenOpaquePipeline;
144 if (!alphaPipe)
return;
145 vk::Pipeline customPipeline =
149 cb.bindPipeline(vk::PipelineBindPoint::eGraphics,
151 cb.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
152 shaderPipelineLayout, 0, 1,
153 &texSet, 0,
nullptr);
154 cb.pushConstants(shaderPipelineLayout,
155 vk::ShaderStageFlagBits::eVertex |
156 vk::ShaderStageFlagBits::eFragment,
158 tb.shader->pushConstantData());
160 vk::Pipeline pipe = offscreenTexPipe(
tb.blend);
162 cb.bindPipeline(vk::PipelineBindPoint::eGraphics, pipe);
163 cb.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
164 texPipelineLayout, 0, 1,
165 &texSet, 0,
nullptr);
167 vk::DeviceSize
offset = 0;
168 cb.bindVertexBuffers(0, 1, vb, &
offset);
169 cb.draw(uint32_t(gpuVerts.size()), 1, 0, 0);
172 std::vector<bool> solidUploaded(solid.size(),
false);
173 auto uploadSolid = [&](
size_t idx) {
174 if (
idx >= solid.size() || solidUploaded[
idx] ||
175 solid[
idx].batch.empty())
177 vk::Pipeline pipe = offscreenSolidPipe(solid[
idx].
blend);
179 Batcher ndc = solid[
idx].batch;
181 std::vector<ColorVertex> gpuVerts;
182 gpuVerts.reserve(ndc.vertices().size());
184 gpuVerts.push_back(ColorVertex{
v.
pos,
v.
color});
185 if (solidBufs.size() <=
idx) solidBufs.resize(
idx + 1);
186 solidBufs[
idx].allocate<ColorVertex>(frameToken(),
device,
188 solidUploaded[
idx] =
true;
191 auto drawSolidSpan = [&](uint32_t batchIndex, uint32_t
begin,
193 if (batchIndex >= solid.size() ||
count == 0 ||
194 solid[batchIndex].batch.empty())
196 vk::Pipeline pipe = offscreenSolidPipe(solid[batchIndex].
blend);
198 uploadSolid(batchIndex);
199 vk::DeviceSize
offset = 0;
200 cb.bindPipeline(vk::PipelineBindPoint::eGraphics, pipe);
201 cb.bindVertexBuffers(0, 1, solidBufs[batchIndex], &
offset);
206 canvas->isHDR() ? bool(hdrOffscreenLitPipeline) : bool(offscreenLitPipeline);
207 if (!spans.empty()) {
208 for (
const auto &sp : spans) {
209 if (sp.kind == OverlayKind::Solid)
210 drawSolidSpan(sp.index, sp.vertBegin, sp.vertCount);
211 else if (sp.kind == OverlayKind::Textured &&
212 sp.index < textured.size())
213 drawOffscreenTextured(textured[sp.index]);
214 else if (sp.kind == OverlayKind::Lit && litOk && sp.index < lit.size()) {
215 std::vector<LitBatch> one;
216 one.push_back(std::move(lit[sp.index]));
217 drawLitBatches(cb, vw, vh, one, texBufs, texBufIndex,
true,
222 for (
size_t i = 0; i < solid.size(); ++i) {
223 if (!solid[i].batch.empty())
224 drawSolidSpan(uint32_t(i), 0,
225 uint32_t(solid[i].batch.vertices().size()));
227 for (
auto &
tb : textured) drawOffscreenTextured(
tb);
229 drawLitBatches(cb, vw, vh, lit, texBufs, texBufIndex,
true, canvas->isHDR());
233 canvas->colorImage().endSampledLayout();
235 if (swapchainPassOpen && !sceneColorPassOpen && presentRecording) {
236 recordOffscreen(currentPresentCb());
238 vkb::executeImmediately(
device.instance, uploadPool,
239 device.getQueue(vkb::QueueType::graphics), recordOffscreen);
std::vector< Point > vertices
static constexpr uint32_t kPushConstantBytes
void waitForSharedGpuResources()
Block until all in-flight GPU work (all frames) has completed.
eve::Color Color
RGBA color used by every graphics draw call. Lives inside eve::graphics so including a graphics heade...
eve::BlendMode BlendMode
Compatibility alias for the shared 2D blend mode.
ControlEdit combo(const char *label, int &selected, const std::vector< const char * > &items)
Shared immediate renderer for indexed combo boxes.