Merge pull request #2476 from yuriks/shader-refactor3

Oh No! More shader changes!
This commit is contained in:
Yuri Kunde Schlesner 2017-02-04 13:02:48 -08:00 committed by GitHub
commit 97e06b0a0d
20 changed files with 184 additions and 180 deletions

View file

@ -4,6 +4,7 @@
#include <cmath>
#include <cstring>
#include "common/bit_set.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "video_core/pica.h"
@ -19,38 +20,32 @@ namespace Pica {
namespace Shader {
OutputVertex OutputVertex::FromRegisters(Math::Vec4<float24> output_regs[16], const Regs& regs,
u32 output_mask) {
OutputVertex OutputVertex::FromAttributeBuffer(const Regs& regs, AttributeBuffer& input) {
// Setup output data
OutputVertex ret;
// TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to
// figure out what those circumstances are and enable the remaining outputs then.
unsigned index = 0;
for (unsigned i = 0; i < 7; ++i) {
union {
OutputVertex ret{};
std::array<float24, 24> vertex_slots;
};
static_assert(sizeof(vertex_slots) == sizeof(ret), "Struct and array have different sizes.");
if (index >= regs.vs_output_total)
break;
unsigned int num_attributes = regs.vs_output_total;
ASSERT(num_attributes <= 7);
for (unsigned int i = 0; i < num_attributes; ++i) {
const auto& output_register_map = regs.vs_output_attributes[i];
if ((output_mask & (1 << i)) == 0)
continue;
const auto& output_register_map = regs.vs_output_attributes[index];
u32 semantics[4] = {output_register_map.map_x, output_register_map.map_y,
output_register_map.map_z, output_register_map.map_w};
Regs::VSOutputAttributes::Semantic semantics[4] = {
output_register_map.map_x, output_register_map.map_y, output_register_map.map_z,
output_register_map.map_w};
for (unsigned comp = 0; comp < 4; ++comp) {
float24* out = ((float24*)&ret) + semantics[comp];
if (semantics[comp] != Regs::VSOutputAttributes::INVALID) {
*out = output_regs[i][comp];
} else {
// Zero output so that attributes which aren't output won't have denormals in them,
// which would slow us down later.
memset(out, 0, sizeof(*out));
Regs::VSOutputAttributes::Semantic semantic = semantics[comp];
float24* out = &vertex_slots[semantic];
if (semantic < vertex_slots.size()) {
*out = input.attr[i][comp];
} else if (semantic != Regs::VSOutputAttributes::INVALID) {
LOG_ERROR(HW_GPU, "Invalid/unknown semantic id: %u", (unsigned int)semantic);
}
}
index++;
}
// The hardware takes the absolute and saturates vertex colors like this, *before* doing
@ -71,12 +66,20 @@ OutputVertex OutputVertex::FromRegisters(Math::Vec4<float24> output_regs[16], co
return ret;
}
void UnitState::LoadInputVertex(const InputVertex& input, int num_attributes) {
// Setup input register table
const auto& attribute_register_map = g_state.regs.vs.input_register_map;
void UnitState::LoadInput(const Regs::ShaderConfig& config, const AttributeBuffer& input) {
const unsigned max_attribute = config.max_input_attribute_index;
for (int i = 0; i < num_attributes; i++)
registers.input[attribute_register_map.GetRegisterForAttribute(i)] = input.attr[i];
for (unsigned attr = 0; attr <= max_attribute; ++attr) {
unsigned reg = config.GetRegisterForAttribute(attr);
registers.input[reg] = input.attr[attr];
}
}
void UnitState::WriteOutput(const Regs::ShaderConfig& config, AttributeBuffer& output) {
unsigned int output_i = 0;
for (unsigned int reg : Common::BitSet<u32>(config.output_mask)) {
output.attr[output_i++] = registers.output[reg];
}
}
MICROPROFILE_DEFINE(GPU_Shader, "GPU", "Shader", MP_RGB(50, 50, 240));

View file

@ -23,14 +23,11 @@ namespace Pica {
namespace Shader {
struct InputVertex {
struct AttributeBuffer {
alignas(16) Math::Vec4<float24> attr[16];
};
struct OutputVertex {
OutputVertex() = default;
// VS output attributes
Math::Vec4<float24> pos;
Math::Vec4<float24> quat;
Math::Vec4<float24> color;
@ -42,43 +39,22 @@ struct OutputVertex {
INSERT_PADDING_WORDS(1);
Math::Vec2<float24> tc2;
// Padding for optimal alignment
INSERT_PADDING_WORDS(4);
// Attributes used to store intermediate results
// position after perspective divide
Math::Vec3<float24> screenpos;
INSERT_PADDING_WORDS(1);
// Linear interpolation
// factor: 0=this, 1=vtx
void Lerp(float24 factor, const OutputVertex& vtx) {
pos = pos * factor + vtx.pos * (float24::FromFloat32(1) - factor);
// TODO: Should perform perspective correct interpolation here...
tc0 = tc0 * factor + vtx.tc0 * (float24::FromFloat32(1) - factor);
tc1 = tc1 * factor + vtx.tc1 * (float24::FromFloat32(1) - factor);
tc2 = tc2 * factor + vtx.tc2 * (float24::FromFloat32(1) - factor);
screenpos = screenpos * factor + vtx.screenpos * (float24::FromFloat32(1) - factor);
color = color * factor + vtx.color * (float24::FromFloat32(1) - factor);
}
// Linear interpolation
// factor: 0=v0, 1=v1
static OutputVertex Lerp(float24 factor, const OutputVertex& v0, const OutputVertex& v1) {
OutputVertex ret = v0;
ret.Lerp(factor, v1);
return ret;
}
static OutputVertex FromRegisters(Math::Vec4<float24> output_regs[16], const Regs& regs,
u32 output_mask);
static OutputVertex FromAttributeBuffer(const Regs& regs, AttributeBuffer& output);
};
#define ASSERT_POS(var, pos) \
static_assert(offsetof(OutputVertex, var) == pos * sizeof(float24), "Semantic at wrong " \
"offset.")
ASSERT_POS(pos, Regs::VSOutputAttributes::POSITION_X);
ASSERT_POS(quat, Regs::VSOutputAttributes::QUATERNION_X);
ASSERT_POS(color, Regs::VSOutputAttributes::COLOR_R);
ASSERT_POS(tc0, Regs::VSOutputAttributes::TEXCOORD0_U);
ASSERT_POS(tc1, Regs::VSOutputAttributes::TEXCOORD1_U);
ASSERT_POS(tc0_w, Regs::VSOutputAttributes::TEXCOORD0_W);
ASSERT_POS(view, Regs::VSOutputAttributes::VIEW_X);
ASSERT_POS(tc2, Regs::VSOutputAttributes::TEXCOORD2_U);
#undef ASSERT_POS
static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD");
static_assert(sizeof(OutputVertex) == 32 * sizeof(float), "OutputVertex has invalid size");
static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size");
/**
* This structure contains the state information that needs to be unique for a shader unit. The 3DS
@ -137,10 +113,12 @@ struct UnitState {
/**
* Loads the unit state with an input vertex.
*
* @param input Input vertex into the shader
* @param num_attributes The number of vertex shader attributes to load
* @param config Shader configuration registers corresponding to the unit.
* @param input Attribute buffer to load into the input registers.
*/
void LoadInputVertex(const InputVertex& input, int num_attributes);
void LoadInput(const Regs::ShaderConfig& config, const AttributeBuffer& input);
void WriteOutput(const Regs::ShaderConfig& config, AttributeBuffer& output);
};
struct ShaderSetup {

View file

@ -668,14 +668,14 @@ void InterpreterEngine::Run(const ShaderSetup& setup, UnitState& state) const {
}
DebugData<true> InterpreterEngine::ProduceDebugInfo(const ShaderSetup& setup,
const InputVertex& input,
int num_attributes) const {
const AttributeBuffer& input,
const Regs::ShaderConfig& config) const {
UnitState state;
DebugData<true> debug_data;
// Setup input register table
boost::fill(state.registers.input, Math::Vec4<float24>::AssignToAll(float24::Zero()));
state.LoadInputVertex(input, num_attributes);
state.LoadInput(config, input);
RunInterpreter(setup, state, debug_data, setup.engine_data.entry_point);
return debug_data;
}

View file

@ -19,12 +19,11 @@ public:
/**
* Produce debug information based on the given shader and input vertex
* @param input Input vertex into the shader
* @param num_attributes The number of vertex shader attributes
* @param config Configuration object for the shader pipeline
* @return Debug information for this shader with regards to the given vertex
*/
DebugData<true> ProduceDebugInfo(const ShaderSetup& setup, const InputVertex& input,
int num_attributes) const;
DebugData<true> ProduceDebugInfo(const ShaderSetup& setup, const AttributeBuffer& input,
const Regs::ShaderConfig& config) const;
};
} // namespace