renderer_vulkan: Begin hardware shader support

* Still experimental and works only with homebrew
This commit is contained in:
GPUCode
2022-10-08 14:10:44 +03:00
parent 523120e03d
commit 9a1cf869f9
3 changed files with 48 additions and 37 deletions

View File

@ -90,8 +90,17 @@ vk::Format ToVkAttributeFormat(VertexAttribute attrib) {
case 4: case 4:
return vk::Format::eR32G32B32A32Sfloat; return vk::Format::eR32G32B32A32Sfloat;
} }
case AttribType::Ubyte:
switch (attrib.size) {
case 4:
return vk::Format::eR8G8B8A8Uint;
default:
fmt::print("{}\n", attrib.size.Value());
UNREACHABLE();
}
default: default:
LOG_CRITICAL(Render_Vulkan, "Unimplemented vertex attribute format!"); LOG_CRITICAL(Render_Vulkan, "Unimplemented vertex attribute type {}", attrib.type.Value());
UNREACHABLE(); UNREACHABLE();
} }

View File

@ -330,14 +330,12 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
u32 vs_input_index_max) { u32 vs_input_index_max) {
auto [array_ptr, array_offset, _] = vertex_buffer.Map(vs_input_size, 4); auto [array_ptr, array_offset, _] = vertex_buffer.Map(vs_input_size, 4);
/** // The Nintendo 3DS has 12 attribute loaders which are used to tell the GPU
* The Nintendo 3DS has 12 attribute loaders which are used to tell the GPU // how to interpret vertex data. The program firsts sets GPUREG_ATTR_BUF_BASE to the base
* how to interpret vertex data. The program firsts sets GPUREG_ATTR_BUF_BASE to the base // address containing the vertex array data. The data for each attribute loader (i) can be found
* address containing the vertex array data. The data for each attribute loader (i) can be found // by adding GPUREG_ATTR_BUFi_OFFSET to the base address. Attribute loaders can be thought
* by adding GPUREG_ATTR_BUFi_OFFSET to the base address. Attribute loaders can be thought // as something analogous to Vulkan bindings. The user can store attributes in separate loaders
* as something analogous to Vulkan bindings. The user can store attributes in separate loaders // or interleave them in the same loader.
* or interleave them in the same loader.
*/
const auto& regs = Pica::g_state.regs; const auto& regs = Pica::g_state.regs;
const auto& vertex_attributes = regs.pipeline.vertex_attributes; const auto& vertex_attributes = regs.pipeline.vertex_attributes;
PAddr base_address = vertex_attributes.GetPhysicalBaseAddress(); // GPUREG_ATTR_BUF_BASE PAddr base_address = vertex_attributes.GetPhysicalBaseAddress(); // GPUREG_ATTR_BUF_BASE
@ -346,7 +344,7 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
std::array<bool, 16> enable_attributes{}; std::array<bool, 16> enable_attributes{};
std::array<u64, 16> binding_offsets{}; std::array<u64, 16> binding_offsets{};
u32 buffer_offset = 0; u32 buffer_offset = array_offset;
for (const auto& loader : vertex_attributes.attribute_loaders) { for (const auto& loader : vertex_attributes.attribute_loaders) {
if (loader.component_count == 0 || loader.byte_count == 0) { if (loader.component_count == 0 || loader.byte_count == 0) {
continue; continue;
@ -401,13 +399,14 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
binding.stride.Assign(loader.byte_count); binding.stride.Assign(loader.byte_count);
// Keep track of the binding offsets so we can bind the vertex buffer later // Keep track of the binding offsets so we can bind the vertex buffer later
binding_offsets[layout.binding_count++] = array_offset + buffer_offset; binding_offsets[layout.binding_count++] = buffer_offset;
array_ptr += data_size; array_ptr += data_size;
buffer_offset += data_size; buffer_offset += data_size;
} }
// Reserve the last binding for fixed attributes // Reserve the last binding for fixed attributes
u32 offset = 0; u32 offset = 0;
bool has_fixed_binding = false;
for (std::size_t i = 0; i < 16; i++) { for (std::size_t i = 0; i < 16; i++) {
if (vertex_attributes.IsDefaultAttribute(i)) { if (vertex_attributes.IsDefaultAttribute(i)) {
const u32 reg = regs.vs.GetRegisterForAttribute(i); const u32 reg = regs.vs.GetRegisterForAttribute(i);
@ -420,12 +419,6 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
const u32 data_size = sizeof(float) * static_cast<u32>(data.size()); const u32 data_size = sizeof(float) * static_cast<u32>(data.size());
std::memcpy(array_ptr, data.data(), data_size); std::memcpy(array_ptr, data.data(), data_size);
// Define the binding. Note that the counter is not incremented
VertexBinding& binding = layout.bindings.at(layout.binding_count);
binding.binding.Assign(layout.binding_count);
binding.fixed.Assign(1);
binding.stride.Assign(offset);
VertexAttribute& attribute = layout.attributes.at(layout.attribute_count++); VertexAttribute& attribute = layout.attributes.at(layout.attribute_count++);
attribute.binding.Assign(layout.binding_count); attribute.binding.Assign(layout.binding_count);
attribute.location.Assign(reg); attribute.location.Assign(reg);
@ -435,18 +428,28 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
offset += data_size; offset += data_size;
array_ptr += data_size; array_ptr += data_size;
binding_offsets[layout.binding_count] = array_offset + buffer_offset; has_fixed_binding = true;
} }
} }
} }
if (has_fixed_binding) {
VertexBinding& binding = layout.bindings.at(layout.binding_count);
binding.binding.Assign(layout.binding_count);
binding.fixed.Assign(1);
binding.stride.Assign(offset);
binding_offsets[layout.binding_count++] = buffer_offset;
buffer_offset += offset;
}
pipeline_info.vertex_layout = layout; pipeline_info.vertex_layout = layout;
vertex_buffer.Commit(vs_input_size); vertex_buffer.Commit(buffer_offset - array_offset);
std::array<vk::Buffer, 16> buffers; std::array<vk::Buffer, 16> buffers;
buffers.fill(vertex_buffer.GetHandle()); buffers.fill(vertex_buffer.GetHandle());
// Bind the vertex buffers with all the bindings // Bind the vertex buffer with all the bindings
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
command_buffer.bindVertexBuffers(0, layout.binding_count, buffers.data(), command_buffer.bindVertexBuffers(0, layout.binding_count, buffers.data(),
binding_offsets.data()); binding_offsets.data());
@ -503,6 +506,7 @@ bool RasterizerVulkan::AccelerateDrawBatchInternal(bool is_indexed) {
} }
SetupVertexArray(vs_input_size, vs_input_index_min, vs_input_index_max); SetupVertexArray(vs_input_size, vs_input_index_min, vs_input_index_max);
pipeline_info.rasterization.topology.Assign(regs.pipeline.triangle_topology);
pipeline_cache.BindPipeline(pipeline_info); pipeline_cache.BindPipeline(pipeline_info);
vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer(); vk::CommandBuffer command_buffer = scheduler.GetRenderCommandBuffer();
@ -528,7 +532,7 @@ bool RasterizerVulkan::AccelerateDrawBatchInternal(bool is_indexed) {
command_buffer.bindIndexBuffer(index_buffer.GetHandle(), index_offset, index_type); command_buffer.bindIndexBuffer(index_buffer.GetHandle(), index_offset, index_type);
// Submit draw // Submit draw
command_buffer.drawIndexed(regs.pipeline.num_vertices, 1, 0, 0, 0); command_buffer.drawIndexed(regs.pipeline.num_vertices, 1, 0, -vs_input_index_min, 0);
} else { } else {
command_buffer.draw(regs.pipeline.num_vertices, 1, 0, 0); command_buffer.draw(regs.pipeline.num_vertices, 1, 0, 0);
} }

View File

@ -8,6 +8,7 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/core.h" #include "core/core.h"
#include "video_core/pica_state.h" #include "video_core/pica_state.h"
#include "video_core/renderer_opengl/gl_shader_decompiler.h"
#include "video_core/renderer_vulkan/vk_shader_gen.h" #include "video_core/renderer_vulkan/vk_shader_gen.h"
#include "video_core/video_core.h" #include "video_core/video_core.h"
@ -1586,8 +1587,8 @@ void main() {
std::optional<std::string> GenerateVertexShader(const Pica::Shader::ShaderSetup& setup, std::optional<std::string> GenerateVertexShader(const Pica::Shader::ShaderSetup& setup,
const PicaVSConfig& config) { const PicaVSConfig& config) {
/*std::string out = "#extension GL_ARB_separate_shader_objects : enable\n"; std::string out = "#extension GL_ARB_separate_shader_objects : enable\n";
out += ShaderDecompiler::GetCommonDeclarations(); out += OpenGL::ShaderDecompiler::GetCommonDeclarations();
std::array<bool, 16> used_regs{}; std::array<bool, 16> used_regs{};
const auto get_input_reg = [&used_regs](u32 reg) { const auto get_input_reg = [&used_regs](u32 reg) {
@ -1604,18 +1605,19 @@ std::optional<std::string> GenerateVertexShader(const Pica::Shader::ShaderSetup&
return ""; return "";
}; };
auto program_source_opt = ShaderDecompiler::DecompileProgram( auto program_source_opt = OpenGL::ShaderDecompiler::DecompileProgram(
setup.program_code, setup.swizzle_data, config.state.main_offset, get_input_reg, setup.program_code, setup.swizzle_data, config.state.main_offset, get_input_reg,
get_output_reg, config.state.sanitize_mul); get_output_reg, config.state.sanitize_mul);
if (!program_source_opt) if (!program_source_opt) {
return std::nullopt; return std::nullopt;
}
std::string& program_source = program_source_opt->code; std::string& program_source = program_source_opt->code;
out += R"( out += R"(
#define uniforms vs_uniforms #define uniforms vs_uniforms
layout (std140) uniform vs_config { layout (set = 0, binding = 0, std140) uniform vs_config {
pica_uniforms uniforms; pica_uniforms uniforms;
}; };
@ -1623,15 +1625,14 @@ layout (std140) uniform vs_config {
// input attributes declaration // input attributes declaration
for (std::size_t i = 0; i < used_regs.size(); ++i) { for (std::size_t i = 0; i < used_regs.size(); ++i) {
if (used_regs[i]) { if (used_regs[i]) {
out += fmt::format("layout(location = {0}) in vec4 vs_in_reg{0};\n", i); out += fmt::format("layout(location = {0}) in {1}vec4 vs_in_reg{0};\n", i, i == 3 ? "" : "");
} }
} }
out += '\n'; out += '\n';
// output attributes declaration // output attributes declaration
for (u32 i = 0; i < config.state.num_outputs; ++i) { for (u32 i = 0; i < config.state.num_outputs; ++i) {
out += "layout(location = " + std::to_string(i) + ") out vec4 vs_out_attr" + out += fmt::format("layout(location = {}) out vec4 vs_out_attr{};\n", i, i);
std::to_string(i) + ";\n";
} }
out += "\nvoid main() {\n"; out += "\nvoid main() {\n";
@ -1642,19 +1643,17 @@ std::to_string(i) + ";\n";
out += program_source; out += program_source;
return {{std::move(out)}};*/ return out;
return std::nullopt;
} }
static std::string GetGSCommonSource(const PicaGSConfigCommonRaw& config) { static std::string GetGSCommonSource(const PicaGSConfigCommonRaw& config) {
/*std::string out = GetVertexInterfaceDeclaration(true, separable_shader); std::string out = GetVertexInterfaceDeclaration(true);
out += UniformBlockDef; out += UniformBlockDef;
out += ShaderDecompiler::GetCommonDeclarations(); out += OpenGL::ShaderDecompiler::GetCommonDeclarations();
out += '\n'; out += '\n';
for (u32 i = 0; i < config.vs_output_attributes; ++i) { for (u32 i = 0; i < config.vs_output_attributes; ++i) {
out += ("layout(location = " + std::to_string(i) + ") in vec4 vs_out_attr" + out += fmt::format("layout(location = {}) in vec4 vs_out_attr{}[];\n", i, i);
std::to_string(i) + "[];\n";
} }
out += R"( out += R"(
@ -1728,8 +1727,7 @@ void EmitPrim(Vertex vtx0, Vertex vtx1, Vertex vtx2) {
} }
)"; )";
return out;*/ return out;
return "";
}; };
std::string GenerateFixedGeometryShader(const PicaFixedGSConfig& config) { std::string GenerateFixedGeometryShader(const PicaFixedGSConfig& config) {