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 "tools/gpu/gl/GLTestContext.h"
10
11#if defined(_M_ARM64)
12
13namespace sk_gpu_test {
14
15GLTestContext* CreatePlatformGLTestContext(GrGLStandard, GLTestContext*) { return nullptr; }
16
17}  // namespace sk_gpu_test
18
19#else
20
21#include <windows.h>
22// #include <GL/GL.h>
23#include <GL/gl.h>
24#include "src/utils/win/SkWGL.h"
25
26#include <windows.h>
27
28namespace {
29
30std::function<void()> context_restorer() {
31    auto glrc = wglGetCurrentContext();
32    auto dc = wglGetCurrentDC();
33    return [glrc, dc] { wglMakeCurrent(dc, glrc); };
34}
35
36class WinGLTestContext : public sk_gpu_test::GLTestContext {
37public:
38    WinGLTestContext(GrGLStandard forcedGpuAPI, WinGLTestContext* shareContext);
39    ~WinGLTestContext() override;
40
41private:
42    void destroyGLContext();
43
44    void onPlatformMakeNotCurrent() const override;
45    void onPlatformMakeCurrent() const override;
46    std::function<void()> onPlatformGetAutoContextRestore() const override;
47    GrGLFuncPtr onPlatformGetProcAddress(const char* name) const override;
48
49    HWND fWindow;
50    HDC fDeviceContext;
51    HGLRC fGlRenderContext;
52    static ATOM gWC;
53    sk_sp<SkWGLPbufferContext> fPbufferContext;
54};
55
56ATOM WinGLTestContext::gWC = 0;
57
58WinGLTestContext::WinGLTestContext(GrGLStandard forcedGpuAPI, WinGLTestContext* shareContext)
59    : fWindow(nullptr)
60    , fDeviceContext(nullptr)
61    , fGlRenderContext(0)
62    , fPbufferContext(nullptr) {
63    HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(nullptr);
64
65    if (!gWC) {
66        WNDCLASS wc;
67        wc.cbClsExtra = 0;
68        wc.cbWndExtra = 0;
69        wc.hbrBackground = nullptr;
70        wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
71        wc.hIcon = LoadIcon(nullptr, IDI_APPLICATION);
72        wc.hInstance = hInstance;
73        wc.lpfnWndProc = (WNDPROC) DefWindowProc;
74        wc.lpszClassName = TEXT("Griffin");
75        wc.lpszMenuName = nullptr;
76        wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
77
78        gWC = RegisterClass(&wc);
79        if (!gWC) {
80            SkDebugf("Could not register window class.\n");
81            return;
82        }
83    }
84
85    if (!(fWindow = CreateWindow(TEXT("Griffin"),
86                                 TEXT("The Invisible Man"),
87                                 WS_OVERLAPPEDWINDOW,
88                                 0, 0, 1, 1,
89                                 nullptr, nullptr,
90                                 hInstance, nullptr))) {
91        SkDebugf("Could not create window.\n");
92        return;
93    }
94
95    if (!(fDeviceContext = GetDC(fWindow))) {
96        SkDebugf("Could not get device context.\n");
97        this->destroyGLContext();
98        return;
99    }
100
101    // We request a compatibility context since glMultiDrawArraysIndirect, apparently, doesn't
102    // work correctly on Intel Iris GPUs with the core profile (skbug.com/11787).
103    SkWGLContextRequest contextType =
104        kGLES_GrGLStandard == forcedGpuAPI ? kGLES_SkWGLContextRequest
105                                           : kGLPreferCompatibilityProfile_SkWGLContextRequest;
106
107    HGLRC winShareContext = nullptr;
108    if (shareContext) {
109        winShareContext = shareContext->fPbufferContext ? shareContext->fPbufferContext->getGLRC()
110                                                        : shareContext->fGlRenderContext;
111    }
112    fPbufferContext = SkWGLPbufferContext::Create(fDeviceContext, contextType, winShareContext);
113
114    HDC dc;
115    HGLRC glrc;
116    if (nullptr == fPbufferContext) {
117        if (!(fGlRenderContext = SkCreateWGLContext(fDeviceContext, 0, false, contextType,
118                                                    winShareContext))) {
119            SkDebugf("Could not create rendering context.\n");
120            this->destroyGLContext();
121            return;
122        }
123        dc = fDeviceContext;
124        glrc = fGlRenderContext;
125    } else {
126        ReleaseDC(fWindow, fDeviceContext);
127        fDeviceContext = 0;
128        DestroyWindow(fWindow);
129        fWindow = 0;
130
131        dc = fPbufferContext->getDC();
132        glrc = fPbufferContext->getGLRC();
133    }
134
135    SkScopeExit restorer(context_restorer());
136    if (!(wglMakeCurrent(dc, glrc))) {
137        SkDebugf("Could not set the context.\n");
138        this->destroyGLContext();
139        return;
140    }
141
142#ifdef SK_GL
143    auto gl = GrGLMakeNativeInterface();
144    if (!gl) {
145        SkDebugf("Could not create GL interface.\n");
146        this->destroyGLContext();
147        return;
148    }
149    if (!gl->validate()) {
150        SkDebugf("Could not validate GL interface.\n");
151        this->destroyGLContext();
152        return;
153    }
154
155    this->init(std::move(gl));
156#else
157    // Allow the GLTestContext creation to succeed without a GrGLInterface to support
158    // GrContextFactory's persistent GL context workaround for Vulkan. We won't need the
159    // GrGLInterface since we're not running the GL backend.
160    this->init(nullptr);
161#endif
162}
163
164WinGLTestContext::~WinGLTestContext() {
165    this->teardown();
166    this->destroyGLContext();
167}
168
169void WinGLTestContext::destroyGLContext() {
170    fPbufferContext = nullptr;
171    if (fGlRenderContext) {
172        // This deletes the context immediately even if it is current.
173        wglDeleteContext(fGlRenderContext);
174        fGlRenderContext = 0;
175    }
176    if (fWindow && fDeviceContext) {
177        ReleaseDC(fWindow, fDeviceContext);
178        fDeviceContext = 0;
179    }
180    if (fWindow) {
181        DestroyWindow(fWindow);
182        fWindow = 0;
183    }
184}
185
186void WinGLTestContext::onPlatformMakeNotCurrent() const {
187    if (!wglMakeCurrent(NULL, NULL)) {
188        SkDebugf("Could not null out the rendering context.\n");
189    }
190}
191
192void WinGLTestContext::onPlatformMakeCurrent() const {
193    HDC dc;
194    HGLRC glrc;
195
196    if (nullptr == fPbufferContext) {
197        dc = fDeviceContext;
198        glrc = fGlRenderContext;
199    } else {
200        dc = fPbufferContext->getDC();
201        glrc = fPbufferContext->getGLRC();
202    }
203
204    if (!wglMakeCurrent(dc, glrc)) {
205        SkDebugf("Could not make current.\n");
206    }
207}
208
209std::function<void()> WinGLTestContext::onPlatformGetAutoContextRestore() const {
210    if (wglGetCurrentContext() == fGlRenderContext) {
211        return nullptr;
212    }
213    return context_restorer();
214}
215
216GrGLFuncPtr WinGLTestContext::onPlatformGetProcAddress(const char* name) const {
217    return reinterpret_cast<GrGLFuncPtr>(wglGetProcAddress(name));
218}
219
220} // anonymous namespace
221
222namespace sk_gpu_test {
223GLTestContext* CreatePlatformGLTestContext(GrGLStandard forcedGpuAPI,
224                                           GLTestContext *shareContext) {
225    WinGLTestContext* winShareContext = reinterpret_cast<WinGLTestContext*>(shareContext);
226    WinGLTestContext *ctx = new WinGLTestContext(forcedGpuAPI, winShareContext);
227    if (!ctx->isValid()) {
228        delete ctx;
229        return nullptr;
230    }
231    return ctx;
232}
233}  // namespace sk_gpu_test
234
235#endif
236