rsdGL.cpp revision b322033c13487a174bb9c26466e9684d1ff4de8d
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    dc->gl.shaderCache->cleanupAll();
158    delete dc->gl.shaderCache;
159    delete dc->gl.vertexArrayState;
160
161    if (dc->gl.egl.context != EGL_NO_CONTEXT) {
162        RSD_CALL_GL(eglMakeCurrent, dc->gl.egl.display,
163                    EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
164        RSD_CALL_GL(eglDestroySurface, dc->gl.egl.display, dc->gl.egl.surfaceDefault);
165        if (dc->gl.egl.surface != EGL_NO_SURFACE) {
166            RSD_CALL_GL(eglDestroySurface, dc->gl.egl.display, dc->gl.egl.surface);
167        }
168        RSD_CALL_GL(eglDestroyContext, dc->gl.egl.display, dc->gl.egl.context);
169        checkEglError("eglDestroyContext");
170    }
171
172    gGLContextCount--;
173    if (!gGLContextCount) {
174        RSD_CALL_GL(eglTerminate, dc->gl.egl.display);
175    }
176}
177
178void getConfigData(const Context *rsc,
179                   EGLint *configAttribs, size_t configAttribsLen,
180                   uint32_t numSamples) {
181    memset(configAttribs, 0, configAttribsLen*sizeof(*configAttribs));
182
183    EGLint *configAttribsPtr = configAttribs;
184
185    configAttribsPtr[0] = EGL_SURFACE_TYPE;
186    configAttribsPtr[1] = EGL_WINDOW_BIT;
187    configAttribsPtr += 2;
188
189    configAttribsPtr[0] = EGL_RENDERABLE_TYPE;
190    configAttribsPtr[1] = EGL_OPENGL_ES2_BIT;
191    configAttribsPtr += 2;
192
193    configAttribsPtr[0] = EGL_RED_SIZE;
194    configAttribsPtr[1] = 8;
195    configAttribsPtr += 2;
196
197    configAttribsPtr[0] = EGL_GREEN_SIZE;
198    configAttribsPtr[1] = 8;
199    configAttribsPtr += 2;
200
201    configAttribsPtr[0] = EGL_BLUE_SIZE;
202    configAttribsPtr[1] = 8;
203    configAttribsPtr += 2;
204
205    if (rsc->mUserSurfaceConfig.alphaMin > 0) {
206        configAttribsPtr[0] = EGL_ALPHA_SIZE;
207        configAttribsPtr[1] = rsc->mUserSurfaceConfig.alphaMin;
208        configAttribsPtr += 2;
209    }
210
211    if (rsc->mUserSurfaceConfig.depthMin > 0) {
212        configAttribsPtr[0] = EGL_DEPTH_SIZE;
213        configAttribsPtr[1] = rsc->mUserSurfaceConfig.depthMin;
214        configAttribsPtr += 2;
215    }
216
217    if (rsc->mDev->mForceSW) {
218        configAttribsPtr[0] = EGL_CONFIG_CAVEAT;
219        configAttribsPtr[1] = EGL_SLOW_CONFIG;
220        configAttribsPtr += 2;
221    }
222
223    if (numSamples > 1) {
224        configAttribsPtr[0] = EGL_SAMPLE_BUFFERS;
225        configAttribsPtr[1] = 1;
226        configAttribsPtr[2] = EGL_SAMPLES;
227        configAttribsPtr[3] = numSamples;
228        configAttribsPtr += 4;
229    }
230
231    configAttribsPtr[0] = EGL_NONE;
232    rsAssert(configAttribsPtr < (configAttribs + configAttribsLen));
233}
234
235bool rsdGLInit(const Context *rsc) {
236    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
237
238    dc->gl.egl.numConfigs = -1;
239
240    EGLint configAttribs[128];
241    EGLint context_attribs2[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
242
243    ALOGV("%p initEGL start", rsc);
244    rsc->setWatchdogGL("eglGetDisplay", __LINE__, __FILE__);
245    dc->gl.egl.display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
246    checkEglError("eglGetDisplay");
247
248    RSD_CALL_GL(eglInitialize, dc->gl.egl.display,
249                &dc->gl.egl.majorVersion, &dc->gl.egl.minorVersion);
250    checkEglError("eglInitialize");
251
252    EGLBoolean ret;
253
254    EGLint numConfigs = -1, n = 0;
255    rsc->setWatchdogGL("eglChooseConfig", __LINE__, __FILE__);
256
257    // Try minding a multisample config that matches the user request
258    uint32_t minSample = rsc->mUserSurfaceConfig.samplesMin;
259    uint32_t prefSample = rsc->mUserSurfaceConfig.samplesPref;
260    for (uint32_t sampleCount = prefSample; sampleCount >= minSample; sampleCount--) {
261        getConfigData(rsc, configAttribs, (sizeof(configAttribs) / sizeof(EGLint)), sampleCount);
262        ret = eglChooseConfig(dc->gl.egl.display, configAttribs, 0, 0, &numConfigs);
263        checkEglError("eglGetConfigs", ret);
264        if (numConfigs > 0) {
265            break;
266        }
267    }
268
269    eglSwapInterval(dc->gl.egl.display, 0);
270
271    if (numConfigs) {
272        EGLConfig* const configs = new EGLConfig[numConfigs];
273
274        rsc->setWatchdogGL("eglChooseConfig", __LINE__, __FILE__);
275        ret = eglChooseConfig(dc->gl.egl.display,
276                configAttribs, configs, numConfigs, &n);
277        if (!ret || !n) {
278            checkEglError("eglChooseConfig", ret);
279            ALOGE("%p, couldn't find an EGLConfig matching the screen format\n", rsc);
280        }
281
282        // The first config is guaranteed to over-satisfy the constraints
283        dc->gl.egl.config = configs[0];
284
285        // go through the list and skip configs that over-satisfy our needs
286        for (int i=0 ; i<n ; i++) {
287            if (rsc->mUserSurfaceConfig.alphaMin <= 0) {
288                EGLint alphaSize;
289                eglGetConfigAttrib(dc->gl.egl.display,
290                        configs[i], EGL_ALPHA_SIZE, &alphaSize);
291                if (alphaSize > 0) {
292                    continue;
293                }
294            }
295
296            if (rsc->mUserSurfaceConfig.depthMin <= 0) {
297                EGLint depthSize;
298                eglGetConfigAttrib(dc->gl.egl.display,
299                        configs[i], EGL_DEPTH_SIZE, &depthSize);
300                if (depthSize > 0) {
301                    continue;
302                }
303            }
304
305            // Found one!
306            dc->gl.egl.config = configs[i];
307            break;
308        }
309
310        delete [] configs;
311    }
312
313    //if (props.mLogVisual) {
314    if (0) {
315        printEGLConfiguration(dc->gl.egl.display, dc->gl.egl.config);
316    }
317    //}
318
319    rsc->setWatchdogGL("eglCreateContext", __LINE__, __FILE__);
320    dc->gl.egl.context = eglCreateContext(dc->gl.egl.display, dc->gl.egl.config,
321                                          EGL_NO_CONTEXT, context_attribs2);
322    checkEglError("eglCreateContext");
323    if (dc->gl.egl.context == EGL_NO_CONTEXT) {
324        ALOGE("%p, eglCreateContext returned EGL_NO_CONTEXT", rsc);
325        rsc->setWatchdogGL(NULL, 0, NULL);
326        return false;
327    }
328    gGLContextCount++;
329
330    // Create a BufferQueue with a fake consumer
331    sp<BufferQueue> bq = new BufferQueue();
332    bq->consumerConnect(new DummyConsumer());
333    sp<SurfaceTextureClient> stc(new SurfaceTextureClient(static_cast<sp<ISurfaceTexture> >(bq)));
334
335    dc->gl.egl.surfaceDefault = eglCreateWindowSurface(dc->gl.egl.display, dc->gl.egl.config,
336                                                       static_cast<ANativeWindow*>(stc.get()),
337                                                       NULL);
338
339    checkEglError("eglCreateWindowSurface");
340    if (dc->gl.egl.surfaceDefault == EGL_NO_SURFACE) {
341        ALOGE("eglCreateWindowSurface returned EGL_NO_SURFACE");
342        rsdGLShutdown(rsc);
343        rsc->setWatchdogGL(NULL, 0, NULL);
344        return false;
345    }
346
347    rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
348    ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault,
349                         dc->gl.egl.surfaceDefault, dc->gl.egl.context);
350    if (ret == EGL_FALSE) {
351        ALOGE("eglMakeCurrent returned EGL_FALSE");
352        checkEglError("eglMakeCurrent", ret);
353        rsdGLShutdown(rsc);
354        rsc->setWatchdogGL(NULL, 0, NULL);
355        return false;
356    }
357
358    dc->gl.gl.version = glGetString(GL_VERSION);
359    dc->gl.gl.vendor = glGetString(GL_VENDOR);
360    dc->gl.gl.renderer = glGetString(GL_RENDERER);
361    dc->gl.gl.extensions = glGetString(GL_EXTENSIONS);
362
363    //ALOGV("EGL Version %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion);
364    //ALOGV("GL Version %s", mGL.mVersion);
365    //ALOGV("GL Vendor %s", mGL.mVendor);
366    //ALOGV("GL Renderer %s", mGL.mRenderer);
367    //ALOGV("GL Extensions %s", mGL.mExtensions);
368
369    const char *verptr = NULL;
370    if (strlen((const char *)dc->gl.gl.version) > 9) {
371        if (!memcmp(dc->gl.gl.version, "OpenGL ES-CM", 12)) {
372            verptr = (const char *)dc->gl.gl.version + 12;
373        }
374        if (!memcmp(dc->gl.gl.version, "OpenGL ES ", 10)) {
375            verptr = (const char *)dc->gl.gl.version + 9;
376        }
377    }
378
379    if (!verptr) {
380        ALOGE("Error, OpenGL ES Lite not supported");
381        rsdGLShutdown(rsc);
382        rsc->setWatchdogGL(NULL, 0, NULL);
383        return false;
384    } else {
385        sscanf(verptr, " %i.%i", &dc->gl.gl.majorVersion, &dc->gl.gl.minorVersion);
386    }
387
388    glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &dc->gl.gl.maxVertexAttribs);
389    glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &dc->gl.gl.maxVertexUniformVectors);
390    glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxVertexTextureUnits);
391
392    glGetIntegerv(GL_MAX_VARYING_VECTORS, &dc->gl.gl.maxVaryingVectors);
393    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxTextureImageUnits);
394
395    glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxFragmentTextureImageUnits);
396    glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &dc->gl.gl.maxFragmentUniformVectors);
397
398    dc->gl.gl.OES_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions,
399                                                "GL_OES_texture_npot");
400    dc->gl.gl.IMG_texture_npot = NULL != strstr((const char *)dc->gl.gl.extensions,
401                                                   "GL_IMG_texture_npot");
402    dc->gl.gl.NV_texture_npot_2D_mipmap = NULL != strstr((const char *)dc->gl.gl.extensions,
403                                                            "GL_NV_texture_npot_2D_mipmap");
404    dc->gl.gl.EXT_texture_max_aniso = 1.0f;
405    bool hasAniso = NULL != strstr((const char *)dc->gl.gl.extensions,
406                                   "GL_EXT_texture_filter_anisotropic");
407    if (hasAniso) {
408        glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &dc->gl.gl.EXT_texture_max_aniso);
409    }
410
411    if (0) {
412        DumpDebug(dc);
413    }
414
415    dc->gl.shaderCache = new RsdShaderCache();
416    dc->gl.vertexArrayState = new RsdVertexArrayState();
417    dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs);
418    dc->gl.currentFrameBuffer = NULL;
419    dc->mHasGraphics = true;
420
421    ALOGV("%p initGLThread end", rsc);
422    rsc->setWatchdogGL(NULL, 0, NULL);
423    return true;
424}
425
426
427bool rsdGLSetInternalSurface(const Context *rsc, RsNativeWindow sur) {
428    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
429
430    EGLBoolean ret;
431    if (dc->gl.egl.surface != NULL) {
432        rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
433        ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault,
434                             dc->gl.egl.surfaceDefault, dc->gl.egl.context);
435        checkEglError("eglMakeCurrent", ret);
436
437        rsc->setWatchdogGL("eglDestroySurface", __LINE__, __FILE__);
438        ret = eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surface);
439        checkEglError("eglDestroySurface", ret);
440
441        dc->gl.egl.surface = NULL;
442    }
443
444    if (dc->gl.currentWndSurface != NULL) {
445        dc->gl.currentWndSurface->decStrong(NULL);
446    }
447
448    dc->gl.currentWndSurface = (ANativeWindow *)sur;
449    if (dc->gl.currentWndSurface != NULL) {
450        dc->gl.currentWndSurface->incStrong(NULL);
451
452        rsc->setWatchdogGL("eglCreateWindowSurface", __LINE__, __FILE__);
453        dc->gl.egl.surface = eglCreateWindowSurface(dc->gl.egl.display, dc->gl.egl.config,
454                                                    dc->gl.currentWndSurface, NULL);
455        checkEglError("eglCreateWindowSurface");
456        if (dc->gl.egl.surface == EGL_NO_SURFACE) {
457            ALOGE("eglCreateWindowSurface returned EGL_NO_SURFACE");
458        }
459
460        rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
461        ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surface,
462                             dc->gl.egl.surface, dc->gl.egl.context);
463        checkEglError("eglMakeCurrent", ret);
464    }
465    rsc->setWatchdogGL(NULL, 0, NULL);
466    return true;
467}
468
469bool rsdGLSetSurface(const Context *rsc, uint32_t w, uint32_t h, RsNativeWindow sur) {
470    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
471
472    if (dc->gl.wndSurface != NULL) {
473        dc->gl.wndSurface->decStrong(NULL);
474        dc->gl.wndSurface = NULL;
475    }
476    if(w && h) {
477        // WAR: Some drivers fail to handle 0 size surfaces correctly. Use the
478        // pbuffer to avoid this pitfall.
479        dc->gl.wndSurface = (ANativeWindow *)sur;
480        if (dc->gl.wndSurface != NULL) {
481            dc->gl.wndSurface->incStrong(NULL);
482        }
483    }
484
485    return rsdGLSetInternalSurface(rsc, sur);
486}
487
488void rsdGLSwap(const android::renderscript::Context *rsc) {
489    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
490    RSD_CALL_GL(eglSwapBuffers, dc->gl.egl.display, dc->gl.egl.surface);
491}
492
493void rsdGLSetPriority(const Context *rsc, int32_t priority) {
494    if (priority > 0) {
495        // Mark context as low priority.
496        ALOGV("low pri");
497    } else {
498        ALOGV("normal pri");
499    }
500}
501
502void rsdGLCheckError(const android::renderscript::Context *rsc,
503                     const char *msg, bool isFatal) {
504    GLenum err = glGetError();
505    if (err != GL_NO_ERROR) {
506        char buf[1024];
507        snprintf(buf, sizeof(buf), "GL Error = 0x%08x, from: %s", err, msg);
508
509        if (isFatal) {
510            rsc->setError(RS_ERROR_FATAL_DRIVER, buf);
511        } else {
512            switch (err) {
513            case GL_OUT_OF_MEMORY:
514                rsc->setError(RS_ERROR_OUT_OF_MEMORY, buf);
515                break;
516            default:
517                rsc->setError(RS_ERROR_DRIVER, buf);
518                break;
519            }
520        }
521
522        ALOGE("%p, %s", rsc, buf);
523    }
524
525}
526
527void rsdGLClearColor(const android::renderscript::Context *rsc,
528                     float r, float g, float b, float a) {
529    RSD_CALL_GL(glClearColor, r, g, b, a);
530    RSD_CALL_GL(glClear, GL_COLOR_BUFFER_BIT);
531}
532
533void rsdGLClearDepth(const android::renderscript::Context *rsc, float v) {
534    RSD_CALL_GL(glClearDepthf, v);
535    RSD_CALL_GL(glClear, GL_DEPTH_BUFFER_BIT);
536}
537
538void rsdGLFinish(const android::renderscript::Context *rsc) {
539    RSD_CALL_GL(glFinish);
540}
541
542void rsdGLDrawQuadTexCoords(const android::renderscript::Context *rsc,
543                            float x1, float y1, float z1, float u1, float v1,
544                            float x2, float y2, float z2, float u2, float v2,
545                            float x3, float y3, float z3, float u3, float v3,
546                            float x4, float y4, float z4, float u4, float v4) {
547
548    float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4};
549    const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4};
550
551    RsdVertexArray::Attrib attribs[2];
552    attribs[0].set(GL_FLOAT, 3, 12, false, (uint32_t)vtx, "ATTRIB_position");
553    attribs[1].set(GL_FLOAT, 2, 8, false, (uint32_t)tex, "ATTRIB_texture0");
554
555    RsdVertexArray va(attribs, 2);
556    va.setup(rsc);
557
558    RSD_CALL_GL(glDrawArrays, GL_TRIANGLE_FAN, 0, 4);
559}
560