GrGLExtensions.cpp 5.4 KB

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