aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/sk_app/ios/RasterWindowContext_ios.cpp
blob: 53d7c1a37294683d9429bf2ee90cdf506874a083 (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

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

#include <OpenGLES/ES2/gl.h>
#include "../GLWindowContext.h"
#include "SDL.h"
#include "SkCanvas.h"
#include "SkColorFilter.h"
#include "WindowContextFactory_ios.h"
#include "gl/GrGLInterface.h"
#include "sk_tool_utils.h"

using sk_app::DisplayParams;
using sk_app::window_context_factory::IOSWindowInfo;
using sk_app::GLWindowContext;

namespace {

// We use SDL to support Mac windowing mainly for convenience's sake. However, it
// does not allow us to support a purely raster backend because we have no hooks into
// the NSWindow's drawRect: method. Hence we use GL to handle the update. Should we
// want to avoid this, we will probably need to write our own windowing backend.

class RasterWindowContext_ios : public GLWindowContext {
public:
    RasterWindowContext_ios(const IOSWindowInfo&, const DisplayParams&);

    ~RasterWindowContext_ios() override;

    sk_sp<SkSurface> getBackbufferSurface() override;

    void onSwapBuffers() override;

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

private:
    SDL_Window*   fWindow;
    SDL_GLContext fGLContext;
    sk_sp<SkSurface> fBackbufferSurface;

    typedef GLWindowContext INHERITED;
};

RasterWindowContext_ios::RasterWindowContext_ios(const IOSWindowInfo& info,
                                                 const DisplayParams& params)
    : INHERITED(params)
    , fWindow(info.fWindow)
    , fGLContext(nullptr) {

    // any config code here (particularly for msaa)?

    this->initializeContext();
}

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

sk_sp<const GrGLInterface> RasterWindowContext_ios::onInitializeContext() {
    SkASSERT(fWindow);

    fGLContext = SDL_GL_CreateContext(fWindow);
    if (!fGLContext) {
        SkDebugf("%s\n", SDL_GetError());
        return nullptr;
    }

    if (0 == SDL_GL_MakeCurrent(fWindow, fGLContext)) {
        glClearStencil(0);
        glClearColor(0, 0, 0, 0);
        glStencilMask(0xffffffff);
        glClear(GL_STENCIL_BUFFER_BIT | GL_COLOR_BUFFER_BIT);

        SDL_GL_GetAttribute(SDL_GL_STENCIL_SIZE, &fStencilBits);
        SDL_GL_GetAttribute(SDL_GL_MULTISAMPLESAMPLES, &fSampleCount);
        fSampleCount = SkTMax(fSampleCount, 1);

        SDL_GL_GetDrawableSize(fWindow, &fWidth, &fHeight);
        glViewport(0, 0, fWidth, fHeight);
    } else {
        SkDebugf("MakeCurrent failed: %s\n", SDL_GetError());
    }

    // make the offscreen image
    SkImageInfo info = SkImageInfo::Make(fWidth, fHeight, fDisplayParams.fColorType,
                                         kPremul_SkAlphaType, fDisplayParams.fColorSpace);
    fBackbufferSurface = SkSurface::MakeRaster(info);
    return GrGLMakeNativeInterface();
}

void RasterWindowContext_ios::onDestroyContext() {
    if (!fWindow || !fGLContext) {
        return;
    }
    fBackbufferSurface.reset(nullptr);
    SDL_GL_DeleteContext(fGLContext);
    fGLContext = nullptr;
}

sk_sp<SkSurface> RasterWindowContext_ios::getBackbufferSurface() { return fBackbufferSurface; }

void RasterWindowContext_ios::onSwapBuffers() {
    if (fWindow && fGLContext) {
        // We made/have an off-screen surface. Get the contents as an SkImage:
        sk_sp<SkImage> snapshot = fBackbufferSurface->makeImageSnapshot();

        sk_sp<SkSurface> gpuSurface = INHERITED::getBackbufferSurface();
        SkCanvas* gpuCanvas = gpuSurface->getCanvas();
        gpuCanvas->drawImage(snapshot, 0, 0);
        gpuCanvas->flush();

        SDL_GL_SwapWindow(fWindow);
    }
}

}  // anonymous namespace

namespace sk_app {
namespace window_context_factory {

WindowContext* NewRasterForIOS(const IOSWindowInfo& info, const DisplayParams& params) {
    WindowContext* ctx = new RasterWindowContext_ios(info, params);
    if (!ctx->isValid()) {
        delete ctx;
        return nullptr;
    }
    return ctx;
}

}  // namespace window_context_factory
}  // namespace sk_app