2 * Copyright (C) 2017-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
11 #include "IRenderManager.h"
12 #include "RenderVideoSettings.h"
13 #include "cores/RetroPlayer/guibridge/IRenderCallback.h"
14 #include "threads/CriticalSection.h"
18 #include <libavutil/pixfmt.h>
35 class CGUIRenderTargetFactory
;
37 class CRenderSettings
;
38 class CRPBaseRenderer
;
40 class IGUIRenderSettings
;
42 class IRenderBufferPool
;
44 struct VideoStreamBuffer
;
47 * \brief Renders video frames provided by the game loop
49 * Generally, buffer pools are registered by the windowing subsystem. A buffer
50 * pool provides a software or hardware buffer to store the added frame. When
51 * RenderManager is created, it instantiates all registered buffer pools.
53 * When a frame arrives, it is copied into a buffer from each buffer pool with
54 * a visible renderer. For example, if a GLES and MMAL renderer are both
55 * visible in the GUI, then the frame will be copied into two buffers.
57 * When it is time to render the frame, the GUI control or window calls into
58 * this class through the IRenderManager interface. RenderManager selects an
59 * appropriate renderer to use to render the frame. The renderer is then
60 * given the buffer that came from its buffer pool.
62 * Special behavior is needed when the game is paused. As no new frames are
63 * delivered, a newly created renderer will stay black. For this scenario,
64 * when we detect a pause event, the frame is preemptively cached so that a
65 * newly created renderer will have something to display.
67 class CRPRenderManager
: public IRenderManager
, public IRenderCallback
70 CRPRenderManager(CRPProcessInfo
& processInfo
);
71 ~CRPRenderManager() override
= default;
77 * \brief Access the factory for creating GUI render targets
79 CGUIRenderTargetFactory
* GetGUIRenderTargetFactory() { return m_renderControlFactory
.get(); }
81 // Stream properties, set upon configuration
82 AVPixelFormat
GetPixelFormat() const { return m_format
; }
83 unsigned int GetNominalWidth() const { return m_nominalWidth
; }
84 unsigned int GetNominalHeight() const { return m_nominalHeight
; }
85 unsigned int GetMaxWidth() const { return m_maxWidth
; }
86 unsigned int GetMaxHeight() const { return m_maxHeight
; }
87 float GetPixelAspectRatio() const { return m_pixelAspectRatio
; }
89 // Functions called from game loop
90 bool Configure(AVPixelFormat format
,
91 unsigned int nominalWidth
,
92 unsigned int nominalHeight
,
93 unsigned int maxWidth
,
94 unsigned int maxHeight
,
95 float pixelAspectRatio
);
96 bool GetVideoBuffer(unsigned int width
, unsigned int height
, VideoStreamBuffer
& buffer
);
97 void AddFrame(const uint8_t* data
,
101 unsigned int orientationDegCW
);
104 // Functions called from the player
105 void SetSpeed(double speed
);
107 // Functions called from render thread
110 // Implementation of IRenderManager
111 void RenderWindow(bool bClear
, const RESOLUTION_INFO
& coordsRes
) override
;
112 void RenderControl(bool bClear
,
114 const CRect
& renderRegion
,
115 const IGUIRenderSettings
* renderSettings
) override
;
116 void ClearBackground() override
;
118 // Implementation of IRenderCallback
119 bool SupportsRenderFeature(RENDERFEATURE feature
) const override
;
120 bool SupportsScalingMethod(SCALINGMETHOD method
) const override
;
122 // Savestate functions
123 void SaveThumbnail(const std::string
& thumbnailPath
);
125 // Savestate functions
126 void CacheVideoFrame(const std::string
& savestatePath
);
127 void SaveVideoFrame(const std::string
& savestatePath
, ISavestate
& savestate
);
128 void ClearVideoFrame(const std::string
& savestatePath
);
132 * \brief Get or create a renderer compatible with the given render settings
134 std::shared_ptr
<CRPBaseRenderer
> GetRendererForSettings(const IGUIRenderSettings
* renderSettings
);
137 * \brief Get or create a renderer for the given buffer pool and render settings
139 std::shared_ptr
<CRPBaseRenderer
> GetRendererForPool(IRenderBufferPool
* bufferPool
,
140 const CRenderSettings
& renderSettings
);
143 * \brief Render a frame using the given renderer
145 void RenderInternal(const std::shared_ptr
<CRPBaseRenderer
>& renderer
,
146 IRenderBuffer
* renderBuffer
,
151 * \brief Return true if we have a render buffer belonging to the specified pool
153 bool HasRenderBuffer(IRenderBufferPool
* bufferPool
);
156 * \brief Get a render buffer belonging to the specified pool
158 IRenderBuffer
* GetRenderBuffer(IRenderBufferPool
* bufferPool
);
161 * \brief Get a render buffer containing pixels from the specified savestate
163 IRenderBuffer
* GetRenderBufferForSavestate(const std::string
& savestatePath
,
164 const IRenderBufferPool
* bufferPool
);
167 * \brief Create a render buffer for the specified pool from a cached frame
169 void CreateRenderBuffer(IRenderBufferPool
* bufferPool
);
172 * \brief Create a render buffer and copy the cached data into it
174 * The cached frame is accessed by both the game and rendering threads,
175 * and therefore requires synchronization.
177 * However, assuming the memory copy is expensive, we must avoid holding
178 * the mutex during the copy.
180 * To allow for this, the function is permitted to invalidate its
181 * cachedFrame parameter, as long as it is restored upon exit. While the
182 * mutex is exited inside this function, cachedFrame is guaranteed to be
185 * \param cachedFrame The cached frame
186 * \param width The width of the cached frame
187 * \param height The height of the cached frame
188 * \param bufferPool The buffer pool used to create the render buffer
189 * \param mutex The locked mutex, to be unlocked during memory copy
191 * \return The render buffer if one was created from the cached frame,
194 IRenderBuffer
* CreateFromCache(std::vector
<uint8_t>& cachedFrame
,
197 IRenderBufferPool
* bufferPool
,
198 CCriticalSection
& mutex
);
201 * \brief Utility function to copy a frame and rescale pixels if necessary
203 void CopyFrame(IRenderBuffer
* renderBuffer
,
204 AVPixelFormat format
,
208 unsigned int height
);
210 CRenderVideoSettings
GetEffectiveSettings(const IGUIRenderSettings
* settings
) const;
214 void GetVideoFrame(IRenderBuffer
*& readableBuffer
, std::vector
<uint8_t>& cachedFrame
);
215 void FreeVideoFrame(IRenderBuffer
* readableBuffer
, std::vector
<uint8_t> cachedFrame
);
216 void LoadVideoFrameAsync(const std::string
& savestatePath
);
217 void LoadVideoFrameSync(const std::string
& savestatePath
);
219 // Construction parameters
220 CRPProcessInfo
& m_processInfo
;
221 CRenderContext
& m_renderContext
;
224 std::shared_ptr
<IGUIRenderSettings
> m_renderSettings
;
225 std::shared_ptr
<CGUIRenderTargetFactory
> m_renderControlFactory
;
228 AVPixelFormat m_format
= AV_PIX_FMT_NONE
;
229 unsigned int m_nominalWidth
{0};
230 unsigned int m_nominalHeight
{0};
231 unsigned int m_maxWidth
= 0;
232 unsigned int m_maxHeight
= 0;
233 float m_pixelAspectRatio
{1.0f
};
236 std::set
<std::shared_ptr
<CRPBaseRenderer
>> m_renderers
;
237 std::vector
<IRenderBuffer
*> m_pendingBuffers
; // Only access from game thread
238 std::vector
<IRenderBuffer
*> m_renderBuffers
;
239 std::map
<AVPixelFormat
, std::map
<AVPixelFormat
, SwsContext
*>> m_scalers
; // From -> to -> context
240 std::vector
<uint8_t> m_cachedFrame
;
241 unsigned int m_cachedWidth
= 0;
242 unsigned int m_cachedHeight
= 0;
243 unsigned int m_cachedRotationCCW
{0};
244 std::map
<std::string
, std::vector
<IRenderBuffer
*>>
245 m_savestateBuffers
; // Render buffers for savestates
246 std::vector
<std::future
<void>> m_savestateThreads
;
249 enum class RENDER_STATE
255 RENDER_STATE m_state
= RENDER_STATE::UNCONFIGURED
;
256 bool m_bHasCachedFrame
= false; // Invariant: m_cachedFrame is empty if false
257 std::set
<std::string
> m_failedShaderPresets
;
258 std::atomic
<bool> m_bFlush
= {false};
261 bool m_bDisplayScaleSet
= false;
263 // Playback parameters
264 std::atomic
<double> m_speed
= {1.0};
266 // Synchronization parameters
267 CCriticalSection m_stateMutex
;
268 CCriticalSection m_bufferMutex
;