gpu.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  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 <type_traits>
  7. #include "common/assert.h"
  8. #include "common/bit_field.h"
  9. #include "common/common_funcs.h"
  10. #include "common/common_types.h"
  11. namespace GPU {
  12. constexpr float SCREEN_REFRESH_RATE = 60;
  13. // Returns index corresponding to the Regs member labeled by field_name
  14. // TODO: Due to Visual studio bug 209229, offsetof does not return constant expressions
  15. // when used with array elements (e.g. GPU_REG_INDEX(memory_fill_config[0])).
  16. // For details cf.
  17. // https://connect.microsoft.com/VisualStudio/feedback/details/209229/offsetof-does-not-produce-a-constant-expression-for-array-members
  18. // Hopefully, this will be fixed sometime in the future.
  19. // For lack of better alternatives, we currently hardcode the offsets when constant
  20. // expressions are needed via GPU_REG_INDEX_WORKAROUND (on sane compilers, static_asserts
  21. // will then make sure the offsets indeed match the automatically calculated ones).
  22. #define GPU_REG_INDEX(field_name) (offsetof(GPU::Regs, field_name) / sizeof(u32))
  23. #if defined(_MSC_VER)
  24. #define GPU_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) (backup_workaround_index)
  25. #else
  26. // NOTE: Yeah, hacking in a static_assert here just to workaround the lacking MSVC compiler
  27. // really is this annoying. This macro just forwards its first argument to GPU_REG_INDEX
  28. // and then performs a (no-op) cast to size_t iff the second argument matches the expected
  29. // field offset. Otherwise, the compiler will fail to compile this code.
  30. #define GPU_REG_INDEX_WORKAROUND(field_name, backup_workaround_index) \
  31. ((typename std::enable_if<backup_workaround_index == GPU_REG_INDEX(field_name), size_t>::type) \
  32. GPU_REG_INDEX(field_name))
  33. #endif
  34. // MMIO region 0x1EFxxxxx
  35. struct Regs {
  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. // Components are laid out in reverse byte order, most significant bits first.
  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. }
  69. UNREACHABLE();
  70. }
  71. INSERT_PADDING_WORDS(0x4);
  72. struct MemoryFillConfig {
  73. u32 address_start;
  74. u32 address_end;
  75. union {
  76. u32 value_32bit;
  77. BitField<0, 16, u32> value_16bit;
  78. // TODO: Verify component order
  79. BitField<0, 8, u32> value_24bit_r;
  80. BitField<8, 8, u32> value_24bit_g;
  81. BitField<16, 8, u32> value_24bit_b;
  82. };
  83. union {
  84. u32 control;
  85. // Setting this field to 1 triggers the memory fill.
  86. // This field also acts as a status flag, and gets reset to 0 upon completion.
  87. BitField<0, 1, u32> trigger;
  88. // Set to 1 upon completion.
  89. BitField<1, 1, u32> finished;
  90. // If both of these bits are unset, then it will fill the memory with a 16 bit value
  91. // 1: fill with 24-bit wide values
  92. BitField<8, 1, u32> fill_24bit;
  93. // 1: fill with 32-bit wide values
  94. BitField<9, 1, u32> fill_32bit;
  95. };
  96. inline u32 GetStartAddress() const {
  97. return DecodeAddressRegister(address_start);
  98. }
  99. inline u32 GetEndAddress() const {
  100. return DecodeAddressRegister(address_end);
  101. }
  102. } memory_fill_config[2];
  103. ASSERT_MEMBER_SIZE(memory_fill_config[0], 0x10);
  104. INSERT_PADDING_WORDS(0x10b);
  105. struct FramebufferConfig {
  106. union {
  107. u32 size;
  108. BitField<0, 16, u32> width;
  109. BitField<16, 16, u32> height;
  110. };
  111. INSERT_PADDING_WORDS(0x2);
  112. u32 address_left1;
  113. u32 address_left2;
  114. union {
  115. u32 format;
  116. BitField<0, 3, PixelFormat> color_format;
  117. };
  118. INSERT_PADDING_WORDS(0x1);
  119. union {
  120. u32 active_fb;
  121. // 0: Use parameters ending with "1"
  122. // 1: Use parameters ending with "2"
  123. BitField<0, 1, u32> second_fb_active;
  124. };
  125. INSERT_PADDING_WORDS(0x5);
  126. // Distance between two pixel rows, in bytes
  127. u32 stride;
  128. u32 address_right1;
  129. u32 address_right2;
  130. INSERT_PADDING_WORDS(0x30);
  131. } framebuffer_config[2];
  132. ASSERT_MEMBER_SIZE(framebuffer_config[0], 0x100);
  133. INSERT_PADDING_WORDS(0x169);
  134. struct DisplayTransferConfig {
  135. u32 input_address;
  136. u32 output_address;
  137. inline u32 GetPhysicalInputAddress() const {
  138. return DecodeAddressRegister(input_address);
  139. }
  140. inline u32 GetPhysicalOutputAddress() const {
  141. return DecodeAddressRegister(output_address);
  142. }
  143. union {
  144. u32 output_size;
  145. BitField<0, 16, u32> output_width;
  146. BitField<16, 16, u32> output_height;
  147. };
  148. union {
  149. u32 input_size;
  150. BitField<0, 16, u32> input_width;
  151. BitField<16, 16, u32> input_height;
  152. };
  153. enum ScalingMode : u32 {
  154. NoScale = 0, // Doesn't scale the image
  155. ScaleX = 1, // Downscales the image in half in the X axis and applies a box filter
  156. ScaleXY =
  157. 2, // Downscales the image in half in both the X and Y axes and applies a box filter
  158. };
  159. union {
  160. u32 flags;
  161. BitField<0, 1, u32> flip_vertically; // flips input data vertically
  162. BitField<1, 1, u32> input_linear; // Converts from linear to tiled format
  163. BitField<2, 1, u32> crop_input_lines;
  164. BitField<3, 1, u32> is_texture_copy; // Copies the data without performing any
  165. // processing and respecting texture copy fields
  166. BitField<5, 1, u32> dont_swizzle;
  167. BitField<8, 3, PixelFormat> input_format;
  168. BitField<12, 3, PixelFormat> output_format;
  169. /// Uses some kind of 32x32 block swizzling mode, instead of the usual 8x8 one.
  170. BitField<16, 1, u32> block_32; // TODO(yuriks): unimplemented
  171. BitField<24, 2, ScalingMode> scaling; // Determines the scaling mode of the transfer
  172. };
  173. INSERT_PADDING_WORDS(0x1);
  174. // it seems that writing to this field triggers the display transfer
  175. u32 trigger;
  176. INSERT_PADDING_WORDS(0x1);
  177. struct {
  178. u32 size; // The lower 4 bits are ignored
  179. union {
  180. u32 input_size;
  181. BitField<0, 16, u32> input_width;
  182. BitField<16, 16, u32> input_gap;
  183. };
  184. union {
  185. u32 output_size;
  186. BitField<0, 16, u32> output_width;
  187. BitField<16, 16, u32> output_gap;
  188. };
  189. } texture_copy;
  190. } display_transfer_config;
  191. ASSERT_MEMBER_SIZE(display_transfer_config, 0x2c);
  192. INSERT_PADDING_WORDS(0x32D);
  193. struct {
  194. // command list size (in bytes)
  195. u32 size;
  196. INSERT_PADDING_WORDS(0x1);
  197. // command list address
  198. u32 address;
  199. INSERT_PADDING_WORDS(0x1);
  200. // it seems that writing to this field triggers command list processing
  201. u32 trigger;
  202. inline u32 GetPhysicalAddress() const {
  203. return DecodeAddressRegister(address);
  204. }
  205. } command_processor_config;
  206. ASSERT_MEMBER_SIZE(command_processor_config, 0x14);
  207. INSERT_PADDING_WORDS(0x9c3);
  208. static constexpr size_t NumIds() {
  209. return sizeof(Regs) / sizeof(u32);
  210. }
  211. const u32& operator[](int index) const {
  212. const u32* content = reinterpret_cast<const u32*>(this);
  213. return content[index];
  214. }
  215. u32& operator[](int index) {
  216. u32* content = reinterpret_cast<u32*>(this);
  217. return content[index];
  218. }
  219. #undef ASSERT_MEMBER_SIZE
  220. private:
  221. /*
  222. * Most physical addresses which GPU registers refer to are 8-byte aligned.
  223. * This function should be used to get the address from a raw register value.
  224. */
  225. static inline u32 DecodeAddressRegister(u32 register_value) {
  226. return register_value * 8;
  227. }
  228. };
  229. static_assert(std::is_standard_layout<Regs>::value, "Structure does not use standard layout");
  230. // TODO: MSVC does not support using offsetof() on non-static data members even though this
  231. // is technically allowed since C++11. This macro should be enabled once MSVC adds
  232. // support for that.
  233. #ifndef _MSC_VER
  234. #define ASSERT_REG_POSITION(field_name, position) \
  235. static_assert(offsetof(Regs, field_name) == position * 4, \
  236. "Field " #field_name " has invalid position")
  237. ASSERT_REG_POSITION(memory_fill_config[0], 0x00004);
  238. ASSERT_REG_POSITION(memory_fill_config[1], 0x00008);
  239. ASSERT_REG_POSITION(framebuffer_config[0], 0x00117);
  240. ASSERT_REG_POSITION(framebuffer_config[1], 0x00157);
  241. ASSERT_REG_POSITION(display_transfer_config, 0x00300);
  242. ASSERT_REG_POSITION(command_processor_config, 0x00638);
  243. #undef ASSERT_REG_POSITION
  244. #endif // !defined(_MSC_VER)
  245. // The total number of registers is chosen arbitrarily, but let's make sure it's not some odd value
  246. // anyway.
  247. static_assert(sizeof(Regs) == 0x1000 * sizeof(u32), "Invalid total size of register set");
  248. extern Regs g_regs;
  249. template <typename T>
  250. void Read(T& var, const u32 addr);
  251. template <typename T>
  252. void Write(u32 addr, const T data);
  253. /// Initialize hardware
  254. void Init();
  255. /// Shutdown hardware
  256. void Shutdown();
  257. } // namespace