// Copyright Epic Games, Inc. All Rights Reserved. #include "WindowsOpenGLPlatform.h" #include "Misc/ScopeLock.h" #include "OpenGLDrvPrivate.h" #include "OpenGLUtil.h" #include "RHI.h" #include "RHIUtilities.h" bool GRunningUnderRenderDoc = false; /*------------------------------------------------------------------------------ OpenGL context management. ------------------------------------------------------------------------------*/ static void ContextMakeCurrent(HDC DC, HGLRC RC) { BOOL Result = wglMakeCurrent(DC, RC); if (!Result) { Result = wglMakeCurrent(nullptr, nullptr); } check(Result); } static HGLRC GetCurrentContext() { return wglGetCurrentContext(); } /** Platform specific OpenGL context. */ struct FPlatformOpenGLContext { HWND WindowHandle; HDC DeviceContext; HGLRC OpenGLContext; bool bReleaseWindowOnDestroy; int32 SyncInterval; GLuint ViewportFramebuffer; GLuint VertexArrayObject; // one has to be generated and set for each context (OpenGL 3.2 Core requirements) GLuint BackBufferResource; GLenum BackBufferTarget; }; class FScopeContext { public: FScopeContext(FPlatformOpenGLContext* Context) { check(Context); PrevDC = wglGetCurrentDC(); PrevContext = GetCurrentContext(); bSameDC = (PrevDC == Context->DeviceContext); bSameDCAndContext = (PrevContext == Context->OpenGLContext) && bSameDC; if (!bSameDCAndContext) { // if (PrevContext) // { // glFlush(); // } // no need to glFlush() on Windows, it does flush by itself before switching contexts ContextMakeCurrent(Context->DeviceContext, Context->OpenGLContext); } } ~FScopeContext(void) { if (!bSameDCAndContext) { // glFlush(); // not needed on Windows, it does flush by itself before switching contexts if (PrevContext) { ContextMakeCurrent(PrevDC, PrevContext); } else { ContextMakeCurrent(NULL, NULL); } } } bool ContextWasAlreadyActive() const { return bSameDCAndContext; } bool ContextsShareSameDC() const { return bSameDC; } private: HDC PrevDC; HGLRC PrevContext; bool bSameDCAndContext; bool bSameDC; }; /** * A dummy wndproc. */ static LRESULT CALLBACK PlatformDummyGLWndproc(HWND hWnd, uint32 Message, WPARAM wParam, LPARAM lParam) { return DefWindowProc(hWnd, Message, wParam, lParam); } /** * Initialize a pixel format descriptor for the given window handle. */ static void PlatformInitPixelFormatForDevice(HDC DeviceContext, bool bTryIsDummyContext) { // Pixel format descriptor for the context. PIXELFORMATDESCRIPTOR PixelFormatDesc; FMemory::Memzero(PixelFormatDesc); PixelFormatDesc.nSize = sizeof(PIXELFORMATDESCRIPTOR); PixelFormatDesc.nVersion = 1; PixelFormatDesc.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; PixelFormatDesc.iPixelType = PFD_TYPE_RGBA; PixelFormatDesc.cColorBits = 32; PixelFormatDesc.cDepthBits = 0; PixelFormatDesc.cStencilBits = 0; PixelFormatDesc.iLayerType = PFD_MAIN_PLANE; static bool bRequestedQuadBufferStereo = FParse::Param(FCommandLine::Get(), TEXT("quad_buffer_stereo")); if (bRequestedQuadBufferStereo) { PixelFormatDesc.dwFlags = PixelFormatDesc.dwFlags | PFD_STEREO; } // Set the pixel format and create the context. int32 PixelFormat = ChoosePixelFormat(DeviceContext, &PixelFormatDesc); if (!PixelFormat || !SetPixelFormat(DeviceContext, PixelFormat, &PixelFormatDesc)) { UE_LOG(LogRHI, Fatal, TEXT("Failed to set pixel format for device context.")); } } /** * Create a dummy window used to construct OpenGL contexts. */ static void PlatformCreateDummyGLWindow(FPlatformOpenGLContext* OutContext) { const TCHAR* WindowClassName = TEXT("DummyGLWindow"); // Register a dummy window class. static bool bInitializedWindowClass = false; if (!bInitializedWindowClass) { WNDCLASS wc; bInitializedWindowClass = true; FMemory::Memzero(wc); wc.style = CS_OWNDC; wc.lpfnWndProc = PlatformDummyGLWndproc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = NULL; wc.hIcon = NULL; wc.hCursor = NULL; wc.hbrBackground = (HBRUSH)(COLOR_MENUTEXT); wc.lpszMenuName = NULL; wc.lpszClassName = WindowClassName; ATOM ClassAtom = ::RegisterClass(&wc); check(ClassAtom); } int32 WinX = 0; int32 WinY = 0; FParse::Value(FCommandLine::Get(), TEXT("WinX="), WinX); FParse::Value(FCommandLine::Get(), TEXT("WinY="), WinY); // Create a dummy window. OutContext->WindowHandle = CreateWindowEx( WS_EX_WINDOWEDGE, WindowClassName, NULL, WS_POPUP, WinX, WinY, 1, 1, NULL, NULL, NULL, NULL); check(OutContext->WindowHandle); OutContext->bReleaseWindowOnDestroy = true; // Get the device context. OutContext->DeviceContext = GetDC(OutContext->WindowHandle); check(OutContext->DeviceContext); PlatformInitPixelFormatForDevice(OutContext->DeviceContext, true); } /** * Set OpenGL Context version to fixed version */ static void GetOpenGLVersionForCoreProfile(int& OutMajorVersion, int& OutMinorVersion) { // Always initialize GL context with version 4.3, it's the only GL desktop version we support now OutMajorVersion = 4; OutMinorVersion = 3; } /** * Enable/Disable debug context from the commandline */ static bool PlatformOpenGLDebugCtx() { return IsOGLDebugOutputEnabled(); } /** * Create a core profile OpenGL context. */ static void PlatformCreateOpenGLContextCore(FPlatformOpenGLContext* OutContext, int MajorVersion, int MinorVersion, HGLRC InParentContext) { check(wglCreateContextAttribsARB); check(OutContext); check(OutContext->DeviceContext); OutContext->SyncInterval = -1; // invalid value to enforce setup on first buffer swap OutContext->ViewportFramebuffer = 0; int DebugFlag = 0; if (PlatformOpenGLDebugCtx()) { DebugFlag = WGL_CONTEXT_DEBUG_BIT_ARB; } #if !EMULATE_ES31 int AttribList[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, MajorVersion, WGL_CONTEXT_MINOR_VERSION_ARB, MinorVersion, WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB | DebugFlag, WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 0 }; #else int AttribList[] = { WGL_CONTEXT_MAJOR_VERSION_ARB, 3, WGL_CONTEXT_MINOR_VERSION_ARB, 1, WGL_CONTEXT_FLAGS_ARB, DebugFlag, WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_ES2_PROFILE_BIT_EXT, 0 }; #endif OutContext->OpenGLContext = wglCreateContextAttribsARB(OutContext->DeviceContext, InParentContext, AttribList); } void PlatformReleaseOpenGLContext(FPlatformOpenGLDevice* Device, FPlatformOpenGLContext* Context); /** Platform specific OpenGL device. */ struct FPlatformOpenGLDevice { static FPlatformOpenGLDevice* Singleton; FPlatformOpenGLContext RenderingContext; TArray ViewportContexts; bool TargetDirty; /** Guards against operating on viewport contexts from more than one thread at the same time. */ FCriticalSection* ContextUsageGuard; FPlatformOpenGLDevice() : TargetDirty(true) { check(!Singleton); Singleton = this; extern void InitDebugContext(); ContextUsageGuard = new FCriticalSection; int MajorVersion = 0; int MinorVersion = 0; GetOpenGLVersionForCoreProfile(MajorVersion, MinorVersion); // Need to call this before we set the debug callback, otherwise if we're not running under RD, the debug extension will assert (invalid enum) GRunningUnderRenderDoc = glIsEnabled(GL_DEBUG_TOOL_EXT) != GL_FALSE; PlatformCreateDummyGLWindow(&RenderingContext); PlatformCreateOpenGLContextCore(&RenderingContext, MajorVersion, MinorVersion, nullptr); ContextMakeCurrent(RenderingContext.DeviceContext, RenderingContext.OpenGLContext); check(RenderingContext.OpenGLContext); InitDebugContext(); glGenVertexArrays(1, &RenderingContext.VertexArrayObject); glBindVertexArray(RenderingContext.VertexArrayObject); InitDefaultGLContextState(); glGenFramebuffers(1, &RenderingContext.ViewportFramebuffer); } ~FPlatformOpenGLDevice() { check(ViewportContexts.Num() == 0); ContextMakeCurrent(NULL, NULL); PlatformReleaseOpenGLContext(this, &RenderingContext); delete ContextUsageGuard; check(Singleton == this); Singleton = nullptr; } }; FPlatformOpenGLDevice* FPlatformOpenGLDevice::Singleton = nullptr; FPlatformOpenGLDevice* PlatformCreateOpenGLDevice() { return new FPlatformOpenGLDevice; } bool PlatformCanEnableGPUCapture() { return GRunningUnderRenderDoc; } void PlatformDestroyOpenGLDevice(FPlatformOpenGLDevice* Device) { delete Device; } /** * Create an OpenGL context. */ FPlatformOpenGLContext* PlatformCreateOpenGLContext(FPlatformOpenGLDevice* Device, void* InWindowHandle) { check(InWindowHandle); Device->TargetDirty = true; FPlatformOpenGLContext* Context = new FPlatformOpenGLContext; Context->WindowHandle = (HWND)InWindowHandle; Context->bReleaseWindowOnDestroy = false; Context->DeviceContext = GetDC(Context->WindowHandle); check(Context->DeviceContext); PlatformInitPixelFormatForDevice(Context->DeviceContext, false); int MajorVersion = 0; int MinorVersion = 0; GetOpenGLVersionForCoreProfile(MajorVersion, MinorVersion); PlatformCreateOpenGLContextCore(Context, MajorVersion, MinorVersion, Device->RenderingContext.OpenGLContext); check(Context->OpenGLContext); { FScopeContext Scope(Context); InitDefaultGLContextState(); glGenFramebuffers(1, &Context->ViewportFramebuffer); } Device->ViewportContexts.Add(Context); return Context; } /** * Release an OpenGL context. */ void PlatformReleaseOpenGLContext(FPlatformOpenGLDevice* Device, FPlatformOpenGLContext* Context) { check(Context && Context->OpenGLContext); Device->ViewportContexts.RemoveSingle(Context); Device->TargetDirty = true; bool bActiveContextWillBeReleased = false; bool bSharedDC = false; { FScopeLock ScopeLock(Device->ContextUsageGuard); { FScopeContext ScopeContext(Context); bActiveContextWillBeReleased = ScopeContext.ContextWasAlreadyActive(); bSharedDC = ScopeContext.ContextsShareSameDC(); glBindVertexArray(0); glDeleteVertexArrays(1, &Context->VertexArrayObject); if (Context->ViewportFramebuffer) { glDeleteFramebuffers(1, &Context->ViewportFramebuffer); // this can be done from any context shared with ours, as long as it's not nil. Context->ViewportFramebuffer = 0; } } wglDeleteContext(Context->OpenGLContext); Context->OpenGLContext = NULL; } check(Context->DeviceContext); if (bActiveContextWillBeReleased) { wglMakeCurrent(NULL, NULL); } ReleaseDC(Context->WindowHandle, Context->DeviceContext); Context->DeviceContext = NULL; if (PlatformOpenGLThreadHasRenderingContext() && bSharedDC) { // The rendering context has been made current using the DC of the now destroyed context. Since this DC has been released the current context will be invalid. // To properly set the rendering context we must make current here with it's own DC. ContextMakeCurrent(Device->RenderingContext.DeviceContext, Device->RenderingContext.OpenGLContext); } check(Context->WindowHandle); if (Context->bReleaseWindowOnDestroy) { DestroyWindow(Context->WindowHandle); } Context->WindowHandle = NULL; } /** * Destroy an OpenGL context. */ void PlatformDestroyOpenGLContext(FPlatformOpenGLDevice* Device, FPlatformOpenGLContext* Context) { PlatformReleaseOpenGLContext(Device, Context); delete Context; } /** * Main function for transferring data to on-screen buffers. * On Windows it temporarily switches OpenGL context, on Mac only context's output view. */ bool PlatformBlitToViewport(IRHICommandContext& RHICmdContext, FPlatformOpenGLDevice* Device, const FOpenGLViewport& Viewport, uint32 BackbufferSizeX, uint32 BackbufferSizeY, bool bPresent, bool bLockToVsync) { int32 SyncInterval = RHIGetSyncInterval(); FPlatformOpenGLContext* const Context = Viewport.GetGLContext(); check(Context && Context->DeviceContext); if (FOpenGL::IsAndroidGLESCompatibilityModeEnabled()) { glDisable(GL_FRAMEBUFFER_SRGB); int32 RealSyncInterval = bLockToVsync ? SyncInterval : 0; if (wglSwapIntervalEXT_ProcAddress && Context->SyncInterval != RealSyncInterval) { wglSwapIntervalEXT_ProcAddress(RealSyncInterval); Context->SyncInterval = RealSyncInterval; } ::SwapBuffers(Context->DeviceContext); return true; } FScopeLock ScopeLock(Device->ContextUsageGuard); { FPlatformOpenGLContext TempContext = *Context; if (Device->ViewportContexts.Num() == 1) { TempContext.OpenGLContext = Device->RenderingContext.OpenGLContext; TempContext.ViewportFramebuffer = Device->RenderingContext.ViewportFramebuffer; } FScopeContext ScopeContext(&TempContext); GLuint vfb = TempContext.ViewportFramebuffer; if (Viewport.GetCustomPresent()) { Device->TargetDirty = false; glDisable(GL_FRAMEBUFFER_SRGB); bool bShouldPresent = Viewport.GetCustomPresent()->Present(RHICmdContext, SyncInterval); glEnable(GL_FRAMEBUFFER_SRGB); if (!bShouldPresent) { return false; } else { Device->TargetDirty = true; } } if (Device->ViewportContexts.Num() == 1 && Device->TargetDirty) { glBindFramebuffer(GL_FRAMEBUFFER, TempContext.ViewportFramebuffer); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, Context->BackBufferTarget, Context->BackBufferResource, 0); FOpenGL::CheckFrameBuffer(); Device->TargetDirty = false; } glDisable(GL_FRAMEBUFFER_SRGB); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); FOpenGL::DrawBuffer(GL_BACK); glBindFramebuffer(GL_READ_FRAMEBUFFER, TempContext.ViewportFramebuffer); glReadBuffer(GL_COLOR_ATTACHMENT0); glBlitFramebuffer( 0, 0, BackbufferSizeX, BackbufferSizeY, 0, BackbufferSizeY, BackbufferSizeX, 0, GL_COLOR_BUFFER_BIT, GL_NEAREST ); glEnable(GL_FRAMEBUFFER_SRGB); if (bPresent) { int32 RealSyncInterval = bLockToVsync ? SyncInterval : 0; if (wglSwapIntervalEXT_ProcAddress && Context->SyncInterval != RealSyncInterval) { wglSwapIntervalEXT_ProcAddress(RealSyncInterval); Context->SyncInterval = RealSyncInterval; } ::SwapBuffers(Context->DeviceContext); } } return true; } void PlatformFlushIfNeeded() { glFinish(); } void PlatformRenderingContextSetup(FPlatformOpenGLDevice* Device) { check(Device && Device->RenderingContext.DeviceContext && Device->RenderingContext.OpenGLContext); if (GetCurrentContext()) { glFlush(); } if (Device->ViewportContexts.Num() == 1) { // use the HDC of the window, to reduce context swap overhead ContextMakeCurrent(Device->ViewportContexts[0]->DeviceContext, Device->RenderingContext.OpenGLContext); } else { ContextMakeCurrent(Device->RenderingContext.DeviceContext, Device->RenderingContext.OpenGLContext); } } void PlatformNULLContextSetup() { if (wglGetCurrentDC()) { // no need to glFlush() on Windows, it does flush by itself before switching contexts ContextMakeCurrent(NULL, NULL); } } /** * Resize the GL context. */ void PlatformResizeGLContext(FPlatformOpenGLDevice* Device, FPlatformOpenGLContext* Context, uint32 SizeX, uint32 SizeY, bool bFullscreen, bool bWasFullscreen, GLenum BackBufferTarget, GLuint BackBufferResource) { FScopeLock ScopeLock(Device->ContextUsageGuard); { uint32 WindowStyle = WS_CAPTION | WS_SYSMENU; uint32 WindowStyleEx = 0; HWND InsertAfter = HWND_NOTOPMOST; if (bFullscreen) { // Get the monitor info from the window handle. HMONITOR hMonitor = MonitorFromWindow(Context->WindowHandle, MONITOR_DEFAULTTOPRIMARY); MONITORINFOEX MonitorInfo; memset(&MonitorInfo, 0, sizeof(MONITORINFOEX)); MonitorInfo.cbSize = sizeof(MONITORINFOEX); GetMonitorInfo(hMonitor, &MonitorInfo); DEVMODE Mode; Mode.dmSize = sizeof(DEVMODE); Mode.dmBitsPerPel = 32; Mode.dmPelsWidth = SizeX; Mode.dmPelsHeight = SizeY; Mode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; // Turn on fullscreen mode for the current monitor ChangeDisplaySettingsEx(MonitorInfo.szDevice, &Mode, NULL, CDS_FULLSCREEN, NULL); WindowStyle = WS_POPUP; WindowStyleEx = WS_EX_APPWINDOW | WS_EX_TOPMOST; InsertAfter = HWND_TOPMOST; } else if (bWasFullscreen) { ChangeDisplaySettings(NULL, 0); } Device->TargetDirty = true; Context->BackBufferResource = BackBufferResource; Context->BackBufferTarget = BackBufferTarget; //SetWindowLong(Context->WindowHandle, GWL_STYLE, WindowStyle); //SetWindowLong(Context->WindowHandle, GWL_EXSTYLE, WindowStyleEx); if (!FOpenGL::IsAndroidGLESCompatibilityModeEnabled()) { FScopeContext ScopeContext(Context); glBindFramebuffer(GL_FRAMEBUFFER, Context->ViewportFramebuffer); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, BackBufferTarget, BackBufferResource, 0); #if UE_BUILD_DEBUG glReadBuffer(GL_COLOR_ATTACHMENT0); FOpenGL::DrawBuffer(GL_COLOR_ATTACHMENT0); #endif FOpenGL::CheckFrameBuffer(); glViewport(0, 0, SizeX, SizeY); static GLfloat ZeroColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; glClearBufferfv(GL_COLOR, 0, ZeroColor); } } } void PlatformGetSupportedResolution(uint32& Width, uint32& Height) { uint32 InitializedMode = false; uint32 BestWidth = 0; uint32 BestHeight = 0; uint32 ModeIndex = 0; DEVMODE DisplayMode; FMemory::Memzero(&DisplayMode, sizeof(DEVMODE)); while (EnumDisplaySettings(NULL, ModeIndex++, &DisplayMode)) { bool IsEqualOrBetterWidth = FMath::Abs((int32)DisplayMode.dmPelsWidth - (int32)Width) <= FMath::Abs((int32)BestWidth - (int32)Width); bool IsEqualOrBetterHeight = FMath::Abs((int32)DisplayMode.dmPelsHeight - (int32)Height) <= FMath::Abs((int32)BestHeight - (int32)Height); if (!InitializedMode || (IsEqualOrBetterWidth && IsEqualOrBetterHeight)) { BestWidth = DisplayMode.dmPelsWidth; BestHeight = DisplayMode.dmPelsHeight; InitializedMode = true; } } check(InitializedMode); Width = BestWidth; Height = BestHeight; } bool PlatformGetAvailableResolutions(FScreenResolutionArray& Resolutions, bool bIgnoreRefreshRate) { int32 MinAllowableResolutionX = 0; int32 MinAllowableResolutionY = 0; int32 MaxAllowableResolutionX = 10480; int32 MaxAllowableResolutionY = 10480; int32 MinAllowableRefreshRate = 0; int32 MaxAllowableRefreshRate = 10480; if (MaxAllowableResolutionX == 0) //-V547 { MaxAllowableResolutionX = 10480; } if (MaxAllowableResolutionY == 0) //-V547 { MaxAllowableResolutionY = 10480; } if (MaxAllowableRefreshRate == 0) //-V547 { MaxAllowableRefreshRate = 10480; } uint32 ModeIndex = 0; DEVMODE DisplayMode; FMemory::Memzero(&DisplayMode, sizeof(DEVMODE)); while (EnumDisplaySettings(NULL, ModeIndex++, &DisplayMode)) { if (((int32)DisplayMode.dmPelsWidth >= MinAllowableResolutionX) && ((int32)DisplayMode.dmPelsWidth <= MaxAllowableResolutionX) && ((int32)DisplayMode.dmPelsHeight >= MinAllowableResolutionY) && ((int32)DisplayMode.dmPelsHeight <= MaxAllowableResolutionY) ) { bool bAddIt = true; if (bIgnoreRefreshRate == false) { if (((int32)DisplayMode.dmDisplayFrequency < MinAllowableRefreshRate) || ((int32)DisplayMode.dmDisplayFrequency > MaxAllowableRefreshRate) ) { continue; } } else { // See if it is in the list already for (int32 CheckIndex = 0; CheckIndex < Resolutions.Num(); CheckIndex++) { FScreenResolutionRHI& CheckResolution = Resolutions[CheckIndex]; if ((CheckResolution.Width == DisplayMode.dmPelsWidth) && (CheckResolution.Height == DisplayMode.dmPelsHeight)) { // Already in the list... bAddIt = false; break; } } } if (bAddIt) { // Add the mode to the list int32 Temp2Index = Resolutions.AddZeroed(); FScreenResolutionRHI& ScreenResolution = Resolutions[Temp2Index]; ScreenResolution.Width = DisplayMode.dmPelsWidth; ScreenResolution.Height = DisplayMode.dmPelsHeight; ScreenResolution.RefreshRate = DisplayMode.dmDisplayFrequency; } } } return true; } void PlatformRestoreDesktopDisplayMode() { ChangeDisplaySettings(NULL, 0); } bool PlatformInitOpenGL() { static bool bInitialized = false; static bool bOpenGLSupported = false; if (!bInitialized) { // Disable warning C4191: 'type cast' : unsafe conversion from 'PROC' to 'XXX' while getting GL entry points. #pragma warning(push) #pragma warning(disable:4191) // Create a dummy context so that wglCreateContextAttribsARB can be initialized. FPlatformOpenGLContext DummyContext; PlatformCreateDummyGLWindow(&DummyContext); DummyContext.OpenGLContext = wglCreateContext(DummyContext.DeviceContext); check(DummyContext.OpenGLContext); ContextMakeCurrent(DummyContext.DeviceContext, DummyContext.OpenGLContext); wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); if (wglCreateContextAttribsARB) { int MajorVersion = 0; int MinorVersion = 0; ContextMakeCurrent(NULL, NULL); wglDeleteContext(DummyContext.OpenGLContext); GetOpenGLVersionForCoreProfile(MajorVersion, MinorVersion); PlatformCreateOpenGLContextCore(&DummyContext, MajorVersion, MinorVersion, NULL); if (DummyContext.OpenGLContext) { bOpenGLSupported = true; ContextMakeCurrent(DummyContext.DeviceContext, DummyContext.OpenGLContext); } else { UE_LOG(LogRHI, Error, TEXT("OpenGL %d.%d not supported by driver"), MajorVersion, MinorVersion); } } if (bOpenGLSupported) { // Retrieve the OpenGL DLL. void* OpenGLDLL = FPlatformProcess::GetDllHandle(TEXT("opengl32.dll")); if (!OpenGLDLL) { UE_LOG(LogRHI, Fatal, TEXT("Couldn't load opengl32.dll")); } // Initialize entry points required by Unreal from opengl32.dll #define GET_GL_ENTRYPOINTS_DLL(Type,Func) Func = (Type)FPlatformProcess::GetDllExport(OpenGLDLL,TEXT(#Func)); ENUM_GL_ENTRYPOINTS_DLL(GET_GL_ENTRYPOINTS_DLL); #undef GET_GL_ENTRYPOINTS_DLL // Release the OpenGL DLL. FPlatformProcess::FreeDllHandle(OpenGLDLL); // Initialize all entry points required by Unreal. #define GET_GL_ENTRYPOINTS(Type,Func) Func = (Type)wglGetProcAddress(#Func); ENUM_GL_ENTRYPOINTS(GET_GL_ENTRYPOINTS); ENUM_GL_ENTRYPOINTS_OPTIONAL(GET_GL_ENTRYPOINTS); #undef GET_GL_ENTRYPOINTS // Restore warning C4191. #pragma warning(pop) // Check that all of the entry points have been initialized. bool bFoundAllEntryPoints = true; #define CHECK_GL_ENTRYPOINTS(Type,Func) if (Func == NULL) { bFoundAllEntryPoints = false; UE_LOG(LogRHI, Warning, TEXT("Failed to find entry point for %s"), TEXT(#Func)); } ENUM_GL_ENTRYPOINTS_DLL(CHECK_GL_ENTRYPOINTS); ENUM_GL_ENTRYPOINTS(CHECK_GL_ENTRYPOINTS); #undef CHECK_GL_ENTRYPOINTS checkf(bFoundAllEntryPoints, TEXT("Failed to find all OpenGL entry points.")); } // The dummy context can now be released. if (DummyContext.OpenGLContext) { ContextMakeCurrent(NULL, NULL); wglDeleteContext(DummyContext.OpenGLContext); } ReleaseDC(DummyContext.WindowHandle, DummyContext.DeviceContext); check(DummyContext.bReleaseWindowOnDestroy); DestroyWindow(DummyContext.WindowHandle); } return bOpenGLSupported; } int32 PlatformGlGetError() { return glGetError(); } bool PlatformOpenGLThreadHasRenderingContext() { return GetCurrentContext() == FPlatformOpenGLDevice::Singleton->RenderingContext.OpenGLContext; } // ============================================================= FOpenGLTexture* PlatformCreateBuiltinBackBuffer(FOpenGLDynamicRHI* OpenGLRHI, uint32 SizeX, uint32 SizeY) { if (FOpenGL::IsAndroidGLESCompatibilityModeEnabled()) { const FRHITextureCreateDesc Desc = FRHITextureCreateDesc::Create2D(TEXT("PlatformCreateBuiltinBackBuffer"), SizeX, SizeY, PF_B8G8R8A8) .SetClearValue(FClearValueBinding::Transparent) .SetFlags(ETextureCreateFlags::RenderTargetable | ETextureCreateFlags::Presentable | ETextureCreateFlags::ResolveTargetable) .DetermineInititialState(); FOpenGLTexture* Texture = new FOpenGLTexture(Desc); Texture->Initialize(FRHICommandListImmediate::Get()); return Texture; } return nullptr; } void* PlatformGetWindow(FPlatformOpenGLContext* Context, void** AddParam) { check(Context && Context->WindowHandle); return (void*)&Context->WindowHandle; }