Line data Source code
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 0 : inline bool extension_compare(const SkString& a, const SkString& b) {
18 0 : 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 0 : static int find_string(const SkTArray<SkString>& strings, const char ext[]) {
24 0 : if (strings.empty()) {
25 0 : return -1;
26 : }
27 0 : SkString extensionStr(ext);
28 0 : int idx = SkTSearch<SkString, extension_compare>(&strings.front(),
29 : strings.count(),
30 : extensionStr,
31 0 : sizeof(SkString));
32 0 : return idx;
33 : }
34 :
35 0 : GrGLExtensions::GrGLExtensions(const GrGLExtensions& that) : fStrings(new SkTArray<SkString>) {
36 0 : *this = that;
37 0 : }
38 :
39 0 : GrGLExtensions& GrGLExtensions::operator=(const GrGLExtensions& that) {
40 0 : *fStrings = *that.fStrings;
41 0 : fInitialized = that.fInitialized;
42 0 : return *this;
43 : }
44 :
45 0 : static void eat_space_sep_strings(SkTArray<SkString>* out, const char in[]) {
46 0 : if (!in) {
47 0 : return;
48 : }
49 : while (true) {
50 : // skip over multiple spaces between extensions
51 0 : while (' ' == *in) {
52 0 : ++in;
53 : }
54 : // quit once we reach the end of the string.
55 0 : if ('\0' == *in) {
56 0 : break;
57 : }
58 : // we found an extension
59 0 : size_t length = strcspn(in, " ");
60 0 : out->push_back().set(in, length);
61 0 : in += length;
62 0 : }
63 : }
64 :
65 0 : 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 0 : fInitialized = false;
72 0 : fStrings->reset();
73 :
74 0 : if (!getString) {
75 0 : return false;
76 : }
77 :
78 : // glGetStringi and indexed extensions were added in version 3.0 of desktop GL and ES.
79 0 : const GrGLubyte* verString = getString(GR_GL_VERSION);
80 0 : GrGLVersion version = GrGLGetVersionFromString((const char*) verString);
81 0 : if (GR_GL_INVALID_VER == version) {
82 0 : return false;
83 : }
84 :
85 0 : bool indexed = version >= GR_GL_VER(3, 0);
86 :
87 0 : if (indexed) {
88 0 : if (!getStringi || !getIntegerv) {
89 0 : return false;
90 : }
91 0 : GrGLint extensionCnt = 0;
92 0 : getIntegerv(GR_GL_NUM_EXTENSIONS, &extensionCnt);
93 0 : fStrings->push_back_n(extensionCnt);
94 0 : for (int i = 0; i < extensionCnt; ++i) {
95 0 : const char* ext = (const char*) getStringi(GR_GL_EXTENSIONS, i);
96 0 : (*fStrings)[i] = ext;
97 : }
98 : } else {
99 0 : const char* extensions = (const char*) getString(GR_GL_EXTENSIONS);
100 0 : if (!extensions) {
101 0 : return false;
102 : }
103 0 : eat_space_sep_strings(fStrings.get(), extensions);
104 : }
105 0 : if (queryString) {
106 0 : const char* extensions = queryString(eglDisplay, GR_EGL_EXTENSIONS);
107 :
108 0 : eat_space_sep_strings(fStrings.get(), extensions);
109 : }
110 0 : if (!fStrings->empty()) {
111 : SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
112 0 : SkTQSort(&fStrings->front(), &fStrings->back(), cmp);
113 : }
114 0 : fInitialized = true;
115 0 : return true;
116 : }
117 :
118 0 : bool GrGLExtensions::has(const char ext[]) const {
119 0 : SkASSERT(fInitialized);
120 0 : return find_string(*fStrings, ext) >= 0;
121 : }
122 :
123 0 : bool GrGLExtensions::remove(const char ext[]) {
124 0 : SkASSERT(fInitialized);
125 0 : int idx = find_string(*fStrings, ext);
126 0 : if (idx < 0) {
127 0 : 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 0 : fStrings->removeShuffle(idx);
133 : SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
134 0 : SkTInsertionSort(&(fStrings->operator[](idx)), &fStrings->back(), cmp);
135 0 : return true;
136 : }
137 :
138 0 : void GrGLExtensions::add(const char ext[]) {
139 0 : int idx = find_string(*fStrings, ext);
140 0 : 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 0 : fStrings->emplace_back(ext);
144 : SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
145 0 : SkTInsertionSort(&fStrings->front(), &fStrings->back(), cmp);
146 : }
147 0 : }
148 :
149 0 : void GrGLExtensions::print(const char* sep) const {
150 0 : if (nullptr == sep) {
151 0 : sep = " ";
152 : }
153 0 : int cnt = fStrings->count();
154 0 : for (int i = 0; i < cnt; ++i) {
155 0 : SkDebugf("%s%s", (*fStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
156 : }
157 0 : }
|