mirror of
https://github.com/ZDoom/qzdoom.git
synced 2024-11-10 14:51:51 +00:00
Split postprocess part into more files
This commit is contained in:
parent
ecd2dc6300
commit
8ebad1003b
18 changed files with 740 additions and 627 deletions
|
@ -803,11 +803,14 @@ set (VULKAN_SOURCES
|
|||
common/rendering/vulkan/renderer/vk_renderpass.cpp
|
||||
common/rendering/vulkan/renderer/vk_streambuffer.cpp
|
||||
common/rendering/vulkan/renderer/vk_postprocess.cpp
|
||||
common/rendering/vulkan/renderer/vk_pprenderstate.cpp
|
||||
common/rendering/vulkan/renderer/vk_descriptorset.cpp
|
||||
common/rendering/vulkan/renderer/vk_raytrace.cpp
|
||||
common/rendering/vulkan/shaders/vk_shader.cpp
|
||||
common/rendering/vulkan/shaders/vk_ppshader.cpp
|
||||
common/rendering/vulkan/textures/vk_samplers.cpp
|
||||
common/rendering/vulkan/textures/vk_hwtexture.cpp
|
||||
common/rendering/vulkan/textures/vk_pptexture.cpp
|
||||
common/rendering/vulkan/textures/vk_imagetransition.cpp
|
||||
common/rendering/vulkan/textures/vk_renderbuffers.cpp
|
||||
common/rendering/vulkan/thirdparty/volk/volk.c
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "vulkan/shaders/vk_shader.h"
|
||||
#include "vulkan/textures/vk_samplers.h"
|
||||
#include "vulkan/textures/vk_renderbuffers.h"
|
||||
#include "vulkan/textures/vk_hwtexture.h"
|
||||
#include "vulkan/system/vk_builders.h"
|
||||
#include "vulkan/system/vk_framebuffer.h"
|
||||
#include "vulkan/system/vk_buffers.h"
|
||||
|
@ -136,6 +137,12 @@ void VkDescriptorSetManager::TextureSetPoolReset()
|
|||
TextureDescriptorsLeft = 0;
|
||||
}
|
||||
|
||||
void VkDescriptorSetManager::FilterModeChanged()
|
||||
{
|
||||
// Destroy the texture descriptors as they used the old samplers
|
||||
VkMaterial::ResetAllDescriptors();
|
||||
}
|
||||
|
||||
void VkDescriptorSetManager::CreateNullTexture()
|
||||
{
|
||||
auto fb = GetVulkanFrameBuffer();
|
||||
|
|
|
@ -13,6 +13,7 @@ public:
|
|||
void UpdateFixedSet();
|
||||
void UpdateDynamicSet();
|
||||
void TextureSetPoolReset();
|
||||
void FilterModeChanged();
|
||||
|
||||
VulkanDescriptorSetLayout* GetDynamicSetLayout() { return DynamicSetLayout.get(); }
|
||||
VulkanDescriptorSetLayout* GetFixedSetLayout() { return FixedSetLayout.get(); }
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
#include "vulkan/system/vk_swapchain.h"
|
||||
#include "vulkan/system/vk_commandbuffer.h"
|
||||
#include "vulkan/renderer/vk_renderstate.h"
|
||||
#include "vulkan/renderer/vk_pprenderstate.h"
|
||||
#include "vulkan/shaders/vk_ppshader.h"
|
||||
#include "vulkan/textures/vk_pptexture.h"
|
||||
#include "vulkan/textures/vk_renderbuffers.h"
|
||||
#include "vulkan/textures/vk_imagetransition.h"
|
||||
#include "hw_cvars.h"
|
||||
|
@ -36,8 +39,6 @@
|
|||
#include "hw_vrmodes.h"
|
||||
#include "flatvertices.h"
|
||||
#include "r_videoscale.h"
|
||||
#include "filesystem.h"
|
||||
|
||||
|
||||
EXTERN_CVAR(Int, gl_dither_bpc)
|
||||
|
||||
|
@ -318,502 +319,7 @@ std::unique_ptr<VulkanDescriptorSet> VkPostprocess::AllocateDescriptorSet(Vulkan
|
|||
return mDescriptorPool->allocate(layout);
|
||||
}
|
||||
|
||||
void VkPostprocess::RenderBuffersReset()
|
||||
{
|
||||
mRenderPassSetup.clear();
|
||||
}
|
||||
|
||||
VulkanSampler *VkPostprocess::GetSampler(PPFilterMode filter, PPWrapMode wrap)
|
||||
{
|
||||
int index = (((int)filter) << 1) | (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);
|
||||
sampler->SetDebugName("VkPostprocess.mSamplers");
|
||||
return sampler.get();
|
||||
}
|
||||
|
||||
void VkPostprocess::NextEye(int eyeCount)
|
||||
{
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
VkPPTexture::VkPPTexture(PPTexture *texture)
|
||||
{
|
||||
auto fb = GetVulkanFrameBuffer();
|
||||
|
||||
VkFormat format;
|
||||
int pixelsize;
|
||||
switch (texture->Format)
|
||||
{
|
||||
default:
|
||||
case PixelFormat::Rgba8: format = VK_FORMAT_R8G8B8A8_UNORM; pixelsize = 4; break;
|
||||
case PixelFormat::Rgba16f: format = VK_FORMAT_R16G16B16A16_SFLOAT; pixelsize = 8; break;
|
||||
case PixelFormat::R32f: format = VK_FORMAT_R32_SFLOAT; pixelsize = 4; break;
|
||||
case PixelFormat::Rg16f: format = VK_FORMAT_R16G16_SFLOAT; pixelsize = 4; break;
|
||||
case PixelFormat::Rgba16_snorm: format = VK_FORMAT_R16G16B16A16_SNORM; pixelsize = 8; break;
|
||||
}
|
||||
|
||||
ImageBuilder imgbuilder;
|
||||
imgbuilder.setFormat(format);
|
||||
imgbuilder.setSize(texture->Width, texture->Height);
|
||||
if (texture->Data)
|
||||
imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
|
||||
else
|
||||
imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
|
||||
if (!imgbuilder.isFormatSupported(fb->device))
|
||||
I_FatalError("Vulkan device does not support the image format required by a postprocess texture\n");
|
||||
TexImage.Image = imgbuilder.create(fb->device);
|
||||
TexImage.Image->SetDebugName("VkPPTexture");
|
||||
Format = format;
|
||||
|
||||
ImageViewBuilder viewbuilder;
|
||||
viewbuilder.setImage(TexImage.Image.get(), format);
|
||||
TexImage.View = viewbuilder.create(fb->device);
|
||||
TexImage.View->SetDebugName("VkPPTextureView");
|
||||
|
||||
if (texture->Data)
|
||||
{
|
||||
size_t totalsize = texture->Width * texture->Height * pixelsize;
|
||||
BufferBuilder stagingbuilder;
|
||||
stagingbuilder.setSize(totalsize);
|
||||
stagingbuilder.setUsage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY);
|
||||
Staging = stagingbuilder.create(fb->device);
|
||||
Staging->SetDebugName("VkPPTextureStaging");
|
||||
|
||||
VkImageTransition barrier0;
|
||||
barrier0.addImage(&TexImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true);
|
||||
barrier0.execute(fb->GetCommands()->GetTransferCommands());
|
||||
|
||||
void *data = Staging->Map(0, totalsize);
|
||||
memcpy(data, texture->Data.get(), totalsize);
|
||||
Staging->Unmap();
|
||||
|
||||
VkBufferImageCopy region = {};
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageExtent.depth = 1;
|
||||
region.imageExtent.width = texture->Width;
|
||||
region.imageExtent.height = texture->Height;
|
||||
fb->GetCommands()->GetTransferCommands()->copyBufferToImage(Staging->buffer, TexImage.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
|
||||
VkImageTransition barrier1;
|
||||
barrier1.addImage(&TexImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false);
|
||||
barrier1.execute(fb->GetCommands()->GetTransferCommands());
|
||||
}
|
||||
else
|
||||
{
|
||||
VkImageTransition barrier;
|
||||
barrier.addImage(&TexImage, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true);
|
||||
barrier.execute(fb->GetCommands()->GetTransferCommands());
|
||||
}
|
||||
}
|
||||
|
||||
VkPPTexture::~VkPPTexture()
|
||||
{
|
||||
if (auto fb = GetVulkanFrameBuffer())
|
||||
{
|
||||
if (TexImage.Image) fb->GetCommands()->FrameDeleteList.Images.push_back(std::move(TexImage.Image));
|
||||
if (TexImage.View) fb->GetCommands()->FrameDeleteList.ImageViews.push_back(std::move(TexImage.View));
|
||||
if (TexImage.DepthOnlyView) fb->GetCommands()->FrameDeleteList.ImageViews.push_back(std::move(TexImage.DepthOnlyView));
|
||||
if (TexImage.PPFramebuffer) fb->GetCommands()->FrameDeleteList.Framebuffers.push_back(std::move(TexImage.PPFramebuffer));
|
||||
if (Staging) fb->GetCommands()->FrameDeleteList.Buffers.push_back(std::move(Staging));
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
VkPPShader::VkPPShader(PPShader *shader)
|
||||
{
|
||||
auto fb = GetVulkanFrameBuffer();
|
||||
|
||||
FString prolog;
|
||||
if (!shader->Uniforms.empty())
|
||||
prolog = UniformBlockDecl::Create("Uniforms", shader->Uniforms, -1);
|
||||
prolog += shader->Defines;
|
||||
|
||||
ShaderBuilder vertbuilder;
|
||||
vertbuilder.setVertexShader(LoadShaderCode(shader->VertexShader, "", shader->Version));
|
||||
VertexShader = vertbuilder.create(shader->VertexShader.GetChars(), fb->device);
|
||||
VertexShader->SetDebugName(shader->VertexShader.GetChars());
|
||||
|
||||
ShaderBuilder fragbuilder;
|
||||
fragbuilder.setFragmentShader(LoadShaderCode(shader->FragmentShader, prolog, shader->Version));
|
||||
FragmentShader = fragbuilder.create(shader->FragmentShader.GetChars(), fb->device);
|
||||
FragmentShader->SetDebugName(shader->FragmentShader.GetChars());
|
||||
}
|
||||
|
||||
FString VkPPShader::LoadShaderCode(const FString &lumpName, const FString &defines, int version)
|
||||
{
|
||||
int lump = fileSystem.CheckNumForFullName(lumpName);
|
||||
if (lump == -1) I_FatalError("Unable to load '%s'", lumpName.GetChars());
|
||||
FString code = fileSystem.ReadFile(lump).GetString().GetChars();
|
||||
|
||||
FString patchedCode;
|
||||
patchedCode.AppendFormat("#version %d\n", 450);
|
||||
patchedCode << defines;
|
||||
patchedCode << "#line 1\n";
|
||||
patchedCode << code;
|
||||
return patchedCode;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void VkPPRenderState::PushGroup(const FString &name)
|
||||
{
|
||||
GetVulkanFrameBuffer()->GetCommands()->PushGroup(name);
|
||||
}
|
||||
|
||||
void VkPPRenderState::PopGroup()
|
||||
{
|
||||
GetVulkanFrameBuffer()->GetCommands()->PopGroup();
|
||||
}
|
||||
|
||||
void VkPPRenderState::Draw()
|
||||
{
|
||||
auto fb = GetVulkanFrameBuffer();
|
||||
auto pp = fb->GetPostprocess();
|
||||
|
||||
fb->GetRenderState()->EndRenderPass();
|
||||
|
||||
VkPPRenderPassKey key;
|
||||
key.BlendMode = BlendMode;
|
||||
key.InputTextures = Textures.Size();
|
||||
key.Uniforms = Uniforms.Data.Size();
|
||||
key.Shader = GetVkShader(Shader);
|
||||
key.SwapChain = (Output.Type == PPTextureType::SwapChain);
|
||||
key.ShadowMapBuffers = ShadowMapBuffers;
|
||||
if (Output.Type == PPTextureType::PPTexture)
|
||||
key.OutputFormat = GetVkTexture(Output.Texture)->Format;
|
||||
else if (Output.Type == PPTextureType::SwapChain)
|
||||
key.OutputFormat = GetVulkanFrameBuffer()->GetCommands()->swapChain->swapChainFormat.format;
|
||||
else if (Output.Type == PPTextureType::ShadowMap)
|
||||
key.OutputFormat = VK_FORMAT_R32_SFLOAT;
|
||||
else
|
||||
key.OutputFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
|
||||
|
||||
if (Output.Type == PPTextureType::SceneColor)
|
||||
{
|
||||
key.StencilTest = 1;
|
||||
key.Samples = fb->GetBuffers()->GetSceneSamples();
|
||||
}
|
||||
else
|
||||
{
|
||||
key.StencilTest = 0;
|
||||
key.Samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
}
|
||||
|
||||
auto &passSetup = pp->mRenderPassSetup[key];
|
||||
if (!passSetup)
|
||||
passSetup.reset(new VkPPRenderPassSetup(key));
|
||||
|
||||
int framebufferWidth = 0, framebufferHeight = 0;
|
||||
VulkanDescriptorSet *input = GetInput(passSetup.get(), Textures, ShadowMapBuffers);
|
||||
VulkanFramebuffer *output = GetOutput(passSetup.get(), Output, key.StencilTest, framebufferWidth, framebufferHeight);
|
||||
|
||||
RenderScreenQuad(passSetup.get(), input, output, framebufferWidth, framebufferHeight, Viewport.left, Viewport.top, Viewport.width, Viewport.height, Uniforms.Data.Data(), Uniforms.Data.Size(), key.StencilTest);
|
||||
|
||||
// Advance to next PP texture if our output was sent there
|
||||
if (Output.Type == PPTextureType::NextPipelineTexture)
|
||||
{
|
||||
pp->mCurrentPipelineImage = (pp->mCurrentPipelineImage + 1) % VkRenderBuffers::NumPipelineImages;
|
||||
}
|
||||
}
|
||||
|
||||
void VkPPRenderState::RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescriptorSet *descriptorSet, VulkanFramebuffer *framebuffer, int framebufferWidth, int framebufferHeight, int x, int y, int width, int height, const void *pushConstants, uint32_t pushConstantsSize, bool stencilTest)
|
||||
{
|
||||
auto fb = GetVulkanFrameBuffer();
|
||||
auto cmdbuffer = fb->GetCommands()->GetDrawCommands();
|
||||
|
||||
VkViewport viewport = { };
|
||||
viewport.x = (float)x;
|
||||
viewport.y = (float)y;
|
||||
viewport.width = (float)width;
|
||||
viewport.height = (float)height;
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
|
||||
VkRect2D scissor = { };
|
||||
scissor.offset.x = 0;
|
||||
scissor.offset.y = 0;
|
||||
scissor.extent.width = framebufferWidth;
|
||||
scissor.extent.height = framebufferHeight;
|
||||
|
||||
RenderPassBegin beginInfo;
|
||||
beginInfo.setRenderPass(passSetup->RenderPass.get());
|
||||
beginInfo.setRenderArea(0, 0, framebufferWidth, framebufferHeight);
|
||||
beginInfo.setFramebuffer(framebuffer);
|
||||
beginInfo.addClearColor(0.0f, 0.0f, 0.0f, 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->bindVertexBuffers(0, 1, vertexBuffers, offsets);
|
||||
cmdbuffer->setViewport(0, 1, &viewport);
|
||||
cmdbuffer->setScissor(0, 1, &scissor);
|
||||
if (stencilTest)
|
||||
cmdbuffer->setStencilReference(VK_STENCIL_FRONT_AND_BACK, screen->stencilValue);
|
||||
if (pushConstantsSize > 0)
|
||||
cmdbuffer->pushConstants(passSetup->PipelineLayout.get(), VK_SHADER_STAGE_FRAGMENT_BIT, 0, pushConstantsSize, pushConstants);
|
||||
cmdbuffer->draw(3, 1, FFlatVertexBuffer::PRESENT_INDEX, 0);
|
||||
cmdbuffer->endRenderPass();
|
||||
}
|
||||
|
||||
VulkanDescriptorSet *VkPPRenderState::GetInput(VkPPRenderPassSetup *passSetup, const TArray<PPTextureInput> &textures, bool bindShadowMapBuffers)
|
||||
{
|
||||
auto fb = GetVulkanFrameBuffer();
|
||||
auto pp = fb->GetPostprocess();
|
||||
auto descriptors = pp->AllocateDescriptorSet(passSetup->DescriptorLayout.get());
|
||||
descriptors->SetDebugName("VkPostprocess.descriptors");
|
||||
|
||||
WriteDescriptors write;
|
||||
VkImageTransition imageTransition;
|
||||
|
||||
for (unsigned int index = 0; index < textures.Size(); index++)
|
||||
{
|
||||
const PPTextureInput &input = textures[index];
|
||||
VulkanSampler *sampler = pp->GetSampler(input.Filter, input.Wrap);
|
||||
VkTextureImage *tex = GetTexture(input.Type, input.Texture);
|
||||
|
||||
write.addCombinedImageSampler(descriptors.get(), index, tex->DepthOnlyView ? tex->DepthOnlyView.get() : tex->View.get(), sampler, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
imageTransition.addImage(tex, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false);
|
||||
}
|
||||
|
||||
if (bindShadowMapBuffers)
|
||||
{
|
||||
write.addBuffer(descriptors.get(), LIGHTNODES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightNodes->mBuffer.get());
|
||||
write.addBuffer(descriptors.get(), LIGHTLINES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightLines->mBuffer.get());
|
||||
write.addBuffer(descriptors.get(), LIGHTLIST_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightList->mBuffer.get());
|
||||
}
|
||||
|
||||
write.updateSets(fb->device);
|
||||
imageTransition.execute(fb->GetCommands()->GetDrawCommands());
|
||||
|
||||
VulkanDescriptorSet *set = descriptors.get();
|
||||
fb->GetCommands()->FrameDeleteList.Descriptors.push_back(std::move(descriptors));
|
||||
return set;
|
||||
}
|
||||
|
||||
VulkanFramebuffer *VkPPRenderState::GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output, bool stencilTest, int &framebufferWidth, int &framebufferHeight)
|
||||
{
|
||||
auto fb = GetVulkanFrameBuffer();
|
||||
|
||||
VkTextureImage *tex = GetTexture(output.Type, output.Texture);
|
||||
|
||||
VkImageView view;
|
||||
std::unique_ptr<VulkanFramebuffer> *framebufferptr = nullptr;
|
||||
int w, h;
|
||||
if (tex)
|
||||
{
|
||||
VkImageTransition imageTransition;
|
||||
imageTransition.addImage(tex, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, output.Type == PPTextureType::NextPipelineTexture);
|
||||
if (stencilTest)
|
||||
imageTransition.addImage(&fb->GetBuffers()->SceneDepthStencil, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false);
|
||||
imageTransition.execute(fb->GetCommands()->GetDrawCommands());
|
||||
|
||||
view = tex->View->view;
|
||||
w = tex->Image->width;
|
||||
h = tex->Image->height;
|
||||
framebufferptr = &tex->PPFramebuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
view = fb->GetCommands()->swapChain->swapChainImageViews[fb->GetCommands()->presentImageIndex];
|
||||
framebufferptr = &fb->GetCommands()->swapChain->framebuffers[fb->GetCommands()->presentImageIndex];
|
||||
w = fb->GetCommands()->swapChain->actualExtent.width;
|
||||
h = fb->GetCommands()->swapChain->actualExtent.height;
|
||||
}
|
||||
|
||||
auto &framebuffer = *framebufferptr;
|
||||
if (!framebuffer)
|
||||
{
|
||||
FramebufferBuilder builder;
|
||||
builder.setRenderPass(passSetup->RenderPass.get());
|
||||
builder.setSize(w, h);
|
||||
builder.addAttachment(view);
|
||||
if (stencilTest)
|
||||
builder.addAttachment(fb->GetBuffers()->SceneDepthStencil.View.get());
|
||||
framebuffer = builder.create(GetVulkanFrameBuffer()->device);
|
||||
}
|
||||
|
||||
framebufferWidth = w;
|
||||
framebufferHeight = h;
|
||||
return framebuffer.get();
|
||||
}
|
||||
|
||||
VkTextureImage *VkPPRenderState::GetTexture(const PPTextureType &type, PPTexture *pptexture)
|
||||
{
|
||||
auto fb = GetVulkanFrameBuffer();
|
||||
|
||||
if (type == PPTextureType::CurrentPipelineTexture || type == PPTextureType::NextPipelineTexture)
|
||||
{
|
||||
int idx = fb->GetPostprocess()->mCurrentPipelineImage;
|
||||
if (type == PPTextureType::NextPipelineTexture)
|
||||
idx = (idx + 1) % VkRenderBuffers::NumPipelineImages;
|
||||
|
||||
return &fb->GetBuffers()->PipelineImage[idx];
|
||||
}
|
||||
else if (type == PPTextureType::PPTexture)
|
||||
{
|
||||
auto vktex = GetVkTexture(pptexture);
|
||||
return &vktex->TexImage;
|
||||
}
|
||||
else if (type == PPTextureType::SceneColor)
|
||||
{
|
||||
return &fb->GetBuffers()->SceneColor;
|
||||
}
|
||||
else if (type == PPTextureType::SceneNormal)
|
||||
{
|
||||
return &fb->GetBuffers()->SceneNormal;
|
||||
}
|
||||
else if (type == PPTextureType::SceneFog)
|
||||
{
|
||||
return &fb->GetBuffers()->SceneFog;
|
||||
}
|
||||
else if (type == PPTextureType::SceneDepth)
|
||||
{
|
||||
return &fb->GetBuffers()->SceneDepthStencil;
|
||||
}
|
||||
else if (type == PPTextureType::ShadowMap)
|
||||
{
|
||||
return &fb->GetBuffers()->Shadowmap;
|
||||
}
|
||||
else if (type == PPTextureType::SwapChain)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
I_FatalError("VkPPRenderState::GetTexture not implemented yet for this texture type");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
VkPPShader *VkPPRenderState::GetVkShader(PPShader *shader)
|
||||
{
|
||||
if (!shader->Backend)
|
||||
shader->Backend = std::make_unique<VkPPShader>(shader);
|
||||
return static_cast<VkPPShader*>(shader->Backend.get());
|
||||
}
|
||||
|
||||
VkPPTexture *VkPPRenderState::GetVkTexture(PPTexture *texture)
|
||||
{
|
||||
if (!texture->Backend)
|
||||
texture->Backend = std::make_unique<VkPPTexture>(texture);
|
||||
return static_cast<VkPPTexture*>(texture->Backend.get());
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
VkPPRenderPassSetup::VkPPRenderPassSetup(const VkPPRenderPassKey &key)
|
||||
{
|
||||
CreateDescriptorLayout(key);
|
||||
CreatePipelineLayout(key);
|
||||
CreateRenderPass(key);
|
||||
CreatePipeline(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);
|
||||
if (key.ShadowMapBuffers)
|
||||
{
|
||||
builder.addBinding(LIGHTNODES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
builder.addBinding(LIGHTLINES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
builder.addBinding(LIGHTLIST_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
}
|
||||
DescriptorLayout = builder.create(GetVulkanFrameBuffer()->device);
|
||||
DescriptorLayout->SetDebugName("VkPPRenderPassSetup.DescriptorLayout");
|
||||
}
|
||||
|
||||
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);
|
||||
PipelineLayout->SetDebugName("VkPPRenderPassSetup.PipelineLayout");
|
||||
}
|
||||
|
||||
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.addDynamicState(VK_DYNAMIC_STATE_SCISSOR);
|
||||
// Note: the actual values are ignored since we use dynamic viewport+scissor states
|
||||
builder.setViewport(0.0f, 0.0f, 320.0f, 200.0f);
|
||||
builder.setScissor(0, 0, 320, 200);
|
||||
if (key.StencilTest)
|
||||
{
|
||||
builder.addDynamicState(VK_DYNAMIC_STATE_STENCIL_REFERENCE);
|
||||
builder.setDepthStencilEnable(false, false, true);
|
||||
builder.setStencil(VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_EQUAL, 0xffffffff, 0xffffffff, 0);
|
||||
}
|
||||
builder.setTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
|
||||
builder.setBlendMode(key.BlendMode);
|
||||
builder.setRasterizationSamples(key.Samples);
|
||||
builder.setLayout(PipelineLayout.get());
|
||||
builder.setRenderPass(RenderPass.get());
|
||||
Pipeline = builder.create(GetVulkanFrameBuffer()->device);
|
||||
Pipeline->SetDebugName("VkPPRenderPassSetup.Pipeline");
|
||||
}
|
||||
|
||||
void VkPPRenderPassSetup::CreateRenderPass(const VkPPRenderPassKey &key)
|
||||
{
|
||||
RenderPassBuilder builder;
|
||||
if (key.SwapChain)
|
||||
builder.addAttachment(key.OutputFormat, key.Samples, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
else
|
||||
builder.addAttachment(key.OutputFormat, key.Samples, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
if (key.StencilTest)
|
||||
{
|
||||
builder.addDepthStencilAttachment(
|
||||
GetVulkanFrameBuffer()->GetBuffers()->SceneDepthStencilFormat, key.Samples,
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE,
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE,
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
}
|
||||
|
||||
builder.addSubpass();
|
||||
builder.addSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
if (key.StencilTest)
|
||||
{
|
||||
builder.addSubpassDepthStencilAttachmentRef(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
builder.addExternalSubpassDependency(
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.addExternalSubpassDependency(
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT);
|
||||
}
|
||||
|
||||
RenderPass = builder.create(GetVulkanFrameBuffer()->device);
|
||||
RenderPass->SetDebugName("VkPPRenderPassSetup.RenderPass");
|
||||
}
|
||||
|
|
|
@ -14,35 +14,14 @@ class FString;
|
|||
|
||||
class VkPPShader;
|
||||
class VkPPTexture;
|
||||
class VkPPRenderPassSetup;
|
||||
class PipelineBarrier;
|
||||
|
||||
class VkPPRenderPassKey
|
||||
{
|
||||
public:
|
||||
VkPPShader *Shader;
|
||||
int Uniforms;
|
||||
int InputTextures;
|
||||
PPBlendMode BlendMode;
|
||||
VkFormat OutputFormat;
|
||||
int SwapChain;
|
||||
int ShadowMapBuffers;
|
||||
int StencilTest;
|
||||
VkSampleCountFlagBits Samples;
|
||||
|
||||
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
|
||||
{
|
||||
public:
|
||||
VkPostprocess();
|
||||
~VkPostprocess();
|
||||
|
||||
void RenderBuffersReset();
|
||||
|
||||
void SetActiveRenderTarget();
|
||||
void PostProcessScene(int fixedcm, float flash, const std::function<void()> &afterBloomDrawEndScene2D);
|
||||
|
||||
|
@ -62,72 +41,9 @@ private:
|
|||
void NextEye(int eyeCount);
|
||||
|
||||
std::unique_ptr<VulkanDescriptorSet> AllocateDescriptorSet(VulkanDescriptorSetLayout *layout);
|
||||
VulkanSampler *GetSampler(PPFilterMode filter, PPWrapMode wrap);
|
||||
|
||||
std::array<std::unique_ptr<VulkanSampler>, 4> mSamplers;
|
||||
std::map<VkPPRenderPassKey, std::unique_ptr<VkPPRenderPassSetup>> mRenderPassSetup;
|
||||
std::unique_ptr<VulkanDescriptorPool> mDescriptorPool;
|
||||
int mCurrentPipelineImage = 0;
|
||||
|
||||
friend class VkPPRenderState;
|
||||
};
|
||||
|
||||
class VkPPShader : public PPShaderBackend
|
||||
{
|
||||
public:
|
||||
VkPPShader(PPShader *shader);
|
||||
|
||||
std::unique_ptr<VulkanShader> VertexShader;
|
||||
std::unique_ptr<VulkanShader> FragmentShader;
|
||||
|
||||
private:
|
||||
FString LoadShaderCode(const FString &lumpname, const FString &defines, int version);
|
||||
};
|
||||
|
||||
class VkPPTexture : public PPTextureBackend
|
||||
{
|
||||
public:
|
||||
VkPPTexture(PPTexture *texture);
|
||||
~VkPPTexture();
|
||||
|
||||
VkTextureImage TexImage;
|
||||
std::unique_ptr<VulkanBuffer> Staging;
|
||||
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;
|
||||
|
||||
private:
|
||||
void CreateDescriptorLayout(const VkPPRenderPassKey &key);
|
||||
void CreatePipelineLayout(const VkPPRenderPassKey &key);
|
||||
void CreatePipeline(const VkPPRenderPassKey &key);
|
||||
void CreateRenderPass(const VkPPRenderPassKey &key);
|
||||
};
|
||||
|
||||
class VkPPRenderState : public PPRenderState
|
||||
{
|
||||
public:
|
||||
void PushGroup(const FString &name) override;
|
||||
void PopGroup() override;
|
||||
|
||||
void Draw() override;
|
||||
|
||||
private:
|
||||
void RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescriptorSet *descriptorSet, VulkanFramebuffer *framebuffer, int framebufferWidth, int framebufferHeight, int x, int y, int width, int height, const void *pushConstants, uint32_t pushConstantsSize, bool stencilTest);
|
||||
|
||||
VulkanDescriptorSet *GetInput(VkPPRenderPassSetup *passSetup, const TArray<PPTextureInput> &textures, bool bindShadowMapBuffers);
|
||||
VulkanFramebuffer *GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output, bool stencilTest, int &framebufferWidth, int &framebufferHeight);
|
||||
|
||||
VkPPShader *GetVkShader(PPShader *shader);
|
||||
VkPPTexture *GetVkTexture(PPTexture *texture);
|
||||
|
||||
VkTextureImage *GetTexture(const PPTextureType &type, PPTexture *tex);
|
||||
};
|
||||
|
|
277
src/common/rendering/vulkan/renderer/vk_pprenderstate.cpp
Normal file
277
src/common/rendering/vulkan/renderer/vk_pprenderstate.cpp
Normal file
|
@ -0,0 +1,277 @@
|
|||
/*
|
||||
** Vulkan backend
|
||||
** Copyright (c) 2016-2020 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "vk_pprenderstate.h"
|
||||
#include "vk_postprocess.h"
|
||||
#include "vulkan/system/vk_framebuffer.h"
|
||||
#include "vulkan/system/vk_commandbuffer.h"
|
||||
#include "vulkan/system/vk_swapchain.h"
|
||||
#include "vulkan/shaders/vk_ppshader.h"
|
||||
#include "vulkan/textures/vk_pptexture.h"
|
||||
#include "vulkan/textures/vk_renderbuffers.h"
|
||||
#include "vulkan/textures/vk_samplers.h"
|
||||
#include "vulkan/renderer/vk_renderstate.h"
|
||||
#include "flatvertices.h"
|
||||
|
||||
void VkPPRenderState::PushGroup(const FString &name)
|
||||
{
|
||||
GetVulkanFrameBuffer()->GetCommands()->PushGroup(name);
|
||||
}
|
||||
|
||||
void VkPPRenderState::PopGroup()
|
||||
{
|
||||
GetVulkanFrameBuffer()->GetCommands()->PopGroup();
|
||||
}
|
||||
|
||||
void VkPPRenderState::Draw()
|
||||
{
|
||||
auto fb = GetVulkanFrameBuffer();
|
||||
auto pp = fb->GetPostprocess();
|
||||
|
||||
fb->GetRenderState()->EndRenderPass();
|
||||
|
||||
VkPPRenderPassKey key;
|
||||
key.BlendMode = BlendMode;
|
||||
key.InputTextures = Textures.Size();
|
||||
key.Uniforms = Uniforms.Data.Size();
|
||||
key.Shader = GetVkShader(Shader);
|
||||
key.SwapChain = (Output.Type == PPTextureType::SwapChain);
|
||||
key.ShadowMapBuffers = ShadowMapBuffers;
|
||||
if (Output.Type == PPTextureType::PPTexture)
|
||||
key.OutputFormat = GetVkTexture(Output.Texture)->Format;
|
||||
else if (Output.Type == PPTextureType::SwapChain)
|
||||
key.OutputFormat = GetVulkanFrameBuffer()->GetCommands()->swapChain->swapChainFormat.format;
|
||||
else if (Output.Type == PPTextureType::ShadowMap)
|
||||
key.OutputFormat = VK_FORMAT_R32_SFLOAT;
|
||||
else
|
||||
key.OutputFormat = VK_FORMAT_R16G16B16A16_SFLOAT;
|
||||
|
||||
if (Output.Type == PPTextureType::SceneColor)
|
||||
{
|
||||
key.StencilTest = 1;
|
||||
key.Samples = fb->GetBuffers()->GetSceneSamples();
|
||||
}
|
||||
else
|
||||
{
|
||||
key.StencilTest = 0;
|
||||
key.Samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
}
|
||||
|
||||
auto passSetup = fb->GetRenderPassManager()->GetPPRenderPass(key);
|
||||
|
||||
int framebufferWidth = 0, framebufferHeight = 0;
|
||||
VulkanDescriptorSet *input = GetInput(passSetup, Textures, ShadowMapBuffers);
|
||||
VulkanFramebuffer *output = GetOutput(passSetup, Output, key.StencilTest, framebufferWidth, framebufferHeight);
|
||||
|
||||
RenderScreenQuad(passSetup, input, output, framebufferWidth, framebufferHeight, Viewport.left, Viewport.top, Viewport.width, Viewport.height, Uniforms.Data.Data(), Uniforms.Data.Size(), key.StencilTest);
|
||||
|
||||
// Advance to next PP texture if our output was sent there
|
||||
if (Output.Type == PPTextureType::NextPipelineTexture)
|
||||
{
|
||||
pp->mCurrentPipelineImage = (pp->mCurrentPipelineImage + 1) % VkRenderBuffers::NumPipelineImages;
|
||||
}
|
||||
}
|
||||
|
||||
void VkPPRenderState::RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescriptorSet *descriptorSet, VulkanFramebuffer *framebuffer, int framebufferWidth, int framebufferHeight, int x, int y, int width, int height, const void *pushConstants, uint32_t pushConstantsSize, bool stencilTest)
|
||||
{
|
||||
auto fb = GetVulkanFrameBuffer();
|
||||
auto cmdbuffer = fb->GetCommands()->GetDrawCommands();
|
||||
|
||||
VkViewport viewport = { };
|
||||
viewport.x = (float)x;
|
||||
viewport.y = (float)y;
|
||||
viewport.width = (float)width;
|
||||
viewport.height = (float)height;
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
|
||||
VkRect2D scissor = { };
|
||||
scissor.offset.x = 0;
|
||||
scissor.offset.y = 0;
|
||||
scissor.extent.width = framebufferWidth;
|
||||
scissor.extent.height = framebufferHeight;
|
||||
|
||||
RenderPassBegin beginInfo;
|
||||
beginInfo.setRenderPass(passSetup->RenderPass.get());
|
||||
beginInfo.setRenderArea(0, 0, framebufferWidth, framebufferHeight);
|
||||
beginInfo.setFramebuffer(framebuffer);
|
||||
beginInfo.addClearColor(0.0f, 0.0f, 0.0f, 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->bindVertexBuffers(0, 1, vertexBuffers, offsets);
|
||||
cmdbuffer->setViewport(0, 1, &viewport);
|
||||
cmdbuffer->setScissor(0, 1, &scissor);
|
||||
if (stencilTest)
|
||||
cmdbuffer->setStencilReference(VK_STENCIL_FRONT_AND_BACK, screen->stencilValue);
|
||||
if (pushConstantsSize > 0)
|
||||
cmdbuffer->pushConstants(passSetup->PipelineLayout.get(), VK_SHADER_STAGE_FRAGMENT_BIT, 0, pushConstantsSize, pushConstants);
|
||||
cmdbuffer->draw(3, 1, FFlatVertexBuffer::PRESENT_INDEX, 0);
|
||||
cmdbuffer->endRenderPass();
|
||||
}
|
||||
|
||||
VulkanDescriptorSet *VkPPRenderState::GetInput(VkPPRenderPassSetup *passSetup, const TArray<PPTextureInput> &textures, bool bindShadowMapBuffers)
|
||||
{
|
||||
auto fb = GetVulkanFrameBuffer();
|
||||
auto descriptors = fb->GetPostprocess()->AllocateDescriptorSet(passSetup->DescriptorLayout.get());
|
||||
descriptors->SetDebugName("VkPostprocess.descriptors");
|
||||
|
||||
WriteDescriptors write;
|
||||
VkImageTransition imageTransition;
|
||||
|
||||
for (unsigned int index = 0; index < textures.Size(); index++)
|
||||
{
|
||||
const PPTextureInput &input = textures[index];
|
||||
VulkanSampler *sampler = fb->GetSamplerManager()->Get(input.Filter, input.Wrap);
|
||||
VkTextureImage *tex = GetTexture(input.Type, input.Texture);
|
||||
|
||||
write.addCombinedImageSampler(descriptors.get(), index, tex->DepthOnlyView ? tex->DepthOnlyView.get() : tex->View.get(), sampler, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
imageTransition.addImage(tex, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false);
|
||||
}
|
||||
|
||||
if (bindShadowMapBuffers)
|
||||
{
|
||||
write.addBuffer(descriptors.get(), LIGHTNODES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightNodes->mBuffer.get());
|
||||
write.addBuffer(descriptors.get(), LIGHTLINES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightLines->mBuffer.get());
|
||||
write.addBuffer(descriptors.get(), LIGHTLIST_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightList->mBuffer.get());
|
||||
}
|
||||
|
||||
write.updateSets(fb->device);
|
||||
imageTransition.execute(fb->GetCommands()->GetDrawCommands());
|
||||
|
||||
VulkanDescriptorSet *set = descriptors.get();
|
||||
fb->GetCommands()->FrameDeleteList.Descriptors.push_back(std::move(descriptors));
|
||||
return set;
|
||||
}
|
||||
|
||||
VulkanFramebuffer *VkPPRenderState::GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output, bool stencilTest, int &framebufferWidth, int &framebufferHeight)
|
||||
{
|
||||
auto fb = GetVulkanFrameBuffer();
|
||||
|
||||
VkTextureImage *tex = GetTexture(output.Type, output.Texture);
|
||||
|
||||
VkImageView view;
|
||||
std::unique_ptr<VulkanFramebuffer> *framebufferptr = nullptr;
|
||||
int w, h;
|
||||
if (tex)
|
||||
{
|
||||
VkImageTransition imageTransition;
|
||||
imageTransition.addImage(tex, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, output.Type == PPTextureType::NextPipelineTexture);
|
||||
if (stencilTest)
|
||||
imageTransition.addImage(&fb->GetBuffers()->SceneDepthStencil, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, false);
|
||||
imageTransition.execute(fb->GetCommands()->GetDrawCommands());
|
||||
|
||||
view = tex->View->view;
|
||||
w = tex->Image->width;
|
||||
h = tex->Image->height;
|
||||
framebufferptr = &tex->PPFramebuffer;
|
||||
}
|
||||
else
|
||||
{
|
||||
view = fb->GetCommands()->swapChain->swapChainImageViews[fb->GetCommands()->presentImageIndex];
|
||||
framebufferptr = &fb->GetCommands()->swapChain->framebuffers[fb->GetCommands()->presentImageIndex];
|
||||
w = fb->GetCommands()->swapChain->actualExtent.width;
|
||||
h = fb->GetCommands()->swapChain->actualExtent.height;
|
||||
}
|
||||
|
||||
auto &framebuffer = *framebufferptr;
|
||||
if (!framebuffer)
|
||||
{
|
||||
FramebufferBuilder builder;
|
||||
builder.setRenderPass(passSetup->RenderPass.get());
|
||||
builder.setSize(w, h);
|
||||
builder.addAttachment(view);
|
||||
if (stencilTest)
|
||||
builder.addAttachment(fb->GetBuffers()->SceneDepthStencil.View.get());
|
||||
framebuffer = builder.create(GetVulkanFrameBuffer()->device);
|
||||
}
|
||||
|
||||
framebufferWidth = w;
|
||||
framebufferHeight = h;
|
||||
return framebuffer.get();
|
||||
}
|
||||
|
||||
VkTextureImage *VkPPRenderState::GetTexture(const PPTextureType &type, PPTexture *pptexture)
|
||||
{
|
||||
auto fb = GetVulkanFrameBuffer();
|
||||
|
||||
if (type == PPTextureType::CurrentPipelineTexture || type == PPTextureType::NextPipelineTexture)
|
||||
{
|
||||
int idx = fb->GetPostprocess()->mCurrentPipelineImage;
|
||||
if (type == PPTextureType::NextPipelineTexture)
|
||||
idx = (idx + 1) % VkRenderBuffers::NumPipelineImages;
|
||||
|
||||
return &fb->GetBuffers()->PipelineImage[idx];
|
||||
}
|
||||
else if (type == PPTextureType::PPTexture)
|
||||
{
|
||||
auto vktex = GetVkTexture(pptexture);
|
||||
return &vktex->TexImage;
|
||||
}
|
||||
else if (type == PPTextureType::SceneColor)
|
||||
{
|
||||
return &fb->GetBuffers()->SceneColor;
|
||||
}
|
||||
else if (type == PPTextureType::SceneNormal)
|
||||
{
|
||||
return &fb->GetBuffers()->SceneNormal;
|
||||
}
|
||||
else if (type == PPTextureType::SceneFog)
|
||||
{
|
||||
return &fb->GetBuffers()->SceneFog;
|
||||
}
|
||||
else if (type == PPTextureType::SceneDepth)
|
||||
{
|
||||
return &fb->GetBuffers()->SceneDepthStencil;
|
||||
}
|
||||
else if (type == PPTextureType::ShadowMap)
|
||||
{
|
||||
return &fb->GetBuffers()->Shadowmap;
|
||||
}
|
||||
else if (type == PPTextureType::SwapChain)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
I_FatalError("VkPPRenderState::GetTexture not implemented yet for this texture type");
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
VkPPShader *VkPPRenderState::GetVkShader(PPShader *shader)
|
||||
{
|
||||
if (!shader->Backend)
|
||||
shader->Backend = std::make_unique<VkPPShader>(shader);
|
||||
return static_cast<VkPPShader*>(shader->Backend.get());
|
||||
}
|
||||
|
||||
VkPPTexture *VkPPRenderState::GetVkTexture(PPTexture *texture)
|
||||
{
|
||||
if (!texture->Backend)
|
||||
texture->Backend = std::make_unique<VkPPTexture>(texture);
|
||||
return static_cast<VkPPTexture*>(texture->Backend.get());
|
||||
}
|
30
src/common/rendering/vulkan/renderer/vk_pprenderstate.h
Normal file
30
src/common/rendering/vulkan/renderer/vk_pprenderstate.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "hwrenderer/postprocessing/hw_postprocess.h"
|
||||
#include "vulkan/system/vk_objects.h"
|
||||
|
||||
class VkPPRenderPassSetup;
|
||||
class VkPPShader;
|
||||
class VkPPTexture;
|
||||
class VkTextureImage;
|
||||
|
||||
class VkPPRenderState : public PPRenderState
|
||||
{
|
||||
public:
|
||||
void PushGroup(const FString &name) override;
|
||||
void PopGroup() override;
|
||||
|
||||
void Draw() override;
|
||||
|
||||
private:
|
||||
void RenderScreenQuad(VkPPRenderPassSetup *passSetup, VulkanDescriptorSet *descriptorSet, VulkanFramebuffer *framebuffer, int framebufferWidth, int framebufferHeight, int x, int y, int width, int height, const void *pushConstants, uint32_t pushConstantsSize, bool stencilTest);
|
||||
|
||||
VulkanDescriptorSet *GetInput(VkPPRenderPassSetup *passSetup, const TArray<PPTextureInput> &textures, bool bindShadowMapBuffers);
|
||||
VulkanFramebuffer *GetOutput(VkPPRenderPassSetup *passSetup, const PPOutput &output, bool stencilTest, int &framebufferWidth, int &framebufferHeight);
|
||||
|
||||
VkPPShader *GetVkShader(PPShader *shader);
|
||||
VkPPTexture *GetVkTexture(PPTexture *texture);
|
||||
|
||||
VkTextureImage *GetTexture(const PPTextureType &type, PPTexture *tex);
|
||||
};
|
|
@ -27,6 +27,7 @@
|
|||
#include "vulkan/textures/vk_renderbuffers.h"
|
||||
#include "vulkan/textures/vk_samplers.h"
|
||||
#include "vulkan/shaders/vk_shader.h"
|
||||
#include "vulkan/shaders/vk_ppshader.h"
|
||||
#include "vulkan/system/vk_builders.h"
|
||||
#include "vulkan/system/vk_framebuffer.h"
|
||||
#include "vulkan/system/vk_buffers.h"
|
||||
|
@ -45,6 +46,7 @@ VkRenderPassManager::~VkRenderPassManager()
|
|||
void VkRenderPassManager::RenderBuffersReset()
|
||||
{
|
||||
RenderPassSetup.clear();
|
||||
PPRenderPassSetup.clear();
|
||||
}
|
||||
|
||||
VkRenderPassSetup *VkRenderPassManager::GetRenderPass(const VkRenderPassKey &key)
|
||||
|
@ -120,6 +122,14 @@ VulkanPipelineLayout* VkRenderPassManager::GetPipelineLayout(int numLayers)
|
|||
return layout.get();
|
||||
}
|
||||
|
||||
VkPPRenderPassSetup* VkRenderPassManager::GetPPRenderPass(const VkPPRenderPassKey& key)
|
||||
{
|
||||
auto& passSetup = PPRenderPassSetup[key];
|
||||
if (!passSetup)
|
||||
passSetup.reset(new VkPPRenderPassSetup(key));
|
||||
return passSetup.get();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
VkRenderPassSetup::VkRenderPassSetup(const VkRenderPassKey &key) : PassKey(key)
|
||||
|
@ -284,3 +294,107 @@ std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipeli
|
|||
pipeline->SetDebugName("VkRenderPassSetup.Pipeline");
|
||||
return pipeline;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
VkPPRenderPassSetup::VkPPRenderPassSetup(const VkPPRenderPassKey& key)
|
||||
{
|
||||
CreateDescriptorLayout(key);
|
||||
CreatePipelineLayout(key);
|
||||
CreateRenderPass(key);
|
||||
CreatePipeline(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);
|
||||
if (key.ShadowMapBuffers)
|
||||
{
|
||||
builder.addBinding(LIGHTNODES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
builder.addBinding(LIGHTLINES_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
builder.addBinding(LIGHTLIST_BINDINGPOINT, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
||||
}
|
||||
DescriptorLayout = builder.create(GetVulkanFrameBuffer()->device);
|
||||
DescriptorLayout->SetDebugName("VkPPRenderPassSetup.DescriptorLayout");
|
||||
}
|
||||
|
||||
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);
|
||||
PipelineLayout->SetDebugName("VkPPRenderPassSetup.PipelineLayout");
|
||||
}
|
||||
|
||||
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.addDynamicState(VK_DYNAMIC_STATE_SCISSOR);
|
||||
// Note: the actual values are ignored since we use dynamic viewport+scissor states
|
||||
builder.setViewport(0.0f, 0.0f, 320.0f, 200.0f);
|
||||
builder.setScissor(0, 0, 320, 200);
|
||||
if (key.StencilTest)
|
||||
{
|
||||
builder.addDynamicState(VK_DYNAMIC_STATE_STENCIL_REFERENCE);
|
||||
builder.setDepthStencilEnable(false, false, true);
|
||||
builder.setStencil(VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_STENCIL_OP_KEEP, VK_COMPARE_OP_EQUAL, 0xffffffff, 0xffffffff, 0);
|
||||
}
|
||||
builder.setTopology(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP);
|
||||
builder.setBlendMode(key.BlendMode);
|
||||
builder.setRasterizationSamples(key.Samples);
|
||||
builder.setLayout(PipelineLayout.get());
|
||||
builder.setRenderPass(RenderPass.get());
|
||||
Pipeline = builder.create(GetVulkanFrameBuffer()->device);
|
||||
Pipeline->SetDebugName("VkPPRenderPassSetup.Pipeline");
|
||||
}
|
||||
|
||||
void VkPPRenderPassSetup::CreateRenderPass(const VkPPRenderPassKey& key)
|
||||
{
|
||||
RenderPassBuilder builder;
|
||||
if (key.SwapChain)
|
||||
builder.addAttachment(key.OutputFormat, key.Samples, VK_ATTACHMENT_LOAD_OP_CLEAR, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_PRESENT_SRC_KHR);
|
||||
else
|
||||
builder.addAttachment(key.OutputFormat, key.Samples, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
if (key.StencilTest)
|
||||
{
|
||||
builder.addDepthStencilAttachment(
|
||||
GetVulkanFrameBuffer()->GetBuffers()->SceneDepthStencilFormat, key.Samples,
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE,
|
||||
VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE,
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
}
|
||||
|
||||
builder.addSubpass();
|
||||
builder.addSubpassColorAttachmentRef(0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
||||
if (key.StencilTest)
|
||||
{
|
||||
builder.addSubpassDepthStencilAttachmentRef(1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
builder.addExternalSubpassDependency(
|
||||
VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT | VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT | VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT);
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.addExternalSubpassDependency(
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT,
|
||||
VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
|
||||
VK_ACCESS_COLOR_ATTACHMENT_READ_BIT | VK_ACCESS_SHADER_READ_BIT);
|
||||
}
|
||||
|
||||
RenderPass = builder.create(GetVulkanFrameBuffer()->device);
|
||||
RenderPass->SetDebugName("VkPPRenderPassSetup.RenderPass");
|
||||
}
|
||||
|
|
|
@ -4,11 +4,12 @@
|
|||
#include "vulkan/system/vk_objects.h"
|
||||
#include "renderstyle.h"
|
||||
#include "hwrenderer/data/buffers.h"
|
||||
#include "hwrenderer/postprocessing/hw_postprocess.h"
|
||||
#include "hw_renderstate.h"
|
||||
#include <string.h>
|
||||
#include <map>
|
||||
|
||||
class VKDataBuffer;
|
||||
class VkPPShader;
|
||||
|
||||
class VkPipelineKey
|
||||
{
|
||||
|
@ -74,6 +75,41 @@ public:
|
|||
int UseVertexData;
|
||||
};
|
||||
|
||||
class VkPPRenderPassKey
|
||||
{
|
||||
public:
|
||||
VkPPShader* Shader;
|
||||
int Uniforms;
|
||||
int InputTextures;
|
||||
PPBlendMode BlendMode;
|
||||
VkFormat OutputFormat;
|
||||
int SwapChain;
|
||||
int ShadowMapBuffers;
|
||||
int StencilTest;
|
||||
VkSampleCountFlagBits Samples;
|
||||
|
||||
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 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;
|
||||
|
||||
private:
|
||||
void CreateDescriptorLayout(const VkPPRenderPassKey& key);
|
||||
void CreatePipelineLayout(const VkPPRenderPassKey& key);
|
||||
void CreatePipeline(const VkPPRenderPassKey& key);
|
||||
void CreateRenderPass(const VkPPRenderPassKey& key);
|
||||
};
|
||||
|
||||
class VkRenderPassManager
|
||||
{
|
||||
public:
|
||||
|
@ -87,8 +123,12 @@ public:
|
|||
VkVertexFormat *GetVertexFormat(int index);
|
||||
VulkanPipelineLayout* GetPipelineLayout(int numLayers);
|
||||
|
||||
VkPPRenderPassSetup* GetPPRenderPass(const VkPPRenderPassKey& key);
|
||||
|
||||
private:
|
||||
std::map<VkRenderPassKey, std::unique_ptr<VkRenderPassSetup>> RenderPassSetup;
|
||||
std::vector<std::unique_ptr<VulkanPipelineLayout>> PipelineLayouts;
|
||||
std::vector<VkVertexFormat> VertexFormats;
|
||||
|
||||
std::map<VkPPRenderPassKey, std::unique_ptr<VkPPRenderPassSetup>> PPRenderPassSetup;
|
||||
};
|
||||
|
|
60
src/common/rendering/vulkan/shaders/vk_ppshader.cpp
Normal file
60
src/common/rendering/vulkan/shaders/vk_ppshader.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
** Vulkan backend
|
||||
** Copyright (c) 2016-2020 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "vk_ppshader.h"
|
||||
#include "vulkan/system/vk_framebuffer.h"
|
||||
#include "vulkan/system/vk_builders.h"
|
||||
#include "filesystem.h"
|
||||
|
||||
VkPPShader::VkPPShader(PPShader *shader)
|
||||
{
|
||||
auto fb = GetVulkanFrameBuffer();
|
||||
|
||||
FString prolog;
|
||||
if (!shader->Uniforms.empty())
|
||||
prolog = UniformBlockDecl::Create("Uniforms", shader->Uniforms, -1);
|
||||
prolog += shader->Defines;
|
||||
|
||||
ShaderBuilder vertbuilder;
|
||||
vertbuilder.setVertexShader(LoadShaderCode(shader->VertexShader, "", shader->Version));
|
||||
VertexShader = vertbuilder.create(shader->VertexShader.GetChars(), fb->device);
|
||||
VertexShader->SetDebugName(shader->VertexShader.GetChars());
|
||||
|
||||
ShaderBuilder fragbuilder;
|
||||
fragbuilder.setFragmentShader(LoadShaderCode(shader->FragmentShader, prolog, shader->Version));
|
||||
FragmentShader = fragbuilder.create(shader->FragmentShader.GetChars(), fb->device);
|
||||
FragmentShader->SetDebugName(shader->FragmentShader.GetChars());
|
||||
}
|
||||
|
||||
FString VkPPShader::LoadShaderCode(const FString &lumpName, const FString &defines, int version)
|
||||
{
|
||||
int lump = fileSystem.CheckNumForFullName(lumpName);
|
||||
if (lump == -1) I_FatalError("Unable to load '%s'", lumpName.GetChars());
|
||||
FString code = fileSystem.ReadFile(lump).GetString().GetChars();
|
||||
|
||||
FString patchedCode;
|
||||
patchedCode.AppendFormat("#version %d\n", 450);
|
||||
patchedCode << defines;
|
||||
patchedCode << "#line 1\n";
|
||||
patchedCode << code;
|
||||
return patchedCode;
|
||||
}
|
17
src/common/rendering/vulkan/shaders/vk_ppshader.h
Normal file
17
src/common/rendering/vulkan/shaders/vk_ppshader.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "hwrenderer/postprocessing/hw_postprocess.h"
|
||||
#include "vulkan/system/vk_objects.h"
|
||||
|
||||
class VkPPShader : public PPShaderBackend
|
||||
{
|
||||
public:
|
||||
VkPPShader(PPShader *shader);
|
||||
|
||||
std::unique_ptr<VulkanShader> VertexShader;
|
||||
std::unique_ptr<VulkanShader> FragmentShader;
|
||||
|
||||
private:
|
||||
FString LoadShaderCode(const FString &lumpname, const FString &defines, int version);
|
||||
};
|
|
@ -36,6 +36,7 @@ public:
|
|||
std::vector<std::unique_ptr<VulkanDescriptorSet>> Descriptors;
|
||||
std::vector<std::unique_ptr<VulkanDescriptorPool>> DescriptorPools;
|
||||
std::vector<std::unique_ptr<VulkanCommandBuffer>> CommandBuffers;
|
||||
std::vector< std::unique_ptr<VulkanSampler>> Samplers;
|
||||
} FrameDeleteList;
|
||||
|
||||
struct
|
||||
|
|
|
@ -151,7 +151,7 @@ void VulkanFrameBuffer::InitializeState()
|
|||
StreamBuffer = new VkStreamBuffer(sizeof(StreamUBO), 300);
|
||||
|
||||
mShaderManager.reset(new VkShaderManager(device));
|
||||
mSamplerManager.reset(new VkSamplerManager(device));
|
||||
mSamplerManager.reset(new VkSamplerManager(this));
|
||||
mDescriptorSetManager->Init();
|
||||
#ifdef __APPLE__
|
||||
mRenderState.reset(new VkRenderStateMolten());
|
||||
|
@ -299,10 +299,8 @@ void VulkanFrameBuffer::SetTextureFilterMode()
|
|||
{
|
||||
if (mSamplerManager)
|
||||
{
|
||||
// Destroy the texture descriptors as they used the old samplers
|
||||
VkMaterial::ResetAllDescriptors();
|
||||
|
||||
mSamplerManager->SetTextureFilterMode();
|
||||
mDescriptorSetManager->FilterModeChanged();
|
||||
mSamplerManager->FilterModeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
108
src/common/rendering/vulkan/textures/vk_pptexture.cpp
Normal file
108
src/common/rendering/vulkan/textures/vk_pptexture.cpp
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
** Vulkan backend
|
||||
** Copyright (c) 2016-2020 Magnus Norddahl
|
||||
**
|
||||
** This software is provided 'as-is', without any express or implied
|
||||
** warranty. In no event will the authors be held liable for any damages
|
||||
** arising from the use of this software.
|
||||
**
|
||||
** Permission is granted to anyone to use this software for any purpose,
|
||||
** including commercial applications, and to alter it and redistribute it
|
||||
** freely, subject to the following restrictions:
|
||||
**
|
||||
** 1. The origin of this software must not be misrepresented; you must not
|
||||
** claim that you wrote the original software. If you use this software
|
||||
** in a product, an acknowledgment in the product documentation would be
|
||||
** appreciated but is not required.
|
||||
** 2. Altered source versions must be plainly marked as such, and must not be
|
||||
** misrepresented as being the original software.
|
||||
** 3. This notice may not be removed or altered from any source distribution.
|
||||
**
|
||||
*/
|
||||
|
||||
#include "vk_pptexture.h"
|
||||
#include "vulkan/system/vk_framebuffer.h"
|
||||
#include "vulkan/system/vk_commandbuffer.h"
|
||||
|
||||
VkPPTexture::VkPPTexture(PPTexture *texture)
|
||||
{
|
||||
auto fb = GetVulkanFrameBuffer();
|
||||
|
||||
VkFormat format;
|
||||
int pixelsize;
|
||||
switch (texture->Format)
|
||||
{
|
||||
default:
|
||||
case PixelFormat::Rgba8: format = VK_FORMAT_R8G8B8A8_UNORM; pixelsize = 4; break;
|
||||
case PixelFormat::Rgba16f: format = VK_FORMAT_R16G16B16A16_SFLOAT; pixelsize = 8; break;
|
||||
case PixelFormat::R32f: format = VK_FORMAT_R32_SFLOAT; pixelsize = 4; break;
|
||||
case PixelFormat::Rg16f: format = VK_FORMAT_R16G16_SFLOAT; pixelsize = 4; break;
|
||||
case PixelFormat::Rgba16_snorm: format = VK_FORMAT_R16G16B16A16_SNORM; pixelsize = 8; break;
|
||||
}
|
||||
|
||||
ImageBuilder imgbuilder;
|
||||
imgbuilder.setFormat(format);
|
||||
imgbuilder.setSize(texture->Width, texture->Height);
|
||||
if (texture->Data)
|
||||
imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT);
|
||||
else
|
||||
imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT);
|
||||
if (!imgbuilder.isFormatSupported(fb->device))
|
||||
I_FatalError("Vulkan device does not support the image format required by a postprocess texture\n");
|
||||
TexImage.Image = imgbuilder.create(fb->device);
|
||||
TexImage.Image->SetDebugName("VkPPTexture");
|
||||
Format = format;
|
||||
|
||||
ImageViewBuilder viewbuilder;
|
||||
viewbuilder.setImage(TexImage.Image.get(), format);
|
||||
TexImage.View = viewbuilder.create(fb->device);
|
||||
TexImage.View->SetDebugName("VkPPTextureView");
|
||||
|
||||
if (texture->Data)
|
||||
{
|
||||
size_t totalsize = texture->Width * texture->Height * pixelsize;
|
||||
BufferBuilder stagingbuilder;
|
||||
stagingbuilder.setSize(totalsize);
|
||||
stagingbuilder.setUsage(VK_BUFFER_USAGE_TRANSFER_SRC_BIT, VMA_MEMORY_USAGE_CPU_ONLY);
|
||||
Staging = stagingbuilder.create(fb->device);
|
||||
Staging->SetDebugName("VkPPTextureStaging");
|
||||
|
||||
VkImageTransition barrier0;
|
||||
barrier0.addImage(&TexImage, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, true);
|
||||
barrier0.execute(fb->GetCommands()->GetTransferCommands());
|
||||
|
||||
void *data = Staging->Map(0, totalsize);
|
||||
memcpy(data, texture->Data.get(), totalsize);
|
||||
Staging->Unmap();
|
||||
|
||||
VkBufferImageCopy region = {};
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageExtent.depth = 1;
|
||||
region.imageExtent.width = texture->Width;
|
||||
region.imageExtent.height = texture->Height;
|
||||
fb->GetCommands()->GetTransferCommands()->copyBufferToImage(Staging->buffer, TexImage.Image->image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
|
||||
VkImageTransition barrier1;
|
||||
barrier1.addImage(&TexImage, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, false);
|
||||
barrier1.execute(fb->GetCommands()->GetTransferCommands());
|
||||
}
|
||||
else
|
||||
{
|
||||
VkImageTransition barrier;
|
||||
barrier.addImage(&TexImage, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, true);
|
||||
barrier.execute(fb->GetCommands()->GetTransferCommands());
|
||||
}
|
||||
}
|
||||
|
||||
VkPPTexture::~VkPPTexture()
|
||||
{
|
||||
if (auto fb = GetVulkanFrameBuffer())
|
||||
{
|
||||
if (TexImage.Image) fb->GetCommands()->FrameDeleteList.Images.push_back(std::move(TexImage.Image));
|
||||
if (TexImage.View) fb->GetCommands()->FrameDeleteList.ImageViews.push_back(std::move(TexImage.View));
|
||||
if (TexImage.DepthOnlyView) fb->GetCommands()->FrameDeleteList.ImageViews.push_back(std::move(TexImage.DepthOnlyView));
|
||||
if (TexImage.PPFramebuffer) fb->GetCommands()->FrameDeleteList.Framebuffers.push_back(std::move(TexImage.PPFramebuffer));
|
||||
if (Staging) fb->GetCommands()->FrameDeleteList.Buffers.push_back(std::move(Staging));
|
||||
}
|
||||
}
|
17
src/common/rendering/vulkan/textures/vk_pptexture.h
Normal file
17
src/common/rendering/vulkan/textures/vk_pptexture.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "hwrenderer/postprocessing/hw_postprocess.h"
|
||||
#include "vulkan/system/vk_objects.h"
|
||||
#include "vulkan/textures/vk_imagetransition.h"
|
||||
|
||||
class VkPPTexture : public PPTextureBackend
|
||||
{
|
||||
public:
|
||||
VkPPTexture(PPTexture *texture);
|
||||
~VkPPTexture();
|
||||
|
||||
VkTextureImage TexImage;
|
||||
std::unique_ptr<VulkanBuffer> Staging;
|
||||
VkFormat Format;
|
||||
};
|
|
@ -68,7 +68,6 @@ void VkRenderBuffers::BeginFrame(int width, int height, int sceneWidth, int scen
|
|||
{
|
||||
auto fb = GetVulkanFrameBuffer();
|
||||
fb->GetRenderPassManager()->RenderBuffersReset();
|
||||
fb->GetPostprocess()->RenderBuffersReset();
|
||||
}
|
||||
|
||||
if (width != mWidth || height != mHeight)
|
||||
|
|
|
@ -23,13 +23,15 @@
|
|||
#include "volk/volk.h"
|
||||
#include "c_cvars.h"
|
||||
#include "v_video.h"
|
||||
|
||||
#include "hw_cvars.h"
|
||||
#include "vulkan/system/vk_device.h"
|
||||
#include "vulkan/system/vk_builders.h"
|
||||
#include "vulkan/system/vk_framebuffer.h"
|
||||
#include "vulkan/system/vk_commandbuffer.h"
|
||||
#include "vk_samplers.h"
|
||||
#include "hw_material.h"
|
||||
#include "i_interface.h"
|
||||
#include "hwrenderer/postprocessing/hw_postprocess.h"
|
||||
|
||||
struct VkTexFilter
|
||||
{
|
||||
|
@ -37,16 +39,17 @@ struct VkTexFilter
|
|||
VkFilter magFilter;
|
||||
VkSamplerMipmapMode mipfilter;
|
||||
bool mipmapping;
|
||||
} ;
|
||||
};
|
||||
|
||||
VkTexFilter TexFilter[]={
|
||||
static VkTexFilter TexFilter[] =
|
||||
{
|
||||
{VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, false},
|
||||
{VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_NEAREST, true},
|
||||
{VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, false},
|
||||
{VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_NEAREST, true},
|
||||
{VK_FILTER_LINEAR, VK_FILTER_LINEAR, VK_SAMPLER_MIPMAP_MODE_LINEAR, true},
|
||||
{VK_FILTER_NEAREST, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_LINEAR, true},
|
||||
{VK_FILTER_LINEAR, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_LINEAR, true},
|
||||
{VK_FILTER_LINEAR, VK_FILTER_NEAREST, VK_SAMPLER_MIPMAP_MODE_LINEAR, true}
|
||||
};
|
||||
|
||||
struct VkTexClamp
|
||||
|
@ -55,31 +58,30 @@ struct VkTexClamp
|
|||
VkSamplerAddressMode clamp_v;
|
||||
};
|
||||
|
||||
VkTexClamp TexClamp[] ={
|
||||
static VkTexClamp TexClamp[] =
|
||||
{
|
||||
{ VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT },
|
||||
{ VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_REPEAT },
|
||||
{ VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE },
|
||||
{ VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE },
|
||||
};
|
||||
|
||||
VkSamplerManager::VkSamplerManager(VulkanDevice *dev)
|
||||
VkSamplerManager::VkSamplerManager(VulkanFrameBuffer* fb) : fb(fb)
|
||||
{
|
||||
vDevice = dev;
|
||||
Create();
|
||||
CreateHWSamplers();
|
||||
}
|
||||
|
||||
VkSamplerManager::~VkSamplerManager()
|
||||
{
|
||||
Destroy();
|
||||
}
|
||||
|
||||
void VkSamplerManager::SetTextureFilterMode()
|
||||
void VkSamplerManager::FilterModeChanged()
|
||||
{
|
||||
Destroy();
|
||||
Create();
|
||||
DeleteHWSamplers();
|
||||
CreateHWSamplers();
|
||||
}
|
||||
|
||||
void VkSamplerManager::Create()
|
||||
void VkSamplerManager::CreateHWSamplers()
|
||||
{
|
||||
int filter = sysCallbacks.DisableTextureFilter && sysCallbacks.DisableTextureFilter()? 0 : gl_texture_filter;
|
||||
|
||||
|
@ -99,7 +101,7 @@ void VkSamplerManager::Create()
|
|||
{
|
||||
builder.setMaxLod(0.25f);
|
||||
}
|
||||
mSamplers[i] = builder.create(vDevice);
|
||||
mSamplers[i] = builder.create(fb->device);
|
||||
mSamplers[i]->SetDebugName("VkSamplerManager.mSamplers");
|
||||
}
|
||||
{
|
||||
|
@ -109,7 +111,7 @@ void VkSamplerManager::Create()
|
|||
builder.setAddressMode(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_REPEAT);
|
||||
builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST);
|
||||
builder.setMaxLod(0.25f);
|
||||
mSamplers[CLAMP_XY_NOMIP] = builder.create(vDevice);
|
||||
mSamplers[CLAMP_XY_NOMIP] = builder.create(fb->device);
|
||||
mSamplers[CLAMP_XY_NOMIP]->SetDebugName("VkSamplerManager.mSamplers");
|
||||
}
|
||||
for (int i = CLAMP_NOFILTER; i <= CLAMP_NOFILTER_XY; i++)
|
||||
|
@ -120,7 +122,7 @@ void VkSamplerManager::Create()
|
|||
builder.setAddressMode(TexClamp[i - CLAMP_NOFILTER].clamp_u, TexClamp[i - CLAMP_NOFILTER].clamp_v, VK_SAMPLER_ADDRESS_MODE_REPEAT);
|
||||
builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST);
|
||||
builder.setMaxLod(0.25f);
|
||||
mSamplers[i] = builder.create(vDevice);
|
||||
mSamplers[i] = builder.create(fb->device);
|
||||
mSamplers[i]->SetDebugName("VkSamplerManager.mSamplers");
|
||||
}
|
||||
// CAMTEX is repeating with texture filter and no mipmap
|
||||
|
@ -131,13 +133,33 @@ void VkSamplerManager::Create()
|
|||
builder.setAddressMode(VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT);
|
||||
builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST);
|
||||
builder.setMaxLod(0.25f);
|
||||
mSamplers[CLAMP_CAMTEX] = builder.create(vDevice);
|
||||
mSamplers[CLAMP_CAMTEX] = builder.create(fb->device);
|
||||
mSamplers[CLAMP_CAMTEX]->SetDebugName("VkSamplerManager.mSamplers");
|
||||
}
|
||||
}
|
||||
|
||||
void VkSamplerManager::Destroy()
|
||||
void VkSamplerManager::DeleteHWSamplers()
|
||||
{
|
||||
for (int i = 0; i < NUMSAMPLERS; i++)
|
||||
mSamplers[i].reset();
|
||||
for (auto& sampler : mSamplers)
|
||||
{
|
||||
if (sampler)
|
||||
fb->GetCommands()->FrameDeleteList.Samplers.push_back(std::move(sampler));
|
||||
}
|
||||
}
|
||||
|
||||
VulkanSampler* VkSamplerManager::Get(PPFilterMode filter, PPWrapMode wrap)
|
||||
{
|
||||
int index = (((int)filter) << 1) | (int)wrap;
|
||||
auto& sampler = mPPSamplers[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);
|
||||
sampler->SetDebugName("VkPostprocess.mSamplers");
|
||||
return sampler.get();
|
||||
}
|
||||
|
|
|
@ -1,32 +1,29 @@
|
|||
#ifndef __VK_SAMPLERS_H
|
||||
#define __VK_SAMPLERS_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "vulkan/system/vk_objects.h"
|
||||
#include <array>
|
||||
|
||||
class VulkanDevice;
|
||||
class VulkanFrameBuffer;
|
||||
enum class PPFilterMode;
|
||||
enum class PPWrapMode;
|
||||
|
||||
class VkSamplerManager
|
||||
{
|
||||
VulkanDevice *vDevice;
|
||||
std::unique_ptr<VulkanSampler> mSamplers[NUMSAMPLERS];
|
||||
|
||||
//void UnbindAll();
|
||||
|
||||
void Create();
|
||||
void Destroy();
|
||||
|
||||
public:
|
||||
|
||||
VkSamplerManager(VulkanDevice *dev);
|
||||
VkSamplerManager(VulkanFrameBuffer* fb);
|
||||
~VkSamplerManager();
|
||||
|
||||
//uint8_t Bind(int texunit, int num, int lastval);
|
||||
void SetTextureFilterMode();
|
||||
void FilterModeChanged();
|
||||
|
||||
VulkanSampler *Get(int no) const { return mSamplers[no].get(); }
|
||||
VulkanSampler* Get(PPFilterMode filter, PPWrapMode wrap);
|
||||
|
||||
private:
|
||||
void CreateHWSamplers();
|
||||
void DeleteHWSamplers();
|
||||
|
||||
VulkanFrameBuffer* fb = nullptr;
|
||||
std::array<std::unique_ptr<VulkanSampler>, NUMSAMPLERS> mSamplers;
|
||||
std::array<std::unique_ptr<VulkanSampler>, 4> mPPSamplers;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in a new issue