1
2/*
3 * Copyright 2013 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#include "gl/SkGLContextHelper.h"
9#include "GrGLUtil.h"
10
11SkGLContextHelper::SkGLContextHelper()
12    : fFBO(0)
13    , fColorBufferID(0)
14    , fDepthStencilBufferID(0)
15    , fGL(NULL) {
16}
17
18SkGLContextHelper::~SkGLContextHelper() {
19
20    if (fGL) {
21        // TODO: determine why DeleteFramebuffers is generating a GL error in tests
22        SK_GL_NOERRCHECK(*this, DeleteFramebuffers(1, &fFBO));
23        SK_GL_NOERRCHECK(*this, DeleteRenderbuffers(1, &fColorBufferID));
24        SK_GL_NOERRCHECK(*this, DeleteRenderbuffers(1, &fDepthStencilBufferID));
25    }
26
27    SkSafeUnref(fGL);
28}
29
30bool SkGLContextHelper::init(GrGLStandard forcedGpuAPI, int width,
31                             int height) {
32    if (fGL) {
33        fGL->unref();
34        this->destroyGLContext();
35    }
36
37    fGL = this->createGLContext(forcedGpuAPI);
38    if (fGL) {
39        const GrGLubyte* temp;
40
41        if (!fGL->validate()) {
42            fGL = NULL;
43            this->destroyGLContext();
44            return false;
45        }
46
47        SK_GL_RET(*this, temp, GetString(GR_GL_VERSION));
48        const char* versionStr = reinterpret_cast<const char*>(temp);
49        GrGLVersion version = GrGLGetVersionFromString(versionStr);
50
51        // clear any existing GL erorrs
52        GrGLenum error;
53        do {
54            SK_GL_RET(*this, error, GetError());
55        } while (GR_GL_NO_ERROR != error);
56
57        SK_GL(*this, GenFramebuffers(1, &fFBO));
58        SK_GL(*this, BindFramebuffer(GR_GL_FRAMEBUFFER, fFBO));
59        SK_GL(*this, GenRenderbuffers(1, &fColorBufferID));
60        SK_GL(*this, BindRenderbuffer(GR_GL_RENDERBUFFER, fColorBufferID));
61        if (kGLES_GrGLStandard == this->gl()->fStandard) {
62            SK_GL(*this, RenderbufferStorage(GR_GL_RENDERBUFFER,
63                                             GR_GL_RGBA8,
64                                             width, height));
65        } else {
66            SK_GL(*this, RenderbufferStorage(GR_GL_RENDERBUFFER,
67                                             GR_GL_RGBA,
68                                             width, height));
69        }
70        SK_GL(*this, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
71                                             GR_GL_COLOR_ATTACHMENT0,
72                                             GR_GL_RENDERBUFFER,
73                                             fColorBufferID));
74        SK_GL(*this, GenRenderbuffers(1, &fDepthStencilBufferID));
75        SK_GL(*this, BindRenderbuffer(GR_GL_RENDERBUFFER, fDepthStencilBufferID));
76
77        // Some drivers that support packed depth stencil will only succeed
78        // in binding a packed format an FBO. However, we can't rely on packed
79        // depth stencil being available.
80        bool supportsPackedDepthStencil;
81        if (kGLES_GrGLStandard == this->gl()->fStandard) {
82            supportsPackedDepthStencil = version >= GR_GL_VER(3,0) ||
83                                         this->hasExtension("GL_OES_packed_depth_stencil");
84        } else {
85            supportsPackedDepthStencil = version >= GR_GL_VER(3,0) ||
86                                         this->hasExtension("GL_EXT_packed_depth_stencil") ||
87                                         this->hasExtension("GL_ARB_framebuffer_object");
88        }
89
90        if (supportsPackedDepthStencil) {
91            // ES2 requires sized internal formats for RenderbufferStorage
92            // On Desktop we let the driver decide.
93            GrGLenum format = kGLES_GrGLStandard == this->gl()->fStandard ?
94                                    GR_GL_DEPTH24_STENCIL8 :
95                                    GR_GL_DEPTH_STENCIL;
96            SK_GL(*this, RenderbufferStorage(GR_GL_RENDERBUFFER,
97                                             format,
98                                             width, height));
99            SK_GL(*this, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
100                                                 GR_GL_DEPTH_ATTACHMENT,
101                                                 GR_GL_RENDERBUFFER,
102                                                 fDepthStencilBufferID));
103        } else {
104            GrGLenum format = kGLES_GrGLStandard == this->gl()->fStandard ? GR_GL_STENCIL_INDEX8 :
105                                                                          GR_GL_STENCIL_INDEX;
106            SK_GL(*this, RenderbufferStorage(GR_GL_RENDERBUFFER,
107                                             format,
108                                             width, height));
109        }
110        SK_GL(*this, FramebufferRenderbuffer(GR_GL_FRAMEBUFFER,
111                                             GR_GL_STENCIL_ATTACHMENT,
112                                             GR_GL_RENDERBUFFER,
113                                             fDepthStencilBufferID));
114        SK_GL(*this, Viewport(0, 0, width, height));
115        SK_GL(*this, ClearStencil(0));
116        SK_GL(*this, Clear(GR_GL_STENCIL_BUFFER_BIT));
117
118        SK_GL_RET(*this, error, GetError());
119        GrGLenum status;
120        SK_GL_RET(*this, status, CheckFramebufferStatus(GR_GL_FRAMEBUFFER));
121
122        if (GR_GL_FRAMEBUFFER_COMPLETE != status ||
123            GR_GL_NO_ERROR != error) {
124            fFBO = 0;
125            fColorBufferID = 0;
126            fDepthStencilBufferID = 0;
127            fGL->unref();
128            fGL = NULL;
129            this->destroyGLContext();
130            return false;
131        } else {
132            return true;
133        }
134    }
135    return false;
136}
137
138void SkGLContextHelper::testAbandon() {
139    if (fGL) {
140        fGL->abandon();
141    }
142}
143