mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-25 00:40:32 +00:00
[vulkan] removal of EDS3 and VIDS
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -60,9 +60,9 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
|
||||
extended_dynamic_state.Assign(features.has_extended_dynamic_state ? 1 : 0);
|
||||
extended_dynamic_state_2.Assign(features.has_extended_dynamic_state_2 ? 1 : 0);
|
||||
extended_dynamic_state_2_logic_op.Assign(features.has_extended_dynamic_state_2_logic_op ? 1 : 0);
|
||||
extended_dynamic_state_3_blend.Assign(features.has_extended_dynamic_state_3_blend ? 1 : 0);
|
||||
extended_dynamic_state_3_enables.Assign(features.has_extended_dynamic_state_3_enables ? 1 : 0);
|
||||
dynamic_vertex_input.Assign(features.has_dynamic_vertex_input ? 1 : 0);
|
||||
reserved_dynamic_state_3_blend.Assign(0);
|
||||
reserved_dynamic_state_3_enables.Assign(0);
|
||||
reserved_bit_5.Assign(0);
|
||||
xfb_enabled.Assign(regs.transform_feedback_enabled != 0);
|
||||
ndc_minus_one_to_one.Assign(regs.depth_mode == Maxwell::DepthMode::MinusOneToOne ? 1 : 0);
|
||||
polygon_mode.Assign(PackPolygonMode(regs.polygon_mode_front));
|
||||
@@ -103,43 +103,22 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
|
||||
point_size = std::bit_cast<u32>(regs.point_size);
|
||||
|
||||
if (maxwell3d.dirty.flags[Dirty::VertexInput]) {
|
||||
if (features.has_dynamic_vertex_input) {
|
||||
// Dirty flag will be reset by the command buffer update
|
||||
static constexpr std::array LUT{
|
||||
0u, // Invalid
|
||||
1u, // SignedNorm
|
||||
1u, // UnsignedNorm
|
||||
2u, // SignedInt
|
||||
3u, // UnsignedInt
|
||||
1u, // UnsignedScaled
|
||||
1u, // SignedScaled
|
||||
1u, // Float
|
||||
};
|
||||
const auto& attrs = regs.vertex_attrib_format;
|
||||
attribute_types = 0;
|
||||
for (size_t i = 0; i < Maxwell::NumVertexAttributes; ++i) {
|
||||
const u32 mask = attrs[i].constant != 0 ? 0 : 3;
|
||||
const u32 type = LUT[static_cast<size_t>(attrs[i].type.Value())];
|
||||
attribute_types |= static_cast<u64>(type & mask) << (i * 2);
|
||||
}
|
||||
} else {
|
||||
maxwell3d.dirty.flags[Dirty::VertexInput] = false;
|
||||
enabled_divisors = 0;
|
||||
for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) {
|
||||
const bool is_enabled = regs.vertex_stream_instances.IsInstancingEnabled(index);
|
||||
binding_divisors[index] = is_enabled ? regs.vertex_streams[index].frequency : 0;
|
||||
enabled_divisors |= (is_enabled ? u64{1} : 0) << index;
|
||||
}
|
||||
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
|
||||
const auto& input = regs.vertex_attrib_format[index];
|
||||
auto& attribute = attributes[index];
|
||||
attribute.raw = 0;
|
||||
attribute.enabled.Assign(input.constant ? 0 : 1);
|
||||
attribute.buffer.Assign(input.buffer);
|
||||
attribute.offset.Assign(input.offset);
|
||||
attribute.type.Assign(static_cast<u32>(input.type.Value()));
|
||||
attribute.size.Assign(static_cast<u32>(input.size.Value()));
|
||||
}
|
||||
maxwell3d.dirty.flags[Dirty::VertexInput] = false;
|
||||
enabled_divisors = 0;
|
||||
for (size_t index = 0; index < Maxwell::NumVertexArrays; ++index) {
|
||||
const bool is_enabled = regs.vertex_stream_instances.IsInstancingEnabled(index);
|
||||
binding_divisors[index] = is_enabled ? regs.vertex_streams[index].frequency : 0;
|
||||
enabled_divisors |= (is_enabled ? u64{1} : 0) << index;
|
||||
}
|
||||
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
|
||||
const auto& input = regs.vertex_attrib_format[index];
|
||||
auto& attribute = attributes[index];
|
||||
attribute.raw = 0;
|
||||
attribute.enabled.Assign(input.constant ? 0 : 1);
|
||||
attribute.buffer.Assign(input.buffer);
|
||||
attribute.offset.Assign(input.offset);
|
||||
attribute.type.Assign(static_cast<u32>(input.type.Value()));
|
||||
attribute.size.Assign(static_cast<u32>(input.size.Value()));
|
||||
}
|
||||
}
|
||||
if (maxwell3d.dirty.flags[Dirty::ViewportSwizzles]) {
|
||||
@@ -160,17 +139,13 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
|
||||
if (!extended_dynamic_state_2_logic_op) {
|
||||
dynamic_state.Refresh2(regs, topology_, extended_dynamic_state_2);
|
||||
}
|
||||
if (!extended_dynamic_state_3_blend) {
|
||||
if (maxwell3d.dirty.flags[Dirty::Blending]) {
|
||||
maxwell3d.dirty.flags[Dirty::Blending] = false;
|
||||
for (size_t index = 0; index < attachments.size(); ++index) {
|
||||
attachments[index].Refresh(regs, index);
|
||||
}
|
||||
if (maxwell3d.dirty.flags[Dirty::Blending]) {
|
||||
maxwell3d.dirty.flags[Dirty::Blending] = false;
|
||||
for (size_t index = 0; index < attachments.size(); ++index) {
|
||||
attachments[index].Refresh(regs, index);
|
||||
}
|
||||
}
|
||||
if (!extended_dynamic_state_3_enables) {
|
||||
dynamic_state.Refresh3(regs);
|
||||
}
|
||||
dynamic_state.Refresh3(regs);
|
||||
if (xfb_enabled) {
|
||||
RefreshXfbState(xfb_state, regs);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -25,9 +25,6 @@ struct DynamicFeatures {
|
||||
bool has_extended_dynamic_state_2;
|
||||
bool has_extended_dynamic_state_2_logic_op;
|
||||
bool has_extended_dynamic_state_2_patch_control_points;
|
||||
bool has_extended_dynamic_state_3_blend;
|
||||
bool has_extended_dynamic_state_3_enables;
|
||||
bool has_dynamic_vertex_input;
|
||||
};
|
||||
|
||||
struct FixedPipelineState {
|
||||
@@ -191,9 +188,9 @@ struct FixedPipelineState {
|
||||
BitField<0, 1, u32> extended_dynamic_state;
|
||||
BitField<1, 1, u32> extended_dynamic_state_2;
|
||||
BitField<2, 1, u32> extended_dynamic_state_2_logic_op;
|
||||
BitField<3, 1, u32> extended_dynamic_state_3_blend;
|
||||
BitField<4, 1, u32> extended_dynamic_state_3_enables;
|
||||
BitField<5, 1, u32> dynamic_vertex_input;
|
||||
BitField<3, 1, u32> reserved_dynamic_state_3_blend;
|
||||
BitField<4, 1, u32> reserved_dynamic_state_3_enables;
|
||||
BitField<5, 1, u32> reserved_bit_5;
|
||||
BitField<6, 1, u32> xfb_enabled;
|
||||
BitField<7, 1, u32> ndc_minus_one_to_one;
|
||||
BitField<8, 2, u32> polygon_mode;
|
||||
@@ -225,10 +222,7 @@ struct FixedPipelineState {
|
||||
u32 point_size;
|
||||
|
||||
std::array<u16, Maxwell::NumViewports> viewport_swizzles;
|
||||
union {
|
||||
u64 attribute_types; // Used with VK_EXT_vertex_input_dynamic_state
|
||||
u64 enabled_divisors;
|
||||
};
|
||||
u64 enabled_divisors;
|
||||
|
||||
DynamicState dynamic_state;
|
||||
std::array<BlendingAttachment, Maxwell::NumRenderTargets> attachments;
|
||||
@@ -260,14 +254,6 @@ struct FixedPipelineState {
|
||||
// When transform feedback is enabled, use the whole struct
|
||||
return sizeof(*this);
|
||||
}
|
||||
if (dynamic_vertex_input && extended_dynamic_state_3_blend) {
|
||||
// Exclude dynamic state and attributes
|
||||
return offsetof(FixedPipelineState, dynamic_state);
|
||||
}
|
||||
if (dynamic_vertex_input) {
|
||||
// Exclude dynamic state
|
||||
return offsetof(FixedPipelineState, attributes);
|
||||
}
|
||||
if (extended_dynamic_state) {
|
||||
// Exclude dynamic state
|
||||
return offsetof(FixedPipelineState, vertex_strides);
|
||||
@@ -275,10 +261,6 @@ struct FixedPipelineState {
|
||||
// Default
|
||||
return offsetof(FixedPipelineState, xfb_state);
|
||||
}
|
||||
|
||||
u32 DynamicAttributeType(size_t index) const noexcept {
|
||||
return (attribute_types >> (index * 2)) & 0b11;
|
||||
}
|
||||
};
|
||||
static_assert(std::has_unique_object_representations_v<FixedPipelineState>);
|
||||
static_assert(std::is_trivially_copyable_v<FixedPipelineState>);
|
||||
|
||||
@@ -577,38 +577,35 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||
static_vector<VkVertexInputBindingDescription, 32> vertex_bindings;
|
||||
static_vector<VkVertexInputBindingDivisorDescriptionEXT, 32> vertex_binding_divisors;
|
||||
static_vector<VkVertexInputAttributeDescription, 32> vertex_attributes;
|
||||
if (!key.state.dynamic_vertex_input) {
|
||||
const size_t num_vertex_arrays = (std::min)(
|
||||
Maxwell::NumVertexArrays, static_cast<size_t>(device.GetMaxVertexInputBindings()));
|
||||
for (size_t index = 0; index < num_vertex_arrays; ++index) {
|
||||
const bool instanced = key.state.binding_divisors[index] != 0;
|
||||
const auto rate =
|
||||
instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
vertex_bindings.push_back({
|
||||
const size_t num_vertex_arrays =
|
||||
(std::min)(Maxwell::NumVertexArrays, static_cast<size_t>(device.GetMaxVertexInputBindings()));
|
||||
for (size_t index = 0; index < num_vertex_arrays; ++index) {
|
||||
const bool instanced = key.state.binding_divisors[index] != 0;
|
||||
const auto rate = instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
vertex_bindings.push_back({
|
||||
.binding = static_cast<u32>(index),
|
||||
.stride = key.state.vertex_strides[index],
|
||||
.inputRate = rate,
|
||||
});
|
||||
if (instanced) {
|
||||
vertex_binding_divisors.push_back({
|
||||
.binding = static_cast<u32>(index),
|
||||
.stride = key.state.vertex_strides[index],
|
||||
.inputRate = rate,
|
||||
});
|
||||
if (instanced) {
|
||||
vertex_binding_divisors.push_back({
|
||||
.binding = static_cast<u32>(index),
|
||||
.divisor = key.state.binding_divisors[index],
|
||||
});
|
||||
}
|
||||
}
|
||||
for (size_t index = 0; index < key.state.attributes.size(); ++index) {
|
||||
const auto& attribute = key.state.attributes[index];
|
||||
if (!attribute.enabled || !stage_infos[0].loads.Generic(index)) {
|
||||
continue;
|
||||
}
|
||||
vertex_attributes.push_back({
|
||||
.location = static_cast<u32>(index),
|
||||
.binding = attribute.buffer,
|
||||
.format = MaxwellToVK::VertexFormat(device, attribute.Type(), attribute.Size()),
|
||||
.offset = attribute.offset,
|
||||
.divisor = key.state.binding_divisors[index],
|
||||
});
|
||||
}
|
||||
}
|
||||
for (size_t index = 0; index < key.state.attributes.size(); ++index) {
|
||||
const auto& attribute = key.state.attributes[index];
|
||||
if (!attribute.enabled || !stage_infos[0].loads.Generic(index)) {
|
||||
continue;
|
||||
}
|
||||
vertex_attributes.push_back({
|
||||
.location = static_cast<u32>(index),
|
||||
.binding = attribute.buffer,
|
||||
.format = MaxwellToVK::VertexFormat(device, attribute.Type(), attribute.Size()),
|
||||
.offset = attribute.offset,
|
||||
});
|
||||
}
|
||||
ASSERT(vertex_attributes.size() <= device.GetMaxVertexInputAttributes());
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertex_input_ci{
|
||||
@@ -850,17 +847,7 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||
};
|
||||
dynamic_states.insert(dynamic_states.end(), extended.begin(), extended.end());
|
||||
|
||||
// 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)
|
||||
if (!key.state.dynamic_vertex_input) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT);
|
||||
}
|
||||
}
|
||||
|
||||
// VK_DYNAMIC_STATE_VERTEX_INPUT_EXT (VIDS) - Independent from EDS
|
||||
// Provides full dynamic vertex input control, replaces VERTEX_INPUT_BINDING_STRIDE
|
||||
if (key.state.dynamic_vertex_input) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT);
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT);
|
||||
}
|
||||
|
||||
// EDS2 - Core (3 states)
|
||||
@@ -878,41 +865,6 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_LOGIC_OP_EXT);
|
||||
}
|
||||
|
||||
// EDS3 - Blending (composite: 3 states)
|
||||
if (key.state.extended_dynamic_state_3_blend) {
|
||||
static constexpr std::array extended3{
|
||||
VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT,
|
||||
VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT,
|
||||
VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT,
|
||||
};
|
||||
dynamic_states.insert(dynamic_states.end(), extended3.begin(), extended3.end());
|
||||
}
|
||||
|
||||
// EDS3 - Enables (composite: per-feature)
|
||||
if (key.state.extended_dynamic_state_3_enables) {
|
||||
if (device.SupportsDynamicState3DepthClampEnable()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT);
|
||||
}
|
||||
if (device.SupportsDynamicState3LogicOpEnable()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT);
|
||||
}
|
||||
if (device.SupportsDynamicState3LineRasterizationMode()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT);
|
||||
}
|
||||
if (device.SupportsDynamicState3ConservativeRasterizationMode()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_CONSERVATIVE_RASTERIZATION_MODE_EXT);
|
||||
}
|
||||
if (device.SupportsDynamicState3LineStippleEnable()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT);
|
||||
}
|
||||
if (device.SupportsDynamicState3AlphaToCoverageEnable()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT);
|
||||
}
|
||||
if (device.SupportsDynamicState3AlphaToOneEnable()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT);
|
||||
}
|
||||
}
|
||||
|
||||
const VkPipelineDynamicStateCreateInfo dynamic_state_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
@@ -81,7 +81,6 @@ public:
|
||||
const GraphicsPipelineCacheKey& key, std::array<vk::ShaderModule, NUM_STAGES> stages,
|
||||
const std::array<const Shader::Info*, NUM_STAGES>& infos);
|
||||
|
||||
bool HasDynamicVertexInput() const noexcept { return key.state.dynamic_vertex_input; }
|
||||
bool SupportsAlphaToCoverage() const noexcept {
|
||||
return fragment_has_color0_output;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@ using VideoCommon::FileEnvironment;
|
||||
using VideoCommon::GenericEnvironment;
|
||||
using VideoCommon::GraphicsEnvironment;
|
||||
|
||||
constexpr u32 CACHE_VERSION = 16;
|
||||
constexpr u32 CACHE_VERSION = 17;
|
||||
constexpr std::array<char, 8> VULKAN_CACHE_MAGIC_NUMBER{'y', 'u', 'z', 'u', 'v', 'k', 'c', 'h'};
|
||||
|
||||
template <typename Container>
|
||||
@@ -132,20 +132,6 @@ Shader::AttributeType CastAttributeType(const FixedPipelineState::VertexAttribut
|
||||
return Shader::AttributeType::Float;
|
||||
}
|
||||
|
||||
Shader::AttributeType AttributeType(const FixedPipelineState& state, size_t index) {
|
||||
switch (state.DynamicAttributeType(index)) {
|
||||
case 0:
|
||||
return Shader::AttributeType::Disabled;
|
||||
case 1:
|
||||
return Shader::AttributeType::Float;
|
||||
case 2:
|
||||
return Shader::AttributeType::SignedInt;
|
||||
case 3:
|
||||
return Shader::AttributeType::UnsignedInt;
|
||||
}
|
||||
return Shader::AttributeType::Disabled;
|
||||
}
|
||||
|
||||
Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> programs,
|
||||
const GraphicsPipelineCacheKey& key,
|
||||
const Shader::IR::Program& program,
|
||||
@@ -183,14 +169,8 @@ Shader::RuntimeInfo MakeRuntimeInfo(std::span<const Shader::IR::Program> program
|
||||
}
|
||||
info.convert_depth_mode = gl_ndc;
|
||||
}
|
||||
if (key.state.dynamic_vertex_input) {
|
||||
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
|
||||
info.generic_input_types[index] = AttributeType(key.state, index);
|
||||
}
|
||||
} else {
|
||||
std::ranges::transform(key.state.attributes, info.generic_input_types.begin(),
|
||||
&CastAttributeType);
|
||||
}
|
||||
std::ranges::transform(key.state.attributes, info.generic_input_types.begin(),
|
||||
&CastAttributeType);
|
||||
break;
|
||||
case Shader::Stage::TessellationEval:
|
||||
info.tess_clockwise = key.state.tessellation_clockwise != 0;
|
||||
@@ -469,7 +449,7 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
// Level 0: Core Dynamic States only
|
||||
// Level 1: Core + EDS1
|
||||
// Level 2: Core + EDS1 + EDS2 (accumulative)
|
||||
// Level 3: Core + EDS1 + EDS2 + EDS3 (accumulative)
|
||||
// Level 2: Core + EDS1 + EDS2 (accumulative)
|
||||
// Here we only verify if extensions were successfully loaded by the device
|
||||
|
||||
dynamic_features.has_extended_dynamic_state =
|
||||
@@ -480,16 +460,6 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
dynamic_features.has_extended_dynamic_state_2_logic_op =
|
||||
device.IsExtExtendedDynamicState2ExtrasSupported();
|
||||
dynamic_features.has_extended_dynamic_state_2_patch_control_points = false;
|
||||
|
||||
dynamic_features.has_extended_dynamic_state_3_blend =
|
||||
device.IsExtExtendedDynamicState3BlendingSupported();
|
||||
dynamic_features.has_extended_dynamic_state_3_enables =
|
||||
device.IsExtExtendedDynamicState3EnablesSupported();
|
||||
|
||||
// VIDS: Independent toggle (not affected by dyna_state levels)
|
||||
dynamic_features.has_dynamic_vertex_input =
|
||||
device.IsExtVertexInputDynamicStateSupported() &&
|
||||
Settings::values.vertex_input_dynamic_state.GetValue();
|
||||
}
|
||||
|
||||
PipelineCache::~PipelineCache() {
|
||||
@@ -595,12 +565,7 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
|
||||
(key.state.extended_dynamic_state_2 != 0) !=
|
||||
dynamic_features.has_extended_dynamic_state_2 ||
|
||||
(key.state.extended_dynamic_state_2_logic_op != 0) !=
|
||||
dynamic_features.has_extended_dynamic_state_2_logic_op ||
|
||||
(key.state.extended_dynamic_state_3_blend != 0) !=
|
||||
dynamic_features.has_extended_dynamic_state_3_blend ||
|
||||
(key.state.extended_dynamic_state_3_enables != 0) !=
|
||||
dynamic_features.has_extended_dynamic_state_3_enables ||
|
||||
(key.state.dynamic_vertex_input != 0) != dynamic_features.has_dynamic_vertex_input) {
|
||||
dynamic_features.has_extended_dynamic_state_2_logic_op) {
|
||||
return;
|
||||
}
|
||||
workers.QueueWork([this, key, envs_ = std::move(envs), &state, &callback]() mutable {
|
||||
|
||||
@@ -1044,42 +1044,6 @@ void RasterizerVulkan::UpdateDynamicStates() {
|
||||
UpdateLogicOp(regs);
|
||||
}
|
||||
|
||||
// EDS3 Enables: LogicOpEnable, DepthClamp, LineStipple, ConservativeRaster
|
||||
if (device.IsExtExtendedDynamicState3EnablesSupported()) {
|
||||
using namespace Tegra::Engines;
|
||||
// AMD Workaround: LogicOp incompatible with float render targets
|
||||
if (device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_OPEN_SOURCE ||
|
||||
device.GetDriverID() == VkDriverIdKHR::VK_DRIVER_ID_AMD_PROPRIETARY) {
|
||||
const auto has_float = std::any_of(
|
||||
regs.vertex_attrib_format.begin(), regs.vertex_attrib_format.end(),
|
||||
[](const auto& attrib) {
|
||||
return attrib.type == Maxwell3D::Regs::VertexAttribute::Type::Float;
|
||||
}
|
||||
);
|
||||
if (regs.logic_op.enable) {
|
||||
regs.logic_op.enable = static_cast<u32>(!has_float);
|
||||
}
|
||||
}
|
||||
UpdateLogicOpEnable(regs);
|
||||
UpdateDepthClampEnable(regs);
|
||||
UpdateLineRasterizationMode(regs);
|
||||
UpdateLineStippleEnable(regs);
|
||||
UpdateConservativeRasterizationMode(regs);
|
||||
UpdateAlphaToCoverageEnable(regs);
|
||||
UpdateAlphaToOneEnable(regs);
|
||||
}
|
||||
|
||||
// EDS3 Blending: ColorBlendEnable, ColorBlendEquation, ColorWriteMask
|
||||
if (device.IsExtExtendedDynamicState3BlendingSupported()) {
|
||||
UpdateBlending(regs);
|
||||
}
|
||||
|
||||
// Vertex Input Dynamic State: Independent from EDS levels
|
||||
if (device.IsExtVertexInputDynamicStateSupported()) {
|
||||
if (auto* gp = pipeline_cache.CurrentGraphicsPipeline(); gp && gp->HasDynamicVertexInput()) {
|
||||
UpdateVertexInput(regs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::HandleTransformFeedback() {
|
||||
@@ -1434,73 +1398,6 @@ void RasterizerVulkan::UpdateRasterizerDiscardEnable(Tegra::Engines::Maxwell3D::
|
||||
});
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateConservativeRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
if (!state_tracker.TouchConservativeRasterizationMode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!device.SupportsDynamicState3ConservativeRasterizationMode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
scheduler.Record([enable = regs.conservative_raster_enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetConservativeRasterizationModeEXT(
|
||||
enable ? VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT
|
||||
: VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT);
|
||||
});
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateLineStippleEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
if (!state_tracker.TouchLineStippleEnable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!device.SupportsDynamicState3LineStippleEnable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
scheduler.Record([enable = regs.line_stipple_enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetLineStippleEnableEXT(enable);
|
||||
});
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateLineRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
if (!device.IsExtLineRasterizationSupported()) {
|
||||
return;
|
||||
}
|
||||
if (!state_tracker.TouchLineRasterizationMode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!device.SupportsDynamicState3LineRasterizationMode()) {
|
||||
static std::once_flag warn_missing_rect;
|
||||
std::call_once(warn_missing_rect, [] {
|
||||
LOG_WARNING(Render_Vulkan,
|
||||
"Driver lacks rectangular line rasterization support; skipping dynamic "
|
||||
"line state updates");
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
const bool wants_smooth = regs.line_anti_alias_enable != 0;
|
||||
VkLineRasterizationModeEXT mode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT;
|
||||
if (wants_smooth) {
|
||||
if (device.SupportsSmoothLines()) {
|
||||
mode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT;
|
||||
} else {
|
||||
static std::once_flag warn_missing_smooth;
|
||||
std::call_once(warn_missing_smooth, [] {
|
||||
LOG_WARNING(Render_Vulkan,
|
||||
"Line anti-aliasing requested but smoothLines feature unavailable; "
|
||||
"using rectangular rasterization");
|
||||
});
|
||||
}
|
||||
}
|
||||
scheduler.Record([mode](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetLineRasterizationModeEXT(mode);
|
||||
});
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
if (!state_tracker.TouchDepthBiasEnable()) {
|
||||
return;
|
||||
@@ -1536,70 +1433,6 @@ void RasterizerVulkan::UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& re
|
||||
[enable](vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthBiasEnableEXT(enable != 0); });
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateLogicOpEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
if (!state_tracker.TouchLogicOpEnable()) {
|
||||
return;
|
||||
}
|
||||
if (!device.SupportsDynamicState3LogicOpEnable()) {
|
||||
return;
|
||||
}
|
||||
scheduler.Record([enable = regs.logic_op.enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetLogicOpEnableEXT(enable != 0);
|
||||
});
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateDepthClampEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
if (!state_tracker.TouchDepthClampEnable()) {
|
||||
return;
|
||||
}
|
||||
if (!device.SupportsDynamicState3DepthClampEnable()) {
|
||||
return;
|
||||
}
|
||||
bool is_enabled = !(regs.viewport_clip_control.geometry_clip ==
|
||||
Maxwell::ViewportClipControl::GeometryClip::Passthrough ||
|
||||
regs.viewport_clip_control.geometry_clip ==
|
||||
Maxwell::ViewportClipControl::GeometryClip::FrustumXYZ ||
|
||||
regs.viewport_clip_control.geometry_clip ==
|
||||
Maxwell::ViewportClipControl::GeometryClip::FrustumZ);
|
||||
scheduler.Record(
|
||||
[is_enabled](vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthClampEnableEXT(is_enabled); });
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateAlphaToCoverageEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
if (!state_tracker.TouchAlphaToCoverageEnable()) {
|
||||
return;
|
||||
}
|
||||
if (!device.SupportsDynamicState3AlphaToCoverageEnable()) {
|
||||
return;
|
||||
}
|
||||
GraphicsPipeline* const pipeline = pipeline_cache.CurrentGraphicsPipeline();
|
||||
const bool enable = pipeline != nullptr && pipeline->SupportsAlphaToCoverage() &&
|
||||
regs.anti_alias_alpha_control.alpha_to_coverage != 0;
|
||||
scheduler.Record([enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetAlphaToCoverageEnableEXT(enable ? VK_TRUE : VK_FALSE);
|
||||
});
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateAlphaToOneEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
if (!state_tracker.TouchAlphaToOneEnable()) {
|
||||
return;
|
||||
}
|
||||
if (!device.SupportsDynamicState3AlphaToOneEnable()) {
|
||||
static std::once_flag warn_alpha_to_one;
|
||||
std::call_once(warn_alpha_to_one, [] {
|
||||
LOG_WARNING(Render_Vulkan,
|
||||
"Alpha-to-one is not supported on this device; forcing it disabled");
|
||||
});
|
||||
return;
|
||||
}
|
||||
GraphicsPipeline* const pipeline = pipeline_cache.CurrentGraphicsPipeline();
|
||||
const bool enable = pipeline != nullptr && pipeline->SupportsAlphaToOne() &&
|
||||
regs.anti_alias_alpha_control.alpha_to_one != 0;
|
||||
scheduler.Record([enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetAlphaToOneEnableEXT(enable ? VK_TRUE : VK_FALSE);
|
||||
});
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
if (!state_tracker.TouchDepthCompareOp()) {
|
||||
return;
|
||||
@@ -1671,81 +1504,6 @@ void RasterizerVulkan::UpdateBlending(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
if (!state_tracker.TouchBlending()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state_tracker.TouchColorMask()) {
|
||||
std::array<VkColorComponentFlags, Maxwell::NumRenderTargets> setup_masks{};
|
||||
for (size_t index = 0; index < Maxwell::NumRenderTargets; index++) {
|
||||
const auto& mask = regs.color_mask[regs.color_mask_common ? 0 : index];
|
||||
auto& current = setup_masks[index];
|
||||
if (mask.R) {
|
||||
current |= VK_COLOR_COMPONENT_R_BIT;
|
||||
}
|
||||
if (mask.G) {
|
||||
current |= VK_COLOR_COMPONENT_G_BIT;
|
||||
}
|
||||
if (mask.B) {
|
||||
current |= VK_COLOR_COMPONENT_B_BIT;
|
||||
}
|
||||
if (mask.A) {
|
||||
current |= VK_COLOR_COMPONENT_A_BIT;
|
||||
}
|
||||
}
|
||||
scheduler.Record([setup_masks](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetColorWriteMaskEXT(0, setup_masks);
|
||||
});
|
||||
}
|
||||
|
||||
if (state_tracker.TouchBlendEnable()) {
|
||||
std::array<VkBool32, Maxwell::NumRenderTargets> setup_enables{};
|
||||
std::ranges::transform(
|
||||
regs.blend.enable, setup_enables.begin(),
|
||||
[&](const auto& is_enabled) { return is_enabled != 0 ? VK_TRUE : VK_FALSE; });
|
||||
scheduler.Record([setup_enables](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetColorBlendEnableEXT(0, setup_enables);
|
||||
});
|
||||
}
|
||||
|
||||
if (state_tracker.TouchBlendEquations()) {
|
||||
std::array<VkColorBlendEquationEXT, Maxwell::NumRenderTargets> setup_blends{};
|
||||
|
||||
const auto blend_setup = [&](auto& host_blend, const auto& guest_blend) {
|
||||
host_blend.srcColorBlendFactor = MaxwellToVK::BlendFactor(guest_blend.color_source);
|
||||
host_blend.dstColorBlendFactor = MaxwellToVK::BlendFactor(guest_blend.color_dest);
|
||||
host_blend.colorBlendOp = MaxwellToVK::BlendEquation(guest_blend.color_op);
|
||||
host_blend.srcAlphaBlendFactor = MaxwellToVK::BlendFactor(guest_blend.alpha_source);
|
||||
host_blend.dstAlphaBlendFactor = MaxwellToVK::BlendFactor(guest_blend.alpha_dest);
|
||||
host_blend.alphaBlendOp = MaxwellToVK::BlendEquation(guest_blend.alpha_op);
|
||||
};
|
||||
|
||||
// Single blend equation for all targets
|
||||
if (!regs.blend_per_target_enabled) {
|
||||
// Temporary workaround for games that use iterated blending
|
||||
if (regs.iterated_blend.enable && Settings::values.use_squashed_iterated_blend) {
|
||||
setup_blends[0].srcColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
setup_blends[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
setup_blends[0].colorBlendOp = VK_BLEND_OP_ADD;
|
||||
setup_blends[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_COLOR;
|
||||
setup_blends[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
setup_blends[0].alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
} else {
|
||||
blend_setup(setup_blends[0], regs.blend);
|
||||
}
|
||||
|
||||
// Copy first blend state to all other targets
|
||||
for (size_t index = 1; index < Maxwell::NumRenderTargets; index++) {
|
||||
setup_blends[index] = setup_blends[0];
|
||||
}
|
||||
} else {
|
||||
// Per-target blending
|
||||
for (size_t index = 0; index < Maxwell::NumRenderTargets; index++) {
|
||||
blend_setup(setup_blends[index], regs.blend_per_target[index]);
|
||||
}
|
||||
}
|
||||
|
||||
scheduler.Record([setup_blends](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetColorBlendEquationEXT(0, setup_blends);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
@@ -1763,56 +1521,6 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs)
|
||||
return;
|
||||
}
|
||||
dirty[Dirty::VertexInput] = false;
|
||||
|
||||
boost::container::static_vector<VkVertexInputBindingDescription2EXT, 32> bindings;
|
||||
boost::container::static_vector<VkVertexInputAttributeDescription2EXT, 32> attributes;
|
||||
|
||||
// There seems to be a bug on Nvidia's driver where updating only higher attributes ends up
|
||||
// generating dirty state. Track the highest dirty attribute and update all attributes until
|
||||
// that one.
|
||||
size_t highest_dirty_attr{};
|
||||
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
|
||||
if (dirty[Dirty::VertexAttribute0 + index]) {
|
||||
highest_dirty_attr = index;
|
||||
}
|
||||
}
|
||||
for (size_t index = 0; index < highest_dirty_attr; ++index) {
|
||||
const Maxwell::VertexAttribute attribute{regs.vertex_attrib_format[index]};
|
||||
const u32 binding{attribute.buffer};
|
||||
dirty[Dirty::VertexAttribute0 + index] = false;
|
||||
dirty[Dirty::VertexBinding0 + static_cast<size_t>(binding)] = true;
|
||||
if (!attribute.constant) {
|
||||
attributes.push_back({
|
||||
.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_ATTRIBUTE_DESCRIPTION_2_EXT,
|
||||
.pNext = nullptr,
|
||||
.location = static_cast<u32>(index),
|
||||
.binding = binding,
|
||||
.format = MaxwellToVK::VertexFormat(device, attribute.type, attribute.size),
|
||||
.offset = attribute.offset,
|
||||
});
|
||||
}
|
||||
}
|
||||
for (size_t index = 0; index < Maxwell::NumVertexAttributes; ++index) {
|
||||
if (!dirty[Dirty::VertexBinding0 + index]) {
|
||||
continue;
|
||||
}
|
||||
dirty[Dirty::VertexBinding0 + index] = false;
|
||||
|
||||
const u32 binding{static_cast<u32>(index)};
|
||||
const auto& input_binding{regs.vertex_streams[binding]};
|
||||
const bool is_instanced{regs.vertex_stream_instances.IsInstancingEnabled(binding)};
|
||||
bindings.push_back({
|
||||
.sType = VK_STRUCTURE_TYPE_VERTEX_INPUT_BINDING_DESCRIPTION_2_EXT,
|
||||
.pNext = nullptr,
|
||||
.binding = binding,
|
||||
.stride = input_binding.stride,
|
||||
.inputRate = is_instanced ? VK_VERTEX_INPUT_RATE_INSTANCE : VK_VERTEX_INPUT_RATE_VERTEX,
|
||||
.divisor = is_instanced ? input_binding.frequency : 1,
|
||||
});
|
||||
}
|
||||
scheduler.Record([bindings, attributes](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetVertexInputEXT(bindings, attributes);
|
||||
});
|
||||
}
|
||||
|
||||
void RasterizerVulkan::InitializeChannel(Tegra::Control::ChannelState& channel) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -176,15 +176,7 @@ private:
|
||||
void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdatePrimitiveRestartEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateRasterizerDiscardEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateConservativeRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateLineStippleEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateLineStipple(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateLineRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateLogicOpEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateDepthClampEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateAlphaToCoverageEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateAlphaToOneEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
@@ -54,19 +54,11 @@ Flags MakeInvalidationFlags() {
|
||||
StateEnable,
|
||||
PrimitiveRestartEnable,
|
||||
DepthBiasEnable,
|
||||
LogicOpEnable,
|
||||
DepthClampEnable,
|
||||
AlphaToCoverageEnable,
|
||||
AlphaToOneEnable,
|
||||
LineRasterizationMode,
|
||||
LogicOp,
|
||||
Blending,
|
||||
ColorMask,
|
||||
BlendEquations,
|
||||
BlendEnable,
|
||||
ConservativeRasterizationMode,
|
||||
LineStippleEnable,
|
||||
LineStippleParams,
|
||||
};
|
||||
Flags flags{};
|
||||
for (const int flag : INVALIDATION_FLAGS) {
|
||||
@@ -149,11 +141,6 @@ void SetupDirtyStateEnable(Tables& tables) {
|
||||
setup(OFF(polygon_offset_point_enable), DepthBiasEnable);
|
||||
setup(OFF(polygon_offset_line_enable), DepthBiasEnable);
|
||||
setup(OFF(polygon_offset_fill_enable), DepthBiasEnable);
|
||||
setup(OFF(logic_op.enable), LogicOpEnable);
|
||||
setup(OFF(viewport_clip_control.geometry_clip), DepthClampEnable);
|
||||
setup(OFF(line_stipple_enable), LineStippleEnable);
|
||||
setup(OFF(anti_alias_alpha_control.alpha_to_coverage), AlphaToCoverageEnable);
|
||||
setup(OFF(anti_alias_alpha_control.alpha_to_one), AlphaToOneEnable);
|
||||
}
|
||||
|
||||
void SetupDirtyDepthCompareOp(Tables& tables) {
|
||||
@@ -227,13 +214,6 @@ void SetupDirtyVertexBindings(Tables& tables) {
|
||||
}
|
||||
}
|
||||
|
||||
void SetupRasterModes(Tables &tables) {
|
||||
auto& table = tables[0];
|
||||
|
||||
table[OFF(line_stipple_params)] = LineStippleParams;
|
||||
table[OFF(conservative_raster_enable)] = ConservativeRasterizationMode;
|
||||
table[OFF(line_anti_alias_enable)] = LineRasterizationMode;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
void StateTracker::SetupTables(Tegra::Control::ChannelState& channel_state) {
|
||||
@@ -256,7 +236,6 @@ void StateTracker::SetupTables(Tegra::Control::ChannelState& channel_state) {
|
||||
SetupDirtyVertexAttributes(tables);
|
||||
SetupDirtyVertexBindings(tables);
|
||||
SetupDirtySpecialOps(tables);
|
||||
SetupRasterModes(tables);
|
||||
}
|
||||
|
||||
void StateTracker::ChangeChannel(Tegra::Control::ChannelState& channel_state) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
|
||||
@@ -53,17 +53,9 @@ enum : u8 {
|
||||
StencilTestEnable,
|
||||
PrimitiveRestartEnable,
|
||||
RasterizerDiscardEnable,
|
||||
ConservativeRasterizationMode,
|
||||
LineRasterizationMode,
|
||||
LineStippleEnable,
|
||||
LineStippleParams,
|
||||
DepthBiasEnable,
|
||||
StateEnable,
|
||||
LogicOp,
|
||||
LogicOpEnable,
|
||||
DepthClampEnable,
|
||||
AlphaToCoverageEnable,
|
||||
AlphaToOneEnable,
|
||||
|
||||
Blending,
|
||||
BlendEnable,
|
||||
@@ -213,33 +205,8 @@ public:
|
||||
return Exchange(Dirty::RasterizerDiscardEnable, false);
|
||||
}
|
||||
|
||||
bool TouchConservativeRasterizationMode()
|
||||
{
|
||||
return Exchange(Dirty::ConservativeRasterizationMode, false);
|
||||
}
|
||||
|
||||
bool TouchLineStippleEnable() { return Exchange(Dirty::LineStippleEnable, false); }
|
||||
|
||||
bool TouchLineStipple() { return Exchange(Dirty::LineStippleParams, false); }
|
||||
|
||||
bool TouchDepthBiasEnable() { return Exchange(Dirty::DepthBiasEnable, false); }
|
||||
|
||||
bool TouchLogicOpEnable() {
|
||||
return Exchange(Dirty::LogicOpEnable, false);
|
||||
}
|
||||
|
||||
bool TouchDepthClampEnable() {
|
||||
return Exchange(Dirty::DepthClampEnable, false);
|
||||
}
|
||||
|
||||
bool TouchAlphaToCoverageEnable() {
|
||||
return Exchange(Dirty::AlphaToCoverageEnable, false);
|
||||
}
|
||||
|
||||
bool TouchAlphaToOneEnable() {
|
||||
return Exchange(Dirty::AlphaToOneEnable, false);
|
||||
}
|
||||
|
||||
bool TouchDepthCompareOp() {
|
||||
return Exchange(Dirty::DepthCompareOp, false);
|
||||
}
|
||||
@@ -276,10 +243,6 @@ public:
|
||||
return Exchange(Dirty::LogicOp, false);
|
||||
}
|
||||
|
||||
bool TouchLineRasterizationMode() {
|
||||
return Exchange(Dirty::LineRasterizationMode, false);
|
||||
}
|
||||
|
||||
bool ChangePrimitiveTopology(Maxwell::PrimitiveTopology new_topology) {
|
||||
const bool has_changed = current_topology != new_topology;
|
||||
current_topology = new_topology;
|
||||
|
||||
Reference in New Issue
Block a user