/* * Copyright (c) 2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #if RENDER_HAS_GL_BACKEND #include "gles/wgl_state.h" #include #include #include "util/log.h" // NOTE: intentional double include of gl_functions.h #include "gles/gl_functions.h" #define declare(a, b) a b = nullptr; #include #include "gles/gl_functions.h" #include "gles/surface_information.h" #include "gles/swapchain_gles.h" using BASE_NS::string_view; using BASE_NS::vector; RENDER_BEGIN_NAMESPACE() namespace WGLHelpers { namespace { #define WGLFUNCS \ declareWGL(PFNWGLGETPROCADDRESSPROC, wglGetProcAddress); \ declareWGL(PFNWGLCREATECONTEXTPROC, wglCreateContext); \ declareWGL(PFNWGLDELETECONTEXTPROC, wglDeleteContext); \ declareWGL(PFNWGLMAKECURRENTPROC, wglMakeCurrent); \ declareWGL(PFNWGLGETCURRENTCONTEXTPROC, wglGetCurrentContext); \ declareWGL(PFNWGLGETCURRENTDCPROC, wglGetCurrentDC); \ declareWGL(PFNWGLCREATECONTEXTATTRIBSARBPROC, wglCreateContextAttribsARB); \ declareWGL(PFNWGLGETPIXELFORMATATTRIBIVARBPROC, wglGetPixelFormatAttribivARB); \ declareWGL(PFNWGLGETPIXELFORMATATTRIBFVARBPROC, wglGetPixelFormatAttribfvARB); \ declareWGL(PFNWGLCHOOSEPIXELFORMATARBPROC, wglChoosePixelFormatARB); \ declareWGL(PFNWGLSWAPINTERVALEXTPROC, wglSwapIntervalEXT); \ declareWGL(PFNWGLGETEXTENSIONSSTRINGARBPROC, wglGetExtensionsStringARB); #define declareWGL(a, b) a b = nullptr; WGLFUNCS; #undef declareWGL constexpr int WGL_ATTRIBS[] = { #if defined(CORE_CREATE_GLES_CONTEXT_WITH_WGL) && (CORE_CREATE_GLES_CONTEXT_WITH_WGL == 1) WGL_CONTEXT_MAJOR_VERSION_ARB, 3, WGL_CONTEXT_MINOR_VERSION_ARB, 2, #if RENDER_GL_DEBUG WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB, #endif WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_ES2_PROFILE_BIT_EXT, 0 #else WGL_CONTEXT_MAJOR_VERSION_ARB, 4, WGL_CONTEXT_MINOR_VERSION_ARB, 5, #if RENDER_GL_DEBUG WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB, #endif WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 0 #endif }; static bool FilterError(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const string_view message, const void* userParam) noexcept { if (source == GL_DEBUG_SOURCE_API) { if (type == GL_DEBUG_TYPE_OTHER) { if ((id == 11) && (severity == GL_DEBUG_SEVERITY_LOW)) { /* Ignore the following warning that Intel drivers seem to spam. (no problems on nvidia or mali...) source: GL_DEBUG_SOURCE_API type: GL_DEBUG_TYPE_OTHER severity: GL_DEBUG_SEVERITY_LOW message: API_ID_SYNC_FLUSH other warning has been generated. ClientWait flush in different gc for sync object 2, "" will be ineffective. */ return true; } if ((id == 131185) && (severity == GL_DEBUG_SEVERITY_NOTIFICATION)) { /* Ignore this warning that Nvidia sends. source: GL_DEBUG_SOURCE_API type: GL_DEBUG_TYPE_OTHER severity: GL_DEBUG_SEVERITY_NOTIFICATION message: Buffer detailed info: Buffer object X (bound to GL_COPY_WRITE_BUFFER_BINDING_EXT, usage hint is GL_DYNAMIC_DRAW) will use SYSTEM HEAP memory as the source for buffer object operations. *OR* message: Buffer detailed info: Buffer object X (bound to GL_COPY_WRITE_BUFFER_BINDING_EXT, usage hint is GL_DYNAMIC_DRAW) has been mapped WRITE_ONLY in SYSTEM HEAP memory (fast). */ return true; } } if (type == GL_DEBUG_TYPE_PERFORMANCE) { if ((id == 131154) && (severity == GL_DEBUG_SEVERITY_MEDIUM)) { /* source: GL_DEBUG_SOURCE_API type: GL_DEBUG_TYPE_PERFORMANCE id: 131154 severity: GL_DEBUG_SEVERITY_MEDIUM message: Pixel-path performance warning: Pixel transfer is synchronized with 3D rendering. */ return true; } if ((id == 131186) && (severity == GL_DEBUG_SEVERITY_MEDIUM)) { /* Ignore this warning that Nvidia sends. source: GL_DEBUG_SOURCE_API type: GL_DEBUG_TYPE_PERFORMANCE id: 131186 severity: GL_DEBUG_SEVERITY_MEDIUM message: Buffer performance warning: Buffer object X (bound to GL_ELEMENT_ARRAY_BUFFER_ARB, usage hint is GL_DYNAMIC_DRAW) is being copied/moved from VIDEO memory to HOST memory. */ return true; } if ((id == 131202) && (severity == GL_DEBUG_SEVERITY_MEDIUM)) { /* Ignore this warning that Nvidia sends. source: GL_DEBUG_SOURCE_API type: GL_DEBUG_TYPE_PERFORMANCE id: 131202 severity: GL_DEBUG_SEVERITY_MEDIUM message: Texture state performance warning: emulating compressed format not supported in hardware with decompressed images */ return true; } } } return false; } static void DoDummy() { WNDCLASS wc = { 0 }; wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; wc.lpfnWndProc = DefWindowProc; // WindowProc; wc.hInstance = GetModuleHandle(nullptr); wc.lpszClassName = TEXT("PureGL_WGL_Dummy"); wc.hCursor = LoadCursor(nullptr, IDC_ARROW); RegisterClass(&wc); const HWND dummyhWnd = CreateWindowEx(0, wc.lpszClassName, wc.lpszClassName, WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, 1, 1, nullptr, nullptr, wc.hInstance, nullptr); const HDC dummyhDC = GetDC(dummyhWnd); PIXELFORMATDESCRIPTOR pfd = { 0 }; pfd.nSize = sizeof(pfd); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_GENERIC_ACCELERATED | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 32; pfd.iLayerType = PFD_MAIN_PLANE; SetPixelFormat(dummyhDC, ChoosePixelFormat(dummyhDC, &pfd), &pfd); const HGLRC dummy = wglCreateContext(dummyhDC); wglMakeCurrent(dummyhDC, dummy); #define declareWGL(a, b) \ if ((b) == nullptr) { \ *(reinterpret_cast(&(b))) = reinterpret_cast(wglGetProcAddress(#b)); \ } WGLFUNCS #undef declareWGL wglMakeCurrent(dummyhDC, nullptr); wglMakeCurrent(nullptr, nullptr); wglDeleteContext(dummy); ReleaseDC(dummyhWnd, dummyhDC); DestroyWindow(dummyhWnd); UnregisterClass(wc.lpszClassName, wc.hInstance); } void ParseExtensions(const string_view extensions, vector& extensionList) { size_t start = 0; for (auto end = extensions.find(' '); end != BASE_NS::string::npos; end = extensions.find(' ', start)) { extensionList.emplace_back(extensions.data() + start, end - start); start = end + 1; } if (start < extensions.size()) { extensionList.emplace_back(extensions.data() + start); } } void FillProperties(DevicePropertiesGL& properties) { glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &properties.max3DTextureSize); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &properties.maxTextureSize); glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &properties.maxArrayTextureLayers); glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &properties.maxTextureLodBias); glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &properties.maxTextureMaxAnisotropy); glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &properties.maxCubeMapTextureSize); glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &properties.maxRenderbufferSize); glGetFloati_v(GL_MAX_VIEWPORT_DIMS, 0, properties.maxViewportDims); glGetFloati_v(GL_MAX_VIEWPORT_DIMS, 1, properties.maxViewportDims + 1); glGetIntegerv(GL_MAX_VIEWPORTS, &properties.maxViewports); glGetIntegerv(GL_VIEWPORT_SUBPIXEL_BITS, &properties.viewportSubpixelBits); glGetIntegerv(GL_VIEWPORT_BOUNDS_RANGE, &properties.viewportBoundsRange); glGetIntegerv(GL_MAJOR_VERSION, &properties.majorVersion); glGetIntegerv(GL_MINOR_VERSION, &properties.minorVersion); glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &properties.numProgramBinaryFormats); glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &properties.numShaderBinaryFormats); glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &properties.maxVertexAttribs); glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &properties.maxVertexUniformComponents); glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &properties.maxVertexUniformVectors); glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &properties.maxVertexUniformBlocks); glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &properties.maxVertexImageUniforms); glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &properties.maxVertexOutputComponents); glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &properties.maxVertexTextureImageUnits); glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &properties.maxVertexAtomicCounterBuffers); glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &properties.maxVertexAtomicCounters); glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &properties.maxVertexShaderStorageBlocks); glGetIntegerv(GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, &properties.maxCombinedVertexUniformComponents); glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &properties.maxFragmentUniformComponents); glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &properties.maxFragmentUniformVectors); glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &properties.maxFragmentUniformBlocks); glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &properties.maxFragmentImageUniforms); glGetIntegerv(GL_MAX_FRAGMENT_INPUT_COMPONENTS, &properties.maxFragmentInputComponents); glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &properties.maxFragmentImageUnits); glGetIntegerv(GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET, &properties.minProgramTextureGatherOffset); glGetIntegerv(GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET, &properties.maxProgramTextureGatherOffset); glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &properties.maxFragmentAtomicCounterBuffers); glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &properties.maxFragmentAtomicCounters); glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &properties.maxFragmentShaderStorageBlocks); glGetIntegerv(GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, &properties.maxCombinedFragmentUniformComponents); glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, properties.maxComputeWorkGroupCount); glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, properties.maxComputeWorkGroupCount + 1); glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, properties.maxComputeWorkGroupCount + 2); glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, properties.maxComputeWorkGroupSize); glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, properties.maxComputeWorkGroupSize + 1); glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, properties.maxComputeWorkGroupSize + 2); glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &properties.maxComputeWorkGroupInvocations); glGetIntegerv(GL_MAX_COMPUTE_UNIFORM_BLOCKS, &properties.maxComputeUniformBlocks); glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &properties.maxComputeImageUniforms); glGetIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, &properties.maxComputeTextureImageUnits); glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, &properties.maxComputeAtomicCounterBuffers); glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, &properties.maxComputeAtomicCounters); glGetIntegerv(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, &properties.maxComputeSharedMemorySize); glGetIntegerv(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, &properties.maxComputeUniformComponents); glGetIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &properties.maxComputeShaderStorageBlocks); glGetIntegerv(GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS, &properties.maxCombinedComputeUniformComponents); glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &properties.maxTextureBufferSize); glGetIntegerv(GL_MIN_PROGRAM_TEXEL_OFFSET, &properties.minProgramTexelOffset); glGetIntegerv(GL_MAX_PROGRAM_TEXEL_OFFSET, &properties.maxProgramTexelOffset); glGetIntegerv(GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET, &properties.minProgramTextureGatherOffset); glGetIntegerv(GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET, &properties.maxProgramTextureGatherOffset); glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &properties.maxUniformBufferBindings); glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &properties.maxUniformBlockSize); glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &properties.uniformBufferOffsetAlignment); glGetIntegerv(GL_MAX_COMBINED_UNIFORM_BLOCKS, &properties.maxCombinedUniformBlocks); glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &properties.maxUniformLocations); glGetIntegerv(GL_MAX_VARYING_COMPONENTS, &properties.maxVaryingComponents); glGetIntegerv(GL_MAX_VARYING_FLOATS, &properties.maxVaryingFloats); glGetIntegerv(GL_MAX_VARYING_VECTORS, &properties.maxVaryingVectors); glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &properties.maxCombinedTextureImageUnits); glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &properties.maxAtomicCounterBufferBindings); glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, &properties.maxAtomicCounterBufferSize); glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTERS, &properties.maxCombinedAtomicCounters); glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS, &properties.maxCombinedAtomicCounterBuffers); glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &properties.maxShaderStorageBufferBindings); glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &properties.maxShaderStorageBlockSize); glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &properties.maxCombinedShaderStorageBlocks); glGetIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &properties.shaderStorageBufferOffsetAlignment); glGetIntegerv(GL_MAX_IMAGE_UNITS, &properties.maxImageUnits); glGetIntegerv(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, &properties.maxCombinedShaderOutputResources); glGetIntegerv(GL_MAX_COMBINED_IMAGE_UNIFORMS, &properties.maxCombinedImageUniforms); glGetIntegerv(GL_MIN_MAP_BUFFER_ALIGNMENT, &properties.minMapBufferAlignment); glGetIntegerv(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, &properties.maxVertexAttribRelativeOffset); glGetIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &properties.maxVertexAttribBindings); glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &properties.maxVertexAttribStride); glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &properties.maxElementsIndices); glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &properties.maxElementsVertices); glGetInteger64v(GL_MAX_ELEMENT_INDEX, &properties.maxElementIndex); glGetIntegerv(GL_MAX_CLIP_DISTANCES, &properties.maxClipDistances); glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &properties.maxColorAttachments); glGetIntegerv(GL_MAX_FRAMEBUFFER_WIDTH, &properties.maxFramebufferWidth); glGetIntegerv(GL_MAX_FRAMEBUFFER_HEIGHT, &properties.maxFramebufferHeight); glGetIntegerv(GL_MAX_FRAMEBUFFER_LAYERS, &properties.maxFramebufferLayers); glGetIntegerv(GL_MAX_FRAMEBUFFER_SAMPLES, &properties.maxFramebufferSamples); glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &properties.maxSampleMaskWords); glGetIntegerv(GL_MAX_SAMPLES, &properties.maxSamples); glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &properties.maxColorTextureSamples); glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &properties.maxDepthTextureSamples); glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &properties.maxIntegerSamples); glGetInteger64v(GL_MAX_SERVER_WAIT_TIMEOUT, &properties.maxServerWaitTimeout); glGetIntegerv(GL_MAX_DRAW_BUFFERS, &properties.maxDrawBuffers); glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, &properties.maxDualSourceDrawBuffers); glGetIntegerv(GL_MAX_LABEL_LENGTH, &properties.maxLabelLength); } } // namespace uintptr_t WGLState::CreateSurface(uintptr_t window, uintptr_t instance) const noexcept { return reinterpret_cast(GetDC(reinterpret_cast(window))); } void WGLState::DestroySurface(uintptr_t surface) const noexcept { auto deviceContext = reinterpret_cast(surface); HWND window = WindowFromDC(deviceContext); ReleaseDC(window, deviceContext); } bool WGLState::GetInformation(HDC surface, int32_t configId, GlesImplementation::SurfaceInfo& res) const { if (configId > 0) { int attribList[16] = { WGL_RED_BITS_ARB, /* 0 */ WGL_GREEN_BITS_ARB, /* 1 */ WGL_BLUE_BITS_ARB, /* 2 */ WGL_ALPHA_BITS_ARB, /* 3 */ WGL_DEPTH_BITS_ARB, /* 4 */ WGL_STENCIL_BITS_ARB, /* 5 */ WGL_SAMPLES_ARB }; /* 6 */ int32_t attribCnt = 7; int32_t colorspaceIndex = 0; int32_t srgbIndex = 0; if (hasColorSpace_) { colorspaceIndex = attribCnt; attribList[attribCnt] = WGL_COLORSPACE_EXT; attribCnt++; } if (hasSRGBFB_) { srgbIndex = attribCnt; attribList[attribCnt] = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB; attribCnt++; } int values[16] {}; const bool ret = wglGetPixelFormatAttribivARB(surface, configId, 0, static_cast(attribCnt), attribList, values); if (ret) { res.configId = static_cast(configId); res.red_size = static_cast(values[0]); res.green_size = static_cast(values[1]); res.blue_size = static_cast(values[2]); res.alpha_size = static_cast(values[3]); res.depth_size = static_cast(values[4]); res.stencil_size = static_cast(values[5]); res.samples = static_cast(values[6]); res.srgb = false; // default to linear framebuffer if (hasSRGBFB_) { // is framebuffer srgb capable? res.srgb = (values[srgbIndex] != 0) ? true : false; } if (hasColorSpace_) { // has srgb colorspace? res.srgb = static_cast(values[colorspaceIndex]) == WGL_COLORSPACE_SRGB_EXT; } return true; } } return false; } bool WGLState::GetSurfaceInformation(HDC surface, GlesImplementation::SurfaceInfo& res) const { RECT rcCli; GetClientRect(WindowFromDC(surface), &rcCli); // then you might have: res.width = static_cast(rcCli.right - rcCli.left); res.height = static_cast(rcCli.bottom - rcCli.top); int32_t configId = GetPixelFormat(surface); if (!configId) { configId = GetPixelFormat(plat_.display); if (configId) { PIXELFORMATDESCRIPTOR pfd = { 0 }; DescribePixelFormat(plat_.display, configId, sizeof(pfd), &pfd); SetPixelFormat(surface, configId, &pfd); } } return GetInformation(surface, configId, res); } void WGLState::SwapBuffers(const SwapchainGLES& swapChain) { auto& plat = swapChain.GetPlatformData(); ::SwapBuffers(reinterpret_cast(plat.surface)); } bool WGLState::HasExtension(const string_view extension) const { for (const auto& e : extensionList_) { if (extension == e) return true; } return false; } int WGLState::ChoosePixelFormat(HDC dc, const vector& attributes) { /* Create a custom algorithm for choosing a best match, it seems wglChoosePixelFormatARB ignores some attributes. Seems to completely ignore WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB for example */ int pixelFormats[64] = { -1 }; UINT numFormats = 0; wglChoosePixelFormatARB(dc, attributes.data(), nullptr, 64, pixelFormats, &numFormats); return pixelFormats[0]; } bool WGLState::IsValid() { return plat_.context != nullptr; } void WGLState::CreateContext(DeviceCreateInfo const& createInfo) { glModule_ = LoadLibrary("opengl32.dll"); #define declareWGL(a, b) \ if (b == nullptr) { \ *(reinterpret_cast(&b)) = reinterpret_cast(GetProcAddress(glModule_, #b)); \ } WGLFUNCS #undef declareWGL auto backendConfig = static_cast(createInfo.backendConfiguration); HGLRC sharedContext = nullptr; if (backendConfig) { plat_.mhWnd = backendConfig->window; sharedContext = backendConfig->sharedContext; } DoDummy(); if (!plat_.mhWnd) { plat_.mhWnd = GetActiveWindow(); } plat_.display = GetDC(plat_.mhWnd); if (wglGetExtensionsStringARB) { extensions_ = wglGetExtensionsStringARB(plat_.display); } PLUGIN_LOG_V("WGL_EXTENSIONS: %s", extensions_.c_str()); ParseExtensions(extensions_, extensionList_); hasSRGBFB_ = HasExtension("WGL_ARB_framebuffer_sRGB"); hasColorSpace_ = HasExtension("WGL_EXT_colorspace"); // construct attribute list dynamically vector attributes; const size_t ATTRIBUTE_RESERVE = 20; // reserve 20 attributes attributes.reserve(ATTRIBUTE_RESERVE * 2); // 2 EGLints per attribute const auto addAttribute = [&attributes](int a, int b) { attributes.push_back(a); attributes.push_back(b); }; addAttribute(WGL_STEREO_ARB, GL_FALSE); addAttribute(WGL_AUX_BUFFERS_ARB, 0); addAttribute(WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_EXT); addAttribute(WGL_DRAW_TO_WINDOW_ARB, GL_TRUE); addAttribute(WGL_SUPPORT_OPENGL_ARB, GL_TRUE); addAttribute(WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB); addAttribute(WGL_DOUBLE_BUFFER_ARB, GL_TRUE); addAttribute(WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB); addAttribute(WGL_RED_BITS_ARB, 8); addAttribute(WGL_GREEN_BITS_ARB, 8); addAttribute(WGL_BLUE_BITS_ARB, 8); if (hasSRGBFB_) { addAttribute(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, GL_TRUE); // srgb capable framebuffers only.. } if (hasColorSpace_) { addAttribute(WGL_COLORSPACE_EXT, WGL_COLORSPACE_SRGB_EXT); // prefer srgb.. } if (backendConfig) { if (backendConfig->MSAASamples > 1) { addAttribute(WGL_SAMPLE_BUFFERS_ARB, 1); addAttribute(WGL_SAMPLES_ARB, static_cast(backendConfig->MSAASamples)); } addAttribute(WGL_DEPTH_BITS_ARB, static_cast(backendConfig->depthBits)); addAttribute(WGL_STENCIL_BITS_ARB, static_cast(backendConfig->stencilBits)); addAttribute(WGL_ALPHA_BITS_ARB, static_cast(backendConfig->alphaBits)); } addAttribute(0, 0); // Terminate the list const int pixelFormat = ChoosePixelFormat(plat_.display, attributes); PIXELFORMATDESCRIPTOR pfd = { 0 }; DescribePixelFormat(plat_.display, pixelFormat, sizeof(pfd), &pfd); SetPixelFormat(plat_.display, pixelFormat, &pfd); plat_.context = wglCreateContextAttribsARB(plat_.display, sharedContext, WGL_ATTRIBS); SaveContext(); SetContext(nullptr); // activate the context with the dummy PBuffer. } void WGLState::DestroyContext() { wglMakeCurrent(nullptr, nullptr); if (plat_.context) { wglDeleteContext(plat_.context); } if (plat_.mhWnd && plat_.display) { ReleaseDC(plat_.mhWnd, plat_.display); } FreeLibrary(glModule_); } void WGLState::GlInitialize() { #define declare(a, b) \ if (b == nullptr) { \ *(reinterpret_cast(&b)) = reinterpret_cast(wglGetProcAddress(#b)); \ } \ if (b == nullptr) { \ *(reinterpret_cast(&b)) = reinterpret_cast(GetProcAddress(glModule_, #b)); \ } \ PLUGIN_ASSERT_MSG(b, "Missing %s\n", #b) #include "gles/gl_functions.h" #undef declare plat_.deviceName = reinterpret_cast(glGetString(GL_RENDERER)); plat_.driverVersion = reinterpret_cast(glGetString(GL_VERSION)); BASE_NS::ClearToValue( &plat_.deviceProperties, sizeof(plat_.deviceProperties), 0x00, sizeof(plat_.deviceProperties)); FillProperties(plat_.deviceProperties); SetSwapInterval(1); // default to vsync enabled. glEnable(GL_FRAMEBUFFER_SRGB); } void WGLState::SetSwapInterval(uint32_t aInterval) { if (wglSwapIntervalEXT) { wglSwapIntervalEXT(static_cast(aInterval)); } } void* WGLState::ErrorFilter() const { return reinterpret_cast(FilterError); } void WGLState::SaveContext() { PLUGIN_ASSERT(!oldIsSet_); oldIsSet_ = true; oldContext_.context = wglGetCurrentContext(); oldContext_.display = wglGetCurrentDC(); } void WGLState::SetContext(const SwapchainGLES* swapChain) { if (swapChain == nullptr) { wglMakeCurrent(plat_.display, plat_.context); } else { const auto& plat = swapChain->GetPlatformData(); if (plat.surface == 0) { const uint64_t swapLoc = reinterpret_cast(swapChain); #if (RENDER_VALIDATION_ENABLED == 1) PLUGIN_LOG_ONCE_E( "gl_invalid_surface" + BASE_NS::to_string(swapLoc), "Invalid swapchain surface for MakeCurrent using default"); #endif wglMakeCurrent(plat_.display, plat_.context); } else { auto display = reinterpret_cast(plat.surface); auto context = plat_.context; if (plat_.context == 0) { PLUGIN_LOG_E("Invalid context for MakeCurrent"); } wglMakeCurrent(display, context); } if (vSync_ != plat.vsync) { vSync_ = plat.vsync; SetSwapInterval(plat.vsync ? 1u : 0u); } } } void WGLState::RestoreContext() { PLUGIN_ASSERT(oldIsSet_); wglMakeCurrent(oldContext_.display, oldContext_.context); oldIsSet_ = false; } const DevicePlatformData& WGLState::GetPlatformData() const { return plat_; } } // namespace WGLHelpers RENDER_END_NAMESPACE() #endif