gpu_debugger.h 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #pragma once
  5. #include <algorithm>
  6. #include <functional>
  7. #include <vector>
  8. #include "core/hle/service/gsp_gpu.h"
  9. #include "command_processor.h"
  10. #include "pica.h"
  11. class GraphicsDebugger
  12. {
  13. public:
  14. // Base class for all objects which need to be notified about GPU events
  15. class DebuggerObserver
  16. {
  17. public:
  18. DebuggerObserver() : observed(nullptr) { }
  19. virtual ~DebuggerObserver()
  20. {
  21. if (observed)
  22. observed->UnregisterObserver(this);
  23. }
  24. /**
  25. * Called when a GX command has been processed and is ready for being
  26. * read via GraphicsDebugger::ReadGXCommandHistory.
  27. * @param total_command_count Total number of commands in the GX history
  28. * @note All methods in this class are called from the GSP thread
  29. */
  30. virtual void GXCommandProcessed(int total_command_count)
  31. {
  32. const GSP_GPU::Command& cmd = observed->ReadGXCommandHistory(total_command_count-1);
  33. LOG_TRACE(Debug_GPU, "Received command: id=%x", (int)cmd.id.Value());
  34. }
  35. protected:
  36. const GraphicsDebugger* GetDebugger() const
  37. {
  38. return observed;
  39. }
  40. private:
  41. GraphicsDebugger* observed;
  42. bool in_destruction;
  43. friend class GraphicsDebugger;
  44. };
  45. void GXCommandProcessed(u8* command_data)
  46. {
  47. if (observers.empty())
  48. return;
  49. gx_command_history.emplace_back();
  50. GSP_GPU::Command& cmd = gx_command_history.back();
  51. memcpy(&cmd, command_data, sizeof(GSP_GPU::Command));
  52. ForEachObserver([this](DebuggerObserver* observer) {
  53. observer->GXCommandProcessed(static_cast<int>(this->gx_command_history.size()));
  54. } );
  55. }
  56. const GSP_GPU::Command& ReadGXCommandHistory(int index) const
  57. {
  58. // TODO: Is this thread-safe?
  59. return gx_command_history[index];
  60. }
  61. void RegisterObserver(DebuggerObserver* observer)
  62. {
  63. // TODO: Check for duplicates
  64. observers.push_back(observer);
  65. observer->observed = this;
  66. }
  67. void UnregisterObserver(DebuggerObserver* observer)
  68. {
  69. observers.erase(std::remove(observers.begin(), observers.end(), observer), observers.end());
  70. observer->observed = nullptr;
  71. }
  72. private:
  73. void ForEachObserver(std::function<void (DebuggerObserver*)> func)
  74. {
  75. std::for_each(observers.begin(),observers.end(), func);
  76. }
  77. std::vector<DebuggerObserver*> observers;
  78. std::vector<GSP_GPU::Command> gx_command_history;
  79. };