diff options
| author | 2014-07-22 19:20:57 -0400 | |
|---|---|---|
| committer | 2014-07-22 19:20:57 -0400 | |
| commit | daa924b906ff3a6f54d00c5d19874c2f839af0a3 (patch) | |
| tree | 127b4998ece87140690b7e74853215522d57ecaa /src/video_core | |
| parent | Merge pull request #32 from yuriks/master (diff) | |
| parent | Use uniform formatting when printing hexadecimal numbers. (diff) | |
| download | yuzu-daa924b906ff3a6f54d00c5d19874c2f839af0a3.tar.gz yuzu-daa924b906ff3a6f54d00c5d19874c2f839af0a3.tar.xz yuzu-daa924b906ff3a6f54d00c5d19874c2f839af0a3.zip | |
Merge pull request #31 from neobrain/gpu_framebuffer
GPU framebuffer emulation improvements
Diffstat (limited to 'src/video_core')
| -rw-r--r-- | src/video_core/gpu_debugger.h | 11 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.cpp | 62 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/renderer_opengl.h | 7 |
3 files changed, 50 insertions, 30 deletions
diff --git a/src/video_core/gpu_debugger.h b/src/video_core/gpu_debugger.h index 5d909beba..d92ceaa72 100644 --- a/src/video_core/gpu_debugger.h +++ b/src/video_core/gpu_debugger.h | |||
| @@ -50,7 +50,7 @@ public: | |||
| 50 | virtual void GXCommandProcessed(int total_command_count) | 50 | virtual void GXCommandProcessed(int total_command_count) |
| 51 | { | 51 | { |
| 52 | const GSP_GPU::GXCommand& cmd = observed->ReadGXCommandHistory(total_command_count-1); | 52 | const GSP_GPU::GXCommand& cmd = observed->ReadGXCommandHistory(total_command_count-1); |
| 53 | ERROR_LOG(GSP, "Received command: id=%x", cmd.id); | 53 | ERROR_LOG(GSP, "Received command: id=%x", (int)cmd.id.Value()); |
| 54 | } | 54 | } |
| 55 | 55 | ||
| 56 | /** | 56 | /** |
| @@ -78,11 +78,13 @@ public: | |||
| 78 | 78 | ||
| 79 | void GXCommandProcessed(u8* command_data) | 79 | void GXCommandProcessed(u8* command_data) |
| 80 | { | 80 | { |
| 81 | if (observers.empty()) | ||
| 82 | return; | ||
| 83 | |||
| 81 | gx_command_history.push_back(GSP_GPU::GXCommand()); | 84 | gx_command_history.push_back(GSP_GPU::GXCommand()); |
| 82 | GSP_GPU::GXCommand& cmd = gx_command_history[gx_command_history.size()-1]; | 85 | GSP_GPU::GXCommand& cmd = gx_command_history[gx_command_history.size()-1]; |
| 83 | 86 | ||
| 84 | const int cmd_length = sizeof(GSP_GPU::GXCommand); | 87 | memcpy(&cmd, command_data, sizeof(GSP_GPU::GXCommand)); |
| 85 | memcpy(cmd.data, command_data, cmd_length); | ||
| 86 | 88 | ||
| 87 | ForEachObserver([this](DebuggerObserver* observer) { | 89 | ForEachObserver([this](DebuggerObserver* observer) { |
| 88 | observer->GXCommandProcessed(this->gx_command_history.size()); | 90 | observer->GXCommandProcessed(this->gx_command_history.size()); |
| @@ -91,6 +93,9 @@ public: | |||
| 91 | 93 | ||
| 92 | void CommandListCalled(u32 address, u32* command_list, u32 size_in_words) | 94 | void CommandListCalled(u32 address, u32* command_list, u32 size_in_words) |
| 93 | { | 95 | { |
| 96 | if (observers.empty()) | ||
| 97 | return; | ||
| 98 | |||
| 94 | PicaCommandList cmdlist; | 99 | PicaCommandList cmdlist; |
| 95 | for (u32* parse_pointer = command_list; parse_pointer < command_list + size_in_words;) | 100 | for (u32* parse_pointer = command_list; parse_pointer < command_list + size_in_words;) |
| 96 | { | 101 | { |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 70af47c59..d0a8ec1da 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -12,8 +12,8 @@ | |||
| 12 | 12 | ||
| 13 | /// RendererOpenGL constructor | 13 | /// RendererOpenGL constructor |
| 14 | RendererOpenGL::RendererOpenGL() { | 14 | RendererOpenGL::RendererOpenGL() { |
| 15 | memset(m_fbo, 0, sizeof(m_fbo)); | 15 | memset(m_fbo, 0, sizeof(m_fbo)); |
| 16 | memset(m_fbo_rbo, 0, sizeof(m_fbo_rbo)); | 16 | memset(m_fbo_rbo, 0, sizeof(m_fbo_rbo)); |
| 17 | memset(m_fbo_depth_buffers, 0, sizeof(m_fbo_depth_buffers)); | 17 | memset(m_fbo_depth_buffers, 0, sizeof(m_fbo_depth_buffers)); |
| 18 | 18 | ||
| 19 | m_resolution_width = max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); | 19 | m_resolution_width = max(VideoCore::kScreenTopWidth, VideoCore::kScreenBottomWidth); |
| @@ -35,7 +35,7 @@ void RendererOpenGL::SwapBuffers() { | |||
| 35 | m_render_window->MakeCurrent(); | 35 | m_render_window->MakeCurrent(); |
| 36 | 36 | ||
| 37 | // EFB->XFB copy | 37 | // EFB->XFB copy |
| 38 | // TODO(bunnei): This is a hack and does not belong here. The copy should be triggered by some | 38 | // 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. | 39 | // register write We're also treating both framebuffers as a single one in OpenGL. |
| 40 | common::Rect framebuffer_size(0, 0, m_resolution_width, m_resolution_height); | 40 | common::Rect framebuffer_size(0, 0, m_resolution_width, m_resolution_height); |
| 41 | RenderXFB(framebuffer_size, framebuffer_size); | 41 | RenderXFB(framebuffer_size, framebuffer_size); |
| @@ -61,24 +61,40 @@ void RendererOpenGL::FlipFramebuffer(const u8* in, u8* out) { | |||
| 61 | int in_coord = 0; | 61 | int in_coord = 0; |
| 62 | for (int x = 0; x < VideoCore::kScreenTopWidth; x++) { | 62 | for (int x = 0; x < VideoCore::kScreenTopWidth; x++) { |
| 63 | for (int y = VideoCore::kScreenTopHeight-1; y >= 0; y--) { | 63 | for (int y = VideoCore::kScreenTopHeight-1; y >= 0; y--) { |
| 64 | // TODO: Properly support other framebuffer formats | ||
| 64 | int out_coord = (x + y * VideoCore::kScreenTopWidth) * 3; | 65 | int out_coord = (x + y * VideoCore::kScreenTopWidth) * 3; |
| 65 | out[out_coord] = in[in_coord]; | 66 | out[out_coord] = in[in_coord]; // blue? |
| 66 | out[out_coord + 1] = in[in_coord + 1]; | 67 | out[out_coord + 1] = in[in_coord + 1]; // green? |
| 67 | out[out_coord + 2] = in[in_coord + 2]; | 68 | out[out_coord + 2] = in[in_coord + 2]; // red? |
| 68 | in_coord+=3; | 69 | in_coord+=3; |
| 69 | } | 70 | } |
| 70 | } | 71 | } |
| 71 | } | 72 | } |
| 72 | 73 | ||
| 73 | /** | 74 | /** |
| 74 | * Renders external framebuffer (XFB) | 75 | * Renders external framebuffer (XFB) |
| 75 | * @param src_rect Source rectangle in XFB to copy | 76 | * @param src_rect Source rectangle in XFB to copy |
| 76 | * @param dst_rect Destination rectangle in output framebuffer to copy to | 77 | * @param dst_rect Destination rectangle in output framebuffer to copy to |
| 77 | */ | 78 | */ |
| 78 | void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect) { | 79 | void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect& dst_rect) { |
| 79 | 80 | ||
| 80 | FlipFramebuffer(GPU::GetFramebufferPointer(GPU::g_regs.framebuffer_top_left_1), m_xfb_top_flipped); | 81 | const auto& framebuffer_top = GPU::g_regs.Get<GPU::Regs::FramebufferTop>(); |
| 81 | FlipFramebuffer(GPU::GetFramebufferPointer(GPU::g_regs.framebuffer_sub_left_1), m_xfb_bottom_flipped); | 82 | const auto& framebuffer_sub = GPU::g_regs.Get<GPU::Regs::FramebufferBottom>(); |
| 83 | const u32 active_fb_top = (framebuffer_top.active_fb == 1) | ||
| 84 | ? framebuffer_top.address_left2 | ||
| 85 | : framebuffer_top.address_left1; | ||
| 86 | const u32 active_fb_sub = (framebuffer_sub.active_fb == 1) | ||
| 87 | ? framebuffer_sub.address_left2 | ||
| 88 | : framebuffer_sub.address_left1; | ||
| 89 | |||
| 90 | DEBUG_LOG(GPU, "RenderXFB: 0x%08x bytes from 0x%08x(%dx%d), fmt %x", | ||
| 91 | framebuffer_top.stride * framebuffer_top.height, | ||
| 92 | GPU::GetFramebufferAddr(active_fb_top), (int)framebuffer_top.width, | ||
| 93 | (int)framebuffer_top.height, (int)framebuffer_top.format); | ||
| 94 | |||
| 95 | // TODO: This should consider the GPU registers for framebuffer width, height and stride. | ||
| 96 | FlipFramebuffer(GPU::GetFramebufferPointer(active_fb_top), m_xfb_top_flipped); | ||
| 97 | FlipFramebuffer(GPU::GetFramebufferPointer(active_fb_sub), m_xfb_bottom_flipped); | ||
| 82 | 98 | ||
| 83 | // Blit the top framebuffer | 99 | // Blit the top framebuffer |
| 84 | // ------------------------ | 100 | // ------------------------ |
| @@ -98,7 +114,7 @@ void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect& | |||
| 98 | glReadBuffer(GL_COLOR_ATTACHMENT0); | 114 | glReadBuffer(GL_COLOR_ATTACHMENT0); |
| 99 | 115 | ||
| 100 | // Blit | 116 | // Blit |
| 101 | glBlitFramebuffer(src_rect.x0_, src_rect.y0_, src_rect.x1_, src_rect.y1_, | 117 | glBlitFramebuffer(src_rect.x0_, src_rect.y0_, src_rect.x1_, src_rect.y1_, |
| 102 | dst_rect.x0_, dst_rect.y1_, dst_rect.x1_, dst_rect.y0_, | 118 | dst_rect.x0_, dst_rect.y1_, dst_rect.x1_, dst_rect.y0_, |
| 103 | GL_COLOR_BUFFER_BIT, GL_LINEAR); | 119 | GL_COLOR_BUFFER_BIT, GL_LINEAR); |
| 104 | 120 | ||
| @@ -110,7 +126,7 @@ void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect& | |||
| 110 | // Update textures with contents of XFB in RAM - bottom | 126 | // Update textures with contents of XFB in RAM - bottom |
| 111 | glBindTexture(GL_TEXTURE_2D, m_xfb_texture_bottom); | 127 | glBindTexture(GL_TEXTURE_2D, m_xfb_texture_bottom); |
| 112 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, | 128 | glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight, |
| 113 | GL_RGB, GL_UNSIGNED_BYTE, m_xfb_bottom_flipped); | 129 | GL_BGR, GL_UNSIGNED_BYTE, m_xfb_bottom_flipped); |
| 114 | glBindTexture(GL_TEXTURE_2D, 0); | 130 | glBindTexture(GL_TEXTURE_2D, 0); |
| 115 | 131 | ||
| 116 | // Render target is destination framebuffer | 132 | // Render target is destination framebuffer |
| @@ -124,7 +140,7 @@ void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect& | |||
| 124 | 140 | ||
| 125 | // Blit | 141 | // Blit |
| 126 | int offset = (VideoCore::kScreenTopWidth - VideoCore::kScreenBottomWidth) / 2; | 142 | int offset = (VideoCore::kScreenTopWidth - VideoCore::kScreenBottomWidth) / 2; |
| 127 | glBlitFramebuffer(0,0, VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight, | 143 | glBlitFramebuffer(0,0, VideoCore::kScreenBottomWidth, VideoCore::kScreenBottomHeight, |
| 128 | offset, VideoCore::kScreenBottomHeight, VideoCore::kScreenBottomWidth + offset, 0, | 144 | offset, VideoCore::kScreenBottomHeight, VideoCore::kScreenBottomWidth + offset, 0, |
| 129 | GL_COLOR_BUFFER_BIT, GL_LINEAR); | 145 | GL_COLOR_BUFFER_BIT, GL_LINEAR); |
| 130 | 146 | ||
| @@ -133,7 +149,7 @@ void RendererOpenGL::RenderXFB(const common::Rect& src_rect, const common::Rect& | |||
| 133 | 149 | ||
| 134 | /// Initialize the FBO | 150 | /// Initialize the FBO |
| 135 | void RendererOpenGL::InitFramebuffer() { | 151 | void RendererOpenGL::InitFramebuffer() { |
| 136 | // TODO(bunnei): This should probably be implemented with the top screen and bottom screen as | 152 | // TODO(bunnei): This should probably be implemented with the top screen and bottom screen as |
| 137 | // separate framebuffers | 153 | // separate framebuffers |
| 138 | 154 | ||
| 139 | // Init the FBOs | 155 | // Init the FBOs |
| @@ -146,12 +162,12 @@ void RendererOpenGL::InitFramebuffer() { | |||
| 146 | for (int i = 0; i < kMaxFramebuffers; i++) { | 162 | for (int i = 0; i < kMaxFramebuffers; i++) { |
| 147 | // Generate color buffer storage | 163 | // Generate color buffer storage |
| 148 | glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_rbo[i]); | 164 | glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_rbo[i]); |
| 149 | glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, VideoCore::kScreenTopWidth, | 165 | glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, VideoCore::kScreenTopWidth, |
| 150 | VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); | 166 | VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); |
| 151 | 167 | ||
| 152 | // Generate depth buffer storage | 168 | // Generate depth buffer storage |
| 153 | glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_depth_buffers[i]); | 169 | glBindRenderbuffer(GL_RENDERBUFFER, m_fbo_depth_buffers[i]); |
| 154 | glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, VideoCore::kScreenTopWidth, | 170 | glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, VideoCore::kScreenTopWidth, |
| 155 | VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); | 171 | VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); |
| 156 | 172 | ||
| 157 | // Attach the buffers | 173 | // Attach the buffers |
| @@ -167,7 +183,7 @@ void RendererOpenGL::InitFramebuffer() { | |||
| 167 | } else { | 183 | } else { |
| 168 | ERROR_LOG(RENDER, "couldn't create OpenGL frame buffer"); | 184 | ERROR_LOG(RENDER, "couldn't create OpenGL frame buffer"); |
| 169 | exit(1); | 185 | exit(1); |
| 170 | } | 186 | } |
| 171 | } | 187 | } |
| 172 | glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer(s) | 188 | glBindFramebuffer(GL_FRAMEBUFFER, 0); // Unbind our frame buffer(s) |
| 173 | 189 | ||
| @@ -175,8 +191,8 @@ void RendererOpenGL::InitFramebuffer() { | |||
| 175 | // ------------------------------- | 191 | // ------------------------------- |
| 176 | 192 | ||
| 177 | // Create XFB textures | 193 | // Create XFB textures |
| 178 | glGenTextures(1, &m_xfb_texture_top); | 194 | glGenTextures(1, &m_xfb_texture_top); |
| 179 | glGenTextures(1, &m_xfb_texture_bottom); | 195 | glGenTextures(1, &m_xfb_texture_bottom); |
| 180 | 196 | ||
| 181 | // Alocate video memorry for XFB textures | 197 | // Alocate video memorry for XFB textures |
| 182 | glBindTexture(GL_TEXTURE_2D, m_xfb_texture_top); | 198 | glBindTexture(GL_TEXTURE_2D, m_xfb_texture_top); |
| @@ -192,13 +208,13 @@ void RendererOpenGL::InitFramebuffer() { | |||
| 192 | // Create the FBO and attach color/depth textures | 208 | // Create the FBO and attach color/depth textures |
| 193 | glGenFramebuffers(1, &m_xfb_top); // Generate framebuffer | 209 | glGenFramebuffers(1, &m_xfb_top); // Generate framebuffer |
| 194 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_top); | 210 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_top); |
| 195 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | 211 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| 196 | m_xfb_texture_top, 0); | 212 | m_xfb_texture_top, 0); |
| 197 | glBindFramebuffer(GL_FRAMEBUFFER, 0); | 213 | glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| 198 | 214 | ||
| 199 | glGenFramebuffers(1, &m_xfb_bottom); // Generate framebuffer | 215 | glGenFramebuffers(1, &m_xfb_bottom); // Generate framebuffer |
| 200 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_bottom); | 216 | glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_xfb_bottom); |
| 201 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, | 217 | glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, |
| 202 | m_xfb_texture_bottom, 0); | 218 | m_xfb_texture_bottom, 0); |
| 203 | glBindFramebuffer(GL_FRAMEBUFFER, 0); | 219 | glBindFramebuffer(GL_FRAMEBUFFER, 0); |
| 204 | } | 220 | } |
| @@ -214,7 +230,7 @@ void RendererOpenGL::RenderFramebuffer() { | |||
| 214 | glReadBuffer(GL_COLOR_ATTACHMENT0); | 230 | glReadBuffer(GL_COLOR_ATTACHMENT0); |
| 215 | 231 | ||
| 216 | // Blit | 232 | // Blit |
| 217 | glBlitFramebuffer(0, 0, m_resolution_width, m_resolution_height, 0, 0, m_resolution_width, | 233 | glBlitFramebuffer(0, 0, m_resolution_width, m_resolution_height, 0, 0, m_resolution_width, |
| 218 | m_resolution_height, GL_COLOR_BUFFER_BIT, GL_LINEAR); | 234 | m_resolution_height, GL_COLOR_BUFFER_BIT, GL_LINEAR); |
| 219 | 235 | ||
| 220 | // Update the FPS count | 236 | // Update the FPS count |
| @@ -230,7 +246,7 @@ void RendererOpenGL::RenderFramebuffer() { | |||
| 230 | void RendererOpenGL::UpdateFramerate() { | 246 | void RendererOpenGL::UpdateFramerate() { |
| 231 | } | 247 | } |
| 232 | 248 | ||
| 233 | /** | 249 | /** |
| 234 | * Set the emulator window to use for renderer | 250 | * Set the emulator window to use for renderer |
| 235 | * @param window EmuWindow handle to emulator window to use for rendering | 251 | * @param window EmuWindow handle to emulator window to use for rendering |
| 236 | */ | 252 | */ |
| @@ -264,7 +280,7 @@ void RendererOpenGL::Init() { | |||
| 264 | 280 | ||
| 265 | GLenum err = glewInit(); | 281 | GLenum err = glewInit(); |
| 266 | if (GLEW_OK != err) { | 282 | if (GLEW_OK != err) { |
| 267 | ERROR_LOG(RENDER, "Failed to initialize GLEW! Error message: \"%s\". Exiting...", | 283 | ERROR_LOG(RENDER, "Failed to initialize GLEW! Error message: \"%s\". Exiting...", |
| 268 | glewGetErrorString(err)); | 284 | glewGetErrorString(err)); |
| 269 | exit(-1); | 285 | exit(-1); |
| 270 | } | 286 | } |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.h b/src/video_core/renderer_opengl/renderer_opengl.h index dd811cad6..30f4febe0 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.h +++ b/src/video_core/renderer_opengl/renderer_opengl.h | |||
| @@ -84,7 +84,6 @@ private: | |||
| 84 | // "Flipped" framebuffers translate scanlines from native 3DS left-to-right to top-to-bottom | 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: | 85 | // as OpenGL expects them in a texture. There probably is a more efficient way of doing this: |
| 86 | 86 | ||
| 87 | u8 m_xfb_top_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopWidth * 4]; | 87 | u8 m_xfb_top_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopHeight * 4]; |
| 88 | u8 m_xfb_bottom_flipped[VideoCore::kScreenTopWidth * VideoCore::kScreenTopWidth * 4]; | 88 | u8 m_xfb_bottom_flipped[VideoCore::kScreenBottomWidth * VideoCore::kScreenBottomHeight * 4]; |
| 89 | 89 | }; | |
| 90 | }; \ No newline at end of file | ||