gpu.h 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  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 <cstddef>
  6. #include "common/common_types.h"
  7. #include "common/bit_field.h"
  8. namespace GPU {
  9. // Returns index corresponding to the Regs member labeled by field_name
  10. // TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions
  11. // when used with array elements (e.g. GPU_REG_INDEX(memory_fill_config[0])).
  12. // For details cf. https://connect.microsoft.com/VisualStudio/feedback/details/209229/offsetof-does-not-produce-a-constant-expression-for-array-members
  13. // Hopefully, this will be fixed sometime in the future.
  14. // For lack of better alternatives, we currently hardcode the offsets when constant
  15. // expressions are needed via GPU_REG_INDEX_WORKAROUND (on sane compilers, static_asserts
  16. // will then make sure the offsets indeed match the automatically calculated ones).
  17. #define GPU_REG_INDEX(field_name) (offsetof(GPU::Regs, field_name) / sizeof(u32))
  18. #if defined(_MSC_VER)
  19. #define GPU_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) (backup_workaround_index)
  20. #else
  21. // NOTE: Yeah, hacking in a static_assert here just to workaround the lacking MSVC compiler
  22. // really is this annoying. This macro just forwards its first argument to GPU_REG_INDEX
  23. // and then performs a (no-op) cast to size_t iff the second argument matches the expected
  24. // field offset. Otherwise, the compiler will fail to compile this code.
  25. #define GPU_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) \
  26. ((typename std::enable_if<backup_workaround_index == GPU_REG_INDEX(field_name), size_t>::type)GPU_REG_INDEX(field_name))
  27. #endif
  28. // MMIO region 0x1EFxxxxx
  29. struct Regs {
  30. // helper macro to properly align structure members.
  31. // Calling INSERT_PADDING_WORDS will add a new member variable with a name like "pad121",
  32. // depending on the current source line to make sure variable names are unique.
  33. #define INSERT_PADDING_WORDS_HELPER1(x, y) x ## y
  34. #define INSERT_PADDING_WORDS_HELPER2(x, y) INSERT_PADDING_WORDS_HELPER1(x, y)
  35. #define INSERT_PADDING_WORDS(num_words) u32 INSERT_PADDING_WORDS_HELPER2(pad, __LINE__)[(num_words)]
  36. // helper macro to make sure the defined structures are of the expected size.
  37. #if defined(_MSC_VER)
  38. // TODO: MSVC does not support using sizeof() on non-static data members even though this
  39. // is technically allowed since C++11. This macro should be enabled once MSVC adds
  40. // support for that.
  41. #define ASSERT_MEMBER_SIZE(name, size_in_bytes)
  42. #else
  43. #define ASSERT_MEMBER_SIZE(name, size_in_bytes) \
  44. static_assert(sizeof(name) == size_in_bytes, \
  45. "Structure size and register block length don't match")
  46. #endif
  47. // All of those formats are described in reverse byte order, since the 3DS is little-endian.
  48. enum class PixelFormat : u32 {
  49. RGBA8 = 0,
  50. RGB8 = 1,
  51. RGB565 = 2,
  52. RGB5A1 = 3,
  53. RGBA4 = 4,
  54. };
  55. /**
  56. * Returns the number of bytes per pixel.
  57. */
  58. static int BytesPerPixel(PixelFormat format) {
  59. switch (format) {
  60. case PixelFormat::RGBA8:
  61. return 4;
  62. case PixelFormat::RGB8:
  63. return 3;
  64. case PixelFormat::RGB565:
  65. case PixelFormat::RGB5A1:
  66. case PixelFormat::RGBA4:
  67. return 2;
  68. default:
  69. UNIMPLEMENTED();
  70. }
  71. }
  72. INSERT_PADDING_WORDS(0x4);
  73. struct {
  74. u32 address_start;
  75. u32 address_end; // ?
  76. u32 size;
  77. u32 value; // ?
  78. inline u32 GetStartAddress() const {
  79. return DecodeAddressRegister(address_start);
  80. }
  81. inline u32 GetEndAddress() const {
  82. return DecodeAddressRegister(address_end);
  83. }
  84. } memory_fill_config[2];
  85. ASSERT_MEMBER_SIZE(memory_fill_config[0], 0x10);
  86. INSERT_PADDING_WORDS(0x10b);
  87. struct FramebufferConfig {
  88. union {
  89. u32 size;
  90. BitField< 0, 16, u32> width;
  91. BitField<16, 16, u32> height;
  92. };
  93. INSERT_PADDING_WORDS(0x2);
  94. u32 address_left1;
  95. u32 address_left2;
  96. union {
  97. u32 format;
  98. BitField< 0, 3, PixelFormat> color_format;
  99. };
  100. INSERT_PADDING_WORDS(0x1);
  101. union {
  102. u32 active_fb;
  103. // 0: Use parameters ending with "1"
  104. // 1: Use parameters ending with "2"
  105. BitField<0, 1, u32> second_fb_active;
  106. };
  107. INSERT_PADDING_WORDS(0x5);
  108. // Distance between two pixel rows, in bytes
  109. u32 stride;
  110. u32 address_right1;
  111. u32 address_right2;
  112. INSERT_PADDING_WORDS(0x30);
  113. } framebuffer_config[2];
  114. ASSERT_MEMBER_SIZE(framebuffer_config[0], 0x100);
  115. INSERT_PADDING_WORDS(0x169);
  116. struct {
  117. u32 input_address;
  118. u32 output_address;
  119. inline u32 GetPhysicalInputAddress() const {
  120. return DecodeAddressRegister(input_address);
  121. }
  122. inline u32 GetPhysicalOutputAddress() const {
  123. return DecodeAddressRegister(output_address);
  124. }
  125. union {
  126. u32 output_size;
  127. BitField< 0, 16, u32> output_width;
  128. BitField<16, 16, u32> output_height;
  129. };
  130. union {
  131. u32 input_size;
  132. BitField< 0, 16, u32> input_width;
  133. BitField<16, 16, u32> input_height;
  134. };
  135. union {
  136. u32 flags;
  137. BitField< 0, 1, u32> flip_data; // flips input data horizontally (TODO) if true
  138. BitField< 8, 3, PixelFormat> input_format;
  139. BitField<12, 3, PixelFormat> output_format;
  140. BitField<16, 1, u32> output_tiled; // stores output in a tiled format
  141. // TODO: Not really sure if this actually scales, or even resizes at all.
  142. BitField<24, 1, u32> scale_horizontally;
  143. };
  144. INSERT_PADDING_WORDS(0x1);
  145. // it seems that writing to this field triggers the display transfer
  146. u32 trigger;
  147. } display_transfer_config;
  148. ASSERT_MEMBER_SIZE(display_transfer_config, 0x1c);
  149. INSERT_PADDING_WORDS(0x331);
  150. struct {
  151. // command list size (in bytes)
  152. u32 size;
  153. INSERT_PADDING_WORDS(0x1);
  154. // command list address
  155. u32 address;
  156. INSERT_PADDING_WORDS(0x1);
  157. // it seems that writing to this field triggers command list processing
  158. u32 trigger;
  159. inline u32 GetPhysicalAddress() const {
  160. return DecodeAddressRegister(address);
  161. }
  162. } command_processor_config;
  163. ASSERT_MEMBER_SIZE(command_processor_config, 0x14);
  164. INSERT_PADDING_WORDS(0x9c3);
  165. #undef INSERT_PADDING_WORDS_HELPER1
  166. #undef INSERT_PADDING_WORDS_HELPER2
  167. #undef INSERT_PADDING_WORDS
  168. static inline size_t NumIds() {
  169. return sizeof(Regs) / sizeof(u32);
  170. }
  171. u32& operator [] (int index) const {
  172. u32* content = (u32*)this;
  173. return content[index];
  174. }
  175. u32& operator [] (int index) {
  176. u32* content = (u32*)this;
  177. return content[index];
  178. }
  179. private:
  180. /*
  181. * Most physical addresses which GPU registers refer to are 8-byte aligned.
  182. * This function should be used to get the address from a raw register value.
  183. */
  184. static inline u32 DecodeAddressRegister(u32 register_value) {
  185. return register_value * 8;
  186. }
  187. };
  188. static_assert(std::is_standard_layout<Regs>::value, "Structure does not use standard layout");
  189. // TODO: MSVC does not support using offsetof() on non-static data members even though this
  190. // is technically allowed since C++11. This macro should be enabled once MSVC adds
  191. // support for that.
  192. #ifndef _MSC_VER
  193. #define ASSERT_REG_POSITION(field_name, position) \
  194. static_assert(offsetof(Regs, field_name) == position * 4, \
  195. "Field "#field_name" has invalid position")
  196. ASSERT_REG_POSITION(memory_fill_config[0], 0x00004);
  197. ASSERT_REG_POSITION(memory_fill_config[1], 0x00008);
  198. ASSERT_REG_POSITION(framebuffer_config[0], 0x00117);
  199. ASSERT_REG_POSITION(framebuffer_config[1], 0x00157);
  200. ASSERT_REG_POSITION(display_transfer_config, 0x00300);
  201. ASSERT_REG_POSITION(command_processor_config, 0x00638);
  202. #undef ASSERT_REG_POSITION
  203. #endif // !defined(_MSC_VER)
  204. // The total number of registers is chosen arbitrarily, but let's make sure it's not some odd value anyway.
  205. static_assert(sizeof(Regs) == 0x1000 * sizeof(u32), "Invalid total size of register set");
  206. extern Regs g_regs;
  207. extern bool g_skip_frame;
  208. template <typename T>
  209. void Read(T &var, const u32 addr);
  210. template <typename T>
  211. void Write(u32 addr, const T data);
  212. /// Initialize hardware
  213. void Init();
  214. /// Shutdown hardware
  215. void Shutdown();
  216. } // namespace