Home | History | Annotate | Download | only in gl
      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 #include "GrGLTestInterface.h"
      9 #include "GrNonAtomicRef.h"
     10 #include "SkMutex.h"
     11 #include "SkTDArray.h"
     12 #include "SkTo.h"
     13 #include "gl/GrGLInterface.h"
     14 
     15 #include <type_traits>
     16 
     17 // added to suppress 'no previous prototype' warning and because this code is duplicated in
     18 // SkNullGLContext.cpp
     19 namespace {
     20 
     21 class GLObject : public GrNonAtomicRef<GLObject> {
     22 public:
     23     GLObject(GrGLuint id) : fID(id) {}
     24     virtual ~GLObject() {}
     25 
     26     GrGLuint id() const { return fID; }
     27 
     28 private:
     29     GrGLuint fID;
     30 };
     31 
     32 // This class maintains a sparsely populated array of object pointers.
     33 template<typename T> class TGLObjectManager {
     34    static_assert(std::is_convertible<T*, GLObject*>::value, "T must be a subclass of GLObject");
     35 
     36 public:
     37     TGLObjectManager() : fFreeListHead(kFreeListEnd) {
     38         *fGLObjects.append() = nullptr; // 0 is not a valid GL object id.
     39     }
     40 
     41     ~TGLObjectManager() {
     42         // nullptr out the entries that are really free list links rather than ptrs before deleting.
     43         intptr_t curr = fFreeListHead;
     44         while (kFreeListEnd != curr) {
     45             intptr_t next = reinterpret_cast<intptr_t>(fGLObjects[SkToS32(curr)]);
     46             fGLObjects[SkToS32(curr)] = nullptr;
     47             curr = next;
     48         }
     49 
     50         fGLObjects.safeUnrefAll();
     51     }
     52 
     53     T* lookUp(GrGLuint id) {
     54         T* object = fGLObjects[id];
     55         SkASSERT(object && object->id() == id);
     56         return object;
     57     }
     58 
     59     T* create() {
     60         GrGLuint id;
     61         T* object;
     62 
     63         if (kFreeListEnd == fFreeListHead) {
     64             // no free slots - create a new one
     65             id = fGLObjects.count();
     66             object = new T(id);
     67             *fGLObjects.append() = object;
     68         } else {
     69             // grab the head of the free list and advance the head to the next free slot.
     70             id = static_cast<GrGLuint>(fFreeListHead);
     71             fFreeListHead = reinterpret_cast<intptr_t>(fGLObjects[id]);
     72 
     73             object = new T(id);
     74             fGLObjects[id] = object;
     75         }
     76 
     77         return object;
     78     }
     79 
     80     void free(T* object) {
     81         SkASSERT(object);
     82         SkASSERT(fGLObjects.count() > 0);
     83 
     84         GrGLuint id = object->id();
     85         object->unref();
     86 
     87         fGLObjects[id] = reinterpret_cast<T*>(fFreeListHead);
     88         fFreeListHead = id;
     89     }
     90 
     91 private:
     92     static const intptr_t kFreeListEnd = -1;
     93     // Index of the first entry of fGLObjects in the free list. Free slots in fGLObjects are indices
     94     // to the next free slot. The last free slot has a value of kFreeListEnd.
     95     intptr_t        fFreeListHead;
     96     SkTDArray<T*>   fGLObjects;
     97 };
     98 
     99 class Buffer : public GLObject {
    100 public:
    101     Buffer(GrGLuint id) : INHERITED(id), fDataPtr(nullptr), fSize(0), fMapped(false) {}
    102     ~Buffer() { delete[] fDataPtr; }
    103 
    104     void allocate(GrGLsizeiptr size, const GrGLchar* dataPtr) {
    105         if (fDataPtr) {
    106             SkASSERT(0 != fSize);
    107             delete[] fDataPtr;
    108         }
    109 
    110         fSize = size;
    111         fDataPtr = new char[size];
    112     }
    113 
    114     GrGLchar* dataPtr()          { return fDataPtr; }
    115     GrGLsizeiptr size() const    { return fSize; }
    116 
    117     void setMapped(bool mapped)  { fMapped = mapped; }
    118     bool mapped() const          { return fMapped; }
    119 
    120 private:
    121     GrGLchar*    fDataPtr;
    122     GrGLsizeiptr fSize;         // size in bytes
    123     bool         fMapped;
    124 
    125     typedef GLObject INHERITED;
    126 };
    127 
    128 class FramebufferAttachment : public GLObject {
    129 public:
    130     int numSamples() const { return fNumSamples; }
    131 
    132 protected:
    133     FramebufferAttachment(int id) : INHERITED(id), fNumSamples(1) {}
    134 
    135     int fNumSamples;
    136 
    137     typedef GLObject INHERITED;
    138 };
    139 
    140 class Renderbuffer : public FramebufferAttachment {
    141 public:
    142     Renderbuffer(int id) : INHERITED(id) {}
    143     void setNumSamples(int numSamples) { fNumSamples = numSamples; }
    144 
    145 private:
    146     typedef FramebufferAttachment INHERITED;
    147 };
    148 
    149 class Texture : public FramebufferAttachment {
    150 public:
    151     Texture() : INHERITED(1) {}
    152 
    153 private:
    154     typedef FramebufferAttachment INHERITED;
    155 };
    156 
    157 class Framebuffer : public GLObject {
    158 public:
    159     Framebuffer(int id) : INHERITED(id) {}
    160 
    161     void setAttachment(GrGLenum attachmentPoint, const FramebufferAttachment* attachment) {
    162         switch (attachmentPoint) {
    163             default:
    164                 SK_ABORT("Invalid framebuffer attachment.");
    165                 break;
    166             case GR_GL_STENCIL_ATTACHMENT:
    167                 fAttachments[(int)AttachmentPoint::kStencil].reset(SkRef(attachment));
    168                 break;
    169             case GR_GL_DEPTH_ATTACHMENT:
    170                 fAttachments[(int)AttachmentPoint::kDepth].reset(SkRef(attachment));
    171                 break;
    172             case GR_GL_COLOR_ATTACHMENT0:
    173                 fAttachments[(int)AttachmentPoint::kColor].reset(SkRef(attachment));
    174                 break;
    175         }
    176     }
    177 
    178     void notifyAttachmentDeleteWhileBound(const FramebufferAttachment* deleted) {
    179         for (auto& attachment : fAttachments) {
    180             if (attachment.get() == deleted) {
    181                 attachment.reset(nullptr);
    182             }
    183         }
    184     }
    185 
    186     int numSamples() const {
    187         int numSamples = 0;
    188         for (auto& attachment : fAttachments) {
    189             if (!attachment) {
    190                 continue;
    191             }
    192             if (numSamples) {
    193                 GrAlwaysAssert(attachment->numSamples() == numSamples);
    194                 continue;
    195             }
    196             numSamples = attachment->numSamples();
    197         }
    198         GrAlwaysAssert(numSamples);
    199         return numSamples;
    200     }
    201 
    202 private:
    203     enum AttachmentPoint {
    204         kStencil,
    205         kDepth,
    206         kColor
    207     };
    208     constexpr int static kNumAttachmentPoints = 1 + (int)AttachmentPoint::kColor;
    209 
    210     sk_sp<const FramebufferAttachment> fAttachments[kNumAttachmentPoints];
    211 
    212     typedef GLObject INHERITED;
    213 };
    214 
    215 /** Null interface implementation */
    216 class NullInterface : public GrGLTestInterface {
    217 public:
    218     NullInterface(bool enableNVPR)
    219         : fCurrDrawFramebuffer(0)
    220         , fCurrReadFramebuffer(0)
    221         , fCurrRenderbuffer(0)
    222         , fCurrProgramID(0)
    223         , fCurrShaderID(0)
    224         , fCurrGenericID(0)
    225         , fCurrUniformLocation(0)
    226         , fCurrPathID(0) {
    227         memset(fBoundBuffers, 0, sizeof(fBoundBuffers));
    228         fAdvertisedExtensions.push_back("GL_ARB_framebuffer_object");
    229         fAdvertisedExtensions.push_back("GL_ARB_blend_func_extended");
    230         fAdvertisedExtensions.push_back("GL_ARB_timer_query");
    231         fAdvertisedExtensions.push_back("GL_ARB_draw_buffers");
    232         fAdvertisedExtensions.push_back("GL_ARB_occlusion_query");
    233         fAdvertisedExtensions.push_back("GL_EXT_stencil_wrap");
    234         if (enableNVPR) {
    235             fAdvertisedExtensions.push_back("GL_NV_path_rendering");
    236             fAdvertisedExtensions.push_back("GL_ARB_program_interface_query");
    237         }
    238         fAdvertisedExtensions.push_back(nullptr);
    239 
    240         this->init(kGL_GrGLStandard);
    241     }
    242 
    243     GrGLenum checkFramebufferStatus(GrGLenum target) override {
    244         return GR_GL_FRAMEBUFFER_COMPLETE;
    245     }
    246 
    247     GrGLvoid genBuffers(GrGLsizei n, GrGLuint* ids) override {
    248         for (int i = 0; i < n; ++i) {
    249             Buffer* buffer = fBufferManager.create();
    250             ids[i] = buffer->id();
    251         }
    252     }
    253 
    254     GrGLvoid bufferData(GrGLenum target, GrGLsizeiptr size, const GrGLvoid* data,
    255                         GrGLenum usage) override {
    256         GrGLuint id = fBoundBuffers[GetBufferIndex(target)];
    257         if (id > 0) {
    258             Buffer* buffer = fBufferManager.lookUp(id);
    259             buffer->allocate(size, (const GrGLchar*) data);
    260         }
    261     }
    262 
    263     GrGLuint createProgram() override {
    264         return ++fCurrProgramID;
    265     }
    266 
    267     GrGLuint createShader(GrGLenum type) override {
    268         return ++fCurrShaderID;
    269     }
    270 
    271     GrGLvoid bindBuffer(GrGLenum target, GrGLuint buffer) override {
    272         fBoundBuffers[GetBufferIndex(target)] = buffer;
    273     }
    274 
    275    // deleting a bound buffer has the side effect of binding 0
    276    GrGLvoid deleteBuffers(GrGLsizei n, const GrGLuint* ids) override {
    277         // First potentially unbind the buffers.
    278         for (int buffIdx = 0; buffIdx < kNumBufferTargets; ++buffIdx) {
    279             if (!fBoundBuffers[buffIdx]) {
    280                 continue;
    281             }
    282             for (int i = 0; i < n; ++i) {
    283                 if (ids[i] == fBoundBuffers[buffIdx]) {
    284                     fBoundBuffers[buffIdx] = 0;
    285                     break;
    286                 }
    287             }
    288         }
    289 
    290         // Then actually "delete" the buffers.
    291         for (int i = 0; i < n; ++i) {
    292             if (ids[i] > 0) {
    293                 Buffer* buffer = fBufferManager.lookUp(ids[i]);
    294                 fBufferManager.free(buffer);
    295             }
    296         }
    297     }
    298 
    299     GrGLvoid genFramebuffers(GrGLsizei n, GrGLuint *framebuffers) override {
    300         for (int i = 0; i < n; ++i) {
    301             Framebuffer* framebuffer = fFramebufferManager.create();
    302             framebuffers[i] = framebuffer->id();
    303         }
    304     }
    305 
    306     GrGLvoid bindFramebuffer(GrGLenum target, GrGLuint framebuffer) override {
    307         SkASSERT(GR_GL_FRAMEBUFFER == target || GR_GL_DRAW_FRAMEBUFFER == target ||
    308                  GR_GL_READ_FRAMEBUFFER == target);
    309         if (GR_GL_READ_FRAMEBUFFER != target) {
    310             fCurrDrawFramebuffer = framebuffer;
    311         }
    312         if (GR_GL_DRAW_FRAMEBUFFER != target) {
    313             fCurrReadFramebuffer = framebuffer;
    314         }
    315     }
    316 
    317     GrGLvoid deleteFramebuffers(GrGLsizei n, const GrGLuint* ids) override {
    318         for (int i = 0; i < n; ++i) {
    319             if (ids[i] == fCurrDrawFramebuffer) {
    320                 fCurrDrawFramebuffer = 0;
    321             }
    322             if (ids[i] == fCurrReadFramebuffer) {
    323                 fCurrReadFramebuffer = 0;
    324             }
    325 
    326             if (ids[i] > 0) {
    327                 Framebuffer* framebuffer = fFramebufferManager.lookUp(ids[i]);
    328                 fFramebufferManager.free(framebuffer);
    329             }
    330         }
    331     }
    332 
    333     GrGLvoid genQueries(GrGLsizei n, GrGLuint *ids) override { this->genGenericIds(n, ids); }
    334 
    335     GrGLvoid genRenderbuffers(GrGLsizei n, GrGLuint *renderbuffers) override {
    336         for (int i = 0; i < n; ++i) {
    337             Renderbuffer* renderbuffer = fRenderbufferManager.create();
    338             renderbuffers[i] = renderbuffer->id();
    339         }
    340     }
    341 
    342     GrGLvoid bindRenderbuffer(GrGLenum target, GrGLuint renderbuffer) override {
    343         SkASSERT(GR_GL_RENDERBUFFER == target);
    344         fCurrRenderbuffer = renderbuffer;
    345     }
    346 
    347     GrGLvoid deleteRenderbuffers(GrGLsizei n, const GrGLuint* ids) override {
    348         for (int i = 0; i < n; ++i) {
    349             if (ids[i] <= 0) {
    350                 continue;
    351             }
    352             if (ids[i] == fCurrRenderbuffer) {
    353                 fCurrRenderbuffer = 0;
    354             }
    355             Renderbuffer* renderbuffer = fRenderbufferManager.lookUp(ids[i]);
    356 
    357             if (fCurrDrawFramebuffer) {
    358                 Framebuffer* drawFramebuffer = fFramebufferManager.lookUp(fCurrDrawFramebuffer);
    359                 drawFramebuffer->notifyAttachmentDeleteWhileBound(renderbuffer);
    360             }
    361             if (fCurrReadFramebuffer) {
    362                 Framebuffer* readFramebuffer = fFramebufferManager.lookUp(fCurrReadFramebuffer);
    363                 readFramebuffer->notifyAttachmentDeleteWhileBound(renderbuffer);
    364             }
    365 
    366             fRenderbufferManager.free(renderbuffer);
    367         }
    368     }
    369 
    370     GrGLvoid renderbufferStorage(GrGLenum target, GrGLenum internalformat, GrGLsizei width,
    371                                  GrGLsizei height) override {
    372         GrAlwaysAssert(GR_GL_RENDERBUFFER == target);
    373         GrAlwaysAssert(fCurrRenderbuffer);
    374         Renderbuffer* renderbuffer = fRenderbufferManager.lookUp(fCurrRenderbuffer);
    375         renderbuffer->setNumSamples(1);
    376     }
    377 
    378     GrGLvoid renderbufferStorageMultisample(GrGLenum target, GrGLsizei samples,
    379                                             GrGLenum internalformat, GrGLsizei width,
    380                                             GrGLsizei height) override {
    381         GrAlwaysAssert(GR_GL_RENDERBUFFER == target);
    382         GrAlwaysAssert(samples > 0);
    383         GrAlwaysAssert(fCurrRenderbuffer);
    384         Renderbuffer* renderbuffer = fRenderbufferManager.lookUp(fCurrRenderbuffer);
    385         renderbuffer->setNumSamples(samples);
    386     }
    387 
    388     GrGLvoid namedRenderbufferStorage(GrGLuint renderbuffer, GrGLenum GrGLinternalformat,
    389                                       GrGLsizei width, GrGLsizei height) override {
    390         SK_ABORT("Not implemented");
    391     }
    392 
    393     GrGLvoid namedRenderbufferStorageMultisample(GrGLuint renderbuffer, GrGLsizei samples,
    394                                                  GrGLenum GrGLinternalformat, GrGLsizei width,
    395                                                  GrGLsizei height) override {
    396         SK_ABORT("Not implemented");
    397     }
    398 
    399     GrGLvoid framebufferRenderbuffer(GrGLenum target, GrGLenum attachment,
    400                                      GrGLenum renderbuffertarget,
    401                                      GrGLuint renderBufferID) override {
    402         GrGLuint id = this->getBoundFramebufferID(target);
    403         GrAlwaysAssert(id);
    404         Framebuffer* framebuffer = fFramebufferManager.lookUp(id);
    405 
    406         GrAlwaysAssert(GR_GL_RENDERBUFFER == renderbuffertarget);
    407         if (!renderBufferID && !fCurrRenderbuffer) {
    408            return;
    409         }
    410         GrAlwaysAssert(fCurrRenderbuffer);
    411         Renderbuffer* renderbuffer = fRenderbufferManager.lookUp(fCurrRenderbuffer);
    412 
    413         framebuffer->setAttachment(attachment, renderbuffer);
    414     }
    415 
    416     GrGLvoid namedFramebufferRenderbuffer(GrGLuint framebuffer, GrGLenum attachment,
    417                                           GrGLenum renderbuffertarget,
    418                                           GrGLuint renderbuffer) override {
    419         SK_ABORT("Not implemented");
    420     }
    421 
    422     GrGLvoid genSamplers(GrGLsizei n, GrGLuint* samplers) override {
    423         this->genGenericIds(n, samplers);
    424     }
    425 
    426     GrGLvoid genTextures(GrGLsizei n, GrGLuint *textures) override {
    427         this->genGenericIds(n, textures);
    428     }
    429 
    430     GrGLvoid framebufferTexture2D(GrGLenum target, GrGLenum attachment, GrGLenum textarget,
    431                                   GrGLuint textureID, GrGLint level) override {
    432         GrGLuint id = this->getBoundFramebufferID(target);
    433         GrAlwaysAssert(id);
    434         Framebuffer* framebuffer = fFramebufferManager.lookUp(id);
    435         framebuffer->setAttachment(attachment, this->getSingleTextureObject());
    436     }
    437 
    438     GrGLvoid framebufferTexture2DMultisample(GrGLenum target, GrGLenum attachment,
    439                                              GrGLenum textarget, GrGLuint texture, GrGLint level,
    440                                              GrGLsizei samples) override {
    441         SK_ABORT("Not implemented");
    442     }
    443 
    444     GrGLvoid namedFramebufferTexture1D(GrGLuint framebuffer, GrGLenum attachment,
    445                                        GrGLenum textarget, GrGLuint texture,
    446                                        GrGLint level) override {
    447         SK_ABORT("Not implemented");
    448     }
    449 
    450     GrGLvoid namedFramebufferTexture2D(GrGLuint framebuffer, GrGLenum attachment,
    451                                        GrGLenum textarget, GrGLuint texture,
    452                                        GrGLint level) override {
    453         SK_ABORT("Not implemented");
    454     }
    455 
    456     GrGLvoid namedFramebufferTexture3D(GrGLuint framebuffer, GrGLenum attachment,
    457                                        GrGLenum textarget, GrGLuint texture, GrGLint level,
    458                                        GrGLint zoffset) override {
    459         SK_ABORT("Not implemented");
    460     }
    461 
    462     GrGLvoid genVertexArrays(GrGLsizei n, GrGLuint *arrays) override {
    463         this->genGenericIds(n, arrays);
    464     }
    465 
    466     GrGLenum getError() override { return GR_GL_NO_ERROR; }
    467 
    468     GrGLvoid getIntegerv(GrGLenum pname, GrGLint* params) override {
    469         // TODO: remove from Ganesh the #defines for gets we don't use.
    470         // We would like to minimize gets overall due to performance issues
    471         switch (pname) {
    472             case GR_GL_CONTEXT_PROFILE_MASK:
    473                 *params = GR_GL_CONTEXT_COMPATIBILITY_PROFILE_BIT;
    474                 break;
    475             case GR_GL_STENCIL_BITS:
    476                 *params = 8;
    477                 break;
    478             case GR_GL_SAMPLES: {
    479                 GrAlwaysAssert(fCurrDrawFramebuffer);
    480                 Framebuffer* framebuffer = fFramebufferManager.lookUp(fCurrDrawFramebuffer);
    481                 *params = framebuffer->numSamples();
    482                 break;
    483             }
    484             case GR_GL_FRAMEBUFFER_BINDING:
    485                 *params = 0;
    486                 break;
    487             case GR_GL_VIEWPORT:
    488                 params[0] = 0;
    489                 params[1] = 0;
    490                 params[2] = 800;
    491                 params[3] = 600;
    492                 break;
    493             case GR_GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS:
    494             case GR_GL_MAX_GEOMETRY_TEXTURE_IMAGE_UNITS:
    495             case GR_GL_MAX_TEXTURE_IMAGE_UNITS:
    496             case GR_GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS:
    497                 *params = 8;
    498                 break;
    499             case GR_GL_MAX_TEXTURE_COORDS:
    500                 *params = 8;
    501                 break;
    502             case GR_GL_MAX_VERTEX_UNIFORM_VECTORS:
    503                 *params = kDefaultMaxVertexUniformVectors;
    504                 break;
    505             case GR_GL_MAX_FRAGMENT_UNIFORM_VECTORS:
    506                 *params = kDefaultMaxFragmentUniformVectors;
    507                 break;
    508             case GR_GL_MAX_FRAGMENT_UNIFORM_COMPONENTS:
    509                 *params = 16 * 4;
    510                 break;
    511             case GR_GL_NUM_COMPRESSED_TEXTURE_FORMATS:
    512                 *params = 0;
    513                 break;
    514             case GR_GL_COMPRESSED_TEXTURE_FORMATS:
    515                 break;
    516             case GR_GL_MAX_TEXTURE_SIZE:
    517                 *params = 8192;
    518                 break;
    519             case GR_GL_MAX_RENDERBUFFER_SIZE:
    520                 *params = 8192;
    521                 break;
    522             case GR_GL_MAX_SAMPLES:
    523                 *params = 32;
    524                 break;
    525             case GR_GL_MAX_VERTEX_ATTRIBS:
    526                 *params = kDefaultMaxVertexAttribs;
    527                 break;
    528             case GR_GL_MAX_VARYING_VECTORS:
    529                 *params = kDefaultMaxVaryingVectors;
    530                 break;
    531             case GR_GL_NUM_EXTENSIONS: {
    532                 GrGLint i = 0;
    533                 while (fAdvertisedExtensions[i++]);
    534                 *params = i;
    535                 break;
    536             }
    537             default:
    538                 SK_ABORT("Unexpected pname to GetIntegerv");
    539         }
    540     }
    541 
    542     GrGLvoid getProgramiv(GrGLuint program, GrGLenum pname, GrGLint* params) override {
    543         this->getShaderOrProgramiv(program, pname, params);
    544     }
    545 
    546     GrGLvoid getProgramInfoLog(GrGLuint program, GrGLsizei bufsize, GrGLsizei* length,
    547                                char* infolog) override {
    548         this->getInfoLog(program, bufsize, length, infolog);
    549     }
    550 
    551     GrGLvoid getMultisamplefv(GrGLenum pname, GrGLuint index, GrGLfloat* val) override {
    552         val[0] = val[1] = 0.5f;
    553     }
    554 
    555     GrGLvoid getQueryiv(GrGLenum GLtarget, GrGLenum pname, GrGLint *params) override {
    556         switch (pname) {
    557             case GR_GL_CURRENT_QUERY:
    558                 *params = 0;
    559                 break;
    560             case GR_GL_QUERY_COUNTER_BITS:
    561                 *params = 32;
    562                 break;
    563             default:
    564                 SK_ABORT("Unexpected pname passed GetQueryiv.");
    565         }
    566     }
    567 
    568     GrGLvoid getQueryObjecti64v(GrGLuint id, GrGLenum pname, GrGLint64 *params) override {
    569         this->queryResult(id, pname, params);
    570     }
    571 
    572     GrGLvoid getQueryObjectiv(GrGLuint id, GrGLenum pname, GrGLint *params) override {
    573         this->queryResult(id, pname, params);
    574     }
    575 
    576     GrGLvoid getQueryObjectui64v(GrGLuint id, GrGLenum pname, GrGLuint64 *params) override {
    577         this->queryResult(id, pname, params);
    578     }
    579 
    580     GrGLvoid getQueryObjectuiv(GrGLuint id, GrGLenum pname, GrGLuint *params) override {
    581         this->queryResult(id, pname, params);
    582     }
    583 
    584     GrGLvoid getShaderiv(GrGLuint shader, GrGLenum pname, GrGLint* params) override {
    585         this->getShaderOrProgramiv(shader, pname, params);
    586     }
    587 
    588     GrGLvoid getShaderInfoLog(GrGLuint shader, GrGLsizei bufsize, GrGLsizei* length,
    589                               char* infolog) override {
    590         this->getInfoLog(shader, bufsize, length, infolog);
    591     }
    592 
    593     const GrGLubyte* getString(GrGLenum name) override {
    594         switch (name) {
    595             case GR_GL_EXTENSIONS:
    596                 return CombinedExtensionString();
    597             case GR_GL_VERSION:
    598                 return (const GrGLubyte*)"4.0 Null GL";
    599             case GR_GL_SHADING_LANGUAGE_VERSION:
    600                 return (const GrGLubyte*)"4.20.8 Null GLSL";
    601             case GR_GL_VENDOR:
    602                 return (const GrGLubyte*)"Null Vendor";
    603             case GR_GL_RENDERER:
    604                 return (const GrGLubyte*)"The Null (Non-)Renderer";
    605             default:
    606                 SK_ABORT("Unexpected name passed to GetString");
    607                 return nullptr;
    608         }
    609     }
    610 
    611     const GrGLubyte* getStringi(GrGLenum name, GrGLuint i) override {
    612         switch (name) {
    613             case GR_GL_EXTENSIONS: {
    614                 GrGLint count;
    615                 this->getIntegerv(GR_GL_NUM_EXTENSIONS, &count);
    616                 if ((GrGLint)i <= count) {
    617                     return (const GrGLubyte*) fAdvertisedExtensions[i];
    618                 } else {
    619                     return nullptr;
    620                 }
    621             }
    622             default:
    623                 SK_ABORT("Unexpected name passed to GetStringi");
    624                 return nullptr;
    625         }
    626     }
    627 
    628     GrGLint getUniformLocation(GrGLuint program, const char* name) override {
    629         return ++fCurrUniformLocation;
    630     }
    631 
    632     GrGLvoid* mapBufferRange(GrGLenum target, GrGLintptr offset, GrGLsizeiptr length,
    633                              GrGLbitfield access) override {
    634         GrGLuint id = fBoundBuffers[GetBufferIndex(target)];
    635         if (id > 0) {
    636             // We just ignore the offset and length here.
    637             Buffer* buffer = fBufferManager.lookUp(id);
    638             SkASSERT(!buffer->mapped());
    639             buffer->setMapped(true);
    640             return buffer->dataPtr();
    641         }
    642         return nullptr;
    643     }
    644 
    645     GrGLvoid* mapBuffer(GrGLenum target, GrGLenum access) override {
    646         GrGLuint id = fBoundBuffers[GetBufferIndex(target)];
    647         if (id > 0) {
    648             Buffer* buffer = fBufferManager.lookUp(id);
    649             SkASSERT(!buffer->mapped());
    650             buffer->setMapped(true);
    651             return buffer->dataPtr();
    652         }
    653 
    654         SkASSERT(false);
    655         return nullptr;            // no buffer bound to target
    656     }
    657 
    658     GrGLboolean unmapBuffer(GrGLenum target) override {
    659         GrGLuint id = fBoundBuffers[GetBufferIndex(target)];
    660         if (id > 0) {
    661             Buffer* buffer = fBufferManager.lookUp(id);
    662             SkASSERT(buffer->mapped());
    663             buffer->setMapped(false);
    664             return GR_GL_TRUE;
    665         }
    666 
    667         GrAlwaysAssert(false);
    668         return GR_GL_FALSE; // GR_GL_INVALID_OPERATION;
    669     }
    670 
    671     GrGLvoid getBufferParameteriv(GrGLenum target, GrGLenum pname, GrGLint* params) override {
    672         switch (pname) {
    673             case GR_GL_BUFFER_MAPPED: {
    674                 *params = GR_GL_FALSE;
    675                 GrGLuint id = fBoundBuffers[GetBufferIndex(target)];
    676                 if (id > 0) {
    677                     Buffer* buffer = fBufferManager.lookUp(id);
    678                     if (buffer->mapped()) {
    679                         *params = GR_GL_TRUE;
    680                     }
    681                 }
    682                 break; }
    683             default:
    684                 SK_ABORT("Unexpected pname to GetBufferParamateriv");
    685                 break;
    686         }
    687     }
    688 
    689     // NV_path_rendering
    690     GrGLuint genPaths(GrGLsizei range) override {
    691         return ++fCurrPathID;
    692     }
    693 
    694 
    695 private:
    696     inline int static GetBufferIndex(GrGLenum glTarget) {
    697         switch (glTarget) {
    698             default:                           SK_ABORT("Unexpected GL target to GetBufferIndex");
    699             case GR_GL_ARRAY_BUFFER:           return 0;
    700             case GR_GL_ELEMENT_ARRAY_BUFFER:   return 1;
    701             case GR_GL_TEXTURE_BUFFER:         return 2;
    702             case GR_GL_DRAW_INDIRECT_BUFFER:   return 3;
    703             case GR_GL_PIXEL_PACK_BUFFER:      return 4;
    704             case GR_GL_PIXEL_UNPACK_BUFFER:    return 5;
    705         }
    706     }
    707     constexpr int static kNumBufferTargets = 6;
    708 
    709     TGLObjectManager<Buffer>         fBufferManager;
    710     GrGLuint                         fBoundBuffers[kNumBufferTargets];
    711     TGLObjectManager<Framebuffer>    fFramebufferManager;
    712     GrGLuint                         fCurrDrawFramebuffer;
    713     GrGLuint                         fCurrReadFramebuffer;
    714     TGLObjectManager<Renderbuffer>   fRenderbufferManager;
    715     GrGLuint                         fCurrRenderbuffer;
    716     GrGLuint                         fCurrProgramID;
    717     GrGLuint                         fCurrShaderID;
    718     GrGLuint                         fCurrGenericID;
    719     GrGLuint                         fCurrUniformLocation;
    720     GrGLuint                         fCurrPathID;
    721     sk_sp<const Texture>             fSingleTextureObject;
    722     SkTArray<const char*>            fAdvertisedExtensions;
    723 
    724     // the OpenGLES 2.0 spec says this must be >= 128
    725     static const GrGLint kDefaultMaxVertexUniformVectors = 128;
    726 
    727     // the OpenGLES 2.0 spec says this must be >=16
    728     static const GrGLint kDefaultMaxFragmentUniformVectors = 16;
    729 
    730     // the OpenGLES 2.0 spec says this must be >= 8
    731     static const GrGLint kDefaultMaxVertexAttribs = 8;
    732 
    733     // the OpenGLES 2.0 spec says this must be >= 8
    734     static const GrGLint kDefaultMaxVaryingVectors = 8;
    735 
    736     GrGLuint getBoundFramebufferID(GrGLenum target) {
    737         switch (target) {
    738             case GR_GL_FRAMEBUFFER:
    739             case GR_GL_DRAW_FRAMEBUFFER:
    740                 return fCurrDrawFramebuffer;
    741             case GR_GL_READ_FRAMEBUFFER:
    742                 return fCurrReadFramebuffer;
    743             default:
    744                 SK_ABORT("Invalid framebuffer target.");
    745                 return 0;
    746         }
    747     }
    748 
    749     const Texture* getSingleTextureObject() {
    750         // We currently only use FramebufferAttachment objects for a sample count, and all textures
    751         // in Skia have one sample, so there is no need as of yet to track individual textures. This
    752         // also works around a bug in chromium's cc_unittests where they send us texture IDs that
    753         // were generated by cc::TestGLES2Interface.
    754         if (!fSingleTextureObject) {
    755             fSingleTextureObject.reset(new Texture);
    756         }
    757         return fSingleTextureObject.get();
    758     }
    759 
    760     const GrGLubyte* CombinedExtensionString() {
    761         static SkString gExtString;
    762         static SkMutex gMutex;
    763         gMutex.acquire();
    764         if (0 == gExtString.size()) {
    765             int i = 0;
    766             while (fAdvertisedExtensions[i]) {
    767                 if (i > 0) {
    768                     gExtString.append(" ");
    769                 }
    770                 gExtString.append(fAdvertisedExtensions[i]);
    771                 ++i;
    772             }
    773         }
    774         gMutex.release();
    775         return (const GrGLubyte*) gExtString.c_str();
    776     }
    777 
    778     GrGLvoid genGenericIds(GrGLsizei n, GrGLuint* ids) {
    779         for (int i = 0; i < n; ++i) {
    780             ids[i] = ++fCurrGenericID;
    781         }
    782     }
    783 
    784     GrGLvoid getInfoLog(GrGLuint object, GrGLsizei bufsize, GrGLsizei* length,
    785                         char* infolog) {
    786         if (length) {
    787             *length = 0;
    788         }
    789         if (bufsize > 0) {
    790             *infolog = 0;
    791         }
    792     }
    793 
    794     GrGLvoid getShaderOrProgramiv(GrGLuint object,  GrGLenum pname, GrGLint* params) {
    795         switch (pname) {
    796             case GR_GL_LINK_STATUS:  // fallthru
    797             case GR_GL_COMPILE_STATUS:
    798                 *params = GR_GL_TRUE;
    799                 break;
    800             case GR_GL_INFO_LOG_LENGTH: // fallthru
    801             case GL_PROGRAM_BINARY_LENGTH:
    802                 *params = 0;
    803                 break;
    804                 // we don't expect any other pnames
    805             default:
    806                 SK_ABORT("Unexpected pname to GetProgramiv");
    807                 break;
    808         }
    809     }
    810 
    811     template <typename T>
    812     void queryResult(GrGLenum GLtarget, GrGLenum pname, T *params) {
    813         switch (pname) {
    814             case GR_GL_QUERY_RESULT_AVAILABLE:
    815                 *params = GR_GL_TRUE;
    816                 break;
    817             case GR_GL_QUERY_RESULT:
    818                 *params = 0;
    819                 break;
    820             default:
    821                 SK_ABORT("Unexpected pname passed to GetQueryObject.");
    822                 break;
    823         }
    824     }
    825 
    826     typedef GrGLTestInterface INHERITED;
    827 };
    828 
    829 }  // anonymous namespace
    830 
    831 const GrGLInterface* GrGLCreateNullInterface(bool enableNVPR) { return new NullInterface(enableNVPR); }
    832