mirror of
https://github.com/moonlight-stream/moonlight-qt.git
synced 2025-07-01 15:26:09 +00:00
Add a new prepareToRender() callback for renders to perform their initial window clears
This consolidates all the clearing that was strewn across the codebase.
This commit is contained in:
parent
1d1fa0577b
commit
e76780e105
@ -1802,24 +1802,6 @@ void Session::execInternal()
|
||||
FillRect(info.info.win.hdc, &clientRect, blackBrush);
|
||||
DeleteObject(blackBrush);
|
||||
}
|
||||
#else
|
||||
if (strcmp(SDL_GetCurrentVideoDriver(), "KMSDRM") == 0) {
|
||||
// Create a dummy renderer to force SDL to complete the modesetting
|
||||
// operation that the KMSDRM backend keeps pending until the next
|
||||
// time we swap buffers.
|
||||
SDL_Renderer* renderer = SDL_CreateRenderer(m_Window, -1, SDL_RENDERER_SOFTWARE);
|
||||
if (renderer != nullptr) {
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderPresent(renderer);
|
||||
SDL_DestroyRenderer(renderer);
|
||||
}
|
||||
else {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_CreateRenderer() for KMSDRM modesetting failed: %s",
|
||||
SDL_GetError());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -47,6 +47,7 @@ extern "C" {
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "streaming/streamutils.h"
|
||||
#include "streaming/session.h"
|
||||
|
||||
#include <Limelight.h>
|
||||
|
||||
@ -178,6 +179,43 @@ bool DrmRenderer::prepareDecoderContext(AVCodecContext* context, AVDictionary**
|
||||
return true;
|
||||
}
|
||||
|
||||
void DrmRenderer::prepareToRender()
|
||||
{
|
||||
// Create a dummy renderer to force SDL to complete the modesetting
|
||||
// operation that the KMSDRM backend keeps pending until the next
|
||||
// time we swap buffers. We have to do this before we enumerate
|
||||
// CRTC modes below.
|
||||
SDL_Renderer* renderer = SDL_CreateRenderer(params->window, -1, SDL_RENDERER_SOFTWARE);
|
||||
if (renderer != nullptr) {
|
||||
// SDL_CreateRenderer() can end up having to recreate our window (SDL_RecreateWindow())
|
||||
// to ensure it's compatible with the renderer's OpenGL context. If that happens, we
|
||||
// can get spurious SDL_WINDOWEVENT events that will cause us to (again) recreate our
|
||||
// renderer. This can lead to an infinite to renderer recreation, so discard all
|
||||
// SDL_WINDOWEVENT events after SDL_CreateRenderer().
|
||||
Session* session = Session::get();
|
||||
if (session != nullptr) {
|
||||
// If we get here during a session, we need to synchronize with the event loop
|
||||
// to ensure we don't drop any important events.
|
||||
session->flushWindowEvents();
|
||||
}
|
||||
else {
|
||||
// If we get here prior to the start of a session, just pump and flush ourselves.
|
||||
SDL_PumpEvents();
|
||||
SDL_FlushEvent(SDL_WINDOWEVENT);
|
||||
}
|
||||
|
||||
SDL_SetRenderDrawColor(renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
|
||||
SDL_RenderClear(renderer);
|
||||
SDL_RenderPresent(renderer);
|
||||
SDL_DestroyRenderer(renderer);
|
||||
}
|
||||
else {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_CreateRenderer() failed: %s",
|
||||
SDL_GetError());
|
||||
}
|
||||
}
|
||||
|
||||
bool DrmRenderer::getPropertyByName(drmModeObjectPropertiesPtr props, const char* name, uint64_t *value) {
|
||||
for (uint32_t j = 0; j < props->count_props; j++) {
|
||||
drmModePropertyPtr prop = drmModeGetProperty(m_DrmFd, props->props[j]);
|
||||
|
@ -52,6 +52,7 @@ public:
|
||||
virtual ~DrmRenderer() override;
|
||||
virtual bool initialize(PDECODER_PARAMETERS params) override;
|
||||
virtual bool prepareDecoderContext(AVCodecContext* context, AVDictionary** options) override;
|
||||
virtual void prepareToRender() override;
|
||||
virtual void renderFrame(AVFrame* frame) override;
|
||||
virtual enum AVPixelFormat getPreferredPixelFormat(int videoFormat) override;
|
||||
virtual bool isPixelFormatSupported(int videoFormat, AVPixelFormat pixelFormat) override;
|
||||
|
@ -691,13 +691,6 @@ bool EGLRenderer::initialize(PDECODER_PARAMETERS params)
|
||||
SDL_GL_SetSwapInterval(0);
|
||||
}
|
||||
|
||||
if (!params->testOnly) {
|
||||
// Draw a black frame until the video stream starts rendering
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
SDL_GL_SwapWindow(params->window);
|
||||
}
|
||||
|
||||
glGenTextures(EGL_MAX_PLANES, m_Textures);
|
||||
for (size_t i = 0; i < EGL_MAX_PLANES; ++i) {
|
||||
glBindTexture(GL_TEXTURE_EXTERNAL_OES, m_Textures[i]);
|
||||
@ -877,6 +870,18 @@ void EGLRenderer::waitToRender()
|
||||
}
|
||||
}
|
||||
|
||||
void EGLRenderer::prepareToRender()
|
||||
{
|
||||
SDL_GL_MakeCurrent(m_Window, m_Context);
|
||||
{
|
||||
// Draw a black frame until the video stream starts rendering
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
SDL_GL_SwapWindow(m_Window);
|
||||
}
|
||||
SDL_GL_MakeCurrent(m_Window, nullptr);
|
||||
}
|
||||
|
||||
void EGLRenderer::renderFrame(AVFrame* frame)
|
||||
{
|
||||
EGLImage imgs[EGL_MAX_PLANES];
|
||||
|
@ -14,6 +14,7 @@ public:
|
||||
virtual bool prepareDecoderContext(AVCodecContext* context, AVDictionary** options) override;
|
||||
virtual void cleanupRenderContext() override;
|
||||
virtual void waitToRender() override;
|
||||
virtual void prepareToRender() override;
|
||||
virtual void renderFrame(AVFrame* frame) override;
|
||||
virtual bool testRenderFrame(AVFrame* frame) override;
|
||||
virtual void notifyOverlayUpdated(Overlay::OverlayType) override;
|
||||
|
@ -59,6 +59,40 @@ bool MmalRenderer::prepareDecoderContext(AVCodecContext* context, AVDictionary**
|
||||
return true;
|
||||
}
|
||||
|
||||
void MmalRenderer::prepareToRender()
|
||||
{
|
||||
// Create a renderer and draw a black background for the area not covered by the MMAL overlay.
|
||||
// On the KMSDRM backend, this triggers the modeset that puts the CRTC into the mode we selected.
|
||||
m_BackgroundRenderer = SDL_CreateRenderer(m_Window, -1, SDL_RENDERER_SOFTWARE);
|
||||
if (m_BackgroundRenderer == nullptr) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_CreateRenderer() failed: %s",
|
||||
SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
// SDL_CreateRenderer() can end up having to recreate our window (SDL_RecreateWindow())
|
||||
// to ensure it's compatible with the renderer's OpenGL context. If that happens, we
|
||||
// can get spurious SDL_WINDOWEVENT events that will cause us to (again) recreate our
|
||||
// renderer. This can lead to an infinite to renderer recreation, so discard all
|
||||
// SDL_WINDOWEVENT events after SDL_CreateRenderer().
|
||||
Session* session = Session::get();
|
||||
if (session != nullptr) {
|
||||
// If we get here during a session, we need to synchronize with the event loop
|
||||
// to ensure we don't drop any important events.
|
||||
session->flushWindowEvents();
|
||||
}
|
||||
else {
|
||||
// If we get here prior to the start of a session, just pump and flush ourselves.
|
||||
SDL_PumpEvents();
|
||||
SDL_FlushEvent(SDL_WINDOWEVENT);
|
||||
}
|
||||
|
||||
SDL_SetRenderDrawColor(m_BackgroundRenderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
|
||||
SDL_RenderClear(m_BackgroundRenderer);
|
||||
SDL_RenderPresent(m_BackgroundRenderer);
|
||||
}
|
||||
|
||||
void MmalRenderer::updateDisplayRegion()
|
||||
{
|
||||
MMAL_STATUS_T status;
|
||||
@ -124,9 +158,6 @@ bool MmalRenderer::initialize(PDECODER_PARAMETERS params)
|
||||
m_VideoWidth = params->width;
|
||||
m_VideoHeight = params->height;
|
||||
|
||||
// Clear the background if possible
|
||||
setupBackground(params);
|
||||
|
||||
status = mmal_component_create(MMAL_COMPONENT_DEFAULT_VIDEO_RENDERER, &m_Renderer);
|
||||
if (status != MMAL_SUCCESS) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
@ -217,42 +248,6 @@ int MmalRenderer::getDecoderColorspace()
|
||||
return COLORSPACE_REC_709;
|
||||
}
|
||||
|
||||
void MmalRenderer::setupBackground(PDECODER_PARAMETERS params)
|
||||
{
|
||||
if (!params->testOnly) {
|
||||
// Create a renderer and draw a black background for the area not covered by the MMAL overlay.
|
||||
// On the KMSDRM backend, this triggers the modeset that puts the CRTC into the mode we selected.
|
||||
m_BackgroundRenderer = SDL_CreateRenderer(params->window, -1, SDL_RENDERER_SOFTWARE);
|
||||
if (m_BackgroundRenderer == nullptr) {
|
||||
SDL_LogError(SDL_LOG_CATEGORY_APPLICATION,
|
||||
"SDL_CreateRenderer() failed: %s",
|
||||
SDL_GetError());
|
||||
return;
|
||||
}
|
||||
|
||||
// SDL_CreateRenderer() can end up having to recreate our window (SDL_RecreateWindow())
|
||||
// to ensure it's compatible with the renderer's OpenGL context. If that happens, we
|
||||
// can get spurious SDL_WINDOWEVENT events that will cause us to (again) recreate our
|
||||
// renderer. This can lead to an infinite to renderer recreation, so discard all
|
||||
// SDL_WINDOWEVENT events after SDL_CreateRenderer().
|
||||
Session* session = Session::get();
|
||||
if (session != nullptr) {
|
||||
// If we get here during a session, we need to synchronize with the event loop
|
||||
// to ensure we don't drop any important events.
|
||||
session->flushWindowEvents();
|
||||
}
|
||||
else {
|
||||
// If we get here prior to the start of a session, just pump and flush ourselves.
|
||||
SDL_PumpEvents();
|
||||
SDL_FlushEvent(SDL_WINDOWEVENT);
|
||||
}
|
||||
|
||||
SDL_SetRenderDrawColor(m_BackgroundRenderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
|
||||
SDL_RenderClear(m_BackgroundRenderer);
|
||||
SDL_RenderPresent(m_BackgroundRenderer);
|
||||
}
|
||||
}
|
||||
|
||||
void MmalRenderer::InputPortCallback(MMAL_PORT_T*, MMAL_BUFFER_HEADER_T* buffer)
|
||||
{
|
||||
mmal_buffer_header_release(buffer);
|
||||
|
@ -13,6 +13,7 @@ public:
|
||||
virtual ~MmalRenderer() override;
|
||||
virtual bool initialize(PDECODER_PARAMETERS params) override;
|
||||
virtual bool prepareDecoderContext(AVCodecContext* context, AVDictionary** options) override;
|
||||
virtual void prepareToRender() override;
|
||||
virtual void renderFrame(AVFrame* frame) override;
|
||||
virtual enum AVPixelFormat getPreferredPixelFormat(int videoFormat) override;
|
||||
virtual bool needsTestFrame() override;
|
||||
@ -23,8 +24,6 @@ private:
|
||||
static void InputPortCallback(MMAL_PORT_T* port, MMAL_BUFFER_HEADER_T* buffer);
|
||||
bool getDtDeviceStatus(QString name, bool ifUnknown);
|
||||
bool isMmalOverlaySupported();
|
||||
|
||||
void setupBackground(PDECODER_PARAMETERS params);
|
||||
void updateDisplayRegion();
|
||||
|
||||
MMAL_COMPONENT_T* m_Renderer;
|
||||
|
@ -256,6 +256,12 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual void prepareToRender() {
|
||||
// Allow renderers to perform any final preparations for
|
||||
// rendering after they have been selected to render. Such
|
||||
// preparations might include clearing the window.
|
||||
}
|
||||
|
||||
// Allow renderers to expose their type
|
||||
enum class RendererType {
|
||||
Unknown,
|
||||
|
@ -54,6 +54,14 @@ bool SdlRenderer::prepareDecoderContext(AVCodecContext*, AVDictionary**)
|
||||
return true;
|
||||
}
|
||||
|
||||
void SdlRenderer::prepareToRender()
|
||||
{
|
||||
// Draw a black frame until the video stream starts rendering
|
||||
SDL_SetRenderDrawColor(m_Renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
|
||||
SDL_RenderClear(m_Renderer);
|
||||
SDL_RenderPresent(m_Renderer);
|
||||
}
|
||||
|
||||
bool SdlRenderer::isRenderThreadSupported()
|
||||
{
|
||||
SDL_RendererInfo info;
|
||||
@ -165,13 +173,6 @@ bool SdlRenderer::initialize(PDECODER_PARAMETERS params)
|
||||
SDL_FlushEvent(SDL_WINDOWEVENT);
|
||||
}
|
||||
|
||||
if (!params->testOnly) {
|
||||
// Draw a black frame until the video stream starts rendering
|
||||
SDL_SetRenderDrawColor(m_Renderer, 0, 0, 0, SDL_ALPHA_OPAQUE);
|
||||
SDL_RenderClear(m_Renderer);
|
||||
SDL_RenderPresent(m_Renderer);
|
||||
}
|
||||
|
||||
#ifdef Q_OS_WIN32
|
||||
// For some reason, using Direct3D9Ex breaks this with multi-monitor setups.
|
||||
// When focus is lost, the window is minimized then immediately restored without
|
||||
|
@ -13,6 +13,7 @@ public:
|
||||
virtual ~SdlRenderer() override;
|
||||
virtual bool initialize(PDECODER_PARAMETERS params) override;
|
||||
virtual bool prepareDecoderContext(AVCodecContext* context, AVDictionary** options) override;
|
||||
virtual void prepareToRender() override;
|
||||
virtual void renderFrame(AVFrame* frame) override;
|
||||
virtual bool isRenderThreadSupported() override;
|
||||
virtual bool isPixelFormatSupported(int videoFormat, enum AVPixelFormat pixelFormat) override;
|
||||
|
@ -600,6 +600,9 @@ bool FFmpegVideoDecoder::completeInitialization(const AVCodec* decoder, enum AVP
|
||||
// Tell overlay manager to use this frontend renderer
|
||||
Session::get()->getOverlayManager().setOverlayRenderer(m_FrontendRenderer);
|
||||
|
||||
// Allow the renderer to perform final preparations for rendering
|
||||
m_FrontendRenderer->prepareToRender();
|
||||
|
||||
// Only create the decoder thread when instantiating the decoder for real. It will use APIs from
|
||||
// moonlight-common-c that can only be legally called with an established connection.
|
||||
m_DecoderThread = SDL_CreateThread(FFmpegVideoDecoder::decoderThreadProcThunk, "FFDecoder", (void*)this);
|
||||
|
Loading…
x
Reference in New Issue
Block a user