diff options
Diffstat (limited to '')
| -rw-r--r-- | src/video_core/src/renderer_opengl/renderer_opengl.cpp | 159 | ||||
| -rw-r--r-- | src/video_core/src/renderer_opengl/renderer_opengl.h | 8 |
2 files changed, 147 insertions, 20 deletions
diff --git a/src/video_core/src/renderer_opengl/renderer_opengl.cpp b/src/video_core/src/renderer_opengl/renderer_opengl.cpp index 133740a74..27917a5a2 100644 --- a/src/video_core/src/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/src/renderer_opengl/renderer_opengl.cpp | |||
| @@ -22,9 +22,31 @@ | |||
| 22 | * http://code.google.com/p/gekko-gc-emu/ | 22 | * http://code.google.com/p/gekko-gc-emu/ |
| 23 | */ | 23 | */ |
| 24 | 24 | ||
| 25 | #include "mem_map.h" | ||
| 25 | #include "video_core.h" | 26 | #include "video_core.h" |
| 26 | #include "renderer_opengl/renderer_opengl.h" | 27 | #include "renderer_opengl/renderer_opengl.h" |
| 27 | 28 | ||
| 29 | /** | ||
| 30 | * Helper function to flip framebuffer from left-to-right to top-to-bottom | ||
| 31 | * @param addr Address of framebuffer in RAM | ||
| 32 | * @param out Pointer to output buffer with flipped framebuffer | ||
| 33 | * @todo Early on hack... I'd like to find a more efficient way of doing this /bunnei | ||
| 34 | */ | ||
| 35 | inline void _flip_framebuffer(u32 addr, u8* out) { | ||
| 36 | u8* in = Memory::GetPointer(addr); | ||
| 37 | for (int y = 0; y < VideoCore::kScreenTopHeight; y++) { | ||
| 38 | for (int x = 0; x < VideoCore::kScreenTopWidth; x++) { | ||
| 39 | int in_coord = (VideoCore::kScreenTopHeight * 3 * x) + (VideoCore::kScreenTopHeight * 3) | ||
| 40 | - (3 * y + 3); | ||
| 41 | int out_coord = (VideoCore::kScreenTopWidth * y * 3) + (x * 3); | ||
| 42 | |||
| 43 | out[out_coord + 0] = in[in_coord + 0]; | ||
| 44 | out[out_coord + 1] = in[in_coord + 1]; | ||
| 45 | out[out_coord + 2] = in[in_coord + 2]; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | } | ||
| 49 | |||
| 28 | /// RendererOpenGL constructor | 50 | /// RendererOpenGL constructor |
| 29 | RendererOpenGL::RendererOpenGL() { | 51 | RendererOpenGL::RendererOpenGL() { |
| 30 | memset(fbo_, 0, sizeof(fbo_)); | 52 | memset(fbo_, 0, sizeof(fbo_)); |
| @@ -33,27 +55,28 @@ RendererOpenGL::RendererOpenGL() { | |||
| 33 | 55 | ||
| 34 | resolution_width_ = max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); | 56 | resolution_width_ = max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); |
| 35 | resolution_height_ = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; | 57 | resolution_height_ = VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight; |
| 58 | |||
| 59 | xfb_texture_top_ = 0; | ||
| 60 | xfb_texture_bottom_ = 0; | ||
| 61 | |||
| 62 | xfb_top_ = 0; | ||
| 63 | xfb_bottom_ = 0; | ||
| 36 | } | 64 | } |
| 37 | 65 | ||
| 38 | /// RendererOpenGL destructor | 66 | /// RendererOpenGL destructor |
| 39 | RendererOpenGL::~RendererOpenGL() { | 67 | RendererOpenGL::~RendererOpenGL() { |
| 40 | } | 68 | } |
| 41 | 69 | ||
| 42 | |||
| 43 | /// Swap buffers (render frame) | 70 | /// Swap buffers (render frame) |
| 44 | void RendererOpenGL::SwapBuffers() { | 71 | void RendererOpenGL::SwapBuffers() { |
| 45 | 72 | ||
| 46 | glClearColor(1.0f, 1.0f, 0.0f, 1.0f); | ||
| 47 | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | ||
| 48 | |||
| 49 | ResetRenderState(); | 73 | ResetRenderState(); |
| 50 | 74 | ||
| 51 | // EFB->XFB copy | 75 | // EFB->XFB copy |
| 52 | // TODO(bunnei): This is a hack and does not belong here. The copy should be triggered by some | 76 | // TODO(bunnei): This is a hack and does not belong here. The copy should be triggered by some |
| 53 | // register write We're also treating both framebuffers as a single one in OpenGL. | 77 | // register write We're also treating both framebuffers as a single one in OpenGL. |
| 54 | Rect framebuffer_size(0, 0, VideoCore::kScreenTopWidth, | 78 | Rect framebuffer_size(0, 0, resolution_width_, resolution_height_); |
| 55 | VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); | 79 | RenderXFB(framebuffer_size, framebuffer_size); |
| 56 | CopyToXFB(framebuffer_size, framebuffer_size); | ||
| 57 | 80 | ||
| 58 | // XFB->Window copy | 81 | // XFB->Window copy |
| 59 | RenderFramebuffer(); | 82 | RenderFramebuffer(); |
| @@ -69,20 +92,34 @@ void RendererOpenGL::SwapBuffers() { | |||
| 69 | } | 92 | } |
| 70 | 93 | ||
| 71 | /** | 94 | /** |
| 72 | * Blits the EFB to the external framebuffer (XFB) | 95 | * Renders external framebuffer (XFB) |
| 73 | * @param src_rect Source rectangle in EFB to copy | 96 | * @param src_rect Source rectangle in XFB to copy |
| 74 | * @param dst_rect Destination rectangle in EFB to copy to | 97 | * @param dst_rect Destination rectangle in output framebuffer to copy to |
| 75 | * @param dest_height Destination height in pixels | ||
| 76 | */ | 98 | */ |
| 77 | void RendererOpenGL::CopyToXFB(const Rect& src_rect, const Rect& dst_rect) { | 99 | void RendererOpenGL::RenderXFB(const Rect& src_rect, const Rect& dst_rect) { |
| 100 | static u8 xfb_top_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopWidth *3]; | ||
| 101 | static u8 xfb_bottom_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopWidth *3]; | ||
| 102 | |||
| 103 | _flip_framebuffer(0x20282160, xfb_top_flipped); | ||
| 104 | _flip_framebuffer(0x202118E0, xfb_bottom_flipped); | ||
| 105 | |||
| 78 | ResetRenderState(); | 106 | ResetRenderState(); |
| 79 | 107 | ||
| 108 | // Blit the top framebuffer | ||
| 109 | // ------------------------ | ||
| 110 | |||
| 111 | // Update textures with contents of XFB in RAM - top | ||
| 112 | glBindTexture(GL_TEXTURE_2D, xfb_texture_top_); | ||
| 113 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, | ||
| 114 | GL_RGB, GL_UNSIGNED_BYTE, xfb_top_flipped); | ||
| 115 | glBindTexture(GL_TEXTURE_2D, 0); | ||
| 116 | |||
| 80 | // Render target is destination framebuffer | 117 | // Render target is destination framebuffer |
| 81 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_[kFramebuffer_VirtualXFB]); | 118 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_[kFramebuffer_VirtualXFB]); |
| 82 | glViewport(0, 0, resolution_width_, resolution_height_); | 119 | glViewport(0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight); |
| 83 | 120 | ||
| 84 | // Render source is our EFB | 121 | // Render source is our EFB |
| 85 | glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_[kFramebuffer_EFB]); | 122 | glBindFramebuffer(GL_READ_FRAMEBUFFER, xfb_top_); |
| 86 | glReadBuffer(GL_COLOR_ATTACHMENT0); | 123 | glReadBuffer(GL_COLOR_ATTACHMENT0); |
| 87 | 124 | ||
| 88 | // Blit | 125 | // Blit |
| @@ -92,9 +129,62 @@ void RendererOpenGL::CopyToXFB(const Rect& src_rect, const Rect& dst_rect) { | |||
| 92 | 129 | ||
| 93 | glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); | 130 | glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); |
| 94 | 131 | ||
| 132 | // Blit the bottom framebuffer | ||
| 133 | // --------------------------- | ||
| 134 | |||
| 135 | // Update textures with contents of XFB in RAM - bottom | ||
| 136 | glBindTexture(GL_TEXTURE_2D, xfb_texture_bottom_); | ||
| 137 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, | ||
| 138 | GL_RGB, GL_UNSIGNED_BYTE, xfb_bottom_flipped); | ||
| 139 | glBindTexture(GL_TEXTURE_2D, 0); | ||
| 140 | |||
| 141 | // Render target is destination framebuffer | ||
| 142 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_[kFramebuffer_VirtualXFB]); | ||
| 143 | glViewport(0, 0, | ||
| 144 | VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight); | ||
| 145 | |||
| 146 | // Render source is our EFB | ||
| 147 | glBindFramebuffer(GL_READ_FRAMEBUFFER, xfb_bottom_); | ||
| 148 | glReadBuffer(GL_COLOR_ATTACHMENT0); | ||
| 149 | |||
| 150 | // Blit | ||
| 151 | int offset = (VideoCore::kScreenTopWidth - VideoCore::kScreenBottomWidth) / 2; | ||
| 152 | glBlitFramebuffer(0,0, VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight, | ||
| 153 | offset, VideoCore::kScreenBottomHeight, VideoCore::kScreenBottomWidth + offset, 0, | ||
| 154 | GL_COLOR_BUFFER_BIT, GL_LINEAR); | ||
| 155 | |||
| 156 | glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); | ||
| 157 | |||
| 95 | RestoreRenderState(); | 158 | RestoreRenderState(); |
| 96 | } | 159 | } |
| 97 | 160 | ||
| 161 | /** | ||
| 162 | * Blits the EFB to the external framebuffer (XFB) | ||
| 163 | * @param src_rect Source rectangle in EFB to copy | ||
| 164 | * @param dst_rect Destination rectangle in EFB to copy to | ||
| 165 | */ | ||
| 166 | void RendererOpenGL::CopyToXFB(const Rect& src_rect, const Rect& dst_rect) { | ||
| 167 | ERROR_LOG(RENDER, "CopyToXFB not implemented! No EFB support yet!"); | ||
| 168 | //ResetRenderState(); | ||
| 169 | |||
| 170 | //// Render target is destination framebuffer | ||
| 171 | //glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_[kFramebuffer_VirtualXFB]); | ||
| 172 | //glViewport(0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight); | ||
| 173 | |||
| 174 | //// Render source is our EFB | ||
| 175 | //glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_[kFramebuffer_EFB]); | ||
| 176 | //glReadBuffer(GL_COLOR_ATTACHMENT0); | ||
| 177 | |||
| 178 | //// Blit | ||
| 179 | //glBlitFramebuffer(src_rect.x0_, src_rect.y0_, src_rect.x1_, src_rect.y1_, | ||
| 180 | // dst_rect.x0_, dst_rect.y1_, dst_rect.x1_, dst_rect.y0_, | ||
| 181 | // GL_COLOR_BUFFER_BIT, GL_LINEAR); | ||
| 182 | |||
| 183 | //glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); | ||
| 184 | |||
| 185 | //RestoreRenderState(); | ||
| 186 | } | ||
| 187 | |||
| 98 | /** | 188 | /** |
| 99 | * Clear the screen | 189 | * Clear the screen |
| 100 | * @param rect Screen rectangle to clear | 190 | * @param rect Screen rectangle to clear |
| @@ -234,12 +324,13 @@ void RendererOpenGL::InitFramebuffer() { | |||
| 234 | for (int i = 0; i < kMaxFramebuffers; i++) { | 324 | for (int i = 0; i < kMaxFramebuffers; i++) { |
| 235 | // Generate color buffer storage | 325 | // Generate color buffer storage |
| 236 | glBindRenderbuffer(GL_RENDERBUFFER, fbo_rbo_[i]); | 326 | glBindRenderbuffer(GL_RENDERBUFFER, fbo_rbo_[i]); |
| 237 | glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, resolution_width_, resolution_height_); | 327 | glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, VideoCore::kScreenTopWidth, |
| 328 | VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); | ||
| 238 | 329 | ||
| 239 | // Generate depth buffer storage | 330 | // Generate depth buffer storage |
| 240 | glBindRenderbuffer(GL_RENDERBUFFER, fbo_depth_buffers_[i]); | 331 | glBindRenderbuffer(GL_RENDERBUFFER, fbo_depth_buffers_[i]); |
| 241 | glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, resolution_width_, | 332 | glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, VideoCore::kScreenTopWidth, |
| 242 | resolution_height_); | 333 | VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); |
| 243 | 334 | ||
| 244 | // Attach the buffers | 335 | // Attach the buffers |
| 245 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_[i]); | 336 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_[i]); |
| @@ -257,6 +348,37 @@ void RendererOpenGL::InitFramebuffer() { | |||
| 257 | } | 348 | } |
| 258 | } | 349 | } |
| 259 | glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer(s) | 350 | glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer(s) |
| 351 | |||
| 352 | // Initialize framebuffer textures | ||
| 353 | // ------------------------------- | ||
| 354 | |||
| 355 | // Create XFB textures | ||
| 356 | glGenTextures(1, &xfb_texture_top_); | ||
| 357 | glGenTextures(1, &xfb_texture_bottom_); | ||
| 358 | |||
| 359 | // Alocate video memorry for XFB textures | ||
| 360 | glBindTexture(GL_TEXTURE_2D, xfb_texture_top_); | ||
| 361 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, | ||
| 362 | 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); | ||
| 363 | glBindTexture(GL_TEXTURE_2D, 0); | ||
| 364 | |||
| 365 | glBindTexture(GL_TEXTURE_2D, xfb_texture_bottom_); | ||
| 366 | glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, | ||
| 367 | 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); | ||
| 368 | glBindTexture(GL_TEXTURE_2D, 0); | ||
| 369 | |||
| 370 | // Create the FBO and attach color/depth textures | ||
| 371 | glGenFramebuffers(1, &xfb_top_); // Generate framebuffer | ||
| 372 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, xfb_top_); | ||
| 373 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | ||
| 374 | xfb_texture_top_, 0); | ||
| 375 | glBindFramebuffer(GL_FRAMEBUFFER, 0); | ||
| 376 | |||
| 377 | glGenFramebuffers(1, &xfb_bottom_); // Generate framebuffer | ||
| 378 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, xfb_bottom_); | ||
| 379 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | ||
| 380 | xfb_texture_bottom_, 0); | ||
| 381 | glBindFramebuffer(GL_FRAMEBUFFER, 0); | ||
| 260 | } | 382 | } |
| 261 | 383 | ||
| 262 | /// Blit the FBO to the OpenGL default framebuffer | 384 | /// Blit the FBO to the OpenGL default framebuffer |
| @@ -272,8 +394,7 @@ void RendererOpenGL::RenderFramebuffer() { | |||
| 272 | 394 | ||
| 273 | // Blit | 395 | // Blit |
| 274 | glBlitFramebuffer(0, 0, resolution_width_, resolution_height_, 0, 0, | 396 | glBlitFramebuffer(0, 0, resolution_width_, resolution_height_, 0, 0, |
| 275 | render_window_->client_area_width(), render_window_->client_area_height(), | 397 | resolution_width_, resolution_height_, GL_COLOR_BUFFER_BIT, GL_LINEAR); |
| 276 | GL_COLOR_BUFFER_BIT, GL_LINEAR); | ||
| 277 | 398 | ||
| 278 | // Update the FPS count | 399 | // Update the FPS count |
| 279 | UpdateFramerate(); | 400 | UpdateFramerate(); |
diff --git a/src/video_core/src/renderer_opengl/renderer_opengl.h b/src/video_core/src/renderer_opengl/renderer_opengl.h index f9fb89d50..b84afc5d2 100644 --- a/src/video_core/src/renderer_opengl/renderer_opengl.h +++ b/src/video_core/src/renderer_opengl/renderer_opengl.h | |||
| @@ -45,10 +45,16 @@ public: | |||
| 45 | void SwapBuffers(); | 45 | void SwapBuffers(); |
| 46 | 46 | ||
| 47 | /** | 47 | /** |
| 48 | * Renders external framebuffer (XFB) | ||
| 49 | * @param src_rect Source rectangle in XFB to copy | ||
| 50 | * @param dst_rect Destination rectangle in output framebuffer to copy to | ||
| 51 | */ | ||
| 52 | void RenderXFB(const Rect& src_rect, const Rect& dst_rect); | ||
| 53 | |||
| 54 | /** | ||
| 48 | * Blits the EFB to the external framebuffer (XFB) | 55 | * Blits the EFB to the external framebuffer (XFB) |
| 49 | * @param src_rect Source rectangle in EFB to copy | 56 | * @param src_rect Source rectangle in EFB to copy |
| 50 | * @param dst_rect Destination rectangle in EFB to copy to | 57 | * @param dst_rect Destination rectangle in EFB to copy to |
| 51 | * @param dest_height Destination height in pixels | ||
| 52 | */ | 58 | */ |
| 53 | void CopyToXFB(const Rect& src_rect, const Rect& dst_rect); | 59 | void CopyToXFB(const Rect& src_rect, const Rect& dst_rect); |
| 54 | 60 | ||