renderer_opengl.cpp 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  1. // Copyright 2014 Citra Emulator Project
  2. // Licensed under GPLv2 or any later version
  3. // Refer to the license.txt file included.
  4. #include <algorithm>
  5. #include <cstddef>
  6. #include <cstdlib>
  7. #include <cstring>
  8. #include <memory>
  9. #include <glad/glad.h>
  10. #include "common/assert.h"
  11. #include "common/bit_field.h"
  12. #include "common/logging/log.h"
  13. #include "core/core.h"
  14. #include "core/core_timing.h"
  15. #include "core/frontend/emu_window.h"
  16. #include "core/hw/hw.h"
  17. #include "core/hw/lcd.h"
  18. #include "core/memory.h"
  19. #include "core/settings.h"
  20. #include "core/tracer/recorder.h"
  21. #include "video_core/renderer_opengl/renderer_opengl.h"
  22. #include "video_core/video_core.h"
  23. static const char vertex_shader[] = R"(
  24. #version 150 core
  25. in vec2 vert_position;
  26. in vec2 vert_tex_coord;
  27. out vec2 frag_tex_coord;
  28. // This is a truncated 3x3 matrix for 2D transformations:
  29. // The upper-left 2x2 submatrix performs scaling/rotation/mirroring.
  30. // The third column performs translation.
  31. // The third row could be used for projection, which we don't need in 2D. It hence is assumed to
  32. // implicitly be [0, 0, 1]
  33. uniform mat3x2 modelview_matrix;
  34. void main() {
  35. // Multiply input position by the rotscale part of the matrix and then manually translate by
  36. // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector
  37. // to `vec3(vert_position.xy, 1.0)`
  38. gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0);
  39. frag_tex_coord = vert_tex_coord;
  40. }
  41. )";
  42. static const char fragment_shader[] = R"(
  43. #version 150 core
  44. in vec2 frag_tex_coord;
  45. out vec4 color;
  46. uniform sampler2D color_texture;
  47. void main() {
  48. // Swap RGBA -> ABGR so we don't have to do this on the CPU. This needs to change if we have to
  49. // support more framebuffer pixel formats.
  50. color = texture(color_texture, frag_tex_coord).abgr;
  51. }
  52. )";
  53. /**
  54. * Vertex structure that the drawn screen rectangles are composed of.
  55. */
  56. struct ScreenRectVertex {
  57. ScreenRectVertex(GLfloat x, GLfloat y, GLfloat u, GLfloat v) {
  58. position[0] = x;
  59. position[1] = y;
  60. tex_coord[0] = u;
  61. tex_coord[1] = v;
  62. }
  63. GLfloat position[2];
  64. GLfloat tex_coord[2];
  65. };
  66. /**
  67. * Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left
  68. * corner and (width, height) on the lower-bottom.
  69. *
  70. * The projection part of the matrix is trivial, hence these operations are represented
  71. * by a 3x2 matrix.
  72. */
  73. static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, const float height) {
  74. std::array<GLfloat, 3 * 2> matrix; // Laid out in column-major order
  75. // clang-format off
  76. matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f;
  77. matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f;
  78. // Last matrix row is implicitly assumed to be [0, 0, 1].
  79. // clang-format on
  80. return matrix;
  81. }
  82. RendererOpenGL::RendererOpenGL() = default;
  83. RendererOpenGL::~RendererOpenGL() = default;
  84. /// Swap buffers (render frame)
  85. void RendererOpenGL::SwapBuffers(boost::optional<const FramebufferInfo&> framebuffer_info) {
  86. // Maintain the rasterizer's state as a priority
  87. OpenGLState prev_state = OpenGLState::GetCurState();
  88. state.Apply();
  89. if (framebuffer_info != boost::none) {
  90. // If framebuffer_info is provided, reload it from memory to a texture
  91. if (screen_info.texture.width != (GLsizei)framebuffer_info->width ||
  92. screen_info.texture.height != (GLsizei)framebuffer_info->height ||
  93. screen_info.texture.pixel_format != framebuffer_info->pixel_format) {
  94. // Reallocate texture if the framebuffer size has changed.
  95. // This is expected to not happen very often and hence should not be a
  96. // performance problem.
  97. ConfigureFramebufferTexture(screen_info.texture, *framebuffer_info);
  98. }
  99. LoadFBToScreenInfo(*framebuffer_info, screen_info);
  100. }
  101. DrawScreens();
  102. Core::System::GetInstance().perf_stats.EndSystemFrame();
  103. // Swap buffers
  104. render_window->PollEvents();
  105. render_window->SwapBuffers();
  106. Core::System::GetInstance().frame_limiter.DoFrameLimiting(CoreTiming::GetGlobalTimeUs());
  107. Core::System::GetInstance().perf_stats.BeginSystemFrame();
  108. prev_state.Apply();
  109. RefreshRasterizerSetting();
  110. }
  111. static inline u32 MortonInterleave128(u32 x, u32 y) {
  112. // 128x128 Z-Order coordinate from 2D coordinates
  113. static constexpr u32 xlut[] = {
  114. 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042,
  115. 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809,
  116. 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000,
  117. 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043,
  118. 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a,
  119. 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001,
  120. 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048,
  121. 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b,
  122. 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002,
  123. 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049,
  124. 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840,
  125. 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003,
  126. 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a,
  127. 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841,
  128. 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008,
  129. 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b,
  130. 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842,
  131. 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009,
  132. 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800,
  133. 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843,
  134. 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a,
  135. 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801,
  136. 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848,
  137. 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b,
  138. 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802,
  139. 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849,
  140. 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040,
  141. 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803,
  142. 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a,
  143. 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041,
  144. 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808,
  145. 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b,
  146. 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042,
  147. 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809,
  148. 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b,
  149. };
  150. static constexpr u32 ylut[] = {
  151. 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090,
  152. 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124,
  153. 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200,
  154. 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294,
  155. 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330,
  156. 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404,
  157. 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0,
  158. 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534,
  159. 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610,
  160. 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4,
  161. 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780,
  162. 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014,
  163. 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0,
  164. 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184,
  165. 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220,
  166. 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4,
  167. 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390,
  168. 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424,
  169. 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500,
  170. 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594,
  171. 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630,
  172. 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704,
  173. 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0,
  174. 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034,
  175. 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110,
  176. 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4,
  177. 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280,
  178. 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314,
  179. 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0,
  180. 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484,
  181. 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520,
  182. 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4,
  183. 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690,
  184. 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724,
  185. 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4,
  186. };
  187. return xlut[x % 128] + ylut[y % 128];
  188. }
  189. static inline u32 GetMortonOffset128(u32 x, u32 y, u32 bytes_per_pixel) {
  190. // Calculates the offset of the position of the pixel in Morton order
  191. // Framebuffer images are split into 128x128 tiles.
  192. const unsigned int block_height = 128;
  193. const unsigned int coarse_x = x & ~127;
  194. u32 i = MortonInterleave128(x, y);
  195. const unsigned int offset = coarse_x * block_height;
  196. return (i + offset) * bytes_per_pixel;
  197. }
  198. static void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixel, u32 gl_bytes_per_pixel,
  199. u8* morton_data, u8* gl_data, bool morton_to_gl) {
  200. u8* data_ptrs[2];
  201. for (unsigned y = 0; y < height; ++y) {
  202. for (unsigned x = 0; x < width; ++x) {
  203. const u32 coarse_y = y & ~127;
  204. u32 morton_offset =
  205. GetMortonOffset128(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel;
  206. u32 gl_pixel_index = (x + (height - 1 - y) * width) * gl_bytes_per_pixel;
  207. data_ptrs[morton_to_gl] = morton_data + morton_offset;
  208. data_ptrs[!morton_to_gl] = &gl_data[gl_pixel_index];
  209. memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel);
  210. }
  211. }
  212. }
  213. /**
  214. * Loads framebuffer from emulated memory into the active OpenGL texture.
  215. */
  216. void RendererOpenGL::LoadFBToScreenInfo(const FramebufferInfo& framebuffer_info,
  217. ScreenInfo& screen_info) {
  218. const u32 bpp{FramebufferInfo::BytesPerPixel(framebuffer_info.pixel_format)};
  219. const u32 size_in_bytes{framebuffer_info.stride * framebuffer_info.height * bpp};
  220. MortonCopyPixels128(framebuffer_info.width, framebuffer_info.height, bpp, 4,
  221. Memory::GetPointer(framebuffer_info.address), gl_framebuffer_data.data(),
  222. true);
  223. LOG_TRACE(Render_OpenGL, "0x%08x bytes from 0x%llx(%dx%d), fmt %x", size_in_bytes,
  224. framebuffer_info.address, framebuffer_info.width, framebuffer_info.height,
  225. (int)framebuffer_info.pixel_format);
  226. // Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default
  227. // only allows rows to have a memory alignement of 4.
  228. ASSERT(framebuffer_info.stride % 4 == 0);
  229. framebuffer_flip_vertical = framebuffer_info.flip_vertical;
  230. // Reset the screen info's display texture to its own permanent texture
  231. screen_info.display_texture = screen_info.texture.resource.handle;
  232. screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f);
  233. // Memory::RasterizerFlushRegion(framebuffer_info.address, size_in_bytes);
  234. state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
  235. state.Apply();
  236. glActiveTexture(GL_TEXTURE0);
  237. glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)framebuffer_info.stride);
  238. // Update existing texture
  239. // TODO: Test what happens on hardware when you change the framebuffer dimensions so that
  240. // they differ from the LCD resolution.
  241. // TODO: Applications could theoretically crash Citra here by specifying too large
  242. // framebuffer sizes. We should make sure that this cannot happen.
  243. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer_info.width, framebuffer_info.height,
  244. screen_info.texture.gl_format, screen_info.texture.gl_type,
  245. gl_framebuffer_data.data());
  246. glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  247. state.texture_units[0].texture_2d = 0;
  248. state.Apply();
  249. }
  250. /**
  251. * Fills active OpenGL texture with the given RGB color. Since the color is solid, the texture can
  252. * be 1x1 but will stretch across whatever it's rendered on.
  253. */
  254. void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b, u8 color_a,
  255. const TextureInfo& texture) {
  256. state.texture_units[0].texture_2d = texture.resource.handle;
  257. state.Apply();
  258. glActiveTexture(GL_TEXTURE0);
  259. u8 framebuffer_data[4] = {color_a, color_b, color_g, color_r};
  260. // Update existing texture
  261. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer_data);
  262. state.texture_units[0].texture_2d = 0;
  263. state.Apply();
  264. }
  265. /**
  266. * Initializes the OpenGL state and creates persistent objects.
  267. */
  268. void RendererOpenGL::InitOpenGLObjects() {
  269. glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue,
  270. 0.0f);
  271. // Link shaders and get variable locations
  272. shader.Create(vertex_shader, nullptr, fragment_shader);
  273. state.draw.shader_program = shader.handle;
  274. state.Apply();
  275. uniform_modelview_matrix = glGetUniformLocation(shader.handle, "modelview_matrix");
  276. uniform_color_texture = glGetUniformLocation(shader.handle, "color_texture");
  277. attrib_position = glGetAttribLocation(shader.handle, "vert_position");
  278. attrib_tex_coord = glGetAttribLocation(shader.handle, "vert_tex_coord");
  279. // Generate VBO handle for drawing
  280. vertex_buffer.Create();
  281. // Generate VAO
  282. vertex_array.Create();
  283. state.draw.vertex_array = vertex_array.handle;
  284. state.draw.vertex_buffer = vertex_buffer.handle;
  285. state.draw.uniform_buffer = 0;
  286. state.Apply();
  287. // Attach vertex data to VAO
  288. glBufferData(GL_ARRAY_BUFFER, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW);
  289. glVertexAttribPointer(attrib_position, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex),
  290. (GLvoid*)offsetof(ScreenRectVertex, position));
  291. glVertexAttribPointer(attrib_tex_coord, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex),
  292. (GLvoid*)offsetof(ScreenRectVertex, tex_coord));
  293. glEnableVertexAttribArray(attrib_position);
  294. glEnableVertexAttribArray(attrib_tex_coord);
  295. // Allocate textures for the screen
  296. screen_info.texture.resource.Create();
  297. // Allocation of storage is deferred until the first frame, when we
  298. // know the framebuffer size.
  299. state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
  300. state.Apply();
  301. glActiveTexture(GL_TEXTURE0);
  302. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
  303. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  304. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  305. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  306. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  307. screen_info.display_texture = screen_info.texture.resource.handle;
  308. state.texture_units[0].texture_2d = 0;
  309. state.Apply();
  310. // Clear screen to black
  311. LoadColorToActiveGLTexture(0, 0, 0, 0, screen_info.texture);
  312. }
  313. void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
  314. const FramebufferInfo& framebuffer_info) {
  315. texture.width = framebuffer_info.width;
  316. texture.height = framebuffer_info.height;
  317. GLint internal_format;
  318. switch (framebuffer_info.pixel_format) {
  319. case FramebufferInfo::PixelFormat::ABGR8:
  320. // Use RGBA8 and swap in the fragment shader
  321. internal_format = GL_RGBA;
  322. texture.gl_format = GL_RGBA;
  323. texture.gl_type = GL_UNSIGNED_INT_8_8_8_8;
  324. gl_framebuffer_data.resize(texture.width * texture.height * 4);
  325. break;
  326. default:
  327. UNIMPLEMENTED();
  328. }
  329. state.texture_units[0].texture_2d = texture.resource.handle;
  330. state.Apply();
  331. glActiveTexture(GL_TEXTURE0);
  332. glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
  333. texture.gl_format, texture.gl_type, nullptr);
  334. state.texture_units[0].texture_2d = 0;
  335. state.Apply();
  336. }
  337. void RendererOpenGL::DrawSingleScreen(const ScreenInfo& screen_info, float x, float y, float w,
  338. float h) {
  339. const auto& texcoords = screen_info.display_texcoords;
  340. const auto& left = framebuffer_flip_vertical ? texcoords.right : texcoords.left;
  341. const auto& right = framebuffer_flip_vertical ? texcoords.left : texcoords.right;
  342. std::array<ScreenRectVertex, 4> vertices = {{
  343. ScreenRectVertex(x, y, texcoords.top, right),
  344. ScreenRectVertex(x + w, y, texcoords.bottom, right),
  345. ScreenRectVertex(x, y + h, texcoords.top, left),
  346. ScreenRectVertex(x + w, y + h, texcoords.bottom, left),
  347. }};
  348. state.texture_units[0].texture_2d = screen_info.display_texture;
  349. state.Apply();
  350. glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data());
  351. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  352. state.texture_units[0].texture_2d = 0;
  353. state.Apply();
  354. }
  355. /**
  356. * Draws the emulated screens to the emulator window.
  357. */
  358. void RendererOpenGL::DrawScreens() {
  359. const auto& layout = render_window->GetFramebufferLayout();
  360. const auto& screen = layout.screen;
  361. glViewport(0, 0, layout.width, layout.height);
  362. glClear(GL_COLOR_BUFFER_BIT);
  363. // Set projection matrix
  364. std::array<GLfloat, 3 * 2> ortho_matrix =
  365. MakeOrthographicMatrix((float)layout.width, (float)layout.height);
  366. glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data());
  367. // Bind texture in Texture Unit 0
  368. glActiveTexture(GL_TEXTURE0);
  369. glUniform1i(uniform_color_texture, 0);
  370. DrawSingleScreen(screen_info, (float)screen.left, (float)screen.top, (float)screen.GetWidth(),
  371. (float)screen.GetHeight());
  372. m_current_frame++;
  373. }
  374. /// Updates the framerate
  375. void RendererOpenGL::UpdateFramerate() {}
  376. /**
  377. * Set the emulator window to use for renderer
  378. * @param window EmuWindow handle to emulator window to use for rendering
  379. */
  380. void RendererOpenGL::SetWindow(EmuWindow* window) {
  381. render_window = window;
  382. }
  383. static const char* GetSource(GLenum source) {
  384. #define RET(s) \
  385. case GL_DEBUG_SOURCE_##s: \
  386. return #s
  387. switch (source) {
  388. RET(API);
  389. RET(WINDOW_SYSTEM);
  390. RET(SHADER_COMPILER);
  391. RET(THIRD_PARTY);
  392. RET(APPLICATION);
  393. RET(OTHER);
  394. default:
  395. UNREACHABLE();
  396. }
  397. #undef RET
  398. }
  399. static const char* GetType(GLenum type) {
  400. #define RET(t) \
  401. case GL_DEBUG_TYPE_##t: \
  402. return #t
  403. switch (type) {
  404. RET(ERROR);
  405. RET(DEPRECATED_BEHAVIOR);
  406. RET(UNDEFINED_BEHAVIOR);
  407. RET(PORTABILITY);
  408. RET(PERFORMANCE);
  409. RET(OTHER);
  410. RET(MARKER);
  411. default:
  412. UNREACHABLE();
  413. }
  414. #undef RET
  415. }
  416. static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity,
  417. GLsizei length, const GLchar* message, const void* user_param) {
  418. Log::Level level;
  419. switch (severity) {
  420. case GL_DEBUG_SEVERITY_HIGH:
  421. level = Log::Level::Error;
  422. break;
  423. case GL_DEBUG_SEVERITY_MEDIUM:
  424. level = Log::Level::Warning;
  425. break;
  426. case GL_DEBUG_SEVERITY_NOTIFICATION:
  427. case GL_DEBUG_SEVERITY_LOW:
  428. level = Log::Level::Debug;
  429. break;
  430. }
  431. LOG_GENERIC(Log::Class::Render_OpenGL, level, "%s %s %d: %s", GetSource(source), GetType(type),
  432. id, message);
  433. }
  434. /// Initialize the renderer
  435. bool RendererOpenGL::Init() {
  436. render_window->MakeCurrent();
  437. if (GLAD_GL_KHR_debug) {
  438. glEnable(GL_DEBUG_OUTPUT);
  439. glDebugMessageCallback(DebugHandler, nullptr);
  440. }
  441. const char* gl_version{reinterpret_cast<char const*>(glGetString(GL_VERSION))};
  442. const char* gpu_vendor{reinterpret_cast<char const*>(glGetString(GL_VENDOR))};
  443. const char* gpu_model{reinterpret_cast<char const*>(glGetString(GL_RENDERER))};
  444. LOG_INFO(Render_OpenGL, "GL_VERSION: %s", gl_version);
  445. LOG_INFO(Render_OpenGL, "GL_VENDOR: %s", gpu_vendor);
  446. LOG_INFO(Render_OpenGL, "GL_RENDERER: %s", gpu_model);
  447. Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Vendor", gpu_vendor);
  448. Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Model", gpu_model);
  449. Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_OpenGL_Version", gl_version);
  450. if (!GLAD_GL_VERSION_3_3) {
  451. return false;
  452. }
  453. InitOpenGLObjects();
  454. RefreshRasterizerSetting();
  455. return true;
  456. }
  457. /// Shutdown the renderer
  458. void RendererOpenGL::ShutDown() {}