Misc multiview hackery

This commit is contained in:
Henrik Rydgård 2022-10-09 20:19:39 +02:00
parent 7a620962aa
commit d3804ec2e5
12 changed files with 68 additions and 26 deletions

View File

@ -326,9 +326,10 @@ static VkAttachmentStoreOp ConvertStoreAction(VKRRenderPassStoreAction action) {
// Also see https://www.khronos.org/registry/vulkan/specs/1.3-extensions/html/vkspec.html#synchronization-pipeline-barriers-subpass-self-dependencies
VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPassType rpType) {
bool selfDependency = rpType == RP_TYPE_COLOR_INPUT || rpType == RP_TYPE_COLOR_DEPTH_INPUT;
bool selfDependency = RenderPassTypeHasInput(rpType);
bool isBackbuffer = rpType == RP_TYPE_BACKBUFFER;
bool hasDepth = rpType == RP_TYPE_BACKBUFFER || rpType == RP_TYPE_COLOR_DEPTH || rpType == RP_TYPE_COLOR_DEPTH_INPUT;
bool hasDepth = RenderPassTypeHasDepth(rpType);
bool multiview = RenderPassTypeHasMultiView(rpType);
VkAttachmentDescription attachments[2] = {};
attachments[0].format = isBackbuffer ? vulkan->GetSwapchainFormat() : VK_FORMAT_R8G8B8A8_UNORM;
@ -390,6 +391,19 @@ VkRenderPass CreateRenderPass(VulkanContext *vulkan, const RPKey &key, RenderPas
rp.subpassCount = 1;
rp.pSubpasses = &subpass;
VkRenderPassMultiviewCreateInfoKHR mv{ VK_STRUCTURE_TYPE_RENDER_PASS_MULTIVIEW_CREATE_INFO_KHR };
uint32_t viewMask = 0x3; // Must be outside the 'if (multiview)' scope!
int viewOffset = 0;
if (multiview) {
rp.pNext = &mv;
mv.subpassCount = 1;
mv.pViewMasks = &viewMask;
mv.dependencyCount = 0;
mv.pCorrelationMasks = &viewMask; // same masks
mv.correlationMaskCount = 1;
mv.pViewOffsets = &viewOffset;
}
if (isBackbuffer) {
deps[numDeps].srcSubpass = VK_SUBPASS_EXTERNAL;
deps[numDeps].dstSubpass = 0;

View File

@ -48,18 +48,24 @@ enum class PipelineFlags {
USES_DEPTH_STENCIL = (1 << 2), // Reads or writes the depth or stencil buffers.
USES_INPUT_ATTACHMENT = (1 << 3),
USES_GEOMETRY_SHADER = (1 << 4),
USES_MULTIVIEW = (1 << 5), // Inherited from the render pass it was created with.
};
ENUM_CLASS_BITOPS(PipelineFlags);
// Pipelines need to be created for the right type of render pass.
enum RenderPassType {
// These four are organized so that bit 0 is DEPTH and bit 1 is INPUT, so
// These eight are organized so that bit 0 is DEPTH and bit 1 is INPUT and bit 2 is MULTIVIEW, so
// they can be OR-ed together in MergeRPTypes.
RP_TYPE_COLOR,
RP_TYPE_COLOR_DEPTH,
RP_TYPE_COLOR_INPUT,
RP_TYPE_COLOR_DEPTH_INPUT,
RP_TYPE_MULTIVIEW_COLOR,
RP_TYPE_MULTIVIEW_COLOR_DEPTH,
RP_TYPE_MULTIVIEW_COLOR_INPUT,
RP_TYPE_MULTIVIEW_COLOR_DEPTH_INPUT,
// This is the odd one out, and gets special handling in MergeRPTypes.
RP_TYPE_BACKBUFFER, // For the backbuffer we can always use CLEAR/DONT_CARE, so bandwidth cost for a depth channel is negligible.
@ -67,12 +73,18 @@ enum RenderPassType {
RP_TYPE_COUNT,
};
// Hm, soon time to exploit the bit properties in these..
inline bool RenderPassTypeHasDepth(RenderPassType type) {
return type == RP_TYPE_BACKBUFFER || type == RP_TYPE_COLOR_DEPTH || type == RP_TYPE_COLOR_DEPTH_INPUT;
return type == RP_TYPE_BACKBUFFER || type == RP_TYPE_COLOR_DEPTH || type == RP_TYPE_COLOR_DEPTH_INPUT || type == RP_TYPE_MULTIVIEW_COLOR_DEPTH || type == RP_TYPE_MULTIVIEW_COLOR_DEPTH_INPUT;
}
inline bool RenderPassTypeHasInput(RenderPassType type) {
return type == RP_TYPE_COLOR_INPUT || type == RP_TYPE_COLOR_DEPTH_INPUT;
return type == RP_TYPE_COLOR_INPUT || type == RP_TYPE_COLOR_DEPTH_INPUT || type == RP_TYPE_MULTIVIEW_COLOR_INPUT || type == RP_TYPE_MULTIVIEW_COLOR_DEPTH_INPUT;
}
inline bool RenderPassTypeHasMultiView(RenderPassType type) {
return type == RP_TYPE_MULTIVIEW_COLOR || type == RP_TYPE_MULTIVIEW_COLOR_DEPTH || type == RP_TYPE_MULTIVIEW_COLOR_INPUT || type == RP_TYPE_MULTIVIEW_COLOR_DEPTH_INPUT;
}
struct VkRenderData {

View File

@ -1295,7 +1295,7 @@ void TextureCacheCommon::LoadClut(u32 clutAddr, u32 loadBytes) {
desc.height = 1;
desc.depth = 1;
desc.z_stencil = false;
desc.numColorAttachments = 1;
desc.numLayers = 1;
desc.tag = "dynamic_clut";
dynamicClutFbo_ = draw_->CreateFramebuffer(desc);
desc.tag = "dynamic_clut_temp";

View File

@ -126,9 +126,12 @@ static const char * const boneWeightDecl[9] = {
"layout(location = 3) in vec4 w1;\nlayout(location = 4) in vec4 w2;\n",
};
bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, Draw::Bugs bugs, uint32_t *attrMask, uint64_t *uniformMask, std::string *errorString) {
bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, Draw::Bugs bugs, uint32_t *attrMask, uint64_t *uniformMask, VertexShaderFlags *vertexShaderFlags, std::string *errorString) {
*attrMask = 0;
*uniformMask = 0;
if (vertexShaderFlags) {
*vertexShaderFlags = (VertexShaderFlags)0;
}
bool highpFog = false;
bool highpTexcoord = false;

View File

@ -25,7 +25,13 @@
struct VShaderID;
bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, const Draw::Bugs bugs, uint32_t *attrMask, uint64_t *uniformMask, std::string *errorString);
// Can technically be deduced from the vertex shader ID, but this is safer.
enum class VertexShaderFlags : u32 {
MULTI_VIEW = 1,
};
ENUM_CLASS_BITOPS(VertexShaderFlags);
bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguageDesc &compat, const Draw::Bugs bugs, uint32_t *attrMask, uint64_t *uniformMask, VertexShaderFlags *vertexShaderFlags, std::string *errorString);
// D3D9 constants.
enum {

View File

@ -212,7 +212,7 @@ void ShaderManagerD3D11::GetShaders(int prim, u32 vertType, D3D11VertexShader **
std::string genErrorString;
uint32_t attrMask;
uint64_t uniformMask;
GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &genErrorString);
GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, nullptr, &genErrorString);
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));
vs = new D3D11VertexShader(device_, featureLevel_, VSID, codeBuffer_, vertType, useHWTransform);
vsCache_[VSID] = vs;

View File

@ -581,7 +581,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat
std::string genErrorString;
uint32_t attrMask;
uint64_t uniformMask;
if (GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &genErrorString)) {
if (GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, nullptr, &genErrorString)) {
vs = new VSShader(device_, VSID, codeBuffer_, useHWTransform);
}
if (!vs || vs->Failed()) {
@ -606,7 +606,7 @@ VSShader *ShaderManagerDX9::ApplyShader(bool useHWTransform, bool useHWTessellat
// Can still work with software transform.
uint32_t attrMask;
uint64_t uniformMask;
bool success = GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &genErrorString);
bool success = GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, nullptr, &genErrorString);
_assert_(success);
vs = new VSShader(device_, VSID, codeBuffer_, false);
}

View File

@ -743,7 +743,7 @@ Shader *ShaderManagerGLES::CompileVertexShader(VShaderID VSID) {
uint32_t attrMask;
uint64_t uniformMask;
std::string errorString;
if (!GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, &errorString)) {
if (!GenerateVertexShader(VSID, codeBuffer_, draw_->GetShaderLanguageDesc(), draw_->GetBugs(), &attrMask, &uniformMask, nullptr, &errorString)) {
ERROR_LOG(G3D, "Shader gen error: %s", errorString.c_str());
return nullptr;
}

View File

@ -336,6 +336,9 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *
if (fs->Flags() & FragmentShaderFlags::INPUT_ATTACHMENT) {
pipelineFlags |= PipelineFlags::USES_INPUT_ATTACHMENT;
}
if (vs->Flags() & VertexShaderFlags::MULTI_VIEW) {
pipelineFlags |= PipelineFlags::USES_MULTIVIEW;
}
VulkanPipeline *pipeline = CreateVulkanPipeline(
renderManager, pipelineCache_, layout, pipelineFlags,

View File

@ -135,8 +135,8 @@ std::string VulkanFragmentShader::GetShaderString(DebugShaderStringType type) co
}
}
VulkanVertexShader::VulkanVertexShader(VulkanContext *vulkan, VShaderID id, const char *code, bool useHWTransform)
: vulkan_(vulkan), useHWTransform_(useHWTransform), id_(id) {
VulkanVertexShader::VulkanVertexShader(VulkanContext *vulkan, VShaderID id, VertexShaderFlags flags, const char *code, bool useHWTransform)
: vulkan_(vulkan), useHWTransform_(useHWTransform), flags_(flags), id_(id) {
source_ = code;
module_ = CompileShaderModuleAsync(vulkan, VK_SHADER_STAGE_VERTEX_BIT, source_.c_str(), new std::string(VertexShaderDesc(id)));
if (!module_) {
@ -331,10 +331,11 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
std::string genErrorString;
uint64_t uniformMask = 0; // Not used
uint32_t attributeMask = 0; // Not used
bool success = GenerateVertexShader(VSID, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &genErrorString);
VertexShaderFlags flags{};
bool success = GenerateVertexShader(VSID, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &flags, &genErrorString);
_assert_msg_(success, "VS gen error: %s", genErrorString.c_str());
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));
vs = new VulkanVertexShader(vulkan, VSID, codeBuffer_, useHWTransform);
vs = new VulkanVertexShader(vulkan, VSID, flags, codeBuffer_, useHWTransform);
vsCache_.Insert(VSID, vs);
}
@ -343,7 +344,7 @@ void ShaderManagerVulkan::GetShaders(int prim, u32 vertType, VulkanVertexShader
// Fragment shader not in cache. Let's compile it.
std::string genErrorString;
uint64_t uniformMask = 0; // Not used
FragmentShaderFlags flags;
FragmentShaderFlags flags{};
bool success = GenerateFragmentShader(FSID, codeBuffer_, compat_, draw_->GetBugs(), &uniformMask, &flags, &genErrorString);
_assert_msg_(success, "FS gen error: %s", genErrorString.c_str());
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "FS length error: %d", (int)strlen(codeBuffer_));
@ -515,11 +516,12 @@ bool ShaderManagerVulkan::LoadCache(FILE *f) {
std::string genErrorString;
uint32_t attributeMask = 0;
uint64_t uniformMask = 0;
if (!GenerateVertexShader(id, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &genErrorString)) {
VertexShaderFlags flags;
if (!GenerateVertexShader(id, codeBuffer_, compat_, draw_->GetBugs(), &attributeMask, &uniformMask, &flags, &genErrorString)) {
return false;
}
_assert_msg_(strlen(codeBuffer_) < CODE_BUFFER_SIZE, "VS length error: %d", (int)strlen(codeBuffer_));
VulkanVertexShader *vs = new VulkanVertexShader(vulkan, id, codeBuffer_, useHWTransform);
VulkanVertexShader *vs = new VulkanVertexShader(vulkan, id, flags, codeBuffer_, useHWTransform);
vsCache_.Insert(id, vs);
}
uint32_t vendorID = vulkan->GetPhysicalDeviceProperties().properties.vendorID;

View File

@ -61,13 +61,14 @@ protected:
class VulkanVertexShader {
public:
VulkanVertexShader(VulkanContext *vulkan, VShaderID id, const char *code, bool useHWTransform);
VulkanVertexShader(VulkanContext *vulkan, VShaderID id, VertexShaderFlags flags, const char *code, bool useHWTransform);
~VulkanVertexShader();
const std::string &source() const { return source_; }
bool Failed() const { return failed_; }
bool UseHWTransform() const { return useHWTransform_; }
bool UseHWTransform() const { return useHWTransform_; } // TODO: Roll into flags
VertexShaderFlags Flags() const { return flags_; }
std::string GetShaderString(DebugShaderStringType type) const;
Promise<VkShaderModule> *GetModule() { return module_; }
@ -81,6 +82,7 @@ protected:
bool failed_ = false;
bool useHWTransform_;
VShaderID id_;
VertexShaderFlags flags_;
};
class VulkanGeometryShader {

View File

@ -67,27 +67,27 @@ bool GenerateVShader(VShaderID id, char *buffer, ShaderLanguage lang, Draw::Bugs
case ShaderLanguage::GLSL_VULKAN:
{
ShaderLanguageDesc compat(ShaderLanguage::GLSL_VULKAN);
return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString);
return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, nullptr, errorString);
}
case ShaderLanguage::GLSL_1xx:
{
ShaderLanguageDesc compat(ShaderLanguage::GLSL_1xx);
return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString);
return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, nullptr, errorString);
}
case ShaderLanguage::GLSL_3xx:
{
ShaderLanguageDesc compat(ShaderLanguage::GLSL_3xx);
return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString);
return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, nullptr, errorString);
}
case ShaderLanguage::HLSL_D3D9:
{
ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D9);
return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString);
return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, nullptr, errorString);
}
case ShaderLanguage::HLSL_D3D11:
{
ShaderLanguageDesc compat(ShaderLanguage::HLSL_D3D11);
return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, errorString);
return GenerateVertexShader(id, buffer, compat, bugs, &attrMask, &uniformMask, nullptr, errorString);
}
default:
return false;