rsdGL.cpp revision 44bef6fba6244292b751387f3d6c31cca96c28ad
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
47using namespace android;
48using namespace android::renderscript;
49
50static int32_t gGLContextCount = 0;
51
52static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
53    struct EGLUtils {
54        static const char *strerror(EGLint err) {
55            switch (err){
56                case EGL_SUCCESS:           return "EGL_SUCCESS";
57                case EGL_NOT_INITIALIZED:   return "EGL_NOT_INITIALIZED";
58                case EGL_BAD_ACCESS:        return "EGL_BAD_ACCESS";
59                case EGL_BAD_ALLOC:         return "EGL_BAD_ALLOC";
60                case EGL_BAD_ATTRIBUTE:     return "EGL_BAD_ATTRIBUTE";
61                case EGL_BAD_CONFIG:        return "EGL_BAD_CONFIG";
62                case EGL_BAD_CONTEXT:       return "EGL_BAD_CONTEXT";
63                case EGL_BAD_CURRENT_SURFACE: return "EGL_BAD_CURRENT_SURFACE";
64                case EGL_BAD_DISPLAY:       return "EGL_BAD_DISPLAY";
65                case EGL_BAD_MATCH:         return "EGL_BAD_MATCH";
66                case EGL_BAD_NATIVE_PIXMAP: return "EGL_BAD_NATIVE_PIXMAP";
67                case EGL_BAD_NATIVE_WINDOW: return "EGL_BAD_NATIVE_WINDOW";
68                case EGL_BAD_PARAMETER:     return "EGL_BAD_PARAMETER";
69                case EGL_BAD_SURFACE:       return "EGL_BAD_SURFACE";
70                case EGL_CONTEXT_LOST:      return "EGL_CONTEXT_LOST";
71                default: return "UNKNOWN";
72            }
73        }
74    };
75
76    if (returnVal != EGL_TRUE) {
77        fprintf(stderr, "%s() returned %d\n", op, returnVal);
78    }
79
80    for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
81            = eglGetError()) {
82        fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, EGLUtils::strerror(error),
83                error);
84    }
85}
86
87static void printEGLConfiguration(EGLDisplay dpy, EGLConfig config) {
88
89#define X(VAL) {VAL, #VAL}
90    struct {EGLint attribute; const char* name;} names[] = {
91    X(EGL_BUFFER_SIZE),
92    X(EGL_ALPHA_SIZE),
93    X(EGL_BLUE_SIZE),
94    X(EGL_GREEN_SIZE),
95    X(EGL_RED_SIZE),
96    X(EGL_DEPTH_SIZE),
97    X(EGL_STENCIL_SIZE),
98    X(EGL_CONFIG_CAVEAT),
99    X(EGL_CONFIG_ID),
100    X(EGL_LEVEL),
101    X(EGL_MAX_PBUFFER_HEIGHT),
102    X(EGL_MAX_PBUFFER_PIXELS),
103    X(EGL_MAX_PBUFFER_WIDTH),
104    X(EGL_NATIVE_RENDERABLE),
105    X(EGL_NATIVE_VISUAL_ID),
106    X(EGL_NATIVE_VISUAL_TYPE),
107    X(EGL_SAMPLES),
108    X(EGL_SAMPLE_BUFFERS),
109    X(EGL_SURFACE_TYPE),
110    X(EGL_TRANSPARENT_TYPE),
111    X(EGL_TRANSPARENT_RED_VALUE),
112    X(EGL_TRANSPARENT_GREEN_VALUE),
113    X(EGL_TRANSPARENT_BLUE_VALUE),
114    X(EGL_BIND_TO_TEXTURE_RGB),
115    X(EGL_BIND_TO_TEXTURE_RGBA),
116    X(EGL_MIN_SWAP_INTERVAL),
117    X(EGL_MAX_SWAP_INTERVAL),
118    X(EGL_LUMINANCE_SIZE),
119    X(EGL_ALPHA_MASK_SIZE),
120    X(EGL_COLOR_BUFFER_TYPE),
121    X(EGL_RENDERABLE_TYPE),
122    X(EGL_CONFORMANT),
123   };
124#undef X
125
126    for (size_t j = 0; j < sizeof(names) / sizeof(names[0]); j++) {
127        EGLint value = -1;
128        EGLBoolean returnVal = eglGetConfigAttrib(dpy, config, names[j].attribute, &value);
129        if (returnVal) {
130            ALOGV(" %s: %d (0x%x)", names[j].name, value, value);
131        }
132    }
133}
134
135static void DumpDebug(RsdHal *dc) {
136    ALOGE(" EGL ver %i %i", dc->gl.egl.majorVersion, dc->gl.egl.minorVersion);
137    ALOGE(" EGL context %p  surface %p,  Display=%p", dc->gl.egl.context, dc->gl.egl.surface,
138         dc->gl.egl.display);
139    ALOGE(" GL vendor: %s", dc->gl.gl.vendor);
140    ALOGE(" GL renderer: %s", dc->gl.gl.renderer);
141    ALOGE(" GL Version: %s", dc->gl.gl.version);
142    ALOGE(" GL Extensions: %s", dc->gl.gl.extensions);
143    ALOGE(" GL int Versions %i %i", dc->gl.gl.majorVersion, dc->gl.gl.minorVersion);
144
145    ALOGV("MAX Textures %i, %i  %i", dc->gl.gl.maxVertexTextureUnits,
146         dc->gl.gl.maxFragmentTextureImageUnits, dc->gl.gl.maxTextureImageUnits);
147    ALOGV("MAX Attribs %i", dc->gl.gl.maxVertexAttribs);
148    ALOGV("MAX Uniforms %i, %i", dc->gl.gl.maxVertexUniformVectors,
149         dc->gl.gl.maxFragmentUniformVectors);
150    ALOGV("MAX Varyings %i", dc->gl.gl.maxVaryingVectors);
151}
152
153void rsdGLShutdown(const Context *rsc) {
154    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
155
156    rsdGLSetSurface(rsc, 0, 0, nullptr);
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    if (numConfigs) {
270        EGLConfig* const configs = new EGLConfig[numConfigs];
271
272        rsc->setWatchdogGL("eglChooseConfig", __LINE__, __FILE__);
273        ret = eglChooseConfig(dc->gl.egl.display,
274                configAttribs, configs, numConfigs, &n);
275        if (!ret || !n) {
276            checkEglError("eglChooseConfig", ret);
277            ALOGE("%p, couldn't find an EGLConfig matching the screen format\n", rsc);
278        }
279
280        // The first config is guaranteed to over-satisfy the constraints
281        dc->gl.egl.config = configs[0];
282
283        // go through the list and skip configs that over-satisfy our needs
284        for (int i=0 ; i<n ; i++) {
285            if (rsc->mUserSurfaceConfig.alphaMin <= 0) {
286                EGLint alphaSize;
287                eglGetConfigAttrib(dc->gl.egl.display,
288                        configs[i], EGL_ALPHA_SIZE, &alphaSize);
289                if (alphaSize > 0) {
290                    continue;
291                }
292            }
293
294            if (rsc->mUserSurfaceConfig.depthMin <= 0) {
295                EGLint depthSize;
296                eglGetConfigAttrib(dc->gl.egl.display,
297                        configs[i], EGL_DEPTH_SIZE, &depthSize);
298                if (depthSize > 0) {
299                    continue;
300                }
301            }
302
303            // Found one!
304            dc->gl.egl.config = configs[i];
305            break;
306        }
307
308        delete [] configs;
309    }
310
311    //if (props.mLogVisual) {
312    if (0) {
313        printEGLConfiguration(dc->gl.egl.display, dc->gl.egl.config);
314    }
315    //}
316
317    rsc->setWatchdogGL("eglCreateContext", __LINE__, __FILE__);
318    dc->gl.egl.context = eglCreateContext(dc->gl.egl.display, dc->gl.egl.config,
319                                          EGL_NO_CONTEXT, context_attribs2);
320    checkEglError("eglCreateContext");
321    if (dc->gl.egl.context == EGL_NO_CONTEXT) {
322        ALOGE("%p, eglCreateContext returned EGL_NO_CONTEXT", rsc);
323        rsc->setWatchdogGL(nullptr, 0, nullptr);
324        return false;
325    }
326    gGLContextCount++;
327
328    EGLint pbuffer_attribs[] = { EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE };
329    rsc->setWatchdogGL("eglCreatePbufferSurface", __LINE__, __FILE__);
330    dc->gl.egl.surfaceDefault = eglCreatePbufferSurface(dc->gl.egl.display, dc->gl.egl.config,
331            pbuffer_attribs);
332    checkEglError("eglCreatePbufferSurface");
333    if (dc->gl.egl.surfaceDefault == EGL_NO_SURFACE) {
334        ALOGE("eglCreatePbufferSurface returned EGL_NO_SURFACE");
335        rsdGLShutdown(rsc);
336        rsc->setWatchdogGL(nullptr, 0, nullptr);
337        return false;
338    }
339
340    rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
341    ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault,
342                         dc->gl.egl.surfaceDefault, dc->gl.egl.context);
343    if (ret == EGL_FALSE) {
344        ALOGE("eglMakeCurrent returned EGL_FALSE");
345        checkEglError("eglMakeCurrent", ret);
346        rsdGLShutdown(rsc);
347        rsc->setWatchdogGL(nullptr, 0, nullptr);
348        return false;
349    }
350
351    dc->gl.gl.version = glGetString(GL_VERSION);
352    dc->gl.gl.vendor = glGetString(GL_VENDOR);
353    dc->gl.gl.renderer = glGetString(GL_RENDERER);
354    dc->gl.gl.extensions = glGetString(GL_EXTENSIONS);
355
356    //ALOGV("EGL Version %i %i", mEGL.mMajorVersion, mEGL.mMinorVersion);
357    //ALOGV("GL Version %s", mGL.mVersion);
358    //ALOGV("GL Vendor %s", mGL.mVendor);
359    //ALOGV("GL Renderer %s", mGL.mRenderer);
360    //ALOGV("GL Extensions %s", mGL.mExtensions);
361
362    const char *verptr = nullptr;
363    if (strlen((const char *)dc->gl.gl.version) > 9) {
364        if (!memcmp(dc->gl.gl.version, "OpenGL ES-CM", 12)) {
365            verptr = (const char *)dc->gl.gl.version + 12;
366        }
367        if (!memcmp(dc->gl.gl.version, "OpenGL ES ", 10)) {
368            verptr = (const char *)dc->gl.gl.version + 9;
369        }
370    }
371
372    if (!verptr) {
373        ALOGE("Error, OpenGL ES Lite not supported");
374        rsdGLShutdown(rsc);
375        rsc->setWatchdogGL(nullptr, 0, nullptr);
376        return false;
377    } else {
378        sscanf(verptr, " %i.%i", &dc->gl.gl.majorVersion, &dc->gl.gl.minorVersion);
379    }
380
381    glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &dc->gl.gl.maxVertexAttribs);
382    glGetIntegerv(GL_MAX_VERTEX_UNIFORM_VECTORS, &dc->gl.gl.maxVertexUniformVectors);
383    glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxVertexTextureUnits);
384
385    glGetIntegerv(GL_MAX_VARYING_VECTORS, &dc->gl.gl.maxVaryingVectors);
386    glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxTextureImageUnits);
387
388    glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &dc->gl.gl.maxFragmentTextureImageUnits);
389    glGetIntegerv(GL_MAX_FRAGMENT_UNIFORM_VECTORS, &dc->gl.gl.maxFragmentUniformVectors);
390
391    dc->gl.gl.OES_texture_npot = nullptr != strstr((const char *)dc->gl.gl.extensions,
392                                                "GL_OES_texture_npot");
393    dc->gl.gl.IMG_texture_npot = nullptr != strstr((const char *)dc->gl.gl.extensions,
394                                                   "GL_IMG_texture_npot");
395    dc->gl.gl.NV_texture_npot_2D_mipmap = nullptr != strstr((const char *)dc->gl.gl.extensions,
396                                                            "GL_NV_texture_npot_2D_mipmap");
397    dc->gl.gl.EXT_texture_max_aniso = 1.0f;
398    bool hasAniso = nullptr != strstr((const char *)dc->gl.gl.extensions,
399                                   "GL_EXT_texture_filter_anisotropic");
400    if (hasAniso) {
401        glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &dc->gl.gl.EXT_texture_max_aniso);
402    }
403
404    if (0) {
405        DumpDebug(dc);
406    }
407
408    dc->gl.shaderCache = new RsdShaderCache();
409    dc->gl.vertexArrayState = new RsdVertexArrayState();
410    dc->gl.vertexArrayState->init(dc->gl.gl.maxVertexAttribs);
411    dc->gl.currentFrameBuffer = nullptr;
412    dc->mHasGraphics = true;
413
414    ALOGV("%p initGLThread end", rsc);
415    rsc->setWatchdogGL(nullptr, 0, nullptr);
416    return true;
417}
418
419
420bool rsdGLSetInternalSurface(const Context *rsc, RsNativeWindow sur) {
421    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
422
423    EGLBoolean ret;
424    if (dc->gl.egl.surface != nullptr) {
425        rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
426        ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surfaceDefault,
427                             dc->gl.egl.surfaceDefault, dc->gl.egl.context);
428        checkEglError("eglMakeCurrent", ret);
429
430        rsc->setWatchdogGL("eglDestroySurface", __LINE__, __FILE__);
431        ret = eglDestroySurface(dc->gl.egl.display, dc->gl.egl.surface);
432        checkEglError("eglDestroySurface", ret);
433
434        dc->gl.egl.surface = nullptr;
435    }
436
437    if (dc->gl.currentWndSurface != nullptr) {
438        dc->gl.currentWndSurface->decStrong(nullptr);
439    }
440
441    dc->gl.currentWndSurface = (ANativeWindow *)sur;
442    if (dc->gl.currentWndSurface != nullptr) {
443        dc->gl.currentWndSurface->incStrong(nullptr);
444
445        rsc->setWatchdogGL("eglCreateWindowSurface", __LINE__, __FILE__);
446        dc->gl.egl.surface = eglCreateWindowSurface(dc->gl.egl.display, dc->gl.egl.config,
447                                                    dc->gl.currentWndSurface, nullptr);
448        checkEglError("eglCreateWindowSurface");
449        if (dc->gl.egl.surface == EGL_NO_SURFACE) {
450            ALOGE("eglCreateWindowSurface returned EGL_NO_SURFACE");
451        }
452
453        rsc->setWatchdogGL("eglMakeCurrent", __LINE__, __FILE__);
454        ret = eglMakeCurrent(dc->gl.egl.display, dc->gl.egl.surface,
455                             dc->gl.egl.surface, dc->gl.egl.context);
456        checkEglError("eglMakeCurrent", ret);
457    }
458    rsc->setWatchdogGL(nullptr, 0, nullptr);
459    return true;
460}
461
462bool rsdGLSetSurface(const Context *rsc, uint32_t w, uint32_t h, RsNativeWindow sur) {
463    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
464
465    if (dc->gl.wndSurface != nullptr) {
466        dc->gl.wndSurface->decStrong(nullptr);
467        dc->gl.wndSurface = nullptr;
468    }
469    if(w && h) {
470        // WAR: Some drivers fail to handle 0 size surfaces correctly. Use the
471        // pbuffer to avoid this pitfall.
472        dc->gl.wndSurface = (ANativeWindow *)sur;
473        if (dc->gl.wndSurface != nullptr) {
474            dc->gl.wndSurface->incStrong(nullptr);
475        }
476    }
477
478    return rsdGLSetInternalSurface(rsc, sur);
479}
480
481void rsdGLSwap(const android::renderscript::Context *rsc) {
482    RsdHal *dc = (RsdHal *)rsc->mHal.drv;
483    RSD_CALL_GL(eglSwapBuffers, dc->gl.egl.display, dc->gl.egl.surface);
484}
485
486void rsdGLSetPriority(const Context *rsc, int32_t priority) {
487    if (priority > 0) {
488        // Mark context as low priority.
489        ALOGV("low pri");
490    } else {
491        ALOGV("normal pri");
492    }
493}
494
495void rsdGLCheckError(const android::renderscript::Context *rsc,
496                     const char *msg, bool isFatal) {
497    GLenum err = glGetError();
498    if (err != GL_NO_ERROR) {
499        char buf[1024];
500        snprintf(buf, sizeof(buf), "GL Error = 0x%08x, from: %s", err, msg);
501
502        if (isFatal) {
503            rsc->setError(RS_ERROR_FATAL_DRIVER, buf);
504        } else {
505            switch (err) {
506            case GL_OUT_OF_MEMORY:
507                rsc->setError(RS_ERROR_OUT_OF_MEMORY, buf);
508                break;
509            default:
510                rsc->setError(RS_ERROR_DRIVER, buf);
511                break;
512            }
513        }
514
515        ALOGE("%p, %s", rsc, buf);
516    }
517
518}
519
520void rsdGLClearColor(const android::renderscript::Context *rsc,
521                     float r, float g, float b, float a) {
522    RSD_CALL_GL(glClearColor, r, g, b, a);
523    RSD_CALL_GL(glClear, GL_COLOR_BUFFER_BIT);
524}
525
526void rsdGLClearDepth(const android::renderscript::Context *rsc, float v) {
527    RSD_CALL_GL(glClearDepthf, v);
528    RSD_CALL_GL(glClear, GL_DEPTH_BUFFER_BIT);
529}
530
531void rsdGLFinish(const android::renderscript::Context *rsc) {
532    RSD_CALL_GL(glFinish);
533}
534
535void rsdGLDrawQuadTexCoords(const android::renderscript::Context *rsc,
536                            float x1, float y1, float z1, float u1, float v1,
537                            float x2, float y2, float z2, float u2, float v2,
538                            float x3, float y3, float z3, float u3, float v3,
539                            float x4, float y4, float z4, float u4, float v4) {
540
541    float vtx[] = {x1,y1,z1, x2,y2,z2, x3,y3,z3, x4,y4,z4};
542    const float tex[] = {u1,v1, u2,v2, u3,v3, u4,v4};
543
544    RsdVertexArray::Attrib attribs[2];
545
546    attribs[0].set(GL_FLOAT, 3, 12, false, (size_t)vtx, "ATTRIB_position");
547    attribs[1].set(GL_FLOAT, 2, 8, false, (size_t)tex, "ATTRIB_texture0");
548
549    RsdVertexArray va(attribs, 2);
550    va.setup(rsc);
551
552    RSD_CALL_GL(glDrawArrays, GL_TRIANGLE_FAN, 0, 4);
553}
554