diff options
author | Kevin Hartman <kevin@hart.mn> | 2014-08-21 09:27:53 +0200 |
---|---|---|
committer | Kevin Hartman <kevin@hart.mn> | 2014-08-26 05:56:59 +0200 |
commit | cbfd6b6e52e3b8c1d6324d86461f4e8aa240a756 (patch) | |
tree | 31355774610d25174521e88ca7dcebfe5bbfe715 /src/video_core/renderer_opengl/renderer_opengl.cpp | |
parent | Update README.md to correct OS X typo (diff) | |
download | yuzu-cbfd6b6e52e3b8c1d6324d86461f4e8aa240a756.tar yuzu-cbfd6b6e52e3b8c1d6324d86461f4e8aa240a756.tar.gz yuzu-cbfd6b6e52e3b8c1d6324d86461f4e8aa240a756.tar.bz2 yuzu-cbfd6b6e52e3b8c1d6324d86461f4e8aa240a756.tar.lz yuzu-cbfd6b6e52e3b8c1d6324d86461f4e8aa240a756.tar.xz yuzu-cbfd6b6e52e3b8c1d6324d86461f4e8aa240a756.tar.zst yuzu-cbfd6b6e52e3b8c1d6324d86461f4e8aa240a756.zip |
Diffstat (limited to 'src/video_core/renderer_opengl/renderer_opengl.cpp')
-rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 322 |
1 files changed, 146 insertions, 176 deletions
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index f11a64fad..dc1b8e28b 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -6,24 +6,56 @@ #include "video_core/video_core.h" #include "video_core/renderer_opengl/renderer_opengl.h" +#include "video_core/renderer_opengl/gl_shader_util.h" +#include "video_core/renderer_opengl/gl_shaders.h" #include "core/mem_map.h" +#include <algorithm> + +static const GLfloat kViewportAspectRatio = + (static_cast<float>(VideoCore::kScreenTopHeight) + VideoCore::kScreenBottomHeight) / VideoCore::kScreenTopWidth; + +// Fullscreen quad dimensions +static const GLfloat kTopScreenWidthNormalized = 2; +static const GLfloat kTopScreenHeightNormalized = kTopScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenTopHeight) / VideoCore::kScreenTopWidth); +static const GLfloat kBottomScreenWidthNormalized = kTopScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenBottomWidth) / VideoCore::kScreenTopWidth); +static const GLfloat kBottomScreenHeightNormalized = kBottomScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenBottomHeight) / VideoCore::kScreenBottomWidth); + +static const GLfloat g_vbuffer_top[] = { + // x, y, z u, v + -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, + 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, + 1.0f, kTopScreenHeightNormalized, 0.0f, 1.0f, 0.0f, + 1.0f, kTopScreenHeightNormalized, 0.0f, 1.0f, 0.0f, + -1.0f, kTopScreenHeightNormalized, 0.0f, 0.0f, 0.0f, + -1.0f, 0.0f, 0.0f, 0.0f, 1.0f +}; + +static const GLfloat g_vbuffer_bottom[] = { + // x, y, z u, v + -(kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 0.0f, 1.0f, + (kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 1.0f, 1.0f, + (kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 1.0f, 0.0f, + (kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 1.0f, 0.0f, + -(kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 0.0f, 0.0f, + -(kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 0.0f, 1.0f +}; /// RendererOpenGL constructor RendererOpenGL::RendererOpenGL() { - memset(m_fbo, 0, sizeof(m_fbo)); - memset(m_fbo_rbo, 0, sizeof(m_fbo_rbo)); - memset(m_fbo_depth_buffers, 0, sizeof(m_fbo_depth_buffers)); - m_resolution_width = max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); - m_resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; + resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); + resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; - m_xfb_texture_top = 0; - m_xfb_texture_bottom = 0; + // Initialize screen info + screen_info.Top().width = VideoCore::kScreenTopWidth; + screen_info.Top().height = VideoCore::kScreenTopHeight; + screen_info.Top().flipped_xfb_data = xfb_top_flipped; - m_xfb_top = 0; - m_xfb_bottom = 0; + screen_info.Bottom().width = VideoCore::kScreenBottomWidth; + screen_info.Bottom().height = VideoCore::kScreenBottomHeight; + screen_info.Bottom().flipped_xfb_data = xfb_bottom_flipped; } /// RendererOpenGL destructor @@ -32,41 +64,41 @@ RendererOpenGL::~RendererOpenGL() { /// Swap buffers (render frame) void RendererOpenGL::SwapBuffers() { - m_render_window->MakeCurrent(); + render_window->MakeCurrent(); // EFB->XFB copy // TODO(bunnei): This is a hack and does not belong here. The copy should be triggered by some - // register write We're also treating both framebuffers as a single one in OpenGL. - common::Rect framebuffer_size(0, 0, m_resolution_width, m_resolution_height); + // register write. + // + // TODO(princesspeachum): (related to above^) this should only be called when there's new data, not every frame. + // Currently this uploads data that shouldn't have changed. + common::Rect framebuffer_size(0, 0, resolution_width, resolution_height); RenderXFB(framebuffer_size, framebuffer_size); // XFB->Window copy RenderFramebuffer(); // Swap buffers - m_render_window->PollEvents(); - m_render_window->SwapBuffers(); - - // Switch back to EFB and clear - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_EFB]); + render_window->PollEvents(); + render_window->SwapBuffers(); } /** * Helper function to flip framebuffer from left-to-right to top-to-bottom - * @param in Pointer to input raw framebuffer in V/RAM - * @param out Pointer to output buffer with flipped framebuffer + * @param raw_data Pointer to input raw framebuffer in V/RAM + * @param screen_info ScreenInfo structure with screen size and output buffer pointer * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei */ -void RendererOpenGL::FlipFramebuffer(const u8* in, u8* out) { +void RendererOpenGL::FlipFramebuffer(const u8* raw_data, ScreenInfo& screen_info) { int in_coord = 0; - for (int x = 0; x < VideoCore::kScreenTopWidth; x++) { - for (int y = VideoCore::kScreenTopHeight-1; y >= 0; y--) { + for (int x = 0; x < screen_info.width; x++) { + for (int y = screen_info.height-1; y >= 0; y--) { // TODO: Properly support other framebuffer formats - int out_coord = (x + y * VideoCore::kScreenTopWidth) * 3; - out[out_coord] = in[in_coord]; // blue? - out[out_coord + 1] = in[in_coord + 1]; // green? - out[out_coord + 2] = in[in_coord + 2]; // red? - in_coord+=3; + int out_coord = (x + y * screen_info.width) * 3; + screen_info.flipped_xfb_data[out_coord] = raw_data[in_coord + 2]; // Red + screen_info.flipped_xfb_data[out_coord + 1] = raw_data[in_coord + 1]; // Green + screen_info.flipped_xfb_data[out_coord + 2] = raw_data[in_coord]; // Blue + in_coord += 3; } } } @@ -77,167 +109,116 @@ void RendererOpenGL::FlipFramebuffer(const u8* in, u8* out) { * @param dst_rect Destination rectangle in output framebuffer to copy to */ void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect) { - const auto& framebuffer_top = GPU::g_regs.framebuffer_config[0]; const auto& framebuffer_sub = GPU::g_regs.framebuffer_config[1]; const u32 active_fb_top = (framebuffer_top.active_fb == 1) - ? Memory::PhysicalToVirtualAddress(framebuffer_top.address_left2) - : Memory::PhysicalToVirtualAddress(framebuffer_top.address_left1); + ? Memory::PhysicalToVirtualAddress(framebuffer_top.address_left2) + : Memory::PhysicalToVirtualAddress(framebuffer_top.address_left1); const u32 active_fb_sub = (framebuffer_sub.active_fb == 1) - ? Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left2) - : Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left1); + ? Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left2) + : Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left1); DEBUG_LOG(GPU, "RenderXFB: 0x%08x bytes from 0x%08x(%dx%d), fmt %x", framebuffer_top.stride * framebuffer_top.height, active_fb_top, (int)framebuffer_top.width, (int)framebuffer_top.height, (int)framebuffer_top.format); - // TODO: This should consider the GPU registers for framebuffer width, height and stride. - FlipFramebuffer(Memory::GetPointer(active_fb_top), m_xfb_top_flipped); - FlipFramebuffer(Memory::GetPointer(active_fb_sub), m_xfb_bottom_flipped); + FlipFramebuffer(Memory::GetPointer(active_fb_top), screen_info.Top()); + FlipFramebuffer(Memory::GetPointer(active_fb_sub), screen_info.Bottom()); + + for (int i = 0; i < 2; i++) { + ScreenInfo* current_screen = &screen_info[i]; - // Blit the top framebuffer - // ------------------------ + glBindTexture(GL_TEXTURE_2D, current_screen->texture_id); + + // TODO: This should consider the GPU registers for framebuffer width, height and stride. + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, current_screen->width, current_screen->height, + GL_RGB, GL_UNSIGNED_BYTE, current_screen->flipped_xfb_data); + } - // Update textures with contents of XFB in RAM - top - glBindTexture(GL_TEXTURE_2D, m_xfb_texture_top); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, - GL_BGR, GL_UNSIGNED_BYTE, m_xfb_top_flipped); glBindTexture(GL_TEXTURE_2D, 0); - // Render target is destination framebuffer - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]); - glViewport(0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight); + // TODO(princesspeachum): + // Only the subset src_rect of the GPU buffer + // should be copied into the texture of the relevant screen. + // + // The method's parameters also only include src_rect and dest_rec for one screen, + // so this may need to be changed (pair for each screen). +} - // Render source is our EFB - glBindFramebuffer(GL_READ_FRAMEBUFFER, m_xfb_top); - glReadBuffer(GL_COLOR_ATTACHMENT0); +/// Initialize the FBO +void RendererOpenGL::InitFramebuffer() { + program_id = ShaderUtil::LoadShaders(GLShaders::g_vertex_shader, GLShaders::g_fragment_shader); + sampler_id = glGetUniformLocation(program_id, "sampler"); - // Blit - glBlitFramebuffer(src_rect.x0_, src_rect.y0_, src_rect.x1_, src_rect.y1_, - dst_rect.x0_, dst_rect.y1_, dst_rect.x1_, dst_rect.y0_, - GL_COLOR_BUFFER_BIT, GL_LINEAR); + // Generate vertex buffers for both screens + glGenBuffers(1, &screen_info.Top().vertex_buffer_id); + glGenBuffers(1, &screen_info.Bottom().vertex_buffer_id); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + // Attach vertex data for top screen + glBindBuffer(GL_ARRAY_BUFFER, screen_info.Top().vertex_buffer_id); + glBufferData(GL_ARRAY_BUFFER, sizeof(g_vbuffer_top), g_vbuffer_top, GL_STATIC_DRAW); - // Blit the bottom framebuffer - // --------------------------- + // Attach vertex data for bottom screen + glBindBuffer(GL_ARRAY_BUFFER, screen_info.Bottom().vertex_buffer_id); + glBufferData(GL_ARRAY_BUFFER, sizeof(g_vbuffer_bottom), g_vbuffer_bottom, GL_STATIC_DRAW); - // Update textures with contents of XFB in RAM - bottom - glBindTexture(GL_TEXTURE_2D, m_xfb_texture_bottom); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, - GL_BGR, GL_UNSIGNED_BYTE, m_xfb_bottom_flipped); - glBindTexture(GL_TEXTURE_2D, 0); + // Create color buffers for both screens + glGenTextures(1, &screen_info.Top().texture_id); + glGenTextures(1, &screen_info.Bottom().texture_id); - // Render target is destination framebuffer - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]); - glViewport(0, 0, - VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight); + for (int i = 0; i < 2; i++) { - // Render source is our EFB - glBindFramebuffer(GL_READ_FRAMEBUFFER, m_xfb_bottom); - glReadBuffer(GL_COLOR_ATTACHMENT0); + ScreenInfo* current_screen = &screen_info[i]; - // Blit - int offset = (VideoCore::kScreenTopWidth - VideoCore::kScreenBottomWidth) / 2; - glBlitFramebuffer(0,0, VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight, - offset, VideoCore::kScreenBottomHeight, VideoCore::kScreenBottomWidth + offset, 0, - GL_COLOR_BUFFER_BIT, GL_LINEAR); + // Allocate texture + glBindTexture(GL_TEXTURE_2D, current_screen->vertex_buffer_id); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, current_screen->width, current_screen->height, + 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + + glBindTexture(GL_TEXTURE_2D, 0); } -/// Initialize the FBO -void RendererOpenGL::InitFramebuffer() { - // TODO(bunnei): This should probably be implemented with the top screen and bottom screen as - // separate framebuffers - - // Init the FBOs - // ------------- - - glGenFramebuffers(kMaxFramebuffers, m_fbo); // Generate primary framebuffer - glGenRenderbuffers(kMaxFramebuffers, m_fbo_rbo); // Generate primary RBOs - glGenRenderbuffers(kMaxFramebuffers, m_fbo_depth_buffers); // Generate primary depth buffer - - for (int i = 0; i < kMaxFramebuffers; i++) { - // Generate color buffer storage - glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_rbo[i]); - glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, VideoCore::kScreenTopWidth, - VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); - - // Generate depth buffer storage - glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_depth_buffers[i]); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, VideoCore::kScreenTopWidth, - VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); - - // Attach the buffers - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[i]); - glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, - GL_RENDERBUFFER, m_fbo_depth_buffers[i]); - glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_RENDERBUFFER, m_fbo_rbo[i]); - - // Check for completeness - if (GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER)) { - NOTICE_LOG(RENDER, "framebuffer(%d) initialized ok", i); - } else { - ERROR_LOG(RENDER, "couldn't create OpenGL frame buffer"); - exit(1); - } - } - glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer(s) +void RendererOpenGL::RenderFramebuffer() { + glClear(GL_COLOR_BUFFER_BIT); - // Initialize framebuffer textures - // ------------------------------- + glUseProgram(program_id); - // Create XFB textures - glGenTextures(1, &m_xfb_texture_top); - glGenTextures(1, &m_xfb_texture_bottom); + // Bind texture in Texture Unit 0 + glActiveTexture(GL_TEXTURE0); - // Alocate video memorry for XFB textures - glBindTexture(GL_TEXTURE_2D, m_xfb_texture_top); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, - 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - glBindTexture(GL_TEXTURE_2D, 0); + glEnableVertexAttribArray(0); + glEnableVertexAttribArray(1); - glBindTexture(GL_TEXTURE_2D, m_xfb_texture_bottom); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, - 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - glBindTexture(GL_TEXTURE_2D, 0); + for (int i = 0; i < 2; i++) { - // Create the FBO and attach color/depth textures - glGenFramebuffers(1, &m_xfb_top); // Generate framebuffer - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_top); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - m_xfb_texture_top, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - glGenFramebuffers(1, &m_xfb_bottom); // Generate framebuffer - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_bottom); - glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, - m_xfb_texture_bottom, 0); - glBindFramebuffer(GL_FRAMEBUFFER, 0); -} + ScreenInfo* current_screen = &screen_info[i]; -/// Blit the FBO to the OpenGL default framebuffer -void RendererOpenGL::RenderFramebuffer() { - // Render target is default framebuffer - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - glViewport(0, 0, m_resolution_width, m_resolution_height); + glBindTexture(GL_TEXTURE_2D, current_screen->texture_id); - // Render source is our XFB - glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]); - glReadBuffer(GL_COLOR_ATTACHMENT0); + // Set sampler on Texture Unit 0 + glUniform1i(sampler_id, 0); - // Blit - glBlitFramebuffer(0, 0, m_resolution_width, m_resolution_height, 0, 0, m_resolution_width, - m_resolution_height, GL_COLOR_BUFFER_BIT, GL_LINEAR); + glBindBuffer(GL_ARRAY_BUFFER, current_screen->vertex_buffer_id); - // Update the FPS count - UpdateFramerate(); + // Vertex buffer layout + const GLsizei stride = 5 * sizeof(GLfloat); + const GLvoid* uv_offset = (const GLvoid*)(3 * sizeof(GLfloat)); - // Rebind EFB - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_EFB]); + // Configure vertex buffer + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, NULL); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, uv_offset); + + // Draw screen + glDrawArrays(GL_TRIANGLES, 0, 6); + } + + glDisableVertexAttribArray(0); + glDisableVertexAttribArray(1); m_current_frame++; } @@ -251,40 +232,29 @@ void RendererOpenGL::UpdateFramerate() { * @param window EmuWindow handle to emulator window to use for rendering */ void RendererOpenGL::SetWindow(EmuWindow* window) { - m_render_window = window; + render_window = window; } /// Initialize the renderer void RendererOpenGL::Init() { - m_render_window->MakeCurrent(); - glShadeModel(GL_SMOOTH); - - - glStencilFunc(GL_ALWAYS, 0, 0); - glBlendFunc(GL_ONE, GL_ONE); - - glViewport(0, 0, m_resolution_width, m_resolution_height); - - glClearDepth(1.0f); - glEnable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glDepthFunc(GL_LEQUAL); - - glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - - glDisable(GL_STENCIL_TEST); - glEnable(GL_SCISSOR_TEST); - - glScissor(0, 0, m_resolution_width, m_resolution_height); - glClearDepth(1.0f); + render_window->MakeCurrent(); GLenum err = glewInit(); if (GLEW_OK != err) { ERROR_LOG(RENDER, "Failed to initialize GLEW! Error message: \"%s\". Exiting...", - glewGetErrorString(err)); + glewGetErrorString(err)); exit(-1); } + // Generate VAO + glGenVertexArrays(1, &vertex_array_id); + glBindVertexArray(vertex_array_id); + + glClearColor(1.0f, 1.0f, 1.0f, 0.0f); + glDisable(GL_DEPTH_TEST); + + glPixelStorei(GL_UNPACK_ALIGNMENT, 4); + // Initialize everything else // -------------------------- |