1 /*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "EglOsApi.h"
17
18 #include "base/Lock.h"
19 #include "base/SharedLibrary.h"
20
21 #include "CoreProfileConfigs.h"
22 #include "host-common/logging.h"
23 #include "GLcommon/GLLibrary.h"
24
25 #include "apigen-codec-common/ErrorLog.h"
26
27 #include <windows.h>
28 #include <wingdi.h>
29
30 #include <GLES/glplatform.h>
31 #include <GL/gl.h>
32 #include <GL/wglext.h>
33
34 #include <EGL/eglext.h>
35
36 #include <algorithm>
37 #include <memory>
38 #include <unordered_map>
39 #include <unordered_set>
40
41 #include <stdio.h>
42 #include <stdlib.h>
43
44 #define IS_TRUE(a) \
45 do { if (!(a)) return NULL; } while (0)
46
47 #define EXIT_IF_FALSE(a) \
48 do { if (!(a)) return; } while (0)
49
50 #define DEBUG 0
51 #if DEBUG
52 #define D(...) fprintf(stderr, __VA_ARGS__)
53 #else
54 #define D(...) ((void)0)
55 #endif
56
57 #define WGL_ERR(...) do { \
58 fprintf(stderr, __VA_ARGS__); \
59 GL_LOG(__VA_ARGS__); \
60 } while(0) \
61
62 // TODO: Replace with latency tracker.
63 #define PROFILE_SLOW(tag)
64
65 namespace {
66
67 using android::base::SharedLibrary;
68 typedef GlLibrary::GlFunctionPointer GlFunctionPointer;
69
70 // Returns true if an extension is include in a given extension list.
71 // |extension| is an GL extension name.
72 // |extensionList| is a space-separated list of supported extension.
73 // Returns true if the extension is supported, false otherwise.
supportsExtension(const char * extension,const char * extensionList)74 bool supportsExtension(const char* extension, const char* extensionList) {
75 size_t extensionLen = ::strlen(extension);
76 const char* list = extensionList;
77 for (;;) {
78 const char* p = const_cast<const char*>(::strstr(list, extension));
79 if (!p) {
80 return false;
81 }
82 // Check that the extension appears as a single word in the list
83 // i.e. that it is wrapped by either spaces or the start/end of
84 // the list.
85 if ((p == extensionList || p[-1] == ' ') &&
86 (p[extensionLen] == '\0' || p[extensionLen] == ' ')) {
87 return true;
88 }
89 // otherwise, skip over the current position to find something else.
90 p += extensionLen;
91 }
92 }
93
94 /////
95 ///// W G L D I S P A T C H T A B L E S
96 /////
97
98 // A technical note to explain what is going here, trust me, it's important.
99 //
100 // I. Library-dependent symbol resolution:
101 // ---------------------------------------
102 //
103 // The code here can deal with two kinds of OpenGL Windows libraries: the
104 // system-provided opengl32.dll, or alternate software renderers like Mesa
105 // (e.g. mesa_opengl32.dll).
106 //
107 // When using the system library, pixel-format related functions, like
108 // SetPixelFormat(), are provided by gdi32.dll, and _not_ opengl32.dll
109 // (even though they are documented as part of the Windows GL API).
110 //
111 // These functions must _not_ be used when using alternative renderers.
112 // Instead, these provide _undocumented_ alternatives with the 'wgl' prefix,
113 // as in wglSetPixelFormat(), wglDescribePixelFormat(), etc... which
114 // implement the same calling conventions.
115 //
116 // For more details about this, see 5.190 of the Windows OpenGL FAQ at:
117 // https://www.opengl.org/archives/resources/faq/technical/mswindows.htm
118 //
119 // Another good source of information on this topic:
120 // http://stackoverflow.com/questions/20645706/why-are-functions-duplicated-between-opengl32-dll-and-gdi32-dll
121 //
122 // In practice, it means that the code here should resolve 'naked' symbols
123 // (e.g. 'GetPixelFormat()) when using the system library, and 'prefixed' ones
124 // (e.g. 'wglGetPixelFormat()) otherwise.
125 //
126
127 // List of WGL functions of interest to probe with GetProcAddress()
128 #define LIST_WGL_FUNCTIONS(X) \
129 X(HGLRC, wglCreateContext, (HDC hdc)) \
130 X(BOOL, wglDeleteContext, (HGLRC hglrc)) \
131 X(BOOL, wglMakeCurrent, (HDC hdc, HGLRC hglrc)) \
132 X(BOOL, wglShareLists, (HGLRC hglrc1, HGLRC hglrc2)) \
133 X(HGLRC, wglGetCurrentContext, (void)) \
134 X(HDC, wglGetCurrentDC, (void)) \
135 X(GlFunctionPointer, wglGetProcAddress, (const char* functionName)) \
136
137 // List of WGL functions exported by GDI32 that must be used when using
138 // the system's opengl32.dll only, i.e. not with a software renderer like
139 // Mesa. For more information, see 5.190 at:
140 // And also:
141 #define LIST_GDI32_FUNCTIONS(X) \
142 X(int, ChoosePixelFormat, (HDC hdc, const PIXELFORMATDESCRIPTOR* ppfd)) \
143 X(BOOL, SetPixelFormat, (HDC hdc, int iPixelFormat, const PIXELFORMATDESCRIPTOR* pfd)) \
144 X(int, GetPixelFormat, (HDC hdc)) \
145 X(int, DescribePixelFormat, (HDC hdc, int iPixelFormat, UINT nbytes, LPPIXELFORMATDESCRIPTOR ppfd)) \
146 X(BOOL, SwapBuffers, (HDC hdc)) \
147
148 // Declare a structure containing pointers to all functions listed above,
149 // and a way to initialize them.
150 struct WglBaseDispatch {
151 // declare all function pointers, followed by a dummy member used
152 // to terminate the constructor's initialization list properly.
153 #define DECLARE_WGL_POINTER(return_type, function_name, signature) \
154 return_type (GL_APIENTRY* function_name) signature;
155 LIST_WGL_FUNCTIONS(DECLARE_WGL_POINTER)
156 LIST_GDI32_FUNCTIONS(DECLARE_WGL_POINTER)
157 SharedLibrary* mLib = nullptr;
158 bool mIsSystemLib = false;
159
160 // Default Constructor
WglBaseDispatch__anon04fdd2550111::WglBaseDispatch161 WglBaseDispatch() :
162 #define INIT_WGL_POINTER(return_type, function_name, signature) \
163 function_name(),
164 LIST_WGL_FUNCTIONS(INIT_WGL_POINTER)
165 LIST_GDI32_FUNCTIONS(INIT_WGL_POINTER)
166 mIsSystemLib(false) {}
167
168 // Copy constructor
WglBaseDispatch__anon04fdd2550111::WglBaseDispatch169 WglBaseDispatch(const WglBaseDispatch& other) :
170 #define COPY_WGL_POINTER(return_type, function_name, signature) \
171 function_name(other.function_name),
172 LIST_WGL_FUNCTIONS(COPY_WGL_POINTER)
173 LIST_GDI32_FUNCTIONS(COPY_WGL_POINTER)
174 mLib(other.mLib),
175 mIsSystemLib(other.mIsSystemLib) {}
176
177 // Initialize the dispatch table from shared library |glLib|, which
178 // must point to either the system or non-system opengl32.dll
179 // implementation. If |systemLib| is true, this considers the library
180 // to be the system one, and will try to find the GDI32 functions
181 // like GetPixelFormat() directly. If |systemLib| is false, this will
182 // try to load the wglXXX variants (e.g. for Mesa). See technical note
183 // above for details.
184 // Returns true on success, false otherwise (i.e. if one of the
185 // required symbols could not be loaded).
init__anon04fdd2550111::WglBaseDispatch186 bool init(SharedLibrary* glLib, bool systemLib) {
187 bool result = true;
188
189 mLib = glLib;
190 mIsSystemLib = systemLib;
191
192 #define LOAD_WGL_POINTER(return_type, function_name, signature) \
193 this->function_name = reinterpret_cast< \
194 return_type (GL_APIENTRY*) signature>( \
195 glLib->findSymbol(#function_name)); \
196 if (!this->function_name) { \
197 WGL_ERR("%s: Could not find %s in GL library\n", __FUNCTION__, \
198 #function_name); \
199 result = false; \
200 }
201
202 #define LOAD_WGL_GDI32_POINTER(return_type, function_name, signature) \
203 this->function_name = reinterpret_cast< \
204 return_type (GL_APIENTRY*) signature>( \
205 GetProcAddress(gdi32, #function_name)); \
206 if (!this->function_name) { \
207 WGL_ERR("%s: Could not find %s in GDI32 library\n", __FUNCTION__, \
208 #function_name); \
209 result = false; \
210 }
211
212 #define LOAD_WGL_INNER_POINTER(return_type, function_name, signature) \
213 this->function_name = reinterpret_cast< \
214 return_type (GL_APIENTRY*) signature>( \
215 glLib->findSymbol("wgl" #function_name)); \
216 if (!this->function_name) { \
217 WGL_ERR("%s: Could not find %s in GL library\n", __FUNCTION__, \
218 "wgl" #function_name); \
219 result = false; \
220 }
221
222 LIST_WGL_FUNCTIONS(LOAD_WGL_POINTER)
223 if (systemLib) {
224 HMODULE gdi32 = GetModuleHandleA("gdi32.dll");
225 LIST_GDI32_FUNCTIONS(LOAD_WGL_GDI32_POINTER)
226 } else {
227 LIST_GDI32_FUNCTIONS(LOAD_WGL_INNER_POINTER)
228 }
229 return result;
230 }
231
232 // Find a function, using wglGetProcAddress() first, and if that doesn't
233 // work, SharedLibrary::findSymbol().
234 // |functionName| is the function name.
235 // |glLib| is the GL library to probe with findSymbol() is needed.
findFunction__anon04fdd2550111::WglBaseDispatch236 GlFunctionPointer findFunction(const char* functionName) const {
237 GlFunctionPointer result = this->wglGetProcAddress(functionName);
238 if (!result && mLib) {
239 result = mLib->findSymbol(functionName);
240 }
241 return result;
242 }
243 };
244
245 // Used internally by createDummyWindow().
dummyWndProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam)246 LRESULT CALLBACK dummyWndProc(HWND hwnd,
247 UINT uMsg,
248 WPARAM wParam,
249 LPARAM lParam) {
250 return DefWindowProcA(hwnd, uMsg, wParam, lParam);
251 }
252
253 // Create a new dummy window, and return its handle.
254 // Note that the window is 1x1 pixels and not visible, but
255 // it can be used to create a device context and associated
256 // OpenGL rendering context. Return NULL on failure.
createDummyWindow()257 HWND createDummyWindow() {
258 WNDCLASSA wcx;
259 // wcx.cbSize = sizeof(wcx); // size of structure
260 wcx.style = CS_OWNDC | CS_HREDRAW | CS_VREDRAW; // redraw if size changes
261 wcx.lpfnWndProc = dummyWndProc; // points to window procedure
262 wcx.cbClsExtra = 0; // no extra class memory
263 wcx.cbWndExtra = sizeof(void*); // save extra window memory, to store VasWindow instance
264 wcx.hInstance = NULL; // handle to instance
265 wcx.hIcon = NULL; // predefined app. icon
266 wcx.hCursor = NULL;
267 wcx.hbrBackground = NULL; // no background brush
268 wcx.lpszMenuName = NULL; // name of menu resource
269 wcx.lpszClassName = "DummyWin"; // name of window class
270
271 RegisterClassA(&wcx);
272
273 HWND hwnd = CreateWindowExA(WS_EX_CLIENTEDGE,
274 "DummyWin",
275 "Dummy",
276 WS_POPUP,
277 0,
278 0,
279 1,
280 1,
281 NULL,
282 NULL,
283 0,0);
284 return hwnd;
285 }
286
287 // List of functions defined by the WGL_ARB_extensions_string extension.
288 #define LIST_extensions_string_FUNCTIONS(X) \
289 X(const char*, wglGetExtensionsString, (HDC hdc))
290
291 // List of functions defined by the WGL_ARB_pixel_format extension.
292 #define LIST_pixel_format_FUNCTIONS(X) \
293 X(BOOL, wglGetPixelFormatAttribiv, (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int* piAttributes, int* piValues)) \
294 X(BOOL, wglGetPixelFormatAttribfv, (HDC hdc, int iPixelFormat, int iLayerPlane, UINT nAttributes, const int* piAttributes, FLOAT* pfValues)) \
295 X(BOOL, wglChoosePixelFormat, (HDC, const int* piAttribList, const FLOAT* pfAttribList, UINT nMaxFormats, int* piFormats, UINT* nNumFormats)) \
296
297 // List of functions defined by the WGL_ARB_make_current_read extension.
298 #define LIST_make_current_read_FUNCTIONS(X) \
299 X(BOOL, wglMakeContextCurrent, (HDC hDrawDC, HDC hReadDC, HGLRC hglrc)) \
300 X(HDC, wglGetCurrentReadDC, (void)) \
301
302 // List of functions defined by the WGL_ARB_pbuffer extension.
303 #define LIST_pbuffer_FUNCTIONS(X) \
304 X(HPBUFFERARB, wglCreatePbuffer, (HDC hdc, int iPixelFormat, int iWidth, int iHeight, const int* piAttribList)) \
305 X(HDC, wglGetPbufferDC, (HPBUFFERARB hPbuffer)) \
306 X(int, wglReleasePbufferDC, (HPBUFFERARB hPbuffer, HDC hdc)) \
307 X(BOOL, wglDestroyPbuffer, (HPBUFFERARB hPbuffer)) \
308
309 // List of functions defined by WGL_ARB_create_context
310 #define LIST_create_context_FUNCTIONS(X) \
311 X(HGLRC, wglCreateContextAttribs, (HDC hDC, HGLRC hshareContext, const int *attribList)) \
312
313 // List of functions define by WGL_EXT_swap_control
314 #define LIST_swap_control_FUNCTIONS(X) \
315 X(void, wglSwapInterval, (int)) \
316 X(int, wglGetSwapInterval, (void)) \
317
318 #define LIST_WGL_EXTENSIONS_FUNCTIONS(X) \
319 LIST_pixel_format_FUNCTIONS(X) \
320 LIST_make_current_read_FUNCTIONS(X) \
321 LIST_pbuffer_FUNCTIONS(X) \
322 LIST_create_context_FUNCTIONS(X) \
323 LIST_swap_control_FUNCTIONS(X) \
324
325 // A structure used to hold pointers to WGL extension functions.
326 struct WglExtensionsDispatch : public WglBaseDispatch {
327 public:
328 LIST_WGL_EXTENSIONS_FUNCTIONS(DECLARE_WGL_POINTER)
329 int dummy;
330
331 // Default constructor
WglExtensionsDispatch__anon04fdd2550111::WglExtensionsDispatch332 explicit WglExtensionsDispatch(const WglBaseDispatch& baseDispatch) :
333 WglBaseDispatch(baseDispatch),
334 LIST_WGL_EXTENSIONS_FUNCTIONS(INIT_WGL_POINTER)
335 dummy(0) {}
336
337 // Initialization
init__anon04fdd2550111::WglExtensionsDispatch338 bool init(HDC hdc) {
339 // Base initialization happens first.
340 bool result = WglBaseDispatch::init(mLib, mIsSystemLib);
341 if (!result) {
342 return false;
343 }
344
345 // Find the list of extensions.
346 typedef const char* (GL_APIENTRY* GetExtensionsStringFunc)(HDC hdc);
347
348 const char* extensionList = nullptr;
349 GetExtensionsStringFunc wglGetExtensionsString =
350 reinterpret_cast<GetExtensionsStringFunc>(
351 this->findFunction("wglGetExtensionsStringARB"));
352
353 bool foundArb = wglGetExtensionsString != nullptr;
354
355 if (wglGetExtensionsString) {
356 extensionList = wglGetExtensionsString(hdc);
357 }
358
359 bool extensionListArbNull = extensionList == nullptr;
360 bool extensionListArbEmpty = !extensionListArbNull && !strcmp(extensionList, "");
361
362 bool foundExt = false;
363 bool extensionListExtNull = false;
364 bool extensionListExtEmpty = false;
365
366 // wglGetExtensionsStringARB failed, try wglGetExtensionsStringEXT.
367 if (!extensionList || !strcmp(extensionList, "")) {
368 wglGetExtensionsString =
369 reinterpret_cast<GetExtensionsStringFunc>(
370 this->findFunction("wglGetExtensionsStringEXT"));
371
372 foundExt = wglGetExtensionsString != nullptr;
373
374 if (wglGetExtensionsString) {
375 extensionList = wglGetExtensionsString(hdc);
376 }
377 }
378
379 extensionListExtNull = extensionList == nullptr;
380 extensionListExtEmpty = !extensionListExtNull && !strcmp(extensionList, "");
381
382 // Both failed, suicide.
383 if (!extensionList || !strcmp(extensionList, "")) {
384 bool isRemoteSession = GetSystemMetrics(SM_REMOTESESSION);
385
386 WGL_ERR(
387 "%s: Could not find wglGetExtensionsString! "
388 "arbFound %d listarbNull/empty %d %d "
389 "extFound %d extNull/empty %d %d remote %d\n",
390 __FUNCTION__,
391 foundArb,
392 extensionListArbNull,
393 extensionListArbEmpty,
394 foundExt,
395 extensionListExtNull,
396 extensionListExtEmpty,
397 isRemoteSession);
398
399 return false;
400 }
401
402 // Load each extension individually.
403 #define LOAD_WGL_EXTENSION_FUNCTION(return_type, function_name, signature) \
404 this->function_name = reinterpret_cast< \
405 return_type (GL_APIENTRY*) signature>( \
406 this->findFunction(#function_name "ARB")); \
407 if (!this->function_name) { \
408 this->function_name = reinterpret_cast< \
409 return_type (GL_APIENTRY*) signature>( \
410 this->findFunction(#function_name "EXT")); \
411 } \
412 if (!this->function_name) { \
413 WGL_ERR("ERROR: %s: Missing extension function %s\n", __FUNCTION__, \
414 #function_name); \
415 result = false; \
416 }
417
418 #define LOAD_WGL_EXTENSION(extension) \
419 if (supportsExtension("WGL_ARB_" #extension, extensionList) || \
420 supportsExtension("WGL_EXT_" #extension, extensionList)) { \
421 LIST_##extension##_FUNCTIONS(LOAD_WGL_EXTENSION_FUNCTION) \
422 } else { \
423 WGL_ERR("WARNING: %s: Missing WGL extension %s\n", __FUNCTION__, #extension); \
424 }
425
426 LOAD_WGL_EXTENSION(pixel_format)
427 LOAD_WGL_EXTENSION(make_current_read)
428 LOAD_WGL_EXTENSION(pbuffer)
429 LOAD_WGL_EXTENSION(create_context)
430 LOAD_WGL_EXTENSION(swap_control)
431
432 // Done.
433 return result;
434 }
435
436 private:
437 WglExtensionsDispatch(); // no default constructor.
438 };
439
initExtensionsDispatch(const WglBaseDispatch * dispatch)440 const WglExtensionsDispatch* initExtensionsDispatch(
441 const WglBaseDispatch* dispatch) {
442 HWND hwnd = createDummyWindow();
443 HDC hdc = GetDC(hwnd);
444 if (!hwnd || !hdc){
445 int err = GetLastError();
446 WGL_ERR("error while getting DC: 0x%x\n", err);
447 return NULL;
448 }
449 PIXELFORMATDESCRIPTOR pfd = {
450 sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
451 1, // version number
452 PFD_DRAW_TO_WINDOW | // support window
453 PFD_SUPPORT_OPENGL | // support OpenGL
454 PFD_DOUBLEBUFFER, // double buffered
455 PFD_TYPE_RGBA, // RGBA type
456 32, // 32-bit color depth
457 0, 0, 0, 0, 0, 0, // color bits ignored
458 0, // no alpha buffer
459 0, // shift bit ignored
460 0, // no accumulation buffer
461 0, 0, 0, 0, // accum bits ignored
462 24, // 24-bit z-buffer
463 0, // no stencil buffer
464 0, // no auxiliary buffer
465 PFD_MAIN_PLANE, // main layer
466 0, // reserved
467 0, 0, 0 // layer masks ignored
468 };
469
470 int iPixelFormat = dispatch->ChoosePixelFormat(hdc, &pfd);
471 if (iPixelFormat <= 0) {
472 int err = GetLastError();
473 WGL_ERR("error while choosing pixel format 0x%x\n", err);
474 return NULL;
475 }
476 if (!dispatch->SetPixelFormat(hdc, iPixelFormat, &pfd)) {
477 int err = GetLastError();
478 WGL_ERR("error while setting pixel format 0x%x\n", err);
479 return NULL;
480 }
481
482 int err;
483 HGLRC ctx = dispatch->wglCreateContext(hdc);
484 if (!ctx) {
485 err = GetLastError();
486 WGL_ERR("error while creating dummy context: 0x%x\n", err);
487 }
488 if (!dispatch->wglMakeCurrent(hdc, ctx)) {
489 err = GetLastError();
490 WGL_ERR("error while making dummy context current: 0x%x\n", err);
491 }
492
493 WglExtensionsDispatch* result = new WglExtensionsDispatch(*dispatch);
494 result->init(hdc);
495
496 dispatch->wglMakeCurrent(hdc, NULL);
497 dispatch->wglDeleteContext(ctx);
498 ReleaseDC(hwnd, hdc);
499 DestroyWindow(hwnd);
500
501 return result;
502 }
503
504 class WinPixelFormat : public EglOS::PixelFormat {
505 public:
WinPixelFormat(const PIXELFORMATDESCRIPTOR * desc,int configId)506 WinPixelFormat(const PIXELFORMATDESCRIPTOR* desc, int configId)
507 : mDesc(*desc), mConfigId(configId) {}
508
clone()509 EglOS::PixelFormat* clone() {
510 return new WinPixelFormat(&mDesc, mConfigId);
511 }
512
desc() const513 const PIXELFORMATDESCRIPTOR* desc() const { return &mDesc; }
configId() const514 const int configId() const { return mConfigId; }
515
from(const EglOS::PixelFormat * f)516 static const WinPixelFormat* from(const EglOS::PixelFormat* f) {
517 return static_cast<const WinPixelFormat*>(f);
518 }
519
520 private:
521 WinPixelFormat(const WinPixelFormat& other) = delete;
522
523 PIXELFORMATDESCRIPTOR mDesc = {};
524 int mConfigId = 0;
525 };
526
527 class WinSurface : public EglOS::Surface {
528 public:
WinSurface(HWND wnd,const WglExtensionsDispatch * dispatch)529 explicit WinSurface(HWND wnd, const WglExtensionsDispatch* dispatch) :
530 Surface(WINDOW),
531 m_hwnd(wnd),
532 m_hdc(GetDC(wnd)),
533 m_dispatch(dispatch) {}
534
WinSurface(HPBUFFERARB pb,const EglOS::PixelFormat * pixelFormat,const WglExtensionsDispatch * dispatch)535 explicit WinSurface(HPBUFFERARB pb, const EglOS::PixelFormat* pixelFormat, const WglExtensionsDispatch* dispatch) :
536 Surface(PBUFFER),
537 m_pb(pb),
538 m_pixelFormat(pixelFormat),
539 m_dispatch(dispatch) {
540 refreshDC();
541 }
542
releaseDC()543 bool releaseDC() {
544 if (m_dcReleased) return true;
545
546 bool res = false;
547 if (m_dispatch->wglReleasePbufferDC) {
548 res = m_dispatch->wglReleasePbufferDC(m_pb, m_hdc);
549 m_hdc = 0;
550 m_dcReleased = true;
551 }
552 return res;
553 }
554
refreshDC()555 bool refreshDC() {
556 if (!m_dcReleased) releaseDC();
557 if (m_dispatch->wglGetPbufferDC) {
558 m_hdc = m_dispatch->wglGetPbufferDC(m_pb);
559 }
560
561 if (!m_hdc) return false;
562
563 m_dcReleased = false;
564
565 return true;
566 }
567
~WinSurface()568 ~WinSurface() {
569 if (type() == WINDOW) {
570 ReleaseDC(m_hwnd, m_hdc);
571 }
572 }
573
onMakeCurrent()574 void onMakeCurrent() {
575 if (m_everMadeCurrent) return;
576 if (m_dispatch->wglSwapInterval) {
577 m_dispatch->wglSwapInterval(0);
578 }
579 m_everMadeCurrent = true;
580 }
581
getHwnd() const582 HWND getHwnd() const { return m_hwnd; }
getDC() const583 HDC getDC() const { return m_hdc; }
getPbuffer() const584 HPBUFFERARB getPbuffer() const { return m_pb; }
getPixelFormat() const585 const EglOS::PixelFormat* getPixelFormat() const { return m_pixelFormat; }
586
from(EglOS::Surface * s)587 static WinSurface* from(EglOS::Surface* s) {
588 return static_cast<WinSurface*>(s);
589 }
590
591 private:
592 bool m_everMadeCurrent = false;
593 bool m_dcReleased = true;
594 HWND m_hwnd = nullptr;
595 HPBUFFERARB m_pb = nullptr;
596 HDC m_hdc = nullptr;
597 const EglOS::PixelFormat* m_pixelFormat = nullptr;
598 const WglExtensionsDispatch* m_dispatch = nullptr;
599 };
600
601 static android::base::StaticLock sGlobalLock;
602
603 class WinContext : public EglOS::Context {
604 public:
WinContext(const WglExtensionsDispatch * dispatch,HGLRC ctx)605 explicit WinContext(const WglExtensionsDispatch* dispatch, HGLRC ctx) :
606 mDispatch(dispatch), mCtx(ctx) {}
607
~WinContext()608 ~WinContext() {
609 android::base::AutoLock lock(sGlobalLock);
610 if (!mDispatch->wglDeleteContext(mCtx)) {
611 WGL_ERR("error deleting WGL context! error 0x%x\n",
612 (unsigned)GetLastError());
613 }
614 }
615
context() const616 HGLRC context() const { return mCtx; }
617
from(const EglOS::Context * c)618 static HGLRC from(const EglOS::Context* c) {
619 if (!c) return nullptr;
620 return static_cast<const WinContext*>(c)->context();
621 }
622
623 private:
624 const WglExtensionsDispatch* mDispatch = nullptr;
625 HGLRC mCtx = nullptr;
626 };
627
628 // A helper class used to deal with a vexing limitation of the WGL API.
629 // The documentation for SetPixelFormat() states the following:
630 //
631 // -- If hdc references a window, calling the SetPixelFormat function also
632 // -- changes the pixel format of the window. Setting the pixel format of a
633 // -- window more than once [...] is not allowed. An application can only set
634 // -- the pixel format of a window one time. Once a window's pixel format is
635 // -- set, it cannot be changed.
636 // --
637 // -- You should select a pixel format in the device context before calling
638 // -- the wglCreateContext function. The wglCreateContext function creates a
639 // -- rendering context for drawing on the device in the selected pixel format
640 // -- of the device context.
641 //
642 // In other words, creating a GL context requires having a unique window and
643 // device context for the corresponding EGLConfig.
644 //
645 // This code deals with this by implementing the followin scheme:
646 //
647 // - For each unique PixelFormat ID (a.k.a. EGLConfig number), provide a way
648 // to create a new hidden 1x1 window, and corresponding HDC.
649 //
650 // - Implement a simple thread-local mapping from PixelFormat IDs to
651 // (HWND, HDC) pairs that are created on demand.
652 //
653 // WinGlobals is the class used to implement this scheme. Usage is the
654 // following:
655 //
656 // - Create a single global instance, passing a WglBaseDispatch pointer
657 // which is required to call its SetPixelFormat() method.
658 //
659 // - Call getDefaultDummyDC() to retrieve a thread-local device context that
660 // can be used to query / probe the list of available pixel formats for the
661 // host window, but not perform rendering.
662 //
663 // - Call getDummyDC() to retrieve a thread-local device context that can be
664 // used to create WGL context objects to render into a specific pixel
665 // format.
666 //
667 // - These devic contexts are thread-local, i.e. they are automatically
668 // reclaimed on thread exit. This also means that the caller should not
669 // call either ReleaseDC() or DeleteDC() on them.
670 //
671 class WinGlobals {
672 public:
673 // Constructor. |dispatch| will be used to call the right version of
674 // ::SetPixelFormat() depending on GPU emulation configuration. See
675 // technical notes above for details.
WinGlobals(const WglBaseDispatch * dispatch)676 explicit WinGlobals(const WglBaseDispatch* dispatch)
677 : mDispatch(dispatch) {}
678
679 // Return a thread-local device context that can be used to list
680 // available pixel formats for the host window. The caller cannot use
681 // this context for drawing though. The context is owned
682 // by this instance and will be automatically reclaimed on thread exit.
getDefaultDummyDC()683 HDC getDefaultDummyDC() {
684 return getInternalDC(nullptr);
685 }
686
getDefaultNontrivialDC()687 HDC getDefaultNontrivialDC() {
688 return mNontrivialDC;
689 }
setNontrivialDC(const WinPixelFormat * format)690 void setNontrivialDC(const WinPixelFormat* format) {
691 mNontrivialDC = getInternalDC(format);
692 }
693
694 // Return a thread-local device context associated with a specific
695 // pixel format. The result is owned by this instance, and is automatically
696 // reclaimed on thread exit. Don't try to call ReleaseDC() on it.
getDummyDC(const WinPixelFormat * format)697 HDC getDummyDC(const WinPixelFormat* format) {
698 return getInternalDC(format);
699 }
700
701 private:
702 // ConfigDC holds a (HWND,HDC) pair to be associated with a given
703 // pixel format ID. This serves as the value type for ConfigMap
704 // declared below. Implemented as a movable type without copy-operations.
705 class ConfigDC {
706 public:
707 // Constructor. This creates a new dummy 1x1 invisible window and
708 // an associated device context. If |format| is not nullptr, then
709 // calls |dispatch->SetPixelFormat()| on the resulting context to
710 // set the window's pixel format.
ConfigDC(const WinPixelFormat * format,const WglBaseDispatch * dispatch)711 ConfigDC(const WinPixelFormat* format,
712 const WglBaseDispatch* dispatch) {
713 mWindow = createDummyWindow();
714 if (mWindow) {
715 mDeviceContext = GetDC(mWindow);
716 if (format) {
717 dispatch->SetPixelFormat(mDeviceContext,
718 format->configId(),
719 format->desc());
720 }
721 }
722 }
723
724 // Destructor.
~ConfigDC()725 ~ConfigDC() {
726 if (mWindow) {
727 ReleaseDC(mWindow, mDeviceContext);
728 DestroyWindow(mWindow);
729 mWindow = nullptr;
730 }
731 }
732
733 // Supports moves - this disables auto-generated copy-constructors.
ConfigDC(ConfigDC && other)734 ConfigDC(ConfigDC&& other)
735 : mWindow(other.mWindow),
736 mDeviceContext(other.mDeviceContext) {
737 other.mWindow = nullptr;
738 }
739
operator =(ConfigDC && other)740 ConfigDC& operator=(ConfigDC&& other) {
741 mWindow = other.mWindow;
742 mDeviceContext = other.mDeviceContext;
743 other.mWindow = nullptr;
744 return *this;
745 }
746
747 // Return device context for this instance.
dc() const748 HDC dc() const { return mDeviceContext; }
749
750 private:
751 HWND mWindow = nullptr;
752 HDC mDeviceContext = nullptr;
753 };
754
755 // Convenience type alias for mapping pixel format IDs, a.k.a. EGLConfig
756 // IDs, to ConfigDC instances.
757 using ConfigMap = std::unordered_map<int, ConfigDC>;
758
759 // Called when a thread terminates to delete the thread-local map
760 // that associates pixel format IDs with ConfigDC instances.
onThreadTermination(void * opaque)761 static void onThreadTermination(void* opaque) {
762 auto map = reinterpret_cast<ConfigMap*>(opaque);
763 delete map;
764 }
765
766 // Helper function used by getDefaultDummyDC() and getDummyDC().
767 //
768 // If |format| is nullptr, return a thread-local device context that can
769 // be used to list all available pixel formats for the host window.
770 //
771 // If |format| is not nullptr, then return a thread-local device context
772 // associated with the corresponding pixel format.
773 //
774 // Both cases will lazily create a 1x1 invisible dummy window which
775 // the device is connected to. All objects are automatically destroyed
776 // on thread exit. Return nullptr on failure.
getInternalDC(const WinPixelFormat * format)777 HDC getInternalDC(const WinPixelFormat* format) {
778 int formatId = format ? format->configId() : 0;
779 static thread_local ConfigMap configMap;
780
781 auto it = configMap.find(formatId);
782 if (it != configMap.end()) {
783 return it->second.dc();
784 }
785
786 ConfigDC newValue(format, mDispatch);
787 HDC result = newValue.dc();
788 configMap.emplace(formatId, std::move(newValue));
789 return result;
790 }
791
792 const WglBaseDispatch* mDispatch = nullptr;
793 HDC mNontrivialDC = nullptr;
794 };
795
initPixelFormat(HDC dc,const WglExtensionsDispatch * dispatch)796 bool initPixelFormat(HDC dc, const WglExtensionsDispatch* dispatch) {
797 if (dispatch->wglChoosePixelFormat) {
798 unsigned int numpf;
799 int iPixelFormat;
800 int i0 = 0;
801 float f0 = 0.0f;
802 return dispatch->wglChoosePixelFormat(
803 dc, &i0, &f0, 1, &iPixelFormat, &numpf);
804 } else {
805 PIXELFORMATDESCRIPTOR pfd = {
806 sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd
807 1, // version number
808 PFD_DRAW_TO_WINDOW | // support window
809 PFD_SUPPORT_OPENGL | // support OpenGL
810 PFD_DOUBLEBUFFER, // double buffered
811 PFD_TYPE_RGBA, // RGBA type
812 32, // 32-bit color depth
813 0, 0, 0, 0, 0, 0, // color bits ignored
814 0, // no alpha buffer
815 0, // shift bit ignored
816 0, // no accumulation buffer
817 0, 0, 0, 0, // accum bits ignored
818 24, // 24-bit z-buffer
819 0, // no stencil buffer
820 0, // no auxiliary buffer
821 PFD_MAIN_PLANE, // main layer
822 0, // reserved
823 0, 0, 0 // layer masks ignored
824 };
825 return dispatch->ChoosePixelFormat(dc, &pfd);
826 }
827 }
828
pixelFormatToConfig(WinGlobals * globals,const WglExtensionsDispatch * dispatch,int renderableType,const PIXELFORMATDESCRIPTOR * frmt,int index,EglOS::AddConfigCallback * addConfigFunc,void * addConfigOpaque)829 void pixelFormatToConfig(WinGlobals* globals,
830 const WglExtensionsDispatch* dispatch,
831 int renderableType,
832 const PIXELFORMATDESCRIPTOR* frmt,
833 int index,
834 EglOS::AddConfigCallback* addConfigFunc,
835 void* addConfigOpaque) {
836 EglOS::ConfigInfo info;
837 memset(&info, 0, sizeof(info));
838
839 if (frmt->iPixelType != PFD_TYPE_RGBA) {
840 D("%s: Not an RGBA type!\n", __FUNCTION__);
841 return; // other formats are not supported yet
842 }
843 if (!(frmt->dwFlags & PFD_SUPPORT_OPENGL)) {
844 D("%s: No OpenGL support\n", __FUNCTION__);
845 return;
846 }
847 // NOTE: Software renderers don't always support double-buffering.
848 if (dispatch->mIsSystemLib && !(frmt->dwFlags & PFD_DOUBLEBUFFER)) {
849 D("%s: No double-buffer support\n", __FUNCTION__);
850 return;
851 }
852 if ((frmt->dwFlags & (PFD_GENERIC_FORMAT | PFD_NEED_PALETTE)) != 0) {
853 //discard generic pixel formats as well as pallete pixel formats
854 D("%s: Generic format or needs palette\n", __FUNCTION__);
855 return;
856 }
857
858 if (!dispatch->wglGetPixelFormatAttribiv) {
859 D("%s: Missing wglGetPixelFormatAttribiv\n", __FUNCTION__);
860 return;
861 }
862
863 GLint window = 0, pbuffer = 0;
864 HDC dpy = globals->getDefaultDummyDC();
865
866 if (dispatch->mIsSystemLib) {
867 int windowAttrib = WGL_DRAW_TO_WINDOW_ARB;
868 EXIT_IF_FALSE(dispatch->wglGetPixelFormatAttribiv(
869 dpy, index, 0, 1, &windowAttrib, &window));
870 }
871 int pbufferAttrib = WGL_DRAW_TO_PBUFFER_ARB;
872 EXIT_IF_FALSE(dispatch->wglGetPixelFormatAttribiv(
873 dpy, index, 0, 1, &pbufferAttrib, &pbuffer));
874
875 info.surface_type = 0;
876 if (window) {
877 info.surface_type |= EGL_WINDOW_BIT;
878 }
879 if (pbuffer) {
880 info.surface_type |= EGL_PBUFFER_BIT;
881 }
882 if (!info.surface_type) {
883 D("%s: Missing surface type\n", __FUNCTION__);
884 return;
885 }
886
887 //default values
888 info.native_visual_id = 0;
889 info.native_visual_type = EGL_NONE;
890 info.caveat = EGL_NONE;
891 info.native_renderable = EGL_FALSE;
892 info.renderable_type = renderableType;
893 info.max_pbuffer_width = PBUFFER_MAX_WIDTH;
894 info.max_pbuffer_height = PBUFFER_MAX_HEIGHT;
895 info.max_pbuffer_size = PBUFFER_MAX_PIXELS;
896 info.samples_per_pixel = 0;
897 info.frame_buffer_level = 0;
898
899 GLint transparent;
900 int transparentAttrib = WGL_TRANSPARENT_ARB;
901 EXIT_IF_FALSE(dispatch->wglGetPixelFormatAttribiv(
902 dpy, index, 0, 1, &transparentAttrib, &transparent));
903 if (transparent) {
904 info.transparent_type = EGL_TRANSPARENT_RGB;
905 int transparentRedAttrib = WGL_TRANSPARENT_RED_VALUE_ARB;
906 EXIT_IF_FALSE(dispatch->wglGetPixelFormatAttribiv(
907 dpy, index, 0, 1, &transparentRedAttrib, &info.trans_red_val));
908 int transparentGreenAttrib = WGL_TRANSPARENT_GREEN_VALUE_ARB;
909 EXIT_IF_FALSE(dispatch->wglGetPixelFormatAttribiv(
910 dpy, index, 0, 1, &transparentGreenAttrib,
911 &info.trans_green_val));
912 int transparentBlueAttrib = WGL_TRANSPARENT_RED_VALUE_ARB;
913 EXIT_IF_FALSE(dispatch->wglGetPixelFormatAttribiv(
914 dpy,index, 0, 1, &transparentBlueAttrib, &info.trans_blue_val));
915 } else {
916 info.transparent_type = EGL_NONE;
917 }
918
919 info.red_size = frmt->cRedBits;
920 info.green_size = frmt->cGreenBits;
921 info.blue_size = frmt->cBlueBits;
922 info.alpha_size = frmt->cAlphaBits;
923 info.depth_size = frmt->cDepthBits;
924 info.stencil_size = frmt->cStencilBits;
925
926 info.frmt = new WinPixelFormat(frmt, index);
927
928 if (!globals->getDefaultNontrivialDC() &&
929 info.red_size >= 8) {
930 globals->setNontrivialDC(WinPixelFormat::from(info.frmt));
931 }
932
933 (*addConfigFunc)(addConfigOpaque, &info);
934 }
935
936 class WglDisplay : public EglOS::Display {
937 public:
WglDisplay(const WglExtensionsDispatch * dispatch,WinGlobals * globals)938 WglDisplay(const WglExtensionsDispatch* dispatch,
939 WinGlobals* globals)
940 : mDispatch(dispatch), mGlobals(globals) {}
941
getMaxGlesVersion()942 virtual EglOS::GlesVersion getMaxGlesVersion() {
943 if (!mCoreProfileSupported) {
944 return EglOS::GlesVersion::ES2;
945 }
946
947 return EglOS::calcMaxESVersionFromCoreVersion(
948 mCoreMajorVersion, mCoreMinorVersion);
949 }
950
queryConfigs(int renderableType,EglOS::AddConfigCallback addConfigFunc,void * addConfigOpaque)951 virtual void queryConfigs(int renderableType,
952 EglOS::AddConfigCallback addConfigFunc,
953 void* addConfigOpaque) {
954 HDC dpy = mGlobals->getDefaultDummyDC();
955
956 // wglChoosePixelFormat() needs to be called at least once,
957 // i.e. it seems that the driver needs to initialize itself.
958 // Do it here during initialization.
959 initPixelFormat(dpy, mDispatch);
960
961 // Quering number of formats
962 PIXELFORMATDESCRIPTOR pfd;
963 int maxFormat = mDispatch->DescribePixelFormat(
964 dpy, 1, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
965
966 if (0 == maxFormat) {
967 WGL_ERR("No pixel formats found from wglDescribePixelFormat! "
968 "error: 0x%x\n", static_cast<unsigned int>(GetLastError()));
969 }
970
971 // Inserting rest of formats. Try to map each one to an EGL Config.
972 for (int configId = 1; configId <= maxFormat; configId++) {
973 mDispatch->DescribePixelFormat(
974 dpy, configId, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
975 pixelFormatToConfig(
976 mGlobals,
977 mDispatch,
978 renderableType,
979 &pfd,
980 configId,
981 addConfigFunc,
982 addConfigOpaque);
983 }
984
985 queryCoreProfileSupport();
986
987 if (mDispatch->wglSwapInterval) {
988 mDispatch->wglSwapInterval(0); // use guest SF / HWC instead
989 }
990 }
991
isValidNativeWin(EglOS::Surface * win)992 virtual bool isValidNativeWin(EglOS::Surface* win) {
993 if (!win) {
994 return false;
995 } else {
996 return isValidNativeWin(WinSurface::from(win)->getHwnd());
997 }
998 }
999
isValidNativeWin(EGLNativeWindowType win)1000 virtual bool isValidNativeWin(EGLNativeWindowType win) {
1001 return IsWindow(win);
1002 }
1003
checkWindowPixelFormatMatch(EGLNativeWindowType win,const EglOS::PixelFormat * pixelFormat,unsigned int * width,unsigned int * height)1004 virtual bool checkWindowPixelFormatMatch(
1005 EGLNativeWindowType win,
1006 const EglOS::PixelFormat* pixelFormat,
1007 unsigned int* width,
1008 unsigned int* height) {
1009 RECT r;
1010 if (!GetClientRect(win, &r)) {
1011 return false;
1012 }
1013 *width = r.right - r.left;
1014 *height = r.bottom - r.top;
1015 HDC dc = GetDC(win);
1016 const WinPixelFormat* format = WinPixelFormat::from(pixelFormat);
1017 bool ret = mDispatch->SetPixelFormat(dc,
1018 format->configId(),
1019 format->desc());
1020 ReleaseDC(win, dc);
1021 return ret;
1022 }
1023
createContext(EGLint profileMask,const EglOS::PixelFormat * pixelFormat,EglOS::Context * sharedContext)1024 virtual std::shared_ptr<EglOS::Context> createContext(
1025 EGLint profileMask,
1026 const EglOS::PixelFormat* pixelFormat,
1027 EglOS::Context* sharedContext) {
1028
1029 android::base::AutoLock lock(sGlobalLock);
1030
1031 const WinPixelFormat* format = WinPixelFormat::from(pixelFormat);
1032 HDC dpy = mGlobals->getDummyDC(format);
1033 if (!dpy) {
1034 return nullptr;
1035 }
1036
1037 bool useCoreProfile =
1038 mCoreProfileSupported &&
1039 (profileMask & EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR);
1040
1041 HGLRC ctx;
1042 if (useCoreProfile) {
1043 ctx = mDispatch->wglCreateContextAttribs(
1044 dpy, WinContext::from(sharedContext),
1045 mCoreProfileCtxAttribs);
1046 } else {
1047 ctx = mDispatch->wglCreateContext(dpy);
1048 if (ctx && sharedContext) {
1049 if (!mDispatch->wglShareLists(WinContext::from(sharedContext), ctx)) {
1050 mDispatch->wglDeleteContext(ctx);
1051 return NULL;
1052 }
1053 }
1054 }
1055
1056 return std::make_shared<WinContext>(mDispatch, ctx);
1057 }
1058
createPbufferSurface(const EglOS::PixelFormat * pixelFormat,const EglOS::PbufferInfo * info)1059 virtual EglOS::Surface* createPbufferSurface(
1060 const EglOS::PixelFormat* pixelFormat,
1061 const EglOS::PbufferInfo* info) {
1062 android::base::AutoLock lock(sGlobalLock);
1063 (void)info;
1064
1065 bool needPrime = false;
1066
1067 auto& freeElts = mFreePbufs[pixelFormat];
1068
1069 if (freeElts.empty()) {
1070 needPrime = true;
1071 }
1072
1073 if (needPrime) {
1074 // Policy here is based on the behavior of Android UI when opening
1075 // and closing lots of apps, and to avoid frequent pauses to create
1076 // pbuffers. We start by priming with 8 pbuffers, and then double
1077 // the current set of live pbuffers each time. This will then
1078 // require only a few primings (up to ~32 pbuffers) to make it
1079 // unnecessary to create or delete a pbuffer ever again after that.
1080 // Creating many pbuffers in a batch is faster than interrupting
1081 // the process at various times to create them one at a time.
1082 PROFILE_SLOW("createPbufferSurface (slow path)");
1083 int toCreate = std::max((int)mLivePbufs[pixelFormat].size(), kPbufPrimingCount);
1084 for (int i = 0; i < toCreate; i++) {
1085 freeElts.push_back(createPbufferSurfaceImpl(pixelFormat));
1086 }
1087 }
1088
1089 PROFILE_SLOW("createPbufferSurface (fast path)");
1090 EglOS::Surface* surf = freeElts.back();
1091 WinSurface* winSurface = WinSurface::from(surf);
1092 if (!winSurface->refreshDC()) {
1093 // TODO: Figure out why some Intel GPUs can hang flakily if
1094 // we just destroy the pbuffer here.
1095 mDeletePbufs.push_back(surf);
1096 surf = createPbufferSurfaceImpl(pixelFormat);
1097 }
1098 freeElts.pop_back();
1099
1100 mLivePbufs[pixelFormat].insert(surf);
1101
1102 return surf;
1103 }
1104
releasePbuffer(EglOS::Surface * pb)1105 virtual bool releasePbuffer(EglOS::Surface* pb) {
1106 android::base::AutoLock lock(sGlobalLock);
1107 if (!pb) return false;
1108
1109 WinSurface* winpb = WinSurface::from(pb);
1110
1111 if (!winpb->releaseDC()) return false;
1112
1113 const EglOS::PixelFormat* pixelFormat =
1114 winpb->getPixelFormat();
1115
1116 auto& frees = mFreePbufs[pixelFormat];
1117 frees.push_back(pb);
1118
1119 mLivePbufs[pixelFormat].erase(pb);
1120
1121 for (auto surf : mDeletePbufs) {
1122 WinSurface* winSurface = WinSurface::from(surf);
1123 mDispatch->wglDestroyPbuffer(winSurface->getPbuffer());
1124 delete winSurface;
1125 }
1126
1127 mDeletePbufs.clear();
1128
1129 return true;
1130 }
1131
makeCurrent(EglOS::Surface * read,EglOS::Surface * draw,EglOS::Context * context)1132 virtual bool makeCurrent(EglOS::Surface* read,
1133 EglOS::Surface* draw,
1134 EglOS::Context* context) {
1135 android::base::AutoLock lock(sGlobalLock);
1136 WinSurface* readWinSurface = WinSurface::from(read);
1137 WinSurface* drawWinSurface = WinSurface::from(draw);
1138 HDC hdcRead = read ? readWinSurface->getDC() : NULL;
1139 HDC hdcDraw = draw ? drawWinSurface->getDC() : NULL;
1140 HGLRC hdcContext = context ? WinContext::from(context) : 0;
1141
1142 const WglExtensionsDispatch* dispatch = mDispatch;
1143
1144 bool ret = false;
1145 if (hdcRead == hdcDraw){
1146 // The following loop is a work-around for a problem when
1147 // occasionally the rendering is incorrect after hibernating and
1148 // waking up windows.
1149 // wglMakeCurrent will sometimes fail for a short period of time
1150 // in such situation.
1151 //
1152 // For a stricter test, in addition to checking the return value, we
1153 // might also want to check its error code. On my computer in such
1154 // situation GetLastError() returns 0 (which is documented as
1155 // success code). This is not a documented behaviour and is
1156 // unreliable. But in case one needs to use it, here is the code:
1157 //
1158 // while (!(isSuccess = dispatch->wglMakeCurrent(hdcDraw, hdcContext))
1159 // && GetLastError()==0) Sleep(16);
1160 //
1161
1162 int count = 100;
1163 while (!dispatch->wglMakeCurrent(hdcDraw, hdcContext)
1164 && --count > 0
1165 && !GetLastError()) {
1166 Sleep(16);
1167 }
1168 if (count <= 0) {
1169 D("Error: wglMakeCurrent() failed, error %d\n", (int)GetLastError());
1170 return false;
1171 }
1172 ret = true;
1173 } else if (!dispatch->wglMakeContextCurrent) {
1174 return false;
1175 } else {
1176 ret = dispatch->wglMakeContextCurrent(
1177 hdcDraw, hdcRead, hdcContext);
1178 }
1179
1180 if (ret) {
1181 if (readWinSurface) readWinSurface->onMakeCurrent();
1182 if (drawWinSurface) drawWinSurface->onMakeCurrent();
1183 }
1184 return ret;
1185 }
1186
swapBuffers(EglOS::Surface * srfc)1187 virtual void swapBuffers(EglOS::Surface* srfc) {
1188 android::base::AutoLock lock(sGlobalLock);
1189 if (srfc && !mDispatch->SwapBuffers(WinSurface::from(srfc)->getDC())) {
1190 GetLastError();
1191 }
1192 }
1193
1194 private:
1195 // Returns the highest level of OpenGL core profile support in
1196 // this WGL implementation.
queryCoreProfileSupport()1197 void queryCoreProfileSupport() {
1198 mCoreProfileSupported = false;
1199
1200 if (!mDispatch->wglCreateContextAttribs) {
1201 WGL_ERR("OpenGL Core Profile not supported.\n");
1202 // Not supported, don't even try.
1203 return;
1204 }
1205
1206 // Ascending index order of context attribs :
1207 // decreasing GL major/minor version
1208 HGLRC testContext = nullptr;
1209 HDC dpy = mGlobals->getDefaultNontrivialDC();
1210
1211 for (int i = 0; i < getNumCoreProfileCtxAttribs(); i++) {
1212 const int* attribs = getCoreProfileCtxAttribs(i);
1213 testContext =
1214 mDispatch->wglCreateContextAttribs(
1215 dpy, nullptr /* no shared context */,
1216 attribs);
1217
1218 if (testContext) {
1219 mCoreProfileSupported = true;
1220 mCoreProfileCtxAttribs = attribs;
1221 getCoreProfileCtxAttribsVersion(
1222 attribs, &mCoreMajorVersion, &mCoreMinorVersion);
1223 mDispatch->wglDeleteContext(testContext);
1224 return;
1225 }
1226 }
1227 }
1228
createPbufferSurfaceImpl(const EglOS::PixelFormat * pixelFormat)1229 EglOS::Surface* createPbufferSurfaceImpl(const EglOS::PixelFormat* pixelFormat) {
1230 // we never care about width or height, since we just use
1231 // opengl fbos anyway.
1232 const WinPixelFormat* format = WinPixelFormat::from(pixelFormat);
1233 HDC dpy = mGlobals->getDummyDC(format);
1234
1235 const WglExtensionsDispatch* dispatch = mDispatch;
1236 if (!dispatch->wglCreatePbuffer) {
1237 return NULL;
1238 }
1239 HPBUFFERARB pb = dispatch->wglCreatePbuffer(dpy, format->configId(), 1, 1, nullptr);
1240 if (!pb) {
1241 GetLastError();
1242 return NULL;
1243 }
1244 return new WinSurface(pb, pixelFormat, dispatch);
1245 }
1246
1247 bool mCoreProfileSupported = false;
1248 int mCoreMajorVersion = 4;
1249 int mCoreMinorVersion = 5;
1250 const int* mCoreProfileCtxAttribs = nullptr;
1251
1252 const WglExtensionsDispatch* mDispatch = nullptr;
1253 WinGlobals* mGlobals = nullptr;
1254
1255 std::unordered_map<const EglOS::PixelFormat*, std::vector<EglOS::Surface* > > mFreePbufs;
1256 std::unordered_map<const EglOS::PixelFormat*, std::unordered_set<EglOS::Surface* > > mLivePbufs;
1257 std::vector<EglOS::Surface*> mDeletePbufs;
1258 static constexpr int kPbufPrimingCount = 8;
1259 };
1260
1261 constexpr int WglDisplay::kPbufPrimingCount;
1262
1263 class WglLibrary : public GlLibrary {
1264 public:
WglLibrary(const WglBaseDispatch * dispatch)1265 WglLibrary(const WglBaseDispatch* dispatch) : mDispatch(dispatch) {}
1266
findSymbol(const char * name)1267 virtual GlFunctionPointer findSymbol(const char* name) {
1268 return mDispatch->findFunction(name);
1269 }
1270
1271 private:
1272 const WglBaseDispatch* mDispatch = nullptr;
1273 };
1274
1275 class WinEngine : public EglOS::Engine {
1276 public:
1277 WinEngine();
1278
~WinEngine()1279 ~WinEngine() {
1280 delete mDispatch;
1281 }
1282
getDefaultDisplay()1283 virtual EglOS::Display* getDefaultDisplay() {
1284 return new WglDisplay(mDispatch, &mGlobals);
1285 }
1286
getGlLibrary()1287 virtual GlLibrary* getGlLibrary() {
1288 return &mGlLib;
1289 }
1290
eglGetProcAddress(const char *)1291 virtual void* eglGetProcAddress(const char*) {
1292 return 0;
1293 }
1294
createWindowSurface(EglOS::PixelFormat * cfg,EGLNativeWindowType wnd)1295 virtual EglOS::Surface* createWindowSurface(EglOS::PixelFormat* cfg,
1296 EGLNativeWindowType wnd) {
1297 (void)cfg;
1298 return new WinSurface(wnd, mDispatch);
1299 }
1300
1301 private:
1302 SharedLibrary* mLib = nullptr;
1303 const WglExtensionsDispatch* mDispatch = nullptr;
1304 WglBaseDispatch mBaseDispatch = {};
1305 WglLibrary mGlLib;
1306 WinGlobals mGlobals;
1307 };
1308
WinEngine()1309 WinEngine::WinEngine() :
1310 mGlLib(&mBaseDispatch),
1311 mGlobals(&mBaseDispatch) {
1312 const char* kLibName = "opengl32.dll";
1313 bool isSystemLib = true;
1314 const char* env = ::getenv("ANDROID_GL_LIB");
1315 if (env && !strcmp(env, "mesa")) {
1316 kLibName = "mesa_opengl32.dll";
1317 isSystemLib = false;
1318 }
1319 char error[256];
1320 GL_LOG("%s: Trying to load %s\n", __FUNCTION__, kLibName);
1321 mLib = SharedLibrary::open(kLibName, error, sizeof(error));
1322 if (!mLib) {
1323 WGL_ERR("ERROR: %s: Could not open %s: %s\n", __FUNCTION__,
1324 kLibName, error);
1325 exit(1);
1326 }
1327
1328 GL_LOG("%s: Library loaded at %p\n", __FUNCTION__, mLib);
1329 mBaseDispatch.init(mLib, isSystemLib);
1330 mDispatch = initExtensionsDispatch(&mBaseDispatch);
1331 GL_LOG("%s: Dispatch initialized\n", __FUNCTION__);
1332 }
1333
sHostEngine()1334 static WinEngine* sHostEngine() {
1335 static WinEngine* e = new WinEngine;
1336 return e;
1337 }
1338
1339 } // namespace
1340
1341 // static
getHostInstance()1342 EglOS::Engine* EglOS::Engine::getHostInstance() {
1343 return sHostEngine();
1344 }
1345