Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2012 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 17 | #include "GLHelper.h" |
| 18 | |
Dominik Laskowski | 3cb3d4e | 2019-11-21 11:14:45 -0800 | [diff] [blame] | 19 | #include <GLES2/gl2.h> |
| 20 | #include <GLES2/gl2ext.h> |
Jim Shargo | a281888 | 2024-07-27 02:52:58 +0000 | [diff] [blame^] | 21 | #include <com_android_graphics_libgui_flags.h> |
Dominik Laskowski | 3cb3d4e | 2019-11-21 11:14:45 -0800 | [diff] [blame] | 22 | #include <gui/SurfaceComposerClient.h> |
Marin Shalamanov | a7fe304 | 2021-01-29 21:02:08 +0100 | [diff] [blame] | 23 | #include <ui/DisplayMode.h> |
Dominik Laskowski | 3cb3d4e | 2019-11-21 11:14:45 -0800 | [diff] [blame] | 24 | |
| 25 | namespace android { |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 26 | |
| 27 | GLHelper::GLHelper() : |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 28 | mDisplay(EGL_NO_DISPLAY), |
| 29 | mContext(EGL_NO_CONTEXT), |
| 30 | mDummySurface(EGL_NO_SURFACE), |
| 31 | mConfig(0), |
Yi Kong | c67f9a4 | 2018-07-20 13:39:55 -0700 | [diff] [blame] | 32 | mShaderPrograms(nullptr), |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 33 | mDitherTexture(0) { |
| 34 | } |
| 35 | |
| 36 | GLHelper::~GLHelper() { |
| 37 | } |
| 38 | |
Huihong Luo | 31b5ac2 | 2022-08-15 20:38:10 -0700 | [diff] [blame] | 39 | bool GLHelper::setUp(const sp<IBinder>& displayToken, const ShaderDesc* shaderDescs, |
| 40 | size_t numShaders) { |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 41 | bool result; |
| 42 | |
Huihong Luo | 31b5ac2 | 2022-08-15 20:38:10 -0700 | [diff] [blame] | 43 | mDisplayToken = displayToken; |
| 44 | |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 45 | mDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY); |
| 46 | if (mDisplay == EGL_NO_DISPLAY) { |
| 47 | fprintf(stderr, "eglGetDisplay error: %#x\n", eglGetError()); |
| 48 | return false; |
| 49 | } |
| 50 | |
| 51 | EGLint majorVersion; |
| 52 | EGLint minorVersion; |
| 53 | result = eglInitialize(mDisplay, &majorVersion, &minorVersion); |
| 54 | if (result != EGL_TRUE) { |
| 55 | fprintf(stderr, "eglInitialize error: %#x\n", eglGetError()); |
| 56 | return false; |
| 57 | } |
| 58 | |
| 59 | EGLint numConfigs = 0; |
| 60 | EGLint configAttribs[] = { |
| 61 | EGL_SURFACE_TYPE, EGL_WINDOW_BIT, |
| 62 | EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, |
| 63 | EGL_RED_SIZE, 8, |
| 64 | EGL_GREEN_SIZE, 8, |
| 65 | EGL_BLUE_SIZE, 8, |
| 66 | EGL_ALPHA_SIZE, 8, |
| 67 | EGL_NONE |
| 68 | }; |
| 69 | result = eglChooseConfig(mDisplay, configAttribs, &mConfig, 1, |
| 70 | &numConfigs); |
| 71 | if (result != EGL_TRUE) { |
| 72 | fprintf(stderr, "eglChooseConfig error: %#x\n", eglGetError()); |
| 73 | return false; |
| 74 | } |
| 75 | |
| 76 | EGLint contextAttribs[] = { |
| 77 | EGL_CONTEXT_CLIENT_VERSION, 2, |
| 78 | EGL_NONE |
| 79 | }; |
| 80 | mContext = eglCreateContext(mDisplay, mConfig, EGL_NO_CONTEXT, |
| 81 | contextAttribs); |
| 82 | if (mContext == EGL_NO_CONTEXT) { |
| 83 | fprintf(stderr, "eglCreateContext error: %#x\n", eglGetError()); |
| 84 | return false; |
| 85 | } |
| 86 | |
| 87 | bool resultb = createNamedSurfaceTexture(0, 1, 1, &mDummyGLConsumer, |
| 88 | &mDummySurface); |
| 89 | if (!resultb) { |
| 90 | return false; |
| 91 | } |
| 92 | |
| 93 | resultb = makeCurrent(mDummySurface); |
| 94 | if (!resultb) { |
| 95 | return false; |
| 96 | } |
| 97 | |
| 98 | resultb = setUpShaders(shaderDescs, numShaders); |
| 99 | if (!resultb) { |
| 100 | return false; |
| 101 | } |
| 102 | |
| 103 | return true; |
| 104 | } |
| 105 | |
| 106 | void GLHelper::tearDown() { |
Yi Kong | c67f9a4 | 2018-07-20 13:39:55 -0700 | [diff] [blame] | 107 | if (mShaderPrograms != nullptr) { |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 108 | delete[] mShaderPrograms; |
Yi Kong | c67f9a4 | 2018-07-20 13:39:55 -0700 | [diff] [blame] | 109 | mShaderPrograms = nullptr; |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 110 | } |
| 111 | |
Yi Kong | c67f9a4 | 2018-07-20 13:39:55 -0700 | [diff] [blame] | 112 | if (mSurfaceComposerClient != nullptr) { |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 113 | mSurfaceComposerClient->dispose(); |
| 114 | mSurfaceComposerClient.clear(); |
| 115 | } |
| 116 | |
| 117 | if (mDisplay != EGL_NO_DISPLAY) { |
| 118 | eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, |
| 119 | EGL_NO_CONTEXT); |
| 120 | } |
| 121 | |
| 122 | if (mContext != EGL_NO_CONTEXT) { |
| 123 | eglDestroyContext(mDisplay, mContext); |
| 124 | } |
| 125 | |
| 126 | if (mDummySurface != EGL_NO_SURFACE) { |
| 127 | eglDestroySurface(mDisplay, mDummySurface); |
| 128 | } |
| 129 | |
| 130 | mDisplay = EGL_NO_DISPLAY; |
| 131 | mContext = EGL_NO_CONTEXT; |
| 132 | mDummySurface = EGL_NO_SURFACE; |
| 133 | mDummyGLConsumer.clear(); |
| 134 | mConfig = 0; |
| 135 | } |
| 136 | |
| 137 | bool GLHelper::makeCurrent(EGLSurface surface) { |
| 138 | EGLint result; |
| 139 | |
| 140 | result = eglMakeCurrent(mDisplay, surface, surface, mContext); |
| 141 | if (result != EGL_TRUE) { |
| 142 | fprintf(stderr, "eglMakeCurrent error: %#x\n", eglGetError()); |
| 143 | return false; |
| 144 | } |
| 145 | |
| 146 | EGLint w, h; |
| 147 | eglQuerySurface(mDisplay, surface, EGL_WIDTH, &w); |
| 148 | eglQuerySurface(mDisplay, surface, EGL_HEIGHT, &h); |
| 149 | glViewport(0, 0, w, h); |
| 150 | |
| 151 | return true; |
| 152 | } |
| 153 | |
| 154 | bool GLHelper::createSurfaceTexture(uint32_t w, uint32_t h, |
| 155 | sp<GLConsumer>* glConsumer, EGLSurface* surface, |
| 156 | GLuint* name) { |
| 157 | if (!makeCurrent(mDummySurface)) { |
| 158 | return false; |
| 159 | } |
| 160 | |
| 161 | *name = 0; |
| 162 | glGenTextures(1, name); |
| 163 | if (*name == 0) { |
| 164 | fprintf(stderr, "glGenTextures error: %#x\n", glGetError()); |
| 165 | return false; |
| 166 | } |
| 167 | |
| 168 | return createNamedSurfaceTexture(*name, w, h, glConsumer, surface); |
| 169 | } |
| 170 | |
| 171 | void GLHelper::destroySurface(EGLSurface* surface) { |
| 172 | if (eglGetCurrentSurface(EGL_READ) == *surface || |
| 173 | eglGetCurrentSurface(EGL_DRAW) == *surface) { |
| 174 | eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, |
| 175 | EGL_NO_CONTEXT); |
| 176 | } |
| 177 | eglDestroySurface(mDisplay, *surface); |
| 178 | *surface = EGL_NO_SURFACE; |
| 179 | } |
| 180 | |
| 181 | bool GLHelper::swapBuffers(EGLSurface surface) { |
| 182 | EGLint result; |
| 183 | result = eglSwapBuffers(mDisplay, surface); |
| 184 | if (result != EGL_TRUE) { |
| 185 | fprintf(stderr, "eglSwapBuffers error: %#x\n", eglGetError()); |
| 186 | return false; |
| 187 | } |
| 188 | return true; |
| 189 | } |
| 190 | |
| 191 | bool GLHelper::getShaderProgram(const char* name, GLuint* outPgm) { |
| 192 | for (size_t i = 0; i < mNumShaders; i++) { |
| 193 | if (strcmp(mShaderDescs[i].name, name) == 0) { |
| 194 | *outPgm = mShaderPrograms[i]; |
| 195 | return true; |
| 196 | } |
| 197 | } |
| 198 | |
| 199 | fprintf(stderr, "unknown shader name: \"%s\"\n", name); |
| 200 | |
| 201 | return false; |
| 202 | } |
| 203 | |
| 204 | bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h, |
| 205 | sp<GLConsumer>* glConsumer, EGLSurface* surface) { |
Jim Shargo | a281888 | 2024-07-27 02:52:58 +0000 | [diff] [blame^] | 206 | #if COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) |
| 207 | sp<GLConsumer> glc = new GLConsumer(name, GL_TEXTURE_EXTERNAL_OES, false, true); |
| 208 | glc->setDefaultBufferSize(w, h); |
| 209 | glc->getSurface()->setMaxDequeuedBufferCount(2); |
| 210 | glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); |
| 211 | |
| 212 | sp<ANativeWindow> anw = glc->getSurface(); |
| 213 | #else |
Dan Stoza | 6780a2d | 2014-03-13 11:31:43 -0700 | [diff] [blame] | 214 | sp<IGraphicBufferProducer> producer; |
| 215 | sp<IGraphicBufferConsumer> consumer; |
Mathias Agopian | 0556d79 | 2017-03-22 15:49:32 -0700 | [diff] [blame] | 216 | BufferQueue::createBufferQueue(&producer, &consumer); |
Dan Stoza | 6780a2d | 2014-03-13 11:31:43 -0700 | [diff] [blame] | 217 | sp<GLConsumer> glc = new GLConsumer(consumer, name, |
Dan Stoza | e49ba8e | 2014-06-24 13:09:19 -0700 | [diff] [blame] | 218 | GL_TEXTURE_EXTERNAL_OES, false, true); |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 219 | glc->setDefaultBufferSize(w, h); |
Pablo Ceballos | 19e3e06 | 2015-08-19 16:16:06 -0700 | [diff] [blame] | 220 | producer->setMaxDequeuedBufferCount(2); |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 221 | glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER); |
| 222 | |
Dan Stoza | 6780a2d | 2014-03-13 11:31:43 -0700 | [diff] [blame] | 223 | sp<ANativeWindow> anw = new Surface(producer); |
Jim Shargo | a281888 | 2024-07-27 02:52:58 +0000 | [diff] [blame^] | 224 | #endif // COM_ANDROID_GRAPHICS_LIBGUI_FLAGS(WB_CONSUMER_BASE_OWNS_BQ) |
Yi Kong | c67f9a4 | 2018-07-20 13:39:55 -0700 | [diff] [blame] | 225 | EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr); |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 226 | if (s == EGL_NO_SURFACE) { |
| 227 | fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError()); |
| 228 | return false; |
| 229 | } |
| 230 | |
| 231 | *glConsumer = glc; |
| 232 | *surface = s; |
| 233 | return true; |
| 234 | } |
| 235 | |
| 236 | bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) { |
Marin Shalamanov | a7fe304 | 2021-01-29 21:02:08 +0100 | [diff] [blame] | 237 | ui::DisplayMode mode; |
Huihong Luo | 31b5ac2 | 2022-08-15 20:38:10 -0700 | [diff] [blame] | 238 | status_t err = mSurfaceComposerClient->getActiveDisplayMode(mDisplayToken, &mode); |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 239 | if (err != NO_ERROR) { |
Marin Shalamanov | a7fe304 | 2021-01-29 21:02:08 +0100 | [diff] [blame] | 240 | fprintf(stderr, "SurfaceComposer::getActiveDisplayMode failed: %#x\n", err); |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 241 | return false; |
| 242 | } |
| 243 | |
Marin Shalamanov | a7fe304 | 2021-01-29 21:02:08 +0100 | [diff] [blame] | 244 | float scaleX = static_cast<float>(mode.resolution.getWidth()) / w; |
| 245 | float scaleY = static_cast<float>(mode.resolution.getHeight()) / h; |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 246 | *scale = scaleX < scaleY ? scaleX : scaleY; |
| 247 | |
| 248 | return true; |
| 249 | } |
| 250 | |
| 251 | bool GLHelper::createWindowSurface(uint32_t w, uint32_t h, |
| 252 | sp<SurfaceControl>* surfaceControl, EGLSurface* surface) { |
| 253 | bool result; |
| 254 | status_t err; |
| 255 | |
Yi Kong | c67f9a4 | 2018-07-20 13:39:55 -0700 | [diff] [blame] | 256 | if (mSurfaceComposerClient == nullptr) { |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 257 | mSurfaceComposerClient = new SurfaceComposerClient; |
| 258 | } |
| 259 | err = mSurfaceComposerClient->initCheck(); |
| 260 | if (err != NO_ERROR) { |
| 261 | fprintf(stderr, "SurfaceComposerClient::initCheck error: %#x\n", err); |
| 262 | return false; |
| 263 | } |
| 264 | |
| 265 | sp<SurfaceControl> sc = mSurfaceComposerClient->createSurface( |
| 266 | String8("Benchmark"), w, h, PIXEL_FORMAT_RGBA_8888, 0); |
Yi Kong | c67f9a4 | 2018-07-20 13:39:55 -0700 | [diff] [blame] | 267 | if (sc == nullptr || !sc->isValid()) { |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 268 | fprintf(stderr, "Failed to create SurfaceControl.\n"); |
| 269 | return false; |
| 270 | } |
| 271 | |
| 272 | float scale; |
| 273 | result = computeWindowScale(w, h, &scale); |
| 274 | if (!result) { |
| 275 | return false; |
| 276 | } |
| 277 | |
Robert Carr | 4cdc58f | 2017-08-23 14:22:20 -0700 | [diff] [blame] | 278 | SurfaceComposerClient::Transaction{}.setLayer(sc, 0x7FFFFFFF) |
| 279 | .setMatrix(sc, scale, 0.0f, 0.0f, scale) |
| 280 | .show(sc) |
| 281 | .apply(); |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 282 | |
| 283 | sp<ANativeWindow> anw = sc->getSurface(); |
Yi Kong | c67f9a4 | 2018-07-20 13:39:55 -0700 | [diff] [blame] | 284 | EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr); |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 285 | if (s == EGL_NO_SURFACE) { |
| 286 | fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError()); |
| 287 | return false; |
| 288 | } |
| 289 | |
| 290 | *surfaceControl = sc; |
| 291 | *surface = s; |
| 292 | return true; |
| 293 | } |
| 294 | |
| 295 | static bool compileShader(GLenum shaderType, const char* src, |
| 296 | GLuint* outShader) { |
| 297 | GLuint shader = glCreateShader(shaderType); |
| 298 | if (shader == 0) { |
| 299 | fprintf(stderr, "glCreateShader error: %#x\n", glGetError()); |
| 300 | return false; |
| 301 | } |
| 302 | |
Yi Kong | c67f9a4 | 2018-07-20 13:39:55 -0700 | [diff] [blame] | 303 | glShaderSource(shader, 1, &src, nullptr); |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 304 | glCompileShader(shader); |
| 305 | |
| 306 | GLint compiled = 0; |
| 307 | glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled); |
| 308 | if (!compiled) { |
| 309 | GLint infoLen = 0; |
| 310 | glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen); |
| 311 | if (infoLen) { |
| 312 | char* buf = new char[infoLen]; |
| 313 | if (buf) { |
Yi Kong | c67f9a4 | 2018-07-20 13:39:55 -0700 | [diff] [blame] | 314 | glGetShaderInfoLog(shader, infoLen, nullptr, buf); |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 315 | fprintf(stderr, "Shader compile log:\n%s\n", buf); |
| 316 | delete[] buf; |
| 317 | } |
| 318 | } |
| 319 | glDeleteShader(shader); |
| 320 | return false; |
| 321 | } |
| 322 | *outShader = shader; |
| 323 | return true; |
| 324 | } |
| 325 | |
| 326 | static void printShaderSource(const char* const* src) { |
Yi Kong | c67f9a4 | 2018-07-20 13:39:55 -0700 | [diff] [blame] | 327 | for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) { |
Mark Salyzyn | 92dc3fc | 2014-03-12 13:12:44 -0700 | [diff] [blame] | 328 | fprintf(stderr, "%3zu: %s\n", i+1, src[i]); |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 329 | } |
| 330 | } |
| 331 | |
| 332 | static const char* makeShaderString(const char* const* src) { |
| 333 | size_t len = 0; |
Yi Kong | c67f9a4 | 2018-07-20 13:39:55 -0700 | [diff] [blame] | 334 | for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) { |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 335 | // The +1 is for the '\n' that will be added. |
| 336 | len += strlen(src[i]) + 1; |
| 337 | } |
| 338 | |
| 339 | char* result = new char[len+1]; |
| 340 | char* end = result; |
Yi Kong | c67f9a4 | 2018-07-20 13:39:55 -0700 | [diff] [blame] | 341 | for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) { |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 342 | strcpy(end, src[i]); |
| 343 | end += strlen(src[i]); |
| 344 | *end = '\n'; |
| 345 | end++; |
| 346 | } |
| 347 | *end = '\0'; |
| 348 | |
| 349 | return result; |
| 350 | } |
| 351 | |
| 352 | static bool compileShaderLines(GLenum shaderType, const char* const* lines, |
| 353 | GLuint* outShader) { |
| 354 | const char* src = makeShaderString(lines); |
| 355 | bool result = compileShader(shaderType, src, outShader); |
| 356 | if (!result) { |
| 357 | fprintf(stderr, "Shader source:\n"); |
| 358 | printShaderSource(lines); |
Manoj Gupta | 4122118 | 2016-11-01 17:30:24 -0700 | [diff] [blame] | 359 | delete[] src; |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 360 | return false; |
| 361 | } |
| 362 | delete[] src; |
| 363 | |
| 364 | return true; |
| 365 | } |
| 366 | |
| 367 | static bool linkShaderProgram(GLuint vs, GLuint fs, GLuint* outPgm) { |
| 368 | GLuint program = glCreateProgram(); |
| 369 | if (program == 0) { |
| 370 | fprintf(stderr, "glCreateProgram error: %#x\n", glGetError()); |
| 371 | return false; |
| 372 | } |
| 373 | |
| 374 | glAttachShader(program, vs); |
| 375 | glAttachShader(program, fs); |
| 376 | glLinkProgram(program); |
| 377 | GLint linkStatus = GL_FALSE; |
| 378 | glGetProgramiv(program, GL_LINK_STATUS, &linkStatus); |
| 379 | if (linkStatus != GL_TRUE) { |
| 380 | GLint bufLength = 0; |
| 381 | glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength); |
| 382 | if (bufLength) { |
| 383 | char* buf = new char[bufLength]; |
| 384 | if (buf) { |
Yi Kong | c67f9a4 | 2018-07-20 13:39:55 -0700 | [diff] [blame] | 385 | glGetProgramInfoLog(program, bufLength, nullptr, buf); |
Jamie Gennis | 9c183f2 | 2012-12-03 16:44:16 -0800 | [diff] [blame] | 386 | fprintf(stderr, "Program link log:\n%s\n", buf); |
| 387 | delete[] buf; |
| 388 | } |
| 389 | } |
| 390 | glDeleteProgram(program); |
| 391 | program = 0; |
| 392 | } |
| 393 | |
| 394 | *outPgm = program; |
| 395 | return program != 0; |
| 396 | } |
| 397 | |
| 398 | bool GLHelper::setUpShaders(const ShaderDesc* shaderDescs, size_t numShaders) { |
| 399 | mShaderPrograms = new GLuint[numShaders]; |
| 400 | bool result = true; |
| 401 | |
| 402 | for (size_t i = 0; i < numShaders && result; i++) { |
| 403 | GLuint vs, fs; |
| 404 | |
| 405 | result = compileShaderLines(GL_VERTEX_SHADER, |
| 406 | shaderDescs[i].vertexShader, &vs); |
| 407 | if (!result) { |
| 408 | return false; |
| 409 | } |
| 410 | |
| 411 | result = compileShaderLines(GL_FRAGMENT_SHADER, |
| 412 | shaderDescs[i].fragmentShader, &fs); |
| 413 | if (!result) { |
| 414 | glDeleteShader(vs); |
| 415 | return false; |
| 416 | } |
| 417 | |
| 418 | result = linkShaderProgram(vs, fs, &mShaderPrograms[i]); |
| 419 | glDeleteShader(vs); |
| 420 | glDeleteShader(fs); |
| 421 | } |
| 422 | |
| 423 | mNumShaders = numShaders; |
| 424 | mShaderDescs = shaderDescs; |
| 425 | |
| 426 | return result; |
| 427 | } |
| 428 | |
| 429 | bool GLHelper::getDitherTexture(GLuint* outTexName) { |
| 430 | if (mDitherTexture == 0) { |
| 431 | const uint8_t pattern[] = { |
| 432 | 0, 8, 2, 10, |
| 433 | 12, 4, 14, 6, |
| 434 | 3, 11, 1, 9, |
| 435 | 15, 7, 13, 5 |
| 436 | }; |
| 437 | |
| 438 | glGenTextures(1, &mDitherTexture); |
| 439 | glBindTexture(GL_TEXTURE_2D, mDitherTexture); |
| 440 | |
| 441 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); |
| 442 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); |
| 443 | |
| 444 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); |
| 445 | glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); |
| 446 | |
| 447 | glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, DITHER_KERNEL_SIZE, |
| 448 | DITHER_KERNEL_SIZE, 0, GL_ALPHA, GL_UNSIGNED_BYTE, &pattern); |
| 449 | } |
| 450 | |
| 451 | *outTexName = mDitherTexture; |
| 452 | |
| 453 | return true; |
| 454 | } |
| 455 | |
| 456 | } |