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