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