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