1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #if RENDER_HAS_GL_BACKEND
17 #include "gles/wgl_state.h"
18 
19 #include <base/containers/fixed_string.h>
20 #include <render/namespace.h>
21 
22 #include "util/log.h"
23 
24 // NOTE: intentional double include of gl_functions.h
25 #include "gles/gl_functions.h"
26 #define declare(a, b) a b = nullptr;
27 #include <gl/wgl.h>
28 
29 #include "gles/gl_functions.h"
30 #include "gles/surface_information.h"
31 #include "gles/swapchain_gles.h"
32 
33 using BASE_NS::string_view;
34 using BASE_NS::vector;
35 
36 RENDER_BEGIN_NAMESPACE()
37 namespace WGLHelpers {
38 namespace {
39 #define WGLFUNCS                                                                   \
40     declareWGL(PFNWGLGETPROCADDRESSPROC, wglGetProcAddress);                       \
41     declareWGL(PFNWGLCREATECONTEXTPROC, wglCreateContext);                         \
42     declareWGL(PFNWGLDELETECONTEXTPROC, wglDeleteContext);                         \
43     declareWGL(PFNWGLMAKECURRENTPROC, wglMakeCurrent);                             \
44     declareWGL(PFNWGLGETCURRENTCONTEXTPROC, wglGetCurrentContext);                 \
45     declareWGL(PFNWGLGETCURRENTDCPROC, wglGetCurrentDC);                           \
46     declareWGL(PFNWGLCREATECONTEXTATTRIBSARBPROC, wglCreateContextAttribsARB);     \
47     declareWGL(PFNWGLGETPIXELFORMATATTRIBIVARBPROC, wglGetPixelFormatAttribivARB); \
48     declareWGL(PFNWGLGETPIXELFORMATATTRIBFVARBPROC, wglGetPixelFormatAttribfvARB); \
49     declareWGL(PFNWGLCHOOSEPIXELFORMATARBPROC, wglChoosePixelFormatARB);           \
50     declareWGL(PFNWGLSWAPINTERVALEXTPROC, wglSwapIntervalEXT);                     \
51     declareWGL(PFNWGLGETEXTENSIONSSTRINGARBPROC, wglGetExtensionsStringARB);
52 
53 #define declareWGL(a, b) a b = nullptr;
54 WGLFUNCS;
55 #undef declareWGL
56 
57 constexpr int WGL_ATTRIBS[] = {
58 #if defined(CORE_CREATE_GLES_CONTEXT_WITH_WGL) && (CORE_CREATE_GLES_CONTEXT_WITH_WGL == 1)
59     WGL_CONTEXT_MAJOR_VERSION_ARB, 3, WGL_CONTEXT_MINOR_VERSION_ARB, 2,
60 #if RENDER_GL_DEBUG
61     WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
62 #endif
63     WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_ES2_PROFILE_BIT_EXT, 0
64 #else
65     WGL_CONTEXT_MAJOR_VERSION_ARB, 4, WGL_CONTEXT_MINOR_VERSION_ARB, 5,
66 #if RENDER_GL_DEBUG
67     WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
68 #endif
69     WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, 0
70 #endif
71 };
72 
FilterError(GLenum source,GLenum type,GLuint id,GLenum severity,GLsizei length,const string_view message,const void * userParam)73 static bool FilterError(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length,
74     const string_view message, const void* userParam) noexcept
75 {
76     if (source == GL_DEBUG_SOURCE_API) {
77         if (type == GL_DEBUG_TYPE_OTHER) {
78             if ((id == 11) && (severity == GL_DEBUG_SEVERITY_LOW)) {
79                 /*  Ignore the following warning that Intel drivers seem to spam. (no problems on nvidia or mali...)
80                 source: GL_DEBUG_SOURCE_API
81                 type: GL_DEBUG_TYPE_OTHER
82                 severity: GL_DEBUG_SEVERITY_LOW
83                 message: API_ID_SYNC_FLUSH other warning has been generated. ClientWait flush in different gc for sync
84                 object 2, "" will be ineffective.
85                 */
86                 return true;
87             }
88 
89             if ((id == 131185) && (severity == GL_DEBUG_SEVERITY_NOTIFICATION)) {
90                 /* Ignore this warning that Nvidia sends.
91                 source:      GL_DEBUG_SOURCE_API
92                 type:        GL_DEBUG_TYPE_OTHER
93                 severity:    GL_DEBUG_SEVERITY_NOTIFICATION
94                 message:     Buffer detailed info: Buffer object X (bound to GL_COPY_WRITE_BUFFER_BINDING_EXT, usage
95                 hint is GL_DYNAMIC_DRAW) will use SYSTEM HEAP memory as the source for buffer object operations. *OR*
96                 message:     Buffer detailed info: Buffer object X (bound to GL_COPY_WRITE_BUFFER_BINDING_EXT, usage
97                 hint is GL_DYNAMIC_DRAW) has been mapped WRITE_ONLY in SYSTEM HEAP memory (fast).
98                 */
99                 return true;
100             }
101         }
102         if (type == GL_DEBUG_TYPE_PERFORMANCE) {
103             if ((id == 131154) && (severity == GL_DEBUG_SEVERITY_MEDIUM)) {
104                 /*
105                 source: GL_DEBUG_SOURCE_API
106                 type: GL_DEBUG_TYPE_PERFORMANCE
107                 id: 131154
108                 severity: GL_DEBUG_SEVERITY_MEDIUM
109                 message: Pixel-path performance warning: Pixel transfer is synchronized with 3D rendering.
110                 */
111                 return true;
112             }
113             if ((id == 131186) && (severity == GL_DEBUG_SEVERITY_MEDIUM)) {
114                 /* Ignore this warning that Nvidia sends.
115                 source: GL_DEBUG_SOURCE_API
116                 type: GL_DEBUG_TYPE_PERFORMANCE
117                 id: 131186
118                 severity: GL_DEBUG_SEVERITY_MEDIUM
119                 message: Buffer performance warning: Buffer object X (bound to GL_ELEMENT_ARRAY_BUFFER_ARB, usage hint
120                 is GL_DYNAMIC_DRAW) is being copied/moved from VIDEO memory to HOST memory.
121                 */
122                 return true;
123             }
124             if ((id == 131202) && (severity == GL_DEBUG_SEVERITY_MEDIUM)) {
125                 /* Ignore this warning that Nvidia sends.
126                 source: GL_DEBUG_SOURCE_API
127                 type: GL_DEBUG_TYPE_PERFORMANCE
128                 id: 131202
129                 severity: GL_DEBUG_SEVERITY_MEDIUM
130                 message: Texture state performance warning: emulating compressed format not supported in hardware with
131                 decompressed images
132                 */
133                 return true;
134             }
135         }
136     }
137     return false;
138 }
139 
DoDummy()140 static void DoDummy()
141 {
142     WNDCLASS wc = { 0 };
143     wc.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
144     wc.lpfnWndProc = DefWindowProc; // WindowProc;
145     wc.hInstance = GetModuleHandle(nullptr);
146     wc.lpszClassName = TEXT("PureGL_WGL_Dummy");
147     wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
148     RegisterClass(&wc);
149     const HWND dummyhWnd = CreateWindowEx(0, wc.lpszClassName, wc.lpszClassName, WS_OVERLAPPED, CW_USEDEFAULT,
150         CW_USEDEFAULT, 1, 1, nullptr, nullptr, wc.hInstance, nullptr);
151     const HDC dummyhDC = GetDC(dummyhWnd);
152     PIXELFORMATDESCRIPTOR pfd = { 0 };
153     pfd.nSize = sizeof(pfd);
154     pfd.nVersion = 1;
155     pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_GENERIC_ACCELERATED | PFD_DOUBLEBUFFER;
156     pfd.iPixelType = PFD_TYPE_RGBA;
157     pfd.cColorBits = 32;
158     pfd.iLayerType = PFD_MAIN_PLANE;
159     SetPixelFormat(dummyhDC, ChoosePixelFormat(dummyhDC, &pfd), &pfd);
160     const HGLRC dummy = wglCreateContext(dummyhDC);
161     wglMakeCurrent(dummyhDC, dummy);
162 #define declareWGL(a, b)                                                                    \
163     if ((b) == nullptr) {                                                                   \
164         *(reinterpret_cast<void**>(&(b))) = reinterpret_cast<void*>(wglGetProcAddress(#b)); \
165     }
166     WGLFUNCS
167 #undef declareWGL
168     wglMakeCurrent(dummyhDC, nullptr);
169     wglMakeCurrent(nullptr, nullptr);
170     wglDeleteContext(dummy);
171     ReleaseDC(dummyhWnd, dummyhDC);
172     DestroyWindow(dummyhWnd);
173     UnregisterClass(wc.lpszClassName, wc.hInstance);
174 }
175 
ParseExtensions(const string_view extensions,vector<string_view> & extensionList)176 void ParseExtensions(const string_view extensions, vector<string_view>& extensionList)
177 {
178     size_t start = 0;
179     for (auto end = extensions.find(' '); end != BASE_NS::string::npos; end = extensions.find(' ', start)) {
180         extensionList.emplace_back(extensions.data() + start, end - start);
181         start = end + 1;
182     }
183     if (start < extensions.size()) {
184         extensionList.emplace_back(extensions.data() + start);
185     }
186 }
187 
FillProperties(DevicePropertiesGL & properties)188 void FillProperties(DevicePropertiesGL& properties)
189 {
190     glGetIntegerv(GL_MAX_3D_TEXTURE_SIZE, &properties.max3DTextureSize);
191     glGetIntegerv(GL_MAX_TEXTURE_SIZE, &properties.maxTextureSize);
192     glGetIntegerv(GL_MAX_ARRAY_TEXTURE_LAYERS, &properties.maxArrayTextureLayers);
193     glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &properties.maxTextureLodBias);
194     glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY, &properties.maxTextureMaxAnisotropy);
195     glGetIntegerv(GL_MAX_CUBE_MAP_TEXTURE_SIZE, &properties.maxCubeMapTextureSize);
196     glGetIntegerv(GL_MAX_RENDERBUFFER_SIZE, &properties.maxRenderbufferSize);
197     glGetFloati_v(GL_MAX_VIEWPORT_DIMS, 0, properties.maxViewportDims);
198     glGetFloati_v(GL_MAX_VIEWPORT_DIMS, 1, properties.maxViewportDims + 1);
199     glGetIntegerv(GL_MAX_VIEWPORTS, &properties.maxViewports);
200     glGetIntegerv(GL_VIEWPORT_SUBPIXEL_BITS, &properties.viewportSubpixelBits);
201     glGetIntegerv(GL_VIEWPORT_BOUNDS_RANGE, &properties.viewportBoundsRange);
202 
203     glGetIntegerv(GL_MAJOR_VERSION, &properties.majorVersion);
204     glGetIntegerv(GL_MINOR_VERSION, &properties.minorVersion);
205     glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &properties.numProgramBinaryFormats);
206     glGetIntegerv(GL_NUM_SHADER_BINARY_FORMATS, &properties.numShaderBinaryFormats);
207 
208     glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &properties.maxVertexAttribs);
209     glGetIntegerv(GL_MAX_VERTEX_UNIFORM_COMPONENTS, &properties.maxVertexUniformComponents);
210     glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &properties.maxVertexUniformVectors);
211     glGetIntegerv(GL_MAX_VERTEX_UNIFORM_BLOCKS, &properties.maxVertexUniformBlocks);
212     glGetIntegerv(GL_MAX_VERTEX_IMAGE_UNIFORMS, &properties.maxVertexImageUniforms);
213     glGetIntegerv(GL_MAX_VERTEX_OUTPUT_COMPONENTS, &properties.maxVertexOutputComponents);
214     glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &properties.maxVertexTextureImageUnits);
215     glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS, &properties.maxVertexAtomicCounterBuffers);
216     glGetIntegerv(GL_MAX_VERTEX_ATOMIC_COUNTERS, &properties.maxVertexAtomicCounters);
217     glGetIntegerv(GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS, &properties.maxVertexShaderStorageBlocks);
218     glGetIntegerv(GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS, &properties.maxCombinedVertexUniformComponents);
219 
220     glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_COMPONENTS, &properties.maxFragmentUniformComponents);
221     glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &properties.maxFragmentUniformVectors);
222     glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_BLOCKS, &properties.maxFragmentUniformBlocks);
223     glGetIntegerv(GL_MAX_FRAGMENT_IMAGE_UNIFORMS, &properties.maxFragmentImageUniforms);
224     glGetIntegerv(GL_MAX_FRAGMENT_INPUT_COMPONENTS, &properties.maxFragmentInputComponents);
225     glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &properties.maxFragmentImageUnits);
226     glGetIntegerv(GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET, &properties.minProgramTextureGatherOffset);
227     glGetIntegerv(GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET, &properties.maxProgramTextureGatherOffset);
228     glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS, &properties.maxFragmentAtomicCounterBuffers);
229     glGetIntegerv(GL_MAX_FRAGMENT_ATOMIC_COUNTERS, &properties.maxFragmentAtomicCounters);
230     glGetIntegerv(GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS, &properties.maxFragmentShaderStorageBlocks);
231     glGetIntegerv(GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS, &properties.maxCombinedFragmentUniformComponents);
232 
233     glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 0, properties.maxComputeWorkGroupCount);
234     glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 1, properties.maxComputeWorkGroupCount + 1);
235     glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_COUNT, 2, properties.maxComputeWorkGroupCount + 2);
236     glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 0, properties.maxComputeWorkGroupSize);
237     glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 1, properties.maxComputeWorkGroupSize + 1);
238     glGetIntegeri_v(GL_MAX_COMPUTE_WORK_GROUP_SIZE, 2, properties.maxComputeWorkGroupSize + 2);
239     glGetIntegerv(GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS, &properties.maxComputeWorkGroupInvocations);
240     glGetIntegerv(GL_MAX_COMPUTE_UNIFORM_BLOCKS, &properties.maxComputeUniformBlocks);
241     glGetIntegerv(GL_MAX_COMPUTE_IMAGE_UNIFORMS, &properties.maxComputeImageUniforms);
242     glGetIntegerv(GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS, &properties.maxComputeTextureImageUnits);
243     glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS, &properties.maxComputeAtomicCounterBuffers);
244     glGetIntegerv(GL_MAX_COMPUTE_ATOMIC_COUNTERS, &properties.maxComputeAtomicCounters);
245     glGetIntegerv(GL_MAX_COMPUTE_SHARED_MEMORY_SIZE, &properties.maxComputeSharedMemorySize);
246     glGetIntegerv(GL_MAX_COMPUTE_UNIFORM_COMPONENTS, &properties.maxComputeUniformComponents);
247     glGetIntegerv(GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS, &properties.maxComputeShaderStorageBlocks);
248     glGetIntegerv(GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS, &properties.maxCombinedComputeUniformComponents);
249 
250     glGetIntegerv(GL_MAX_TEXTURE_BUFFER_SIZE, &properties.maxTextureBufferSize);
251     glGetIntegerv(GL_MIN_PROGRAM_TEXEL_OFFSET, &properties.minProgramTexelOffset);
252     glGetIntegerv(GL_MAX_PROGRAM_TEXEL_OFFSET, &properties.maxProgramTexelOffset);
253     glGetIntegerv(GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET, &properties.minProgramTextureGatherOffset);
254     glGetIntegerv(GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET, &properties.maxProgramTextureGatherOffset);
255     glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &properties.maxUniformBufferBindings);
256     glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &properties.maxUniformBlockSize);
257     glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &properties.uniformBufferOffsetAlignment);
258     glGetIntegerv(GL_MAX_COMBINED_UNIFORM_BLOCKS, &properties.maxCombinedUniformBlocks);
259     glGetIntegerv(GL_MAX_UNIFORM_LOCATIONS, &properties.maxUniformLocations);
260     glGetIntegerv(GL_MAX_VARYING_COMPONENTS, &properties.maxVaryingComponents);
261     glGetIntegerv(GL_MAX_VARYING_FLOATS, &properties.maxVaryingFloats);
262     glGetIntegerv(GL_MAX_VARYING_VECTORS, &properties.maxVaryingVectors);
263     glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &properties.maxCombinedTextureImageUnits);
264     glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS, &properties.maxAtomicCounterBufferBindings);
265     glGetIntegerv(GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE, &properties.maxAtomicCounterBufferSize);
266     glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTERS, &properties.maxCombinedAtomicCounters);
267     glGetIntegerv(GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS, &properties.maxCombinedAtomicCounterBuffers);
268     glGetIntegerv(GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS, &properties.maxShaderStorageBufferBindings);
269     glGetIntegerv(GL_MAX_SHADER_STORAGE_BLOCK_SIZE, &properties.maxShaderStorageBlockSize);
270     glGetIntegerv(GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS, &properties.maxCombinedShaderStorageBlocks);
271     glGetIntegerv(GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT, &properties.shaderStorageBufferOffsetAlignment);
272     glGetIntegerv(GL_MAX_IMAGE_UNITS, &properties.maxImageUnits);
273     glGetIntegerv(GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES, &properties.maxCombinedShaderOutputResources);
274     glGetIntegerv(GL_MAX_COMBINED_IMAGE_UNIFORMS, &properties.maxCombinedImageUniforms);
275 
276     glGetIntegerv(GL_MIN_MAP_BUFFER_ALIGNMENT, &properties.minMapBufferAlignment);
277     glGetIntegerv(GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET, &properties.maxVertexAttribRelativeOffset);
278     glGetIntegerv(GL_MAX_VERTEX_ATTRIB_BINDINGS, &properties.maxVertexAttribBindings);
279     glGetIntegerv(GL_MAX_VERTEX_ATTRIB_STRIDE, &properties.maxVertexAttribStride);
280     glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &properties.maxElementsIndices);
281     glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &properties.maxElementsVertices);
282     glGetInteger64v(GL_MAX_ELEMENT_INDEX, &properties.maxElementIndex);
283     glGetIntegerv(GL_MAX_CLIP_DISTANCES, &properties.maxClipDistances);
284     glGetIntegerv(GL_MAX_COLOR_ATTACHMENTS, &properties.maxColorAttachments);
285     glGetIntegerv(GL_MAX_FRAMEBUFFER_WIDTH, &properties.maxFramebufferWidth);
286     glGetIntegerv(GL_MAX_FRAMEBUFFER_HEIGHT, &properties.maxFramebufferHeight);
287     glGetIntegerv(GL_MAX_FRAMEBUFFER_LAYERS, &properties.maxFramebufferLayers);
288     glGetIntegerv(GL_MAX_FRAMEBUFFER_SAMPLES, &properties.maxFramebufferSamples);
289     glGetIntegerv(GL_MAX_SAMPLE_MASK_WORDS, &properties.maxSampleMaskWords);
290     glGetIntegerv(GL_MAX_SAMPLES, &properties.maxSamples);
291     glGetIntegerv(GL_MAX_COLOR_TEXTURE_SAMPLES, &properties.maxColorTextureSamples);
292     glGetIntegerv(GL_MAX_DEPTH_TEXTURE_SAMPLES, &properties.maxDepthTextureSamples);
293     glGetIntegerv(GL_MAX_INTEGER_SAMPLES, &properties.maxIntegerSamples);
294     glGetInteger64v(GL_MAX_SERVER_WAIT_TIMEOUT, &properties.maxServerWaitTimeout);
295     glGetIntegerv(GL_MAX_DRAW_BUFFERS, &properties.maxDrawBuffers);
296     glGetIntegerv(GL_MAX_DUAL_SOURCE_DRAW_BUFFERS, &properties.maxDualSourceDrawBuffers);
297     glGetIntegerv(GL_MAX_LABEL_LENGTH, &properties.maxLabelLength);
298 }
299 } // namespace
300 
CreateSurface(uintptr_t window,uintptr_t instance) const301 uintptr_t WGLState::CreateSurface(uintptr_t window, uintptr_t instance) const noexcept
302 {
303     return reinterpret_cast<uintptr_t>(GetDC(reinterpret_cast<HWND>(window)));
304 }
305 
DestroySurface(uintptr_t surface) const306 void WGLState::DestroySurface(uintptr_t surface) const noexcept
307 {
308     auto deviceContext = reinterpret_cast<HDC>(surface);
309     HWND window = WindowFromDC(deviceContext);
310     ReleaseDC(window, deviceContext);
311 }
312 
GetInformation(HDC surface,int32_t configId,GlesImplementation::SurfaceInfo & res) const313 bool WGLState::GetInformation(HDC surface, int32_t configId, GlesImplementation::SurfaceInfo& res) const
314 {
315     if (configId > 0) {
316         int attribList[16] = { WGL_RED_BITS_ARB, /* 0 */
317             WGL_GREEN_BITS_ARB,                  /* 1 */
318             WGL_BLUE_BITS_ARB,                   /* 2 */
319             WGL_ALPHA_BITS_ARB,                  /* 3 */
320             WGL_DEPTH_BITS_ARB,                  /* 4 */
321             WGL_STENCIL_BITS_ARB,                /* 5 */
322             WGL_SAMPLES_ARB };                   /* 6 */
323         int32_t attribCnt = 7;
324         int32_t colorspaceIndex = 0;
325         int32_t srgbIndex = 0;
326         if (hasColorSpace_) {
327             colorspaceIndex = attribCnt;
328             attribList[attribCnt] = WGL_COLORSPACE_EXT;
329             attribCnt++;
330         }
331         if (hasSRGBFB_) {
332             srgbIndex = attribCnt;
333             attribList[attribCnt] = WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB;
334             attribCnt++;
335         }
336         int values[16] {};
337         const bool ret =
338             wglGetPixelFormatAttribivARB(surface, configId, 0, static_cast<UINT>(attribCnt), attribList, values);
339         if (ret) {
340             res.configId = static_cast<uint32_t>(configId);
341             res.red_size = static_cast<uint32_t>(values[0]);
342             res.green_size = static_cast<uint32_t>(values[1]);
343             res.blue_size = static_cast<uint32_t>(values[2]);
344             res.alpha_size = static_cast<uint32_t>(values[3]);
345             res.depth_size = static_cast<uint32_t>(values[4]);
346             res.stencil_size = static_cast<uint32_t>(values[5]);
347             res.samples = static_cast<uint32_t>(values[6]);
348             res.srgb = false; // default to linear framebuffer
349             if (hasSRGBFB_) {
350                 // is framebuffer srgb capable?
351                 res.srgb = (values[srgbIndex] != 0) ? true : false;
352             }
353             if (hasColorSpace_) {
354                 // has srgb colorspace?
355                 res.srgb = static_cast<uint32_t>(values[colorspaceIndex]) == WGL_COLORSPACE_SRGB_EXT;
356             }
357             return true;
358         }
359     }
360     return false;
361 }
362 
GetSurfaceInformation(HDC surface,GlesImplementation::SurfaceInfo & res) const363 bool WGLState::GetSurfaceInformation(HDC surface, GlesImplementation::SurfaceInfo& res) const
364 {
365     RECT rcCli;
366     GetClientRect(WindowFromDC(surface), &rcCli);
367     // then you might have:
368     res.width = static_cast<uint32_t>(rcCli.right - rcCli.left);
369     res.height = static_cast<uint32_t>(rcCli.bottom - rcCli.top);
370     int32_t configId = GetPixelFormat(surface);
371     if (!configId) {
372         configId = GetPixelFormat(plat_.display);
373         if (configId) {
374             PIXELFORMATDESCRIPTOR pfd = { 0 };
375             DescribePixelFormat(plat_.display, configId, sizeof(pfd), &pfd);
376             SetPixelFormat(surface, configId, &pfd);
377         }
378     }
379     return GetInformation(surface, configId, res);
380 }
381 
SwapBuffers(const SwapchainGLES & swapChain)382 void WGLState::SwapBuffers(const SwapchainGLES& swapChain)
383 {
384     auto& plat = swapChain.GetPlatformData();
385     ::SwapBuffers(reinterpret_cast<HDC>(plat.surface));
386 }
387 
HasExtension(const string_view extension) const388 bool WGLState::HasExtension(const string_view extension) const
389 {
390     for (const auto& e : extensionList_) {
391         if (extension == e)
392             return true;
393     }
394     return false;
395 }
396 
ChoosePixelFormat(HDC dc,const vector<int> & attributes)397 int WGLState::ChoosePixelFormat(HDC dc, const vector<int>& attributes)
398 {
399     /*
400     Create a custom algorithm for choosing a best match, it seems wglChoosePixelFormatARB ignores some attributes.
401     Seems to completely ignore WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB for example */
402     int pixelFormats[64] = { -1 };
403     UINT numFormats = 0;
404     wglChoosePixelFormatARB(dc, attributes.data(), nullptr, 64, pixelFormats, &numFormats);
405     return pixelFormats[0];
406 }
407 
IsValid()408 bool WGLState::IsValid()
409 {
410     return plat_.context != nullptr;
411 }
412 
CreateContext(DeviceCreateInfo const & createInfo)413 void WGLState::CreateContext(DeviceCreateInfo const& createInfo)
414 {
415     glModule_ = LoadLibrary("opengl32.dll");
416 #define declareWGL(a, b)                                                                          \
417     if (b == nullptr) {                                                                           \
418         *(reinterpret_cast<void**>(&b)) = reinterpret_cast<void*>(GetProcAddress(glModule_, #b)); \
419     }
420     WGLFUNCS
421 #undef declareWGL
422     auto backendConfig = static_cast<const BackendExtraGL*>(createInfo.backendConfiguration);
423 
424     HGLRC sharedContext = nullptr;
425     if (backendConfig) {
426         plat_.mhWnd = backendConfig->window;
427         sharedContext = backendConfig->sharedContext;
428     }
429 
430     DoDummy();
431 
432     if (!plat_.mhWnd) {
433         plat_.mhWnd = GetActiveWindow();
434     }
435     plat_.display = GetDC(plat_.mhWnd);
436     if (wglGetExtensionsStringARB) {
437         extensions_ = wglGetExtensionsStringARB(plat_.display);
438     }
439 
440     PLUGIN_LOG_V("WGL_EXTENSIONS: %s", extensions_.c_str());
441 
442     ParseExtensions(extensions_, extensionList_);
443 
444     hasSRGBFB_ = HasExtension("WGL_ARB_framebuffer_sRGB");
445     hasColorSpace_ = HasExtension("WGL_EXT_colorspace");
446 
447     // construct attribute list dynamically
448     vector<int> attributes;
449     const size_t ATTRIBUTE_RESERVE = 20;       // reserve 20 attributes
450     attributes.reserve(ATTRIBUTE_RESERVE * 2); // 2 EGLints per attribute
451     const auto addAttribute = [&attributes](int a, int b) {
452         attributes.push_back(a);
453         attributes.push_back(b);
454     };
455     addAttribute(WGL_STEREO_ARB, GL_FALSE);
456     addAttribute(WGL_AUX_BUFFERS_ARB, 0);
457     addAttribute(WGL_SWAP_METHOD_ARB, WGL_SWAP_EXCHANGE_EXT);
458     addAttribute(WGL_DRAW_TO_WINDOW_ARB, GL_TRUE);
459     addAttribute(WGL_SUPPORT_OPENGL_ARB, GL_TRUE);
460     addAttribute(WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB);
461     addAttribute(WGL_DOUBLE_BUFFER_ARB, GL_TRUE);
462     addAttribute(WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB);
463     addAttribute(WGL_RED_BITS_ARB, 8);
464     addAttribute(WGL_GREEN_BITS_ARB, 8);
465     addAttribute(WGL_BLUE_BITS_ARB, 8);
466     if (hasSRGBFB_) {
467         addAttribute(WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB, GL_TRUE); // srgb capable framebuffers only..
468     }
469     if (hasColorSpace_) {
470         addAttribute(WGL_COLORSPACE_EXT, WGL_COLORSPACE_SRGB_EXT); // prefer srgb..
471     }
472     if (backendConfig) {
473         if (backendConfig->MSAASamples > 1) {
474             addAttribute(WGL_SAMPLE_BUFFERS_ARB, 1);
475             addAttribute(WGL_SAMPLES_ARB, static_cast<int>(backendConfig->MSAASamples));
476         }
477         addAttribute(WGL_DEPTH_BITS_ARB, static_cast<int>(backendConfig->depthBits));
478         addAttribute(WGL_STENCIL_BITS_ARB, static_cast<int>(backendConfig->stencilBits));
479         addAttribute(WGL_ALPHA_BITS_ARB, static_cast<int>(backendConfig->alphaBits));
480     }
481     addAttribute(0, 0); // Terminate the list
482     const int pixelFormat = ChoosePixelFormat(plat_.display, attributes);
483     PIXELFORMATDESCRIPTOR pfd = { 0 };
484     DescribePixelFormat(plat_.display, pixelFormat, sizeof(pfd), &pfd);
485     SetPixelFormat(plat_.display, pixelFormat, &pfd);
486 
487     plat_.context = wglCreateContextAttribsARB(plat_.display, sharedContext, WGL_ATTRIBS);
488 
489     SaveContext();
490     SetContext(nullptr); // activate the context with the dummy PBuffer.
491 }
492 
DestroyContext()493 void WGLState::DestroyContext()
494 {
495     wglMakeCurrent(nullptr, nullptr);
496     if (plat_.context) {
497         wglDeleteContext(plat_.context);
498     }
499     if (plat_.mhWnd && plat_.display) {
500         ReleaseDC(plat_.mhWnd, plat_.display);
501     }
502     FreeLibrary(glModule_);
503 }
504 
GlInitialize()505 void WGLState::GlInitialize()
506 {
507 #define declare(a, b)                                                                             \
508     if (b == nullptr) {                                                                           \
509         *(reinterpret_cast<void**>(&b)) = reinterpret_cast<void*>(wglGetProcAddress(#b));         \
510     }                                                                                             \
511     if (b == nullptr) {                                                                           \
512         *(reinterpret_cast<void**>(&b)) = reinterpret_cast<void*>(GetProcAddress(glModule_, #b)); \
513     }                                                                                             \
514     PLUGIN_ASSERT_MSG(b, "Missing %s\n", #b)
515 
516 #include "gles/gl_functions.h"
517 #undef declare
518 
519     plat_.deviceName = reinterpret_cast<const char*>(glGetString(GL_RENDERER));
520     plat_.driverVersion = reinterpret_cast<const char*>(glGetString(GL_VERSION));
521     BASE_NS::ClearToValue(
522         &plat_.deviceProperties, sizeof(plat_.deviceProperties), 0x00, sizeof(plat_.deviceProperties));
523     FillProperties(plat_.deviceProperties);
524 
525     SetSwapInterval(1); // default to vsync enabled.
526 
527     glEnable(GL_FRAMEBUFFER_SRGB);
528 }
529 
SetSwapInterval(uint32_t aInterval)530 void WGLState::SetSwapInterval(uint32_t aInterval)
531 {
532     if (wglSwapIntervalEXT) {
533         wglSwapIntervalEXT(static_cast<int>(aInterval));
534     }
535 }
536 
ErrorFilter() const537 void* WGLState::ErrorFilter() const
538 {
539     return reinterpret_cast<void*>(FilterError);
540 }
541 
SaveContext()542 void WGLState::SaveContext()
543 {
544     PLUGIN_ASSERT(!oldIsSet_);
545     oldIsSet_ = true;
546     oldContext_.context = wglGetCurrentContext();
547     oldContext_.display = wglGetCurrentDC();
548 }
549 
SetContext(const SwapchainGLES * swapChain)550 void WGLState::SetContext(const SwapchainGLES* swapChain)
551 {
552     if (swapChain == nullptr) {
553         wglMakeCurrent(plat_.display, plat_.context);
554     } else {
555         const auto& plat = swapChain->GetPlatformData();
556         if (plat.surface == 0) {
557             const uint64_t swapLoc = reinterpret_cast<uint64_t>(swapChain);
558 #if (RENDER_VALIDATION_ENABLED == 1)
559             PLUGIN_LOG_ONCE_E(
560                 "gl_invalid_surface" + BASE_NS::to_string(swapLoc),
561                     "Invalid swapchain surface for MakeCurrent using default");
562 #endif
563             wglMakeCurrent(plat_.display, plat_.context);
564         } else {
565             auto display = reinterpret_cast<HDC>(plat.surface);
566             auto context = plat_.context;
567             if (plat_.context == 0) {
568                 PLUGIN_LOG_E("Invalid context for MakeCurrent");
569             }
570             wglMakeCurrent(display, context);
571         }
572 
573         if (vSync_ != plat.vsync) {
574             vSync_ = plat.vsync;
575             SetSwapInterval(plat.vsync ? 1u : 0u);
576         }
577     }
578 }
579 
RestoreContext()580 void WGLState::RestoreContext()
581 {
582     PLUGIN_ASSERT(oldIsSet_);
583     wglMakeCurrent(oldContext_.display, oldContext_.context);
584     oldIsSet_ = false;
585 }
586 
GetPlatformData() const587 const DevicePlatformData& WGLState::GetPlatformData() const
588 {
589     return plat_;
590 }
591 
592 } // namespace WGLHelpers
593 RENDER_END_NAMESPACE()
594 #endif