1/*
2 * Copyright (C) 2010 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#define LOG_TAG "HardwareRenderer"
18
19#include "jni.h"
20#include <nativehelper/JNIHelp.h>
21#include <android_runtime/AndroidRuntime.h>
22
23#include <EGL/egl_cache.h>
24
25#ifdef USE_OPENGL_RENDERER
26    EGLAPI void EGLAPIENTRY eglBeginFrame(EGLDisplay dpy, EGLSurface surface);
27#endif
28
29namespace android {
30
31/**
32 * Note: OpenGLRenderer JNI layer is generated and compiled only on supported
33 *       devices. This means all the logic must be compiled only when the
34 *       preprocessor variable USE_OPENGL_RENDERER is defined.
35 */
36#ifdef USE_OPENGL_RENDERER
37
38// ----------------------------------------------------------------------------
39// Defines
40// ----------------------------------------------------------------------------
41
42// Debug
43#define DEBUG_RENDERER 0
44
45// Debug
46#if DEBUG_RENDERER
47    #define RENDERER_LOGD(...) ALOGD(__VA_ARGS__)
48#else
49    #define RENDERER_LOGD(...)
50#endif
51
52// ----------------------------------------------------------------------------
53// Surface and display management
54// ----------------------------------------------------------------------------
55
56static jboolean android_view_HardwareRenderer_preserveBackBuffer(JNIEnv* env, jobject clazz) {
57    EGLDisplay display = eglGetCurrentDisplay();
58    EGLSurface surface = eglGetCurrentSurface(EGL_DRAW);
59
60    eglGetError();
61    eglSurfaceAttrib(display, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED);
62
63    EGLint error = eglGetError();
64    if (error != EGL_SUCCESS) {
65        RENDERER_LOGD("Could not enable buffer preserved swap behavior (%x)", error);
66    }
67
68    return error == EGL_SUCCESS;
69}
70
71static jboolean android_view_HardwareRenderer_isBackBufferPreserved(JNIEnv* env, jobject clazz) {
72    EGLDisplay display = eglGetCurrentDisplay();
73    EGLSurface surface = eglGetCurrentSurface(EGL_DRAW);
74    EGLint value;
75
76    eglGetError();
77    eglQuerySurface(display, surface, EGL_SWAP_BEHAVIOR, &value);
78
79    EGLint error = eglGetError();
80    if (error != EGL_SUCCESS) {
81        RENDERER_LOGD("Could not query buffer preserved swap behavior (%x)", error);
82    }
83
84    return error == EGL_SUCCESS && value == EGL_BUFFER_PRESERVED;
85}
86
87static void android_view_HardwareRenderer_disableVsync(JNIEnv* env, jobject clazz) {
88    EGLDisplay display = eglGetCurrentDisplay();
89
90    eglGetError();
91    eglSwapInterval(display, 0);
92
93    EGLint error = eglGetError();
94    if (error != EGL_SUCCESS) {
95        RENDERER_LOGD("Could not disable v-sync (%x)", error);
96    }
97}
98
99// ----------------------------------------------------------------------------
100// Tracing and debugging
101// ----------------------------------------------------------------------------
102
103static void android_view_HardwareRenderer_beginFrame(JNIEnv* env, jobject clazz,
104        jintArray size) {
105
106    EGLDisplay display = eglGetCurrentDisplay();
107    EGLSurface surface = eglGetCurrentSurface(EGL_DRAW);
108
109    if (size) {
110        EGLint value;
111        jint* storage = env->GetIntArrayElements(size, NULL);
112
113        eglQuerySurface(display, surface, EGL_WIDTH, &value);
114        storage[0] = value;
115
116        eglQuerySurface(display, surface, EGL_HEIGHT, &value);
117        storage[1] = value;
118
119        env->ReleaseIntArrayElements(size, storage, 0);
120    }
121
122    eglBeginFrame(display, surface);
123}
124
125#endif // USE_OPENGL_RENDERER
126
127// ----------------------------------------------------------------------------
128// Shaders
129// ----------------------------------------------------------------------------
130
131static void android_view_HardwareRenderer_setupShadersDiskCache(JNIEnv* env, jobject clazz,
132        jstring diskCachePath) {
133
134    const char* cacheArray = env->GetStringUTFChars(diskCachePath, NULL);
135    egl_cache_t::get()->setCacheFilename(cacheArray);
136    env->ReleaseStringUTFChars(diskCachePath, cacheArray);
137}
138
139// ----------------------------------------------------------------------------
140// JNI Glue
141// ----------------------------------------------------------------------------
142
143const char* const kClassPathName = "android/view/HardwareRenderer";
144
145static JNINativeMethod gMethods[] = {
146#ifdef USE_OPENGL_RENDERER
147    { "nIsBackBufferPreserved", "()Z",   (void*) android_view_HardwareRenderer_isBackBufferPreserved },
148    { "nPreserveBackBuffer",    "()Z",   (void*) android_view_HardwareRenderer_preserveBackBuffer },
149    { "nDisableVsync",          "()V",   (void*) android_view_HardwareRenderer_disableVsync },
150
151    { "nBeginFrame",            "([I)V", (void*) android_view_HardwareRenderer_beginFrame },
152#endif
153
154    { "nSetupShadersDiskCache", "(Ljava/lang/String;)V",
155            (void*) android_view_HardwareRenderer_setupShadersDiskCache },
156};
157
158int register_android_view_HardwareRenderer(JNIEnv* env) {
159    return AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods));
160}
161
162};
163