Support multiple null GL contexts on a thread.

This has the side effect of requiring SkNullGLContext to use the null GL interface.

It exposes SkNullGLContext and also removes null context support from SampleApp.

Review URL: https://codereview.chromium.org/916733002
This commit is contained in:
bsalomon 2015-02-11 11:11:11 -08:00 committed by Commit bot
parent 0ea80f43a1
commit bb0502eec5
5 changed files with 534 additions and 37 deletions

View File

@ -370,11 +370,8 @@
'<(skia_src_path)/gpu/gl/debug/SkDebugGLContext.h',
],
'skgpu_null_gl_sources': [
'<(skia_src_path)/gpu/gl/GrGLCreateNullInterface.cpp',
# Sk files
'<(skia_src_path)/gpu/gl/SkNullGLContext.cpp',
'<(skia_src_path)/gpu/gl/SkNullGLContext.h',
'<(skia_include_path)/gpu/gl/SkNullGLContext.h',
],
},
}

View File

@ -13,23 +13,17 @@
class SK_API SkNullGLContext : public SkGLContext {
public:
~SkNullGLContext() SK_OVERRIDE;
void makeCurrent() const SK_OVERRIDE {};
void makeCurrent() const SK_OVERRIDE;
void swapBuffers() const SK_OVERRIDE {};
static SkNullGLContext* Create(GrGLStandard forcedGpuAPI) {
if (kGLES_GrGLStandard == forcedGpuAPI) {
return NULL;
}
SkNullGLContext* ctx = SkNEW(SkNullGLContext);
if (!ctx->isValid()) {
SkDELETE(ctx);
return NULL;
}
return ctx;
}
static SkNullGLContext* Create(GrGLStandard);
struct ContextState;
private:
SkNullGLContext();
ContextState* fState;
};
#endif

View File

@ -188,8 +188,6 @@ public:
case kPicture_DeviceType:
// fallthrough
case kGPU_DeviceType:
// fallthrough
case kNullGPU_DeviceType:
// all these guys use the native backend
fBackend = kNativeGL_BackEndType;
break;
@ -227,9 +225,6 @@ public:
glInterface.reset(GrGLCreateANGLEInterface());
break;
#endif // SK_ANGLE
case kNullGPU_DeviceType:
glInterface.reset(GrGLCreateNullInterface());
break;
default:
SkASSERT(false);
break;
@ -680,7 +675,6 @@ static inline SampleWindow::DeviceType cycle_devicetype(SampleWindow::DeviceType
#if SK_ANGLE
SampleWindow::kANGLE_DeviceType,
#endif // SK_ANGLE
SampleWindow::kRaster_DeviceType, // skip the null gpu device in normal cycling
#endif // SK_SUPPORT_GPU
SampleWindow::kRaster_DeviceType
};
@ -1258,12 +1252,7 @@ SkCanvas* SampleWindow::beforeChildren(SkCanvas* canvas) {
} else if (kPicture_DeviceType == fDeviceType) {
canvas = fRecorder.beginRecording(9999, 9999, NULL, 0);
} else {
#if SK_SUPPORT_GPU
if (kNullGPU_DeviceType != fDeviceType)
#endif
{
canvas = this->INHERITED::beforeChildren(canvas);
}
canvas = this->INHERITED::beforeChildren(canvas);
}
if (fUseClip) {
@ -1724,11 +1713,6 @@ bool SampleWindow::onHandleChar(SkUnichar uni) {
this->updateTitle();
return true;
#if SK_SUPPORT_GPU
case '\\':
this->setDeviceType(kNullGPU_DeviceType);
this->inval(NULL);
this->updateTitle();
return true;
case 'p':
{
GrContext* grContext = this->getGrContext();
@ -1961,7 +1945,6 @@ static const char* gDeviceTypePrefix[] = {
#if SK_ANGLE
"angle: ",
#endif // SK_ANGLE
"null-gl: "
#endif // SK_SUPPORT_GPU
};
SK_COMPILE_ASSERT(SK_ARRAY_COUNT(gDeviceTypePrefix) == SampleWindow::kDeviceTypeCnt,

View File

@ -38,7 +38,6 @@ public:
#if SK_ANGLE
kANGLE_DeviceType,
#endif // SK_ANGLE
kNullGPU_DeviceType,
#endif // SK_SUPPORT_GPU
kDeviceTypeCnt
@ -51,7 +50,6 @@ public:
#if SK_ANGLE
case kANGLE_DeviceType:
#endif // SK_ANGLE
case kNullGPU_DeviceType:
return true;
default:
return false;

View File

@ -7,12 +7,537 @@
*/
#include "gl/SkNullGLContext.h"
#include "gl/GrGLInterface.h"
#include "GrGLDefines.h"
#include "GrGLNoOpInterface.h"
#include "SkTDArray.h"
#include "SkTLS.h"
static const SkNullGLContext* current_context();
/////////////////////////////////////////////////////////////////////////////////////////////////
class BufferObj {
public:
SK_DECLARE_INST_COUNT(BufferObj);
BufferObj(GrGLuint id) : fID(id), fDataPtr(NULL), fSize(0), fMapped(false) {}
~BufferObj() { SkDELETE_ARRAY(fDataPtr); }
void allocate(GrGLsizeiptr size, const GrGLchar* dataPtr) {
if (fDataPtr) {
SkASSERT(0 != fSize);
SkDELETE_ARRAY(fDataPtr);
}
fSize = size;
fDataPtr = SkNEW_ARRAY(char, size);
}
GrGLuint id() const { return fID; }
GrGLchar* dataPtr() { return fDataPtr; }
GrGLsizeiptr size() const { return fSize; }
void setMapped(bool mapped) { fMapped = mapped; }
bool mapped() const { return fMapped; }
private:
GrGLuint fID;
GrGLchar* fDataPtr;
GrGLsizeiptr fSize; // size in bytes
bool fMapped;
};
// This class maintains a sparsely populated array of buffer pointers.
class BufferManager {
public:
SK_DECLARE_INST_COUNT(BufferManager);
BufferManager() : fFreeListHead(kFreeListEnd) {}
~BufferManager() {
// NULL out the entries that are really free list links rather than ptrs before deleting.
intptr_t curr = fFreeListHead;
while (kFreeListEnd != curr) {
intptr_t next = reinterpret_cast<intptr_t>(fBuffers[SkToS32(curr)]);
fBuffers[SkToS32(curr)] = NULL;
curr = next;
}
fBuffers.deleteAll();
}
BufferObj* lookUp(GrGLuint id) {
BufferObj* buffer = fBuffers[id];
SkASSERT(buffer && buffer->id() == id);
return buffer;
}
BufferObj* create() {
GrGLuint id;
BufferObj* buffer;
if (kFreeListEnd == fFreeListHead) {
// no free slots - create a new one
id = fBuffers.count();
buffer = SkNEW_ARGS(BufferObj, (id));
*fBuffers.append() = buffer;
} else {
// grab the head of the free list and advance the head to the next free slot.
id = static_cast<GrGLuint>(fFreeListHead);
fFreeListHead = reinterpret_cast<intptr_t>(fBuffers[id]);
buffer = SkNEW_ARGS(BufferObj, (id));
fBuffers[id] = buffer;
}
return buffer;
}
void free(BufferObj* buffer) {
SkASSERT(fBuffers.count() > 0);
GrGLuint id = buffer->id();
SkDELETE(buffer);
fBuffers[id] = reinterpret_cast<BufferObj*>(fFreeListHead);
fFreeListHead = id;
}
private:
static const intptr_t kFreeListEnd = -1;
// Index of the first entry of fBuffers in the free list. Free slots in fBuffers are indices to
// the next free slot. The last free slot has a value of kFreeListEnd.
intptr_t fFreeListHead;
SkTDArray<BufferObj*> fBuffers;
};
/**
* The state object for the null interface.
*/
struct SkNullGLContext::ContextState {
public:
SK_DECLARE_INST_COUNT(ContextState);
BufferManager fBufferManager;
GrGLuint fCurrArrayBuffer;
GrGLuint fCurrElementArrayBuffer;
GrGLuint fCurrProgramID;
GrGLuint fCurrShaderID;
ContextState()
: fCurrArrayBuffer(0)
, fCurrElementArrayBuffer(0)
, fCurrProgramID(0)
, fCurrShaderID(0) {}
static ContextState* Get() {
const SkNullGLContext* context = current_context();
SkASSERT(context);
return context->fState;
}
};
typedef SkNullGLContext::ContextState State;
// Functions not declared in GrGLBogusInterface.h (not common with the Debug GL interface).
namespace { // added to suppress 'no previous prototype' warning
GrGLvoid GR_GL_FUNCTION_TYPE nullGLActiveTexture(GrGLenum texture) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLAttachShader(GrGLuint program, GrGLuint shader) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLBeginQuery(GrGLenum target, GrGLuint id) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindAttribLocation(GrGLuint program, GrGLuint index, const char* name) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindTexture(GrGLenum target, GrGLuint texture) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindVertexArray(GrGLuint id) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLGenBuffers(GrGLsizei n, GrGLuint* ids) {
State* state = State::Get();
for (int i = 0; i < n; ++i) {
BufferObj* buffer = state->fBufferManager.create();
ids[i] = buffer->id();
}
}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLGenerateMipmap(GrGLenum target) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLBufferData(GrGLenum target,
GrGLsizeiptr size,
const GrGLvoid* data,
GrGLenum usage) {
State* state = State::Get();
GrGLuint id = 0;
switch (target) {
case GR_GL_ARRAY_BUFFER:
id = state->fCurrArrayBuffer;
break;
case GR_GL_ELEMENT_ARRAY_BUFFER:
id = state->fCurrElementArrayBuffer;
break;
default:
SkFAIL("Unexpected target to nullGLBufferData");
break;
}
if (id > 0) {
BufferObj* buffer = state->fBufferManager.lookUp(id);
buffer->allocate(size, (const GrGLchar*) data);
}
}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLPixelStorei(GrGLenum pname, GrGLint param) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLReadPixels(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height, GrGLenum format, GrGLenum type, GrGLvoid* pixels) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLUseProgram(GrGLuint program) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLViewport(GrGLint x, GrGLint y, GrGLsizei width, GrGLsizei height) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindFramebuffer(GrGLenum target, GrGLuint framebuffer) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindRenderbuffer(GrGLenum target, GrGLuint renderbuffer) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLDeleteFramebuffers(GrGLsizei n, const GrGLuint *framebuffers) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLDeleteRenderbuffers(GrGLsizei n, const GrGLuint *renderbuffers) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLFramebufferRenderbuffer(GrGLenum target, GrGLenum attachment, GrGLenum renderbuffertarget, GrGLuint renderbuffer) {}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLFramebufferTexture2D(GrGLenum target, GrGLenum attachment, GrGLenum textarget, GrGLuint texture, GrGLint level) {}
GrGLuint GR_GL_FUNCTION_TYPE nullGLCreateProgram() {
return ++State::Get()->fCurrProgramID;
}
GrGLuint GR_GL_FUNCTION_TYPE nullGLCreateShader(GrGLenum type) {
return ++State::Get()->fCurrShaderID;
}
// same delete used for shaders and programs
GrGLvoid GR_GL_FUNCTION_TYPE nullGLDelete(GrGLuint program) {
}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLBindBuffer(GrGLenum target, GrGLuint buffer) {
State* state = State::Get();
switch (target) {
case GR_GL_ARRAY_BUFFER:
state->fCurrArrayBuffer = buffer;
break;
case GR_GL_ELEMENT_ARRAY_BUFFER:
state->fCurrElementArrayBuffer = buffer;
break;
}
}
// deleting a bound buffer has the side effect of binding 0
GrGLvoid GR_GL_FUNCTION_TYPE nullGLDeleteBuffers(GrGLsizei n, const GrGLuint* ids) {
State* state = State::Get();
for (int i = 0; i < n; ++i) {
if (ids[i] == state->fCurrArrayBuffer) {
state->fCurrArrayBuffer = 0;
}
if (ids[i] == state->fCurrElementArrayBuffer) {
state->fCurrElementArrayBuffer = 0;
}
BufferObj* buffer = state->fBufferManager.lookUp(ids[i]);
state->fBufferManager.free(buffer);
}
}
GrGLvoid* GR_GL_FUNCTION_TYPE nullGLMapBufferRange(GrGLenum target, GrGLintptr offset,
GrGLsizeiptr length, GrGLbitfield access) {
State* state = State::Get();
GrGLuint id = 0;
switch (target) {
case GR_GL_ARRAY_BUFFER:
id = state->fCurrArrayBuffer;
break;
case GR_GL_ELEMENT_ARRAY_BUFFER:
id = state->fCurrElementArrayBuffer;
break;
}
if (id > 0) {
// We just ignore the offset and length here.
BufferObj* buffer = state->fBufferManager.lookUp(id);
SkASSERT(!buffer->mapped());
buffer->setMapped(true);
return buffer->dataPtr();
}
return NULL;
}
GrGLvoid* GR_GL_FUNCTION_TYPE nullGLMapBuffer(GrGLenum target, GrGLenum access) {
State* state = State::Get();
GrGLuint id = 0;
switch (target) {
case GR_GL_ARRAY_BUFFER:
id = state->fCurrArrayBuffer;
break;
case GR_GL_ELEMENT_ARRAY_BUFFER:
id = state->fCurrElementArrayBuffer;
break;
}
if (id > 0) {
BufferObj* buffer = state->fBufferManager.lookUp(id);
SkASSERT(!buffer->mapped());
buffer->setMapped(true);
return buffer->dataPtr();
}
SkASSERT(false);
return NULL; // no buffer bound to target
}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLFlushMappedBufferRange(GrGLenum target,
GrGLintptr offset,
GrGLsizeiptr length) {}
GrGLboolean GR_GL_FUNCTION_TYPE nullGLUnmapBuffer(GrGLenum target) {
State* state = State::Get();
GrGLuint id = 0;
switch (target) {
case GR_GL_ARRAY_BUFFER:
id = state->fCurrArrayBuffer;
break;
case GR_GL_ELEMENT_ARRAY_BUFFER:
id = state->fCurrElementArrayBuffer;
break;
}
if (id > 0) {
BufferObj* buffer = state->fBufferManager.lookUp(id);
SkASSERT(buffer->mapped());
buffer->setMapped(false);
return GR_GL_TRUE;
}
GrAlwaysAssert(false);
return GR_GL_FALSE; // GR_GL_INVALID_OPERATION;
}
GrGLvoid GR_GL_FUNCTION_TYPE nullGLGetBufferParameteriv(GrGLenum target, GrGLenum pname, GrGLint* params) {
State* state = State::Get();
switch (pname) {
case GR_GL_BUFFER_MAPPED: {
*params = GR_GL_FALSE;
GrGLuint id = 0;
switch (target) {
case GR_GL_ARRAY_BUFFER:
id = state->fCurrArrayBuffer;
break;
case GR_GL_ELEMENT_ARRAY_BUFFER:
id = state->fCurrElementArrayBuffer;
break;
}
if (id > 0) {
BufferObj* buffer = state->fBufferManager.lookUp(id);
if (buffer->mapped()) {
*params = GR_GL_TRUE;
}
}
break; }
default:
SkFAIL("Unexpected pname to GetBufferParamateriv");
break;
}
};
} // end anonymous namespace
static const GrGLInterface* create_null_interface() {
GrGLInterface* interface = SkNEW(GrGLInterface);
interface->fStandard = kGL_GrGLStandard;
GrGLInterface::Functions* functions = &interface->fFunctions;
functions->fActiveTexture = nullGLActiveTexture;
functions->fAttachShader = nullGLAttachShader;
functions->fBeginQuery = nullGLBeginQuery;
functions->fBindAttribLocation = nullGLBindAttribLocation;
functions->fBindBuffer = nullGLBindBuffer;
functions->fBindFragDataLocation = noOpGLBindFragDataLocation;
functions->fBindTexture = nullGLBindTexture;
functions->fBindVertexArray = nullGLBindVertexArray;
functions->fBlendColor = noOpGLBlendColor;
functions->fBlendFunc = noOpGLBlendFunc;
functions->fBufferData = nullGLBufferData;
functions->fBufferSubData = noOpGLBufferSubData;
functions->fClear = noOpGLClear;
functions->fClearColor = noOpGLClearColor;
functions->fClearStencil = noOpGLClearStencil;
functions->fColorMask = noOpGLColorMask;
functions->fCompileShader = noOpGLCompileShader;
functions->fCompressedTexImage2D = noOpGLCompressedTexImage2D;
functions->fCompressedTexSubImage2D = noOpGLCompressedTexSubImage2D;
functions->fCopyTexSubImage2D = noOpGLCopyTexSubImage2D;
functions->fCreateProgram = nullGLCreateProgram;
functions->fCreateShader = nullGLCreateShader;
functions->fCullFace = noOpGLCullFace;
functions->fDeleteBuffers = nullGLDeleteBuffers;
functions->fDeleteProgram = nullGLDelete;
functions->fDeleteQueries = noOpGLDeleteIds;
functions->fDeleteShader = nullGLDelete;
functions->fDeleteTextures = noOpGLDeleteIds;
functions->fDeleteVertexArrays = noOpGLDeleteIds;
functions->fDepthMask = noOpGLDepthMask;
functions->fDisable = noOpGLDisable;
functions->fDisableVertexAttribArray = noOpGLDisableVertexAttribArray;
functions->fDrawArrays = noOpGLDrawArrays;
functions->fDrawBuffer = noOpGLDrawBuffer;
functions->fDrawBuffers = noOpGLDrawBuffers;
functions->fDrawElements = noOpGLDrawElements;
functions->fEnable = noOpGLEnable;
functions->fEnableVertexAttribArray = noOpGLEnableVertexAttribArray;
functions->fEndQuery = noOpGLEndQuery;
functions->fFinish = noOpGLFinish;
functions->fFlush = noOpGLFlush;
functions->fFlushMappedBufferRange = nullGLFlushMappedBufferRange;
functions->fFrontFace = noOpGLFrontFace;
functions->fGenBuffers = nullGLGenBuffers;
functions->fGenerateMipmap = nullGLGenerateMipmap;
functions->fGenQueries = noOpGLGenIds;
functions->fGenTextures = noOpGLGenIds;
functions->fGenVertexArrays = noOpGLGenIds;
functions->fGetBufferParameteriv = nullGLGetBufferParameteriv;
functions->fGetError = noOpGLGetError;
functions->fGetIntegerv = noOpGLGetIntegerv;
functions->fGetQueryObjecti64v = noOpGLGetQueryObjecti64v;
functions->fGetQueryObjectiv = noOpGLGetQueryObjectiv;
functions->fGetQueryObjectui64v = noOpGLGetQueryObjectui64v;
functions->fGetQueryObjectuiv = noOpGLGetQueryObjectuiv;
functions->fGetQueryiv = noOpGLGetQueryiv;
functions->fGetProgramInfoLog = noOpGLGetInfoLog;
functions->fGetProgramiv = noOpGLGetShaderOrProgramiv;
functions->fGetShaderInfoLog = noOpGLGetInfoLog;
functions->fGetShaderiv = noOpGLGetShaderOrProgramiv;
functions->fGetString = noOpGLGetString;
functions->fGetStringi = noOpGLGetStringi;
functions->fGetTexLevelParameteriv = noOpGLGetTexLevelParameteriv;
functions->fGetUniformLocation = noOpGLGetUniformLocation;
functions->fInsertEventMarker = noOpGLInsertEventMarker;
functions->fLineWidth = noOpGLLineWidth;
functions->fLinkProgram = noOpGLLinkProgram;
functions->fMapBuffer = nullGLMapBuffer;
functions->fMapBufferRange = nullGLMapBufferRange;
functions->fPixelStorei = nullGLPixelStorei;
functions->fPopGroupMarker = noOpGLPopGroupMarker;
functions->fPushGroupMarker = noOpGLPushGroupMarker;
functions->fQueryCounter = noOpGLQueryCounter;
functions->fReadBuffer = noOpGLReadBuffer;
functions->fReadPixels = nullGLReadPixels;
functions->fScissor = noOpGLScissor;
functions->fShaderSource = noOpGLShaderSource;
functions->fStencilFunc = noOpGLStencilFunc;
functions->fStencilFuncSeparate = noOpGLStencilFuncSeparate;
functions->fStencilMask = noOpGLStencilMask;
functions->fStencilMaskSeparate = noOpGLStencilMaskSeparate;
functions->fStencilOp = noOpGLStencilOp;
functions->fStencilOpSeparate = noOpGLStencilOpSeparate;
functions->fTexImage2D = noOpGLTexImage2D;
functions->fTexParameteri = noOpGLTexParameteri;
functions->fTexParameteriv = noOpGLTexParameteriv;
functions->fTexSubImage2D = noOpGLTexSubImage2D;
functions->fTexStorage2D = noOpGLTexStorage2D;
functions->fDiscardFramebuffer = noOpGLDiscardFramebuffer;
functions->fUniform1f = noOpGLUniform1f;
functions->fUniform1i = noOpGLUniform1i;
functions->fUniform1fv = noOpGLUniform1fv;
functions->fUniform1iv = noOpGLUniform1iv;
functions->fUniform2f = noOpGLUniform2f;
functions->fUniform2i = noOpGLUniform2i;
functions->fUniform2fv = noOpGLUniform2fv;
functions->fUniform2iv = noOpGLUniform2iv;
functions->fUniform3f = noOpGLUniform3f;
functions->fUniform3i = noOpGLUniform3i;
functions->fUniform3fv = noOpGLUniform3fv;
functions->fUniform3iv = noOpGLUniform3iv;
functions->fUniform4f = noOpGLUniform4f;
functions->fUniform4i = noOpGLUniform4i;
functions->fUniform4fv = noOpGLUniform4fv;
functions->fUniform4iv = noOpGLUniform4iv;
functions->fUniformMatrix2fv = noOpGLUniformMatrix2fv;
functions->fUniformMatrix3fv = noOpGLUniformMatrix3fv;
functions->fUniformMatrix4fv = noOpGLUniformMatrix4fv;
functions->fUnmapBuffer = nullGLUnmapBuffer;
functions->fUseProgram = nullGLUseProgram;
functions->fVertexAttrib1f = noOpGLVertexAttrib1f;
functions->fVertexAttrib2fv = noOpGLVertexAttrib2fv;
functions->fVertexAttrib3fv = noOpGLVertexAttrib3fv;
functions->fVertexAttrib4fv = noOpGLVertexAttrib4fv;
functions->fVertexAttribPointer = noOpGLVertexAttribPointer;
functions->fViewport = nullGLViewport;
functions->fBindFramebuffer = nullGLBindFramebuffer;
functions->fBindRenderbuffer = nullGLBindRenderbuffer;
functions->fCheckFramebufferStatus = noOpGLCheckFramebufferStatus;
functions->fDeleteFramebuffers = nullGLDeleteFramebuffers;
functions->fDeleteRenderbuffers = nullGLDeleteRenderbuffers;
functions->fFramebufferRenderbuffer = nullGLFramebufferRenderbuffer;
functions->fFramebufferTexture2D = nullGLFramebufferTexture2D;
functions->fGenFramebuffers = noOpGLGenIds;
functions->fGenRenderbuffers = noOpGLGenIds;
functions->fGetFramebufferAttachmentParameteriv = noOpGLGetFramebufferAttachmentParameteriv;
functions->fGetRenderbufferParameteriv = noOpGLGetRenderbufferParameteriv;
functions->fRenderbufferStorage = noOpGLRenderbufferStorage;
functions->fRenderbufferStorageMultisample = noOpGLRenderbufferStorageMultisample;
functions->fBlitFramebuffer = noOpGLBlitFramebuffer;
functions->fResolveMultisampleFramebuffer = noOpGLResolveMultisampleFramebuffer;
functions->fMatrixLoadf = noOpGLMatrixLoadf;
functions->fMatrixLoadIdentity = noOpGLMatrixLoadIdentity;
functions->fBindFragDataLocationIndexed = noOpGLBindFragDataLocationIndexed;
interface->fExtensions.init(kGL_GrGLStandard, functions->fGetString, functions->fGetStringi,
functions->fGetIntegerv);
return interface;
}
//////////////////////////////////////////////////////////////////////////////
static void* create_tls() {
const SkNullGLContext** current = SkNEW(const SkNullGLContext*);
*current = NULL;
return current;
}
static void delete_tls(void* ctx) {
const SkNullGLContext** current = static_cast<const SkNullGLContext**>(ctx);
if (*current) {
(*current)->unref();
}
SkDELETE(current);
}
static const SkNullGLContext* current_context() {
return *static_cast<const SkNullGLContext**>(SkTLS::Get(create_tls, delete_tls));
}
static void set_current_context(const SkNullGLContext* context) {
const SkNullGLContext** current =
static_cast<const SkNullGLContext**>(SkTLS::Get(create_tls, delete_tls));
if (*current) {
(*current)->unref();
}
*current = context;
if (context) {
context->ref();
}
}
SkNullGLContext* SkNullGLContext::Create(GrGLStandard forcedGpuAPI) {
if (kGLES_GrGLStandard == forcedGpuAPI) {
return NULL;
}
SkNullGLContext* ctx = SkNEW(SkNullGLContext);
if (!ctx->isValid()) {
SkDELETE(ctx);
return NULL;
}
return ctx;
}
SkNullGLContext::SkNullGLContext() {
fGL.reset(GrGLCreateNullInterface());
fGL.reset(create_null_interface());
fState = SkNEW(ContextState);
}
SkNullGLContext::~SkNullGLContext() {
fGL.reset(NULL);
SkDELETE(fState);
}
void SkNullGLContext::makeCurrent() const { set_current_context(this); }