mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Merge pull request #636 from bunnei/refactor-screen-win
Set framebuffer layout from EmuWindow.
This commit is contained in:
		
						commit
						06bf471581
					
				
					 7 changed files with 88 additions and 60 deletions
				
			
		|  | @ -36,20 +36,13 @@ const bool EmuWindow_GLFW::IsOpen() { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void EmuWindow_GLFW::OnFramebufferResizeEvent(GLFWwindow* win, int width, int height) { | void EmuWindow_GLFW::OnFramebufferResizeEvent(GLFWwindow* win, int width, int height) { | ||||||
|     ASSERT(width > 0); |     GetEmuWindow(win)->NotifyFramebufferLayoutChanged(EmuWindow::FramebufferLayout::DefaultScreenLayout(width, height)); | ||||||
|     ASSERT(height > 0); |  | ||||||
| 
 |  | ||||||
|     GetEmuWindow(win)->NotifyFramebufferSizeChanged(std::pair<unsigned,unsigned>(width, height)); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void EmuWindow_GLFW::OnClientAreaResizeEvent(GLFWwindow* win, int width, int height) { | void EmuWindow_GLFW::OnClientAreaResizeEvent(GLFWwindow* win, int width, int height) { | ||||||
|     ASSERT(width > 0); |  | ||||||
|     ASSERT(height > 0); |  | ||||||
| 
 |  | ||||||
|     // NOTE: GLFW provides no proper way to set a minimal window size.
 |     // NOTE: GLFW provides no proper way to set a minimal window size.
 | ||||||
|     //       Hence, we just ignore the corresponding EmuWindow hint.
 |     //       Hence, we just ignore the corresponding EmuWindow hint.
 | ||||||
| 
 |     OnFramebufferResizeEvent(win, width, height); | ||||||
|     GetEmuWindow(win)->NotifyClientAreaSizeChanged(std::pair<unsigned,unsigned>(width, height)); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /// EmuWindow_GLFW constructor
 | /// EmuWindow_GLFW constructor
 | ||||||
|  |  | ||||||
|  | @ -155,6 +155,7 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this | ||||||
| 
 | 
 | ||||||
|     child = new GGLWidgetInternal(fmt, this); |     child = new GGLWidgetInternal(fmt, this); | ||||||
|     QBoxLayout* layout = new QHBoxLayout(this); |     QBoxLayout* layout = new QHBoxLayout(this); | ||||||
|  | 
 | ||||||
|     resize(VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); |     resize(VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); | ||||||
|     layout->addWidget(child); |     layout->addWidget(child); | ||||||
|     layout->setMargin(0); |     layout->setMargin(0); | ||||||
|  | @ -234,7 +235,7 @@ void GRenderWindow::OnFramebufferSizeChanged() | ||||||
|     unsigned height = child->QPaintDevice::height(); |     unsigned height = child->QPaintDevice::height(); | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|     NotifyFramebufferSizeChanged(std::make_pair(width, height)); |     NotifyFramebufferLayoutChanged(EmuWindow::FramebufferLayout::DefaultScreenLayout(width, height)); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GRenderWindow::BackupGeometry() | void GRenderWindow::BackupGeometry() | ||||||
|  |  | ||||||
|  | @ -3,6 +3,7 @@ | ||||||
| // Refer to the license.txt file included.
 | // Refer to the license.txt file included.
 | ||||||
| 
 | 
 | ||||||
| #include "emu_window.h" | #include "emu_window.h" | ||||||
|  | #include "video_core/video_core.h" | ||||||
| 
 | 
 | ||||||
| void EmuWindow::KeyPressed(KeyMap::HostDeviceKey key) { | void EmuWindow::KeyPressed(KeyMap::HostDeviceKey key) { | ||||||
|     Service::HID::PadState mapped_key = KeyMap::GetPadKey(key); |     Service::HID::PadState mapped_key = KeyMap::GetPadKey(key); | ||||||
|  | @ -15,3 +16,52 @@ void EmuWindow::KeyReleased(KeyMap::HostDeviceKey key) { | ||||||
| 
 | 
 | ||||||
|     Service::HID::PadButtonRelease(mapped_key); |     Service::HID::PadButtonRelease(mapped_key); | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(int width, int height) { | ||||||
|  |     ASSERT(width > 0); | ||||||
|  |     ASSERT(height > 0); | ||||||
|  | 
 | ||||||
|  |     EmuWindow::FramebufferLayout res = { width, height, {}, {} }; | ||||||
|  | 
 | ||||||
|  |     float window_aspect_ratio = static_cast<float>(height) / width; | ||||||
|  |     float emulation_aspect_ratio = static_cast<float>(VideoCore::kScreenTopHeight * 2) / | ||||||
|  |         VideoCore::kScreenTopWidth; | ||||||
|  | 
 | ||||||
|  |     if (window_aspect_ratio > emulation_aspect_ratio) { | ||||||
|  |         // Window is narrower than the emulation content => apply borders to the top and bottom
 | ||||||
|  |         int viewport_height = static_cast<int>(std::round(emulation_aspect_ratio * width)); | ||||||
|  | 
 | ||||||
|  |         res.top_screen.left = 0; | ||||||
|  |         res.top_screen.right = res.top_screen.left + width; | ||||||
|  |         res.top_screen.top = (height - viewport_height) / 2; | ||||||
|  |         res.top_screen.bottom = res.top_screen.top + viewport_height / 2; | ||||||
|  | 
 | ||||||
|  |         int bottom_width = static_cast<int>((static_cast<float>(VideoCore::kScreenBottomWidth) / | ||||||
|  |             VideoCore::kScreenTopWidth) * (res.top_screen.right - res.top_screen.left)); | ||||||
|  |         int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2; | ||||||
|  | 
 | ||||||
|  |         res.bottom_screen.left = bottom_border; | ||||||
|  |         res.bottom_screen.right = res.bottom_screen.left + bottom_width; | ||||||
|  |         res.bottom_screen.top = res.top_screen.bottom; | ||||||
|  |         res.bottom_screen.bottom = res.bottom_screen.top + viewport_height / 2; | ||||||
|  |     } else { | ||||||
|  |         // Otherwise, apply borders to the left and right sides of the window.
 | ||||||
|  |         int viewport_width = static_cast<int>(std::round(height / emulation_aspect_ratio)); | ||||||
|  | 
 | ||||||
|  |         res.top_screen.left = (width - viewport_width) / 2; | ||||||
|  |         res.top_screen.right = res.top_screen.left + viewport_width; | ||||||
|  |         res.top_screen.top = 0; | ||||||
|  |         res.top_screen.bottom = res.top_screen.top + height / 2; | ||||||
|  | 
 | ||||||
|  |         int bottom_width = static_cast<int>((static_cast<float>(VideoCore::kScreenBottomWidth) / | ||||||
|  |             VideoCore::kScreenTopWidth) * (res.top_screen.right - res.top_screen.left)); | ||||||
|  |         int bottom_border = ((res.top_screen.right - res.top_screen.left) - bottom_width) / 2; | ||||||
|  | 
 | ||||||
|  |         res.bottom_screen.left = res.top_screen.left + bottom_border; | ||||||
|  |         res.bottom_screen.right = res.bottom_screen.left + bottom_width; | ||||||
|  |         res.bottom_screen.top = res.top_screen.bottom; | ||||||
|  |         res.bottom_screen.bottom = res.bottom_screen.top + height / 2; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return res; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -8,6 +8,7 @@ | ||||||
| #include "common/scm_rev.h" | #include "common/scm_rev.h" | ||||||
| #include "common/string_util.h" | #include "common/string_util.h" | ||||||
| #include "common/key_map.h" | #include "common/key_map.h" | ||||||
|  | #include "common/math_util.h" | ||||||
| 
 | 
 | ||||||
| /**
 | /**
 | ||||||
|  * Abstraction class used to provide an interface between emulation code and the frontend |  * Abstraction class used to provide an interface between emulation code and the frontend | ||||||
|  | @ -38,6 +39,23 @@ public: | ||||||
|         std::pair<unsigned,unsigned> min_client_area_size; |         std::pair<unsigned,unsigned> min_client_area_size; | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  |     /// Describes the layout of the window framebuffer (size and top/bottom screen positions)
 | ||||||
|  |     struct FramebufferLayout { | ||||||
|  | 
 | ||||||
|  |         /**
 | ||||||
|  |          * Factory method for constructing a default FramebufferLayout | ||||||
|  |          * @param width Window framebuffer width in pixels | ||||||
|  |          * @param height Window framebuffer height in pixels | ||||||
|  |          * @return Newly created FramebufferLayout object with default screen regions initialized | ||||||
|  |          */ | ||||||
|  |         static FramebufferLayout DefaultScreenLayout(int width, int height); | ||||||
|  | 
 | ||||||
|  |         unsigned width; | ||||||
|  |         unsigned height; | ||||||
|  |         MathUtil::Rectangle<unsigned> top_screen; | ||||||
|  |         MathUtil::Rectangle<unsigned> bottom_screen; | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|     /// Swap buffers to display the next frame
 |     /// Swap buffers to display the next frame
 | ||||||
|     virtual void SwapBuffers() = 0; |     virtual void SwapBuffers() = 0; | ||||||
| 
 | 
 | ||||||
|  | @ -75,11 +93,11 @@ public: | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|       * Gets the framebuffer size in pixels. |       * Gets the framebuffer layout (width, height, and screen regions) | ||||||
|       * @note This method is thread-safe |       * @note This method is thread-safe | ||||||
|       */ |       */ | ||||||
|     const std::pair<unsigned,unsigned> GetFramebufferSize() const { |     const FramebufferLayout& GetFramebufferLayout() const { | ||||||
|         return framebuffer_size; |         return framebuffer_layout; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|  | @ -118,11 +136,11 @@ protected: | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Update internal framebuffer size with the given parameter. |      * Update framebuffer layout with the given parameter. | ||||||
|      * @note EmuWindow implementations will usually use this in window resize event handlers. |      * @note EmuWindow implementations will usually use this in window resize event handlers. | ||||||
|      */ |      */ | ||||||
|     void NotifyFramebufferSizeChanged(const std::pair<unsigned,unsigned>& size) { |     void NotifyFramebufferLayoutChanged(const FramebufferLayout& layout) { | ||||||
|         framebuffer_size = size; |         framebuffer_layout = layout; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|  | @ -143,7 +161,7 @@ private: | ||||||
|         // By default, ignore this request and do nothing.
 |         // By default, ignore this request and do nothing.
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     std::pair<unsigned,unsigned> framebuffer_size; |     FramebufferLayout framebuffer_layout; ///< Current framebuffer layout
 | ||||||
| 
 | 
 | ||||||
|     unsigned client_area_width;    ///< Current client width, should be set by window impl.
 |     unsigned client_area_width;    ///< Current client width, should be set by window impl.
 | ||||||
|     unsigned client_area_height;   ///< Current client height, should be set by window impl.
 |     unsigned client_area_height;   ///< Current client height, should be set by window impl.
 | ||||||
|  |  | ||||||
|  | @ -254,28 +254,26 @@ void RendererOpenGL::DrawSingleScreenRotated(const TextureInfo& texture, float x | ||||||
|  * Draws the emulated screens to the emulator window. |  * Draws the emulated screens to the emulator window. | ||||||
|  */ |  */ | ||||||
| void RendererOpenGL::DrawScreens() { | void RendererOpenGL::DrawScreens() { | ||||||
|     auto viewport_extent = GetViewportExtent(); |     auto layout = render_window->GetFramebufferLayout(); | ||||||
|     glViewport(viewport_extent.left, viewport_extent.top, viewport_extent.GetWidth(), viewport_extent.GetHeight()); // TODO: Or bottom?
 | 
 | ||||||
|  |     glViewport(0, 0, layout.width, layout.height); | ||||||
|     glClear(GL_COLOR_BUFFER_BIT); |     glClear(GL_COLOR_BUFFER_BIT); | ||||||
| 
 | 
 | ||||||
|     glUseProgram(program_id); |     glUseProgram(program_id); | ||||||
| 
 | 
 | ||||||
|     // Set projection matrix
 |     // Set projection matrix
 | ||||||
|     std::array<GLfloat, 3*2> ortho_matrix = MakeOrthographicMatrix((float)resolution_width, (float)resolution_height); |     std::array<GLfloat, 3 * 2> ortho_matrix = MakeOrthographicMatrix((float)layout.width, | ||||||
|  |         (float)layout.height); | ||||||
|     glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data()); |     glUniformMatrix3x2fv(uniform_modelview_matrix, 1, GL_FALSE, ortho_matrix.data()); | ||||||
| 
 | 
 | ||||||
|     // Bind texture in Texture Unit 0
 |     // Bind texture in Texture Unit 0
 | ||||||
|     glActiveTexture(GL_TEXTURE0); |     glActiveTexture(GL_TEXTURE0); | ||||||
|     glUniform1i(uniform_color_texture, 0); |     glUniform1i(uniform_color_texture, 0); | ||||||
| 
 | 
 | ||||||
|     const float max_width = std::max((float)VideoCore::kScreenTopWidth, (float)VideoCore::kScreenBottomWidth); |     DrawSingleScreenRotated(textures[0], (float)layout.top_screen.left, (float)layout.top_screen.top, | ||||||
|     const float top_x = 0.5f * (max_width - VideoCore::kScreenTopWidth); |         (float)layout.top_screen.GetWidth(), (float)layout.top_screen.GetHeight()); | ||||||
|     const float bottom_x = 0.5f * (max_width - VideoCore::kScreenBottomWidth); |     DrawSingleScreenRotated(textures[1], (float)layout.bottom_screen.left,(float)layout.bottom_screen.top, | ||||||
| 
 |         (float)layout.bottom_screen.GetWidth(), (float)layout.bottom_screen.GetHeight()); | ||||||
|     DrawSingleScreenRotated(textures[0], top_x, 0, |  | ||||||
|         (float)VideoCore::kScreenTopWidth, (float)VideoCore::kScreenTopHeight); |  | ||||||
|     DrawSingleScreenRotated(textures[1], bottom_x, (float)VideoCore::kScreenTopHeight, |  | ||||||
|         (float)VideoCore::kScreenBottomWidth, (float)VideoCore::kScreenBottomHeight); |  | ||||||
| 
 | 
 | ||||||
|     m_current_frame++; |     m_current_frame++; | ||||||
| } | } | ||||||
|  | @ -292,34 +290,6 @@ void RendererOpenGL::SetWindow(EmuWindow* window) { | ||||||
|     render_window = window; |     render_window = window; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MathUtil::Rectangle<unsigned> RendererOpenGL::GetViewportExtent() { |  | ||||||
|     unsigned framebuffer_width; |  | ||||||
|     unsigned framebuffer_height; |  | ||||||
|     std::tie(framebuffer_width, framebuffer_height) = render_window->GetFramebufferSize(); |  | ||||||
| 
 |  | ||||||
|     float window_aspect_ratio = static_cast<float>(framebuffer_height) / framebuffer_width; |  | ||||||
|     float emulation_aspect_ratio = static_cast<float>(resolution_height) / resolution_width; |  | ||||||
| 
 |  | ||||||
|     MathUtil::Rectangle<unsigned> viewport_extent; |  | ||||||
|     if (window_aspect_ratio > emulation_aspect_ratio) { |  | ||||||
|         // Window is narrower than the emulation content => apply borders to the top and bottom
 |  | ||||||
|         unsigned viewport_height = static_cast<unsigned>(std::round(emulation_aspect_ratio * framebuffer_width)); |  | ||||||
|         viewport_extent.left = 0; |  | ||||||
|         viewport_extent.top = (framebuffer_height - viewport_height) / 2; |  | ||||||
|         viewport_extent.right = viewport_extent.left + framebuffer_width; |  | ||||||
|         viewport_extent.bottom = viewport_extent.top + viewport_height; |  | ||||||
|     } else { |  | ||||||
|         // Otherwise, apply borders to the left and right sides of the window.
 |  | ||||||
|         unsigned viewport_width = static_cast<unsigned>(std::round(framebuffer_height / emulation_aspect_ratio)); |  | ||||||
|         viewport_extent.left = (framebuffer_width - viewport_width) / 2; |  | ||||||
|         viewport_extent.top = 0; |  | ||||||
|         viewport_extent.right = viewport_extent.left + viewport_width; |  | ||||||
|         viewport_extent.bottom = viewport_extent.top + framebuffer_height; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return viewport_extent; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// Initialize the renderer
 | /// Initialize the renderer
 | ||||||
| void RendererOpenGL::Init() { | void RendererOpenGL::Init() { | ||||||
|     render_window->MakeCurrent(); |     render_window->MakeCurrent(); | ||||||
|  |  | ||||||
|  | @ -18,7 +18,6 @@ namespace VideoCore { | ||||||
| 
 | 
 | ||||||
| EmuWindow*      g_emu_window    = nullptr;     ///< Frontend emulator window
 | EmuWindow*      g_emu_window    = nullptr;     ///< Frontend emulator window
 | ||||||
| RendererBase*   g_renderer      = nullptr;     ///< Renderer plugin
 | RendererBase*   g_renderer      = nullptr;     ///< Renderer plugin
 | ||||||
| int             g_current_frame = 0; |  | ||||||
| 
 | 
 | ||||||
| /// Initialize the video core
 | /// Initialize the video core
 | ||||||
| void Init(EmuWindow* emu_window) { | void Init(EmuWindow* emu_window) { | ||||||
|  | @ -27,8 +26,6 @@ void Init(EmuWindow* emu_window) { | ||||||
|     g_renderer->SetWindow(g_emu_window); |     g_renderer->SetWindow(g_emu_window); | ||||||
|     g_renderer->Init(); |     g_renderer->Init(); | ||||||
| 
 | 
 | ||||||
|     g_current_frame = 0; |  | ||||||
| 
 |  | ||||||
|     LOG_DEBUG(Render, "initialized OK"); |     LOG_DEBUG(Render, "initialized OK"); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -30,7 +30,6 @@ static const int kScreenBottomHeight    = 240;  ///< 3DS bottom screen height | ||||||
| // ---------------------
 | // ---------------------
 | ||||||
| 
 | 
 | ||||||
| extern RendererBase*   g_renderer;              ///< Renderer plugin
 | extern RendererBase*   g_renderer;              ///< Renderer plugin
 | ||||||
| extern int             g_current_frame;         ///< Current frame
 |  | ||||||
| extern EmuWindow*      g_emu_window;            ///< Emu window
 | extern EmuWindow*      g_emu_window;            ///< Emu window
 | ||||||
| 
 | 
 | ||||||
| /// Start the video core
 | /// Start the video core
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue