mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-26 23:10:38 +00:00
Add support for the EXT_provoking_vertex Vulkan extension, allowing us to skip software transform for this case.
This commit is contained in:
parent
2a35a92514
commit
138193a776
@ -691,6 +691,8 @@ VkResult VulkanContext::CreateDevice(int physical_device) {
|
||||
extensionsLookup_.KHR_present_wait = EnableDeviceExtension(VK_KHR_PRESENT_WAIT_EXTENSION_NAME, 0);
|
||||
}
|
||||
|
||||
extensionsLookup_.EXT_provoking_vertex = EnableDeviceExtension(VK_EXT_PROVOKING_VERTEX_EXTENSION_NAME, 0);
|
||||
|
||||
// Optional features
|
||||
if (extensionsLookup_.KHR_get_physical_device_properties2 && vkGetPhysicalDeviceFeatures2) {
|
||||
VkPhysicalDeviceFeatures2 features2{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR };
|
||||
@ -698,17 +700,23 @@ VkResult VulkanContext::CreateDevice(int physical_device) {
|
||||
VkPhysicalDeviceMultiviewFeatures multiViewFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES };
|
||||
VkPhysicalDevicePresentWaitFeaturesKHR presentWaitFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_WAIT_FEATURES_KHR };
|
||||
VkPhysicalDevicePresentIdFeaturesKHR presentIdFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PRESENT_ID_FEATURES_KHR };
|
||||
VkPhysicalDeviceProvokingVertexFeaturesEXT provokingVertexFeatures{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT };
|
||||
|
||||
features2.pNext = &multiViewFeatures;
|
||||
multiViewFeatures.pNext = &presentWaitFeatures;
|
||||
presentWaitFeatures.pNext = &presentIdFeatures;
|
||||
presentIdFeatures.pNext = nullptr;
|
||||
|
||||
if (extensionsLookup_.EXT_provoking_vertex) {
|
||||
presentIdFeatures.pNext = &provokingVertexFeatures;
|
||||
provokingVertexFeatures.pNext = nullptr;
|
||||
} else {
|
||||
presentIdFeatures.pNext = nullptr;
|
||||
}
|
||||
vkGetPhysicalDeviceFeatures2(physical_devices_[physical_device_], &features2);
|
||||
deviceFeatures_.available.standard = features2.features;
|
||||
deviceFeatures_.available.multiview = multiViewFeatures;
|
||||
deviceFeatures_.available.presentWait = presentWaitFeatures;
|
||||
deviceFeatures_.available.presentId = presentIdFeatures;
|
||||
deviceFeatures_.available.provokingVertex = provokingVertexFeatures;
|
||||
} else {
|
||||
vkGetPhysicalDeviceFeatures(physical_devices_[physical_device_], &deviceFeatures_.available.standard);
|
||||
deviceFeatures_.available.multiview = {};
|
||||
@ -744,6 +752,11 @@ VkResult VulkanContext::CreateDevice(int physical_device) {
|
||||
if (extensionsLookup_.KHR_present_wait) {
|
||||
deviceFeatures_.enabled.presentWait.presentWait = deviceFeatures_.available.presentWait.presentWait;
|
||||
}
|
||||
deviceFeatures_.enabled.provokingVertex = { VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROVOKING_VERTEX_FEATURES_EXT };
|
||||
if (extensionsLookup_.EXT_provoking_vertex) {
|
||||
deviceFeatures_.enabled.provokingVertex.provokingVertexLast = true;
|
||||
}
|
||||
|
||||
// deviceFeatures_.enabled.multiview.multiviewGeometryShader = deviceFeatures_.available.multiview.multiviewGeometryShader;
|
||||
|
||||
VkPhysicalDeviceFeatures2 features2{ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2 };
|
||||
@ -762,7 +775,13 @@ VkResult VulkanContext::CreateDevice(int physical_device) {
|
||||
features2.pNext = &deviceFeatures_.enabled.multiview;
|
||||
deviceFeatures_.enabled.multiview.pNext = &deviceFeatures_.enabled.presentWait;
|
||||
deviceFeatures_.enabled.presentWait.pNext = &deviceFeatures_.enabled.presentId;
|
||||
deviceFeatures_.enabled.presentId.pNext = nullptr;
|
||||
if (extensionsLookup_.EXT_provoking_vertex) {
|
||||
// TODO: Write some proper chaining thing.
|
||||
deviceFeatures_.enabled.presentId.pNext = &deviceFeatures_.enabled.provokingVertex;
|
||||
deviceFeatures_.enabled.provokingVertex.pNext = nullptr;
|
||||
} else {
|
||||
deviceFeatures_.enabled.presentId.pNext = nullptr;
|
||||
}
|
||||
} else {
|
||||
device_info.pEnabledFeatures = &deviceFeatures_.enabled.standard;
|
||||
}
|
||||
|
@ -279,6 +279,7 @@ public:
|
||||
VkPhysicalDeviceMultiviewFeatures multiview;
|
||||
VkPhysicalDevicePresentWaitFeaturesKHR presentWait;
|
||||
VkPhysicalDevicePresentIdFeaturesKHR presentId;
|
||||
VkPhysicalDeviceProvokingVertexFeaturesEXT provokingVertex;
|
||||
};
|
||||
|
||||
const PhysicalDeviceProps &GetPhysicalDeviceProperties(int i = -1) const {
|
||||
|
@ -268,6 +268,7 @@ struct VulkanExtensions {
|
||||
bool KHR_present_id; // Should probably check the feature flags instead.
|
||||
bool KHR_present_wait; // Same
|
||||
bool GOOGLE_display_timing;
|
||||
bool EXT_provoking_vertex;
|
||||
// bool EXT_depth_range_unrestricted; // Allows depth outside [0.0, 1.0] in 32-bit float depth buffers.
|
||||
};
|
||||
|
||||
|
@ -50,6 +50,7 @@ enum class PipelineFlags : u8 {
|
||||
USES_GEOMETRY_SHADER = (1 << 3),
|
||||
USES_MULTIVIEW = (1 << 4), // Inherited from the render pass it was created with.
|
||||
USES_DISCARD = (1 << 5),
|
||||
USES_FLAT_SHADING = (1 << 6),
|
||||
};
|
||||
ENUM_CLASS_BITOPS(PipelineFlags);
|
||||
|
||||
|
@ -90,6 +90,7 @@ public:
|
||||
VkDynamicState dynamicStates[6]{};
|
||||
VkPipelineDynamicStateCreateInfo ds{ VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
|
||||
VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
|
||||
VkPipelineRasterizationProvokingVertexStateCreateInfoEXT rs_provoking{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_PROVOKING_VERTEX_STATE_CREATE_INFO_EXT };
|
||||
|
||||
// Replaced the ShaderStageInfo with promises here so we can wait for compiles to finish.
|
||||
Promise<VkShaderModule> *vertexShader = nullptr;
|
||||
|
@ -1221,8 +1221,6 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char
|
||||
|
||||
gDesc.dss = depth->info;
|
||||
|
||||
raster->ToVulkan(&gDesc.rs);
|
||||
|
||||
// Copy bindings from input layout.
|
||||
gDesc.topology = primToVK[(int)desc.prim];
|
||||
|
||||
@ -1244,6 +1242,11 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc, const char
|
||||
VkPipelineRasterizationStateCreateInfo rs{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO };
|
||||
raster->ToVulkan(&gDesc.rs);
|
||||
|
||||
if (renderManager_.GetVulkanContext()->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast) {
|
||||
gDesc.rs.pNext = &gDesc.rs_provoking;
|
||||
gDesc.rs_provoking.provokingVertexMode = VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT;
|
||||
}
|
||||
|
||||
pipeline->pipeline = renderManager_.CreateGraphicsPipeline(&gDesc, pipelineFlags, 1 << (size_t)RenderPassType::BACKBUFFER, VK_SAMPLE_COUNT_1_BIT, false, tag ? tag : "thin3d");
|
||||
|
||||
if (desc.uniformDesc) {
|
||||
@ -1564,6 +1567,7 @@ std::vector<std::string> VKContext::GetFeatureList() const {
|
||||
AddFeature(features, "multiviewGeometryShader", vulkan_->GetDeviceFeatures().available.multiview.multiviewGeometryShader, vulkan_->GetDeviceFeatures().enabled.multiview.multiviewGeometryShader);
|
||||
AddFeature(features, "presentId", vulkan_->GetDeviceFeatures().available.presentId.presentId, vulkan_->GetDeviceFeatures().enabled.presentId.presentId);
|
||||
AddFeature(features, "presentWait", vulkan_->GetDeviceFeatures().available.presentWait.presentWait, vulkan_->GetDeviceFeatures().enabled.presentWait.presentWait);
|
||||
AddFeature(features, "provokingVertexLast", vulkan_->GetDeviceFeatures().available.provokingVertex.provokingVertexLast, vulkan_->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast);
|
||||
|
||||
features.emplace_back(std::string("Preferred depth buffer format: ") + VulkanFormatToString(vulkan_->GetDeviceInfo().preferredDepthStencilFormat));
|
||||
|
||||
|
@ -132,8 +132,8 @@ void VR_GetResolution(engine_t* engine, int *pWidth, int *pHeight) {
|
||||
*pHeight = height;
|
||||
}
|
||||
|
||||
*pWidth *= VR_GetConfigFloat(VR_CONFIG_VIEWPORT_SUPERSAMPLING);
|
||||
*pHeight *= VR_GetConfigFloat(VR_CONFIG_VIEWPORT_SUPERSAMPLING);
|
||||
*pWidth = (int)(*pWidth * VR_GetConfigFloat(VR_CONFIG_VIEWPORT_SUPERSAMPLING));
|
||||
*pHeight = (int)(*pHeight * VR_GetConfigFloat(VR_CONFIG_VIEWPORT_SUPERSAMPLING));
|
||||
}
|
||||
|
||||
void VR_Recenter(engine_t* engine) {
|
||||
|
@ -124,6 +124,10 @@ bool GenerateFragmentShader(const FShaderID &id, char *buffer, const ShaderLangu
|
||||
bool flatBug = bugs.Has(Draw::Bugs::BROKEN_FLAT_IN_SHADER) && g_Config.bVendorBugChecksEnabled;
|
||||
|
||||
bool doFlatShading = id.Bit(FS_BIT_FLATSHADE) && !flatBug;
|
||||
if (doFlatShading) {
|
||||
*fragmentShaderFlags |= FragmentShaderFlags::USES_FLAT_SHADING;
|
||||
}
|
||||
|
||||
ShaderDepalMode shaderDepalMode = (ShaderDepalMode)id.Bits(FS_BIT_SHADER_DEPAL_MODE, 2);
|
||||
if (texture3D) {
|
||||
shaderDepalMode = ShaderDepalMode::OFF;
|
||||
|
@ -47,6 +47,7 @@ struct FShaderID;
|
||||
// Can technically be deduced from the fragment shader ID, but this is safer.
|
||||
enum class FragmentShaderFlags : u32 {
|
||||
USES_DISCARD = 2,
|
||||
USES_FLAT_SHADING = 4,
|
||||
};
|
||||
ENUM_CLASS_BITOPS(FragmentShaderFlags);
|
||||
|
||||
|
@ -229,12 +229,17 @@ void DrawEngineVulkan::DoFlush() {
|
||||
|
||||
GEPrimitiveType prim = prevPrim_;
|
||||
|
||||
// Always use software for flat shading to fix the provoking index.
|
||||
bool useHWTransform = CanUseHardwareTransform(prim) && (tess || gstate.getShadeMode() != GE_SHADE_FLAT);
|
||||
// Always use software for flat shading to fix the provoking index
|
||||
// if the provoking vertex extension is not available.
|
||||
bool provokingVertexOk = (tess || gstate.getShadeMode() != GE_SHADE_FLAT);
|
||||
if (renderManager->GetVulkanContext()->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast) {
|
||||
provokingVertexOk = true;
|
||||
}
|
||||
bool useHWTransform = CanUseHardwareTransform(prim) && provokingVertexOk;
|
||||
|
||||
uint32_t ibOffset;
|
||||
uint32_t vbOffset;
|
||||
|
||||
|
||||
// The optimization to avoid indexing isn't really worth it on Vulkan since it means creating more pipelines.
|
||||
// This could be avoided with the new dynamic state extensions, but not available enough on mobile.
|
||||
const bool forceIndexed = draw_->GetDeviceCaps().verySlowShaderCompiler;
|
||||
@ -399,6 +404,10 @@ void DrawEngineVulkan::DoFlush() {
|
||||
params.allowClear = framebufferManager_->UseBufferedRendering();
|
||||
params.allowSeparateAlphaClear = false;
|
||||
params.provokeFlatFirst = true;
|
||||
if (renderManager->GetVulkanContext()->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast) {
|
||||
// We can get the OpenGL behavior, no need for workarounds.
|
||||
params.provokeFlatFirst = false;
|
||||
}
|
||||
params.flippedY = true;
|
||||
params.usesHalfZ = true;
|
||||
|
||||
|
@ -285,6 +285,11 @@ static VulkanPipeline *CreateVulkanPipeline(VulkanRenderManager *renderManager,
|
||||
rs.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
rs.depthClampEnable = key.depthClampEnable;
|
||||
|
||||
if (renderManager->GetVulkanContext()->GetDeviceFeatures().enabled.provokingVertex.provokingVertexLast) {
|
||||
rs.pNext = &desc->rs_provoking;
|
||||
desc->rs_provoking.provokingVertexMode = VK_PROVOKING_VERTEX_MODE_LAST_VERTEX_EXT;
|
||||
}
|
||||
|
||||
desc->fragmentShaderSource = fs->GetShaderString(SHADER_STRING_SOURCE_CODE);
|
||||
desc->vertexShaderSource = vs->GetShaderString(SHADER_STRING_SOURCE_CODE);
|
||||
if (gs) {
|
||||
@ -376,6 +381,9 @@ VulkanPipeline *PipelineManagerVulkan::GetOrCreatePipeline(VulkanRenderManager *
|
||||
if (fs->Flags() & FragmentShaderFlags::USES_DISCARD) {
|
||||
pipelineFlags |= PipelineFlags::USES_DISCARD;
|
||||
}
|
||||
if (fs->Flags() & FragmentShaderFlags::USES_FLAT_SHADING) {
|
||||
pipelineFlags |= PipelineFlags::USES_FLAT_SHADING;
|
||||
}
|
||||
if (vs->Flags() & VertexShaderFlags::MULTI_VIEW) {
|
||||
pipelineFlags |= PipelineFlags::USES_MULTIVIEW;
|
||||
}
|
||||
|
@ -75,6 +75,7 @@ struct VulkanPipeline {
|
||||
bool UsesDepthStencil() const { return (pipelineFlags & PipelineFlags::USES_DEPTH_STENCIL) != 0; }
|
||||
bool UsesGeometryShader() const { return (pipelineFlags & PipelineFlags::USES_GEOMETRY_SHADER) != 0; }
|
||||
bool UsesDiscard() const { return (pipelineFlags & PipelineFlags::USES_DISCARD) != 0; }
|
||||
bool UsesFlatShading() const { return (pipelineFlags & PipelineFlags::USES_FLAT_SHADING) != 0; }
|
||||
|
||||
u32 GetVariantsBitmask() const;
|
||||
};
|
||||
|
@ -616,7 +616,7 @@ void GPUDriverTestScreen::ShaderTest(UIContext &dc) {
|
||||
// Draw rectangle that should be flat shaded
|
||||
dc.BeginPipeline(flatShadingPipeline_, samplerNearest_);
|
||||
// There is a "provoking vertex" difference here between GL and Vulkan when using flat shading. One gets one color, one gets the other.
|
||||
// Wherever possible we should reconfigure the GL provoking vertex to match Vulkan, probably.
|
||||
// However, we now use the VK_EXT_provoking_vertex extension to make it match up (and match with the PSP).
|
||||
dc.DrawImageVGradient(ImageID("I_ICON"), 0xFFFFFFFF, 0xFF808080, bounds);
|
||||
dc.Flush();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user