// Copyright 2016 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include #include #include #include "common/bit_field.h" #include "common/common_types.h" #include "common/vector_math.h" #include "core/memory.h" #include "video_core/geometry_pipeline.h" #include "video_core/primitive_assembly.h" #include "video_core/regs.h" #include "video_core/shader/shader.h" #include "video_core/video_core.h" // Boost::serialization doesn't like union types for some reason, // so we need to mark arrays of union values with a special serialization method template struct UnionArray : public std::array { private: template void serialize(Archive& ar, const unsigned int) { static_assert(sizeof(Value) == sizeof(u32)); ar&* static_cast(static_cast(this->data())); } friend class boost::serialization::access; }; namespace Pica { /// Struct used to describe current Pica state struct State { State(); void Reset(); /// Pica registers Regs regs; Shader::ShaderSetup vs; Shader::ShaderSetup gs; Shader::AttributeBuffer input_default_attributes; struct ProcTex { union ValueEntry { u32 raw; // LUT value, encoded as 12-bit fixed point, with 12 fraction bits BitField<0, 12, u32> value; // 0.0.12 fixed point // Difference between two entry values. Used for efficient interpolation. // 0.0.12 fixed point with two's complement. The range is [-0.5, 0.5). // Note: the type of this is different from the one of lighting LUT BitField<12, 12, s32> difference; float ToFloat() const { return static_cast(value) / 4095.f; } float DiffToFloat() const { return static_cast(difference) / 4095.f; } }; union ColorEntry { u32 raw; BitField<0, 8, u32> r; BitField<8, 8, u32> g; BitField<16, 8, u32> b; BitField<24, 8, u32> a; Common::Vec4 ToVector() const { return {static_cast(r), static_cast(g), static_cast(b), static_cast(a)}; } }; union ColorDifferenceEntry { u32 raw; BitField<0, 8, s32> r; // half of the difference between two ColorEntry BitField<8, 8, s32> g; BitField<16, 8, s32> b; BitField<24, 8, s32> a; Common::Vec4 ToVector() const { return Common::Vec4{r, g, b, a} * 2; } }; UnionArray noise_table; UnionArray color_map_table; UnionArray alpha_map_table; UnionArray color_table; UnionArray color_diff_table; private: friend class boost::serialization::access; template void serialize(Archive& ar, const unsigned int file_version) { ar& noise_table; ar& color_map_table; ar& alpha_map_table; ar& color_table; ar& color_diff_table; } } proctex; struct Lighting { union LutEntry { // Used for raw access u32 raw; // LUT value, encoded as 12-bit fixed point, with 12 fraction bits BitField<0, 12, u32> value; // 0.0.12 fixed point // Used for efficient interpolation. BitField<12, 11, u32> difference; // 0.0.11 fixed point BitField<23, 1, u32> neg_difference; float ToFloat() const { return static_cast(value) / 4095.f; } float DiffToFloat() const { float diff = static_cast(difference) / 2047.f; return neg_difference ? -diff : diff; } template void serialize(Archive& ar, const unsigned int file_version) { ar& raw; } }; std::array, 24> luts; } lighting; struct { union LutEntry { // Used for raw access u32 raw; BitField<0, 13, s32> difference; // 1.1.11 fixed point BitField<13, 11, u32> value; // 0.0.11 fixed point float ToFloat() const { return static_cast(value) / 2047.0f; } float DiffToFloat() const { return static_cast(difference) / 2047.0f; } }; UnionArray lut; } fog; /// Current Pica command list struct { PAddr addr; // This exists only for serialization const u32* head_ptr; const u32* current_ptr; u32 length; } cmd_list; /// Struct used to describe immediate mode rendering state struct ImmediateModeState { // Used to buffer partial vertices for immediate-mode rendering. Shader::AttributeBuffer input_vertex; // Index of the next attribute to be loaded into `input_vertex`. u32 current_attribute = 0; // Indicates the immediate mode just started and the geometry pipeline needs to reconfigure bool reset_geometry_pipeline = true; private: friend class boost::serialization::access; template void serialize(Archive& ar, const unsigned int file_version) { ar& input_vertex; ar& current_attribute; ar& reset_geometry_pipeline; } } immediate; // the geometry shader needs to be kept in the global state because some shaders relie on // preserved register value across shader invocation. // TODO: also bring the three vertex shader units here and implement the shader scheduler. Shader::GSUnitState gs_unit; GeometryPipeline geometry_pipeline; // This is constructed with a dummy triangle topology PrimitiveAssembler primitive_assembler; int vs_float_regs_counter = 0; std::array vs_uniform_write_buffer{}; int gs_float_regs_counter = 0; std::array gs_uniform_write_buffer{}; int default_attr_counter = 0; std::array default_attr_write_buffer{}; private: friend class boost::serialization::access; template void serialize(Archive& ar, const unsigned int file_version) { ar& regs.reg_array; ar& vs; ar& gs; ar& input_default_attributes; ar& proctex; ar& lighting.luts; ar& fog.lut; ar& cmd_list.addr; ar& cmd_list.length; ar& immediate; ar& gs_unit; ar& geometry_pipeline; ar& primitive_assembler; ar& vs_float_regs_counter; ar& boost::serialization::make_array(vs_uniform_write_buffer.data(), vs_uniform_write_buffer.size()); ar& gs_float_regs_counter; ar& boost::serialization::make_array(gs_uniform_write_buffer.data(), gs_uniform_write_buffer.size()); ar& default_attr_counter; ar& boost::serialization::make_array(default_attr_write_buffer.data(), default_attr_write_buffer.size()); boost::serialization::split_member(ar, *this, file_version); } template void save(Archive& ar, const unsigned int file_version) const { ar << static_cast(cmd_list.current_ptr - cmd_list.head_ptr); } template void load(Archive& ar, const unsigned int file_version) { u32 offset{}; ar >> offset; cmd_list.head_ptr = reinterpret_cast(VideoCore::g_memory->GetPhysicalPointer(cmd_list.addr)); cmd_list.current_ptr = cmd_list.head_ptr + offset; } }; extern State g_state; ///< Current Pica state } // namespace Pica