diff options
Diffstat (limited to 'src/video_core')
| -rw-r--r-- | src/video_core/gpu_debugger.h | 157 | ||||
| -rw-r--r-- | src/video_core/pica.h | 130 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 6 | ||||
| -rw-r--r-- | src/video_core/video_core.cpp | 3 | ||||
| -rw-r--r-- | src/video_core/video_core.vcxproj | 6 | ||||
| -rw-r--r-- | src/video_core/video_core.vcxproj.filters | 4 |
6 files changed, 300 insertions, 6 deletions
diff --git a/src/video_core/gpu_debugger.h b/src/video_core/gpu_debugger.h new file mode 100644 index 000000000..5d909beba --- /dev/null +++ b/src/video_core/gpu_debugger.h @@ -0,0 +1,157 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include <algorithm> +#include <functional> +#include <vector> + +#include "common/log.h" + +#include "core/hle/service/gsp.h" +#include "pica.h" + +class GraphicsDebugger +{ +public: + // A few utility structs used to expose data + // A vector of commands represented by their raw byte sequence + struct PicaCommand : public std::vector<u32> + { + const Pica::CommandHeader& GetHeader() const + { + const u32& val = at(1); + return *(Pica::CommandHeader*)&val; + } + }; + + typedef std::vector<PicaCommand> PicaCommandList; + + // Base class for all objects which need to be notified about GPU events + class DebuggerObserver + { + public: + DebuggerObserver() : observed(nullptr) { } + + virtual ~DebuggerObserver() + { + if (observed) + observed->UnregisterObserver(this); + } + + /** + * Called when a GX command has been processed and is ready for being + * read via GraphicsDebugger::ReadGXCommandHistory. + * @param total_command_count Total number of commands in the GX history + * @note All methods in this class are called from the GSP thread + */ + virtual void GXCommandProcessed(int total_command_count) + { + const GSP_GPU::GXCommand& cmd = observed->ReadGXCommandHistory(total_command_count-1); + ERROR_LOG(GSP, "Received command: id=%x", cmd.id); + } + + /** + * @param lst command list which triggered this call + * @param is_new true if the command list was called for the first time + * @todo figure out how to make sure called functions don't keep references around beyond their life time + */ + virtual void OnCommandListCalled(const PicaCommandList& lst, bool is_new) + { + ERROR_LOG(GSP, "Command list called: %d", (int)is_new); + } + + protected: + const GraphicsDebugger* GetDebugger() const + { + return observed; + } + + private: + GraphicsDebugger* observed; + bool in_destruction; + + friend class GraphicsDebugger; + }; + + void GXCommandProcessed(u8* command_data) + { + gx_command_history.push_back(GSP_GPU::GXCommand()); + GSP_GPU::GXCommand& cmd = gx_command_history[gx_command_history.size()-1]; + + const int cmd_length = sizeof(GSP_GPU::GXCommand); + memcpy(cmd.data, command_data, cmd_length); + + ForEachObserver([this](DebuggerObserver* observer) { + observer->GXCommandProcessed(this->gx_command_history.size()); + } ); + } + + void CommandListCalled(u32 address, u32* command_list, u32 size_in_words) + { + PicaCommandList cmdlist; + for (u32* parse_pointer = command_list; parse_pointer < command_list + size_in_words;) + { + const Pica::CommandHeader header = static_cast<Pica::CommandHeader>(parse_pointer[1]); + + cmdlist.push_back(PicaCommand()); + auto& cmd = cmdlist.back(); + + size_t size = 2 + header.extra_data_length; + size = (size + 1) / 2 * 2; // align to 8 bytes + cmd.reserve(size); + std::copy(parse_pointer, parse_pointer + size, std::back_inserter(cmd)); + + parse_pointer += size; + } + + auto obj = std::pair<u32,PicaCommandList>(address, cmdlist); + auto it = std::find(command_lists.begin(), command_lists.end(), obj); + bool is_new = (it == command_lists.end()); + if (is_new) + command_lists.push_back(obj); + + ForEachObserver([&](DebuggerObserver* observer) { + observer->OnCommandListCalled(obj.second, is_new); + } ); + } + + const GSP_GPU::GXCommand& ReadGXCommandHistory(int index) const + { + // TODO: Is this thread-safe? + return gx_command_history[index]; + } + + const std::vector<std::pair<u32,PicaCommandList>>& GetCommandLists() const + { + return command_lists; + } + + void RegisterObserver(DebuggerObserver* observer) + { + // TODO: Check for duplicates + observers.push_back(observer); + observer->observed = this; + } + + void UnregisterObserver(DebuggerObserver* observer) + { + std::remove(observers.begin(), observers.end(), observer); + observer->observed = nullptr; + } + +private: + void ForEachObserver(std::function<void (DebuggerObserver*)> func) + { + std::for_each(observers.begin(),observers.end(), func); + } + + std::vector<DebuggerObserver*> observers; + + std::vector<GSP_GPU::GXCommand> gx_command_history; + + // vector of pairs of command lists and their storage address + std::vector<std::pair<u32,PicaCommandList>> command_lists; +}; diff --git a/src/video_core/pica.h b/src/video_core/pica.h new file mode 100644 index 000000000..f0fa3aba9 --- /dev/null +++ b/src/video_core/pica.h @@ -0,0 +1,130 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include <initializer_list> +#include <map> + +#include "common/bit_field.h" +#include "common/common_types.h" +#include "common/register_set.h" + +namespace Pica { + +struct Regs { + enum Id : u32 { + ViewportSizeX = 0x41, + ViewportInvSizeX = 0x42, + ViewportSizeY = 0x43, + ViewportInvSizeY = 0x44, + ViewportCorner = 0x68, + DepthBufferFormat = 0x116, + ColorBufferFormat = 0x117, + DepthBufferAddress = 0x11C, + ColorBufferAddress = 0x11D, + ColorBufferSize = 0x11E, + + VertexArrayBaseAddr = 0x200, + VertexDescriptor = 0x201, // 0x202 + VertexAttributeOffset = 0x203, // 0x206,0x209,0x20C,0x20F,0x212,0x215,0x218,0x21B,0x21E,0x221,0x224 + VertexAttributeInfo0 = 0x204, // 0x207,0x20A,0x20D,0x210,0x213,0x216,0x219,0x21C,0x21F,0x222,0x225 + VertexAttributeInfo1 = 0x205, // 0x208,0x20B,0x20E,0x211,0x214,0x217,0x21A,0x21D,0x220,0x223,0x226 + + NumIds = 0x300, + }; + + template<Id id> + union Struct; +}; + +static inline Regs::Id VertexAttributeOffset(int n) +{ + return static_cast<Regs::Id>(0x203 + 3*n); +} + +static inline Regs::Id VertexAttributeInfo0(int n) +{ + return static_cast<Regs::Id>(0x204 + 3*n); +} + +static inline Regs::Id VertexAttributeInfo1(int n) +{ + return static_cast<Regs::Id>(0x205 + 3*n); +} + +union CommandHeader { + CommandHeader(u32 h) : hex(h) {} + + u32 hex; + + BitField< 0, 16, Regs::Id> cmd_id; + BitField<16, 4, u32> parameter_mask; + BitField<20, 11, u32> extra_data_length; + BitField<31, 1, u32> group_commands; +}; + +static std::map<Regs::Id, const char*> command_names = { + {Regs::ViewportSizeX, "ViewportSizeX" }, + {Regs::ViewportInvSizeX, "ViewportInvSizeX" }, + {Regs::ViewportSizeY, "ViewportSizeY" }, + {Regs::ViewportInvSizeY, "ViewportInvSizeY" }, + {Regs::ViewportCorner, "ViewportCorner" }, + {Regs::DepthBufferFormat, "DepthBufferFormat" }, + {Regs::ColorBufferFormat, "ColorBufferFormat" }, + {Regs::DepthBufferAddress, "DepthBufferAddress" }, + {Regs::ColorBufferAddress, "ColorBufferAddress" }, + {Regs::ColorBufferSize, "ColorBufferSize" }, +}; + +template<> +union Regs::Struct<Regs::ViewportSizeX> { + BitField<0, 24, u32> value; +}; + +template<> +union Regs::Struct<Regs::ViewportSizeY> { + BitField<0, 24, u32> value; +}; + +template<> +union Regs::Struct<Regs::VertexDescriptor> { + enum class Format : u64 { + BYTE = 0, + UBYTE = 1, + SHORT = 2, + FLOAT = 3, + }; + + BitField< 0, 2, Format> format0; + BitField< 2, 2, u64> size0; // number of elements minus 1 + BitField< 4, 2, Format> format1; + BitField< 6, 2, u64> size1; + BitField< 8, 2, Format> format2; + BitField<10, 2, u64> size2; + BitField<12, 2, Format> format3; + BitField<14, 2, u64> size3; + BitField<16, 2, Format> format4; + BitField<18, 2, u64> size4; + BitField<20, 2, Format> format5; + BitField<22, 2, u64> size5; + BitField<24, 2, Format> format6; + BitField<26, 2, u64> size6; + BitField<28, 2, Format> format7; + BitField<30, 2, u64> size7; + BitField<32, 2, Format> format8; + BitField<34, 2, u64> size8; + BitField<36, 2, Format> format9; + BitField<38, 2, u64> size9; + BitField<40, 2, Format> format10; + BitField<42, 2, u64> size10; + BitField<44, 2, Format> format11; + BitField<46, 2, u64> size11; + + BitField<48, 12, u64> attribute_mask; + BitField<60, 4, u64> num_attributes; // number of total attributes minus 1 +}; + + +} // namespace diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index bb5eb34aa..70af47c59 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -2,7 +2,7 @@ // Licensed under GPLv2 // Refer to the license.txt file included. -#include "core/hw/lcd.h" +#include "core/hw/gpu.h" #include "video_core/video_core.h" #include "video_core/renderer_opengl/renderer_opengl.h" @@ -77,8 +77,8 @@ void RendererOpenGL::FlipFramebuffer(const u8* in, u8* out) { */ void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect) { - FlipFramebuffer(LCD::GetFramebufferPointer(LCD::g_regs.framebuffer_top_left_1), m_xfb_top_flipped); - FlipFramebuffer(LCD::GetFramebufferPointer(LCD::g_regs.framebuffer_sub_left_1), m_xfb_bottom_flipped); + FlipFramebuffer(GPU::GetFramebufferPointer(GPU::g_regs.framebuffer_top_left_1), m_xfb_top_flipped); + FlipFramebuffer(GPU::GetFramebufferPointer(GPU::g_regs.framebuffer_sub_left_1), m_xfb_bottom_flipped); // Blit the top framebuffer // ------------------------ diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp index cbd540bdf..3b8039de4 100644 --- a/src/video_core/video_core.cpp +++ b/src/video_core/video_core.cpp @@ -30,8 +30,11 @@ void Start() { /// Initialize the video core void Init(EmuWindow* emu_window) { + +#if EMU_PLATFORM == PLATFORM_MACOSX // Known problem with GLEW prevents contexts above 2.x on OSX unless glewExperimental is enabled. glewExperimental = GL_TRUE; +#endif g_emu_window = emu_window; g_emu_window->MakeCurrent(); diff --git a/src/video_core/video_core.vcxproj b/src/video_core/video_core.vcxproj index d8c53271e..d77be2bef 100644 --- a/src/video_core/video_core.vcxproj +++ b/src/video_core/video_core.vcxproj @@ -24,10 +24,12 @@ <ClCompile Include="video_core.cpp" /> </ItemGroup> <ItemGroup> + <ClInclude Include="gpu_debugger.h" /> + <ClInclude Include="pica.h" /> <ClInclude Include="renderer_base.h" /> - <ClInclude Include="renderer_opengl\renderer_opengl.h" /> <ClInclude Include="utils.h" /> <ClInclude Include="video_core.h" /> + <ClInclude Include="renderer_opengl\renderer_opengl.h" /> </ItemGroup> <ItemGroup> <Text Include="CMakeLists.txt" /> @@ -128,4 +130,4 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project>
\ No newline at end of file +</Project> diff --git a/src/video_core/video_core.vcxproj.filters b/src/video_core/video_core.vcxproj.filters index 4eb2ef0a4..b89ac1ac4 100644 --- a/src/video_core/video_core.vcxproj.filters +++ b/src/video_core/video_core.vcxproj.filters @@ -16,6 +16,8 @@ <ClInclude Include="renderer_opengl\renderer_opengl.h"> <Filter>renderer_opengl</Filter> </ClInclude> + <ClInclude Include="gpu_debugger.h" /> + <ClInclude Include="pica.h" /> <ClInclude Include="renderer_base.h" /> <ClInclude Include="utils.h" /> <ClInclude Include="video_core.h" /> @@ -23,4 +25,4 @@ <ItemGroup> <Text Include="CMakeLists.txt" /> </ItemGroup> -</Project>
\ No newline at end of file +</Project> |
