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