Fix three-vertex rectangle rendering

This commit is contained in:
nmzik
2026-09-20 15:25:06 +04:00
parent 25f2699523
commit 0ad9149c90
4 changed files with 102 additions and 26 deletions
+4
View File
@@ -26,6 +26,10 @@ enum class PrimitiveType : uint32_t {
kPolygon = 21,
};
constexpr bool IsRectList(PrimitiveType type) {
return type == PrimitiveType::kRectList || type == PrimitiveType::kRectListLegacy;
}
enum class IndexType : uint32_t {
kIndex16 = 0,
kIndex32 = 1,
@@ -755,8 +755,7 @@ PipelineCache::Pipeline& PipelineCache::GetGraphicsPipeline(
static_params.depth_bounds_test_enable = depth.depth_bounds_test_enable;
static_params.depth_min_bounds = depth.depth_min_bounds;
static_params.depth_max_bounds = depth.depth_max_bounds;
const bool rect_list =
command.GetUserConfig().GetPrimType() == Prospero::PrimitiveType::kRectList;
const bool rect_list = Prospero::IsRectList(command.GetUserConfig().GetPrimType());
static_params.cull_back = !rect_list && mc.cull_back;
static_params.cull_front = !rect_list && mc.cull_front;
static_params.face = mc.face;
+9 -24
View File
@@ -790,8 +790,7 @@ static void SetDrawDebugPhase(CommandBuffer& buffer, uint64_t submit_id, const D
draw.instance_count, draw.first_instance);
}
static bool GetDrawTopology(const HW::UserConfig& ucfg, bool auto_draw,
vk::PrimitiveTopology& topology) {
static bool GetDrawTopology(const HW::UserConfig& ucfg, vk::PrimitiveTopology& topology) {
topology = vk::PrimitiveTopology::ePointList;
@@ -817,13 +816,8 @@ static bool GetDrawTopology(const HW::UserConfig& ucfg, bool auto_draw,
if (!Config::TessellationEnabled()) return false;
[[fallthrough]];
case Prospero::PrimitiveType::kRectList:
topology = vk::PrimitiveTopology::ePatchList;
break;
case Prospero::PrimitiveType::kRectListLegacy:
if (!auto_draw) {
EXIT("unknown primitive type: %u\n", static_cast<uint32_t>(ucfg.GetPrimType()));
}
topology = vk::PrimitiveTopology::eTriangleStrip;
topology = vk::PrimitiveTopology::ePatchList;
break;
case Prospero::PrimitiveType::kQuadListLegacy:
topology = vk::PrimitiveTopology::eTriangleFan;
@@ -1002,8 +996,7 @@ static void LogDrawStateIfNeeded(const CommandBuffer& buffer, const DrawCallInfo
return;
}
if (!draw.IsIndexed() &&
buffer.GetUserConfig().GetPrimType() != Prospero::PrimitiveType::kRectListLegacy) {
if (!draw.IsIndexed() && !Prospero::IsRectList(buffer.GetUserConfig().GetPrimType())) {
return;
}
@@ -1016,8 +1009,7 @@ static void LogDrawStateIfNeeded(const CommandBuffer& buffer, const DrawCallInfo
}
static void EmitDrawPrimitives(const HW::UserConfig& ucfg, vk::CommandBuffer vk_buffer,
const ShaderVertexInputInfo& vs_input_info, const DrawCallInfo& draw,
const DrawEmitInfo& emit) {
const DrawCallInfo& draw, const DrawEmitInfo& emit) {
switch (ucfg.GetPrimType()) {
case Prospero::PrimitiveType::kPointList:
case Prospero::PrimitiveType::kLineList:
@@ -1026,6 +1018,7 @@ static void EmitDrawPrimitives(const HW::UserConfig& ucfg, vk::CommandBuffer vk_
case Prospero::PrimitiveType::kTriFan:
case Prospero::PrimitiveType::kTriStrip:
case Prospero::PrimitiveType::kRectList:
case Prospero::PrimitiveType::kRectListLegacy:
case Prospero::PrimitiveType::kPatch:
if (draw.IsIndexed()) {
vk_buffer.drawIndexed(draw.index_count, draw.instance_count, 0, emit.vertex_offset,
@@ -1035,14 +1028,6 @@ static void EmitDrawPrimitives(const HW::UserConfig& ucfg, vk::CommandBuffer vk_
emit.first_instance);
}
break;
case Prospero::PrimitiveType::kRectListLegacy:
if (draw.IsIndexed()) {
EXIT("unknown primitive type: %u\n", static_cast<uint32_t>(ucfg.GetPrimType()));
}
// Sarah
EXIT_NOT_IMPLEMENTED(!(draw.index_count == 3 && vs_input_info.buffers_num == 0));
vk_buffer.draw(4, draw.instance_count, emit.first_vertex, emit.first_instance);
break;
case Prospero::PrimitiveType::kQuadListLegacy:
EXIT_NOT_IMPLEMENTED((draw.index_count & 0x3u) != 0);
for (uint32_t i = 0; i < draw.index_count; i += 4) {
@@ -1185,7 +1170,7 @@ void RenderExecutor::ExecutePreparedDraw(uint64_t submit_id, CommandBuffer& buff
if (mesh_active) {
vk_buffer.drawMeshTasksEXT(mesh_groups, draw.instance_count, 1);
} else {
EmitDrawPrimitives(ucfg, vk_buffer, state.vertex_info[0], draw, emit);
EmitDrawPrimitives(ucfg, vk_buffer, draw, emit);
}
if (!draw.IsIndexed()) {
@@ -1261,7 +1246,7 @@ void RenderExecutor::DrawIndex(uint64_t submit_id, CommandBuffer& buffer,
hw_check(buffer);
vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList;
if (!GetDrawTopology(ucfg, false, topology)) {
if (!GetDrawTopology(ucfg, topology)) {
return;
}
@@ -1371,7 +1356,7 @@ void RenderExecutor::DrawAuto(uint64_t submit_id, CommandBuffer& buffer, const D
args.vertex_count, args.instance_count, args.first_instance};
vk::PrimitiveTopology topology = vk::PrimitiveTopology::ePointList;
if (!GetDrawTopology(ucfg, true, topology)) {
if (!GetDrawTopology(ucfg, topology)) {
ResetBindings();
return;
}
@@ -1381,7 +1366,7 @@ void RenderExecutor::DrawAuto(uint64_t submit_id, CommandBuffer& buffer, const D
return;
}
const bool rect_list = ucfg.GetPrimType() == Prospero::PrimitiveType::kRectList;
const bool rect_list = Prospero::IsRectList(ucfg.GetPrimType());
if (rect_list && state.vertex_info[0].buffers_num == 0 &&
state.vertex_info[0].stage.program->param_export_mask == 0 &&
state.ps_input_info.input_num != 0) {
+88
View File
@@ -12831,6 +12831,7 @@ public:
const uint32_t extent = depth_feedback ? 8 : 32;
constexpr uintptr_t depth_address = 0x0000000204400000ull;
constexpr uint64_t allocation_size = 0x40000;
constexpr uint64_t rect_address = depth_address + 0x8000;
EnsureRuntimeContext();
RenderContext context(m_runtime_context);
auto &scheduler = context.GetCommandScheduler();
@@ -12865,6 +12866,15 @@ public:
static_cast<float *>(mapped)[y * 64 + x] = initial_depth(x, y);
}
}
if (!depth_feedback && !packed_vertex_color) {
// Rectangle input contains three position/UV records.
constexpr std::array<float, 24> rect_vertices{
-0.75f, -0.75f, 0, 0, 0, 0, 0, 0,
0.75f, -0.75f, 0, 0, 1, 0, 0, 0,
-0.75f, 0.75f, 0, 0, 0, 1, 0, 0};
std::memcpy(reinterpret_cast<void *>(rect_address), rect_vertices.data(),
sizeof(rect_vertices));
}
resources.MapMemory(depth_address, allocation_size);
if (depth_feedback) {
depth.desc.type = BindingType::DepthTarget;
@@ -13521,6 +13531,82 @@ public:
Require(name, "sparse MRT3 output", sparse_pixels[component] == expected,
"MRT3 was compacted to a different slot or clipped by unused MRT0");
}
// A fourth VS invocation reads beyond the descriptor instead of reconstructing the corner.
const ShaderBufferResource rect_buffer{{
static_cast<u32>(rect_address),
static_cast<u32>(rect_address >> 32u) | (32u << 16u), 3,
DstSel(4, 5, 6, 7) |
(static_cast<u32>(Prospero::BufferFormat::k32Float) << 12u)}};
static const auto rect_vertex_code = [] {
std::vector<u32> code{
EncodeMubuf0(0x0d, 0, true, false), EncodeMubuf1(0, 2, 5),
EncodeMubuf0(0x0d, 16, true, false), EncodeMubuf1(2, 2, 5)};
AppendVMovU32(&code, 4, 0);
AppendVMovLiteral(&code, 6, 0x3f800000u);
code.insert(code.end(), {EncodeExp0(0x0c, 0xf), EncodeExp1(0, 1, 4, 6),
EncodeExp0(0x20, 0xf), EncodeExp1(2, 3, 4, 6)});
AppendEnd(&code);
return code;
}();
static const auto rect_pixel_code = [] {
std::vector<u32> code;
for (u32 component = 0; component < 2; component++) {
code.push_back(EncodeVintrp(0, 20 + component, 0, component, 0));
code.push_back(EncodeVintrp(1, 20 + component, 0, component, 1));
}
AppendVMovU32(&code, 22, 0);
AppendVMovLiteral(&code, 23, 0x3f800000u);
code.insert(code.end(), {EncodeExp0(0x03, 0xf), EncodeExp1(20, 21, 22, 23)});
AppendEnd(&code);
return code;
}();
const auto rect_vs = reinterpret_cast<uint64_t>(rect_vertex_code.data());
const auto rect_ps = reinterpret_cast<uint64_t>(rect_pixel_code.data());
ShaderMapUserData(rect_vs,
{.type = Prospero::ShaderBinaryType::kGs, .user_data = &native_user_data,
.code_size_bytes = static_cast<u32>(rect_vertex_code.size() * sizeof(u32))});
ShaderMapUserData(rect_ps,
{.type = Prospero::ShaderBinaryType::kPs,
.code_size_bytes = static_cast<u32>(rect_pixel_code.size() * sizeof(u32))});
shaders.SetEsShaderBase(rect_vs);
shaders.SetPsShaderBase(rect_ps);
shaders.SetGsShaderResource2({.user_sgpr = 4});
for (u32 i = 0; i < 4; i++) {
shaders.SetGsUserSgpr(i, rect_buffer.fields[i], HW::UserSgprType::Vsharp);
}
registers.SetPsInControl(0x8001);
registers.SetPsInputEna(2);
registers.SetPsInputAddr(2);
registers.SetPsInputSettings(0, 0);
for (const auto primitive : {Prospero::PrimitiveType::kRectList,
Prospero::PrimitiveType::kRectListLegacy}) {
const char *rect_name = primitive == Prospero::PrimitiveType::kRectList
? "RectListThreeRecords" : "LegacyRectListThreeRecords";
user_config.SetPrimitiveType(primitive);
registers.SetModeControl({});
TextureCacheTestAccess::ClearImage(cache, scheduler.Current(), sparse_color.image_id,
{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}, {});
RenderExecutorTestAccess::DrawAuto(
executor, scheduler.Current(), {.vertex_count = 3, .instance_count = 1});
const auto pixels = ReadCachedTexel(name, context, sparse_color.image_id,
{}, {extent, extent, 1});
for (u32 y = 0; y < extent; y++) {
for (u32 x = 0; x < extent; x++) {
const bool inside = x >= 4 && x < 28 && y >= 4 && y < 28;
const auto offset = 4 * (y * extent + x);
const std::array<float, 4> expected{
inside ? (x + 0.5f - 4) / 24 : 0,
inside ? (y + 0.5f - 4) / 24 : 0, 0, inside ? 1.0f : 0};
for (u32 component = 0; component < 4; component++) {
Require(rect_name, "three-vertex rectangle coverage and UV",
std::abs(std::bit_cast<float>(pixels[offset + component]) -
expected[component]) < 0.0001f,
"rectangle reconstruction lost its fourth corner or interpolated UVs");
}
}
}
}
DestroyBuffer(&stencil_readback);
vertex_shader = owned_vertex_shader;
@@ -15011,6 +15097,7 @@ private:
Require("VulkanHarness", "graphics", available_features12.shaderOutputLayer == true,
"vertex layer output is not supported");
Require("VulkanHarness", "graphics", available_features.fillModeNonSolid &&
available_features.tessellationShader &&
available_depth_clip.depthClipEnable && available_clip_control.depthClipControl &&
available_color_write.colorWriteEnable &&
available_feedback_layout.attachmentFeedbackLoopLayout &&
@@ -15076,6 +15163,7 @@ private:
device_features.sampleRateShading = true;
device_features.shaderInt64 = true;
device_features.fillModeNonSolid = true;
device_features.tessellationShader = true;
device_info.pEnabledFeatures = &device_features;
constexpr const char *device_extensions[] = {
VK_KHR_PUSH_DESCRIPTOR_EXTENSION_NAME,