// Copyright 2023 Citra Emulator Project // Licensed under GPLv2 or any later version // Refer to the license.txt file included. #pragma once #include "core/hle/service/gsp/gsp_interrupt.h" #include "video_core/pica/geometry_pipeline.h" #include "video_core/pica/packed_attribute.h" #include "video_core/pica/primitive_assembly.h" #include "video_core/pica/regs_external.h" #include "video_core/pica/regs_internal.h" #include "video_core/pica/regs_lcd.h" #include "video_core/pica/shader_setup.h" #include "video_core/pica/shader_unit.h" namespace Memory { class MemorySystem; } namespace VideoCore { class RasterizerInterface; } namespace Pica { class DebugContext; class ShaderEngine; class PicaCore { public: explicit PicaCore(Memory::MemorySystem& memory, std::shared_ptr debug_context_); ~PicaCore(); void BindRasterizer(VideoCore::RasterizerInterface* rasterizer); void SetInterruptHandler(Service::GSP::InterruptHandler& signal_interrupt); void ProcessCmdList(PAddr list, u32 size); private: void InitializeRegs(); void WriteInternalReg(u32 id, u32 value, u32 mask); void SubmitImmediate(u32 data); void DrawImmediate(); void DrawArrays(bool is_indexed); void LoadVertices(bool is_indexed); public: union Regs { static constexpr std::size_t NUM_REGS = 0x732; struct { u32 hardware_id; INSERT_PADDING_WORDS(0x3); MemoryFillConfig memory_fill_config[2]; u32 vram_bank_control; u32 gpu_busy; INSERT_PADDING_WORDS(0x22); u32 backlight_control; INSERT_PADDING_WORDS(0xCF); FramebufferConfig framebuffer_config[2]; INSERT_PADDING_WORDS(0x180); DisplayTransferConfig display_transfer_config; INSERT_PADDING_WORDS(0xF5); RegsInternal internal; }; std::array reg_array; }; static_assert(sizeof(Regs) == Regs::NUM_REGS * sizeof(u32)); struct CommandList { PAddr addr; const u32* head; u32 current_index; u32 length; void Reset(PAddr addr, const u8* head, u32 size) { this->addr = addr; this->head = reinterpret_cast(head); this->length = size / sizeof(u32); current_index = 0; } private: friend class boost::serialization::access; template void serialize(Archive& ar, const u32 file_version); }; struct ImmediateModeState { AttributeBuffer input_vertex{}; u32 current_attribute{}; bool reset_geometry_pipeline{true}; PackedAttribute queue; void Reset() { current_attribute = 0; reset_geometry_pipeline = true; queue.Reset(); } private: friend class boost::serialization::access; template void serialize(Archive& ar, const u32 file_version) { ar& input_vertex; ar& current_attribute; ar& reset_geometry_pipeline; ar& queue; } }; 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; f32 ToFloat() const { return static_cast(value) / 4095.f; } f32 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; } }; std::array noise_table; std::array color_map_table; std::array alpha_map_table; std::array color_table; std::array color_diff_table; private: friend class boost::serialization::access; template void serialize(Archive& ar, const u32 file_version) { ar& boost::serialization::make_binary_object(this, sizeof(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; f32 ToFloat() const { return static_cast(value) / 4095.f; } f32 DiffToFloat() const { const f32 diff = static_cast(difference) / 2047.f; return neg_difference ? -diff : diff; } template void serialize(Archive& ar, const u32 file_version) { ar& raw; } }; std::array, 24> luts; private: friend class boost::serialization::access; template void serialize(Archive& ar, const u32 file_version) { ar& boost::serialization::make_binary_object(this, sizeof(Lighting)); } }; struct Fog { 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 f32 ToFloat() const { return static_cast(value) / 2047.0f; } f32 DiffToFloat() const { return static_cast(difference) / 2047.0f; } }; std::array lut; private: friend class boost::serialization::access; template void serialize(Archive& ar, const u32 file_version) { ar& boost::serialization::make_binary_object(this, sizeof(Fog)); } }; RegsLcd regs_lcd{}; Regs regs{}; // TODO: Move these to a separate shader scheduler class GeometryShaderUnit gs_unit; ShaderSetup vs_setup; ShaderSetup gs_setup; ProcTex proctex{}; Lighting lighting{}; Fog fog{}; AttributeBuffer input_default_attributes{}; ImmediateModeState immediate{}; private: friend class boost::serialization::access; template void serialize(Archive& ar, const u32 file_version) { ar& regs_lcd; ar& regs.reg_array; ar& gs_unit; ar& vs_setup; ar& gs_setup; ar& proctex; ar& lighting; ar& fog; ar& input_default_attributes; ar& immediate; ar& geometry_pipeline; ar& primitive_assembler; ar& cmd_list; } private: Memory::MemorySystem& memory; VideoCore::RasterizerInterface* rasterizer; std::shared_ptr debug_context; Service::GSP::InterruptHandler signal_interrupt; GeometryPipeline geometry_pipeline; PrimitiveAssembler primitive_assembler; CommandList cmd_list; std::unique_ptr shader_engine; }; #define GPU_REG_INDEX(field_name) (offsetof(Pica::PicaCore::Regs, field_name) / sizeof(u32)) } // namespace Pica