19c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis/*
29c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis * Copyright (C) 2012 The Android Open Source Project
39c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis *
49c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis * Licensed under the Apache License, Version 2.0 (the "License");
59c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis * you may not use this file except in compliance with the License.
69c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis * You may obtain a copy of the License at
79c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis *
89c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis *      http://www.apache.org/licenses/LICENSE-2.0
99c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis *
109c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis * Unless required by applicable law or agreed to in writing, software
119c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis * distributed under the License is distributed on an "AS IS" BASIS,
129c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis * See the License for the specific language governing permissions and
149c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis * limitations under the License.
159c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis */
169c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
175bbe0ab655713849fbfe750d4d09690106f95d7fMathias Agopian#include <GLES2/gl2.h>
185bbe0ab655713849fbfe750d4d09690106f95d7fMathias Agopian#include <GLES2/gl2ext.h>
195bbe0ab655713849fbfe750d4d09690106f95d7fMathias Agopian
209c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis#include <ui/DisplayInfo.h>
219c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis#include <gui/SurfaceComposerClient.h>
229c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
239c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis#include "GLHelper.h"
249c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
259c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis namespace android {
269c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
279c183f2493222000fa512d927cfde3f4c748eda0Jamie GennisGLHelper::GLHelper() :
289c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    mGraphicBufferAlloc(new GraphicBufferAlloc()),
299c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    mDisplay(EGL_NO_DISPLAY),
309c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    mContext(EGL_NO_CONTEXT),
319c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    mDummySurface(EGL_NO_SURFACE),
329c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    mConfig(0),
339c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    mShaderPrograms(NULL),
349c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    mDitherTexture(0) {
359c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
369c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
379c183f2493222000fa512d927cfde3f4c748eda0Jamie GennisGLHelper::~GLHelper() {
389c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
399c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
409c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennisbool GLHelper::setUp(const ShaderDesc* shaderDescs, size_t numShaders) {
419c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    bool result;
429c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
439c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
449c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (mDisplay == EGL_NO_DISPLAY) {
459c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "eglGetDisplay error: %#x\n", eglGetError());
469c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
479c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
489c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
499c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    EGLint majorVersion;
509c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    EGLint minorVersion;
519c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    result = eglInitialize(mDisplay, &majorVersion, &minorVersion);
529c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (result != EGL_TRUE) {
539c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "eglInitialize error: %#x\n", eglGetError());
549c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
559c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
569c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
579c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    EGLint numConfigs = 0;
589c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    EGLint configAttribs[] = {
599c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
609c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
619c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        EGL_RED_SIZE, 8,
629c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        EGL_GREEN_SIZE, 8,
639c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        EGL_BLUE_SIZE, 8,
649c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        EGL_ALPHA_SIZE, 8,
659c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        EGL_NONE
669c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    };
679c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    result = eglChooseConfig(mDisplay, configAttribs, &mConfig, 1,
689c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            &numConfigs);
699c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (result != EGL_TRUE) {
709c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "eglChooseConfig error: %#x\n", eglGetError());
719c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
729c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
739c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
749c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    EGLint contextAttribs[] = {
759c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        EGL_CONTEXT_CLIENT_VERSION, 2,
769c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        EGL_NONE
779c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    };
789c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    mContext = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT,
799c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            contextAttribs);
809c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (mContext == EGL_NO_CONTEXT) {
819c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "eglCreateContext error: %#x\n", eglGetError());
829c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
839c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
849c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
859c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    bool resultb = createNamedSurfaceTexture(0, 1, 1, &mDummyGLConsumer,
869c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            &mDummySurface);
879c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (!resultb) {
889c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
899c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
909c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
919c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    resultb = makeCurrent(mDummySurface);
929c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (!resultb) {
939c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
949c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
959c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
969c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    resultb = setUpShaders(shaderDescs, numShaders);
979c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (!resultb) {
989c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
999c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
1009c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1019c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    return true;
1029c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
1039c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1049c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennisvoid GLHelper::tearDown() {
1059c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (mShaderPrograms != NULL) {
1069c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        delete[] mShaderPrograms;
1079c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        mShaderPrograms = NULL;
1089c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
1099c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1109c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (mSurfaceComposerClient != NULL) {
1119c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        mSurfaceComposerClient->dispose();
1129c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        mSurfaceComposerClient.clear();
1139c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
1149c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1159c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (mDisplay != EGL_NO_DISPLAY) {
1169c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
1179c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis                EGL_NO_CONTEXT);
1189c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
1199c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1209c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (mContext != EGL_NO_CONTEXT) {
1219c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        eglDestroyContext(mDisplay, mContext);
1229c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
1239c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1249c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (mDummySurface != EGL_NO_SURFACE) {
1259c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        eglDestroySurface(mDisplay, mDummySurface);
1269c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
1279c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1289c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    mDisplay = EGL_NO_DISPLAY;
1299c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    mContext = EGL_NO_CONTEXT;
1309c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    mDummySurface = EGL_NO_SURFACE;
1319c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    mDummyGLConsumer.clear();
1329c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    mConfig = 0;
1339c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
1349c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1359c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennisbool GLHelper::makeCurrent(EGLSurface surface) {
1369c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    EGLint result;
1379c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1389c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    result = eglMakeCurrent(mDisplay, surface, surface, mContext);
1399c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (result != EGL_TRUE) {
1409c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "eglMakeCurrent error: %#x\n", eglGetError());
1419c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
1429c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
1439c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1449c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    EGLint w, h;
1459c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    eglQuerySurface(mDisplay, surface, EGL_WIDTH, &w);
1469c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    eglQuerySurface(mDisplay, surface, EGL_HEIGHT, &h);
1479c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    glViewport(0, 0, w, h);
1489c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1499c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    return true;
1509c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
1519c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1529c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennisbool GLHelper::createSurfaceTexture(uint32_t w, uint32_t h,
1539c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        sp<GLConsumer>* glConsumer, EGLSurface* surface,
1549c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        GLuint* name) {
1559c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (!makeCurrent(mDummySurface)) {
1569c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
1579c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
1589c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1599c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    *name = 0;
1609c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    glGenTextures(1, name);
1619c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (*name == 0) {
1629c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "glGenTextures error: %#x\n", glGetError());
1639c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
1649c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
1659c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1669c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    return createNamedSurfaceTexture(*name, w, h, glConsumer, surface);
1679c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
1689c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1699c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennisvoid GLHelper::destroySurface(EGLSurface* surface) {
1709c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (eglGetCurrentSurface(EGL_READ) == *surface ||
1719c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            eglGetCurrentSurface(EGL_DRAW) == *surface) {
1729c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE,
1739c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis                EGL_NO_CONTEXT);
1749c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
1759c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    eglDestroySurface(mDisplay, *surface);
1769c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    *surface = EGL_NO_SURFACE;
1779c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
1789c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1799c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennisbool GLHelper::swapBuffers(EGLSurface surface) {
1809c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    EGLint result;
1819c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    result = eglSwapBuffers(mDisplay, surface);
1829c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (result != EGL_TRUE) {
1839c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "eglSwapBuffers error: %#x\n", eglGetError());
1849c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
1859c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
1869c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    return true;
1879c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
1889c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1899c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennisbool GLHelper::getShaderProgram(const char* name, GLuint* outPgm) {
1909c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    for (size_t i = 0; i < mNumShaders; i++) {
1919c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        if (strcmp(mShaderDescs[i].name, name) == 0) {
1929c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            *outPgm = mShaderPrograms[i];
1939c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            return true;
1949c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        }
1959c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
1969c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1979c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    fprintf(stderr, "unknown shader name: \"%s\"\n", name);
1989c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
1999c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    return false;
2009c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
2019c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
2029c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennisbool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h,
2039c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        sp<GLConsumer>* glConsumer, EGLSurface* surface) {
2046780a2d6a5351977a793c08935bd3492c9942494Dan Stoza    sp<IGraphicBufferProducer> producer;
2056780a2d6a5351977a793c08935bd3492c9942494Dan Stoza    sp<IGraphicBufferConsumer> consumer;
2066780a2d6a5351977a793c08935bd3492c9942494Dan Stoza    BufferQueue::createBufferQueue(&producer, &consumer, mGraphicBufferAlloc);
2076780a2d6a5351977a793c08935bd3492c9942494Dan Stoza    sp<GLConsumer> glc = new GLConsumer(consumer, name,
208e49ba8e2ed8e17156eb00c8fc8e2285df62bc018Dan Stoza            GL_TEXTURE_EXTERNAL_OES, false, true);
2099c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    glc->setDefaultBufferSize(w, h);
2109c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    glc->setDefaultMaxBufferCount(3);
2119c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
2129c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
2136780a2d6a5351977a793c08935bd3492c9942494Dan Stoza    sp<ANativeWindow> anw = new Surface(producer);
2149c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL);
2159c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (s == EGL_NO_SURFACE) {
2169c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError());
2179c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
2189c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
2199c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
2209c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    *glConsumer = glc;
2219c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    *surface = s;
2229c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    return true;
2239c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
2249c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
2259c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennisbool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) {
2269c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    sp<IBinder> dpy = mSurfaceComposerClient->getBuiltInDisplay(0);
2279c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (dpy == NULL) {
2289c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "SurfaceComposer::getBuiltInDisplay failed.\n");
2299c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
2309c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
2319c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
2329c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    DisplayInfo info;
2339c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    status_t err = mSurfaceComposerClient->getDisplayInfo(dpy, &info);
2349c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (err != NO_ERROR) {
2359c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "SurfaceComposer::getDisplayInfo failed: %#x\n", err);
2369c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
2379c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
2389c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
2399c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    float scaleX = float(info.w) / float(w);
2409c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    float scaleY = float(info.h) / float(h);
2419c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    *scale = scaleX < scaleY ? scaleX : scaleY;
2429c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
2439c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    return true;
2449c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
2459c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
2469c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennisbool GLHelper::createWindowSurface(uint32_t w, uint32_t h,
2479c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        sp<SurfaceControl>* surfaceControl, EGLSurface* surface) {
2489c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    bool result;
2499c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    status_t err;
2509c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
2519c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (mSurfaceComposerClient == NULL) {
2529c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        mSurfaceComposerClient = new SurfaceComposerClient;
2539c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
2549c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    err = mSurfaceComposerClient->initCheck();
2559c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (err != NO_ERROR) {
2569c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "SurfaceComposerClient::initCheck error: %#x\n", err);
2579c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
2589c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
2599c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
2609c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    sp<SurfaceControl> sc = mSurfaceComposerClient->createSurface(
2619c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            String8("Benchmark"), w, h, PIXEL_FORMAT_RGBA_8888, 0);
2629c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (sc == NULL || !sc->isValid()) {
2639c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "Failed to create SurfaceControl.\n");
2649c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
2659c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
2669c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
2679c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    float scale;
2689c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    result = computeWindowScale(w, h, &scale);
2699c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (!result) {
2709c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
2719c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
2729c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
2739c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    SurfaceComposerClient::openGlobalTransaction();
2749c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    err = sc->setLayer(0x7FFFFFFF);
2759c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (err != NO_ERROR) {
2769c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "SurfaceComposer::setLayer error: %#x\n", err);
2779c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
2789c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
2799c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    err = sc->setMatrix(scale, 0.0f, 0.0f, scale);
2809c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (err != NO_ERROR) {
2819c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "SurfaceComposer::setMatrix error: %#x\n", err);
2829c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
2839c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
2849c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
2859c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    err = sc->show();
2869c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (err != NO_ERROR) {
2879c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "SurfaceComposer::show error: %#x\n", err);
2889c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
2899c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
2909c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    SurfaceComposerClient::closeGlobalTransaction();
2919c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
2929c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    sp<ANativeWindow> anw = sc->getSurface();
2939c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL);
2949c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (s == EGL_NO_SURFACE) {
2959c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError());
2969c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
2979c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
2989c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
2999c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    *surfaceControl = sc;
3009c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    *surface = s;
3019c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    return true;
3029c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
3039c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
3049c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennisstatic bool compileShader(GLenum shaderType, const char* src,
3059c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        GLuint* outShader) {
3069c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    GLuint shader = glCreateShader(shaderType);
3079c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (shader == 0) {
3089c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "glCreateShader error: %#x\n", glGetError());
3099c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
3109c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
3119c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
3129c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    glShaderSource(shader, 1, &src, NULL);
3139c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    glCompileShader(shader);
3149c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
3159c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    GLint compiled = 0;
3169c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
3179c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (!compiled) {
3189c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        GLint infoLen = 0;
3199c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
3209c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        if (infoLen) {
3219c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            char* buf = new char[infoLen];
3229c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            if (buf) {
3239c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis                glGetShaderInfoLog(shader, infoLen, NULL, buf);
3249c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis                fprintf(stderr, "Shader compile log:\n%s\n", buf);
3259c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis                delete[] buf;
3269c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            }
3279c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        }
3289c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        glDeleteShader(shader);
3299c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
3309c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
3319c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    *outShader = shader;
3329c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    return true;
3339c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
3349c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
3359c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennisstatic void printShaderSource(const char* const* src) {
3369c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) {
33792dc3fc52cf097bd105460cf377779bdcf146d62Mark Salyzyn        fprintf(stderr, "%3zu: %s\n", i+1, src[i]);
3389c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
3399c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
3409c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
3419c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennisstatic const char* makeShaderString(const char* const* src) {
3429c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    size_t len = 0;
3439c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) {
3449c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        // The +1 is for the '\n' that will be added.
3459c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        len += strlen(src[i]) + 1;
3469c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
3479c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
3489c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    char* result = new char[len+1];
3499c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    char* end = result;
3509c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) {
3519c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        strcpy(end, src[i]);
3529c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        end += strlen(src[i]);
3539c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        *end = '\n';
3549c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        end++;
3559c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
3569c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    *end = '\0';
3579c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
3589c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    return result;
3599c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
3609c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
3619c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennisstatic bool compileShaderLines(GLenum shaderType, const char* const* lines,
3629c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        GLuint* outShader) {
3639c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    const char* src = makeShaderString(lines);
3649c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    bool result = compileShader(shaderType, src, outShader);
3659c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (!result) {
3669c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "Shader source:\n");
3679c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        printShaderSource(lines);
3689c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
3699c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
3709c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    delete[] src;
3719c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
3729c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    return true;
3739c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
3749c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
3759c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennisstatic bool linkShaderProgram(GLuint vs, GLuint fs, GLuint* outPgm) {
3769c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    GLuint program = glCreateProgram();
3779c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (program == 0) {
3789c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        fprintf(stderr, "glCreateProgram error: %#x\n", glGetError());
3799c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        return false;
3809c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
3819c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
3829c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    glAttachShader(program, vs);
3839c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    glAttachShader(program, fs);
3849c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    glLinkProgram(program);
3859c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    GLint linkStatus = GL_FALSE;
3869c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
3879c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (linkStatus != GL_TRUE) {
3889c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        GLint bufLength = 0;
3899c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
3909c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        if (bufLength) {
3919c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            char* buf = new char[bufLength];
3929c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            if (buf) {
3939c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis                glGetProgramInfoLog(program, bufLength, NULL, buf);
3949c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis                fprintf(stderr, "Program link log:\n%s\n", buf);
3959c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis                delete[] buf;
3969c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            }
3979c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        }
3989c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        glDeleteProgram(program);
3999c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        program = 0;
4009c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
4019c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
4029c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    *outPgm = program;
4039c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    return program != 0;
4049c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
4059c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
4069c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennisbool GLHelper::setUpShaders(const ShaderDesc* shaderDescs, size_t numShaders) {
4079c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    mShaderPrograms = new GLuint[numShaders];
4089c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    bool result = true;
4099c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
4109c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    for (size_t i = 0; i < numShaders && result; i++) {
4119c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        GLuint vs, fs;
4129c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
4139c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        result = compileShaderLines(GL_VERTEX_SHADER,
4149c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis                shaderDescs[i].vertexShader, &vs);
4159c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        if (!result) {
4169c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            return false;
4179c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        }
4189c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
4199c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        result = compileShaderLines(GL_FRAGMENT_SHADER,
4209c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis                shaderDescs[i].fragmentShader, &fs);
4219c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        if (!result) {
4229c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            glDeleteShader(vs);
4239c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            return false;
4249c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        }
4259c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
4269c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        result = linkShaderProgram(vs, fs, &mShaderPrograms[i]);
4279c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        glDeleteShader(vs);
4289c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        glDeleteShader(fs);
4299c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
4309c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
4319c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    mNumShaders = numShaders;
4329c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    mShaderDescs = shaderDescs;
4339c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
4349c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    return result;
4359c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
4369c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
4379c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennisbool GLHelper::getDitherTexture(GLuint* outTexName) {
4389c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    if (mDitherTexture == 0) {
4399c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        const uint8_t pattern[] = {
4409c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis             0,  8,  2, 10,
4419c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            12,  4, 14,  6,
4429c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis             3, 11,  1,  9,
4439c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis            15,  7, 13,  5
4449c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        };
4459c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
4469c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        glGenTextures(1, &mDitherTexture);
4479c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        glBindTexture(GL_TEXTURE_2D, mDitherTexture);
4489c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
4499c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
4509c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
4519c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
4529c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
4539c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
4549c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
4559c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis        glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, DITHER_KERNEL_SIZE,
4569c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis                DITHER_KERNEL_SIZE, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &pattern);
4579c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    }
4589c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
4599c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    *outTexName = mDitherTexture;
4609c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
4619c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis    return true;
4629c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
4639c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis
4649c183f2493222000fa512d927cfde3f4c748eda0Jamie Gennis}
465