1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
4 *
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 */
9
10 #include <memory>
11 #include <string_view>
12 #include <thread>
13 #include <vcl/opengl/OpenGLContext.hxx>
14 #include <vcl/opengl/OpenGLHelper.hxx>
15
16 #include <sal/log.hxx>
17 #include <comphelper/windowserrorstring.hxx>
18 #include <opengl/zone.hxx>
19 #include <win/wincomp.hxx>
20 #include <win/saldata.hxx>
21 #include <win/salframe.h>
22 #include <win/salinst.h>
23 #include <epoxy/wgl.h>
24 #include <ControlCacheKey.hxx>
25
26 static std::vector<HGLRC> g_vShareList;
27 static bool g_bAnyCurrent;
28
29 namespace {
30
31 class GLWinWindow : public GLWindow
32 {
33 public:
34 HWND hWnd;
35 HDC hDC;
36 HGLRC hRC;
37 GLWinWindow();
38 };
39
40 }
41
GLWinWindow()42 GLWinWindow::GLWinWindow()
43 : hWnd(nullptr)
44 , hDC(nullptr)
45 , hRC(nullptr)
46 {
47 }
48
49 namespace {
50
51 class WinOpenGLContext : public OpenGLContext
52 {
53 public:
54 virtual void initWindow() override;
55 private:
56 GLWinWindow m_aGLWin;
getOpenGLWindow() const57 virtual const GLWindow& getOpenGLWindow() const override { return m_aGLWin; }
getModifiableOpenGLWindow()58 virtual GLWindow& getModifiableOpenGLWindow() override { return m_aGLWin; }
59 virtual bool ImplInit() override;
60 virtual void makeCurrent() override;
61 virtual void destroyCurrentContext() override;
62 virtual bool isCurrent() override;
63 virtual bool isAnyCurrent() override;
64 virtual void resetCurrent() override;
65 virtual void swapBuffers() override;
66 };
67
68 }
69
swapBuffers()70 void WinOpenGLContext::swapBuffers()
71 {
72 OpenGLZone aZone;
73
74 SwapBuffers(m_aGLWin.hDC);
75
76 BuffersSwapped();
77 }
78
resetCurrent()79 void WinOpenGLContext::resetCurrent()
80 {
81 clearCurrent();
82
83 OpenGLZone aZone;
84
85 wglMakeCurrent(nullptr, nullptr);
86 g_bAnyCurrent = false;
87 }
88
ensureDispatchTable()89 static void ensureDispatchTable()
90 {
91 thread_local bool bEpoxyDispatchMakeCurrentCalled = false;
92 if (!bEpoxyDispatchMakeCurrentCalled)
93 {
94 epoxy_handle_external_wglMakeCurrent();
95 bEpoxyDispatchMakeCurrentCalled = true;
96 }
97 }
98
isCurrent()99 bool WinOpenGLContext::isCurrent()
100 {
101 OpenGLZone aZone;
102 if (!g_bAnyCurrent || !m_aGLWin.hRC)
103 return false;
104 ensureDispatchTable();
105 return wglGetCurrentContext() == m_aGLWin.hRC && wglGetCurrentDC() == m_aGLWin.hDC;
106 }
107
isAnyCurrent()108 bool WinOpenGLContext::isAnyCurrent()
109 {
110 return g_bAnyCurrent && wglGetCurrentContext() != nullptr;
111 }
112
makeCurrent()113 void WinOpenGLContext::makeCurrent()
114 {
115 if (isCurrent())
116 return;
117
118 OpenGLZone aZone;
119
120 clearCurrent();
121
122 ensureDispatchTable();
123
124 if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC))
125 {
126 g_bAnyCurrent = false;
127 DWORD nLastError = GetLastError();
128 if (nLastError != ERROR_SUCCESS)
129 SAL_WARN("vcl.opengl", "wglMakeCurrent failed: " << WindowsErrorString(nLastError));
130 return;
131 }
132
133 g_bAnyCurrent = true;
134
135 registerAsCurrent();
136 }
137
initWindow()138 void WinOpenGLContext::initWindow()
139 {
140 if( !m_pChildWindow )
141 {
142 SystemWindowData winData = generateWinData(mpWindow, false);
143 m_pChildWindow = VclPtr<SystemChildWindow>::Create(mpWindow, 0, &winData, false);
144 }
145
146 if (m_pChildWindow)
147 {
148 InitChildWindow(m_pChildWindow.get());
149 const SystemEnvData* sysData(m_pChildWindow->GetSystemData());
150 m_aGLWin.hWnd = sysData->hWnd;
151 }
152
153 m_aGLWin.hDC = GetDC(m_aGLWin.hWnd);
154 }
155
destroyCurrentContext()156 void WinOpenGLContext::destroyCurrentContext()
157 {
158 if (m_aGLWin.hRC)
159 {
160 std::vector<HGLRC>::iterator itr = std::remove(g_vShareList.begin(), g_vShareList.end(), m_aGLWin.hRC);
161 if (itr != g_vShareList.end())
162 g_vShareList.erase(itr);
163
164 if (wglGetCurrentContext() != nullptr)
165 {
166 wglMakeCurrent(nullptr, nullptr);
167 g_bAnyCurrent = false;
168 }
169 wglDeleteContext( m_aGLWin.hRC );
170 ReleaseDC( m_aGLWin.hWnd, m_aGLWin.hDC );
171 m_aGLWin.hRC = nullptr;
172 }
173 }
174
WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)175 static LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
176 {
177 switch (message)
178 {
179 case WM_CREATE:
180 return 0;
181 case WM_CLOSE:
182 PostQuitMessage(0);
183 return 0;
184 case WM_DESTROY:
185 return 0;
186 default:
187 return DefWindowProcW(hwnd, message, wParam, lParam);
188 }
189 }
190
InitTempWindow(HWND & hwnd,int width,int height,const PIXELFORMATDESCRIPTOR & inPfd,GLWinWindow & glWin)191 static bool InitTempWindow(HWND& hwnd, int width, int height, const PIXELFORMATDESCRIPTOR& inPfd, GLWinWindow& glWin)
192 {
193 OpenGLZone aZone;
194
195 PIXELFORMATDESCRIPTOR pfd = inPfd;
196 int ret;
197 WNDCLASSW wc;
198 wc.style = 0;
199 wc.lpfnWndProc = WndProc;
200 wc.cbClsExtra = wc.cbWndExtra = 0;
201 wc.hInstance = nullptr;
202 wc.hIcon = nullptr;
203 wc.hCursor = nullptr;
204 wc.hbrBackground = nullptr;
205 wc.lpszMenuName = nullptr;
206 wc.lpszClassName = L"GLRenderer";
207 RegisterClassW(&wc);
208 hwnd = CreateWindowW(wc.lpszClassName, nullptr, WS_DISABLED, 0, 0, width, height, nullptr, nullptr, wc.hInstance, nullptr);
209 glWin.hDC = GetDC(hwnd);
210
211 int nPixelFormat = ChoosePixelFormat(glWin.hDC, &pfd);
212 if (!nPixelFormat)
213 {
214 ReleaseDC(hwnd, glWin.hDC);
215 DestroyWindow(hwnd);
216 return false;
217 }
218 ret = SetPixelFormat(glWin.hDC, nPixelFormat, &pfd);
219 if(!ret)
220 {
221 ReleaseDC(hwnd, glWin.hDC);
222 DestroyWindow(hwnd);
223 return false;
224 }
225 glWin.hRC = wglCreateContext(glWin.hDC);
226 if(!(glWin.hRC))
227 {
228 ReleaseDC(hwnd, glWin.hDC);
229 DestroyWindow(hwnd);
230 return false;
231 }
232 ret = wglMakeCurrent(glWin.hDC, glWin.hRC);
233 if(!ret)
234 {
235 wglMakeCurrent(nullptr, nullptr);
236 g_bAnyCurrent = false;
237 wglDeleteContext(glWin.hRC);
238 ReleaseDC(hwnd, glWin.hDC);
239 DestroyWindow(hwnd);
240 return false;
241 }
242 g_bAnyCurrent = false;
243
244 return true;
245 }
246
WGLisExtensionSupported(const char * extension)247 static bool WGLisExtensionSupported(const char *extension)
248 {
249 OpenGLZone aZone;
250
251 const size_t extlen = strlen(extension);
252 const char *supported = nullptr;
253
254 // Try to use wglGetExtensionStringARB on current DC, if possible
255 PROC wglGetExtString = wglGetProcAddress("wglGetExtensionsStringARB");
256
257 if (wglGetExtString)
258 supported = reinterpret_cast<char*(__stdcall*)(HDC)>(wglGetExtString)(wglGetCurrentDC());
259 // If that failed, try standard OpenGL extensions string
260 if (supported == nullptr)
261 supported = reinterpret_cast<char const *>(glGetString(GL_EXTENSIONS));
262 // If that failed too, must be no extensions supported
263 if (supported == nullptr)
264 return false;
265
266 // Begin examination at start of string, increment by 1 on false match
267 for (const char* p = supported; ; p++)
268 {
269 // Advance p up to the next possible match
270 p = strstr(p, extension);
271
272 if (p == nullptr)
273 return false; // No Match
274
275 // Make sure that match is at the start of the string or that
276 // the previous char is a space, or else we could accidentally
277 // match "wglFunkywglExtension" with "wglExtension"
278
279 // Also, make sure that the following character is space or null
280 // or else "wglExtensionTwo" might match "wglExtension"
281 if ((p==supported || p[-1]==' ') && (p[extlen]=='\0' || p[extlen]==' '))
282 return true; // Match
283 }
284 }
285
InitMultisample(const PIXELFORMATDESCRIPTOR & pfd,int & rPixelFormat,bool bUseDoubleBufferedRendering,bool bRequestVirtualDevice)286 static bool InitMultisample(const PIXELFORMATDESCRIPTOR& pfd, int& rPixelFormat,
287 bool bUseDoubleBufferedRendering, bool bRequestVirtualDevice)
288 {
289 OpenGLZone aZone;
290
291 HWND hWnd = nullptr;
292 GLWinWindow glWin;
293 // Create a temp window to check whether support multi-sample, if support, get the format
294 if (!InitTempWindow(hWnd, 32, 32, pfd, glWin))
295 {
296 SAL_WARN("vcl.opengl", "Can't create temp window to test");
297 return false;
298 }
299
300 // See if the string exists in WGL
301 if (!WGLisExtensionSupported("WGL_ARB_multisample"))
302 {
303 SAL_WARN("vcl.opengl", "Device doesn't support multisample");
304 wglMakeCurrent(nullptr, nullptr);
305 g_bAnyCurrent = false;
306 wglDeleteContext(glWin.hRC);
307 ReleaseDC(hWnd, glWin.hDC);
308 DestroyWindow(hWnd);
309 return false;
310 }
311 // Get our pixel format
312 PFNWGLCHOOSEPIXELFORMATARBPROC fn_wglChoosePixelFormatARB = reinterpret_cast<PFNWGLCHOOSEPIXELFORMATARBPROC>(wglGetProcAddress("wglChoosePixelFormatARB"));
313 if (!fn_wglChoosePixelFormatARB)
314 {
315 wglMakeCurrent(nullptr, nullptr);
316 g_bAnyCurrent = false;
317 wglDeleteContext(glWin.hRC);
318 ReleaseDC(hWnd, glWin.hDC);
319 DestroyWindow(hWnd);
320 return false;
321 }
322 // Get our current device context
323 HDC hDC = GetDC(hWnd);
324
325 int pixelFormat;
326 int valid;
327 UINT numFormats;
328 float fAttributes[] = {0,0};
329 // These attributes are the bits we want to test for in our sample.
330 // Everything is pretty standard, the only one we want to
331 // really focus on is the WGL_SAMPLE_BUFFERS_ARB and WGL_SAMPLES_ARB.
332 // These two are going to do the main testing for whether or not
333 // we support multisampling on this hardware.
334 int iAttributes[] =
335 {
336 WGL_DOUBLE_BUFFER_ARB,GL_TRUE,
337 WGL_DRAW_TO_WINDOW_ARB,GL_TRUE,
338 WGL_SUPPORT_OPENGL_ARB,GL_TRUE,
339 WGL_ACCELERATION_ARB,WGL_FULL_ACCELERATION_ARB,
340 WGL_COLOR_BITS_ARB,24,
341 WGL_ALPHA_BITS_ARB,8,
342 WGL_DEPTH_BITS_ARB,24,
343 WGL_STENCIL_BITS_ARB,0,
344 WGL_SAMPLE_BUFFERS_ARB,GL_TRUE,
345 WGL_SAMPLES_ARB,8,
346 0,0
347 };
348
349 if (!bUseDoubleBufferedRendering)
350 {
351 // Use asserts to make sure the iAttributes array is not changed without changing these ugly
352 // hardcode indexes into it.
353 assert(iAttributes[0] == WGL_DOUBLE_BUFFER_ARB);
354 iAttributes[1] = GL_FALSE;
355 }
356
357 if (bRequestVirtualDevice)
358 {
359 assert(iAttributes[2] == WGL_DRAW_TO_WINDOW_ARB);
360 iAttributes[2] = WGL_DRAW_TO_BITMAP_ARB;
361 }
362
363 bool bArbMultisampleSupported = false;
364
365 // First we check to see if we can get a pixel format for 8 samples
366 valid = fn_wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);
367 // If we returned true, and our format count is greater than 1
368 if (valid && numFormats >= 1)
369 {
370 bArbMultisampleSupported = true;
371 rPixelFormat = pixelFormat;
372 wglMakeCurrent(nullptr, nullptr);
373 g_bAnyCurrent = false;
374 wglDeleteContext(glWin.hRC);
375 ReleaseDC(hWnd, glWin.hDC);
376 DestroyWindow(hWnd);
377 return bArbMultisampleSupported;
378 }
379 // Our pixel format with 8 samples failed, test for 2 samples
380 assert(iAttributes[18] == WGL_SAMPLES_ARB);
381 iAttributes[19] = 2;
382 valid = fn_wglChoosePixelFormatARB(hDC, iAttributes, fAttributes, 1, &pixelFormat, &numFormats);
383 if (valid && numFormats >= 1)
384 {
385 bArbMultisampleSupported = true;
386 rPixelFormat = pixelFormat;
387 wglMakeCurrent(nullptr, nullptr);
388 g_bAnyCurrent = false;
389 wglDeleteContext(glWin.hRC);
390 ReleaseDC(hWnd, glWin.hDC);
391 DestroyWindow(hWnd);
392 return bArbMultisampleSupported;
393 }
394 // Return the valid format
395 wglMakeCurrent(nullptr, nullptr);
396 g_bAnyCurrent = false;
397 wglDeleteContext(glWin.hRC);
398 ReleaseDC(hWnd, glWin.hDC);
399 DestroyWindow(hWnd);
400
401 return bArbMultisampleSupported;
402 }
403
404 namespace
405 {
406
tryShaders(const OUString & rVertexShader,const OUString & rFragmentShader,const OUString & rGeometryShader="",std::string_view rPreamble="")407 bool tryShaders(const OUString& rVertexShader, const OUString& rFragmentShader, const OUString& rGeometryShader = "", std::string_view rPreamble = "")
408 {
409 GLint nId;
410
411 // Somewhat mysteriously, the OpenGLHelper::LoadShaders() API saves a compiled binary of the
412 // shader only if you give it the digest of the shaders. We have API to calculate the digest
413 // only of the combination of vertex and fragment (but not geometry) shader. So if we have a
414 // geometry shader, we should not save the binary.
415 if (rGeometryShader.isEmpty())
416 {
417 nId = OpenGLHelper::LoadShaders(rVertexShader, rFragmentShader, rPreamble, OpenGLHelper::GetDigest( rVertexShader, rFragmentShader, rPreamble));
418 }
419 else
420 {
421 assert(rPreamble.empty());
422 nId = OpenGLHelper::LoadShaders(rVertexShader, rFragmentShader, rGeometryShader);
423 }
424 if (!nId)
425 return false;
426
427 // We're interested in the error returned by glDeleteProgram().
428 glGetError();
429
430 glDeleteProgram(nId);
431 return glGetError() == GL_NO_ERROR;
432 }
433
compiledShaderBinariesWork()434 bool compiledShaderBinariesWork()
435 {
436 static bool bBeenHere = false;
437 static bool bResult;
438
439 if (bBeenHere)
440 return bResult;
441
442 bBeenHere = true;
443
444 bResult =
445 (
446 #if 0 // Only look at shaders used by slideshow for now
447 // canvas
448 tryShaders("dummyVertexShader", "linearMultiColorGradientFragmentShader") &&
449 tryShaders("dummyVertexShader", "linearTwoColorGradientFragmentShader") &&
450 tryShaders("dummyVertexShader", "radialMultiColorGradientFragmentShader") &&
451 tryShaders("dummyVertexShader", "radialTwoColorGradientFragmentShader") &&
452 tryShaders("dummyVertexShader", "rectangularMultiColorGradientFragmentShader") &&
453 tryShaders("dummyVertexShader", "rectangularTwoColorGradientFragmentShader") &&
454 #endif
455 // slideshow
456 tryShaders("reflectionVertexShader", "reflectionFragmentShader") &&
457 tryShaders("basicVertexShader", "basicFragmentShader") &&
458 tryShaders("vortexVertexShader", "vortexFragmentShader", "vortexGeometryShader") &&
459 tryShaders("basicVertexShader", "rippleFragmentShader") &&
460 tryShaders("glitterVertexShader", "glitterFragmentShader") &&
461 tryShaders("honeycombVertexShader", "honeycombFragmentShader", "honeycombGeometryShader"));
462
463 return bResult;
464 }
465
466 } // unnamed namespace
467
ImplInit()468 bool WinOpenGLContext::ImplInit()
469 {
470 static bool bFirstCall = true;
471
472 OpenGLZone aZone;
473
474 VCL_GL_INFO("OpenGLContext::ImplInit----start");
475 // PixelFormat tells Windows how we want things to be
476 PIXELFORMATDESCRIPTOR PixelFormatFront =
477 {
478 sizeof(PIXELFORMATDESCRIPTOR),
479 1, // Version Number
480 PFD_SUPPORT_OPENGL,
481 PFD_TYPE_RGBA, // Request An RGBA Format
482 BYTE(32), // Select Our Color Depth
483 0, 0, 0, 0, 0, 0, // Color Bits Ignored
484 0, // No Alpha Buffer
485 0, // Shift Bit Ignored
486 0, // No Accumulation Buffer
487 0, 0, 0, 0, // Accumulation Bits Ignored
488 24, // 24 bit z-buffer
489 8, // stencil buffer
490 0, // No Auxiliary Buffer
491 0, // now ignored
492 0, // Reserved
493 0, 0, 0 // Layer Masks Ignored
494 };
495
496 PixelFormatFront.dwFlags |= PFD_DOUBLEBUFFER;
497 PixelFormatFront.dwFlags |= PFD_DRAW_TO_WINDOW;
498
499 // we must check whether can set the MSAA
500 int WindowPix = 0;
501 bool bMultiSampleSupport = false;
502
503 bMultiSampleSupport = InitMultisample(PixelFormatFront, WindowPix, /*bUseDoubleBufferedRendering*/true, false);
504
505 if (bMultiSampleSupport && WindowPix != 0)
506 {
507 m_aGLWin.bMultiSampleSupported = true;
508 }
509 else
510 {
511 WindowPix = ChoosePixelFormat(m_aGLWin.hDC, &PixelFormatFront);
512 #if OSL_DEBUG_LEVEL > 0
513 PIXELFORMATDESCRIPTOR pfd;
514 DescribePixelFormat(m_aGLWin.hDC, WindowPix, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
515 SAL_WARN("vcl.opengl", "Render Target: Window: " << static_cast<int>((pfd.dwFlags & PFD_DRAW_TO_WINDOW) != 0) << ", Bitmap: " << static_cast<int>((pfd.dwFlags & PFD_DRAW_TO_BITMAP) != 0));
516 SAL_WARN("vcl.opengl", "Supports OpenGL: " << static_cast<int>((pfd.dwFlags & PFD_SUPPORT_OPENGL) != 0));
517 #endif
518 }
519
520 if (WindowPix == 0)
521 {
522 SAL_WARN("vcl.opengl", "Invalid pixelformat");
523 return false;
524 }
525
526 if (!SetPixelFormat(m_aGLWin.hDC, WindowPix, &PixelFormatFront))
527 {
528 SAL_WARN("vcl.opengl", "SetPixelFormat failed: " << WindowsErrorString(GetLastError()));
529 return false;
530 }
531
532 HGLRC hTempRC = wglCreateContext(m_aGLWin.hDC);
533 if (hTempRC == nullptr)
534 {
535 SAL_WARN("vcl.opengl", "wglCreateContext failed: "<< WindowsErrorString(GetLastError()));
536 return false;
537 }
538
539 if (!wglMakeCurrent(m_aGLWin.hDC, hTempRC))
540 {
541 g_bAnyCurrent = false;
542 SAL_WARN("vcl.opengl", "wglMakeCurrent failed: "<< WindowsErrorString(GetLastError()));
543 return false;
544 }
545
546 g_bAnyCurrent = true;
547
548 if (!InitGL())
549 {
550 wglMakeCurrent(nullptr, nullptr);
551 g_bAnyCurrent = false;
552 wglDeleteContext(hTempRC);
553 return false;
554 }
555
556 HGLRC hSharedCtx = nullptr;
557 if (!g_vShareList.empty())
558 hSharedCtx = g_vShareList.front();
559
560 if (!wglCreateContextAttribsARB)
561 {
562 wglMakeCurrent(nullptr, nullptr);
563 g_bAnyCurrent = false;
564 wglDeleteContext(hTempRC);
565 return false;
566 }
567
568 // now setup the shared context; this needs a temporary context already
569 // set up in order to work
570 int const attribs [] =
571 {
572 #ifdef DBG_UTIL
573 WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_DEBUG_BIT_ARB,
574 #endif
575 0
576 };
577 m_aGLWin.hRC = wglCreateContextAttribsARB(m_aGLWin.hDC, hSharedCtx, attribs);
578 if (m_aGLWin.hRC == nullptr)
579 {
580 SAL_WARN("vcl.opengl", "wglCreateContextAttribsARB failed: "<< WindowsErrorString(GetLastError()));
581 wglMakeCurrent(nullptr, nullptr);
582 g_bAnyCurrent = false;
583 wglDeleteContext(hTempRC);
584 return false;
585 }
586
587 if (!compiledShaderBinariesWork())
588 {
589 wglMakeCurrent(nullptr, nullptr);
590 g_bAnyCurrent = false;
591 wglDeleteContext(hTempRC);
592 return false;
593 }
594
595 wglMakeCurrent(nullptr, nullptr);
596 g_bAnyCurrent = false;
597 wglDeleteContext(hTempRC);
598
599 if (!wglMakeCurrent(m_aGLWin.hDC, m_aGLWin.hRC))
600 {
601 g_bAnyCurrent = false;
602 SAL_WARN("vcl.opengl", "wglMakeCurrent failed: " << WindowsErrorString(GetLastError()));
603 return false;
604 }
605
606 g_bAnyCurrent = true;
607
608 if (bFirstCall)
609 {
610 // Checking texture size
611 GLint nMaxTextureSize;
612 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &nMaxTextureSize);
613 if (nMaxTextureSize <= 4096)
614 SAL_WARN("vcl.opengl", "Max texture size is " << nMaxTextureSize
615 << ". This may not be enough for normal operation.");
616 else
617 VCL_GL_INFO("Max texture size: " << nMaxTextureSize);
618
619 // Trying to make a texture and check its size
620 for (GLint nWidthHeight = 1023; nWidthHeight < nMaxTextureSize; nWidthHeight += (nWidthHeight + 1))
621 {
622 glTexImage2D(GL_PROXY_TEXTURE_2D, 0, 4, nWidthHeight, nWidthHeight, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8, nullptr);
623 CHECK_GL_ERROR();
624 if (glGetError() == GL_NO_ERROR)
625 {
626 GLint nWidth = 0;
627 GLint nHeight = 0;
628 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &nWidth);
629 glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_HEIGHT, &nHeight);
630 VCL_GL_INFO("Created texture " << nWidthHeight << "," << nWidthHeight << " reports size: " << nWidth << ", " << nHeight);
631 }
632 else
633 {
634 SAL_WARN("vcl.opengl", "Error when creating a " << nWidthHeight << ", " << nWidthHeight << " test texture.");
635 }
636 }
637 }
638
639 InitGLDebugging();
640
641 g_vShareList.push_back(m_aGLWin.hRC);
642
643 RECT clientRect;
644 GetClientRect(WindowFromDC(m_aGLWin.hDC), &clientRect);
645 m_aGLWin.Width = clientRect.right - clientRect.left;
646 m_aGLWin.Height = clientRect.bottom - clientRect.top;
647
648 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
649
650 registerAsCurrent();
651
652 bFirstCall = false;
653
654 return true;
655 }
656
CreateOpenGLContext()657 OpenGLContext* WinSalInstance::CreateOpenGLContext()
658 {
659 return new WinOpenGLContext;
660 }
661
662 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
663