mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-10-06 14:09:58 +00:00
A quick topology test
This commit is contained in:
@@ -282,28 +282,68 @@ void Maxwell3D::DrawManager::DrawTexture(Maxwell3D& maxwell3d) {
|
||||
}
|
||||
|
||||
void Maxwell3D::DrawManager::UpdateTopology(Maxwell3D& maxwell3d) {
|
||||
using Topology = Maxwell3D::Regs::PrimitiveTopology;
|
||||
using Override = Maxwell3D::Regs::PrimitiveTopologyOverride;
|
||||
switch (maxwell3d.regs.primitive_topology_control) {
|
||||
case Maxwell3D::Regs::PrimitiveTopologyControl::UseInBeginMethods:
|
||||
break;
|
||||
case Maxwell3D::Regs::PrimitiveTopologyControl::UseSeparateState:
|
||||
switch (maxwell3d.regs.topology_override) {
|
||||
case Maxwell3D::Regs::PrimitiveTopologyOverride::None:
|
||||
case Override::None:
|
||||
break;
|
||||
case Maxwell3D::Regs::PrimitiveTopologyOverride::Points:
|
||||
draw_state.topology = Maxwell3D::Regs::PrimitiveTopology::Points;
|
||||
case Override::Points:
|
||||
case Override::LegacyPoints:
|
||||
draw_state.topology = Topology::Points;
|
||||
break;
|
||||
case Maxwell3D::Regs::PrimitiveTopologyOverride::Lines:
|
||||
draw_state.topology = Maxwell3D::Regs::PrimitiveTopology::Lines;
|
||||
case Override::Lines:
|
||||
case Override::LegacyLines:
|
||||
case Override::LegacyLinesImm:
|
||||
case Override::LegacyIndexedLines:
|
||||
case Override::LegacyIndexedLines2:
|
||||
draw_state.topology = Topology::Lines;
|
||||
break;
|
||||
case Maxwell3D::Regs::PrimitiveTopologyOverride::LineStrip:
|
||||
draw_state.topology = Maxwell3D::Regs::PrimitiveTopology::LineStrip;
|
||||
case Override::LineStrip:
|
||||
case Override::LegacyLineStrip:
|
||||
case Override::LegacyIndexedLineStrip:
|
||||
draw_state.topology = Topology::LineStrip;
|
||||
break;
|
||||
default:
|
||||
draw_state.topology = Maxwell3D::Regs::PrimitiveTopology(maxwell3d.regs.topology_override);
|
||||
case Override::Triangles:
|
||||
case Override::LegacyTriangles:
|
||||
case Override::LegacyIndexedTriangles:
|
||||
case Override::LegacyIndexedTriangles2:
|
||||
draw_state.topology = Topology::Triangles;
|
||||
break;
|
||||
case Override::TriangleStrip:
|
||||
case Override::LegacyTriangleStrip:
|
||||
case Override::LegacyIndexedTriangleStrip:
|
||||
draw_state.topology = Topology::TriangleStrip;
|
||||
break;
|
||||
case Override::LegacyTriangleFan:
|
||||
case Override::LegacyTriangleFanImm:
|
||||
case Override::LegacyIndexedTriangleFan:
|
||||
draw_state.topology = Topology::TriangleFan;
|
||||
break;
|
||||
case Override::LinesAdjacency:
|
||||
draw_state.topology = Topology::LinesAdjacency;
|
||||
break;
|
||||
case Override::LineStripAdjacency:
|
||||
draw_state.topology = Topology::LineStripAdjacency;
|
||||
break;
|
||||
case Override::TrianglesAdjacency:
|
||||
draw_state.topology = Topology::TrianglesAdjacency;
|
||||
break;
|
||||
case Override::TriangleStripAdjacency:
|
||||
draw_state.topology = Topology::TriangleStripAdjacency;
|
||||
break;
|
||||
case Override::Patches:
|
||||
draw_state.topology = Topology::Patches;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (u32(draw_state.topology) > u32(Topology::Patches)) {
|
||||
draw_state.topology = Topology::Triangles;
|
||||
}
|
||||
}
|
||||
|
||||
void Maxwell3D::DrawManager::ProcessDraw(Maxwell3D& maxwell3d, bool draw_indexed, u32 instance_count) {
|
||||
|
||||
@@ -78,6 +78,7 @@ set(SHADER_FILES
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vulkan_fidelityfx_fsr_easu_fp32.frag
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vulkan_fidelityfx_fsr_rcas_fp16.frag
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vulkan_fidelityfx_fsr_rcas_fp32.frag
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vulkan_indirect_quads.comp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vulkan_present.frag
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vulkan_present.vert
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/vulkan_present_scaleforce_fp16.frag
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#version 460 core
|
||||
|
||||
layout (local_size_x = 32) in;
|
||||
|
||||
layout (std430, set = 0, binding = 0) readonly buffer InputBuffer {
|
||||
uint input_commands[];
|
||||
};
|
||||
|
||||
layout (std430, set = 0, binding = 1) writeonly buffer OutputBuffer {
|
||||
uint output_commands[];
|
||||
};
|
||||
|
||||
layout (push_constant) uniform PushConstants {
|
||||
uint num_draws;
|
||||
uint src_stride;
|
||||
};
|
||||
|
||||
void main() {
|
||||
uint draw = gl_GlobalInvocationID.x;
|
||||
if (draw >= num_draws) {
|
||||
return;
|
||||
}
|
||||
uint src = draw * src_stride;
|
||||
uint dst = draw * 5;
|
||||
output_commands[dst + 0] = input_commands[src + 0] / 4 * 6;
|
||||
output_commands[dst + 1] = input_commands[src + 1];
|
||||
output_commands[dst + 2] = input_commands[src + 2] / 4 * 6;
|
||||
output_commands[dst + 3] = input_commands[src + 3];
|
||||
output_commands[dst + 4] = input_commands[src + 4];
|
||||
}
|
||||
@@ -62,6 +62,10 @@ bool IsTopologySafe(Maxwell3D::Regs::PrimitiveTopology topology) {
|
||||
}
|
||||
}
|
||||
|
||||
bool IsTopologySafeIndexedIndirect(Maxwell3D::Regs::PrimitiveTopology topology) {
|
||||
return IsTopologySafe(topology) || topology == Maxwell3D::Regs::PrimitiveTopology::Quads;
|
||||
}
|
||||
|
||||
} // Anonymous namespace
|
||||
|
||||
void HLE_DrawArraysIndirect::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
|
||||
@@ -125,7 +129,7 @@ void HLE_DrawArraysIndirect::Fallback(Core::System& system, Engines::Maxwell3D&
|
||||
|
||||
void HLE_DrawIndexedIndirect::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
|
||||
auto topology = static_cast<Maxwell3D::Regs::PrimitiveTopology>(parameters[0]);
|
||||
if (!maxwell3d.AnyParametersDirty() || !IsTopologySafe(topology)) {
|
||||
if (!maxwell3d.AnyParametersDirty() || !IsTopologySafeIndexedIndirect(topology)) {
|
||||
Fallback(system, maxwell3d, parameters);
|
||||
return;
|
||||
}
|
||||
@@ -198,7 +202,7 @@ void HLE_MultiLayerClear::Execute(Core::System& system, Engines::Maxwell3D& maxw
|
||||
}
|
||||
void HLE_MultiDrawIndexedIndirectCount::Execute(Core::System& system, Engines::Maxwell3D& maxwell3d, std::span<const u32> parameters, [[maybe_unused]] u32 method) {
|
||||
const auto topology = Maxwell3D::Regs::PrimitiveTopology(parameters[2]);
|
||||
if (IsTopologySafe(topology)) {
|
||||
if (IsTopologySafeIndexedIndirect(topology)) {
|
||||
const u32 start_indirect = parameters[0];
|
||||
const u32 end_indirect = parameters[1];
|
||||
if (start_indirect >= end_indirect) {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "video_core/host_shaders/queries_prefix_scan_sum_comp_spv.h"
|
||||
#include "video_core/host_shaders/queries_prefix_scan_sum_nosubgroups_comp_spv.h"
|
||||
#include "video_core/host_shaders/resolve_conditional_render_comp_spv.h"
|
||||
#include "video_core/host_shaders/vulkan_indirect_quads_comp_spv.h"
|
||||
#include "video_core/host_shaders/vulkan_quad_indexed_comp_spv.h"
|
||||
#include "video_core/host_shaders/vulkan_uint8_comp_spv.h"
|
||||
#include "video_core/renderer_vulkan/vk_compute_pass.h"
|
||||
@@ -375,6 +376,56 @@ std::pair<VkBuffer, VkDeviceSize> QuadIndexedPass::Assemble(
|
||||
return {staging.buffer, staging.offset};
|
||||
}
|
||||
|
||||
IndirectQuadsPass::IndirectQuadsPass(const Device& device_, Scheduler& scheduler_,
|
||||
DescriptorPool& descriptor_pool_,
|
||||
StagingBufferPool& staging_buffer_pool_,
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
|
||||
: ComputePass(device_, scheduler_, descriptor_pool_, INPUT_OUTPUT_DESCRIPTOR_SET_BINDINGS,
|
||||
INPUT_OUTPUT_DESCRIPTOR_UPDATE_TEMPLATE, INPUT_OUTPUT_BANK_INFO,
|
||||
COMPUTE_PUSH_CONSTANT_RANGE<sizeof(u32) * 2>, VULKAN_INDIRECT_QUADS_COMP_SPV),
|
||||
scheduler{scheduler_}, staging_buffer_pool{staging_buffer_pool_},
|
||||
compute_pass_descriptor_queue{compute_pass_descriptor_queue_} {}
|
||||
|
||||
IndirectQuadsPass::~IndirectQuadsPass() = default;
|
||||
|
||||
std::pair<VkBuffer, VkDeviceSize> IndirectQuadsPass::Assemble(u32 num_draws, u32 stride,
|
||||
VkBuffer src_buffer, u32 src_offset) {
|
||||
u32 src_stride = stride / static_cast<u32>(sizeof(u32));
|
||||
if (src_stride < COMMAND_WORDS) {
|
||||
src_stride = COMMAND_WORDS;
|
||||
}
|
||||
const u32 input_size = num_draws * src_stride * static_cast<u32>(sizeof(u32));
|
||||
const std::size_t staging_size = std::size_t(num_draws) * COMMAND_WORDS * sizeof(u32);
|
||||
const auto staging = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal);
|
||||
|
||||
compute_pass_descriptor_queue.Acquire(scheduler, 2);
|
||||
compute_pass_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size);
|
||||
compute_pass_descriptor_queue.AddBuffer(staging.buffer, staging.offset, staging_size);
|
||||
const void* const descriptor_data{compute_pass_descriptor_queue.UpdateData()};
|
||||
|
||||
scheduler.RequestOutsideRenderPassOperationContext();
|
||||
scheduler.Record([this, descriptor_data, num_draws, src_stride](vk::CommandBuffer cmdbuf) {
|
||||
static constexpr u32 DISPATCH_SIZE = 32;
|
||||
static constexpr VkMemoryBarrier WRITE_BARRIER{
|
||||
.sType = VK_STRUCTURE_TYPE_MEMORY_BARRIER,
|
||||
.pNext = nullptr,
|
||||
.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT,
|
||||
.dstAccessMask = VK_ACCESS_INDIRECT_COMMAND_READ_BIT,
|
||||
};
|
||||
const std::array<u32, 2> push_constants{num_draws, src_stride};
|
||||
const VkDescriptorSet set = descriptor_allocator.Commit();
|
||||
device.GetLogical().UpdateDescriptorSet(set, *descriptor_template, descriptor_data);
|
||||
cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, *pipeline);
|
||||
cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, *layout, 0, set, {});
|
||||
cmdbuf.PushConstants(*layout, VK_SHADER_STAGE_COMPUTE_BIT, 0, sizeof(push_constants),
|
||||
&push_constants);
|
||||
cmdbuf.Dispatch(Common::DivCeil(num_draws, DISPATCH_SIZE), 1, 1);
|
||||
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
|
||||
VK_PIPELINE_STAGE_DRAW_INDIRECT_BIT, 0, WRITE_BARRIER);
|
||||
});
|
||||
return {staging.buffer, staging.offset};
|
||||
}
|
||||
|
||||
ConditionalRenderingResolvePass::ConditionalRenderingResolvePass(
|
||||
const Device& device_, Scheduler& scheduler_, DescriptorPool& descriptor_pool_,
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_)
|
||||
|
||||
@@ -88,6 +88,25 @@ private:
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
||||
};
|
||||
|
||||
class IndirectQuadsPass final : public ComputePass {
|
||||
public:
|
||||
explicit IndirectQuadsPass(const Device& device_, Scheduler& scheduler_,
|
||||
DescriptorPool& descriptor_pool_,
|
||||
StagingBufferPool& staging_buffer_pool_,
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue_);
|
||||
~IndirectQuadsPass();
|
||||
|
||||
static constexpr u32 COMMAND_WORDS = 5;
|
||||
|
||||
std::pair<VkBuffer, VkDeviceSize> Assemble(u32 num_draws, u32 stride, VkBuffer src_buffer,
|
||||
u32 src_offset);
|
||||
|
||||
private:
|
||||
Scheduler& scheduler;
|
||||
StagingBufferPool& staging_buffer_pool;
|
||||
ComputePassDescriptorQueue& compute_pass_descriptor_queue;
|
||||
};
|
||||
|
||||
class ConditionalRenderingResolvePass final : public ComputePass {
|
||||
public:
|
||||
explicit ConditionalRenderingResolvePass(
|
||||
|
||||
@@ -212,6 +212,8 @@ RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra
|
||||
compute_pass_descriptor_queue(device, UpdateDescriptorQueue::COMPUTE_FRAME_PAYLOAD_SIZE),
|
||||
descriptor_buffer_ring(device, memory_allocator),
|
||||
blit_image(device, scheduler, state_tracker, descriptor_pool), render_pass_cache(device),
|
||||
indirect_quads_pass(device, scheduler, descriptor_pool, staging_pool,
|
||||
compute_pass_descriptor_queue),
|
||||
texture_cache_runtime{
|
||||
device, scheduler, memory_allocator, staging_pool,
|
||||
blit_image, render_pass_cache, descriptor_pool, compute_pass_descriptor_queue},
|
||||
@@ -314,6 +316,18 @@ void RasterizerVulkan::DrawIndirect() {
|
||||
const auto indirect_buffer = buffer_cache.GetDrawIndirectBuffer();
|
||||
const auto& buffer = indirect_buffer.first;
|
||||
const auto& offset = indirect_buffer.second;
|
||||
VkBuffer command_buffer = buffer->Handle();
|
||||
VkDeviceSize command_offset = offset;
|
||||
u32 command_stride = static_cast<u32>(params.stride);
|
||||
if (params.is_indexed &&
|
||||
maxwell3d->draw_manager.draw_state.topology == Maxwell::PrimitiveTopology::Quads) {
|
||||
const auto patched = indirect_quads_pass.Assemble(
|
||||
static_cast<u32>(params.max_draw_counts), command_stride, command_buffer,
|
||||
static_cast<u32>(offset));
|
||||
command_buffer = patched.first;
|
||||
command_offset = patched.second;
|
||||
command_stride = IndirectQuadsPass::COMMAND_WORDS * static_cast<u32>(sizeof(u32));
|
||||
}
|
||||
if (params.is_byte_count) {
|
||||
scheduler.Record([buffer_obj = buffer->Handle(), offset,
|
||||
stride = params.stride](vk::CommandBuffer cmdbuf) {
|
||||
@@ -326,29 +340,32 @@ void RasterizerVulkan::DrawIndirect() {
|
||||
const auto count = buffer_cache.GetDrawIndirectCount();
|
||||
const auto& draw_buffer = count.first;
|
||||
const auto& offset_base = count.second;
|
||||
scheduler.Record([draw_buffer_obj = draw_buffer->Handle(),
|
||||
buffer_obj = buffer->Handle(), offset_base, offset,
|
||||
scheduler.Record([draw_buffer_obj = draw_buffer->Handle(), command_buffer,
|
||||
offset_base, command_offset, command_stride,
|
||||
params](vk::CommandBuffer cmdbuf) {
|
||||
if (params.is_indexed) {
|
||||
cmdbuf.DrawIndexedIndirectCount(
|
||||
buffer_obj, offset, draw_buffer_obj, offset_base,
|
||||
static_cast<u32>(params.max_draw_counts), static_cast<u32>(params.stride));
|
||||
cmdbuf.DrawIndexedIndirectCount(command_buffer, command_offset, draw_buffer_obj,
|
||||
offset_base,
|
||||
static_cast<u32>(params.max_draw_counts),
|
||||
command_stride);
|
||||
} else {
|
||||
cmdbuf.DrawIndirectCount(buffer_obj, offset, draw_buffer_obj, offset_base,
|
||||
cmdbuf.DrawIndirectCount(command_buffer, command_offset, draw_buffer_obj,
|
||||
offset_base,
|
||||
static_cast<u32>(params.max_draw_counts),
|
||||
static_cast<u32>(params.stride));
|
||||
command_stride);
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
scheduler.Record([buffer_obj = buffer->Handle(), offset, params](vk::CommandBuffer cmdbuf) {
|
||||
scheduler.Record([command_buffer, command_offset, command_stride,
|
||||
params](vk::CommandBuffer cmdbuf) {
|
||||
if (params.is_indexed) {
|
||||
cmdbuf.DrawIndexedIndirect(buffer_obj, offset,
|
||||
cmdbuf.DrawIndexedIndirect(command_buffer, command_offset,
|
||||
static_cast<u32>(params.max_draw_counts),
|
||||
static_cast<u32>(params.stride));
|
||||
command_stride);
|
||||
} else {
|
||||
cmdbuf.DrawIndirect(buffer_obj, offset, static_cast<u32>(params.max_draw_counts),
|
||||
static_cast<u32>(params.stride));
|
||||
cmdbuf.DrawIndirect(command_buffer, command_offset,
|
||||
static_cast<u32>(params.max_draw_counts), command_stride);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/renderer_vulkan/blit_image.h"
|
||||
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
||||
#include "video_core/renderer_vulkan/vk_compute_pass.h"
|
||||
#include "video_core/renderer_vulkan/vk_descriptor_buffer.h"
|
||||
#include "video_core/renderer_vulkan/vk_descriptor_pool.h"
|
||||
#include "video_core/renderer_vulkan/vk_fence_manager.h"
|
||||
@@ -211,6 +212,7 @@ private:
|
||||
DescriptorBufferRing descriptor_buffer_ring;
|
||||
BlitImageHelper blit_image;
|
||||
RenderPassCache render_pass_cache;
|
||||
IndirectQuadsPass indirect_quads_pass;
|
||||
|
||||
TextureCacheRuntime texture_cache_runtime;
|
||||
TextureCache texture_cache;
|
||||
|
||||
@@ -211,7 +211,8 @@ StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage
|
||||
.size = 1ULL << log2_size,
|
||||
.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT |
|
||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT,
|
||||
VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT |
|
||||
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT,
|
||||
.sharingMode = VK_SHARING_MODE_EXCLUSIVE,
|
||||
.queueFamilyIndexCount = 0,
|
||||
.pQueueFamilyIndices = nullptr,
|
||||
|
||||
Reference in New Issue
Block a user