mirror of
https://git.eden-emu.dev/eden-emu/eden
synced 2026-04-10 03:18:55 +02:00
[vulkan] eds overhaul
added: 1. VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT 2. VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT 3. VK_DYNAMIC_STATE_LINE_STIPPLE_EXT VIDS changes: fixed attribute update which was off by one in UpdateVertexInput() (VIDS has to be tested) Added cached tracking for current primitive topology and patch control points in state tracker.
This commit is contained in:
parent
8678cb06eb
commit
0d39d21843
8 changed files with 169 additions and 28 deletions
|
|
@ -830,7 +830,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||||
.pAttachments = cb_attachments.data(),
|
.pAttachments = cb_attachments.data(),
|
||||||
.blendConstants = {}
|
.blendConstants = {}
|
||||||
};
|
};
|
||||||
static_vector<VkDynamicState, 34> dynamic_states{
|
static_vector<VkDynamicState, 40> dynamic_states{
|
||||||
VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR,
|
VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR,
|
||||||
VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_BLEND_CONSTANTS,
|
VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_BLEND_CONSTANTS,
|
||||||
VK_DYNAMIC_STATE_DEPTH_BOUNDS, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
|
VK_DYNAMIC_STATE_DEPTH_BOUNDS, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
|
||||||
|
|
@ -849,6 +849,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||||
VK_DYNAMIC_STATE_STENCIL_OP_EXT,
|
VK_DYNAMIC_STATE_STENCIL_OP_EXT,
|
||||||
};
|
};
|
||||||
dynamic_states.insert(dynamic_states.end(), extended.begin(), extended.end());
|
dynamic_states.insert(dynamic_states.end(), extended.begin(), extended.end());
|
||||||
|
dynamic_states.push_back(VK_DYNAMIC_STATE_PRIMITIVE_TOPOLOGY_EXT);
|
||||||
|
|
||||||
// VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT is part of EDS1
|
// VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT is part of EDS1
|
||||||
// Only use it if VIDS is not active (VIDS replaces it with full vertex input control)
|
// Only use it if VIDS is not active (VIDS replaces it with full vertex input control)
|
||||||
|
|
@ -863,7 +864,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||||
dynamic_states.push_back(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT);
|
dynamic_states.push_back(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT);
|
||||||
}
|
}
|
||||||
|
|
||||||
// EDS2 - Core (3 states)
|
// EDS2 - Core states
|
||||||
if (key.state.extended_dynamic_state_2) {
|
if (key.state.extended_dynamic_state_2) {
|
||||||
static constexpr std::array extended2{
|
static constexpr std::array extended2{
|
||||||
VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT,
|
VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT,
|
||||||
|
|
@ -871,6 +872,9 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||||
VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT,
|
VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT,
|
||||||
};
|
};
|
||||||
dynamic_states.insert(dynamic_states.end(), extended2.begin(), extended2.end());
|
dynamic_states.insert(dynamic_states.end(), extended2.begin(), extended2.end());
|
||||||
|
if (device.IsExtExtendedDynamicState2PatchControlPointsSupported()) {
|
||||||
|
dynamic_states.push_back(VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EDS2 - LogicOp (granular)
|
// EDS2 - LogicOp (granular)
|
||||||
|
|
@ -913,6 +917,10 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (device.IsExtLineRasterizationSupported() && device.SupportsStippledRectangularLines()) {
|
||||||
|
dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_STIPPLE_EXT);
|
||||||
|
}
|
||||||
|
|
||||||
const VkPipelineDynamicStateCreateInfo dynamic_state_ci{
|
const VkPipelineDynamicStateCreateInfo dynamic_state_ci{
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,10 @@ public:
|
||||||
return fragment_has_color0_output;
|
return fragment_has_color0_output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HasTessellationStages() const noexcept {
|
||||||
|
return spv_modules[1] || spv_modules[2];
|
||||||
|
}
|
||||||
|
|
||||||
bool UsesExtendedDynamicState() const noexcept {
|
bool UsesExtendedDynamicState() const noexcept {
|
||||||
return key.state.extended_dynamic_state != 0;
|
return key.state.extended_dynamic_state != 0;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -479,7 +479,8 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||||
device.IsExtExtendedDynamicState2Supported();
|
device.IsExtExtendedDynamicState2Supported();
|
||||||
dynamic_features.has_extended_dynamic_state_2_logic_op =
|
dynamic_features.has_extended_dynamic_state_2_logic_op =
|
||||||
device.IsExtExtendedDynamicState2ExtrasSupported();
|
device.IsExtExtendedDynamicState2ExtrasSupported();
|
||||||
dynamic_features.has_extended_dynamic_state_2_patch_control_points = false;
|
dynamic_features.has_extended_dynamic_state_2_patch_control_points =
|
||||||
|
device.IsExtExtendedDynamicState2PatchControlPointsSupported();
|
||||||
|
|
||||||
dynamic_features.has_extended_dynamic_state_3_blend =
|
dynamic_features.has_extended_dynamic_state_3_blend =
|
||||||
device.IsExtExtendedDynamicState3BlendingSupported();
|
device.IsExtExtendedDynamicState3BlendingSupported();
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,33 @@ struct DrawParams {
|
||||||
bool is_indexed;
|
bool is_indexed;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
bool SupportsPrimitiveRestart(VkPrimitiveTopology topology) {
|
||||||
|
static constexpr std::array unsupported_topologies{
|
||||||
|
VK_PRIMITIVE_TOPOLOGY_POINT_LIST,
|
||||||
|
VK_PRIMITIVE_TOPOLOGY_LINE_LIST,
|
||||||
|
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST,
|
||||||
|
VK_PRIMITIVE_TOPOLOGY_LINE_LIST_WITH_ADJACENCY,
|
||||||
|
VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY,
|
||||||
|
VK_PRIMITIVE_TOPOLOGY_PATCH_LIST,
|
||||||
|
// VK_PRIMITIVE_TOPOLOGY_QUAD_LIST_EXT,
|
||||||
|
};
|
||||||
|
return std::ranges::find(unsupported_topologies, topology) == unsupported_topologies.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
VkPrimitiveTopology DynamicInputAssemblyTopology(const Device& device,
|
||||||
|
const MaxwellDrawState& draw_state,
|
||||||
|
const GraphicsPipeline& pipeline) {
|
||||||
|
auto topology = MaxwellToVK::PrimitiveTopology(device, draw_state.topology);
|
||||||
|
if (topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST) {
|
||||||
|
if (!pipeline.HasTessellationStages()) {
|
||||||
|
topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST;
|
||||||
|
}
|
||||||
|
} else if (pipeline.HasTessellationStages()) {
|
||||||
|
topology = VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
|
||||||
|
}
|
||||||
|
return topology;
|
||||||
|
}
|
||||||
|
|
||||||
VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index, float scale) {
|
VkViewport GetViewportState(const Device& device, const Maxwell& regs, size_t index, float scale) {
|
||||||
const auto& src = regs.viewport_transform[index];
|
const auto& src = regs.viewport_transform[index];
|
||||||
const auto conv = [scale](float value) {
|
const auto conv = [scale](float value) {
|
||||||
|
|
@ -1017,9 +1044,12 @@ void RasterizerVulkan::UpdateDynamicStates() {
|
||||||
UpdateDepthBounds(regs);
|
UpdateDepthBounds(regs);
|
||||||
UpdateStencilFaces(regs);
|
UpdateStencilFaces(regs);
|
||||||
UpdateLineWidth(regs);
|
UpdateLineWidth(regs);
|
||||||
|
UpdateLineStipple(regs);
|
||||||
|
|
||||||
// EDS1: CullMode, DepthCompare, FrontFace, StencilOp, DepthBoundsTest, DepthTest, DepthWrite, StencilTest
|
// EDS1: PrimitiveTopology, CullMode, DepthCompare, FrontFace, StencilOp, DepthBoundsTest,
|
||||||
|
// DepthTest, DepthWrite, StencilTest
|
||||||
if (device.IsExtExtendedDynamicStateSupported()) {
|
if (device.IsExtExtendedDynamicStateSupported()) {
|
||||||
|
UpdatePrimitiveTopology();
|
||||||
UpdateCullMode(regs);
|
UpdateCullMode(regs);
|
||||||
UpdateDepthCompareOp(regs);
|
UpdateDepthCompareOp(regs);
|
||||||
UpdateFrontFace(regs);
|
UpdateFrontFace(regs);
|
||||||
|
|
@ -1032,11 +1062,12 @@ void RasterizerVulkan::UpdateDynamicStates() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// EDS2: PrimitiveRestart, RasterizerDiscard, DepthBias enable/disable
|
// EDS2: PrimitiveRestart, RasterizerDiscard, DepthBias enable/disable, PatchControlPoints
|
||||||
if (device.IsExtExtendedDynamicState2Supported()) {
|
if (device.IsExtExtendedDynamicState2Supported()) {
|
||||||
UpdatePrimitiveRestartEnable(regs);
|
UpdatePrimitiveRestartEnable(regs);
|
||||||
UpdateRasterizerDiscardEnable(regs);
|
UpdateRasterizerDiscardEnable(regs);
|
||||||
UpdateDepthBiasEnable(regs);
|
UpdateDepthBiasEnable(regs);
|
||||||
|
UpdatePatchControlPoints(regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
// EDS2 Extras: LogicOp operation selection
|
// EDS2 Extras: LogicOp operation selection
|
||||||
|
|
@ -1384,6 +1415,28 @@ void RasterizerVulkan::UpdateCullMode(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RasterizerVulkan::UpdatePrimitiveTopology() {
|
||||||
|
GraphicsPipeline* const pipeline = pipeline_cache.CurrentGraphicsPipeline();
|
||||||
|
if (pipeline == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MaxwellDrawState& draw_state = maxwell3d->draw_manager->GetDrawState();
|
||||||
|
const VkPrimitiveTopology topology = DynamicInputAssemblyTopology(device, draw_state, *pipeline);
|
||||||
|
|
||||||
|
if (!state_tracker.ChangePrimitiveTopology(static_cast<u32>(topology))) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Primitive restart support depends on topology, so force re-evaluation on topology changes
|
||||||
|
if (device.IsExtExtendedDynamicState2Supported()) {
|
||||||
|
maxwell3d->dirty.flags[Dirty::PrimitiveRestartEnable] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduler.Record([topology](vk::CommandBuffer cmdbuf) {
|
||||||
|
cmdbuf.SetPrimitiveTopologyEXT(topology);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void RasterizerVulkan::UpdateDepthBoundsTestEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
void RasterizerVulkan::UpdateDepthBoundsTestEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||||
if (!state_tracker.TouchDepthBoundsTestEnable()) {
|
if (!state_tracker.TouchDepthBoundsTestEnable()) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -1420,11 +1473,49 @@ void RasterizerVulkan::UpdatePrimitiveRestartEnable(Tegra::Engines::Maxwell3D::R
|
||||||
if (!state_tracker.TouchPrimitiveRestartEnable()) {
|
if (!state_tracker.TouchPrimitiveRestartEnable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
scheduler.Record([enable = regs.primitive_restart.enabled](vk::CommandBuffer cmdbuf) {
|
GraphicsPipeline* const pipeline = pipeline_cache.CurrentGraphicsPipeline();
|
||||||
|
if (pipeline == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const MaxwellDrawState& draw_state = maxwell3d->draw_manager->GetDrawState();
|
||||||
|
const VkPrimitiveTopology topology = DynamicInputAssemblyTopology(device, draw_state, *pipeline);
|
||||||
|
|
||||||
|
bool enable = regs.primitive_restart.enabled != 0;
|
||||||
|
if (device.IsMoltenVK()) {
|
||||||
|
// MoltenVK/Metal
|
||||||
|
enable = true;
|
||||||
|
} else if (enable) {
|
||||||
|
enable =
|
||||||
|
((topology != VK_PRIMITIVE_TOPOLOGY_PATCH_LIST &&
|
||||||
|
device.IsTopologyListPrimitiveRestartSupported()) ||
|
||||||
|
SupportsPrimitiveRestart(topology) ||
|
||||||
|
(topology == VK_PRIMITIVE_TOPOLOGY_PATCH_LIST &&
|
||||||
|
device.IsPatchListPrimitiveRestartSupported()));
|
||||||
|
}
|
||||||
|
|
||||||
|
scheduler.Record([enable](vk::CommandBuffer cmdbuf) {
|
||||||
cmdbuf.SetPrimitiveRestartEnableEXT(enable);
|
cmdbuf.SetPrimitiveRestartEnableEXT(enable);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RasterizerVulkan::UpdatePatchControlPoints(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||||
|
if (!device.IsExtExtendedDynamicState2PatchControlPointsSupported()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
GraphicsPipeline* const pipeline = pipeline_cache.CurrentGraphicsPipeline();
|
||||||
|
if (pipeline == nullptr || !pipeline->HasTessellationStages()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const u32 patch_control_points = (std::max)(regs.patch_vertices, 1u);
|
||||||
|
if (!state_tracker.ChangePatchControlPoints(patch_control_points)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scheduler.Record([patch_control_points](vk::CommandBuffer cmdbuf) {
|
||||||
|
cmdbuf.SetPatchControlPointsEXT(patch_control_points);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void RasterizerVulkan::UpdateRasterizerDiscardEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
void RasterizerVulkan::UpdateRasterizerDiscardEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||||
if (!state_tracker.TouchRasterizerDiscardEnable()) {
|
if (!state_tracker.TouchRasterizerDiscardEnable()) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -1464,6 +1555,20 @@ void RasterizerVulkan::UpdateLineStippleEnable(Tegra::Engines::Maxwell3D::Regs&
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void RasterizerVulkan::UpdateLineStipple(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||||
|
if (!state_tracker.TouchLineStipple()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!device.IsExtLineRasterizationSupported() || !device.SupportsStippledRectangularLines()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
scheduler.Record([factor = regs.line_stipple_params.factor,
|
||||||
|
pattern = static_cast<u16>(regs.line_stipple_params.pattern)](
|
||||||
|
vk::CommandBuffer cmdbuf) {
|
||||||
|
cmdbuf.SetLineStippleEXT(factor, pattern);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void RasterizerVulkan::UpdateLineRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs) {
|
void RasterizerVulkan::UpdateLineRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||||
if (!device.IsExtLineRasterizationSupported()) {
|
if (!device.IsExtLineRasterizationSupported()) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -1771,25 +1876,29 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs)
|
||||||
// generating dirty state. Track the highest dirty attribute and update all attributes until
|
// generating dirty state. Track the highest dirty attribute and update all attributes until
|
||||||
// that one.
|
// that one.
|
||||||
size_t highest_dirty_attr{};
|
size_t highest_dirty_attr{};
|
||||||
|
bool has_dirty_attr = false;
|
||||||
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
|
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
|
||||||
if (dirty[Dirty::VertexAttribute0 + index]) {
|
if (dirty[Dirty::VertexAttribute0 + index]) {
|
||||||
|
has_dirty_attr = true;
|
||||||
highest_dirty_attr = index;
|
highest_dirty_attr = index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (size_t index = 0; index < highest_dirty_attr; ++index) {
|
if (has_dirty_attr) {
|
||||||
const Maxwell::VertexAttribute attribute{regs.vertex_attrib_format[index]};
|
for (size_t index = 0; index <= highest_dirty_attr; ++index) {
|
||||||
const u32 binding{attribute.buffer};
|
const Maxwell::VertexAttribute attribute{regs.vertex_attrib_format[index]};
|
||||||
dirty[Dirty::VertexAttribute0 + index] = false;
|
const u32 binding{attribute.buffer};
|
||||||
dirty[Dirty::VertexBinding0 + static_cast<size_t>(binding)] = true;
|
dirty[Dirty::VertexAttribute0 + index] = false;
|
||||||
if (!attribute.constant) {
|
dirty[Dirty::VertexBinding0 + static_cast<size_t>(binding)] = true;
|
||||||
attributes.push_back({
|
if (!attribute.constant) {
|
||||||
.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT,
|
attributes.push_back({
|
||||||
.pNext = nullptr,
|
.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT,
|
||||||
.location = static_cast<u32>(index),
|
.pNext = nullptr,
|
||||||
.binding = binding,
|
.location = static_cast<u32>(index),
|
||||||
.format = MaxwellToVK::VertexFormat(device, attribute.type, attribute.size),
|
.binding = binding,
|
||||||
.offset = attribute.offset,
|
.format = MaxwellToVK::VertexFormat(device, attribute.type, attribute.size),
|
||||||
});
|
.offset = attribute.offset,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
|
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
|
||||||
|
|
|
||||||
|
|
@ -170,11 +170,13 @@ private:
|
||||||
void UpdateLineWidth(Tegra::Engines::Maxwell3D::Regs& regs);
|
void UpdateLineWidth(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||||
|
|
||||||
void UpdateCullMode(Tegra::Engines::Maxwell3D::Regs& regs);
|
void UpdateCullMode(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||||
|
void UpdatePrimitiveTopology();
|
||||||
void UpdateDepthBoundsTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
void UpdateDepthBoundsTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||||
void UpdateDepthTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
void UpdateDepthTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||||
void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||||
void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs);
|
void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||||
void UpdatePrimitiveRestartEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
void UpdatePrimitiveRestartEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||||
|
void UpdatePatchControlPoints(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||||
void UpdateRasterizerDiscardEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
void UpdateRasterizerDiscardEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||||
void UpdateConservativeRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs);
|
void UpdateConservativeRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||||
void UpdateLineStippleEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
void UpdateLineStippleEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||||
|
|
|
||||||
|
|
@ -216,12 +216,15 @@ void SetupDirtyVertexAttributes(Tables& tables) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetupDirtyVertexBindings(Tables& tables) {
|
void SetupDirtyVertexBindings(Tables& tables) {
|
||||||
// Do NOT include stride here, it's implicit in VertexBuffer
|
// Dynamic vertex input needs binding state updates when stride/divisor/instancing changes
|
||||||
|
static constexpr size_t stride_offset = 0;
|
||||||
static constexpr size_t divisor_offset = 3;
|
static constexpr size_t divisor_offset = 3;
|
||||||
for (size_t i = 0; i < Regs::NumVertexArrays; ++i) {
|
for (size_t i = 0; i < Regs::NumVertexArrays; ++i) {
|
||||||
const u8 flag = static_cast<u8>(VertexBinding0 + i);
|
const u8 flag = static_cast<u8>(VertexBinding0 + i);
|
||||||
tables[0][OFF(vertex_stream_instances) + i] = VertexInput;
|
tables[0][OFF(vertex_stream_instances) + i] = VertexInput;
|
||||||
tables[1][OFF(vertex_stream_instances) + i] = flag;
|
tables[1][OFF(vertex_stream_instances) + i] = flag;
|
||||||
|
tables[0][OFF(vertex_streams) + i * NUM(vertex_streams[0]) + stride_offset] = VertexInput;
|
||||||
|
tables[1][OFF(vertex_streams) + i * NUM(vertex_streams[0]) + stride_offset] = flag;
|
||||||
tables[0][OFF(vertex_streams) + i * NUM(vertex_streams[0]) + divisor_offset] = VertexInput;
|
tables[0][OFF(vertex_streams) + i * NUM(vertex_streams[0]) + divisor_offset] = VertexInput;
|
||||||
tables[1][OFF(vertex_streams) + i * NUM(vertex_streams[0]) + divisor_offset] = flag;
|
tables[1][OFF(vertex_streams) + i * NUM(vertex_streams[0]) + divisor_offset] = flag;
|
||||||
}
|
}
|
||||||
|
|
@ -265,7 +268,8 @@ void StateTracker::ChangeChannel(Tegra::Control::ChannelState& channel_state) {
|
||||||
|
|
||||||
void StateTracker::InvalidateState() {
|
void StateTracker::InvalidateState() {
|
||||||
flags->set();
|
flags->set();
|
||||||
current_topology = INVALID_TOPOLOGY;
|
current_primitive_topology = INVALID_PRIMITIVE_TOPOLOGY;
|
||||||
|
current_patch_control_points = INVALID_PATCH_CONTROL_POINTS;
|
||||||
stencil_reset = true;
|
stencil_reset = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -85,7 +85,8 @@ public:
|
||||||
|
|
||||||
void InvalidateCommandBufferState() {
|
void InvalidateCommandBufferState() {
|
||||||
(*flags) |= invalidation_flags;
|
(*flags) |= invalidation_flags;
|
||||||
current_topology = INVALID_TOPOLOGY;
|
current_primitive_topology = INVALID_PRIMITIVE_TOPOLOGY;
|
||||||
|
current_patch_control_points = INVALID_PATCH_CONTROL_POINTS;
|
||||||
stencil_reset = true;
|
stencil_reset = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -280,9 +281,15 @@ public:
|
||||||
return Exchange(Dirty::LineRasterizationMode, false);
|
return Exchange(Dirty::LineRasterizationMode, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ChangePrimitiveTopology(Maxwell::PrimitiveTopology new_topology) {
|
bool ChangePrimitiveTopology(u32 new_topology) {
|
||||||
const bool has_changed = current_topology != new_topology;
|
const bool has_changed = current_primitive_topology != new_topology;
|
||||||
current_topology = new_topology;
|
current_primitive_topology = new_topology;
|
||||||
|
return has_changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ChangePatchControlPoints(u32 new_patch_control_points) {
|
||||||
|
const bool has_changed = current_patch_control_points != new_patch_control_points;
|
||||||
|
current_patch_control_points = new_patch_control_points;
|
||||||
return has_changed;
|
return has_changed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -293,7 +300,8 @@ public:
|
||||||
void InvalidateState();
|
void InvalidateState();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr auto INVALID_TOPOLOGY = static_cast<Maxwell::PrimitiveTopology>(~0u);
|
static constexpr u32 INVALID_PRIMITIVE_TOPOLOGY = ~0u;
|
||||||
|
static constexpr u32 INVALID_PATCH_CONTROL_POINTS = ~0u;
|
||||||
|
|
||||||
bool Exchange(std::size_t id, bool new_value) const noexcept {
|
bool Exchange(std::size_t id, bool new_value) const noexcept {
|
||||||
const bool is_dirty = (*flags)[id];
|
const bool is_dirty = (*flags)[id];
|
||||||
|
|
@ -310,7 +318,8 @@ private:
|
||||||
Tegra::Engines::Maxwell3D::DirtyState::Flags* flags;
|
Tegra::Engines::Maxwell3D::DirtyState::Flags* flags;
|
||||||
Tegra::Engines::Maxwell3D::DirtyState::Flags default_flags;
|
Tegra::Engines::Maxwell3D::DirtyState::Flags default_flags;
|
||||||
Tegra::Engines::Maxwell3D::DirtyState::Flags invalidation_flags;
|
Tegra::Engines::Maxwell3D::DirtyState::Flags invalidation_flags;
|
||||||
Maxwell::PrimitiveTopology current_topology = INVALID_TOPOLOGY;
|
u32 current_primitive_topology = INVALID_PRIMITIVE_TOPOLOGY;
|
||||||
|
u32 current_patch_control_points = INVALID_PATCH_CONTROL_POINTS;
|
||||||
bool two_sided_stencil = false;
|
bool two_sided_stencil = false;
|
||||||
StencilProperties front{};
|
StencilProperties front{};
|
||||||
StencilProperties back{};
|
StencilProperties back{};
|
||||||
|
|
|
||||||
|
|
@ -625,6 +625,10 @@ public:
|
||||||
return features.extended_dynamic_state2.extendedDynamicState2LogicOp;
|
return features.extended_dynamic_state2.extendedDynamicState2LogicOp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool IsExtExtendedDynamicState2PatchControlPointsSupported() const {
|
||||||
|
return features.extended_dynamic_state2.extendedDynamicState2PatchControlPoints;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if the device supports VK_EXT_extended_dynamic_state3.
|
/// Returns true if the device supports VK_EXT_extended_dynamic_state3.
|
||||||
bool IsExtExtendedDynamicState3Supported() const {
|
bool IsExtExtendedDynamicState3Supported() const {
|
||||||
return extensions.extended_dynamic_state3;
|
return extensions.extended_dynamic_state3;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue