summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Kevin Hartman2014-08-21 00:27:53 -0700
committerGravatar Kevin Hartman2014-08-25 20:56:59 -0700
commitcbfd6b6e52e3b8c1d6324d86461f4e8aa240a756 (patch)
tree31355774610d25174521e88ca7dcebfe5bbfe715 /src
parentUpdate README.md to correct OS X typo (diff)
downloadyuzu-cbfd6b6e52e3b8c1d6324d86461f4e8aa240a756.tar.gz
yuzu-cbfd6b6e52e3b8c1d6324d86461f4e8aa240a756.tar.xz
yuzu-cbfd6b6e52e3b8c1d6324d86461f4e8aa240a756.zip
Rewrite of OpenGL renderer, including OS X support
Screen contents are now displayed using textured quads. This can be updated to expose an FBO once an OpenGL backend for when Pica rendering is being worked on. That FBO's texture can then be applied to the quads. Previously, FBO blitting was used in order to display screen contents, which did not work on OS X. The new textured quad approach is less of a compatibility risk.
Diffstat (limited to 'src')
-rw-r--r--src/video_core/CMakeLists.txt11
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.cpp81
-rw-r--r--src/video_core/renderer_opengl/gl_shader_util.h13
-rw-r--r--src/video_core/renderer_opengl/gl_shaders.h39
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp322
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h63
-rw-r--r--src/video_core/video_core.vcxproj5
-rw-r--r--src/video_core/video_core.vcxproj.filters17
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
5 utils.cpp 5 utils.cpp
6 vertex_shader.cpp 6 vertex_shader.cpp
7 video_core.cpp 7 video_core.cpp
8 debug_utils/debug_utils.cpp 8 renderer_opengl/renderer_opengl.cpp
9 renderer_opengl/renderer_opengl.cpp) 9 renderer_opengl/gl_shader_util.cpp
10 debug_utils/debug_utils.cpp)
10 11
11set(HEADERS clipper.h 12set(HEADERS clipper.h
12 command_processor.h 13 command_processor.h
@@ -18,7 +19,9 @@ set(HEADERS clipper.h
18 renderer_base.h 19 renderer_base.h
19 vertex_shader.h 20 vertex_shader.h
20 video_core.h 21 video_core.h
21 debug_utils/debug_utils.h 22 renderer_opengl/renderer_opengl.h
22 renderer_opengl/renderer_opengl.h) 23 renderer_opengl/gl_shader_util.h
24 renderer_opengl/gl_shaders.h
25 debug_utils/debug_utils.h)
23 26
24add_library(video_core STATIC ${SRCS} ${HEADERS}) 27add_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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "gl_shader_util.h"
6#include "common/log.h"
7
8#include <vector>
9#include <algorithm>
10
11namespace ShaderUtil {
12
13GLuint LoadShaders(const char* vertex_shader, const char* fragment_shader) {
14
15 // Create the shaders
16 GLuint vertex_shader_id = glCreateShader(GL_VERTEX_SHADER);
17 GLuint fragment_shader_id = glCreateShader(GL_FRAGMENT_SHADER);
18
19 GLint result = GL_FALSE;
20 int info_log_length;
21
22 // Compile Vertex Shader
23 DEBUG_LOG(GPU, "Compiling vertex shader.");
24
25 glShaderSource(vertex_shader_id, 1, &vertex_shader, NULL);
26 glCompileShader(vertex_shader_id);
27
28 // Check Vertex Shader
29 glGetShaderiv(vertex_shader_id, GL_COMPILE_STATUS, &result);
30 glGetShaderiv(vertex_shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
31
32 std::vector<char> vertex_shader_error(info_log_length);
33 glGetShaderInfoLog(vertex_shader_id, info_log_length, NULL, &vertex_shader_error[0]);
34
35 if (info_log_length > 1) {
36 DEBUG_LOG(GPU, "%s", &vertex_shader_error[0]);
37 }
38
39 // Compile Fragment Shader
40 DEBUG_LOG(GPU, "Compiling fragment shader.");
41
42 glShaderSource(fragment_shader_id, 1, &fragment_shader, NULL);
43 glCompileShader(fragment_shader_id);
44
45 // Check Fragment Shader
46 glGetShaderiv(fragment_shader_id, GL_COMPILE_STATUS, &result);
47 glGetShaderiv(fragment_shader_id, GL_INFO_LOG_LENGTH, &info_log_length);
48
49 std::vector<char> fragment_shader_error(info_log_length);
50 glGetShaderInfoLog(fragment_shader_id, info_log_length, NULL, &fragment_shader_error[0]);
51
52 if (info_log_length > 1) {
53 DEBUG_LOG(GPU, "%s", &fragment_shader_error[0]);
54 }
55
56 // Link the program
57 DEBUG_LOG(GPU, "Linking program.");
58
59 GLuint program_id = glCreateProgram();
60 glAttachShader(program_id, vertex_shader_id);
61 glAttachShader(program_id, fragment_shader_id);
62 glLinkProgram(program_id);
63
64 // Check the program
65 glGetProgramiv(program_id, GL_LINK_STATUS, &result);
66 glGetProgramiv(program_id, GL_INFO_LOG_LENGTH, &info_log_length);
67
68 std::vector<char> program_error(std::max(info_log_length, int(1)));
69 glGetProgramInfoLog(program_id, info_log_length, NULL, &program_error[0]);
70
71 if (info_log_length > 1) {
72 DEBUG_LOG(GPU, "%s", &program_error[0]);
73 }
74
75 glDeleteShader(vertex_shader_id);
76 glDeleteShader(fragment_shader_id);
77
78 return program_id;
79}
80
81}
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <GL/glew.h>
8
9namespace ShaderUtil {
10
11GLuint LoadShaders(const char* vertex_file_path, const char* fragment_file_path);
12
13}
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#pragma once
6
7namespace GLShaders {
8
9static const char g_vertex_shader[] = R"(
10#version 330 core
11layout(location = 0) in vec3 position;
12layout(location = 1) in vec2 texCoord;
13
14out vec2 UV;
15
16mat3 window_scale = mat3(
17 vec3(1.0, 0.0, 0.0),
18 vec3(0.0, 5.0/6.0, 0.0), // TODO(princesspeachum): replace hard-coded aspect with uniform
19 vec3(0.0, 0.0, 1.0)
20 );
21
22void main() {
23 gl_Position.xyz = window_scale * position;
24 gl_Position.w = 1.0;
25
26 UV = texCoord;
27})";
28
29static const char g_fragment_shader[] = R"(
30#version 330 core
31in vec2 UV;
32out vec3 color;
33uniform sampler2D sampler;
34
35void main() {
36 color = texture(sampler, UV).rgb;
37})";
38
39}
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 @@
6 6
7#include "video_core/video_core.h" 7#include "video_core/video_core.h"
8#include "video_core/renderer_opengl/renderer_opengl.h" 8#include "video_core/renderer_opengl/renderer_opengl.h"
9#include "video_core/renderer_opengl/gl_shader_util.h"
10#include "video_core/renderer_opengl/gl_shaders.h"
9 11
10#include "core/mem_map.h" 12#include "core/mem_map.h"
11 13
14#include <algorithm>
15
16static const GLfloat kViewportAspectRatio =
17 (static_cast<float>(VideoCore::kScreenTopHeight) + VideoCore::kScreenBottomHeight) / VideoCore::kScreenTopWidth;
18
19// Fullscreen quad dimensions
20static const GLfloat kTopScreenWidthNormalized = 2;
21static const GLfloat kTopScreenHeightNormalized = kTopScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenTopHeight) / VideoCore::kScreenTopWidth);
22static const GLfloat kBottomScreenWidthNormalized = kTopScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenBottomWidth) / VideoCore::kScreenTopWidth);
23static const GLfloat kBottomScreenHeightNormalized = kBottomScreenWidthNormalized * (static_cast<float>(VideoCore::kScreenBottomHeight) / VideoCore::kScreenBottomWidth);
24
25static const GLfloat g_vbuffer_top[] = {
26 // x, y, z u, v
27 -1.0f, 0.0f, 0.0f, 0.0f, 1.0f,
28 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
29 1.0f, kTopScreenHeightNormalized, 0.0f, 1.0f, 0.0f,
30 1.0f, kTopScreenHeightNormalized, 0.0f, 1.0f, 0.0f,
31 -1.0f, kTopScreenHeightNormalized, 0.0f, 0.0f, 0.0f,
32 -1.0f, 0.0f, 0.0f, 0.0f, 1.0f
33};
34
35static const GLfloat g_vbuffer_bottom[] = {
36 // x, y, z u, v
37 -(kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 0.0f, 1.0f,
38 (kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 1.0f, 1.0f,
39 (kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 1.0f, 0.0f,
40 (kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 1.0f, 0.0f,
41 -(kBottomScreenWidthNormalized / 2), 0.0f, 0.0f, 0.0f, 0.0f,
42 -(kBottomScreenWidthNormalized / 2), -kBottomScreenHeightNormalized, 0.0f, 0.0f, 1.0f
43};
12 44
13/// RendererOpenGL constructor 45/// RendererOpenGL constructor
14RendererOpenGL::RendererOpenGL() { 46RendererOpenGL::RendererOpenGL() {
15 memset(m_fbo, 0, sizeof(m_fbo));
16 memset(m_fbo_rbo, 0, sizeof(m_fbo_rbo));
17 memset(m_fbo_depth_buffers, 0, sizeof(m_fbo_depth_buffers));
18 47
19 m_resolution_width = max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); 48 resolution_width = std::max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth);
20 m_resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; 49 resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight;
21 50
22 m_xfb_texture_top = 0; 51 // Initialize screen info
23 m_xfb_texture_bottom = 0; 52 screen_info.Top().width = VideoCore::kScreenTopWidth;
53 screen_info.Top().height = VideoCore::kScreenTopHeight;
54 screen_info.Top().flipped_xfb_data = xfb_top_flipped;
24 55
25 m_xfb_top = 0; 56 screen_info.Bottom().width = VideoCore::kScreenBottomWidth;
26 m_xfb_bottom = 0; 57 screen_info.Bottom().height = VideoCore::kScreenBottomHeight;
58 screen_info.Bottom().flipped_xfb_data = xfb_bottom_flipped;
27} 59}
28 60
29/// RendererOpenGL destructor 61/// RendererOpenGL destructor
@@ -32,41 +64,41 @@ RendererOpenGL::~RendererOpenGL() {
32 64
33/// Swap buffers (render frame) 65/// Swap buffers (render frame)
34void RendererOpenGL::SwapBuffers() { 66void RendererOpenGL::SwapBuffers() {
35 m_render_window->MakeCurrent(); 67 render_window->MakeCurrent();
36 68
37 // EFB->XFB copy 69 // EFB->XFB copy
38 // TODO(bunnei): This is a hack and does not belong here. The copy should be triggered by some 70 // TODO(bunnei): This is a hack and does not belong here. The copy should be triggered by some
39 // register write We're also treating both framebuffers as a single one in OpenGL. 71 // register write.
40 common::Rect framebuffer_size(0, 0, m_resolution_width, m_resolution_height); 72 //
73 // TODO(princesspeachum): (related to above^) this should only be called when there's new data, not every frame.
74 // Currently this uploads data that shouldn't have changed.
75 common::Rect framebuffer_size(0, 0, resolution_width, resolution_height);
41 RenderXFB(framebuffer_size, framebuffer_size); 76 RenderXFB(framebuffer_size, framebuffer_size);
42 77
43 // XFB->Window copy 78 // XFB->Window copy
44 RenderFramebuffer(); 79 RenderFramebuffer();
45 80
46 // Swap buffers 81 // Swap buffers
47 m_render_window->PollEvents(); 82 render_window->PollEvents();
48 m_render_window->SwapBuffers(); 83 render_window->SwapBuffers();
49
50 // Switch back to EFB and clear
51 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_EFB]);
52} 84}
53 85
54/** 86/**
55 * Helper function to flip framebuffer from left-to-right to top-to-bottom 87 * Helper function to flip framebuffer from left-to-right to top-to-bottom
56 * @param in Pointer to input raw framebuffer in V/RAM 88 * @param raw_data Pointer to input raw framebuffer in V/RAM
57 * @param out Pointer to output buffer with flipped framebuffer 89 * @param screen_info ScreenInfo structure with screen size and output buffer pointer
58 * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei 90 * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei
59 */ 91 */
60void RendererOpenGL::FlipFramebuffer(const u8* in, u8* out) { 92void RendererOpenGL::FlipFramebuffer(const u8* raw_data, ScreenInfo& screen_info) {
61 int in_coord = 0; 93 int in_coord = 0;
62 for (int x = 0; x < VideoCore::kScreenTopWidth; x++) { 94 for (int x = 0; x < screen_info.width; x++) {
63 for (int y = VideoCore::kScreenTopHeight-1; y >= 0; y--) { 95 for (int y = screen_info.height-1; y >= 0; y--) {
64 // TODO: Properly support other framebuffer formats 96 // TODO: Properly support other framebuffer formats
65 int out_coord = (x + y * VideoCore::kScreenTopWidth) * 3; 97 int out_coord = (x + y * screen_info.width) * 3;
66 out[out_coord] = in[in_coord]; // blue? 98 screen_info.flipped_xfb_data[out_coord] = raw_data[in_coord + 2]; // Red
67 out[out_coord + 1] = in[in_coord + 1]; // green? 99 screen_info.flipped_xfb_data[out_coord + 1] = raw_data[in_coord + 1]; // Green
68 out[out_coord + 2] = in[in_coord + 2]; // red? 100 screen_info.flipped_xfb_data[out_coord + 2] = raw_data[in_coord]; // Blue
69 in_coord+=3; 101 in_coord += 3;
70 } 102 }
71 } 103 }
72} 104}
@@ -77,167 +109,116 @@ void RendererOpenGL::FlipFramebuffer(const u8* in, u8* out) {
77 * @param dst_rect Destination rectangle in output framebuffer to copy to 109 * @param dst_rect Destination rectangle in output framebuffer to copy to
78 */ 110 */
79void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect) { 111void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect) {
80
81 const auto& framebuffer_top = GPU::g_regs.framebuffer_config[0]; 112 const auto& framebuffer_top = GPU::g_regs.framebuffer_config[0];
82 const auto& framebuffer_sub = GPU::g_regs.framebuffer_config[1]; 113 const auto& framebuffer_sub = GPU::g_regs.framebuffer_config[1];
83 const u32 active_fb_top = (framebuffer_top.active_fb == 1) 114 const u32 active_fb_top = (framebuffer_top.active_fb == 1)
84 ? Memory::PhysicalToVirtualAddress(framebuffer_top.address_left2) 115 ? Memory::PhysicalToVirtualAddress(framebuffer_top.address_left2)
85 : Memory::PhysicalToVirtualAddress(framebuffer_top.address_left1); 116 : Memory::PhysicalToVirtualAddress(framebuffer_top.address_left1);
86 const u32 active_fb_sub = (framebuffer_sub.active_fb == 1) 117 const u32 active_fb_sub = (framebuffer_sub.active_fb == 1)
87 ? Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left2) 118 ? Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left2)
88 : Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left1); 119 : Memory::PhysicalToVirtualAddress(framebuffer_sub.address_left1);
89 120
90 DEBUG_LOG(GPU, "RenderXFB: 0x%08x bytes from 0x%08x(%dx%d), fmt %x", 121 DEBUG_LOG(GPU, "RenderXFB: 0x%08x bytes from 0x%08x(%dx%d), fmt %x",
91 framebuffer_top.stride * framebuffer_top.height, 122 framebuffer_top.stride * framebuffer_top.height,
92 active_fb_top, (int)framebuffer_top.width, 123 active_fb_top, (int)framebuffer_top.width,
93 (int)framebuffer_top.height, (int)framebuffer_top.format); 124 (int)framebuffer_top.height, (int)framebuffer_top.format);
94 125
95 // TODO: This should consider the GPU registers for framebuffer width, height and stride. 126 FlipFramebuffer(Memory::GetPointer(active_fb_top), screen_info.Top());
96 FlipFramebuffer(Memory::GetPointer(active_fb_top), m_xfb_top_flipped); 127 FlipFramebuffer(Memory::GetPointer(active_fb_sub), screen_info.Bottom());
97 FlipFramebuffer(Memory::GetPointer(active_fb_sub), m_xfb_bottom_flipped); 128
129 for (int i = 0; i < 2; i++) {
130 ScreenInfo* current_screen = &screen_info[i];
98 131
99 // Blit the top framebuffer 132 glBindTexture(GL_TEXTURE_2D, current_screen->texture_id);
100 // ------------------------ 133
134 // TODO: This should consider the GPU registers for framebuffer width, height and stride.
135 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, current_screen->width, current_screen->height,
136 GL_RGB, GL_UNSIGNED_BYTE, current_screen->flipped_xfb_data);
137 }
101 138
102 // Update textures with contents of XFB in RAM - top
103 glBindTexture(GL_TEXTURE_2D, m_xfb_texture_top);
104 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight,
105 GL_BGR, GL_UNSIGNED_BYTE, m_xfb_top_flipped);
106 glBindTexture(GL_TEXTURE_2D, 0); 139 glBindTexture(GL_TEXTURE_2D, 0);
107 140
108 // Render target is destination framebuffer 141 // TODO(princesspeachum):
109 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]); 142 // Only the subset src_rect of the GPU buffer
110 glViewport(0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight); 143 // should be copied into the texture of the relevant screen.
144 //
145 // The method's parameters also only include src_rect and dest_rec for one screen,
146 // so this may need to be changed (pair for each screen).
147}
111 148
112 // Render source is our EFB 149/// Initialize the FBO
113 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_xfb_top); 150void RendererOpenGL::InitFramebuffer() {
114 glReadBuffer(GL_COLOR_ATTACHMENT0); 151 program_id = ShaderUtil::LoadShaders(GLShaders::g_vertex_shader, GLShaders::g_fragment_shader);
152 sampler_id = glGetUniformLocation(program_id, "sampler");
115 153
116 // Blit 154 // Generate vertex buffers for both screens
117 glBlitFramebuffer(src_rect.x0_, src_rect.y0_, src_rect.x1_, src_rect.y1_, 155 glGenBuffers(1, &screen_info.Top().vertex_buffer_id);
118 dst_rect.x0_, dst_rect.y1_, dst_rect.x1_, dst_rect.y0_, 156 glGenBuffers(1, &screen_info.Bottom().vertex_buffer_id);
119 GL_COLOR_BUFFER_BIT, GL_LINEAR);
120 157
121 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); 158 // Attach vertex data for top screen
159 glBindBuffer(GL_ARRAY_BUFFER, screen_info.Top().vertex_buffer_id);
160 glBufferData(GL_ARRAY_BUFFER, sizeof(g_vbuffer_top), g_vbuffer_top, GL_STATIC_DRAW);
122 161
123 // Blit the bottom framebuffer 162 // Attach vertex data for bottom screen
124 // --------------------------- 163 glBindBuffer(GL_ARRAY_BUFFER, screen_info.Bottom().vertex_buffer_id);
164 glBufferData(GL_ARRAY_BUFFER, sizeof(g_vbuffer_bottom), g_vbuffer_bottom, GL_STATIC_DRAW);
125 165
126 // Update textures with contents of XFB in RAM - bottom 166 // Create color buffers for both screens
127 glBindTexture(GL_TEXTURE_2D, m_xfb_texture_bottom); 167 glGenTextures(1, &screen_info.Top().texture_id);
128 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, 168 glGenTextures(1, &screen_info.Bottom().texture_id);
129 GL_BGR, GL_UNSIGNED_BYTE, m_xfb_bottom_flipped);
130 glBindTexture(GL_TEXTURE_2D, 0);
131 169
132 // Render target is destination framebuffer 170 for (int i = 0; i < 2; i++) {
133 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]);
134 glViewport(0, 0,
135 VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight);
136 171
137 // Render source is our EFB 172 ScreenInfo* current_screen = &screen_info[i];
138 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_xfb_bottom);
139 glReadBuffer(GL_COLOR_ATTACHMENT0);
140 173
141 // Blit 174 // Allocate texture
142 int offset = (VideoCore::kScreenTopWidth - VideoCore::kScreenBottomWidth) / 2; 175 glBindTexture(GL_TEXTURE_2D, current_screen->vertex_buffer_id);
143 glBlitFramebuffer(0,0, VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight, 176 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, current_screen->width, current_screen->height,
144 offset, VideoCore::kScreenBottomHeight, VideoCore::kScreenBottomWidth + offset, 0, 177 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
145 GL_COLOR_BUFFER_BIT, GL_LINEAR);
146 178
147 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); 179 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
180 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
181 }
182
183 glBindTexture(GL_TEXTURE_2D, 0);
148} 184}
149 185
150/// Initialize the FBO 186void RendererOpenGL::RenderFramebuffer() {
151void RendererOpenGL::InitFramebuffer() { 187 glClear(GL_COLOR_BUFFER_BIT);
152 // TODO(bunnei): This should probably be implemented with the top screen and bottom screen as
153 // separate framebuffers
154
155 // Init the FBOs
156 // -------------
157
158 glGenFramebuffers(kMaxFramebuffers, m_fbo); // Generate primary framebuffer
159 glGenRenderbuffers(kMaxFramebuffers, m_fbo_rbo); // Generate primary RBOs
160 glGenRenderbuffers(kMaxFramebuffers, m_fbo_depth_buffers); // Generate primary depth buffer
161
162 for (int i = 0; i < kMaxFramebuffers; i++) {
163 // Generate color buffer storage
164 glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_rbo[i]);
165 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, VideoCore::kScreenTopWidth,
166 VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight);
167
168 // Generate depth buffer storage
169 glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_depth_buffers[i]);
170 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, VideoCore::kScreenTopWidth,
171 VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight);
172
173 // Attach the buffers
174 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[i]);
175 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
176 GL_RENDERBUFFER, m_fbo_depth_buffers[i]);
177 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
178 GL_RENDERBUFFER, m_fbo_rbo[i]);
179
180 // Check for completeness
181 if (GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER)) {
182 NOTICE_LOG(RENDER, "framebuffer(%d) initialized ok", i);
183 } else {
184 ERROR_LOG(RENDER, "couldn't create OpenGL frame buffer");
185 exit(1);
186 }
187 }
188 glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer(s)
189 188
190 // Initialize framebuffer textures 189 glUseProgram(program_id);
191 // -------------------------------
192 190
193 // Create XFB textures 191 // Bind texture in Texture Unit 0
194 glGenTextures(1, &m_xfb_texture_top); 192 glActiveTexture(GL_TEXTURE0);
195 glGenTextures(1, &m_xfb_texture_bottom);
196 193
197 // Alocate video memorry for XFB textures 194 glEnableVertexAttribArray(0);
198 glBindTexture(GL_TEXTURE_2D, m_xfb_texture_top); 195 glEnableVertexAttribArray(1);
199 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight,
200 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
201 glBindTexture(GL_TEXTURE_2D, 0);
202 196
203 glBindTexture(GL_TEXTURE_2D, m_xfb_texture_bottom); 197 for (int i = 0; i < 2; i++) {
204 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight,
205 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
206 glBindTexture(GL_TEXTURE_2D, 0);
207 198
208 // Create the FBO and attach color/depth textures 199 ScreenInfo* current_screen = &screen_info[i];
209 glGenFramebuffers(1, &m_xfb_top); // Generate framebuffer
210 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_top);
211 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
212 m_xfb_texture_top, 0);
213 glBindFramebuffer(GL_FRAMEBUFFER, 0);
214
215 glGenFramebuffers(1, &m_xfb_bottom); // Generate framebuffer
216 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_bottom);
217 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
218 m_xfb_texture_bottom, 0);
219 glBindFramebuffer(GL_FRAMEBUFFER, 0);
220}
221 200
222/// Blit the FBO to the OpenGL default framebuffer 201 glBindTexture(GL_TEXTURE_2D, current_screen->texture_id);
223void RendererOpenGL::RenderFramebuffer() {
224 // Render target is default framebuffer
225 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
226 glViewport(0, 0, m_resolution_width, m_resolution_height);
227 202
228 // Render source is our XFB 203 // Set sampler on Texture Unit 0
229 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]); 204 glUniform1i(sampler_id, 0);
230 glReadBuffer(GL_COLOR_ATTACHMENT0);
231 205
232 // Blit 206 glBindBuffer(GL_ARRAY_BUFFER, current_screen->vertex_buffer_id);
233 glBlitFramebuffer(0, 0, m_resolution_width, m_resolution_height, 0, 0, m_resolution_width,
234 m_resolution_height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
235 207
236 // Update the FPS count 208 // Vertex buffer layout
237 UpdateFramerate(); 209 const GLsizei stride = 5 * sizeof(GLfloat);
210 const GLvoid* uv_offset = (const GLvoid*)(3 * sizeof(GLfloat));
238 211
239 // Rebind EFB 212 // Configure vertex buffer
240 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_EFB]); 213 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, stride, NULL);
214 glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, stride, uv_offset);
215
216 // Draw screen
217 glDrawArrays(GL_TRIANGLES, 0, 6);
218 }
219
220 glDisableVertexAttribArray(0);
221 glDisableVertexAttribArray(1);
241 222
242 m_current_frame++; 223 m_current_frame++;
243} 224}
@@ -251,40 +232,29 @@ void RendererOpenGL::UpdateFramerate() {
251 * @param window EmuWindow handle to emulator window to use for rendering 232 * @param window EmuWindow handle to emulator window to use for rendering
252 */ 233 */
253void RendererOpenGL::SetWindow(EmuWindow* window) { 234void RendererOpenGL::SetWindow(EmuWindow* window) {
254 m_render_window = window; 235 render_window = window;
255} 236}
256 237
257/// Initialize the renderer 238/// Initialize the renderer
258void RendererOpenGL::Init() { 239void RendererOpenGL::Init() {
259 m_render_window->MakeCurrent(); 240 render_window->MakeCurrent();
260 glShadeModel(GL_SMOOTH);
261
262
263 glStencilFunc(GL_ALWAYS, 0, 0);
264 glBlendFunc(GL_ONE, GL_ONE);
265
266 glViewport(0, 0, m_resolution_width, m_resolution_height);
267
268 glClearDepth(1.0f);
269 glEnable(GL_DEPTH_TEST);
270 glDisable(GL_LIGHTING);
271 glDepthFunc(GL_LEQUAL);
272
273 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
274
275 glDisable(GL_STENCIL_TEST);
276 glEnable(GL_SCISSOR_TEST);
277
278 glScissor(0, 0, m_resolution_width, m_resolution_height);
279 glClearDepth(1.0f);
280 241
281 GLenum err = glewInit(); 242 GLenum err = glewInit();
282 if (GLEW_OK != err) { 243 if (GLEW_OK != err) {
283 ERROR_LOG(RENDER, "Failed to initialize GLEW! Error message: \"%s\". Exiting...", 244 ERROR_LOG(RENDER, "Failed to initialize GLEW! Error message: \"%s\". Exiting...",
284 glewGetErrorString(err)); 245 glewGetErrorString(err));
285 exit(-1); 246 exit(-1);
286 } 247 }
287 248
249 // Generate VAO
250 glGenVertexArrays(1, &vertex_array_id);
251 glBindVertexArray(vertex_array_id);
252
253 glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
254 glDisable(GL_DEPTH_TEST);
255
256 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
257
288 // Initialize everything else 258 // Initialize everything else
289 // -------------------------- 259 // --------------------------
290 260
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 @@
11 11
12#include "video_core/renderer_base.h" 12#include "video_core/renderer_base.h"
13 13
14#include <array>
14 15
15class RendererOpenGL : virtual public RendererBase { 16class RendererOpenGL : virtual public RendererBase {
16public: 17public:
17 18
18 static const int kMaxFramebuffers = 2; ///< Maximum number of framebuffers
19
20 RendererOpenGL(); 19 RendererOpenGL();
21 ~RendererOpenGL(); 20 ~RendererOpenGL();
22 21
23 /// Swap buffers (render frame) 22 /// Swap buffers (render frame)
24 void SwapBuffers(); 23 void SwapBuffers();
25 24
26 /** 25 /**
27 * Renders external framebuffer (XFB) 26 * Renders external framebuffer (XFB)
28 * @param src_rect Source rectangle in XFB to copy 27 * @param src_rect Source rectangle in XFB to copy
29 * @param dst_rect Destination rectangle in output framebuffer to copy to 28 * @param dst_rect Destination rectangle in output framebuffer to copy to
30 */ 29 */
31 void RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect); 30 void RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect);
32 31
33 /** 32 /**
34 * Set the emulator window to use for renderer 33 * Set the emulator window to use for renderer
35 * @param window EmuWindow handle to emulator window to use for rendering 34 * @param window EmuWindow handle to emulator window to use for rendering
36 */ 35 */
@@ -53,37 +52,47 @@ private:
53 /// Updates the framerate 52 /// Updates the framerate
54 void UpdateFramerate(); 53 void UpdateFramerate();
55 54
56 /** 55 /// Structure used for storing information for rendering each 3DS screen
57 * Helper function to flip framebuffer from left-to-right to top-to-bottom 56 struct ScreenInfo {
58 * @param in Pointer to input raw framebuffer in V/RAM 57 // Properties
59 * @param out Pointer to output buffer with flipped framebuffer 58 int width;
60 * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei 59 int height;
61 */ 60
62 void FlipFramebuffer(const u8* in, u8* out); 61 // OpenGL object IDs
62 GLuint texture_id;
63 GLuint vertex_buffer_id;
63 64
65 // Temporary
66 u8* flipped_xfb_data;
67 };
64 68
65 EmuWindow* m_render_window; ///< Handle to render window 69 /**
66 u32 m_last_mode; ///< Last render mode 70 * Helper function to flip framebuffer from left-to-right to top-to-bottom
71 * @param raw_data Pointer to input raw framebuffer in V/RAM
72 * @param screen_info ScreenInfo structure with screen size and output buffer pointer
73 * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei
74 */
75 void FlipFramebuffer(const u8* raw_data, ScreenInfo& screen_info);
67 76
68 int m_resolution_width; ///< Current resolution width 77 EmuWindow* render_window; ///< Handle to render window
69 int m_resolution_height; ///< Current resolution height 78 u32 last_mode; ///< Last render mode
70 79
71 // Framebuffers 80 int resolution_width; ///< Current resolution width
72 // ------------ 81 int resolution_height; ///< Current resolution height
73 82
74 GLuint m_fbo[kMaxFramebuffers]; ///< Framebuffer objects 83 // OpenGL global object IDs
75 GLuint m_fbo_rbo[kMaxFramebuffers]; ///< Render buffer objects 84 GLuint vertex_array_id;
76 GLuint m_fbo_depth_buffers[kMaxFramebuffers]; ///< Depth buffers objects 85 GLuint program_id;
86 GLuint sampler_id;
77 87
78 GLuint m_xfb_texture_top; ///< GL handle to top framebuffer texture 88 struct : std::array<ScreenInfo, 2> {
79 GLuint m_xfb_texture_bottom; ///< GL handle to bottom framebuffer texture 89 ScreenInfo& Top() { return (*this)[0]; }
80 90 ScreenInfo& Bottom() { return (*this)[1]; }
81 GLuint m_xfb_top; ///< GL handle to top framebuffer 91 } screen_info;
82 GLuint m_xfb_bottom; ///< GL handle to bottom framebuffer
83 92
84 // "Flipped" framebuffers translate scanlines from native 3DS left-to-right to top-to-bottom 93 // "Flipped" framebuffers translate scanlines from native 3DS left-to-right to top-to-bottom
85 // as OpenGL expects them in a texture. There probably is a more efficient way of doing this: 94 // as OpenGL expects them in a texture. There probably is a more efficient way of doing this:
95 u8 xfb_top_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopHeight * 4];
96 u8 xfb_bottom_flipped[VideoCore::kScreenBottomWidth * VideoCore::kScreenBottomHeight * 4];
86 97
87 u8 m_xfb_top_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopHeight * 4];
88 u8 m_xfb_bottom_flipped[VideoCore::kScreenBottomWidth * VideoCore::kScreenBottomHeight * 4];
89}; 98};
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 @@
1<?xml version="1.0" encoding="utf-8"?> 1<?xml version="1.0" encoding="utf-8"?>
2<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 2<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <ItemGroup Label="ProjectConfigurations"> 3 <ItemGroup Label="ProjectConfigurations">
4 <ProjectConfiguration Include="Debug|Win32"> 4 <ProjectConfiguration Include="Debug|Win32">
@@ -21,6 +21,7 @@
21 <ItemGroup> 21 <ItemGroup>
22 <ClCompile Include="debug_utils\debug_utils.cpp" /> 22 <ClCompile Include="debug_utils\debug_utils.cpp" />
23 <ClCompile Include="renderer_opengl\renderer_opengl.cpp" /> 23 <ClCompile Include="renderer_opengl\renderer_opengl.cpp" />
24 <ClCompile Include="renderer_opengl\gl_shader_util.cpp" />
24 <ClCompile Include="clipper.cpp" /> 25 <ClCompile Include="clipper.cpp" />
25 <ClCompile Include="command_processor.cpp" /> 26 <ClCompile Include="command_processor.cpp" />
26 <ClCompile Include="primitive_assembly.cpp" /> 27 <ClCompile Include="primitive_assembly.cpp" />
@@ -43,6 +44,8 @@
43 <ClInclude Include="video_core.h" /> 44 <ClInclude Include="video_core.h" />
44 <ClInclude Include="debug_utils\debug_utils.h" /> 45 <ClInclude Include="debug_utils\debug_utils.h" />
45 <ClInclude Include="renderer_opengl\renderer_opengl.h" /> 46 <ClInclude Include="renderer_opengl\renderer_opengl.h" />
47 <ClInclude Include="renderer_opengl\gl_shader_util.h" />
48 <ClInclude Include="renderer_opengl\gl_shaders.h" />
46 </ItemGroup> 49 </ItemGroup>
47 <ItemGroup> 50 <ItemGroup>
48 <Text Include="CMakeLists.txt" /> 51 <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 @@
1<?xml version="1.0" encoding="utf-8"?> 1<?xml version="1.0" encoding="utf-8"?>
2<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> 2<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 <ItemGroup> 3 <ItemGroup>
4 <Filter Include="renderer_opengl"> 4 <Filter Include="renderer_opengl">
@@ -12,6 +12,9 @@
12 <ClCompile Include="renderer_opengl\renderer_opengl.cpp"> 12 <ClCompile Include="renderer_opengl\renderer_opengl.cpp">
13 <Filter>renderer_opengl</Filter> 13 <Filter>renderer_opengl</Filter>
14 </ClCompile> 14 </ClCompile>
15 <ClCompile Include="renderer_opengl\gl_shader_util.cpp">
16 <Filter>renderer_opengl</Filter>
17 </ClCompile>
15 <ClCompile Include="clipper.cpp" /> 18 <ClCompile Include="clipper.cpp" />
16 <ClCompile Include="command_processor.cpp" /> 19 <ClCompile Include="command_processor.cpp" />
17 <ClCompile Include="primitive_assembly.cpp" /> 20 <ClCompile Include="primitive_assembly.cpp" />
@@ -35,7 +38,15 @@
35 <ClInclude Include="utils.h" /> 38 <ClInclude Include="utils.h" />
36 <ClInclude Include="vertex_shader.h" /> 39 <ClInclude Include="vertex_shader.h" />
37 <ClInclude Include="video_core.h" /> 40 <ClInclude Include="video_core.h" />
38 <ClInclude Include="renderer_opengl\renderer_opengl.h" /> 41 <ClInclude Include="renderer_opengl\renderer_opengl.h">
42 <Filter>renderer_opengl</Filter>
43 </ClInclude>
44 <ClInclude Include="renderer_opengl\gl_shader_util.h">
45 <Filter>renderer_opengl</Filter>
46 </ClInclude>
47 <ClInclude Include="renderer_opengl\gl_shaders.h">
48 <Filter>renderer_opengl</Filter>
49 </ClInclude>
39 <ClInclude Include="debug_utils\debug_utils.h"> 50 <ClInclude Include="debug_utils\debug_utils.h">
40 <Filter>debug_utils</Filter> 51 <Filter>debug_utils</Filter>
41 </ClInclude> 52 </ClInclude>
@@ -43,4 +54,4 @@
43 <ItemGroup> 54 <ItemGroup>
44 <Text Include="CMakeLists.txt" /> 55 <Text Include="CMakeLists.txt" />
45 </ItemGroup> 56 </ItemGroup>
46</Project> \ No newline at end of file 57</Project>