Merge pull request #4940 from jroweboy/presentation-thread
Split Presentation thread from Render thread
This commit is contained in:
commit
439d550850
27 changed files with 899 additions and 243 deletions
|
@ -10,6 +10,8 @@
|
|||
|
||||
namespace Frontend {
|
||||
|
||||
GraphicsContext::~GraphicsContext() = default;
|
||||
|
||||
class EmuWindow::TouchState : public Input::Factory<Input::TouchDevice>,
|
||||
public std::enable_shared_from_this<TouchState> {
|
||||
public:
|
||||
|
|
|
@ -12,6 +12,61 @@
|
|||
|
||||
namespace Frontend {
|
||||
|
||||
struct Frame;
|
||||
/**
|
||||
* For smooth Vsync rendering, we want to always present the latest frame that the core generates,
|
||||
* but also make sure that rendering happens at the pace that the frontend dictates. This is a
|
||||
* helper class that the renderer can define to sync frames between the render thread and the
|
||||
* presentation thread
|
||||
*/
|
||||
class TextureMailbox {
|
||||
public:
|
||||
virtual ~TextureMailbox() = default;
|
||||
|
||||
/**
|
||||
* Recreate the render objects attached to this frame with the new specified width/height
|
||||
*/
|
||||
virtual void ReloadRenderFrame(Frontend::Frame* frame, u32 width, u32 height) = 0;
|
||||
|
||||
/**
|
||||
* Recreate the presentation objects attached to this frame with the new specified width/height
|
||||
*/
|
||||
virtual void ReloadPresentFrame(Frontend::Frame* frame, u32 width, u32 height) = 0;
|
||||
|
||||
/**
|
||||
* Render thread calls this to get an available frame to present
|
||||
*/
|
||||
virtual Frontend::Frame* GetRenderFrame() = 0;
|
||||
|
||||
/**
|
||||
* Render thread calls this after draw commands are done to add to the presentation mailbox
|
||||
*/
|
||||
virtual void ReleaseRenderFrame(Frame* frame) = 0;
|
||||
|
||||
/**
|
||||
* Presentation thread calls this to get the latest frame available to present. If there is no
|
||||
* frame available after timeout, returns the previous frame. If there is no previous frame it
|
||||
* returns nullptr
|
||||
*/
|
||||
virtual Frontend::Frame* TryGetPresentFrame(int timeout_ms) = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Represents a graphics context that can be used for background computation or drawing. If the
|
||||
* graphics backend doesn't require the context, then the implementation of these methods can be
|
||||
* stubs
|
||||
*/
|
||||
class GraphicsContext {
|
||||
public:
|
||||
virtual ~GraphicsContext();
|
||||
|
||||
/// Makes the graphics context current for the caller thread
|
||||
virtual void MakeCurrent() = 0;
|
||||
|
||||
/// Releases (dunno if this is the "right" word) the context from the caller thread
|
||||
virtual void DoneCurrent() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Abstraction class used to provide an interface between emulation code and the frontend
|
||||
* (e.g. SDL, QGLWidget, GLFW, etc...).
|
||||
|
@ -30,7 +85,7 @@ namespace Frontend {
|
|||
* - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please
|
||||
* re-read the upper points again and think about it if you don't see this.
|
||||
*/
|
||||
class EmuWindow {
|
||||
class EmuWindow : public GraphicsContext {
|
||||
public:
|
||||
/// Data structure to store emuwindow configuration
|
||||
struct WindowConfig {
|
||||
|
@ -40,17 +95,21 @@ public:
|
|||
std::pair<unsigned, unsigned> min_client_area_size;
|
||||
};
|
||||
|
||||
/// Swap buffers to display the next frame
|
||||
virtual void SwapBuffers() = 0;
|
||||
|
||||
/// Polls window events
|
||||
virtual void PollEvents() = 0;
|
||||
|
||||
/// Makes the graphics context current for the caller thread
|
||||
virtual void MakeCurrent() = 0;
|
||||
|
||||
/// Releases (dunno if this is the "right" word) the GLFW context from the caller thread
|
||||
virtual void DoneCurrent() = 0;
|
||||
/**
|
||||
* Returns a GraphicsContext that the frontend provides that is shared with the emu window. This
|
||||
* context can be used from other threads for background graphics computation. If the frontend
|
||||
* is using a graphics backend that doesn't need anything specific to run on a different thread,
|
||||
* then it can use a stubbed implemenation for GraphicsContext.
|
||||
*
|
||||
* If the return value is null, then the core should assume that the frontend cannot provide a
|
||||
* Shared Context
|
||||
*/
|
||||
virtual std::unique_ptr<GraphicsContext> CreateSharedContext() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Signal that a touch pressed event has occurred (e.g. mouse click pressed)
|
||||
|
@ -102,6 +161,8 @@ public:
|
|||
*/
|
||||
void UpdateCurrentFramebufferLayout(unsigned width, unsigned height);
|
||||
|
||||
std::unique_ptr<TextureMailbox> mailbox = nullptr;
|
||||
|
||||
protected:
|
||||
EmuWindow();
|
||||
virtual ~EmuWindow();
|
||||
|
@ -131,15 +192,6 @@ protected:
|
|||
framebuffer_layout = layout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update internal client area size with the given parameter.
|
||||
* @note EmuWindow implementations will usually use this in window resize event handlers.
|
||||
*/
|
||||
void NotifyClientAreaSizeChanged(const std::pair<unsigned, unsigned>& size) {
|
||||
client_area_width = size.first;
|
||||
client_area_height = size.second;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* Handler called when the minimal client area was requested to be changed via SetConfig.
|
||||
|
@ -152,9 +204,6 @@ private:
|
|||
|
||||
Layout::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.
|
||||
|
||||
WindowConfig config; ///< Internal configuration (changes pending for being applied in
|
||||
/// ProcessConfigurationChanges)
|
||||
WindowConfig active_config; ///< Internal active configuration
|
||||
|
|
17
src/core/frontend/scope_acquire_context.cpp
Normal file
17
src/core/frontend/scope_acquire_context.cpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/frontend/scope_acquire_context.h"
|
||||
|
||||
namespace Frontend {
|
||||
|
||||
ScopeAcquireContext::ScopeAcquireContext(Frontend::GraphicsContext& context) : context{context} {
|
||||
context.MakeCurrent();
|
||||
}
|
||||
ScopeAcquireContext::~ScopeAcquireContext() {
|
||||
context.DoneCurrent();
|
||||
}
|
||||
|
||||
} // namespace Frontend
|
23
src/core/frontend/scope_acquire_context.h
Normal file
23
src/core/frontend/scope_acquire_context.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
// Copyright 2019 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Frontend {
|
||||
|
||||
class GraphicsContext;
|
||||
|
||||
/// Helper class to acquire/release window context within a given scope
|
||||
class ScopeAcquireContext : NonCopyable {
|
||||
public:
|
||||
explicit ScopeAcquireContext(Frontend::GraphicsContext& context);
|
||||
~ScopeAcquireContext();
|
||||
|
||||
private:
|
||||
Frontend::GraphicsContext& context;
|
||||
};
|
||||
|
||||
} // namespace Frontend
|
Loading…
Add table
Add a link
Reference in a new issue