Home | History | Annotate | Download | only in gl
      1 /*
      2  * Copyright 2013 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 "gl/GrGLExtensions.h"
      9 #include "gl/GrGLDefines.h"
     10 #include "gl/GrGLUtil.h"
     11 
     12 #include "SkTSearch.h"
     13 #include "SkTSort.h"
     14 
     15 namespace { // This cannot be static because it is used as a template parameter.
     16 inline bool extension_compare(const SkString& a, const SkString& b) {
     17     return strcmp(a.c_str(), b.c_str()) < 0;
     18 }
     19 }
     20 
     21 // finds the index of ext in strings or a negative result if ext is not found.
     22 static int find_string(const SkTArray<SkString>& strings, const char ext[]) {
     23     if (strings.empty()) {
     24         return -1;
     25     }
     26     SkString extensionStr(ext);
     27     int idx = SkTSearch<SkString, extension_compare>(&strings.front(),
     28                                                      strings.count(),
     29                                                      extensionStr,
     30                                                      sizeof(SkString));
     31     return idx;
     32 }
     33 
     34 GrGLExtensions::GrGLExtensions(const GrGLExtensions& that) : fStrings(SkNEW(SkTArray<SkString>)) {
     35     *this = that;
     36 }
     37 
     38 GrGLExtensions& GrGLExtensions::operator=(const GrGLExtensions& that) {
     39     *fStrings = *that.fStrings;
     40     fInitialized = that.fInitialized;
     41     return *this;
     42 }
     43 
     44 bool GrGLExtensions::init(GrGLStandard standard,
     45                           GrGLGetStringProc getString,
     46                           GrGLGetStringiProc getStringi,
     47                           GrGLGetIntegervProc getIntegerv) {
     48     fInitialized = false;
     49     fStrings->reset();
     50 
     51     if (NULL == getString) {
     52         return false;
     53     }
     54 
     55     // glGetStringi and indexed extensions were added in version 3.0 of desktop GL and ES.
     56     const GrGLubyte* verString = getString(GR_GL_VERSION);
     57     GrGLVersion version = GrGLGetVersionFromString((const char*) verString);
     58     if (GR_GL_INVALID_VER == version) {
     59         return false;
     60     }
     61 
     62     bool indexed = version >= GR_GL_VER(3, 0);
     63 
     64     if (indexed) {
     65         if (NULL == getStringi || NULL == getIntegerv) {
     66             return false;
     67         }
     68         GrGLint extensionCnt = 0;
     69         getIntegerv(GR_GL_NUM_EXTENSIONS, &extensionCnt);
     70         fStrings->push_back_n(extensionCnt);
     71         for (int i = 0; i < extensionCnt; ++i) {
     72             const char* ext = (const char*) getStringi(GR_GL_EXTENSIONS, i);
     73             (*fStrings)[i] = ext;
     74         }
     75     } else {
     76         const char* extensions = (const char*) getString(GR_GL_EXTENSIONS);
     77         if (NULL == extensions) {
     78             return false;
     79         }
     80         while (true) {
     81             // skip over multiple spaces between extensions
     82             while (' ' == *extensions) {
     83                 ++extensions;
     84             }
     85             // quit once we reach the end of the string.
     86             if ('\0' == *extensions) {
     87                 break;
     88             }
     89             // we found an extension
     90             size_t length = strcspn(extensions, " ");
     91             fStrings->push_back().set(extensions, length);
     92             extensions += length;
     93         }
     94     }
     95     if (!fStrings->empty()) {
     96         SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
     97         SkTQSort(&fStrings->front(), &fStrings->back(), cmp);
     98     }
     99     fInitialized = true;
    100     return true;
    101 }
    102 
    103 bool GrGLExtensions::has(const char ext[]) const {
    104     SkASSERT(fInitialized);
    105     return find_string(*fStrings, ext) >= 0;
    106 }
    107 
    108 bool GrGLExtensions::remove(const char ext[]) {
    109     SkASSERT(fInitialized);
    110     int idx = find_string(*fStrings, ext);
    111     if (idx >= 0) {
    112         // This is not terribly effecient but we really only expect this function to be called at
    113         // most a handful of times when our test programs start.
    114         SkAutoTDelete< SkTArray<SkString> > oldStrings(fStrings.detach());
    115         fStrings.reset(SkNEW(SkTArray<SkString>(oldStrings->count() - 1)));
    116         fStrings->push_back_n(idx, &oldStrings->front());
    117         fStrings->push_back_n(oldStrings->count() - idx - 1, &(*oldStrings)[idx] + 1);
    118         return true;
    119     } else {
    120         return false;
    121     }
    122 }
    123 
    124 void GrGLExtensions::add(const char ext[]) {
    125     int idx = find_string(*fStrings, ext);
    126     if (idx < 0) {
    127         // This is not the most effecient approach since we end up doing a full sort of the
    128         // extensions after the add
    129         fStrings->push_back().set(ext);
    130         SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
    131         SkTQSort(&fStrings->front(), &fStrings->back(), cmp);
    132     }
    133 }
    134 
    135 void GrGLExtensions::print(const char* sep) const {
    136     if (NULL == sep) {
    137         sep = " ";
    138     }
    139     int cnt = fStrings->count();
    140     for (int i = 0; i < cnt; ++i) {
    141         GrPrintf("%s%s", (*fStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
    142     }
    143 }
    144