summaryrefslogtreecommitdiff
path: root/src/video_core/renderer_opengl
diff options
context:
space:
mode:
authorGravatar bunnei2014-04-08 19:25:03 -0400
committerGravatar bunnei2014-04-08 19:25:03 -0400
commit63e46abdb8764bc97e91bae862c8d461e61b1965 (patch)
treee73f4aa25d7b4015a265e7bbfb6004dab7561027 /src/video_core/renderer_opengl
parentfixed some license headers that I missed (diff)
downloadyuzu-63e46abdb8764bc97e91bae862c8d461e61b1965.tar.gz
yuzu-63e46abdb8764bc97e91bae862c8d461e61b1965.tar.xz
yuzu-63e46abdb8764bc97e91bae862c8d461e61b1965.zip
got rid of 'src' folders in each sub-project
Diffstat (limited to 'src/video_core/renderer_opengl')
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp279
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.h91
2 files changed, 370 insertions, 0 deletions
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 @@
1// Copyright 2014 Citra Emulator Project
2// Licensed under GPLv2
3// Refer to the license.txt file included.
4
5#include "mem_map.h"
6#include "video_core.h"
7#include "renderer_opengl/renderer_opengl.h"
8
9
10/// RendererOpenGL constructor
11RendererOpenGL::RendererOpenGL() {
12 memset(m_fbo, 0, sizeof(m_fbo));
13 memset(m_fbo_rbo, 0, sizeof(m_fbo_rbo));
14 memset(m_fbo_depth_buffers, 0, sizeof(m_fbo_depth_buffers));
15
16 m_resolution_width = max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth);
17 m_resolution_height = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight;
18
19 m_xfb_texture_top = 0;
20 m_xfb_texture_bottom = 0;
21
22 m_xfb_top = 0;
23 m_xfb_bottom = 0;
24}
25
26/// RendererOpenGL destructor
27RendererOpenGL::~RendererOpenGL() {
28}
29
30/// Swap buffers (render frame)
31void RendererOpenGL::SwapBuffers() {
32 // EFB->XFB copy
33 // TODO(bunnei): This is a hack and does not belong here. The copy should be triggered by some
34 // register write We're also treating both framebuffers as a single one in OpenGL.
35 Rect framebuffer_size(0, 0, m_resolution_width, m_resolution_height);
36 RenderXFB(framebuffer_size, framebuffer_size);
37
38 // XFB->Window copy
39 RenderFramebuffer();
40
41 // Swap buffers
42 m_render_window->PollEvents();
43 m_render_window->SwapBuffers();
44
45 // Switch back to EFB and clear
46 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_EFB]);
47}
48
49/**
50 * Helper function to flip framebuffer from left-to-right to top-to-bottom
51 * @param addr Address of framebuffer in RAM
52 * @param out Pointer to output buffer with flipped framebuffer
53 * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei
54 */
55void RendererOpenGL::FlipFramebuffer(u32 addr, u8* out) {
56 u8* in = Memory::GetPointer(addr);
57 for (int y = 0; y < VideoCore::kScreenTopHeight; y++) {
58 for (int x = 0; x < VideoCore::kScreenTopWidth; x++) {
59 int in_coord = (VideoCore::kScreenTopHeight * 3 * x) + (VideoCore::kScreenTopHeight * 3)
60 - (3 * y + 3);
61 int out_coord = (VideoCore::kScreenTopWidth * y * 3) + (x * 3);
62
63 out[out_coord + 0] = in[in_coord + 0];
64 out[out_coord + 1] = in[in_coord + 1];
65 out[out_coord + 2] = in[in_coord + 2];
66 }
67 }
68}
69
70/**
71 * Renders external framebuffer (XFB)
72 * @param src_rect Source rectangle in XFB to copy
73 * @param dst_rect Destination rectangle in output framebuffer to copy to
74 */
75void RendererOpenGL::RenderXFB(const Rect& src_rect, const Rect& dst_rect) {
76
77 FlipFramebuffer(0x20282160, m_xfb_top_flipped);
78 FlipFramebuffer(0x202118E0, m_xfb_bottom_flipped);
79
80 // Blit the top framebuffer
81 // ------------------------
82
83 // Update textures with contents of XFB in RAM - top
84 glBindTexture(GL_TEXTURE_2D, m_xfb_texture_top);
85 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight,
86 GL_RGB, GL_UNSIGNED_BYTE, m_xfb_top_flipped);
87 glBindTexture(GL_TEXTURE_2D, 0);
88
89 // Render target is destination framebuffer
90 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]);
91 glViewport(0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight);
92
93 // Render source is our EFB
94 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_xfb_top);
95 glReadBuffer(GL_COLOR_ATTACHMENT0);
96
97 // Blit
98 glBlitFramebuffer(src_rect.x0_, src_rect.y0_, src_rect.x1_, src_rect.y1_,
99 dst_rect.x0_, dst_rect.y1_, dst_rect.x1_, dst_rect.y0_,
100 GL_COLOR_BUFFER_BIT, GL_LINEAR);
101
102 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
103
104 // Blit the bottom framebuffer
105 // ---------------------------
106
107 // Update textures with contents of XFB in RAM - bottom
108 glBindTexture(GL_TEXTURE_2D, m_xfb_texture_bottom);
109 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight,
110 GL_RGB, GL_UNSIGNED_BYTE, m_xfb_bottom_flipped);
111 glBindTexture(GL_TEXTURE_2D, 0);
112
113 // Render target is destination framebuffer
114 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]);
115 glViewport(0, 0,
116 VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight);
117
118 // Render source is our EFB
119 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_xfb_bottom);
120 glReadBuffer(GL_COLOR_ATTACHMENT0);
121
122 // Blit
123 int offset = (VideoCore::kScreenTopWidth - VideoCore::kScreenBottomWidth) / 2;
124 glBlitFramebuffer(0,0, VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight,
125 offset, VideoCore::kScreenBottomHeight, VideoCore::kScreenBottomWidth + offset, 0,
126 GL_COLOR_BUFFER_BIT, GL_LINEAR);
127
128 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
129}
130
131/// Initialize the FBO
132void RendererOpenGL::InitFramebuffer() {
133 // TODO(bunnei): This should probably be implemented with the top screen and bottom screen as
134 // separate framebuffers
135
136 // Init the FBOs
137 // -------------
138
139 glGenFramebuffers(kMaxFramebuffers, m_fbo); // Generate primary framebuffer
140 glGenRenderbuffers(kMaxFramebuffers, m_fbo_rbo); // Generate primary RBOs
141 glGenRenderbuffers(kMaxFramebuffers, m_fbo_depth_buffers); // Generate primary depth buffer
142
143 for (int i = 0; i < kMaxFramebuffers; i++) {
144 // Generate color buffer storage
145 glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_rbo[i]);
146 glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, VideoCore::kScreenTopWidth,
147 VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight);
148
149 // Generate depth buffer storage
150 glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_depth_buffers[i]);
151 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, VideoCore::kScreenTopWidth,
152 VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight);
153
154 // Attach the buffers
155 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[i]);
156 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
157 GL_RENDERBUFFER, m_fbo_depth_buffers[i]);
158 glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
159 GL_RENDERBUFFER, m_fbo_rbo[i]);
160
161 // Check for completeness
162 if (GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER)) {
163 NOTICE_LOG(RENDER, "framebuffer(%d) initialized ok", i);
164 } else {
165 ERROR_LOG(RENDER, "couldn't create OpenGL frame buffer");
166 exit(1);
167 }
168 }
169 glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer(s)
170
171 // Initialize framebuffer textures
172 // -------------------------------
173
174 // Create XFB textures
175 glGenTextures(1, &m_xfb_texture_top);
176 glGenTextures(1, &m_xfb_texture_bottom);
177
178 // Alocate video memorry for XFB textures
179 glBindTexture(GL_TEXTURE_2D, m_xfb_texture_top);
180 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight,
181 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
182 glBindTexture(GL_TEXTURE_2D, 0);
183
184 glBindTexture(GL_TEXTURE_2D, m_xfb_texture_bottom);
185 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight,
186 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
187 glBindTexture(GL_TEXTURE_2D, 0);
188
189 // Create the FBO and attach color/depth textures
190 glGenFramebuffers(1, &m_xfb_top); // Generate framebuffer
191 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_top);
192 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
193 m_xfb_texture_top, 0);
194 glBindFramebuffer(GL_FRAMEBUFFER, 0);
195
196 glGenFramebuffers(1, &m_xfb_bottom); // Generate framebuffer
197 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_bottom);
198 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
199 m_xfb_texture_bottom, 0);
200 glBindFramebuffer(GL_FRAMEBUFFER, 0);
201}
202
203/// Blit the FBO to the OpenGL default framebuffer
204void RendererOpenGL::RenderFramebuffer() {
205 // Render target is default framebuffer
206 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
207 glViewport(0, 0, m_resolution_width, m_resolution_height);
208
209 // Render source is our XFB
210 glBindFramebuffer(GL_READ_FRAMEBUFFER, m_fbo[kFramebuffer_VirtualXFB]);
211 glReadBuffer(GL_COLOR_ATTACHMENT0);
212
213 // Blit
214 glBlitFramebuffer(0, 0, m_resolution_width, m_resolution_height, 0, 0, m_resolution_width,
215 m_resolution_height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
216
217 // Update the FPS count
218 UpdateFramerate();
219
220 // Rebind EFB
221 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_fbo[kFramebuffer_EFB]);
222
223 m_current_frame++;
224}
225
226/// Updates the framerate
227void RendererOpenGL::UpdateFramerate() {
228}
229
230/**
231 * Set the emulator window to use for renderer
232 * @param window EmuWindow handle to emulator window to use for rendering
233 */
234void RendererOpenGL::SetWindow(EmuWindow* window) {
235 m_render_window = window;
236}
237
238/// Initialize the renderer
239void RendererOpenGL::Init() {
240 m_render_window->MakeCurrent();
241 glShadeModel(GL_SMOOTH);
242
243
244 glStencilFunc(GL_ALWAYS, 0, 0);
245 glBlendFunc(GL_ONE, GL_ONE);
246
247 glViewport(0, 0, m_resolution_width, m_resolution_height);
248
249 glClearDepth(1.0f);
250 glEnable(GL_DEPTH_TEST);
251 glDisable(GL_LIGHTING);
252 glDepthFunc(GL_LEQUAL);
253
254 glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
255
256 glDisable(GL_STENCIL_TEST);
257 glEnable(GL_SCISSOR_TEST);
258
259 glScissor(0, 0, m_resolution_width, m_resolution_height);
260 glClearDepth(1.0f);
261
262 GLenum err = glewInit();
263 if (GLEW_OK != err) {
264 ERROR_LOG(RENDER, "Failed to initialize GLEW! Error message: \"%s\". Exiting...",
265 glewGetErrorString(err));
266 exit(-1);
267 }
268
269 // Initialize everything else
270 // --------------------------
271
272 InitFramebuffer();
273
274 NOTICE_LOG(RENDER, "GL_VERSION: %s\n", glGetString(GL_VERSION));
275}
276
277/// Shutdown the renderer
278void RendererOpenGL::ShutDown() {
279}
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 @@
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
9#include "common.h"
10#include "emu_window.h"
11
12#include "renderer_base.h"
13
14
15class RendererOpenGL : virtual public RendererBase {
16public:
17
18 static const int kMaxFramebuffers = 2; ///< Maximum number of framebuffers
19
20 RendererOpenGL();
21 ~RendererOpenGL();
22
23 /// Swap buffers (render frame)
24 void SwapBuffers();
25
26 /**
27 * Renders external framebuffer (XFB)
28 * @param src_rect Source rectangle in XFB to copy
29 * @param dst_rect Destination rectangle in output framebuffer to copy to
30 */
31 void RenderXFB(const Rect& src_rect, const Rect& dst_rect);
32
33 /**
34 * Set the emulator window to use for renderer
35 * @param window EmuWindow handle to emulator window to use for rendering
36 */
37 void SetWindow(EmuWindow* window);
38
39 /// Initialize the renderer
40 void Init();
41
42 /// Shutdown the renderer
43 void ShutDown();
44
45private:
46
47 /// Initialize the FBO
48 void InitFramebuffer();
49
50 // Blit the FBO to the OpenGL default framebuffer
51 void RenderFramebuffer();
52
53 /// Updates the framerate
54 void UpdateFramerate();
55
56 /**
57 * Helper function to flip framebuffer from left-to-right to top-to-bottom
58 * @param addr Address of framebuffer in RAM
59 * @param out Pointer to output buffer with flipped framebuffer
60 * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei
61 */
62 void RendererOpenGL::FlipFramebuffer(u32 addr, u8* out);
63
64
65 EmuWindow* m_render_window; ///< Handle to render window
66 u32 m_last_mode; ///< Last render mode
67
68 int m_resolution_width; ///< Current resolution width
69 int m_resolution_height; ///< Current resolution height
70
71 // Framebuffers
72 // ------------
73
74 GLuint m_fbo[kMaxFramebuffers]; ///< Framebuffer objects
75 GLuint m_fbo_rbo[kMaxFramebuffers]; ///< Render buffer objects
76 GLuint m_fbo_depth_buffers[kMaxFramebuffers]; ///< Depth buffers objects
77
78 GLuint m_xfb_texture_top; ///< GL handle to top framebuffer texture
79 GLuint m_xfb_texture_bottom; ///< GL handle to bottom framebuffer texture
80
81 GLuint m_xfb_top; ///< GL handle to top framebuffer
82 GLuint m_xfb_bottom; ///< GL handle to bottom framebuffer
83
84 // "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:
86
87 u8 m_xfb_top_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopWidth * 4];
88 u8 m_xfb_bottom_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopWidth * 4];
89
90 DISALLOW_COPY_AND_ASSIGN(RendererOpenGL);
91}; \ No newline at end of file