1
2/*
3 * Copyright 2011 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
9#include "gl/SkNullGLContext.h"
10#include "gl/GrGLInterface.h"
11#include "GrGLDefines.h"
12#include "GrGLNoOpInterface.h"
13#include "SkTDArray.h"
14#include "SkTLS.h"
15
16static SkNullGLContext::ContextState* current_context();
17
18/////////////////////////////////////////////////////////////////////////////////////////////////
19
20class BufferObj {
21public:
22    SK_DECLARE_INST_COUNT(BufferObj);
23
24    BufferObj(GrGLuint id) : fID(id), fDataPtr(NULL), fSize(0), fMapped(false) {}
25    ~BufferObj() { SkDELETE_ARRAY(fDataPtr); }
26
27    void allocate(GrGLsizeiptr size, const GrGLchar* dataPtr) {
28        if (fDataPtr) {
29            SkASSERT(0 != fSize);
30            SkDELETE_ARRAY(fDataPtr);
31        }
32
33        fSize = size;
34        fDataPtr = SkNEW_ARRAY(char, size);
35    }
36
37    GrGLuint id() const          { return fID; }
38    GrGLchar* dataPtr()          { return fDataPtr; }
39    GrGLsizeiptr size() const    { return fSize; }
40
41    void setMapped(bool mapped)  { fMapped = mapped; }
42    bool mapped() const          { return fMapped; }
43
44private:
45    GrGLuint     fID;
46    GrGLchar*    fDataPtr;
47    GrGLsizeiptr fSize;         // size in bytes
48    bool         fMapped;
49};
50
51// This class maintains a sparsely populated array of buffer pointers.
52class BufferManager {
53public:
54    SK_DECLARE_INST_COUNT(BufferManager);
55
56    BufferManager() : fFreeListHead(kFreeListEnd) {}
57
58    ~BufferManager() {
59        // NULL out the entries that are really free list links rather than ptrs before deleting.
60        intptr_t curr = fFreeListHead;
61        while (kFreeListEnd != curr) {
62            intptr_t next = reinterpret_cast<intptr_t>(fBuffers[SkToS32(curr)]);
63            fBuffers[SkToS32(curr)] = NULL;
64            curr = next;
65        }
66
67        fBuffers.deleteAll();
68    }
69
70    BufferObj* lookUp(GrGLuint id) {
71        BufferObj* buffer = fBuffers[id];
72        SkASSERT(buffer && buffer->id() == id);
73        return buffer;
74    }
75
76    BufferObj* create() {
77        GrGLuint id;
78        BufferObj* buffer;
79
80        if (kFreeListEnd == fFreeListHead) {
81            // no free slots - create a new one
82            id = fBuffers.count();
83            buffer = SkNEW_ARGS(BufferObj, (id));
84            *fBuffers.append() = buffer;
85        } else {
86            // grab the head of the free list and advance the head to the next free slot.
87            id = static_cast<GrGLuint>(fFreeListHead);
88            fFreeListHead = reinterpret_cast<intptr_t>(fBuffers[id]);
89
90            buffer = SkNEW_ARGS(BufferObj, (id));
91            fBuffers[id] = buffer;
92        }
93
94        return buffer;
95    }
96
97    void free(BufferObj* buffer) {
98        SkASSERT(fBuffers.count() > 0);
99
100        GrGLuint id = buffer->id();
101        SkDELETE(buffer);
102
103        fBuffers[id] = reinterpret_cast<BufferObj*>(fFreeListHead);
104        fFreeListHead = id;
105    }
106
107private:
108    static const intptr_t kFreeListEnd = -1;
109    // Index of the first entry of fBuffers in the free list. Free slots in fBuffers are indices to
110    // the next free slot. The last free slot has a value of kFreeListEnd.
111    intptr_t                fFreeListHead;
112    SkTDArray<BufferObj*>   fBuffers;
113};
114
115/**
116 * The state object for the null interface.
117 */
118class SkNullGLContext::ContextState : public SkRefCnt {
119public:
120    SK_DECLARE_INST_COUNT(ContextState);
121
122    BufferManager   fBufferManager;
123    GrGLuint        fCurrArrayBuffer;
124    GrGLuint        fCurrElementArrayBuffer;
125    GrGLuint        fCurrProgramID;
126    GrGLuint        fCurrShaderID;
127
128
129    ContextState()
130        : fCurrArrayBuffer(0)
131        , fCurrElementArrayBuffer(0)
132        , fCurrProgramID(0)
133        , fCurrShaderID(0) {}
134
135    static ContextState* Get() { return current_context(); }
136};
137
138typedef SkNullGLContext::ContextState State;
139
140// Functions not declared in GrGLBogusInterface.h (not common with the Debug GL interface).
141
142namespace { // added to suppress 'no previous prototype' warning
143
144GrGLvoid GR_GL_FUNCTION_TYPE nullGLActiveTexture(GrGLenum texture) {}
145GrGLvoid GR_GL_FUNCTION_TYPE nullGLAttachShader(GrGLuint program, GrGLuint shader) {}
146GrGLvoid GR_GL_FUNCTION_TYPE nullGLBeginQuery(GrGLenum target, GrGLuint id) {}
147GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindAttribLocation(GrGLuint program, GrGLuint index, const char* name) {}
148GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindTexture(GrGLenum target, GrGLuint texture) {}
149GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindVertexArray(GrGLuint id) {}
150
151GrGLvoid GR_GL_FUNCTION_TYPE nullGLGenBuffers(GrGLsizei n, GrGLuint* ids) {
152    State* state = State::Get();
153    for (int i = 0; i < n; ++i) {
154        BufferObj* buffer = state->fBufferManager.create();
155        ids[i] = buffer->id();
156    }
157}
158
159GrGLvoid GR_GL_FUNCTION_TYPE nullGLGenerateMipmap(GrGLenum target) {}
160
161GrGLvoid GR_GL_FUNCTION_TYPE nullGLBufferData(GrGLenum target,
162                                              GrGLsizeiptr size,
163                                              const GrGLvoid* data,
164                                              GrGLenum usage) {
165    State* state = State::Get();
166    GrGLuint id = 0;
167
168    switch (target) {
169    case GR_GL_ARRAY_BUFFER:
170        id = state->fCurrArrayBuffer;
171        break;
172    case GR_GL_ELEMENT_ARRAY_BUFFER:
173        id = state->fCurrElementArrayBuffer;
174        break;
175    default:
176        SkFAIL("Unexpected target to nullGLBufferData");
177        break;
178    }
179
180    if (id > 0) {
181        BufferObj* buffer = state->fBufferManager.lookUp(id);
182        buffer->allocate(size, (const GrGLchar*) data);
183    }
184}
185
186GrGLvoid GR_GL_FUNCTION_TYPE nullGLPixelStorei(GrGLenum pname, GrGLint param) {}
187GrGLvoid GR_GL_FUNCTION_TYPE nullGLReadPixels(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, GrGLvoid* pixels) {}
188GrGLvoid GR_GL_FUNCTION_TYPE nullGLUseProgram(GrGLuint program) {}
189GrGLvoid GR_GL_FUNCTION_TYPE nullGLViewport(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height) {}
190GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindFramebuffer(GrGLenum target, GrGLuint framebuffer) {}
191GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindRenderbuffer(GrGLenum target, GrGLuint renderbuffer) {}
192GrGLvoid GR_GL_FUNCTION_TYPE nullGLDeleteFramebuffers(GrGLsizei n, const GrGLuint *framebuffers) {}
193GrGLvoid GR_GL_FUNCTION_TYPE nullGLDeleteRenderbuffers(GrGLsizei n, const GrGLuint *renderbuffers) {}
194GrGLvoid GR_GL_FUNCTION_TYPE nullGLFramebufferRenderbuffer(GrGLenum target, GrGLenum attachment, GrGLenum renderbuffertarget, GrGLuint renderbuffer) {}
195GrGLvoid GR_GL_FUNCTION_TYPE nullGLFramebufferTexture2D(GrGLenum target, GrGLenum attachment, GrGLenum textarget, GrGLuint texture, GrGLint level) {}
196
197GrGLuint GR_GL_FUNCTION_TYPE nullGLCreateProgram() {
198    return ++State::Get()->fCurrProgramID;
199}
200
201GrGLuint GR_GL_FUNCTION_TYPE nullGLCreateShader(GrGLenum type) {
202    return ++State::Get()->fCurrShaderID;
203}
204
205// same delete used for shaders and programs
206GrGLvoid GR_GL_FUNCTION_TYPE nullGLDelete(GrGLuint program) {
207}
208
209GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindBuffer(GrGLenum target, GrGLuint buffer) {
210    State* state = State::Get();
211    switch (target) {
212    case GR_GL_ARRAY_BUFFER:
213        state->fCurrArrayBuffer = buffer;
214        break;
215    case GR_GL_ELEMENT_ARRAY_BUFFER:
216        state->fCurrElementArrayBuffer = buffer;
217        break;
218    }
219}
220
221// deleting a bound buffer has the side effect of binding 0
222GrGLvoid GR_GL_FUNCTION_TYPE nullGLDeleteBuffers(GrGLsizei n, const GrGLuint* ids) {
223    State* state = State::Get();
224    for (int i = 0; i < n; ++i) {
225        if (ids[i] == state->fCurrArrayBuffer) {
226            state->fCurrArrayBuffer = 0;
227        }
228        if (ids[i] == state->fCurrElementArrayBuffer) {
229            state->fCurrElementArrayBuffer = 0;
230        }
231
232        BufferObj* buffer = state->fBufferManager.lookUp(ids[i]);
233        state->fBufferManager.free(buffer);
234    }
235}
236
237GrGLvoid* GR_GL_FUNCTION_TYPE nullGLMapBufferRange(GrGLenum target, GrGLintptr offset,
238                                                   GrGLsizeiptr length, GrGLbitfield access) {
239    State* state = State::Get();
240    GrGLuint id = 0;
241    switch (target) {
242        case GR_GL_ARRAY_BUFFER:
243            id = state->fCurrArrayBuffer;
244            break;
245        case GR_GL_ELEMENT_ARRAY_BUFFER:
246            id = state->fCurrElementArrayBuffer;
247            break;
248    }
249
250    if (id > 0) {
251        // We just ignore the offset and length here.
252        BufferObj* buffer = state->fBufferManager.lookUp(id);
253        SkASSERT(!buffer->mapped());
254        buffer->setMapped(true);
255        return buffer->dataPtr();
256    }
257    return NULL;
258}
259
260GrGLvoid* GR_GL_FUNCTION_TYPE nullGLMapBuffer(GrGLenum target, GrGLenum access) {
261    State* state = State::Get();
262    GrGLuint id = 0;
263    switch (target) {
264        case GR_GL_ARRAY_BUFFER:
265            id = state->fCurrArrayBuffer;
266            break;
267        case GR_GL_ELEMENT_ARRAY_BUFFER:
268            id = state->fCurrElementArrayBuffer;
269            break;
270    }
271
272    if (id > 0) {
273        BufferObj* buffer = state->fBufferManager.lookUp(id);
274        SkASSERT(!buffer->mapped());
275        buffer->setMapped(true);
276        return buffer->dataPtr();
277    }
278
279    SkASSERT(false);
280    return NULL;            // no buffer bound to target
281}
282
283GrGLvoid GR_GL_FUNCTION_TYPE nullGLFlushMappedBufferRange(GrGLenum target,
284                                                          GrGLintptr offset,
285                                                          GrGLsizeiptr length) {}
286
287
288GrGLboolean GR_GL_FUNCTION_TYPE nullGLUnmapBuffer(GrGLenum target) {
289    State* state = State::Get();
290    GrGLuint id = 0;
291    switch (target) {
292    case GR_GL_ARRAY_BUFFER:
293        id = state->fCurrArrayBuffer;
294        break;
295    case GR_GL_ELEMENT_ARRAY_BUFFER:
296        id = state->fCurrElementArrayBuffer;
297        break;
298    }
299    if (id > 0) {
300        BufferObj* buffer = state->fBufferManager.lookUp(id);
301        SkASSERT(buffer->mapped());
302        buffer->setMapped(false);
303        return GR_GL_TRUE;
304    }
305
306    GrAlwaysAssert(false);
307    return GR_GL_FALSE; // GR_GL_INVALID_OPERATION;
308}
309
310GrGLvoid GR_GL_FUNCTION_TYPE nullGLGetBufferParameteriv(GrGLenum target, GrGLenum pname, GrGLint* params) {
311    State* state = State::Get();
312    switch (pname) {
313        case GR_GL_BUFFER_MAPPED: {
314            *params = GR_GL_FALSE;
315            GrGLuint id = 0;
316            switch (target) {
317                case GR_GL_ARRAY_BUFFER:
318                    id = state->fCurrArrayBuffer;
319                    break;
320                case GR_GL_ELEMENT_ARRAY_BUFFER:
321                    id = state->fCurrElementArrayBuffer;
322                    break;
323            }
324            if (id > 0) {
325                BufferObj* buffer = state->fBufferManager.lookUp(id);
326                if (buffer->mapped()) {
327                    *params = GR_GL_TRUE;
328                }
329            }
330            break; }
331        default:
332            SkFAIL("Unexpected pname to GetBufferParamateriv");
333            break;
334    }
335};
336
337class NullInterface : public GrGLInterface {
338public:
339    NullInterface(State* state) : fState(SkRef(state)) {}
340    ~NullInterface() override {
341        fState->unref();
342    }
343    State* fState;
344};
345
346} // end anonymous namespace
347
348static GrGLInterface* create_null_interface(State* state) {
349    GrGLInterface* interface = SkNEW_ARGS(NullInterface, (state));
350
351    interface->fStandard = kGL_GrGLStandard;
352
353    GrGLInterface::Functions* functions = &interface->fFunctions;
354    functions->fActiveTexture = nullGLActiveTexture;
355    functions->fAttachShader = nullGLAttachShader;
356    functions->fBeginQuery = nullGLBeginQuery;
357    functions->fBindAttribLocation = nullGLBindAttribLocation;
358    functions->fBindBuffer = nullGLBindBuffer;
359    functions->fBindFragDataLocation = noOpGLBindFragDataLocation;
360    functions->fBindTexture = nullGLBindTexture;
361    functions->fBindVertexArray = nullGLBindVertexArray;
362    functions->fBlendColor = noOpGLBlendColor;
363    functions->fBlendEquation = noOpGLBlendEquation;
364    functions->fBlendFunc = noOpGLBlendFunc;
365    functions->fBufferData = nullGLBufferData;
366    functions->fBufferSubData = noOpGLBufferSubData;
367    functions->fClear = noOpGLClear;
368    functions->fClearColor = noOpGLClearColor;
369    functions->fClearStencil = noOpGLClearStencil;
370    functions->fColorMask = noOpGLColorMask;
371    functions->fCompileShader = noOpGLCompileShader;
372    functions->fCompressedTexImage2D = noOpGLCompressedTexImage2D;
373    functions->fCompressedTexSubImage2D = noOpGLCompressedTexSubImage2D;
374    functions->fCopyTexSubImage2D = noOpGLCopyTexSubImage2D;
375    functions->fCreateProgram = nullGLCreateProgram;
376    functions->fCreateShader = nullGLCreateShader;
377    functions->fCullFace = noOpGLCullFace;
378    functions->fDeleteBuffers = nullGLDeleteBuffers;
379    functions->fDeleteProgram = nullGLDelete;
380    functions->fDeleteQueries = noOpGLDeleteIds;
381    functions->fDeleteShader = nullGLDelete;
382    functions->fDeleteTextures = noOpGLDeleteIds;
383    functions->fDeleteVertexArrays = noOpGLDeleteIds;
384    functions->fDepthMask = noOpGLDepthMask;
385    functions->fDisable = noOpGLDisable;
386    functions->fDisableVertexAttribArray = noOpGLDisableVertexAttribArray;
387    functions->fDrawArrays = noOpGLDrawArrays;
388    functions->fDrawBuffer = noOpGLDrawBuffer;
389    functions->fDrawBuffers = noOpGLDrawBuffers;
390    functions->fDrawElements = noOpGLDrawElements;
391    functions->fEnable = noOpGLEnable;
392    functions->fEnableVertexAttribArray = noOpGLEnableVertexAttribArray;
393    functions->fEndQuery = noOpGLEndQuery;
394    functions->fFinish = noOpGLFinish;
395    functions->fFlush = noOpGLFlush;
396    functions->fFlushMappedBufferRange = nullGLFlushMappedBufferRange;
397    functions->fFrontFace = noOpGLFrontFace;
398    functions->fGenBuffers = nullGLGenBuffers;
399    functions->fGenerateMipmap = nullGLGenerateMipmap;
400    functions->fGenQueries = noOpGLGenIds;
401    functions->fGenTextures = noOpGLGenIds;
402    functions->fGenVertexArrays = noOpGLGenIds;
403    functions->fGetBufferParameteriv = nullGLGetBufferParameteriv;
404    functions->fGetError = noOpGLGetError;
405    functions->fGetIntegerv = noOpGLGetIntegerv;
406    functions->fGetQueryObjecti64v = noOpGLGetQueryObjecti64v;
407    functions->fGetQueryObjectiv = noOpGLGetQueryObjectiv;
408    functions->fGetQueryObjectui64v = noOpGLGetQueryObjectui64v;
409    functions->fGetQueryObjectuiv = noOpGLGetQueryObjectuiv;
410    functions->fGetQueryiv = noOpGLGetQueryiv;
411    functions->fGetProgramInfoLog = noOpGLGetInfoLog;
412    functions->fGetProgramiv = noOpGLGetShaderOrProgramiv;
413    functions->fGetShaderInfoLog = noOpGLGetInfoLog;
414    functions->fGetShaderiv = noOpGLGetShaderOrProgramiv;
415    functions->fGetString = noOpGLGetString;
416    functions->fGetStringi = noOpGLGetStringi;
417    functions->fGetTexLevelParameteriv = noOpGLGetTexLevelParameteriv;
418    functions->fGetUniformLocation = noOpGLGetUniformLocation;
419    functions->fInsertEventMarker = noOpGLInsertEventMarker;
420    functions->fLineWidth = noOpGLLineWidth;
421    functions->fLinkProgram = noOpGLLinkProgram;
422    functions->fMapBuffer = nullGLMapBuffer;
423    functions->fMapBufferRange = nullGLMapBufferRange;
424    functions->fPixelStorei = nullGLPixelStorei;
425    functions->fPopGroupMarker = noOpGLPopGroupMarker;
426    functions->fPushGroupMarker = noOpGLPushGroupMarker;
427    functions->fQueryCounter = noOpGLQueryCounter;
428    functions->fReadBuffer = noOpGLReadBuffer;
429    functions->fReadPixels = nullGLReadPixels;
430    functions->fScissor = noOpGLScissor;
431    functions->fShaderSource = noOpGLShaderSource;
432    functions->fStencilFunc = noOpGLStencilFunc;
433    functions->fStencilFuncSeparate = noOpGLStencilFuncSeparate;
434    functions->fStencilMask = noOpGLStencilMask;
435    functions->fStencilMaskSeparate = noOpGLStencilMaskSeparate;
436    functions->fStencilOp = noOpGLStencilOp;
437    functions->fStencilOpSeparate = noOpGLStencilOpSeparate;
438    functions->fTexImage2D = noOpGLTexImage2D;
439    functions->fTexParameteri = noOpGLTexParameteri;
440    functions->fTexParameteriv = noOpGLTexParameteriv;
441    functions->fTexSubImage2D = noOpGLTexSubImage2D;
442    functions->fTexStorage2D = noOpGLTexStorage2D;
443    functions->fDiscardFramebuffer = noOpGLDiscardFramebuffer;
444    functions->fUniform1f = noOpGLUniform1f;
445    functions->fUniform1i = noOpGLUniform1i;
446    functions->fUniform1fv = noOpGLUniform1fv;
447    functions->fUniform1iv = noOpGLUniform1iv;
448    functions->fUniform2f = noOpGLUniform2f;
449    functions->fUniform2i = noOpGLUniform2i;
450    functions->fUniform2fv = noOpGLUniform2fv;
451    functions->fUniform2iv = noOpGLUniform2iv;
452    functions->fUniform3f = noOpGLUniform3f;
453    functions->fUniform3i = noOpGLUniform3i;
454    functions->fUniform3fv = noOpGLUniform3fv;
455    functions->fUniform3iv = noOpGLUniform3iv;
456    functions->fUniform4f = noOpGLUniform4f;
457    functions->fUniform4i = noOpGLUniform4i;
458    functions->fUniform4fv = noOpGLUniform4fv;
459    functions->fUniform4iv = noOpGLUniform4iv;
460    functions->fUniformMatrix2fv = noOpGLUniformMatrix2fv;
461    functions->fUniformMatrix3fv = noOpGLUniformMatrix3fv;
462    functions->fUniformMatrix4fv = noOpGLUniformMatrix4fv;
463    functions->fUnmapBuffer = nullGLUnmapBuffer;
464    functions->fUseProgram = nullGLUseProgram;
465    functions->fVertexAttrib1f = noOpGLVertexAttrib1f;
466    functions->fVertexAttrib2fv = noOpGLVertexAttrib2fv;
467    functions->fVertexAttrib3fv = noOpGLVertexAttrib3fv;
468    functions->fVertexAttrib4fv = noOpGLVertexAttrib4fv;
469    functions->fVertexAttribPointer = noOpGLVertexAttribPointer;
470    functions->fViewport = nullGLViewport;
471    functions->fBindFramebuffer = nullGLBindFramebuffer;
472    functions->fBindRenderbuffer = nullGLBindRenderbuffer;
473    functions->fCheckFramebufferStatus = noOpGLCheckFramebufferStatus;
474    functions->fDeleteFramebuffers = nullGLDeleteFramebuffers;
475    functions->fDeleteRenderbuffers = nullGLDeleteRenderbuffers;
476    functions->fFramebufferRenderbuffer = nullGLFramebufferRenderbuffer;
477    functions->fFramebufferTexture2D = nullGLFramebufferTexture2D;
478    functions->fGenFramebuffers = noOpGLGenIds;
479    functions->fGenRenderbuffers = noOpGLGenIds;
480    functions->fGetFramebufferAttachmentParameteriv = noOpGLGetFramebufferAttachmentParameteriv;
481    functions->fGetRenderbufferParameteriv = noOpGLGetRenderbufferParameteriv;
482    functions->fRenderbufferStorage = noOpGLRenderbufferStorage;
483    functions->fRenderbufferStorageMultisample = noOpGLRenderbufferStorageMultisample;
484    functions->fBlitFramebuffer = noOpGLBlitFramebuffer;
485    functions->fResolveMultisampleFramebuffer = noOpGLResolveMultisampleFramebuffer;
486    functions->fMatrixLoadf = noOpGLMatrixLoadf;
487    functions->fMatrixLoadIdentity = noOpGLMatrixLoadIdentity;
488    functions->fBindFragDataLocationIndexed = noOpGLBindFragDataLocationIndexed;
489
490    interface->fExtensions.init(kGL_GrGLStandard, functions->fGetString, functions->fGetStringi,
491                                functions->fGetIntegerv);
492    return interface;
493}
494
495//////////////////////////////////////////////////////////////////////////////
496
497static void* create_tls() {
498    State** current = SkNEW(State*);
499    *current = NULL;
500    return current;
501}
502
503static void delete_tls(void* ctx) {
504    State** current = static_cast<State**>(ctx);
505    if (*current) {
506        (*current)->unref();
507    }
508    SkDELETE(current);
509}
510
511static State* current_context() {
512    return *static_cast<State**>(SkTLS::Get(create_tls, delete_tls));
513}
514
515static void set_current_context(State* state) {
516    State** current = static_cast<State**>(SkTLS::Get(create_tls, delete_tls));
517    if (*current) {
518        (*current)->unref();
519    }
520    *current = state;
521    if (state) {
522        state->ref();
523    }
524}
525
526#if GR_GL_PER_GL_FUNC_CALLBACK
527static void set_current_context_from_interface(const GrGLInterface* interface) {
528    set_current_context(reinterpret_cast<State*>(interface->fCallbackData));
529}
530#endif
531
532SkNullGLContext* SkNullGLContext::Create(GrGLStandard forcedGpuAPI) {
533    if (kGLES_GrGLStandard == forcedGpuAPI) {
534        return NULL;
535    }
536    SkNullGLContext* ctx = SkNEW(SkNullGLContext);
537    if (!ctx->isValid()) {
538        SkDELETE(ctx);
539        return NULL;
540    }
541    return ctx;
542}
543
544SkNullGLContext::SkNullGLContext() {
545    fState = SkNEW(ContextState);
546    GrGLInterface* interface = create_null_interface(fState);
547    fGL.reset(interface);
548#if GR_GL_PER_GL_FUNC_CALLBACK
549    interface->fCallback = set_current_context_from_interface;
550    interface->fCallbackData = reinterpret_cast<GrGLInterfaceCallbackData>(fState);
551#endif
552}
553
554SkNullGLContext::~SkNullGLContext() {
555    fGL.reset(NULL);
556    fState->unref();
557}
558
559void SkNullGLContext::makeCurrent() const { set_current_context(fState); }
560