2020-05-31 08:53:11 +00:00
|
|
|
/*
|
|
|
|
** 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_renderpass.h"
|
|
|
|
#include "vk_renderbuffers.h"
|
|
|
|
#include "vk_renderstate.h"
|
|
|
|
#include "vulkan/textures/vk_samplers.h"
|
|
|
|
#include "vulkan/shaders/vk_shader.h"
|
|
|
|
#include "vulkan/system/vk_builders.h"
|
|
|
|
#include "vulkan/system/vk_framebuffer.h"
|
|
|
|
#include "vulkan/system/vk_buffers.h"
|
|
|
|
#include "flatvertices.h"
|
|
|
|
#include "hw_viewpointuniforms.h"
|
|
|
|
#include "v_2ddrawer.h"
|
|
|
|
|
|
|
|
VkRenderPassManager::VkRenderPassManager()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
VkRenderPassManager::~VkRenderPassManager()
|
|
|
|
{
|
|
|
|
DynamicSet.reset(); // Needed since it must come before destruction of DynamicDescriptorPool
|
|
|
|
}
|
|
|
|
|
|
|
|
void VkRenderPassManager::Init()
|
|
|
|
{
|
|
|
|
CreateDynamicSetLayout();
|
|
|
|
CreateDescriptorPool();
|
|
|
|
CreateDynamicSet();
|
|
|
|
CreateNullTexture();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VkRenderPassManager::RenderBuffersReset()
|
|
|
|
{
|
|
|
|
RenderPassSetup.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VkRenderPassManager::TextureSetPoolReset()
|
|
|
|
{
|
|
|
|
if (auto fb = GetVulkanFrameBuffer())
|
|
|
|
{
|
|
|
|
auto &deleteList = fb->FrameDeleteList;
|
|
|
|
|
|
|
|
for (auto &desc : TextureDescriptorPools)
|
|
|
|
{
|
|
|
|
deleteList.DescriptorPools.push_back(std::move(desc));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
NullTextureDescriptorSet.reset();
|
|
|
|
TextureDescriptorPools.clear();
|
|
|
|
TextureDescriptorSetsLeft = 0;
|
|
|
|
TextureDescriptorsLeft = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkRenderPassSetup *VkRenderPassManager::GetRenderPass(const VkRenderPassKey &key)
|
|
|
|
{
|
|
|
|
auto &item = RenderPassSetup[key];
|
|
|
|
if (!item)
|
|
|
|
item.reset(new VkRenderPassSetup(key));
|
|
|
|
return item.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
int VkRenderPassManager::GetVertexFormat(int numBindingPoints, int numAttributes, size_t stride, const FVertexBufferAttribute *attrs)
|
|
|
|
{
|
|
|
|
for (size_t i = 0; i < VertexFormats.size(); i++)
|
|
|
|
{
|
|
|
|
const auto &f = VertexFormats[i];
|
|
|
|
if (f.Attrs.size() == (size_t)numAttributes && f.NumBindingPoints == numBindingPoints && f.Stride == stride)
|
|
|
|
{
|
|
|
|
bool matches = true;
|
|
|
|
for (int j = 0; j < numAttributes; j++)
|
|
|
|
{
|
|
|
|
if (memcmp(&f.Attrs[j], &attrs[j], sizeof(FVertexBufferAttribute)) != 0)
|
|
|
|
{
|
|
|
|
matches = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (matches)
|
|
|
|
return (int)i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VkVertexFormat fmt;
|
|
|
|
fmt.NumBindingPoints = numBindingPoints;
|
|
|
|
fmt.Stride = stride;
|
|
|
|
fmt.UseVertexData = 0;
|
|
|
|
for (int j = 0; j < numAttributes; j++)
|
|
|
|
{
|
|
|
|
if (attrs[j].location == VATTR_COLOR)
|
|
|
|
fmt.UseVertexData |= 1;
|
|
|
|
else if (attrs[j].location == VATTR_NORMAL)
|
|
|
|
fmt.UseVertexData |= 2;
|
|
|
|
fmt.Attrs.push_back(attrs[j]);
|
|
|
|
}
|
|
|
|
VertexFormats.push_back(fmt);
|
|
|
|
return (int)VertexFormats.size() - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
VkVertexFormat *VkRenderPassManager::GetVertexFormat(int index)
|
|
|
|
{
|
|
|
|
return &VertexFormats[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
void VkRenderPassManager::CreateDynamicSetLayout()
|
|
|
|
{
|
|
|
|
DescriptorSetLayoutBuilder builder;
|
|
|
|
builder.addBinding(0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
|
|
builder.addBinding(1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
|
|
builder.addBinding(2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
|
|
builder.addBinding(3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 1, VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
|
|
builder.addBinding(4, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
|
|
DynamicSetLayout = builder.create(GetVulkanFrameBuffer()->device);
|
|
|
|
DynamicSetLayout->SetDebugName("VkRenderPassManager.DynamicSetLayout");
|
|
|
|
}
|
|
|
|
|
|
|
|
VulkanDescriptorSetLayout *VkRenderPassManager::GetTextureSetLayout(int numLayers)
|
|
|
|
{
|
|
|
|
if (TextureSetLayouts.size() < (size_t)numLayers)
|
|
|
|
TextureSetLayouts.resize(numLayers);
|
|
|
|
|
|
|
|
auto &layout = TextureSetLayouts[numLayers - 1];
|
|
|
|
if (layout)
|
|
|
|
return layout.get();
|
|
|
|
|
|
|
|
DescriptorSetLayoutBuilder builder;
|
|
|
|
for (int i = 0; i < numLayers; i++)
|
|
|
|
{
|
|
|
|
builder.addBinding(i, VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1, VK_SHADER_STAGE_FRAGMENT_BIT);
|
|
|
|
}
|
|
|
|
layout = builder.create(GetVulkanFrameBuffer()->device);
|
|
|
|
layout->SetDebugName("VkRenderPassManager.TextureSetLayout");
|
|
|
|
return layout.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
VulkanPipelineLayout* VkRenderPassManager::GetPipelineLayout(int numLayers)
|
|
|
|
{
|
|
|
|
if (PipelineLayouts.size() <= (size_t)numLayers)
|
|
|
|
PipelineLayouts.resize(numLayers + 1);
|
|
|
|
|
|
|
|
auto &layout = PipelineLayouts[numLayers];
|
|
|
|
if (layout)
|
|
|
|
return layout.get();
|
|
|
|
|
|
|
|
PipelineLayoutBuilder builder;
|
|
|
|
builder.addSetLayout(DynamicSetLayout.get());
|
|
|
|
if (numLayers != 0)
|
|
|
|
builder.addSetLayout(GetTextureSetLayout(numLayers));
|
|
|
|
builder.addPushConstantRange(VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT, 0, sizeof(PushConstants));
|
|
|
|
layout = builder.create(GetVulkanFrameBuffer()->device);
|
|
|
|
layout->SetDebugName("VkRenderPassManager.PipelineLayout");
|
|
|
|
return layout.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VkRenderPassManager::CreateDescriptorPool()
|
|
|
|
{
|
|
|
|
DescriptorPoolBuilder builder;
|
|
|
|
builder.addPoolSize(VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, 3);
|
|
|
|
builder.addPoolSize(VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, 1);
|
|
|
|
builder.addPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, 1);
|
|
|
|
builder.setMaxSets(1);
|
|
|
|
DynamicDescriptorPool = builder.create(GetVulkanFrameBuffer()->device);
|
|
|
|
DynamicDescriptorPool->SetDebugName("VkRenderPassManager.DynamicDescriptorPool");
|
|
|
|
}
|
|
|
|
|
|
|
|
void VkRenderPassManager::CreateDynamicSet()
|
|
|
|
{
|
|
|
|
DynamicSet = DynamicDescriptorPool->allocate(DynamicSetLayout.get());
|
|
|
|
if (!DynamicSet)
|
|
|
|
I_FatalError("CreateDynamicSet failed.\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
void VkRenderPassManager::CreateNullTexture()
|
|
|
|
{
|
|
|
|
auto fb = GetVulkanFrameBuffer();
|
|
|
|
|
|
|
|
ImageBuilder imgbuilder;
|
|
|
|
imgbuilder.setFormat(VK_FORMAT_R8G8B8A8_UNORM);
|
|
|
|
imgbuilder.setSize(1, 1);
|
|
|
|
imgbuilder.setUsage(VK_IMAGE_USAGE_SAMPLED_BIT);
|
|
|
|
NullTexture = imgbuilder.create(fb->device);
|
|
|
|
NullTexture->SetDebugName("VkRenderPassManager.NullTexture");
|
|
|
|
|
|
|
|
ImageViewBuilder viewbuilder;
|
|
|
|
viewbuilder.setImage(NullTexture.get(), VK_FORMAT_R8G8B8A8_UNORM);
|
|
|
|
NullTextureView = viewbuilder.create(fb->device);
|
|
|
|
NullTextureView->SetDebugName("VkRenderPassManager.NullTextureView");
|
|
|
|
|
|
|
|
PipelineBarrier barrier;
|
|
|
|
barrier.addImage(NullTexture.get(), VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, 0, VK_ACCESS_SHADER_READ_BIT, VK_IMAGE_ASPECT_COLOR_BIT);
|
|
|
|
barrier.execute(fb->GetTransferCommands(), VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT);
|
|
|
|
}
|
|
|
|
|
|
|
|
VulkanDescriptorSet* VkRenderPassManager::GetNullTextureDescriptorSet()
|
|
|
|
{
|
|
|
|
if (!NullTextureDescriptorSet)
|
|
|
|
{
|
|
|
|
NullTextureDescriptorSet = AllocateTextureDescriptorSet(SHADER_MIN_REQUIRED_TEXTURE_LAYERS);
|
|
|
|
|
|
|
|
auto fb = GetVulkanFrameBuffer();
|
|
|
|
WriteDescriptors update;
|
|
|
|
for (int i = 0; i < SHADER_MIN_REQUIRED_TEXTURE_LAYERS; i++)
|
|
|
|
{
|
|
|
|
update.addCombinedImageSampler(NullTextureDescriptorSet.get(), i, NullTextureView.get(), fb->GetSamplerManager()->Get(CLAMP_XY_NOMIP), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
|
|
|
}
|
|
|
|
update.updateSets(fb->device);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NullTextureDescriptorSet.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
VulkanImageView* VkRenderPassManager::GetNullTextureView()
|
|
|
|
{
|
|
|
|
return NullTextureView.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
void VkRenderPassManager::UpdateDynamicSet()
|
|
|
|
{
|
|
|
|
auto fb = GetVulkanFrameBuffer();
|
|
|
|
|
|
|
|
// In some rare cases drawing commands may already have been created before VulkanFrameBuffer::BeginFrame is called.
|
|
|
|
// Make sure there there are no active command buffers using DynamicSet when we update it:
|
|
|
|
fb->GetRenderState()->EndRenderPass();
|
|
|
|
fb->WaitForCommands(false);
|
|
|
|
|
|
|
|
WriteDescriptors update;
|
|
|
|
update.addBuffer(DynamicSet.get(), 0, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->ViewpointUBO->mBuffer.get(), 0, sizeof(HWViewpointUniforms));
|
|
|
|
update.addBuffer(DynamicSet.get(), 1, VK_DESCRIPTOR_TYPE_STORAGE_BUFFER, fb->LightBufferSSO->mBuffer.get());
|
|
|
|
update.addBuffer(DynamicSet.get(), 2, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->MatrixBuffer->UniformBuffer->mBuffer.get(), 0, sizeof(MatricesUBO));
|
|
|
|
update.addBuffer(DynamicSet.get(), 3, VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC, fb->StreamBuffer->UniformBuffer->mBuffer.get(), 0, sizeof(StreamUBO));
|
|
|
|
update.addCombinedImageSampler(DynamicSet.get(), 4, fb->GetBuffers()->Shadowmap.View.get(), fb->GetBuffers()->ShadowmapSampler.get(), VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
|
|
|
update.updateSets(fb->device);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<VulkanDescriptorSet> VkRenderPassManager::AllocateTextureDescriptorSet(int numLayers)
|
|
|
|
{
|
|
|
|
if (TextureDescriptorSetsLeft == 0 || TextureDescriptorsLeft < numLayers)
|
|
|
|
{
|
|
|
|
TextureDescriptorSetsLeft = 1000;
|
|
|
|
TextureDescriptorsLeft = 2000;
|
|
|
|
|
|
|
|
DescriptorPoolBuilder builder;
|
|
|
|
builder.addPoolSize(VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, TextureDescriptorsLeft);
|
|
|
|
builder.setMaxSets(TextureDescriptorSetsLeft);
|
|
|
|
TextureDescriptorPools.push_back(builder.create(GetVulkanFrameBuffer()->device));
|
|
|
|
TextureDescriptorPools.back()->SetDebugName("VkRenderPassManager.TextureDescriptorPool");
|
|
|
|
}
|
|
|
|
|
|
|
|
TextureDescriptorSetsLeft--;
|
|
|
|
TextureDescriptorsLeft -= numLayers;
|
|
|
|
return TextureDescriptorPools.back()->allocate(GetTextureSetLayout(numLayers));
|
|
|
|
}
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
VkRenderPassSetup::VkRenderPassSetup(const VkRenderPassKey &key) : PassKey(key)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<VulkanRenderPass> VkRenderPassSetup::CreateRenderPass(int clearTargets)
|
|
|
|
{
|
|
|
|
auto buffers = GetVulkanFrameBuffer()->GetBuffers();
|
|
|
|
|
|
|
|
VkFormat drawBufferFormats[] = { VK_FORMAT_R16G16B16A16_SFLOAT, VK_FORMAT_R8G8B8A8_UNORM, VK_FORMAT_A2R10G10B10_UNORM_PACK32 };
|
|
|
|
|
|
|
|
RenderPassBuilder builder;
|
|
|
|
|
|
|
|
builder.addAttachment(
|
|
|
|
PassKey.DrawBufferFormat, (VkSampleCountFlagBits)PassKey.Samples,
|
|
|
|
(clearTargets & CT_Color) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE,
|
|
|
|
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
|
|
|
|
|
|
|
for (int i = 1; i < PassKey.DrawBuffers; i++)
|
|
|
|
{
|
|
|
|
builder.addAttachment(
|
|
|
|
drawBufferFormats[i], buffers->GetSceneSamples(),
|
|
|
|
(clearTargets & CT_Color) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE,
|
|
|
|
VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
|
|
|
}
|
|
|
|
if (PassKey.DepthStencil)
|
|
|
|
{
|
|
|
|
builder.addDepthStencilAttachment(
|
|
|
|
buffers->SceneDepthStencilFormat, PassKey.DrawBufferFormat == VK_FORMAT_R8G8B8A8_UNORM ? VK_SAMPLE_COUNT_1_BIT : buffers->GetSceneSamples(),
|
|
|
|
(clearTargets & CT_Depth) ? VK_ATTACHMENT_LOAD_OP_CLEAR : VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE,
|
|
|
|
(clearTargets & CT_Stencil) ? VK_ATTACHMENT_LOAD_OP_CLEAR : 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();
|
|
|
|
for (int i = 0; i < PassKey.DrawBuffers; i++)
|
|
|
|
builder.addSubpassColorAttachmentRef(i, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
|
|
|
|
if (PassKey.DepthStencil)
|
|
|
|
{
|
|
|
|
builder.addSubpassDepthStencilAttachmentRef(PassKey.DrawBuffers, 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_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);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
auto renderpass = builder.create(GetVulkanFrameBuffer()->device);
|
|
|
|
renderpass->SetDebugName("VkRenderPassSetup.RenderPass");
|
|
|
|
return renderpass;
|
|
|
|
}
|
|
|
|
|
|
|
|
VulkanRenderPass *VkRenderPassSetup::GetRenderPass(int clearTargets)
|
|
|
|
{
|
|
|
|
if (!RenderPasses[clearTargets])
|
|
|
|
RenderPasses[clearTargets] = CreateRenderPass(clearTargets);
|
|
|
|
return RenderPasses[clearTargets].get();
|
|
|
|
}
|
|
|
|
|
|
|
|
VulkanPipeline *VkRenderPassSetup::GetPipeline(const VkPipelineKey &key)
|
|
|
|
{
|
|
|
|
auto &item = Pipelines[key];
|
|
|
|
if (!item)
|
|
|
|
item = CreatePipeline(key);
|
|
|
|
return item.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
std::unique_ptr<VulkanPipeline> VkRenderPassSetup::CreatePipeline(const VkPipelineKey &key)
|
|
|
|
{
|
|
|
|
auto fb = GetVulkanFrameBuffer();
|
|
|
|
GraphicsPipelineBuilder builder;
|
|
|
|
|
|
|
|
VkShaderProgram *program;
|
|
|
|
if (key.SpecialEffect != EFF_NONE)
|
|
|
|
{
|
|
|
|
program = fb->GetShaderManager()->GetEffect(key.SpecialEffect, PassKey.DrawBuffers > 1 ? GBUFFER_PASS : NORMAL_PASS);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
program = fb->GetShaderManager()->Get(key.EffectState, key.AlphaTest, PassKey.DrawBuffers > 1 ? GBUFFER_PASS : NORMAL_PASS);
|
|
|
|
}
|
|
|
|
builder.addVertexShader(program->vert.get());
|
|
|
|
builder.addFragmentShader(program->frag.get());
|
|
|
|
|
|
|
|
const VkVertexFormat &vfmt = *fb->GetRenderPassManager()->GetVertexFormat(key.VertexFormat);
|
|
|
|
|
|
|
|
for (int i = 0; i < vfmt.NumBindingPoints; i++)
|
|
|
|
builder.addVertexBufferBinding(i, vfmt.Stride);
|
|
|
|
|
|
|
|
const static VkFormat vkfmts[] = {
|
|
|
|
VK_FORMAT_R32G32B32A32_SFLOAT,
|
|
|
|
VK_FORMAT_R32G32B32_SFLOAT,
|
|
|
|
VK_FORMAT_R32G32_SFLOAT,
|
|
|
|
VK_FORMAT_R32_SFLOAT,
|
|
|
|
VK_FORMAT_R8G8B8A8_UNORM,
|
|
|
|
VK_FORMAT_A2B10G10R10_SNORM_PACK32
|
|
|
|
};
|
|
|
|
|
|
|
|
bool inputLocations[6] = { false, false, false, false, false, false };
|
|
|
|
|
|
|
|
for (size_t i = 0; i < vfmt.Attrs.size(); i++)
|
|
|
|
{
|
|
|
|
const auto &attr = vfmt.Attrs[i];
|
|
|
|
builder.addVertexAttribute(attr.location, attr.binding, vkfmts[attr.format], attr.offset);
|
|
|
|
inputLocations[attr.location] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Vulkan requires an attribute binding for each location specified in the shader
|
|
|
|
for (int i = 0; i < 6; i++)
|
|
|
|
{
|
|
|
|
if (!inputLocations[i])
|
|
|
|
builder.addVertexAttribute(i, 0, VK_FORMAT_R32G32B32_SFLOAT, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
builder.addDynamicState(VK_DYNAMIC_STATE_VIEWPORT);
|
|
|
|
builder.addDynamicState(VK_DYNAMIC_STATE_SCISSOR);
|
|
|
|
// builder.addDynamicState(VK_DYNAMIC_STATE_LINE_WIDTH);
|
|
|
|
builder.addDynamicState(VK_DYNAMIC_STATE_DEPTH_BIAS);
|
|
|
|
// builder.addDynamicState(VK_DYNAMIC_STATE_BLEND_CONSTANTS);
|
|
|
|
// builder.addDynamicState(VK_DYNAMIC_STATE_DEPTH_BOUNDS);
|
|
|
|
// builder.addDynamicState(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK);
|
|
|
|
// builder.addDynamicState(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK);
|
|
|
|
builder.addDynamicState(VK_DYNAMIC_STATE_STENCIL_REFERENCE);
|
|
|
|
|
|
|
|
// Note: the actual values are ignored since we use dynamic viewport+scissor states
|
|
|
|
builder.setViewport(0.0f, 0.0f, 320.0f, 200.0f);
|
2020-05-03 07:31:37 +00:00
|
|
|
builder.setScissor(0, 0, 320, 200);
|
2020-05-31 08:53:11 +00:00
|
|
|
|
|
|
|
static const VkPrimitiveTopology vktopology[] = {
|
|
|
|
VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
|
|
|
|
VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
|
|
|
|
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
|
|
|
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_FAN,
|
|
|
|
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP
|
|
|
|
};
|
|
|
|
|
|
|
|
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 };
|
|
|
|
|
|
|
|
builder.setTopology(vktopology[key.DrawType]);
|
|
|
|
builder.setDepthStencilEnable(key.DepthTest, key.DepthWrite, key.StencilTest);
|
|
|
|
builder.setDepthFunc(depthfunc2vk[key.DepthFunc]);
|
|
|
|
builder.setDepthClampEnable(key.DepthClamp);
|
|
|
|
builder.setDepthBias(key.DepthBias, 0.0f, 0.0f, 0.0f);
|
|
|
|
|
|
|
|
// Note: CCW and CW is intentionally swapped here because the vulkan and opengl coordinate systems differ.
|
|
|
|
// main.vp addresses this by patching up gl_Position.z, which has the side effect of flipping the sign of the front face calculations.
|
|
|
|
builder.setCull(key.CullMode == Cull_None ? VK_CULL_MODE_NONE : VK_CULL_MODE_BACK_BIT, key.CullMode == Cull_CW ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_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(key.RenderStyle);
|
|
|
|
builder.setSubpassColorAttachmentCount(PassKey.DrawBuffers);
|
|
|
|
builder.setRasterizationSamples((VkSampleCountFlagBits)PassKey.Samples);
|
|
|
|
|
|
|
|
builder.setLayout(fb->GetRenderPassManager()->GetPipelineLayout(key.NumTextureLayers));
|
|
|
|
builder.setRenderPass(GetRenderPass(0));
|
|
|
|
auto pipeline = builder.create(fb->device);
|
|
|
|
pipeline->SetDebugName("VkRenderPassSetup.Pipeline");
|
|
|
|
return pipeline;
|
|
|
|
}
|