mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-08-14 04:24:31 +00:00
Compare commits
17 Commits
v0.2.1
...
vulkanasync
| Author | SHA1 | Date | |
|---|---|---|---|
| 699d35f8a6 | |||
| 93237dec5e | |||
| ec9e32fdcd | |||
| 769a4c043a | |||
| 53dd313ee5 | |||
| 8553e7e7de | |||
| e3adea7826 | |||
| c0d1438862 | |||
| b3d4dbca60 | |||
| 477157d029 | |||
| 16bdb64ec9 | |||
| d565a250b6 | |||
| 354c5efde6 | |||
| 6e17a47120 | |||
| 90b312617b | |||
| 86bb14bcd8 | |||
| 63db10763d |
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
@@ -352,7 +352,8 @@ void BufferCache<P>::UpdateComputeBuffers() {
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::BindHostGeometryBuffers(bool is_indexed) {
|
||||
void BufferCache<P>::BindHostGeometryBuffers(bool is_indexed, bool use_dynamic_vertex_input,
|
||||
vk::CommandBufferPtr cmd) {
|
||||
if (is_indexed) {
|
||||
BindHostIndexBuffer();
|
||||
} else if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
|
||||
@@ -363,7 +364,7 @@ void BufferCache<P>::BindHostGeometryBuffers(bool is_indexed) {
|
||||
draw_state.vertex_buffer.count);
|
||||
}
|
||||
}
|
||||
BindHostVertexBuffers();
|
||||
BindHostVertexBuffers(use_dynamic_vertex_input, cmd);
|
||||
BindHostTransformFeedbackBuffers();
|
||||
if (current_draw_indirect) {
|
||||
BindHostDrawIndirectBuffers();
|
||||
@@ -764,7 +765,7 @@ void BufferCache<P>::BindHostIndexBuffer() {
|
||||
}
|
||||
|
||||
template <class P>
|
||||
void BufferCache<P>::BindHostVertexBuffers() {
|
||||
void BufferCache<P>::BindHostVertexBuffers(bool use_dynamic_vertex_input, vk::CommandBufferPtr cmd) {
|
||||
HostBindings<typename P::Buffer> host_bindings;
|
||||
bool any_valid{false};
|
||||
auto& flags = maxwell3d->dirty.flags;
|
||||
@@ -800,7 +801,7 @@ void BufferCache<P>::BindHostVertexBuffers() {
|
||||
host_bindings.sizes.push_back(binding.size);
|
||||
host_bindings.strides.push_back(stride);
|
||||
}
|
||||
runtime.BindVertexBuffers(host_bindings);
|
||||
runtime.BindVertexBuffers(host_bindings, use_dynamic_vertex_input, cmd);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
||||
@@ -38,6 +38,10 @@
|
||||
|
||||
namespace VideoCommon {
|
||||
|
||||
namespace vk {
|
||||
using CommandBufferPtr = void*;
|
||||
}
|
||||
|
||||
using BufferId = Common::SlotId;
|
||||
|
||||
using VideoCore::Surface::PixelFormat;
|
||||
@@ -232,7 +236,8 @@ public:
|
||||
|
||||
void UpdateComputeBuffers();
|
||||
|
||||
void BindHostGeometryBuffers(bool is_indexed);
|
||||
void BindHostGeometryBuffers(bool is_indexed, bool use_dynamic_vertex_input = false,
|
||||
vk::CommandBuffer* cmd = nullptr);
|
||||
|
||||
void BindHostStageBuffers(size_t stage);
|
||||
|
||||
@@ -358,7 +363,7 @@ private:
|
||||
|
||||
void BindHostIndexBuffer();
|
||||
|
||||
void BindHostVertexBuffers();
|
||||
void BindHostVertexBuffers(bool use_dynamic_vertex_input = false, vk::CommandBuffer* cmd = nullptr);
|
||||
|
||||
void BindHostDrawIndirectBuffers();
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
@@ -242,7 +242,8 @@ void BufferCacheRuntime::BindVertexBuffer(u32 index, Buffer& buffer, u32 offset,
|
||||
}
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings) {
|
||||
void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings,
|
||||
bool /*use_dynamic_vertex_input*/) {
|
||||
// TODO: Should HostBindings provide the correct runtime types to avoid these transforms?
|
||||
std::array<GLuint, 32> buffer_handles;
|
||||
std::array<GLsizei, 32> buffer_strides;
|
||||
@@ -271,6 +272,13 @@ void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bi
|
||||
}
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings,
|
||||
bool use_dynamic_vertex_input,
|
||||
VideoCommon::vk::CommandBufferPtr /*cmd*/) {
|
||||
// Forward to the existing implementation; OpenGL doesn't use Vulkan command buffers.
|
||||
BindVertexBuffers(bindings, use_dynamic_vertex_input);
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer,
|
||||
u32 offset, u32 size) {
|
||||
if (use_assembly_shaders) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
@@ -101,7 +101,13 @@ public:
|
||||
|
||||
void BindVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size, u32 stride);
|
||||
|
||||
void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings);
|
||||
void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings,
|
||||
bool use_dynamic_vertex_input = false);
|
||||
|
||||
// Compatibility overload to allow code that provides an optional Vulkan command buffer
|
||||
// pointer to compile for OpenGL. The pointer is ignored for OpenGL runtime.
|
||||
void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings,
|
||||
bool use_dynamic_vertex_input, VideoCommon::vk::CommandBufferPtr cmd);
|
||||
|
||||
void BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer, u32 offset, u32 size);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
@@ -436,7 +436,7 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
bind_stage_info(4);
|
||||
}
|
||||
buffer_cache.UpdateGraphicsBuffers(is_indexed);
|
||||
buffer_cache.BindHostGeometryBuffers(is_indexed);
|
||||
buffer_cache.BindHostGeometryBuffers(is_indexed, false);
|
||||
|
||||
if (!IsBuilt()) {
|
||||
WaitForBuild();
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
||||
|
||||
@@ -761,10 +762,25 @@ void BlitImageHelper::ClearDepthStencil(const Framebuffer* dst_framebuffer, bool
|
||||
const VkPipeline pipeline = FindOrEmplaceClearStencilPipeline(key);
|
||||
const VkPipelineLayout layout = *clear_color_pipeline_layout;
|
||||
scheduler.RequestRenderpass(dst_framebuffer);
|
||||
scheduler.Record([pipeline, layout, clear_depth, dst_region](vk::CommandBuffer cmdbuf) {
|
||||
const bool dyn_stencil_compare = device.SupportsDynamicStateStencilCompareMask();
|
||||
const bool dyn_stencil_write = device.SupportsDynamicStateStencilWriteMask();
|
||||
const bool dyn_stencil_ref = device.SupportsDynamicStateStencilReference();
|
||||
|
||||
scheduler.Record([pipeline, layout, clear_depth, dst_region, stencil_mask, stencil_ref,
|
||||
stencil_compare_mask, dyn_stencil_compare, dyn_stencil_write,
|
||||
dyn_stencil_ref](vk::CommandBuffer cmdbuf) {
|
||||
constexpr std::array blend_constants{0.0f, 0.0f, 0.0f, 0.0f};
|
||||
cmdbuf.SetBlendConstants(blend_constants.data());
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline);
|
||||
if (dyn_stencil_compare) {
|
||||
cmdbuf.SetStencilCompareMask(VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT, stencil_compare_mask);
|
||||
}
|
||||
if (dyn_stencil_write) {
|
||||
cmdbuf.SetStencilWriteMask(VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT, stencil_mask);
|
||||
}
|
||||
if (dyn_stencil_ref) {
|
||||
cmdbuf.SetStencilReference(VK_STENCIL_FACE_FRONT_BIT | VK_STENCIL_FACE_BACK_BIT, stencil_ref);
|
||||
}
|
||||
BindBlitState(cmdbuf, dst_region);
|
||||
cmdbuf.PushConstants(layout, VK_SHADER_STAGE_FRAGMENT_BIT, clear_depth);
|
||||
cmdbuf.Draw(3, 1, 0, 0);
|
||||
@@ -1010,14 +1026,19 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
|
||||
}
|
||||
clear_stencil_keys.push_back(key);
|
||||
const std::array stages = MakeStages(*clear_color_vert, *clear_stencil_frag);
|
||||
// Allow using dynamic stencil masks if the device supports them.
|
||||
const bool dyn_stencil_compare = device.SupportsDynamicStateStencilCompareMask();
|
||||
const bool dyn_stencil_write = device.SupportsDynamicStateStencilWriteMask();
|
||||
const bool dyn_stencil_ref = device.SupportsDynamicStateStencilReference();
|
||||
|
||||
const auto stencil = VkStencilOpState{
|
||||
.failOp = VK_STENCIL_OP_KEEP,
|
||||
.passOp = VK_STENCIL_OP_REPLACE,
|
||||
.depthFailOp = VK_STENCIL_OP_KEEP,
|
||||
.compareOp = VK_COMPARE_OP_ALWAYS,
|
||||
.compareMask = key.stencil_compare_mask,
|
||||
.writeMask = key.stencil_mask,
|
||||
.reference = key.stencil_ref,
|
||||
.compareMask = dyn_stencil_compare ? 0u : key.stencil_compare_mask,
|
||||
.writeMask = dyn_stencil_write ? 0u : key.stencil_mask,
|
||||
.reference = dyn_stencil_ref ? 0u : key.stencil_ref,
|
||||
};
|
||||
const VkPipelineDepthStencilStateCreateInfo depth_stencil_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,
|
||||
@@ -1034,6 +1055,29 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
|
||||
.maxDepthBounds = 0.0f,
|
||||
};
|
||||
const VkPipelineInputAssemblyStateCreateInfo input_assembly_ci = GetPipelineInputAssemblyStateCreateInfo(device);
|
||||
|
||||
// Build dynamic state list for this pipeline (base + optional stencil/linewidth)
|
||||
std::vector<VkDynamicState> dyn_states(DYNAMIC_STATES.begin(), DYNAMIC_STATES.end());
|
||||
if (device.SupportsDynamicStateLineWidth()) {
|
||||
dyn_states.push_back(VK_DYNAMIC_STATE_LINE_WIDTH);
|
||||
}
|
||||
if (dyn_stencil_compare) {
|
||||
dyn_states.push_back(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK);
|
||||
}
|
||||
if (dyn_stencil_write) {
|
||||
dyn_states.push_back(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK);
|
||||
}
|
||||
if (dyn_stencil_ref) {
|
||||
dyn_states.push_back(VK_DYNAMIC_STATE_STENCIL_REFERENCE);
|
||||
}
|
||||
const VkPipelineDynamicStateCreateInfo dynamic_state_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
.flags = 0,
|
||||
.dynamicStateCount = static_cast<u32>(dyn_states.size()),
|
||||
.pDynamicStates = dyn_states.data(),
|
||||
};
|
||||
|
||||
clear_stencil_pipelines.push_back(device.GetLogical().CreateGraphicsPipeline({
|
||||
.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
@@ -1048,7 +1092,7 @@ VkPipeline BlitImageHelper::FindOrEmplaceClearStencilPipeline(
|
||||
.pMultisampleState = &PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,
|
||||
.pDepthStencilState = &depth_stencil_ci,
|
||||
.pColorBlendState = &PIPELINE_COLOR_BLEND_STATE_GENERIC_CREATE_INFO,
|
||||
.pDynamicState = &PIPELINE_DYNAMIC_STATE_CREATE_INFO,
|
||||
.pDynamicState = &dynamic_state_ci,
|
||||
.layout = *clear_color_pipeline_layout,
|
||||
.renderPass = key.renderpass,
|
||||
.subpass = 0,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -171,6 +171,15 @@ void FixedPipelineState::Refresh(Tegra::Engines::Maxwell3D& maxwell3d, DynamicFe
|
||||
if (!extended_dynamic_state_3_enables) {
|
||||
dynamic_state.Refresh3(regs);
|
||||
}
|
||||
if (features.has_depth_bounds) {
|
||||
depth_bounds_min = 0;
|
||||
depth_bounds_max = 0;
|
||||
dynamic_state.depth_bounds_enable.Assign(0);
|
||||
}
|
||||
|
||||
if (features.has_depth_bias) {
|
||||
dynamic_state.depth_bias_enable.Assign(0);
|
||||
}
|
||||
if (xfb_enabled) {
|
||||
RefreshXfbState(xfb_state, regs);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -21,6 +21,15 @@ namespace Vulkan {
|
||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||
|
||||
struct DynamicFeatures {
|
||||
bool has_viewport;
|
||||
bool has_scissor;
|
||||
bool has_depth_bias;
|
||||
bool has_blend_constants;
|
||||
bool has_depth_bounds;
|
||||
bool has_stencil_compare_mask;
|
||||
bool has_stencil_write_mask;
|
||||
bool has_stencil_reference;
|
||||
bool has_line_width;
|
||||
bool has_extended_dynamic_state;
|
||||
bool has_extended_dynamic_state_2;
|
||||
bool has_extended_dynamic_state_2_logic_op;
|
||||
@@ -260,6 +269,9 @@ struct FixedPipelineState {
|
||||
// When transform feedback is enabled, use the whole struct
|
||||
return sizeof(*this);
|
||||
}
|
||||
if (extended_dynamic_state_3_blend) {
|
||||
return offsetof(FixedPipelineState, attachments);
|
||||
}
|
||||
if (dynamic_vertex_input && extended_dynamic_state_3_blend) {
|
||||
// Exclude dynamic state and attributes
|
||||
return offsetof(FixedPipelineState, dynamic_state);
|
||||
@@ -268,6 +280,9 @@ struct FixedPipelineState {
|
||||
// Exclude dynamic state
|
||||
return offsetof(FixedPipelineState, attributes);
|
||||
}
|
||||
if (extended_dynamic_state_3_enables) {
|
||||
return offsetof(FixedPipelineState, dynamic_state);
|
||||
}
|
||||
if (extended_dynamic_state) {
|
||||
// Exclude dynamic state
|
||||
return offsetof(FixedPipelineState, vertex_strides);
|
||||
|
||||
@@ -551,30 +551,46 @@ void BufferCacheRuntime::BindQuadIndexBuffer(PrimitiveTopology topology, u32 fir
|
||||
}
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size, u32 stride) {
|
||||
void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size, u32 stride,
|
||||
bool use_dynamic_vertex_input, VideoCommon::vk::CommandBufferPtr cmd) {
|
||||
if (index >= device.GetMaxVertexInputBindings()) {
|
||||
return;
|
||||
}
|
||||
if (device.IsExtExtendedDynamicStateSupported()) {
|
||||
scheduler.Record([index, buffer, offset, size, stride](vk::CommandBuffer cmdbuf) {
|
||||
if (use_dynamic_vertex_input && device.IsExtExtendedDynamicStateSupported()) {
|
||||
if (cmd) {
|
||||
auto cmdbuf = static_cast<vk::CommandBuffer*>(cmd);
|
||||
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_stride = stride;
|
||||
cmdbuf.BindVertexBuffers2EXT(index, 1, &buffer, &vk_offset, &vk_size, &vk_stride);
|
||||
});
|
||||
cmdbuf->BindVertexBuffers2EXT(index, 1, &buffer, &vk_offset, &vk_size, &vk_stride);
|
||||
} else {
|
||||
scheduler.Record([index, buffer, offset, size, stride](vk::CommandBuffer cmdbuf) {
|
||||
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_stride = stride;
|
||||
cmdbuf.BindVertexBuffers2EXT(index, 1, &buffer, &vk_offset, &vk_size, &vk_stride);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
if (!device.HasNullDescriptor() && buffer == VK_NULL_HANDLE) {
|
||||
ReserveNullBuffer();
|
||||
buffer = *null_buffer;
|
||||
offset = 0;
|
||||
}
|
||||
scheduler.Record([index, buffer, offset](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.BindVertexBuffer(index, buffer, offset);
|
||||
});
|
||||
if (cmd) {
|
||||
auto cmdbuf = static_cast<vk::CommandBuffer*>(cmd);
|
||||
cmdbuf->BindVertexBuffer(index, buffer, offset);
|
||||
} else {
|
||||
scheduler.Record([index, buffer, offset](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.BindVertexBuffer(index, buffer, offset);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings) {
|
||||
void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings,
|
||||
bool use_dynamic_vertex_input,
|
||||
VideoCommon::vk::CommandBufferPtr cmd) {
|
||||
boost::container::small_vector<VkBuffer, 32> buffer_handles;
|
||||
for (u32 index = 0; index < bindings.buffers.size(); ++index) {
|
||||
auto handle = bindings.buffers[index]->Handle();
|
||||
@@ -595,21 +611,34 @@ void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bi
|
||||
if (binding_count == 0) {
|
||||
return;
|
||||
}
|
||||
if (device.IsExtExtendedDynamicStateSupported()) {
|
||||
scheduler.Record([bindings_ = std::move(bindings),
|
||||
buffer_handles_ = std::move(buffer_handles),
|
||||
binding_count](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.BindVertexBuffers2EXT(bindings_.min_index, binding_count, buffer_handles_.data(),
|
||||
bindings_.offsets.data(), bindings_.sizes.data(),
|
||||
bindings_.strides.data());
|
||||
});
|
||||
if (use_dynamic_vertex_input && device.IsExtExtendedDynamicStateSupported()) {
|
||||
if (cmd) {
|
||||
auto cmdbuf = static_cast<vk::CommandBuffer*>(cmd);
|
||||
cmdbuf->BindVertexBuffers2EXT(bindings.min_index, binding_count, buffer_handles.data(),
|
||||
bindings.offsets.data(), bindings.sizes.data(),
|
||||
bindings.strides.data());
|
||||
} else {
|
||||
scheduler.Record([
|
||||
bindings_ = std::move(bindings), buffer_handles_ = std::move(buffer_handles),
|
||||
binding_count](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.BindVertexBuffers2EXT(bindings_.min_index, binding_count,
|
||||
buffer_handles_.data(), bindings_.offsets.data(),
|
||||
bindings_.sizes.data(), bindings_.strides.data());
|
||||
});
|
||||
}
|
||||
} else {
|
||||
scheduler.Record([bindings_ = std::move(bindings),
|
||||
buffer_handles_ = std::move(buffer_handles),
|
||||
binding_count](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.BindVertexBuffers(bindings_.min_index, binding_count, buffer_handles_.data(),
|
||||
bindings_.offsets.data());
|
||||
});
|
||||
if (cmd) {
|
||||
auto cmdbuf = static_cast<vk::CommandBuffer*>(cmd);
|
||||
cmdbuf->BindVertexBuffers(bindings.min_index, binding_count, buffer_handles.data(),
|
||||
bindings.offsets.data());
|
||||
} else {
|
||||
scheduler.Record([
|
||||
bindings_ = std::move(bindings), buffer_handles_ = std::move(buffer_handles),
|
||||
binding_count](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.BindVertexBuffers(bindings_.min_index, binding_count,
|
||||
buffer_handles_.data(), bindings_.offsets.data());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -123,9 +123,11 @@ public:
|
||||
|
||||
void BindQuadIndexBuffer(PrimitiveTopology topology, u32 first, u32 count);
|
||||
|
||||
void BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size, u32 stride);
|
||||
void BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size, u32 stride,
|
||||
bool use_dynamic_vertex_input, VideoCommon::vk::CommandBufferPtr cmd = nullptr);
|
||||
|
||||
void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings);
|
||||
void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings,
|
||||
bool use_dynamic_vertex_input, VideoCommon::vk::CommandBufferPtr cmd = nullptr);
|
||||
|
||||
void BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
@@ -459,7 +459,7 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
|
||||
}
|
||||
|
||||
buffer_cache.UpdateGraphicsBuffers(is_indexed);
|
||||
buffer_cache.BindHostGeometryBuffers(is_indexed);
|
||||
buffer_cache.BindHostGeometryBuffers(is_indexed, HasDynamicVertexInput());
|
||||
|
||||
guest_descriptor_queue.Acquire();
|
||||
|
||||
@@ -519,6 +519,7 @@ void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling,
|
||||
uses_render_area = render_area.uses_render_area,
|
||||
render_area_data = render_area.words](vk::CommandBuffer cmdbuf) {
|
||||
if (bind_pipeline) {
|
||||
if (pre_bind_callback) pre_bind_callback(cmdbuf);
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
|
||||
}
|
||||
cmdbuf.PushConstants(*pipeline_layout, VK_SHADER_STAGE_ALL_GRAPHICS,
|
||||
@@ -815,13 +816,35 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||
.pAttachments = cb_attachments.data(),
|
||||
.blendConstants = {}
|
||||
};
|
||||
static_vector<VkDynamicState, 34> dynamic_states{
|
||||
VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR,
|
||||
VK_DYNAMIC_STATE_DEPTH_BIAS, 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,
|
||||
VK_DYNAMIC_STATE_LINE_WIDTH,
|
||||
};
|
||||
static_vector<VkDynamicState, 34> dynamic_states;
|
||||
|
||||
if (device.SupportsDynamicStateViewport()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_VIEWPORT);
|
||||
}
|
||||
if (device.SupportsDynamicStateScissor()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_SCISSOR);
|
||||
}
|
||||
if (device.SupportsDynamicStateDepthBias()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BIAS);
|
||||
}
|
||||
if (device.SupportsDynamicStateBlendConstants()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_BLEND_CONSTANTS);
|
||||
}
|
||||
if (device.SupportsDynamicStateDepthBounds()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_DEPTH_BOUNDS);
|
||||
}
|
||||
if (device.SupportsDynamicStateStencilCompareMask()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK);
|
||||
}
|
||||
if (device.SupportsDynamicStateStencilWriteMask()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_WRITE_MASK);
|
||||
}
|
||||
if (device.SupportsDynamicStateStencilReference()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_STENCIL_REFERENCE);
|
||||
}
|
||||
if (device.SupportsDynamicStateLineWidth()) {
|
||||
dynamic_states.push_back(VK_DYNAMIC_STATE_LINE_WIDTH);
|
||||
}
|
||||
if (key.state.extended_dynamic_state) {
|
||||
static constexpr std::array extended{
|
||||
VK_DYNAMIC_STATE_CULL_MODE_EXT,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
||||
#include "video_core/renderer_vulkan/vk_texture_cache.h"
|
||||
#include "video_core/vulkan_common/vulkan_wrapper.h"
|
||||
#include <functional>
|
||||
|
||||
namespace VideoCore {
|
||||
class ShaderNotify;
|
||||
@@ -128,6 +129,9 @@ public:
|
||||
gpu_memory = gpu_memory_;
|
||||
}
|
||||
|
||||
void SetPreBindCallback(std::function<void(vk::CommandBuffer)> cb) { pre_bind_callback = std::move(cb); }
|
||||
void ClearPreBindCallback() { pre_bind_callback = {};}
|
||||
|
||||
private:
|
||||
template <typename Spec>
|
||||
bool ConfigureImpl(bool is_indexed);
|
||||
@@ -135,6 +139,8 @@ private:
|
||||
void ConfigureDraw(const RescalingPushConstant& rescaling,
|
||||
const RenderAreaPushConstant& render_are);
|
||||
|
||||
std::function<void(vk::CommandBuffer)> pre_bind_callback;
|
||||
|
||||
void MakePipeline(VkRenderPass render_pass);
|
||||
|
||||
void Validate();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -418,12 +418,24 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
|
||||
dynamic_features = {};
|
||||
|
||||
// User granularity enforced in vulkan_device.cpp switch statement:
|
||||
// Level 0: Core Dynamic States only
|
||||
// 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_viewport =
|
||||
device.SupportsDynamicStateViewport();
|
||||
dynamic_features.has_scissor =
|
||||
device.SupportsDynamicStateScissor();
|
||||
dynamic_features.has_depth_bias =
|
||||
device.SupportsDynamicStateDepthBias();
|
||||
dynamic_features.has_blend_constants =
|
||||
device.SupportsDynamicStateBlendConstants();
|
||||
dynamic_features.has_depth_bounds =
|
||||
device.SupportsDynamicStateDepthBounds();
|
||||
dynamic_features.has_stencil_compare_mask =
|
||||
device.SupportsDynamicStateStencilCompareMask();
|
||||
dynamic_features.has_stencil_write_mask =
|
||||
device.SupportsDynamicStateStencilWriteMask();
|
||||
dynamic_features.has_stencil_reference =
|
||||
device.SupportsDynamicStateStencilReference();
|
||||
dynamic_features.has_line_width =
|
||||
device.SupportsDynamicStateLineWidth();
|
||||
|
||||
dynamic_features.has_extended_dynamic_state =
|
||||
device.IsExtExtendedDynamicStateSupported();
|
||||
@@ -439,7 +451,6 @@ PipelineCache::PipelineCache(Tegra::MaxwellDeviceMemoryManager& device_memory_,
|
||||
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();
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -200,7 +200,7 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
|
||||
|
||||
// Log multi-draw support
|
||||
if (device.IsExtMultiDrawSupported()) {
|
||||
LOG_INFO(Render_Vulkan, "VK_EXT_multi_draw is enabled for optimized draw calls");
|
||||
LOG_INFO(Render_Vulkan, "VK_EXT_multi_draw is enabled for draw calls");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,11 +222,18 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
|
||||
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
|
||||
// update engine as channel may be different.
|
||||
pipeline->SetEngine(maxwell3d, gpu_memory);
|
||||
if (!pipeline->Configure(is_indexed))
|
||||
return;
|
||||
|
||||
UpdateDynamicStates();
|
||||
|
||||
pipeline->SetPreBindCallback([this, is_indexed, pipeline](vk::CommandBuffer cmdbuf) {
|
||||
RecordDynamicStates(cmdbuf);
|
||||
buffer_cache.BindHostGeometryBuffers(is_indexed, pipeline->HasDynamicVertexInput(), &cmdbuf);
|
||||
});
|
||||
SCOPE_EXIT { pipeline->ClearPreBindCallback(); };
|
||||
|
||||
if (!pipeline->Configure(is_indexed))
|
||||
return;
|
||||
|
||||
HandleTransformFeedback();
|
||||
query_cache.CounterEnable(VideoCommon::QueryType::ZPassPixelCount64,
|
||||
maxwell3d->regs.zpass_pixel_count_enable);
|
||||
@@ -1046,6 +1053,199 @@ void RasterizerVulkan::UpdateDynamicStates() {
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::RecordDynamicStates(vk::CommandBuffer cmdbuf) {
|
||||
auto& regs = maxwell3d->regs;
|
||||
|
||||
// Viewports
|
||||
if (state_tracker.TouchViewports()) {
|
||||
if (!regs.viewport_scale_offset_enabled) {
|
||||
float x = static_cast<float>(regs.surface_clip.x);
|
||||
float y = static_cast<float>(regs.surface_clip.y);
|
||||
float width = (std::max)(1.0f, static_cast<float>(regs.surface_clip.width));
|
||||
float height = (std::max)(1.0f, static_cast<float>(regs.surface_clip.height));
|
||||
if (regs.window_origin.mode != Maxwell::WindowOrigin::Mode::UpperLeft) {
|
||||
y += height;
|
||||
height = -height;
|
||||
}
|
||||
VkViewport viewport{
|
||||
.x = x,
|
||||
.y = y,
|
||||
.width = width,
|
||||
.height = height,
|
||||
.minDepth = 0.0f,
|
||||
.maxDepth = 1.0f,
|
||||
};
|
||||
if (!device.IsExtDepthRangeUnrestrictedSupported()) {
|
||||
viewport.minDepth = std::clamp(viewport.minDepth, 0.0f, 1.0f);
|
||||
viewport.maxDepth = std::clamp(viewport.maxDepth, 0.0f, 1.0f);
|
||||
}
|
||||
cmdbuf.SetViewport(0, viewport);
|
||||
} else {
|
||||
const bool is_rescaling{texture_cache.IsRescaling()};
|
||||
const float scale = is_rescaling ? Settings::values.resolution_info.up_factor : 1.0f;
|
||||
const std::array viewport_list{
|
||||
GetViewportState(device, regs, 0, scale), GetViewportState(device, regs, 1, scale),
|
||||
GetViewportState(device, regs, 2, scale), GetViewportState(device, regs, 3, scale),
|
||||
GetViewportState(device, regs, 4, scale), GetViewportState(device, regs, 5, scale),
|
||||
GetViewportState(device, regs, 6, scale), GetViewportState(device, regs, 7, scale),
|
||||
GetViewportState(device, regs, 8, scale), GetViewportState(device, regs, 9, scale),
|
||||
GetViewportState(device, regs, 10, scale), GetViewportState(device, regs, 11, scale),
|
||||
GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale),
|
||||
GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale),
|
||||
};
|
||||
const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
|
||||
const vk::Span<VkViewport> viewports(viewport_list.data(), num_viewports);
|
||||
cmdbuf.SetViewport(0, viewports);
|
||||
}
|
||||
}
|
||||
|
||||
// Scissors
|
||||
if (state_tracker.TouchScissors()) {
|
||||
if (!regs.viewport_scale_offset_enabled) {
|
||||
u32 x = regs.surface_clip.x;
|
||||
u32 y = regs.surface_clip.y;
|
||||
u32 width = (std::max)(1u, static_cast<u32>(regs.surface_clip.width));
|
||||
u32 height = (std::max)(1u, static_cast<u32>(regs.surface_clip.height));
|
||||
if (regs.window_origin.mode != Maxwell::WindowOrigin::Mode::UpperLeft) {
|
||||
y = regs.surface_clip.height - (y + height);
|
||||
}
|
||||
VkRect2D scissor{};
|
||||
scissor.offset.x = static_cast<int32_t>(x);
|
||||
scissor.offset.y = static_cast<int32_t>(y);
|
||||
scissor.extent.width = width;
|
||||
scissor.extent.height = height;
|
||||
cmdbuf.SetScissor(0, scissor);
|
||||
} else {
|
||||
u32 up_scale = 1;
|
||||
u32 down_shift = 0;
|
||||
if (texture_cache.IsRescaling()) {
|
||||
up_scale = Settings::values.resolution_info.up_scale;
|
||||
down_shift = Settings::values.resolution_info.down_shift;
|
||||
}
|
||||
const std::array scissor_list{
|
||||
GetScissorState(regs, 0, up_scale, down_shift),
|
||||
GetScissorState(regs, 1, up_scale, down_shift),
|
||||
GetScissorState(regs, 2, up_scale, down_shift),
|
||||
GetScissorState(regs, 3, up_scale, down_shift),
|
||||
GetScissorState(regs, 4, up_scale, down_shift),
|
||||
GetScissorState(regs, 5, up_scale, down_shift),
|
||||
GetScissorState(regs, 6, up_scale, down_shift),
|
||||
GetScissorState(regs, 7, up_scale, down_shift),
|
||||
GetScissorState(regs, 8, up_scale, down_shift),
|
||||
GetScissorState(regs, 9, up_scale, down_shift),
|
||||
GetScissorState(regs, 10, up_scale, down_shift),
|
||||
GetScissorState(regs, 11, up_scale, down_shift),
|
||||
GetScissorState(regs, 12, up_scale, down_shift),
|
||||
GetScissorState(regs, 13, up_scale, down_shift),
|
||||
GetScissorState(regs, 14, up_scale, down_shift),
|
||||
GetScissorState(regs, 15, up_scale, down_shift),
|
||||
};
|
||||
const u32 num_scissors = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
|
||||
const vk::Span<VkRect2D> scissors(scissor_list.data(), num_scissors);
|
||||
cmdbuf.SetScissor(0, scissors);
|
||||
}
|
||||
}
|
||||
|
||||
// Depth bias
|
||||
if (state_tracker.TouchDepthBias()) {
|
||||
float units = regs.depth_bias / 2.0f;
|
||||
const bool is_d24 = regs.zeta.format == Tegra::DepthFormat::Z24_UNORM_S8_UINT ||
|
||||
regs.zeta.format == Tegra::DepthFormat::X8Z24_UNORM ||
|
||||
regs.zeta.format == Tegra::DepthFormat::S8Z24_UNORM ||
|
||||
regs.zeta.format == Tegra::DepthFormat::V8Z24_UNORM;
|
||||
if (is_d24 && !device.SupportsD24DepthBuffer()) {
|
||||
static constexpr const size_t length = sizeof(NEEDS_D24) / sizeof(NEEDS_D24[0]);
|
||||
static constexpr const u64* start = NEEDS_D24;
|
||||
static constexpr const u64* end = NEEDS_D24 + length;
|
||||
const u64* it = std::find(start, end, program_id);
|
||||
if (it != end) {
|
||||
const double rescale_factor =
|
||||
static_cast<double>(1ULL << (32 - 24)) / (static_cast<double>(0x1.ep+127));
|
||||
units = static_cast<float>(static_cast<double>(units) * rescale_factor);
|
||||
}
|
||||
}
|
||||
if (device.IsExtDepthBiasControlSupported()) {
|
||||
static VkDepthBiasRepresentationInfoEXT bias_info{
|
||||
.sType = VK_STRUCTURE_TYPE_DEPTH_BIAS_REPRESENTATION_INFO_EXT,
|
||||
.pNext = nullptr,
|
||||
.depthBiasRepresentation =
|
||||
VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT,
|
||||
.depthBiasExact = VK_FALSE,
|
||||
};
|
||||
cmdbuf.SetDepthBias(units, regs.depth_bias_clamp, regs.slope_scale_depth_bias, &bias_info);
|
||||
} else {
|
||||
cmdbuf.SetDepthBias(units, regs.depth_bias_clamp, regs.slope_scale_depth_bias);
|
||||
}
|
||||
}
|
||||
|
||||
// Blend constants
|
||||
if (state_tracker.TouchBlendConstants()) {
|
||||
const std::array blend_color = {regs.blend_color.r, regs.blend_color.g, regs.blend_color.b,
|
||||
regs.blend_color.a};
|
||||
cmdbuf.SetBlendConstants(blend_color.data());
|
||||
}
|
||||
|
||||
// Depth bounds
|
||||
if (state_tracker.TouchDepthBounds()) {
|
||||
cmdbuf.SetDepthBounds(regs.depth_bounds[0], regs.depth_bounds[1]);
|
||||
}
|
||||
|
||||
// Stencil faces
|
||||
if (state_tracker.TouchStencilProperties()) {
|
||||
UpdateStencilOp(regs, &cmdbuf);
|
||||
UpdateStencilTestEnable(regs, &cmdbuf);
|
||||
}
|
||||
|
||||
// Line width
|
||||
if (state_tracker.TouchLineWidth()) {
|
||||
UpdateLineWidth(regs, &cmdbuf);
|
||||
}
|
||||
|
||||
// Extended Dynamic State (a subset) - call existing helpers but target cmdbuf where appropriate
|
||||
if (device.IsExtExtendedDynamicStateSupported()) {
|
||||
UpdateCullMode(regs, &cmdbuf);
|
||||
UpdateDepthCompareOp(regs, &cmdbuf);
|
||||
UpdateFrontFace(regs, &cmdbuf);
|
||||
UpdateStencilOp(regs, &cmdbuf);
|
||||
if (state_tracker.TouchStateEnable()) {
|
||||
UpdateDepthBoundsTestEnable(regs, &cmdbuf);
|
||||
UpdateDepthTestEnable(regs, &cmdbuf);
|
||||
UpdateDepthWriteEnable(regs, &cmdbuf);
|
||||
UpdateStencilTestEnable(regs, &cmdbuf);
|
||||
}
|
||||
}
|
||||
|
||||
if (device.IsExtExtendedDynamicState2Supported()) {
|
||||
UpdatePrimitiveRestartEnable(regs, &cmdbuf);
|
||||
UpdateRasterizerDiscardEnable(regs, &cmdbuf);
|
||||
UpdateDepthBiasEnable(regs, &cmdbuf);
|
||||
}
|
||||
|
||||
if (device.IsExtExtendedDynamicState2ExtrasSupported()) {
|
||||
UpdateLogicOp(regs, &cmdbuf);
|
||||
}
|
||||
|
||||
if (device.IsExtExtendedDynamicState3EnablesSupported()) {
|
||||
UpdateLogicOpEnable(regs, &cmdbuf);
|
||||
UpdateDepthClampEnable(regs, &cmdbuf);
|
||||
UpdateLineRasterizationMode(regs, &cmdbuf);
|
||||
UpdateLineStippleEnable(regs, &cmdbuf);
|
||||
UpdateConservativeRasterizationMode(regs, &cmdbuf);
|
||||
UpdateAlphaToCoverageEnable(regs, &cmdbuf);
|
||||
UpdateAlphaToOneEnable(regs, &cmdbuf);
|
||||
}
|
||||
|
||||
if (device.IsExtExtendedDynamicState3BlendingSupported()) {
|
||||
UpdateBlending(regs, &cmdbuf);
|
||||
}
|
||||
|
||||
if (device.IsExtVertexInputDynamicStateSupported()) {
|
||||
if (auto* gp = pipeline_cache.CurrentGraphicsPipeline(); gp && gp->HasDynamicVertexInput()) {
|
||||
UpdateVertexInput(regs, &cmdbuf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::HandleTransformFeedback() {
|
||||
static std::once_flag warn_unsupported;
|
||||
|
||||
@@ -1071,7 +1271,7 @@ void RasterizerVulkan::HandleTransformFeedback() {
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchViewports()) {
|
||||
return;
|
||||
}
|
||||
@@ -1092,9 +1292,11 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
|
||||
.minDepth = 0.0f,
|
||||
.maxDepth = 1.0f,
|
||||
};
|
||||
scheduler.Record([viewport](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetViewport(0, viewport);
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetViewport(0, viewport);
|
||||
} else {
|
||||
scheduler.Record([viewport](vk::CommandBuffer cmdbuf) { cmdbuf.SetViewport(0, viewport); });
|
||||
}
|
||||
return;
|
||||
}
|
||||
const bool is_rescaling{texture_cache.IsRescaling()};
|
||||
@@ -1109,14 +1311,20 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
|
||||
GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale),
|
||||
GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale),
|
||||
};
|
||||
scheduler.Record([this, viewport_list](vk::CommandBuffer cmdbuf) {
|
||||
if (cmd) {
|
||||
const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
|
||||
const vk::Span<VkViewport> viewports(viewport_list.data(), num_viewports);
|
||||
cmdbuf.SetViewport(0, viewports);
|
||||
});
|
||||
cmd->SetViewport(0, viewports);
|
||||
} else {
|
||||
scheduler.Record([this, viewport_list](vk::CommandBuffer cmdbuf) {
|
||||
const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
|
||||
const vk::Span<VkViewport> viewports(viewport_list.data(), num_viewports);
|
||||
cmdbuf.SetViewport(0, viewports);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchScissors()) {
|
||||
return;
|
||||
}
|
||||
@@ -1133,9 +1341,11 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
|
||||
scissor.offset.y = static_cast<int32_t>(y);
|
||||
scissor.extent.width = width;
|
||||
scissor.extent.height = height;
|
||||
scheduler.Record([scissor](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetScissor(0, scissor);
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetScissor(0, scissor);
|
||||
} else {
|
||||
scheduler.Record([scissor](vk::CommandBuffer cmdbuf) { cmdbuf.SetScissor(0, scissor); });
|
||||
}
|
||||
return;
|
||||
}
|
||||
u32 up_scale = 1;
|
||||
@@ -1162,14 +1372,20 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
|
||||
GetScissorState(regs, 14, up_scale, down_shift),
|
||||
GetScissorState(regs, 15, up_scale, down_shift),
|
||||
};
|
||||
scheduler.Record([this, scissor_list](vk::CommandBuffer cmdbuf) {
|
||||
if (cmd) {
|
||||
const u32 num_scissors = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
|
||||
const vk::Span<VkRect2D> scissors(scissor_list.data(), num_scissors);
|
||||
cmdbuf.SetScissor(0, scissors);
|
||||
});
|
||||
cmd->SetScissor(0, scissors);
|
||||
} else {
|
||||
scheduler.Record([this, scissor_list](vk::CommandBuffer cmdbuf) {
|
||||
const u32 num_scissors = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
|
||||
const vk::Span<VkRect2D> scissors(scissor_list.data(), num_scissors);
|
||||
cmdbuf.SetScissor(0, scissors);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchDepthBias()) {
|
||||
return;
|
||||
}
|
||||
@@ -1196,8 +1412,7 @@ void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
}
|
||||
}
|
||||
|
||||
scheduler.Record([constant = units, clamp = regs.depth_bias_clamp,
|
||||
factor = regs.slope_scale_depth_bias, this](vk::CommandBuffer cmdbuf) {
|
||||
if (cmd) {
|
||||
if (device.IsExtDepthBiasControlSupported()) {
|
||||
static VkDepthBiasRepresentationInfoEXT bias_info{
|
||||
.sType = VK_STRUCTURE_TYPE_DEPTH_BIAS_REPRESENTATION_INFO_EXT,
|
||||
@@ -1207,32 +1422,57 @@ void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
.depthBiasExact = VK_FALSE,
|
||||
};
|
||||
|
||||
cmdbuf.SetDepthBias(constant, clamp, factor, &bias_info);
|
||||
cmd->SetDepthBias(units, regs.depth_bias_clamp, regs.slope_scale_depth_bias, &bias_info);
|
||||
} else {
|
||||
cmdbuf.SetDepthBias(constant, clamp, factor);
|
||||
cmd->SetDepthBias(units, regs.depth_bias_clamp, regs.slope_scale_depth_bias);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
scheduler.Record([constant = units, clamp = regs.depth_bias_clamp,
|
||||
factor = regs.slope_scale_depth_bias, this](vk::CommandBuffer cmdbuf) {
|
||||
if (device.IsExtDepthBiasControlSupported()) {
|
||||
static VkDepthBiasRepresentationInfoEXT bias_info{
|
||||
.sType = VK_STRUCTURE_TYPE_DEPTH_BIAS_REPRESENTATION_INFO_EXT,
|
||||
.pNext = nullptr,
|
||||
.depthBiasRepresentation =
|
||||
VK_DEPTH_BIAS_REPRESENTATION_LEAST_REPRESENTABLE_VALUE_FORCE_UNORM_EXT,
|
||||
.depthBiasExact = VK_FALSE,
|
||||
};
|
||||
|
||||
cmdbuf.SetDepthBias(constant, clamp, factor, &bias_info);
|
||||
} else {
|
||||
cmdbuf.SetDepthBias(constant, clamp, factor);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateBlendConstants(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateBlendConstants(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchBlendConstants()) {
|
||||
return;
|
||||
}
|
||||
const std::array blend_color = {regs.blend_color.r, regs.blend_color.g, regs.blend_color.b,
|
||||
regs.blend_color.a};
|
||||
scheduler.Record(
|
||||
[blend_color](vk::CommandBuffer cmdbuf) { cmdbuf.SetBlendConstants(blend_color.data()); });
|
||||
if (cmd) {
|
||||
cmd->SetBlendConstants(blend_color.data());
|
||||
} else {
|
||||
scheduler.Record([blend_color](vk::CommandBuffer cmdbuf) { cmdbuf.SetBlendConstants(blend_color.data()); });
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateDepthBounds(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateDepthBounds(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchDepthBounds()) {
|
||||
return;
|
||||
}
|
||||
scheduler.Record([min = regs.depth_bounds[0], max = regs.depth_bounds[1]](
|
||||
vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthBounds(min, max); });
|
||||
if (cmd) {
|
||||
cmd->SetDepthBounds(regs.depth_bounds[0], regs.depth_bounds[1]);
|
||||
} else {
|
||||
scheduler.Record([min = regs.depth_bounds[0], max = regs.depth_bounds[1]](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetDepthBounds(min, max);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchStencilProperties()) {
|
||||
return;
|
||||
}
|
||||
@@ -1256,17 +1496,25 @@ void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs)
|
||||
return;
|
||||
}
|
||||
}
|
||||
scheduler.Record([front_ref = regs.stencil_front_ref, back_ref = regs.stencil_back_ref,
|
||||
two_sided = regs.stencil_two_side_enable](vk::CommandBuffer cmdbuf) {
|
||||
const bool set_back = two_sided && front_ref != back_ref;
|
||||
// Front face
|
||||
cmdbuf.SetStencilReference(set_back ? VK_STENCIL_FACE_FRONT_BIT
|
||||
: VK_STENCIL_FACE_FRONT_AND_BACK,
|
||||
front_ref);
|
||||
if (cmd) {
|
||||
const bool set_back = regs.stencil_two_side_enable && regs.stencil_front_ref != regs.stencil_back_ref;
|
||||
cmd->SetStencilReference(set_back ? VK_STENCIL_FACE_FRONT_BIT : VK_STENCIL_FACE_FRONT_AND_BACK,
|
||||
regs.stencil_front_ref);
|
||||
if (set_back) {
|
||||
cmdbuf.SetStencilReference(VK_STENCIL_FACE_BACK_BIT, back_ref);
|
||||
cmd->SetStencilReference(VK_STENCIL_FACE_BACK_BIT, regs.stencil_back_ref);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
scheduler.Record([front_ref = regs.stencil_front_ref, back_ref = regs.stencil_back_ref,
|
||||
two_sided = regs.stencil_two_side_enable](vk::CommandBuffer cmdbuf) {
|
||||
const bool set_back = two_sided && front_ref != back_ref;
|
||||
cmdbuf.SetStencilReference(set_back ? VK_STENCIL_FACE_FRONT_BIT
|
||||
: VK_STENCIL_FACE_FRONT_AND_BACK,
|
||||
front_ref);
|
||||
if (set_back) {
|
||||
cmdbuf.SetStencilReference(VK_STENCIL_FACE_BACK_BIT, back_ref);
|
||||
}
|
||||
});
|
||||
}
|
||||
}();
|
||||
}
|
||||
if (update_write_mask) {
|
||||
@@ -1281,18 +1529,26 @@ void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs)
|
||||
return;
|
||||
}
|
||||
}
|
||||
scheduler.Record([front_write_mask = regs.stencil_front_mask,
|
||||
back_write_mask = regs.stencil_back_mask,
|
||||
two_sided = regs.stencil_two_side_enable](vk::CommandBuffer cmdbuf) {
|
||||
const bool set_back = two_sided && front_write_mask != back_write_mask;
|
||||
// Front face
|
||||
cmdbuf.SetStencilWriteMask(set_back ? VK_STENCIL_FACE_FRONT_BIT
|
||||
: VK_STENCIL_FACE_FRONT_AND_BACK,
|
||||
front_write_mask);
|
||||
if (cmd) {
|
||||
const bool set_back = regs.stencil_two_side_enable && regs.stencil_front_mask != regs.stencil_back_mask;
|
||||
cmd->SetStencilWriteMask(set_back ? VK_STENCIL_FACE_FRONT_BIT : VK_STENCIL_FACE_FRONT_AND_BACK,
|
||||
regs.stencil_front_mask);
|
||||
if (set_back) {
|
||||
cmdbuf.SetStencilWriteMask(VK_STENCIL_FACE_BACK_BIT, back_write_mask);
|
||||
cmd->SetStencilWriteMask(VK_STENCIL_FACE_BACK_BIT, regs.stencil_back_mask);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
scheduler.Record([front_write_mask = regs.stencil_front_mask,
|
||||
back_write_mask = regs.stencil_back_mask,
|
||||
two_sided = regs.stencil_two_side_enable](vk::CommandBuffer cmdbuf) {
|
||||
const bool set_back = two_sided && front_write_mask != back_write_mask;
|
||||
cmdbuf.SetStencilWriteMask(set_back ? VK_STENCIL_FACE_FRONT_BIT
|
||||
: VK_STENCIL_FACE_FRONT_AND_BACK,
|
||||
front_write_mask);
|
||||
if (set_back) {
|
||||
cmdbuf.SetStencilWriteMask(VK_STENCIL_FACE_BACK_BIT, back_write_mask);
|
||||
}
|
||||
});
|
||||
}
|
||||
}();
|
||||
}
|
||||
if (update_compare_masks) {
|
||||
@@ -1307,43 +1563,59 @@ void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs)
|
||||
return;
|
||||
}
|
||||
}
|
||||
scheduler.Record([front_test_mask = regs.stencil_front_func_mask,
|
||||
back_test_mask = regs.stencil_back_func_mask,
|
||||
two_sided = regs.stencil_two_side_enable](vk::CommandBuffer cmdbuf) {
|
||||
const bool set_back = two_sided && front_test_mask != back_test_mask;
|
||||
// Front face
|
||||
cmdbuf.SetStencilCompareMask(set_back ? VK_STENCIL_FACE_FRONT_BIT
|
||||
: VK_STENCIL_FACE_FRONT_AND_BACK,
|
||||
front_test_mask);
|
||||
if (cmd) {
|
||||
const bool set_back = regs.stencil_two_side_enable && regs.stencil_front_func_mask != regs.stencil_back_func_mask;
|
||||
cmd->SetStencilCompareMask(set_back ? VK_STENCIL_FACE_FRONT_BIT : VK_STENCIL_FACE_FRONT_AND_BACK,
|
||||
regs.stencil_front_func_mask);
|
||||
if (set_back) {
|
||||
cmdbuf.SetStencilCompareMask(VK_STENCIL_FACE_BACK_BIT, back_test_mask);
|
||||
cmd->SetStencilCompareMask(VK_STENCIL_FACE_BACK_BIT, regs.stencil_back_func_mask);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
scheduler.Record([front_test_mask = regs.stencil_front_func_mask,
|
||||
back_test_mask = regs.stencil_back_func_mask,
|
||||
two_sided = regs.stencil_two_side_enable](vk::CommandBuffer cmdbuf) {
|
||||
const bool set_back = two_sided && front_test_mask != back_test_mask;
|
||||
cmdbuf.SetStencilCompareMask(set_back ? VK_STENCIL_FACE_FRONT_BIT
|
||||
: VK_STENCIL_FACE_FRONT_AND_BACK,
|
||||
front_test_mask);
|
||||
if (set_back) {
|
||||
cmdbuf.SetStencilCompareMask(VK_STENCIL_FACE_BACK_BIT, back_test_mask);
|
||||
}
|
||||
});
|
||||
}
|
||||
}();
|
||||
}
|
||||
state_tracker.ClearStencilReset();
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateLineWidth(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateLineWidth(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchLineWidth()) {
|
||||
return;
|
||||
}
|
||||
const float width =
|
||||
regs.line_anti_alias_enable ? regs.line_width_smooth : regs.line_width_aliased;
|
||||
scheduler.Record([width](vk::CommandBuffer cmdbuf) { cmdbuf.SetLineWidth(width); });
|
||||
const float width = regs.line_anti_alias_enable ? regs.line_width_smooth : regs.line_width_aliased;
|
||||
if (cmd) {
|
||||
cmd->SetLineWidth(width);
|
||||
} else {
|
||||
scheduler.Record([width](vk::CommandBuffer cmdbuf) { cmdbuf.SetLineWidth(width); });
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateCullMode(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateCullMode(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchCullMode()) {
|
||||
return;
|
||||
}
|
||||
scheduler.Record([enabled = regs.gl_cull_test_enabled,
|
||||
cull_face = regs.gl_cull_face](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetCullModeEXT(enabled ? MaxwellToVK::CullFace(cull_face) : VK_CULL_MODE_NONE);
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetCullModeEXT(regs.gl_cull_test_enabled ? MaxwellToVK::CullFace(regs.gl_cull_face)
|
||||
: VK_CULL_MODE_NONE);
|
||||
} else {
|
||||
scheduler.Record([enabled = regs.gl_cull_test_enabled,
|
||||
cull_face = regs.gl_cull_face](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetCullModeEXT(enabled ? MaxwellToVK::CullFace(cull_face) : VK_CULL_MODE_NONE);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateDepthBoundsTestEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateDepthBoundsTestEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchDepthBoundsTestEnable()) {
|
||||
return;
|
||||
}
|
||||
@@ -1352,48 +1624,60 @@ void RasterizerVulkan::UpdateDepthBoundsTestEnable(Tegra::Engines::Maxwell3D::Re
|
||||
LOG_WARNING(Render_Vulkan, "Depth bounds is enabled but not supported");
|
||||
enabled = false;
|
||||
}
|
||||
scheduler.Record([enable = enabled](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetDepthBoundsTestEnableEXT(enable);
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetDepthBoundsTestEnableEXT(enabled);
|
||||
} else {
|
||||
scheduler.Record([enable = enabled](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetDepthBoundsTestEnableEXT(enable);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateDepthTestEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateDepthTestEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchDepthTestEnable()) {
|
||||
return;
|
||||
}
|
||||
scheduler.Record([enable = regs.depth_test_enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetDepthTestEnableEXT(enable);
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetDepthTestEnableEXT(regs.depth_test_enable);
|
||||
} else {
|
||||
scheduler.Record([enable = regs.depth_test_enable](vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthTestEnableEXT(enable); });
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchDepthWriteEnable()) {
|
||||
return;
|
||||
}
|
||||
scheduler.Record([enable = regs.depth_write_enabled](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetDepthWriteEnableEXT(enable);
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetDepthWriteEnableEXT(regs.depth_write_enabled);
|
||||
} else {
|
||||
scheduler.Record([enable = regs.depth_write_enabled](vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthWriteEnableEXT(enable); });
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdatePrimitiveRestartEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdatePrimitiveRestartEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchPrimitiveRestartEnable()) {
|
||||
return;
|
||||
}
|
||||
scheduler.Record([enable = regs.primitive_restart.enabled](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetPrimitiveRestartEnableEXT(enable);
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetPrimitiveRestartEnableEXT(regs.primitive_restart.enabled);
|
||||
} else {
|
||||
scheduler.Record([enable = regs.primitive_restart.enabled](vk::CommandBuffer cmdbuf) { cmdbuf.SetPrimitiveRestartEnableEXT(enable); });
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateRasterizerDiscardEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateRasterizerDiscardEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchRasterizerDiscardEnable()) {
|
||||
return;
|
||||
}
|
||||
scheduler.Record([disable = regs.rasterize_enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetRasterizerDiscardEnableEXT(disable == 0);
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetRasterizerDiscardEnableEXT(regs.rasterize_enable == 0);
|
||||
} else {
|
||||
scheduler.Record([disable = regs.rasterize_enable](vk::CommandBuffer cmdbuf) { cmdbuf.SetRasterizerDiscardEnableEXT(disable == 0); });
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateConservativeRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateConservativeRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchConservativeRasterizationMode()) {
|
||||
return;
|
||||
}
|
||||
@@ -1401,15 +1685,20 @@ void RasterizerVulkan::UpdateConservativeRasterizationMode(Tegra::Engines::Maxwe
|
||||
if (!device.SupportsDynamicState3ConservativeRasterizationMode()) {
|
||||
return;
|
||||
}
|
||||
|
||||
scheduler.Record([enable = regs.conservative_raster_enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetConservativeRasterizationModeEXT(
|
||||
enable ? VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT
|
||||
: VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT);
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetConservativeRasterizationModeEXT(
|
||||
regs.conservative_raster_enable ? VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT
|
||||
: VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT);
|
||||
} else {
|
||||
scheduler.Record([enable = regs.conservative_raster_enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetConservativeRasterizationModeEXT(
|
||||
enable ? VK_CONSERVATIVE_RASTERIZATION_MODE_OVERESTIMATE_EXT
|
||||
: VK_CONSERVATIVE_RASTERIZATION_MODE_DISABLED_EXT);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateLineStippleEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateLineStippleEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchLineStippleEnable()) {
|
||||
return;
|
||||
}
|
||||
@@ -1417,13 +1706,16 @@ void RasterizerVulkan::UpdateLineStippleEnable(Tegra::Engines::Maxwell3D::Regs&
|
||||
if (!device.SupportsDynamicState3LineStippleEnable()) {
|
||||
return;
|
||||
}
|
||||
|
||||
scheduler.Record([enable = regs.line_stipple_enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetLineStippleEnableEXT(enable);
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetLineStippleEnableEXT(regs.line_stipple_enable);
|
||||
} else {
|
||||
scheduler.Record([enable = regs.line_stipple_enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetLineStippleEnableEXT(enable);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateLineRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateLineRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!device.IsExtLineRasterizationSupported()) {
|
||||
return;
|
||||
}
|
||||
@@ -1455,12 +1747,16 @@ void RasterizerVulkan::UpdateLineRasterizationMode(Tegra::Engines::Maxwell3D::Re
|
||||
});
|
||||
}
|
||||
}
|
||||
scheduler.Record([mode](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetLineRasterizationModeEXT(mode);
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetLineRasterizationModeEXT(mode);
|
||||
} else {
|
||||
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, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchDepthBiasEnable()) {
|
||||
return;
|
||||
}
|
||||
@@ -1491,23 +1787,30 @@ void RasterizerVulkan::UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& re
|
||||
};
|
||||
const u32 topology_index = static_cast<u32>(maxwell3d->draw_manager->GetDrawState().topology);
|
||||
const u32 enable = enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]];
|
||||
scheduler.Record(
|
||||
[enable](vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthBiasEnableEXT(enable != 0); });
|
||||
if (cmd) {
|
||||
cmd->SetDepthBiasEnableEXT(enable != 0);
|
||||
} else {
|
||||
scheduler.Record([enable](vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthBiasEnableEXT(enable != 0); });
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateLogicOpEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateLogicOpEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchLogicOpEnable()) {
|
||||
return;
|
||||
}
|
||||
if (!device.SupportsDynamicState3LogicOpEnable()) {
|
||||
return;
|
||||
}
|
||||
scheduler.Record([enable = regs.logic_op.enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetLogicOpEnableEXT(enable != 0);
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetLogicOpEnableEXT(regs.logic_op.enable != 0);
|
||||
} else {
|
||||
scheduler.Record([enable = regs.logic_op.enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetLogicOpEnableEXT(enable != 0);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateDepthClampEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateDepthClampEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchDepthClampEnable()) {
|
||||
return;
|
||||
}
|
||||
@@ -1520,11 +1823,14 @@ void RasterizerVulkan::UpdateDepthClampEnable(Tegra::Engines::Maxwell3D::Regs& r
|
||||
Maxwell::ViewportClipControl::GeometryClip::FrustumXYZ ||
|
||||
regs.viewport_clip_control.geometry_clip ==
|
||||
Maxwell::ViewportClipControl::GeometryClip::FrustumZ);
|
||||
scheduler.Record(
|
||||
[is_enabled](vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthClampEnableEXT(is_enabled); });
|
||||
if (cmd) {
|
||||
cmd->SetDepthClampEnableEXT(is_enabled);
|
||||
} else {
|
||||
scheduler.Record([is_enabled](vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthClampEnableEXT(is_enabled); });
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateAlphaToCoverageEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateAlphaToCoverageEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchAlphaToCoverageEnable()) {
|
||||
return;
|
||||
}
|
||||
@@ -1534,12 +1840,16 @@ void RasterizerVulkan::UpdateAlphaToCoverageEnable(Tegra::Engines::Maxwell3D::Re
|
||||
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);
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetAlphaToCoverageEnableEXT(enable ? VK_TRUE : VK_FALSE);
|
||||
} else {
|
||||
scheduler.Record([enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetAlphaToCoverageEnableEXT(enable ? VK_TRUE : VK_FALSE);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateAlphaToOneEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateAlphaToOneEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchAlphaToOneEnable()) {
|
||||
return;
|
||||
}
|
||||
@@ -1554,21 +1864,29 @@ void RasterizerVulkan::UpdateAlphaToOneEnable(Tegra::Engines::Maxwell3D::Regs& r
|
||||
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);
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetAlphaToOneEnableEXT(enable ? VK_TRUE : VK_FALSE);
|
||||
} else {
|
||||
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, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchDepthCompareOp()) {
|
||||
return;
|
||||
}
|
||||
scheduler.Record([func = regs.depth_test_func](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetDepthCompareOpEXT(MaxwellToVK::ComparisonOp(func));
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetDepthCompareOpEXT(MaxwellToVK::ComparisonOp(regs.depth_test_func));
|
||||
} else {
|
||||
scheduler.Record([func = regs.depth_test_func](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetDepthCompareOpEXT(MaxwellToVK::ComparisonOp(func));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchFrontFace()) {
|
||||
return;
|
||||
}
|
||||
@@ -1578,11 +1896,14 @@ void RasterizerVulkan::UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
front_face = front_face == VK_FRONT_FACE_CLOCKWISE ? VK_FRONT_FACE_COUNTER_CLOCKWISE
|
||||
: VK_FRONT_FACE_CLOCKWISE;
|
||||
}
|
||||
scheduler.Record(
|
||||
[front_face](vk::CommandBuffer cmdbuf) { cmdbuf.SetFrontFaceEXT(front_face); });
|
||||
if (cmd) {
|
||||
cmd->SetFrontFaceEXT(front_face);
|
||||
} else {
|
||||
scheduler.Record([front_face](vk::CommandBuffer cmdbuf) { cmdbuf.SetFrontFaceEXT(front_face); });
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchStencilOp()) {
|
||||
return;
|
||||
}
|
||||
@@ -1596,37 +1917,57 @@ void RasterizerVulkan::UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
const Maxwell::StencilOp::Op back_zfail = regs.stencil_back_op.zfail;
|
||||
const Maxwell::StencilOp::Op back_zpass = regs.stencil_back_op.zpass;
|
||||
const Maxwell::ComparisonOp back_compare = regs.stencil_back_op.func;
|
||||
scheduler.Record([fail, zfail, zpass, compare, back_fail, back_zfail, back_zpass,
|
||||
back_compare](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetStencilOpEXT(VK_STENCIL_FACE_FRONT_BIT, MaxwellToVK::StencilOp(fail),
|
||||
if (cmd) {
|
||||
cmd->SetStencilOpEXT(VK_STENCIL_FACE_FRONT_BIT, MaxwellToVK::StencilOp(fail),
|
||||
MaxwellToVK::StencilOp(zpass), MaxwellToVK::StencilOp(zfail),
|
||||
MaxwellToVK::ComparisonOp(compare));
|
||||
cmdbuf.SetStencilOpEXT(VK_STENCIL_FACE_BACK_BIT, MaxwellToVK::StencilOp(back_fail),
|
||||
cmd->SetStencilOpEXT(VK_STENCIL_FACE_BACK_BIT, MaxwellToVK::StencilOp(back_fail),
|
||||
MaxwellToVK::StencilOp(back_zpass),
|
||||
MaxwellToVK::StencilOp(back_zfail),
|
||||
MaxwellToVK::ComparisonOp(back_compare));
|
||||
});
|
||||
} else {
|
||||
scheduler.Record([fail, zfail, zpass, compare, back_fail, back_zfail, back_zpass,
|
||||
back_compare](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetStencilOpEXT(VK_STENCIL_FACE_FRONT_BIT, MaxwellToVK::StencilOp(fail),
|
||||
MaxwellToVK::StencilOp(zpass), MaxwellToVK::StencilOp(zfail),
|
||||
MaxwellToVK::ComparisonOp(compare));
|
||||
cmdbuf.SetStencilOpEXT(VK_STENCIL_FACE_BACK_BIT, MaxwellToVK::StencilOp(back_fail),
|
||||
MaxwellToVK::StencilOp(back_zpass),
|
||||
MaxwellToVK::StencilOp(back_zfail),
|
||||
MaxwellToVK::ComparisonOp(back_compare));
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Front face defines the stencil op of both faces
|
||||
scheduler.Record([fail, zfail, zpass, compare](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetStencilOpEXT(VK_STENCIL_FACE_FRONT_AND_BACK, MaxwellToVK::StencilOp(fail),
|
||||
if (cmd) {
|
||||
cmd->SetStencilOpEXT(VK_STENCIL_FACE_FRONT_AND_BACK, MaxwellToVK::StencilOp(fail),
|
||||
MaxwellToVK::StencilOp(zpass), MaxwellToVK::StencilOp(zfail),
|
||||
MaxwellToVK::ComparisonOp(compare));
|
||||
});
|
||||
} else {
|
||||
scheduler.Record([fail, zfail, zpass, compare](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetStencilOpEXT(VK_STENCIL_FACE_FRONT_AND_BACK, MaxwellToVK::StencilOp(fail),
|
||||
MaxwellToVK::StencilOp(zpass), MaxwellToVK::StencilOp(zfail),
|
||||
MaxwellToVK::ComparisonOp(compare));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateLogicOp(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateLogicOp(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchLogicOp()) {
|
||||
return;
|
||||
}
|
||||
const auto op_value = static_cast<u32>(regs.logic_op.op);
|
||||
auto op = op_value >= 0x1500 && op_value < 0x1510 ? static_cast<VkLogicOp>(op_value - 0x1500)
|
||||
: VK_LOGIC_OP_NO_OP;
|
||||
scheduler.Record([op](vk::CommandBuffer cmdbuf) { cmdbuf.SetLogicOpEXT(op); });
|
||||
if (cmd) {
|
||||
cmd->SetLogicOpEXT(op);
|
||||
} else {
|
||||
scheduler.Record([op](vk::CommandBuffer cmdbuf) { cmdbuf.SetLogicOpEXT(op); });
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateBlending(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateBlending(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchBlending()) {
|
||||
return;
|
||||
}
|
||||
@@ -1649,9 +1990,13 @@ void RasterizerVulkan::UpdateBlending(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
current |= VK_COLOR_COMPONENT_A_BIT;
|
||||
}
|
||||
}
|
||||
scheduler.Record([setup_masks](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetColorWriteMaskEXT(0, setup_masks);
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetColorWriteMaskEXT(0, setup_masks);
|
||||
} else {
|
||||
scheduler.Record([setup_masks](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetColorWriteMaskEXT(0, setup_masks);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (state_tracker.TouchBlendEnable()) {
|
||||
@@ -1659,9 +2004,13 @@ void RasterizerVulkan::UpdateBlending(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
std::ranges::transform(
|
||||
regs.blend.enable, setup_enables.begin(),
|
||||
[&](const auto& is_enabled) { return is_enabled != 0 ? VK_TRUE : VK_FALSE; });
|
||||
scheduler.Record([setup_enables](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetColorBlendEnableEXT(0, setup_enables);
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetColorBlendEnableEXT(0, setup_enables);
|
||||
} else {
|
||||
scheduler.Record([setup_enables](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetColorBlendEnableEXT(0, setup_enables);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (state_tracker.TouchBlendEquations()) {
|
||||
@@ -1701,22 +2050,30 @@ void RasterizerVulkan::UpdateBlending(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
}
|
||||
}
|
||||
|
||||
scheduler.Record([setup_blends](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetColorBlendEquationEXT(0, setup_blends);
|
||||
if (cmd) {
|
||||
cmd->SetColorBlendEquationEXT(0, setup_blends);
|
||||
} else {
|
||||
scheduler.Record([setup_blends](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetColorBlendEquationEXT(0, setup_blends);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
if (!state_tracker.TouchStencilTestEnable()) {
|
||||
return;
|
||||
}
|
||||
if (cmd) {
|
||||
cmd->SetStencilTestEnableEXT(regs.stencil_enable);
|
||||
} else {
|
||||
scheduler.Record([enable = regs.stencil_enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetStencilTestEnableEXT(enable);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
if (!state_tracker.TouchStencilTestEnable()) {
|
||||
return;
|
||||
}
|
||||
scheduler.Record([enable = regs.stencil_enable](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetStencilTestEnableEXT(enable);
|
||||
});
|
||||
}
|
||||
|
||||
void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd) {
|
||||
auto& dirty{maxwell3d->dirty.flags};
|
||||
if (!dirty[Dirty::VertexInput]) {
|
||||
return;
|
||||
@@ -1769,9 +2126,13 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs)
|
||||
.divisor = is_instanced ? input_binding.frequency : 1,
|
||||
});
|
||||
}
|
||||
scheduler.Record([bindings, attributes](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetVertexInputEXT(bindings, attributes);
|
||||
});
|
||||
if (cmd) {
|
||||
cmd->SetVertexInputEXT(bindings, attributes);
|
||||
} else {
|
||||
scheduler.Record([bindings, attributes](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetVertexInputEXT(bindings, attributes);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerVulkan::InitializeChannel(Tegra::Control::ChannelState& channel) {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
@@ -161,37 +161,38 @@ private:
|
||||
|
||||
void HandleTransformFeedback();
|
||||
|
||||
void UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateBlendConstants(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateDepthBounds(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateLineWidth(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateBlendConstants(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateDepthBounds(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateLineWidth(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
|
||||
void UpdateCullMode(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateDepthBoundsTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateDepthTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdatePrimitiveRestartEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateRasterizerDiscardEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateConservativeRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateLineStippleEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateLineStipple(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateLineRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateLogicOpEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateDepthClampEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateAlphaToCoverageEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateAlphaToOneEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateLogicOp(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateBlending(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateCullMode(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateDepthBoundsTestEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateDepthTestEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdatePrimitiveRestartEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateRasterizerDiscardEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateConservativeRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateLineStippleEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateLineStipple(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateLineRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateLogicOpEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateDepthClampEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateAlphaToCoverageEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateAlphaToOneEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateLogicOp(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void UpdateBlending(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
|
||||
void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs);
|
||||
void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmd = nullptr);
|
||||
void RecordDynamicStates(vk::CommandBuffer cmdbuf);
|
||||
|
||||
Tegra::GPU& gpu;
|
||||
Tegra::MaxwellDeviceMemoryManager& device_memory;
|
||||
|
||||
@@ -445,7 +445,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
|
||||
// GetSuitability has already configured the linked list of features for us.
|
||||
// Reuse it here.
|
||||
const void* first_next = &features2;
|
||||
void* first_next = &features2;
|
||||
|
||||
VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv{};
|
||||
const bool use_diagnostics_nv = Settings::values.enable_nsight_aftermath && extensions.device_diagnostics_config;
|
||||
@@ -462,16 +462,67 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
first_next = &diagnostics_nv;
|
||||
}
|
||||
|
||||
VkPhysicalDeviceDescriptorIndexingFeaturesEXT descriptor_indexing{
|
||||
// Query descriptor indexing features from the physical device first so we only
|
||||
// request sub-features that are actually supported by the driver.
|
||||
VkPhysicalDeviceDescriptorIndexingFeaturesEXT descriptor_indexing_temp{};
|
||||
descriptor_indexing_temp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT;
|
||||
descriptor_indexing_temp.pNext = nullptr;
|
||||
VkPhysicalDeviceFeatures2 desc_idx_features2{};
|
||||
desc_idx_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
||||
desc_idx_features2.pNext = &descriptor_indexing_temp;
|
||||
physical.GetFeatures2(desc_idx_features2);
|
||||
|
||||
VkPhysicalDeviceDescriptorIndexingFeaturesEXT descriptor_indexing_req{
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_INDEXING_FEATURES_EXT,
|
||||
.pNext = use_diagnostics_nv ? static_cast<void*>(&diagnostics_nv) : static_cast<void*>(&features2),
|
||||
.shaderSampledImageArrayNonUniformIndexing = VK_TRUE,
|
||||
.descriptorBindingPartiallyBound = VK_TRUE,
|
||||
.descriptorBindingVariableDescriptorCount = VK_TRUE,
|
||||
.shaderSampledImageArrayNonUniformIndexing = descriptor_indexing_temp.shaderSampledImageArrayNonUniformIndexing,
|
||||
.descriptorBindingPartiallyBound = descriptor_indexing_temp.descriptorBindingPartiallyBound,
|
||||
.descriptorBindingVariableDescriptorCount = descriptor_indexing_temp.descriptorBindingVariableDescriptorCount,
|
||||
};
|
||||
|
||||
if (extensions.descriptor_indexing && Settings::values.descriptor_indexing.GetValue()) {
|
||||
first_next = &descriptor_indexing;
|
||||
first_next = &descriptor_indexing_req;
|
||||
}
|
||||
|
||||
// VK_EXT_descriptor_buffer
|
||||
VkPhysicalDeviceDescriptorBufferFeaturesEXT descriptor_buffer_temp{};
|
||||
descriptor_buffer_temp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT;
|
||||
descriptor_buffer_temp.pNext = nullptr;
|
||||
VkPhysicalDeviceFeatures2 db_features2{};
|
||||
db_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
||||
db_features2.pNext = &descriptor_buffer_temp;
|
||||
physical.GetFeatures2(db_features2);
|
||||
|
||||
VkPhysicalDeviceDescriptorBufferFeaturesEXT descriptor_buffer_features{
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_FEATURES_EXT,
|
||||
.pNext = first_next,
|
||||
.descriptorBuffer = descriptor_buffer_temp.descriptorBuffer ? VK_TRUE : VK_FALSE,
|
||||
.descriptorBufferCaptureReplay = descriptor_buffer_temp.descriptorBufferCaptureReplay ? VK_TRUE : VK_FALSE,
|
||||
.descriptorBufferImageLayoutIgnored = descriptor_buffer_temp.descriptorBufferImageLayoutIgnored ? VK_TRUE : VK_FALSE,
|
||||
.descriptorBufferPushDescriptors = descriptor_buffer_temp.descriptorBufferPushDescriptors ? VK_TRUE : VK_FALSE,
|
||||
};
|
||||
|
||||
if (extensions.descriptor_buffer && descriptor_buffer_temp.descriptorBuffer) {
|
||||
first_next = &descriptor_buffer_features;
|
||||
}
|
||||
|
||||
// VK_EXT_inline_uniform_block
|
||||
VkPhysicalDeviceInlineUniformBlockFeaturesEXT inline_uniform_block_temp{};
|
||||
inline_uniform_block_temp.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT;
|
||||
inline_uniform_block_temp.pNext = nullptr;
|
||||
VkPhysicalDeviceFeatures2 iub_features2{};
|
||||
iub_features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
||||
iub_features2.pNext = &inline_uniform_block_temp;
|
||||
physical.GetFeatures2(iub_features2);
|
||||
|
||||
VkPhysicalDeviceInlineUniformBlockFeaturesEXT inline_uniform_block_features{
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_INLINE_UNIFORM_BLOCK_FEATURES_EXT,
|
||||
.pNext = first_next,
|
||||
.inlineUniformBlock = inline_uniform_block_temp.inlineUniformBlock ? VK_TRUE : VK_FALSE,
|
||||
};
|
||||
|
||||
if (extensions.inline_uniform_block && inline_uniform_block_temp.inlineUniformBlock) {
|
||||
first_next = &inline_uniform_block_features;
|
||||
}
|
||||
|
||||
is_blit_depth24_stencil8_supported = TestDepthStencilBlits(VK_FORMAT_D24_UNORM_S8_UINT);
|
||||
@@ -657,13 +708,6 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
|
||||
const auto dyna_state = Settings::values.dyna_state.GetValue();
|
||||
|
||||
// Base dynamic states (VIEWPORT, SCISSOR, DEPTH_BIAS, etc.) are ALWAYS active in vk_graphics_pipeline.cpp
|
||||
// This slider controls EXTENDED dynamic states with accumulative levels per Vulkan specs:
|
||||
// Level 0 = Core Dynamic States only (Vulkan 1.0)
|
||||
// Level 1 = Core + VK_EXT_extended_dynamic_state
|
||||
// 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
|
||||
|
||||
switch (dyna_state) {
|
||||
case Settings::ExtendedDynamicState::Disabled:
|
||||
// Level 0: Disable all extended dynamic state extensions
|
||||
@@ -698,8 +742,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
break;
|
||||
}
|
||||
|
||||
// VK_EXT_vertex_input_dynamic_state is independent from EDS
|
||||
// It can be enabled even without extended_dynamic_state
|
||||
// VK_EXT_vertex_input_dynamic_state is independent from ExtendedDynamicState level
|
||||
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);
|
||||
}
|
||||
@@ -1126,6 +1169,14 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
SetNext(next, properties.multi_draw);
|
||||
}
|
||||
|
||||
// VK_EXT_descriptor_buffer properties
|
||||
VkPhysicalDeviceDescriptorBufferPropertiesEXT descriptor_buffer_properties{};
|
||||
if (extensions.descriptor_buffer) {
|
||||
descriptor_buffer_properties.sType =
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DESCRIPTOR_BUFFER_PROPERTIES_EXT;
|
||||
SetNext(next, descriptor_buffer_properties);
|
||||
}
|
||||
|
||||
// Perform the property fetch.
|
||||
physical.GetProperties2(properties2);
|
||||
|
||||
@@ -1203,16 +1254,11 @@ bool Device::GetSuitability(bool requires_swapchain) {
|
||||
features.extended_dynamic_state3.extendedDynamicState3LogicOpEnable = false;
|
||||
}
|
||||
|
||||
// Return whether we were suitable.
|
||||
return suitable;
|
||||
}
|
||||
|
||||
void Device::RemoveUnsuitableExtensions() {
|
||||
// VK_EXT_custom_border_color
|
||||
// Enable extension if driver supports it, then check individual features
|
||||
// - 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) {
|
||||
@@ -1308,7 +1354,6 @@ void Device::RemoveUnsuitableExtensions() {
|
||||
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;
|
||||
@@ -1317,7 +1362,6 @@ void Device::RemoveUnsuitableExtensions() {
|
||||
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);
|
||||
@@ -1359,10 +1403,6 @@ void Device::RemoveUnsuitableExtensions() {
|
||||
VK_EXT_SUBGROUP_SIZE_CONTROL_EXTENSION_NAME);
|
||||
|
||||
// VK_EXT_transform_feedback
|
||||
// We only require the basic transformFeedback feature and at least
|
||||
// one transform feedback buffer. We keep transformFeedbackQueries as it's used by
|
||||
// the streaming byte count implementation. GeometryStreams and multiple streams
|
||||
// are not strictly required since we currently support only stream 0.
|
||||
extensions.transform_feedback =
|
||||
features.transform_feedback.transformFeedback &&
|
||||
properties.transform_feedback.maxTransformFeedbackBuffers > 0 &&
|
||||
@@ -1475,17 +1515,26 @@ void Device::RemoveUnsuitableExtensions() {
|
||||
RemoveExtensionFeatureIfUnsuitable(extensions.maintenance6, features.maintenance6,
|
||||
VK_KHR_MAINTENANCE_6_EXTENSION_NAME);
|
||||
|
||||
// VK_KHR_maintenance7 (proposed for Vulkan 1.4, no features)
|
||||
// VK_KHR_maintenance7
|
||||
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)
|
||||
// VK_KHR_maintenance8
|
||||
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)
|
||||
// VK_KHR_maintenance9
|
||||
extensions.maintenance9 = loaded_extensions.contains(VK_KHR_MAINTENANCE_9_EXTENSION_NAME);
|
||||
RemoveExtensionIfUnsuitable(extensions.maintenance9, VK_KHR_MAINTENANCE_9_EXTENSION_NAME);
|
||||
|
||||
// VK_EXT_graphics_pipeline_library
|
||||
extensions.graphics_pipeline_library = loaded_extensions.contains(VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||
RemoveExtensionIfUnsuitable(extensions.graphics_pipeline_library, VK_EXT_GRAPHICS_PIPELINE_LIBRARY_EXTENSION_NAME);
|
||||
if (extensions.graphics_pipeline_library) {
|
||||
LOG_INFO(Render_Vulkan, "Driver supports VK_EXT_graphics_pipeline_library; enabling use");
|
||||
} else {
|
||||
LOG_INFO(Render_Vulkan, "VK_EXT_graphics_pipeline_library not available");
|
||||
}
|
||||
}
|
||||
|
||||
void Device::SetupFamilies(VkSurfaceKHR surface) {
|
||||
|
||||
@@ -105,7 +105,10 @@ VK_DEFINE_HANDLE(VmaAllocator)
|
||||
EXTENSION(NV, VIEWPORT_SWIZZLE, viewport_swizzle) \
|
||||
EXTENSION(EXT, DESCRIPTOR_INDEXING, descriptor_indexing) \
|
||||
EXTENSION(EXT, FILTER_CUBIC, filter_cubic) \
|
||||
EXTENSION(QCOM, FILTER_CUBIC_WEIGHTS, filter_cubic_weights)
|
||||
EXTENSION(QCOM, FILTER_CUBIC_WEIGHTS, filter_cubic_weights) \
|
||||
EXTENSION(EXT, GRAPHICS_PIPELINE_LIBRARY, graphics_pipeline_library) \
|
||||
EXTENSION(EXT, DESCRIPTOR_BUFFER, descriptor_buffer) \
|
||||
EXTENSION(EXT, INLINE_UNIFORM_BLOCK, inline_uniform_block) \
|
||||
|
||||
// Define extensions which must be supported.
|
||||
#define FOR_EACH_VK_MANDATORY_EXTENSION(EXTENSION_NAME) \
|
||||
@@ -293,6 +296,11 @@ public:
|
||||
return properties.properties.driverVersion;
|
||||
}
|
||||
|
||||
/// Returns true if the device and driver have VK_EXT_graphics_pipeline_library enabled.
|
||||
bool HasGraphicsPipelineLibrary() const {
|
||||
return extensions.graphics_pipeline_library;
|
||||
}
|
||||
|
||||
/// Returns the device name.
|
||||
std::string_view GetModelName() const {
|
||||
return properties.properties.deviceName;
|
||||
@@ -696,6 +704,43 @@ public:
|
||||
return dynamic_state3_alpha_to_one;
|
||||
}
|
||||
|
||||
// Core dynamic state support checks
|
||||
bool SupportsDynamicStateViewport() const {
|
||||
return dld.vkCmdSetViewport != nullptr;
|
||||
}
|
||||
|
||||
bool SupportsDynamicStateScissor() const {
|
||||
return dld.vkCmdSetScissor != nullptr;
|
||||
}
|
||||
|
||||
bool SupportsDynamicStateDepthBias() const {
|
||||
return dld.vkCmdSetDepthBias != nullptr || dld.vkCmdSetDepthBias2EXT != nullptr;
|
||||
}
|
||||
|
||||
bool SupportsDynamicStateBlendConstants() const {
|
||||
return dld.vkCmdSetBlendConstants != nullptr;
|
||||
}
|
||||
|
||||
bool SupportsDynamicStateDepthBounds() const {
|
||||
return dld.vkCmdSetDepthBounds != nullptr && IsDepthBoundsSupported();
|
||||
}
|
||||
|
||||
bool SupportsDynamicStateStencilCompareMask() const {
|
||||
return dld.vkCmdSetStencilCompareMask != nullptr;
|
||||
}
|
||||
|
||||
bool SupportsDynamicStateStencilWriteMask() const {
|
||||
return dld.vkCmdSetStencilWriteMask != nullptr;
|
||||
}
|
||||
|
||||
bool SupportsDynamicStateStencilReference() const {
|
||||
return dld.vkCmdSetStencilReference != nullptr;
|
||||
}
|
||||
|
||||
bool SupportsDynamicStateLineWidth() const {
|
||||
return dld.vkCmdSetLineWidth != nullptr;
|
||||
}
|
||||
|
||||
/// Returns true if the device supports VK_EXT_vertex_input_dynamic_state.
|
||||
bool IsExtVertexInputDynamicStateSupported() const {
|
||||
return extensions.vertex_input_dynamic_state;
|
||||
|
||||
Reference in New Issue
Block a user