- hook up postprocessing

This commit is contained in:
Magnus Norddahl 2019-03-07 18:05:12 +01:00
parent a5c820e1e6
commit 6db231596f
9 changed files with 156 additions and 69 deletions

View file

@ -6,6 +6,7 @@
#include "vulkan/system/vk_framebuffer.h"
#include "vulkan/system/vk_buffers.h"
#include "vulkan/system/vk_swapchain.h"
#include "vulkan/renderer/vk_renderstate.h"
#include "hwrenderer/utility/hw_cvars.h"
#include "hwrenderer/postprocessing/hw_presentshader.h"
#include "hwrenderer/postprocessing/hw_postprocess.h"
@ -25,6 +26,13 @@ VkPostprocess::~VkPostprocess()
{
}
void VkPostprocess::SetActiveRenderTarget()
{
auto fb = GetVulkanFrameBuffer();
auto buffers = fb->GetBuffers();
fb->GetRenderPassManager()->SetRenderTarget(buffers->PipelineView[mCurrentPipelineImage].get(), buffers->GetWidth(), buffers->GetHeight());
}
void VkPostprocess::PostProcessScene(int fixedcm, const std::function<void()> &afterBloomDrawEndScene2D)
{
auto fb = GetVulkanFrameBuffer();
@ -43,7 +51,7 @@ void VkPostprocess::PostProcessScene(int fixedcm, const std::function<void()> &a
RenderEffect("UpdateCameraExposure");
//mCustomPostProcessShaders->Run("beforebloom");
RenderEffect("BloomScene");
//BindCurrentFB();
SetActiveRenderTarget();
afterBloomDrawEndScene2D();
RenderEffect("TonemapScene");
RenderEffect("ColormapScene");
@ -52,6 +60,73 @@ void VkPostprocess::PostProcessScene(int fixedcm, const std::function<void()> &a
//mCustomPostProcessShaders->Run("scene");
}
void VkPostprocess::BlitSceneToTexture()
{
auto fb = GetVulkanFrameBuffer();
fb->GetRenderState()->EndRenderPass();
auto buffers = fb->GetBuffers();
auto cmdbuffer = fb->GetDrawCommands();
auto sceneColor = buffers->SceneColor.get();
mCurrentPipelineImage = 0;
PipelineBarrier barrier0;
barrier0.addImage(sceneColor, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
barrier0.addImage(buffers->PipelineImage[mCurrentPipelineImage].get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
barrier0.execute(cmdbuffer, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
if (buffers->SceneSamples > 1)
{
VkImageResolve resolve = {};
resolve.srcOffset = { 0, 0, 0 };
resolve.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
resolve.srcSubresource.mipLevel = 0;
resolve.srcSubresource.baseArrayLayer = 0;
resolve.srcSubresource.layerCount = 1;
resolve.dstOffset = { 0, 0, 0 };
resolve.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
resolve.dstSubresource.mipLevel = 0;
resolve.dstSubresource.baseArrayLayer = 0;
resolve.dstSubresource.layerCount = 1;
resolve.extent = { (uint32_t)sceneColor->width, (uint32_t)sceneColor->height, 1 };
cmdbuffer->resolveImage(
sceneColor->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
buffers->PipelineImage[mCurrentPipelineImage]->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &resolve);
}
else
{
VkImageBlit blit = {};
blit.srcOffsets[0] = { 0, 0, 0 };
blit.srcOffsets[1] = { sceneColor->width, sceneColor->height, 1 };
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.srcSubresource.mipLevel = 0;
blit.srcSubresource.baseArrayLayer = 0;
blit.srcSubresource.layerCount = 1;
blit.dstOffsets[0] = { 0, 0, 0 };
blit.dstOffsets[1] = { sceneColor->width, sceneColor->height, 1 };
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.dstSubresource.mipLevel = 0;
blit.dstSubresource.baseArrayLayer = 0;
blit.dstSubresource.layerCount = 1;
cmdbuffer->blitImage(
sceneColor->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
buffers->PipelineImage[mCurrentPipelineImage]->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &blit, VK_FILTER_NEAREST);
}
// Note: this destroys the sceneColor contents
PipelineBarrier barrier1;
barrier1.addImage(sceneColor, VK_IMAGE_LAYOUT_UNDEFINED/*VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL*/, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, 0);
barrier1.execute(cmdbuffer, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
buffers->SceneColorLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
buffers->PipelineLayout[mCurrentPipelineImage] = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL;
}
void VkPostprocess::DrawPresentTexture(const IntRect &box, bool applyGamma, bool clearBorders)
{
auto fb = GetVulkanFrameBuffer();
@ -85,8 +160,7 @@ void VkPostprocess::DrawPresentTexture(const IntRect &box, bool applyGamma, bool
step.ShaderName = "Present";
step.Uniforms.Set(uniforms);
step.Viewport = box;
//step.SetInputCurrent(0, ViewportLinearScale() ? PPFilterMode::Linear : PPFilterMode::Nearest);
step.SetInputSceneColor(0, ViewportLinearScale() ? PPFilterMode::Linear : PPFilterMode::Nearest);
step.SetInputCurrent(0, ViewportLinearScale() ? PPFilterMode::Linear : PPFilterMode::Nearest);
step.SetInputTexture(1, "PresentDither", PPFilterMode::Nearest, PPWrapMode::Repeat);
step.SetOutputSwapChain();
step.SetNoBlend();
@ -292,6 +366,8 @@ FString VkPostprocess::LoadShaderCode(const FString &lumpName, const FString &de
void VkPostprocess::RenderEffect(const FString &name)
{
GetVulkanFrameBuffer()->GetRenderState()->EndRenderPass();
if (hw_postprocess.Effects[name].Size() == 0)
return;
@ -362,6 +438,8 @@ VulkanDescriptorSet *VkPostprocess::GetInput(VkPPRenderPassSetup *passSetup, con
PipelineBarrier barrier;
bool needbarrier = false;
VkPipelineStageFlags srcPipelineBits = 0;
for (unsigned int index = 0; index < textures.Size(); index++)
{
const PPTextureInput &input = textures[index];
@ -370,17 +448,24 @@ VulkanDescriptorSet *VkPostprocess::GetInput(VkPPRenderPassSetup *passSetup, con
write.addCombinedImageSampler(descriptors.get(), index, tex.view, sampler, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
if (*tex.layout != VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
if (*tex.layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
{
barrier.addImage(tex.image, *tex.layout, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
srcPipelineBits |= VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
barrier.addImage(tex.image, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
*tex.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
needbarrier = true;
}
else if (*tex.layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
{
srcPipelineBits |= VK_PIPELINE_STAGE_TRANSFER_BIT;
barrier.addImage(tex.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_SHADER_READ_BIT);
*tex.layout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
}
}
write.updateSets(fb->device);
if (needbarrier)
barrier.execute(fb->GetDrawCommands(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
barrier.execute(fb->GetDrawCommands(), srcPipelineBits, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
mFrameDescriptorSets.push_back(std::move(descriptors));
return mFrameDescriptorSets.back().get();
@ -392,13 +477,20 @@ VulkanFramebuffer *VkPostprocess::GetOutput(VkPPRenderPassSetup *passSetup, cons
TextureImage tex = GetTexture(output.Type, output.Texture);
if (tex.layout && *tex.layout != VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL)
if (tex.layout && *tex.layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL)
{
PipelineBarrier barrier;
barrier.addImage(tex.image, *tex.layout, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
barrier.addImage(tex.image, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ACCESS_SHADER_READ_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
barrier.execute(fb->GetDrawCommands(), VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
*tex.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
else if (tex.layout && *tex.layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL)
{
PipelineBarrier barrier;
barrier.addImage(tex.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ACCESS_TRANSFER_WRITE_BIT, VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT);
barrier.execute(fb->GetDrawCommands(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT);
*tex.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
}
VkImageView view;
int w, h;

View file

@ -37,12 +37,14 @@ public:
void BeginFrame();
void RenderBuffersReset();
void SetActiveRenderTarget();
void PostProcessScene(int fixedcm, const std::function<void()> &afterBloomDrawEndScene2D);
void AmbientOccludeScene(float m5);
void BlurScene(float gameinfobluramount);
void ClearTonemapPalette();
void BlitSceneToTexture();
void DrawPresentTexture(const IntRect &box, bool applyGamma, bool clearBorders);
private:

View file

@ -23,6 +23,7 @@ public:
std::unique_ptr<VulkanImageView> SceneDepthView;
VkFormat SceneDepthStencilFormat = VK_FORMAT_D24_UNORM_S8_UINT;
VkImageLayout SceneColorLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
int SceneSamples = 1;
static const int NumPipelineImages = 2;
std::unique_ptr<VulkanImage> PipelineImage[NumPipelineImages];

View file

@ -1,6 +1,7 @@
#include "vk_renderpass.h"
#include "vk_renderbuffers.h"
#include "vk_renderstate.h"
#include "vulkan/shaders/vk_shader.h"
#include "vulkan/system/vk_builders.h"
#include "vulkan/system/vk_framebuffer.h"
@ -27,16 +28,38 @@ void VkRenderPassManager::RenderBuffersReset()
RenderPassSetup.clear();
}
void VkRenderPassManager::SetRenderTarget(VulkanImageView *view, int width, int height)
{
GetVulkanFrameBuffer()->GetRenderState()->EndRenderPass();
mRenderTargetView = view;
mRenderTargetWidth = width;
mRenderTargetHeight = height;
}
void VkRenderPassManager::BeginRenderPass(const VkRenderPassKey &key, VulkanCommandBuffer *cmdbuffer)
{
auto buffers = GetVulkanFrameBuffer()->GetBuffers();
auto fb = GetVulkanFrameBuffer();
auto buffers = fb->GetBuffers();
VkRenderPassSetup *passSetup = GetRenderPass(key);
auto &framebuffer = passSetup->Framebuffer[mRenderTargetView->view];
if (!framebuffer)
{
auto buffers = fb->GetBuffers();
FramebufferBuilder builder;
builder.setRenderPass(passSetup->RenderPass.get());
builder.setSize(mRenderTargetWidth, mRenderTargetHeight);
builder.addAttachment(mRenderTargetView->view);
if (key.DepthTest || key.DepthWrite || key.StencilTest)
builder.addAttachment(buffers->SceneDepthStencilView.get());
framebuffer = builder.create(GetVulkanFrameBuffer()->device);
}
RenderPassBegin beginInfo;
beginInfo.setRenderPass(passSetup->RenderPass.get());
beginInfo.setRenderArea(0, 0, buffers->GetWidth(), buffers->GetHeight());
beginInfo.setFramebuffer(passSetup->Framebuffer.get());
beginInfo.setFramebuffer(framebuffer.get());
cmdbuffer->beginRenderPass(beginInfo);
cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->Pipeline.get());
}
@ -144,7 +167,6 @@ VkRenderPassSetup::VkRenderPassSetup(const VkRenderPassKey &key)
{
CreateRenderPass(key);
CreatePipeline(key);
CreateFramebuffer(key);
}
void VkRenderPassSetup::CreateRenderPass(const VkRenderPassKey &key)
@ -260,16 +282,3 @@ void VkRenderPassSetup::CreatePipeline(const VkRenderPassKey &key)
builder.setRenderPass(RenderPass.get());
Pipeline = builder.create(fb->device);
}
void VkRenderPassSetup::CreateFramebuffer(const VkRenderPassKey &key)
{
auto fb = GetVulkanFrameBuffer();
auto buffers = fb->GetBuffers();
FramebufferBuilder builder;
builder.setRenderPass(RenderPass.get());
builder.setSize(buffers->GetWidth(), buffers->GetHeight());
builder.addAttachment(buffers->SceneColorView.get());
if (key.DepthTest || key.DepthWrite || key.StencilTest)
builder.addAttachment(buffers->SceneDepthStencilView.get());
Framebuffer = builder.create(GetVulkanFrameBuffer()->device);
}

View file

@ -40,12 +40,11 @@ public:
std::unique_ptr<VulkanRenderPass> RenderPass;
std::unique_ptr<VulkanPipeline> Pipeline;
std::unique_ptr<VulkanFramebuffer> Framebuffer;
std::map<VkImageView, std::unique_ptr<VulkanFramebuffer>> Framebuffer;
private:
void CreatePipeline(const VkRenderPassKey &key);
void CreateRenderPass(const VkRenderPassKey &key);
void CreateFramebuffer(const VkRenderPassKey &key);
};
class VkVertexFormat
@ -65,6 +64,7 @@ public:
void Init();
void RenderBuffersReset();
void SetRenderTarget(VulkanImageView *view, int width, int height);
void BeginRenderPass(const VkRenderPassKey &key, VulkanCommandBuffer *cmdbuffer);
int GetVertexFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs);
@ -87,4 +87,8 @@ private:
void CreateDynamicSet();
VkRenderPassSetup *GetRenderPass(const VkRenderPassKey &key);
VulkanImageView *mRenderTargetView = nullptr;
int mRenderTargetWidth = 0;
int mRenderTargetHeight = 0;
};

View file

@ -596,9 +596,6 @@ void VkRenderState::EndRenderPass()
mCommandBuffer = nullptr;
mRenderPassKey = {};
mMatricesOffset = 0;
mStreamDataOffset = 0;
mDataIndex = -1;
mLastViewpointOffset = 0xffffffff;
mLastLightBufferOffset = 0xffffffff;
mLastVertexBuffer = nullptr;
@ -610,3 +607,10 @@ void VkRenderState::EndRenderPass()
mLastTextureMatrixEnabled = true;
}
}
void VkRenderState::EndFrame()
{
mMatricesOffset = 0;
mStreamDataOffset = 0;
mDataIndex = -1;
}

View file

@ -43,6 +43,7 @@ public:
void Bind(int bindingpoint, uint32_t offset);
void EndRenderPass();
void EndFrame();
private:
void Apply(int dt);

View file

@ -150,45 +150,15 @@ void VulkanFrameBuffer::Update()
device->beginFrame();
GetPostprocess()->SetActiveRenderTarget();
Draw2D();
Clear2D();
mRenderState->EndRenderPass();
mRenderState->EndFrame();
mPostprocess->DrawPresentTexture(mOutputLetterbox, true, true);
#if 0
{
auto sceneColor = mScreenBuffers->SceneColor.get();
PipelineBarrier barrier0;
barrier0.addImage(sceneColor, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
barrier0.addImage(device->swapChain->swapChainImages[device->presentImageIndex], VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT, VK_ACCESS_TRANSFER_READ_BIT);
barrier0.execute(GetDrawCommands(), VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT);
VkImageBlit blit = {};
blit.srcOffsets[0] = { 0, 0, 0 };
blit.srcOffsets[1] = { sceneColor->width, sceneColor->height, 1 };
blit.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.srcSubresource.mipLevel = 0;
blit.srcSubresource.baseArrayLayer = 0;
blit.srcSubresource.layerCount = 1;
blit.dstOffsets[0] = { 0, 0, 0 };
blit.dstOffsets[1] = { (int32_t)device->swapChain->actualExtent.width, (int32_t)device->swapChain->actualExtent.height, 1 };
blit.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
blit.dstSubresource.mipLevel = 0;
blit.dstSubresource.baseArrayLayer = 0;
blit.dstSubresource.layerCount = 1;
GetDrawCommands()->blitImage(
sceneColor->image, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL,
device->swapChain->swapChainImages[device->presentImageIndex], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
1, &blit, VK_FILTER_NEAREST);
PipelineBarrier barrier1;
barrier1.addImage(sceneColor, VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_ACCESS_TRANSFER_READ_BIT, 0);
barrier1.addImage(device->swapChain->swapChainImages[device->presentImageIndex], VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR, VK_ACCESS_TRANSFER_WRITE_BIT, 0);
barrier1.execute(GetDrawCommands(), VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT);
}
#endif
mDrawCommands->end();
@ -353,16 +323,16 @@ sector_t *VulkanFrameBuffer::RenderViewpoint(FRenderViewpoint &mainvp, AActor *
const auto &eye = vrmode->mEyes[eye_ix];
screen->SetViewportRects(bounds);
#if 0
if (mainview) // Bind the scene frame buffer and turn on draw buffers used by ssao
{
mRenderPassManager->SetRenderTarget(GetBuffers()->SceneColorView.get(), GetBuffers()->GetWidth(), GetBuffers()->GetHeight());
#if 0
bool useSSAO = (gl_ssao != 0);
mBuffers->BindSceneFB(useSSAO);
GetRenderState()->SetPassType(useSSAO ? GBUFFER_PASS : NORMAL_PASS);
GetRenderState()->EnableDrawBuffers(gl_RenderState.GetPassDrawBufferCount());
GetRenderState()->Apply();
}
#endif
}
auto di = HWDrawInfo::StartDrawInfo(mainvp.ViewLevel, nullptr, mainvp, nullptr);
auto &vp = di->Viewpoint;
@ -394,13 +364,11 @@ sector_t *VulkanFrameBuffer::RenderViewpoint(FRenderViewpoint &mainvp, AActor *
GetRenderState()->SetPassType(NORMAL_PASS);
GetRenderState()->EnableDrawBuffers(1);
}
#endif
mBuffers->BlitSceneToTexture(); // Copy the resulting scene to the current post process texture
mPostprocess->BlitSceneToTexture(); // Copy the resulting scene to the current post process texture
PostProcessScene(cm, [&]() { di->DrawEndScene2D(mainvp.sector, *GetRenderState()); });
#else
di->DrawEndScene2D(mainvp.sector, *GetRenderState());
#endif
PostProcess.Unclock();
}
@ -478,6 +446,11 @@ void VulkanFrameBuffer::DrawScene(HWDrawInfo *di, int drawmode)
di->RenderTranslucent(*GetRenderState());
}
void VulkanFrameBuffer::PostProcessScene(int fixedcm, const std::function<void()> &afterBloomDrawEndScene2D)
{
mPostprocess->PostProcessScene(fixedcm, afterBloomDrawEndScene2D);
}
uint32_t VulkanFrameBuffer::GetCaps()
{
if (!V_IsHardwareRenderer())

View file

@ -62,6 +62,7 @@ public:
void TextureFilterChanged() override;
void BeginFrame() override;
void BlurScene(float amount) override;
void PostProcessScene(int fixedcm, const std::function<void()> &afterBloomDrawEndScene2D) override;
IHardwareTexture *CreateHardwareTexture() override;
FModelRenderer *CreateModelRenderer(int mli) override;