Files
UnrealEngine/Engine/Source/Developer/StandaloneRenderer/Private/Linux/OpenGL/SlateOpenGLContext.cpp
2025-05-18 13:04:45 +08:00

315 lines
8.2 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
#include "CoreMinimal.h"
#include "Misc/CommandLine.h"
#include "OpenGL/SlateOpenGLExtensions.h"
#include "StandaloneRendererLog.h"
#include "OpenGL/SlateOpenGLRenderer.h"
#include "HAL/PlatformApplicationMisc.h"
#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* KHRTypeStrings[] =
{
TEXT("Marker"),
TEXT("PushGroup"),
TEXT("PopGroup"),
};
if (Type >= GL_DEBUG_TYPE_MARKER && Type <= GL_DEBUG_TYPE_POP_GROUP)
{
return KHRTypeStrings[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.
*/
static void APIENTRY OpenGLDebugMessageCallbackARB(
GLenum Source,
GLenum Type,
GLuint Id,
GLenum Severity,
GLsizei Length,
const GLchar* Message,
GLvoid* UserParam)
{
#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) <= FLogCategoryLogStandaloneRenderer::CompileTimeVerbosity)
{
if (!LogStandaloneRenderer.IsSuppressed(Verbosity))
{
FMsg::Logf(__FILE__, __LINE__, LogStandaloneRenderer.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 // defined(GL_ARB_debug_output) || defined(GL_KHR_debug)
/**
* Enable/Disable debug context from the commandline
*/
static bool PlatformOpenGLDebugCtx()
{
#if UE_BUILD_DEBUG
return ! FParse::Param(FCommandLine::Get(),TEXT("openglNoDebug"));
#else
return FParse::Param(FCommandLine::Get(),TEXT("openglDebug"));;
#endif
}
static SDL_Window* CreateDummyGLWindow()
{
FPlatformApplicationMisc::InitSDL(); // will not initialize more than once
#if DO_CHECK
uint32 InitializedSubsystems = SDL_WasInit(SDL_INIT_VIDEO);
check(InitializedSubsystems & SDL_INIT_VIDEO);
#endif // DO_CHECK
// Create a dummy window.
SDL_Window *h_wnd = SDL_CreateWindow( NULL,
1, 1,
SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_HIDDEN );
return h_wnd;
}
FSlateOpenGLContext::FSlateOpenGLContext()
: WindowHandle(NULL)
, Context(NULL)
, bReleaseWindowOnDestroy(false)
#if LINUX_USE_OPENGL_3_2
, VertexArrayObject(0)
#endif // LINUX_USE_OPENGL_3_2
{
}
FSlateOpenGLContext::~FSlateOpenGLContext()
{
Destroy();
}
void FSlateOpenGLContext::Initialize( void* InWindow, const FSlateOpenGLContext* SharedContext )
{
WindowHandle = (SDL_Window*)InWindow;
if ( WindowHandle == NULL )
{
WindowHandle = CreateDummyGLWindow();
bReleaseWindowOnDestroy = true;
}
if (SDL_GL_LoadLibrary(nullptr) == false)
{
FString SdlError(ANSI_TO_TCHAR(SDL_GetError()));
UE_LOG(LogInit, Fatal, TEXT("FSlateOpenGLContext::Initialize - Unable to dynamically load libGL: %s\n."), *SdlError);
}
int OpenGLMajorVersionToUse = 2;
int OpenGLMinorVersionToUse = 1;
#if LINUX_USE_OPENGL_3_2
OpenGLMajorVersionToUse = 3;
OpenGLMinorVersionToUse = 2;
#endif // LINUX_USE_OPENGL_3_2
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, OpenGLMajorVersionToUse );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, OpenGLMinorVersionToUse );
SDL_GL_SetAttribute( SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE );
if (PlatformOpenGLDebugCtx())
{
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG);
}
if( SharedContext )
{
SDL_GL_SetAttribute( SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 1 );
SDL_GL_MakeCurrent( SharedContext->WindowHandle, SharedContext->Context );
}
else
{
SDL_GL_SetAttribute( SDL_GL_SHARE_WITH_CURRENT_CONTEXT, 0 );
}
UE_LOG(LogInit, Log, TEXT("FSlateOpenGLContext::Initialize - creating OpenGL %d.%d context"), OpenGLMajorVersionToUse, OpenGLMinorVersionToUse);
Context = SDL_GL_CreateContext( WindowHandle );
if (Context == nullptr)
{
FString SdlError(ANSI_TO_TCHAR(SDL_GetError()));
// ignore errors getting version, it will be clear from the logs
int OpenGLMajorVersion = -1;
int OpenGLMinorVersion = -1;
SDL_GL_GetAttribute( SDL_GL_CONTEXT_MAJOR_VERSION, &OpenGLMajorVersion );
SDL_GL_GetAttribute( SDL_GL_CONTEXT_MINOR_VERSION, &OpenGLMinorVersion );
UE_LOG(LogInit, Fatal, TEXT("FSlateOpenGLContext::Initialize - Could not create OpenGL %d.%d context, SDL error: '%s'"),
OpenGLMajorVersion, OpenGLMinorVersion,
*SdlError
);
// unreachable
return;
}
SDL_GL_MakeCurrent( WindowHandle, Context );
LoadOpenGLExtensions();
if (PlatformOpenGLDebugCtx())
{
if (glDebugMessageCallbackARB)
{
#if GL_ARB_debug_output || GL_KHR_debug
// 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=*/ nullptr);
checkf(glGetError() == GL_NO_ERROR, TEXT("Could not register glDebugMessageCallbackARB()"));
if(glDebugMessageControlARB)
{
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(LogStandaloneRenderer,Verbose,TEXT("disabling reporting back of debug groups and markers to the OpenGL debug output callback"));
}
#endif // GL_ARB_debug_output || GL_KHR_debug
}
}
#if LINUX_USE_OPENGL_3_2
// one Vertex Array Object is reportedly needed for OpenGL 3.2+ core profiles
glGenVertexArrays(1, &VertexArrayObject);
glBindVertexArray(VertexArrayObject);
#endif // LINUX_USE_OPENGL_3_2
}
void FSlateOpenGLContext::Destroy()
{
if ( WindowHandle != NULL )
{
SDL_GL_MakeCurrent( NULL, NULL );
#if LINUX_USE_OPENGL_3_2
glDeleteVertexArrays(1, &VertexArrayObject);
#endif // LINUX_USE_OPENGL_3_2
SDL_GL_DestroyContext( Context );
if ( bReleaseWindowOnDestroy )
{
SDL_DestroyWindow( WindowHandle );
// we will tear down SDL in PlatformTearDown()
}
WindowHandle = NULL;
}
}
void FSlateOpenGLContext::MakeCurrent()
{
if ( WindowHandle )
{
if(SDL_GL_MakeCurrent( WindowHandle, Context ) == 0)
{
#if LINUX_USE_OPENGL_3_2
glBindVertexArray(VertexArrayObject);
#endif // LINUX_USE_OPENGL_3_2
}
}
}