1
0
mirror of https://github.com/doitsujin/dxvk.git synced 2024-12-14 00:48:44 +01:00

[dxvk] Perform more extensive validation on pipeline state vectors

This commit is contained in:
Philip Rebohle 2022-05-06 15:25:36 +02:00
parent 4ff7687dea
commit 80e125a130
No known key found for this signature in database
GPG Key ID: C8CC613427A31C99
2 changed files with 81 additions and 6 deletions

View File

@ -67,7 +67,7 @@ namespace dxvk {
if (unlikely(!instance)) { if (unlikely(!instance)) {
// Exit early if the state vector is invalid // Exit early if the state vector is invalid
if (!this->validatePipelineState(state)) if (!this->validatePipelineState(state, true))
return VK_NULL_HANDLE; return VK_NULL_HANDLE;
// Prevent other threads from adding new instances and check again // Prevent other threads from adding new instances and check again
@ -90,7 +90,7 @@ namespace dxvk {
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineStateInfo& state,
const DxvkRenderPass* renderPass) { const DxvkRenderPass* renderPass) {
// Exit early if the state vector is invalid // Exit early if the state vector is invalid
if (!this->validatePipelineState(state)) if (!this->validatePipelineState(state, false))
return; return;
// Keep the object locked while compiling a pipeline since compiling // Keep the object locked while compiling a pipeline since compiling
@ -510,7 +510,8 @@ namespace dxvk {
bool DxvkGraphicsPipeline::validatePipelineState( bool DxvkGraphicsPipeline::validatePipelineState(
const DxvkGraphicsPipelineStateInfo& state) const { const DxvkGraphicsPipelineStateInfo& state,
bool trusted) const {
// Tessellation shaders and patches must be used together // Tessellation shaders and patches must be used together
bool hasPatches = state.ia.primitiveTopology() == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST; bool hasPatches = state.ia.primitiveTopology() == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
@ -529,7 +530,68 @@ namespace dxvk {
|| state.il.bindingCount() > DxvkLimits::MaxNumVertexBindings) || state.il.bindingCount() > DxvkLimits::MaxNumVertexBindings)
return false; return false;
// No errors // Exit here on the fast path, perform more thorough validation if
// the state vector comes from an untrusted source (i.e. the cache)
if (trusted)
return true;
// Validate shaders
if (!m_shaders.validate()) {
Logger::err("Invalid pipeline: Shader types do not match stage");
return false;
}
// Validate vertex input layout
const DxvkDevice* device = m_pipeMgr->m_device;
uint32_t ilLocationMask = 0;
uint32_t ilBindingMask = 0;
for (uint32_t i = 0; i < state.il.bindingCount(); i++)
ilBindingMask |= 1u << state.ilBindings[i].binding();
for (uint32_t i = 0; i < state.il.attributeCount(); i++) {
const DxvkIlAttribute& attribute = state.ilAttributes[i];
if (ilLocationMask & (1u << attribute.location())) {
Logger::err(str::format("Invalid pipeline: Vertex location ", attribute.location(), " defined twice"));
return false;
}
if (!(ilBindingMask & (1u << attribute.binding()))) {
Logger::err(str::format("Invalid pipeline: Vertex binding ", attribute.binding(), " not defined"));
return false;
}
VkFormatProperties formatInfo = device->adapter()->formatProperties(attribute.format());
if (!(formatInfo.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT)) {
Logger::err(str::format("Invalid pipeline: Format ", attribute.format(), " not supported for vertex buffers"));
return false;
}
ilLocationMask |= 1u << attribute.location();
}
// Validate rasterization state
if (state.rs.conservativeMode() != VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT) {
if (!device->extensions().extConservativeRasterization) {
Logger::err("Conservative rasterization not supported by device");
return false;
}
if (state.rs.conservativeMode() == VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT
&& !device->properties().extConservativeRasterization.primitiveUnderestimation) {
Logger::err("Primitive underestimation not supported by device");
return false;
}
}
// Validate depth-stencil state
if (state.ds.enableDepthBoundsTest() && !device->features().core.features.depthBounds) {
Logger::err("Depth bounds not supported by device");
return false;
}
return true; return true;
} }

View File

@ -55,6 +55,18 @@ namespace dxvk {
state.add(DxvkShader::getHash(fs)); state.add(DxvkShader::getHash(fs));
return state; return state;
} }
bool validate() const {
return validateShaderType(vs, VK_SHADER_STAGE_VERTEX_BIT)
&& validateShaderType(tcs, VK_SHADER_STAGE_TESSELLATION_CONTROL_BIT)
&& validateShaderType(tes, VK_SHADER_STAGE_TESSELLATION_EVALUATION_BIT)
&& validateShaderType(gs, VK_SHADER_STAGE_GEOMETRY_BIT)
&& validateShaderType(fs, VK_SHADER_STAGE_FRAGMENT_BIT);
}
static bool validateShaderType(const Rc<DxvkShader>& shader, VkShaderStageFlagBits stage) {
return shader == nullptr || shader->info().stage == stage;
}
}; };
@ -249,7 +261,8 @@ namespace dxvk {
VkShaderStageFlagBits stage) const; VkShaderStageFlagBits stage) const;
bool validatePipelineState( bool validatePipelineState(
const DxvkGraphicsPipelineStateInfo& state) const; const DxvkGraphicsPipelineStateInfo& state,
bool trusted) const;
void writePipelineStateToCache( void writePipelineStateToCache(
const DxvkGraphicsPipelineStateInfo& state, const DxvkGraphicsPipelineStateInfo& state,