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:
parent
4ff7687dea
commit
80e125a130
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user