From 63e46abdb8764bc97e91bae862c8d461e61b1965 Mon Sep 17 00:00:00 2001 From: bunnei Date: Tue, 8 Apr 2014 19:25:03 -0400 Subject: got rid of 'src' folders in each sub-project --- src/video_core/renderer_base.h | 58 +++++ src/video_core/renderer_opengl/renderer_opengl.cpp | 279 +++++++++++++++++++++ src/video_core/renderer_opengl/renderer_opengl.h | 91 +++++++ src/video_core/src/renderer_base.h | 58 ----- .../src/renderer_opengl/renderer_opengl.cpp | 279 --------------------- .../src/renderer_opengl/renderer_opengl.h | 91 ------- src/video_core/src/utils.cpp | 46 ---- src/video_core/src/utils.h | 64 ----- src/video_core/src/video_core.cpp | 49 ---- src/video_core/src/video_core.h | 39 --- src/video_core/utils.cpp | 46 ++++ src/video_core/utils.h | 64 +++++ src/video_core/video_core.cpp | 49 ++++ src/video_core/video_core.h | 39 +++ 14 files changed, 626 insertions(+), 626 deletions(-) create mode 100644 src/video_core/renderer_base.h create mode 100644 src/video_core/renderer_opengl/renderer_opengl.cpp create mode 100644 src/video_core/renderer_opengl/renderer_opengl.h delete mode 100644 src/video_core/src/renderer_base.h delete mode 100644 src/video_core/src/renderer_opengl/renderer_opengl.cpp delete mode 100644 src/video_core/src/renderer_opengl/renderer_opengl.h delete mode 100644 src/video_core/src/utils.cpp delete mode 100644 src/video_core/src/utils.h delete mode 100644 src/video_core/src/video_core.cpp delete mode 100644 src/video_core/src/video_core.h create mode 100644 src/video_core/utils.cpp create mode 100644 src/video_core/utils.h create mode 100644 src/video_core/video_core.cpp create mode 100644 src/video_core/video_core.h (limited to 'src/video_core') diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h new file mode 100644 index 000000000..94748d690 --- /dev/null +++ b/src/video_core/renderer_base.h @@ -0,0 +1,58 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common.h" +#include "hash.h" + +class RendererBase { +public: + + /// Used to reference a framebuffer + enum kFramebuffer { + kFramebuffer_VirtualXFB = 0, + kFramebuffer_EFB, + kFramebuffer_Texture + }; + + RendererBase() : m_current_fps(0), m_current_frame(0) { + } + + ~RendererBase() { + } + + /// Swap buffers (render frame) + virtual void SwapBuffers() = 0; + + /** + * Set the emulator window to use for renderer + * @param window EmuWindow handle to emulator window to use for rendering + */ + virtual void SetWindow(EmuWindow* window) = 0; + + /// Initialize the renderer + virtual void Init() = 0; + + /// Shutdown the renderer + virtual void ShutDown() = 0; + + // Getter/setter functions: + // ------------------------ + + f32 GetCurrentframe() const { + return m_current_fps; + } + + int current_frame() const { + return m_current_frame; + } + +protected: + f32 m_current_fps; ///< Current framerate, should be set by the renderer + int m_current_frame; ///< Current frame, should be set by the renderer + +private: + DISALLOW_COPY_AND_ASSIGN(RendererBase); +}; diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp new file mode 100644 index 000000000..6010bcbc3 --- /dev/null +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp @@ -0,0 +1,279 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "mem_map.h" +#include "video_core.h" +#include "renderer_opengl/renderer_opengl.h" + + +/// 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; + + m_xfb_texture_top = 0; + m_xfb_texture_bottom = 0; + + m_xfb_top = 0; + m_xfb_bottom = 0; +} + +/// RendererOpenGL destructor +RendererOpenGL::~RendererOpenGL() { +} + +/// Swap buffers (render frame) +void RendererOpenGL::SwapBuffers() { + // 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. + Rect framebuffer_size(0, 0, m_resolution_width, m_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]); +} + +/** + * Helper function to flip framebuffer from left-to-right to top-to-bottom + * @param addr Address of framebuffer in RAM + * @param out Pointer to output buffer with flipped framebuffer + * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei + */ +void RendererOpenGL::FlipFramebuffer(u32 addr, u8* out) { + u8* in = Memory::GetPointer(addr); + for (int y = 0; y < VideoCore::kScreenTopHeight; y++) { + for (int x = 0; x < VideoCore::kScreenTopWidth; x++) { + int in_coord = (VideoCore::kScreenTopHeight * 3 * x) + (VideoCore::kScreenTopHeight * 3) + - (3 * y + 3); + int out_coord = (VideoCore::kScreenTopWidth * y * 3) + (x * 3); + + out[out_coord + 0] = in[in_coord + 0]; + out[out_coord + 1] = in[in_coord + 1]; + out[out_coord + 2] = in[in_coord + 2]; + } + } +} + +/** + * Renders external framebuffer (XFB) + * @param src_rect Source rectangle in XFB to copy + * @param dst_rect Destination rectangle in output framebuffer to copy to + */ +void RendererOpenGL::RenderXFB(const Rect& src_rect, const Rect& dst_rect) { + + FlipFramebuffer(0x20282160, m_xfb_top_flipped); + FlipFramebuffer(0x202118E0, m_xfb_bottom_flipped); + + // Blit the top framebuffer + // ------------------------ + + // 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_RGB, 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); + + // Render source is our EFB + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_xfb_top); + glReadBuffer(GL_COLOR_ATTACHMENT0); + + // 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); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + + // Blit the bottom framebuffer + // --------------------------- + + // 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_RGB, GL_UNSIGNED_BYTE, m_xfb_bottom_flipped); + glBindTexture(GL_TEXTURE_2D, 0); + + // Render target is destination framebuffer + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]); + glViewport(0, 0, + VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight); + + // Render source is our EFB + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_xfb_bottom); + glReadBuffer(GL_COLOR_ATTACHMENT0); + + // 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); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, 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) + + // Initialize framebuffer textures + // ------------------------------- + + // Create XFB textures + glGenTextures(1, &m_xfb_texture_top); + glGenTextures(1, &m_xfb_texture_bottom); + + // 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); + + 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); + + // 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); +} + +/// 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); + + // Render source is our XFB + glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]); + glReadBuffer(GL_COLOR_ATTACHMENT0); + + // Blit + glBlitFramebuffer(0, 0, m_resolution_width, m_resolution_height, 0, 0, m_resolution_width, + m_resolution_height, GL_COLOR_BUFFER_BIT, GL_LINEAR); + + // Update the FPS count + UpdateFramerate(); + + // Rebind EFB + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_EFB]); + + m_current_frame++; +} + +/// Updates the framerate +void RendererOpenGL::UpdateFramerate() { +} + +/** + * Set the emulator window to use for renderer + * @param window EmuWindow handle to emulator window to use for rendering + */ +void RendererOpenGL::SetWindow(EmuWindow* window) { + m_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); + + GLenum err = glewInit(); + if (GLEW_OK != err) { + ERROR_LOG(RENDER, "Failed to initialize GLEW! Error message: \"%s\". Exiting...", + glewGetErrorString(err)); + exit(-1); + } + + // Initialize everything else + // -------------------------- + + InitFramebuffer(); + + NOTICE_LOG(RENDER, "GL_VERSION: %s\n", glGetString(GL_VERSION)); +} + +/// Shutdown the renderer +void RendererOpenGL::ShutDown() { +} diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h new file mode 100644 index 000000000..86dc7b70e --- /dev/null +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -0,0 +1,91 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common.h" +#include "emu_window.h" + +#include "renderer_base.h" + + +class RendererOpenGL : virtual public RendererBase { +public: + + static const int kMaxFramebuffers = 2; ///< Maximum number of framebuffers + + RendererOpenGL(); + ~RendererOpenGL(); + + /// Swap buffers (render frame) + void SwapBuffers(); + + /** + * Renders external framebuffer (XFB) + * @param src_rect Source rectangle in XFB to copy + * @param dst_rect Destination rectangle in output framebuffer to copy to + */ + void RenderXFB(const Rect& src_rect, const Rect& dst_rect); + + /** + * Set the emulator window to use for renderer + * @param window EmuWindow handle to emulator window to use for rendering + */ + void SetWindow(EmuWindow* window); + + /// Initialize the renderer + void Init(); + + /// Shutdown the renderer + void ShutDown(); + +private: + + /// Initialize the FBO + void InitFramebuffer(); + + // Blit the FBO to the OpenGL default framebuffer + void RenderFramebuffer(); + + /// Updates the framerate + void UpdateFramerate(); + + /** + * Helper function to flip framebuffer from left-to-right to top-to-bottom + * @param addr Address of framebuffer in RAM + * @param out Pointer to output buffer with flipped framebuffer + * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei + */ + void RendererOpenGL::FlipFramebuffer(u32 addr, u8* out); + + + EmuWindow* m_render_window; ///< Handle to render window + u32 m_last_mode; ///< Last render mode + + int m_resolution_width; ///< Current resolution width + int m_resolution_height; ///< Current resolution height + + // Framebuffers + // ------------ + + GLuint m_fbo[kMaxFramebuffers]; ///< Framebuffer objects + GLuint m_fbo_rbo[kMaxFramebuffers]; ///< Render buffer objects + GLuint m_fbo_depth_buffers[kMaxFramebuffers]; ///< Depth buffers objects + + GLuint m_xfb_texture_top; ///< GL handle to top framebuffer texture + GLuint m_xfb_texture_bottom; ///< GL handle to bottom framebuffer texture + + GLuint m_xfb_top; ///< GL handle to top framebuffer + GLuint m_xfb_bottom; ///< GL handle to bottom framebuffer + + // "Flipped" framebuffers translate scanlines from native 3DS left-to-right to top-to-bottom + // as OpenGL expects them in a texture. There probably is a more efficient way of doing this: + + u8 m_xfb_top_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopWidth * 4]; + u8 m_xfb_bottom_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopWidth * 4]; + + DISALLOW_COPY_AND_ASSIGN(RendererOpenGL); +}; \ No newline at end of file diff --git a/src/video_core/src/renderer_base.h b/src/video_core/src/renderer_base.h deleted file mode 100644 index 94748d690..000000000 --- a/src/video_core/src/renderer_base.h +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "common.h" -#include "hash.h" - -class RendererBase { -public: - - /// Used to reference a framebuffer - enum kFramebuffer { - kFramebuffer_VirtualXFB = 0, - kFramebuffer_EFB, - kFramebuffer_Texture - }; - - RendererBase() : m_current_fps(0), m_current_frame(0) { - } - - ~RendererBase() { - } - - /// Swap buffers (render frame) - virtual void SwapBuffers() = 0; - - /** - * Set the emulator window to use for renderer - * @param window EmuWindow handle to emulator window to use for rendering - */ - virtual void SetWindow(EmuWindow* window) = 0; - - /// Initialize the renderer - virtual void Init() = 0; - - /// Shutdown the renderer - virtual void ShutDown() = 0; - - // Getter/setter functions: - // ------------------------ - - f32 GetCurrentframe() const { - return m_current_fps; - } - - int current_frame() const { - return m_current_frame; - } - -protected: - f32 m_current_fps; ///< Current framerate, should be set by the renderer - int m_current_frame; ///< Current frame, should be set by the renderer - -private: - DISALLOW_COPY_AND_ASSIGN(RendererBase); -}; diff --git a/src/video_core/src/renderer_opengl/renderer_opengl.cpp b/src/video_core/src/renderer_opengl/renderer_opengl.cpp deleted file mode 100644 index 6010bcbc3..000000000 --- a/src/video_core/src/renderer_opengl/renderer_opengl.cpp +++ /dev/null @@ -1,279 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "mem_map.h" -#include "video_core.h" -#include "renderer_opengl/renderer_opengl.h" - - -/// 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; - - m_xfb_texture_top = 0; - m_xfb_texture_bottom = 0; - - m_xfb_top = 0; - m_xfb_bottom = 0; -} - -/// RendererOpenGL destructor -RendererOpenGL::~RendererOpenGL() { -} - -/// Swap buffers (render frame) -void RendererOpenGL::SwapBuffers() { - // 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. - Rect framebuffer_size(0, 0, m_resolution_width, m_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]); -} - -/** - * Helper function to flip framebuffer from left-to-right to top-to-bottom - * @param addr Address of framebuffer in RAM - * @param out Pointer to output buffer with flipped framebuffer - * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei - */ -void RendererOpenGL::FlipFramebuffer(u32 addr, u8* out) { - u8* in = Memory::GetPointer(addr); - for (int y = 0; y < VideoCore::kScreenTopHeight; y++) { - for (int x = 0; x < VideoCore::kScreenTopWidth; x++) { - int in_coord = (VideoCore::kScreenTopHeight * 3 * x) + (VideoCore::kScreenTopHeight * 3) - - (3 * y + 3); - int out_coord = (VideoCore::kScreenTopWidth * y * 3) + (x * 3); - - out[out_coord + 0] = in[in_coord + 0]; - out[out_coord + 1] = in[in_coord + 1]; - out[out_coord + 2] = in[in_coord + 2]; - } - } -} - -/** - * Renders external framebuffer (XFB) - * @param src_rect Source rectangle in XFB to copy - * @param dst_rect Destination rectangle in output framebuffer to copy to - */ -void RendererOpenGL::RenderXFB(const Rect& src_rect, const Rect& dst_rect) { - - FlipFramebuffer(0x20282160, m_xfb_top_flipped); - FlipFramebuffer(0x202118E0, m_xfb_bottom_flipped); - - // Blit the top framebuffer - // ------------------------ - - // 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_RGB, 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); - - // Render source is our EFB - glBindFramebuffer(GL_READ_FRAMEBUFFER, m_xfb_top); - glReadBuffer(GL_COLOR_ATTACHMENT0); - - // 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); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - - // Blit the bottom framebuffer - // --------------------------- - - // 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_RGB, GL_UNSIGNED_BYTE, m_xfb_bottom_flipped); - glBindTexture(GL_TEXTURE_2D, 0); - - // Render target is destination framebuffer - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]); - glViewport(0, 0, - VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight); - - // Render source is our EFB - glBindFramebuffer(GL_READ_FRAMEBUFFER, m_xfb_bottom); - glReadBuffer(GL_COLOR_ATTACHMENT0); - - // 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); - - glBindFramebuffer(GL_READ_FRAMEBUFFER, 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) - - // Initialize framebuffer textures - // ------------------------------- - - // Create XFB textures - glGenTextures(1, &m_xfb_texture_top); - glGenTextures(1, &m_xfb_texture_bottom); - - // 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); - - 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); - - // 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); -} - -/// 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); - - // Render source is our XFB - glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]); - glReadBuffer(GL_COLOR_ATTACHMENT0); - - // Blit - glBlitFramebuffer(0, 0, m_resolution_width, m_resolution_height, 0, 0, m_resolution_width, - m_resolution_height, GL_COLOR_BUFFER_BIT, GL_LINEAR); - - // Update the FPS count - UpdateFramerate(); - - // Rebind EFB - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_EFB]); - - m_current_frame++; -} - -/// Updates the framerate -void RendererOpenGL::UpdateFramerate() { -} - -/** - * Set the emulator window to use for renderer - * @param window EmuWindow handle to emulator window to use for rendering - */ -void RendererOpenGL::SetWindow(EmuWindow* window) { - m_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); - - GLenum err = glewInit(); - if (GLEW_OK != err) { - ERROR_LOG(RENDER, "Failed to initialize GLEW! Error message: \"%s\". Exiting...", - glewGetErrorString(err)); - exit(-1); - } - - // Initialize everything else - // -------------------------- - - InitFramebuffer(); - - NOTICE_LOG(RENDER, "GL_VERSION: %s\n", glGetString(GL_VERSION)); -} - -/// Shutdown the renderer -void RendererOpenGL::ShutDown() { -} diff --git a/src/video_core/src/renderer_opengl/renderer_opengl.h b/src/video_core/src/renderer_opengl/renderer_opengl.h deleted file mode 100644 index 86dc7b70e..000000000 --- a/src/video_core/src/renderer_opengl/renderer_opengl.h +++ /dev/null @@ -1,91 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include - -#include "common.h" -#include "emu_window.h" - -#include "renderer_base.h" - - -class RendererOpenGL : virtual public RendererBase { -public: - - static const int kMaxFramebuffers = 2; ///< Maximum number of framebuffers - - RendererOpenGL(); - ~RendererOpenGL(); - - /// Swap buffers (render frame) - void SwapBuffers(); - - /** - * Renders external framebuffer (XFB) - * @param src_rect Source rectangle in XFB to copy - * @param dst_rect Destination rectangle in output framebuffer to copy to - */ - void RenderXFB(const Rect& src_rect, const Rect& dst_rect); - - /** - * Set the emulator window to use for renderer - * @param window EmuWindow handle to emulator window to use for rendering - */ - void SetWindow(EmuWindow* window); - - /// Initialize the renderer - void Init(); - - /// Shutdown the renderer - void ShutDown(); - -private: - - /// Initialize the FBO - void InitFramebuffer(); - - // Blit the FBO to the OpenGL default framebuffer - void RenderFramebuffer(); - - /// Updates the framerate - void UpdateFramerate(); - - /** - * Helper function to flip framebuffer from left-to-right to top-to-bottom - * @param addr Address of framebuffer in RAM - * @param out Pointer to output buffer with flipped framebuffer - * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei - */ - void RendererOpenGL::FlipFramebuffer(u32 addr, u8* out); - - - EmuWindow* m_render_window; ///< Handle to render window - u32 m_last_mode; ///< Last render mode - - int m_resolution_width; ///< Current resolution width - int m_resolution_height; ///< Current resolution height - - // Framebuffers - // ------------ - - GLuint m_fbo[kMaxFramebuffers]; ///< Framebuffer objects - GLuint m_fbo_rbo[kMaxFramebuffers]; ///< Render buffer objects - GLuint m_fbo_depth_buffers[kMaxFramebuffers]; ///< Depth buffers objects - - GLuint m_xfb_texture_top; ///< GL handle to top framebuffer texture - GLuint m_xfb_texture_bottom; ///< GL handle to bottom framebuffer texture - - GLuint m_xfb_top; ///< GL handle to top framebuffer - GLuint m_xfb_bottom; ///< GL handle to bottom framebuffer - - // "Flipped" framebuffers translate scanlines from native 3DS left-to-right to top-to-bottom - // as OpenGL expects them in a texture. There probably is a more efficient way of doing this: - - u8 m_xfb_top_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopWidth * 4]; - u8 m_xfb_bottom_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopWidth * 4]; - - DISALLOW_COPY_AND_ASSIGN(RendererOpenGL); -}; \ No newline at end of file diff --git a/src/video_core/src/utils.cpp b/src/video_core/src/utils.cpp deleted file mode 100644 index a6dd1e02c..000000000 --- a/src/video_core/src/utils.cpp +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include -#include - -#include "utils.h" - -namespace VideoCore { - -/** - * Dumps a texture to TGA - * @param filename String filename to dump texture to - * @param width Width of texture in pixels - * @param height Height of texture in pixels - * @param raw_data Raw RGBA8 texture data to dump - * @todo This should be moved to some general purpose/common code - */ -void DumpTGA(std::string filename, int width, int height, u8* raw_data) { - TGAHeader hdr; - FILE* fout; - u8 r, g, b; - - memset(&hdr, 0, sizeof(hdr)); - hdr.datatypecode = 2; // uncompressed RGB - hdr.bitsperpixel = 24; // 24 bpp - hdr.width = width; - hdr.height = height; - - fout = fopen(filename.c_str(), "wb"); - fwrite(&hdr, sizeof(TGAHeader), 1, fout); - for (int i = 0; i < height; i++) { - for (int j = 0; j < width; j++) { - r = raw_data[(4 * (i * width)) + (4 * j) + 0]; - g = raw_data[(4 * (i * width)) + (4 * j) + 1]; - b = raw_data[(4 * (i * width)) + (4 * j) + 2]; - putc(b, fout); - putc(g, fout); - putc(r, fout); - } - } - fclose(fout); -} - -} // namespace diff --git a/src/video_core/src/utils.h b/src/video_core/src/utils.h deleted file mode 100644 index c417342e1..000000000 --- a/src/video_core/src/utils.h +++ /dev/null @@ -1,64 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include - -#include "common_types.h" - -namespace FormatPrecision { - -/// Adjust RGBA8 color with RGBA6 precision -static inline u32 rgba8_with_rgba6(u32 src) { - u32 color = src; - color &= 0xFCFCFCFC; - color |= (color >> 6) & 0x03030303; - return color; -} - -/// Adjust RGBA8 color with RGB565 precision -static inline u32 rgba8_with_rgb565(u32 src) { - u32 color = (src & 0xF8FCF8); - color |= (color >> 5) & 0x070007; - color |= (color >> 6) & 0x000300; - color |= 0xFF000000; - return color; -} - -/// Adjust Z24 depth value with Z16 precision -static inline u32 z24_with_z16(u32 src) { - return (src & 0xFFFF00) | (src >> 16); -} - -} // namespace - -namespace VideoCore { - -/// Structure for the TGA texture format (for dumping) -struct TGAHeader { - char idlength; - char colourmaptype; - char datatypecode; - short int colourmaporigin; - short int colourmaplength; - short int x_origin; - short int y_origin; - short width; - short height; - char bitsperpixel; - char imagedescriptor; -}; - -/** - * Dumps a texture to TGA - * @param filename String filename to dump texture to - * @param width Width of texture in pixels - * @param height Height of texture in pixels - * @param raw_data Raw RGBA8 texture data to dump - * @todo This should be moved to some general purpose/common code - */ -void DumpTGA(std::string filename, int width, int height, u8* raw_data); - -} // namespace diff --git a/src/video_core/src/video_core.cpp b/src/video_core/src/video_core.cpp deleted file mode 100644 index 6c0c415f5..000000000 --- a/src/video_core/src/video_core.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#include "common.h" -#include "emu_window.h" -#include "log.h" - -#include "core.h" - -#include "video_core.h" -#include "renderer_base.h" -#include "renderer_opengl/renderer_opengl.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Video Core namespace - -namespace VideoCore { - -EmuWindow* g_emu_window = NULL; ///< Frontend emulator window -RendererBase* g_renderer = NULL; ///< Renderer plugin -int g_current_frame = 0; - -/// Start the video core -void Start() { - if (g_emu_window == NULL) { - ERROR_LOG(VIDEO, "VideoCore::Start called without calling Init()!"); - } -} - -/// Initialize the video core -void Init(EmuWindow* emu_window) { - g_emu_window = emu_window; - g_emu_window->MakeCurrent(); - g_renderer = new RendererOpenGL(); - g_renderer->SetWindow(g_emu_window); - g_renderer->Init(); - - g_current_frame = 0; - - NOTICE_LOG(VIDEO, "initialized ok"); -} - -/// Shutdown the video core -void Shutdown() { - delete g_renderer; -} - -} // namespace diff --git a/src/video_core/src/video_core.h b/src/video_core/src/video_core.h deleted file mode 100644 index 19bf49dd7..000000000 --- a/src/video_core/src/video_core.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 -// Refer to the license.txt file included. - -#pragma once - -#include "common.h" -#include "emu_window.h" -#include "renderer_base.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Video Core namespace - -namespace VideoCore { - -// 3DS Video Constants -// ------------------- - -static const int kScreenTopWidth = 400; ///< 3DS top screen width -static const int kScreenTopHeight = 240; ///< 3DS top screen height -static const int kScreenBottomWidth = 320; ///< 3DS bottom screen width -static const int kScreenBottomHeight = 240; ///< 3DS bottom screen height - -// Video core renderer -// --------------------- - -extern RendererBase* g_renderer; ///< Renderer plugin -extern int g_current_frame; ///< Current frame - -/// Start the video core -void Start(); - -/// Initialize the video core -void Init(EmuWindow* emu_window); - -/// Shutdown the video core -void Shutdown(); - -} // namespace diff --git a/src/video_core/utils.cpp b/src/video_core/utils.cpp new file mode 100644 index 000000000..a6dd1e02c --- /dev/null +++ b/src/video_core/utils.cpp @@ -0,0 +1,46 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include +#include + +#include "utils.h" + +namespace VideoCore { + +/** + * Dumps a texture to TGA + * @param filename String filename to dump texture to + * @param width Width of texture in pixels + * @param height Height of texture in pixels + * @param raw_data Raw RGBA8 texture data to dump + * @todo This should be moved to some general purpose/common code + */ +void DumpTGA(std::string filename, int width, int height, u8* raw_data) { + TGAHeader hdr; + FILE* fout; + u8 r, g, b; + + memset(&hdr, 0, sizeof(hdr)); + hdr.datatypecode = 2; // uncompressed RGB + hdr.bitsperpixel = 24; // 24 bpp + hdr.width = width; + hdr.height = height; + + fout = fopen(filename.c_str(), "wb"); + fwrite(&hdr, sizeof(TGAHeader), 1, fout); + for (int i = 0; i < height; i++) { + for (int j = 0; j < width; j++) { + r = raw_data[(4 * (i * width)) + (4 * j) + 0]; + g = raw_data[(4 * (i * width)) + (4 * j) + 1]; + b = raw_data[(4 * (i * width)) + (4 * j) + 2]; + putc(b, fout); + putc(g, fout); + putc(r, fout); + } + } + fclose(fout); +} + +} // namespace diff --git a/src/video_core/utils.h b/src/video_core/utils.h new file mode 100644 index 000000000..c417342e1 --- /dev/null +++ b/src/video_core/utils.h @@ -0,0 +1,64 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include + +#include "common_types.h" + +namespace FormatPrecision { + +/// Adjust RGBA8 color with RGBA6 precision +static inline u32 rgba8_with_rgba6(u32 src) { + u32 color = src; + color &= 0xFCFCFCFC; + color |= (color >> 6) & 0x03030303; + return color; +} + +/// Adjust RGBA8 color with RGB565 precision +static inline u32 rgba8_with_rgb565(u32 src) { + u32 color = (src & 0xF8FCF8); + color |= (color >> 5) & 0x070007; + color |= (color >> 6) & 0x000300; + color |= 0xFF000000; + return color; +} + +/// Adjust Z24 depth value with Z16 precision +static inline u32 z24_with_z16(u32 src) { + return (src & 0xFFFF00) | (src >> 16); +} + +} // namespace + +namespace VideoCore { + +/// Structure for the TGA texture format (for dumping) +struct TGAHeader { + char idlength; + char colourmaptype; + char datatypecode; + short int colourmaporigin; + short int colourmaplength; + short int x_origin; + short int y_origin; + short width; + short height; + char bitsperpixel; + char imagedescriptor; +}; + +/** + * Dumps a texture to TGA + * @param filename String filename to dump texture to + * @param width Width of texture in pixels + * @param height Height of texture in pixels + * @param raw_data Raw RGBA8 texture data to dump + * @todo This should be moved to some general purpose/common code + */ +void DumpTGA(std::string filename, int width, int height, u8* raw_data); + +} // namespace diff --git a/src/video_core/video_core.cpp b/src/video_core/video_core.cpp new file mode 100644 index 000000000..6c0c415f5 --- /dev/null +++ b/src/video_core/video_core.cpp @@ -0,0 +1,49 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "common.h" +#include "emu_window.h" +#include "log.h" + +#include "core.h" + +#include "video_core.h" +#include "renderer_base.h" +#include "renderer_opengl/renderer_opengl.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Video Core namespace + +namespace VideoCore { + +EmuWindow* g_emu_window = NULL; ///< Frontend emulator window +RendererBase* g_renderer = NULL; ///< Renderer plugin +int g_current_frame = 0; + +/// Start the video core +void Start() { + if (g_emu_window == NULL) { + ERROR_LOG(VIDEO, "VideoCore::Start called without calling Init()!"); + } +} + +/// Initialize the video core +void Init(EmuWindow* emu_window) { + g_emu_window = emu_window; + g_emu_window->MakeCurrent(); + g_renderer = new RendererOpenGL(); + g_renderer->SetWindow(g_emu_window); + g_renderer->Init(); + + g_current_frame = 0; + + NOTICE_LOG(VIDEO, "initialized ok"); +} + +/// Shutdown the video core +void Shutdown() { + delete g_renderer; +} + +} // namespace diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h new file mode 100644 index 000000000..19bf49dd7 --- /dev/null +++ b/src/video_core/video_core.h @@ -0,0 +1,39 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include "common.h" +#include "emu_window.h" +#include "renderer_base.h" + +//////////////////////////////////////////////////////////////////////////////////////////////////// +// Video Core namespace + +namespace VideoCore { + +// 3DS Video Constants +// ------------------- + +static const int kScreenTopWidth = 400; ///< 3DS top screen width +static const int kScreenTopHeight = 240; ///< 3DS top screen height +static const int kScreenBottomWidth = 320; ///< 3DS bottom screen width +static const int kScreenBottomHeight = 240; ///< 3DS bottom screen height + +// Video core renderer +// --------------------- + +extern RendererBase* g_renderer; ///< Renderer plugin +extern int g_current_frame; ///< Current frame + +/// Start the video core +void Start(); + +/// Initialize the video core +void Init(EmuWindow* emu_window); + +/// Shutdown the video core +void Shutdown(); + +} // namespace -- cgit v1.2.3