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
17namespace {
18
19std::function<void()> context_restorer() {
20    auto glrc = wglGetCurrentContext();
21    auto dc = wglGetCurrentDC();
22    return [glrc, dc] { wglMakeCurrent(dc, glrc); };
23}
24
25class WinGLTestContext : public sk_gpu_test::GLTestContext {
26public:
27    WinGLTestContext(GrGLStandard forcedGpuAPI, WinGLTestContext* shareContext);
28    ~WinGLTestContext() override;
29
30private:
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
45ATOM WinGLTestContext::gWC = 0;
46
47WinGLTestContext::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
145WinGLTestContext::~WinGLTestContext() {
146    this->teardown();
147    this->destroyGLContext();
148}
149
150void 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
167void 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
184std::function<void()> WinGLTestContext::onPlatformGetAutoContextRestore() const {
185    if (wglGetCurrentContext() == fGlRenderContext) {
186        return nullptr;
187    }
188    return context_restorer();
189}
190
191void 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
204GrGLFuncPtr WinGLTestContext::onPlatformGetProcAddress(const char* name) const {
205    return reinterpret_cast<GrGLFuncPtr>(wglGetProcAddress(name));
206}
207
208} // anonymous namespace
209
210namespace sk_gpu_test {
211GLTestContext* 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