1 /*
2  * Copyright (C) 2020 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 <android/log.h>
18 #include <android/native_window.h>
19 #include <android/native_window_jni.h>
20 #include <android/window.h>
21 #include <gui/Surface.h>
22 #include <jni.h>
23 #include <system/window.h>
24 #include <utils/RefBase.h>
25 #include <cassert>
26 #include <chrono>
27 #include <thread>
28 
29 #define TAG "SurfaceViewBufferTests"
30 #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__)
31 
32 extern "C" {
33 int i = 0;
34 static ANativeWindow* sAnw;
35 static std::map<uint32_t /* slot */, ANativeWindowBuffer*> sBuffers;
36 
Java_com_android_test_SurfaceProxy_setSurface(JNIEnv * env,jclass,jobject surfaceObject)37 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_setSurface(JNIEnv* env, jclass,
38                                                                      jobject surfaceObject) {
39     sAnw = ANativeWindow_fromSurface(env, surfaceObject);
40     assert(sAnw);
41     android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
42     surface->enableFrameTimestamps(true);
43     surface->connect(NATIVE_WINDOW_API_CPU, nullptr, false);
44     native_window_set_usage(sAnw, GRALLOC_USAGE_SW_WRITE_OFTEN);
45     native_window_set_buffers_format(sAnw, HAL_PIXEL_FORMAT_RGBA_8888);
46     return 0;
47 }
48 
Java_com_android_test_SurfaceProxy_waitUntilBufferDisplayed(JNIEnv *,jclass,jlong jFrameNumber,jint timeoutMs)49 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_waitUntilBufferDisplayed(
50         JNIEnv*, jclass, jlong jFrameNumber, jint timeoutMs) {
51     using namespace std::chrono_literals;
52     assert(sAnw);
53     android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
54 
55     uint64_t frameNumber = static_cast<uint64_t>(jFrameNumber);
56     nsecs_t outRequestedPresentTime, outAcquireTime, outLatchTime, outFirstRefreshStartTime;
57     nsecs_t outLastRefreshStartTime, outGlCompositionDoneTime, outDequeueReadyTime;
58     nsecs_t outDisplayPresentTime = -1;
59     nsecs_t outReleaseTime;
60 
61     auto start = std::chrono::steady_clock::now();
62     while (outDisplayPresentTime < 0) {
63         std::this_thread::sleep_for(8ms);
64         surface->getFrameTimestamps(frameNumber, &outRequestedPresentTime, &outAcquireTime,
65                                     &outLatchTime, &outFirstRefreshStartTime,
66                                     &outLastRefreshStartTime, &outGlCompositionDoneTime,
67                                     &outDisplayPresentTime, &outDequeueReadyTime, &outReleaseTime);
68         if (outDisplayPresentTime < 0) {
69             auto end = std::chrono::steady_clock::now();
70             if (std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count() >
71                 timeoutMs) {
72                 return -1;
73             }
74         }
75     }
76     return 0;
77 }
78 
Java_com_android_test_SurfaceProxy_draw(JNIEnv *,jclass)79 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_draw(JNIEnv*, jclass) {
80     assert(sAnw);
81     ANativeWindow_Buffer outBuffer;
82     ANativeWindow_lock(sAnw, &outBuffer, nullptr);
83     return 0;
84 }
85 
Java_com_android_test_SurfaceProxy_ANativeWindowLock(JNIEnv *,jclass)86 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowLock(JNIEnv*, jclass) {
87     assert(sAnw);
88     ANativeWindow_Buffer outBuffer;
89     ANativeWindow_lock(sAnw, &outBuffer, nullptr);
90     return 0;
91 }
92 
Java_com_android_test_SurfaceProxy_ANativeWindowUnlockAndPost(JNIEnv *,jclass)93 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowUnlockAndPost(JNIEnv*,
94                                                                                      jclass) {
95     assert(sAnw);
96     ANativeWindow_unlockAndPost(sAnw);
97     return 0;
98 }
99 
Java_com_android_test_SurfaceProxy_ANativeWindowSetBuffersGeometry(JNIEnv *,jclass,jobject,jint w,jint h,jint format)100 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowSetBuffersGeometry(
101         JNIEnv* /* env */, jclass /* clazz */, jobject /* surfaceObject */, jint w, jint h,
102         jint format) {
103     assert(sAnw);
104     return ANativeWindow_setBuffersGeometry(sAnw, w, h, format);
105 }
106 
Java_com_android_test_SurfaceProxy_ANativeWindowSetBuffersTransform(JNIEnv *,jclass,jint transform)107 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_ANativeWindowSetBuffersTransform(
108         JNIEnv* /* env */, jclass /* clazz */, jint transform) {
109     assert(sAnw);
110     return native_window_set_buffers_transform(sAnw, transform);
111 }
112 
Java_com_android_test_SurfaceProxy_SurfaceSetScalingMode(JNIEnv *,jclass,jint scalingMode)113 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetScalingMode(JNIEnv* /* env */,
114                                                                                 jclass /* clazz */,
115                                                                                 jint scalingMode) {
116     assert(sAnw);
117     android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
118     return surface->setScalingMode(scalingMode);
119 }
120 
Java_com_android_test_SurfaceProxy_SurfaceDequeueBuffer(JNIEnv *,jclass,jint slot,jint timeoutMs)121 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceDequeueBuffer(JNIEnv* /* env */,
122                                                                                jclass /* clazz */,
123                                                                                jint slot,
124                                                                                jint timeoutMs) {
125     assert(sAnw);
126     ANativeWindowBuffer* anb;
127     int fenceFd;
128     int result = sAnw->dequeueBuffer(sAnw, &anb, &fenceFd);
129     if (result != android::OK) {
130         return result;
131     }
132     sBuffers[slot] = anb;
133     if (timeoutMs == 0) {
134         return android::OK;
135     }
136     android::sp<android::Fence> fence(new android::Fence(fenceFd));
137     int waitResult = fence->wait(timeoutMs);
138     if (waitResult != android::OK) {
139         sAnw->cancelBuffer(sAnw, sBuffers[slot], -1);
140         sBuffers[slot] = nullptr;
141         return waitResult;
142     }
143     return 0;
144 }
145 
Java_com_android_test_SurfaceProxy_SurfaceCancelBuffer(JNIEnv *,jclass,jint slot)146 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceCancelBuffer(JNIEnv* /* env */,
147                                                                               jclass /* clazz */,
148                                                                               jint slot) {
149     assert(sAnw);
150     assert(sBuffers[slot]);
151     int result = sAnw->cancelBuffer(sAnw, sBuffers[slot], -1);
152     sBuffers[slot] = nullptr;
153     return result;
154 }
155 
Java_com_android_test_SurfaceProxy_drawBuffer(JNIEnv * env,jclass,jint slot,jintArray jintArrayColor)156 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_drawBuffer(JNIEnv* env,
157                                                                      jclass /* clazz */, jint slot,
158                                                                      jintArray jintArrayColor) {
159     assert(sAnw);
160     assert(sBuffers[slot]);
161 
162     int* color = env->GetIntArrayElements(jintArrayColor, nullptr);
163 
164     ANativeWindowBuffer* buffer = sBuffers[slot];
165     android::sp<android::GraphicBuffer> graphicBuffer(static_cast<android::GraphicBuffer*>(buffer));
166     const android::Rect bounds(buffer->width, buffer->height);
167     android::Region newDirtyRegion;
168     newDirtyRegion.set(bounds);
169 
170     void* vaddr;
171     int fenceFd = -1;
172     graphicBuffer->lockAsync(GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN,
173                              newDirtyRegion.bounds(), &vaddr, fenceFd);
174 
175     for (int32_t row = 0; row < buffer->height; row++) {
176         uint8_t* dst = static_cast<uint8_t*>(vaddr) + (buffer->stride * row) * 4;
177         for (int32_t column = 0; column < buffer->width; column++) {
178             dst[0] = color[0];
179             dst[1] = color[1];
180             dst[2] = color[2];
181             dst[3] = color[3];
182             dst += 4;
183         }
184     }
185     graphicBuffer->unlockAsync(&fenceFd);
186     env->ReleaseIntArrayElements(jintArrayColor, color, JNI_ABORT);
187     return 0;
188 }
189 
Java_com_android_test_SurfaceProxy_SurfaceQueueBuffer(JNIEnv *,jclass,jint slot,jboolean freeSlot)190 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceQueueBuffer(JNIEnv* /* env */,
191                                                                              jclass /* clazz */,
192                                                                              jint slot,
193                                                                              jboolean freeSlot) {
194     assert(sAnw);
195     assert(sBuffers[slot]);
196     int result = sAnw->queueBuffer(sAnw, sBuffers[slot], -1);
197     if (freeSlot) {
198         sBuffers[slot] = nullptr;
199     }
200     return result;
201 }
202 
Java_com_android_test_SurfaceProxy_SurfaceSetAsyncMode(JNIEnv *,jclass,jboolean async)203 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetAsyncMode(JNIEnv* /* env */,
204                                                                               jclass /* clazz */,
205                                                                               jboolean async) {
206     assert(sAnw);
207     android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
208     return surface->setAsyncMode(async);
209 }
210 
Java_com_android_test_SurfaceProxy_SurfaceSetDequeueTimeout(JNIEnv *,jclass,jlong timeoutMs)211 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetDequeueTimeout(
212         JNIEnv* /* env */, jclass /* clazz */, jlong timeoutMs) {
213     assert(sAnw);
214     android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
215     return surface->setDequeueTimeout(timeoutMs);
216 }
217 
Java_com_android_test_SurfaceProxy_SurfaceSetMaxDequeuedBufferCount(JNIEnv *,jclass,jint maxDequeuedBuffers)218 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_SurfaceSetMaxDequeuedBufferCount(
219         JNIEnv* /* env */, jclass /* clazz */, jint maxDequeuedBuffers) {
220     assert(sAnw);
221     android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
222     return surface->setMaxDequeuedBufferCount(maxDequeuedBuffers);
223 }
224 
Java_com_android_test_SurfaceProxy_NativeWindowSetBufferCount(JNIEnv *,jclass,jint count)225 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetBufferCount(
226         JNIEnv* /* env */, jclass /* clazz */, jint count) {
227     assert(sAnw);
228     android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
229     int result = native_window_set_buffer_count(sAnw, count);
230     return result;
231 }
232 
Java_com_android_test_SurfaceProxy_NativeWindowSetSharedBufferMode(JNIEnv *,jclass,jboolean shared)233 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetSharedBufferMode(
234         JNIEnv* /* env */, jclass /* clazz */, jboolean shared) {
235     assert(sAnw);
236     android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
237     int result = native_window_set_shared_buffer_mode(sAnw, shared);
238     return result;
239 }
240 
Java_com_android_test_SurfaceProxy_NativeWindowSetAutoRefresh(JNIEnv *,jclass,jboolean autoRefresh)241 JNIEXPORT jint JNICALL Java_com_android_test_SurfaceProxy_NativeWindowSetAutoRefresh(
242         JNIEnv* /* env */, jclass /* clazz */, jboolean autoRefresh) {
243     assert(sAnw);
244     android::sp<android::Surface> surface = static_cast<android::Surface*>(sAnw);
245     int result = native_window_set_auto_refresh(sAnw, autoRefresh);
246     return result;
247 }
248 }