idk_me/src/engine/vkn/DeferredPass.cpp
2024-05-24 22:57:42 +08:00

889 lines
30 KiB
C++

#include "pch.h"
#include "DeferredPass.h"
#include <gfx/FramebufferFactory.h>
#include <vkn/PipelineBinders.h>
#include <vkn/VknRenderTarget.h>
#include <vkn/GraphicsState.h>
#include <vkn/utils/utils.h>
#include <gfx/MeshRenderer.h>
#include <vkn/PipelineBinders.h>
#include <vkn/PipelineBinders.inl>
#include <vkn/FrameRenderer.h>
#include <vkn/VknTextureLoader.h>
#include <vkn/VulkanTextureFactory.h>
#include <vkn/VknTextureRenderMeta.h>
#include <vkn/RenderPassInfo.h>
#include <vkn/VknFrameBufferFactory.h>
#include <vkn/VknTexture.h>
#include <res/ResourceManager.inl>
#include <res/ResourceHandle.inl>
#include <res/ResourceMeta.inl>
#include <ds/result.inl>
#include "DeferredPass.h"
#if 1
namespace idk::vkn
{
using EGBufferBinding = meta::enum_info<GBufferBinding, meta::enum_pack<GBufferBinding,
GBufferBinding::eAlbedoAmbOcc,
GBufferBinding::eUvMetallicRoughness,
GBufferBinding::eViewPos,
GBufferBinding::eNormal,
GBufferBinding::eTangent
>>;
enum class DeferredBinding
{
eMetallicPass ,
eSpecularPass ,
eUnlitPass ,
eDepths
};
using EDeferredBinding = meta::enum_info<DeferredBinding, meta::enum_pack<DeferredBinding,
DeferredBinding::eMetallicPass,
DeferredBinding::eSpecularPass,
DeferredBinding::eUnlitPass ,
DeferredBinding::eDepths
>>;
struct DeferredBindingIndex
{
static constexpr uint32_t fb_buffer_size [EDeferredBinding::size()] = { static_cast<uint32_t>(EDeferredBinding::size()),static_cast<uint32_t>(EDeferredBinding::size()),1,3};
static constexpr uint32_t begin(DeferredBinding binding)
{
uint32_t result = 0;
for (int i = 0; i < (int)binding; ++i)
{
result += fb_buffer_size[i];
}
return result;
}
static constexpr uint32_t end (DeferredBinding binding)
{
uint32_t result = 0;
for (int i = 0; i <= (int)binding; ++i)
{
result += fb_buffer_size[i];
}
return result;
}
static constexpr uint32_t size(DeferredBinding binding)
{
return fb_buffer_size[(int)binding] ;
}
};
pipeline_config ConfigWithVP(pipeline_config config, const CameraData& camera, const ivec2& offset, const uvec2& size);
template<typename T, typename...Args>
using has_setstate = decltype(std::declval<T>().SetState(std::declval<Args>()...));
PipelineThingy ProcessRoUniforms(const GraphicsState& state, UboManager& ubo_manager, StandardBindings& binders);
std::pair<ivec2, uvec2> ComputeVulkanViewport(const vec2& sz, const rect& vp);
void GBufferBarrier(vk::CommandBuffer cmd_buffer, DeferredGBuffer& gbuffer)
{
constexpr auto num_buffers = 0;// EGBufferBinding::size();
std::array<vk::ImageMemoryBarrier, num_buffers + 1> barriers;
//for (size_t i = 0; i < EGBufferBinding::size(); ++i)
//{
// auto& tex = gbuffer.gbuffer->GetAttachment(i).buffer.as<VknTexture>();
// barriers[i] = vk::ImageMemoryBarrier
// {
// vk::AccessFlagBits::eColorAttachmentWrite,
// vk::AccessFlagBits::eShaderRead,
// vk::ImageLayout::eColorAttachmentOptimal,
// vk::ImageLayout::eShaderReadOnlyOptimal,
// *View().QueueFamily().graphics_family,
// *View().QueueFamily().graphics_family,
// tex.Image(),
// vk::ImageSubresourceRange
// {
// tex.ImageAspects(),
// 0,1,
// 0,1,
// }
// };
//}
auto& depth_tex = gbuffer.gbuffer->DepthAttachment().buffer.as<VknTexture>();
//depth
barriers[num_buffers] = vk::ImageMemoryBarrier
{
{},
vk::AccessFlagBits::eTransferRead,
vk::ImageLayout::eGeneral,
vk::ImageLayout::eTransferSrcOptimal,
*View().QueueFamily().graphics_family,
*View().QueueFamily().graphics_family,
depth_tex.Image(),
vk::ImageSubresourceRange
{
depth_tex.ImageAspects(),
0,1,
0,1,
}
};
cmd_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlagBits::eByRegion, nullptr, nullptr, barriers, vk::DispatchLoaderDefault{});
}
vk::Semaphore DeferredGBuffer::RenderCompleteSignal()
{
return *_render_complete;
}
struct RpBindInfo
{
index_t index;
};
struct SubFramebuffer
{
vector<index_t> color_attachments;
index_t depth_attachment;
};
bool DeferredGBuffer::Init(uvec2 size)
{
bool inited = false;
if (!gbuffer || gbuffer->Size()!=size)
{
inited = true;
FrameBufferBuilder fbf;
fbf.Begin("GBuffer",size)
.AddAttachment(idk::AttachmentInfo{ // GBufferBinding::eAlbedoAmbOcc
LoadOp::eClear,StoreOp::eStore,
TextureInternalFormat::RGBA_8,
FilterMode::_enum::Nearest
})
.AddAttachment(idk::AttachmentInfo{ // GBufferBinding::eUvMetallicRoughness
LoadOp::eClear,StoreOp::eStore,
TextureInternalFormat::RGBA_8,
FilterMode::_enum::Nearest
})
.AddAttachment(idk::AttachmentInfo{ // GBufferBinding::eViewPos
LoadOp::eClear,StoreOp::eStore,
TextureInternalFormat::RGBA_16_F,
FilterMode::_enum::Nearest
})
.AddAttachment(idk::AttachmentInfo{ // GBufferBinding::eNormal
LoadOp::eClear,StoreOp::eStore,
TextureInternalFormat::RGBA_8,
FilterMode::_enum::Nearest
})
.AddAttachment(idk::AttachmentInfo{ // GBufferBinding::eTangent
LoadOp::eClear,StoreOp::eStore,
TextureInternalFormat::RGBA_8,
FilterMode::_enum::Nearest
})
.SetDepthAttachment(idk::AttachmentInfo{
LoadOp::eClear,StoreOp::eStore,
TextureInternalFormat::DEPTH_32_F_STENCIL_8,
FilterMode::_enum::Nearest
});
auto fb_info = fbf.End();
auto& fb_factory = Core::GetResourceManager().GetFactory<FrameBufferFactory>();
if (gbuffer)
Core::GetResourceManager().Release(gbuffer);
auto new_buffer = fb_factory.Create(fb_info);
gbuffer = RscHandle<VknFrameBuffer>{ new_buffer };
fbf.Begin("Accum Buffer",size);
fbf.AddAttachment(idk::AttachmentInfo{
LoadOp::eClear,StoreOp::eStore,
TextureInternalFormat::RGBA_16_F,
FilterMode::_enum::Nearest
});
uint32_t i = 0;
for (i = 0; i < EGBufferBinding::size(); ++i)
{
auto att = idk::AttachmentInfo{
LoadOp::eLoad,StoreOp::eDontCare,
TextureInternalFormat::RGBA_16_F,
FilterMode::_enum::Nearest,
false,
gbuffer->GetAttachment(i).buffer
};
att.is_input_att = true;
fbf.AddAttachment(att);
}
auto vkn_att = idk::AttachmentInfo{
LoadOp::eLoad,StoreOp::eDontCare,
TextureInternalFormat::DEPTH_32_F,
FilterMode::_enum::Nearest,
false,
gbuffer->DepthAttachment().buffer
};
vkn_att.override_as_depth = true;
vkn_att.is_input_att = true;
fbf.AddAttachment(vkn_att);
if (accum_buffer)
Core::GetResourceManager().Release(accum_buffer);
accum_buffer = RscHandle<VknFrameBuffer>{ fb_factory.Create(fbf.End()) };
_render_complete = View().Device()->createSemaphoreUnique(vk::SemaphoreCreateInfo{});
}
return inited;
}
////
vk::UniqueRenderPass BuildAccumRenderPass(VknFrameBuffer& fb)
{
RenderPassInfo rp_info;
SubPassConfig spc{};
//Output
spc.AddOutputAttachment(0, vk::ImageLayout::eColorAttachmentOptimal);
rp_info.RegisterAttachment(fb.GetAttachment(0), vk::ImageLayout::eUndefined, vk::ImageLayout::eShaderReadOnlyOptimal);
uint32_t i = 0;
for (i = 0; i < EGBufferBinding::size(); ++i)
{
spc.AddInputAttachment(1+i, vk::ImageLayout::eShaderReadOnlyOptimal);
rp_info.RegisterAttachment(fb.GetAttachment(1 + i), vk::ImageLayout::eGeneral, vk::ImageLayout::eShaderReadOnlyOptimal);
}
spc.AddInputAttachment(1+i, vk::ImageLayout::eShaderReadOnlyOptimal);
rp_info.RegisterAttachment(fb.GetAttachment(1 + i), vk::ImageLayout::eGeneral, vk::ImageLayout::eShaderReadOnlyOptimal);
spc.BuildSubpass();
rp_info.RegisterSubpass(spc);
rp_info.AddDependency(VK_SUBPASS_EXTERNAL, 0,
{},vk::AccessFlagBits::eColorAttachmentRead,
vk::PipelineStageFlagBits::eTopOfPipe,
vk::PipelineStageFlagBits::eFragmentShader
);
auto tmp = rp_info.BuildRenderPass();
return View().Device()->createRenderPassUnique(tmp);
}
////
vk::UniqueRenderPass BuildHdrRenderPass(const FrameBufferInfo& hdr_out)
{
RenderPassInfo rp_info;
//Output
int i = 0;
SubPassConfig spc{};
spc.AddOutputAttachment(i, vk::ImageLayout::eColorAttachmentOptimal);
rp_info.RegisterAttachment(hdr_out.attachments[i++], vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral);
spc.AddInputAttachment(i, vk::ImageLayout::eShaderReadOnlyOptimal);
rp_info.RegisterAttachment(hdr_out.attachments[i++], vk::ImageLayout::eShaderReadOnlyOptimal, vk::ImageLayout::eShaderReadOnlyOptimal);
spc.AddInputAttachment(i, vk::ImageLayout::eShaderReadOnlyOptimal);
rp_info.RegisterAttachment(hdr_out.attachments[i++], vk::ImageLayout::eShaderReadOnlyOptimal, vk::ImageLayout::eShaderReadOnlyOptimal);
spc.AddInputAttachment(i, vk::ImageLayout::eShaderReadOnlyOptimal);
rp_info.RegisterAttachment(hdr_out.attachments[i++], vk::ImageLayout::eShaderReadOnlyOptimal, vk::ImageLayout::eShaderReadOnlyOptimal);
spc.AddInputAttachment(i, vk::ImageLayout::eShaderReadOnlyOptimal);
rp_info.RegisterAttachment(hdr_out.attachments[i++], vk::ImageLayout::eShaderReadOnlyOptimal, vk::ImageLayout::eShaderReadOnlyOptimal);
spc.SetDepthAttachment(i, vk::ImageLayout::eDepthStencilAttachmentOptimal);
rp_info.RegisterAttachment(*hdr_out.depth_attachment, vk::ImageLayout::eGeneral, vk::ImageLayout::eGeneral);
spc.BuildSubpass();
rp_info.RegisterSubpass(spc);
rp_info.AddDependency(VK_SUBPASS_EXTERNAL, 0,
vk::AccessFlagBits::eColorAttachmentWrite | vk::AccessFlagBits::eDepthStencilAttachmentWrite,
vk::AccessFlagBits::eShaderRead,
vk::PipelineStageFlagBits::eColorAttachmentOutput | vk::PipelineStageFlagBits::eLateFragmentTests,
vk::PipelineStageFlagBits::eFragmentShader);
//auto create_info = rp_info.BuildRenderPass();
return View().Device()->createRenderPassUnique(rp_info.BuildRenderPass());
}
void DeferredPass::Init(VknRenderTarget& )
{
}
void DeferredPass::Init(VknRenderTarget& rt, DeferredGBuffer(&gbuf)[EGBufferType::size()])
{
_gbuffer = &gbuf;
const static renderer_attributes fsq_requirements =
{
{
{vtx::Attrib::Position,0},
{vtx::Attrib::UV,1},
}
};
{
if (!hdr_frag)
{
auto frag_opt = Core::GetResourceManager().Load<ShaderProgram>("/engine_data/shaders/deferred_hdr.frag", false);
if (frag_opt)
hdr_frag = *frag_opt;
}
}
if (!hdr_buffer ||(hdr_buffer->Size() != rt.Size() || hdr_buffer->attachments[0]->buffer!=rt.GetColorBuffer()))
{
auto& fb_factory = Core::GetResourceManager().GetFactory<FrameBufferFactory>();
FrameBufferBuilder fbf;
fbf.Begin("HDR Buffer",rt.Size());
auto ai = idk::AttachmentInfo{
LoadOp::eLoad,StoreOp::eStore,
TextureInternalFormat::SRGBA_8,
FilterMode::_enum::Nearest,false,
rt.GetColorBuffer()
};
fbf.AddAttachment(ai);
auto add_src = [](FrameBufferBuilder& fbf, auto& gbuffer) {
auto& buffer = *gbuffer.accum_buffer;
auto accum_att = idk::AttachmentInfo{
LoadOp::eLoad,StoreOp::eDontCare,
TextureInternalFormat::SRGB_8,
FilterMode::_enum::Nearest,false,
buffer.GetAttachment(0).buffer
};
accum_att.is_input_att = true;
fbf.AddAttachment(accum_att);
auto depth_att = idk::AttachmentInfo{
LoadOp::eLoad,StoreOp::eDontCare,
TextureInternalFormat::DEPTH_32_F_STENCIL_8,
FilterMode::_enum::Nearest,false,
gbuffer.gbuffer->DepthAttachment().buffer
};
depth_att.override_as_depth = true;
depth_att.is_input_att = true;
fbf.AddAttachment(depth_att);
};
for (auto& gbuffer : GBuffers())
add_src(fbf, gbuffer);
auto depth_att = idk::AttachmentInfo{
LoadOp::eDontCare,StoreOp::eStore,
TextureInternalFormat::DEPTH_32_F_STENCIL_8,
FilterMode::_enum::Nearest,false,
rt.GetDepthBuffer()//GetColorBuffer()
};
fbf.SetDepthAttachment(depth_att);
if (hdr_buffer)
Core::GetResourceManager().Release(hdr_buffer);
auto hdr_info = fbf.End();
hdr_pass = RenderPassObj{ BuildHdrRenderPass(hdr_info) };
auto tmp = VknSpecializedInfo{ hdr_pass };
hdr_buffer = RscHandle<VknFrameBuffer>{ fb_factory.Create(hdr_info,&tmp) };
}
if(!accum_pass)
accum_pass = BuildAccumRenderPass(GBuffers()[0].accum_buffer.as<VknFrameBuffer>());
if(!hdr_pass)
hdr_pass = hdr_buffer->GetRenderPass();
fsq_light_ro.mesh = fsq_amb_ro.mesh = Mesh::defaults[MeshType::INV_FSQ];
fsq_light_ro.renderer_req = fsq_amb_ro.renderer_req = &fsq_requirements;
if (!fsq_light_ro.config)
{
ambient_config = std::make_shared<pipeline_config>(*Core::GetSystem<GraphicsSystem>().MeshRenderConfig());
light_config = std::make_shared<pipeline_config>(*Core::GetSystem<GraphicsSystem>().MeshRenderConfig());
light_config->attachment_configs.resize(1);
auto& blend = light_config->attachment_configs[0];
blend.blend_enable = true;
blend.dst_color_blend_factor = BlendFactor::eOne;
blend.src_color_blend_factor = BlendFactor::eOne;
blend.color_blend_op = BlendOp::eAdd;
blend.alpha_blend_op = BlendOp::eMax;
blend.dst_alpha_blend_factor = BlendFactor::eOne;
blend.src_alpha_blend_factor = BlendFactor::eOne;
light_config->depth_test = false;
fsq_light_ro.config = light_config;
fsq_amb_ro.config = ambient_config;
}
}
GBufferType MapToGBufferType(ShadingModel model)noexcept
{
switch (model)
{
case ShadingModel::_enum::Specular:
return GBufferType::eSpecular;
break;
case ShadingModel::_enum::DefaultLit:
return GBufferType::eMetallic;
break;
default:
LOG_TO(LogPool::GFX, "GBufferType doesn't support %s yet. Defaulting to eMetallic", model.to_string().data());
return GBufferType::eMetallic;
break;
}
}
static auto& PopulateGbufferNames()
{
static const char* gbuffer_names[EGBufferBinding::size()+1];
gbuffer_names[EGBufferBinding::map(GBufferBinding::eAlbedoAmbOcc)] = "gAlbAmbOcc";
gbuffer_names[EGBufferBinding::map(GBufferBinding::eViewPos)] = "gViewPos";
gbuffer_names[EGBufferBinding::map(GBufferBinding::eNormal)] = "gNormal";
gbuffer_names[EGBufferBinding::map(GBufferBinding::eTangent)] = "gTangent";
gbuffer_names[EGBufferBinding::map(GBufferBinding::eUvMetallicRoughness)] = "gUvMetRough";
gbuffer_names[EGBufferBinding::size()] = "gDepth";
return gbuffer_names;
}
static const auto gbuffer_names = PopulateGbufferNames();
struct DeferredPostBinder : StandardBindings
{
bool is_ambient = false;
GBufferType type;
DeferredPass* deferred_pass;
void SetDeferredPass(DeferredPass& pass)
{
deferred_pass = &pass;
}
bool Skip(PipelineThingy&, const RenderObject& dc)
{
return MapToGBufferType(dc.material_instance->material->model) != type;
}
void Bind(PipelineThingy& the_interface) override
{
RscHandle<ShaderProgram> fsq_vert = deferred_pass->fullscreen_quad_vert;
RscHandle<ShaderProgram> deferred_post_frag = deferred_pass->deferred_post_frag[EGBufferType::map(type)];
RscHandle<ShaderProgram> deferred_post_ambient = deferred_pass->deferred_post_ambient;
the_interface.BindShader(ShaderStage::Vertex, fsq_vert);
the_interface.BindShader(ShaderStage::Fragment, (is_ambient)? deferred_post_ambient:deferred_post_frag);
auto& gbuffer_fb = deferred_pass->GBuffer(type).gbuffer;
for (uint32_t i = 0; i < EGBufferBinding::size(); ++i)
the_interface.BindAttachment(gbuffer_names[i], 0, gbuffer_fb->GetAttachment(i).buffer.as<VknTexture>(),true,vk::ImageLayout::eShaderReadOnlyOptimal);
the_interface.BindAttachment(gbuffer_names[static_cast<uint32_t>(EGBufferBinding::size())], 0, gbuffer_fb->DepthAttachment().buffer.as<VknTexture>(),false, vk::ImageLayout::eShaderReadOnlyOptimal);
}
};
struct DeferredHdrBinder : StandardBindings
{
bool is_ambient = false;
DeferredPass* deferred_pass;
void SetDeferredPass(DeferredPass& pass)
{
deferred_pass = &pass;
}
void Bind(PipelineThingy& the_interface) override
{
RscHandle<ShaderProgram> fsq_vert = deferred_pass->fullscreen_quad_vert;
RscHandle<ShaderProgram> hdr_frag = deferred_pass->hdr_frag;
the_interface.BindShader(ShaderStage::Vertex, fsq_vert);
the_interface.BindShader(ShaderStage::Fragment, hdr_frag);
}
};
using PbrDeferredPostBinding = CombinedBindings<DeferredPostBinder, PbrFwdBindings>;
void DeferredPass::LightPass(GBufferType type, PipelineThingy& the_interface, const GraphicsState& graphics_state, [[maybe_unused]]RenderStateV2& rs, std::optional<std::pair<size_t, size_t>> light_range,bool is_ambient)
{
PbrDeferredPostBinding binding;
auto& def_bind = std::get<DeferredPostBinder>(binding.binders);
def_bind.type = type;
def_bind.SetDeferredPass(*this);
def_bind.is_ambient = is_ambient;
auto& pbr_fwd_binding = std::get<PbrFwdBindings>(binding.binders);
pbr_fwd_binding.light_range = light_range;
pbr_fwd_binding.rebind_light = true;
pbr_fwd_binding.SetState(graphics_state);
auto& fsq_ro = (is_ambient) ? fsq_amb_ro : fsq_light_ro;
binding.Bind(the_interface);
binding.Bind(the_interface, fsq_ro);
the_interface.BindMeshBuffers(fsq_ro);
//Draw Fullscreen Quad
the_interface.FinalizeDrawCall(fsq_ro);
//Insert Forward stuff here?
}
static std::pair<const char*,vk::ImageLayout> hdr_attachment_info[]
=
{
{"metallic_light_accum_input" , vk::ImageLayout::eShaderReadOnlyOptimal},
{"metallic_depth_input" , vk::ImageLayout::eShaderReadOnlyOptimal },
{"specular_light_accum_input" , vk::ImageLayout::eShaderReadOnlyOptimal},
{"specular_depth_input" , vk::ImageLayout::eShaderReadOnlyOptimal },
};
PipelineThingy DeferredPass::HdrPass([[maybe_unused]]const GraphicsState& graphics_state, RenderStateV2& rs)
{
PipelineThingy the_interface{};
the_interface.SetRef(rs.ubo_manager);
DeferredHdrBinder binding;
binding.SetDeferredPass(*this);
auto& fsq_ro = fsq_amb_ro ;
binding.Bind(the_interface);
auto& buffer = *hdr_buffer;
/*for (auto& g_buffer : GBuffers())
{
auto& gbuffer = g_buffer.gbuffer.as<VknFrameBuffer>();
}*/
int i = 1;
for (auto& [name, layout]:hdr_attachment_info )
the_interface.BindAttachment(name, 0, buffer.GetAttachment(i++).buffer.as<VknTexture>(), false, layout);
the_interface.BindMeshBuffers(fsq_ro);
//Draw Fullscreen Quad
the_interface.FinalizeDrawCall(fsq_ro);
return the_interface;
}
void PostRenderCopy(vk::CommandBuffer cmd_buffer,ivec2 size, vk::Image render_target_depth, vk::Image gbuffer_depth)
{
//Transit RTD -> Transfer
vk::ImageMemoryBarrier depth
{
{},
vk::AccessFlagBits::eTransferWrite,
vk::ImageLayout::eDepthStencilAttachmentOptimal,
vk::ImageLayout::eTransferDstOptimal,
*View().QueueFamily().graphics_family,
*View().QueueFamily().graphics_family,
render_target_depth,
vk::ImageSubresourceRange
{
vk::ImageAspectFlagBits::eDepth,
0,1,0,1
}
};
std::array<vk::ImageMemoryBarrier, 2> convert_barriers = { depth,depth };
convert_barriers[1].setDstAccessMask(vk::AccessFlagBits::eTransferRead);
convert_barriers[1].setOldLayout(vk::ImageLayout::eShaderReadOnlyOptimal);
convert_barriers[1].setNewLayout(vk::ImageLayout::eTransferSrcOptimal);
convert_barriers[1].setImage(gbuffer_depth);
cmd_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eBottomOfPipe, vk::PipelineStageFlagBits::eTransfer, vk::DependencyFlagBits::eByRegion, nullptr, nullptr, convert_barriers);
//Blit
//expect depth attachments to be the exact same size and format.
cmd_buffer.copyImage(
gbuffer_depth, vk::ImageLayout::eTransferSrcOptimal,
render_target_depth, vk::ImageLayout::eTransferDstOptimal,
vk::ImageCopy
{
vk::ImageSubresourceLayers
{
vk::ImageAspectFlagBits::eDepth,
0u,0u,1u
},
vk::Offset3D{0,0,0},
vk::ImageSubresourceLayers
{
vk::ImageAspectFlagBits::eDepth,
0ui32,0ui32,1ui32
},
vk::Offset3D{0,0,0},
vk::Extent3D{s_cast<uint32_t>(size.x),s_cast<uint32_t>(size.y)}
}
);
//Transit RTD -> General
std::array<vk::ImageMemoryBarrier, 2> & return_barriers = convert_barriers;// { depth, depth };
std::swap(return_barriers[0].dstAccessMask, return_barriers[0].srcAccessMask);
std::swap(return_barriers[0].oldLayout, return_barriers[0].newLayout);
return_barriers[0].setDstAccessMask({});// vk::AccessFlagBits::eDepthStencilAttachmentRead | vk::AccessFlagBits::eDepthStencilAttachmentWrite);
return_barriers[0].setNewLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal);
//Transit GD -> DepthAttachmentOptimal
return_barriers[1].setSrcAccessMask(vk::AccessFlagBits::eTransferRead);
return_barriers[1].setDstAccessMask({});
return_barriers[1].setOldLayout(vk::ImageLayout::eTransferSrcOptimal);
return_barriers[1].setNewLayout(vk::ImageLayout::eDepthStencilAttachmentOptimal);
return_barriers[1].setImage(gbuffer_depth);
cmd_buffer.pipelineBarrier(vk::PipelineStageFlagBits::eTransfer, vk::PipelineStageFlagBits::eEarlyFragmentTests, vk::DependencyFlagBits::eByRegion, nullptr, nullptr, return_barriers);
}
bool RenderProcessedDrawCalls(vk::CommandBuffer cmd_buffer,
const vector<ProcessedRO>& processed_ro,
const CameraData& camera,
PipelineManager& pipeline_manager,
uint32_t frame_index,
const vk::RenderPassBeginInfo& rpbi,
RenderPassObj render_pass,
uint32_t num_attachments,
const GraphicsState* state = nullptr
)
{
auto offset = ivec2{ rpbi.renderArea.offset.x,rpbi.renderArea.offset.y };
auto size= uvec2{ s_cast<uint32_t>(rpbi.renderArea.extent.width),s_cast<uint32_t>(rpbi.renderArea.extent.height )};
auto& view = View();
vector<RscHandle<ShaderProgram>> shaders;
VulkanPipeline* prev_pipeline = nullptr;
//Draw stuff into the gbuffers
//auto& processed_ro = the_interface.DrawCalls();
bool rendered = false;
for (auto& p_ro : processed_ro)
{
rendered = true;
auto& obj = p_ro.Object();
bool is_mesh_renderer = p_ro.vertex_shader == Core::GetSystem<GraphicsSystem>().renderer_vertex_shaders[VNormalMesh];
if (p_ro.rebind_shaders)
{
shaders.resize(0);
if (p_ro.frag_shader)
shaders.emplace_back(*p_ro.frag_shader);
if (p_ro.vertex_shader)
shaders.emplace_back(*p_ro.vertex_shader);
if (p_ro.geom_shader)
shaders.emplace_back(*p_ro.geom_shader);
auto config = ConfigWithVP(*obj.config, camera, offset, size);
config.attachment_configs.resize(num_attachments);
if (is_mesh_renderer)
config.buffer_descriptions.emplace_back(
buffer_desc
{
buffer_desc::binding_info{ std::nullopt,sizeof(mat4) * 2,VertexRate::eInstance},
{buffer_desc::attribute_info{AttribFormat::eMat4,4,0,true},
buffer_desc::attribute_info{AttribFormat::eMat4,8,sizeof(mat4),true}
}
}
);
auto& pipeline = pipeline_manager.GetPipeline(config, shaders, frame_index, render_pass, true);
pipeline.Bind(cmd_buffer, view);
SetViewport(cmd_buffer, offset, size);
prev_pipeline = &pipeline;
}
auto& pipeline = *prev_pipeline;
auto& mesh = obj.mesh.as<VulkanMesh>();
{
uint32_t set = 0;
for (auto& ods : p_ro.descriptor_sets)
{
if (ods)
{
auto& ds = *ods;
cmd_buffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *pipeline.pipelinelayout, set, ds, {});
}
++set;
}
}
auto& renderer_req = *obj.renderer_req;
for (auto&& [attrib, location] : renderer_req.mesh_requirements)
{
auto& attrib_buffer = mesh.Get(attrib);
cmd_buffer.bindVertexBuffers(*pipeline.GetBinding(location), *attrib_buffer.buffer(), vk::DeviceSize{ attrib_buffer.offset }, vk::DispatchLoaderDefault{});
}
if (state&&is_mesh_renderer)
{
uint32_t obj_trf_loc = 4;
cmd_buffer.bindVertexBuffers(*pipeline.GetBinding(obj_trf_loc), state->shared_gfx_state->inst_mesh_render_buffer.buffer(), { 0 }, vk::DispatchLoaderDefault{});
}
auto& oidx = mesh.GetIndexBuffer();
if (oidx)
{
cmd_buffer.bindIndexBuffer(*(*oidx).buffer(), 0, mesh.IndexType(), vk::DispatchLoaderDefault{});
cmd_buffer.drawIndexed(mesh.IndexCount(), static_cast<uint32_t>(p_ro.num_instances), 0, 0, static_cast<uint32_t>(p_ro.inst_offset), vk::DispatchLoaderDefault{});
}
}
return rendered;
}
struct TypeCheck : StandardBindings
{
ShadingModel model;
bool Skip([[maybe_unused]]PipelineThingy& the_interface, const RenderObject& dc) override
{
if (dc.material_instance)
{
auto& mat_inst = *dc.material_instance;
if (mat_inst.material)
{
auto& mat = *mat_inst.material;
return mat.blend != BlendMode::Opaque || mat.model != model;
}
}
return true;
}
};
using PbrDeferredGbufferBinding = CombinedBindings<TypeCheck, StandardVertexBindings, StandardMaterialFragBindings, StandardMaterialBindings>;
static ShadingModel gbuffer_type_to_model[] = {ShadingModel::DefaultLit,ShadingModel::Specular};
void DeferredPass::DrawToGBuffers(vk::CommandBuffer cmd_buffer,const GraphicsState& graphics_state,RenderStateV2& rs)
{
int i = 0;
std::array<float, 4> depth_clear{ 1.0f,1.0f ,1.0f ,1.0f };
std::array<float, 4> g_clear{ 0.0f,0.0f ,0.0f ,0.0f };
auto& camera = graphics_state.camera;
const rect& viewport = graphics_state.camera.viewport;
for (auto& gbuffer : GBuffers())
{
//Bind the material uniforms
PbrDeferredGbufferBinding binder;
binder.for_each_binder<has_setstate>([](auto& binder, const GraphicsState& state) { binder.SetState(state); }, graphics_state);
auto& type_checker = std::get<TypeCheck>(binder.binders);
type_checker.model = gbuffer_type_to_model[i];
//Preprocess MeshRender's uniforms
auto&& the_interface = ProcessRoUniforms(graphics_state, rs.ubo_manager, binder);
the_interface.GenerateDS(rs.dpools,false);
//std::array<float, 4> a{};
auto& g_buffer = *gbuffer.gbuffer;
auto frame_buffer = g_buffer.GetFramebuffer();
//auto sz = ;
auto [offset, size] = ComputeVulkanViewport(vec2{ g_buffer.Size() }, viewport);
vk::ClearValue v[EGBufferBinding::size()+1]{};
for(auto& value : v)
{
value = vk::ClearValue{ g_clear };
};
v[EGBufferBinding::size()] =vk::ClearValue{ vk::ClearColorValue{ depth_clear } };
vk::Rect2D render_area
{
vk::Offset2D
{
s_cast<int32_t>(offset.x),s_cast<int32_t>(offset.y)
},vk::Extent2D
{
s_cast<uint32_t>(size.x),s_cast<uint32_t>(size.y)
}
};
auto& rp = g_buffer.GetRenderPass();
vk::RenderPassBeginInfo rpbi
{
*rp, frame_buffer,
render_area,hlp::arr_count(v),std::data(v)
};
cmd_buffer.beginRenderPass(rpbi, vk::SubpassContents::eInline);
if (RenderProcessedDrawCalls(cmd_buffer, the_interface.DrawCalls(), camera, pipeline_manager(), frame_index(), rpbi,rp,static_cast<uint32_t>(g_buffer.NumColorAttachments()),&graphics_state))
rs.FlagRendered();
cmd_buffer.endRenderPass();//End GBuffer pass
++i;
}
//GBufferBarrier(cmd_buffer, gbuffer);
}
//
void DeferredPass::DrawToAccum(vk::CommandBuffer cmd_buffer, PipelineThingy(&accum_stuff)[EGBufferType::size()], const CameraData& camera, [[maybe_unused]]RenderStateV2& rs)
{
int i = 0;
auto sz = vec2{ camera.render_target->Size() };
auto viewport = rect{};// camera.viewport;
for (auto& gbuffer : GBuffers())
{
auto [offset, size] = ComputeVulkanViewport(sz, viewport);
vk::Rect2D render_area
{
vk::Offset2D
{
s_cast<int32_t>(offset.x),s_cast<int32_t>(offset.y)
},vk::Extent2D
{
s_cast<uint32_t>(size.x),s_cast<uint32_t>(size.y)
}
};
vk::ClearValue v[2]
{
vk::ClearColorValue{std::array<float,4>{0.0f,0.0f,0.0f,0.0f}},
vk::ClearDepthStencilValue{1,0},
};
const auto& rp = accum_pass;
vk::RenderPassBeginInfo rpbi
{
*rp, gbuffer.accum_buffer.as<VknFrameBuffer>().GetFramebuffer(),
render_area,hlp::arr_count(v),std::data(v)
};
//Transit depth buffer to general for sampling
//Begin Depthless RT renderpass
cmd_buffer.beginRenderPass(rpbi, vk::SubpassContents::eInline);
//Draw FSQ
auto& dc = accum_stuff[i].DrawCalls();
RenderProcessedDrawCalls(cmd_buffer, dc, camera, pipeline_manager(), frame_index(), rpbi, rp, 1);
//End Depthless RT renderpass
cmd_buffer.endRenderPass();
++i;
}
//Copy depth buffer to render target's depth buffer
}
void DoNothing();
void DeferredPass::DrawToRenderTarget(vk::CommandBuffer cmd_buffer, PipelineThingy& fsq_stuff,const CameraData& camera, [[maybe_unused]]VknRenderTarget& rt, [[maybe_unused]]RenderStateV2& rs)
{
auto sz = vec2{ camera.render_target->Size() };
auto [offset, size] = ComputeVulkanViewport(sz, camera.viewport);
vk::Rect2D render_area
{
vk::Offset2D
{
s_cast<int32_t>(offset.x),s_cast<int32_t>(offset.y)
},vk::Extent2D
{
s_cast<uint32_t>(size.x),s_cast<uint32_t>(size.y)
}
};
vk::ClearValue v[2]
{
vk::ClearColorValue{std::array<float,4>{0.0f,0.0f,0.0f,0.0f}},
vk::ClearDepthStencilValue{1,0},
};
const auto& rp = hdr_pass;
auto& fb = *hdr_buffer;
///vector<vk::Format> formats;
///for (auto& b : fb.attachments)
///{
/// formats.emplace_back(b->buffer.as<VknTexture>().format);
///}
///formats.emplace_back(rt.color_tex.as<VknTexture>().format);
///formats.emplace_back(rt.depth_tex.as<VknTexture>().format);
vk::RenderPassBeginInfo rpbi
{
*rp, fb.GetFramebuffer(),
render_area,hlp::arr_count(v),std::data(v)
};
//if (formats[0] != formats[fb.attachments.size()])
// DoNothing();
//Transit depth buffer to general for sampling
//Begin Depthless RT renderpass
cmd_buffer.beginRenderPass(rpbi,vk::SubpassContents::eInline);
//Draw FSQ
RenderProcessedDrawCalls(cmd_buffer, fsq_stuff.DrawCalls(), camera, pipeline_manager(), frame_index(),rpbi,rp,1);
//End Depthless RT renderpass
cmd_buffer.endRenderPass();
//Copy depth buffer to render target's depth buffer
//auto gbuffer_depth_img = GBuffer().gbuffer->DepthAttachment()->as<VknTexture>().Image();
//PostRenderCopy(cmd_buffer, ivec2{ s_cast<int>(render_area.extent.width),s_cast<int>(render_area.extent.height) },rt.GetDepthBuffer().as<VknTexture>().Image(), gbuffer_depth_img);
}
}
#endif
//returns color and depth