You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#jira UE-151907 #rb mihnea.balta #preflight 627e751b7c26e2477354c142 [CL 20182229 by christopher waters in ue5-main branch]
339 lines
9.7 KiB
C++
339 lines
9.7 KiB
C++
// Copyright Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
OpenGLViewport.cpp: OpenGL viewport RHI implementation.
|
|
=============================================================================*/
|
|
|
|
#include "CoreMinimal.h"
|
|
#include "Stats/Stats.h"
|
|
#include "HAL/IConsoleManager.h"
|
|
#include "RHI.h"
|
|
#include "OpenGLDrv.h"
|
|
#include "OpenGLDrvPrivate.h"
|
|
|
|
void FOpenGLDynamicRHI::RHIGetSupportedResolution(uint32 &Width, uint32 &Height)
|
|
{
|
|
PlatformGetSupportedResolution(Width, Height);
|
|
}
|
|
|
|
bool FOpenGLDynamicRHI::RHIGetAvailableResolutions(FScreenResolutionArray& Resolutions, bool bIgnoreRefreshRate)
|
|
{
|
|
const bool Result = PlatformGetAvailableResolutions(Resolutions, bIgnoreRefreshRate);
|
|
if (Result)
|
|
{
|
|
Resolutions.Sort([](const FScreenResolutionRHI& L, const FScreenResolutionRHI& R)
|
|
{
|
|
if (L.Width != R.Width)
|
|
{
|
|
return L.Width < R.Width;
|
|
}
|
|
else if (L.Height != R.Height)
|
|
{
|
|
return L.Height < R.Height;
|
|
}
|
|
else
|
|
{
|
|
return L.RefreshRate < R.RefreshRate;
|
|
}
|
|
});
|
|
}
|
|
return Result;
|
|
}
|
|
|
|
/*=============================================================================
|
|
* The following RHI functions must be called from the main thread.
|
|
*=============================================================================*/
|
|
FViewportRHIRef FOpenGLDynamicRHI::RHICreateViewport(void* WindowHandle,uint32 SizeX,uint32 SizeY,bool bIsFullscreen,EPixelFormat PreferredPixelFormat)
|
|
{
|
|
check(IsInGameThread());
|
|
|
|
// SCOPED_SUSPEND_RENDERING_THREAD(true);
|
|
|
|
// Use a default pixel format if none was specified
|
|
PreferredPixelFormat = RHIPreferredPixelFormatHint(PreferredPixelFormat);
|
|
|
|
return new FOpenGLViewport(this,WindowHandle,SizeX,SizeY,bIsFullscreen,PreferredPixelFormat);
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::RHIResizeViewport(FRHIViewport* ViewportRHI,uint32 SizeX,uint32 SizeY,bool bIsFullscreen)
|
|
{
|
|
FOpenGLViewport* Viewport = ResourceCast(ViewportRHI);
|
|
check( IsInGameThread() );
|
|
|
|
// SCOPED_SUSPEND_RENDERING_THREAD(true);
|
|
|
|
Viewport->Resize(SizeX,SizeY,bIsFullscreen);
|
|
}
|
|
|
|
EPixelFormat FOpenGLDynamicRHI::RHIPreferredPixelFormatHint(EPixelFormat PreferredPixelFormat)
|
|
{
|
|
return FOpenGL::PreferredPixelFormatHint(PreferredPixelFormat);
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::RHITick( float DeltaTime )
|
|
{
|
|
}
|
|
|
|
/*=============================================================================
|
|
* Viewport functions.
|
|
*=============================================================================*/
|
|
|
|
void FOpenGLDynamicRHI::RHIBeginDrawingViewport(FRHIViewport* ViewportRHI, FRHITexture* RenderTarget)
|
|
{
|
|
VERIFY_GL_SCOPE();
|
|
|
|
FOpenGLViewport* Viewport = ResourceCast(ViewportRHI);
|
|
|
|
SCOPE_CYCLE_COUNTER(STAT_OpenGLPresentTime);
|
|
|
|
check(!DrawingViewport);
|
|
DrawingViewport = Viewport;
|
|
|
|
bRevertToSharedContextAfterDrawingViewport = false;
|
|
EOpenGLCurrentContext CurrentContext = PlatformOpenGLCurrentContext( PlatformDevice );
|
|
if( CurrentContext != CONTEXT_Rendering )
|
|
{
|
|
check(CurrentContext == CONTEXT_Shared);
|
|
check(!bIsRenderingContextAcquired || !GUseThreadedRendering);
|
|
|
|
bRevertToSharedContextAfterDrawingViewport = true;
|
|
PlatformRenderingContextSetup(PlatformDevice);
|
|
}
|
|
|
|
// Set the render target and viewport.
|
|
if( RenderTarget )
|
|
{
|
|
FRHIRenderTargetView RTV(RenderTarget, ERenderTargetLoadAction::ELoad);
|
|
SetRenderTargets(1, &RTV, nullptr);
|
|
}
|
|
else
|
|
{
|
|
FRHIRenderTargetView RTV(DrawingViewport->GetBackBuffer(), ERenderTargetLoadAction::ELoad);
|
|
SetRenderTargets(1, &RTV, nullptr);
|
|
}
|
|
|
|
if (IsValidRef(CustomPresent))
|
|
{
|
|
CustomPresent->BeginDrawing();
|
|
}
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::RHIEndDrawingViewport(FRHIViewport* ViewportRHI,bool bPresent,bool bLockToVsync)
|
|
{
|
|
VERIFY_GL_SCOPE();
|
|
|
|
FOpenGLViewport* Viewport = ResourceCast(ViewportRHI);
|
|
|
|
SCOPE_CYCLE_COUNTER(STAT_OpenGLPresentTime);
|
|
uint32 IdleStart = FPlatformTime::Cycles();
|
|
|
|
|
|
check(DrawingViewport.GetReference() == Viewport);
|
|
|
|
FOpenGLTexture* BackBuffer = Viewport->GetBackBuffer();
|
|
|
|
FOpenGLContextState& ContextState = GetContextStateForCurrentContext();
|
|
|
|
if (ContextState.bScissorEnabled)
|
|
{
|
|
ContextState.bScissorEnabled = false;
|
|
glDisable(GL_SCISSOR_TEST);
|
|
}
|
|
|
|
bool bNeedFinishFrame = PlatformBlitToViewport(PlatformDevice,
|
|
*Viewport,
|
|
BackBuffer->GetSizeX(),
|
|
BackBuffer->GetSizeY(),
|
|
bPresent,
|
|
bLockToVsync
|
|
);
|
|
|
|
// Always consider the Framebuffer in the rendering context dirty after the blit
|
|
RenderingContextState.Framebuffer = -1;
|
|
|
|
DrawingViewport = NULL;
|
|
|
|
// Don't wait on the GPU when using SLI, let the driver determine how many frames behind the GPU should be allowed to get
|
|
if (GNumAlternateFrameRenderingGroups == 1)
|
|
{
|
|
if (bNeedFinishFrame)
|
|
{
|
|
static const auto CFinishFrameVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.FinishCurrentFrame"));
|
|
if (!CFinishFrameVar->GetValueOnRenderThread())
|
|
{
|
|
// Wait for the GPU to finish rendering the previous frame before finishing this frame.
|
|
Viewport->WaitForFrameEventCompletion();
|
|
Viewport->IssueFrameEvent();
|
|
}
|
|
else
|
|
{
|
|
// Finish current frame immediately to reduce latency
|
|
Viewport->IssueFrameEvent();
|
|
Viewport->WaitForFrameEventCompletion();
|
|
}
|
|
}
|
|
|
|
// If the input latency timer has been triggered, block until the GPU is completely
|
|
// finished displaying this frame and calculate the delta time.
|
|
if ( GInputLatencyTimer.RenderThreadTrigger )
|
|
{
|
|
Viewport->WaitForFrameEventCompletion();
|
|
uint32 EndTime = FPlatformTime::Cycles();
|
|
GInputLatencyTimer.DeltaTime = EndTime - GInputLatencyTimer.StartTime;
|
|
GInputLatencyTimer.RenderThreadTrigger = false;
|
|
}
|
|
}
|
|
|
|
if (bRevertToSharedContextAfterDrawingViewport)
|
|
{
|
|
PlatformSharedContextSetup(PlatformDevice);
|
|
bRevertToSharedContextAfterDrawingViewport = false;
|
|
}
|
|
uint32 ThisCycles = FPlatformTime::Cycles() - IdleStart;
|
|
if (IsInRHIThread())
|
|
{
|
|
GWorkingRHIThreadStallTime += ThisCycles;
|
|
}
|
|
else if (IsInActualRenderingThread())
|
|
{
|
|
GRenderThreadIdle[ERenderThreadIdleTypes::WaitingForGPUPresent] += ThisCycles;
|
|
GRenderThreadNumIdle[ERenderThreadIdleTypes::WaitingForGPUPresent]++;
|
|
}
|
|
|
|
// TODO: find better location to poll this, or create programs on separate thread. Gil had a prototype of this.
|
|
FOpenGLProgramBinaryCache::CheckPendingGLProgramCreateRequests();
|
|
|
|
FTextureEvictionLRU::Get().TickEviction();
|
|
}
|
|
|
|
|
|
FTexture2DRHIRef FOpenGLDynamicRHI::RHIGetViewportBackBuffer(FRHIViewport* ViewportRHI)
|
|
{
|
|
FOpenGLViewport* Viewport = ResourceCast(ViewportRHI);
|
|
return Viewport->GetBackBuffer();
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::RHIAdvanceFrameForGetViewportBackBuffer(FRHIViewport* Viewport)
|
|
{
|
|
}
|
|
|
|
|
|
FOpenGLViewport::FOpenGLViewport(FOpenGLDynamicRHI* InOpenGLRHI,void* InWindowHandle,uint32 InSizeX,uint32 InSizeY,bool bInIsFullscreen,EPixelFormat PreferredPixelFormat)
|
|
: OpenGLRHI(InOpenGLRHI)
|
|
, OpenGLContext(NULL)
|
|
, SizeX(0)
|
|
, SizeY(0)
|
|
, bIsFullscreen(false)
|
|
, PixelFormat(PreferredPixelFormat)
|
|
, bIsValid(true)
|
|
{
|
|
check(OpenGLRHI);
|
|
// @todo lumin: Add a "PLATFORM_HAS_NO_NATIVE_WINDOW" or something
|
|
#if !PLATFORM_ANDROID
|
|
check(InWindowHandle);
|
|
#endif
|
|
check(IsInGameThread());
|
|
|
|
// flush out old errors.
|
|
PlatformGlGetError();
|
|
|
|
OpenGLRHI->Viewports.Add(this);
|
|
|
|
check(PlatformOpenGLCurrentContext(OpenGLRHI->PlatformDevice) == CONTEXT_Shared);
|
|
|
|
OpenGLContext = PlatformCreateOpenGLContext(OpenGLRHI->PlatformDevice, InWindowHandle);
|
|
Resize(InSizeX, InSizeY, bInIsFullscreen);
|
|
|
|
check(PlatformOpenGLCurrentContext(OpenGLRHI->PlatformDevice) == CONTEXT_Shared);
|
|
|
|
ENQUEUE_RENDER_COMMAND(CreateFrameSyncEvent)([this](FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
RunOnGLRenderContextThread([this]()
|
|
{
|
|
FrameSyncEvent = MakeUnique<FOpenGLEventQuery>();
|
|
});
|
|
});
|
|
}
|
|
|
|
FOpenGLViewport::~FOpenGLViewport()
|
|
{
|
|
check(IsInRenderingThread() || IsInRHIThread());
|
|
|
|
if (bIsFullscreen)
|
|
{
|
|
PlatformRestoreDesktopDisplayMode();
|
|
}
|
|
|
|
// Release back buffer, before OpenGL context becomes invalid, making it impossible
|
|
BackBuffer.SafeRelease();
|
|
check(!IsValidRef(BackBuffer));
|
|
|
|
RunOnGLRenderContextThread([&]()
|
|
{
|
|
FrameSyncEvent = nullptr;
|
|
PlatformDestroyOpenGLContext(OpenGLRHI->PlatformDevice, OpenGLContext);
|
|
}, true);
|
|
|
|
OpenGLContext = NULL;
|
|
OpenGLRHI->Viewports.Remove(this);
|
|
}
|
|
|
|
void FOpenGLViewport::WaitForFrameEventCompletion()
|
|
{
|
|
VERIFY_GL_SCOPE();
|
|
FrameSyncEvent->WaitForCompletion();
|
|
}
|
|
|
|
void FOpenGLViewport::IssueFrameEvent()
|
|
{
|
|
VERIFY_GL_SCOPE();
|
|
FrameSyncEvent->IssueEvent();
|
|
}
|
|
|
|
void FOpenGLViewport::Resize(uint32 InSizeX,uint32 InSizeY,bool bInIsFullscreen)
|
|
{
|
|
check(IsInGameThread());
|
|
if ((InSizeX == SizeX) && (InSizeY == SizeY) && (bInIsFullscreen == bIsFullscreen))
|
|
{
|
|
return;
|
|
}
|
|
|
|
SizeX = InSizeX;
|
|
SizeY = InSizeY;
|
|
bool bWasFullscreen = bIsFullscreen;
|
|
bIsFullscreen = bInIsFullscreen;
|
|
|
|
ENQUEUE_RENDER_COMMAND(ResizeViewport)([this, InSizeX, InSizeY, bInIsFullscreen, bWasFullscreen](FRHICommandListImmediate& RHICmdList)
|
|
{
|
|
if (IsValidRef(CustomPresent))
|
|
{
|
|
CustomPresent->OnBackBufferResize();
|
|
}
|
|
|
|
BackBuffer.SafeRelease(); // when the rest of the engine releases it, its framebuffers will be released too (those the engine knows about)
|
|
|
|
BackBuffer = PlatformCreateBuiltinBackBuffer(OpenGLRHI, InSizeX, InSizeY);
|
|
if (!BackBuffer)
|
|
{
|
|
const FRHITextureCreateDesc Desc =
|
|
FRHITextureCreateDesc::Create2D(TEXT("FOpenGLViewport"), InSizeX, InSizeY, PixelFormat)
|
|
.SetClearValue(FClearValueBinding::Transparent)
|
|
.SetFlags(ETextureCreateFlags::RenderTargetable | ETextureCreateFlags::ResolveTargetable)
|
|
.DetermineInititialState();
|
|
|
|
BackBuffer = new FOpenGLTexture(Desc);
|
|
}
|
|
|
|
RHICmdList.EnqueueLambda([=](FRHICommandListImmediate&)
|
|
{
|
|
PlatformResizeGLContext(OpenGLRHI->PlatformDevice, OpenGLContext, InSizeX, InSizeY, bInIsFullscreen, bWasFullscreen, BackBuffer->Target, BackBuffer->GetResource());
|
|
});
|
|
});
|
|
}
|
|
|
|
void* FOpenGLViewport::GetNativeWindow(void** AddParam) const
|
|
{
|
|
return PlatformGetWindow(OpenGLContext, AddParam);
|
|
}
|
|
|