1 /* 2 * Copyright (C) 2011 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 17 #include <ui/FramebufferNativeWindow.h> 18 #include <ui/PixelFormat.h> 19 20 #include <system/window.h> 21 22 #include <sys/types.h> 23 #include <sys/resource.h> 24 #include <sched.h> 25 26 #include <cutils/properties.h> 27 28 #include <GLES/gl.h> 29 #include <GLES/glext.h> 30 #include <GLES2/gl2.h> 31 #include <GLES2/gl2ext.h> 32 33 #include <string.h> 34 35 #include "rsdCore.h" 36 #include "rsdGL.h" 37 38 #include <malloc.h> 39 #include "rsContext.h" 40 #include "rsDevice.h" 41 #include "rsdShaderCache.h" 42 #include "rsdVertexArray.h" 43 #include "rsdFrameBufferObj.h" 44 45 #include <gui/Surface.h> 46 #include <gui/DummyConsumer.h> 47 48 using namespace android; 49 using namespace android::renderscript; 50 51 static int32_t gGLContextCount = 0; 52 53 static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) { 54 struct EGLUtils { 55 static const char *strerror(EGLint err) { 56 switch (err){ 57 case EGL_SUCCESS: return "EGL_SUCCESS"; 58 case EGL_NOT_INITIALIZED: return "EGL_NOT_INITIALIZED"; 59 case EGL_BAD_ACCESS: return "EGL_BAD_ACCESS"; 60 case EGL_BAD_ALLOC: return "EGL_BAD_ALLOC"; 61 case EGL_BAD_ATTRIBUTE: return "EGL_BAD_ATTRIBUTE"; 62 case EGL_BAD_CONFIG: return "EGL_BAD_CONFIG"; 63 case EGL_BAD_CONTEXT: return "EGL_BAD_CONTEXT"; 64 case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE"; 65 case EGL_BAD_DISPLAY: return "EGL_BAD_DISPLAY"; 66 case EGL_BAD_MATCH: return "EGL_BAD_MATCH"; 67 case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP"; 68 case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW"; 69 case EGL_BAD_PARAMETER: return "EGL_BAD_PARAMETER"; 70 case EGL_BAD_SURFACE: return "EGL_BAD_SURFACE"; 71 case EGL_CONTEXT_LOST: return "EGL_CONTEXT_LOST"; 72 default: return "UNKNOWN"; 73 } 74 } 75 }; 76 77 if (returnVal != EGL_TRUE) { 78 fprintf(stderr, "%s() returned %d\n", op, returnVal); 79 } 80 81 for (EGLint error = eglGetError(); error != EGL_SUCCESS; error 82 = eglGetError()) { 83 fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error), 84 error); 85 } 86 } 87 88 static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) { 89 90 #define X(VAL) {VAL, #VAL} 91 struct {EGLint attribute; const char* name;} names[] = { 92 X(EGL_BUFFER_SIZE), 93 X(EGL_ALPHA_SIZE), 94 X(EGL_BLUE_SIZE), 95 X(EGL_GREEN_SIZE), 96 X(EGL_RED_SIZE), 97 X(EGL_DEPTH_SIZE), 98 X(EGL_STENCIL_SIZE), 99 X(EGL_CONFIG_CAVEAT), 100 X(EGL_CONFIG_ID), 101 X(EGL_LEVEL), 102 X(EGL_MAX_PBUFFER_HEIGHT), 103 X(EGL_MAX_PBUFFER_PIXELS), 104 X(EGL_MAX_PBUFFER_WIDTH), 105 X(EGL_NATIVE_RENDERABLE), 106 X(EGL_NATIVE_VISUAL_ID), 107 X(EGL_NATIVE_VISUAL_TYPE), 108 X(EGL_SAMPLES), 109 X(EGL_SAMPLE_BUFFERS), 110 X(EGL_SURFACE_TYPE), 111 X(EGL_TRANSPARENT_TYPE), 112 X(EGL_TRANSPARENT_RED_VALUE), 113 X(EGL_TRANSPARENT_GREEN_VALUE), 114 X(EGL_TRANSPARENT_BLUE_VALUE), 115 X(EGL_BIND_TO_TEXTURE_RGB), 116 X(EGL_BIND_TO_TEXTURE_RGBA), 117 X(EGL_MIN_SWAP_INTERVAL), 118 X(EGL_MAX_SWAP_INTERVAL), 119 X(EGL_LUMINANCE_SIZE), 120 X(EGL_ALPHA_MASK_SIZE), 121 X(EGL_COLOR_BUFFER_TYPE), 122 X(EGL_RENDERABLE_TYPE), 123 X(EGL_CONFORMANT), 124 }; 125 #undef X 126 127 for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) { 128 EGLint value = -1; 129 EGLBoolean returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value); 130 if (returnVal) { 131 ALOGV(" %s: %d (0x%x)", names[j].name, value, value); 132 } 133 } 134 } 135 136 static void DumpDebug(RsdHal *dc) { 137 ALOGE(" EGL ver %i %i", dc->gl.egl.majorVersion, dc->gl.egl.minorVersion); 138 ALOGE(" EGL context %p surface %p, Display=%p", dc->gl.egl.context, dc->gl.egl.surface, 139 dc->gl.egl.display); 140 ALOGE(" GL vendor: %s", dc->gl.gl.vendor); 141 ALOGE(" GL renderer: %s", dc->gl.gl.renderer); 142 ALOGE(" GL Version: %s", dc->gl.gl.version); 143 ALOGE(" GL Extensions: %s", dc->gl.gl.extensions); 144 ALOGE(" GL int Versions %i %i", dc->gl.gl.majorVersion, dc->gl.gl.minorVersion); 145 146 ALOGV("MAX Textures %i, %i %i", dc->gl.gl.maxVertexTextureUnits, 147 dc->gl.gl.maxFragmentTextureImageUnits, dc->gl.gl.maxTextureImageUnits); 148 ALOGV("MAX Attribs %i", dc->gl.gl.maxVertexAttribs); 149 ALOGV("MAX Uniforms %i, %i", dc->gl.gl.maxVertexUniformVectors, 150 dc->gl.gl.maxFragmentUniformVectors); 151 ALOGV("MAX Varyings %i", dc->gl.gl.maxVaryingVectors); 152 } 153 154 void rsdGLShutdown(const Context *rsc) { 155 RsdHal *dc = (RsdHal *)rsc->mHal.drv; 156 157 rsdGLSetSurface(rsc, 0, 0, NULL); 158 dc->gl.shaderCache->cleanupAll(); 159 delete dc->gl.shaderCache; 160 delete dc->gl.vertexArrayState; 161 162 if (dc->gl.egl.context != EGL_NO_CONTEXT) { 163 RSD_CALL_GL(eglMakeCurrent, dc->gl.egl.display, 164 EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); 165 RSD_CALL_GL(eglDestroySurface, dc->gl.egl.display, dc->gl.egl.surfaceDefault); 166 if (dc->gl.egl.surface != EGL_NO_SURFACE) { 167 RSD_CALL_GL(eglDestroySurface, dc->gl.egl.display, dc->gl.egl.surface); 168 } 169 RSD_CALL_GL(eglDestroyContext, dc->gl.egl.display, dc->gl.egl.context); 170 checkEglError("eglDestroyContext"); 171 } 172 173 gGLContextCount--; 174 if (!gGLContextCount) { 175 RSD_CALL_GL(eglTerminate, dc->gl.egl.display); 176 } 177 } 178 179 void getConfigData(const Context *rsc, 180 EGLint *configAttribs, size_t configAttribsLen, 181 uint32_t numSamples) { 182 memset(configAttribs, 0, configAttribsLen*sizeof(*configAttribs)); 183 184 EGLint *configAttribsPtr = configAttribs; 185 186 configAttribsPtr[0] = EGL_SURFACE_TYPE; 187 configAttribsPtr[1] = EGL_WINDOW_BIT; 188 configAttribsPtr += 2; 189 190 configAttribsPtr[0] = EGL_RENDERABLE_TYPE; 191 configAttribsPtr[1] = EGL_OPENGL_ES2_BIT; 192 configAttribsPtr += 2; 193 194 configAttribsPtr[0] = EGL_RED_SIZE; 195 configAttribsPtr[1] = 8; 196 configAttribsPtr += 2; 197 198 configAttribsPtr[0] = EGL_GREEN_SIZE; 199 configAttribsPtr[1] = 8; 200 configAttribsPtr += 2; 201 202 configAttribsPtr[0] = EGL_BLUE_SIZE; 203 configAttribsPtr[1] = 8; 204 configAttribsPtr += 2; 205 206 if (rsc->mUserSurfaceConfig.alphaMin > 0) { 207 configAttribsPtr[0] = EGL_ALPHA_SIZE; 208 configAttribsPtr[1] = rsc->mUserSurfaceConfig.alphaMin; 209 configAttribsPtr += 2; 210 } 211 212 if (rsc->mUserSurfaceConfig.depthMin > 0) { 213 configAttribsPtr[0] = EGL_DEPTH_SIZE; 214 configAttribsPtr[1] = rsc->mUserSurfaceConfig.depthMin; 215 configAttribsPtr += 2; 216 } 217 218 if (rsc->mDev->mForceSW) { 219 configAttribsPtr[0] = EGL_CONFIG_CAVEAT; 220 configAttribsPtr[1] = EGL_SLOW_CONFIG; 221 configAttribsPtr += 2; 222 } 223 224 if (numSamples > 1) { 225 configAttribsPtr[0] = EGL_SAMPLE_BUFFERS; 226 configAttribsPtr[1] = 1; 227 configAttribsPtr[2] = EGL_SAMPLES; 228 configAttribsPtr[3] = numSamples; 229 configAttribsPtr += 4; 230 } 231 232 configAttribsPtr[0] = EGL_NONE; 233 rsAssert(configAttribsPtr < (configAttribs + configAttribsLen)); 234 } 235 236 bool rsdGLInit(const Context *rsc) { 237 RsdHal *dc = (RsdHal *)rsc->mHal.drv; 238 239 dc->gl.egl.numConfigs = -1; 240 241 EGLint configAttribs[128]; 242 EGLint context_attribs2[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE }; 243 244 ALOGV("%p initEGL start", rsc); 245 rsc->setWatchdogGL("eglGetDisplay", __LINE__, __FILE__); 246 dc->gl.egl.display = eglGetDisplay(EGL_DEFAULT_DISPLAY); 247 checkEglError("eglGetDisplay"); 248 249 RSD_CALL_GL(eglInitialize, dc->gl.egl.display, 250 &dc->gl.egl.majorVersion, &dc->gl.egl.minorVersion); 251 checkEglError("eglInitialize"); 252 253 EGLBoolean ret; 254 255 EGLint numConfigs = -1, n = 0; 256 rsc->setWatchdogGL("eglChooseConfig", __LINE__, __FILE__); 257 258 // Try minding a multisample config that matches the user request 259 uint32_t minSample = rsc->mUserSurfaceConfig.samplesMin; 260 uint32_t prefSample = rsc->mUserSurfaceConfig.samplesPref; 261 for (uint32_t sampleCount = prefSample; sampleCount >= minSample; sampleCount--) { 262 getConfigData(rsc, configAttribs, (sizeof(configAttribs) / sizeof(EGLint)), sampleCount); 263 ret = eglChooseConfig(dc->gl.egl.display, configAttribs, 0, 0, &numConfigs); 264 checkEglError("eglGetConfigs", ret); 265 if (numConfigs > 0) { 266 break; 267 } 268 } 269 270 if (numConfigs) { 271 EGLConfig* const configs = new EGLConfig[numConfigs]; 272 273 rsc->setWatchdogGL("eglChooseConfig", __LINE__, __FILE__); 274 ret = eglChooseConfig(dc->gl.egl.display, 275 configAttribs, configs, numConfigs, &n); 276 if (!ret || !n) { 277 checkEglError("eglChooseConfig", ret); 278 ALOGE("%p, couldn't find an EGLConfig matching the screen format\n", rsc); 279 } 280 281 // The first config is guaranteed to over-satisfy the constraints 282 dc->gl.egl.config = configs[0]; 283 284 // go through the list and skip configs that over-satisfy our needs 285 for (int i=0 ; i<n ; i++) { 286 if (rsc->mUserSurfaceConfig.alphaMin <= 0) { 287 EGLint alphaSize; 288 eglGetConfigAttrib(dc->gl.egl.display, 289 configs[i], EGL_ALPHA_SIZE, &alphaSize); 290 if (alphaSize > 0) { 291 continue; 292 } 293 } 294 295 if (rsc->mUserSurfaceConfig.depthMin <= 0) { 296 EGLint depthSize; 297 eglGetConfigAttrib(dc->gl.egl.display, 298 configs[i], EGL_DEPTH_SIZE, &depthSize); 299 if (depthSize > 0) { 300 continue; 301 } 302 } 303 304 // Found one! 305 dc->gl.egl.config = configs[i]; 306 break; 307 } 308 309 delete [] configs; 310 } 311 312 //if (props.mLogVisual) { 313 if (0) { 314 printEGLConfiguration(dc->gl.egl.display, dc->gl.egl.config); 315 } 316 //} 317 318 rsc->setWatchdogGL("eglCreateContext", __LINE__, __FILE__); 319 dc->gl.egl.context = eglCreateContext(dc->gl.egl.display, dc->gl.egl.config, 320 EGL_NO_CONTEXT, context_attribs2); 321 checkEglError("eglCreateContext"); 322 if (dc->gl.egl.context == EGL_NO_CONTEXT) { 323 ALOGE("%p, eglCreateContext returned EGL_NO_CONTEXT", rsc); 324 rsc->setWatchdogGL(NULL, 0, NULL); 325 return false; 326 } 327 gGLContextCount++; 328 329 // Create a BufferQueue with a fake consumer 330 sp<BufferQueue> bq = new BufferQueue(); 331 bq->consumerConnect(new DummyConsumer()); 332 sp<Surface> stc(new Surface(static_cast<sp<IGraphicBufferProducer> >(bq))); 333 334 dc->gl.egl.surfaceDefault = eglCreateWindowSurface(dc->gl.egl.display, dc->gl.egl.config, 335 static_cast<ANativeWindow*>(stc.get()), 336 NULL); 337 338 checkEglError("eglCreateWindowSurface"); 339 if (dc->gl.egl.surfaceDefault == EGL_NO_SURFACE) { 340 ALOGE("eglCreateWindowSurface returned EGL_NO_SURFACE"); 341 rsdGLShutdown(rsc); 342 rsc->setWatchdogGL(NULL, 0, NULL); 343 return false; 344 } 345 346 rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__); 347 ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault, 348 dc->gl.egl.surfaceDefault, dc->gl.egl.context); 349 if (ret == EGL_FALSE) { 350 ALOGE("eglMakeCurrent returned EGL_FALSE"); 351 checkEglError("eglMakeCurrent", ret); 352 rsdGLShutdown(rsc); 353 rsc->setWatchdogGL(NULL, 0, NULL); 354 return false; 355 } 356 357 dc->gl.gl.version = glGetString(GL_VERSION); 358 dc->gl.gl.vendor = glGetString(GL_VENDOR); 359 dc->gl.gl.renderer = glGetString(GL_RENDERER); 360 dc->gl.gl.extensions = glGetString(GL_EXTENSIONS); 361 362 //ALOGV("EGL Version %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion); 363 //ALOGV("GL Version %s", mGL.mVersion); 364 //ALOGV("GL Vendor %s", mGL.mVendor); 365 //ALOGV("GL Renderer %s", mGL.mRenderer); 366 //ALOGV("GL Extensions %s", mGL.mExtensions); 367 368 const char *verptr = NULL; 369 if (strlen((const char *)dc->gl.gl.version) > 9) { 370 if (!memcmp(dc->gl.gl.version, "OpenGL ES-CM", 12)) { 371 verptr = (const char *)dc->gl.gl.version + 12; 372 } 373 if (!memcmp(dc->gl.gl.version, "OpenGL ES ", 10)) { 374 verptr = (const char *)dc->gl.gl.version + 9; 375 } 376 } 377 378 if (!verptr) { 379 ALOGE("Error, OpenGL ES Lite not supported"); 380 rsdGLShutdown(rsc); 381 rsc->setWatchdogGL(NULL, 0, NULL); 382 return false; 383 } else { 384 sscanf(verptr, " %i.%i", &dc->gl.gl.majorVersion, &dc->gl.gl.minorVersion); 385 } 386 387 glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &dc->gl.gl.maxVertexAttribs); 388 glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &dc->gl.gl.maxVertexUniformVectors); 389 glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxVertexTextureUnits); 390 391 glGetIntegerv(GL_MAX_VARYING_VECTORS, &dc->gl.gl.maxVaryingVectors); 392 glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxTextureImageUnits); 393 394 glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxFragmentTextureImageUnits); 395 glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &dc->gl.gl.maxFragmentUniformVectors); 396 397 dc->gl.gl.OES_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions, 398 "GL_OES_texture_npot"); 399 dc->gl.gl.IMG_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions, 400 "GL_IMG_texture_npot"); 401 dc->gl.gl.NV_texture_npot_2D_mipmap = NULL != strstr((const char *)dc->gl.gl.extensions, 402 "GL_NV_texture_npot_2D_mipmap"); 403 dc->gl.gl.EXT_texture_max_aniso = 1.0f; 404 bool hasAniso = NULL != strstr((const char *)dc->gl.gl.extensions, 405 "GL_EXT_texture_filter_anisotropic"); 406 if (hasAniso) { 407 glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &dc->gl.gl.EXT_texture_max_aniso); 408 } 409 410 if (0) { 411 DumpDebug(dc); 412 } 413 414 dc->gl.shaderCache = new RsdShaderCache(); 415 dc->gl.vertexArrayState = new RsdVertexArrayState(); 416 dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs); 417 dc->gl.currentFrameBuffer = NULL; 418 dc->mHasGraphics = true; 419 420 ALOGV("%p initGLThread end", rsc); 421 rsc->setWatchdogGL(NULL, 0, NULL); 422 return true; 423 } 424 425 426 bool rsdGLSetInternalSurface(const Context *rsc, RsNativeWindow sur) { 427 RsdHal *dc = (RsdHal *)rsc->mHal.drv; 428 429 EGLBoolean ret; 430 if (dc->gl.egl.surface != NULL) { 431 rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__); 432 ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault, 433 dc->gl.egl.surfaceDefault, dc->gl.egl.context); 434 checkEglError("eglMakeCurrent", ret); 435 436 rsc->setWatchdogGL("eglDestroySurface", __LINE__, __FILE__); 437 ret = eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surface); 438 checkEglError("eglDestroySurface", ret); 439 440 dc->gl.egl.surface = NULL; 441 } 442 443 if (dc->gl.currentWndSurface != NULL) { 444 dc->gl.currentWndSurface->decStrong(NULL); 445 } 446 447 dc->gl.currentWndSurface = (ANativeWindow *)sur; 448 if (dc->gl.currentWndSurface != NULL) { 449 dc->gl.currentWndSurface->incStrong(NULL); 450 451 rsc->setWatchdogGL("eglCreateWindowSurface", __LINE__, __FILE__); 452 dc->gl.egl.surface = eglCreateWindowSurface(dc->gl.egl.display, dc->gl.egl.config, 453 dc->gl.currentWndSurface, NULL); 454 checkEglError("eglCreateWindowSurface"); 455 if (dc->gl.egl.surface == EGL_NO_SURFACE) { 456 ALOGE("eglCreateWindowSurface returned EGL_NO_SURFACE"); 457 } 458 459 rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__); 460 ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surface, 461 dc->gl.egl.surface, dc->gl.egl.context); 462 checkEglError("eglMakeCurrent", ret); 463 } 464 rsc->setWatchdogGL(NULL, 0, NULL); 465 return true; 466 } 467 468 bool rsdGLSetSurface(const Context *rsc, uint32_t w, uint32_t h, RsNativeWindow sur) { 469 RsdHal *dc = (RsdHal *)rsc->mHal.drv; 470 471 if (dc->gl.wndSurface != NULL) { 472 dc->gl.wndSurface->decStrong(NULL); 473 dc->gl.wndSurface = NULL; 474 } 475 if(w && h) { 476 // WAR: Some drivers fail to handle 0 size surfaces correctly. Use the 477 // pbuffer to avoid this pitfall. 478 dc->gl.wndSurface = (ANativeWindow *)sur; 479 if (dc->gl.wndSurface != NULL) { 480 dc->gl.wndSurface->incStrong(NULL); 481 } 482 } 483 484 return rsdGLSetInternalSurface(rsc, sur); 485 } 486 487 void rsdGLSwap(const android::renderscript::Context *rsc) { 488 RsdHal *dc = (RsdHal *)rsc->mHal.drv; 489 RSD_CALL_GL(eglSwapBuffers, dc->gl.egl.display, dc->gl.egl.surface); 490 } 491 492 void rsdGLSetPriority(const Context *rsc, int32_t priority) { 493 if (priority > 0) { 494 // Mark context as low priority. 495 ALOGV("low pri"); 496 } else { 497 ALOGV("normal pri"); 498 } 499 } 500 501 void rsdGLCheckError(const android::renderscript::Context *rsc, 502 const char *msg, bool isFatal) { 503 GLenum err = glGetError(); 504 if (err != GL_NO_ERROR) { 505 char buf[1024]; 506 snprintf(buf, sizeof(buf), "GL Error = 0x%08x, from: %s", err, msg); 507 508 if (isFatal) { 509 rsc->setError(RS_ERROR_FATAL_DRIVER, buf); 510 } else { 511 switch (err) { 512 case GL_OUT_OF_MEMORY: 513 rsc->setError(RS_ERROR_OUT_OF_MEMORY, buf); 514 break; 515 default: 516 rsc->setError(RS_ERROR_DRIVER, buf); 517 break; 518 } 519 } 520 521 ALOGE("%p, %s", rsc, buf); 522 } 523 524 } 525 526 void rsdGLClearColor(const android::renderscript::Context *rsc, 527 float r, float g, float b, float a) { 528 RSD_CALL_GL(glClearColor, r, g, b, a); 529 RSD_CALL_GL(glClear, GL_COLOR_BUFFER_BIT); 530 } 531 532 void rsdGLClearDepth(const android::renderscript::Context *rsc, float v) { 533 RSD_CALL_GL(glClearDepthf, v); 534 RSD_CALL_GL(glClear, GL_DEPTH_BUFFER_BIT); 535 } 536 537 void rsdGLFinish(const android::renderscript::Context *rsc) { 538 RSD_CALL_GL(glFinish); 539 } 540 541 void rsdGLDrawQuadTexCoords(const android::renderscript::Context *rsc, 542 float x1, float y1, float z1, float u1, float v1, 543 float x2, float y2, float z2, float u2, float v2, 544 float x3, float y3, float z3, float u3, float v3, 545 float x4, float y4, float z4, float u4, float v4) { 546 547 float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4}; 548 const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4}; 549 550 RsdVertexArray::Attrib attribs[2]; 551 attribs[0].set(GL_FLOAT, 3, 12, false, (uint32_t)vtx, "ATTRIB_position"); 552 attribs[1].set(GL_FLOAT, 2, 8, false, (uint32_t)tex, "ATTRIB_texture0"); 553 554 RsdVertexArray va(attribs, 2); 555 va.setup(rsc); 556 557 RSD_CALL_GL(glDrawArrays, GL_TRIANGLE_FAN, 0, 4); 558 } 559