Files
UnrealEngine/Engine/Source/Runtime/OpenGLDrv/Private/Android/AndroidEGL.h
2025-05-18 13:04:45 +08:00

245 lines
6.6 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
AndroidEGL.h: Private EGL definitions for Android-specific functionality
=============================================================================*/
#pragma once
#include "Android/AndroidPlatform.h"
#if USE_ANDROID_OPENGL
#include "CoreMinimal.h"
#include "Logging/LogMacros.h"
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <GLES3/gl31.h>
#include "Android/AndroidWindow.h"
struct AndroidESPImpl;
struct ANativeWindow;
#ifndef USE_ANDROID_EGL_NO_ERROR_CONTEXT
#if UE_BUILD_SHIPPING
#define USE_ANDROID_EGL_NO_ERROR_CONTEXT 1
#else
#define USE_ANDROID_EGL_NO_ERROR_CONTEXT 0
#endif
#endif // USE_ANDROID_EGL_NO_ERROR_CONTEXT
DECLARE_LOG_CATEGORY_EXTERN(LogEGL, Log, All);
struct FPlatformOpenGLContext
{
EGLContext eglContext;
GLuint ViewportFramebuffer;
EGLSurface eglSurface;
GLuint DefaultVertexArrayObject;
GLuint BackBufferResource;
GLenum BackBufferTarget;
GLuint DummyFrameBuffer;
FPlatformOpenGLContext()
{
Reset();
}
void Reset()
{
eglContext = EGL_NO_CONTEXT;
eglSurface = EGL_NO_SURFACE;
ViewportFramebuffer = 0;
DefaultVertexArrayObject = 0;
BackBufferResource = 0;
BackBufferTarget = 0;
DummyFrameBuffer = 0;
}
};
class AndroidEGL
{
public:
enum APIVariant
{
AV_OpenGLES,
AV_OpenGLCore
};
static AndroidEGL* GetInstance();
~AndroidEGL();
bool IsInitialized();
void InitBackBuffer();
void DestroyBackBuffer();
void Init(APIVariant API, uint32 MajorVersion, uint32 MinorVersion);
void UnBindRender();
void Terminate();
// Initialize the surface of the context.
// when using the new window locking behavior, if WindowContainer is not set an off screen surface will be used.
// TODO: remove bCreateWndSurface (and possibly bUseSmallSurface), these can be inferred from WindowContainer.
void InitRenderSurface(bool bUseSmallSurface, bool bCreateWndSurface, const TOptional<FAndroidWindow::FNativeAccessor>& WindowContainer);
void UpdateBuffersTransform();
bool IsOfflineSurfaceRequired();
void GetDimensions(uint32& OutWidth, uint32& OutHeight);
bool IsUsingRobustContext() const { return bIsEXTRobustContextActive; }
EGLDisplay GetDisplay() const;
EGLSurface GetSurface() const;
EGLConfig GetConfig() const;
ANativeWindow* GetNativeWindow() const;
void GetSwapIntervalRange(EGLint& OutMinSwapInterval, EGLint& OutMaxSwapInterval) const;
EGLContext CreateContext(EGLContext InParentContext);
int32 GetError();
EGLBoolean SetCurrentContext(EGLContext InContext, EGLSurface InSurface);
void AcquireCurrentRenderingContext();
void ReleaseContextOwnership();
GLuint GetResolveFrameBuffer();
EGLContext GetCurrentContext();
void SetCurrentRenderingContext();
bool ThreadHasRenderingContext();
FPlatformOpenGLContext* GetRenderingContext();
bool GetSupportsNoErrorContext();
// recreate the EGL surface for the current hardware window.
void SetRenderContextWindowSurface(const TOptional<FAndroidWindow::FNativeAccessor>& WindowHandle);
// Called from game thread when a window is reinited.
void RefreshWindowSize(const TOptional<FAndroidWindow::FNativeAccessor>& WindowContainer);
// true if the current surface is associated with a window.
bool IsUsingWindowedSurface() const;
protected:
AndroidEGL();
static AndroidEGL* Singleton;
private:
void InitEGL(APIVariant API);
void TerminateEGL();
void CreateEGLRenderSurface(ANativeWindow* InWindow, bool bCreateWndSurface);
void DestroyRenderSurface();
bool InitContexts();
void DestroyContext(EGLContext InContext);
void ResetDisplay();
AndroidESPImpl* PImplData;
void ResetInternal();
void LogConfigInfo(EGLConfig EGLConfigInfo);
// Actual Update to the egl surface to match the GT's requested size.
void ResizeRenderContextSurface(const TOptional<FAndroidWindow::FNativeAccessor>& WindowContainer);
bool bSupportsKHRCreateContext = false;
bool bSupportsKHRSurfacelessContext = false;
bool bSupportsKHRNoErrorContext = false;
bool bSupportsEXTRobustContext = false;
bool bIsEXTRobustContextActive = false;
int* ContextAttributes = nullptr;
};
#define ENABLE_CONFIG_FILTER 1
#define ENABLE_EGL_DEBUG 0
#define ENABLE_VERIFY_EGL 0
#define ENABLE_VERIFY_EGL_TRACE 0
#if ENABLE_VERIFY_EGL
#define VERIFY_EGL(msg) { VerifyEGLResult(eglGetError(),TEXT(#msg),TEXT(""),TEXT(__FILE__),__LINE__); }
void VerifyEGLResult(EGLint ErrorCode, const TCHAR* Msg1, const TCHAR* Msg2, const TCHAR* Filename, uint32 Line)
{
if (ErrorCode != EGL_SUCCESS)
{
static const TCHAR* EGLErrorStrings[] =
{
TEXT("EGL_NOT_INITIALIZED"),
TEXT("EGL_BAD_ACCESS"),
TEXT("EGL_BAD_ALLOC"),
TEXT("EGL_BAD_ATTRIBUTE"),
TEXT("EGL_BAD_CONFIG"),
TEXT("EGL_BAD_CONTEXT"),
TEXT("EGL_BAD_CURRENT_SURFACE"),
TEXT("EGL_BAD_DISPLAY"),
TEXT("EGL_BAD_MATCH"),
TEXT("EGL_BAD_NATIVE_PIXMAP"),
TEXT("EGL_BAD_NATIVE_WINDOW"),
TEXT("EGL_BAD_PARAMETER"),
TEXT("EGL_BAD_SURFACE"),
TEXT("EGL_CONTEXT_LOST"),
TEXT("UNKNOWN EGL ERROR")
};
uint32 ErrorIndex = FMath::Min<uint32>(ErrorCode - EGL_SUCCESS, UE_ARRAY_COUNT(EGLErrorStrings) - 1);
UE_LOG(LogRHI, Warning, TEXT("%s(%u): %s%s failed with error %s (0x%x)"),
Filename, Line, Msg1, Msg2, EGLErrorStrings[ErrorIndex], ErrorCode);
check(0);
}
}
class FEGLErrorScope
{
public:
FEGLErrorScope(
const TCHAR* InFunctionName,
const TCHAR* InFilename,
const uint32 InLine)
: FunctionName(InFunctionName)
, Filename(InFilename)
, Line(InLine)
{
#if ENABLE_VERIFY_EGL_TRACE
UE_LOG(LogRHI, Log, TEXT("EGL log before %s(%d): %s"), InFilename, InLine, InFunctionName);
#endif
CheckForErrors(TEXT("Before "));
}
~FEGLErrorScope()
{
#if ENABLE_VERIFY_EGL_TRACE
UE_LOG(LogRHI, Log, TEXT("EGL log after %s(%d): %s"), Filename, Line, FunctionName);
#endif
CheckForErrors(TEXT("After "));
}
private:
const TCHAR* FunctionName;
const TCHAR* Filename;
const uint32 Line;
void CheckForErrors(const TCHAR* PrefixString)
{
VerifyEGLResult(eglGetError(), PrefixString, FunctionName, Filename, Line);
}
};
#define MACRO_TOKENIZER(IdentifierName, Msg, FileName, LineNumber) FEGLErrorScope IdentifierName_ ## LineNumber (Msg, FileName, LineNumber)
#define MACRO_TOKENIZER2(IdentifierName, Msg, FileName, LineNumber) MACRO_TOKENIZER(IdentiferName, Msg, FileName, LineNumber)
#define VERIFY_EGL_SCOPE_WITH_MSG_STR(MsgStr) MACRO_TOKENIZER2(ErrorScope_, MsgStr, TEXT(__FILE__), __LINE__)
#define VERIFY_EGL_SCOPE() VERIFY_EGL_SCOPE_WITH_MSG_STR(ANSI_TO_TCHAR(__FUNCTION__))
#define VERIFY_EGL_FUNC(Func, ...) { VERIFY_EGL_SCOPE_WITH_MSG_STR(TEXT(#Func)); Func(__VA_ARGS__); }
#else
#define VERIFY_EGL(...)
#define VERIFY_EGL_SCOPE(...)
#endif
#endif