renderer_vulkan: Begin hardware shader support
* Still experimental and works only with homebrew
This commit is contained in:
@ -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:
|
||||
LOG_CRITICAL(Render_Vulkan, "Unimplemented vertex attribute format!");
|
||||
fmt::print("{}\n", attrib.size.Value());
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
default:
|
||||
LOG_CRITICAL(Render_Vulkan, "Unimplemented vertex attribute type {}", attrib.type.Value());
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
Reference in New Issue
Block a user