1 // Copyright 2016 Citra Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <array> 8 #include <boost/serialization/array.hpp> 9 #include <boost/serialization/split_member.hpp> 10 #include "common/bit_field.h" 11 #include "common/common_types.h" 12 #include "common/vector_math.h" 13 #include "core/memory.h" 14 #include "video_core/geometry_pipeline.h" 15 #include "video_core/primitive_assembly.h" 16 #include "video_core/regs.h" 17 #include "video_core/shader/shader.h" 18 #include "video_core/video_core.h" 19 20 // Boost::serialization doesn't like union types for some reason, 21 // so we need to mark arrays of union values with a special serialization method 22 template <typename Value, size_t Size> 23 struct UnionArray : public std::array<Value, Size> { 24 private: 25 template <class Archive> serializeUnionArray26 void serialize(Archive& ar, const unsigned int) { 27 static_assert(sizeof(Value) == sizeof(u32)); 28 ar&* static_cast<u32(*)[Size]>(static_cast<void*>(this->data())); 29 } 30 friend class boost::serialization::access; 31 }; 32 33 namespace Pica { 34 35 /// Struct used to describe current Pica state 36 struct State { 37 State(); 38 void Reset(); 39 40 /// Pica registers 41 Regs regs; 42 43 Shader::ShaderSetup vs; 44 Shader::ShaderSetup gs; 45 46 Shader::AttributeBuffer input_default_attributes; 47 48 struct ProcTex { 49 union ValueEntry { 50 u32 raw; 51 52 // LUT value, encoded as 12-bit fixed point, with 12 fraction bits 53 BitField<0, 12, u32> value; // 0.0.12 fixed point 54 55 // Difference between two entry values. Used for efficient interpolation. 56 // 0.0.12 fixed point with two's complement. The range is [-0.5, 0.5). 57 // Note: the type of this is different from the one of lighting LUT 58 BitField<12, 12, s32> difference; 59 ToFloat()60 float ToFloat() const { 61 return static_cast<float>(value) / 4095.f; 62 } 63 DiffToFloat()64 float DiffToFloat() const { 65 return static_cast<float>(difference) / 4095.f; 66 } 67 }; 68 69 union ColorEntry { 70 u32 raw; 71 BitField<0, 8, u32> r; 72 BitField<8, 8, u32> g; 73 BitField<16, 8, u32> b; 74 BitField<24, 8, u32> a; 75 ToVector()76 Common::Vec4<u8> ToVector() const { 77 return {static_cast<u8>(r), static_cast<u8>(g), static_cast<u8>(b), 78 static_cast<u8>(a)}; 79 } 80 }; 81 82 union ColorDifferenceEntry { 83 u32 raw; 84 BitField<0, 8, s32> r; // half of the difference between two ColorEntry 85 BitField<8, 8, s32> g; 86 BitField<16, 8, s32> b; 87 BitField<24, 8, s32> a; 88 ToVector()89 Common::Vec4<s32> ToVector() const { 90 return Common::Vec4<s32>{r, g, b, a} * 2; 91 } 92 }; 93 94 UnionArray<ValueEntry, 128> noise_table; 95 UnionArray<ValueEntry, 128> color_map_table; 96 UnionArray<ValueEntry, 128> alpha_map_table; 97 UnionArray<ColorEntry, 256> color_table; 98 UnionArray<ColorDifferenceEntry, 256> color_diff_table; 99 100 private: 101 friend class boost::serialization::access; 102 template <class Archive> serializeState::ProcTex103 void serialize(Archive& ar, const unsigned int file_version) { 104 ar& noise_table; 105 ar& color_map_table; 106 ar& alpha_map_table; 107 ar& color_table; 108 ar& color_diff_table; 109 } 110 } proctex; 111 112 struct Lighting { 113 union LutEntry { 114 // Used for raw access 115 u32 raw; 116 117 // LUT value, encoded as 12-bit fixed point, with 12 fraction bits 118 BitField<0, 12, u32> value; // 0.0.12 fixed point 119 120 // Used for efficient interpolation. 121 BitField<12, 11, u32> difference; // 0.0.11 fixed point 122 BitField<23, 1, u32> neg_difference; 123 ToFloat()124 float ToFloat() const { 125 return static_cast<float>(value) / 4095.f; 126 } 127 DiffToFloat()128 float DiffToFloat() const { 129 float diff = static_cast<float>(difference) / 2047.f; 130 return neg_difference ? -diff : diff; 131 } 132 133 template <class Archive> serialize(Archive & ar,const unsigned int file_version)134 void serialize(Archive& ar, const unsigned int file_version) { 135 ar& raw; 136 } 137 }; 138 139 std::array<UnionArray<LutEntry, 256>, 24> luts; 140 } lighting; 141 142 struct { 143 union LutEntry { 144 // Used for raw access 145 u32 raw; 146 147 BitField<0, 13, s32> difference; // 1.1.11 fixed point 148 BitField<13, 11, u32> value; // 0.0.11 fixed point 149 ToFloat()150 float ToFloat() const { 151 return static_cast<float>(value) / 2047.0f; 152 } 153 DiffToFloat()154 float DiffToFloat() const { 155 return static_cast<float>(difference) / 2047.0f; 156 } 157 }; 158 159 UnionArray<LutEntry, 128> lut; 160 } fog; 161 162 /// Current Pica command list 163 struct { 164 PAddr addr; // This exists only for serialization 165 const u32* head_ptr; 166 const u32* current_ptr; 167 u32 length; 168 } cmd_list; 169 170 /// Struct used to describe immediate mode rendering state 171 struct ImmediateModeState { 172 // Used to buffer partial vertices for immediate-mode rendering. 173 Shader::AttributeBuffer input_vertex; 174 // Index of the next attribute to be loaded into `input_vertex`. 175 u32 current_attribute = 0; 176 // Indicates the immediate mode just started and the geometry pipeline needs to reconfigure 177 bool reset_geometry_pipeline = true; 178 179 private: 180 friend class boost::serialization::access; 181 template <class Archive> serializeState::ImmediateModeState182 void serialize(Archive& ar, const unsigned int file_version) { 183 ar& input_vertex; 184 ar& current_attribute; 185 ar& reset_geometry_pipeline; 186 } 187 188 } immediate; 189 190 // the geometry shader needs to be kept in the global state because some shaders relie on 191 // preserved register value across shader invocation. 192 // TODO: also bring the three vertex shader units here and implement the shader scheduler. 193 Shader::GSUnitState gs_unit; 194 195 GeometryPipeline geometry_pipeline; 196 197 // This is constructed with a dummy triangle topology 198 PrimitiveAssembler<Shader::OutputVertex> primitive_assembler; 199 200 int vs_float_regs_counter = 0; 201 std::array<u32, 4> vs_uniform_write_buffer{}; 202 203 int gs_float_regs_counter = 0; 204 std::array<u32, 4> gs_uniform_write_buffer{}; 205 206 int default_attr_counter = 0; 207 std::array<u32, 3> default_attr_write_buffer{}; 208 209 private: 210 friend class boost::serialization::access; 211 template <class Archive> serializeState212 void serialize(Archive& ar, const unsigned int file_version) { 213 ar& regs.reg_array; 214 ar& vs; 215 ar& gs; 216 ar& input_default_attributes; 217 ar& proctex; 218 ar& lighting.luts; 219 ar& fog.lut; 220 ar& cmd_list.addr; 221 ar& cmd_list.length; 222 ar& immediate; 223 ar& gs_unit; 224 ar& geometry_pipeline; 225 ar& primitive_assembler; 226 ar& vs_float_regs_counter; 227 ar& boost::serialization::make_array(vs_uniform_write_buffer.data(), 228 vs_uniform_write_buffer.size()); 229 ar& gs_float_regs_counter; 230 ar& boost::serialization::make_array(gs_uniform_write_buffer.data(), 231 gs_uniform_write_buffer.size()); 232 ar& default_attr_counter; 233 ar& boost::serialization::make_array(default_attr_write_buffer.data(), 234 default_attr_write_buffer.size()); 235 boost::serialization::split_member(ar, *this, file_version); 236 } 237 238 template <class Archive> saveState239 void save(Archive& ar, const unsigned int file_version) const { 240 ar << static_cast<u32>(cmd_list.current_ptr - cmd_list.head_ptr); 241 } 242 243 template <class Archive> loadState244 void load(Archive& ar, const unsigned int file_version) { 245 u32 offset{}; 246 ar >> offset; 247 cmd_list.head_ptr = 248 reinterpret_cast<u32*>(VideoCore::g_memory->GetPhysicalPointer(cmd_list.addr)); 249 cmd_list.current_ptr = cmd_list.head_ptr + offset; 250 } 251 }; 252 253 extern State g_state; ///< Current Pica state 254 255 } // namespace Pica 256