citra/src/video_core/pica/shader_unit.h

121 lines
3.4 KiB
C++

// Copyright 2023 Citra Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <functional>
#include <span>
#include <boost/serialization/base_object.hpp>
#include "video_core/pica/output_vertex.h"
namespace Pica {
/// 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 ShaderRegs;
struct GeometryEmitter;
/**
* 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.
*/
struct ShaderUnit {
explicit ShaderUnit(GeometryEmitter* emitter = nullptr);
~ShaderUnit();
void LoadInput(const ShaderRegs& config, const AttributeBuffer& input);
void WriteOutput(const ShaderRegs& config, AttributeBuffer& output);
static constexpr std::size_t InputOffset(s32 register_index) {
return offsetof(ShaderUnit, input) + register_index * sizeof(Common::Vec4<f24>);
}
static constexpr std::size_t OutputOffset(s32 register_index) {
return offsetof(ShaderUnit, output) + register_index * sizeof(Common::Vec4<f24>);
}
static constexpr std::size_t TemporaryOffset(s32 register_index) {
return offsetof(ShaderUnit, temporary) + register_index * sizeof(Common::Vec4<f24>);
}
public:
s32 address_registers[3];
bool conditional_code[2];
alignas(16) std::array<Common::Vec4<f24>, 16> input;
alignas(16) std::array<Common::Vec4<f24>, 16> temporary;
alignas(16) std::array<Common::Vec4<f24>, 16> output;
GeometryEmitter* emitter_ptr;
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const u32 file_version) {
ar& input;
ar& temporary;
ar& output;
ar& conditional_code;
ar& address_registers;
}
};
struct Handlers {
VertexHandler vertex_handler;
WindingSetter winding_setter;
};
/// This structure contains state information for primitive emitting in geometry shader.
struct GeometryEmitter {
void Emit(std::span<Common::Vec4<f24>, 16> output_regs);
public:
std::array<AttributeBuffer, 3> buffer;
u8 vertex_id;
bool prim_emit;
bool winding;
u32 output_mask;
Handlers* handlers;
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const u32 file_version) {
ar& buffer;
ar& vertex_id;
ar& prim_emit;
ar& winding;
ar& output_mask;
}
};
/**
* 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 GeometryShaderUnit : public ShaderUnit {
GeometryShaderUnit();
~GeometryShaderUnit();
void SetVertexHandlers(VertexHandler vertex_handler, WindingSetter winding_setter);
void ConfigOutput(const ShaderRegs& config);
GeometryEmitter emitter;
private:
friend class boost::serialization::access;
template <class Archive>
void serialize(Archive& ar, const u32 file_version) {
ar& boost::serialization::base_object<ShaderUnit>(*this);
ar& emitter;
}
};
} // namespace Pica