renderer_vulkan: Make some primitive state dynamic. (#2764)
Some checks failed
Build and Release / reuse (push) Has been cancelled
Build and Release / clang-format (push) Has been cancelled
Build and Release / get-info (push) Has been cancelled
Build and Release / windows-sdl (push) Has been cancelled
Build and Release / windows-qt (push) Has been cancelled
Build and Release / macos-sdl (push) Has been cancelled
Build and Release / macos-qt (push) Has been cancelled
Build and Release / linux-sdl (push) Has been cancelled
Build and Release / linux-qt (push) Has been cancelled
Build and Release / linux-sdl-gcc (push) Has been cancelled
Build and Release / linux-qt-gcc (push) Has been cancelled
Build and Release / pre-release (push) Has been cancelled

* renderer_vulkan: Make some primitive state dynamic.

* renderer_vulkan: Silence MoltenVK primitive restart warning spam.
This commit is contained in:
squidbus 2025-04-10 16:20:01 -07:00 committed by GitHub
parent 5abec2a291
commit 37d4cd091c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 105 additions and 37 deletions

View file

@ -156,6 +156,18 @@ vk::CullModeFlags CullMode(Liverpool::CullMode mode) {
}
}
vk::FrontFace FrontFace(Liverpool::FrontFace face) {
switch (face) {
case Liverpool::FrontFace::Clockwise:
return vk::FrontFace::eClockwise;
case Liverpool::FrontFace::CounterClockwise:
return vk::FrontFace::eCounterClockwise;
default:
UNREACHABLE();
return vk::FrontFace::eClockwise;
}
}
vk::BlendFactor BlendFactor(Liverpool::BlendControl::BlendFactor factor) {
using BlendFactor = Liverpool::BlendControl::BlendFactor;
switch (factor) {

View file

@ -26,6 +26,8 @@ vk::PolygonMode PolygonMode(Liverpool::PolygonMode mode);
vk::CullModeFlags CullMode(Liverpool::CullMode mode);
vk::FrontFace FrontFace(Liverpool::FrontFace mode);
vk::BlendFactor BlendFactor(Liverpool::BlendControl::BlendFactor factor);
vk::BlendOp BlendOp(Liverpool::BlendControl::BlendFunc func);

View file

@ -28,6 +28,15 @@ static constexpr std::array LogicalStageToStageBit = {
vk::ShaderStageFlagBits::eCompute,
};
static bool IsPrimitiveTopologyList(const vk::PrimitiveTopology topology) {
return topology == vk::PrimitiveTopology::ePointList ||
topology == vk::PrimitiveTopology::eLineList ||
topology == vk::PrimitiveTopology::eTriangleList ||
topology == vk::PrimitiveTopology::eLineListWithAdjacency ||
topology == vk::PrimitiveTopology::eTriangleListWithAdjacency ||
topology == vk::PrimitiveTopology::ePatchList;
}
GraphicsPipeline::GraphicsPipeline(
const Instance& instance, Scheduler& scheduler, DescriptorHeap& desc_heap,
const Shader::Profile& profile, const GraphicsPipelineKey& key_,
@ -75,19 +84,15 @@ GraphicsPipeline::GraphicsPipeline(
.pVertexAttributeDescriptions = vertex_attributes.data(),
};
auto prim_restart = key.enable_primitive_restart != 0;
if (prim_restart && IsPrimitiveListTopology() && !instance.IsListRestartSupported()) {
LOG_DEBUG(Render_Vulkan,
"Primitive restart is enabled for list topology but not supported by driver.");
prim_restart = false;
}
const auto topology = LiverpoolToVK::PrimitiveType(key.prim_type);
const vk::PipelineInputAssemblyStateCreateInfo input_assembly = {
.topology = LiverpoolToVK::PrimitiveType(key.prim_type),
.primitiveRestartEnable = prim_restart,
.topology = topology,
// Avoid warning spam on all pipelines about unsupported restart disable, if not supported.
// However, must be false for list topologies to avoid validation errors.
.primitiveRestartEnable =
!instance.IsPrimitiveRestartDisableSupported() && !IsPrimitiveTopologyList(topology),
};
ASSERT_MSG(!prim_restart || key.primitive_restart_index == 0xFFFF ||
key.primitive_restart_index == 0xFFFFFFFF,
"Primitive restart index other than -1 is not supported yet");
const bool is_rect_list = key.prim_type == AmdGpu::PrimitiveType::RectList;
const bool is_quad_list = key.prim_type == AmdGpu::PrimitiveType::QuadList;
const auto& fs_info = runtime_infos[u32(Shader::LogicalStage::Fragment)].fs_info;
@ -99,12 +104,6 @@ GraphicsPipeline::GraphicsPipeline(
.depthClampEnable = false,
.rasterizerDiscardEnable = false,
.polygonMode = LiverpoolToVK::PolygonMode(key.polygon_mode),
.cullMode = LiverpoolToVK::IsPrimitiveCulled(key.prim_type)
? LiverpoolToVK::CullMode(key.cull_mode)
: vk::CullModeFlagBits::eNone,
.frontFace = key.front_face == Liverpool::FrontFace::Clockwise
? vk::FrontFace::eClockwise
: vk::FrontFace::eCounterClockwise,
.lineWidth = 1.0f,
};
@ -122,16 +121,20 @@ GraphicsPipeline::GraphicsPipeline(
.pNext = instance.IsDepthClipControlSupported() ? &clip_control : nullptr,
};
boost::container::static_vector<vk::DynamicState, 17> dynamic_states = {
boost::container::static_vector<vk::DynamicState, 20> dynamic_states = {
vk::DynamicState::eViewportWithCountEXT, vk::DynamicState::eScissorWithCountEXT,
vk::DynamicState::eBlendConstants, vk::DynamicState::eDepthTestEnableEXT,
vk::DynamicState::eDepthWriteEnableEXT, vk::DynamicState::eDepthCompareOpEXT,
vk::DynamicState::eDepthBiasEnableEXT, vk::DynamicState::eDepthBias,
vk::DynamicState::eStencilTestEnableEXT, vk::DynamicState::eStencilReference,
vk::DynamicState::eStencilCompareMask, vk::DynamicState::eStencilWriteMask,
vk::DynamicState::eStencilOpEXT,
vk::DynamicState::eStencilOpEXT, vk::DynamicState::eCullModeEXT,
vk::DynamicState::eFrontFaceEXT,
};
if (instance.IsPrimitiveRestartDisableSupported()) {
dynamic_states.push_back(vk::DynamicState::ePrimitiveRestartEnableEXT);
}
if (instance.IsDepthBoundsSupported()) {
dynamic_states.push_back(vk::DynamicState::eDepthBoundsTestEnableEXT);
dynamic_states.push_back(vk::DynamicState::eDepthBounds);

View file

@ -42,11 +42,7 @@ struct GraphicsPipelineKey {
u32 num_samples;
u32 mrt_mask;
AmdGpu::PrimitiveType prim_type;
u32 enable_primitive_restart;
u32 primitive_restart_index;
Liverpool::PolygonMode polygon_mode;
Liverpool::CullMode cull_mode;
Liverpool::FrontFace front_face;
Liverpool::ClipSpace clip_space;
Liverpool::ColorBufferMask cb_shader_mask;
std::array<Liverpool::BlendControl, Liverpool::NumColorBuffers> blend_controls;
@ -82,16 +78,6 @@ public:
return key.mrt_mask;
}
[[nodiscard]] bool IsPrimitiveListTopology() const {
return key.prim_type == AmdGpu::PrimitiveType::PointList ||
key.prim_type == AmdGpu::PrimitiveType::LineList ||
key.prim_type == AmdGpu::PrimitiveType::TriangleList ||
key.prim_type == AmdGpu::PrimitiveType::AdjLineList ||
key.prim_type == AmdGpu::PrimitiveType::AdjTriangleList ||
key.prim_type == AmdGpu::PrimitiveType::RectList ||
key.prim_type == AmdGpu::PrimitiveType::QuadList;
}
/// Gets the attributes and bindings for vertex inputs.
template <typename Attribute, typename Binding>
void GetVertexInputs(VertexInputs<Attribute>& attributes, VertexInputs<Binding>& bindings,

View file

@ -292,6 +292,11 @@ public:
properties.limits.framebufferStencilSampleCounts;
}
/// Returns whether disabling primitive restart is supported.
bool IsPrimitiveRestartDisableSupported() const {
return driver_id != vk::DriverId::eMoltenvk;
}
private:
/// Creates the logical device opportunistically enabling extensions
bool CreateDevice();

View file

@ -283,12 +283,8 @@ bool PipelineCache::RefreshGraphicsKey() {
}
key.prim_type = regs.primitive_type;
key.enable_primitive_restart = regs.enable_primitive_restart & 1;
key.primitive_restart_index = regs.primitive_restart_index;
key.polygon_mode = regs.polygon_control.PolyMode();
key.cull_mode = regs.polygon_control.CullingMode();
key.clip_space = regs.clipper_control.clip_space;
key.front_face = regs.polygon_control.front_face;
key.num_samples = regs.NumSamples();
const bool skip_cb_binding =

View file

@ -949,6 +949,7 @@ void Rasterizer::UnmapMemory(VAddr addr, u64 size) {
void Rasterizer::UpdateDynamicState(const GraphicsPipeline& pipeline) const {
UpdateViewportScissorState();
UpdateDepthStencilState();
UpdatePrimitiveState();
auto& dynamic_state = scheduler.GetDynamicState();
dynamic_state.SetBlendConstants(&liverpool->regs.blend_constants.red);
@ -1132,6 +1133,25 @@ void Rasterizer::UpdateDepthStencilState() const {
}
}
void Rasterizer::UpdatePrimitiveState() const {
const auto& regs = liverpool->regs;
auto& dynamic_state = scheduler.GetDynamicState();
const auto prim_restart = (regs.enable_primitive_restart & 1) != 0;
ASSERT_MSG(!prim_restart || regs.primitive_restart_index == 0xFFFF ||
regs.primitive_restart_index == 0xFFFFFFFF,
"Primitive restart index other than -1 is not supported yet");
const auto cull_mode = LiverpoolToVK::IsPrimitiveCulled(regs.primitive_type)
? LiverpoolToVK::CullMode(regs.polygon_control.CullingMode())
: vk::CullModeFlagBits::eNone;
const auto front_face = LiverpoolToVK::FrontFace(regs.polygon_control.front_face);
dynamic_state.SetPrimitiveRestartEnabled(prim_restart);
dynamic_state.SetCullMode(cull_mode);
dynamic_state.SetFrontFace(front_face);
}
void Rasterizer::ScopeMarkerBegin(const std::string_view& str, bool from_guest) {
if ((from_guest && !Config::getVkGuestMarkersEnabled()) ||
(!from_guest && !Config::getVkHostMarkersEnabled())) {

View file

@ -78,6 +78,7 @@ private:
void UpdateDynamicState(const GraphicsPipeline& pipeline) const;
void UpdateViewportScissorState() const;
void UpdateDepthStencilState() const;
void UpdatePrimitiveState() const;
bool FilterDraw();

View file

@ -288,6 +288,20 @@ void DynamicState::Commit(const Instance& instance, const vk::CommandBuffer& cmd
}
}
}
if (dirty_state.primitive_restart_enable) {
dirty_state.primitive_restart_enable = false;
if (instance.IsPrimitiveRestartDisableSupported()) {
cmdbuf.setPrimitiveRestartEnableEXT(primitive_restart_enable);
}
}
if (dirty_state.cull_mode) {
dirty_state.cull_mode = false;
cmdbuf.setCullModeEXT(cull_mode);
}
if (dirty_state.front_face) {
dirty_state.front_face = false;
cmdbuf.setFrontFaceEXT(front_face);
}
if (dirty_state.blend_constants) {
dirty_state.blend_constants = false;
cmdbuf.setBlendConstants(blend_constants);

View file

@ -95,6 +95,10 @@ struct DynamicState {
bool stencil_back_write_mask : 1;
bool stencil_back_compare_mask : 1;
bool primitive_restart_enable : 1;
bool cull_mode : 1;
bool front_face : 1;
bool blend_constants : 1;
bool color_write_masks : 1;
} dirty_state{};
@ -125,6 +129,10 @@ struct DynamicState {
u32 stencil_back_write_mask{};
u32 stencil_back_compare_mask{};
bool primitive_restart_enable{};
vk::CullModeFlags cull_mode{};
vk::FrontFace front_face{};
float blend_constants[4]{};
ColorWriteMasks color_write_masks{};
@ -254,6 +262,27 @@ struct DynamicState {
}
}
void SetPrimitiveRestartEnabled(const bool enabled) {
if (primitive_restart_enable != enabled) {
primitive_restart_enable = enabled;
dirty_state.primitive_restart_enable = true;
}
}
void SetCullMode(const vk::CullModeFlags cull_mode_) {
if (cull_mode != cull_mode_) {
cull_mode = cull_mode_;
dirty_state.cull_mode = true;
}
}
void SetFrontFace(const vk::FrontFace front_face_) {
if (front_face != front_face_) {
front_face = front_face_;
dirty_state.front_face = true;
}
}
void SetBlendConstants(const float blend_constants_[4]) {
if (!std::equal(blend_constants, std::end(blend_constants), blend_constants_)) {
std::memcpy(blend_constants, blend_constants_, sizeof(blend_constants));