11744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com/*
21744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com * Copyright 2013 Google Inc.
31744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com *
41744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com * Use of this source code is governed by a BSD-style license that can be
51744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com * found in the LICENSE file.
61744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com */
71744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com
81744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com#include "gl/GrGLExtensions.h"
91744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com#include "gl/GrGLDefines.h"
101744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com#include "gl/GrGLUtil.h"
111744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com
12ff436617d8f11297f0eff93ddd49fb9022d0843bbsalomon@google.com#include "SkTSearch.h"
13ff436617d8f11297f0eff93ddd49fb9022d0843bbsalomon@google.com#include "SkTSort.h"
14ff436617d8f11297f0eff93ddd49fb9022d0843bbsalomon@google.com
15d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.orgnamespace { // This cannot be static because it is used as a template parameter.
1620f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.cominline bool extension_compare(const SkString& a, const SkString& b) {
1720f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com    return strcmp(a.c_str(), b.c_str()) < 0;
18ff436617d8f11297f0eff93ddd49fb9022d0843bbsalomon@google.com}
19ff436617d8f11297f0eff93ddd49fb9022d0843bbsalomon@google.com}
20ff436617d8f11297f0eff93ddd49fb9022d0843bbsalomon@google.com
21d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org// finds the index of ext in strings or a negative result if ext is not found.
22d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.orgstatic int find_string(const SkTArray<SkString>& strings, const char ext[]) {
23d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org    if (strings.empty()) {
24d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org        return -1;
25d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org    }
26d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org    SkString extensionStr(ext);
27d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org    int idx = SkTSearch<SkString, extension_compare>(&strings.front(),
28d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org                                                     strings.count(),
29d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org                                                     extensionStr,
30d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org                                                     sizeof(SkString));
31d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org    return idx;
32d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org}
33d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org
34d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.orgGrGLExtensions::GrGLExtensions(const GrGLExtensions& that) : fStrings(SkNEW(SkTArray<SkString>)) {
35d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org    *this = that;
36d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org}
37d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org
38d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.orgGrGLExtensions& GrGLExtensions::operator=(const GrGLExtensions& that) {
39d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org    *fStrings = *that.fStrings;
40d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org    fInitialized = that.fInitialized;
41d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org    return *this;
42d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org}
43d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org
449e90aed5de82732cc9921f01388d3063a41a053bcommit-bot@chromium.orgbool GrGLExtensions::init(GrGLStandard standard,
451744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com                          GrGLGetStringProc getString,
461744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com                          GrGLGetStringiProc getStringi,
471744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com                          GrGLGetIntegervProc getIntegerv) {
4890313cc36a6f43a3e9d3818aca536cd6631c222bcommit-bot@chromium.org    fInitialized = false;
4990313cc36a6f43a3e9d3818aca536cd6631c222bcommit-bot@chromium.org    fStrings->reset();
5090313cc36a6f43a3e9d3818aca536cd6631c222bcommit-bot@chromium.org
511744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com    if (NULL == getString) {
521744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com        return false;
531744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com    }
54726e621000582e4de7c9ce0f7e9950c3af4e5d9bcommit-bot@chromium.org
55726e621000582e4de7c9ce0f7e9950c3af4e5d9bcommit-bot@chromium.org    // glGetStringi and indexed extensions were added in version 3.0 of desktop GL and ES.
56726e621000582e4de7c9ce0f7e9950c3af4e5d9bcommit-bot@chromium.org    const GrGLubyte* verString = getString(GR_GL_VERSION);
57f4e67e3e5e5017284300a61e7bb046723a44b0cfcommit-bot@chromium.org    GrGLVersion version = GrGLGetVersionFromString((const char*) verString);
58f4e67e3e5e5017284300a61e7bb046723a44b0cfcommit-bot@chromium.org    if (GR_GL_INVALID_VER == version) {
59726e621000582e4de7c9ce0f7e9950c3af4e5d9bcommit-bot@chromium.org        return false;
601744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com    }
61f4e67e3e5e5017284300a61e7bb046723a44b0cfcommit-bot@chromium.org
62726e621000582e4de7c9ce0f7e9950c3af4e5d9bcommit-bot@chromium.org    bool indexed = version >= GR_GL_VER(3, 0);
63726e621000582e4de7c9ce0f7e9950c3af4e5d9bcommit-bot@chromium.org
641744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com    if (indexed) {
651744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com        if (NULL == getStringi || NULL == getIntegerv) {
661744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com            return false;
671744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com        }
681744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com        GrGLint extensionCnt = 0;
691744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com        getIntegerv(GR_GL_NUM_EXTENSIONS, &extensionCnt);
7090313cc36a6f43a3e9d3818aca536cd6631c222bcommit-bot@chromium.org        fStrings->push_back_n(extensionCnt);
711744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com        for (int i = 0; i < extensionCnt; ++i) {
721744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com            const char* ext = (const char*) getStringi(GR_GL_EXTENSIONS, i);
7390313cc36a6f43a3e9d3818aca536cd6631c222bcommit-bot@chromium.org            (*fStrings)[i] = ext;
741744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com        }
751744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com    } else {
761744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com        const char* extensions = (const char*) getString(GR_GL_EXTENSIONS);
77eed625df23ee83a94f1814c43744b1961b79adf1skia.committer@gmail.com        if (NULL == extensions) {
781744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com            return false;
791744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com        }
801744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com        while (true) {
81a22407283650ae570d8f93db0f4f6df266812716bsalomon@google.com            // skip over multiple spaces between extensions
82a22407283650ae570d8f93db0f4f6df266812716bsalomon@google.com            while (' ' == *extensions) {
83a22407283650ae570d8f93db0f4f6df266812716bsalomon@google.com                ++extensions;
84a22407283650ae570d8f93db0f4f6df266812716bsalomon@google.com            }
85a22407283650ae570d8f93db0f4f6df266812716bsalomon@google.com            // quit once we reach the end of the string.
86a22407283650ae570d8f93db0f4f6df266812716bsalomon@google.com            if ('\0' == *extensions) {
871744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com                break;
881744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com            }
89a22407283650ae570d8f93db0f4f6df266812716bsalomon@google.com            // we found an extension
90a22407283650ae570d8f93db0f4f6df266812716bsalomon@google.com            size_t length = strcspn(extensions, " ");
9190313cc36a6f43a3e9d3818aca536cd6631c222bcommit-bot@chromium.org            fStrings->push_back().set(extensions, length);
92a22407283650ae570d8f93db0f4f6df266812716bsalomon@google.com            extensions += length;
931744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com        }
941744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com    }
9590313cc36a6f43a3e9d3818aca536cd6631c222bcommit-bot@chromium.org    if (!fStrings->empty()) {
9620f7f173e05b60f541910d0c1da9850ac73e2958bsalomon@google.com        SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
9790313cc36a6f43a3e9d3818aca536cd6631c222bcommit-bot@chromium.org        SkTQSort(&fStrings->front(), &fStrings->back(), cmp);
98a1d27cd07af36436a3c9c4495055fea5bbd219afbsalomon@google.com    }
9990313cc36a6f43a3e9d3818aca536cd6631c222bcommit-bot@chromium.org    fInitialized = true;
1001744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com    return true;
1011744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com}
1021744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com
103d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.orgbool GrGLExtensions::has(const char ext[]) const {
104d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org    SkASSERT(fInitialized);
105d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org    return find_string(*fStrings, ext) >= 0;
106d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org}
107d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org
108d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.orgbool GrGLExtensions::remove(const char ext[]) {
109d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org    SkASSERT(fInitialized);
110d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org    int idx = find_string(*fStrings, ext);
111d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org    if (idx >= 0) {
112d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org        // This is not terribly effecient but we really only expect this function to be called at
113d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org        // most a handful of times when our test programs start.
114d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org        SkAutoTDelete< SkTArray<SkString> > oldStrings(fStrings.detach());
115d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org        fStrings.reset(SkNEW(SkTArray<SkString>(oldStrings->count() - 1)));
116d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org        fStrings->push_back_n(idx, &oldStrings->front());
117d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org        fStrings->push_back_n(oldStrings->count() - idx - 1, &(*oldStrings)[idx] + 1);
118d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org        return true;
119d8ed85101ee77ad2cb0c186a79d197698a75d246commit-bot@chromium.org    } else {
12042db2e45137cf93bb1df7f9a1d4f71d45a3e8bd5bsalomon@google.com        return false;
12142db2e45137cf93bb1df7f9a1d4f71d45a3e8bd5bsalomon@google.com    }
1221744f97ea73384b9f75b0ccee0a36a213c681d3absalomon@google.com}
12300142c44057e5a7c156b17a4bfc98a9605cf3f18bsalomon@google.com
124a3baf3be0e2a3128fb73bd41d40d130f75a4dc86commit-bot@chromium.orgvoid GrGLExtensions::add(const char ext[]) {
125a3baf3be0e2a3128fb73bd41d40d130f75a4dc86commit-bot@chromium.org    int idx = find_string(*fStrings, ext);
126a3baf3be0e2a3128fb73bd41d40d130f75a4dc86commit-bot@chromium.org    if (idx < 0) {
127a3baf3be0e2a3128fb73bd41d40d130f75a4dc86commit-bot@chromium.org        // This is not the most effecient approach since we end up doing a full sort of the
128a3baf3be0e2a3128fb73bd41d40d130f75a4dc86commit-bot@chromium.org        // extensions after the add
129a3baf3be0e2a3128fb73bd41d40d130f75a4dc86commit-bot@chromium.org        fStrings->push_back().set(ext);
130a3baf3be0e2a3128fb73bd41d40d130f75a4dc86commit-bot@chromium.org        SkTLessFunctionToFunctorAdaptor<SkString, extension_compare> cmp;
131a3baf3be0e2a3128fb73bd41d40d130f75a4dc86commit-bot@chromium.org        SkTQSort(&fStrings->front(), &fStrings->back(), cmp);
132a3baf3be0e2a3128fb73bd41d40d130f75a4dc86commit-bot@chromium.org    }
133a3baf3be0e2a3128fb73bd41d40d130f75a4dc86commit-bot@chromium.org}
134a3baf3be0e2a3128fb73bd41d40d130f75a4dc86commit-bot@chromium.org
13500142c44057e5a7c156b17a4bfc98a9605cf3f18bsalomon@google.comvoid GrGLExtensions::print(const char* sep) const {
13600142c44057e5a7c156b17a4bfc98a9605cf3f18bsalomon@google.com    if (NULL == sep) {
13700142c44057e5a7c156b17a4bfc98a9605cf3f18bsalomon@google.com        sep = " ";
13800142c44057e5a7c156b17a4bfc98a9605cf3f18bsalomon@google.com    }
13990313cc36a6f43a3e9d3818aca536cd6631c222bcommit-bot@chromium.org    int cnt = fStrings->count();
14000142c44057e5a7c156b17a4bfc98a9605cf3f18bsalomon@google.com    for (int i = 0; i < cnt; ++i) {
14190313cc36a6f43a3e9d3818aca536cd6631c222bcommit-bot@chromium.org        GrPrintf("%s%s", (*fStrings)[i].c_str(), (i < cnt - 1) ? sep : "");
14200142c44057e5a7c156b17a4bfc98a9605cf3f18bsalomon@google.com    }
14300142c44057e5a7c156b17a4bfc98a9605cf3f18bsalomon@google.com}
144