- implement VkPostprocess::RenderScreenQuad

This commit is contained in:
Magnus Norddahl 2019-03-05 23:31:38 +01:00
parent fb983186b1
commit c280153ac2
6 changed files with 304 additions and 36 deletions

View file

@ -46,7 +46,11 @@ public:
{
FString decl;
FString layout;
if (screen->glslversion < 4.20)
if (bindingpoint == -1)
{
layout = "push_constant";
}
else if (screen->glslversion < 4.20)
{
layout = "std140";
}

View file

@ -94,6 +94,7 @@ void VkPostprocess::ClearTonemapPalette()
void VkPostprocess::RenderBuffersReset()
{
mRenderPassSetup.clear();
}
void VkPostprocess::UpdateEffectTextures()
@ -136,6 +137,7 @@ void VkPostprocess::UpdateEffectTextures()
if (!imgbuilder.isFormatSupported(fb->device))
I_FatalError("Vulkan device does not support the image format required by %s\n", pair->Key.GetChars());
vktex->Image = imgbuilder.create(fb->device);
vktex->Format = format;
ImageViewBuilder viewbuilder;
viewbuilder.setImage(vktex->Image.get(), format);
@ -197,7 +199,7 @@ void VkPostprocess::CompileEffectShaders()
FString prolog;
if (!desc.Uniforms.empty())
prolog = UniformBlockDecl::Create("Uniforms", desc.Uniforms, uniformbindingpoint);
prolog = UniformBlockDecl::Create("Uniforms", desc.Uniforms, -1);
prolog += desc.Defines;
ShaderBuilder vertbuilder;
@ -227,15 +229,215 @@ FString VkPostprocess::LoadShaderCode(const FString &lumpName, const FString &de
void VkPostprocess::RenderEffect(const FString &name)
{
if (hw_postprocess.Effects[name].Size() == 0)
return;
for (const PPStep &step : hw_postprocess.Effects[name])
{
VkPPRenderPassKey key;
key.BlendMode = step.BlendMode;
key.InputTextures = step.Textures.Size();
key.Uniforms = step.Uniforms.Data.Size() != 0;
key.Shader = mShaders[step.ShaderName].get();
key.OutputFormat = (step.Output.Type == PPTextureType::PPTexture) ? mTextures[step.Output.Texture]->Format : VK_FORMAT_R16G16B16A16_SFLOAT;
auto &passSetup = mRenderPassSetup[key];
if (!passSetup)
passSetup.reset(new VkPPRenderPassSetup(key));
VulkanDescriptorSet *input = GetInput(passSetup.get(), step.Textures);
VulkanFramebuffer *output = GetOutput(passSetup.get(), step.Output);
RenderScreenQuad(passSetup.get(), input, output, step.Viewport.left, step.Viewport.top, step.Viewport.width, step.Viewport.height, step.Uniforms.Data.Data(), step.Uniforms.Data.Size());
// Advance to next PP texture if our output was sent there
if (step.Output.Type == PPTextureType::NextPipelineTexture)
NextTexture();
}
}
void VkPostprocess::RenderScreenQuad()
void VkPostprocess::RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescriptorSet *descriptorSet, VulkanFramebuffer *framebuffer, int x, int y, int width, int height, const void *pushConstants, uint32_t pushConstantsSize)
{
//auto buffer = static_cast<VKVertexBuffer *>(screen->mVertexData->GetBufferObjects().first);
//buffer->Bind(nullptr);
//glDrawArrays(GL_TRIANGLE_STRIP, FFlatVertexBuffer::PRESENT_INDEX, 4);
auto fb = GetVulkanFrameBuffer();
auto cmdbuffer = fb->GetDrawCommands();
RenderPassBegin beginInfo;
beginInfo.setRenderPass(passSetup->RenderPass.get());
beginInfo.setRenderArea(x, y, width, height);
beginInfo.setFramebuffer(framebuffer);
VkViewport viewport = { };
viewport.x = x;
viewport.y = y;
viewport.width = width;
viewport.height = height;
viewport.minDepth = 0.0f;
viewport.maxDepth = 1.0f;
VkBuffer vertexBuffers[] = { static_cast<VKVertexBuffer*>(screen->mVertexData->GetBufferObjects().first)->mBuffer->buffer };
VkDeviceSize offsets[] = { 0 };
cmdbuffer->beginRenderPass(beginInfo);
cmdbuffer->bindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->Pipeline.get());
cmdbuffer->bindDescriptorSet(VK_PIPELINE_BIND_POINT_GRAPHICS, passSetup->PipelineLayout.get(), 0, descriptorSet);
cmdbuffer->setViewport(0, 1, &viewport);
cmdbuffer->bindVertexBuffers(0, 1, vertexBuffers, offsets);
if (pushConstantsSize > 0)
cmdbuffer->pushConstants(passSetup->PipelineLayout.get(), VK_SHADER_STAGE_FRAGMENT_BIT, 0, pushConstantsSize, pushConstants);
cmdbuffer->draw(4, 1, FFlatVertexBuffer::PRESENT_INDEX, 0);
cmdbuffer->endRenderPass();
}
VulkanDescriptorSet *VkPostprocess::GetInput(VkPPRenderPassSetup *passSetup, const TArray<PPTextureInput> &textures)
{
#if 0
// Bind input textures
for (unsigned int index = 0; index < step.Textures.Size(); index++)
{
const PPTextureInput &input = step.Textures[index];
VulkanSampler *sampler = GetSampler(input.Filter, input.Wrap);
switch (input.Type)
{
default:
case PPTextureType::CurrentPipelineTexture:
BindCurrentTexture(index, filter, wrap);
break;
case PPTextureType::NextPipelineTexture:
I_FatalError("PPTextureType::NextPipelineTexture not allowed as input\n");
break;
case PPTextureType::PPTexture:
GLTextures[input.Texture].Bind(index, filter, wrap);
break;
case PPTextureType::SceneColor:
BindSceneColorTexture(index);
break;
case PPTextureType::SceneFog:
BindSceneFogTexture(index);
break;
case PPTextureType::SceneNormal:
BindSceneNormalTexture(index);
break;
case PPTextureType::SceneDepth:
BindSceneDepthTexture(index);
break;
}
}
#endif
return nullptr;
}
VulkanFramebuffer *VkPostprocess::GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output)
{
#if 0
switch (output.Type)
{
default:
I_FatalError("Unsupported postprocess output type\n");
break;
case PPTextureType::CurrentPipelineTexture:
BindCurrentFB();
break;
case PPTextureType::NextPipelineTexture:
BindNextFB();
break;
case PPTextureType::PPTexture:
mTextures[step.Output.Texture]->View
break;
case PPTextureType::SceneColor:
BindSceneFB(false);
break;
}
#endif
return nullptr;
}
VulkanSampler *VkPostprocess::GetSampler(PPFilterMode filter, PPWrapMode wrap)
{
int index = (((int)filter) << 2) | (int)wrap;
auto &sampler = mSamplers[index];
if (sampler)
return sampler.get();
SamplerBuilder builder;
builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST);
builder.setMinFilter(filter == PPFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR);
builder.setMagFilter(filter == PPFilterMode::Nearest ? VK_FILTER_NEAREST : VK_FILTER_LINEAR);
builder.setAddressMode(wrap == PPWrapMode::Clamp ? VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE : VK_SAMPLER_ADDRESS_MODE_REPEAT);
sampler = builder.create(GetVulkanFrameBuffer()->device);
return sampler.get();
}
void VkPostprocess::NextEye(int eyeCount)
{
}
void VkPostprocess::NextTexture()
{
}
/////////////////////////////////////////////////////////////////////////////
VkPPRenderPassSetup::VkPPRenderPassSetup(const VkPPRenderPassKey &key)
{
CreateDescriptorLayout(key);
}
void VkPPRenderPassSetup::CreateDescriptorLayout(const VkPPRenderPassKey &key)
{
DescriptorSetLayoutBuilder builder;
for (int i = 0; i < key.InputTextures; i++)
builder.addBinding(i, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
DescriptorLayout = builder.create(GetVulkanFrameBuffer()->device);
}
void VkPPRenderPassSetup::CreatePipelineLayout(const VkPPRenderPassKey &key)
{
PipelineLayoutBuilder builder;
builder.addSetLayout(DescriptorLayout.get());
if (key.Uniforms > 0)
builder.addPushConstantRange(VK_SHADER_STAGE_FRAGMENT_BIT, 0, key.Uniforms);
PipelineLayout = builder.create(GetVulkanFrameBuffer()->device);
}
void VkPPRenderPassSetup::CreatePipeline(const VkPPRenderPassKey &key)
{
GraphicsPipelineBuilder builder;
builder.addVertexShader(key.Shader->VertexShader.get());
builder.addFragmentShader(key.Shader->FragmentShader.get());
builder.addVertexBufferBinding(0, sizeof(FFlatVertex));
builder.addVertexAttribute(0, 0, VK_FORMAT_R32G32B32_SFLOAT, offsetof(FFlatVertex, x));
builder.addVertexAttribute(1, 0, VK_FORMAT_R32G32_SFLOAT, offsetof(FFlatVertex, u));
builder.addDynamicState(VK_DYNAMIC_STATE_VIEWPORT);
builder.setViewport(0.0f, 0.0f, (float)SCREENWIDTH, (float)SCREENHEIGHT);
builder.setTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
builder.setBlendMode(key.BlendMode);
builder.setLayout(PipelineLayout.get());
builder.setRenderPass(RenderPass.get());
Pipeline = builder.create(GetVulkanFrameBuffer()->device);
}
void VkPPRenderPassSetup::CreateRenderPass(const VkPPRenderPassKey &key)
{
RenderPassBuilder builder;
builder.addColorAttachment(false, key.OutputFormat, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
builder.addSubpass();
builder.addSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
builder.addExternalSubpassDependency(
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT);
RenderPass = builder.create(GetVulkanFrameBuffer()->device);
}

View file

@ -3,6 +3,7 @@
#include <functional>
#include <map>
#include <array>
#include "hwrenderer/postprocessing/hw_postprocess.h"
#include "vulkan/system/vk_objects.h"
@ -11,6 +12,21 @@ class FString;
class VkPPShader;
class VkPPTexture;
class VkPPRenderPassSetup;
class VkPPRenderPassKey
{
public:
VkPPShader *Shader;
int Uniforms;
int InputTextures;
PPBlendMode BlendMode;
VkFormat OutputFormat;
bool operator<(const VkPPRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkPPRenderPassKey)) < 0; }
bool operator==(const VkPPRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkPPRenderPassKey)) == 0; }
bool operator!=(const VkPPRenderPassKey &other) const { return memcmp(this, &other, sizeof(VkPPRenderPassKey)) != 0; }
};
class VkPostprocess
{
@ -32,12 +48,17 @@ private:
FString LoadShaderCode(const FString &lumpname, const FString &defines, int version);
void RenderEffect(const FString &name);
void NextEye(int eyeCount);
void RenderScreenQuad();
void NextTexture();
void RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescriptorSet *descriptorSet, VulkanFramebuffer *framebuffer, int x, int y, int width, int height, const void *pushConstants, uint32_t pushConstantsSize);
VulkanDescriptorSet *GetInput(VkPPRenderPassSetup *passSetup, const TArray<PPTextureInput> &textures);
VulkanFramebuffer *GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output);
VulkanSampler *GetSampler(PPFilterMode filter, PPWrapMode wrap);
std::map<PPTextureName, std::unique_ptr<VkPPTexture>> mTextures;
std::map<PPShaderName, std::unique_ptr<VkPPShader>> mShaders;
const static int uniformbindingpoint = 7;
std::array<std::unique_ptr<VulkanSampler>, 16> mSamplers;
std::map<VkPPRenderPassKey, std::unique_ptr<VkPPRenderPassSetup>> mRenderPassSetup;
};
class VkPPShader
@ -54,4 +75,27 @@ public:
std::unique_ptr<VulkanImageView> View;
std::unique_ptr<VulkanBuffer> Staging;
VkImageLayout Layout = VK_IMAGE_LAYOUT_UNDEFINED;
VkFormat Format;
};
class VkPPRenderPassSetup
{
public:
VkPPRenderPassSetup(const VkPPRenderPassKey &key);
std::unique_ptr<VulkanDescriptorSetLayout> DescriptorLayout;
std::unique_ptr<VulkanPipelineLayout> PipelineLayout;
std::unique_ptr<VulkanRenderPass> RenderPass;
std::unique_ptr<VulkanPipeline> Pipeline;
//std::unique_ptr<VulkanDescriptorPool> DescriptorPool;
//std::unique_ptr<VulkanFramebuffer> Framebuffer;
//std::unique_ptr<VulkanDescriptorSet> DescriptorSet;
private:
void CreateDescriptorLayout(const VkPPRenderPassKey &key);
void CreatePipelineLayout(const VkPPRenderPassKey &key);
void CreatePipeline(const VkPPRenderPassKey &key);
void CreateRenderPass(const VkPPRenderPassKey &key);
};

View file

@ -243,32 +243,6 @@ void VkRenderPassSetup::CreatePipeline(const VkRenderPassKey &key)
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP
};
static const int blendstyles[] = {
VK_BLEND_FACTOR_ZERO,
VK_BLEND_FACTOR_ONE,
VK_BLEND_FACTOR_SRC_ALPHA,
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
VK_BLEND_FACTOR_SRC_COLOR,
VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
VK_BLEND_FACTOR_DST_COLOR,
VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR,
};
static const int renderops[] = {
0, VK_BLEND_OP_ADD, VK_BLEND_OP_SUBTRACT, VK_BLEND_OP_REVERSE_SUBTRACT, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
int srcblend = blendstyles[key.RenderStyle.SrcAlpha%STYLEALPHA_MAX];
int dstblend = blendstyles[key.RenderStyle.DestAlpha%STYLEALPHA_MAX];
int blendequation = renderops[key.RenderStyle.BlendOp & 15];
if (blendequation == -1) // This was a fuzz style.
{
srcblend = VK_BLEND_FACTOR_DST_COLOR;
dstblend = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blendequation = VK_BLEND_OP_ADD;
}
static const VkStencilOp op2vk[] = { VK_STENCIL_OP_KEEP, VK_STENCIL_OP_INCREMENT_AND_CLAMP, VK_STENCIL_OP_DECREMENT_AND_CLAMP };
static const VkCompareOp depthfunc2vk[] = { VK_COMPARE_OP_LESS, VK_COMPARE_OP_LESS_OR_EQUAL, VK_COMPARE_OP_ALWAYS };
@ -280,7 +254,7 @@ void VkRenderPassSetup::CreatePipeline(const VkRenderPassKey &key)
builder.setCull(key.CullMode == Cull_None ? VK_CULL_MODE_NONE : VK_CULL_MODE_FRONT_AND_BACK, key.CullMode == Cull_CW ? VK_FRONT_FACE_CLOCKWISE : VK_FRONT_FACE_COUNTER_CLOCKWISE);
builder.setColorWriteMask((VkColorComponentFlags)key.ColorMask);
builder.setStencil(VK_STENCIL_OP_KEEP, op2vk[key.StencilPassOp], VK_STENCIL_OP_KEEP, VK_COMPARE_OP_EQUAL, 0xffffffff, 0xffffffff, 0);
builder.setBlendMode((VkBlendOp)blendequation, (VkBlendFactor)srcblend, (VkBlendFactor)dstblend);
builder.setBlendMode(key.RenderStyle);
builder.setLayout(fb->GetRenderPassManager()->PipelineLayout.get());
builder.setRenderPass(RenderPass.get());

View file

@ -1,6 +1,7 @@
#include "vk_builders.h"
#include "doomerrors.h"
#include "r_data/renderstyle.h"
#include <ShaderLang.h>
#include <GlslangToSpv.h>
@ -180,3 +181,43 @@ std::unique_ptr<VulkanShader> ShaderBuilder::create(VulkanDevice *device)
return std::make_unique<VulkanShader>(device, shaderModule);
}
/////////////////////////////////////////////////////////////////////////////
void GraphicsPipelineBuilder::setBlendMode(const FRenderStyle &style)
{
// Just in case Vulkan doesn't do this optimization itself
if (style.BlendOp == STYLEOP_Add && style.SrcAlpha == STYLEALPHA_One && style.DestAlpha == STYLEALPHA_Zero && style.Flags == 0)
{
colorBlendAttachment.blendEnable = VK_FALSE;
return;
}
static const int blendstyles[] = {
VK_BLEND_FACTOR_ZERO,
VK_BLEND_FACTOR_ONE,
VK_BLEND_FACTOR_SRC_ALPHA,
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
VK_BLEND_FACTOR_SRC_COLOR,
VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
VK_BLEND_FACTOR_DST_COLOR,
VK_BLEND_FACTOR_ONE_MINUS_DST_COLOR,
};
static const int renderops[] = {
0, VK_BLEND_OP_ADD, VK_BLEND_OP_SUBTRACT, VK_BLEND_OP_REVERSE_SUBTRACT, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
int srcblend = blendstyles[style.SrcAlpha%STYLEALPHA_MAX];
int dstblend = blendstyles[style.DestAlpha%STYLEALPHA_MAX];
int blendequation = renderops[style.BlendOp & 15];
if (blendequation == -1) // This was a fuzz style.
{
srcblend = VK_BLEND_FACTOR_DST_COLOR;
dstblend = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
blendequation = VK_BLEND_OP_ADD;
}
setBlendMode((VkBlendOp)blendequation, (VkBlendFactor)srcblend, (VkBlendFactor)dstblend);
}

View file

@ -175,6 +175,8 @@ private:
FixedSizeVector<VkImageView, 8> attachments;
};
union FRenderStyle;
class GraphicsPipelineBuilder
{
public:
@ -197,6 +199,7 @@ public:
void setAdditiveBlendMode();
void setAlphaBlendMode();
void setBlendMode(const FRenderStyle &style);
void setBlendMode(VkBlendOp op, VkBlendFactor src, VkBlendFactor dst);
void setSubpassColorAttachmentCount(int count);