renderer_opengl.cpp 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519
  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 <memory>
  8. #include <glad/glad.h>
  9. #include "common/assert.h"
  10. #include "common/bit_field.h"
  11. #include "common/logging/log.h"
  12. #include "common/profiler_reporting.h"
  13. #include "common/synchronized_wrapper.h"
  14. #include "core/core.h"
  15. #include "core/frontend/emu_window.h"
  16. #include "core/hw/gpu.h"
  17. #include "core/hw/hw.h"
  18. #include "core/hw/lcd.h"
  19. #include "core/memory.h"
  20. #include "core/settings.h"
  21. #include "core/tracer/recorder.h"
  22. #include "video_core/debug_utils/debug_utils.h"
  23. #include "video_core/rasterizer_interface.h"
  24. #include "video_core/renderer_opengl/renderer_opengl.h"
  25. #include "video_core/video_core.h"
  26. static const char vertex_shader[] = R"(
  27. #version 150 core
  28. in vec2 vert_position;
  29. in vec2 vert_tex_coord;
  30. out vec2 frag_tex_coord;
  31. // This is a truncated 3x3 matrix for 2D transformations:
  32. // The upper-left 2x2 submatrix performs scaling/rotation/mirroring.
  33. // The third column performs translation.
  34. // The third row could be used for projection, which we don't need in 2D. It hence is assumed to
  35. // implicitly be [0, 0, 1]
  36. uniform mat3x2 modelview_matrix;
  37. void main() {
  38. // Multiply input position by the rotscale part of the matrix and then manually translate by
  39. // the last column. This is equivalent to using a full 3x3 matrix and expanding the vector
  40. // to `vec3(vert_position.xy, 1.0)`
  41. gl_Position = vec4(mat2(modelview_matrix) * vert_position + modelview_matrix[2], 0.0, 1.0);
  42. frag_tex_coord = vert_tex_coord;
  43. }
  44. )";
  45. static const char fragment_shader[] = R"(
  46. #version 150 core
  47. in vec2 frag_tex_coord;
  48. out vec4 color;
  49. uniform sampler2D color_texture;
  50. void main() {
  51. color = texture(color_texture, frag_tex_coord);
  52. }
  53. )";
  54. /**
  55. * Vertex structure that the drawn screen rectangles are composed of.
  56. */
  57. struct ScreenRectVertex {
  58. ScreenRectVertex(GLfloat x, GLfloat y, GLfloat u, GLfloat v) {
  59. position[0] = x;
  60. position[1] = y;
  61. tex_coord[0] = u;
  62. tex_coord[1] = v;
  63. }
  64. GLfloat position[2];
  65. GLfloat tex_coord[2];
  66. };
  67. /**
  68. * Defines a 1:1 pixel ortographic projection matrix with (0,0) on the top-left
  69. * corner and (width, height) on the lower-bottom.
  70. *
  71. * The projection part of the matrix is trivial, hence these operations are represented
  72. * by a 3x2 matrix.
  73. */
  74. static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, const float height) {
  75. std::array<GLfloat, 3 * 2> matrix; // Laid out in column-major order
  76. // clang-format off
  77. matrix[0] = 2.f / width; matrix[2] = 0.f; matrix[4] = -1.f;
  78. matrix[1] = 0.f; matrix[3] = -2.f / height; matrix[5] = 1.f;
  79. // Last matrix row is implicitly assumed to be [0, 0, 1].
  80. // clang-format on
  81. return matrix;
  82. }
  83. /// RendererOpenGL constructor
  84. RendererOpenGL::RendererOpenGL() {
  85. resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth);
  86. resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight;
  87. }
  88. /// RendererOpenGL destructor
  89. RendererOpenGL::~RendererOpenGL() {}
  90. /// Swap buffers (render frame)
  91. void RendererOpenGL::SwapBuffers() {
  92. // Maintain the rasterizer's state as a priority
  93. OpenGLState prev_state = OpenGLState::GetCurState();
  94. state.Apply();
  95. for (int i : {0, 1}) {
  96. const auto& framebuffer = GPU::g_regs.framebuffer_config[i];
  97. // Main LCD (0): 0x1ED02204, Sub LCD (1): 0x1ED02A04
  98. u32 lcd_color_addr =
  99. (i == 0) ? LCD_REG_INDEX(color_fill_top) : LCD_REG_INDEX(color_fill_bottom);
  100. lcd_color_addr = HW::VADDR_LCD + 4 * lcd_color_addr;
  101. LCD::Regs::ColorFill color_fill = {0};
  102. LCD::Read(color_fill.raw, lcd_color_addr);
  103. if (color_fill.is_enabled) {
  104. LoadColorToActiveGLTexture(color_fill.color_r, color_fill.color_g, color_fill.color_b,
  105. screen_infos[i].texture);
  106. // Resize the texture in case the framebuffer size has changed
  107. screen_infos[i].texture.width = 1;
  108. screen_infos[i].texture.height = 1;
  109. } else {
  110. if (screen_infos[i].texture.width != (GLsizei)framebuffer.width ||
  111. screen_infos[i].texture.height != (GLsizei)framebuffer.height ||
  112. screen_infos[i].texture.format != framebuffer.color_format) {
  113. // Reallocate texture if the framebuffer size has changed.
  114. // This is expected to not happen very often and hence should not be a
  115. // performance problem.
  116. ConfigureFramebufferTexture(screen_infos[i].texture, framebuffer);
  117. }
  118. LoadFBToScreenInfo(framebuffer, screen_infos[i]);
  119. // Resize the texture in case the framebuffer size has changed
  120. screen_infos[i].texture.width = framebuffer.width;
  121. screen_infos[i].texture.height = framebuffer.height;
  122. }
  123. }
  124. DrawScreens();
  125. auto& profiler = Common::Profiling::GetProfilingManager();
  126. profiler.FinishFrame();
  127. {
  128. auto aggregator = Common::Profiling::GetTimingResultsAggregator();
  129. aggregator->AddFrame(profiler.GetPreviousFrameResults());
  130. }
  131. {
  132. auto perf_stats = Core::System::GetInstance().perf_stats.Lock();
  133. perf_stats->EndSystemFrame();
  134. }
  135. // Swap buffers
  136. render_window->PollEvents();
  137. render_window->SwapBuffers();
  138. prev_state.Apply();
  139. profiler.BeginFrame();
  140. {
  141. auto perf_stats = Core::System::GetInstance().perf_stats.Lock();
  142. perf_stats->BeginSystemFrame();
  143. }
  144. RefreshRasterizerSetting();
  145. if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
  146. Pica::g_debug_context->recorder->FrameFinished();
  147. }
  148. }
  149. /**
  150. * Loads framebuffer from emulated memory into the active OpenGL texture.
  151. */
  152. void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& framebuffer,
  153. ScreenInfo& screen_info) {
  154. const PAddr framebuffer_addr =
  155. framebuffer.active_fb == 0 ? framebuffer.address_left1 : framebuffer.address_left2;
  156. LOG_TRACE(Render_OpenGL, "0x%08x bytes from 0x%08x(%dx%d), fmt %x",
  157. framebuffer.stride * framebuffer.height, framebuffer_addr, (int)framebuffer.width,
  158. (int)framebuffer.height, (int)framebuffer.format);
  159. int bpp = GPU::Regs::BytesPerPixel(framebuffer.color_format);
  160. size_t pixel_stride = framebuffer.stride / bpp;
  161. // OpenGL only supports specifying a stride in units of pixels, not bytes, unfortunately
  162. ASSERT(pixel_stride * bpp == framebuffer.stride);
  163. // Ensure no bad interactions with GL_UNPACK_ALIGNMENT, which by default
  164. // only allows rows to have a memory alignement of 4.
  165. ASSERT(pixel_stride % 4 == 0);
  166. if (!Rasterizer()->AccelerateDisplay(framebuffer, framebuffer_addr,
  167. static_cast<u32>(pixel_stride), screen_info)) {
  168. // Reset the screen info's display texture to its own permanent texture
  169. screen_info.display_texture = screen_info.texture.resource.handle;
  170. screen_info.display_texcoords = MathUtil::Rectangle<float>(0.f, 0.f, 1.f, 1.f);
  171. Memory::RasterizerFlushRegion(framebuffer_addr, framebuffer.stride * framebuffer.height);
  172. const u8* framebuffer_data = Memory::GetPhysicalPointer(framebuffer_addr);
  173. state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
  174. state.Apply();
  175. glActiveTexture(GL_TEXTURE0);
  176. glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride);
  177. // Update existing texture
  178. // TODO: Test what happens on hardware when you change the framebuffer dimensions so that
  179. // they differ from the LCD resolution.
  180. // TODO: Applications could theoretically crash Citra here by specifying too large
  181. // framebuffer sizes. We should make sure that this cannot happen.
  182. glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, framebuffer.width, framebuffer.height,
  183. screen_info.texture.gl_format, screen_info.texture.gl_type,
  184. framebuffer_data);
  185. glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
  186. state.texture_units[0].texture_2d = 0;
  187. state.Apply();
  188. }
  189. }
  190. /**
  191. * Fills active OpenGL texture with the given RGB color. Since the color is solid, the texture can
  192. * be 1x1 but will stretch across whatever it's rendered on.
  193. */
  194. void RendererOpenGL::LoadColorToActiveGLTexture(u8 color_r, u8 color_g, u8 color_b,
  195. const TextureInfo& texture) {
  196. state.texture_units[0].texture_2d = texture.resource.handle;
  197. state.Apply();
  198. glActiveTexture(GL_TEXTURE0);
  199. u8 framebuffer_data[3] = {color_r, color_g, color_b};
  200. // Update existing texture
  201. glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, framebuffer_data);
  202. state.texture_units[0].texture_2d = 0;
  203. state.Apply();
  204. }
  205. /**
  206. * Initializes the OpenGL state and creates persistent objects.
  207. */
  208. void RendererOpenGL::InitOpenGLObjects() {
  209. glClearColor(Settings::values.bg_red, Settings::values.bg_green, Settings::values.bg_blue,
  210. 0.0f);
  211. // Link shaders and get variable locations
  212. shader.Create(vertex_shader, fragment_shader);
  213. state.draw.shader_program = shader.handle;
  214. state.Apply();
  215. uniform_modelview_matrix = glGetUniformLocation(shader.handle, "modelview_matrix");
  216. uniform_color_texture = glGetUniformLocation(shader.handle, "color_texture");
  217. attrib_position = glGetAttribLocation(shader.handle, "vert_position");
  218. attrib_tex_coord = glGetAttribLocation(shader.handle, "vert_tex_coord");
  219. // Generate VBO handle for drawing
  220. vertex_buffer.Create();
  221. // Generate VAO
  222. vertex_array.Create();
  223. state.draw.vertex_array = vertex_array.handle;
  224. state.draw.vertex_buffer = vertex_buffer.handle;
  225. state.draw.uniform_buffer = 0;
  226. state.Apply();
  227. // Attach vertex data to VAO
  228. glBufferData(GL_ARRAY_BUFFER, sizeof(ScreenRectVertex) * 4, nullptr, GL_STREAM_DRAW);
  229. glVertexAttribPointer(attrib_position, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex),
  230. (GLvoid*)offsetof(ScreenRectVertex, position));
  231. glVertexAttribPointer(attrib_tex_coord, 2, GL_FLOAT, GL_FALSE, sizeof(ScreenRectVertex),
  232. (GLvoid*)offsetof(ScreenRectVertex, tex_coord));
  233. glEnableVertexAttribArray(attrib_position);
  234. glEnableVertexAttribArray(attrib_tex_coord);
  235. // Allocate textures for each screen
  236. for (auto& screen_info : screen_infos) {
  237. screen_info.texture.resource.Create();
  238. // Allocation of storage is deferred until the first frame, when we
  239. // know the framebuffer size.
  240. state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
  241. state.Apply();
  242. glActiveTexture(GL_TEXTURE0);
  243. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
  244. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  245. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  246. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  247. glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  248. screen_info.display_texture = screen_info.texture.resource.handle;
  249. }
  250. state.texture_units[0].texture_2d = 0;
  251. state.Apply();
  252. }
  253. void RendererOpenGL::ConfigureFramebufferTexture(TextureInfo& texture,
  254. const GPU::Regs::FramebufferConfig& framebuffer) {
  255. GPU::Regs::PixelFormat format = framebuffer.color_format;
  256. GLint internal_format;
  257. texture.format = format;
  258. texture.width = framebuffer.width;
  259. texture.height = framebuffer.height;
  260. switch (format) {
  261. case GPU::Regs::PixelFormat::RGBA8:
  262. internal_format = GL_RGBA;
  263. texture.gl_format = GL_RGBA;
  264. texture.gl_type = GL_UNSIGNED_INT_8_8_8_8;
  265. break;
  266. case GPU::Regs::PixelFormat::RGB8:
  267. // This pixel format uses BGR since GL_UNSIGNED_BYTE specifies byte-order, unlike every
  268. // specific OpenGL type used in this function using native-endian (that is, little-endian
  269. // mostly everywhere) for words or half-words.
  270. // TODO: check how those behave on big-endian processors.
  271. internal_format = GL_RGB;
  272. texture.gl_format = GL_BGR;
  273. texture.gl_type = GL_UNSIGNED_BYTE;
  274. break;
  275. case GPU::Regs::PixelFormat::RGB565:
  276. internal_format = GL_RGB;
  277. texture.gl_format = GL_RGB;
  278. texture.gl_type = GL_UNSIGNED_SHORT_5_6_5;
  279. break;
  280. case GPU::Regs::PixelFormat::RGB5A1:
  281. internal_format = GL_RGBA;
  282. texture.gl_format = GL_RGBA;
  283. texture.gl_type = GL_UNSIGNED_SHORT_5_5_5_1;
  284. break;
  285. case GPU::Regs::PixelFormat::RGBA4:
  286. internal_format = GL_RGBA;
  287. texture.gl_format = GL_RGBA;
  288. texture.gl_type = GL_UNSIGNED_SHORT_4_4_4_4;
  289. break;
  290. default:
  291. UNIMPLEMENTED();
  292. }
  293. state.texture_units[0].texture_2d = texture.resource.handle;
  294. state.Apply();
  295. glActiveTexture(GL_TEXTURE0);
  296. glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0,
  297. texture.gl_format, texture.gl_type, nullptr);
  298. state.texture_units[0].texture_2d = 0;
  299. state.Apply();
  300. }
  301. /**
  302. * Draws a single texture to the emulator window, rotating the texture to correct for the 3DS's LCD
  303. * rotation.
  304. */
  305. void RendererOpenGL::DrawSingleScreenRotated(const ScreenInfo& screen_info, float x, float y,
  306. float w, float h) {
  307. auto& texcoords = screen_info.display_texcoords;
  308. std::array<ScreenRectVertex, 4> vertices = {{
  309. ScreenRectVertex(x, y, texcoords.bottom, texcoords.left),
  310. ScreenRectVertex(x + w, y, texcoords.bottom, texcoords.right),
  311. ScreenRectVertex(x, y + h, texcoords.top, texcoords.left),
  312. ScreenRectVertex(x + w, y + h, texcoords.top, texcoords.right),
  313. }};
  314. state.texture_units[0].texture_2d = screen_info.display_texture;
  315. state.Apply();
  316. glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices.data());
  317. glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
  318. state.texture_units[0].texture_2d = 0;
  319. state.Apply();
  320. }
  321. /**
  322. * Draws the emulated screens to the emulator window.
  323. */
  324. void RendererOpenGL::DrawScreens() {
  325. auto layout = render_window->GetFramebufferLayout();
  326. const auto& top_screen = layout.top_screen;
  327. const auto& bottom_screen = layout.bottom_screen;
  328. glViewport(0, 0, layout.width, layout.height);
  329. glClear(GL_COLOR_BUFFER_BIT);
  330. // Set projection matrix
  331. std::array<GLfloat, 3 * 2> ortho_matrix =
  332. MakeOrthographicMatrix((float)layout.width, (float)layout.height);
  333. glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data());
  334. // Bind texture in Texture Unit 0
  335. glActiveTexture(GL_TEXTURE0);
  336. glUniform1i(uniform_color_texture, 0);
  337. if (layout.top_screen_enabled) {
  338. DrawSingleScreenRotated(screen_infos[0], (float)top_screen.left, (float)top_screen.top,
  339. (float)top_screen.GetWidth(), (float)top_screen.GetHeight());
  340. }
  341. if (layout.bottom_screen_enabled) {
  342. DrawSingleScreenRotated(screen_infos[1], (float)bottom_screen.left,
  343. (float)bottom_screen.top, (float)bottom_screen.GetWidth(),
  344. (float)bottom_screen.GetHeight());
  345. }
  346. m_current_frame++;
  347. }
  348. /// Updates the framerate
  349. void RendererOpenGL::UpdateFramerate() {}
  350. /**
  351. * Set the emulator window to use for renderer
  352. * @param window EmuWindow handle to emulator window to use for rendering
  353. */
  354. void RendererOpenGL::SetWindow(EmuWindow* window) {
  355. render_window = window;
  356. }
  357. static const char* GetSource(GLenum source) {
  358. #define RET(s) \
  359. case GL_DEBUG_SOURCE_##s: \
  360. return #s
  361. switch (source) {
  362. RET(API);
  363. RET(WINDOW_SYSTEM);
  364. RET(SHADER_COMPILER);
  365. RET(THIRD_PARTY);
  366. RET(APPLICATION);
  367. RET(OTHER);
  368. default:
  369. UNREACHABLE();
  370. }
  371. #undef RET
  372. }
  373. static const char* GetType(GLenum type) {
  374. #define RET(t) \
  375. case GL_DEBUG_TYPE_##t: \
  376. return #t
  377. switch (type) {
  378. RET(ERROR);
  379. RET(DEPRECATED_BEHAVIOR);
  380. RET(UNDEFINED_BEHAVIOR);
  381. RET(PORTABILITY);
  382. RET(PERFORMANCE);
  383. RET(OTHER);
  384. RET(MARKER);
  385. default:
  386. UNREACHABLE();
  387. }
  388. #undef RET
  389. }
  390. static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum severity,
  391. GLsizei length, const GLchar* message, const void* user_param) {
  392. Log::Level level;
  393. switch (severity) {
  394. case GL_DEBUG_SEVERITY_HIGH:
  395. level = Log::Level::Error;
  396. break;
  397. case GL_DEBUG_SEVERITY_MEDIUM:
  398. level = Log::Level::Warning;
  399. break;
  400. case GL_DEBUG_SEVERITY_NOTIFICATION:
  401. case GL_DEBUG_SEVERITY_LOW:
  402. level = Log::Level::Debug;
  403. break;
  404. }
  405. LOG_GENERIC(Log::Class::Render_OpenGL, level, "%s %s %d: %s", GetSource(source), GetType(type),
  406. id, message);
  407. }
  408. /// Initialize the renderer
  409. bool RendererOpenGL::Init() {
  410. render_window->MakeCurrent();
  411. if (GLAD_GL_KHR_debug) {
  412. glEnable(GL_DEBUG_OUTPUT);
  413. glDebugMessageCallback(DebugHandler, nullptr);
  414. }
  415. LOG_INFO(Render_OpenGL, "GL_VERSION: %s", glGetString(GL_VERSION));
  416. LOG_INFO(Render_OpenGL, "GL_VENDOR: %s", glGetString(GL_VENDOR));
  417. LOG_INFO(Render_OpenGL, "GL_RENDERER: %s", glGetString(GL_RENDERER));
  418. if (!GLAD_GL_VERSION_3_3) {
  419. return false;
  420. }
  421. InitOpenGLObjects();
  422. RefreshRasterizerSetting();
  423. return true;
  424. }
  425. /// Shutdown the renderer
  426. void RendererOpenGL::ShutDown() {}