1 
2 /*
3  * Copyright 2011 Google Inc.
4  *
5  * Use of this source code is governed by a BSD-style license that can be
6  * found in the LICENSE file.
7  */
8 
9 #include "gl/GLTestContext.h"
10 
11 #include <windows.h>
12 #include <GL/GL.h>
13 #include "win/SkWGL.h"
14 
15 #include <windows.h>
16 
17 namespace {
18 
context_restorer()19 std::function<void()> context_restorer() {
20     auto glrc = wglGetCurrentContext();
21     auto dc = wglGetCurrentDC();
22     return [glrc, dc] { wglMakeCurrent(dc, glrc); };
23 }
24 
25 class WinGLTestContext : public sk_gpu_test::GLTestContext {
26 public:
27     WinGLTestContext(GrGLStandard forcedGpuAPI, WinGLTestContext* shareContext);
28     ~WinGLTestContext() override;
29 
30 private:
31     void destroyGLContext();
32 
33     void onPlatformMakeCurrent() const override;
34     std::function<void()> onPlatformGetAutoContextRestore() const override;
35     void onPlatformSwapBuffers() const override;
36     GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override;
37 
38     HWND fWindow;
39     HDC fDeviceContext;
40     HGLRC fGlRenderContext;
41     static ATOM gWC;
42     SkWGLPbufferContext* fPbufferContext;
43 };
44 
45 ATOM WinGLTestContext::gWC = 0;
46 
WinGLTestContext(GrGLStandard forcedGpuAPI,WinGLTestContext * shareContext)47 WinGLTestContext::WinGLTestContext(GrGLStandard forcedGpuAPI, WinGLTestContext* shareContext)
48     : fWindow(nullptr)
49     , fDeviceContext(nullptr)
50     , fGlRenderContext(0)
51     , fPbufferContext(nullptr) {
52     HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(nullptr);
53 
54     if (!gWC) {
55         WNDCLASS wc;
56         wc.cbClsExtra = 0;
57         wc.cbWndExtra = 0;
58         wc.hbrBackground = nullptr;
59         wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
60         wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
61         wc.hInstance = hInstance;
62         wc.lpfnWndProc = (WNDPROC) DefWindowProc;
63         wc.lpszClassName = TEXT("Griffin");
64         wc.lpszMenuName = nullptr;
65         wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
66 
67         gWC = RegisterClass(&wc);
68         if (!gWC) {
69             SkDebugf("Could not register window class.\n");
70             return;
71         }
72     }
73 
74     if (!(fWindow = CreateWindow(TEXT("Griffin"),
75                                  TEXT("The Invisible Man"),
76                                  WS_OVERLAPPEDWINDOW,
77                                  0, 0, 1, 1,
78                                  nullptr, nullptr,
79                                  hInstance, nullptr))) {
80         SkDebugf("Could not create window.\n");
81         return;
82     }
83 
84     if (!(fDeviceContext = GetDC(fWindow))) {
85         SkDebugf("Could not get device context.\n");
86         this->destroyGLContext();
87         return;
88     }
89     // Requesting a Core profile would bar us from using NVPR. So we request
90     // compatibility profile or GL ES.
91     SkWGLContextRequest contextType =
92         kGLES_GrGLStandard == forcedGpuAPI ?
93         kGLES_SkWGLContextRequest : kGLPreferCompatibilityProfile_SkWGLContextRequest;
94 
95     HGLRC winShareContext = nullptr;
96     if (shareContext) {
97         winShareContext = shareContext->fPbufferContext ? shareContext->fPbufferContext->getGLRC()
98                                                         : shareContext->fGlRenderContext;
99     }
100     fPbufferContext = SkWGLPbufferContext::Create(fDeviceContext, contextType, winShareContext);
101 
102     HDC dc;
103     HGLRC glrc;
104     if (nullptr == fPbufferContext) {
105         if (!(fGlRenderContext = SkCreateWGLContext(fDeviceContext, 0, false, contextType,
106                                                     winShareContext))) {
107             SkDebugf("Could not create rendering context.\n");
108             this->destroyGLContext();
109             return;
110         }
111         dc = fDeviceContext;
112         glrc = fGlRenderContext;
113     } else {
114         ReleaseDC(fWindow, fDeviceContext);
115         fDeviceContext = 0;
116         DestroyWindow(fWindow);
117         fWindow = 0;
118 
119         dc = fPbufferContext->getDC();
120         glrc = fPbufferContext->getGLRC();
121     }
122 
123     SkScopeExit restorer(context_restorer());
124     if (!(wglMakeCurrent(dc, glrc))) {
125         SkDebugf("Could not set the context.\n");
126         this->destroyGLContext();
127         return;
128     }
129 
130     auto gl = GrGLMakeNativeInterface();
131     if (!gl) {
132         SkDebugf("Could not create GL interface.\n");
133         this->destroyGLContext();
134         return;
135     }
136     if (!gl->validate()) {
137         SkDebugf("Could not validate GL interface.\n");
138         this->destroyGLContext();
139         return;
140     }
141 
142     this->init(std::move(gl));
143 }
144 
~WinGLTestContext()145 WinGLTestContext::~WinGLTestContext() {
146     this->teardown();
147     this->destroyGLContext();
148 }
149 
destroyGLContext()150 void WinGLTestContext::destroyGLContext() {
151     SkSafeSetNull(fPbufferContext);
152     if (fGlRenderContext) {
153         // This deletes the context immediately even if it is current.
154         wglDeleteContext(fGlRenderContext);
155         fGlRenderContext = 0;
156     }
157     if (fWindow && fDeviceContext) {
158         ReleaseDC(fWindow, fDeviceContext);
159         fDeviceContext = 0;
160     }
161     if (fWindow) {
162         DestroyWindow(fWindow);
163         fWindow = 0;
164     }
165 }
166 
onPlatformMakeCurrent() const167 void WinGLTestContext::onPlatformMakeCurrent() const {
168     HDC dc;
169     HGLRC glrc;
170 
171     if (nullptr == fPbufferContext) {
172         dc = fDeviceContext;
173         glrc = fGlRenderContext;
174     } else {
175         dc = fPbufferContext->getDC();
176         glrc = fPbufferContext->getGLRC();
177     }
178 
179     if (!wglMakeCurrent(dc, glrc)) {
180         SkDebugf("Could not create rendering context.\n");
181     }
182 }
183 
onPlatformGetAutoContextRestore() const184 std::function<void()> WinGLTestContext::onPlatformGetAutoContextRestore() const {
185     if (wglGetCurrentContext() == fGlRenderContext) {
186         return nullptr;
187     }
188     return context_restorer();
189 }
190 
onPlatformSwapBuffers() const191 void WinGLTestContext::onPlatformSwapBuffers() const {
192     HDC dc;
193 
194     if (nullptr == fPbufferContext) {
195         dc = fDeviceContext;
196     } else {
197         dc = fPbufferContext->getDC();
198     }
199     if (!SwapBuffers(dc)) {
200         SkDebugf("Could not complete SwapBuffers.\n");
201     }
202 }
203 
onPlatformGetProcAddress(const char * name) const204 GrGLFuncPtr WinGLTestContext::onPlatformGetProcAddress(const char* name) const {
205     return reinterpret_cast<GrGLFuncPtr>(wglGetProcAddress(name));
206 }
207 
208 } // anonymous namespace
209 
210 namespace sk_gpu_test {
CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,GLTestContext * shareContext)211 GLTestContext* CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,
212                                            GLTestContext *shareContext) {
213     WinGLTestContext* winShareContext = reinterpret_cast<WinGLTestContext*>(shareContext);
214     WinGLTestContext *ctx = new WinGLTestContext(forcedGpuAPI, winShareContext);
215     if (!ctx->isValid()) {
216         delete ctx;
217         return nullptr;
218     }
219     return ctx;
220 }
221 }  // namespace sk_gpu_test
222 
223