2019-10-05 09:50:14 +00:00
|
|
|
/*
|
|
|
|
* Created on: Oct 3, 2019
|
|
|
|
|
|
|
|
Copyright 2019 flyinghead
|
|
|
|
|
|
|
|
This file is part of Flycast.
|
|
|
|
|
|
|
|
Flycast is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
Flycast is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with Flycast. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "vulkan.h"
|
|
|
|
#include "shaders.h"
|
|
|
|
#include "texture.h"
|
2019-11-26 09:42:44 +00:00
|
|
|
#include "utils.h"
|
2019-11-29 18:28:22 +00:00
|
|
|
#include "vulkan_context.h"
|
2022-03-12 16:56:46 +00:00
|
|
|
#include "desc_set.h"
|
2021-11-04 08:13:47 +00:00
|
|
|
#include <array>
|
2022-03-13 10:39:30 +00:00
|
|
|
#include <unordered_map>
|
2019-10-05 09:50:14 +00:00
|
|
|
|
|
|
|
class DescriptorSets
|
|
|
|
{
|
|
|
|
public:
|
2022-03-12 16:56:46 +00:00
|
|
|
void init(SamplerManager* samplerManager, vk::PipelineLayout pipelineLayout, vk::DescriptorSetLayout perFrameLayout, vk::DescriptorSetLayout perPolyLayout)
|
2019-10-05 09:50:14 +00:00
|
|
|
{
|
2019-10-09 19:16:12 +00:00
|
|
|
this->samplerManager = samplerManager;
|
|
|
|
this->pipelineLayout = pipelineLayout;
|
2022-03-12 16:56:46 +00:00
|
|
|
perFrameAlloc.setLayout(perFrameLayout);
|
|
|
|
perPolyAlloc.setLayout(perPolyLayout);
|
2019-10-05 09:50:14 +00:00
|
|
|
|
2019-10-09 19:16:12 +00:00
|
|
|
}
|
2022-03-12 16:56:46 +00:00
|
|
|
void updateUniforms(vk::Buffer buffer, u32 vertexUniformOffset, u32 fragmentUniformOffset, vk::ImageView fogImageView, vk::ImageView paletteImageView)
|
2019-10-05 09:50:14 +00:00
|
|
|
{
|
2022-03-12 16:56:46 +00:00
|
|
|
if (!perFrameDescSet)
|
|
|
|
perFrameDescSet = perFrameAlloc.alloc();
|
2020-12-15 14:09:42 +00:00
|
|
|
|
2019-10-05 09:50:14 +00:00
|
|
|
std::vector<vk::DescriptorBufferInfo> bufferInfos;
|
2021-03-13 12:47:38 +00:00
|
|
|
bufferInfos.emplace_back(buffer, vertexUniformOffset, sizeof(VertexShaderUniforms));
|
|
|
|
bufferInfos.emplace_back(buffer, fragmentUniformOffset, sizeof(FragmentShaderUniforms));
|
2019-10-06 15:02:17 +00:00
|
|
|
|
2019-10-05 09:50:14 +00:00
|
|
|
std::vector<vk::WriteDescriptorSet> writeDescriptorSets;
|
2022-10-06 16:02:01 +00:00
|
|
|
writeDescriptorSets.emplace_back(perFrameDescSet, 0, 0, vk::DescriptorType::eUniformBuffer, nullptr, bufferInfos[0]);
|
|
|
|
writeDescriptorSets.emplace_back(perFrameDescSet, 1, 0, vk::DescriptorType::eUniformBuffer, nullptr, bufferInfos[1]);
|
2019-10-06 15:02:17 +00:00
|
|
|
if (fogImageView)
|
|
|
|
{
|
|
|
|
TSP fogTsp = {};
|
|
|
|
fogTsp.FilterMode = 1;
|
|
|
|
fogTsp.ClampU = 1;
|
|
|
|
fogTsp.ClampV = 1;
|
2019-10-09 19:16:12 +00:00
|
|
|
vk::Sampler fogSampler = samplerManager->GetSampler(fogTsp);
|
2019-11-13 19:08:14 +00:00
|
|
|
static vk::DescriptorImageInfo imageInfo;
|
|
|
|
imageInfo = { fogSampler, fogImageView, vk::ImageLayout::eShaderReadOnlyOptimal };
|
2022-10-06 16:02:01 +00:00
|
|
|
writeDescriptorSets.emplace_back(perFrameDescSet, 2, 0, vk::DescriptorType::eCombinedImageSampler, imageInfo);
|
2019-10-06 15:02:17 +00:00
|
|
|
}
|
2020-07-08 16:17:15 +00:00
|
|
|
if (paletteImageView)
|
|
|
|
{
|
|
|
|
TSP palTsp = {};
|
|
|
|
palTsp.FilterMode = 0;
|
|
|
|
palTsp.ClampU = 1;
|
|
|
|
palTsp.ClampV = 1;
|
|
|
|
vk::Sampler palSampler = samplerManager->GetSampler(palTsp);
|
|
|
|
static vk::DescriptorImageInfo imageInfo;
|
|
|
|
imageInfo = { palSampler, paletteImageView, vk::ImageLayout::eShaderReadOnlyOptimal };
|
2022-10-06 16:02:01 +00:00
|
|
|
writeDescriptorSets.emplace_back(perFrameDescSet, 3, 0, vk::DescriptorType::eCombinedImageSampler, imageInfo);
|
2020-07-08 16:17:15 +00:00
|
|
|
}
|
2022-03-12 16:56:46 +00:00
|
|
|
getContext()->GetDevice().updateDescriptorSets(writeDescriptorSets, nullptr);
|
2019-10-05 09:50:14 +00:00
|
|
|
}
|
|
|
|
|
2022-03-12 16:56:46 +00:00
|
|
|
void bindPerPolyDescriptorSets(vk::CommandBuffer cmdBuffer, const PolyParam& poly, int polyNumber, vk::Buffer buffer,
|
2023-10-09 19:09:03 +00:00
|
|
|
vk::DeviceSize uniformOffset, vk::DeviceSize lightOffset, bool punchThrough)
|
2019-10-05 09:50:14 +00:00
|
|
|
{
|
2022-03-13 10:39:30 +00:00
|
|
|
vk::DescriptorSet perPolyDescSet;
|
|
|
|
auto it = perPolyDescSets.find(&poly);
|
|
|
|
if (it == perPolyDescSets.end())
|
2019-10-05 09:50:14 +00:00
|
|
|
{
|
2022-03-13 10:39:30 +00:00
|
|
|
perPolyDescSet = perPolyAlloc.alloc();
|
|
|
|
std::vector<vk::WriteDescriptorSet> writeDescriptorSets;
|
2019-10-05 09:50:14 +00:00
|
|
|
|
2022-03-13 10:39:30 +00:00
|
|
|
vk::DescriptorImageInfo imageInfo;
|
|
|
|
if (poly.texture != nullptr)
|
|
|
|
{
|
2023-10-09 19:09:03 +00:00
|
|
|
imageInfo = vk::DescriptorImageInfo(samplerManager->GetSampler(poly.tsp, punchThrough),
|
2022-03-13 10:39:30 +00:00
|
|
|
((Texture *)poly.texture)->GetReadOnlyImageView(), vk::ImageLayout::eShaderReadOnlyOptimal);
|
2022-10-06 16:02:01 +00:00
|
|
|
writeDescriptorSets.emplace_back(perPolyDescSet, 0, 0, vk::DescriptorType::eCombinedImageSampler, imageInfo);
|
2022-03-13 10:39:30 +00:00
|
|
|
}
|
2022-03-12 16:56:46 +00:00
|
|
|
|
2022-03-13 10:39:30 +00:00
|
|
|
vk::DescriptorBufferInfo uniBufferInfo;
|
|
|
|
vk::DescriptorBufferInfo lightBufferInfo;
|
|
|
|
if (poly.isNaomi2())
|
2022-03-12 16:56:46 +00:00
|
|
|
{
|
2022-03-13 10:39:30 +00:00
|
|
|
const vk::DeviceSize uniformAlignment = VulkanContext::Instance()->GetUniformBufferAlignment();
|
|
|
|
size_t size = sizeof(N2VertexShaderUniforms) + align(sizeof(N2VertexShaderUniforms), uniformAlignment);
|
|
|
|
uniBufferInfo = vk::DescriptorBufferInfo{ buffer, uniformOffset + polyNumber * size, sizeof(N2VertexShaderUniforms) };
|
2022-10-06 16:02:01 +00:00
|
|
|
writeDescriptorSets.emplace_back(perPolyDescSet, 2, 0, vk::DescriptorType::eUniformBuffer, nullptr, uniBufferInfo);
|
2022-03-13 10:39:30 +00:00
|
|
|
|
2022-05-17 14:36:34 +00:00
|
|
|
size = sizeof(N2LightModel) + align(sizeof(N2LightModel), uniformAlignment);
|
2023-01-27 10:16:25 +00:00
|
|
|
lightBufferInfo = vk::DescriptorBufferInfo{ buffer, lightOffset + poly.lightModel * size, sizeof(N2LightModel) };
|
2022-10-06 16:02:01 +00:00
|
|
|
writeDescriptorSets.emplace_back(perPolyDescSet, 3, 0, vk::DescriptorType::eUniformBuffer, nullptr, lightBufferInfo);
|
2022-03-12 16:56:46 +00:00
|
|
|
}
|
2019-10-05 09:50:14 +00:00
|
|
|
|
2022-03-13 10:39:30 +00:00
|
|
|
getContext()->GetDevice().updateDescriptorSets(writeDescriptorSets, nullptr);
|
|
|
|
perPolyDescSets[&poly] = perPolyDescSet;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
perPolyDescSet = it->second;
|
2022-10-06 16:02:01 +00:00
|
|
|
cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 1, perPolyDescSet, nullptr);
|
2019-10-05 09:50:14 +00:00
|
|
|
}
|
|
|
|
|
2022-03-12 16:56:46 +00:00
|
|
|
void bindPerPolyDescriptorSets(vk::CommandBuffer cmdBuffer, const ModifierVolumeParam& mvParam, int polyNumber, vk::Buffer buffer,
|
|
|
|
vk::DeviceSize uniformOffset)
|
2019-10-05 09:50:14 +00:00
|
|
|
{
|
2022-03-12 16:56:46 +00:00
|
|
|
if (!mvParam.isNaomi2())
|
|
|
|
return;
|
2022-03-13 10:39:30 +00:00
|
|
|
vk::DescriptorSet perPolyDescSet;
|
|
|
|
auto it = perPolyDescSets.find(&mvParam);
|
|
|
|
if (it == perPolyDescSets.end())
|
|
|
|
{
|
|
|
|
perPolyDescSet = perPolyAlloc.alloc();
|
2022-03-12 16:56:46 +00:00
|
|
|
|
2022-03-13 10:39:30 +00:00
|
|
|
const vk::DeviceSize uniformAlignment = VulkanContext::Instance()->GetUniformBufferAlignment();
|
|
|
|
size_t size = sizeof(N2VertexShaderUniforms) + align(sizeof(N2VertexShaderUniforms), uniformAlignment);
|
|
|
|
vk::DescriptorBufferInfo uniBufferInfo{ buffer, uniformOffset + polyNumber * size, sizeof(N2VertexShaderUniforms) };
|
2022-10-06 16:02:01 +00:00
|
|
|
vk::WriteDescriptorSet writeDescriptorSet(perPolyDescSet, 2, 0, vk::DescriptorType::eUniformBuffer, nullptr, uniBufferInfo);
|
2022-03-12 16:56:46 +00:00
|
|
|
|
2022-10-06 16:02:01 +00:00
|
|
|
getContext()->GetDevice().updateDescriptorSets(writeDescriptorSet, nullptr);
|
2022-03-13 10:39:30 +00:00
|
|
|
perPolyDescSets[&mvParam] = perPolyDescSet;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
perPolyDescSet = it->second;
|
2022-10-06 16:02:01 +00:00
|
|
|
cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 1, perPolyDescSet, nullptr);
|
2019-10-05 09:50:14 +00:00
|
|
|
}
|
|
|
|
|
2022-03-12 16:56:46 +00:00
|
|
|
void bindPerFrameDescriptorSets(vk::CommandBuffer cmdBuffer)
|
2019-10-05 09:50:14 +00:00
|
|
|
{
|
2022-10-06 16:02:01 +00:00
|
|
|
cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, pipelineLayout, 0, perFrameDescSet, nullptr);
|
2019-10-05 09:50:14 +00:00
|
|
|
}
|
|
|
|
|
2022-03-13 10:39:30 +00:00
|
|
|
void nextFrame()
|
2022-03-12 16:56:46 +00:00
|
|
|
{
|
|
|
|
perFrameAlloc.nextFrame();
|
|
|
|
perPolyAlloc.nextFrame();
|
|
|
|
perFrameDescSet = vk::DescriptorSet{};
|
2022-03-13 10:39:30 +00:00
|
|
|
perPolyDescSets.clear();
|
2022-03-12 16:56:46 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void term()
|
2019-10-05 09:50:14 +00:00
|
|
|
{
|
2022-03-12 16:56:46 +00:00
|
|
|
perFrameAlloc.term();
|
|
|
|
perPolyAlloc.term();
|
2019-10-05 09:50:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2022-03-12 16:56:46 +00:00
|
|
|
VulkanContext *getContext() const { return VulkanContext::Instance(); }
|
2019-10-05 09:50:14 +00:00
|
|
|
|
2019-10-09 19:16:12 +00:00
|
|
|
vk::PipelineLayout pipelineLayout;
|
2022-03-12 16:56:46 +00:00
|
|
|
DynamicDescSetAlloc perFrameAlloc;
|
|
|
|
DynamicDescSetAlloc perPolyAlloc;
|
|
|
|
vk::DescriptorSet perFrameDescSet = {};
|
2022-03-13 10:39:30 +00:00
|
|
|
std::unordered_map<const void *, vk::DescriptorSet> perPolyDescSets;
|
2019-10-06 10:24:07 +00:00
|
|
|
|
2021-01-09 17:16:39 +00:00
|
|
|
SamplerManager* samplerManager = nullptr;
|
2019-10-05 09:50:14 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class PipelineManager
|
|
|
|
{
|
|
|
|
public:
|
2019-11-10 09:16:18 +00:00
|
|
|
virtual ~PipelineManager() = default;
|
2019-10-09 19:16:12 +00:00
|
|
|
|
2019-11-29 18:28:22 +00:00
|
|
|
void Init(ShaderManager *shaderManager, vk::RenderPass renderPass)
|
2019-10-05 09:50:14 +00:00
|
|
|
{
|
2019-10-09 19:16:12 +00:00
|
|
|
this->shaderManager = shaderManager;
|
|
|
|
|
2019-10-12 11:47:25 +00:00
|
|
|
if (!perFrameLayout)
|
|
|
|
{
|
|
|
|
// Descriptor set and pipeline layout
|
2022-10-06 16:02:01 +00:00
|
|
|
std::array<vk::DescriptorSetLayoutBinding, 4> perFrameBindings = {
|
|
|
|
vk::DescriptorSetLayoutBinding(0, vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eVertex), // vertex uniforms
|
|
|
|
vk::DescriptorSetLayoutBinding(1, vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eFragment), // fragment uniforms
|
|
|
|
vk::DescriptorSetLayoutBinding(2, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment),// fog texture
|
|
|
|
vk::DescriptorSetLayoutBinding(3, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment),// palette texture
|
2019-10-12 11:47:25 +00:00
|
|
|
};
|
2022-10-06 16:02:01 +00:00
|
|
|
std::array<vk::DescriptorSetLayoutBinding, 3> perPolyBindings = {
|
|
|
|
vk::DescriptorSetLayoutBinding(0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment),// texture
|
|
|
|
vk::DescriptorSetLayoutBinding(2, vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eVertex), // Naomi2 uniforms
|
|
|
|
vk::DescriptorSetLayoutBinding(3, vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eVertex), // Naomi2 lights
|
2019-10-12 11:47:25 +00:00
|
|
|
};
|
2019-10-25 17:20:15 +00:00
|
|
|
perFrameLayout = GetContext()->GetDevice().createDescriptorSetLayoutUnique(
|
2022-10-06 16:02:01 +00:00
|
|
|
vk::DescriptorSetLayoutCreateInfo(vk::DescriptorSetLayoutCreateFlags(), perFrameBindings));
|
2019-10-25 17:20:15 +00:00
|
|
|
perPolyLayout = GetContext()->GetDevice().createDescriptorSetLayoutUnique(
|
2022-10-06 16:02:01 +00:00
|
|
|
vk::DescriptorSetLayoutCreateInfo(vk::DescriptorSetLayoutCreateFlags(), perPolyBindings));
|
|
|
|
std::array<vk::DescriptorSetLayout, 2> layouts = { *perFrameLayout, *perPolyLayout };
|
2020-07-08 16:17:15 +00:00
|
|
|
vk::PushConstantRange pushConstant(vk::ShaderStageFlagBits::eFragment, 0, 24);
|
2019-10-25 17:20:15 +00:00
|
|
|
pipelineLayout = GetContext()->GetDevice().createPipelineLayoutUnique(
|
2022-10-06 16:02:01 +00:00
|
|
|
vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), layouts, pushConstant));
|
2019-10-12 11:47:25 +00:00
|
|
|
}
|
2019-10-09 19:16:12 +00:00
|
|
|
|
2019-11-29 18:28:22 +00:00
|
|
|
if (this->renderPass != renderPass)
|
2019-10-13 20:01:20 +00:00
|
|
|
{
|
2019-11-29 18:28:22 +00:00
|
|
|
this->renderPass = renderPass;
|
2019-12-25 12:09:54 +00:00
|
|
|
Reset();
|
2019-10-13 20:01:20 +00:00
|
|
|
}
|
2019-10-05 09:50:14 +00:00
|
|
|
}
|
|
|
|
|
2023-09-10 14:25:19 +00:00
|
|
|
vk::Pipeline GetPipeline(u32 listType, bool sortTriangles, const PolyParam& pp, bool gpuPalette, bool dithering)
|
2019-10-05 09:50:14 +00:00
|
|
|
{
|
2023-09-10 14:25:19 +00:00
|
|
|
u32 pipehash = hash(listType, sortTriangles, &pp, gpuPalette, dithering);
|
2019-10-05 09:50:14 +00:00
|
|
|
const auto &pipeline = pipelines.find(pipehash);
|
|
|
|
if (pipeline != pipelines.end())
|
|
|
|
return pipeline->second.get();
|
|
|
|
|
2023-09-10 14:25:19 +00:00
|
|
|
CreatePipeline(listType, sortTriangles, pp, gpuPalette, dithering);
|
2019-10-05 09:50:14 +00:00
|
|
|
|
|
|
|
return *pipelines[pipehash];
|
|
|
|
}
|
|
|
|
|
2022-03-12 16:56:46 +00:00
|
|
|
vk::Pipeline GetModifierVolumePipeline(ModVolMode mode, int cullMode, bool naomi2)
|
2019-10-07 10:30:56 +00:00
|
|
|
{
|
2022-03-12 16:56:46 +00:00
|
|
|
u32 pipehash = hash(mode, cullMode, naomi2);
|
2019-12-05 17:48:54 +00:00
|
|
|
const auto &pipeline = modVolPipelines.find(pipehash);
|
|
|
|
if (pipeline != modVolPipelines.end())
|
|
|
|
return pipeline->second.get();
|
2022-03-12 16:56:46 +00:00
|
|
|
CreateModVolPipeline(mode, cullMode, naomi2);
|
2019-12-05 17:48:54 +00:00
|
|
|
|
|
|
|
return *modVolPipelines[pipehash];
|
2019-10-07 10:30:56 +00:00
|
|
|
}
|
2019-12-25 12:09:54 +00:00
|
|
|
|
2022-03-12 16:56:46 +00:00
|
|
|
vk::Pipeline GetDepthPassPipeline(int cullMode, bool naomi2)
|
2021-11-04 08:13:47 +00:00
|
|
|
{
|
2022-03-12 16:56:46 +00:00
|
|
|
u32 pipehash = hash(cullMode, naomi2);
|
|
|
|
const auto &pipeline = depthPassPipelines.find(pipehash);
|
|
|
|
if (pipeline != depthPassPipelines.end())
|
|
|
|
return pipeline->second.get();
|
|
|
|
CreateDepthPassPipeline(cullMode, naomi2);
|
2021-11-04 08:13:47 +00:00
|
|
|
|
2022-03-12 16:56:46 +00:00
|
|
|
return *depthPassPipelines[pipehash];
|
2021-11-04 08:13:47 +00:00
|
|
|
}
|
|
|
|
|
2019-12-25 12:09:54 +00:00
|
|
|
void Reset()
|
|
|
|
{
|
|
|
|
pipelines.clear();
|
|
|
|
modVolPipelines.clear();
|
|
|
|
}
|
|
|
|
|
2019-10-09 19:16:12 +00:00
|
|
|
vk::PipelineLayout GetPipelineLayout() const { return *pipelineLayout; }
|
|
|
|
vk::DescriptorSetLayout GetPerFrameDSLayout() const { return *perFrameLayout; }
|
|
|
|
vk::DescriptorSetLayout GetPerPolyDSLayout() const { return *perPolyLayout; }
|
|
|
|
vk::RenderPass GetRenderPass() const { return renderPass; }
|
2019-10-07 10:30:56 +00:00
|
|
|
|
2019-10-05 09:50:14 +00:00
|
|
|
private:
|
2022-03-12 16:56:46 +00:00
|
|
|
void CreateModVolPipeline(ModVolMode mode, int cullMode, bool naomi2);
|
|
|
|
void CreateDepthPassPipeline(int cullMode, bool naomi2);
|
2019-10-05 09:50:14 +00:00
|
|
|
|
2023-09-10 14:25:19 +00:00
|
|
|
u32 hash(u32 listType, bool sortTriangles, const PolyParam *pp, bool gpuPalette, bool dithering) const
|
2019-10-05 09:50:14 +00:00
|
|
|
{
|
|
|
|
u32 hash = pp->pcw.Gouraud | (pp->pcw.Offset << 1) | (pp->pcw.Texture << 2) | (pp->pcw.Shadow << 3)
|
2019-10-13 20:01:20 +00:00
|
|
|
| (((pp->tileclip >> 28) == 3) << 4);
|
|
|
|
hash |= ((listType >> 1) << 5);
|
2020-12-15 14:09:42 +00:00
|
|
|
bool ignoreTexAlpha = pp->tsp.IgnoreTexA || pp->tcw.PixelFmt == Pixel565;
|
|
|
|
hash |= (pp->tsp.ShadInstr << 7) | (ignoreTexAlpha << 9) | (pp->tsp.UseAlpha << 10)
|
2021-03-01 09:13:40 +00:00
|
|
|
| (pp->tsp.ColorClamp << 11) | ((config::Fog ? pp->tsp.FogCtrl : 2) << 12) | (pp->tsp.SrcInstr << 14)
|
2019-10-13 20:01:20 +00:00
|
|
|
| (pp->tsp.DstInstr << 17);
|
|
|
|
hash |= (pp->isp.ZWriteDis << 20) | (pp->isp.CullMode << 21) | (pp->isp.DepthMode << 23);
|
2022-03-12 16:56:46 +00:00
|
|
|
hash |= ((u32)sortTriangles << 26) | ((u32)gpuPalette << 27) | ((u32)pp->isNaomi2() << 28);
|
2022-05-12 11:43:43 +00:00
|
|
|
hash |= (u32)(!settings.platform.isNaomi2() && config::NativeDepthInterpolation) << 29;
|
2023-09-23 09:13:14 +00:00
|
|
|
hash |= (u32)(pp->tcw.PixelFmt == PixelBumpMap) << 30;
|
2023-09-25 20:17:29 +00:00
|
|
|
hash |= (u32)dithering << 31;
|
2019-10-05 09:50:14 +00:00
|
|
|
|
|
|
|
return hash;
|
|
|
|
}
|
2022-03-12 16:56:46 +00:00
|
|
|
u32 hash(ModVolMode mode, int cullMode, bool naomi2) const
|
|
|
|
{
|
2022-05-12 11:43:43 +00:00
|
|
|
return ((int)mode << 2) | cullMode | ((int)naomi2 << 5) | ((int)(!settings.platform.isNaomi2() && config::NativeDepthInterpolation) << 6);
|
2022-03-12 16:56:46 +00:00
|
|
|
}
|
|
|
|
u32 hash(int cullMode, bool naomi2) const
|
2019-12-05 17:48:54 +00:00
|
|
|
{
|
2022-05-12 11:43:43 +00:00
|
|
|
return cullMode | ((int)naomi2 << 2) | ((int)(!settings.platform.isNaomi2() && config::NativeDepthInterpolation) << 3);
|
2019-12-05 17:48:54 +00:00
|
|
|
}
|
2019-10-06 19:21:31 +00:00
|
|
|
|
2019-10-07 10:30:56 +00:00
|
|
|
vk::PipelineVertexInputStateCreateInfo GetMainVertexInputStateCreateInfo(bool full = true) const
|
2019-10-06 19:21:31 +00:00
|
|
|
{
|
|
|
|
// Vertex input state
|
|
|
|
static const vk::VertexInputBindingDescription vertexBindingDescriptions[] =
|
|
|
|
{
|
|
|
|
{ 0, sizeof(Vertex) },
|
|
|
|
};
|
|
|
|
static const vk::VertexInputAttributeDescription vertexInputAttributeDescriptions[] =
|
|
|
|
{
|
|
|
|
vk::VertexInputAttributeDescription(0, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, x)), // pos
|
|
|
|
vk::VertexInputAttributeDescription(1, 0, vk::Format::eR8G8B8A8Uint, offsetof(Vertex, col)), // base color
|
|
|
|
vk::VertexInputAttributeDescription(2, 0, vk::Format::eR8G8B8A8Uint, offsetof(Vertex, spc)), // offset color
|
|
|
|
vk::VertexInputAttributeDescription(3, 0, vk::Format::eR32G32Sfloat, offsetof(Vertex, u)), // tex coord
|
2022-03-12 16:56:46 +00:00
|
|
|
vk::VertexInputAttributeDescription(4, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, nx)), // naomi2 normal
|
2019-10-06 19:21:31 +00:00
|
|
|
};
|
2019-10-07 10:30:56 +00:00
|
|
|
static const vk::VertexInputAttributeDescription vertexInputLightAttributeDescriptions[] =
|
|
|
|
{
|
|
|
|
vk::VertexInputAttributeDescription(0, 0, vk::Format::eR32G32B32Sfloat, offsetof(Vertex, x)), // pos
|
|
|
|
};
|
2019-10-06 19:21:31 +00:00
|
|
|
return vk::PipelineVertexInputStateCreateInfo(
|
|
|
|
vk::PipelineVertexInputStateCreateFlags(),
|
2023-02-18 12:24:34 +00:00
|
|
|
std::size(vertexBindingDescriptions),
|
2019-10-06 19:21:31 +00:00
|
|
|
vertexBindingDescriptions,
|
2023-02-18 12:24:34 +00:00
|
|
|
full ? std::size(vertexInputAttributeDescriptions) : std::size(vertexInputLightAttributeDescriptions),
|
2019-10-07 10:30:56 +00:00
|
|
|
full ? vertexInputAttributeDescriptions : vertexInputLightAttributeDescriptions);
|
2019-10-06 19:21:31 +00:00
|
|
|
}
|
|
|
|
|
2023-09-10 14:25:19 +00:00
|
|
|
void CreatePipeline(u32 listType, bool sortTriangles, const PolyParam& pp, bool gpuPalette, bool dithering);
|
2019-10-05 09:50:14 +00:00
|
|
|
|
|
|
|
std::map<u32, vk::UniquePipeline> pipelines;
|
2019-12-05 17:48:54 +00:00
|
|
|
std::map<u32, vk::UniquePipeline> modVolPipelines;
|
2022-03-12 16:56:46 +00:00
|
|
|
std::map<u32, vk::UniquePipeline> depthPassPipelines;
|
2019-10-09 19:16:12 +00:00
|
|
|
|
|
|
|
vk::UniquePipelineLayout pipelineLayout;
|
|
|
|
vk::UniqueDescriptorSetLayout perFrameLayout;
|
|
|
|
vk::UniqueDescriptorSetLayout perPolyLayout;
|
|
|
|
|
|
|
|
protected:
|
|
|
|
VulkanContext *GetContext() const { return VulkanContext::Instance(); }
|
|
|
|
|
|
|
|
vk::RenderPass renderPass;
|
2021-01-09 17:16:39 +00:00
|
|
|
ShaderManager *shaderManager = nullptr;
|
2019-10-05 09:50:14 +00:00
|
|
|
};
|
|
|
|
|
2019-10-09 19:16:12 +00:00
|
|
|
class RttPipelineManager : public PipelineManager
|
|
|
|
{
|
|
|
|
public:
|
2019-11-29 18:28:22 +00:00
|
|
|
void Init(ShaderManager *shaderManager)
|
2019-10-09 19:16:12 +00:00
|
|
|
{
|
|
|
|
// RTT render pass
|
2021-03-01 09:13:40 +00:00
|
|
|
renderToTextureBuffer = config::RenderToTextureBuffer;
|
2019-10-09 19:16:12 +00:00
|
|
|
vk::AttachmentDescription attachmentDescriptions[] = {
|
|
|
|
vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), vk::Format::eR8G8B8A8Unorm, vk::SampleCountFlagBits::e1,
|
|
|
|
vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eStore, vk::AttachmentLoadOp::eDontCare, vk::AttachmentStoreOp::eDontCare,
|
|
|
|
vk::ImageLayout::eColorAttachmentOptimal,
|
2019-10-16 08:40:06 +00:00
|
|
|
renderToTextureBuffer ? vk::ImageLayout::eTransferSrcOptimal : vk::ImageLayout::eShaderReadOnlyOptimal),
|
|
|
|
vk::AttachmentDescription(vk::AttachmentDescriptionFlags(), GetContext()->GetDepthFormat(), vk::SampleCountFlagBits::e1,
|
2019-10-09 19:16:12 +00:00
|
|
|
vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eDontCare, vk::AttachmentLoadOp::eClear, vk::AttachmentStoreOp::eDontCare,
|
|
|
|
vk::ImageLayout::eUndefined, vk::ImageLayout::eDepthStencilAttachmentOptimal),
|
|
|
|
};
|
|
|
|
vk::AttachmentReference colorReference(0, vk::ImageLayout::eColorAttachmentOptimal);
|
|
|
|
vk::AttachmentReference depthReference(1, vk::ImageLayout::eDepthStencilAttachmentOptimal);
|
2022-10-06 16:02:01 +00:00
|
|
|
vk::SubpassDescription subpass(vk::SubpassDescriptionFlags(), vk::PipelineBindPoint::eGraphics, nullptr, colorReference, nullptr, &depthReference);
|
2019-10-09 19:16:12 +00:00
|
|
|
vk::SubpassDependency dependencies[] {
|
|
|
|
vk::SubpassDependency(VK_SUBPASS_EXTERNAL, 0, vk::PipelineStageFlagBits::eFragmentShader, vk::PipelineStageFlagBits::eColorAttachmentOutput,
|
|
|
|
vk::AccessFlagBits::eShaderRead, vk::AccessFlagBits::eColorAttachmentWrite),
|
|
|
|
vk::SubpassDependency(0, VK_SUBPASS_EXTERNAL, vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eFragmentShader,
|
|
|
|
vk::AccessFlagBits::eColorAttachmentWrite, vk::AccessFlagBits::eShaderRead),
|
|
|
|
};
|
|
|
|
vk::SubpassDependency vramWriteDeps[] {
|
|
|
|
vk::SubpassDependency(0, VK_SUBPASS_EXTERNAL,
|
|
|
|
vk::PipelineStageFlagBits::eColorAttachmentOutput, vk::PipelineStageFlagBits::eTransfer | vk::PipelineStageFlagBits::eHost,
|
|
|
|
vk::AccessFlagBits::eColorAttachmentWrite, vk::AccessFlagBits::eTransferRead | vk::AccessFlagBits::eHostRead),
|
|
|
|
};
|
|
|
|
|
2019-10-25 17:20:15 +00:00
|
|
|
rttRenderPass = GetContext()->GetDevice().createRenderPassUnique(vk::RenderPassCreateInfo(vk::RenderPassCreateFlags(), 2, attachmentDescriptions,
|
2023-02-18 12:24:34 +00:00
|
|
|
1, &subpass, renderToTextureBuffer ? std::size(vramWriteDeps) : std::size(dependencies), renderToTextureBuffer ? vramWriteDeps : dependencies));
|
2019-11-29 18:28:22 +00:00
|
|
|
|
|
|
|
PipelineManager::Init(shaderManager, *rttRenderPass);
|
2019-10-09 19:16:12 +00:00
|
|
|
}
|
2019-11-29 18:28:22 +00:00
|
|
|
|
2019-10-16 08:40:06 +00:00
|
|
|
void CheckSettingsChange()
|
|
|
|
{
|
2021-03-01 09:13:40 +00:00
|
|
|
if (renderToTextureBuffer != config::RenderToTextureBuffer)
|
2019-10-16 08:40:06 +00:00
|
|
|
Init(shaderManager);
|
|
|
|
}
|
2019-10-05 09:50:14 +00:00
|
|
|
|
2019-10-09 19:16:12 +00:00
|
|
|
private:
|
|
|
|
vk::UniqueRenderPass rttRenderPass;
|
2021-01-09 17:16:39 +00:00
|
|
|
bool renderToTextureBuffer = false;
|
2019-10-09 19:16:12 +00:00
|
|
|
};
|
2019-10-14 15:41:49 +00:00
|
|
|
|
2019-10-21 14:39:16 +00:00
|
|
|
class OSDPipeline
|
|
|
|
{
|
|
|
|
public:
|
2019-11-29 18:28:22 +00:00
|
|
|
void Init(ShaderManager *shaderManager, vk::ImageView imageView, vk::RenderPass renderPass)
|
2019-10-21 14:39:16 +00:00
|
|
|
{
|
|
|
|
this->shaderManager = shaderManager;
|
|
|
|
if (!pipelineLayout)
|
|
|
|
{
|
2022-10-06 16:02:01 +00:00
|
|
|
vk::DescriptorSetLayoutBinding binding(0, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment); // texture
|
2019-10-25 17:20:15 +00:00
|
|
|
descSetLayout = GetContext()->GetDevice().createDescriptorSetLayoutUnique(
|
2022-10-06 16:02:01 +00:00
|
|
|
vk::DescriptorSetLayoutCreateInfo(vk::DescriptorSetLayoutCreateFlags(), binding));
|
2019-10-25 17:20:15 +00:00
|
|
|
pipelineLayout = GetContext()->GetDevice().createPipelineLayoutUnique(
|
2022-10-06 16:02:01 +00:00
|
|
|
vk::PipelineLayoutCreateInfo(vk::PipelineLayoutCreateFlags(), descSetLayout.get()));
|
2019-10-21 14:39:16 +00:00
|
|
|
}
|
|
|
|
if (!sampler)
|
|
|
|
{
|
2019-11-29 18:28:22 +00:00
|
|
|
sampler = GetContext()->GetDevice().createSamplerUnique(
|
2019-10-21 14:39:16 +00:00
|
|
|
vk::SamplerCreateInfo(vk::SamplerCreateFlags(), vk::Filter::eLinear, vk::Filter::eLinear,
|
|
|
|
vk::SamplerMipmapMode::eLinear, vk::SamplerAddressMode::eClampToEdge, vk::SamplerAddressMode::eClampToEdge,
|
|
|
|
vk::SamplerAddressMode::eClampToEdge, 0.0f, false, 16.0f, false,
|
|
|
|
vk::CompareOp::eNever, 0.0f, 0.0f, vk::BorderColor::eFloatOpaqueBlack));
|
|
|
|
}
|
2019-11-29 18:28:22 +00:00
|
|
|
if (this->renderPass != renderPass)
|
2019-10-21 14:39:16 +00:00
|
|
|
{
|
2019-11-13 19:08:14 +00:00
|
|
|
this->renderPass = renderPass;
|
2019-10-21 14:39:16 +00:00
|
|
|
pipeline.reset();
|
|
|
|
}
|
|
|
|
if (!descriptorSet)
|
|
|
|
{
|
2019-10-25 17:20:15 +00:00
|
|
|
descriptorSet = std::move(GetContext()->GetDevice().allocateDescriptorSetsUnique(
|
2022-10-06 16:02:01 +00:00
|
|
|
vk::DescriptorSetAllocateInfo(GetContext()->GetDescriptorPool(), descSetLayout.get())).front());
|
2019-10-21 14:39:16 +00:00
|
|
|
}
|
|
|
|
vk::DescriptorImageInfo imageInfo(*sampler, imageView, vk::ImageLayout::eShaderReadOnlyOptimal);
|
2022-10-06 16:02:01 +00:00
|
|
|
vk::WriteDescriptorSet writeDescriptorSet(*descriptorSet, 0, 0, vk::DescriptorType::eCombinedImageSampler, imageInfo);
|
|
|
|
GetContext()->GetDevice().updateDescriptorSets(writeDescriptorSet, nullptr);
|
2019-10-21 14:39:16 +00:00
|
|
|
}
|
|
|
|
|
2022-10-23 14:32:42 +00:00
|
|
|
void Term()
|
|
|
|
{
|
|
|
|
descriptorSet.reset();
|
|
|
|
pipeline.reset();
|
|
|
|
sampler.reset();
|
|
|
|
pipelineLayout.reset();
|
|
|
|
descSetLayout.reset();
|
|
|
|
}
|
|
|
|
|
2019-10-21 14:39:16 +00:00
|
|
|
vk::Pipeline GetPipeline()
|
|
|
|
{
|
|
|
|
if (!pipeline)
|
|
|
|
CreatePipeline();
|
|
|
|
return *pipeline;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BindDescriptorSets(vk::CommandBuffer cmdBuffer) const
|
|
|
|
{
|
2022-10-06 16:02:01 +00:00
|
|
|
cmdBuffer.bindDescriptorSets(vk::PipelineBindPoint::eGraphics, *pipelineLayout, 0, descriptorSet.get(), nullptr);
|
2019-10-21 14:39:16 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
VulkanContext *GetContext() const { return VulkanContext::Instance(); }
|
|
|
|
void CreatePipeline();
|
|
|
|
|
|
|
|
vk::RenderPass renderPass;
|
|
|
|
vk::UniquePipeline pipeline;
|
|
|
|
vk::UniqueSampler sampler;
|
|
|
|
vk::UniqueDescriptorSet descriptorSet;
|
|
|
|
vk::UniquePipelineLayout pipelineLayout;
|
|
|
|
vk::UniqueDescriptorSetLayout descSetLayout;
|
2021-01-09 17:16:39 +00:00
|
|
|
ShaderManager *shaderManager = nullptr;
|
2019-10-14 15:41:49 +00:00
|
|
|
};
|