Compare commits
64 Commits
master
...
true-eds-g
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5046f84da8 | ||
|
|
58b2a8a810 | ||
|
|
b50ace27ee | ||
|
|
93eb41e531 | ||
|
|
d8acbdb71b | ||
|
|
dcc95778fd | ||
|
|
2392a1cfb6 | ||
|
|
abd88d5498 | ||
|
|
e60e448b10 | ||
|
|
0bb092b0d9 | ||
|
|
3928495e7e | ||
|
|
2a6e734fa2 | ||
|
|
239841ec93 | ||
|
|
629d1f3609 | ||
|
|
e4bb934438 | ||
|
|
54bb5b79f8 | ||
|
|
a18f78367d | ||
|
|
29dfd96ae6 | ||
|
|
0d92c21ca7 | ||
|
|
b4f4ec7cbb | ||
|
|
7034974dce | ||
|
|
7d41cc6a72 | ||
|
|
8315f15cc1 | ||
|
|
f63818be3c | ||
|
|
8cce12f3d3 | ||
|
|
2abf124f09 | ||
|
|
2afdafc5cb | ||
|
|
6a230bec1a | ||
|
|
18dabbaaff | ||
|
|
f24b7015be | ||
|
|
5738b48694 | ||
|
|
3adf212933 | ||
|
|
60645dc51c | ||
|
|
b9f3e3b258 | ||
|
|
f6287ea7cd | ||
|
|
7867c19b2c | ||
|
|
b1ec27dfce | ||
|
|
3760b8c097 | ||
|
|
34530edd39 | ||
|
|
a3c0e0ac2d | ||
|
|
39e3a56575 | ||
|
|
66c26e39fe | ||
|
|
7389b35a98 | ||
|
|
a96b601cb5 | ||
|
|
567a203f56 | ||
|
|
1cd270cf4f | ||
|
|
b053517c67 | ||
|
|
1f5b866290 | ||
|
|
57d56086c4 | ||
|
|
ad4ceaf7e3 | ||
|
|
b0d0b61f88 | ||
|
|
e7eb4dba78 | ||
|
|
d82b333383 | ||
|
|
8e90752f62 | ||
|
|
c28c19dffa | ||
|
|
3cadb3715b | ||
|
|
a17e295a13 | ||
|
|
d7c932cc93 | ||
|
|
3334e9aafb | ||
|
|
21a4752401 | ||
|
|
e537cba7f3 | ||
|
|
9578c4b29c | ||
|
|
963fb7c803 | ||
|
|
3ba40e7274 |
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -542,8 +545,9 @@ Id EmitImageFetch(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id c
|
|||||||
lod = Id{};
|
lod = Id{};
|
||||||
}
|
}
|
||||||
const ImageOperands operands(lod, ms);
|
const ImageOperands operands(lod, ms);
|
||||||
return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst, ctx.F32[4],
|
return Emit(&EmitContext::OpImageSparseFetch, &EmitContext::OpImageFetch, ctx, inst,
|
||||||
TextureImage(ctx, info, index), coords, operands.MaskOptional(), operands.Span());
|
ctx.F32[4], TextureImage(ctx, info, index), coords, operands.MaskOptional(),
|
||||||
|
operands.Span());
|
||||||
}
|
}
|
||||||
|
|
||||||
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod,
|
Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id lod,
|
||||||
|
|||||||
@@ -315,6 +315,9 @@ void DefineSsbos(EmitContext& ctx, StorageTypeDefinition& type_def,
|
|||||||
ctx.Decorate(id, spv::Decoration::Binding, binding);
|
ctx.Decorate(id, spv::Decoration::Binding, binding);
|
||||||
ctx.Decorate(id, spv::Decoration::DescriptorSet, 0U);
|
ctx.Decorate(id, spv::Decoration::DescriptorSet, 0U);
|
||||||
ctx.Name(id, fmt::format("ssbo{}", index));
|
ctx.Name(id, fmt::format("ssbo{}", index));
|
||||||
|
if (!desc.is_written) {
|
||||||
|
ctx.Decorate(id, spv::Decoration::NonWritable);
|
||||||
|
}
|
||||||
if (ctx.profile.supported_spirv >= 0x00010400) {
|
if (ctx.profile.supported_spirv >= 0x00010400) {
|
||||||
ctx.interfaces.push_back(id);
|
ctx.interfaces.push_back(id);
|
||||||
}
|
}
|
||||||
@@ -1432,6 +1435,9 @@ void EmitContext::DefineInputs(const IR::Program& program) {
|
|||||||
}
|
}
|
||||||
if (info.uses_sample_id) {
|
if (info.uses_sample_id) {
|
||||||
sample_id = DefineInput(*this, U32[1], false, spv::BuiltIn::SampleId);
|
sample_id = DefineInput(*this, U32[1], false, spv::BuiltIn::SampleId);
|
||||||
|
if (stage == Stage::Fragment) {
|
||||||
|
Decorate(sample_id, spv::Decoration::Flat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (info.uses_is_helper_invocation) {
|
if (info.uses_is_helper_invocation) {
|
||||||
is_helper_invocation = DefineInput(*this, U1, false, spv::BuiltIn::HelperInvocation);
|
is_helper_invocation = DefineInput(*this, U1, false, spv::BuiltIn::HelperInvocation);
|
||||||
@@ -1442,6 +1448,13 @@ void EmitContext::DefineInputs(const IR::Program& program) {
|
|||||||
subgroup_mask_le = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupLeMaskKHR);
|
subgroup_mask_le = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupLeMaskKHR);
|
||||||
subgroup_mask_gt = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGtMaskKHR);
|
subgroup_mask_gt = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGtMaskKHR);
|
||||||
subgroup_mask_ge = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGeMaskKHR);
|
subgroup_mask_ge = DefineInput(*this, U32[4], false, spv::BuiltIn::SubgroupGeMaskKHR);
|
||||||
|
if (stage == Stage::Fragment) {
|
||||||
|
Decorate(subgroup_mask_eq, spv::Decoration::Flat);
|
||||||
|
Decorate(subgroup_mask_lt, spv::Decoration::Flat);
|
||||||
|
Decorate(subgroup_mask_le, spv::Decoration::Flat);
|
||||||
|
Decorate(subgroup_mask_gt, spv::Decoration::Flat);
|
||||||
|
Decorate(subgroup_mask_ge, spv::Decoration::Flat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (info.uses_fswzadd || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles ||
|
if (info.uses_fswzadd || info.uses_subgroup_invocation_id || info.uses_subgroup_shuffles ||
|
||||||
(profile.warp_size_potentially_larger_than_guest &&
|
(profile.warp_size_potentially_larger_than_guest &&
|
||||||
@@ -1449,7 +1462,9 @@ void EmitContext::DefineInputs(const IR::Program& program) {
|
|||||||
AddCapability(spv::Capability::GroupNonUniform);
|
AddCapability(spv::Capability::GroupNonUniform);
|
||||||
subgroup_local_invocation_id =
|
subgroup_local_invocation_id =
|
||||||
DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId);
|
DefineInput(*this, U32[1], false, spv::BuiltIn::SubgroupLocalInvocationId);
|
||||||
Decorate(subgroup_local_invocation_id, spv::Decoration::Flat);
|
if (stage == Stage::Fragment) {
|
||||||
|
Decorate(subgroup_local_invocation_id, spv::Decoration::Flat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (info.uses_fswzadd) {
|
if (info.uses_fswzadd) {
|
||||||
const Id f32_one{Const(1.0f)};
|
const Id f32_one{Const(1.0f)};
|
||||||
@@ -1461,6 +1476,9 @@ void EmitContext::DefineInputs(const IR::Program& program) {
|
|||||||
}
|
}
|
||||||
if (loads[IR::Attribute::PrimitiveId]) {
|
if (loads[IR::Attribute::PrimitiveId]) {
|
||||||
primitive_id = DefineInput(*this, U32[1], false, spv::BuiltIn::PrimitiveId);
|
primitive_id = DefineInput(*this, U32[1], false, spv::BuiltIn::PrimitiveId);
|
||||||
|
if (stage == Stage::Fragment) {
|
||||||
|
Decorate(primitive_id, spv::Decoration::Flat);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (loads[IR::Attribute::Layer]) {
|
if (loads[IR::Attribute::Layer]) {
|
||||||
AddCapability(spv::Capability::Geometry);
|
AddCapability(spv::Capability::Geometry);
|
||||||
@@ -1552,17 +1570,21 @@ void EmitContext::DefineInputs(const IR::Program& program) {
|
|||||||
if (stage != Stage::Fragment) {
|
if (stage != Stage::Fragment) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
switch (info.interpolation[index]) {
|
const bool is_integer = input_type == AttributeType::SignedInt ||
|
||||||
case Interpolation::Smooth:
|
input_type == AttributeType::UnsignedInt;
|
||||||
// Default
|
if (is_integer) {
|
||||||
// Decorate(id, spv::Decoration::Smooth);
|
|
||||||
break;
|
|
||||||
case Interpolation::NoPerspective:
|
|
||||||
Decorate(id, spv::Decoration::NoPerspective);
|
|
||||||
break;
|
|
||||||
case Interpolation::Flat:
|
|
||||||
Decorate(id, spv::Decoration::Flat);
|
Decorate(id, spv::Decoration::Flat);
|
||||||
break;
|
} else {
|
||||||
|
switch (info.interpolation[index]) {
|
||||||
|
case Interpolation::Smooth:
|
||||||
|
break;
|
||||||
|
case Interpolation::NoPerspective:
|
||||||
|
Decorate(id, spv::Decoration::NoPerspective);
|
||||||
|
break;
|
||||||
|
case Interpolation::Flat:
|
||||||
|
Decorate(id, spv::Decoration::Flat);
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (stage == Stage::TessellationEval) {
|
if (stage == Stage::TessellationEval) {
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -351,7 +354,7 @@ std::optional<StorageBufferAddr> Track(const IR::Value& value, const Bias* bias)
|
|||||||
.index = index.U32(),
|
.index = index.U32(),
|
||||||
.offset = offset.U32(),
|
.offset = offset.U32(),
|
||||||
};
|
};
|
||||||
const u32 alignment{bias ? bias->alignment : 8U};
|
const u32 alignment{bias ? bias->alignment : 16U};
|
||||||
if (!Common::IsAligned(storage_buffer.offset, alignment)) {
|
if (!Common::IsAligned(storage_buffer.offset, alignment)) {
|
||||||
// The SSBO pointer has to be aligned
|
// The SSBO pointer has to be aligned
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
@@ -372,9 +375,9 @@ void CollectStorageBuffers(IR::Block& block, IR::Inst& inst, StorageInfo& info)
|
|||||||
// avoid getting false positives
|
// avoid getting false positives
|
||||||
static constexpr Bias nvn_bias{
|
static constexpr Bias nvn_bias{
|
||||||
.index = 0,
|
.index = 0,
|
||||||
.offset_begin = 0x100,
|
.offset_begin = 0x110,
|
||||||
.offset_end = 0x700,
|
.offset_end = 0x800,
|
||||||
.alignment = 16,
|
.alignment = 32,
|
||||||
};
|
};
|
||||||
// Track the low address of the instruction
|
// Track the low address of the instruction
|
||||||
const std::optional<LowAddrInfo> low_addr_info{TrackLowAddress(&inst)};
|
const std::optional<LowAddrInfo> low_addr_info{TrackLowAddress(&inst)};
|
||||||
|
|||||||
@@ -525,18 +525,24 @@ BlitImageHelper::BlitImageHelper(const Device& device_, Scheduler& scheduler_,
|
|||||||
nullptr, PUSH_CONSTANT_RANGE<VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(float) * 4>))),
|
nullptr, PUSH_CONSTANT_RANGE<VK_SHADER_STAGE_FRAGMENT_BIT, sizeof(float) * 4>))),
|
||||||
full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)),
|
full_screen_vert(BuildShader(device, FULL_SCREEN_TRIANGLE_VERT_SPV)),
|
||||||
blit_color_to_color_frag(BuildShader(device, BLIT_COLOR_FLOAT_FRAG_SPV)),
|
blit_color_to_color_frag(BuildShader(device, BLIT_COLOR_FLOAT_FRAG_SPV)),
|
||||||
blit_depth_stencil_frag(BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)),
|
blit_depth_stencil_frag(device.IsExtShaderStencilExportSupported()
|
||||||
|
? BuildShader(device, VULKAN_BLIT_DEPTH_STENCIL_FRAG_SPV)
|
||||||
|
: vk::ShaderModule{}),
|
||||||
clear_color_vert(BuildShader(device, VULKAN_COLOR_CLEAR_VERT_SPV)),
|
clear_color_vert(BuildShader(device, VULKAN_COLOR_CLEAR_VERT_SPV)),
|
||||||
clear_color_frag(BuildShader(device, VULKAN_COLOR_CLEAR_FRAG_SPV)),
|
clear_color_frag(BuildShader(device, VULKAN_COLOR_CLEAR_FRAG_SPV)),
|
||||||
clear_stencil_frag(BuildShader(device, VULKAN_DEPTHSTENCIL_CLEAR_FRAG_SPV)),
|
clear_stencil_frag(BuildShader(device, VULKAN_DEPTHSTENCIL_CLEAR_FRAG_SPV)),
|
||||||
convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)),
|
convert_depth_to_float_frag(BuildShader(device, CONVERT_DEPTH_TO_FLOAT_FRAG_SPV)),
|
||||||
convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)),
|
convert_float_to_depth_frag(BuildShader(device, CONVERT_FLOAT_TO_DEPTH_FRAG_SPV)),
|
||||||
convert_abgr8_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)),
|
convert_abgr8_to_d24s8_frag(device.IsExtShaderStencilExportSupported()
|
||||||
|
? BuildShader(device, CONVERT_ABGR8_TO_D24S8_FRAG_SPV)
|
||||||
|
: vk::ShaderModule{}),
|
||||||
convert_abgr8_to_d32f_frag(BuildShader(device, CONVERT_ABGR8_TO_D32F_FRAG_SPV)),
|
convert_abgr8_to_d32f_frag(BuildShader(device, CONVERT_ABGR8_TO_D32F_FRAG_SPV)),
|
||||||
convert_d32f_to_abgr8_frag(BuildShader(device, CONVERT_D32F_TO_ABGR8_FRAG_SPV)),
|
convert_d32f_to_abgr8_frag(BuildShader(device, CONVERT_D32F_TO_ABGR8_FRAG_SPV)),
|
||||||
convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
|
convert_d24s8_to_abgr8_frag(BuildShader(device, CONVERT_D24S8_TO_ABGR8_FRAG_SPV)),
|
||||||
convert_s8d24_to_abgr8_frag(BuildShader(device, CONVERT_S8D24_TO_ABGR8_FRAG_SPV)),
|
convert_s8d24_to_abgr8_frag(BuildShader(device, CONVERT_S8D24_TO_ABGR8_FRAG_SPV)),
|
||||||
convert_abgr8_srgb_to_d24s8_frag(BuildShader(device, CONVERT_ABGR8_SRGB_TO_D24S8_FRAG_SPV)),
|
convert_abgr8_srgb_to_d24s8_frag(device.IsExtShaderStencilExportSupported()
|
||||||
|
? BuildShader(device, CONVERT_ABGR8_SRGB_TO_D24S8_FRAG_SPV)
|
||||||
|
: vk::ShaderModule{}),
|
||||||
convert_rgba_to_bgra_frag(BuildShader(device, CONVERT_RGBA8_TO_BGRA8_FRAG_SPV)),
|
convert_rgba_to_bgra_frag(BuildShader(device, CONVERT_RGBA8_TO_BGRA8_FRAG_SPV)),
|
||||||
convert_yuv420_to_rgb_comp(BuildShader(device, CONVERT_YUV420_TO_RGB_COMP_SPV)),
|
convert_yuv420_to_rgb_comp(BuildShader(device, CONVERT_YUV420_TO_RGB_COMP_SPV)),
|
||||||
convert_rgb_to_yuv420_comp(BuildShader(device, CONVERT_RGB_TO_YUV420_COMP_SPV)),
|
convert_rgb_to_yuv420_comp(BuildShader(device, CONVERT_RGB_TO_YUV420_COMP_SPV)),
|
||||||
@@ -667,6 +673,11 @@ void BlitImageHelper::ConvertR16ToD16(const Framebuffer* dst_framebuffer,
|
|||||||
|
|
||||||
void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertABGR8ToD24S8(const Framebuffer* dst_framebuffer,
|
||||||
const ImageView& src_image_view) {
|
const ImageView& src_image_view) {
|
||||||
|
if (!device.IsExtShaderStencilExportSupported()) {
|
||||||
|
// Shader requires VK_EXT_shader_stencil_export which is not available
|
||||||
|
LOG_WARNING(Render_Vulkan, "ConvertABGR8ToD24S8 requires shader_stencil_export, skipping");
|
||||||
|
return;
|
||||||
|
}
|
||||||
ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
|
ConvertPipelineDepthTargetEx(convert_abgr8_to_d24s8_pipeline, dst_framebuffer->RenderPass(),
|
||||||
convert_abgr8_to_d24s8_frag);
|
convert_abgr8_to_d24s8_frag);
|
||||||
Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view);
|
Convert(*convert_abgr8_to_d24s8_pipeline, dst_framebuffer, src_image_view);
|
||||||
@@ -702,6 +713,11 @@ void BlitImageHelper::ConvertS8D24ToABGR8(const Framebuffer* dst_framebuffer,
|
|||||||
|
|
||||||
void BlitImageHelper::ConvertABGR8SRGBToD24S8(const Framebuffer* dst_framebuffer,
|
void BlitImageHelper::ConvertABGR8SRGBToD24S8(const Framebuffer* dst_framebuffer,
|
||||||
const ImageView& src_image_view) {
|
const ImageView& src_image_view) {
|
||||||
|
if (!device.IsExtShaderStencilExportSupported()) {
|
||||||
|
// Shader requires VK_EXT_shader_stencil_export which is not available
|
||||||
|
LOG_WARNING(Render_Vulkan, "ConvertABGR8SRGBToD24S8 requires shader_stencil_export, skipping");
|
||||||
|
return;
|
||||||
|
}
|
||||||
ConvertPipelineDepthTargetEx(convert_abgr8_srgb_to_d24s8_pipeline,
|
ConvertPipelineDepthTargetEx(convert_abgr8_srgb_to_d24s8_pipeline,
|
||||||
dst_framebuffer->RenderPass(),
|
dst_framebuffer->RenderPass(),
|
||||||
convert_abgr8_srgb_to_d24s8_frag);
|
convert_abgr8_srgb_to_d24s8_frag);
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
|
|||||||
raw1 = 0;
|
raw1 = 0;
|
||||||
extended_dynamic_state.Assign(features.has_extended_dynamic_state ? 1 : 0);
|
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.Assign(features.has_extended_dynamic_state_2 ? 1 : 0);
|
||||||
extended_dynamic_state_2_extra.Assign(features.has_extended_dynamic_state_2_extra ? 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_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);
|
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);
|
dynamic_vertex_input.Assign(features.has_dynamic_vertex_input ? 1 : 0);
|
||||||
@@ -158,7 +158,7 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
|
|||||||
return static_cast<u16>(array.stride.Value());
|
return static_cast<u16>(array.stride.Value());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (!extended_dynamic_state_2_extra) {
|
if (!extended_dynamic_state_2_logic_op) {
|
||||||
dynamic_state.Refresh2(regs, topology_, extended_dynamic_state_2);
|
dynamic_state.Refresh2(regs, topology_, extended_dynamic_state_2);
|
||||||
}
|
}
|
||||||
if (!extended_dynamic_state_3_blend) {
|
if (!extended_dynamic_state_3_blend) {
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -20,7 +23,8 @@ using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
|||||||
struct DynamicFeatures {
|
struct DynamicFeatures {
|
||||||
bool has_extended_dynamic_state;
|
bool has_extended_dynamic_state;
|
||||||
bool has_extended_dynamic_state_2;
|
bool has_extended_dynamic_state_2;
|
||||||
bool has_extended_dynamic_state_2_extra;
|
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_blend;
|
||||||
bool has_extended_dynamic_state_3_enables;
|
bool has_extended_dynamic_state_3_enables;
|
||||||
bool has_dynamic_vertex_input;
|
bool has_dynamic_vertex_input;
|
||||||
@@ -186,7 +190,7 @@ struct FixedPipelineState {
|
|||||||
u32 raw1;
|
u32 raw1;
|
||||||
BitField<0, 1, u32> extended_dynamic_state;
|
BitField<0, 1, u32> extended_dynamic_state;
|
||||||
BitField<1, 1, u32> extended_dynamic_state_2;
|
BitField<1, 1, u32> extended_dynamic_state_2;
|
||||||
BitField<2, 1, u32> extended_dynamic_state_2_extra;
|
BitField<2, 1, u32> extended_dynamic_state_2_logic_op;
|
||||||
BitField<3, 1, u32> extended_dynamic_state_3_blend;
|
BitField<3, 1, u32> extended_dynamic_state_3_blend;
|
||||||
BitField<4, 1, u32> extended_dynamic_state_3_enables;
|
BitField<4, 1, u32> extended_dynamic_state_3_enables;
|
||||||
BitField<5, 1, u32> dynamic_vertex_input;
|
BitField<5, 1, u32> dynamic_vertex_input;
|
||||||
|
|||||||
@@ -583,7 +583,9 @@ void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset
|
|||||||
if (index >= device.GetMaxVertexInputBindings()) {
|
if (index >= device.GetMaxVertexInputBindings()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (device.IsExtExtendedDynamicStateSupported()) {
|
// Use BindVertexBuffers2EXT only if EDS1 is supported AND VIDS is not active
|
||||||
|
// When VIDS is active, the pipeline doesn't declare VERTEX_INPUT_BINDING_STRIDE as dynamic
|
||||||
|
if (device.IsExtExtendedDynamicStateSupported() && !device.IsExtVertexInputDynamicStateSupported()) {
|
||||||
scheduler.Record([index, buffer, offset, size, stride](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([index, buffer, offset, size, stride](vk::CommandBuffer cmdbuf) {
|
||||||
const VkDeviceSize vk_offset = buffer != VK_NULL_HANDLE ? offset : 0;
|
const VkDeviceSize vk_offset = buffer != VK_NULL_HANDLE ? offset : 0;
|
||||||
const VkDeviceSize vk_size = buffer != VK_NULL_HANDLE ? size : VK_WHOLE_SIZE;
|
const VkDeviceSize vk_size = buffer != VK_NULL_HANDLE ? size : VK_WHOLE_SIZE;
|
||||||
@@ -623,7 +625,8 @@ void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bi
|
|||||||
if (binding_count == 0) {
|
if (binding_count == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (device.IsExtExtendedDynamicStateSupported()) {
|
// Use BindVertexBuffers2EXT only if EDS1 is supported AND VIDS is not active
|
||||||
|
if (device.IsExtExtendedDynamicStateSupported() && !device.IsExtVertexInputDynamicStateSupported()) {
|
||||||
scheduler.Record([bindings_ = std::move(bindings),
|
scheduler.Record([bindings_ = std::move(bindings),
|
||||||
buffer_handles_ = std::move(buffer_handles),
|
buffer_handles_ = std::move(buffer_handles),
|
||||||
binding_count](vk::CommandBuffer cmdbuf) {
|
binding_count](vk::CommandBuffer cmdbuf) {
|
||||||
|
|||||||
@@ -418,6 +418,9 @@ ConditionalRenderingResolvePass::ConditionalRenderingResolvePass(
|
|||||||
|
|
||||||
void ConditionalRenderingResolvePass::Resolve(VkBuffer dst_buffer, VkBuffer src_buffer,
|
void ConditionalRenderingResolvePass::Resolve(VkBuffer dst_buffer, VkBuffer src_buffer,
|
||||||
u32 src_offset, bool compare_to_zero) {
|
u32 src_offset, bool compare_to_zero) {
|
||||||
|
if (!device.IsExtConditionalRendering()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const size_t compare_size = compare_to_zero ? 8 : 24;
|
const size_t compare_size = compare_to_zero ? 8 : 24;
|
||||||
|
|
||||||
compute_pass_descriptor_queue.Acquire();
|
compute_pass_descriptor_queue.Acquire();
|
||||||
@@ -448,7 +451,7 @@ void ConditionalRenderingResolvePass::Resolve(VkBuffer dst_buffer, VkBuffer src_
|
|||||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
||||||
cmdbuf.Dispatch(1, 1, 1);
|
cmdbuf.Dispatch(1, 1, 1);
|
||||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT, 0, write_barrier);
|
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, write_barrier);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -470,6 +473,14 @@ QueriesPrefixScanPass::QueriesPrefixScanPass(
|
|||||||
void QueriesPrefixScanPass::Run(VkBuffer accumulation_buffer, VkBuffer dst_buffer,
|
void QueriesPrefixScanPass::Run(VkBuffer accumulation_buffer, VkBuffer dst_buffer,
|
||||||
VkBuffer src_buffer, size_t number_of_sums,
|
VkBuffer src_buffer, size_t number_of_sums,
|
||||||
size_t min_accumulation_limit, size_t max_accumulation_limit) {
|
size_t min_accumulation_limit, size_t max_accumulation_limit) {
|
||||||
|
constexpr VkAccessFlags BASE_DST_ACCESS = VK_ACCESS_SHADER_READ_BIT |
|
||||||
|
VK_ACCESS_TRANSFER_READ_BIT |
|
||||||
|
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
|
||||||
|
VK_ACCESS_INDIRECT_COMMAND_READ_BIT |
|
||||||
|
VK_ACCESS_INDEX_READ_BIT |
|
||||||
|
VK_ACCESS_UNIFORM_READ_BIT;
|
||||||
|
const VkAccessFlags conditional_access =
|
||||||
|
device.IsExtConditionalRendering() ? VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT : 0;
|
||||||
size_t current_runs = number_of_sums;
|
size_t current_runs = number_of_sums;
|
||||||
size_t offset = 0;
|
size_t offset = 0;
|
||||||
while (current_runs != 0) {
|
while (current_runs != 0) {
|
||||||
@@ -486,22 +497,18 @@ void QueriesPrefixScanPass::Run(VkBuffer accumulation_buffer, VkBuffer dst_buffe
|
|||||||
|
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
scheduler.Record([this, descriptor_data, min_accumulation_limit, max_accumulation_limit,
|
scheduler.Record([this, descriptor_data, min_accumulation_limit, max_accumulation_limit,
|
||||||
runs_to_do, used_offset](vk::CommandBuffer cmdbuf) {
|
runs_to_do, used_offset, conditional_access](vk::CommandBuffer cmdbuf) {
|
||||||
static constexpr VkMemoryBarrier read_barrier{
|
static constexpr VkMemoryBarrier read_barrier{
|
||||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT,
|
||||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_SHADER_WRITE_BIT,
|
||||||
};
|
};
|
||||||
static constexpr VkMemoryBarrier write_barrier{
|
const VkMemoryBarrier write_barrier{
|
||||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
|
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
|
||||||
.dstAccessMask = VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_TRANSFER_READ_BIT |
|
.dstAccessMask = BASE_DST_ACCESS | conditional_access,
|
||||||
VK_ACCESS_VERTEX_ATTRIBUTE_READ_BIT |
|
|
||||||
VK_ACCESS_INDIRECT_COMMAND_READ_BIT | VK_ACCESS_INDEX_READ_BIT |
|
|
||||||
VK_ACCESS_UNIFORM_READ_BIT |
|
|
||||||
VK_ACCESS_CONDITIONAL_RENDERING_READ_BIT_EXT,
|
|
||||||
};
|
};
|
||||||
const QueriesPrefixScanPushConstants uniforms{
|
const QueriesPrefixScanPushConstants uniforms{
|
||||||
.min_accumulation_base = static_cast<u32>(min_accumulation_limit),
|
.min_accumulation_base = static_cast<u32>(min_accumulation_limit),
|
||||||
@@ -519,8 +526,7 @@ void QueriesPrefixScanPass::Run(VkBuffer accumulation_buffer, VkBuffer dst_buffe
|
|||||||
cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, uniforms);
|
cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, uniforms);
|
||||||
cmdbuf.Dispatch(1, 1, 1);
|
cmdbuf.Dispatch(1, 1, 1);
|
||||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||||
VK_PIPELINE_STAGE_CONDITIONAL_RENDERING_BIT_EXT, 0,
|
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, write_barrier);
|
||||||
write_barrier);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -265,6 +265,7 @@ GraphicsPipeline::GraphicsPipeline(
|
|||||||
std::ranges::copy(info->constant_buffer_used_sizes, uniform_buffer_sizes[stage].begin());
|
std::ranges::copy(info->constant_buffer_used_sizes, uniform_buffer_sizes[stage].begin());
|
||||||
num_textures += Shader::NumDescriptors(info->texture_descriptors);
|
num_textures += Shader::NumDescriptors(info->texture_descriptors);
|
||||||
}
|
}
|
||||||
|
fragment_has_color0_output = stage_infos[NUM_STAGES - 1].stores_frag_color[0];
|
||||||
auto func{[this, shader_notify, &render_pass_cache, &descriptor_pool, pipeline_statistics] {
|
auto func{[this, shader_notify, &render_pass_cache, &descriptor_pool, pipeline_statistics] {
|
||||||
DescriptorLayoutBuilder builder{MakeBuilder(device, stage_infos)};
|
DescriptorLayoutBuilder builder{MakeBuilder(device, stage_infos)};
|
||||||
uses_push_descriptor = builder.CanUsePushDescriptor();
|
uses_push_descriptor = builder.CanUsePushDescriptor();
|
||||||
@@ -734,13 +735,18 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
|||||||
.lineWidth = 1.0f,
|
.lineWidth = 1.0f,
|
||||||
// TODO(alekpop): Transfer from regs
|
// TODO(alekpop): Transfer from regs
|
||||||
};
|
};
|
||||||
|
const bool smooth_lines_supported =
|
||||||
|
device.IsExtLineRasterizationSupported() && device.SupportsSmoothLines();
|
||||||
|
const bool stippled_lines_supported =
|
||||||
|
device.IsExtLineRasterizationSupported() && device.SupportsStippledRectangularLines();
|
||||||
VkPipelineRasterizationLineStateCreateInfoEXT line_state{
|
VkPipelineRasterizationLineStateCreateInfoEXT line_state{
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_LINE_STATE_CREATE_INFO_EXT,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
.lineRasterizationMode = key.state.smooth_lines != 0
|
.lineRasterizationMode = key.state.smooth_lines != 0 && smooth_lines_supported
|
||||||
? VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT
|
? VK_LINE_RASTERIZATION_MODE_RECTANGULAR_SMOOTH_EXT
|
||||||
: VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT,
|
: VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT,
|
||||||
.stippledLineEnable = dynamic.line_stipple_enable ? VK_TRUE : VK_FALSE,
|
.stippledLineEnable =
|
||||||
|
(dynamic.line_stipple_enable && stippled_lines_supported) ? VK_TRUE : VK_FALSE,
|
||||||
.lineStippleFactor = key.state.line_stipple_factor,
|
.lineStippleFactor = key.state.line_stipple_factor,
|
||||||
.lineStipplePattern = static_cast<uint16_t>(key.state.line_stipple_pattern),
|
.lineStipplePattern = static_cast<uint16_t>(key.state.line_stipple_pattern),
|
||||||
};
|
};
|
||||||
@@ -771,6 +777,8 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
|||||||
provoking_vertex.pNext = std::exchange(rasterization_ci.pNext, &provoking_vertex);
|
provoking_vertex.pNext = std::exchange(rasterization_ci.pNext, &provoking_vertex);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const bool supports_alpha_output = fragment_has_color0_output;
|
||||||
|
const bool alpha_to_one_supported = device.SupportsAlphaToOne();
|
||||||
const VkPipelineMultisampleStateCreateInfo multisample_ci{
|
const VkPipelineMultisampleStateCreateInfo multisample_ci{
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
@@ -779,8 +787,10 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
|||||||
.sampleShadingEnable = Settings::values.sample_shading.GetValue() ? VK_TRUE : VK_FALSE,
|
.sampleShadingEnable = Settings::values.sample_shading.GetValue() ? VK_TRUE : VK_FALSE,
|
||||||
.minSampleShading = static_cast<float>(Settings::values.sample_shading_fraction.GetValue()) / 100.0f,
|
.minSampleShading = static_cast<float>(Settings::values.sample_shading_fraction.GetValue()) / 100.0f,
|
||||||
.pSampleMask = nullptr,
|
.pSampleMask = nullptr,
|
||||||
.alphaToCoverageEnable = key.state.alpha_to_coverage_enabled != 0 ? VK_TRUE : VK_FALSE,
|
.alphaToCoverageEnable =
|
||||||
.alphaToOneEnable = key.state.alpha_to_one_enabled != 0 ? VK_TRUE : VK_FALSE,
|
supports_alpha_output && key.state.alpha_to_coverage_enabled != 0 ? VK_TRUE : VK_FALSE,
|
||||||
|
.alphaToOneEnable = supports_alpha_output && alpha_to_one_supported &&
|
||||||
|
key.state.alpha_to_one_enabled != 0 ? VK_TRUE : VK_FALSE,
|
||||||
};
|
};
|
||||||
const VkPipelineDepthStencilStateCreateInfo depth_stencil_ci{
|
const VkPipelineDepthStencilStateCreateInfo depth_stencil_ci{
|
||||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
||||||
@@ -838,14 +848,25 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
|||||||
.blendConstants = {}
|
.blendConstants = {}
|
||||||
};
|
};
|
||||||
static_vector<VkDynamicState, 34> dynamic_states{
|
static_vector<VkDynamicState, 34> dynamic_states{
|
||||||
VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR,
|
VK_DYNAMIC_STATE_VIEWPORT,
|
||||||
VK_DYNAMIC_STATE_DEPTH_BIAS, VK_DYNAMIC_STATE_BLEND_CONSTANTS,
|
VK_DYNAMIC_STATE_SCISSOR,
|
||||||
VK_DYNAMIC_STATE_DEPTH_BOUNDS, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
|
VK_DYNAMIC_STATE_DEPTH_BIAS,
|
||||||
VK_DYNAMIC_STATE_STENCIL_WRITE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE,
|
|
||||||
VK_DYNAMIC_STATE_LINE_WIDTH,
|
VK_DYNAMIC_STATE_LINE_WIDTH,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (device.UsesAdvancedCoreDynamicState()) {
|
||||||
|
static constexpr std::array core_dynamic_states{
|
||||||
|
VK_DYNAMIC_STATE_BLEND_CONSTANTS,
|
||||||
|
VK_DYNAMIC_STATE_DEPTH_BOUNDS,
|
||||||
|
VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK,
|
||||||
|
VK_DYNAMIC_STATE_STENCIL_WRITE_MASK,
|
||||||
|
VK_DYNAMIC_STATE_STENCIL_REFERENCE,
|
||||||
|
};
|
||||||
|
dynamic_states.insert(dynamic_states.end(), core_dynamic_states.begin(),
|
||||||
|
core_dynamic_states.end());
|
||||||
|
}
|
||||||
if (key.state.extended_dynamic_state) {
|
if (key.state.extended_dynamic_state) {
|
||||||
std::vector<VkDynamicState> extended{
|
static constexpr std::array extended{
|
||||||
VK_DYNAMIC_STATE_CULL_MODE_EXT,
|
VK_DYNAMIC_STATE_CULL_MODE_EXT,
|
||||||
VK_DYNAMIC_STATE_FRONT_FACE_EXT,
|
VK_DYNAMIC_STATE_FRONT_FACE_EXT,
|
||||||
VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT,
|
VK_DYNAMIC_STATE_DEPTH_TEST_ENABLE_EXT,
|
||||||
@@ -855,51 +876,68 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
|||||||
VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT,
|
VK_DYNAMIC_STATE_STENCIL_TEST_ENABLE_EXT,
|
||||||
VK_DYNAMIC_STATE_STENCIL_OP_EXT,
|
VK_DYNAMIC_STATE_STENCIL_OP_EXT,
|
||||||
};
|
};
|
||||||
if (!device.IsExtVertexInputDynamicStateSupported()) {
|
|
||||||
extended.push_back(VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT);
|
|
||||||
}
|
|
||||||
if (key.state.dynamic_vertex_input) {
|
|
||||||
dynamic_states.push_back(VK_DYNAMIC_STATE_VERTEX_INPUT_EXT);
|
|
||||||
}
|
|
||||||
dynamic_states.insert(dynamic_states.end(), extended.begin(), extended.end());
|
dynamic_states.insert(dynamic_states.end(), extended.begin(), extended.end());
|
||||||
if (key.state.extended_dynamic_state_2) {
|
|
||||||
static constexpr std::array extended2{
|
// VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT is part of EDS1
|
||||||
VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT,
|
// Only use it if VIDS is not active (VIDS replaces it with full vertex input control)
|
||||||
VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT,
|
if (!key.state.dynamic_vertex_input) {
|
||||||
VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT,
|
dynamic_states.push_back(VK_DYNAMIC_STATE_VERTEX_INPUT_BINDING_STRIDE_EXT);
|
||||||
};
|
|
||||||
dynamic_states.insert(dynamic_states.end(), extended2.begin(), extended2.end());
|
|
||||||
}
|
}
|
||||||
if (key.state.extended_dynamic_state_2_extra) {
|
}
|
||||||
dynamic_states.push_back(VK_DYNAMIC_STATE_LOGIC_OP_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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// EDS2 - Core (3 states)
|
||||||
|
if (key.state.extended_dynamic_state_2) {
|
||||||
|
static constexpr std::array extended2{
|
||||||
|
VK_DYNAMIC_STATE_DEPTH_BIAS_ENABLE_EXT,
|
||||||
|
VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE_EXT,
|
||||||
|
VK_DYNAMIC_STATE_RASTERIZER_DISCARD_ENABLE_EXT,
|
||||||
|
};
|
||||||
|
dynamic_states.insert(dynamic_states.end(), extended2.begin(), extended2.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
// EDS2 - LogicOp (granular)
|
||||||
|
if (key.state.extended_dynamic_state_2_logic_op) {
|
||||||
|
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 (key.state.extended_dynamic_state_3_blend) {
|
if (device.SupportsDynamicState3LogicOpEnable()) {
|
||||||
static constexpr std::array extended3{
|
dynamic_states.push_back(VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT);
|
||||||
VK_DYNAMIC_STATE_COLOR_BLEND_ENABLE_EXT,
|
|
||||||
VK_DYNAMIC_STATE_COLOR_BLEND_EQUATION_EXT,
|
|
||||||
VK_DYNAMIC_STATE_COLOR_WRITE_MASK_EXT,
|
|
||||||
|
|
||||||
// VK_DYNAMIC_STATE_COLOR_BLEND_ADVANCED_EXT,
|
|
||||||
};
|
|
||||||
dynamic_states.insert(dynamic_states.end(), extended3.begin(), extended3.end());
|
|
||||||
}
|
}
|
||||||
if (key.state.extended_dynamic_state_3_enables) {
|
if (device.SupportsDynamicState3LineRasterizationMode()) {
|
||||||
static constexpr std::array extended3{
|
dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT);
|
||||||
VK_DYNAMIC_STATE_DEPTH_CLAMP_ENABLE_EXT,
|
}
|
||||||
VK_DYNAMIC_STATE_LOGIC_OP_ENABLE_EXT,
|
if (device.SupportsDynamicState3ConservativeRasterizationMode()) {
|
||||||
|
dynamic_states.push_back(VK_DYNAMIC_STATE_CONSERVATIVE_RASTERIZATION_MODE_EXT);
|
||||||
// additional state3 extensions
|
}
|
||||||
VK_DYNAMIC_STATE_LINE_RASTERIZATION_MODE_EXT,
|
if (device.SupportsDynamicState3LineStippleEnable()) {
|
||||||
|
dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT);
|
||||||
VK_DYNAMIC_STATE_CONSERVATIVE_RASTERIZATION_MODE_EXT,
|
}
|
||||||
|
if (device.SupportsDynamicState3AlphaToCoverageEnable()) {
|
||||||
VK_DYNAMIC_STATE_LINE_STIPPLE_ENABLE_EXT,
|
dynamic_states.push_back(VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT);
|
||||||
VK_DYNAMIC_STATE_ALPHA_TO_COVERAGE_ENABLE_EXT,
|
}
|
||||||
VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT,
|
if (device.SupportsDynamicState3AlphaToOneEnable()) {
|
||||||
VK_DYNAMIC_STATE_DEPTH_CLIP_ENABLE_EXT,
|
dynamic_states.push_back(VK_DYNAMIC_STATE_ALPHA_TO_ONE_ENABLE_EXT);
|
||||||
VK_DYNAMIC_STATE_PROVOKING_VERTEX_MODE_EXT,
|
|
||||||
};
|
|
||||||
dynamic_states.insert(dynamic_states.end(), extended3.begin(), extended3.end());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -82,6 +82,17 @@ public:
|
|||||||
const std::array<const Shader::Info*, NUM_STAGES>& infos);
|
const std::array<const Shader::Info*, NUM_STAGES>& infos);
|
||||||
|
|
||||||
bool HasDynamicVertexInput() const noexcept { return key.state.dynamic_vertex_input; }
|
bool HasDynamicVertexInput() const noexcept { return key.state.dynamic_vertex_input; }
|
||||||
|
bool SupportsAlphaToCoverage() const noexcept {
|
||||||
|
return fragment_has_color0_output;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SupportsAlphaToOne() const noexcept {
|
||||||
|
return fragment_has_color0_output;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool UsesExtendedDynamicState() const noexcept {
|
||||||
|
return key.state.extended_dynamic_state != 0;
|
||||||
|
}
|
||||||
GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete;
|
GraphicsPipeline& operator=(GraphicsPipeline&&) noexcept = delete;
|
||||||
GraphicsPipeline(GraphicsPipeline&&) noexcept = delete;
|
GraphicsPipeline(GraphicsPipeline&&) noexcept = delete;
|
||||||
|
|
||||||
@@ -149,6 +160,7 @@ private:
|
|||||||
std::array<u32, 5> enabled_uniform_buffer_masks{};
|
std::array<u32, 5> enabled_uniform_buffer_masks{};
|
||||||
VideoCommon::UniformBufferSizes uniform_buffer_sizes{};
|
VideoCommon::UniformBufferSizes uniform_buffer_sizes{};
|
||||||
u32 num_textures{};
|
u32 num_textures{};
|
||||||
|
bool fragment_has_color0_output{};
|
||||||
|
|
||||||
vk::DescriptorSetLayout descriptor_set_layout;
|
vk::DescriptorSetLayout descriptor_set_layout;
|
||||||
DescriptorAllocator descriptor_allocator;
|
DescriptorAllocator descriptor_allocator;
|
||||||
|
|||||||
@@ -404,14 +404,35 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
|||||||
device.GetMaxVertexInputBindings(), Maxwell::NumVertexArrays);
|
device.GetMaxVertexInputBindings(), Maxwell::NumVertexArrays);
|
||||||
}
|
}
|
||||||
|
|
||||||
dynamic_features = DynamicFeatures{
|
LOG_INFO(Render_Vulkan, "DynamicState setting value: {}", Settings::values.dyna_state.GetValue());
|
||||||
.has_extended_dynamic_state = device.IsExtExtendedDynamicStateSupported(),
|
|
||||||
.has_extended_dynamic_state_2 = device.IsExtExtendedDynamicState2Supported(),
|
dynamic_features = {};
|
||||||
.has_extended_dynamic_state_2_extra = device.IsExtExtendedDynamicState2ExtrasSupported(),
|
|
||||||
.has_extended_dynamic_state_3_blend = device.IsExtExtendedDynamicState3BlendingSupported(),
|
// User granularity enforced in vulkan_device.cpp switch statement:
|
||||||
.has_extended_dynamic_state_3_enables = device.IsExtExtendedDynamicState3EnablesSupported(),
|
// Level 0: Core Dynamic States only
|
||||||
.has_dynamic_vertex_input = device.IsExtVertexInputDynamicStateSupported(),
|
// Level 1: Core + EDS1
|
||||||
};
|
// Level 2: Core + EDS1 + EDS2 (accumulative)
|
||||||
|
// Level 3: Core + EDS1 + EDS2 + EDS3 (accumulative)
|
||||||
|
// Here we only verify if extensions were successfully loaded by the device
|
||||||
|
|
||||||
|
dynamic_features.has_extended_dynamic_state =
|
||||||
|
device.IsExtExtendedDynamicStateSupported();
|
||||||
|
|
||||||
|
dynamic_features.has_extended_dynamic_state_2 =
|
||||||
|
device.IsExtExtendedDynamicState2Supported();
|
||||||
|
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() {
|
PipelineCache::~PipelineCache() {
|
||||||
@@ -516,8 +537,8 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
|
|||||||
dynamic_features.has_extended_dynamic_state ||
|
dynamic_features.has_extended_dynamic_state ||
|
||||||
(key.state.extended_dynamic_state_2 != 0) !=
|
(key.state.extended_dynamic_state_2 != 0) !=
|
||||||
dynamic_features.has_extended_dynamic_state_2 ||
|
dynamic_features.has_extended_dynamic_state_2 ||
|
||||||
(key.state.extended_dynamic_state_2_extra != 0) !=
|
(key.state.extended_dynamic_state_2_logic_op != 0) !=
|
||||||
dynamic_features.has_extended_dynamic_state_2_extra ||
|
dynamic_features.has_extended_dynamic_state_2_logic_op ||
|
||||||
(key.state.extended_dynamic_state_3_blend != 0) !=
|
(key.state.extended_dynamic_state_3_blend != 0) !=
|
||||||
dynamic_features.has_extended_dynamic_state_3_blend ||
|
dynamic_features.has_extended_dynamic_state_3_blend ||
|
||||||
(key.state.extended_dynamic_state_3_enables != 0) !=
|
(key.state.extended_dynamic_state_3_enables != 0) !=
|
||||||
|
|||||||
@@ -202,6 +202,11 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
|
|||||||
fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler),
|
fence_manager(*this, gpu, texture_cache, buffer_cache, query_cache, device, scheduler),
|
||||||
wfi_event(device.GetLogical().CreateEvent()) {
|
wfi_event(device.GetLogical().CreateEvent()) {
|
||||||
scheduler.SetQueryCache(query_cache);
|
scheduler.SetQueryCache(query_cache);
|
||||||
|
|
||||||
|
// Log multi-draw support
|
||||||
|
if (device.IsExtMultiDrawSupported()) {
|
||||||
|
LOG_INFO(Render_Vulkan, "VK_EXT_multi_draw is enabled for optimized draw calls");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RasterizerVulkan::~RasterizerVulkan() = default;
|
RasterizerVulkan::~RasterizerVulkan() = default;
|
||||||
@@ -243,16 +248,44 @@ void RasterizerVulkan::Draw(bool is_indexed, u32 instance_count) {
|
|||||||
const u32 num_instances{instance_count};
|
const u32 num_instances{instance_count};
|
||||||
const auto polygon_mode = VideoCore::EffectivePolygonMode(maxwell3d->regs);
|
const auto polygon_mode = VideoCore::EffectivePolygonMode(maxwell3d->regs);
|
||||||
const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed, polygon_mode)};
|
const DrawParams draw_params{MakeDrawParams(draw_state, num_instances, is_indexed, polygon_mode)};
|
||||||
scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) {
|
|
||||||
if (draw_params.is_indexed) {
|
// Use VK_EXT_multi_draw if available (single draw becomes multi-draw with count=1)
|
||||||
cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances,
|
if (device.IsExtMultiDrawSupported()) {
|
||||||
draw_params.first_index, draw_params.base_vertex,
|
scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) {
|
||||||
draw_params.base_instance);
|
if (draw_params.is_indexed) {
|
||||||
} else {
|
// Use multi-draw indexed with single draw
|
||||||
cmdbuf.Draw(draw_params.num_vertices, draw_params.num_instances,
|
const VkMultiDrawIndexedInfoEXT multi_draw_info{
|
||||||
draw_params.base_vertex, draw_params.base_instance);
|
.firstIndex = draw_params.first_index,
|
||||||
}
|
.indexCount = draw_params.num_vertices,
|
||||||
});
|
};
|
||||||
|
const int32_t vertex_offset = static_cast<int32_t>(draw_params.base_vertex);
|
||||||
|
cmdbuf.DrawMultiIndexedEXT(1, &multi_draw_info, draw_params.num_instances,
|
||||||
|
draw_params.base_instance,
|
||||||
|
sizeof(VkMultiDrawIndexedInfoEXT), &vertex_offset);
|
||||||
|
} else {
|
||||||
|
// Use multi-draw with single draw
|
||||||
|
const VkMultiDrawInfoEXT multi_draw_info{
|
||||||
|
.firstVertex = draw_params.base_vertex,
|
||||||
|
.vertexCount = draw_params.num_vertices,
|
||||||
|
};
|
||||||
|
cmdbuf.DrawMultiEXT(1, &multi_draw_info, draw_params.num_instances,
|
||||||
|
draw_params.base_instance,
|
||||||
|
sizeof(VkMultiDrawInfoEXT));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Fallback to standard draw calls
|
||||||
|
scheduler.Record([draw_params](vk::CommandBuffer cmdbuf) {
|
||||||
|
if (draw_params.is_indexed) {
|
||||||
|
cmdbuf.DrawIndexed(draw_params.num_vertices, draw_params.num_instances,
|
||||||
|
draw_params.first_index, draw_params.base_vertex,
|
||||||
|
draw_params.base_instance);
|
||||||
|
} else {
|
||||||
|
cmdbuf.Draw(draw_params.num_vertices, draw_params.num_instances,
|
||||||
|
draw_params.base_vertex, draw_params.base_instance);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -395,13 +428,48 @@ void RasterizerVulkan::Clear(u32 layer_count) {
|
|||||||
.baseArrayLayer = regs.clear_surface.layer,
|
.baseArrayLayer = regs.clear_surface.layer,
|
||||||
.layerCount = layer_count,
|
.layerCount = layer_count,
|
||||||
};
|
};
|
||||||
if (clear_rect.rect.extent.width == 0 || clear_rect.rect.extent.height == 0) {
|
const auto clamp_rect_to_render_area = [render_area](VkRect2D& rect) -> bool {
|
||||||
|
const auto clamp_axis = [](s32& offset, u32& extent, u32 limit) {
|
||||||
|
auto clamp_offset = [&offset, limit]() {
|
||||||
|
if (limit == 0) {
|
||||||
|
offset = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
offset = std::clamp(offset, 0, static_cast<s32>(limit));
|
||||||
|
};
|
||||||
|
|
||||||
|
if (extent == 0) {
|
||||||
|
clamp_offset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (offset < 0) {
|
||||||
|
const u32 shrink = (std::min)(extent, static_cast<u32>(-offset));
|
||||||
|
extent -= shrink;
|
||||||
|
offset = 0;
|
||||||
|
}
|
||||||
|
if (limit == 0) {
|
||||||
|
extent = 0;
|
||||||
|
offset = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (offset >= static_cast<s32>(limit)) {
|
||||||
|
offset = static_cast<s32>(limit);
|
||||||
|
extent = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const u64 end_coord = static_cast<u64>(offset) + extent;
|
||||||
|
if (end_coord > limit) {
|
||||||
|
extent = limit - static_cast<u32>(offset);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
clamp_axis(rect.offset.x, rect.extent.width, render_area.width);
|
||||||
|
clamp_axis(rect.offset.y, rect.extent.height, render_area.height);
|
||||||
|
return rect.extent.width != 0 && rect.extent.height != 0;
|
||||||
|
};
|
||||||
|
if (!clamp_rect_to_render_area(clear_rect.rect)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
clear_rect.rect.extent = VkExtent2D{
|
|
||||||
.width = (std::min)(clear_rect.rect.extent.width, render_area.width),
|
|
||||||
.height = (std::min)(clear_rect.rect.extent.height, render_area.height),
|
|
||||||
};
|
|
||||||
|
|
||||||
const u32 color_attachment = regs.clear_surface.RT;
|
const u32 color_attachment = regs.clear_surface.RT;
|
||||||
if (use_color && framebuffer->HasAspectColorBit(color_attachment)) {
|
if (use_color && framebuffer->HasAspectColorBit(color_attachment)) {
|
||||||
@@ -851,23 +919,21 @@ void RasterizerVulkan::LoadDiskResources(u64 title_id, std::stop_token stop_load
|
|||||||
|
|
||||||
void RasterizerVulkan::FlushWork() {
|
void RasterizerVulkan::FlushWork() {
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
static constexpr u32 DRAWS_TO_DISPATCH = 1024;
|
static constexpr u32 DRAWS_TO_DISPATCH = 512;
|
||||||
|
static constexpr u32 CHECK_MASK = 3;
|
||||||
#else
|
#else
|
||||||
static constexpr u32 DRAWS_TO_DISPATCH = 4096;
|
static constexpr u32 DRAWS_TO_DISPATCH = 4096;
|
||||||
|
static constexpr u32 CHECK_MASK = 7;
|
||||||
#endif // ANDROID
|
#endif // ANDROID
|
||||||
|
|
||||||
// Only check multiples of 8 draws
|
static_assert(DRAWS_TO_DISPATCH % (CHECK_MASK + 1) == 0);
|
||||||
static_assert(DRAWS_TO_DISPATCH % 8 == 0);
|
if ((++draw_counter & CHECK_MASK) != CHECK_MASK) {
|
||||||
if ((++draw_counter & 7) != 7) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (draw_counter < DRAWS_TO_DISPATCH) {
|
if (draw_counter < DRAWS_TO_DISPATCH) {
|
||||||
// Send recorded tasks to the worker thread
|
|
||||||
scheduler.DispatchWork();
|
scheduler.DispatchWork();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Otherwise (every certain number of draws) flush execution.
|
|
||||||
// This submits commands to the Vulkan driver.
|
|
||||||
scheduler.Flush();
|
scheduler.Flush();
|
||||||
draw_counter = 0;
|
draw_counter = 0;
|
||||||
}
|
}
|
||||||
@@ -933,6 +999,8 @@ bool AccelerateDMA::BufferToImage(const Tegra::DMA::ImageCopy& copy_info,
|
|||||||
|
|
||||||
void RasterizerVulkan::UpdateDynamicStates() {
|
void RasterizerVulkan::UpdateDynamicStates() {
|
||||||
auto& regs = maxwell3d->regs;
|
auto& regs = maxwell3d->regs;
|
||||||
|
|
||||||
|
// Core Dynamic States (Vulkan 1.0) - Always active regardless of dyna_state setting
|
||||||
UpdateViewportsState(regs);
|
UpdateViewportsState(regs);
|
||||||
UpdateScissorsState(regs);
|
UpdateScissorsState(regs);
|
||||||
UpdateDepthBias(regs);
|
UpdateDepthBias(regs);
|
||||||
@@ -940,6 +1008,8 @@ void RasterizerVulkan::UpdateDynamicStates() {
|
|||||||
UpdateDepthBounds(regs);
|
UpdateDepthBounds(regs);
|
||||||
UpdateStencilFaces(regs);
|
UpdateStencilFaces(regs);
|
||||||
UpdateLineWidth(regs);
|
UpdateLineWidth(regs);
|
||||||
|
|
||||||
|
// EDS1: CullMode, DepthCompare, FrontFace, StencilOp, DepthBoundsTest, DepthTest, DepthWrite, StencilTest
|
||||||
if (device.IsExtExtendedDynamicStateSupported()) {
|
if (device.IsExtExtendedDynamicStateSupported()) {
|
||||||
UpdateCullMode(regs);
|
UpdateCullMode(regs);
|
||||||
UpdateDepthCompareOp(regs);
|
UpdateDepthCompareOp(regs);
|
||||||
@@ -950,40 +1020,52 @@ void RasterizerVulkan::UpdateDynamicStates() {
|
|||||||
UpdateDepthTestEnable(regs);
|
UpdateDepthTestEnable(regs);
|
||||||
UpdateDepthWriteEnable(regs);
|
UpdateDepthWriteEnable(regs);
|
||||||
UpdateStencilTestEnable(regs);
|
UpdateStencilTestEnable(regs);
|
||||||
if (device.IsExtExtendedDynamicState2Supported()) {
|
|
||||||
UpdatePrimitiveRestartEnable(regs);
|
|
||||||
UpdateRasterizerDiscardEnable(regs);
|
|
||||||
UpdateDepthBiasEnable(regs);
|
|
||||||
}
|
|
||||||
if (device.IsExtExtendedDynamicState3EnablesSupported()) {
|
|
||||||
using namespace Tegra::Engines;
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (device.IsExtExtendedDynamicState2ExtrasSupported()) {
|
|
||||||
UpdateLogicOp(regs);
|
|
||||||
}
|
|
||||||
if (device.IsExtExtendedDynamicState3BlendingSupported()) {
|
|
||||||
UpdateBlending(regs);
|
|
||||||
}
|
|
||||||
if (device.IsExtExtendedDynamicState3EnablesSupported()) {
|
|
||||||
UpdateLineStippleEnable(regs);
|
|
||||||
UpdateConservativeRasterizationMode(regs);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EDS2: PrimitiveRestart, RasterizerDiscard, DepthBias enable/disable
|
||||||
|
if (device.IsExtExtendedDynamicState2Supported()) {
|
||||||
|
UpdatePrimitiveRestartEnable(regs);
|
||||||
|
UpdateRasterizerDiscardEnable(regs);
|
||||||
|
UpdateDepthBiasEnable(regs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// EDS2 Extras: LogicOp operation selection
|
||||||
|
if (device.IsExtExtendedDynamicState2ExtrasSupported()) {
|
||||||
|
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 (device.IsExtVertexInputDynamicStateSupported()) {
|
||||||
if (auto* gp = pipeline_cache.CurrentGraphicsPipeline(); gp && gp->HasDynamicVertexInput()) {
|
if (auto* gp = pipeline_cache.CurrentGraphicsPipeline(); gp && gp->HasDynamicVertexInput()) {
|
||||||
UpdateVertexInput(regs);
|
UpdateVertexInput(regs);
|
||||||
@@ -1156,6 +1238,9 @@ void RasterizerVulkan::UpdateBlendConstants(Tegra::Engines::Maxwell3D::Regs& reg
|
|||||||
if (!state_tracker.TouchBlendConstants()) {
|
if (!state_tracker.TouchBlendConstants()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!device.UsesAdvancedCoreDynamicState()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const std::array blend_color = {regs.blend_color.r, regs.blend_color.g, regs.blend_color.b,
|
const std::array blend_color = {regs.blend_color.r, regs.blend_color.g, regs.blend_color.b,
|
||||||
regs.blend_color.a};
|
regs.blend_color.a};
|
||||||
scheduler.Record(
|
scheduler.Record(
|
||||||
@@ -1166,6 +1251,9 @@ void RasterizerVulkan::UpdateDepthBounds(Tegra::Engines::Maxwell3D::Regs& regs)
|
|||||||
if (!state_tracker.TouchDepthBounds()) {
|
if (!state_tracker.TouchDepthBounds()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!device.UsesAdvancedCoreDynamicState() || !device.IsDepthBoundsSupported()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
scheduler.Record([min = regs.depth_bounds[0], max = regs.depth_bounds[1]](
|
scheduler.Record([min = regs.depth_bounds[0], max = regs.depth_bounds[1]](
|
||||||
vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthBounds(min, max); });
|
vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthBounds(min, max); });
|
||||||
}
|
}
|
||||||
@@ -1174,6 +1262,10 @@ void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs)
|
|||||||
if (!state_tracker.TouchStencilProperties()) {
|
if (!state_tracker.TouchStencilProperties()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!device.UsesAdvancedCoreDynamicState()) {
|
||||||
|
state_tracker.ClearStencilReset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
bool update_references = state_tracker.TouchStencilReference();
|
bool update_references = state_tracker.TouchStencilReference();
|
||||||
bool update_write_mask = state_tracker.TouchStencilWriteMask();
|
bool update_write_mask = state_tracker.TouchStencilWriteMask();
|
||||||
bool update_compare_masks = state_tracker.TouchStencilCompare();
|
bool update_compare_masks = state_tracker.TouchStencilCompare();
|
||||||
@@ -1336,6 +1428,10 @@ void RasterizerVulkan::UpdateConservativeRasterizationMode(Tegra::Engines::Maxwe
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!device.SupportsDynamicState3ConservativeRasterizationMode()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
scheduler.Record([enable = regs.conservative_raster_enable](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([enable = regs.conservative_raster_enable](vk::CommandBuffer cmdbuf) {
|
||||||
cmdbuf.SetConservativeRasterizationModeEXT(
|
cmdbuf.SetConservativeRasterizationModeEXT(
|
||||||
enable ? VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT
|
enable ? VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT
|
||||||
@@ -1348,23 +1444,50 @@ void RasterizerVulkan::UpdateLineStippleEnable(Tegra::Engines::Maxwell3D::Regs&
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!device.SupportsDynamicState3LineStippleEnable()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
scheduler.Record([enable = regs.line_stipple_enable](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([enable = regs.line_stipple_enable](vk::CommandBuffer cmdbuf) {
|
||||||
cmdbuf.SetLineStippleEnableEXT(enable);
|
cmdbuf.SetLineStippleEnableEXT(enable);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerVulkan::UpdateLineRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs) {
|
void RasterizerVulkan::UpdateLineRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||||
// if (!state_tracker.TouchLi()) {
|
if (!device.IsExtLineRasterizationSupported()) {
|
||||||
// return;
|
return;
|
||||||
// }
|
}
|
||||||
|
if (!state_tracker.TouchLineRasterizationMode()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: The maxwell emulator does not capture line rasters
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
// scheduler.Record([enable = regs.line](vk::CommandBuffer cmdbuf) {
|
const bool wants_smooth = regs.line_anti_alias_enable != 0;
|
||||||
// cmdbuf.SetConservativeRasterizationModeEXT(
|
VkLineRasterizationModeEXT mode = VK_LINE_RASTERIZATION_MODE_RECTANGULAR_EXT;
|
||||||
// enable ? VK_CONSERVATIVE_RASTERIZATION_MODE_UNDERESTIMATE_EXT
|
if (wants_smooth) {
|
||||||
// : VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT);
|
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) {
|
void RasterizerVulkan::UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||||
@@ -1406,6 +1529,9 @@ void RasterizerVulkan::UpdateLogicOpEnable(Tegra::Engines::Maxwell3D::Regs& regs
|
|||||||
if (!state_tracker.TouchLogicOpEnable()) {
|
if (!state_tracker.TouchLogicOpEnable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!device.SupportsDynamicState3LogicOpEnable()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
scheduler.Record([enable = regs.logic_op.enable](vk::CommandBuffer cmdbuf) {
|
scheduler.Record([enable = regs.logic_op.enable](vk::CommandBuffer cmdbuf) {
|
||||||
cmdbuf.SetLogicOpEnableEXT(enable != 0);
|
cmdbuf.SetLogicOpEnableEXT(enable != 0);
|
||||||
});
|
});
|
||||||
@@ -1415,6 +1541,9 @@ void RasterizerVulkan::UpdateDepthClampEnable(Tegra::Engines::Maxwell3D::Regs& r
|
|||||||
if (!state_tracker.TouchDepthClampEnable()) {
|
if (!state_tracker.TouchDepthClampEnable()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (!device.SupportsDynamicState3DepthClampEnable()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
bool is_enabled = !(regs.viewport_clip_control.geometry_clip ==
|
bool is_enabled = !(regs.viewport_clip_control.geometry_clip ==
|
||||||
Maxwell::ViewportClipControl::GeometryClip::Passthrough ||
|
Maxwell::ViewportClipControl::GeometryClip::Passthrough ||
|
||||||
regs.viewport_clip_control.geometry_clip ==
|
regs.viewport_clip_control.geometry_clip ==
|
||||||
@@ -1425,6 +1554,41 @@ void RasterizerVulkan::UpdateDepthClampEnable(Tegra::Engines::Maxwell3D::Regs& r
|
|||||||
[is_enabled](vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthClampEnableEXT(is_enabled); });
|
[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) {
|
void RasterizerVulkan::UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||||
if (!state_tracker.TouchDepthCompareOp()) {
|
if (!state_tracker.TouchDepthCompareOp()) {
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -183,6 +183,8 @@ private:
|
|||||||
void UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
void UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||||
void UpdateLogicOpEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
void UpdateLogicOpEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||||
void UpdateDepthClampEnable(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 UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||||
void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs);
|
void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||||
void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include "common/thread.h"
|
#include "common/thread.h"
|
||||||
#include "video_core/renderer_vulkan/vk_command_pool.h"
|
#include "video_core/renderer_vulkan/vk_command_pool.h"
|
||||||
|
#include "video_core/renderer_vulkan/vk_graphics_pipeline.h"
|
||||||
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
|
#include "video_core/renderer_vulkan/vk_master_semaphore.h"
|
||||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||||
#include "video_core/renderer_vulkan/vk_state_tracker.h"
|
#include "video_core/renderer_vulkan/vk_state_tracker.h"
|
||||||
@@ -130,9 +131,27 @@ void Scheduler::RequestOutsideRenderPassOperationContext() {
|
|||||||
|
|
||||||
bool Scheduler::UpdateGraphicsPipeline(GraphicsPipeline* pipeline) {
|
bool Scheduler::UpdateGraphicsPipeline(GraphicsPipeline* pipeline) {
|
||||||
if (state.graphics_pipeline == pipeline) {
|
if (state.graphics_pipeline == pipeline) {
|
||||||
|
if (pipeline && pipeline->UsesExtendedDynamicState() &&
|
||||||
|
state.needs_state_enable_refresh) {
|
||||||
|
state_tracker.InvalidateStateEnableFlag();
|
||||||
|
state.needs_state_enable_refresh = false;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
state.graphics_pipeline = pipeline;
|
state.graphics_pipeline = pipeline;
|
||||||
|
|
||||||
|
if (!pipeline) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pipeline->UsesExtendedDynamicState()) {
|
||||||
|
state.needs_state_enable_refresh = true;
|
||||||
|
} else if (state.needs_state_enable_refresh) {
|
||||||
|
state_tracker.InvalidateStateEnableFlag();
|
||||||
|
state.needs_state_enable_refresh = false;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,6 +296,7 @@ void Scheduler::EndRenderPass()
|
|||||||
}
|
}
|
||||||
|
|
||||||
query_cache->CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, false);
|
query_cache->CounterEnable(VideoCommon::QueryType::ZPassPixelCount64, false);
|
||||||
|
query_cache->CounterEnable(VideoCommon::QueryType::StreamingByteCount, false);
|
||||||
query_cache->NotifySegment(false);
|
query_cache->NotifySegment(false);
|
||||||
|
|
||||||
Record([num_images = num_renderpass_images,
|
Record([num_images = num_renderpass_images,
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -214,6 +217,7 @@ private:
|
|||||||
GraphicsPipeline* graphics_pipeline = nullptr;
|
GraphicsPipeline* graphics_pipeline = nullptr;
|
||||||
bool is_rescaling = false;
|
bool is_rescaling = false;
|
||||||
bool rescaling_defined = false;
|
bool rescaling_defined = false;
|
||||||
|
bool needs_state_enable_refresh = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
void WorkerThread(std::stop_token stop_token);
|
void WorkerThread(std::stop_token stop_token);
|
||||||
|
|||||||
@@ -48,6 +48,7 @@ Flags MakeInvalidationFlags() {
|
|||||||
FrontFace,
|
FrontFace,
|
||||||
StencilOp,
|
StencilOp,
|
||||||
StencilTestEnable,
|
StencilTestEnable,
|
||||||
|
RasterizerDiscardEnable,
|
||||||
VertexBuffers,
|
VertexBuffers,
|
||||||
VertexInput,
|
VertexInput,
|
||||||
StateEnable,
|
StateEnable,
|
||||||
@@ -55,6 +56,9 @@ Flags MakeInvalidationFlags() {
|
|||||||
DepthBiasEnable,
|
DepthBiasEnable,
|
||||||
LogicOpEnable,
|
LogicOpEnable,
|
||||||
DepthClampEnable,
|
DepthClampEnable,
|
||||||
|
AlphaToCoverageEnable,
|
||||||
|
AlphaToOneEnable,
|
||||||
|
LineRasterizationMode,
|
||||||
LogicOp,
|
LogicOp,
|
||||||
Blending,
|
Blending,
|
||||||
ColorMask,
|
ColorMask,
|
||||||
@@ -148,6 +152,8 @@ void SetupDirtyStateEnable(Tables& tables) {
|
|||||||
setup(OFF(logic_op.enable), LogicOpEnable);
|
setup(OFF(logic_op.enable), LogicOpEnable);
|
||||||
setup(OFF(viewport_clip_control.geometry_clip), DepthClampEnable);
|
setup(OFF(viewport_clip_control.geometry_clip), DepthClampEnable);
|
||||||
setup(OFF(line_stipple_enable), LineStippleEnable);
|
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) {
|
void SetupDirtyDepthCompareOp(Tables& tables) {
|
||||||
@@ -226,6 +232,7 @@ void SetupRasterModes(Tables &tables) {
|
|||||||
|
|
||||||
table[OFF(line_stipple_params)] = LineStippleParams;
|
table[OFF(line_stipple_params)] = LineStippleParams;
|
||||||
table[OFF(conservative_raster_enable)] = ConservativeRasterizationMode;
|
table[OFF(conservative_raster_enable)] = ConservativeRasterizationMode;
|
||||||
|
table[OFF(line_anti_alias_enable)] = LineRasterizationMode;
|
||||||
}
|
}
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ enum : u8 {
|
|||||||
PrimitiveRestartEnable,
|
PrimitiveRestartEnable,
|
||||||
RasterizerDiscardEnable,
|
RasterizerDiscardEnable,
|
||||||
ConservativeRasterizationMode,
|
ConservativeRasterizationMode,
|
||||||
|
LineRasterizationMode,
|
||||||
LineStippleEnable,
|
LineStippleEnable,
|
||||||
LineStippleParams,
|
LineStippleParams,
|
||||||
DepthBiasEnable,
|
DepthBiasEnable,
|
||||||
@@ -61,6 +62,8 @@ enum : u8 {
|
|||||||
LogicOp,
|
LogicOp,
|
||||||
LogicOpEnable,
|
LogicOpEnable,
|
||||||
DepthClampEnable,
|
DepthClampEnable,
|
||||||
|
AlphaToCoverageEnable,
|
||||||
|
AlphaToOneEnable,
|
||||||
|
|
||||||
Blending,
|
Blending,
|
||||||
BlendEnable,
|
BlendEnable,
|
||||||
@@ -94,6 +97,10 @@ public:
|
|||||||
(*flags)[Dirty::Scissors] = true;
|
(*flags)[Dirty::Scissors] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void InvalidateStateEnableFlag() {
|
||||||
|
(*flags)[Dirty::StateEnable] = true;
|
||||||
|
}
|
||||||
|
|
||||||
bool TouchViewports() {
|
bool TouchViewports() {
|
||||||
const bool dirty_viewports = Exchange(Dirty::Viewports, false);
|
const bool dirty_viewports = Exchange(Dirty::Viewports, false);
|
||||||
const bool rescale_viewports = Exchange(VideoCommon::Dirty::RescaleViewports, false);
|
const bool rescale_viewports = Exchange(VideoCommon::Dirty::RescaleViewports, false);
|
||||||
@@ -225,6 +232,14 @@ public:
|
|||||||
return Exchange(Dirty::DepthClampEnable, false);
|
return Exchange(Dirty::DepthClampEnable, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TouchAlphaToCoverageEnable() {
|
||||||
|
return Exchange(Dirty::AlphaToCoverageEnable, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TouchAlphaToOneEnable() {
|
||||||
|
return Exchange(Dirty::AlphaToOneEnable, false);
|
||||||
|
}
|
||||||
|
|
||||||
bool TouchDepthCompareOp() {
|
bool TouchDepthCompareOp() {
|
||||||
return Exchange(Dirty::DepthCompareOp, false);
|
return Exchange(Dirty::DepthCompareOp, false);
|
||||||
}
|
}
|
||||||
@@ -261,6 +276,10 @@ public:
|
|||||||
return Exchange(Dirty::LogicOp, false);
|
return Exchange(Dirty::LogicOp, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TouchLineRasterizationMode() {
|
||||||
|
return Exchange(Dirty::LineRasterizationMode, false);
|
||||||
|
}
|
||||||
|
|
||||||
bool ChangePrimitiveTopology(Maxwell::PrimitiveTopology new_topology) {
|
bool ChangePrimitiveTopology(Maxwell::PrimitiveTopology new_topology) {
|
||||||
const bool has_changed = current_topology != new_topology;
|
const bool has_changed = current_topology != new_topology;
|
||||||
current_topology = new_topology;
|
current_topology = new_topology;
|
||||||
|
|||||||
@@ -306,7 +306,17 @@ void Swapchain::CreateSwapchain(const VkSurfaceCapabilitiesKHR& capabilities) {
|
|||||||
swapchain_ci.queueFamilyIndexCount = static_cast<u32>(queue_indices.size());
|
swapchain_ci.queueFamilyIndexCount = static_cast<u32>(queue_indices.size());
|
||||||
swapchain_ci.pQueueFamilyIndices = queue_indices.data();
|
swapchain_ci.pQueueFamilyIndices = queue_indices.data();
|
||||||
}
|
}
|
||||||
static constexpr std::array view_formats{VK_FORMAT_B8G8R8A8_UNORM, VK_FORMAT_B8G8R8A8_SRGB};
|
// According to Vulkan spec, when using VK_SWAPCHAIN_CREATE_MUTABLE_FORMAT_BIT_KHR,
|
||||||
|
// the base format (imageFormat) MUST be included in pViewFormats
|
||||||
|
const std::array view_formats{
|
||||||
|
swapchain_ci.imageFormat, // Base format MUST be first
|
||||||
|
VK_FORMAT_B8G8R8A8_UNORM,
|
||||||
|
VK_FORMAT_B8G8R8A8_SRGB,
|
||||||
|
#ifdef ANDROID
|
||||||
|
VK_FORMAT_R8G8B8A8_UNORM, // Android may use RGBA
|
||||||
|
VK_FORMAT_R8G8B8A8_SRGB,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
VkImageFormatListCreateInfo format_list{
|
VkImageFormatListCreateInfo format_list{
|
||||||
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
|
.sType = VK_STRUCTURE_TYPE_IMAGE_FORMAT_LIST_CREATE_INFO_KHR,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -101,7 +104,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
VkSemaphore CurrentRenderSemaphore() const {
|
VkSemaphore CurrentRenderSemaphore() const {
|
||||||
return *render_semaphores[frame_index];
|
return *render_semaphores[image_index];
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetWidth() const {
|
u32 GetWidth() const {
|
||||||
|
|||||||
@@ -1104,6 +1104,8 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
|
|||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
// Use shader-based depth/stencil blits if hardware doesn't support the format
|
||||||
|
// Note: MSAA resolves (MSAA->single) use vkCmdResolveImage which works fine
|
||||||
if (!can_blit_depth_stencil) {
|
if (!can_blit_depth_stencil) {
|
||||||
UNIMPLEMENTED_IF(is_src_msaa || is_dst_msaa);
|
UNIMPLEMENTED_IF(is_src_msaa || is_dst_msaa);
|
||||||
blit_image_helper.BlitDepthStencil(dst_framebuffer, src, dst_region, src_region,
|
blit_image_helper.BlitDepthStencil(dst_framebuffer, src, dst_region, src_region,
|
||||||
@@ -1118,6 +1120,15 @@ void TextureCacheRuntime::BlitImage(Framebuffer* dst_framebuffer, ImageView& dst
|
|||||||
const VkImage src_image = src.ImageHandle();
|
const VkImage src_image = src.ImageHandle();
|
||||||
const VkImageSubresourceLayers dst_layers = MakeSubresourceLayers(&dst);
|
const VkImageSubresourceLayers dst_layers = MakeSubresourceLayers(&dst);
|
||||||
const VkImageSubresourceLayers src_layers = MakeSubresourceLayers(&src);
|
const VkImageSubresourceLayers src_layers = MakeSubresourceLayers(&src);
|
||||||
|
const bool is_msaa_to_msaa = is_src_msaa && is_dst_msaa;
|
||||||
|
|
||||||
|
// NVIDIA 510+ and Intel crash on MSAA->MSAA blits (scaling operations)
|
||||||
|
// Fall back to 3D helpers for MSAA scaling
|
||||||
|
if (is_msaa_to_msaa && device.CantBlitMSAA()) {
|
||||||
|
// This should be handled by NeedsScaleHelper() and use 3D helpers instead
|
||||||
|
UNIMPLEMENTED_MSG("MSAA to MSAA blit not supported on this driver");
|
||||||
|
return;
|
||||||
|
}
|
||||||
const bool is_resolve = is_src_msaa && !is_dst_msaa;
|
const bool is_resolve = is_src_msaa && !is_dst_msaa;
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
scheduler.Record([filter, dst_region, src_region, dst_image, src_image, dst_layers, src_layers,
|
scheduler.Record([filter, dst_region, src_region, dst_image, src_image, dst_layers, src_layers,
|
||||||
@@ -2211,18 +2222,26 @@ vk::ImageView ImageView::MakeView(VkFormat vk_format, VkImageAspectFlags aspect_
|
|||||||
|
|
||||||
Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& tsc) {
|
Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& tsc) {
|
||||||
const auto& device = runtime.device;
|
const auto& device = runtime.device;
|
||||||
const bool arbitrary_borders = runtime.device.IsExtCustomBorderColorSupported();
|
// Check if custom border colors are supported
|
||||||
|
const bool has_custom_border_colors = runtime.device.IsCustomBorderColorsSupported();
|
||||||
|
const bool has_format_undefined = runtime.device.IsCustomBorderColorWithoutFormatSupported();
|
||||||
const auto color = tsc.BorderColor();
|
const auto color = tsc.BorderColor();
|
||||||
|
|
||||||
|
// Determine border format based on available features:
|
||||||
|
// - If customBorderColorWithoutFormat is available: use VK_FORMAT_UNDEFINED (most flexible)
|
||||||
|
// - If only customBorderColors is available: use concrete format (R8G8B8A8_UNORM)
|
||||||
|
// - If neither is available: use standard border colors (handled by ConvertBorderColor)
|
||||||
|
const VkFormat border_format = has_format_undefined ? VK_FORMAT_UNDEFINED
|
||||||
|
: VK_FORMAT_R8G8B8A8_UNORM;
|
||||||
|
|
||||||
const VkSamplerCustomBorderColorCreateInfoEXT border_ci{
|
const VkSamplerCustomBorderColorCreateInfoEXT border_ci{
|
||||||
.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT,
|
.sType = VK_STRUCTURE_TYPE_SAMPLER_CUSTOM_BORDER_COLOR_CREATE_INFO_EXT,
|
||||||
.pNext = nullptr,
|
.pNext = nullptr,
|
||||||
// TODO: Make use of std::bit_cast once libc++ supports it.
|
|
||||||
.customBorderColor = std::bit_cast<VkClearColorValue>(color),
|
.customBorderColor = std::bit_cast<VkClearColorValue>(color),
|
||||||
.format = VK_FORMAT_UNDEFINED,
|
.format = border_format,
|
||||||
};
|
};
|
||||||
const void* pnext = nullptr;
|
const void* pnext = nullptr;
|
||||||
if (arbitrary_borders) {
|
if (has_custom_border_colors) {
|
||||||
pnext = &border_ci;
|
pnext = &border_ci;
|
||||||
}
|
}
|
||||||
const VkSamplerReductionModeCreateInfoEXT reduction_ci{
|
const VkSamplerReductionModeCreateInfoEXT reduction_ci{
|
||||||
@@ -2256,8 +2275,8 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const Tegra::Texture::TSCEntry& t
|
|||||||
.compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func),
|
.compareOp = MaxwellToVK::Sampler::DepthCompareFunction(tsc.depth_compare_func),
|
||||||
.minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(),
|
.minLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.0f : tsc.MinLod(),
|
||||||
.maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(),
|
.maxLod = tsc.mipmap_filter == TextureMipmapFilter::None ? 0.25f : tsc.MaxLod(),
|
||||||
.borderColor =
|
.borderColor = has_custom_border_colors ? VK_BORDER_COLOR_FLOAT_CUSTOM_EXT
|
||||||
arbitrary_borders ? VK_BORDER_COLOR_FLOAT_CUSTOM_EXT : ConvertBorderColor(color),
|
: ConvertBorderColor(color),
|
||||||
.unnormalizedCoordinates = VK_FALSE,
|
.unnormalizedCoordinates = VK_FALSE,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
@@ -241,7 +244,6 @@ public:
|
|||||||
[[nodiscard]] VkImageView Handle(Shader::TextureType texture_type) const noexcept {
|
[[nodiscard]] VkImageView Handle(Shader::TextureType texture_type) const noexcept {
|
||||||
return *image_views[static_cast<size_t>(texture_type)];
|
return *image_views[static_cast<size_t>(texture_type)];
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] VkImage ImageHandle() const noexcept {
|
[[nodiscard]] VkImage ImageHandle() const noexcept {
|
||||||
return image_handle;
|
return image_handle;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ ImageInfo::ImageInfo(const TICEntry& config) noexcept {
|
|||||||
dma_downloaded = forced_flushed;
|
dma_downloaded = forced_flushed;
|
||||||
format = PixelFormatFromTextureInfo(config.format, config.r_type, config.g_type, config.b_type,
|
format = PixelFormatFromTextureInfo(config.format, config.r_type, config.g_type, config.b_type,
|
||||||
config.a_type, config.srgb_conversion);
|
config.a_type, config.srgb_conversion);
|
||||||
|
|
||||||
num_samples = NumSamples(config.msaa_mode);
|
num_samples = NumSamples(config.msaa_mode);
|
||||||
resources.levels = config.max_mip_level + 1;
|
resources.levels = config.max_mip_level + 1;
|
||||||
if (config.IsPitchLinear()) {
|
if (config.IsPitchLinear()) {
|
||||||
|
|||||||
@@ -22,6 +22,17 @@
|
|||||||
|
|
||||||
#include <vulkan/vulkan.h>
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
// Define maintenance 7-9 extension names (not yet in official Vulkan headers)
|
||||||
|
#ifndef VK_KHR_MAINTENANCE_7_EXTENSION_NAME
|
||||||
|
#define VK_KHR_MAINTENANCE_7_EXTENSION_NAME "VK_KHR_maintenance7"
|
||||||
|
#endif
|
||||||
|
#ifndef VK_KHR_MAINTENANCE_8_EXTENSION_NAME
|
||||||
|
#define VK_KHR_MAINTENANCE_8_EXTENSION_NAME "VK_KHR_maintenance8"
|
||||||
|
#endif
|
||||||
|
#ifndef VK_KHR_MAINTENANCE_9_EXTENSION_NAME
|
||||||
|
#define VK_KHR_MAINTENANCE_9_EXTENSION_NAME "VK_KHR_maintenance9"
|
||||||
|
#endif
|
||||||
|
|
||||||
// Sanitize macros
|
// Sanitize macros
|
||||||
#undef CreateEvent
|
#undef CreateEvent
|
||||||
#undef CreateSemaphore
|
#undef CreateSemaphore
|
||||||
|
|||||||
@@ -292,9 +292,10 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(vk::Physica
|
|||||||
#if defined(ANDROID) && defined(ARCHITECTURE_arm64)
|
#if defined(ANDROID) && defined(ARCHITECTURE_arm64)
|
||||||
void OverrideBcnFormats(std::unordered_map<VkFormat, VkFormatProperties>& format_properties) {
|
void OverrideBcnFormats(std::unordered_map<VkFormat, VkFormatProperties>& format_properties) {
|
||||||
// These properties are extracted from Adreno driver 512.687.0
|
// These properties are extracted from Adreno driver 512.687.0
|
||||||
constexpr VkFormatFeatureFlags tiling_features{
|
constexpr VkFormatFeatureFlags tiling_features{VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
|
||||||
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT |
|
VK_FORMAT_FEATURE_BLIT_SRC_BIT |
|
||||||
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
|
VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT |
|
||||||
|
VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
|
||||||
VK_FORMAT_FEATURE_TRANSFER_DST_BIT};
|
VK_FORMAT_FEATURE_TRANSFER_DST_BIT};
|
||||||
|
|
||||||
constexpr VkFormatFeatureFlags buffer_features{VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT};
|
constexpr VkFormatFeatureFlags buffer_features{VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT};
|
||||||
@@ -416,7 +417,6 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
|||||||
const bool is_suitable = GetSuitability(surface != nullptr);
|
const bool is_suitable = GetSuitability(surface != nullptr);
|
||||||
|
|
||||||
const VkDriverId driver_id = properties.driver.driverID;
|
const VkDriverId driver_id = properties.driver.driverID;
|
||||||
const auto device_id = properties.properties.deviceID;
|
|
||||||
const bool is_radv = driver_id == VK_DRIVER_ID_MESA_RADV;
|
const bool is_radv = driver_id == VK_DRIVER_ID_MESA_RADV;
|
||||||
const bool is_amd_driver =
|
const bool is_amd_driver =
|
||||||
driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE;
|
driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE;
|
||||||
@@ -427,7 +427,6 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
|||||||
const bool is_mvk = driver_id == VK_DRIVER_ID_MOLTENVK;
|
const bool is_mvk = driver_id == VK_DRIVER_ID_MOLTENVK;
|
||||||
const bool is_qualcomm = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY;
|
const bool is_qualcomm = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY;
|
||||||
const bool is_turnip = driver_id == VK_DRIVER_ID_MESA_TURNIP;
|
const bool is_turnip = driver_id == VK_DRIVER_ID_MESA_TURNIP;
|
||||||
const bool is_s8gen2 = device_id == 0x43050a01;
|
|
||||||
const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY;
|
const bool is_arm = driver_id == VK_DRIVER_ID_ARM_PROPRIETARY;
|
||||||
|
|
||||||
if ((is_mvk || is_qualcomm || is_turnip || is_arm) && !is_suitable) {
|
if ((is_mvk || is_qualcomm || is_turnip || is_arm) && !is_suitable) {
|
||||||
@@ -495,6 +494,11 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
|||||||
CollectToolingInfo();
|
CollectToolingInfo();
|
||||||
|
|
||||||
if (is_qualcomm) {
|
if (is_qualcomm) {
|
||||||
|
// Qualcomm Adreno GPUs doesn't handle scaled vertex attributes; keep emulation enabled
|
||||||
|
must_emulate_scaled_formats = true;
|
||||||
|
LOG_WARNING(Render_Vulkan,
|
||||||
|
"Qualcomm drivers require scaled vertex format emulation; forcing fallback");
|
||||||
|
|
||||||
LOG_WARNING(Render_Vulkan,
|
LOG_WARNING(Render_Vulkan,
|
||||||
"Disabling shader float controls and 64-bit integer features on Qualcomm proprietary drivers");
|
"Disabling shader float controls and 64-bit integer features on Qualcomm proprietary drivers");
|
||||||
RemoveExtension(extensions.shader_float_controls, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME);
|
RemoveExtension(extensions.shader_float_controls, VK_KHR_SHADER_FLOAT_CONTROLS_EXTENSION_NAME);
|
||||||
@@ -536,35 +540,31 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (nv_major_version >= 510) {
|
if (nv_major_version >= 510) {
|
||||||
LOG_WARNING(Render_Vulkan, "NVIDIA Drivers >= 510 do not support MSAA image blits");
|
LOG_WARNING(Render_Vulkan,
|
||||||
|
"NVIDIA Drivers >= 510 do not support MSAA->MSAA image blits. "
|
||||||
|
"MSAA scaling will use 3D helpers. MSAA resolves work normally.");
|
||||||
cant_blit_msaa = true;
|
cant_blit_msaa = true;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (extensions.extended_dynamic_state3 && is_radv) {
|
// Mali/ NVIDIA proprietary drivers: Shader stencil export not supported
|
||||||
LOG_WARNING(Render_Vulkan, "RADV has broken extendedDynamicState3ColorBlendEquation");
|
// Use hardware depth/stencil blits instead when available
|
||||||
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable = false;
|
if (!extensions.shader_stencil_export) {
|
||||||
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation = false;
|
LOG_INFO(Render_Vulkan,
|
||||||
dynamic_state3_blending = false;
|
"NVIDIA: VK_EXT_shader_stencil_export not supported, using hardware blits "
|
||||||
|
"for depth/stencil operations");
|
||||||
const u32 version = (properties.properties.driverVersion << 3) >> 3;
|
LOG_INFO(Render_Vulkan, " D24S8 hardware blit support: {}",
|
||||||
if (version < VK_MAKE_API_VERSION(0, 23, 1, 0)) {
|
is_blit_depth24_stencil8_supported);
|
||||||
LOG_WARNING(Render_Vulkan,
|
LOG_INFO(Render_Vulkan, " D32S8 hardware blit support: {}",
|
||||||
"RADV versions older than 23.1.0 have broken depth clamp dynamic state");
|
is_blit_depth32_stencil8_supported);
|
||||||
features.extended_dynamic_state3.extendedDynamicState3DepthClampEnable = false;
|
|
||||||
dynamic_state3_enables = false;
|
if (!is_blit_depth24_stencil8_supported && !is_blit_depth32_stencil8_supported) {
|
||||||
|
LOG_WARNING(Render_Vulkan,
|
||||||
|
"NVIDIA: Neither shader export nor hardware blits available for "
|
||||||
|
"depth/stencil. Performance may be degraded.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extensions.extended_dynamic_state3 && (is_amd_driver || driver_id == VK_DRIVER_ID_SAMSUNG_PROPRIETARY)) {
|
|
||||||
// AMD and Samsung drivers have broken extendedDynamicState3ColorBlendEquation
|
|
||||||
LOG_WARNING(Render_Vulkan,
|
|
||||||
"AMD and Samsung drivers have broken extendedDynamicState3ColorBlendEquation");
|
|
||||||
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable = false;
|
|
||||||
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation = false;
|
|
||||||
dynamic_state3_blending = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
sets_per_pool = 64;
|
sets_per_pool = 64;
|
||||||
if (is_amd_driver) {
|
if (is_amd_driver) {
|
||||||
// AMD drivers need a higher amount of Sets per Pool in certain circumstances like in XC2.
|
// AMD drivers need a higher amount of Sets per Pool in certain circumstances like in XC2.
|
||||||
@@ -601,15 +601,27 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_intel_windows) {
|
if (is_intel_windows) {
|
||||||
LOG_WARNING(Render_Vulkan, "Intel proprietary drivers do not support MSAA image blits");
|
LOG_WARNING(Render_Vulkan,
|
||||||
|
"Intel proprietary drivers do not support MSAA->MSAA image blits. "
|
||||||
|
"MSAA scaling will use 3D helpers. MSAA resolves work normally.");
|
||||||
cant_blit_msaa = true;
|
cant_blit_msaa = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
has_broken_compute =
|
has_broken_compute =
|
||||||
CheckBrokenCompute(properties.driver.driverID, properties.properties.driverVersion) &&
|
CheckBrokenCompute(properties.driver.driverID, properties.properties.driverVersion) &&
|
||||||
!Settings::values.enable_compute_pipelines.GetValue();
|
!Settings::values.enable_compute_pipelines.GetValue();
|
||||||
if (is_intel_anv || (is_qualcomm && !is_s8gen2)) {
|
must_emulate_bgr565 = false; // Default: assume emulation isn't required
|
||||||
LOG_WARNING(Render_Vulkan, "Driver does not support native BGR format");
|
|
||||||
|
if (is_intel_anv) {
|
||||||
|
LOG_WARNING(Render_Vulkan, "Intel ANV driver does not support native BGR format");
|
||||||
|
must_emulate_bgr565 = true;
|
||||||
|
} else if (is_qualcomm) {
|
||||||
|
LOG_WARNING(Render_Vulkan,
|
||||||
|
"Qualcomm driver mishandles BGR5 formats even with VK_KHR_maintenance5, forcing emulation");
|
||||||
|
must_emulate_bgr565 = true;
|
||||||
|
} else if (is_arm) {
|
||||||
|
LOG_WARNING(Render_Vulkan,
|
||||||
|
"ARM Mali driver mishandles BGR5 formats even with VK_KHR_maintenance5, forcing emulation");
|
||||||
must_emulate_bgr565 = true;
|
must_emulate_bgr565 = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -622,54 +634,54 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
|||||||
(std::min)(properties.properties.limits.maxVertexInputBindings, 16U);
|
(std::min)(properties.properties.limits.maxVertexInputBindings, 16U);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_turnip) {
|
if (is_turnip || is_qualcomm) {
|
||||||
LOG_WARNING(Render_Vulkan, "Turnip requires higher-than-reported binding limits");
|
LOG_WARNING(Render_Vulkan, "Driver requires higher-than-reported binding limits");
|
||||||
properties.properties.limits.maxVertexInputBindings = 32;
|
properties.properties.limits.maxVertexInputBindings = 32;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!extensions.extended_dynamic_state && extensions.extended_dynamic_state2) {
|
// Base dynamic states (VIEWPORT, SCISSOR, DEPTH_BIAS, etc.) are ALWAYS active in vk_graphics_pipeline.cpp
|
||||||
LOG_INFO(Render_Vulkan,
|
// This slider controls EXTENDED dynamic states with accumulative levels per Vulkan specs:
|
||||||
"Removing extendedDynamicState2 due to missing extendedDynamicState");
|
// Level 0 = Core Dynamic States only (Vulkan 1.0)
|
||||||
RemoveExtensionFeature(extensions.extended_dynamic_state2, features.extended_dynamic_state2,
|
// Level 1 = Core + VK_EXT_extended_dynamic_state
|
||||||
VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
|
// Level 2 = Core + VK_EXT_extended_dynamic_state + VK_EXT_extended_dynamic_state2
|
||||||
}
|
// Level 3 = Core + VK_EXT_extended_dynamic_state + VK_EXT_extended_dynamic_state2 + VK_EXT_extended_dynamic_state3
|
||||||
|
|
||||||
if (!extensions.extended_dynamic_state2 && extensions.extended_dynamic_state3) {
|
|
||||||
LOG_INFO(Render_Vulkan,
|
|
||||||
"Removing extendedDynamicState3 due to missing extendedDynamicState2");
|
|
||||||
RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3,
|
|
||||||
VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
|
|
||||||
dynamic_state3_blending = false;
|
|
||||||
dynamic_state3_enables = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mesa Intel drivers on UHD 620 have broken EDS causing extreme flickering - unknown if it affects other iGPUs
|
|
||||||
// ALSO affects ALL versions of UHD drivers on Windows 10+, seems to cause even worse issues like straight up crashing
|
|
||||||
// So... Yeah, UHD drivers fucking suck -- maybe one day we can work past this, maybe; some driver hacking?
|
|
||||||
// And then we can rest in peace by doing `< VK_MAKE_API_VERSION(26, 0, 0)` for our beloved mesa drivers... one day
|
|
||||||
if ((is_mvk || (is_integrated && is_intel_anv) || (is_integrated && is_intel_windows)) && Settings::values.dyna_state.GetValue() != 0) {
|
|
||||||
LOG_WARNING(Render_Vulkan, "Driver has broken dynamic state, forcing to 0 to prevent graphical issues");
|
|
||||||
Settings::values.dyna_state.SetValue(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (Settings::values.dyna_state.GetValue()) {
|
switch (Settings::values.dyna_state.GetValue()) {
|
||||||
case 0:
|
case 0:
|
||||||
RemoveExtensionFeature(extensions.extended_dynamic_state, features.extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
|
// Level 0: Disable all extended dynamic state extensions
|
||||||
[[fallthrough]];
|
RemoveExtensionFeature(extensions.extended_dynamic_state, features.extended_dynamic_state,
|
||||||
case 1:
|
VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);
|
||||||
RemoveExtensionFeature(extensions.extended_dynamic_state2, features.extended_dynamic_state2, VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
|
RemoveExtensionFeature(extensions.extended_dynamic_state2, features.extended_dynamic_state2,
|
||||||
[[fallthrough]];
|
VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
|
||||||
case 2:
|
RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3,
|
||||||
RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3, VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
|
VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
|
||||||
dynamic_state3_blending = false;
|
dynamic_state3_blending = false;
|
||||||
dynamic_state3_enables = false;
|
dynamic_state3_enables = false;
|
||||||
break;
|
break;
|
||||||
|
case 1:
|
||||||
|
// Level 1: Enable EDS1, disable EDS2 and EDS3
|
||||||
|
RemoveExtensionFeature(extensions.extended_dynamic_state2, features.extended_dynamic_state2,
|
||||||
|
VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
|
||||||
|
RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3,
|
||||||
|
VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
|
||||||
|
dynamic_state3_blending = false;
|
||||||
|
dynamic_state3_enables = false;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
// Level 2: Enable EDS1 + EDS2, disable EDS3
|
||||||
|
RemoveExtensionFeature(extensions.extended_dynamic_state3, features.extended_dynamic_state3,
|
||||||
|
VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
|
||||||
|
dynamic_state3_blending = false;
|
||||||
|
dynamic_state3_enables = false;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
default:
|
||||||
|
// Level 3: Enable all (EDS1 + EDS2 + EDS3)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!extensions.extended_dynamic_state) {
|
// VK_EXT_vertex_input_dynamic_state is independent from EDS
|
||||||
Settings::values.vertex_input_dynamic_state.SetValue(false);
|
// It can be enabled even without extended_dynamic_state
|
||||||
}
|
|
||||||
|
|
||||||
if (!Settings::values.vertex_input_dynamic_state.GetValue()) {
|
if (!Settings::values.vertex_input_dynamic_state.GetValue()) {
|
||||||
RemoveExtensionFeature(extensions.vertex_input_dynamic_state, features.vertex_input_dynamic_state, VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
|
RemoveExtensionFeature(extensions.vertex_input_dynamic_state, features.vertex_input_dynamic_state, VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
|
||||||
}
|
}
|
||||||
@@ -758,8 +770,8 @@ void Device::SaveShader(std::span<const u32> spirv) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool Device::ComputeIsOptimalAstcSupported() const {
|
bool Device::ComputeIsOptimalAstcSupported() const {
|
||||||
// Disable for now to avoid converting ASTC twice.
|
// Verify hardware supports all ASTC formats with optimal tiling to avoid software conversion
|
||||||
static constexpr std::array astc_formats = {
|
static constexpr std::array<VkFormat, 28> astc_formats = {
|
||||||
VK_FORMAT_ASTC_4x4_UNORM_BLOCK, VK_FORMAT_ASTC_4x4_SRGB_BLOCK,
|
VK_FORMAT_ASTC_4x4_UNORM_BLOCK, VK_FORMAT_ASTC_4x4_SRGB_BLOCK,
|
||||||
VK_FORMAT_ASTC_5x4_UNORM_BLOCK, VK_FORMAT_ASTC_5x4_SRGB_BLOCK,
|
VK_FORMAT_ASTC_5x4_UNORM_BLOCK, VK_FORMAT_ASTC_5x4_SRGB_BLOCK,
|
||||||
VK_FORMAT_ASTC_5x5_UNORM_BLOCK, VK_FORMAT_ASTC_5x5_SRGB_BLOCK,
|
VK_FORMAT_ASTC_5x5_UNORM_BLOCK, VK_FORMAT_ASTC_5x5_SRGB_BLOCK,
|
||||||
@@ -778,9 +790,10 @@ bool Device::ComputeIsOptimalAstcSupported() const {
|
|||||||
if (!features.features.textureCompressionASTC_LDR) {
|
if (!features.features.textureCompressionASTC_LDR) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const auto format_feature_usage{
|
const auto format_feature_usage{VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT |
|
||||||
VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT | VK_FORMAT_FEATURE_BLIT_SRC_BIT |
|
VK_FORMAT_FEATURE_BLIT_SRC_BIT |
|
||||||
VK_FORMAT_FEATURE_BLIT_DST_BIT | VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
|
VK_FORMAT_FEATURE_BLIT_DST_BIT |
|
||||||
|
VK_FORMAT_FEATURE_TRANSFER_SRC_BIT |
|
||||||
VK_FORMAT_FEATURE_TRANSFER_DST_BIT};
|
VK_FORMAT_FEATURE_TRANSFER_DST_BIT};
|
||||||
for (const auto format : astc_formats) {
|
for (const auto format : astc_formats) {
|
||||||
const auto physical_format_properties{physical.GetFormatProperties(format)};
|
const auto physical_format_properties{physical.GetFormatProperties(format)};
|
||||||
@@ -977,7 +990,7 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
|||||||
// Set next pointer.
|
// Set next pointer.
|
||||||
void** next = &features2.pNext;
|
void** next = &features2.pNext;
|
||||||
|
|
||||||
// Vulkan 1.2, 1.3 and 1.4 features
|
// Vulkan 1.2 and 1.3 features
|
||||||
if (instance_version >= VK_API_VERSION_1_2) {
|
if (instance_version >= VK_API_VERSION_1_2) {
|
||||||
features_1_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
|
features_1_2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
|
||||||
features_1_3.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
|
features_1_3.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_3_FEATURES;
|
||||||
@@ -1083,6 +1096,16 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
|||||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
|
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TRANSFORM_FEEDBACK_PROPERTIES_EXT;
|
||||||
SetNext(next, properties.transform_feedback);
|
SetNext(next, properties.transform_feedback);
|
||||||
}
|
}
|
||||||
|
if (extensions.maintenance5) {
|
||||||
|
properties.maintenance5.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_5_PROPERTIES_KHR;
|
||||||
|
SetNext(next, properties.maintenance5);
|
||||||
|
}
|
||||||
|
if (extensions.multi_draw) {
|
||||||
|
properties.multi_draw.sType =
|
||||||
|
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTI_DRAW_PROPERTIES_EXT;
|
||||||
|
SetNext(next, properties.multi_draw);
|
||||||
|
}
|
||||||
|
|
||||||
// Perform the property fetch.
|
// Perform the property fetch.
|
||||||
physical.GetProperties2(properties2);
|
physical.GetProperties2(properties2);
|
||||||
@@ -1115,14 +1138,75 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VK_DYNAMIC_STATE
|
||||||
|
|
||||||
|
// Driver detection variables for workarounds in GetSuitability
|
||||||
|
const VkDriverId driver_id = properties.driver.driverID;
|
||||||
|
[[maybe_unused]] const bool is_amd_driver =
|
||||||
|
driver_id == VK_DRIVER_ID_AMD_PROPRIETARY || driver_id == VK_DRIVER_ID_AMD_OPEN_SOURCE;
|
||||||
|
const bool is_intel_windows = driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS;
|
||||||
|
[[maybe_unused]] const bool is_qualcomm = driver_id == VK_DRIVER_ID_QUALCOMM_PROPRIETARY;
|
||||||
|
|
||||||
|
// VK_EXT_extended_dynamic_state2 below this will appear drivers that need workarounds.
|
||||||
|
|
||||||
|
// VK_EXT_extended_dynamic_state3 below this will appear drivers that need workarounds.
|
||||||
|
|
||||||
|
[[maybe_unused]] const auto device_id = properties.properties.deviceID;
|
||||||
|
|
||||||
|
// Samsung: Broken extendedDynamicState3ColorBlendEquation
|
||||||
|
// Disable blend equation dynamic state, force static pipeline state
|
||||||
|
if (extensions.extended_dynamic_state3 &&
|
||||||
|
(driver_id == VK_DRIVER_ID_SAMSUNG_PROPRIETARY)) {
|
||||||
|
LOG_WARNING(Render_Vulkan,
|
||||||
|
"Samsung: Disabling broken extendedDynamicState3ColorBlendEquation");
|
||||||
|
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable = false;
|
||||||
|
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Intel Windows < 27.20.100.0: Broken VertexInputDynamicState
|
||||||
|
// Disable VertexInputDynamicState on old Intel Windows drivers
|
||||||
|
if (extensions.vertex_input_dynamic_state && is_intel_windows) {
|
||||||
|
const u32 version = (properties.properties.driverVersion << 3) >> 3;
|
||||||
|
if (version < VK_MAKE_API_VERSION(27, 20, 100, 0)) {
|
||||||
|
LOG_WARNING(Render_Vulkan,
|
||||||
|
"Intel Windows < 27.20.100.0: Disabling broken VK_EXT_vertex_input_dynamic_state");
|
||||||
|
RemoveExtensionFeature(extensions.vertex_input_dynamic_state,
|
||||||
|
features.vertex_input_dynamic_state,
|
||||||
|
VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Settings::values.dyna_state.GetValue() == 0) {
|
||||||
|
LOG_INFO(Render_Vulkan, "Extended Dynamic State disabled by user setting, clearing all EDS features");
|
||||||
|
features.custom_border_color.customBorderColors = false;
|
||||||
|
features.custom_border_color.customBorderColorWithoutFormat = false;
|
||||||
|
features.extended_dynamic_state.extendedDynamicState = false;
|
||||||
|
features.extended_dynamic_state2.extendedDynamicState2 = false;
|
||||||
|
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable = false;
|
||||||
|
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation = false;
|
||||||
|
features.extended_dynamic_state3.extendedDynamicState3ColorWriteMask = false;
|
||||||
|
features.extended_dynamic_state3.extendedDynamicState3DepthClampEnable = false;
|
||||||
|
features.extended_dynamic_state3.extendedDynamicState3LogicOpEnable = false;
|
||||||
|
}
|
||||||
|
|
||||||
// Return whether we were suitable.
|
// Return whether we were suitable.
|
||||||
return suitable;
|
return suitable;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::RemoveUnsuitableExtensions() {
|
void Device::RemoveUnsuitableExtensions() {
|
||||||
// VK_EXT_custom_border_color
|
// VK_EXT_custom_border_color
|
||||||
extensions.custom_border_color = features.custom_border_color.customBorderColors &&
|
// Enable extension if driver supports it, then check individual features
|
||||||
features.custom_border_color.customBorderColorWithoutFormat;
|
// - customBorderColors: Required to use VK_BORDER_COLOR_FLOAT_CUSTOM_EXT
|
||||||
|
// - customBorderColorWithoutFormat: Optional, allows VK_FORMAT_UNDEFINED
|
||||||
|
// If only customBorderColors is available, we must provide a specific format
|
||||||
|
if (extensions.custom_border_color) {
|
||||||
|
// Verify that at least customBorderColors is available
|
||||||
|
if (!features.custom_border_color.customBorderColors) {
|
||||||
|
LOG_WARNING(Render_Vulkan,
|
||||||
|
"VK_EXT_custom_border_color reported but customBorderColors feature not available, disabling");
|
||||||
|
extensions.custom_border_color = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
RemoveExtensionFeatureIfUnsuitable(extensions.custom_border_color, features.custom_border_color,
|
RemoveExtensionFeatureIfUnsuitable(extensions.custom_border_color, features.custom_border_color,
|
||||||
VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
|
VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME);
|
||||||
|
|
||||||
@@ -1151,21 +1235,79 @@ void Device::RemoveUnsuitableExtensions() {
|
|||||||
VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
|
VK_EXT_EXTENDED_DYNAMIC_STATE_2_EXTENSION_NAME);
|
||||||
|
|
||||||
// VK_EXT_extended_dynamic_state3
|
// VK_EXT_extended_dynamic_state3
|
||||||
dynamic_state3_blending =
|
const bool supports_color_blend_enable =
|
||||||
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable &&
|
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEnable;
|
||||||
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation &&
|
const bool supports_color_blend_equation =
|
||||||
|
features.extended_dynamic_state3.extendedDynamicState3ColorBlendEquation;
|
||||||
|
const bool supports_color_write_mask =
|
||||||
features.extended_dynamic_state3.extendedDynamicState3ColorWriteMask;
|
features.extended_dynamic_state3.extendedDynamicState3ColorWriteMask;
|
||||||
dynamic_state3_enables =
|
dynamic_state3_blending = supports_color_blend_enable && supports_color_blend_equation &&
|
||||||
features.extended_dynamic_state3.extendedDynamicState3DepthClampEnable &&
|
supports_color_write_mask;
|
||||||
|
|
||||||
|
const bool supports_depth_clamp_enable =
|
||||||
|
features.extended_dynamic_state3.extendedDynamicState3DepthClampEnable;
|
||||||
|
const bool supports_logic_op_enable =
|
||||||
features.extended_dynamic_state3.extendedDynamicState3LogicOpEnable;
|
features.extended_dynamic_state3.extendedDynamicState3LogicOpEnable;
|
||||||
|
const bool supports_line_raster_mode =
|
||||||
|
features.extended_dynamic_state3.extendedDynamicState3LineRasterizationMode &&
|
||||||
|
extensions.line_rasterization && features.line_rasterization.rectangularLines;
|
||||||
|
const bool supports_conservative_raster_mode =
|
||||||
|
features.extended_dynamic_state3.extendedDynamicState3ConservativeRasterizationMode &&
|
||||||
|
extensions.conservative_rasterization;
|
||||||
|
const bool supports_line_stipple_enable =
|
||||||
|
features.extended_dynamic_state3.extendedDynamicState3LineStippleEnable &&
|
||||||
|
extensions.line_rasterization && features.line_rasterization.stippledRectangularLines;
|
||||||
|
const bool supports_alpha_to_coverage =
|
||||||
|
features.extended_dynamic_state3.extendedDynamicState3AlphaToCoverageEnable;
|
||||||
|
const bool supports_alpha_to_one =
|
||||||
|
features.extended_dynamic_state3.extendedDynamicState3AlphaToOneEnable &&
|
||||||
|
features.features.alphaToOne;
|
||||||
|
|
||||||
|
dynamic_state3_depth_clamp_enable = supports_depth_clamp_enable;
|
||||||
|
dynamic_state3_logic_op_enable = supports_logic_op_enable;
|
||||||
|
dynamic_state3_line_raster_mode = supports_line_raster_mode;
|
||||||
|
dynamic_state3_conservative_raster_mode = supports_conservative_raster_mode;
|
||||||
|
dynamic_state3_line_stipple_enable = supports_line_stipple_enable;
|
||||||
|
dynamic_state3_alpha_to_coverage = supports_alpha_to_coverage;
|
||||||
|
dynamic_state3_alpha_to_one = supports_alpha_to_one;
|
||||||
|
|
||||||
|
dynamic_state3_enables = dynamic_state3_depth_clamp_enable || dynamic_state3_logic_op_enable ||
|
||||||
|
dynamic_state3_line_raster_mode ||
|
||||||
|
dynamic_state3_conservative_raster_mode ||
|
||||||
|
dynamic_state3_line_stipple_enable ||
|
||||||
|
dynamic_state3_alpha_to_coverage || dynamic_state3_alpha_to_one;
|
||||||
|
|
||||||
extensions.extended_dynamic_state3 = dynamic_state3_blending || dynamic_state3_enables;
|
extensions.extended_dynamic_state3 = dynamic_state3_blending || dynamic_state3_enables;
|
||||||
dynamic_state3_blending = dynamic_state3_blending && extensions.extended_dynamic_state3;
|
if (!extensions.extended_dynamic_state3) {
|
||||||
dynamic_state3_enables = dynamic_state3_enables && extensions.extended_dynamic_state3;
|
dynamic_state3_blending = false;
|
||||||
|
dynamic_state3_enables = false;
|
||||||
|
dynamic_state3_depth_clamp_enable = false;
|
||||||
|
dynamic_state3_logic_op_enable = false;
|
||||||
|
dynamic_state3_line_raster_mode = false;
|
||||||
|
dynamic_state3_conservative_raster_mode = false;
|
||||||
|
dynamic_state3_line_stipple_enable = false;
|
||||||
|
dynamic_state3_alpha_to_coverage = false;
|
||||||
|
dynamic_state3_alpha_to_one = false;
|
||||||
|
}
|
||||||
RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state3,
|
RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state3,
|
||||||
features.extended_dynamic_state3,
|
features.extended_dynamic_state3,
|
||||||
VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
|
VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
|
||||||
|
|
||||||
|
// VK_EXT_robustness2
|
||||||
|
// Enable if at least one robustness2 feature is available
|
||||||
|
extensions.robustness_2 = features.robustness2.robustBufferAccess2 ||
|
||||||
|
features.robustness2.robustImageAccess2 ||
|
||||||
|
features.robustness2.nullDescriptor;
|
||||||
|
|
||||||
|
RemoveExtensionFeatureIfUnsuitable(extensions.robustness_2, features.robustness2,
|
||||||
|
VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
|
||||||
|
|
||||||
|
// VK_EXT_image_robustness
|
||||||
|
// Enable if robustImageAccess is available
|
||||||
|
extensions.image_robustness = features.image_robustness.robustImageAccess;
|
||||||
|
RemoveExtensionFeatureIfUnsuitable(extensions.image_robustness, features.image_robustness,
|
||||||
|
VK_EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME);
|
||||||
|
|
||||||
// VK_EXT_provoking_vertex
|
// VK_EXT_provoking_vertex
|
||||||
if (Settings::values.provoking_vertex.GetValue()) {
|
if (Settings::values.provoking_vertex.GetValue()) {
|
||||||
extensions.provoking_vertex = features.provoking_vertex.provokingVertexLast
|
extensions.provoking_vertex = features.provoking_vertex.provokingVertexLast
|
||||||
@@ -1220,6 +1362,17 @@ void Device::RemoveUnsuitableExtensions() {
|
|||||||
features.vertex_input_dynamic_state,
|
features.vertex_input_dynamic_state,
|
||||||
VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
|
VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME);
|
||||||
|
|
||||||
|
// VK_EXT_multi_draw
|
||||||
|
extensions.multi_draw = features.multi_draw.multiDraw;
|
||||||
|
|
||||||
|
if (extensions.multi_draw) {
|
||||||
|
LOG_INFO(Render_Vulkan, "VK_EXT_multi_draw: maxMultiDrawCount={}",
|
||||||
|
properties.multi_draw.maxMultiDrawCount);
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveExtensionFeatureIfUnsuitable(extensions.multi_draw, features.multi_draw,
|
||||||
|
VK_EXT_MULTI_DRAW_EXTENSION_NAME);
|
||||||
|
|
||||||
// VK_KHR_pipeline_executable_properties
|
// VK_KHR_pipeline_executable_properties
|
||||||
if (Settings::values.renderer_shader_feedback.GetValue()) {
|
if (Settings::values.renderer_shader_feedback.GetValue()) {
|
||||||
extensions.pipeline_executable_properties =
|
extensions.pipeline_executable_properties =
|
||||||
@@ -1243,6 +1396,76 @@ void Device::RemoveUnsuitableExtensions() {
|
|||||||
RemoveExtensionFeatureIfUnsuitable(extensions.workgroup_memory_explicit_layout,
|
RemoveExtensionFeatureIfUnsuitable(extensions.workgroup_memory_explicit_layout,
|
||||||
features.workgroup_memory_explicit_layout,
|
features.workgroup_memory_explicit_layout,
|
||||||
VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME);
|
VK_KHR_WORKGROUP_MEMORY_EXPLICIT_LAYOUT_EXTENSION_NAME);
|
||||||
|
|
||||||
|
// VK_EXT_swapchain_maintenance1 (extension only, has features)
|
||||||
|
// Requires VK_EXT_surface_maintenance1 instance extension
|
||||||
|
extensions.swapchain_maintenance1 = features.swapchain_maintenance1.swapchainMaintenance1;
|
||||||
|
if (extensions.swapchain_maintenance1) {
|
||||||
|
// Check if VK_EXT_surface_maintenance1 instance extension is available
|
||||||
|
const auto instance_extensions = vk::EnumerateInstanceExtensionProperties(dld);
|
||||||
|
const bool has_surface_maintenance1 = instance_extensions && std::ranges::any_of(*instance_extensions,
|
||||||
|
[](const VkExtensionProperties& prop) {
|
||||||
|
return std::strcmp(prop.extensionName, VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME) == 0;
|
||||||
|
});
|
||||||
|
if (!has_surface_maintenance1) {
|
||||||
|
LOG_WARNING(Render_Vulkan,
|
||||||
|
"VK_EXT_swapchain_maintenance1 requires VK_EXT_surface_maintenance1, disabling");
|
||||||
|
extensions.swapchain_maintenance1 = false;
|
||||||
|
features.swapchain_maintenance1.swapchainMaintenance1 = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
RemoveExtensionFeatureIfUnsuitable(extensions.swapchain_maintenance1, features.swapchain_maintenance1,
|
||||||
|
VK_EXT_SWAPCHAIN_MAINTENANCE_1_EXTENSION_NAME);
|
||||||
|
|
||||||
|
// VK_KHR_maintenance1 (core in Vulkan 1.1, no features)
|
||||||
|
extensions.maintenance1 = loaded_extensions.contains(VK_KHR_MAINTENANCE_1_EXTENSION_NAME);
|
||||||
|
RemoveExtensionIfUnsuitable(extensions.maintenance1, VK_KHR_MAINTENANCE_1_EXTENSION_NAME);
|
||||||
|
|
||||||
|
// VK_KHR_maintenance2 (core in Vulkan 1.1, no features)
|
||||||
|
extensions.maintenance2 = loaded_extensions.contains(VK_KHR_MAINTENANCE_2_EXTENSION_NAME);
|
||||||
|
RemoveExtensionIfUnsuitable(extensions.maintenance2, VK_KHR_MAINTENANCE_2_EXTENSION_NAME);
|
||||||
|
|
||||||
|
// VK_KHR_maintenance3 (core in Vulkan 1.1, no features)
|
||||||
|
extensions.maintenance3 = loaded_extensions.contains(VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
|
||||||
|
RemoveExtensionIfUnsuitable(extensions.maintenance3, VK_KHR_MAINTENANCE_3_EXTENSION_NAME);
|
||||||
|
|
||||||
|
// VK_KHR_maintenance4
|
||||||
|
extensions.maintenance4 = features.maintenance4.maintenance4;
|
||||||
|
RemoveExtensionFeatureIfUnsuitable(extensions.maintenance4, features.maintenance4,
|
||||||
|
VK_KHR_MAINTENANCE_4_EXTENSION_NAME);
|
||||||
|
|
||||||
|
// VK_KHR_maintenance5
|
||||||
|
extensions.maintenance5 = features.maintenance5.maintenance5;
|
||||||
|
|
||||||
|
if (extensions.maintenance5) {
|
||||||
|
LOG_INFO(Render_Vulkan, "VK_KHR_maintenance5 properties: polygonModePointSize={} "
|
||||||
|
"depthStencilSwizzleOne={} earlyFragmentTests={} nonStrictWideLines={}",
|
||||||
|
properties.maintenance5.polygonModePointSize,
|
||||||
|
properties.maintenance5.depthStencilSwizzleOneSupport,
|
||||||
|
properties.maintenance5.earlyFragmentMultisampleCoverageAfterSampleCounting &&
|
||||||
|
properties.maintenance5.earlyFragmentSampleMaskTestBeforeSampleCounting,
|
||||||
|
properties.maintenance5.nonStrictWideLinesUseParallelogram);
|
||||||
|
}
|
||||||
|
|
||||||
|
RemoveExtensionFeatureIfUnsuitable(extensions.maintenance5, features.maintenance5,
|
||||||
|
VK_KHR_MAINTENANCE_5_EXTENSION_NAME);
|
||||||
|
|
||||||
|
// VK_KHR_maintenance6
|
||||||
|
extensions.maintenance6 = features.maintenance6.maintenance6;
|
||||||
|
RemoveExtensionFeatureIfUnsuitable(extensions.maintenance6, features.maintenance6,
|
||||||
|
VK_KHR_MAINTENANCE_6_EXTENSION_NAME);
|
||||||
|
|
||||||
|
// VK_KHR_maintenance7 (proposed for Vulkan 1.4, no features)
|
||||||
|
extensions.maintenance7 = loaded_extensions.contains(VK_KHR_MAINTENANCE_7_EXTENSION_NAME);
|
||||||
|
RemoveExtensionIfUnsuitable(extensions.maintenance7, VK_KHR_MAINTENANCE_7_EXTENSION_NAME);
|
||||||
|
|
||||||
|
// VK_KHR_maintenance8 (proposed for Vulkan 1.4, no features)
|
||||||
|
extensions.maintenance8 = loaded_extensions.contains(VK_KHR_MAINTENANCE_8_EXTENSION_NAME);
|
||||||
|
RemoveExtensionIfUnsuitable(extensions.maintenance8, VK_KHR_MAINTENANCE_8_EXTENSION_NAME);
|
||||||
|
|
||||||
|
// VK_KHR_maintenance9 (proposed for Vulkan 1.4, no features)
|
||||||
|
extensions.maintenance9 = loaded_extensions.contains(VK_KHR_MAINTENANCE_9_EXTENSION_NAME);
|
||||||
|
RemoveExtensionIfUnsuitable(extensions.maintenance9, VK_KHR_MAINTENANCE_9_EXTENSION_NAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Device::SetupFamilies(VkSurfaceKHR surface) {
|
void Device::SetupFamilies(VkSurfaceKHR surface) {
|
||||||
|
|||||||
@@ -37,9 +37,13 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
|||||||
FEATURE(KHR, TimelineSemaphore, TIMELINE_SEMAPHORE, timeline_semaphore)
|
FEATURE(KHR, TimelineSemaphore, TIMELINE_SEMAPHORE, timeline_semaphore)
|
||||||
|
|
||||||
#define FOR_EACH_VK_FEATURE_1_3(FEATURE) \
|
#define FOR_EACH_VK_FEATURE_1_3(FEATURE) \
|
||||||
|
FEATURE(EXT, ImageRobustness, IMAGE_ROBUSTNESS, image_robustness) \
|
||||||
FEATURE(EXT, ShaderDemoteToHelperInvocation, SHADER_DEMOTE_TO_HELPER_INVOCATION, \
|
FEATURE(EXT, ShaderDemoteToHelperInvocation, SHADER_DEMOTE_TO_HELPER_INVOCATION, \
|
||||||
shader_demote_to_helper_invocation) \
|
shader_demote_to_helper_invocation) \
|
||||||
FEATURE(EXT, SubgroupSizeControl, SUBGROUP_SIZE_CONTROL, subgroup_size_control)
|
FEATURE(EXT, SubgroupSizeControl, SUBGROUP_SIZE_CONTROL, subgroup_size_control) \
|
||||||
|
FEATURE(KHR, Maintenance4, MAINTENANCE_4, maintenance4)
|
||||||
|
|
||||||
|
#define FOR_EACH_VK_FEATURE_1_4(FEATURE)
|
||||||
|
|
||||||
// Define all features which may be used by the implementation and require an extension here.
|
// Define all features which may be used by the implementation and require an extension here.
|
||||||
#define FOR_EACH_VK_FEATURE_EXT(FEATURE) \
|
#define FOR_EACH_VK_FEATURE_EXT(FEATURE) \
|
||||||
@@ -52,12 +56,16 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
|||||||
FEATURE(EXT, 4444Formats, 4444_FORMATS, format_a4b4g4r4) \
|
FEATURE(EXT, 4444Formats, 4444_FORMATS, format_a4b4g4r4) \
|
||||||
FEATURE(EXT, IndexTypeUint8, INDEX_TYPE_UINT8, index_type_uint8) \
|
FEATURE(EXT, IndexTypeUint8, INDEX_TYPE_UINT8, index_type_uint8) \
|
||||||
FEATURE(EXT, LineRasterization, LINE_RASTERIZATION, line_rasterization) \
|
FEATURE(EXT, LineRasterization, LINE_RASTERIZATION, line_rasterization) \
|
||||||
|
FEATURE(EXT, MultiDraw, MULTI_DRAW, multi_draw) \
|
||||||
FEATURE(EXT, PrimitiveTopologyListRestart, PRIMITIVE_TOPOLOGY_LIST_RESTART, \
|
FEATURE(EXT, PrimitiveTopologyListRestart, PRIMITIVE_TOPOLOGY_LIST_RESTART, \
|
||||||
primitive_topology_list_restart) \
|
primitive_topology_list_restart) \
|
||||||
FEATURE(EXT, ProvokingVertex, PROVOKING_VERTEX, provoking_vertex) \
|
FEATURE(EXT, ProvokingVertex, PROVOKING_VERTEX, provoking_vertex) \
|
||||||
FEATURE(EXT, Robustness2, ROBUSTNESS_2, robustness2) \
|
FEATURE(EXT, Robustness2, ROBUSTNESS_2, robustness2) \
|
||||||
FEATURE(EXT, TransformFeedback, TRANSFORM_FEEDBACK, transform_feedback) \
|
FEATURE(EXT, TransformFeedback, TRANSFORM_FEEDBACK, transform_feedback) \
|
||||||
FEATURE(EXT, VertexInputDynamicState, VERTEX_INPUT_DYNAMIC_STATE, vertex_input_dynamic_state) \
|
FEATURE(EXT, VertexInputDynamicState, VERTEX_INPUT_DYNAMIC_STATE, vertex_input_dynamic_state) \
|
||||||
|
FEATURE(EXT, SwapchainMaintenance1, SWAPCHAIN_MAINTENANCE_1, swapchain_maintenance1) \
|
||||||
|
FEATURE(KHR, Maintenance5, MAINTENANCE_5, maintenance5) \
|
||||||
|
FEATURE(KHR, Maintenance6, MAINTENANCE_6, maintenance6) \
|
||||||
FEATURE(KHR, PipelineExecutableProperties, PIPELINE_EXECUTABLE_PROPERTIES, \
|
FEATURE(KHR, PipelineExecutableProperties, PIPELINE_EXECUTABLE_PROPERTIES, \
|
||||||
pipeline_executable_properties) \
|
pipeline_executable_properties) \
|
||||||
FEATURE(KHR, WorkgroupMemoryExplicitLayout, WORKGROUP_MEMORY_EXPLICIT_LAYOUT, \
|
FEATURE(KHR, WorkgroupMemoryExplicitLayout, WORKGROUP_MEMORY_EXPLICIT_LAYOUT, \
|
||||||
@@ -84,6 +92,12 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
|||||||
EXTENSION(KHR, SWAPCHAIN, swapchain) \
|
EXTENSION(KHR, SWAPCHAIN, swapchain) \
|
||||||
EXTENSION(KHR, SWAPCHAIN_MUTABLE_FORMAT, swapchain_mutable_format) \
|
EXTENSION(KHR, SWAPCHAIN_MUTABLE_FORMAT, swapchain_mutable_format) \
|
||||||
EXTENSION(KHR, IMAGE_FORMAT_LIST, image_format_list) \
|
EXTENSION(KHR, IMAGE_FORMAT_LIST, image_format_list) \
|
||||||
|
EXTENSION(KHR, MAINTENANCE_1, maintenance1) \
|
||||||
|
EXTENSION(KHR, MAINTENANCE_2, maintenance2) \
|
||||||
|
EXTENSION(KHR, MAINTENANCE_3, maintenance3) \
|
||||||
|
EXTENSION(KHR, MAINTENANCE_7, maintenance7) \
|
||||||
|
EXTENSION(KHR, MAINTENANCE_8, maintenance8) \
|
||||||
|
EXTENSION(KHR, MAINTENANCE_9, maintenance9) \
|
||||||
EXTENSION(NV, DEVICE_DIAGNOSTICS_CONFIG, device_diagnostics_config) \
|
EXTENSION(NV, DEVICE_DIAGNOSTICS_CONFIG, device_diagnostics_config) \
|
||||||
EXTENSION(NV, GEOMETRY_SHADER_PASSTHROUGH, geometry_shader_passthrough) \
|
EXTENSION(NV, GEOMETRY_SHADER_PASSTHROUGH, geometry_shader_passthrough) \
|
||||||
EXTENSION(NV, VIEWPORT_ARRAY2, viewport_array2) \
|
EXTENSION(NV, VIEWPORT_ARRAY2, viewport_array2) \
|
||||||
@@ -110,6 +124,7 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
|||||||
EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME) \
|
EXTENSION_NAME(VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME) \
|
||||||
EXTENSION_NAME(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME) \
|
EXTENSION_NAME(VK_EXT_EXTERNAL_MEMORY_HOST_EXTENSION_NAME) \
|
||||||
EXTENSION_NAME(VK_EXT_4444_FORMATS_EXTENSION_NAME) \
|
EXTENSION_NAME(VK_EXT_4444_FORMATS_EXTENSION_NAME) \
|
||||||
|
EXTENSION_NAME(VK_EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME) \
|
||||||
EXTENSION_NAME(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME) \
|
EXTENSION_NAME(VK_EXT_LINE_RASTERIZATION_EXTENSION_NAME) \
|
||||||
EXTENSION_NAME(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME) \
|
EXTENSION_NAME(VK_EXT_ROBUSTNESS_2_EXTENSION_NAME) \
|
||||||
EXTENSION_NAME(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME) \
|
EXTENSION_NAME(VK_EXT_VERTEX_INPUT_DYNAMIC_STATE_EXTENSION_NAME) \
|
||||||
@@ -161,6 +176,7 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
|||||||
FEATURE_NAME(depth_bias_control, depthBiasExact) \
|
FEATURE_NAME(depth_bias_control, depthBiasExact) \
|
||||||
FEATURE_NAME(extended_dynamic_state, extendedDynamicState) \
|
FEATURE_NAME(extended_dynamic_state, extendedDynamicState) \
|
||||||
FEATURE_NAME(format_a4b4g4r4, formatA4B4G4R4) \
|
FEATURE_NAME(format_a4b4g4r4, formatA4B4G4R4) \
|
||||||
|
FEATURE_NAME(image_robustness, robustImageAccess) \
|
||||||
FEATURE_NAME(index_type_uint8, indexTypeUint8) \
|
FEATURE_NAME(index_type_uint8, indexTypeUint8) \
|
||||||
FEATURE_NAME(primitive_topology_list_restart, primitiveTopologyListRestart) \
|
FEATURE_NAME(primitive_topology_list_restart, primitiveTopologyListRestart) \
|
||||||
FEATURE_NAME(provoking_vertex, provokingVertexLast) \
|
FEATURE_NAME(provoking_vertex, provokingVertexLast) \
|
||||||
@@ -440,6 +456,11 @@ public:
|
|||||||
return extensions.swapchain_mutable_format;
|
return extensions.swapchain_mutable_format;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if VK_EXT_swapchain_maintenance1 is enabled.
|
||||||
|
bool IsExtSwapchainMaintenance1Enabled() const {
|
||||||
|
return extensions.swapchain_maintenance1;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if VK_KHR_shader_float_controls is enabled.
|
/// Returns true if VK_KHR_shader_float_controls is enabled.
|
||||||
bool IsKhrShaderFloatControlsSupported() const {
|
bool IsKhrShaderFloatControlsSupported() const {
|
||||||
return extensions.shader_float_controls;
|
return extensions.shader_float_controls;
|
||||||
@@ -476,10 +497,18 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if the device supports VK_EXT_shader_stencil_export.
|
/// Returns true if the device supports VK_EXT_shader_stencil_export.
|
||||||
|
/// Note: Most Mali/NVIDIA drivers don't support this. Use hardware blits as fallback.
|
||||||
bool IsExtShaderStencilExportSupported() const {
|
bool IsExtShaderStencilExportSupported() const {
|
||||||
return extensions.shader_stencil_export;
|
return extensions.shader_stencil_export;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if depth/stencil operations can be performed efficiently.
|
||||||
|
/// Either through shader export or hardware blits.
|
||||||
|
bool CanPerformDepthStencilOperations() const {
|
||||||
|
return extensions.shader_stencil_export || is_blit_depth24_stencil8_supported ||
|
||||||
|
is_blit_depth32_stencil8_supported;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if the device supports VK_EXT_depth_range_unrestricted.
|
/// Returns true if the device supports VK_EXT_depth_range_unrestricted.
|
||||||
bool IsExtDepthRangeUnrestrictedSupported() const {
|
bool IsExtDepthRangeUnrestrictedSupported() const {
|
||||||
return extensions.depth_range_unrestricted;
|
return extensions.depth_range_unrestricted;
|
||||||
@@ -520,6 +549,46 @@ public:
|
|||||||
return extensions.custom_border_color;
|
return extensions.custom_border_color;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the device supports VK_EXT_image_robustness.
|
||||||
|
bool IsExtImageRobustnessSupported() const {
|
||||||
|
return extensions.image_robustness;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if robustImageAccess is supported.
|
||||||
|
bool IsRobustImageAccessSupported() const {
|
||||||
|
return features.image_robustness.robustImageAccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the device supports VK_EXT_robustness2.
|
||||||
|
bool IsExtRobustness2Supported() const {
|
||||||
|
return extensions.robustness_2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if robustBufferAccess2 is supported.
|
||||||
|
bool IsRobustBufferAccess2Supported() const {
|
||||||
|
return features.robustness2.robustBufferAccess2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if robustImageAccess2 is supported.
|
||||||
|
bool IsRobustImageAccess2Supported() const {
|
||||||
|
return features.robustness2.robustImageAccess2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if nullDescriptor is supported.
|
||||||
|
bool IsNullDescriptorSupported() const {
|
||||||
|
return features.robustness2.nullDescriptor;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if customBorderColors feature is available.
|
||||||
|
bool IsCustomBorderColorsSupported() const {
|
||||||
|
return features.custom_border_color.customBorderColors;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if customBorderColorWithoutFormat feature is available.
|
||||||
|
bool IsCustomBorderColorWithoutFormatSupported() const {
|
||||||
|
return features.custom_border_color.customBorderColorWithoutFormat;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if the device supports VK_EXT_extended_dynamic_state.
|
/// Returns true if the device supports VK_EXT_extended_dynamic_state.
|
||||||
bool IsExtExtendedDynamicStateSupported() const {
|
bool IsExtExtendedDynamicStateSupported() const {
|
||||||
return extensions.extended_dynamic_state;
|
return extensions.extended_dynamic_state;
|
||||||
@@ -569,6 +638,55 @@ public:
|
|||||||
return extensions.line_rasterization;
|
return extensions.line_rasterization;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SupportsRectangularLines() const {
|
||||||
|
return features.line_rasterization.rectangularLines != VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SupportsSmoothLines() const {
|
||||||
|
return features.line_rasterization.smoothLines != VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SupportsStippledRectangularLines() const {
|
||||||
|
return features.line_rasterization.stippledRectangularLines != VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SupportsAlphaToOne() const {
|
||||||
|
return features.features.alphaToOne != VK_FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SupportsDynamicState3DepthClampEnable() const {
|
||||||
|
return dynamic_state3_depth_clamp_enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SupportsDynamicState3LogicOpEnable() const {
|
||||||
|
return dynamic_state3_logic_op_enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SupportsDynamicState3LineRasterizationMode() const {
|
||||||
|
return dynamic_state3_line_raster_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SupportsDynamicState3ConservativeRasterizationMode() const {
|
||||||
|
return dynamic_state3_conservative_raster_mode;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SupportsDynamicState3LineStippleEnable() const {
|
||||||
|
return dynamic_state3_line_stipple_enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SupportsDynamicState3AlphaToCoverageEnable() const {
|
||||||
|
return dynamic_state3_alpha_to_coverage;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SupportsDynamicState3AlphaToOneEnable() const {
|
||||||
|
return dynamic_state3_alpha_to_one;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true when the user enabled extended core dynamic states (level > 0).
|
||||||
|
bool UsesAdvancedCoreDynamicState() const {
|
||||||
|
return Settings::values.dyna_state.GetValue() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if the device supports VK_EXT_vertex_input_dynamic_state.
|
/// Returns true if the device supports VK_EXT_vertex_input_dynamic_state.
|
||||||
bool IsExtVertexInputDynamicStateSupported() const {
|
bool IsExtVertexInputDynamicStateSupported() const {
|
||||||
return extensions.vertex_input_dynamic_state;
|
return extensions.vertex_input_dynamic_state;
|
||||||
@@ -703,6 +821,73 @@ public:
|
|||||||
return features2.features.multiViewport;
|
return features2.features.multiViewport;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true if the device supports VK_KHR_maintenance1.
|
||||||
|
bool IsKhrMaintenance1Supported() const {
|
||||||
|
return extensions.maintenance1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the device supports VK_KHR_maintenance2.
|
||||||
|
bool IsKhrMaintenance2Supported() const {
|
||||||
|
return extensions.maintenance2;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the device supports VK_KHR_maintenance3.
|
||||||
|
bool IsKhrMaintenance3Supported() const {
|
||||||
|
return extensions.maintenance3;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the device supports VK_KHR_maintenance4.
|
||||||
|
bool IsKhrMaintenance4Supported() const {
|
||||||
|
return extensions.maintenance4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the device supports VK_KHR_maintenance5.
|
||||||
|
bool IsKhrMaintenance5Supported() const {
|
||||||
|
return extensions.maintenance5;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if polygon mode POINT supports gl_PointSize.
|
||||||
|
bool SupportsPolygonModePointSize() const {
|
||||||
|
return extensions.maintenance5 && properties.maintenance5.polygonModePointSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if depth/stencil swizzle ONE is supported.
|
||||||
|
bool SupportsDepthStencilSwizzleOne() const {
|
||||||
|
return extensions.maintenance5 && properties.maintenance5.depthStencilSwizzleOneSupport;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if early fragment tests optimizations are available.
|
||||||
|
bool SupportsEarlyFragmentTests() const {
|
||||||
|
return extensions.maintenance5 &&
|
||||||
|
properties.maintenance5.earlyFragmentMultisampleCoverageAfterSampleCounting &&
|
||||||
|
properties.maintenance5.earlyFragmentSampleMaskTestBeforeSampleCounting;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the device supports VK_KHR_maintenance6.
|
||||||
|
bool IsKhrMaintenance6Supported() const {
|
||||||
|
return extensions.maintenance6;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the device supports VK_EXT_multi_draw.
|
||||||
|
bool IsExtMultiDrawSupported() const {
|
||||||
|
return extensions.multi_draw;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the device supports VK_KHR_maintenance7.
|
||||||
|
bool IsKhrMaintenance7Supported() const {
|
||||||
|
return extensions.maintenance7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the device supports VK_KHR_maintenance8.
|
||||||
|
bool IsKhrMaintenance8Supported() const {
|
||||||
|
return extensions.maintenance8;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns true if the device supports VK_KHR_maintenance9.
|
||||||
|
bool IsKhrMaintenance9Supported() const {
|
||||||
|
return extensions.maintenance9;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] static constexpr bool CheckBrokenCompute(VkDriverId driver_id,
|
[[nodiscard]] static constexpr bool CheckBrokenCompute(VkDriverId driver_id,
|
||||||
u32 driver_version) {
|
u32 driver_version) {
|
||||||
if (driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) {
|
if (driver_id == VK_DRIVER_ID_INTEL_PROPRIETARY_WINDOWS) {
|
||||||
@@ -786,6 +971,7 @@ private:
|
|||||||
FOR_EACH_VK_FEATURE_1_1(FEATURE);
|
FOR_EACH_VK_FEATURE_1_1(FEATURE);
|
||||||
FOR_EACH_VK_FEATURE_1_2(FEATURE);
|
FOR_EACH_VK_FEATURE_1_2(FEATURE);
|
||||||
FOR_EACH_VK_FEATURE_1_3(FEATURE);
|
FOR_EACH_VK_FEATURE_1_3(FEATURE);
|
||||||
|
FOR_EACH_VK_FEATURE_1_4(FEATURE);
|
||||||
FOR_EACH_VK_FEATURE_EXT(FEATURE);
|
FOR_EACH_VK_FEATURE_EXT(FEATURE);
|
||||||
FOR_EACH_VK_EXTENSION(EXTENSION);
|
FOR_EACH_VK_EXTENSION(EXTENSION);
|
||||||
|
|
||||||
@@ -802,6 +988,7 @@ private:
|
|||||||
FOR_EACH_VK_FEATURE_1_1(FEATURE_CORE);
|
FOR_EACH_VK_FEATURE_1_1(FEATURE_CORE);
|
||||||
FOR_EACH_VK_FEATURE_1_2(FEATURE_CORE);
|
FOR_EACH_VK_FEATURE_1_2(FEATURE_CORE);
|
||||||
FOR_EACH_VK_FEATURE_1_3(FEATURE_CORE);
|
FOR_EACH_VK_FEATURE_1_3(FEATURE_CORE);
|
||||||
|
FOR_EACH_VK_FEATURE_1_4(FEATURE_CORE);
|
||||||
FOR_EACH_VK_FEATURE_EXT(FEATURE_EXT);
|
FOR_EACH_VK_FEATURE_EXT(FEATURE_EXT);
|
||||||
|
|
||||||
#undef FEATURE_CORE
|
#undef FEATURE_CORE
|
||||||
@@ -817,6 +1004,8 @@ private:
|
|||||||
VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor{};
|
VkPhysicalDevicePushDescriptorPropertiesKHR push_descriptor{};
|
||||||
VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{};
|
VkPhysicalDeviceSubgroupSizeControlProperties subgroup_size_control{};
|
||||||
VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback{};
|
VkPhysicalDeviceTransformFeedbackPropertiesEXT transform_feedback{};
|
||||||
|
VkPhysicalDeviceMaintenance5PropertiesKHR maintenance5{};
|
||||||
|
VkPhysicalDeviceMultiDrawPropertiesEXT multi_draw{};
|
||||||
|
|
||||||
VkPhysicalDeviceProperties properties{};
|
VkPhysicalDeviceProperties properties{};
|
||||||
};
|
};
|
||||||
@@ -846,8 +1035,15 @@ private:
|
|||||||
bool cant_blit_msaa{}; ///< Does not support MSAA<->MSAA blitting.
|
bool cant_blit_msaa{}; ///< Does not support MSAA<->MSAA blitting.
|
||||||
bool must_emulate_scaled_formats{}; ///< Requires scaled vertex format emulation
|
bool must_emulate_scaled_formats{}; ///< Requires scaled vertex format emulation
|
||||||
bool must_emulate_bgr565{}; ///< Emulates BGR565 by swizzling RGB565 format.
|
bool must_emulate_bgr565{}; ///< Emulates BGR565 by swizzling RGB565 format.
|
||||||
bool dynamic_state3_blending{}; ///< Has all blending features of dynamic_state3.
|
bool dynamic_state3_blending{}; ///< Has blending features of dynamic_state3.
|
||||||
bool dynamic_state3_enables{}; ///< Has all enables features of dynamic_state3.
|
bool dynamic_state3_enables{}; ///< Has at least one enable feature of dynamic_state3.
|
||||||
|
bool dynamic_state3_depth_clamp_enable{};
|
||||||
|
bool dynamic_state3_logic_op_enable{};
|
||||||
|
bool dynamic_state3_line_raster_mode{};
|
||||||
|
bool dynamic_state3_conservative_raster_mode{};
|
||||||
|
bool dynamic_state3_line_stipple_enable{};
|
||||||
|
bool dynamic_state3_alpha_to_coverage{};
|
||||||
|
bool dynamic_state3_alpha_to_one{};
|
||||||
bool supports_conditional_barriers{}; ///< Allows barriers in conditional control flow.
|
bool supports_conditional_barriers{}; ///< Allows barriers in conditional control flow.
|
||||||
u64 device_access_memory{}; ///< Total size of device local memory in bytes.
|
u64 device_access_memory{}; ///< Total size of device local memory in bytes.
|
||||||
u32 sets_per_pool{}; ///< Sets per Description Pool
|
u32 sets_per_pool{}; ///< Sets per Description Pool
|
||||||
|
|||||||
@@ -87,6 +87,11 @@ namespace {
|
|||||||
AreExtensionsSupported(dld, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME})) {
|
AreExtensionsSupported(dld, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME})) {
|
||||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||||
}
|
}
|
||||||
|
// VK_EXT_surface_maintenance1 is required for VK_EXT_swapchain_maintenance1
|
||||||
|
if (window_type != Core::Frontend::WindowSystemType::Headless &&
|
||||||
|
AreExtensionsSupported(dld, std::array{VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME})) {
|
||||||
|
extensions.push_back(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME);
|
||||||
|
}
|
||||||
return extensions;
|
return extensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -116,6 +116,8 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
|
|||||||
X(vkCmdDrawIndirectCount);
|
X(vkCmdDrawIndirectCount);
|
||||||
X(vkCmdDrawIndexedIndirectCount);
|
X(vkCmdDrawIndexedIndirectCount);
|
||||||
X(vkCmdDrawIndirectByteCountEXT);
|
X(vkCmdDrawIndirectByteCountEXT);
|
||||||
|
X(vkCmdDrawMultiEXT);
|
||||||
|
X(vkCmdDrawMultiIndexedEXT);
|
||||||
X(vkCmdEndConditionalRenderingEXT);
|
X(vkCmdEndConditionalRenderingEXT);
|
||||||
X(vkCmdEndQuery);
|
X(vkCmdEndQuery);
|
||||||
X(vkCmdEndRenderPass);
|
X(vkCmdEndRenderPass);
|
||||||
@@ -145,6 +147,8 @@ void Load(VkDevice device, DeviceDispatch& dld) noexcept {
|
|||||||
X(vkCmdSetDepthWriteEnableEXT);
|
X(vkCmdSetDepthWriteEnableEXT);
|
||||||
X(vkCmdSetPrimitiveRestartEnableEXT);
|
X(vkCmdSetPrimitiveRestartEnableEXT);
|
||||||
X(vkCmdSetRasterizerDiscardEnableEXT);
|
X(vkCmdSetRasterizerDiscardEnableEXT);
|
||||||
|
X(vkCmdSetAlphaToCoverageEnableEXT);
|
||||||
|
X(vkCmdSetAlphaToOneEnableEXT);
|
||||||
X(vkCmdSetConservativeRasterizationModeEXT);
|
X(vkCmdSetConservativeRasterizationModeEXT);
|
||||||
X(vkCmdSetLineRasterizationModeEXT);
|
X(vkCmdSetLineRasterizationModeEXT);
|
||||||
X(vkCmdSetLineStippleEnableEXT);
|
X(vkCmdSetLineStippleEnableEXT);
|
||||||
|
|||||||
@@ -216,6 +216,8 @@ struct DeviceDispatch : InstanceDispatch {
|
|||||||
PFN_vkCmdDrawIndirectCount vkCmdDrawIndirectCount{};
|
PFN_vkCmdDrawIndirectCount vkCmdDrawIndirectCount{};
|
||||||
PFN_vkCmdDrawIndexedIndirectCount vkCmdDrawIndexedIndirectCount{};
|
PFN_vkCmdDrawIndexedIndirectCount vkCmdDrawIndexedIndirectCount{};
|
||||||
PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT{};
|
PFN_vkCmdDrawIndirectByteCountEXT vkCmdDrawIndirectByteCountEXT{};
|
||||||
|
PFN_vkCmdDrawMultiEXT vkCmdDrawMultiEXT{};
|
||||||
|
PFN_vkCmdDrawMultiIndexedEXT vkCmdDrawMultiIndexedEXT{};
|
||||||
PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT{};
|
PFN_vkCmdEndConditionalRenderingEXT vkCmdEndConditionalRenderingEXT{};
|
||||||
PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT{};
|
PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT{};
|
||||||
PFN_vkCmdEndQuery vkCmdEndQuery{};
|
PFN_vkCmdEndQuery vkCmdEndQuery{};
|
||||||
@@ -238,6 +240,8 @@ struct DeviceDispatch : InstanceDispatch {
|
|||||||
PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT{};
|
PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT{};
|
||||||
PFN_vkCmdSetPrimitiveRestartEnableEXT vkCmdSetPrimitiveRestartEnableEXT{};
|
PFN_vkCmdSetPrimitiveRestartEnableEXT vkCmdSetPrimitiveRestartEnableEXT{};
|
||||||
PFN_vkCmdSetRasterizerDiscardEnableEXT vkCmdSetRasterizerDiscardEnableEXT{};
|
PFN_vkCmdSetRasterizerDiscardEnableEXT vkCmdSetRasterizerDiscardEnableEXT{};
|
||||||
|
PFN_vkCmdSetAlphaToCoverageEnableEXT vkCmdSetAlphaToCoverageEnableEXT{};
|
||||||
|
PFN_vkCmdSetAlphaToOneEnableEXT vkCmdSetAlphaToOneEnableEXT{};
|
||||||
PFN_vkCmdSetConservativeRasterizationModeEXT vkCmdSetConservativeRasterizationModeEXT{};
|
PFN_vkCmdSetConservativeRasterizationModeEXT vkCmdSetConservativeRasterizationModeEXT{};
|
||||||
PFN_vkCmdSetLineRasterizationModeEXT vkCmdSetLineRasterizationModeEXT{};
|
PFN_vkCmdSetLineRasterizationModeEXT vkCmdSetLineRasterizationModeEXT{};
|
||||||
PFN_vkCmdSetLineStippleEnableEXT vkCmdSetLineStippleEnableEXT{};
|
PFN_vkCmdSetLineStippleEnableEXT vkCmdSetLineStippleEnableEXT{};
|
||||||
@@ -1239,6 +1243,19 @@ public:
|
|||||||
counter_buffer_offset, counter_offset, stride);
|
counter_buffer_offset, counter_offset, stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DrawMultiEXT(u32 draw_count, const VkMultiDrawInfoEXT* vertex_info,
|
||||||
|
u32 instance_count, u32 first_instance, u32 stride) const noexcept {
|
||||||
|
dld->vkCmdDrawMultiEXT(handle, draw_count, vertex_info, instance_count, first_instance,
|
||||||
|
stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DrawMultiIndexedEXT(u32 draw_count, const VkMultiDrawIndexedInfoEXT* index_info,
|
||||||
|
u32 instance_count, u32 first_instance, u32 stride,
|
||||||
|
const int32_t* vertex_offset) const noexcept {
|
||||||
|
dld->vkCmdDrawMultiIndexedEXT(handle, draw_count, index_info, instance_count,
|
||||||
|
first_instance, stride, vertex_offset);
|
||||||
|
}
|
||||||
|
|
||||||
void ClearAttachments(Span<VkClearAttachment> attachments,
|
void ClearAttachments(Span<VkClearAttachment> attachments,
|
||||||
Span<VkClearRect> rects) const noexcept {
|
Span<VkClearRect> rects) const noexcept {
|
||||||
dld->vkCmdClearAttachments(handle, attachments.size(), attachments.data(), rects.size(),
|
dld->vkCmdClearAttachments(handle, attachments.size(), attachments.data(), rects.size(),
|
||||||
@@ -1471,6 +1488,14 @@ public:
|
|||||||
dld->vkCmdSetLogicOpEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
|
dld->vkCmdSetLogicOpEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SetAlphaToCoverageEnableEXT(bool enable) const noexcept {
|
||||||
|
dld->vkCmdSetAlphaToCoverageEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SetAlphaToOneEnableEXT(bool enable) const noexcept {
|
||||||
|
dld->vkCmdSetAlphaToOneEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
void SetDepthClampEnableEXT(bool enable) const noexcept {
|
void SetDepthClampEnableEXT(bool enable) const noexcept {
|
||||||
dld->vkCmdSetDepthClampEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
|
dld->vkCmdSetDepthClampEnableEXT(handle, enable ? VK_TRUE : VK_FALSE);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user