Browse Source

[vulkan] Increased logic handling of DynamicState and VertexInputDynamicState

vulkanasync
CamilleLaVey 2 months ago
parent
commit
8553e7e7de
  1. 10
      src/video_core/buffer_cache/buffer_cache.h
  2. 6
      src/video_core/buffer_cache/buffer_cache_base.h
  3. 5
      src/video_core/renderer_opengl/gl_buffer_cache.cpp
  4. 5
      src/video_core/renderer_opengl/gl_buffer_cache.h
  5. 4
      src/video_core/renderer_opengl/gl_graphics_pipeline.cpp
  6. 10
      src/video_core/renderer_vulkan/vk_buffer_cache.cpp
  7. 8
      src/video_core/renderer_vulkan/vk_buffer_cache.h
  8. 3
      src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp
  9. 8
      src/video_core/renderer_vulkan/vk_graphics_pipeline.h
  10. 677
      src/video_core/renderer_vulkan/vk_rasterizer.cpp
  11. 65
      src/video_core/renderer_vulkan/vk_rasterizer.h
  12. 14
      src/video_core/vulkan_common/vulkan_device.cpp

10
src/video_core/buffer_cache/buffer_cache.h

@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
@ -352,7 +352,7 @@ void BufferCache<P>::UpdateComputeBuffers() {
} }
template <class P> template <class P>
void BufferCache<P>::BindHostGeometryBuffers(bool is_indexed) {
void BufferCache<P>::BindHostGeometryBuffers(bool is_indexed, bool use_dynamic_vertex_input) {
if (is_indexed) { if (is_indexed) {
BindHostIndexBuffer(); BindHostIndexBuffer();
} else if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) { } else if constexpr (!HAS_FULL_INDEX_AND_PRIMITIVE_SUPPORT) {
@ -363,7 +363,7 @@ void BufferCache<P>::BindHostGeometryBuffers(bool is_indexed) {
draw_state.vertex_buffer.count); draw_state.vertex_buffer.count);
} }
} }
BindHostVertexBuffers();
BindHostVertexBuffers(use_dynamic_vertex_input);
BindHostTransformFeedbackBuffers(); BindHostTransformFeedbackBuffers();
if (current_draw_indirect) { if (current_draw_indirect) {
BindHostDrawIndirectBuffers(); BindHostDrawIndirectBuffers();
@ -764,7 +764,7 @@ void BufferCache<P>::BindHostIndexBuffer() {
} }
template <class P> template <class P>
void BufferCache<P>::BindHostVertexBuffers() {
void BufferCache<P>::BindHostVertexBuffers(bool use_dynamic_vertex_input) {
HostBindings<typename P::Buffer> host_bindings; HostBindings<typename P::Buffer> host_bindings;
bool any_valid{false}; bool any_valid{false};
auto& flags = maxwell3d->dirty.flags; auto& flags = maxwell3d->dirty.flags;
@ -800,7 +800,7 @@ void BufferCache<P>::BindHostVertexBuffers() {
host_bindings.sizes.push_back(binding.size); host_bindings.sizes.push_back(binding.size);
host_bindings.strides.push_back(stride); host_bindings.strides.push_back(stride);
} }
runtime.BindVertexBuffers(host_bindings);
runtime.BindVertexBuffers(host_bindings, use_dynamic_vertex_input);
} }
} }

6
src/video_core/buffer_cache/buffer_cache_base.h

@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
@ -232,7 +232,7 @@ public:
void UpdateComputeBuffers(); void UpdateComputeBuffers();
void BindHostGeometryBuffers(bool is_indexed);
void BindHostGeometryBuffers(bool is_indexed, bool use_dynamic_vertex_input = false);
void BindHostStageBuffers(size_t stage); void BindHostStageBuffers(size_t stage);
@ -358,7 +358,7 @@ private:
void BindHostIndexBuffer(); void BindHostIndexBuffer();
void BindHostVertexBuffers();
void BindHostVertexBuffers(bool use_dynamic_vertex_input = false);
void BindHostDrawIndirectBuffers(); void BindHostDrawIndirectBuffers();

5
src/video_core/renderer_opengl/gl_buffer_cache.cpp

@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // 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? // TODO: Should HostBindings provide the correct runtime types to avoid these transforms?
std::array<GLuint, 32> buffer_handles; std::array<GLuint, 32> buffer_handles;
std::array<GLsizei, 32> buffer_strides; std::array<GLsizei, 32> buffer_strides;

5
src/video_core/renderer_opengl/gl_buffer_cache.h

@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
@ -101,7 +101,8 @@ public:
void BindVertexBuffer(u32 index, Buffer& buffer, u32 offset, u32 size, u32 stride); 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);
void BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer, u32 offset, u32 size); void BindUniformBuffer(size_t stage, u32 binding_index, Buffer& buffer, u32 offset, u32 size);

4
src/video_core/renderer_opengl/gl_graphics_pipeline.cpp

@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
@ -436,7 +436,7 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
bind_stage_info(4); bind_stage_info(4);
} }
buffer_cache.UpdateGraphicsBuffers(is_indexed); buffer_cache.UpdateGraphicsBuffers(is_indexed);
buffer_cache.BindHostGeometryBuffers(is_indexed);
buffer_cache.BindHostGeometryBuffers(is_indexed, false);
if (!IsBuilt()) { if (!IsBuilt()) {
WaitForBuild(); WaitForBuild();

10
src/video_core/renderer_vulkan/vk_buffer_cache.cpp

@ -551,11 +551,12 @@ 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) {
if (index >= device.GetMaxVertexInputBindings()) { if (index >= device.GetMaxVertexInputBindings()) {
return; return;
} }
if (device.IsExtExtendedDynamicStateSupported()) {
if (use_dynamic_vertex_input && device.IsExtExtendedDynamicStateSupported()) {
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;
@ -574,7 +575,8 @@ void BufferCacheRuntime::BindVertexBuffer(u32 index, VkBuffer buffer, u32 offset
} }
} }
void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings) {
void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings,
bool use_dynamic_vertex_input) {
boost::container::small_vector<VkBuffer, 32> buffer_handles; boost::container::small_vector<VkBuffer, 32> buffer_handles;
for (u32 index = 0; index < bindings.buffers.size(); ++index) { for (u32 index = 0; index < bindings.buffers.size(); ++index) {
auto handle = bindings.buffers[index]->Handle(); auto handle = bindings.buffers[index]->Handle();
@ -595,7 +597,7 @@ void BufferCacheRuntime::BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bi
if (binding_count == 0) { if (binding_count == 0) {
return; return;
} }
if (device.IsExtExtendedDynamicStateSupported()) {
if (use_dynamic_vertex_input && device.IsExtExtendedDynamicStateSupported()) {
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) {

8
src/video_core/renderer_vulkan/vk_buffer_cache.h

@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
@ -123,9 +123,11 @@ public:
void BindQuadIndexBuffer(PrimitiveTopology topology, u32 first, u32 count); 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);
void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings);
void BindVertexBuffers(VideoCommon::HostBindings<Buffer>& bindings,
bool use_dynamic_vertex_input);
void BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size); void BindTransformFeedbackBuffer(u32 index, VkBuffer buffer, u32 offset, u32 size);

3
src/video_core/renderer_vulkan/vk_graphics_pipeline.cpp

@ -459,7 +459,7 @@ bool GraphicsPipeline::ConfigureImpl(bool is_indexed) {
} }
buffer_cache.UpdateGraphicsBuffers(is_indexed); buffer_cache.UpdateGraphicsBuffers(is_indexed);
buffer_cache.BindHostGeometryBuffers(is_indexed);
buffer_cache.BindHostGeometryBuffers(is_indexed, HasDynamicVertexInput());
guest_descriptor_queue.Acquire(); guest_descriptor_queue.Acquire();
@ -519,6 +519,7 @@ void GraphicsPipeline::ConfigureDraw(const RescalingPushConstant& rescaling,
uses_render_area = render_area.uses_render_area, uses_render_area = render_area.uses_render_area,
render_area_data = render_area.words](vk::CommandBuffer cmdbuf) { render_area_data = render_area.words](vk::CommandBuffer cmdbuf) {
if (bind_pipeline) { if (bind_pipeline) {
if (pre_bind_callback) pre_bind_callback(cmdbuf);
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline); cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_GRAPHICS, *pipeline);
} }
cmdbuf.PushConstants(*pipeline_layout, VK_SHADER_STAGE_ALL_GRAPHICS, cmdbuf.PushConstants(*pipeline_layout, VK_SHADER_STAGE_ALL_GRAPHICS,

8
src/video_core/renderer_vulkan/vk_graphics_pipeline.h

@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // 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_descriptor_pool.h"
#include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/renderer_vulkan/vk_texture_cache.h"
#include "video_core/vulkan_common/vulkan_wrapper.h" #include "video_core/vulkan_common/vulkan_wrapper.h"
#include <functional>
namespace VideoCore { namespace VideoCore {
class ShaderNotify; class ShaderNotify;
@ -128,6 +129,9 @@ public:
gpu_memory = gpu_memory_; gpu_memory = gpu_memory_;
} }
void SetPreBindCallback(std::function<void(vk::CommandBuffer)> cb) { pre_bind_callback = std::move(cb); }
void ClearPreBindCallback() { pre_bind_callback = {};}
private: private:
template <typename Spec> template <typename Spec>
bool ConfigureImpl(bool is_indexed); bool ConfigureImpl(bool is_indexed);
@ -135,6 +139,8 @@ private:
void ConfigureDraw(const RescalingPushConstant& rescaling, void ConfigureDraw(const RescalingPushConstant& rescaling,
const RenderAreaPushConstant& render_are); const RenderAreaPushConstant& render_are);
std::function<void(vk::CommandBuffer)> pre_bind_callback;
void MakePipeline(VkRenderPass render_pass); void MakePipeline(VkRenderPass render_pass);
void Validate(); void Validate();

677
src/video_core/renderer_vulkan/vk_rasterizer.cpp

@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
@ -225,6 +225,9 @@ void RasterizerVulkan::PrepareDraw(bool is_indexed, Func&& draw_func) {
UpdateDynamicStates(); UpdateDynamicStates();
pipeline->SetPreBindCallback([this](vk::CommandBuffer cmdbuf) { RecordDynamicStates(cmdbuf); });
SCOPE_EXIT { pipeline->ClearPreBindCallback(); };
if (!pipeline->Configure(is_indexed)) if (!pipeline->Configure(is_indexed))
return; return;
@ -1047,6 +1050,219 @@ 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()) {
const VkStencilOpState front_state{
.failOp = static_cast<VkStencilOp>(regs.stencil_front_fail),
.passOp = static_cast<VkStencilOp>(regs.stencil_front_pass),
.depthFailOp = static_cast<VkStencilOp>(regs.stencil_front_depth_fail),
.compareOp = static_cast<VkCompareOp>(regs.stencil_front_compare),
.compareMask = regs.stencil_front_mask,
.writeMask = regs.stencil_front_write_mask,
.reference = regs.stencil_front_reference,
};
const VkStencilOpState back_state{
.failOp = static_cast<VkStencilOp>(regs.stencil_back_fail),
.passOp = static_cast<VkStencilOp>(regs.stencil_back_pass),
.depthFailOp = static_cast<VkStencilOp>(regs.stencil_back_depth_fail),
.compareOp = static_cast<VkCompareOp>(regs.stencil_back_compare),
.compareMask = regs.stencil_back_mask,
.writeMask = regs.stencil_back_write_mask,
.reference = regs.stencil_back_reference,
};
cmdbuf.SetStencilOpEXT(front_state, back_state);
if (state_tracker.TouchStencilReference()) {
cmdbuf.SetStencilReference(front_state.reference, back_state.reference);
}
}
// Line width
if (state_tracker.TouchLineWidth()) {
cmdbuf.SetLineWidth(regs.line_width);
}
// 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() { void RasterizerVulkan::HandleTransformFeedback() {
static std::once_flag warn_unsupported; static std::once_flag warn_unsupported;
@ -1072,7 +1288,7 @@ void RasterizerVulkan::HandleTransformFeedback() {
} }
} }
void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs) {
void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf) {
if (!state_tracker.TouchViewports()) { if (!state_tracker.TouchViewports()) {
return; return;
} }
@ -1093,9 +1309,11 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
.minDepth = 0.0f, .minDepth = 0.0f,
.maxDepth = 1.0f, .maxDepth = 1.0f,
}; };
scheduler.Record([viewport](vk::CommandBuffer cmdbuf) {
cmdbuf.SetViewport(0, viewport);
});
if (cmdbuf) {
cmdbuf->SetViewport(0, viewport);
} else {
scheduler.Record([viewport](vk::CommandBuffer cmdbuf) { cmdbuf.SetViewport(0, viewport); });
}
return; return;
} }
const bool is_rescaling{texture_cache.IsRescaling()}; const bool is_rescaling{texture_cache.IsRescaling()};
@ -1110,14 +1328,20 @@ void RasterizerVulkan::UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& reg
GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale), GetViewportState(device, regs, 12, scale), GetViewportState(device, regs, 13, scale),
GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale), GetViewportState(device, regs, 14, scale), GetViewportState(device, regs, 15, scale),
}; };
scheduler.Record([this, viewport_list](vk::CommandBuffer cmdbuf) {
if (cmdbuf) {
const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports); const u32 num_viewports = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
const vk::Span<VkViewport> viewports(viewport_list.data(), num_viewports); const vk::Span<VkViewport> viewports(viewport_list.data(), num_viewports);
cmdbuf.SetViewport(0, viewports);
});
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchScissors()) { if (!state_tracker.TouchScissors()) {
return; return;
} }
@ -1134,9 +1358,11 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
scissor.offset.y = static_cast<int32_t>(y); scissor.offset.y = static_cast<int32_t>(y);
scissor.extent.width = width; scissor.extent.width = width;
scissor.extent.height = height; scissor.extent.height = height;
scheduler.Record([scissor](vk::CommandBuffer cmdbuf) {
cmdbuf.SetScissor(0, scissor);
});
if (cmdbuf) {
cmdbuf->SetScissor(0, scissor);
} else {
scheduler.Record([scissor](vk::CommandBuffer cmdbuf) { cmdbuf.SetScissor(0, scissor); });
}
return; return;
} }
u32 up_scale = 1; u32 up_scale = 1;
@ -1163,14 +1389,20 @@ void RasterizerVulkan::UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs
GetScissorState(regs, 14, up_scale, down_shift), GetScissorState(regs, 14, up_scale, down_shift),
GetScissorState(regs, 15, up_scale, down_shift), GetScissorState(regs, 15, up_scale, down_shift),
}; };
scheduler.Record([this, scissor_list](vk::CommandBuffer cmdbuf) {
if (cmdbuf) {
const u32 num_scissors = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports); const u32 num_scissors = std::min<u32>(device.GetMaxViewports(), Maxwell::NumViewports);
const vk::Span<VkRect2D> scissors(scissor_list.data(), num_scissors); const vk::Span<VkRect2D> scissors(scissor_list.data(), num_scissors);
cmdbuf.SetScissor(0, scissors);
});
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchDepthBias()) { if (!state_tracker.TouchDepthBias()) {
return; return;
} }
@ -1197,8 +1429,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 (cmdbuf) {
if (device.IsExtDepthBiasControlSupported()) { if (device.IsExtDepthBiasControlSupported()) {
static VkDepthBiasRepresentationInfoEXT bias_info{ static VkDepthBiasRepresentationInfoEXT bias_info{
.sType = VK_STRUCTURE_TYPE_DEPTH_BIAS_REPRESENTATION_INFO_EXT, .sType = VK_STRUCTURE_TYPE_DEPTH_BIAS_REPRESENTATION_INFO_EXT,
@ -1208,32 +1439,57 @@ void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) {
.depthBiasExact = VK_FALSE, .depthBiasExact = VK_FALSE,
}; };
cmdbuf.SetDepthBias(constant, clamp, factor, &bias_info);
cmdbuf->SetDepthBias(units, regs.depth_bias_clamp, regs.slope_scale_depth_bias, &bias_info);
} else { } else {
cmdbuf.SetDepthBias(constant, clamp, factor);
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchBlendConstants()) { if (!state_tracker.TouchBlendConstants()) {
return; 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(
[blend_color](vk::CommandBuffer cmdbuf) { cmdbuf.SetBlendConstants(blend_color.data()); });
if (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchDepthBounds()) { if (!state_tracker.TouchDepthBounds()) {
return; return;
} }
scheduler.Record([min = regs.depth_bounds[0], max = regs.depth_bounds[1]](
vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthBounds(min, max); });
if (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchStencilProperties()) { if (!state_tracker.TouchStencilProperties()) {
return; return;
} }
@ -1257,17 +1513,25 @@ void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs)
return; 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 (cmdbuf) {
const bool set_back = regs.stencil_two_side_enable && regs.stencil_front_ref != regs.stencil_back_ref;
cmdbuf->SetStencilReference(set_back ? VK_STENCIL_FACE_FRONT_BIT : VK_STENCIL_FACE_FRONT_AND_BACK,
regs.stencil_front_ref);
if (set_back) { if (set_back) {
cmdbuf.SetStencilReference(VK_STENCIL_FACE_BACK_BIT, back_ref);
cmdbuf->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) { if (update_write_mask) {
@ -1282,18 +1546,26 @@ void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs)
return; 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 (cmdbuf) {
const bool set_back = regs.stencil_two_side_enable && regs.stencil_front_mask != regs.stencil_back_mask;
cmdbuf->SetStencilWriteMask(set_back ? VK_STENCIL_FACE_FRONT_BIT : VK_STENCIL_FACE_FRONT_AND_BACK,
regs.stencil_front_mask);
if (set_back) { if (set_back) {
cmdbuf.SetStencilWriteMask(VK_STENCIL_FACE_BACK_BIT, back_write_mask);
cmdbuf->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) { if (update_compare_masks) {
@ -1308,40 +1580,56 @@ void RasterizerVulkan::UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs)
return; 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 (cmdbuf) {
const bool set_back = regs.stencil_two_side_enable && regs.stencil_front_func_mask != regs.stencil_back_func_mask;
cmdbuf->SetStencilCompareMask(set_back ? VK_STENCIL_FACE_FRONT_BIT : VK_STENCIL_FACE_FRONT_AND_BACK,
regs.stencil_front_func_mask);
if (set_back) { if (set_back) {
cmdbuf.SetStencilCompareMask(VK_STENCIL_FACE_BACK_BIT, back_test_mask);
cmdbuf->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(); state_tracker.ClearStencilReset();
} }
void RasterizerVulkan::UpdateLineWidth(Tegra::Engines::Maxwell3D::Regs& regs) {
void RasterizerVulkan::UpdateLineWidth(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf) {
if (!state_tracker.TouchLineWidth()) { if (!state_tracker.TouchLineWidth()) {
return; 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 (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchCullMode()) { if (!state_tracker.TouchCullMode()) {
return; 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 (cmdbuf) {
cmdbuf->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) {
@ -1358,43 +1646,51 @@ void RasterizerVulkan::UpdateDepthBoundsTestEnable(Tegra::Engines::Maxwell3D::Re
}); });
} }
void RasterizerVulkan::UpdateDepthTestEnable(Tegra::Engines::Maxwell3D::Regs& regs) {
void RasterizerVulkan::UpdateDepthTestEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf) {
if (!state_tracker.TouchDepthTestEnable()) { if (!state_tracker.TouchDepthTestEnable()) {
return; return;
} }
scheduler.Record([enable = regs.depth_test_enable](vk::CommandBuffer cmdbuf) {
cmdbuf.SetDepthTestEnableEXT(enable);
});
if (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchDepthWriteEnable()) { if (!state_tracker.TouchDepthWriteEnable()) {
return; return;
} }
scheduler.Record([enable = regs.depth_write_enabled](vk::CommandBuffer cmdbuf) {
cmdbuf.SetDepthWriteEnableEXT(enable);
});
if (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchPrimitiveRestartEnable()) { if (!state_tracker.TouchPrimitiveRestartEnable()) {
return; return;
} }
scheduler.Record([enable = regs.primitive_restart.enabled](vk::CommandBuffer cmdbuf) {
cmdbuf.SetPrimitiveRestartEnableEXT(enable);
});
if (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchRasterizerDiscardEnable()) { if (!state_tracker.TouchRasterizerDiscardEnable()) {
return; return;
} }
scheduler.Record([disable = regs.rasterize_enable](vk::CommandBuffer cmdbuf) {
cmdbuf.SetRasterizerDiscardEnableEXT(disable == 0);
});
if (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchConservativeRasterizationMode()) { if (!state_tracker.TouchConservativeRasterizationMode()) {
return; return;
} }
@ -1402,15 +1698,20 @@ void RasterizerVulkan::UpdateConservativeRasterizationMode(Tegra::Engines::Maxwe
if (!device.SupportsDynamicState3ConservativeRasterizationMode()) { if (!device.SupportsDynamicState3ConservativeRasterizationMode()) {
return; 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 (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchLineStippleEnable()) { if (!state_tracker.TouchLineStippleEnable()) {
return; return;
} }
@ -1418,13 +1719,16 @@ void RasterizerVulkan::UpdateLineStippleEnable(Tegra::Engines::Maxwell3D::Regs&
if (!device.SupportsDynamicState3LineStippleEnable()) { if (!device.SupportsDynamicState3LineStippleEnable()) {
return; return;
} }
scheduler.Record([enable = regs.line_stipple_enable](vk::CommandBuffer cmdbuf) {
cmdbuf.SetLineStippleEnableEXT(enable);
});
if (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!device.IsExtLineRasterizationSupported()) { if (!device.IsExtLineRasterizationSupported()) {
return; return;
} }
@ -1456,12 +1760,16 @@ void RasterizerVulkan::UpdateLineRasterizationMode(Tegra::Engines::Maxwell3D::Re
}); });
} }
} }
scheduler.Record([mode](vk::CommandBuffer cmdbuf) {
cmdbuf.SetLineRasterizationModeEXT(mode);
});
if (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchDepthBiasEnable()) { if (!state_tracker.TouchDepthBiasEnable()) {
return; return;
} }
@ -1492,23 +1800,30 @@ void RasterizerVulkan::UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& re
}; };
const u32 topology_index = static_cast<u32>(maxwell3d->draw_manager->GetDrawState().topology); const u32 topology_index = static_cast<u32>(maxwell3d->draw_manager->GetDrawState().topology);
const u32 enable = enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]]; const u32 enable = enabled_lut[POLYGON_OFFSET_ENABLE_LUT[topology_index]];
scheduler.Record(
[enable](vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthBiasEnableEXT(enable != 0); });
if (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchLogicOpEnable()) { if (!state_tracker.TouchLogicOpEnable()) {
return; return;
} }
if (!device.SupportsDynamicState3LogicOpEnable()) { if (!device.SupportsDynamicState3LogicOpEnable()) {
return; return;
} }
scheduler.Record([enable = regs.logic_op.enable](vk::CommandBuffer cmdbuf) {
cmdbuf.SetLogicOpEnableEXT(enable != 0);
});
if (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchDepthClampEnable()) { if (!state_tracker.TouchDepthClampEnable()) {
return; return;
} }
@ -1521,11 +1836,14 @@ void RasterizerVulkan::UpdateDepthClampEnable(Tegra::Engines::Maxwell3D::Regs& r
Maxwell::ViewportClipControl::GeometryClip::FrustumXYZ || Maxwell::ViewportClipControl::GeometryClip::FrustumXYZ ||
regs.viewport_clip_control.geometry_clip == regs.viewport_clip_control.geometry_clip ==
Maxwell::ViewportClipControl::GeometryClip::FrustumZ); Maxwell::ViewportClipControl::GeometryClip::FrustumZ);
scheduler.Record(
[is_enabled](vk::CommandBuffer cmdbuf) { cmdbuf.SetDepthClampEnableEXT(is_enabled); });
if (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchAlphaToCoverageEnable()) { if (!state_tracker.TouchAlphaToCoverageEnable()) {
return; return;
} }
@ -1535,12 +1853,16 @@ void RasterizerVulkan::UpdateAlphaToCoverageEnable(Tegra::Engines::Maxwell3D::Re
GraphicsPipeline* const pipeline = pipeline_cache.CurrentGraphicsPipeline(); GraphicsPipeline* const pipeline = pipeline_cache.CurrentGraphicsPipeline();
const bool enable = pipeline != nullptr && pipeline->SupportsAlphaToCoverage() && const bool enable = pipeline != nullptr && pipeline->SupportsAlphaToCoverage() &&
regs.anti_alias_alpha_control.alpha_to_coverage != 0; regs.anti_alias_alpha_control.alpha_to_coverage != 0;
scheduler.Record([enable](vk::CommandBuffer cmdbuf) {
cmdbuf.SetAlphaToCoverageEnableEXT(enable ? VK_TRUE : VK_FALSE);
});
if (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchAlphaToOneEnable()) { if (!state_tracker.TouchAlphaToOneEnable()) {
return; return;
} }
@ -1555,21 +1877,29 @@ void RasterizerVulkan::UpdateAlphaToOneEnable(Tegra::Engines::Maxwell3D::Regs& r
GraphicsPipeline* const pipeline = pipeline_cache.CurrentGraphicsPipeline(); GraphicsPipeline* const pipeline = pipeline_cache.CurrentGraphicsPipeline();
const bool enable = pipeline != nullptr && pipeline->SupportsAlphaToOne() && const bool enable = pipeline != nullptr && pipeline->SupportsAlphaToOne() &&
regs.anti_alias_alpha_control.alpha_to_one != 0; regs.anti_alias_alpha_control.alpha_to_one != 0;
scheduler.Record([enable](vk::CommandBuffer cmdbuf) {
cmdbuf.SetAlphaToOneEnableEXT(enable ? VK_TRUE : VK_FALSE);
});
if (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchDepthCompareOp()) { if (!state_tracker.TouchDepthCompareOp()) {
return; return;
} }
scheduler.Record([func = regs.depth_test_func](vk::CommandBuffer cmdbuf) {
cmdbuf.SetDepthCompareOpEXT(MaxwellToVK::ComparisonOp(func));
});
if (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchFrontFace()) { if (!state_tracker.TouchFrontFace()) {
return; return;
} }
@ -1579,11 +1909,14 @@ void RasterizerVulkan::UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs) {
front_face = front_face == VK_FRONT_FACE_CLOCKWISE ? VK_FRONT_FACE_COUNTER_CLOCKWISE front_face = front_face == VK_FRONT_FACE_CLOCKWISE ? VK_FRONT_FACE_COUNTER_CLOCKWISE
: VK_FRONT_FACE_CLOCKWISE; : VK_FRONT_FACE_CLOCKWISE;
} }
scheduler.Record(
[front_face](vk::CommandBuffer cmdbuf) { cmdbuf.SetFrontFaceEXT(front_face); });
if (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchStencilOp()) { if (!state_tracker.TouchStencilOp()) {
return; return;
} }
@ -1597,37 +1930,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_zfail = regs.stencil_back_op.zfail;
const Maxwell::StencilOp::Op back_zpass = regs.stencil_back_op.zpass; const Maxwell::StencilOp::Op back_zpass = regs.stencil_back_op.zpass;
const Maxwell::ComparisonOp back_compare = regs.stencil_back_op.func; 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 (cmdbuf) {
cmdbuf->SetStencilOpEXT(VK_STENCIL_FACE_FRONT_BIT, MaxwellToVK::StencilOp(fail),
MaxwellToVK::StencilOp(zpass), MaxwellToVK::StencilOp(zfail), MaxwellToVK::StencilOp(zpass), MaxwellToVK::StencilOp(zfail),
MaxwellToVK::ComparisonOp(compare)); MaxwellToVK::ComparisonOp(compare));
cmdbuf.SetStencilOpEXT(VK_STENCIL_FACE_BACK_BIT, MaxwellToVK::StencilOp(back_fail),
cmdbuf->SetStencilOpEXT(VK_STENCIL_FACE_BACK_BIT, MaxwellToVK::StencilOp(back_fail),
MaxwellToVK::StencilOp(back_zpass), MaxwellToVK::StencilOp(back_zpass),
MaxwellToVK::StencilOp(back_zfail), MaxwellToVK::StencilOp(back_zfail),
MaxwellToVK::ComparisonOp(back_compare)); 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 { } else {
// Front face defines the stencil op of both faces // 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 (cmdbuf) {
cmdbuf->SetStencilOpEXT(VK_STENCIL_FACE_FRONT_AND_BACK, MaxwellToVK::StencilOp(fail),
MaxwellToVK::StencilOp(zpass), MaxwellToVK::StencilOp(zfail), MaxwellToVK::StencilOp(zpass), MaxwellToVK::StencilOp(zfail),
MaxwellToVK::ComparisonOp(compare)); 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* cmdbuf) {
if (!state_tracker.TouchLogicOp()) { if (!state_tracker.TouchLogicOp()) {
return; return;
} }
const auto op_value = static_cast<u32>(regs.logic_op.op); 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) auto op = op_value >= 0x1500 && op_value < 0x1510 ? static_cast<VkLogicOp>(op_value - 0x1500)
: VK_LOGIC_OP_NO_OP; : VK_LOGIC_OP_NO_OP;
scheduler.Record([op](vk::CommandBuffer cmdbuf) { cmdbuf.SetLogicOpEXT(op); });
if (cmdbuf) {
cmdbuf->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* cmdbuf) {
if (!state_tracker.TouchBlending()) { if (!state_tracker.TouchBlending()) {
return; return;
} }
@ -1650,9 +2003,13 @@ void RasterizerVulkan::UpdateBlending(Tegra::Engines::Maxwell3D::Regs& regs) {
current |= VK_COLOR_COMPONENT_A_BIT; current |= VK_COLOR_COMPONENT_A_BIT;
} }
} }
scheduler.Record([setup_masks](vk::CommandBuffer cmdbuf) {
cmdbuf.SetColorWriteMaskEXT(0, setup_masks);
});
if (cmdbuf) {
cmdbuf->SetColorWriteMaskEXT(0, setup_masks);
} else {
scheduler.Record([setup_masks](vk::CommandBuffer cmdbuf) {
cmdbuf.SetColorWriteMaskEXT(0, setup_masks);
});
}
} }
if (state_tracker.TouchBlendEnable()) { if (state_tracker.TouchBlendEnable()) {
@ -1660,9 +2017,13 @@ void RasterizerVulkan::UpdateBlending(Tegra::Engines::Maxwell3D::Regs& regs) {
std::ranges::transform( std::ranges::transform(
regs.blend.enable, setup_enables.begin(), regs.blend.enable, setup_enables.begin(),
[&](const auto& is_enabled) { return is_enabled != 0 ? VK_TRUE : VK_FALSE; }); [&](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 (cmdbuf) {
cmdbuf->SetColorBlendEnableEXT(0, setup_enables);
} else {
scheduler.Record([setup_enables](vk::CommandBuffer cmdbuf) {
cmdbuf.SetColorBlendEnableEXT(0, setup_enables);
});
}
} }
if (state_tracker.TouchBlendEquations()) { if (state_tracker.TouchBlendEquations()) {
@ -1702,22 +2063,30 @@ void RasterizerVulkan::UpdateBlending(Tegra::Engines::Maxwell3D::Regs& regs) {
} }
} }
scheduler.Record([setup_blends](vk::CommandBuffer cmdbuf) {
cmdbuf.SetColorBlendEquationEXT(0, setup_blends);
});
if (cmdbuf) {
cmdbuf->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) {
void RasterizerVulkan::UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf) {
if (!state_tracker.TouchStencilTestEnable()) { if (!state_tracker.TouchStencilTestEnable()) {
return; return;
} }
scheduler.Record([enable = regs.stencil_enable](vk::CommandBuffer cmdbuf) {
cmdbuf.SetStencilTestEnableEXT(enable);
});
if (cmdbuf) {
cmdbuf->SetStencilTestEnableEXT(regs.stencil_enable);
} else {
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* cmdbuf) {
auto& dirty{maxwell3d->dirty.flags}; auto& dirty{maxwell3d->dirty.flags};
if (!dirty[Dirty::VertexInput]) { if (!dirty[Dirty::VertexInput]) {
return; return;
@ -1770,9 +2139,13 @@ void RasterizerVulkan::UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs)
.divisor = is_instanced ? input_binding.frequency : 1, .divisor = is_instanced ? input_binding.frequency : 1,
}); });
} }
scheduler.Record([bindings, attributes](vk::CommandBuffer cmdbuf) {
cmdbuf.SetVertexInputEXT(bindings, attributes);
});
if (cmdbuf) {
cmdbuf->SetVertexInputEXT(bindings, attributes);
} else {
scheduler.Record([bindings, attributes](vk::CommandBuffer cmdbuf) {
cmdbuf.SetVertexInputEXT(bindings, attributes);
});
}
} }
void RasterizerVulkan::InitializeChannel(Tegra::Control::ChannelState& channel) { void RasterizerVulkan::InitializeChannel(Tegra::Control::ChannelState& channel) {

65
src/video_core/renderer_vulkan/vk_rasterizer.h

@ -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-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
@ -161,37 +161,38 @@ private:
void HandleTransformFeedback(); 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 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 UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs);
void UpdateViewportsState(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateScissorsState(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateBlendConstants(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateDepthBounds(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateStencilFaces(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateLineWidth(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateCullMode(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateDepthBoundsTestEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateDepthTestEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateDepthWriteEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateDepthCompareOp(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdatePrimitiveRestartEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateRasterizerDiscardEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateConservativeRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateLineStippleEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateLineStipple(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateLineRasterizationMode(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateDepthBiasEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateLogicOpEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateDepthClampEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateAlphaToCoverageEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateAlphaToOneEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateFrontFace(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateStencilOp(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateStencilTestEnable(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateLogicOp(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateBlending(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void UpdateVertexInput(Tegra::Engines::Maxwell3D::Regs& regs, vk::CommandBuffer* cmdbuf = nullptr);
void RecordDynamicStates(vk::CommandBuffer cmdbuf);
Tegra::GPU& gpu; Tegra::GPU& gpu;
Tegra::MaxwellDeviceMemoryManager& device_memory; Tegra::MaxwellDeviceMemoryManager& device_memory;

14
src/video_core/vulkan_common/vulkan_device.cpp

@ -663,11 +663,6 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
"allowing Eden to use {} (75%) to avoid heap exhaustion", "allowing Eden to use {} (75%) to avoid heap exhaustion",
sampler_limit, reserved, sampler_heap_budget); sampler_limit, reserved, sampler_heap_budget);
} }
// Qualcomm proprietary drivers have issues with MSAA->MSAA image blits.
LOG_WARNING(Render_Vulkan,
"Qualcomm drivers do not support MSAA->MSAA image blits. "
"MSAA scaling will use 3D helpers. MSAA resolves work normally.");
cant_blit_msaa = true;
} }
if (extensions.sampler_filter_minmax && is_amd) { if (extensions.sampler_filter_minmax && is_amd) {
@ -1259,7 +1254,6 @@ bool Device::GetSuitability(bool requires_swapchain) {
features.extended_dynamic_state3.extendedDynamicState3LogicOpEnable = false; features.extended_dynamic_state3.extendedDynamicState3LogicOpEnable = false;
} }
// Return whether we were suitable.
return suitable; return suitable;
} }
@ -1360,7 +1354,6 @@ void Device::RemoveUnsuitableExtensions() {
VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME); VK_EXT_EXTENDED_DYNAMIC_STATE_3_EXTENSION_NAME);
// VK_EXT_robustness2 // VK_EXT_robustness2
// Enable if at least one robustness2 feature is available
extensions.robustness_2 = features.robustness2.robustBufferAccess2 || extensions.robustness_2 = features.robustness2.robustBufferAccess2 ||
features.robustness2.robustImageAccess2 || features.robustness2.robustImageAccess2 ||
features.robustness2.nullDescriptor; features.robustness2.nullDescriptor;
@ -1369,7 +1362,6 @@ void Device::RemoveUnsuitableExtensions() {
VK_EXT_ROBUSTNESS_2_EXTENSION_NAME); VK_EXT_ROBUSTNESS_2_EXTENSION_NAME);
// VK_EXT_image_robustness // VK_EXT_image_robustness
// Enable if robustImageAccess is available
extensions.image_robustness = features.image_robustness.robustImageAccess; extensions.image_robustness = features.image_robustness.robustImageAccess;
RemoveExtensionFeatureIfUnsuitable(extensions.image_robustness, features.image_robustness, RemoveExtensionFeatureIfUnsuitable(extensions.image_robustness, features.image_robustness,
VK_EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME); VK_EXT_IMAGE_ROBUSTNESS_EXTENSION_NAME);
@ -1523,15 +1515,15 @@ void Device::RemoveUnsuitableExtensions() {
RemoveExtensionFeatureIfUnsuitable(extensions.maintenance6, features.maintenance6, RemoveExtensionFeatureIfUnsuitable(extensions.maintenance6, features.maintenance6,
VK_KHR_MAINTENANCE_6_EXTENSION_NAME); 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); extensions.maintenance7 = loaded_extensions.contains(VK_KHR_MAINTENANCE_7_EXTENSION_NAME);
RemoveExtensionIfUnsuitable(extensions.maintenance7, 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); extensions.maintenance8 = loaded_extensions.contains(VK_KHR_MAINTENANCE_8_EXTENSION_NAME);
RemoveExtensionIfUnsuitable(extensions.maintenance8, 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); extensions.maintenance9 = loaded_extensions.contains(VK_KHR_MAINTENANCE_9_EXTENSION_NAME);
RemoveExtensionIfUnsuitable(extensions.maintenance9, VK_KHR_MAINTENANCE_9_EXTENSION_NAME); RemoveExtensionIfUnsuitable(extensions.maintenance9, VK_KHR_MAINTENANCE_9_EXTENSION_NAME);

Loading…
Cancel
Save