diff options
Diffstat (limited to 'src/video_core')
| -rw-r--r-- | src/video_core/CMakeLists.txt | 11 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_util.cpp | 81 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shader_util.h | 13 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_shaders.h | 39 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 322 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.h | 63 | ||||
| -rw-r--r-- | src/video_core/video_core.vcxproj | 5 | ||||
| -rw-r--r-- | src/video_core/video_core.vcxproj.filters | 17 | 
8 files changed, 340 insertions, 211 deletions
| diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 71a1b5ecc..0d737573b 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -5,8 +5,9 @@ set(SRCS    clipper.cpp              utils.cpp              vertex_shader.cpp              video_core.cpp -            debug_utils/debug_utils.cpp -            renderer_opengl/renderer_opengl.cpp) +            renderer_opengl/renderer_opengl.cpp +            renderer_opengl/gl_shader_util.cpp +            debug_utils/debug_utils.cpp)  set(HEADERS clipper.h              command_processor.h @@ -18,7 +19,9 @@ set(HEADERS clipper.h              renderer_base.h              vertex_shader.h              video_core.h -            debug_utils/debug_utils.h -            renderer_opengl/renderer_opengl.h) +            renderer_opengl/renderer_opengl.h +            renderer_opengl/gl_shader_util.h +            renderer_opengl/gl_shaders.h +            debug_utils/debug_utils.h)  add_library(video_core STATIC ${SRCS} ${HEADERS}) diff --git a/src/video_core/renderer_opengl/gl_shader_util.cpp b/src/video_core/renderer_opengl/gl_shader_util.cpp new file mode 100644 index 000000000..10239c8a7 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_shader_util.cpp @@ -0,0 +1,81 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#include "gl_shader_util.h" +#include "common/log.h" + +#include <vector> +#include <algorithm> + +namespace ShaderUtil { + +GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) { + +    // Create the shaders +    GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER); +    GLuint fragment_shader_id = glCreateShader(GL_FRAGMENT_SHADER); + +    GLint result = GL_FALSE; +    int info_log_length; + +    // Compile Vertex Shader +    DEBUG_LOG(GPU, "Compiling vertex shader."); + +    glShaderSource(vertex_shader_id, 1, &vertex_shader, NULL); +    glCompileShader(vertex_shader_id); + +    // Check Vertex Shader +    glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS, &result); +    glGetShaderiv(vertex_shader_id, GL_INFO_LOG_LENGTH, &info_log_length); + +    std::vector<char> vertex_shader_error(info_log_length); +    glGetShaderInfoLog(vertex_shader_id, info_log_length, NULL, &vertex_shader_error[0]); + +    if (info_log_length > 1) { +        DEBUG_LOG(GPU, "%s", &vertex_shader_error[0]); +    } + +    // Compile Fragment Shader +    DEBUG_LOG(GPU, "Compiling fragment shader."); + +    glShaderSource(fragment_shader_id, 1, &fragment_shader, NULL); +    glCompileShader(fragment_shader_id); + +    // Check Fragment Shader +    glGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS, &result); +    glGetShaderiv(fragment_shader_id, GL_INFO_LOG_LENGTH, &info_log_length); + +    std::vector<char> fragment_shader_error(info_log_length); +    glGetShaderInfoLog(fragment_shader_id, info_log_length, NULL, &fragment_shader_error[0]); + +    if (info_log_length > 1) { +        DEBUG_LOG(GPU, "%s", &fragment_shader_error[0]); +    } + +    // Link the program +    DEBUG_LOG(GPU, "Linking program."); + +    GLuint program_id = glCreateProgram(); +    glAttachShader(program_id, vertex_shader_id); +    glAttachShader(program_id, fragment_shader_id); +    glLinkProgram(program_id); + +    // Check the program +    glGetProgramiv(program_id, GL_LINK_STATUS, &result); +    glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length); + +    std::vector<char> program_error(std::max(info_log_length, int(1))); +    glGetProgramInfoLog(program_id, info_log_length, NULL, &program_error[0]); + +    if (info_log_length > 1) { +        DEBUG_LOG(GPU, "%s", &program_error[0]); +    } + +    glDeleteShader(vertex_shader_id); +    glDeleteShader(fragment_shader_id); + +    return program_id; +} + +} diff --git a/src/video_core/renderer_opengl/gl_shader_util.h b/src/video_core/renderer_opengl/gl_shader_util.h new file mode 100644 index 000000000..563f1015c --- /dev/null +++ b/src/video_core/renderer_opengl/gl_shader_util.h @@ -0,0 +1,13 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +#include <GL/glew.h> + +namespace ShaderUtil { + +GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path); + +} diff --git a/src/video_core/renderer_opengl/gl_shaders.h b/src/video_core/renderer_opengl/gl_shaders.h new file mode 100644 index 000000000..f84424c47 --- /dev/null +++ b/src/video_core/renderer_opengl/gl_shaders.h @@ -0,0 +1,39 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 +// Refer to the license.txt file included. + +#pragma once + +namespace GLShaders { + +static const char g_vertex_shader[] = R"( +#version 330 core +layout(location = 0) in vec3 position; +layout(location = 1) in vec2 texCoord; + +out vec2 UV; + +mat3 window_scale = mat3( +                         vec3(1.0, 0.0, 0.0), +                         vec3(0.0, 5.0/6.0, 0.0), // TODO(princesspeachum): replace hard-coded aspect with uniform +                         vec3(0.0, 0.0, 1.0) +                         ); + +void main() { +    gl_Position.xyz = window_scale * position; +    gl_Position.w = 1.0; + +    UV = texCoord; +})"; + +static const char g_fragment_shader[] = R"( +#version 330 core +in vec2 UV; +out vec3 color; +uniform sampler2D sampler; + +void main() { +    color = texture(sampler, UV).rgb; +})"; + +} 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      // -------------------------- diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index 30f4febe0..b21092f07 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h @@ -11,26 +11,25 @@  #include "video_core/renderer_base.h" +#include <array>  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 common::Rect& src_rect, const common::Rect& dst_rect); -    /**  +    /**       * Set the emulator window to use for renderer       * @param window EmuWindow handle to emulator window to use for rendering       */ @@ -53,37 +52,47 @@ private:      /// Updates the framerate      void UpdateFramerate(); -    /** -     * 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 -     * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei -     */ -    void FlipFramebuffer(const u8* in, u8* out); +    /// Structure used for storing information for rendering each 3DS screen +    struct ScreenInfo { +        // Properties +        int width; +        int height; + +        // OpenGL object IDs +        GLuint texture_id; +        GLuint vertex_buffer_id; +        // Temporary +        u8* flipped_xfb_data; +    }; -    EmuWindow*  m_render_window;                    ///< Handle to render window -    u32         m_last_mode;                        ///< Last render mode +    /** +    * Helper function to flip framebuffer from left-to-right to top-to-bottom +    * @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 FlipFramebuffer(const u8* raw_data, ScreenInfo& screen_info); -    int m_resolution_width;                         ///< Current resolution width -    int m_resolution_height;                        ///< Current resolution height +    EmuWindow*  render_window;                    ///< Handle to render window +    u32         last_mode;                        ///< Last render mode -    // Framebuffers -    // ------------ +    int resolution_width;                         ///< Current resolution width +    int resolution_height;                        ///< Current resolution height -    GLuint m_fbo[kMaxFramebuffers];                 ///< Framebuffer objects -    GLuint m_fbo_rbo[kMaxFramebuffers];             ///< Render buffer objects -    GLuint m_fbo_depth_buffers[kMaxFramebuffers];   ///< Depth buffers objects +    // OpenGL global object IDs +    GLuint vertex_array_id; +    GLuint program_id; +    GLuint sampler_id; -    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 +    struct : std::array<ScreenInfo, 2> { +        ScreenInfo& Top() { return (*this)[0]; } +        ScreenInfo& Bottom() { return (*this)[1]; } +    } screen_info;      // "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 xfb_top_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopHeight * 4]; +    u8 xfb_bottom_flipped[VideoCore::kScreenBottomWidth * VideoCore::kScreenBottomHeight * 4]; -    u8 m_xfb_top_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopHeight * 4]; -    u8 m_xfb_bottom_flipped[VideoCore::kScreenBottomWidth * VideoCore::kScreenBottomHeight * 4];  }; diff --git a/src/video_core/video_core.vcxproj b/src/video_core/video_core.vcxproj index 4e129fbe7..885567b6d 100644 --- a/src/video_core/video_core.vcxproj +++ b/src/video_core/video_core.vcxproj @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?>  <Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">    <ItemGroup Label="ProjectConfigurations">      <ProjectConfiguration Include="Debug|Win32"> @@ -21,6 +21,7 @@    <ItemGroup>      <ClCompile Include="debug_utils\debug_utils.cpp" />      <ClCompile Include="renderer_opengl\renderer_opengl.cpp" /> +    <ClCompile Include="renderer_opengl\gl_shader_util.cpp" />      <ClCompile Include="clipper.cpp" />      <ClCompile Include="command_processor.cpp" />      <ClCompile Include="primitive_assembly.cpp" /> @@ -43,6 +44,8 @@      <ClInclude Include="video_core.h" />      <ClInclude Include="debug_utils\debug_utils.h" />      <ClInclude Include="renderer_opengl\renderer_opengl.h" /> +    <ClInclude Include="renderer_opengl\gl_shader_util.h" /> +    <ClInclude Include="renderer_opengl\gl_shaders.h" />    </ItemGroup>    <ItemGroup>      <Text Include="CMakeLists.txt" /> diff --git a/src/video_core/video_core.vcxproj.filters b/src/video_core/video_core.vcxproj.filters index 90541aca0..ee6d8e8b4 100644 --- a/src/video_core/video_core.vcxproj.filters +++ b/src/video_core/video_core.vcxproj.filters @@ -1,4 +1,4 @@ -<?xml version="1.0" encoding="utf-8"?> +<?xml version="1.0" encoding="utf-8"?>  <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">    <ItemGroup>      <Filter Include="renderer_opengl"> @@ -12,6 +12,9 @@      <ClCompile Include="renderer_opengl\renderer_opengl.cpp">        <Filter>renderer_opengl</Filter>      </ClCompile> +    <ClCompile Include="renderer_opengl\gl_shader_util.cpp"> +      <Filter>renderer_opengl</Filter> +    </ClCompile>      <ClCompile Include="clipper.cpp" />      <ClCompile Include="command_processor.cpp" />      <ClCompile Include="primitive_assembly.cpp" /> @@ -35,7 +38,15 @@      <ClInclude Include="utils.h" />      <ClInclude Include="vertex_shader.h" />      <ClInclude Include="video_core.h" /> -    <ClInclude Include="renderer_opengl\renderer_opengl.h" /> +    <ClInclude Include="renderer_opengl\renderer_opengl.h"> +      <Filter>renderer_opengl</Filter> +    </ClInclude> +    <ClInclude Include="renderer_opengl\gl_shader_util.h"> +      <Filter>renderer_opengl</Filter> +    </ClInclude> +    <ClInclude Include="renderer_opengl\gl_shaders.h"> +      <Filter>renderer_opengl</Filter> +    </ClInclude>      <ClInclude Include="debug_utils\debug_utils.h">        <Filter>debug_utils</Filter>      </ClInclude> @@ -43,4 +54,4 @@    <ItemGroup>      <Text Include="CMakeLists.txt" />    </ItemGroup> -</Project>
\ No newline at end of file +</Project> | 
