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

302 lines
14 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
/*=============================================================================
OpenGLES.cpp: OpenGL ES implementation.
=============================================================================*/
#include "OpenGLES.h"
#if UGL_PLATFORM_SUPPORTS_GLES
#include "OpenGLDrvPrivate.h"
/** GL_EXT_disjoint_timer_query */
bool FOpenGLES::bSupportsDisjointTimeQueries = false;
static TAutoConsoleVariable<int32> CVarDisjointTimerQueries(
TEXT("r.DisjointTimerQueries"),
0,
TEXT("If set to 1, allows GPU time to be measured (e.g. STAT UNIT). It defaults to 0 because some devices supports it but very slowly."),
ECVF_ReadOnly);
/** Some timer query implementations are never disjoint */
bool FOpenGLES::bTimerQueryCanBeDisjoint = true;
/** GL_APPLE_texture_format_BGRA8888 */
bool FOpenGLES::bSupportsBGRA8888 = false;
/** GL_EXT_color_buffer_half_float */
bool FOpenGLES::bSupportsColorBufferHalfFloat = false;
/** GL_EXT_color_buffer_float */
bool FOpenGLES::bSupportsColorBufferFloat = false;
/** GL_EXT_shader_framebuffer_fetch */
bool FOpenGLES::bSupportsShaderFramebufferFetch = false;
/** GL_EXT_shader_framebuffer_fetch (MRT's) */
bool FOpenGLES::bSupportsShaderMRTFramebufferFetch = false;
/** GL_ARM_shader_framebuffer_fetch_depth_stencil */
bool FOpenGLES::bSupportsShaderDepthStencilFetch = false;
/** GL_EXT_multisampled_render_to_texture */
bool FOpenGLES::bSupportsMultisampledRenderToTexture = false;
/** OpenGL ES 3.0 profile */
bool FOpenGLES::bSupportsETC2 = false;
/** GL_EXT_shader_pixel_local_storage */
bool FOpenGLES::bSupportsPixelLocalStorage = false;
/** GL_FRAGMENT_SHADER, GL_LOW_FLOAT */
int FOpenGLES::ShaderLowPrecision = 0;
/** GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT */
int FOpenGLES::ShaderMediumPrecision = 0;
/** GL_FRAGMENT_SHADER, GL_HIGH_FLOAT */
int FOpenGLES::ShaderHighPrecision = 0;
/** GL_NV_framebuffer_blit */
bool FOpenGLES::bSupportsNVFrameBufferBlit = false;
/* This indicates failure when attempting to retrieve driver's binary representation of the hack program */
bool FOpenGLES::bBinaryProgramRetrievalFailed = false;
/* Some Mali devices do not work correctly with early_fragment_test enabled */
bool FOpenGLES::bRequiresDisabledEarlyFragmentTests = false;
/* This is a workaround for a Mali bug where read-only buffers do not work when passed to functions*/
bool FOpenGLES::bRequiresReadOnlyBuffersWorkaround = false;
/* This is a workaround for Samsung xclipse that fails to compile shaders that use the 'precise' qualifier*/
bool FOpenGLES::bRequiresPreciseQualifierWorkaround = false;
/* This is to avoid a bug in Adreno drivers that define GL_ARM_shader_framebuffer_fetch_depth_stencil even when device does not support this extension */
bool FOpenGLES::bRequiresARMShaderFramebufferFetchDepthStencilUndef = false;
/** Framebuffer fetch can be used to do programmable blending without running into driver issues */
bool FOpenGLES::bSupportsShaderFramebufferFetchProgrammableBlending = true;
/** GL_EXT_buffer_storage */
bool FOpenGLES::bSupportsBufferStorage = false;
/** GL_EXT_depth_clamp */
bool FOpenGLES::bSupportsDepthClamp = false;
bool FOpenGLES::bHasHardwareHiddenSurfaceRemoval = false;
bool FOpenGLES::bSupportsMobileMultiView = false;
GLint FOpenGLES::MaxMSAASamplesTileMem = 1;
GLint FOpenGLES::MaxComputeUniformComponents = -1;
GLint FOpenGLES::MaxComputeUAVUnits = -1;
GLint FOpenGLES::MaxPixelUAVUnits = -1;
GLint FOpenGLES::MaxCombinedUAVUnits = 0;
/** GL_EXT_texture_compression_astc_decode_mode */
bool FOpenGLES::bSupportsASTCDecodeMode = false;
// GL_OES_get_program_binary
bool FOpenGLES::bSupportsProgramBinary = false;
FOpenGLES::EFeatureLevelSupport FOpenGLES::CurrentFeatureLevelSupport = FOpenGLES::EFeatureLevelSupport::ES31;
bool FOpenGLES::SupportsDisjointTimeQueries()
{
bool bAllowDisjointTimerQueries = false;
bAllowDisjointTimerQueries = (CVarDisjointTimerQueries.GetValueOnRenderThread() == 1);
return bSupportsDisjointTimeQueries && bAllowDisjointTimerQueries;
}
void FOpenGLES::ProcessQueryGLInt()
{
GLint MaxVertexAttribs;
LOG_AND_GET_GL_INT(GL_MAX_VERTEX_ATTRIBS, 0, MaxVertexAttribs);
if (MaxVertexAttribs < 16)
{
UE_LOG(LogRHI, Error,
TEXT("Device reports support for %d vertex attributes, UnrealEditor requires 16. Rendering artifacts may occur."),
MaxVertexAttribs
);
}
LOG_AND_GET_GL_INT(GL_MAX_VARYING_VECTORS, 0, MaxVaryingVectors);
LOG_AND_GET_GL_INT(GL_MAX_VERTEX_UNIFORM_VECTORS, 0, MaxVertexUniformComponents);
LOG_AND_GET_GL_INT(GL_MAX_FRAGMENT_UNIFORM_VECTORS, 0, MaxPixelUniformComponents);
LOG_AND_GET_GL_INT(GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT, 0, TextureBufferAlignment);
LOG_AND_GET_GL_INT(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, 0, MaxComputeUniformComponents);
LOG_AND_GET_GL_INT(GL_MAX_COMBINED_IMAGE_UNIFORMS, 0, MaxCombinedUAVUnits);
LOG_AND_GET_GL_INT(GL_MAX_COMPUTE_IMAGE_UNIFORMS, 0, MaxComputeUAVUnits);
LOG_AND_GET_GL_INT(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, 0, MaxPixelUAVUnits);
GLint MaxCombinedSSBOUnits = 0;
GET_GL_INT(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, 0, MaxCombinedSSBOUnits);
// UAVs slots in UE are shared between Images and SSBO, so this should be max(GL_MAX_COMBINED_IMAGE_UNIFORMS, GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS)
MaxCombinedUAVUnits = FMath::Max(MaxCombinedUAVUnits, MaxCombinedSSBOUnits);
// clamp UAV units to a sensible limit
MaxCombinedUAVUnits = FMath::Min(MaxCombinedUAVUnits, 16);
MaxComputeUAVUnits = FMath::Min(MaxComputeUAVUnits, 16);
// this is split between VS and PS, 4 to each stage
MaxPixelUAVUnits = FMath::Min(MaxPixelUAVUnits, 4);
const GLint RequiredMaxVertexUniformComponents = 256;
if (MaxVertexUniformComponents < RequiredMaxVertexUniformComponents)
{
UE_LOG(LogRHI, Warning,
TEXT("Device reports support for %d vertex uniform vectors, UnrealEditor requires %d. Rendering artifacts may occur, especially with skeletal meshes. Some drivers, e.g. iOS, report a smaller number than is actually supported."),
MaxVertexUniformComponents,
RequiredMaxVertexUniformComponents
);
}
MaxVertexUniformComponents = FMath::Max<GLint>(MaxVertexUniformComponents, RequiredMaxVertexUniformComponents);
MaxGeometryUniformComponents = 0;
MaxGeometryTextureImageUnits = 0;
// Set lowest possible limits for texture units, to avoid extra work in GL RHI
MaxTextureImageUnits = FMath::Min(MaxTextureImageUnits, 16);
MaxVertexTextureImageUnits = FMath::Min(MaxVertexTextureImageUnits, 16);
MaxCombinedTextureImageUnits = FMath::Min(MaxCombinedTextureImageUnits, 32);
}
void FOpenGLES::ProcessExtensions(const FString& ExtensionsString)
{
ProcessQueryGLInt();
FOpenGLBase::ProcessExtensions(ExtensionsString);
bSupportsDisjointTimeQueries = ExtensionsString.Contains(TEXT("GL_EXT_disjoint_timer_query"));
if (bSupportsDisjointTimeQueries)
{
glQueryCounterEXT = (PFNGLQUERYCOUNTEREXTPROC)((void*)eglGetProcAddress("glQueryCounterEXT"));;
glGetQueryObjectui64vEXT = (PFNGLGETQUERYOBJECTUI64VEXTPROC)((void*)eglGetProcAddress("glGetQueryObjectui64vEXT"));
}
bTimerQueryCanBeDisjoint = !ExtensionsString.Contains(TEXT("GL_NV_timer_query"));
bSupportsBGRA8888 = ExtensionsString.Contains(TEXT("GL_APPLE_texture_format_BGRA8888")) || ExtensionsString.Contains(TEXT("GL_IMG_texture_format_BGRA8888")) || ExtensionsString.Contains(TEXT("GL_EXT_texture_format_BGRA8888"));
bSupportsColorBufferFloat = ExtensionsString.Contains(TEXT("GL_EXT_color_buffer_float"));
bSupportsColorBufferHalfFloat = ExtensionsString.Contains(TEXT("GL_EXT_color_buffer_half_float"));
bSupportsMultisampledRenderToTexture = ExtensionsString.Contains(TEXT("GL_EXT_multisampled_render_to_texture"));
bSupportsNVFrameBufferBlit = ExtensionsString.Contains(TEXT("GL_NV_framebuffer_blit"));
bSupportsBufferStorage = ExtensionsString.Contains(TEXT("GL_EXT_buffer_storage"));
bSupportsDepthClamp = ExtensionsString.Contains(TEXT("GL_EXT_depth_clamp"));
bSupportsASTCDecodeMode = ExtensionsString.Contains(TEXT("GL_EXT_texture_compression_astc_decode_mode"));
if (MobileAllowFramebufferFetch(GMaxRHIShaderPlatform))
{
bSupportsShaderFramebufferFetch = ExtensionsString.Contains(TEXT("GL_EXT_shader_framebuffer_fetch")) || ExtensionsString.Contains(TEXT("GL_NV_shader_framebuffer_fetch")) || ExtensionsString.Contains(TEXT("GL_ARM_shader_framebuffer_fetch ")); // has space at the end to exclude GL_ARM_shader_framebuffer_fetch_depth_stencil match
bSupportsShaderMRTFramebufferFetch = ExtensionsString.Contains(TEXT("GL_EXT_shader_framebuffer_fetch")) || ExtensionsString.Contains(TEXT("GL_NV_shader_framebuffer_fetch"));
bSupportsPixelLocalStorage = ExtensionsString.Contains(TEXT("GL_EXT_shader_pixel_local_storage"));
bSupportsShaderDepthStencilFetch = ExtensionsString.Contains(TEXT("GL_ARM_shader_framebuffer_fetch_depth_stencil"));
}
// Report shader precision
int Range[2];
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_LOW_FLOAT, Range, &ShaderLowPrecision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_MEDIUM_FLOAT, Range, &ShaderMediumPrecision);
glGetShaderPrecisionFormat(GL_FRAGMENT_SHADER, GL_HIGH_FLOAT, Range, &ShaderHighPrecision);
UE_LOG(LogRHI, Log, TEXT("Fragment shader lowp precision: %d"), ShaderLowPrecision);
UE_LOG(LogRHI, Log, TEXT("Fragment shader mediump precision: %d"), ShaderMediumPrecision);
UE_LOG(LogRHI, Log, TEXT("Fragment shader highp precision: %d"), ShaderHighPrecision);
if (FPlatformMisc::IsDebuggerPresent() && UE_BUILD_DEBUG)
{
// Enable GL debug markers if we're running in Xcode
extern int32 GEmitMeshDrawEvent;
GEmitMeshDrawEvent = 1;
SetEmitDrawEvents(true);
}
glPushGroupMarkerEXT = (PFNGLPUSHGROUPMARKEREXTPROC)((void*)eglGetProcAddress("glPushGroupMarkerEXT"));
glPopGroupMarkerEXT = (PFNGLPOPGROUPMARKEREXTPROC)((void*)eglGetProcAddress("glPopGroupMarkerEXT"));
if (ExtensionsString.Contains(TEXT("GL_EXT_DEBUG_LABEL")))
{
glLabelObjectEXT = (PFNGLLABELOBJECTEXTPROC)((void*)eglGetProcAddress("glLabelObjectEXT"));
glGetObjectLabelEXT = (PFNGLGETOBJECTLABELEXTPROC)((void*)eglGetProcAddress("glGetObjectLabelEXT"));
}
if (bSupportsBufferStorage)
{
glBufferStorageEXT = (PFNGLBUFFERSTORAGEEXTPROC)((void*)eglGetProcAddress("glBufferStorageEXT"));
}
if (ExtensionsString.Contains(TEXT("GL_EXT_multisampled_render_to_texture2")))
{
glFramebufferTexture2DMultisampleEXT = (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)((void*)eglGetProcAddress("glFramebufferTexture2DMultisampleEXT"));
glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)((void*)eglGetProcAddress("glRenderbufferStorageMultisampleEXT"));
glGetIntegerv(GL_MAX_SAMPLES_EXT, &MaxMSAASamplesTileMem);
MaxMSAASamplesTileMem = FMath::Max<GLint>(MaxMSAASamplesTileMem, 1);
UE_LOG(LogRHI, Log, TEXT("Support for %dx MSAA detected"), MaxMSAASamplesTileMem);
}
else
{
// indicates RHI supports on-chip MSAA but this device does not.
MaxMSAASamplesTileMem = 1;
}
bSupportsProgramBinary = ExtensionsString.Contains(TEXT("GL_OES_get_program_binary"));
bSupportsETC2 = true;
// According to https://www.khronos.org/registry/gles/extensions/EXT/EXT_color_buffer_float.txt
bSupportsColorBufferHalfFloat = (bSupportsColorBufferHalfFloat || bSupportsColorBufferFloat);
// Mobile multi-view setup
const bool bMultiViewSupport = ExtensionsString.Contains(TEXT("GL_OVR_multiview"));
const bool bMultiView2Support = ExtensionsString.Contains(TEXT("GL_OVR_multiview2"));
const bool bMultiViewMultiSampleSupport = ExtensionsString.Contains(TEXT("GL_OVR_multiview_multisampled_render_to_texture"));
if (bMultiViewSupport && bMultiView2Support && bMultiViewMultiSampleSupport)
{
glFramebufferTextureMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)((void*)eglGetProcAddress("glFramebufferTextureMultiviewOVR"));
glFramebufferTextureMultisampleMultiviewOVR = (PFNGLFRAMEBUFFERTEXTUREMULTISAMPLEMULTIVIEWOVRPROC)((void*)eglGetProcAddress("glFramebufferTextureMultisampleMultiviewOVR"));
bSupportsMobileMultiView = (glFramebufferTextureMultiviewOVR != NULL) && (glFramebufferTextureMultisampleMultiviewOVR != NULL);
// Just because the driver declares multi-view support and hands us valid function pointers doesn't actually guarantee the feature works...
if (bSupportsMobileMultiView)
{
UE_LOG(LogRHI, Log, TEXT("Device supports mobile multi-view."));
}
}
if (IsES32Usable())
{
glTexBufferEXT = (PFNGLTEXBUFFEREXTPROC)((void*)eglGetProcAddress("glTexBuffer"));
glTexBufferRangeEXT = (PFNGLTEXBUFFERRANGEEXTPROC)((void*)eglGetProcAddress("glTexBufferRange"));
glCopyImageSubData = (PFNGLCOPYIMAGESUBDATAEXTPROC)((void*)eglGetProcAddress("glCopyImageSubData"));
glEnableiEXT = (PFNGLENABLEIEXTPROC)((void*)eglGetProcAddress("glEnablei"));
glDisableiEXT = (PFNGLDISABLEIEXTPROC)((void*)eglGetProcAddress("glDisablei"));
glBlendEquationiEXT = (PFNGLBLENDEQUATIONIEXTPROC)((void*)eglGetProcAddress("glBlendEquationi"));
glBlendEquationSeparateiEXT = (PFNGLBLENDEQUATIONSEPARATEIEXTPROC)((void*)eglGetProcAddress("glBlendEquationSeparatei"));
glBlendFunciEXT = (PFNGLBLENDFUNCIEXTPROC)((void*)eglGetProcAddress("glBlendFunci"));
glBlendFuncSeparateiEXT = (PFNGLBLENDFUNCSEPARATEIEXTPROC)((void*)eglGetProcAddress("glBlendFuncSeparatei"));
glColorMaskiEXT = (PFNGLCOLORMASKIEXTPROC)((void*)eglGetProcAddress("glColorMaski"));
glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC)((void*)eglGetProcAddress("glFramebufferTexture"));
}
if (!glEnableiEXT && ExtensionsString.Contains(TEXT("GL_EXT_draw_buffers_indexed")))
{
// GL_EXT_draw_buffers_indexed
glEnableiEXT = (PFNGLENABLEIEXTPROC)((void*)eglGetProcAddress("glEnableiEXT"));
glDisableiEXT = (PFNGLDISABLEIEXTPROC)((void*)eglGetProcAddress("glDisableiEXT"));
glBlendEquationiEXT = (PFNGLBLENDEQUATIONIEXTPROC)((void*)eglGetProcAddress("glBlendEquationiEXT"));
glBlendEquationSeparateiEXT = (PFNGLBLENDEQUATIONSEPARATEIEXTPROC)((void*)eglGetProcAddress("glBlendEquationSeparateiEXT"));
glBlendFunciEXT = (PFNGLBLENDFUNCIEXTPROC)((void*)eglGetProcAddress("glBlendFunciEXT"));
glBlendFuncSeparateiEXT = (PFNGLBLENDFUNCSEPARATEIEXTPROC)((void*)eglGetProcAddress("glBlendFuncSeparateiEXT"));
glColorMaskiEXT = (PFNGLCOLORMASKIEXTPROC)((void*)eglGetProcAddress("glColorMaskiEXT"));
}
bSupportsDrawBuffersBlend = (glEnableiEXT != nullptr);
if (!glTexBufferEXT && ExtensionsString.Contains(TEXT("GL_EXT_texture_buffer")))
{
// GL_EXT_texture_buffer
glTexBufferEXT = (PFNGLTEXBUFFEREXTPROC)((void*)eglGetProcAddress("glTexBufferEXT"));
glTexBufferRangeEXT = (PFNGLTEXBUFFERRANGEEXTPROC)((void*)eglGetProcAddress("glTexBufferRangeEXT"));
}
}
#endif //UGL_PLATFORM_SUPPORTS_GLES