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