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