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