载入中...
搜索中...
未找到
GraphicsOffscreen.cpp
浏览该文件的文档.
4#include "common/Exception.h"
5#include <array>
6#include <vector>
7namespace eve::graphics::vulkan {
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);
13 clear2DBatches();
14
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;
21
22 // Offscreen color is a single shared image. An in-flight swapchain frame
23 // may still be sampling it (draw canvas to screen last frame), so drain
24 // those frames before transitioning it back to a color attachment.
26
27 auto recordOffscreen = [&](vk::CommandBuffer cb) {
28 canvas->colorImage().setLayout(cb, vk::ImageLayout::eColorAttachmentOptimal);
29
30 vk::ClearValue cv{
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);
42 if (needClear) {
43 vk::ClearAttachment attachment{};
44 attachment.aspectMask = vk::ImageAspectFlagBits::eColor;
45 attachment.colorAttachment = 0;
46 attachment.clearValue = cv;
47 vk::ClearRect rect{};
48 rect.rect = rpBegin.renderArea;
49 rect.layerCount = 1;
50 cb.clearAttachments(attachment, rect);
51 }
52
53 setViewportAndScissor(cb, uint32_t(canvas->getWidth()),
54 uint32_t(canvas->getHeight()));
55
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();
62
63 auto offscreenTexPipe = [&](BlendMode mode) -> vk::Pipeline {
64 switch (mode) {
66 return offscreenAdditiveTexPipeline;
68 return offscreenPremultipliedTexPipeline;
70 return offscreenMultiplyTexPipeline;
72 return canvas->isHDR() ? hdrOffscreenOpaqueTexPipeline
73 : offscreenOpaqueTexPipeline;
75 default:
76 return canvas->isHDR() ? hdrOffscreenTexPipeline
77 : offscreenTexPipeline;
78 }
79 };
80 auto offscreenSolidPipe = [&](BlendMode mode) -> vk::Pipeline {
81 switch (mode) {
83 return offscreenAdditiveSolidPipeline;
85 return offscreenPremultipliedSolidPipeline;
87 return offscreenMultiplySolidPipeline;
89 return offscreenSolidAlphaPipeline;
91 default:
92 return offscreenSolidPipeline;
93 }
94 };
95
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)
105 : nullptr;
106 auto *motionGpu = tb.motion
107 ? static_cast<GpuTexture *>(tb.motion->gpuHandle)
108 : nullptr;
109 auto *extraGpu = tb.extra
110 ? static_cast<GpuTexture *>(tb.extra->gpuHandle)
111 : nullptr;
112 auto *specularGpu =
113 tb.specular
114 ? static_cast<GpuTexture *>(tb.specular->gpuHandle)
115 : nullptr;
116 if (vk::DescriptorSet combo =
117 post2SetFor(gpu, depthGpu, motionGpu, extraGpu,
118 specularGpu))
119 texSet = combo;
120 }
121 Batcher ndc = tb.batch;
122 ndc.toNDC(vw, vh);
123 std::vector<TexturedVertex> gpuVerts;
124 gpuVerts.reserve(ndc.vertices().size());
125 for (const auto &v : ndc.vertices())
126 gpuVerts.push_back(TexturedVertex{v.pos, v.color, v.uv});
127
128 if (texBufIndex >= texBufs.size()) texBufs.emplace_back();
129 vkb::HostVertexBuffer &vb = texBufs[texBufIndex++];
130 vb.allocate<TexturedVertex>(frameToken(), device, gpuVerts);
131
132 if (tb.shader && tb.shader->gpuHandle) {
133 if (canvas->isHDR())
134 ensureShaderHdrOffscreenPipeline(tb.shader);
135 else
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 =
146 tb.blend == BlendMode::Opaque && opaquePipe
147 ? opaquePipe
148 : alphaPipe;
149 cb.bindPipeline(vk::PipelineBindPoint::eGraphics,
150 customPipeline);
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());
159 } else {
160 vk::Pipeline pipe = offscreenTexPipe(tb.blend);
161 if (!pipe) return;
162 cb.bindPipeline(vk::PipelineBindPoint::eGraphics, pipe);
163 cb.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
164 texPipelineLayout, 0, 1,
165 &texSet, 0, nullptr);
166 }
167 vk::DeviceSize offset = 0;
168 cb.bindVertexBuffers(0, 1, vb, &offset);
169 cb.draw(uint32_t(gpuVerts.size()), 1, 0, 0);
170 };
171
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())
176 return;
177 vk::Pipeline pipe = offscreenSolidPipe(solid[idx].blend);
178 if (!pipe) return;
179 Batcher ndc = solid[idx].batch;
180 ndc.toNDC(vw, vh);
181 std::vector<ColorVertex> gpuVerts;
182 gpuVerts.reserve(ndc.vertices().size());
183 for (const auto &v : ndc.vertices())
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,
187 gpuVerts);
188 solidUploaded[idx] = true;
189 };
190
191 auto drawSolidSpan = [&](uint32_t batchIndex, uint32_t begin,
192 uint32_t count) {
193 if (batchIndex >= solid.size() || count == 0 ||
194 solid[batchIndex].batch.empty())
195 return;
196 vk::Pipeline pipe = offscreenSolidPipe(solid[batchIndex].blend);
197 if (!pipe) return;
198 uploadSolid(batchIndex);
199 vk::DeviceSize offset = 0;
200 cb.bindPipeline(vk::PipelineBindPoint::eGraphics, pipe);
201 cb.bindVertexBuffers(0, 1, solidBufs[batchIndex], &offset);
202 cb.draw(count, 1, begin, 0);
203 };
204
205 const bool litOk =
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,
218 canvas->isHDR());
219 }
220 }
221 } else {
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()));
226 }
227 for (auto &tb : textured) drawOffscreenTextured(tb);
228 if (litOk)
229 drawLitBatches(cb, vw, vh, lit, texBufs, texBufIndex, true, canvas->isHDR());
230 }
231
232 cb.endRenderPass();
233 canvas->colorImage().endSampledLayout();
234 };
235 if (swapchainPassOpen && !sceneColorPassOpen && presentRecording) {
236 recordOffscreen(currentPresentCb());
237 } else {
238 vkb::executeImmediately(device.instance, uploadPool,
239 device.getQueue(vkb::QueueType::graphics), recordOffscreen);
240 }
241}
242
243
244} // namespace eve::graphics::vulkan
float uv
vkb::Device & device
float v
float blend
size_t offset
float tb
int idx
std::vector< Point > vertices
float begin
std::uint32_t count
static constexpr uint32_t kPushConstantBytes
Definition Shader.h:43
void waitForSharedGpuResources()
Block until all in-flight GPU work (all frames) has completed.
Definition Graphics.cpp:885
eve::Color Color
RGBA color used by every graphics draw call. Lives inside eve::graphics so including a graphics heade...
Definition Color.h:13
eve::BlendMode BlendMode
Compatibility alias for the shared 2D blend mode.
Definition BlendMode.h:8
ControlEdit combo(const char *label, int &selected, const std::vector< const char * > &items)
Shared immediate renderer for indexed combo boxes.
glm::vec4 color