mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Set framebuffer layout from EmuWindow.
This commit is contained in:
		
							parent
							
								
									8e4e28aacb
								
							
						
					
					
						commit
						9960c49c21
					
				
					 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) { | ||||
|     ASSERT(width > 0); | ||||
|     ASSERT(height > 0); | ||||
| 
 | ||||
|     GetEmuWindow(win)->NotifyFramebufferSizeChanged(std::pair<unsigned,unsigned>(width, height)); | ||||
|     GetEmuWindow(win)->NotifyFramebufferLayoutChanged(EmuWindow::FramebufferLayout::DefaultScreenLayout(width, 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.
 | ||||
|     //       Hence, we just ignore the corresponding EmuWindow hint.
 | ||||
| 
 | ||||
|     GetEmuWindow(win)->NotifyClientAreaSizeChanged(std::pair<unsigned,unsigned>(width, height)); | ||||
|     OnFramebufferResizeEvent(win, width, height); | ||||
| } | ||||
| 
 | ||||
| /// EmuWindow_GLFW constructor
 | ||||
|  |  | |||
|  | @ -155,6 +155,7 @@ GRenderWindow::GRenderWindow(QWidget* parent) : QWidget(parent), emu_thread(this | |||
| 
 | ||||
|     child = new GGLWidgetInternal(fmt, this); | ||||
|     QBoxLayout* layout = new QHBoxLayout(this); | ||||
| 
 | ||||
|     resize(VideoCore::kScreenTopWidth, VideoCore::kScreenTopHeight + VideoCore::kScreenBottomHeight); | ||||
|     layout->addWidget(child); | ||||
|     layout->setMargin(0); | ||||
|  | @ -234,7 +235,7 @@ void GRenderWindow::OnFramebufferSizeChanged() | |||
|     unsigned height = child->QPaintDevice::height(); | ||||
| #endif | ||||
| 
 | ||||
|     NotifyFramebufferSizeChanged(std::make_pair(width, height)); | ||||
|     NotifyFramebufferLayoutChanged(EmuWindow::FramebufferLayout::DefaultScreenLayout(width, height)); | ||||
| } | ||||
| 
 | ||||
| void GRenderWindow::BackupGeometry() | ||||
|  |  | |||
|  | @ -3,6 +3,7 @@ | |||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "emu_window.h" | ||||
| #include "video_core/video_core.h" | ||||
| 
 | ||||
| void EmuWindow::KeyPressed(KeyMap::HostDeviceKey key) { | ||||
|     Service::HID::PadState mapped_key = KeyMap::GetPadKey(key); | ||||
|  | @ -15,3 +16,52 @@ void EmuWindow::KeyReleased(KeyMap::HostDeviceKey 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/string_util.h" | ||||
| #include "common/key_map.h" | ||||
| #include "common/math_util.h" | ||||
| 
 | ||||
| /**
 | ||||
|  * 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; | ||||
|     }; | ||||
| 
 | ||||
|     /// 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
 | ||||
|     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 | ||||
|       */ | ||||
|     const std::pair<unsigned,unsigned> GetFramebufferSize() const { | ||||
|         return framebuffer_size; | ||||
|     const FramebufferLayout& GetFramebufferLayout() const { | ||||
|         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. | ||||
|      */ | ||||
|     void NotifyFramebufferSizeChanged(const std::pair<unsigned,unsigned>& size) { | ||||
|         framebuffer_size = size; | ||||
|     void NotifyFramebufferLayoutChanged(const FramebufferLayout& layout) { | ||||
|         framebuffer_layout = layout; | ||||
|     } | ||||
| 
 | ||||
|     /**
 | ||||
|  | @ -143,7 +161,7 @@ private: | |||
|         // 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_height;   ///< Current client height, should be set by window impl.
 | ||||
|  |  | |||
|  | @ -242,28 +242,26 @@ void RendererOpenGL::DrawSingleScreenRotated(const TextureInfo& texture, float x | |||
|  * Draws the emulated screens to the emulator window. | ||||
|  */ | ||||
| void RendererOpenGL::DrawScreens() { | ||||
|     auto viewport_extent = GetViewportExtent(); | ||||
|     glViewport(viewport_extent.left, viewport_extent.top, viewport_extent.GetWidth(), viewport_extent.GetHeight()); // TODO: Or bottom?
 | ||||
|     auto layout = render_window->GetFramebufferLayout(); | ||||
| 
 | ||||
|     glViewport(0, 0, layout.width, layout.height); | ||||
|     glClear(GL_COLOR_BUFFER_BIT); | ||||
| 
 | ||||
|     glUseProgram(program_id); | ||||
| 
 | ||||
|     // 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()); | ||||
| 
 | ||||
|     // Bind texture in Texture Unit 0
 | ||||
|     glActiveTexture(GL_TEXTURE0); | ||||
|     glUniform1i(uniform_color_texture, 0); | ||||
| 
 | ||||
|     const float max_width = std::max((float)VideoCore::kScreenTopWidth, (float)VideoCore::kScreenBottomWidth); | ||||
|     const float top_x = 0.5f * (max_width - VideoCore::kScreenTopWidth); | ||||
|     const float bottom_x = 0.5f * (max_width - VideoCore::kScreenBottomWidth); | ||||
| 
 | ||||
|     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); | ||||
|     DrawSingleScreenRotated(textures[0], (float)layout.top_screen.left, (float)layout.top_screen.top, | ||||
|         (float)layout.top_screen.GetWidth(), (float)layout.top_screen.GetHeight()); | ||||
|     DrawSingleScreenRotated(textures[1], (float)layout.bottom_screen.left,(float)layout.bottom_screen.top, | ||||
|         (float)layout.bottom_screen.GetWidth(), (float)layout.bottom_screen.GetHeight()); | ||||
| 
 | ||||
|     m_current_frame++; | ||||
| } | ||||
|  | @ -280,34 +278,6 @@ void RendererOpenGL::SetWindow(EmuWindow* 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
 | ||||
| void RendererOpenGL::Init() { | ||||
|     render_window->MakeCurrent(); | ||||
|  |  | |||
|  | @ -18,7 +18,6 @@ namespace VideoCore { | |||
| 
 | ||||
| EmuWindow*      g_emu_window    = nullptr;     ///< Frontend emulator window
 | ||||
| RendererBase*   g_renderer      = nullptr;     ///< Renderer plugin
 | ||||
| int             g_current_frame = 0; | ||||
| 
 | ||||
| /// Initialize the video core
 | ||||
| void Init(EmuWindow* emu_window) { | ||||
|  | @ -27,8 +26,6 @@ void Init(EmuWindow* emu_window) { | |||
|     g_renderer->SetWindow(g_emu_window); | ||||
|     g_renderer->Init(); | ||||
| 
 | ||||
|     g_current_frame = 0; | ||||
| 
 | ||||
|     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 int             g_current_frame;         ///< Current frame
 | ||||
| extern EmuWindow*      g_emu_window;            ///< Emu window
 | ||||
| 
 | ||||
| /// Start the video core
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue