12void Graphics::resetDeferredFrameGraphs() {
15 if (device.instance) device->waitIdle();
17 deferredGraphRecorded_ =
false;
18 deferredGraphRecordedSlot_ = 0;
21vkb::FrameGraph *Graphics::currentDeferredFrameGraph() {
22 if (deferredFrameGraphs_[0] ==
nullptr)
return nullptr;
23 return deferredFrameGraphs_[currentFrameSlot() % deferredFrameGraphs_.size()].get();
26void Graphics::buildDeferredFrameGraphs() {
37 const vk::Format depthFmt = vk::Format::eD32Sfloat;
38 const vk::Format colorFmt = pickGBufferColorFormat(device);
41 const uint32_t
w = gbufferWidth > 0 ? uint32_t(gbufferWidth) : 1u;
42 const uint32_t
h = gbufferHeight > 0 ? uint32_t(gbufferHeight) : 1u;
44 for (
size_t i = 0; i < deferredFrameGraphs_.size(); ++i) {
45 auto graph = std::make_unique<vkb::FrameGraph>(&device, 1);
47 vkb::TextureDesc shadowDesc;
48 shadowDesc.format = depthFmt;
49 shadowDesc.extent = vk::Extent3D{mapSize, mapSize, 1};
50 shadowDesc.arrayLayers = shadowLayers;
51 shadowDesc.aspect = vk::ImageAspectFlagBits::eDepth;
52 shadowDesc.usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eDepthStencilAttachment;
55 shadowDesc.afterLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
56 vk::ClearValue shadowClear{};
57 shadowClear.depthStencil = vk::ClearDepthStencilValue{1.0f, 0};
58 const bool haveShadowSlot = i < shadowMaps.size() && shadowMaps[i].image.layerCount() >= shadowLayers;
60 const vk::Image shadowImage = shadowMaps[i].image.image();
61 for (uint32_t
c = 0;
c < shadowLayers; ++
c) {
62 auto shadowH =
graph->importTexture(
"shadowCascade" + std::to_string(
c), shadowImage,
63 shadowMaps[i].
image.layerView(
c), shadowDesc);
64 graph->addPass(
"shadow" + std::to_string(
c))
65 .depthAttachment(shadowH, vkb::AttachmentOp::clear(shadowClear))
66 .record([
this,
c](vkb::FrameGraphPassContext &ctx) { recordShadowCascadePass(ctx,
int(
c)); });
70 if (i < gbufferSlots.size() && gbufferWidth > 0 && gbufferHeight > 0) {
71 auto &slot = gbufferSlots[i];
72 vkb::TextureDesc colorDesc;
73 colorDesc.format = colorFmt;
74 colorDesc.extent = vk::Extent3D{
w,
h, 1};
75 colorDesc.usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eColorAttachment |
76 vk::ImageUsageFlagBits::eTransferSrc;
77 colorDesc.afterLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
78 auto normalH =
graph->importTexture(
"gbNormal", slot.normal.image(), slot.normal.imageView(), colorDesc);
80 graph->importTexture(
"gbDepthColor", slot.depthColor.image(), slot.depthColor.imageView(), colorDesc);
81 auto albedoH =
graph->importTexture(
"gbAlbedo", slot.albedo.image(), slot.albedo.imageView(), colorDesc);
83 graph->importTexture(
"gbPbrParams", slot.pbrParams.image(), slot.pbrParams.imageView(), colorDesc);
85 graph->importTexture(
"gbEmissive", slot.emissive.image(), slot.emissive.imageView(), colorDesc);
87 vkb::TextureDesc depthDesc;
88 depthDesc.format = depthFmt;
89 depthDesc.extent = vk::Extent3D{
w,
h, 1};
90 depthDesc.aspect = vk::ImageAspectFlagBits::eDepth;
91 depthDesc.usage = vk::ImageUsageFlagBits::eSampled | vk::ImageUsageFlagBits::eDepthStencilAttachment;
92 depthDesc.afterLayout = vk::ImageLayout::eShaderReadOnlyOptimal;
93 auto depthH =
graph->importTexture(
"gbHwDepth", slot.depth.image(), slot.depth.imageView(), depthDesc);
95 std::array<vk::ClearValue, 6> clears{};
96 clears[0].color = vk::ClearColorValue(std::array<float, 4>{0, 0, 0, 0});
97 clears[1].color = vk::ClearColorValue(std::array<float, 4>{1, 1, 1, 1});
98 clears[2].color = vk::ClearColorValue(std::array<float, 4>{0, 0, 0, 0});
99 clears[3].color = vk::ClearColorValue(std::array<float, 4>{0, 1, 1, 1});
100 clears[4].color = vk::ClearColorValue(std::array<float, 4>{0, 0, 0, 0});
101 clears[5].depthStencil = vk::ClearDepthStencilValue{1.0f, 0};
102 graph->addPass(
"gbuffer")
103 .colorAttachment(normalH, vkb::AttachmentOp::clear(clears[0]))
104 .colorAttachment(depthColorH, vkb::AttachmentOp::clear(clears[1]))
105 .colorAttachment(albedoH, vkb::AttachmentOp::clear(clears[2]))
106 .colorAttachment(pbrParamsH, vkb::AttachmentOp::clear(clears[3]))
107 .colorAttachment(emissiveH, vkb::AttachmentOp::clear(clears[4]))
108 .depthAttachment(depthH, vkb::AttachmentOp::clear(clears[5]))
109 .record([
this](vkb::FrameGraphPassContext& ctx) { recordGBufferPassDraws(ctx); });
112 deferredFrameGraphs_[i] = std::move(
graph);
116void Graphics::recordShadowCascadePass(vkb::FrameGraphPassContext &ctx,
int cascade) {
122 auto &cb = ctx.commandBuffer();
123 const vk::Extent2D extent = ctx.extent();
125 setViewportAndScissor(cb,
size,
size);
126 vk::Pipeline boundPipeline{};
127 for (
const auto &
d : shadowCascadeDraws[cascade]) {
128 if (!
d.mesh || !
d.mesh->gpuHandle)
continue;
129 const bool wantAlpha =
d.alphaTest && shadowAlphaPipeline;
130 const bool skinned =
d.skinSet &&
d.mesh->hasGpuSkinning();
131 vk::Pipeline wanted{};
133 wanted = wantAlpha ? (
d.doubleSided ? shadowSkinAlphaPipeline : shadowSkinAlphaSingleSidedPipeline)
134 : (
d.
doubleSided ? shadowSkinPipeline : shadowSkinSingleSidedPipeline);
136 wanted = wantAlpha ? (
d.doubleSided ? shadowAlphaPipeline : shadowAlphaSingleSidedPipeline)
137 : (
d.
doubleSided ? shadowPipeline : shadowSingleSidedPipeline);
139 if (wanted != boundPipeline) {
140 cb.bindPipeline(vk::PipelineBindPoint::eGraphics, wanted);
141 boundPipeline = wanted;
143 auto *gpuMesh =
static_cast<GpuMesh *
>(
d.mesh->gpuHandle);
145 cb.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, skinPassPipelineLayout, 0, 1, &
d.skinSet, 1,
147 }
else if (wantAlpha) {
148 Texture *alb =
d.albedo ?
d.albedo : whiteTexture;
149 if (alb && alb->gpuHandle && texSetLayout) {
150 auto *gpuTex =
static_cast<GpuTexture *
>(alb->gpuHandle);
151 cb.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, shadowAlphaPipelineLayout, 0, 1,
152 gpuTex->descriptorSet.ptr(), 0,
nullptr);
157 ShadowAlphaPush
push{
d.mvp,
d.lodFade};
158 cb.pushConstants(shadowAlphaPipelineLayout,
159 vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment,
162 cb.pushConstants(shadowPipelineLayout, vk::ShaderStageFlagBits::eVertex,
163 0,
sizeof(glm::mat4), &
d.mvp);
166 drawIndexedMesh(cb, *gpuMesh);
170void Graphics::recordGBufferPassDraws(vkb::FrameGraphPassContext &ctx) {
175 auto &cb = ctx.commandBuffer();
176 const vk::Extent2D extent = ctx.extent();
177 const uint32_t
w = extent.width ? extent.width : uint32_t(gbufferWidth);
178 const uint32_t
h = extent.height ? extent.height : uint32_t(gbufferHeight);
179 setViewportAndScissor(cb,
w,
h);
180 vk::Pipeline boundPipeline{};
181 for (
const auto &
d : gbufferPassDraws) {
182 if (!
d.mesh || !
d.mesh->gpuHandle)
continue;
183 const bool wantAlpha =
d.alphaTest && gbufferAlphaPipeline;
184 const bool skinned =
d.skinSet &&
d.mesh->hasGpuSkinning();
185 vk::Pipeline wanted = skinned ? (wantAlpha ? gbufferSkinAlphaPipeline : gbufferSkinPipeline)
186 : (wantAlpha ? gbufferAlphaPipeline : gbufferPipeline);
187 if (wanted != boundPipeline) {
188 cb.bindPipeline(vk::PipelineBindPoint::eGraphics, wanted);
189 boundPipeline = wanted;
191 auto *gpuMesh =
static_cast<GpuMesh *
>(
d.mesh->gpuHandle);
192 Texture *alb =
d.albedo ?
d.albedo : whiteTexture;
194 cb.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, skinPassPipelineLayout, 0, 1, &
d.skinSet, 1,
196 }
else if (alb && alb->gpuHandle && texSetLayout) {
197 auto *gpuTex =
static_cast<GpuTexture *
>(alb->gpuHandle);
198 cb.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, gbufferPipelineLayout, 0, 1,
199 gpuTex->descriptorSet.ptr(), 0,
nullptr);
202 cb.pushConstants(gbufferPipelineLayout,
203 vk::ShaderStageFlagBits::eVertex | vk::ShaderStageFlagBits::eFragment, 0,
204 sizeof(GBufferPush), &
d.push);
205 drawIndexedMesh(cb, *gpuMesh);
209void Graphics::recordDeferredFrameGraph() {
214 if (!gbufferPending && shadowPendingMask == 0) {
215 dropPendingOffscreenPasses();
218 const size_t slot = currentFrameSlot();
219 if (deferredGraphRecorded_ && deferredGraphRecordedSlot_ == slot) {
227 auto *
graph = currentDeferredFrameGraph();
228 if (!
graph && (!shadowMaps.empty() || !gbufferSlots.empty())) {
231 buildDeferredFrameGraphs();
232 graph = currentDeferredFrameGraph();
234 if (!
graph || !gbufferPipeline || !gbufferRenderPass || !shadowPipeline) {
235 dropPendingOffscreenPasses();
245 auto *jobs = thread::Thread::create()->getJobSystem();
258 if (!shadowMaps.empty()) currentShadowMap().image.setCurrentLayout(vk::ImageLayout::eDepthStencilReadOnlyOptimal);
260 for (
auto &
d : shadowCascadeDraws)
d.
clear();
261 gbufferPassDraws.clear();
262 shadowPendingMask = 0;
263 gbufferPending =
false;
264 deferredGraphRecorded_ =
true;
265 deferredGraphRecordedSlot_ = slot;
std::map< std::string, std::vector< std::string > > graph
virtual void reset()
Resets the current color, background color, line style, and so forth.
void push(bool all)
Pushes .
void clear(std::optional< Color > color, std::optional< int > stencil, std::optional< double > depth) override
Clears .
void recordFrameGraphWithJobSystem(vkb::FrameGraph &graph, eve::thread::JobSystem *jobs)
Record a vkb::FrameGraph with the engine JobSystem as the parallel recording executor.
static constexpr int kMapSize
static constexpr int kTotalLayers