|
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 */ |
|
31 class GrContextFactory : public SkNoncopyable { |
|
32 public: |
|
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 GrCrash("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 |
|
188 private: |
|
189 struct GPUContext { |
|
190 GLContextType fType; |
|
191 SkGLContextHelper* fGLContext; |
|
192 GrContext* fGrContext; |
|
193 }; |
|
194 SkTArray<GPUContext, true> fContexts; |
|
195 }; |
|
196 |
|
197 #endif |