• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2017 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 package android.graphics.cts;
18 
19 import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION;
20 import static android.opengl.EGL14.EGL_DEFAULT_DISPLAY;
21 import static android.opengl.EGL14.EGL_HEIGHT;
22 import static android.opengl.EGL14.EGL_NONE;
23 import static android.opengl.EGL14.EGL_NO_CONTEXT;
24 import static android.opengl.EGL14.EGL_NO_DISPLAY;
25 import static android.opengl.EGL14.EGL_NO_SURFACE;
26 import static android.opengl.EGL14.EGL_OPENGL_ES2_BIT;
27 import static android.opengl.EGL14.EGL_PBUFFER_BIT;
28 import static android.opengl.EGL14.EGL_RENDERABLE_TYPE;
29 import static android.opengl.EGL14.EGL_SURFACE_TYPE;
30 import static android.opengl.EGL14.EGL_WIDTH;
31 import static android.system.OsConstants.EINVAL;
32 
33 import static org.junit.Assert.assertEquals;
34 import static org.junit.Assert.assertNotEquals;
35 import static org.junit.Assert.assertTrue;
36 
37 import android.graphics.SurfaceTexture;
38 import android.media.ImageReader;
39 import android.opengl.EGL14;
40 import android.opengl.EGLConfig;
41 import android.opengl.EGLContext;
42 import android.opengl.EGLDisplay;
43 import android.opengl.EGLSurface;
44 import android.opengl.GLES20;
45 import android.os.Parcel;
46 import android.util.Log;
47 import android.view.Surface;
48 
49 import androidx.test.filters.SmallTest;
50 
51 import org.junit.Before;
52 import org.junit.Test;
53 import org.junit.runner.RunWith;
54 import org.junit.runners.BlockJUnit4ClassRunner;
55 
56 @SmallTest
57 @RunWith(BlockJUnit4ClassRunner.class)
58 public class ANativeWindowTest {
59 
60     static {
61         System.loadLibrary("ctsgraphics_jni");
62     }
63 
64     private static final String TAG = ANativeWindowTest.class.getSimpleName();
65     private static final boolean DEBUG = false;
66 
67     private EGLDisplay mEglDisplay = EGL_NO_DISPLAY;
68     private EGLConfig mEglConfig = null;
69     private EGLSurface mEglPbuffer = EGL_NO_SURFACE;
70     private EGLContext mEglContext = EGL_NO_CONTEXT;
71 
72     @Before
setup()73     public void setup() throws Throwable {
74         mEglDisplay = EGL14.eglGetDisplay(EGL_DEFAULT_DISPLAY);
75         if (mEglDisplay == EGL_NO_DISPLAY) {
76             throw new RuntimeException("no EGL display");
77         }
78         int[] major = new int[1];
79         int[] minor = new int[1];
80         if (!EGL14.eglInitialize(mEglDisplay, major, 0, minor, 0)) {
81             throw new RuntimeException("error in eglInitialize");
82         }
83 
84         // If we could rely on having EGL_KHR_surfaceless_context and EGL_KHR_context_no_config, we
85         // wouldn't have to create a config or pbuffer at all.
86 
87         int[] numConfigs = new int[1];
88         EGLConfig[] configs = new EGLConfig[1];
89         if (!EGL14.eglChooseConfig(mEglDisplay,
90                 new int[] {
91                     EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
92                     EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
93                     EGL_NONE},
94                 0, configs, 0, 1, numConfigs, 0)) {
95             throw new RuntimeException("eglChooseConfig failed");
96         }
97         mEglConfig = configs[0];
98 
99         mEglPbuffer = EGL14.eglCreatePbufferSurface(mEglDisplay, mEglConfig,
100                 new int[] {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}, 0);
101         if (mEglPbuffer == EGL_NO_SURFACE) {
102             throw new RuntimeException("eglCreatePbufferSurface failed");
103         }
104 
105         mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT,
106                 new int[] {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}, 0);
107         if (mEglContext == EGL_NO_CONTEXT) {
108             throw new RuntimeException("eglCreateContext failed");
109         }
110 
111         if (!EGL14.eglMakeCurrent(mEglDisplay, mEglPbuffer, mEglPbuffer, mEglContext)) {
112             throw new RuntimeException("eglMakeCurrent failed");
113         }
114     }
115 
116     @Test
testSetBuffersTransform()117     public void testSetBuffersTransform() {
118         final int MIRROR_HORIZONTAL_BIT = 0x01;
119         final int MIRROR_VERTICAL_BIT   = 0x02;
120         final int ROTATE_90_BIT         = 0x04;
121         final int ALL_TRANSFORM_BITS    =
122                 MIRROR_HORIZONTAL_BIT | MIRROR_VERTICAL_BIT | ROTATE_90_BIT;
123 
124         // 4x4 GL-style matrices, as returned by SurfaceTexture#getTransformMatrix(). Note they're
125         // transforming texture coordinates ([0,1]^2), so the origin for the transforms is
126         // (0.5, 0.5), not (0,0).
127         final float[] MIRROR_HORIZONTAL_MATRIX = new float[] {
128             -1.0f,  0.0f,  0.0f,  0.0f,
129              0.0f,  1.0f,  0.0f,  0.0f,
130              0.0f,  0.0f,  1.0f,  0.0f,
131              1.0f,  0.0f,  0.0f,  1.0f,
132         };
133         final float[] MIRROR_VERTICAL_MATRIX = new float[] {
134              1.0f,  0.0f,  0.0f,  0.0f,
135              0.0f, -1.0f,  0.0f,  0.0f,
136              0.0f,  0.0f,  1.0f,  0.0f,
137              0.0f,  1.0f,  0.0f,  1.0f,
138         };
139         final float[] ROTATE_90_MATRIX = new float[] {
140              0.0f,  1.0f,  0.0f,  0.0f,
141             -1.0f,  0.0f,  0.0f,  0.0f,
142              0.0f,  0.0f,  1.0f,  0.0f,
143              1.0f,  0.0f,  0.0f,  1.0f,
144         };
145 
146         int[] texId = new int[1];
147         GLES20.glGenTextures(1, texId, 0);
148 
149         SurfaceTexture consumer = new SurfaceTexture(texId[0]);
150         consumer.setDefaultBufferSize(16, 16);
151         Surface surface = new Surface(consumer);
152 
153         float[] computedTransform = new float[16];
154         float[] receivedTransform = new float[16];
155         float[] tmp = new float[16];
156         for (int transform = 0; transform <= ALL_TRANSFORM_BITS; transform++) {
157             nPushBufferWithTransform(surface, transform);
158 
159             // The SurfaceTexture texture transform matrix first does a vertical flip so that
160             // "first row in memory" corresponds to "texture coordinate v=0".
161             System.arraycopy(MIRROR_VERTICAL_MATRIX, 0, computedTransform, 0, 16);
162 
163             if ((transform & MIRROR_HORIZONTAL_BIT) != 0) {
164                 matrixMultiply(computedTransform, computedTransform, MIRROR_HORIZONTAL_MATRIX, tmp);
165             }
166             if ((transform & MIRROR_VERTICAL_BIT) != 0) {
167                 matrixMultiply(computedTransform, computedTransform, MIRROR_VERTICAL_MATRIX, tmp);
168             }
169             if ((transform & ROTATE_90_BIT) != 0) {
170                 matrixMultiply(computedTransform, computedTransform, ROTATE_90_MATRIX, tmp);
171             }
172 
173             consumer.updateTexImage();
174             consumer.getTransformMatrix(receivedTransform);
175 
176             if (DEBUG) {
177                 Log.d(TAG, String.format(
178                         "Transform 0x%x:\n" +
179                         "  expected: % 2.0f % 2.0f % 2.0f % 2.0f\n" +
180                         "            % 2.0f % 2.0f % 2.0f % 2.0f\n" +
181                         "            % 2.0f % 2.0f % 2.0f % 2.0f\n" +
182                         "            % 2.0f % 2.0f % 2.0f % 2.0f\n" +
183                         "  actual:   % 2.0f % 2.0f % 2.0f % 2.0f\n" +
184                         "            % 2.0f % 2.0f % 2.0f % 2.0f\n" +
185                         "            % 2.0f % 2.0f % 2.0f % 2.0f\n" +
186                         "            % 2.0f % 2.0f % 2.0f % 2.0f\n",
187                         transform,
188                         computedTransform[ 0], computedTransform[ 1],
189                         computedTransform[ 2], computedTransform[ 3],
190                         computedTransform[ 4], computedTransform[ 5],
191                         computedTransform[ 6], computedTransform[ 7],
192                         computedTransform[ 8], computedTransform[ 9],
193                         computedTransform[10], computedTransform[11],
194                         computedTransform[12], computedTransform[13],
195                         computedTransform[14], computedTransform[15],
196                         receivedTransform[ 0], receivedTransform[ 1],
197                         receivedTransform[ 2], receivedTransform[ 3],
198                         receivedTransform[ 4], receivedTransform[ 5],
199                         receivedTransform[ 6], receivedTransform[ 7],
200                         receivedTransform[ 8], receivedTransform[ 9],
201                         receivedTransform[10], receivedTransform[11],
202                         receivedTransform[12], receivedTransform[13],
203                         receivedTransform[14], receivedTransform[15]));
204             }
205 
206             for (int i = 0; i < 16; i++) {
207                 assertEquals(computedTransform[i], receivedTransform[i], 0.0f);
208             }
209         }
210     }
211 
212     @Test
testSetBuffersDataSpace()213     public void testSetBuffersDataSpace() {
214         int[] texId = new int[1];
215         GLES20.glGenTextures(1, texId, 0);
216 
217         SurfaceTexture consumer = new SurfaceTexture(texId[0]);
218         consumer.setDefaultBufferSize(16, 16);
219         Surface surface = new Surface(consumer);
220 
221         assertEquals(nGetBuffersDataSpace(surface), 0);
222         assertEquals(nSetBuffersDataSpace(surface, DataSpace.ADATASPACE_SRGB), 0);
223         assertEquals(nGetBuffersDataSpace(surface), DataSpace.ADATASPACE_SRGB);
224 
225         assertEquals(nSetBuffersDataSpace(null, DataSpace.ADATASPACE_SRGB), -EINVAL);
226         assertEquals(nGetBuffersDataSpace(null), -EINVAL);
227         assertEquals(nGetBuffersDataSpace(surface), DataSpace.ADATASPACE_SRGB);
228     }
229 
230     @Test
testGetBuffersDefaultDataspace()231     public void testGetBuffersDefaultDataspace() {
232         assertEquals(nGetBuffersDefaultDataSpace(null), -EINVAL);
233 
234         ImageReader reader1 = new ImageReader.Builder(32, 32)
235                 .setDefaultDataSpace(DataSpace.ADATASPACE_BT709)
236                 .build();
237         assertEquals(nGetBuffersDefaultDataSpace(reader1.getSurface()), DataSpace.ADATASPACE_BT709);
238         reader1.close();
239 
240         ImageReader reader2 = new ImageReader.Builder(32, 32)
241                 .setDefaultDataSpace(DataSpace.ADATASPACE_BT2020)
242                 .build();
243         assertEquals(nGetBuffersDefaultDataSpace(reader2.getSurface()),
244                 DataSpace.ADATASPACE_BT2020);
245         reader2.close();
246     }
247 
248     @Test
testWriteToParcel()249     public void testWriteToParcel() {
250         ImageReader reader = new ImageReader.Builder(32, 32)
251                 .setDefaultDataSpace(DataSpace.ADATASPACE_BT709)
252                 .build();
253         Parcel parcel = Parcel.obtain();
254         assertEquals(0, parcel.dataPosition());
255         assertEquals(0, parcel.dataAvail());
256         nWriteToParcel(reader.getSurface(), parcel);
257         assertNotEquals(0, parcel.dataPosition());
258         parcel.setDataPosition(0);
259         final Surface outSurface = Surface.CREATOR.createFromParcel(parcel);
260         parcel.recycle();
261         assertTrue(outSurface.isValid());
262         assertEquals(nGetBuffersDefaultDataSpace(outSurface), DataSpace.ADATASPACE_BT709);
263         reader.close();
264     }
265 
266     @Test
testReadFromParcel()267     public void testReadFromParcel() {
268         ImageReader reader = new ImageReader.Builder(32, 32)
269                 .setDefaultDataSpace(DataSpace.ADATASPACE_BT709)
270                 .build();
271         Parcel parcel = Parcel.obtain();
272         assertEquals(0, parcel.dataPosition());
273         assertEquals(0, parcel.dataAvail());
274         reader.getSurface().writeToParcel(parcel, 0);
275         assertNotEquals(0, parcel.dataPosition());
276         parcel.setDataPosition(0);
277         final Surface outSurface = nReadFromParcel(parcel);
278         parcel.recycle();
279         assertTrue(outSurface.isValid());
280         assertEquals(nGetBuffersDefaultDataSpace(outSurface), DataSpace.ADATASPACE_BT709);
281         reader.close();
282     }
283 
284     @Test
testWriteReadFromParcel()285     public void testWriteReadFromParcel() {
286         ImageReader reader = new ImageReader.Builder(32, 32)
287                 .setDefaultDataSpace(DataSpace.ADATASPACE_BT709)
288                 .build();
289         Parcel parcel = Parcel.obtain();
290         assertEquals(0, parcel.dataPosition());
291         assertEquals(0, parcel.dataAvail());
292         nWriteToParcel(reader.getSurface(), parcel);
293         assertNotEquals(0, parcel.dataPosition());
294         parcel.setDataPosition(0);
295         final Surface outSurface = nReadFromParcel(parcel);
296         parcel.recycle();
297         assertTrue(outSurface.isValid());
298         assertEquals(nGetBuffersDefaultDataSpace(outSurface), DataSpace.ADATASPACE_BT709);
299         reader.close();
300     }
301 
302     // Multiply 4x4 matrices result = a*b. result can be the same as either a or b,
303     // allowing for result *= b. Another 4x4 matrix tmp must be provided as scratch space.
matrixMultiply(float[] result, float[] a, float[] b, float[] tmp)304     private void matrixMultiply(float[] result, float[] a, float[] b, float[] tmp) {
305         tmp[ 0] = a[ 0]*b[ 0] + a[ 4]*b[ 1] + a[ 8]*b[ 2] + a[12]*b[ 3];
306         tmp[ 1] = a[ 1]*b[ 0] + a[ 5]*b[ 1] + a[ 9]*b[ 2] + a[13]*b[ 3];
307         tmp[ 2] = a[ 2]*b[ 0] + a[ 6]*b[ 1] + a[10]*b[ 2] + a[14]*b[ 3];
308         tmp[ 3] = a[ 3]*b[ 0] + a[ 7]*b[ 1] + a[11]*b[ 2] + a[15]*b[ 3];
309 
310         tmp[ 4] = a[ 0]*b[ 4] + a[ 4]*b[ 5] + a[ 8]*b[ 6] + a[12]*b[ 7];
311         tmp[ 5] = a[ 1]*b[ 4] + a[ 5]*b[ 5] + a[ 9]*b[ 6] + a[13]*b[ 7];
312         tmp[ 6] = a[ 2]*b[ 4] + a[ 6]*b[ 5] + a[10]*b[ 6] + a[14]*b[ 7];
313         tmp[ 7] = a[ 3]*b[ 4] + a[ 7]*b[ 5] + a[11]*b[ 6] + a[15]*b[ 7];
314 
315         tmp[ 8] = a[ 0]*b[ 8] + a[ 4]*b[ 9] + a[ 8]*b[10] + a[12]*b[11];
316         tmp[ 9] = a[ 1]*b[ 8] + a[ 5]*b[ 9] + a[ 9]*b[10] + a[13]*b[11];
317         tmp[10] = a[ 2]*b[ 8] + a[ 6]*b[ 9] + a[10]*b[10] + a[14]*b[11];
318         tmp[11] = a[ 3]*b[ 8] + a[ 7]*b[ 9] + a[11]*b[10] + a[15]*b[11];
319 
320         tmp[12] = a[ 0]*b[12] + a[ 4]*b[13] + a[ 8]*b[14] + a[12]*b[15];
321         tmp[13] = a[ 1]*b[12] + a[ 5]*b[13] + a[ 9]*b[14] + a[13]*b[15];
322         tmp[14] = a[ 2]*b[12] + a[ 6]*b[13] + a[10]*b[14] + a[14]*b[15];
323         tmp[15] = a[ 3]*b[12] + a[ 7]*b[13] + a[11]*b[14] + a[15]*b[15];
324 
325         System.arraycopy(tmp, 0, result, 0, 16);
326     }
327 
328     @Test
testTryAllocateBuffersDoesNotCrash()329     public void testTryAllocateBuffersDoesNotCrash() {
330         int[] texId = new int[1];
331         GLES20.glGenTextures(1, texId, 0);
332 
333         SurfaceTexture consumer = new SurfaceTexture(texId[0]);
334         consumer.setDefaultBufferSize(16, 16);
335         Surface surface = new Surface(consumer);
336 
337         nTryAllocateBuffers(surface);
338         nTryAllocateBuffers(null);
339     }
340 
nPushBufferWithTransform(Surface surface, int transform)341     private static native void nPushBufferWithTransform(Surface surface, int transform);
nSetBuffersDataSpace(Surface surface, int dataSpace)342     private static native int nSetBuffersDataSpace(Surface surface, int dataSpace);
nGetBuffersDataSpace(Surface surface)343     private static native int nGetBuffersDataSpace(Surface surface);
nGetBuffersDefaultDataSpace(Surface surface)344     private static native int nGetBuffersDefaultDataSpace(Surface surface);
nTryAllocateBuffers(Surface surface)345     private static native void nTryAllocateBuffers(Surface surface);
nReadFromParcel(Parcel parcel)346     private static native Surface nReadFromParcel(Parcel parcel);
nWriteToParcel(Surface surface, Parcel parcel)347     private static native void nWriteToParcel(Surface surface, Parcel parcel);
348 }
349