1/*
2 * Copyright 2012 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#ifndef GrContextFactory_DEFINED
9#define GrContextFactory_DEFINED
10
11#if SK_ANGLE
12    #include "gl/SkANGLEGLContext.h"
13#endif
14#include "gl/SkDebugGLContext.h"
15#if SK_MESA
16    #include "gl/SkMesaGLContext.h"
17#endif
18#include "gl/SkNativeGLContext.h"
19#include "gl/SkNullGLContext.h"
20
21#include "GrContext.h"
22#include "SkTArray.h"
23
24/**
25 * This is a simple class that is useful in test apps that use different
26 * GrContexts backed by different types of GL contexts. It manages creating the
27 * GL context and a GrContext that uses it. The GL/Gr contexts persist until the
28 * factory is destroyed (though the caller can always grab a ref on the returned
29 * Gr and GL contexts to make them outlive the factory).
30 */
31class GrContextFactory : SkNoncopyable {
32public:
33    /**
34     * Types of GL contexts supported. For historical and testing reasons the native GrContext will
35     * not use "GL_NV_path_rendering" even when the driver supports it. There is a separate context
36     * type that does not remove NVPR support and which will fail when the driver does not support
37     * the extension.
38     */
39    enum GLContextType {
40      kNative_GLContextType,
41#if SK_ANGLE
42      kANGLE_GLContextType,
43#endif
44#if SK_MESA
45      kMESA_GLContextType,
46#endif
47      /** Similar to kNative but does not filter NVPR. It will fail if the GL driver does not
48          support NVPR */
49      kNVPR_GLContextType,
50      kNull_GLContextType,
51      kDebug_GLContextType,
52
53      kLastGLContextType = kDebug_GLContextType
54    };
55
56    static const int kGLContextTypeCnt = kLastGLContextType + 1;
57
58    static bool IsRenderingGLContext(GLContextType type) {
59        switch (type) {
60            case kNull_GLContextType:
61            case kDebug_GLContextType:
62                return false;
63            default:
64                return true;
65        }
66    }
67
68    static const char* GLContextTypeName(GLContextType type) {
69        switch (type) {
70            case kNative_GLContextType:
71                return "native";
72            case kNull_GLContextType:
73                return "null";
74#if SK_ANGLE
75            case kANGLE_GLContextType:
76                return "angle";
77#endif
78#if SK_MESA
79            case kMESA_GLContextType:
80                return "mesa";
81#endif
82            case kNVPR_GLContextType:
83                return "nvpr";
84            case kDebug_GLContextType:
85                return "debug";
86            default:
87                SkFAIL("Unknown GL Context type.");
88        }
89    }
90
91    GrContextFactory() {
92    }
93
94    ~GrContextFactory() { this->destroyContexts(); }
95
96    void destroyContexts() {
97        for (int i = 0; i < fContexts.count(); ++i) {
98            fContexts[i].fGLContext->makeCurrent();
99            fContexts[i].fGrContext->unref();
100            fContexts[i].fGLContext->unref();
101        }
102        fContexts.reset();
103    }
104
105    /**
106     * Get a GrContext initialized with a type of GL context. It also makes the GL context current.
107     */
108    GrContext* get(GLContextType type) {
109
110        for (int i = 0; i < fContexts.count(); ++i) {
111            if (fContexts[i].fType == type) {
112                fContexts[i].fGLContext->makeCurrent();
113                return fContexts[i].fGrContext;
114            }
115        }
116        SkAutoTUnref<SkGLContextHelper> glCtx;
117        SkAutoTUnref<GrContext> grCtx;
118        switch (type) {
119            case kNVPR_GLContextType: // fallthru
120            case kNative_GLContextType:
121                glCtx.reset(SkNEW(SkNativeGLContext));
122                break;
123#ifdef SK_ANGLE
124            case kANGLE_GLContextType:
125                glCtx.reset(SkNEW(SkANGLEGLContext));
126                break;
127#endif
128#ifdef SK_MESA
129            case kMESA_GLContextType:
130                glCtx.reset(SkNEW(SkMesaGLContext));
131                break;
132#endif
133            case kNull_GLContextType:
134                glCtx.reset(SkNEW(SkNullGLContext));
135                break;
136            case kDebug_GLContextType:
137                glCtx.reset(SkNEW(SkDebugGLContext));
138                break;
139        }
140        static const int kBogusSize = 1;
141        if (!glCtx.get()) {
142            return NULL;
143        }
144        if (!glCtx.get()->init(kBogusSize, kBogusSize)) {
145            return NULL;
146        }
147
148        // Ensure NVPR is available for the NVPR type and block it from other types.
149        SkAutoTUnref<const GrGLInterface> glInterface(SkRef(glCtx.get()->gl()));
150        if (kNVPR_GLContextType == type) {
151            if (!glInterface->hasExtension("GL_NV_path_rendering")) {
152                return NULL;
153            }
154        } else {
155            glInterface.reset(GrGLInterfaceRemoveNVPR(glInterface));
156            if (!glInterface) {
157                return NULL;
158            }
159        }
160
161        glCtx->makeCurrent();
162        GrBackendContext p3dctx = reinterpret_cast<GrBackendContext>(glInterface.get());
163        grCtx.reset(GrContext::Create(kOpenGL_GrBackend, p3dctx));
164        if (!grCtx.get()) {
165            return NULL;
166        }
167        GPUContext& ctx = fContexts.push_back();
168        ctx.fGLContext = glCtx.get();
169        ctx.fGLContext->ref();
170        ctx.fGrContext = grCtx.get();
171        ctx.fGrContext->ref();
172        ctx.fType = type;
173        return ctx.fGrContext;
174    }
175
176    // Returns the GLContext of the given type. If it has not been created yet,
177    // NULL is returned instead.
178    SkGLContextHelper* getGLContext(GLContextType type) {
179        for (int i = 0; i < fContexts.count(); ++i) {
180            if (fContexts[i].fType == type) {
181                return fContexts[i].fGLContext;
182            }
183        }
184
185        return NULL;
186    }
187
188private:
189    struct GPUContext {
190        GLContextType             fType;
191        SkGLContextHelper*        fGLContext;
192        GrContext*                fGrContext;
193    };
194    SkTArray<GPUContext, true> fContexts;
195};
196
197#endif
198