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:
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:
LOG_CRITICAL(Render_Vulkan, "Unimplemented vertex attribute format!");
LOG_CRITICAL(Render_Vulkan, "Unimplemented vertex attribute type {}", attrib.type.Value());
UNREACHABLE();
}

View File

@ -330,14 +330,12 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
u32 vs_input_index_max) {
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
* 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
* 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
* or interleave them in the same loader.
*/
// 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
// 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
// as something analogous to Vulkan bindings. The user can store attributes in separate loaders
// or interleave them in the same loader.
const auto& regs = Pica::g_state.regs;
const auto& vertex_attributes = regs.pipeline.vertex_attributes;
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<u64, 16> binding_offsets{};
u32 buffer_offset = 0;
u32 buffer_offset = array_offset;
for (const auto& loader : vertex_attributes.attribute_loaders) {
if (loader.component_count == 0 || loader.byte_count == 0) {
continue;
@ -401,13 +399,14 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
binding.stride.Assign(loader.byte_count);
// 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;
buffer_offset += data_size;
}
// Reserve the last binding for fixed attributes
u32 offset = 0;
bool has_fixed_binding = false;
for (std::size_t i = 0; i < 16; i++) {
if (vertex_attributes.IsDefaultAttribute(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());
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++);
attribute.binding.Assign(layout.binding_count);
attribute.location.Assign(reg);
@ -435,18 +428,28 @@ void RasterizerVulkan::SetupVertexArray(u32 vs_input_size, u32 vs_input_index_mi
offset += 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;
vertex_buffer.Commit(vs_input_size);
vertex_buffer.Commit(buffer_offset - array_offset);
std::array<vk::Buffer, 16> buffers;
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();
command_buffer.bindVertexBuffers(0, layout.binding_count, buffers.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);
pipeline_info.rasterization.topology.Assign(regs.pipeline.triangle_topology);
pipeline_cache.BindPipeline(pipeline_info);
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);
// 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 {
command_buffer.draw(regs.pipeline.num_vertices, 1, 0, 0);
}

View File

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