summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorwwylele <wwylele@gmail.com>2017-07-25 21:30:29 +0200
committerwwylele <wwylele@gmail.com>2017-08-19 09:13:20 +0200
commit46c6973d2bde25a2a8ae9ac434660798fd1dfaee (patch)
tree3910b3b8b95de67f70a482f08351e807c532b784 /src
parentpica/regs: layout geometry shader configuration regs (diff)
downloadyuzu-46c6973d2bde25a2a8ae9ac434660798fd1dfaee.tar
yuzu-46c6973d2bde25a2a8ae9ac434660798fd1dfaee.tar.gz
yuzu-46c6973d2bde25a2a8ae9ac434660798fd1dfaee.tar.bz2
yuzu-46c6973d2bde25a2a8ae9ac434660798fd1dfaee.tar.lz
yuzu-46c6973d2bde25a2a8ae9ac434660798fd1dfaee.tar.xz
yuzu-46c6973d2bde25a2a8ae9ac434660798fd1dfaee.tar.zst
yuzu-46c6973d2bde25a2a8ae9ac434660798fd1dfaee.zip
Diffstat (limited to 'src')
-rw-r--r--src/video_core/shader/shader.cpp38
-rw-r--r--src/video_core/shader/shader.h46
2 files changed, 84 insertions, 0 deletions
diff --git a/src/video_core/shader/shader.cpp b/src/video_core/shader/shader.cpp
index 67ed19ba8..b12468d3a 100644
--- a/src/video_core/shader/shader.cpp
+++ b/src/video_core/shader/shader.cpp
@@ -82,6 +82,44 @@ void UnitState::WriteOutput(const ShaderRegs& config, AttributeBuffer& output) {
}
}
+UnitState::UnitState(GSEmitter* emitter) : emitter_ptr(emitter) {}
+
+GSEmitter::GSEmitter() {
+ handlers = new Handlers;
+}
+
+GSEmitter::~GSEmitter() {
+ delete handlers;
+}
+
+void GSEmitter::Emit(Math::Vec4<float24> (&vertex)[16]) {
+ ASSERT(vertex_id < 3);
+ std::copy(std::begin(vertex), std::end(vertex), buffer[vertex_id].begin());
+ if (prim_emit) {
+ if (winding)
+ handlers->winding_setter();
+ for (size_t i = 0; i < buffer.size(); ++i) {
+ AttributeBuffer output;
+ unsigned int output_i = 0;
+ for (unsigned int reg : Common::BitSet<u32>(output_mask)) {
+ output.attr[output_i++] = buffer[i][reg];
+ }
+ handlers->vertex_handler(output);
+ }
+ }
+}
+
+GSUnitState::GSUnitState() : UnitState(&emitter) {}
+
+void GSUnitState::SetVertexHandler(VertexHandler vertex_handler, WindingSetter winding_setter) {
+ emitter.handlers->vertex_handler = std::move(vertex_handler);
+ emitter.handlers->winding_setter = std::move(winding_setter);
+}
+
+void GSUnitState::ConfigOutput(const ShaderRegs& config) {
+ emitter.output_mask = config.output_mask;
+}
+
MICROPROFILE_DEFINE(GPU_Shader, "GPU", "Shader", MP_RGB(50, 50, 240));
#ifdef ARCHITECTURE_x86_64
diff --git a/src/video_core/shader/shader.h b/src/video_core/shader/shader.h
index e156f6aef..caec96043 100644
--- a/src/video_core/shader/shader.h
+++ b/src/video_core/shader/shader.h
@@ -6,6 +6,7 @@
#include <array>
#include <cstddef>
+#include <functional>
#include <type_traits>
#include <nihstro/shader_bytecode.h>
#include "common/assert.h"
@@ -31,6 +32,12 @@ struct AttributeBuffer {
alignas(16) Math::Vec4<float24> attr[16];
};
+/// Handler type for receiving vertex outputs from vertex shader or geometry shader
+using VertexHandler = std::function<void(const AttributeBuffer&)>;
+
+/// Handler type for signaling to invert the vertex order of the next triangle
+using WindingSetter = std::function<void()>;
+
struct OutputVertex {
Math::Vec4<float24> pos;
Math::Vec4<float24> quat;
@@ -61,12 +68,36 @@ static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD");
static_assert(sizeof(OutputVertex) == 24 * sizeof(float), "OutputVertex has invalid size");
/**
+ * This structure contains state information for primitive emitting in geometry shader.
+ */
+struct GSEmitter {
+ std::array<std::array<Math::Vec4<float24>, 16>, 3> buffer;
+ u8 vertex_id;
+ bool prim_emit;
+ bool winding;
+ u32 output_mask;
+
+ // Function objects are hidden behind a raw pointer to make the structure standard layout type,
+ // for JIT to use offsetof to access other members.
+ struct Handlers {
+ VertexHandler vertex_handler;
+ WindingSetter winding_setter;
+ } * handlers;
+
+ GSEmitter();
+ ~GSEmitter();
+ void Emit(Math::Vec4<float24> (&vertex)[16]);
+};
+static_assert(std::is_standard_layout<GSEmitter>::value, "GSEmitter is not standard layout type");
+
+/**
* This structure contains the state information that needs to be unique for a shader unit. The 3DS
* has four shader units that process shaders in parallel. At the present, Citra only implements a
* single shader unit that processes all shaders serially. Putting the state information in a struct
* here will make it easier for us to parallelize the shader processing later.
*/
struct UnitState {
+ explicit UnitState(GSEmitter* emitter = nullptr);
struct Registers {
// The registers are accessed by the shader JIT using SSE instructions, and are therefore
// required to be 16-byte aligned.
@@ -82,6 +113,8 @@ struct UnitState {
// TODO: How many bits do these actually have?
s32 address_registers[3];
+ GSEmitter* emitter_ptr;
+
static size_t InputOffset(const SourceRegister& reg) {
switch (reg.GetRegisterType()) {
case RegisterType::Input:
@@ -125,6 +158,19 @@ struct UnitState {
void WriteOutput(const ShaderRegs& config, AttributeBuffer& output);
};
+/**
+ * This is an extended shader unit state that represents the special unit that can run both vertex
+ * shader and geometry shader. It contains an additional primitive emitter and utilities for
+ * geometry shader.
+ */
+struct GSUnitState : public UnitState {
+ GSUnitState();
+ void SetVertexHandler(VertexHandler vertex_handler, WindingSetter winding_setter);
+ void ConfigOutput(const ShaderRegs& config);
+
+ GSEmitter emitter;
+};
+
struct ShaderSetup {
struct {
// The float uniforms are accessed by the shader JIT using SSE instructions, and are