You've already forked UnrealEngineUWP
mirror of
https://github.com/izzy2lost/UnrealEngineUWP.git
synced 2026-03-26 18:15:20 -07:00
#lockdown nick.penwarden ========================== MAJOR FEATURES + CHANGES ========================== Change 2854295 on 2016/02/03 by Gareth.Martin@gareth.martin Added support for Landscape grass to use the landscape's light/shadow maps (original github pull request #1798 by Frugality) Change 2875167 on 2016/02/21 by Rolando.Caloca@Home_DM DM - glslang Change 2875650 on 2016/02/22 by Rolando.Caloca@rolando.caloca_T3903_DM DM - Common RHI changes Change 2876429 on 2016/02/22 by Rolando.Caloca@rolando.caloca_T3903_DM DM - Initial rhi check-in. Tappy & SunTemple working on PC. #codereview Jack.Porter, Chris.Babcock, Josh.Adams Change 2876665 on 2016/02/22 by Rolando.Caloca@rolando.caloca_T3903_DM DM - Split Immediate command list off RHI Change 2881242 on 2016/02/25 by Jack.Porter@Jack.Porter_UE4_Stream changes to exclude LPV shaders from Vulkan (reapplied with edit instead of integrate records) Change 2881356 on 2016/02/25 by Jack.Porter@Jack.Porter_UE4_Stream Static shadowing + dynamic-object CSM Change 2881359 on 2016/02/25 by Jack.Porter@Jack.Porter_UE4_Stream Mobile GPU particles Change 2881360 on 2016/02/25 by Jack.Porter@Jack.Porter_UE4_Stream Planar reflections very WIP Change 2881363 on 2016/02/25 by Jack.Porter@Jack.Porter_UE4_Stream Separate Translucency very WIP Change 2881365 on 2016/02/25 by Jack.Porter@Jack.Porter_UE4_Stream ProtoStar engine changes Change 2881371 on 2016/02/25 by Jack.Porter@Jack.Porter_UE4_Stream HACK for Max Texture Samplers hardcoded to 8 on ES2 Should be cleaned up better with UE-24419. Change 2884295 on 2016/02/26 by Rolando.Caloca@rolando.caloca_T3903_DM DM - Integrate pipeline cache Change 2887043 on 2016/02/29 by Rolando.Caloca@Home_DM DM - Initial CCT support Change 2887572 on 2016/03/01 by Rolando.Caloca@rolando.caloca_T3903_DM DM - Empty bound shader states cache - Only used currently on Vulkan Change 2889114 on 2016/03/01 by Rolando.Caloca@Home_DM DM - Added GRHINeedsExtraDeletionLatency from 4.11 Change 2889115 on 2016/03/01 by Rolando.Caloca@Home_DM DM - Remove batched elements quads (was not been used at least since UE3!) Change 2895373 on 2016/03/04 by Rolando.Caloca@rolando.caloca_T3903_DM DM - Fence mgr (disabled) Change 2898926 on 2016/03/08 by Rolando.Caloca@rolando.caloca_T3903_DM DM - Resource management (disabled) Change 2899937 on 2016/03/08 by Rolando.Caloca@rolando.caloca_T3903_DM DM - Expand number of stencil op bits Change 2901132 on 2016/03/09 by Rolando.Caloca@rolando.caloca_T3903_DM DM - Add support for more MaxSimultaneousRenderTargets Change 2903074 on 2016/03/10 by Rolando.Caloca@rolando.caloca_T3903_DM DM - Support for 3d staging textures Change 2903211 on 2016/03/10 by Jack.Porter@Jack.Porter_UE4_Stream Vulkan RHI stub for new SharedResourceView RHI call Change 2904014 on 2016/03/10 by Rolando.Caloca@rolando.caloca_T3903_DM DM - SM4 preq Change 2905389 on 2016/03/11 by Jack.Porter@Jack.Porter_UE4_Stream Android Vulkan support initial checkin Change 2908458 on 2016/03/14 by Allan.Bentham@Dev-Mobile Reinstate vertex fog, fixes UE-28166 Change 2910294 on 2016/03/15 by Rolando.Caloca@rolando.caloca_T3903_DM DM - Use fence manager Change 2910801 on 2016/03/15 by Rolando.Caloca@rolando.caloca_T3903_DM DM - Descriptor pool [CL 2912606 by Peter Sauerbrei in Main branch]
1486 lines
55 KiB
C++
1486 lines
55 KiB
C++
// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
|
|
|
|
/*=============================================================================
|
|
OpenGLDevice.cpp: OpenGL device RHI implementation.
|
|
=============================================================================*/
|
|
|
|
#include "OpenGLDrvPrivate.h"
|
|
|
|
#include "HardwareInfo.h"
|
|
#include "ShaderCache.h"
|
|
|
|
#ifndef GL_STEREO
|
|
#define GL_STEREO 0x0C33
|
|
#endif
|
|
|
|
extern GLint GMaxOpenGLColorSamples;
|
|
extern GLint GMaxOpenGLDepthSamples;
|
|
extern GLint GMaxOpenGLIntegerSamples;
|
|
extern GLint GMaxOpenGLTextureFilterAnisotropic;
|
|
|
|
/** OpenGL texture format table. */
|
|
FOpenGLTextureFormat GOpenGLTextureFormats[PF_MAX];
|
|
|
|
/** Device is necessary for vertex buffers, so they can reach the global device on destruction, and tell it to reset vertex array caches */
|
|
static FOpenGLDynamicRHI* PrivateOpenGLDevicePtr = NULL;
|
|
|
|
/** true if we're not using UBOs. (ES2) */
|
|
bool GUseEmulatedUniformBuffers;
|
|
|
|
void OnQueryCreation( FOpenGLRenderQuery* Query )
|
|
{
|
|
check(PrivateOpenGLDevicePtr);
|
|
PrivateOpenGLDevicePtr->RegisterQuery( Query );
|
|
}
|
|
|
|
void OnQueryDeletion( FOpenGLRenderQuery* Query )
|
|
{
|
|
if(PrivateOpenGLDevicePtr)
|
|
{
|
|
PrivateOpenGLDevicePtr->UnregisterQuery( Query );
|
|
}
|
|
}
|
|
|
|
void OnQueryInvalidation( void )
|
|
{
|
|
if(PrivateOpenGLDevicePtr)
|
|
{
|
|
PrivateOpenGLDevicePtr->InvalidateQueries();
|
|
}
|
|
}
|
|
|
|
void OnProgramDeletion( GLint ProgramResource )
|
|
{
|
|
check(PrivateOpenGLDevicePtr);
|
|
PrivateOpenGLDevicePtr->OnProgramDeletion( ProgramResource );
|
|
}
|
|
|
|
void OnVertexBufferDeletion( GLuint VertexBufferResource )
|
|
{
|
|
check(PrivateOpenGLDevicePtr);
|
|
PrivateOpenGLDevicePtr->OnVertexBufferDeletion( VertexBufferResource );
|
|
}
|
|
|
|
void OnIndexBufferDeletion( GLuint IndexBufferResource )
|
|
{
|
|
check(PrivateOpenGLDevicePtr);
|
|
PrivateOpenGLDevicePtr->OnIndexBufferDeletion( IndexBufferResource );
|
|
}
|
|
|
|
void OnPixelBufferDeletion( GLuint PixelBufferResource )
|
|
{
|
|
check(PrivateOpenGLDevicePtr);
|
|
PrivateOpenGLDevicePtr->OnPixelBufferDeletion( PixelBufferResource );
|
|
}
|
|
|
|
void OnUniformBufferDeletion( GLuint UniformBufferResource, uint32 AllocatedSize, bool bStreamDraw, uint32 , uint8* )
|
|
{
|
|
check(PrivateOpenGLDevicePtr);
|
|
PrivateOpenGLDevicePtr->OnUniformBufferDeletion( UniformBufferResource, AllocatedSize, bStreamDraw );
|
|
}
|
|
|
|
void CachedBindArrayBuffer( GLuint Buffer )
|
|
{
|
|
check(PrivateOpenGLDevicePtr);
|
|
PrivateOpenGLDevicePtr->CachedBindArrayBuffer(PrivateOpenGLDevicePtr->GetContextStateForCurrentContext(),Buffer);
|
|
}
|
|
|
|
void CachedBindElementArrayBuffer( GLuint Buffer )
|
|
{
|
|
check(PrivateOpenGLDevicePtr);
|
|
PrivateOpenGLDevicePtr->CachedBindElementArrayBuffer(PrivateOpenGLDevicePtr->GetContextStateForCurrentContext(),Buffer);
|
|
}
|
|
|
|
void CachedBindPixelUnpackBuffer( GLuint Buffer )
|
|
{
|
|
check(PrivateOpenGLDevicePtr);
|
|
if ( FOpenGL::SupportsPixelBuffers() )
|
|
{
|
|
PrivateOpenGLDevicePtr->CachedBindPixelUnpackBuffer(PrivateOpenGLDevicePtr->GetContextStateForCurrentContext(),Buffer);
|
|
}
|
|
}
|
|
|
|
void CachedBindUniformBuffer( GLuint Buffer )
|
|
{
|
|
check(PrivateOpenGLDevicePtr);
|
|
if (FOpenGL::SupportsUniformBuffers())
|
|
{
|
|
PrivateOpenGLDevicePtr->CachedBindUniformBuffer(PrivateOpenGLDevicePtr->GetContextStateForCurrentContext(),Buffer);
|
|
}
|
|
}
|
|
|
|
bool IsUniformBufferBound( GLuint Buffer )
|
|
{
|
|
check(PrivateOpenGLDevicePtr);
|
|
return PrivateOpenGLDevicePtr->IsUniformBufferBound(PrivateOpenGLDevicePtr->GetContextStateForCurrentContext(),Buffer);
|
|
}
|
|
|
|
extern void BeginFrame_UniformBufferPoolCleanup();
|
|
extern void BeginFrame_VertexBufferCleanup();
|
|
|
|
FOpenGLContextState& FOpenGLDynamicRHI::GetContextStateForCurrentContext()
|
|
{
|
|
int32 ContextType = (int32)PlatformOpenGLCurrentContext(PlatformDevice);
|
|
check(ContextType >= 0);
|
|
if (ContextType == CONTEXT_Rendering)
|
|
{
|
|
return RenderingContextState;
|
|
}
|
|
else
|
|
{
|
|
return SharedContextState;
|
|
}
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::RHIBeginFrame()
|
|
{
|
|
RHIPrivateBeginFrame();
|
|
BeginFrame_UniformBufferPoolCleanup();
|
|
BeginFrame_VertexBufferCleanup();
|
|
GPUProfilingData.BeginFrame(this);
|
|
|
|
#if PLATFORM_ANDROID //adding #if since not sure if this is required for any other platform.
|
|
//we need to differential between 0 (backbuffer) and lastcolorRT.
|
|
FOpenGLContextState& ContextState = GetContextStateForCurrentContext();
|
|
ContextState.LastES2ColorRTResource = 0xFFFFFFFF;
|
|
PendingState.DepthStencil = 0 ;
|
|
#endif
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::RHIEndFrame()
|
|
{
|
|
GPUProfilingData.EndFrame();
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::RHIBeginScene()
|
|
{
|
|
// Increment the frame counter. INDEX_NONE is a special value meaning "uninitialized", so if
|
|
// we hit it just wrap around to zero.
|
|
SceneFrameCounter++;
|
|
if (SceneFrameCounter == INDEX_NONE)
|
|
{
|
|
SceneFrameCounter++;
|
|
}
|
|
|
|
static auto* ResourceTableCachingCvar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("rhi.ResourceTableCaching"));
|
|
if (ResourceTableCachingCvar == NULL || ResourceTableCachingCvar->GetValueOnAnyThread() == 1)
|
|
{
|
|
ResourceTableFrameCounter = SceneFrameCounter;
|
|
}
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::RHIEndScene()
|
|
{
|
|
ResourceTableFrameCounter = INDEX_NONE;
|
|
}
|
|
|
|
|
|
|
|
bool GDisableOpenGLDebugOutput = false;
|
|
|
|
// workaround for HTML5.
|
|
#if PLATFORM_HTML5
|
|
#undef GL_ARB_debug_output
|
|
#undef GL_KHR_debug
|
|
#endif
|
|
|
|
#if defined(GL_ARB_debug_output) || defined(GL_KHR_debug)
|
|
/**
|
|
* Map GL_DEBUG_SOURCE_*_ARB to a human-readable string.
|
|
*/
|
|
static const TCHAR* GetOpenGLDebugSourceStringARB(GLenum Source)
|
|
{
|
|
static const TCHAR* SourceStrings[] =
|
|
{
|
|
TEXT("API"),
|
|
TEXT("System"),
|
|
TEXT("ShaderCompiler"),
|
|
TEXT("ThirdParty"),
|
|
TEXT("Application"),
|
|
TEXT("Other")
|
|
};
|
|
|
|
if (Source >= GL_DEBUG_SOURCE_API_ARB && Source <= GL_DEBUG_SOURCE_OTHER_ARB)
|
|
{
|
|
return SourceStrings[Source - GL_DEBUG_SOURCE_API_ARB];
|
|
}
|
|
return TEXT("Unknown");
|
|
}
|
|
|
|
/**
|
|
* Map GL_DEBUG_TYPE_*_ARB to a human-readable string.
|
|
*/
|
|
static const TCHAR* GetOpenGLDebugTypeStringARB(GLenum Type)
|
|
{
|
|
static const TCHAR* TypeStrings[] =
|
|
{
|
|
TEXT("Error"),
|
|
TEXT("Deprecated"),
|
|
TEXT("UndefinedBehavior"),
|
|
TEXT("Portability"),
|
|
TEXT("Performance"),
|
|
TEXT("Other")
|
|
};
|
|
|
|
if (Type >= GL_DEBUG_TYPE_ERROR_ARB && Type <= GL_DEBUG_TYPE_OTHER_ARB)
|
|
{
|
|
return TypeStrings[Type - GL_DEBUG_TYPE_ERROR_ARB];
|
|
}
|
|
#ifdef GL_KHR_debug
|
|
{
|
|
static const TCHAR* DebugTypeStrings[] =
|
|
{
|
|
TEXT("Marker"),
|
|
TEXT("PushGroup"),
|
|
TEXT("PopGroup"),
|
|
};
|
|
|
|
if (Type >= GL_DEBUG_TYPE_MARKER && Type <= GL_DEBUG_TYPE_POP_GROUP)
|
|
{
|
|
return DebugTypeStrings[Type - GL_DEBUG_TYPE_MARKER];
|
|
}
|
|
}
|
|
#endif
|
|
return TEXT("Unknown");
|
|
}
|
|
|
|
/**
|
|
* Map GL_DEBUG_SEVERITY_*_ARB to a human-readable string.
|
|
*/
|
|
static const TCHAR* GetOpenGLDebugSeverityStringARB(GLenum Severity)
|
|
{
|
|
static const TCHAR* SeverityStrings[] =
|
|
{
|
|
TEXT("High"),
|
|
TEXT("Medium"),
|
|
TEXT("Low")
|
|
};
|
|
|
|
if (Severity >= GL_DEBUG_SEVERITY_HIGH_ARB && Severity <= GL_DEBUG_SEVERITY_LOW_ARB)
|
|
{
|
|
return SeverityStrings[Severity - GL_DEBUG_SEVERITY_HIGH_ARB];
|
|
}
|
|
#ifdef GL_KHR_debug
|
|
if(Severity == GL_DEBUG_SEVERITY_NOTIFICATION)
|
|
return TEXT("Notification");
|
|
#endif
|
|
return TEXT("Unknown");
|
|
}
|
|
|
|
/**
|
|
* OpenGL debug message callback. Conforms to GLDEBUGPROCARB.
|
|
*/
|
|
#if (PLATFORM_ANDROID && !PLATFORM_ANDROIDGL4) || PLATFORM_HTML5
|
|
#ifndef GL_APIENTRY
|
|
#define GL_APIENTRY APIENTRY
|
|
#endif
|
|
static void GL_APIENTRY OpenGLDebugMessageCallbackARB(
|
|
#else
|
|
static void APIENTRY OpenGLDebugMessageCallbackARB(
|
|
#endif
|
|
GLenum Source,
|
|
GLenum Type,
|
|
GLuint Id,
|
|
GLenum Severity,
|
|
GLsizei Length,
|
|
const GLchar* Message,
|
|
GLvoid* UserParam)
|
|
{
|
|
if (GDisableOpenGLDebugOutput)
|
|
return;
|
|
#if !NO_LOGGING
|
|
const TCHAR* SourceStr = GetOpenGLDebugSourceStringARB(Source);
|
|
const TCHAR* TypeStr = GetOpenGLDebugTypeStringARB(Type);
|
|
const TCHAR* SeverityStr = GetOpenGLDebugSeverityStringARB(Severity);
|
|
|
|
ELogVerbosity::Type Verbosity = ELogVerbosity::Warning;
|
|
if (Type == GL_DEBUG_TYPE_ERROR_ARB && Severity == GL_DEBUG_SEVERITY_HIGH_ARB)
|
|
{
|
|
Verbosity = ELogVerbosity::Fatal;
|
|
}
|
|
|
|
if ((Verbosity & ELogVerbosity::VerbosityMask) <= FLogCategoryLogRHI::CompileTimeVerbosity)
|
|
{
|
|
if (!LogRHI.IsSuppressed(Verbosity))
|
|
{
|
|
FMsg::Logf(__FILE__, __LINE__, LogRHI.GetCategoryName(), Verbosity,
|
|
TEXT("[%s][%s][%s][%u] %s"),
|
|
SourceStr,
|
|
TypeStr,
|
|
SeverityStr,
|
|
Id,
|
|
ANSI_TO_TCHAR(Message)
|
|
);
|
|
}
|
|
|
|
// this is a debugging code to catch VIDEO->HOST copying
|
|
if (Id == 131186)
|
|
{
|
|
int A = 5;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#endif // GL_ARB_debug_output
|
|
|
|
#ifdef GL_AMD_debug_output
|
|
|
|
/**
|
|
* Map GL_DEBUG_CATEGORY_*_AMD to a human-readable string.
|
|
*/
|
|
static const TCHAR* GetOpenGLDebugCategoryStringAMD(GLenum Category)
|
|
{
|
|
static const TCHAR* CategoryStrings[] =
|
|
{
|
|
TEXT("API"),
|
|
TEXT("System"),
|
|
TEXT("Deprecation"),
|
|
TEXT("UndefinedBehavior"),
|
|
TEXT("Performance"),
|
|
TEXT("ShaderCompiler"),
|
|
TEXT("Application"),
|
|
TEXT("Other")
|
|
};
|
|
|
|
if (Category >= GL_DEBUG_CATEGORY_API_ERROR_AMD && Category <= GL_DEBUG_CATEGORY_OTHER_AMD)
|
|
{
|
|
return CategoryStrings[Category - GL_DEBUG_CATEGORY_API_ERROR_AMD];
|
|
}
|
|
return TEXT("Unknown");
|
|
}
|
|
|
|
/**
|
|
* Map GL_DEBUG_SEVERITY_*_AMD to a human-readable string.
|
|
*/
|
|
static const TCHAR* GetOpenGLDebugSeverityStringAMD(GLenum Severity)
|
|
{
|
|
static const TCHAR* SeverityStrings[] =
|
|
{
|
|
TEXT("High"),
|
|
TEXT("Medium"),
|
|
TEXT("Low")
|
|
};
|
|
|
|
if (Severity >= GL_DEBUG_SEVERITY_HIGH_AMD && Severity <= GL_DEBUG_SEVERITY_LOW_AMD)
|
|
{
|
|
return SeverityStrings[Severity - GL_DEBUG_SEVERITY_HIGH_AMD];
|
|
}
|
|
return TEXT("Unknown");
|
|
}
|
|
|
|
/**
|
|
* OpenGL debug message callback. Conforms to GLDEBUGPROCAMD.
|
|
*/
|
|
static void APIENTRY OpenGLDebugMessageCallbackAMD(
|
|
GLuint Id,
|
|
GLenum Category,
|
|
GLenum Severity,
|
|
GLsizei Length,
|
|
const GLchar* Message,
|
|
GLvoid* UserParam)
|
|
{
|
|
#if !NO_LOGGING
|
|
const TCHAR* CategoryStr = GetOpenGLDebugCategoryStringAMD(Category);
|
|
const TCHAR* SeverityStr = GetOpenGLDebugSeverityStringAMD(Severity);
|
|
|
|
ELogVerbosity::Type Verbosity = ELogVerbosity::Warning;
|
|
if (Severity == GL_DEBUG_SEVERITY_HIGH_AMD)
|
|
{
|
|
Verbosity = ELogVerbosity::Fatal;
|
|
}
|
|
|
|
if ((Verbosity & ELogVerbosity::VerbosityMask) <= FLogCategoryLogRHI::CompileTimeVerbosity)
|
|
{
|
|
if (!LogRHI.IsSuppressed(Verbosity))
|
|
{
|
|
FMsg::Logf(__FILE__, __LINE__, LogRHI.GetCategoryName(), Verbosity,
|
|
TEXT("[%s][%s][%u] %s"),
|
|
CategoryStr,
|
|
SeverityStr,
|
|
Id,
|
|
ANSI_TO_TCHAR(Message)
|
|
);
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
#endif // GL_AMD_debug_output
|
|
|
|
#if PLATFORM_WINDOWS
|
|
PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT_ProcAddress = NULL;
|
|
#endif
|
|
|
|
|
|
static inline void SetupTextureFormat( EPixelFormat Format, const FOpenGLTextureFormat& GLFormat)
|
|
{
|
|
GOpenGLTextureFormats[Format] = GLFormat;
|
|
GPixelFormats[Format].Supported = (GLFormat.Format != GL_NONE && (GLFormat.InternalFormat[0] != GL_NONE || GLFormat.InternalFormat[1] != GL_NONE));
|
|
}
|
|
|
|
|
|
void InitDebugContext()
|
|
{
|
|
// Set the debug output callback if the driver supports it.
|
|
VERIFY_GL(__FUNCTION__);
|
|
bool bDebugOutputInitialized = false;
|
|
#if !ENABLE_VERIFY_GL
|
|
#if defined(GL_ARB_debug_output)
|
|
if (glDebugMessageCallbackARB)
|
|
{
|
|
// Synchronous output can slow things down, but we'll get better callstack if breaking in or crashing in the callback. This is debug only after all.
|
|
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
|
glDebugMessageCallbackARB(GLDEBUGPROCARB(OpenGLDebugMessageCallbackARB), /*UserParam=*/ NULL);
|
|
bDebugOutputInitialized = (glGetError() == GL_NO_ERROR);
|
|
}
|
|
#elif defined(GL_KHR_debug)
|
|
// OpenGLES names the debug functions differently, but they behave the same
|
|
if (glDebugMessageCallbackKHR)
|
|
{
|
|
glDebugMessageCallbackKHR(GLDEBUGPROCKHR(OpenGLDebugMessageCallbackARB), /*UserParam=*/ NULL);
|
|
bDebugOutputInitialized = (glGetError() == GL_NO_ERROR);
|
|
}
|
|
#endif // GL_ARB_debug_output / GL_KHR_debug
|
|
#if defined(GL_AMD_debug_output)
|
|
if (glDebugMessageCallbackAMD && !bDebugOutputInitialized)
|
|
{
|
|
glDebugMessageCallbackAMD(OpenGLDebugMessageCallbackAMD, /*UserParam=*/ NULL);
|
|
bDebugOutputInitialized = (glGetError() == GL_NO_ERROR);
|
|
}
|
|
#endif // GL_AMD_debug_output
|
|
#endif // !ENABLE_VERIFY_GL
|
|
if (!bDebugOutputInitialized && !PLATFORM_MAC)
|
|
{
|
|
UE_LOG(LogRHI,Warning,TEXT("OpenGL debug output extension not supported!"));
|
|
}
|
|
|
|
// this is to suppress feeding back of the debug markers and groups to the log, since those originate in the app anyways...
|
|
#if ENABLE_OPENGL_DEBUG_GROUPS && GL_ARB_debug_output && GL_KHR_debug && !OPENGL_ES31
|
|
if(glDebugMessageControlARB && bDebugOutputInitialized)
|
|
{
|
|
glDebugMessageControlARB(GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_MARKER, GL_DONT_CARE, 0, NULL, GL_FALSE);
|
|
glDebugMessageControlARB(GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_PUSH_GROUP, GL_DONT_CARE, 0, NULL, GL_FALSE);
|
|
glDebugMessageControlARB(GL_DEBUG_SOURCE_APPLICATION_ARB, GL_DEBUG_TYPE_POP_GROUP, GL_DONT_CARE, 0, NULL, GL_FALSE);
|
|
#ifdef GL_KHR_debug
|
|
glDebugMessageControlARB(GL_DEBUG_SOURCE_API_ARB, GL_DEBUG_TYPE_OTHER_ARB, GL_DEBUG_SEVERITY_NOTIFICATION, 0, NULL, GL_FALSE);
|
|
#endif
|
|
UE_LOG(LogRHI,Verbose,TEXT("disabling reporting back of debug groups and markers to the OpenGL debug output callback"));
|
|
}
|
|
#elif ENABLE_OPENGL_DEBUG_GROUPS && !defined(GL_ARB_debug_output) && GL_KHR_debug
|
|
if(glDebugMessageControlKHR)
|
|
{
|
|
glDebugMessageControlKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, GL_DEBUG_TYPE_MARKER_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE);
|
|
glDebugMessageControlKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, GL_DEBUG_TYPE_PUSH_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE);
|
|
glDebugMessageControlKHR(GL_DEBUG_SOURCE_APPLICATION_KHR, GL_DEBUG_TYPE_POP_GROUP_KHR, GL_DONT_CARE, 0, NULL, GL_FALSE);
|
|
glDebugMessageControlKHR(GL_DEBUG_SOURCE_API_KHR, GL_DEBUG_TYPE_OTHER_KHR, GL_DEBUG_SEVERITY_NOTIFICATION, 0, NULL, GL_FALSE);
|
|
UE_LOG(LogRHI,Verbose,TEXT("disabling reporting back of debug groups and markers to the OpenGL debug output callback"));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
/**
|
|
* Initialize RHI capabilities for the current OpenGL context.
|
|
*/
|
|
static void InitRHICapabilitiesForGL()
|
|
{
|
|
VERIFY_GL_SCOPE();
|
|
|
|
GTexturePoolSize = 0;
|
|
GPoolSizeVRAMPercentage = 0;
|
|
#if PLATFORM_WINDOWS || PLATFORM_LINUX
|
|
GConfig->GetInt( TEXT( "TextureStreaming" ), TEXT( "PoolSizeVRAMPercentage" ), GPoolSizeVRAMPercentage, GEngineIni );
|
|
#endif
|
|
|
|
// GL vendor and version information.
|
|
#if !defined(__GNUC__) && !defined(__clang__) && !(defined(_MSC_VER) && _MSC_VER >= 1900)
|
|
#define LOG_GL_STRING(StringEnum) UE_LOG(LogRHI, Log, TEXT(" ") ## TEXT(#StringEnum) ## TEXT(": %s"), ANSI_TO_TCHAR((const ANSICHAR*)glGetString(StringEnum)))
|
|
#else
|
|
#define LOG_GL_STRING(StringEnum) UE_LOG(LogRHI, Log, TEXT(" " #StringEnum ": %s"), ANSI_TO_TCHAR((const ANSICHAR*)glGetString(StringEnum)))
|
|
#endif
|
|
UE_LOG(LogRHI, Log, TEXT("Initializing OpenGL RHI"));
|
|
LOG_GL_STRING(GL_VENDOR);
|
|
LOG_GL_STRING(GL_RENDERER);
|
|
LOG_GL_STRING(GL_VERSION);
|
|
LOG_GL_STRING(GL_SHADING_LANGUAGE_VERSION);
|
|
#undef LOG_GL_STRING
|
|
|
|
GRHIAdapterName = FOpenGL::GetAdapterName();
|
|
|
|
// Log all supported extensions.
|
|
#if PLATFORM_WINDOWS
|
|
bool bWindowsSwapControlExtensionPresent = false;
|
|
#endif
|
|
{
|
|
extern void GetExtensionsString( FString& ExtensionsString);
|
|
FString ExtensionsString;
|
|
|
|
GetExtensionsString(ExtensionsString);
|
|
|
|
#if PLATFORM_WINDOWS
|
|
if (ExtensionsString.Contains(TEXT("WGL_EXT_swap_control")))
|
|
{
|
|
bWindowsSwapControlExtensionPresent = true;
|
|
}
|
|
#endif
|
|
|
|
// Log supported GL extensions
|
|
UE_LOG(LogRHI, Log, TEXT("OpenGL Extensions:"));
|
|
TArray<FString> GLExtensionArray;
|
|
ExtensionsString.ParseIntoArray(GLExtensionArray, TEXT(" "), true);
|
|
for (int ExtIndex = 0; ExtIndex < GLExtensionArray.Num(); ExtIndex++)
|
|
{
|
|
UE_LOG(LogRHI, Log, TEXT(" %s"), *GLExtensionArray[ExtIndex]);
|
|
}
|
|
|
|
FOpenGL::ProcessExtensions(ExtensionsString);
|
|
}
|
|
|
|
#if PLATFORM_WINDOWS
|
|
#pragma warning(push)
|
|
#pragma warning(disable:4191)
|
|
if (!bWindowsSwapControlExtensionPresent)
|
|
{
|
|
// Disable warning C4191: 'type cast' : unsafe conversion from 'PROC' to 'XXX' while getting GL entry points.
|
|
PFNWGLGETEXTENSIONSSTRINGEXTPROC wglGetExtensionsStringEXT_ProcAddress =
|
|
(PFNWGLGETEXTENSIONSSTRINGEXTPROC) wglGetProcAddress("wglGetExtensionsStringEXT");
|
|
|
|
if (strstr(wglGetExtensionsStringEXT_ProcAddress(), "WGL_EXT_swap_control") != NULL)
|
|
{
|
|
bWindowsSwapControlExtensionPresent = true;
|
|
}
|
|
}
|
|
|
|
if (bWindowsSwapControlExtensionPresent)
|
|
{
|
|
wglSwapIntervalEXT_ProcAddress = (PFNWGLSWAPINTERVALEXTPROC) wglGetProcAddress("wglSwapIntervalEXT");
|
|
}
|
|
#pragma warning(pop)
|
|
#endif
|
|
|
|
// Set debug flag if context was setup with debugging
|
|
FOpenGL::InitDebugContext();
|
|
|
|
// Log and get various limits.
|
|
#if !defined(__GNUC__) && !defined(__clang__) && !(defined(_MSC_VER) && _MSC_VER >= 1900)
|
|
#define LOG_AND_GET_GL_INT_TEMP(IntEnum,Default) GLint Value_##IntEnum = Default; if (IntEnum) {glGetIntegerv(IntEnum, &Value_##IntEnum); glGetError();} else {Value_##IntEnum = Default;} UE_LOG(LogRHI, Log, TEXT(" ") ## TEXT(#IntEnum) ## TEXT(": %d"), Value_##IntEnum)
|
|
#else
|
|
#define LOG_AND_GET_GL_INT_TEMP(IntEnum,Default) GLint Value_##IntEnum = Default; if (IntEnum) {glGetIntegerv(IntEnum, &Value_##IntEnum); glGetError();} else {Value_##IntEnum = Default;} UE_LOG(LogRHI, Log, TEXT(" " #IntEnum ": %d"), Value_##IntEnum)
|
|
#endif
|
|
LOG_AND_GET_GL_INT_TEMP(GL_MAX_TEXTURE_SIZE, 0);
|
|
LOG_AND_GET_GL_INT_TEMP(GL_MAX_CUBE_MAP_TEXTURE_SIZE, 0);
|
|
#if GL_MAX_ARRAY_TEXTURE_LAYERS
|
|
LOG_AND_GET_GL_INT_TEMP(GL_MAX_ARRAY_TEXTURE_LAYERS, 0);
|
|
#endif
|
|
#if GL_MAX_3D_TEXTURE_SIZE
|
|
LOG_AND_GET_GL_INT_TEMP(GL_MAX_3D_TEXTURE_SIZE, 0);
|
|
#endif
|
|
LOG_AND_GET_GL_INT_TEMP(GL_MAX_RENDERBUFFER_SIZE, 0);
|
|
LOG_AND_GET_GL_INT_TEMP(GL_MAX_TEXTURE_IMAGE_UNITS, 0);
|
|
if (FOpenGL::SupportsDrawBuffers())
|
|
{
|
|
LOG_AND_GET_GL_INT_TEMP(GL_MAX_DRAW_BUFFERS, 1);
|
|
}
|
|
LOG_AND_GET_GL_INT_TEMP(GL_MAX_COLOR_ATTACHMENTS, 1);
|
|
LOG_AND_GET_GL_INT_TEMP(GL_MAX_SAMPLES, 1);
|
|
LOG_AND_GET_GL_INT_TEMP(GL_MAX_COLOR_TEXTURE_SAMPLES, 1);
|
|
LOG_AND_GET_GL_INT_TEMP(GL_MAX_DEPTH_TEXTURE_SAMPLES, 1);
|
|
LOG_AND_GET_GL_INT_TEMP(GL_MAX_INTEGER_SAMPLES, 1);
|
|
LOG_AND_GET_GL_INT_TEMP(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, 0);
|
|
LOG_AND_GET_GL_INT_TEMP(GL_MAX_VERTEX_ATTRIBS, 0);
|
|
|
|
if (FParse::Param(FCommandLine::Get(), TEXT("quad_buffer_stereo")))
|
|
{
|
|
GLboolean Result = GL_FALSE;
|
|
glGetBooleanv(GL_STEREO, &Result);
|
|
// Skip any errors if any were generated
|
|
glGetError();
|
|
GSupportsQuadBufferStereo = (Result == GL_TRUE);
|
|
}
|
|
|
|
if( FOpenGL::SupportsTextureFilterAnisotropic())
|
|
{
|
|
LOG_AND_GET_GL_INT_TEMP(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, 0);
|
|
GMaxOpenGLTextureFilterAnisotropic = Value_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT;
|
|
}
|
|
#undef LOG_AND_GET_GL_INT_TEMP
|
|
|
|
GMaxOpenGLColorSamples = Value_GL_MAX_COLOR_TEXTURE_SAMPLES;
|
|
GMaxOpenGLDepthSamples = Value_GL_MAX_DEPTH_TEXTURE_SAMPLES;
|
|
GMaxOpenGLIntegerSamples = Value_GL_MAX_INTEGER_SAMPLES;
|
|
|
|
// Verify some assumptions.
|
|
// Android seems like reports one color attachment even when it supports MRT
|
|
#if !PLATFORM_ANDROID
|
|
check(Value_GL_MAX_COLOR_ATTACHMENTS >= MaxSimultaneousRenderTargets || !FOpenGL::SupportsMultipleRenderTargets());
|
|
#endif
|
|
|
|
// We don't check for compressed formats right now because vendors have not
|
|
// done a great job reporting what is actually supported:
|
|
// OSX/NVIDIA doesn't claim to support SRGB DXT formats even though they work correctly.
|
|
// Windows/AMD sometimes claim to support no compressed formats even though they all work correctly.
|
|
#if 0
|
|
// Check compressed texture formats.
|
|
bool bSupportsCompressedTextures = true;
|
|
{
|
|
FString CompressedFormatsString = TEXT(" GL_COMPRESSED_TEXTURE_FORMATS:");
|
|
TArray<GLint> CompressedFormats;
|
|
GLint NumCompressedFormats = 0;
|
|
glGetIntegerv(GL_NUM_COMPRESSED_TEXTURE_FORMATS, &NumCompressedFormats);
|
|
CompressedFormats.Empty(NumCompressedFormats);
|
|
CompressedFormats.AddZeroed(NumCompressedFormats);
|
|
glGetIntegerv(GL_COMPRESSED_TEXTURE_FORMATS, CompressedFormats.GetTypedData());
|
|
|
|
#define CHECK_COMPRESSED_FORMAT(GLName) if (CompressedFormats.Contains(GLName)) { CompressedFormatsString += TEXT(" ") TEXT(#GLName); } else { bSupportsCompressedTextures = false; }
|
|
CHECK_COMPRESSED_FORMAT(GL_COMPRESSED_RGB_S3TC_DXT1_EXT);
|
|
CHECK_COMPRESSED_FORMAT(GL_COMPRESSED_SRGB_S3TC_DXT1_EXT);
|
|
CHECK_COMPRESSED_FORMAT(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT);
|
|
CHECK_COMPRESSED_FORMAT(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT);
|
|
CHECK_COMPRESSED_FORMAT(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT);
|
|
CHECK_COMPRESSED_FORMAT(GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT);
|
|
//CHECK_COMPRESSED_FORMAT(GL_COMPRESSED_RG_RGTC2);
|
|
#undef CHECK_COMPRESSED_FORMAT
|
|
|
|
// ATI does not report that it supports RGTC2, but the 3.2 core profile mandates it.
|
|
// For now assume it is supported and bring it up with ATI if it really isn't(?!)
|
|
CompressedFormatsString += TEXT(" GL_COMPRESSED_RG_RGTC2");
|
|
|
|
UE_LOG(LogRHI, Log, *CompressedFormatsString);
|
|
}
|
|
check(bSupportsCompressedTextures);
|
|
#endif
|
|
|
|
// Set capabilities.
|
|
const GLint MajorVersion = FOpenGL::GetMajorVersion();
|
|
const GLint MinorVersion = FOpenGL::GetMinorVersion();
|
|
|
|
// Shader platform & RHI feature level
|
|
GMaxRHIFeatureLevel = FOpenGL::GetFeatureLevel();
|
|
GMaxRHIShaderPlatform = FOpenGL::GetShaderPlatform();
|
|
|
|
// Emulate uniform buffers on ES2, unless we're on a desktop platform emulating ES2.
|
|
GUseEmulatedUniformBuffers = IsES2Platform(GMaxRHIShaderPlatform) && !IsPCPlatform(GMaxRHIShaderPlatform);
|
|
if (!GUseEmulatedUniformBuffers && IsPCPlatform(GMaxRHIShaderPlatform))
|
|
{
|
|
static auto* CVar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("OpenGL.UseEmulatedUBs"));
|
|
GUseEmulatedUniformBuffers = CVar && CVar->GetValueOnAnyThread() != 0;
|
|
}
|
|
|
|
FString FeatureLevelName;
|
|
GetFeatureLevelName(GMaxRHIFeatureLevel, FeatureLevelName);
|
|
FString ShaderPlatformName = LegacyShaderPlatformToShaderFormat(GMaxRHIShaderPlatform).ToString();
|
|
|
|
UE_LOG(LogRHI, Log, TEXT("OpenGL MajorVersion = %d, MinorVersion = %d, ShaderPlatform = %s, FeatureLevel = %s"), MajorVersion, MinorVersion, *ShaderPlatformName, *FeatureLevelName);
|
|
#if PLATFORM_ANDROIDGL4
|
|
UE_LOG(LogRHI, Log, TEXT("PLATFORM_ANDROIDGL4"));
|
|
#elif PLATFORM_ANDROIDES31
|
|
UE_LOG(LogRHI, Log, TEXT("PLATFORM_ANDROIDES31"));
|
|
#elif PLATFORM_ANDROID
|
|
UE_LOG(LogRHI, Log, TEXT("PLATFORM_ANDROID"));
|
|
#endif
|
|
|
|
GMaxTextureMipCount = FMath::CeilLogTwo(Value_GL_MAX_TEXTURE_SIZE) + 1;
|
|
GMaxTextureMipCount = FMath::Min<int32>(MAX_TEXTURE_MIP_COUNT, GMaxTextureMipCount);
|
|
GMaxTextureDimensions = Value_GL_MAX_TEXTURE_SIZE;
|
|
GMaxCubeTextureDimensions = Value_GL_MAX_CUBE_MAP_TEXTURE_SIZE;
|
|
#if GL_MAX_ARRAY_TEXTURE_LAYERS
|
|
GMaxTextureArrayLayers = Value_GL_MAX_ARRAY_TEXTURE_LAYERS;
|
|
#endif
|
|
|
|
GSupportsVolumeTextureRendering = FOpenGL::SupportsVolumeTextureRendering();
|
|
GSupportsRenderDepthTargetableShaderResources = true;
|
|
GSupportsRenderTargetFormat_PF_G8 = true;
|
|
GSupportsSeparateRenderTargetBlendState = FOpenGL::SupportsSeparateAlphaBlend();
|
|
GSupportsDepthBoundsTest = FOpenGL::SupportsDepthBoundsTest();
|
|
|
|
GSupportsRenderTargetFormat_PF_FloatRGBA = FOpenGL::SupportsColorBufferHalfFloat();
|
|
|
|
GSupportsMultipleRenderTargets = FOpenGL::SupportsMultipleRenderTargets();
|
|
GSupportsTexture3D = FOpenGL::SupportsTexture3D();
|
|
GSupportsResourceView = FOpenGL::SupportsResourceView();
|
|
|
|
GSupportsShaderFramebufferFetch = FOpenGL::SupportsShaderFramebufferFetch();
|
|
GSupportsShaderDepthStencilFetch = FOpenGL::SupportsShaderDepthStencilFetch();
|
|
GMaxShadowDepthBufferSizeX = FMath::Min<int32>(Value_GL_MAX_RENDERBUFFER_SIZE, 4096); // Limit to the D3D11 max.
|
|
GMaxShadowDepthBufferSizeY = FMath::Min<int32>(Value_GL_MAX_RENDERBUFFER_SIZE, 4096);
|
|
GHardwareHiddenSurfaceRemoval = FOpenGL::HasHardwareHiddenSurfaceRemoval();
|
|
GRHISupportsInstancing = FOpenGL::SupportsInstancing(); // HTML5 does not support it. Android supports it with OpenGL ES3.0+
|
|
GSupportsTimestampRenderQueries = FOpenGL::SupportsTimestampQueries();
|
|
|
|
GSupportsHDR32bppEncodeModeIntrinsic = FOpenGL::SupportsHDR32bppEncodeModeIntrinsic();
|
|
|
|
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::ES2] = (GMaxRHIFeatureLevel == ERHIFeatureLevel::ES2) ? GMaxRHIShaderPlatform : SP_OPENGL_PCES2;
|
|
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::ES3_1] = (GMaxRHIFeatureLevel == ERHIFeatureLevel::ES3_1) ? GMaxRHIShaderPlatform : SP_OPENGL_PCES3_1;
|
|
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::SM4] = PLATFORM_MAC ? SP_OPENGL_SM4_MAC : SP_OPENGL_SM4;
|
|
GShaderPlatformForFeatureLevel[ERHIFeatureLevel::SM5] = OPENGL_ES31 ? SP_OPENGL_ES31_EXT : SP_OPENGL_SM5;
|
|
|
|
// Set to same values as in DX11, as for the time being clip space adjustment are done entirely
|
|
// in HLSLCC-generated shader code and OpenGLDrv.
|
|
GMinClipZ = 0.0f;
|
|
GProjectionSignY = 1.0f;
|
|
|
|
// Disable texture streaming on ES2 unless we have the GL_APPLE_copy_texture_levels extension
|
|
if (GMaxRHIFeatureLevel == ERHIFeatureLevel::ES2 && !FOpenGL::SupportsCopyTextureLevels())
|
|
{
|
|
GRHISupportsTextureStreaming = false;
|
|
}
|
|
else
|
|
{
|
|
GRHISupportsTextureStreaming = true;
|
|
}
|
|
|
|
GVertexElementTypeSupport.SetSupported(VET_Half2, FOpenGL::SupportsVertexHalfFloat());
|
|
GVertexElementTypeSupport.SetSupported(VET_Half4, FOpenGL::SupportsVertexHalfFloat());
|
|
|
|
for (int32 PF = 0; PF < PF_MAX; ++PF)
|
|
{
|
|
SetupTextureFormat(EPixelFormat(PF), FOpenGLTextureFormat());
|
|
}
|
|
|
|
GLenum DepthFormat = FOpenGL::GetDepthFormat();
|
|
GLenum ShadowDepthFormat = FOpenGL::GetShadowDepthFormat();
|
|
|
|
// Initialize the platform pixel format map. InternalFormat InternalFormatSRGB Format Type bCompressed bBGRA
|
|
SetupTextureFormat( PF_Unknown, FOpenGLTextureFormat( ));
|
|
SetupTextureFormat( PF_A32B32G32R32F, FOpenGLTextureFormat( GL_RGBA32F, GL_NONE, GL_RGBA, GL_FLOAT, false, false));
|
|
SetupTextureFormat( PF_UYVY, FOpenGLTextureFormat( ));
|
|
//@todo: ES2 requires GL_OES_depth_texture extension to support depth textures of any kind.
|
|
SetupTextureFormat( PF_ShadowDepth, FOpenGLTextureFormat( ShadowDepthFormat, GL_NONE, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, false, false));
|
|
SetupTextureFormat( PF_D24, FOpenGLTextureFormat( DepthFormat, GL_NONE, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, false, false));
|
|
SetupTextureFormat( PF_A16B16G16R16, FOpenGLTextureFormat( GL_RGBA16, GL_RGBA16, GL_RGBA, GL_UNSIGNED_SHORT, false, false));
|
|
SetupTextureFormat( PF_A1, FOpenGLTextureFormat( ));
|
|
SetupTextureFormat( PF_R16G16B16A16_UINT, FOpenGLTextureFormat( GL_RGBA16UI, GL_NONE, GL_RGBA_INTEGER, GL_UNSIGNED_SHORT, false, false));
|
|
SetupTextureFormat( PF_R16G16B16A16_SINT, FOpenGLTextureFormat( GL_RGBA16I, GL_NONE, GL_RGBA_INTEGER, GL_SHORT, false, false));
|
|
SetupTextureFormat( PF_R5G6B5_UNORM, FOpenGLTextureFormat( ));
|
|
#if PLATFORM_DESKTOP || PLATFORM_ANDROIDGL4 || PLATFORM_ANDROIDES31
|
|
if (PLATFORM_DESKTOP != 0 || PLATFORM_ANDROIDGL4 != 0 || FOpenGL::GetFeatureLevel() >= ERHIFeatureLevel::SM4)
|
|
{
|
|
// Not supported for rendering:
|
|
SetupTextureFormat( PF_G16, FOpenGLTextureFormat( GL_R16, GL_R16, GL_RED, GL_UNSIGNED_SHORT, false, false));
|
|
SetupTextureFormat( PF_R32_FLOAT, FOpenGLTextureFormat( GL_R32F, GL_R32F, GL_RED, GL_FLOAT, false, false));
|
|
SetupTextureFormat( PF_G16R16F, FOpenGLTextureFormat( GL_RG16F, GL_RG16F, GL_RG, GL_HALF_FLOAT, false, false));
|
|
SetupTextureFormat( PF_G16R16F_FILTER, FOpenGLTextureFormat( GL_RG16F, GL_RG16F, GL_RG, GL_HALF_FLOAT, false, false));
|
|
SetupTextureFormat( PF_G32R32F, FOpenGLTextureFormat( GL_RG32F, GL_RG32F, GL_RG, GL_FLOAT, false, false));
|
|
SetupTextureFormat( PF_A2B10G10R10, FOpenGLTextureFormat( GL_RGB10_A2, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false, false));
|
|
SetupTextureFormat( PF_R16F, FOpenGLTextureFormat( GL_R16F, GL_R16F, GL_RED, GL_HALF_FLOAT, false, false));
|
|
SetupTextureFormat( PF_R16F_FILTER, FOpenGLTextureFormat( GL_R16F, GL_R16F, GL_RED, GL_HALF_FLOAT, false, false));
|
|
if (FOpenGL::SupportsR11G11B10F())
|
|
{
|
|
// Note: Also needs to include support for compute shaders to be defined here (e.g. glBindImageTexture)
|
|
SetupTextureFormat(PF_FloatRGB, FOpenGLTextureFormat(GL_R11F_G11F_B10F, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, false, false));
|
|
SetupTextureFormat(PF_FloatR11G11B10, FOpenGLTextureFormat(GL_RGBA16F, GL_RGBA16F, GL_RGB, GL_HALF_FLOAT, false, false));
|
|
}
|
|
else
|
|
{
|
|
SetupTextureFormat(PF_FloatRGB, FOpenGLTextureFormat(GL_RGBA16F, GL_RGBA16F, GL_RGB, GL_HALF_FLOAT, false, false));
|
|
SetupTextureFormat(PF_FloatR11G11B10, FOpenGLTextureFormat(GL_R11F_G11F_B10F, GL_R11F_G11F_B10F, GL_RGB, GL_UNSIGNED_INT_10F_11F_11F_REV, false, false));
|
|
}
|
|
SetupTextureFormat(PF_V8U8, FOpenGLTextureFormat(GL_RG8_SNORM, GL_NONE, GL_RG, GL_BYTE, false, false));
|
|
SetupTextureFormat( PF_R8G8, FOpenGLTextureFormat( GL_RG8, GL_NONE, GL_RG, GL_UNSIGNED_BYTE, false, false));
|
|
SetupTextureFormat( PF_BC5, FOpenGLTextureFormat( GL_COMPRESSED_RG_RGTC2, GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_BYTE, true, false));
|
|
SetupTextureFormat( PF_BC4, FOpenGLTextureFormat( GL_COMPRESSED_RED_RGTC1, GL_COMPRESSED_RED_RGTC1,GL_RED, GL_UNSIGNED_BYTE, true, false));
|
|
SetupTextureFormat( PF_A8, FOpenGLTextureFormat( GL_R8, GL_NONE, GL_RED, GL_UNSIGNED_BYTE, false, false));
|
|
SetupTextureFormat( PF_R32_UINT, FOpenGLTextureFormat( GL_R32UI, GL_NONE, GL_RED_INTEGER, GL_UNSIGNED_INT, false, false));
|
|
SetupTextureFormat( PF_R32_SINT, FOpenGLTextureFormat( GL_R32I, GL_NONE, GL_RED_INTEGER, GL_INT, false, false));
|
|
SetupTextureFormat( PF_R16_UINT, FOpenGLTextureFormat( GL_R16UI, GL_NONE, GL_RED_INTEGER, GL_UNSIGNED_SHORT, false, false));
|
|
SetupTextureFormat( PF_R16_SINT, FOpenGLTextureFormat( GL_R16I, GL_NONE, GL_RED_INTEGER, GL_SHORT, false, false));
|
|
SetupTextureFormat( PF_FloatRGBA, FOpenGLTextureFormat( GL_RGBA16F, GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, false, false));
|
|
if (FOpenGL::GetShaderPlatform() == EShaderPlatform::SP_OPENGL_ES31_EXT)
|
|
{
|
|
SetupTextureFormat(PF_G8, FOpenGLTextureFormat(GL_R8, GL_R8, GL_RED, GL_UNSIGNED_BYTE, false, false));
|
|
SetupTextureFormat(PF_B8G8R8A8, FOpenGLTextureFormat(GL_RGBA8, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, false, true));
|
|
SetupTextureFormat(PF_R8G8B8A8, FOpenGLTextureFormat(GL_RGBA8, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, false, false));
|
|
if (FOpenGL::SupportsRG16UI())
|
|
{
|
|
// The user should check for support for PF_G16R16 and implement a fallback if it's not supported!
|
|
SetupTextureFormat(PF_G16R16, FOpenGLTextureFormat(GL_RG16, GL_RG16, GL_RG, GL_UNSIGNED_SHORT, false, false));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
SetupTextureFormat(PF_G8, FOpenGLTextureFormat(GL_R8, GL_SRGB8, GL_RED, GL_UNSIGNED_BYTE, false, false));
|
|
SetupTextureFormat(PF_B8G8R8A8, FOpenGLTextureFormat(GL_RGBA8, GL_SRGB8_ALPHA8, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, false, false));
|
|
SetupTextureFormat(PF_R8G8B8A8, FOpenGLTextureFormat(GL_RGBA8, GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false, false));
|
|
SetupTextureFormat(PF_G16R16, FOpenGLTextureFormat(GL_RG16, GL_RG16, GL_RG, GL_UNSIGNED_SHORT, false, false));
|
|
}
|
|
if (FOpenGL::SupportsPackedDepthStencil())
|
|
{
|
|
SetupTextureFormat(PF_DepthStencil, FOpenGLTextureFormat(GL_DEPTH24_STENCIL8, GL_NONE, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, false, false));
|
|
}
|
|
else
|
|
{
|
|
// @todo android: This is cheating by not setting a stencil anywhere, need that! And Shield is still rendering black scene
|
|
SetupTextureFormat(PF_DepthStencil, FOpenGLTextureFormat(DepthFormat, GL_NONE, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, false, false));
|
|
}
|
|
}
|
|
else
|
|
#endif // PLATFORM_DESKTOP || PLATFORM_ANDROIDGL4 || PLATFORM_ANDROIDES31
|
|
{
|
|
#if !PLATFORM_DESKTOP && !PLATFORM_ANDROIDGL4
|
|
// ES2-based cases
|
|
GLuint BGRA8888 = FOpenGL::SupportsBGRA8888() ? GL_BGRA_EXT : GL_RGBA;
|
|
GLuint RGBA8 = FOpenGL::SupportsRGBA8() ? GL_RGBA8_OES : GL_RGBA;
|
|
|
|
#if PLATFORM_ANDROID
|
|
SetupTextureFormat(PF_B8G8R8A8, FOpenGLTextureFormat(BGRA8888, FOpenGL::SupportsSRGB() ? GL_SRGB_ALPHA_EXT : BGRA8888, BGRA8888, GL_UNSIGNED_BYTE, false, false));
|
|
#else
|
|
SetupTextureFormat(PF_B8G8R8A8, FOpenGLTextureFormat(GL_RGBA, FOpenGL::SupportsSRGB() ? GL_SRGB_ALPHA_EXT : GL_RGBA, GL_BGRA8_EXT, FOpenGL::SupportsSRGB() ? GL_SRGB8_ALPHA8_EXT : GL_BGRA8_EXT, BGRA8888, GL_UNSIGNED_BYTE, false, false));
|
|
#endif
|
|
SetupTextureFormat(PF_R8G8B8A8, FOpenGLTextureFormat(RGBA8, FOpenGL::SupportsSRGB() ? GL_SRGB_ALPHA_EXT : RGBA8, GL_RGBA8, FOpenGL::SupportsSRGB() ? GL_SRGB8_ALPHA8_EXT : GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, false, false));
|
|
#if PLATFORM_IOS
|
|
SetupTextureFormat(PF_G8, FOpenGLTextureFormat(GL_LUMINANCE, GL_LUMINANCE, GL_LUMINANCE8_EXT, GL_LUMINANCE8_EXT, GL_LUMINANCE, GL_UNSIGNED_BYTE, false, false));
|
|
SetupTextureFormat(PF_A8, FOpenGLTextureFormat(GL_ALPHA, GL_ALPHA, GL_ALPHA8_EXT, GL_ALPHA8_EXT, GL_ALPHA, GL_UNSIGNED_BYTE, false, false));
|
|
#else
|
|
SetupTextureFormat(PF_G8, FOpenGLTextureFormat(GL_LUMINANCE, GL_LUMINANCE, GL_LUMINANCE, GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, false, false));
|
|
SetupTextureFormat(PF_A8, FOpenGLTextureFormat(GL_ALPHA, GL_ALPHA, GL_ALPHA, GL_ALPHA, GL_ALPHA, GL_UNSIGNED_BYTE, false, false));
|
|
#endif
|
|
|
|
if (GSupportsRenderTargetFormat_PF_FloatRGBA && FOpenGL::SupportsTextureHalfFloat())
|
|
{
|
|
#if PLATFORM_ANDROID
|
|
SetupTextureFormat(PF_FloatRGBA, FOpenGLTextureFormat(GL_RGBA, GL_RGBA, GL_RGBA16F_EXT, GL_RGBA16F_EXT, GL_RGBA, GL_HALF_FLOAT_OES, false, false));
|
|
#else
|
|
SetupTextureFormat(PF_FloatRGBA, FOpenGLTextureFormat(GL_RGBA, GL_RGBA, GL_RGBA, GL_HALF_FLOAT_OES, false, false));
|
|
#endif
|
|
}
|
|
else
|
|
{
|
|
SetupTextureFormat( PF_FloatRGBA, FOpenGLTextureFormat(GL_RGBA, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, false, false));
|
|
}
|
|
|
|
if (FOpenGL::SupportsColorBufferFloat() && FOpenGL::SupportsTextureFloat())
|
|
{
|
|
SetupTextureFormat( PF_G16, FOpenGLTextureFormat( GL_R16, GL_R16, GL_RED, GL_UNSIGNED_SHORT, false, false));
|
|
SetupTextureFormat( PF_R32_FLOAT, FOpenGLTextureFormat( GL_R32F, GL_R32F, GL_RED, GL_FLOAT, false, false));
|
|
SetupTextureFormat( PF_G16R16F, FOpenGLTextureFormat( GL_RG16F, GL_RG16F, GL_RG_EXT, GL_HALF_FLOAT, false, false));
|
|
SetupTextureFormat( PF_G16R16F_FILTER, FOpenGLTextureFormat( GL_RG16F, GL_RG16F, GL_RG_EXT, GL_HALF_FLOAT, false, false));
|
|
SetupTextureFormat( PF_G32R32F, FOpenGLTextureFormat( GL_RG32F, GL_RG32F, GL_RG_EXT, GL_FLOAT, false, false));
|
|
#ifdef GL_UNSIGNED_INT_2_10_10_10_REV
|
|
SetupTextureFormat( PF_A2B10G10R10, FOpenGLTextureFormat( GL_RGB10_A2, GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false, false));
|
|
#endif
|
|
SetupTextureFormat( PF_R16F, FOpenGLTextureFormat( GL_R16F, GL_R16F, GL_RED, GL_HALF_FLOAT, false, false));
|
|
SetupTextureFormat( PF_R16F_FILTER, FOpenGLTextureFormat( GL_R16F, GL_R16F, GL_RED, GL_HALF_FLOAT, false, false));
|
|
}
|
|
|
|
if (FOpenGL::SupportsPackedDepthStencil())
|
|
{
|
|
SetupTextureFormat(PF_DepthStencil, FOpenGLTextureFormat(GL_DEPTH_STENCIL_OES, GL_NONE, GL_DEPTH_STENCIL_OES, GL_UNSIGNED_INT_24_8_OES, false, false));
|
|
}
|
|
else
|
|
{
|
|
// @todo android: This is cheating by not setting a stencil anywhere, need that! And Shield is still rendering black scene
|
|
SetupTextureFormat(PF_DepthStencil, FOpenGLTextureFormat(GL_DEPTH_COMPONENT, GL_NONE, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, false, false));
|
|
}
|
|
#endif // !PLATFORM_DESKTOP
|
|
}
|
|
|
|
if (FOpenGL::SupportsDXT())
|
|
{
|
|
if ( FOpenGL::SupportsSRGB() )
|
|
{
|
|
SetupTextureFormat( PF_DXT1, FOpenGLTextureFormat(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true, false));
|
|
SetupTextureFormat( PF_DXT3, FOpenGLTextureFormat(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true, false));
|
|
SetupTextureFormat( PF_DXT5, FOpenGLTextureFormat(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true, false));
|
|
}
|
|
else
|
|
{
|
|
// WebGL does not support SRGB versions of DXTn texture formats! Run with SRGB formats disabled. Will need to make sure
|
|
// sRGB is always emulated if it's needed.
|
|
SetupTextureFormat( PF_DXT1, FOpenGLTextureFormat(GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true, false));
|
|
SetupTextureFormat( PF_DXT3, FOpenGLTextureFormat(GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true, false));
|
|
SetupTextureFormat( PF_DXT5, FOpenGLTextureFormat(GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_BYTE, true, false));
|
|
}
|
|
}
|
|
if ( FOpenGL::SupportsPVRTC() )
|
|
{
|
|
SetupTextureFormat( PF_PVRTC2, FOpenGLTextureFormat(GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, GL_RGBA, GL_UNSIGNED_BYTE, true, false));
|
|
SetupTextureFormat( PF_PVRTC4, FOpenGLTextureFormat(GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG, GL_RGBA, GL_UNSIGNED_BYTE, true, false));
|
|
}
|
|
if ( FOpenGL::SupportsATITC() )
|
|
{
|
|
SetupTextureFormat( PF_ATC_RGB, FOpenGLTextureFormat(GL_ATC_RGB_AMD, GL_ATC_RGB_AMD, GL_RGBA, GL_UNSIGNED_BYTE, true, false));
|
|
SetupTextureFormat( PF_ATC_RGBA_E, FOpenGLTextureFormat(GL_ATC_RGBA_EXPLICIT_ALPHA_AMD, GL_ATC_RGBA_EXPLICIT_ALPHA_AMD, GL_RGBA, GL_UNSIGNED_BYTE, true, false));
|
|
SetupTextureFormat( PF_ATC_RGBA_I, FOpenGLTextureFormat(GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD, GL_ATC_RGBA_INTERPOLATED_ALPHA_AMD, GL_RGBA, GL_UNSIGNED_BYTE, true, false));
|
|
}
|
|
if ( FOpenGL::SupportsETC1() )
|
|
{
|
|
SetupTextureFormat( PF_ETC1, FOpenGLTextureFormat(GL_ETC1_RGB8_OES, GL_ETC1_RGB8_OES, GL_RGBA, GL_UNSIGNED_BYTE, true, false));
|
|
}
|
|
#if PLATFORM_ANDROID
|
|
if ( FOpenGL::SupportsETC2() )
|
|
{
|
|
SetupTextureFormat( PF_ETC2_RGB, FOpenGLTextureFormat(GL_COMPRESSED_RGB8_ETC2, FOpenGL::SupportsSRGB() ? GL_COMPRESSED_SRGB8_ETC2 : GL_COMPRESSED_RGB8_ETC2, GL_RGBA, GL_UNSIGNED_BYTE, true, false));
|
|
SetupTextureFormat( PF_ETC2_RGBA, FOpenGLTextureFormat(GL_COMPRESSED_RGBA8_ETC2_EAC, FOpenGL::SupportsSRGB() ? GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : GL_COMPRESSED_RGBA8_ETC2_EAC, GL_RGBA, GL_UNSIGNED_BYTE, true, false));
|
|
}
|
|
#endif
|
|
if (FOpenGL::SupportsASTC())
|
|
{
|
|
SetupTextureFormat( PF_ASTC_4x4, FOpenGLTextureFormat(GL_COMPRESSED_RGBA_ASTC_4x4_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR, GL_RGBA, GL_UNSIGNED_BYTE, true, false) );
|
|
SetupTextureFormat( PF_ASTC_6x6, FOpenGLTextureFormat(GL_COMPRESSED_RGBA_ASTC_6x6_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR, GL_RGBA, GL_UNSIGNED_BYTE, true, false) );
|
|
SetupTextureFormat( PF_ASTC_8x8, FOpenGLTextureFormat(GL_COMPRESSED_RGBA_ASTC_8x8_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR, GL_RGBA, GL_UNSIGNED_BYTE, true, false) );
|
|
SetupTextureFormat( PF_ASTC_10x10, FOpenGLTextureFormat(GL_COMPRESSED_RGBA_ASTC_10x10_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR, GL_RGBA, GL_UNSIGNED_BYTE, true, false) );
|
|
SetupTextureFormat( PF_ASTC_12x12, FOpenGLTextureFormat(GL_COMPRESSED_RGBA_ASTC_12x12_KHR, GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR, GL_RGBA, GL_UNSIGNED_BYTE, true, false) );
|
|
}
|
|
|
|
// Some formats need to know how large a block is.
|
|
GPixelFormats[ PF_DepthStencil ].BlockBytes = 4;
|
|
GPixelFormats[ PF_FloatRGB ].BlockBytes = 4;
|
|
GPixelFormats[ PF_FloatRGBA ].BlockBytes = 8;
|
|
}
|
|
|
|
FOpenGLDynamicRHI::FOpenGLDynamicRHI()
|
|
: SceneFrameCounter(0)
|
|
, ResourceTableFrameCounter(INDEX_NONE)
|
|
, bRevertToSharedContextAfterDrawingViewport(false)
|
|
, bIsRenderingContextAcquired(false)
|
|
, PlatformDevice(NULL)
|
|
, GPUProfilingData(this)
|
|
{
|
|
// This should be called once at the start
|
|
check( IsInGameThread() );
|
|
check( !GIsThreadedRendering );
|
|
|
|
PlatformInitOpenGL();
|
|
PlatformDevice = PlatformCreateOpenGLDevice();
|
|
VERIFY_GL_SCOPE();
|
|
InitRHICapabilitiesForGL();
|
|
|
|
check(PlatformOpenGLCurrentContext(PlatformDevice) == CONTEXT_Shared);
|
|
|
|
PrivateOpenGLDevicePtr = this;
|
|
}
|
|
|
|
extern void DestroyShadersAndPrograms();
|
|
|
|
#if PLATFORM_ANDROID
|
|
// only used to test for shader compatibility issues
|
|
static bool VerifyCompiledShader(GLuint Shader, const ANSICHAR* GlslCode, bool IsFatal )
|
|
{
|
|
SCOPE_CYCLE_COUNTER(STAT_OpenGLShaderCompileVerifyTime);
|
|
|
|
GLint CompileStatus;
|
|
glGetShaderiv(Shader, GL_COMPILE_STATUS, &CompileStatus);
|
|
if (CompileStatus != GL_TRUE)
|
|
{
|
|
GLint LogLength;
|
|
ANSICHAR DefaultLog[] = "No log";
|
|
ANSICHAR *CompileLog = DefaultLog;
|
|
glGetShaderiv(Shader, GL_INFO_LOG_LENGTH, &LogLength);
|
|
#if PLATFORM_ANDROID
|
|
if ( LogLength == 0 )
|
|
{
|
|
// make it big anyway
|
|
// there was a bug in android 2.2 where glGetShaderiv would return 0 even though there was a error message
|
|
// https://code.google.com/p/android/issues/detail?id=9953
|
|
LogLength = 4096;
|
|
}
|
|
#endif
|
|
if (LogLength > 1)
|
|
{
|
|
CompileLog = (ANSICHAR *)FMemory::Malloc(LogLength);
|
|
glGetShaderInfoLog(Shader, LogLength, NULL, CompileLog);
|
|
}
|
|
|
|
#if DEBUG_GL_SHADERS
|
|
if (GlslCode)
|
|
{
|
|
UE_LOG(LogRHI,Warning,TEXT("Shader:\n%s"),ANSI_TO_TCHAR(GlslCode));
|
|
|
|
|
|
const ANSICHAR *Temp = GlslCode;
|
|
|
|
for ( int i = 0; i < 30 && (*Temp != '\0'); ++i )
|
|
{
|
|
FString Converted = ANSI_TO_TCHAR( Temp );
|
|
Converted.LeftChop( 256 );
|
|
|
|
UE_LOG(LogRHI,Display,TEXT("%s"), *Converted );
|
|
Temp += Converted.Len();
|
|
}
|
|
|
|
}
|
|
#endif
|
|
UE_LOG(LogRHI,Warning,TEXT("Failed to compile shader. Compile log:\n%s"), ANSI_TO_TCHAR(CompileLog));
|
|
|
|
if (LogLength > 1)
|
|
{
|
|
FMemory::Free(CompileLog);
|
|
}
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
static void CheckVaryingLimit()
|
|
{
|
|
#if PLATFORM_ANDROID
|
|
FOpenGL::bRequiresGLFragCoordVaryingLimitHack = false;
|
|
if (IsES2Platform(GMaxRHIShaderPlatform))
|
|
{
|
|
// Some mobile GPUs require an available varying vector to support gl_FragCoord.
|
|
// If there are only 8 supported, it is possible to run out of varyings on these
|
|
// GPUs so test to see if need to fake gl_FragCoord with the assumption it is
|
|
// used for mobile HDR mosaic.
|
|
|
|
// Do not need to do this check if more than 8 varyings supported
|
|
if (FOpenGL::GetMaxVaryingVectors() > 8)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Make sure MobileHDR is on and device needs mosaic
|
|
static auto* MobileHDRCvar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileHDR"));
|
|
static auto* MobileHDR32bppModeCvar = IConsoleManager::Get().FindTConsoleVariableDataInt(TEXT("r.MobileHDR32bppMode"));
|
|
|
|
const bool bMobileHDR32bpp = (MobileHDRCvar && MobileHDRCvar->GetValueOnAnyThread() == 1)
|
|
&& (FAndroidMisc::SupportsFloatingPointRenderTargets() == false || (MobileHDR32bppModeCvar && MobileHDR32bppModeCvar->GetValueOnAnyThread() != 0));
|
|
const bool bRequiresMosaic = bMobileHDR32bpp && (!FAndroidMisc::SupportsShaderFramebufferFetch() || (MobileHDR32bppModeCvar && MobileHDR32bppModeCvar->GetValueOnAnyThread() == 1));
|
|
|
|
if (!bRequiresMosaic)
|
|
{
|
|
return;
|
|
}
|
|
|
|
UE_LOG(LogRHI, Display, TEXT("Testing for gl_FragCoord requiring a varying since mosaic is enabled"));
|
|
FOpenGL::bIsCheckingShaderCompilerHacks = true;
|
|
|
|
static const ANSICHAR* TestVertexProgram = "\n"
|
|
"#version 100\n"
|
|
"attribute vec4 in_ATTRIBUTE0;\n"
|
|
"attribute vec4 in_ATTRIBUTE1;\n"
|
|
"varying highp vec4 TexCoord0;\n"
|
|
"varying highp vec4 TexCoord1;\n"
|
|
"varying highp vec4 TexCoord2;\n"
|
|
"varying highp vec4 TexCoord3;\n"
|
|
"varying highp vec4 TexCoord4;\n"
|
|
"varying highp vec4 TexCoord5;\n"
|
|
"varying highp vec4 TexCoord6;\n"
|
|
"varying highp vec4 TexCoord7;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" TexCoord0 = in_ATTRIBUTE1 * vec4(0.1,0.2,0.3,0.4);\n"
|
|
" TexCoord1 = in_ATTRIBUTE1 * vec4(0.5,0.6,0.7,0.8);\n"
|
|
" TexCoord2 = in_ATTRIBUTE1 * vec4(0.12,0.22,0.32,0.42);\n"
|
|
" TexCoord3 = in_ATTRIBUTE1 * vec4(0.52,0.62,0.72,0.82);\n"
|
|
" TexCoord4 = in_ATTRIBUTE1 * vec4(0.14,0.24,0.34,0.44);\n"
|
|
" TexCoord5 = in_ATTRIBUTE1 * vec4(0.54,0.64,0.74,0.84);\n"
|
|
" TexCoord6 = in_ATTRIBUTE1 * vec4(0.16,0.26,0.36,0.46);\n"
|
|
" TexCoord7 = in_ATTRIBUTE1 * vec4(0.56,0.66,0.76,0.86);\n"
|
|
" gl_Position.xyzw = in_ATTRIBUTE0;\n"
|
|
"}\n";
|
|
static const ANSICHAR* TestFragmentProgram = "\n"
|
|
"#version 100\n"
|
|
"varying highp vec4 TexCoord0;\n"
|
|
"varying highp vec4 TexCoord1;\n"
|
|
"varying highp vec4 TexCoord2;\n"
|
|
"varying highp vec4 TexCoord3;\n"
|
|
"varying highp vec4 TexCoord4;\n"
|
|
"varying highp vec4 TexCoord5;\n"
|
|
"varying highp vec4 TexCoord6;\n"
|
|
"varying highp vec4 TexCoord7;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" gl_FragColor = TexCoord0 * TexCoord1 * TexCoord2 * TexCoord3 * TexCoord4 * TexCoord5 * TexCoord6 * TexCoord7 * gl_FragCoord.xyxy;"
|
|
"}\n";
|
|
|
|
FShaderCode VertexShaderCode;
|
|
{
|
|
FOpenGLCodeHeader Header;
|
|
Header.FrequencyMarker = 0x5653;
|
|
Header.GlslMarker = 0x474c534c;
|
|
|
|
FMemoryWriter Writer(VertexShaderCode.GetWriteAccess(), true);
|
|
Writer << Header;
|
|
Writer.Serialize((void*)TestVertexProgram, sizeof(TestVertexProgram));
|
|
Writer.Close();
|
|
}
|
|
|
|
FShaderCode FragmentShaderCode;
|
|
{
|
|
FOpenGLCodeHeader Header;
|
|
Header.FrequencyMarker = 0x5053;
|
|
Header.GlslMarker = 0x474c534c;
|
|
|
|
FMemoryWriter Writer(FragmentShaderCode.GetWriteAccess(), true);
|
|
Writer << Header;
|
|
Writer.Serialize((void*)(TestFragmentProgram), sizeof(TestFragmentProgram));
|
|
Writer.Close();
|
|
}
|
|
|
|
// Try to compile test shaders
|
|
TRefCountPtr<FOpenGLVertexShader> VertexShader = (FOpenGLVertexShader*)(RHICreateVertexShader(VertexShaderCode.GetReadAccess()).GetReference());
|
|
if (!VerifyCompiledShader(VertexShader->Resource, TestVertexProgram, false))
|
|
{
|
|
UE_LOG(LogRHI, Warning, TEXT("Vertex shader for varying test failed to compile. Try running anyway."));
|
|
FOpenGL::bIsCheckingShaderCompilerHacks = false;
|
|
return;
|
|
}
|
|
TRefCountPtr<FOpenGLPixelShader> PixelShader = (FOpenGLPixelShader*)(RHICreatePixelShader(FragmentShaderCode.GetReadAccess()).GetReference());
|
|
if (!VerifyCompiledShader(PixelShader->Resource, TestFragmentProgram, false))
|
|
{
|
|
UE_LOG(LogRHI, Warning, TEXT("Fragment shader for varying test failed to compile. Try running anyway."));
|
|
FOpenGL::bIsCheckingShaderCompilerHacks = false;
|
|
return;
|
|
}
|
|
|
|
FOpenGL::bIsCheckingShaderCompilerHacks = false;
|
|
|
|
// Now try linking them.. this is where gl_FragCoord may cause a failure
|
|
GLuint Program = glCreateProgram();
|
|
glAttachShader(Program, VertexShader->Resource);
|
|
glAttachShader(Program, PixelShader->Resource);
|
|
glLinkProgram(Program);
|
|
GLint LinkStatus = 0;
|
|
glGetProgramiv(Program, GL_LINK_STATUS, &LinkStatus);
|
|
if (LinkStatus != GL_TRUE)
|
|
{
|
|
FOpenGL::bRequiresGLFragCoordVaryingLimitHack = true;
|
|
UE_LOG(LogRHI, Warning, TEXT("gl_FragCoord uses a varying... enabled hack"));
|
|
return;
|
|
}
|
|
|
|
UE_LOG(LogRHI, Warning, TEXT("gl_FragCoord does not need a varying"));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
static void CheckTextureCubeLodSupport()
|
|
{
|
|
#if PLATFORM_ANDROID
|
|
if (IsES2Platform(GMaxRHIShaderPlatform))
|
|
{
|
|
UE_LOG(LogRHI, Display, TEXT("Testing for shader compiler compatibility"));
|
|
FOpenGL::bIsCheckingShaderCompilerHacks = true;
|
|
|
|
// This code creates a sample program and finds out which hacks are required to compile it
|
|
static const ANSICHAR TestFragmentProgram[] = "\n"
|
|
"#version 100\n"
|
|
"#ifndef DONTEMITEXTENSIONSHADERTEXTURELODENABLE\n"
|
|
"#extension GL_EXT_shader_texture_lod : enable\n"
|
|
"#endif\n"
|
|
"precision mediump float;\n"
|
|
"precision mediump int;\n"
|
|
"#ifndef DONTEMITSAMPLERDEFAULTPRECISION\n"
|
|
"precision mediump sampler2D;\n"
|
|
"precision mediump samplerCube;\n"
|
|
"#endif\n"
|
|
"varying vec3 TexCoord;\n"
|
|
"uniform samplerCube Texture;\n"
|
|
"void main()\n"
|
|
"{\n"
|
|
" gl_FragColor = textureCubeLodEXT(Texture,TexCoord, 4.0);\n"
|
|
"}\n";
|
|
|
|
FOpenGL::bRequiresDontEmitPrecisionForTextureSamplers = false;
|
|
FOpenGL::bRequiresTextureCubeLodEXTToTextureCubeLodDefine = false;
|
|
|
|
FShaderCode ShaderCode;
|
|
{
|
|
FOpenGLCodeHeader Header;
|
|
Header.FrequencyMarker = 0x5053;
|
|
Header.GlslMarker = 0x474c534c;
|
|
|
|
FMemoryWriter Writer(ShaderCode.GetWriteAccess(), true);
|
|
Writer << Header;
|
|
Writer.Serialize((void*)TestFragmentProgram, sizeof(TestFragmentProgram));
|
|
Writer.Close();
|
|
}
|
|
const TArray<uint8>& Code = ShaderCode.GetReadAccess();
|
|
|
|
// try to compile without any hacks
|
|
TRefCountPtr<FOpenGLPixelShader> PixelShader = (FOpenGLPixelShader*)(RHICreatePixelShader(Code).GetReference());
|
|
|
|
if (VerifyCompiledShader(PixelShader->Resource, TestFragmentProgram, false))
|
|
{
|
|
UE_LOG(LogRHI, Display, TEXT("Shaders compile fine no need to enable hacks"));
|
|
// we are done
|
|
FOpenGL::bIsCheckingShaderCompilerHacks = false;
|
|
return;
|
|
}
|
|
|
|
FOpenGL::bRequiresDontEmitPrecisionForTextureSamplers = true;
|
|
FOpenGL::bRequiresTextureCubeLodEXTToTextureCubeLodDefine = false;
|
|
|
|
// second most number of devices fall into this hack category
|
|
// try to compile without using precision for texture samplers
|
|
// Samsung Galaxy Express Samsung Galaxy S3 Samsung Galaxy S3 mini Samsung Galaxy Tab GT-P1000 Samsung Galaxy Tab 2
|
|
PixelShader = (FOpenGLPixelShader*)(RHICreatePixelShader(Code).GetReference());
|
|
|
|
if (VerifyCompiledShader(PixelShader->Resource, TestFragmentProgram, false))
|
|
{
|
|
UE_LOG(LogRHI, Warning, TEXT("Enabling shader compiler hack to remove precision modifiers for texture samplers"));
|
|
|
|
// we are done
|
|
FOpenGL::bIsCheckingShaderCompilerHacks = false;
|
|
return;
|
|
}
|
|
|
|
FOpenGL::bRequiresDontEmitPrecisionForTextureSamplers = false;
|
|
FOpenGL::bRequiresTextureCubeLodEXTToTextureCubeLodDefine = true;
|
|
|
|
// third most likely Samsung Galaxy Tab GT-P1000
|
|
PixelShader = (FOpenGLPixelShader*)(RHICreatePixelShader(Code).GetReference());
|
|
|
|
if (VerifyCompiledShader(PixelShader->Resource, TestFragmentProgram, false))
|
|
{
|
|
UE_LOG(LogRHI, Warning, TEXT("Enabling shader compiler hack to redefine textureCubeLodEXT to textureCubeLod"));
|
|
// we are done
|
|
FOpenGL::bIsCheckingShaderCompilerHacks = false;
|
|
return;
|
|
}
|
|
|
|
FOpenGL::bRequiresDontEmitPrecisionForTextureSamplers = true;
|
|
FOpenGL::bRequiresTextureCubeLodEXTToTextureCubeLodDefine = true;
|
|
|
|
// try both hacks
|
|
PixelShader = (FOpenGLPixelShader*)(RHICreatePixelShader(Code).GetReference());
|
|
|
|
if (VerifyCompiledShader(PixelShader->Resource, TestFragmentProgram, false))
|
|
{
|
|
UE_LOG(LogRHI, Warning, TEXT("Enabling shader compiler hack to redefine textureCubeLodEXT to textureCubeLod and remove precision modifiers"));
|
|
// we are done
|
|
FOpenGL::bIsCheckingShaderCompilerHacks = false;
|
|
return;
|
|
}
|
|
|
|
UE_LOG(LogRHI, Warning, TEXT("Unable to find a test shader that compiles try running anyway"));
|
|
FOpenGL::bIsCheckingShaderCompilerHacks = false;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::Init()
|
|
{
|
|
check(!GIsRHIInitialized);
|
|
VERIFY_GL_SCOPE();
|
|
|
|
#if PLATFORM_DESKTOP
|
|
FShaderCache::InitShaderCache(SCO_Default, FOpenGL::GetMaxTextureImageUnits());
|
|
#endif
|
|
|
|
InitializeStateResources();
|
|
|
|
// Create a default point sampler state for internal use.
|
|
FSamplerStateInitializerRHI PointSamplerStateParams(SF_Point,AM_Clamp,AM_Clamp,AM_Clamp);
|
|
PointSamplerState = this->RHICreateSamplerState(PointSamplerStateParams);
|
|
|
|
// Allocate vertex and index buffers for DrawPrimitiveUP calls.
|
|
DynamicVertexBuffers.Init(CalcDynamicBufferSize(1));
|
|
DynamicIndexBuffers.Init(CalcDynamicBufferSize(1));
|
|
|
|
// Notify all initialized FRenderResources that there's a valid RHI device to create their RHI resources for now.
|
|
for(TLinkedList<FRenderResource*>::TIterator ResourceIt(FRenderResource::GetResourceList());ResourceIt;ResourceIt.Next())
|
|
{
|
|
ResourceIt->InitRHI();
|
|
}
|
|
// Dynamic resources can have dependencies on static resources (with uniform buffers) and must initialized last!
|
|
for(TLinkedList<FRenderResource*>::TIterator ResourceIt(FRenderResource::GetResourceList());ResourceIt;ResourceIt.Next())
|
|
{
|
|
ResourceIt->InitDynamicRHI();
|
|
}
|
|
|
|
#if PLATFORM_WINDOWS || PLATFORM_MAC || PLATFORM_LINUX
|
|
|
|
extern int64 GOpenGLDedicatedVideoMemory;
|
|
extern int64 GOpenGLTotalGraphicsMemory;
|
|
|
|
GOpenGLDedicatedVideoMemory = FOpenGL::GetVideoMemorySize();
|
|
|
|
if ( GOpenGLDedicatedVideoMemory != 0)
|
|
{
|
|
GOpenGLTotalGraphicsMemory = GOpenGLDedicatedVideoMemory;
|
|
|
|
if ( GPoolSizeVRAMPercentage > 0 )
|
|
{
|
|
float PoolSize = float(GPoolSizeVRAMPercentage) * 0.01f * float(GOpenGLTotalGraphicsMemory);
|
|
|
|
// Truncate GTexturePoolSize to MB (but still counted in bytes)
|
|
GTexturePoolSize = int64(FGenericPlatformMath::TruncToInt(PoolSize / 1024.0f / 1024.0f)) * 1024 * 1024;
|
|
|
|
UE_LOG(LogRHI, Log, TEXT("Texture pool is %llu MB (%d%% of %llu MB)"),
|
|
GTexturePoolSize / 1024 / 1024,
|
|
GPoolSizeVRAMPercentage,
|
|
GOpenGLTotalGraphicsMemory / 1024 / 1024);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
// Flush here since we might be switching to a different context/thread for rendering
|
|
FOpenGL::Flush();
|
|
|
|
FHardwareInfo::RegisterHardwareInfo( NAME_RHI, TEXT( "OpenGL" ) );
|
|
|
|
// Set the RHI initialized flag.
|
|
GIsRHIInitialized = true;
|
|
|
|
CheckTextureCubeLodSupport();
|
|
CheckVaryingLimit();
|
|
|
|
#if PLATFORM_DESKTOP
|
|
FShaderCache::LoadBinaryCache();
|
|
#endif
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::Shutdown()
|
|
{
|
|
check(IsInGameThread() && IsInRenderingThread()); // require that the render thread has been shut down
|
|
|
|
Cleanup();
|
|
|
|
DestroyShadersAndPrograms();
|
|
PlatformDestroyOpenGLDevice(PlatformDevice);
|
|
|
|
PrivateOpenGLDevicePtr = NULL;
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::Cleanup()
|
|
{
|
|
if(GIsRHIInitialized)
|
|
{
|
|
#if PLATFORM_DESKTOP
|
|
FShaderCache::ShutdownShaderCache();
|
|
#endif
|
|
|
|
// Reset the RHI initialized flag.
|
|
GIsRHIInitialized = false;
|
|
|
|
GPUProfilingData.Cleanup();
|
|
|
|
// Ask all initialized FRenderResources to release their RHI resources.
|
|
for(TLinkedList<FRenderResource*>::TIterator ResourceIt(FRenderResource::GetResourceList());ResourceIt;ResourceIt.Next())
|
|
{
|
|
ResourceIt->ReleaseRHI();
|
|
}
|
|
for(TLinkedList<FRenderResource*>::TIterator ResourceIt(FRenderResource::GetResourceList());ResourceIt;ResourceIt.Next())
|
|
{
|
|
ResourceIt->ReleaseDynamicRHI();
|
|
}
|
|
}
|
|
|
|
// Release dynamic vertex and index buffers.
|
|
DynamicVertexBuffers.Cleanup();
|
|
DynamicIndexBuffers.Cleanup();
|
|
|
|
FreeZeroStrideBuffers();
|
|
|
|
// Release the point sampler state.
|
|
PointSamplerState.SafeRelease();
|
|
|
|
extern void EmptyGLSamplerStateCache();
|
|
EmptyGLSamplerStateCache();
|
|
|
|
// Release zero-filled dummy uniform buffer, if it exists.
|
|
if (PendingState.ZeroFilledDummyUniformBuffer)
|
|
{
|
|
FOpenGL::DeleteBuffers(1, &PendingState.ZeroFilledDummyUniformBuffer);
|
|
PendingState.ZeroFilledDummyUniformBuffer = 0;
|
|
DecrementBufferMemory(GL_UNIFORM_BUFFER, false, ZERO_FILLED_DUMMY_UNIFORM_BUFFER_SIZE);
|
|
}
|
|
|
|
// Release pending shader
|
|
PendingState.BoundShaderState.SafeRelease();
|
|
check(!IsValidRef(PendingState.BoundShaderState));
|
|
|
|
PendingState.CleanupResources();
|
|
SharedContextState.CleanupResources();
|
|
RenderingContextState.CleanupResources();
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::RHIFlushResources()
|
|
{
|
|
PlatformFlushIfNeeded();
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::RHIAcquireThreadOwnership()
|
|
{
|
|
check(!bRevertToSharedContextAfterDrawingViewport); // if this is true, then main thread is rendering using our context right now.
|
|
PlatformRenderingContextSetup(PlatformDevice);
|
|
PlatformRebindResources(PlatformDevice);
|
|
bIsRenderingContextAcquired = true;
|
|
VERIFY_GL(RHIAcquireThreadOwnership);
|
|
{
|
|
FScopeLock lock(&CustomPresentSection);
|
|
if (CustomPresent)
|
|
{
|
|
CustomPresent->OnAcquireThreadOwnership();
|
|
}
|
|
}
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::RHIReleaseThreadOwnership()
|
|
{
|
|
{
|
|
FScopeLock lock(&CustomPresentSection);
|
|
if (CustomPresent)
|
|
{
|
|
CustomPresent->OnReleaseThreadOwnership();
|
|
}
|
|
}
|
|
VERIFY_GL(RHIReleaseThreadOwnership);
|
|
bIsRenderingContextAcquired = false;
|
|
PlatformNULLContextSetup();
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::RegisterQuery( FOpenGLRenderQuery* Query )
|
|
{
|
|
FScopeLock Lock(&QueriesListCriticalSection);
|
|
Queries.Add(Query);
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::UnregisterQuery( FOpenGLRenderQuery* Query )
|
|
{
|
|
FScopeLock Lock(&QueriesListCriticalSection);
|
|
Queries.RemoveSingleSwap(Query);
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::RHIAutomaticCacheFlushAfterComputeShader(bool bEnable)
|
|
{
|
|
// Nothing to do here...
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::RHIFlushComputeShaderCache()
|
|
{
|
|
// Nothing to do here...
|
|
}
|
|
|
|
|
|
|
|
void* FOpenGLDynamicRHI::RHIGetNativeDevice()
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::InvalidateQueries( void )
|
|
{
|
|
{
|
|
FScopeLock Lock(&QueriesListCriticalSection);
|
|
PendingState.RunningOcclusionQuery = 0;
|
|
for( int32 Index = 0; Index < Queries.Num(); ++Index )
|
|
{
|
|
Queries[Index]->bInvalidResource = true;
|
|
}
|
|
}
|
|
|
|
{
|
|
FScopeLock Lock(&TimerQueriesListCriticalSection);
|
|
|
|
for( int32 Index = 0; Index < TimerQueries.Num(); ++Index )
|
|
{
|
|
TimerQueries[Index]->bInvalidResource = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
void FOpenGLDynamicRHI::SetCustomPresent(FRHICustomPresent* InCustomPresent)
|
|
{
|
|
FScopeLock lock(&CustomPresentSection);
|
|
CustomPresent = InCustomPresent;
|
|
}
|
|
|
|
bool FOpenGLDynamicRHIModule::IsSupported()
|
|
{
|
|
return PlatformInitOpenGL();
|
|
}
|