diff --git a/Common/GPU/ShaderTranslation.cpp b/Common/GPU/ShaderTranslation.cpp index 9391d1b7da..732ef68633 100644 --- a/Common/GPU/ShaderTranslation.cpp +++ b/Common/GPU/ShaderTranslation.cpp @@ -98,7 +98,7 @@ R"(#version 450 )"; static const char *vulkanUboDecl = R"( -layout (std140, set = 0, binding = 0) uniform Data { +layout (std140, set = 1, binding = 0) uniform Data { vec2 u_texelDelta; vec2 u_pixelDelta; vec4 u_time; @@ -187,11 +187,11 @@ bool ConvertToVulkanGLSL(std::string *dest, TranslatedShaderMetadata *destMetada continue; } else if (line.find("uniform sampler2D") == 0) { if (sscanf(line.c_str(), "uniform sampler2D sampler%d", &num) == 1) - line = StringFromFormat("layout(set = 0, binding = %d) ", num + 1) + line; + line = StringFromFormat("layout(set = 1, binding = %d) ", num + 1) + line; else if (line.find("sampler0") != line.npos) - line = "layout(set = 0, binding = 1) " + line; + line = "layout(set = 1, binding = 1) " + line; else - line = "layout(set = 0, binding = 2) " + line; + line = "layout(set = 1, binding = 2) " + line; } else if (line.find("uniform ") != std::string::npos) { continue; } else if (2 == sscanf(line.c_str(), "varying vec%d v_texcoord%d;", &vecSize, &num)) { diff --git a/Common/GPU/ShaderWriter.cpp b/Common/GPU/ShaderWriter.cpp index ed7a3612f9..01132b11de 100644 --- a/Common/GPU/ShaderWriter.cpp +++ b/Common/GPU/ShaderWriter.cpp @@ -326,7 +326,7 @@ void ShaderWriter::BeginFSMain(Slice uniforms, Slice var } C("layout(location = 0, index = 0) out vec4 fragColor0;\n"); if (!uniforms.is_empty()) { - C("layout(std140, set = 0, binding = 0) uniform bufferVals {\n"); + C("layout(std140, set = 1, binding = 0) uniform bufferVals {\n"); for (auto &uniform : uniforms) { F("%s %s;\n", uniform.type, uniform.name); } @@ -480,9 +480,9 @@ void ShaderWriter::DeclareTexture2D(const SamplerDef &def) { case GLSL_VULKAN: // texBindingBase_ is used for the thin3d descriptor set layout, where they start at 1. if (def.flags & SamplerFlags::ARRAY_ON_VULKAN) { - F("layout(set = 0, binding = %d) uniform sampler2DArray %s;\n", def.binding + texBindingBase_, def.name); + F("layout(set = 1, binding = %d) uniform sampler2DArray %s;\n", def.binding + texBindingBase_, def.name); } else { - F("layout(set = 0, binding = %d) uniform sampler2D %s;\n", def.binding + texBindingBase_, def.name); + F("layout(set = 1, binding = %d) uniform sampler2D %s;\n", def.binding + texBindingBase_, def.name); } break; default: diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.cpp b/Common/GPU/Vulkan/VulkanQueueRunner.cpp index 1e31ca8525..47e5b94046 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.cpp +++ b/Common/GPU/Vulkan/VulkanQueueRunner.cpp @@ -1567,7 +1567,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c case VKRRenderCommand::DRAW_INDEXED: { - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &c.drawIndexed.ds, c.drawIndexed.numUboOffsets, c.drawIndexed.uboOffsets); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &c.drawIndexed.ds, c.drawIndexed.numUboOffsets, c.drawIndexed.uboOffsets); vkCmdBindIndexBuffer(cmd, c.drawIndexed.ibuffer, c.drawIndexed.ioffset, (VkIndexType)c.drawIndexed.indexType); VkDeviceSize voffset = c.drawIndexed.voffset; vkCmdBindVertexBuffers(cmd, 0, 1, &c.drawIndexed.vbuffer, &voffset); @@ -1576,7 +1576,7 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c } case VKRRenderCommand::DRAW: - vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 0, 1, &c.draw.ds, c.draw.numUboOffsets, c.draw.uboOffsets); + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, pipelineLayout, 1, 1, &c.draw.ds, c.draw.numUboOffsets, c.draw.uboOffsets); if (c.draw.vbuffer) { vkCmdBindVertexBuffers(cmd, 0, 1, &c.draw.vbuffer, &c.draw.voffset); } @@ -1625,6 +1625,10 @@ void VulkanQueueRunner::PerformRenderPass(const VKRStep &step, VkCommandBuffer c } break; + case VKRRenderCommand::BIND_DESCRIPTOR_SET: + vkCmdBindDescriptorSets(cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, c.bindDescSet.pipelineLayout, c.bindDescSet.setNumber, 1, &c.bindDescSet.set, 0, nullptr); + break; + default: ERROR_LOG(G3D, "Unimpl queue command"); break; diff --git a/Common/GPU/Vulkan/VulkanQueueRunner.h b/Common/GPU/Vulkan/VulkanQueueRunner.h index effc3645bc..2466e576f7 100644 --- a/Common/GPU/Vulkan/VulkanQueueRunner.h +++ b/Common/GPU/Vulkan/VulkanQueueRunner.h @@ -39,6 +39,7 @@ enum class VKRRenderCommand : uint8_t { PUSH_CONSTANTS, SELF_DEPENDENCY_BARRIER, DEBUG_ANNOTATION, + BIND_DESCRIPTOR_SET, NUM_RENDER_COMMANDS, }; @@ -152,6 +153,11 @@ struct VkRenderData { struct { const char *annotation; } debugAnnotation; + struct { + int setNumber; + VkDescriptorSet set; + VkPipelineLayout pipelineLayout; + } bindDescSet; }; }; diff --git a/Common/GPU/Vulkan/VulkanRenderManager.h b/Common/GPU/Vulkan/VulkanRenderManager.h index afe8ac15fe..c8ca219d17 100644 --- a/Common/GPU/Vulkan/VulkanRenderManager.h +++ b/Common/GPU/Vulkan/VulkanRenderManager.h @@ -270,6 +270,16 @@ public: compileMutex_.unlock(); } + // Mainly used to bind the frame-global desc set. + // Can be done before binding a pipeline, so not asserting on that. + void BindDescriptorSet(int setNumber, VkDescriptorSet set, VkPipelineLayout pipelineLayout) { + VkRenderData data{ VKRRenderCommand::BIND_DESCRIPTOR_SET }; + data.bindDescSet.setNumber = setNumber; + data.bindDescSet.set = set; + data.bindDescSet.pipelineLayout = pipelineLayout; + curRenderStep_->commands.push_back(data); + } + void BindPipeline(VKRGraphicsPipeline *pipeline, PipelineFlags flags, VkPipelineLayout pipelineLayout) { _dbg_assert_(curRenderStep_ && curRenderStep_->stepType == VKRStepType::RENDER); _dbg_assert_(pipeline != nullptr); diff --git a/Common/GPU/Vulkan/thin3d_vulkan.cpp b/Common/GPU/Vulkan/thin3d_vulkan.cpp index c5dcc65f40..fda775f1d0 100644 --- a/Common/GPU/Vulkan/thin3d_vulkan.cpp +++ b/Common/GPU/Vulkan/thin3d_vulkan.cpp @@ -35,15 +35,22 @@ #include "Core/Config.h" -// We use a simple descriptor set for all rendering: 1 sampler, 1 texture, 1 UBO binding point. -// binding 0 - uniform data -// binding 1 - sampler -// binding 2 - sampler -// -// Vertex data lives in a separate namespace (location = 0, 1, etc) - #include "Common/GPU/Vulkan/VulkanLoader.h" +// We support a frame-global descriptor set, which can be optionally used by other code, +// but is not directly used by thin3d. It has to be defined here though, be in set 0 +// and specified in every pipeline layout, otherwise it can't sit undisturbed when other +// descriptor sets are bound on top. + +// For descriptor set 1, we use a simple descriptor set for all thin3d rendering: 1 UBO binding point, 3 combined texture/samples. +// +// binding 0 - uniform buffer +// binding 1 - texture/sampler +// binding 2 - texture/sampler +// binding 3 - texture/sampler +// +// Vertex data lives in a separate namespace (location = 0, 1, etc). + using namespace PPSSPP_VK; namespace Draw { @@ -514,6 +521,7 @@ private: int curIBufferOffset_ = 0; VkDescriptorSetLayout descriptorSetLayout_ = VK_NULL_HANDLE; + VkDescriptorSetLayout frameDescSetLayout_ = VK_NULL_HANDLE; VkPipelineLayout pipelineLayout_ = VK_NULL_HANDLE; VkPipelineCache pipelineCache_ = VK_NULL_HANDLE; AutoRef curFramebuffer_; @@ -921,13 +929,25 @@ VKContext::VKContext(VulkanContext *vulkan) VkResult res = vkCreateDescriptorSetLayout(device_, &dsl, nullptr, &descriptorSetLayout_); _assert_(VK_SUCCESS == res); + VkDescriptorSetLayoutBinding frameBindings[1]{}; + frameBindings[0].descriptorCount = 1; + frameBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + frameBindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + frameBindings[0].binding = 0; + + dsl.bindingCount = ARRAY_SIZE(frameBindings); + dsl.pBindings = frameBindings; + res = vkCreateDescriptorSetLayout(device_, &dsl, nullptr, &frameDescSetLayout_); + _dbg_assert_(VK_SUCCESS == res); + vulkan_->SetDebugName(descriptorSetLayout_, VK_OBJECT_TYPE_DESCRIPTOR_SET_LAYOUT, "thin3d_d_layout"); VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; pl.pPushConstantRanges = nullptr; pl.pushConstantRangeCount = 0; - pl.setLayoutCount = 1; - pl.pSetLayouts = &descriptorSetLayout_; + VkDescriptorSetLayout setLayouts[2] = { frameDescSetLayout_, descriptorSetLayout_ }; + pl.setLayoutCount = ARRAY_SIZE(setLayouts); + pl.pSetLayouts = setLayouts; res = vkCreatePipelineLayout(device_, &pl, nullptr, &pipelineLayout_); _assert_(VK_SUCCESS == res); @@ -947,6 +967,7 @@ VKContext::~VKContext() { delete frame_[i].pushBuffer; } vulkan_->Delete().QueueDeleteDescriptorSetLayout(descriptorSetLayout_); + vulkan_->Delete().QueueDeleteDescriptorSetLayout(frameDescSetLayout_); vulkan_->Delete().QueueDeletePipelineLayout(pipelineLayout_); vulkan_->Delete().QueueDeletePipelineCache(pipelineCache_); } @@ -1681,6 +1702,11 @@ uint64_t VKContext::GetNativeObject(NativeObject obj, void *srcObject) { _dbg_assert_(layer < curFramebuffer_->Layers()); return (uint64_t)curFramebuffer_->GetFB()->color.texLayerViews[layer]; } + case NativeObject::FRAME_DATA_DESC_SET_LAYOUT: + return (uint64_t)frameDescSetLayout_; + case NativeObject::THIN3D_PIPELINE_LAYOUT: + return (uint64_t)pipelineLayout_; + default: Crash(); return 0; diff --git a/Common/GPU/thin3d.cpp b/Common/GPU/thin3d.cpp index ac2daa68c7..3aad02abc6 100644 --- a/Common/GPU/thin3d.cpp +++ b/Common/GPU/thin3d.cpp @@ -137,7 +137,7 @@ static const std::vector fsTexCol = { "layout(location = 0) in vec4 oColor0;\n" "layout(location = 1) in vec2 oTexCoord0;\n" "layout(location = 0) out vec4 fragColor0;\n" - "layout(set = 0, binding = 1) uniform sampler2D Sampler0;\n" + "layout(set = 1, binding = 1) uniform sampler2D Sampler0;\n" "void main() { fragColor0 = texture(Sampler0, oTexCoord0) * oColor0; }\n" } }; @@ -181,7 +181,7 @@ static const std::vector fsTexColRBSwizzle = { "layout(location = 0) in vec4 oColor0;\n" "layout(location = 1) in vec2 oTexCoord0;\n" "layout(location = 0) out vec4 fragColor0\n;" - "layout(set = 0, binding = 1) uniform sampler2D Sampler0;\n" + "layout(set = 1, binding = 1) uniform sampler2D Sampler0;\n" "void main() { fragColor0 = texture(Sampler0, oTexCoord0).bgra * oColor0; }\n" } }; @@ -270,7 +270,7 @@ static const std::vector vsCol = { R"(#version 450 #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable -layout (std140, set = 0, binding = 0) uniform bufferVals { +layout (std140, set = 1, binding = 0) uniform bufferVals { mat4 WorldViewProj; vec2 TintSaturation; } myBufferVals; @@ -416,7 +416,7 @@ VS_OUTPUT main(VS_INPUT input) { R"(#version 450 #extension GL_ARB_separate_shader_objects : enable #extension GL_ARB_shading_language_420pack : enable -layout (std140, set = 0, binding = 0) uniform bufferVals { +layout (std140, set = 1, binding = 0) uniform bufferVals { mat4 WorldViewProj; vec2 TintSaturation; } myBufferVals; diff --git a/Common/GPU/thin3d.h b/Common/GPU/thin3d.h index e617954010..695e1c83c8 100644 --- a/Common/GPU/thin3d.h +++ b/Common/GPU/thin3d.h @@ -249,6 +249,8 @@ enum class NativeObject { RENDER_MANAGER, TEXTURE_VIEW, NULL_IMAGEVIEW, + FRAME_DATA_DESC_SET_LAYOUT, + THIN3D_PIPELINE_LAYOUT, }; enum FBChannel { diff --git a/GPU/Common/FragmentShaderGenerator.cpp b/GPU/Common/FragmentShaderGenerator.cpp index 7f09f7c390..1cfd750540 100644 --- a/GPU/Common/FragmentShaderGenerator.cpp +++ b/GPU/Common/FragmentShaderGenerator.cpp @@ -185,23 +185,23 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu WRITE(p, "layout (depth_unchanged) out float gl_FragDepth;\n"); } - WRITE(p, "layout (std140, set = 0, binding = 3) uniform baseUBO {\n%s};\n", ub_baseStr); + WRITE(p, "layout (std140, set = 1, binding = 3) uniform baseUBO {\n%s};\n", ub_baseStr); if (doTexture) { - WRITE(p, "layout (binding = 0) uniform %s%s tex;\n", texture3D ? "sampler3D" : "sampler2D", arrayTexture ? "Array" : ""); + WRITE(p, "layout (set = 1, binding = 0) uniform %s%s tex;\n", texture3D ? "sampler3D" : "sampler2D", arrayTexture ? "Array" : ""); } if (readFramebufferTex) { // The framebuffer texture is always bound as an array. - p.C("layout (binding = 1) uniform sampler2DArray fbotex;\n"); + p.C("layout (set = 1, binding = 1) uniform sampler2DArray fbotex;\n"); } else if (fetchFramebuffer) { - p.C("layout (input_attachment_index = 0, binding = 9) uniform subpassInput inputColor;\n"); + p.C("layout (input_attachment_index = 0, set = 1, binding = 9) uniform subpassInput inputColor;\n"); if (fragmentShaderFlags) { *fragmentShaderFlags |= FragmentShaderFlags::INPUT_ATTACHMENT; } } if (shaderDepalMode != ShaderDepalMode::OFF) { - WRITE(p, "layout (binding = 2) uniform sampler2D pal;\n"); + WRITE(p, "layout (set = 1, binding = 2) uniform sampler2D pal;\n"); } // Note: the precision qualifiers must match the vertex shader! diff --git a/GPU/Common/PresentationCommon.cpp b/GPU/Common/PresentationCommon.cpp index 025888896c..b4e05d8d50 100644 --- a/GPU/Common/PresentationCommon.cpp +++ b/GPU/Common/PresentationCommon.cpp @@ -233,14 +233,13 @@ bool PresentationCommon::UpdatePostShader() { if (gstate_c.Use(GPU_USE_SIMPLE_STEREO_PERSPECTIVE)) { const ShaderInfo *stereoShaderInfo = GetPostShaderInfo(g_Config.sStereoToMonoShader); - bool result = CompilePostShader(stereoShaderInfo, &stereoPipeline_); - if (!result) { - // We won't have a stereo shader. We have to check for this later. - delete stereoShaderInfo_; - stereoShaderInfo_ = nullptr; - stereoPipeline_ = nullptr; + if (stereoShaderInfo) { + bool result = CompilePostShader(stereoShaderInfo, &stereoPipeline_); + if (result) { + stereoShaderInfo_ = new ShaderInfo(*stereoShaderInfo); + } } else { - stereoShaderInfo_ = new ShaderInfo(*stereoShaderInfo); + WARN_LOG(G3D, "Failed to get info about stereo shader '%s'", g_Config.sStereoToMonoShader.c_str()); } } @@ -296,6 +295,8 @@ bool PresentationCommon::UpdatePostShader() { } bool PresentationCommon::CompilePostShader(const ShaderInfo *shaderInfo, Draw::Pipeline **outPipeline) const { + _assert_(shaderInfo); + std::string vsSourceGLSL = ReadShaderSrc(shaderInfo->vertexShaderFile); std::string fsSourceGLSL = ReadShaderSrc(shaderInfo->fragmentShaderFile); if (vsSourceGLSL.empty() || fsSourceGLSL.empty()) { diff --git a/GPU/Common/ShaderUniforms.h b/GPU/Common/ShaderUniforms.h index 96cfe98411..12bc273da3 100644 --- a/GPU/Common/ShaderUniforms.h +++ b/GPU/Common/ShaderUniforms.h @@ -133,12 +133,12 @@ R"( mat3x4 u_bone0; mat3x4 u_bone1; mat3x4 u_bone2; mat3x4 u_bone3; mat3x4 u_bon static const char * const ub_frame_globalstr = -R"( vec4 unused; +R"( vec4 stereoParams; )"; -// VR stuff will go here. +// Frame-global uniforms. struct UB_FrameGlobal { - float unused[4]; + float stereoParams[4]; }; void CalcCullRange(float minValues[4], float maxValues[4], bool flipViewport, bool hasNegZ); diff --git a/GPU/Common/VertexShaderGenerator.cpp b/GPU/Common/VertexShaderGenerator.cpp index cbf51f1b24..6c6cc57ab2 100644 --- a/GPU/Common/VertexShaderGenerator.cpp +++ b/GPU/Common/VertexShaderGenerator.cpp @@ -249,11 +249,11 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag if (compat.shaderLanguage == GLSL_VULKAN) { WRITE(p, "\n"); - WRITE(p, "layout (std140, set = 0, binding = 3) uniform baseVars {\n%s};\n", ub_baseStr); + WRITE(p, "layout (std140, set = 1, binding = 3) uniform baseVars {\n%s};\n", ub_baseStr); if (enableLighting || doShadeMapping) - WRITE(p, "layout (std140, set = 0, binding = 4) uniform lightVars {\n%s};\n", ub_vs_lightsStr); + WRITE(p, "layout (std140, set = 1, binding = 4) uniform lightVars {\n%s};\n", ub_vs_lightsStr); if (enableBones) - WRITE(p, "layout (std140, set = 0, binding = 5) uniform boneVars {\n%s};\n", ub_vs_bonesStr); + WRITE(p, "layout (std140, set = 1, binding = 5) uniform boneVars {\n%s};\n", ub_vs_bonesStr); if (enableBones) { WRITE(p, "%s", boneWeightDecl[numBoneWeights]); @@ -631,7 +631,7 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " vec4 tex;\n"); WRITE(p, " vec4 col;\n"); WRITE(p, "};\n"); - WRITE(p, "layout (std430, set = 0, binding = 6) readonly buffer s_tess_data {\n"); + WRITE(p, "layout (std430, set = 1, binding = 6) readonly buffer s_tess_data {\n"); WRITE(p, " TessData tess_data[];\n"); WRITE(p, "};\n"); @@ -639,10 +639,10 @@ bool GenerateVertexShader(const VShaderID &id, char *buffer, const ShaderLanguag WRITE(p, " vec4 basis;\n"); WRITE(p, " vec4 deriv;\n"); WRITE(p, "};\n"); - WRITE(p, "layout (std430, set = 0, binding = 7) readonly buffer s_tess_weights_u {\n"); + WRITE(p, "layout (std430, set = 1, binding = 7) readonly buffer s_tess_weights_u {\n"); WRITE(p, " TessWeight tess_weights_u[];\n"); WRITE(p, "};\n"); - WRITE(p, "layout (std430, set = 0, binding = 8) readonly buffer s_tess_weights_v {\n"); + WRITE(p, "layout (std430, set = 1, binding = 8) readonly buffer s_tess_weights_v {\n"); WRITE(p, " TessWeight tess_weights_v[];\n"); WRITE(p, "};\n"); } else if (ShaderLanguageIsOpenGL(compat.shaderLanguage)) { diff --git a/GPU/Vulkan/DrawEngineVulkan.cpp b/GPU/Vulkan/DrawEngineVulkan.cpp index 8af2727736..68108fe107 100644 --- a/GPU/Vulkan/DrawEngineVulkan.cpp +++ b/GPU/Vulkan/DrawEngineVulkan.cpp @@ -154,7 +154,7 @@ void DrawEngineVulkan::InitDeviceObjects() { static constexpr int DEFAULT_DESC_POOL_SIZE = 512; std::vector dpTypes; - dpTypes.resize(4); + dpTypes.resize(5); dpTypes[0].descriptorCount = DEFAULT_DESC_POOL_SIZE * 3; dpTypes[0].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; dpTypes[1].descriptorCount = DEFAULT_DESC_POOL_SIZE * 3; // Don't use these for tess anymore, need max three per set. @@ -163,6 +163,8 @@ void DrawEngineVulkan::InitDeviceObjects() { dpTypes[2].type = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER; dpTypes[3].descriptorCount = DEFAULT_DESC_POOL_SIZE; // TODO: Use a separate layout when no spline stuff is needed to reduce the need for these. dpTypes[3].type = VK_DESCRIPTOR_TYPE_INPUT_ATTACHMENT; + dpTypes[4].descriptorCount = 1; // For the frame global uniform buffer. + dpTypes[4].type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; VkDescriptorPoolCreateInfo dp{ VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO }; // Don't want to mess around with individually freeing these. @@ -185,10 +187,12 @@ void DrawEngineVulkan::InitDeviceObjects() { VkPipelineLayoutCreateInfo pl{ VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; pl.pPushConstantRanges = nullptr; pl.pushConstantRangeCount = 0; - VkDescriptorSetLayout layouts[1] = { descriptorSetLayout_ }; + VkDescriptorSetLayout frameDescSetLayout = (VkDescriptorSetLayout)draw_->GetNativeObject(Draw::NativeObject::FRAME_DATA_DESC_SET_LAYOUT); + VkDescriptorSetLayout layouts[2] = { frameDescSetLayout, descriptorSetLayout_}; pl.setLayoutCount = ARRAY_SIZE(layouts); pl.pSetLayouts = layouts; pl.flags = 0; + res = vkCreatePipelineLayout(device, &pl, nullptr, &pipelineLayout_); _dbg_assert_(VK_SUCCESS == res); @@ -310,7 +314,8 @@ void DrawEngineVulkan::BeginFrame() { frame->pushVertex->Begin(vulkan); frame->pushIndex->Begin(vulkan); - // TODO: How can we make this nicer... + frame->frameDescSetUpdated = false; + tessDataTransferVulkan->SetPushBuffer(frame->pushUBO); DirtyAllUBOs(); @@ -1014,6 +1019,30 @@ void DrawEngineVulkan::DoFlush() { } void DrawEngineVulkan::UpdateUBOs(FrameData *frame) { + if (!frame->frameDescSetUpdated) { + // Push frame global constants. + UB_FrameGlobal frameConstants{}; + VkDescriptorBufferInfo frameConstantsBufInfo; + frame->pushUBO->PushUBOData(frameConstants, &frameConstantsBufInfo); + + VulkanContext *vulkan = (VulkanContext *)draw_->GetNativeObject(Draw::NativeObject::CONTEXT); + VulkanRenderManager *renderManager = (VulkanRenderManager *)draw_->GetNativeObject(Draw::NativeObject::RENDER_MANAGER); + VkDescriptorSetLayout frameDescSetLayout = (VkDescriptorSetLayout)draw_->GetNativeObject(Draw::NativeObject::FRAME_DATA_DESC_SET_LAYOUT); + + VkDescriptorSet frameDescSet = frame->descPool.Allocate(1, &frameDescSetLayout, "frame_desc_set"); + + VkWriteDescriptorSet descWrite{ VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET }; + descWrite.descriptorCount = 1; + descWrite.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; + descWrite.dstBinding = 0; + descWrite.dstSet = frameDescSet; + descWrite.pBufferInfo = &frameConstantsBufInfo; + vkUpdateDescriptorSets(vulkan->GetDevice(), 1, &descWrite, 0, nullptr); + renderManager->BindDescriptorSet(0, frameDescSet, pipelineLayout_); + + frame->frameDescSetUpdated = true; + } + if ((dirtyUniforms_ & DIRTY_BASE_UNIFORMS) || baseBuf == VK_NULL_HANDLE) { baseUBOOffset = shaderManager_->PushBaseBuffer(frame->pushUBO, &baseBuf); dirtyUniforms_ &= ~DIRTY_BASE_UNIFORMS; diff --git a/GPU/Vulkan/DrawEngineVulkan.h b/GPU/Vulkan/DrawEngineVulkan.h index 258f95ae6d..035bc595df 100644 --- a/GPU/Vulkan/DrawEngineVulkan.h +++ b/GPU/Vulkan/DrawEngineVulkan.h @@ -211,7 +211,8 @@ private: Draw::DrawContext *draw_; - // We use a shared descriptor set layout for all PSP draws. + // We use a shared descriptor set layouts for all PSP draws. + // Descriptors created from descriptorSetLayout_ is rebound all the time at set 1. VkDescriptorSetLayout descriptorSetLayout_; VkPipelineLayout pipelineLayout_; @@ -254,6 +255,8 @@ private: VulkanPushBuffer *pushVertex = nullptr; VulkanPushBuffer *pushIndex = nullptr; + bool frameDescSetUpdated = false; + // We do rolling allocation and reset instead of caching across frames. That we might do later. DenseHashMap descSets; diff --git a/GPU/Vulkan/TextureCacheVulkan.cpp b/GPU/Vulkan/TextureCacheVulkan.cpp index 8f80aa8474..d536bedabd 100644 --- a/GPU/Vulkan/TextureCacheVulkan.cpp +++ b/GPU/Vulkan/TextureCacheVulkan.cpp @@ -65,9 +65,9 @@ const char *uploadShader = R"( // hardware vendors. layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in; -uniform layout(binding = 0, rgba8) writeonly image2D img; +uniform layout(set = 1, binding = 0, rgba8) writeonly image2D img; -layout(std430, binding = 1) buffer Buf { +layout(std430, set = 1, binding = 1) buffer Buf { uint data[]; } buf; @@ -251,7 +251,7 @@ void TextureCacheVulkan::DeviceRestore(Draw::DrawContext *draw) { CompileScalingShader(); - computeShaderManager_.DeviceRestore(vulkan); + computeShaderManager_.DeviceRestore(draw); } void TextureCacheVulkan::NotifyConfigChanged() { @@ -626,7 +626,7 @@ void TextureCacheVulkan::BuildTexture(TexCacheEntry *const entry) { VK_PROFILE_BEGIN(vulkan, cmdInit, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, "Compute Upload: %dx%d->%dx%d", mipUnscaledWidth, mipUnscaledHeight, mipWidth, mipHeight); vkCmdBindPipeline(cmdInit, VK_PIPELINE_BIND_POINT_COMPUTE, computeShaderManager_.GetPipeline(uploadCS_)); - vkCmdBindDescriptorSets(cmdInit, VK_PIPELINE_BIND_POINT_COMPUTE, computeShaderManager_.GetPipelineLayout(), 0, 1, &descSet, 0, nullptr); + vkCmdBindDescriptorSets(cmdInit, VK_PIPELINE_BIND_POINT_COMPUTE, computeShaderManager_.GetPipelineLayout(), 1, 1, &descSet, 0, nullptr); vkCmdPushConstants(cmdInit, computeShaderManager_.GetPipelineLayout(), VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(params), ¶ms); vkCmdDispatch(cmdInit, (mipUnscaledWidth + 7) / 8, (mipUnscaledHeight + 7) / 8, 1); VK_PROFILE_END(vulkan, cmdInit, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT); diff --git a/GPU/Vulkan/VulkanUtil.cpp b/GPU/Vulkan/VulkanUtil.cpp index d23f2ad9b2..fbfb8ad3fa 100644 --- a/GPU/Vulkan/VulkanUtil.cpp +++ b/GPU/Vulkan/VulkanUtil.cpp @@ -56,7 +56,7 @@ VulkanComputeShaderManager::VulkanComputeShaderManager(VulkanContext *vulkan) : } VulkanComputeShaderManager::~VulkanComputeShaderManager() {} -void VulkanComputeShaderManager::InitDeviceObjects() { +void VulkanComputeShaderManager::InitDeviceObjects(Draw::DrawContext *draw) { VkPipelineCacheCreateInfo pc{ VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO }; VkResult res = vkCreatePipelineCache(vulkan_->GetDevice(), &pc, nullptr, &pipelineCache_); _assert_(VK_SUCCESS == res); @@ -106,8 +106,10 @@ void VulkanComputeShaderManager::InitDeviceObjects() { VkPipelineLayoutCreateInfo pl = { VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO }; pl.pPushConstantRanges = &push; pl.pushConstantRangeCount = 1; - pl.setLayoutCount = 1; - pl.pSetLayouts = &descriptorSetLayout_; + VkDescriptorSetLayout frameDescSetLayout = (VkDescriptorSetLayout)draw->GetNativeObject(Draw::NativeObject::FRAME_DATA_DESC_SET_LAYOUT); + VkDescriptorSetLayout setLayouts[2] = { frameDescSetLayout, descriptorSetLayout_ }; + pl.setLayoutCount = ARRAY_SIZE(setLayouts); + pl.pSetLayouts = setLayouts; pl.flags = 0; res = vkCreatePipelineLayout(device, &pl, nullptr, &pipelineLayout_); _assert_(VK_SUCCESS == res); diff --git a/GPU/Vulkan/VulkanUtil.h b/GPU/Vulkan/VulkanUtil.h index b31fdb75f9..8663d3ce1e 100644 --- a/GPU/Vulkan/VulkanUtil.h +++ b/GPU/Vulkan/VulkanUtil.h @@ -25,6 +25,7 @@ #include "Common/GPU/Vulkan/VulkanImage.h" #include "Common/GPU/Vulkan/VulkanLoader.h" #include "Common/GPU/Vulkan/VulkanMemory.h" +#include "Common/GPU/thin3d.h" extern const VkComponentMapping VULKAN_4444_SWIZZLE; extern const VkComponentMapping VULKAN_1555_SWIZZLE; @@ -47,9 +48,9 @@ public: void DeviceLost() { DestroyDeviceObjects(); } - void DeviceRestore(VulkanContext *vulkan) { - vulkan_ = vulkan; - InitDeviceObjects(); + void DeviceRestore(Draw::DrawContext *draw) { + vulkan_ = (VulkanContext *)draw->GetNativeObject(Draw::NativeObject::CONTEXT); + InitDeviceObjects(draw); } // Note: This doesn't cache. The descriptor is for immediate use only. @@ -63,7 +64,7 @@ public: void EndFrame(); private: - void InitDeviceObjects(); + void InitDeviceObjects(Draw::DrawContext *draw); void DestroyDeviceObjects(); VulkanContext *vulkan_ = nullptr; diff --git a/UI/GPUDriverTestScreen.cpp b/UI/GPUDriverTestScreen.cpp index 023b9e1def..ab0a11d300 100644 --- a/UI/GPUDriverTestScreen.cpp +++ b/UI/GPUDriverTestScreen.cpp @@ -44,7 +44,7 @@ static const std::vector fsDiscard = { layout(location = 0) in vec4 oColor0; layout(location = 1) in vec2 oTexCoord0; layout(location = 0) out vec4 fragColor0; - layout(set = 0, binding = 1) uniform sampler2D Sampler0; + layout(set = 1, binding = 1) uniform sampler2D Sampler0; void main() { vec4 color = texture(Sampler0, oTexCoord0) * oColor0; if (color.a <= 0.0) @@ -86,7 +86,7 @@ static const std::vector fsAdrenoLogicTest = { layout(location = 0) in vec4 oColor0; layout(location = 1) in highp vec2 oTexCoord0; layout(location = 0) out vec4 fragColor0; - layout(set = 0, binding = 1) uniform sampler2D Sampler0; + layout(set = 1, binding = 1) uniform sampler2D Sampler0; void main() { vec4 v = texture(Sampler0, oTexCoord0).aaaa * oColor0; if (v.r < 0.2 && v.g < 0.2 && v.b < 0.2) discard; @@ -117,7 +117,7 @@ static const std::vector vsAdrenoLogicTest = { "#version 450\n" "#extension GL_ARB_separate_shader_objects : enable\n" "#extension GL_ARB_shading_language_420pack : enable\n" - "layout (std140, set = 0, binding = 0) uniform bufferVals {\n" + "layout (std140, set = 1, binding = 0) uniform bufferVals {\n" " mat4 WorldViewProj;\n" "} myBufferVals;\n" "layout (location = 0) in vec4 pos;\n" @@ -173,7 +173,7 @@ static const std::vector fsFlat = { "layout(location = 0) flat in lowp vec4 oColor0;\n" "layout(location = 1) in highp vec2 oTexCoord0;\n" "layout(location = 0) out vec4 fragColor0;\n" - "layout(set = 0, binding = 1) uniform sampler2D Sampler0;\n" + "layout(set = 1, binding = 1) uniform sampler2D Sampler0;\n" "void main() { fragColor0 = texture(Sampler0, oTexCoord0) * oColor0; }\n" } }; @@ -214,7 +214,7 @@ static const std::vector vsFlat = { "#version 450\n" "#extension GL_ARB_separate_shader_objects : enable\n" "#extension GL_ARB_shading_language_420pack : enable\n" - "layout (std140, set = 0, binding = 0) uniform bufferVals {\n" + "layout (std140, set = 1, binding = 0) uniform bufferVals {\n" " mat4 WorldViewProj;\n" "} myBufferVals;\n" "layout (location = 0) in vec4 pos;\n"