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