rsdGL.cpp revision 58fd6a5f10480551786739280d56dfa620c80b39
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/SurfaceTextureClient.h>
46#include <gui/DummyConsumer.h>
47
48using namespace android;
49using namespace android::renderscript;
50
51static int32_t gGLContextCount = 0;
52
53static 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
88static 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
136static 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
154void 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
179void 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
236bool 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    eglSwapInterval(dc->gl.egl.display, 0);
271
272    if (numConfigs) {
273        EGLConfig* const configs = new EGLConfig[numConfigs];
274
275        rsc->setWatchdogGL("eglChooseConfig", __LINE__, __FILE__);
276        ret = eglChooseConfig(dc->gl.egl.display,
277                configAttribs, configs, numConfigs, &n);
278        if (!ret || !n) {
279            checkEglError("eglChooseConfig", ret);
280            ALOGE("%p, couldn't find an EGLConfig matching the screen format\n", rsc);
281        }
282
283        // The first config is guaranteed to over-satisfy the constraints
284        dc->gl.egl.config = configs[0];
285
286        // go through the list and skip configs that over-satisfy our needs
287        for (int i=0 ; i<n ; i++) {
288            if (rsc->mUserSurfaceConfig.alphaMin <= 0) {
289                EGLint alphaSize;
290                eglGetConfigAttrib(dc->gl.egl.display,
291                        configs[i], EGL_ALPHA_SIZE, &alphaSize);
292                if (alphaSize > 0) {
293                    continue;
294                }
295            }
296
297            if (rsc->mUserSurfaceConfig.depthMin <= 0) {
298                EGLint depthSize;
299                eglGetConfigAttrib(dc->gl.egl.display,
300                        configs[i], EGL_DEPTH_SIZE, &depthSize);
301                if (depthSize > 0) {
302                    continue;
303                }
304            }
305
306            // Found one!
307            dc->gl.egl.config = configs[i];
308            break;
309        }
310
311        delete [] configs;
312    }
313
314    //if (props.mLogVisual) {
315    if (0) {
316        printEGLConfiguration(dc->gl.egl.display, dc->gl.egl.config);
317    }
318    //}
319
320    rsc->setWatchdogGL("eglCreateContext", __LINE__, __FILE__);
321    dc->gl.egl.context = eglCreateContext(dc->gl.egl.display, dc->gl.egl.config,
322                                          EGL_NO_CONTEXT, context_attribs2);
323    checkEglError("eglCreateContext");
324    if (dc->gl.egl.context == EGL_NO_CONTEXT) {
325        ALOGE("%p, eglCreateContext returned EGL_NO_CONTEXT", rsc);
326        rsc->setWatchdogGL(NULL, 0, NULL);
327        return false;
328    }
329    gGLContextCount++;
330
331    // Create a BufferQueue with a fake consumer
332    sp<BufferQueue> bq = new BufferQueue();
333    bq->consumerConnect(new DummyConsumer());
334    sp<SurfaceTextureClient> stc(new SurfaceTextureClient(static_cast<sp<IGraphicBufferProducer> >(bq)));
335
336    dc->gl.egl.surfaceDefault = eglCreateWindowSurface(dc->gl.egl.display, dc->gl.egl.config,
337                                                       static_cast<ANativeWindow*>(stc.get()),
338                                                       NULL);
339
340    checkEglError("eglCreateWindowSurface");
341    if (dc->gl.egl.surfaceDefault == EGL_NO_SURFACE) {
342        ALOGE("eglCreateWindowSurface returned EGL_NO_SURFACE");
343        rsdGLShutdown(rsc);
344        rsc->setWatchdogGL(NULL, 0, NULL);
345        return false;
346    }
347
348    rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
349    ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault,
350                         dc->gl.egl.surfaceDefault, dc->gl.egl.context);
351    if (ret == EGL_FALSE) {
352        ALOGE("eglMakeCurrent returned EGL_FALSE");
353        checkEglError("eglMakeCurrent", ret);
354        rsdGLShutdown(rsc);
355        rsc->setWatchdogGL(NULL, 0, NULL);
356        return false;
357    }
358
359    dc->gl.gl.version = glGetString(GL_VERSION);
360    dc->gl.gl.vendor = glGetString(GL_VENDOR);
361    dc->gl.gl.renderer = glGetString(GL_RENDERER);
362    dc->gl.gl.extensions = glGetString(GL_EXTENSIONS);
363
364    //ALOGV("EGL Version %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion);
365    //ALOGV("GL Version %s", mGL.mVersion);
366    //ALOGV("GL Vendor %s", mGL.mVendor);
367    //ALOGV("GL Renderer %s", mGL.mRenderer);
368    //ALOGV("GL Extensions %s", mGL.mExtensions);
369
370    const char *verptr = NULL;
371    if (strlen((const char *)dc->gl.gl.version) > 9) {
372        if (!memcmp(dc->gl.gl.version, "OpenGL ES-CM", 12)) {
373            verptr = (const char *)dc->gl.gl.version + 12;
374        }
375        if (!memcmp(dc->gl.gl.version, "OpenGL ES ", 10)) {
376            verptr = (const char *)dc->gl.gl.version + 9;
377        }
378    }
379
380    if (!verptr) {
381        ALOGE("Error, OpenGL ES Lite not supported");
382        rsdGLShutdown(rsc);
383        rsc->setWatchdogGL(NULL, 0, NULL);
384        return false;
385    } else {
386        sscanf(verptr, " %i.%i", &dc->gl.gl.majorVersion, &dc->gl.gl.minorVersion);
387    }
388
389    glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &dc->gl.gl.maxVertexAttribs);
390    glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &dc->gl.gl.maxVertexUniformVectors);
391    glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxVertexTextureUnits);
392
393    glGetIntegerv(GL_MAX_VARYING_VECTORS, &dc->gl.gl.maxVaryingVectors);
394    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxTextureImageUnits);
395
396    glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxFragmentTextureImageUnits);
397    glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &dc->gl.gl.maxFragmentUniformVectors);
398
399    dc->gl.gl.OES_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions,
400                                                "GL_OES_texture_npot");
401    dc->gl.gl.IMG_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions,
402                                                   "GL_IMG_texture_npot");
403    dc->gl.gl.NV_texture_npot_2D_mipmap = NULL != strstr((const char *)dc->gl.gl.extensions,
404                                                            "GL_NV_texture_npot_2D_mipmap");
405    dc->gl.gl.EXT_texture_max_aniso = 1.0f;
406    bool hasAniso = NULL != strstr((const char *)dc->gl.gl.extensions,
407                                   "GL_EXT_texture_filter_anisotropic");
408    if (hasAniso) {
409        glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &dc->gl.gl.EXT_texture_max_aniso);
410    }
411
412    if (0) {
413        DumpDebug(dc);
414    }
415
416    dc->gl.shaderCache = new RsdShaderCache();
417    dc->gl.vertexArrayState = new RsdVertexArrayState();
418    dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs);
419    dc->gl.currentFrameBuffer = NULL;
420    dc->mHasGraphics = true;
421
422    ALOGV("%p initGLThread end", rsc);
423    rsc->setWatchdogGL(NULL, 0, NULL);
424    return true;
425}
426
427
428bool rsdGLSetInternalSurface(const Context *rsc, RsNativeWindow sur) {
429    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
430
431    EGLBoolean ret;
432    if (dc->gl.egl.surface != NULL) {
433        rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
434        ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault,
435                             dc->gl.egl.surfaceDefault, dc->gl.egl.context);
436        checkEglError("eglMakeCurrent", ret);
437
438        rsc->setWatchdogGL("eglDestroySurface", __LINE__, __FILE__);
439        ret = eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surface);
440        checkEglError("eglDestroySurface", ret);
441
442        dc->gl.egl.surface = NULL;
443    }
444
445    if (dc->gl.currentWndSurface != NULL) {
446        dc->gl.currentWndSurface->decStrong(NULL);
447    }
448
449    dc->gl.currentWndSurface = (ANativeWindow *)sur;
450    if (dc->gl.currentWndSurface != NULL) {
451        dc->gl.currentWndSurface->incStrong(NULL);
452
453        rsc->setWatchdogGL("eglCreateWindowSurface", __LINE__, __FILE__);
454        dc->gl.egl.surface = eglCreateWindowSurface(dc->gl.egl.display, dc->gl.egl.config,
455                                                    dc->gl.currentWndSurface, NULL);
456        checkEglError("eglCreateWindowSurface");
457        if (dc->gl.egl.surface == EGL_NO_SURFACE) {
458            ALOGE("eglCreateWindowSurface returned EGL_NO_SURFACE");
459        }
460
461        rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
462        ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surface,
463                             dc->gl.egl.surface, dc->gl.egl.context);
464        checkEglError("eglMakeCurrent", ret);
465    }
466    rsc->setWatchdogGL(NULL, 0, NULL);
467    return true;
468}
469
470bool rsdGLSetSurface(const Context *rsc, uint32_t w, uint32_t h, RsNativeWindow sur) {
471    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
472
473    if (dc->gl.wndSurface != NULL) {
474        dc->gl.wndSurface->decStrong(NULL);
475        dc->gl.wndSurface = NULL;
476    }
477    if(w && h) {
478        // WAR: Some drivers fail to handle 0 size surfaces correctly. Use the
479        // pbuffer to avoid this pitfall.
480        dc->gl.wndSurface = (ANativeWindow *)sur;
481        if (dc->gl.wndSurface != NULL) {
482            dc->gl.wndSurface->incStrong(NULL);
483        }
484    }
485
486    return rsdGLSetInternalSurface(rsc, sur);
487}
488
489void rsdGLSwap(const android::renderscript::Context *rsc) {
490    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
491    RSD_CALL_GL(eglSwapBuffers, dc->gl.egl.display, dc->gl.egl.surface);
492}
493
494void rsdGLSetPriority(const Context *rsc, int32_t priority) {
495    if (priority > 0) {
496        // Mark context as low priority.
497        ALOGV("low pri");
498    } else {
499        ALOGV("normal pri");
500    }
501}
502
503void rsdGLCheckError(const android::renderscript::Context *rsc,
504                     const char *msg, bool isFatal) {
505    GLenum err = glGetError();
506    if (err != GL_NO_ERROR) {
507        char buf[1024];
508        snprintf(buf, sizeof(buf), "GL Error = 0x%08x, from: %s", err, msg);
509
510        if (isFatal) {
511            rsc->setError(RS_ERROR_FATAL_DRIVER, buf);
512        } else {
513            switch (err) {
514            case GL_OUT_OF_MEMORY:
515                rsc->setError(RS_ERROR_OUT_OF_MEMORY, buf);
516                break;
517            default:
518                rsc->setError(RS_ERROR_DRIVER, buf);
519                break;
520            }
521        }
522
523        ALOGE("%p, %s", rsc, buf);
524    }
525
526}
527
528void rsdGLClearColor(const android::renderscript::Context *rsc,
529                     float r, float g, float b, float a) {
530    RSD_CALL_GL(glClearColor, r, g, b, a);
531    RSD_CALL_GL(glClear, GL_COLOR_BUFFER_BIT);
532}
533
534void rsdGLClearDepth(const android::renderscript::Context *rsc, float v) {
535    RSD_CALL_GL(glClearDepthf, v);
536    RSD_CALL_GL(glClear, GL_DEPTH_BUFFER_BIT);
537}
538
539void rsdGLFinish(const android::renderscript::Context *rsc) {
540    RSD_CALL_GL(glFinish);
541}
542
543void rsdGLDrawQuadTexCoords(const android::renderscript::Context *rsc,
544                            float x1, float y1, float z1, float u1, float v1,
545                            float x2, float y2, float z2, float u2, float v2,
546                            float x3, float y3, float z3, float u3, float v3,
547                            float x4, float y4, float z4, float u4, float v4) {
548
549    float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4};
550    const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4};
551
552    RsdVertexArray::Attrib attribs[2];
553    attribs[0].set(GL_FLOAT, 3, 12, false, (uint32_t)vtx, "ATTRIB_position");
554    attribs[1].set(GL_FLOAT, 2, 8, false, (uint32_t)tex, "ATTRIB_texture0");
555
556    RsdVertexArray va(attribs, 2);
557    va.setup(rsc);
558
559    RSD_CALL_GL(glDrawArrays, GL_TRIANGLE_FAN, 0, 4);
560}
561