aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/sk_app/win/ANGLEWindowContext_win.cpp
blob: 649528d6cd4795a69e101593c651a1fa185e7e07 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177

/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include <EGL/egl.h>
#include <EGL/eglext.h>
#include "../GLWindowContext.h"
#include "WindowContextFactory_win.h"
#include "gl/GrGLAssembleInterface.h"
#include "gl/GrGLDefines.h"

using sk_app::GLWindowContext;
using sk_app::DisplayParams;

namespace {

EGLDisplay get_angle_egl_display(HDC hdc) {
    PFNEGLGETPLATFORMDISPLAYEXTPROC eglGetPlatformDisplayEXT;
    eglGetPlatformDisplayEXT =
            (PFNEGLGETPLATFORMDISPLAYEXTPROC)eglGetProcAddress("eglGetPlatformDisplayEXT");

    // We expect ANGLE to support this extension
    if (!eglGetPlatformDisplayEXT) {
        return EGL_NO_DISPLAY;
    }

    // We currently only support D3D11 ANGLE.
    static constexpr EGLint kType = EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE;
    static constexpr EGLint attribs[] = {EGL_PLATFORM_ANGLE_TYPE_ANGLE, kType, EGL_NONE};
    return eglGetPlatformDisplayEXT(EGL_PLATFORM_ANGLE_ANGLE, hdc, attribs);
}

class ANGLEGLWindowContext_win : public GLWindowContext {
public:
    ANGLEGLWindowContext_win(HWND, const DisplayParams&);
    ~ANGLEGLWindowContext_win() override;

protected:
    void onSwapBuffers() override;

    sk_sp<const GrGLInterface> onInitializeContext() override;
    void onDestroyContext() override;

private:
    HWND fHWND;
    EGLDisplay fDisplay = EGL_NO_DISPLAY;
    EGLContext fEGLContext = EGL_NO_CONTEXT;
    EGLSurface fEGLSurface = EGL_NO_SURFACE;

    typedef GLWindowContext INHERITED;
};

ANGLEGLWindowContext_win::ANGLEGLWindowContext_win(HWND wnd, const DisplayParams& params)
        : INHERITED(params), fHWND(wnd) {
    this->initializeContext();
}

ANGLEGLWindowContext_win::~ANGLEGLWindowContext_win() { this->destroyContext(); }

sk_sp<const GrGLInterface> ANGLEGLWindowContext_win::onInitializeContext() {
    HDC dc = GetDC(fHWND);
    fDisplay = get_angle_egl_display(dc);
    if (EGL_NO_DISPLAY == fDisplay) {
        return nullptr;
    }

    EGLint majorVersion;
    EGLint minorVersion;
    if (!eglInitialize(fDisplay, &majorVersion, &minorVersion)) {
        SkDebugf("Could not initialize display!\n");
        return nullptr;
    }
    EGLint numConfigs;
    fSampleCount = this->getDisplayParams().fMSAASampleCount;
    const int sampleBuffers = fSampleCount > 0 ? 1 : 0;
    const EGLint configAttribs[] = {EGL_RENDERABLE_TYPE,
                                    // We currently only support ES3.
                                    EGL_OPENGL_ES3_BIT,
                                    EGL_RED_SIZE,
                                    8,
                                    EGL_GREEN_SIZE,
                                    8,
                                    EGL_BLUE_SIZE,
                                    8,
                                    EGL_ALPHA_SIZE,
                                    8,
                                    EGL_SAMPLE_BUFFERS,
                                    sampleBuffers,
                                    EGL_SAMPLES,
                                    fSampleCount,
                                    EGL_NONE};

    EGLConfig surfaceConfig;
    if (!eglChooseConfig(fDisplay, configAttribs, &surfaceConfig, 1, &numConfigs)) {
        SkDebugf("Could not create choose config!\n");
        return nullptr;
    }
    // We currently only support ES3.
    const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
    fEGLContext = eglCreateContext(fDisplay, surfaceConfig, nullptr, contextAttribs);
    if (EGL_NO_CONTEXT == fEGLContext) {
        SkDebugf("Could not create context!\n");
        return nullptr;
    }
    fEGLSurface = eglCreateWindowSurface(fDisplay, surfaceConfig, fHWND, nullptr);
    if (EGL_NO_SURFACE == fEGLSurface) {
        SkDebugf("Could not create surface!\n");
        return nullptr;
    }
    if (!eglMakeCurrent(fDisplay, fEGLSurface, fEGLSurface, fEGLContext)) {
        SkDebugf("Could not make contxt current!\n");
        return nullptr;
    }

    sk_sp<const GrGLInterface> interface(GrGLMakeAssembledInterface(
            nullptr,
            [](void* ctx, const char name[]) -> GrGLFuncPtr { return eglGetProcAddress(name); }));
    if (interface) {
        interface->fFunctions.fClearStencil(0);
        interface->fFunctions.fClearColor(0, 0, 0, 0);
        interface->fFunctions.fStencilMask(0xffffffff);
        interface->fFunctions.fClear(GR_GL_STENCIL_BUFFER_BIT | GR_GL_COLOR_BUFFER_BIT);

        // use DescribePixelFormat to get the stencil depth.
        int pixelFormat = GetPixelFormat(dc);
        PIXELFORMATDESCRIPTOR pfd;
        DescribePixelFormat(dc, pixelFormat, sizeof(pfd), &pfd);
        fStencilBits = pfd.cStencilBits;

        RECT rect;
        GetClientRect(fHWND, &rect);
        fWidth = rect.right - rect.left;
        fHeight = rect.bottom - rect.top;
        interface->fFunctions.fViewport(0, 0, fWidth, fHeight);
    }
    return interface;
}

void ANGLEGLWindowContext_win::onDestroyContext() {
    eglMakeCurrent(fDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    if (EGL_NO_CONTEXT != fEGLContext) {
        eglDestroyContext(fDisplay, fEGLContext);
    }
    if (EGL_NO_SURFACE != fEGLSurface) {
        eglDestroySurface(fDisplay, fEGLSurface);
    }
    if (EGL_NO_DISPLAY != fDisplay) {
        eglTerminate(fDisplay);
    }
}

void ANGLEGLWindowContext_win::onSwapBuffers() {
    if (!eglSwapBuffers(fDisplay, fEGLSurface)) {
        SkDebugf("Could not complete eglSwapBuffers.\n");
    }
}

}  // anonymous namespace

namespace sk_app {
namespace window_context_factory {

WindowContext* NewANGLEForWin(HWND wnd, const DisplayParams& params) {
    ANGLEGLWindowContext_win* ctx = new ANGLEGLWindowContext_win(wnd, params);
    if (!ctx->isValid()) {
        delete ctx;
        return nullptr;
    }
    return ctx;
}

}  // namespace window_context_factory
}  // namespace sk_app