michael@0: /* michael@0: * Copyright 2013 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: #include "gl/GrGLExtensions.h" michael@0: #include "gl/GrGLDefines.h" michael@0: #include "gl/GrGLUtil.h" michael@0: michael@0: #include "SkTSearch.h" michael@0: #include "SkTSort.h" michael@0: michael@0: namespace { // This cannot be static because it is used as a template parameter. michael@0: inline bool extension_compare(const SkString& a, const SkString& b) { michael@0: return strcmp(a.c_str(), b.c_str()) < 0; michael@0: } michael@0: } michael@0: michael@0: // finds the index of ext in strings or a negative result if ext is not found. michael@0: static int find_string(const SkTArray& strings, const char ext[]) { michael@0: if (strings.empty()) { michael@0: return -1; michael@0: } michael@0: SkString extensionStr(ext); michael@0: int idx = SkTSearch(&strings.front(), michael@0: strings.count(), michael@0: extensionStr, michael@0: sizeof(SkString)); michael@0: return idx; michael@0: } michael@0: michael@0: GrGLExtensions::GrGLExtensions(const GrGLExtensions& that) : fStrings(SkNEW(SkTArray)) { michael@0: *this = that; michael@0: } michael@0: michael@0: GrGLExtensions& GrGLExtensions::operator=(const GrGLExtensions& that) { michael@0: *fStrings = *that.fStrings; michael@0: fInitialized = that.fInitialized; michael@0: return *this; michael@0: } michael@0: michael@0: bool GrGLExtensions::init(GrGLStandard standard, michael@0: GrGLGetStringProc getString, michael@0: GrGLGetStringiProc getStringi, michael@0: GrGLGetIntegervProc getIntegerv) { michael@0: fInitialized = false; michael@0: fStrings->reset(); michael@0: michael@0: if (NULL == getString) { michael@0: return false; michael@0: } michael@0: michael@0: // glGetStringi and indexed extensions were added in version 3.0 of desktop GL and ES. michael@0: const GrGLubyte* verString = getString(GR_GL_VERSION); michael@0: if (NULL == verString) { michael@0: return false; michael@0: } michael@0: GrGLVersion version = GrGLGetVersionFromString((const char*) verString); michael@0: bool indexed = version >= GR_GL_VER(3, 0); michael@0: michael@0: if (indexed) { michael@0: if (NULL == getStringi || NULL == getIntegerv) { michael@0: return false; michael@0: } michael@0: GrGLint extensionCnt = 0; michael@0: getIntegerv(GR_GL_NUM_EXTENSIONS, &extensionCnt); michael@0: fStrings->push_back_n(extensionCnt); michael@0: for (int i = 0; i < extensionCnt; ++i) { michael@0: const char* ext = (const char*) getStringi(GR_GL_EXTENSIONS, i); michael@0: (*fStrings)[i] = ext; michael@0: } michael@0: } else { michael@0: const char* extensions = (const char*) getString(GR_GL_EXTENSIONS); michael@0: if (NULL == extensions) { michael@0: return false; michael@0: } michael@0: while (true) { michael@0: // skip over multiple spaces between extensions michael@0: while (' ' == *extensions) { michael@0: ++extensions; michael@0: } michael@0: // quit once we reach the end of the string. michael@0: if ('\0' == *extensions) { michael@0: break; michael@0: } michael@0: // we found an extension michael@0: size_t length = strcspn(extensions, " "); michael@0: fStrings->push_back().set(extensions, length); michael@0: extensions += length; michael@0: } michael@0: } michael@0: if (!fStrings->empty()) { michael@0: SkTLessFunctionToFunctorAdaptor cmp; michael@0: SkTQSort(&fStrings->front(), &fStrings->back(), cmp); michael@0: } michael@0: fInitialized = true; michael@0: return true; michael@0: } michael@0: michael@0: bool GrGLExtensions::has(const char ext[]) const { michael@0: SkASSERT(fInitialized); michael@0: return find_string(*fStrings, ext) >= 0; michael@0: } michael@0: michael@0: bool GrGLExtensions::remove(const char ext[]) { michael@0: SkASSERT(fInitialized); michael@0: int idx = find_string(*fStrings, ext); michael@0: if (idx >= 0) { michael@0: // This is not terribly effecient but we really only expect this function to be called at michael@0: // most a handful of times when our test programs start. michael@0: SkAutoTDelete< SkTArray > oldStrings(fStrings.detach()); michael@0: fStrings.reset(SkNEW(SkTArray(oldStrings->count() - 1))); michael@0: fStrings->push_back_n(idx, &oldStrings->front()); michael@0: fStrings->push_back_n(oldStrings->count() - idx - 1, &(*oldStrings)[idx] + 1); michael@0: return true; michael@0: } else { michael@0: return false; michael@0: } michael@0: } michael@0: michael@0: void GrGLExtensions::add(const char ext[]) { michael@0: int idx = find_string(*fStrings, ext); michael@0: if (idx < 0) { michael@0: // This is not the most effecient approach since we end up doing a full sort of the michael@0: // extensions after the add michael@0: fStrings->push_back().set(ext); michael@0: SkTLessFunctionToFunctorAdaptor cmp; michael@0: SkTQSort(&fStrings->front(), &fStrings->back(), cmp); michael@0: } michael@0: } michael@0: michael@0: void GrGLExtensions::print(const char* sep) const { michael@0: if (NULL == sep) { michael@0: sep = " "; michael@0: } michael@0: int cnt = fStrings->count(); michael@0: for (int i = 0; i < cnt; ++i) { michael@0: GrPrintf("%s%s", (*fStrings)[i].c_str(), (i < cnt - 1) ? sep : ""); michael@0: } michael@0: }