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 org.junit.Assert.assertEquals; 20 import static android.opengl.EGL14.*; 21 22 import android.graphics.SurfaceTexture; 23 import android.opengl.EGL14; 24 import android.opengl.EGLConfig; 25 import android.opengl.EGLContext; 26 import android.opengl.EGLDisplay; 27 import android.opengl.EGLSurface; 28 import android.opengl.GLES20; 29 import android.support.test.filters.SmallTest; 30 import android.view.Surface; 31 import android.util.Log; 32 33 import org.junit.Before; 34 import org.junit.Test; 35 import org.junit.runner.RunWith; 36 import org.junit.runners.BlockJUnit4ClassRunner; 37 38 39 @SmallTest 40 @RunWith(BlockJUnit4ClassRunner.class) 41 public class ANativeWindowTest { 42 43 static { 44 System.loadLibrary("ctsgraphics_jni"); 45 } 46 47 private static final String TAG = ANativeWindowTest.class.getSimpleName(); 48 private static final boolean DEBUG = false; 49 50 private EGLDisplay mEglDisplay = EGL_NO_DISPLAY; 51 private EGLConfig mEglConfig = null; 52 private EGLSurface mEglPbuffer = EGL_NO_SURFACE; 53 private EGLContext mEglContext = EGL_NO_CONTEXT; 54 55 @Before 56 public void setup() throws Throwable { 57 mEglDisplay = EGL14.eglGetDisplay(EGL_DEFAULT_DISPLAY); 58 if (mEglDisplay == EGL_NO_DISPLAY) { 59 throw new RuntimeException("no EGL display"); 60 } 61 int[] major = new int[1]; 62 int[] minor = new int[1]; 63 if (!EGL14.eglInitialize(mEglDisplay, major, 0, minor, 0)) { 64 throw new RuntimeException("error in eglInitialize"); 65 } 66 67 // If we could rely on having EGL_KHR_surfaceless_context and EGL_KHR_context_no_config, we 68 // wouldn't have to create a config or pbuffer at all. 69 70 int[] numConfigs = new int[1]; 71 EGLConfig[] configs = new EGLConfig[1]; 72 if (!EGL14.eglChooseConfig(mEglDisplay, 73 new int[] { 74 EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, 75 EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, 76 EGL_NONE}, 77 0, configs, 0, 1, numConfigs, 0)) { 78 throw new RuntimeException("eglChooseConfig failed"); 79 } 80 mEglConfig = configs[0]; 81 82 mEglPbuffer = EGL14.eglCreatePbufferSurface(mEglDisplay, mEglConfig, 83 new int[] {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE}, 0); 84 if (mEglPbuffer == EGL_NO_SURFACE) { 85 throw new RuntimeException("eglCreatePbufferSurface failed"); 86 } 87 88 mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, 89 new int[] {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE}, 0); 90 if (mEglContext == EGL_NO_CONTEXT) { 91 throw new RuntimeException("eglCreateContext failed"); 92 } 93 94 if (!EGL14.eglMakeCurrent(mEglDisplay, mEglPbuffer, mEglPbuffer, mEglContext)) { 95 throw new RuntimeException("eglMakeCurrent failed"); 96 } 97 } 98 99 @Test 100 public void testSetBuffersTransform() { 101 final int MIRROR_HORIZONTAL_BIT = 0x01; 102 final int MIRROR_VERTICAL_BIT = 0x02; 103 final int ROTATE_90_BIT = 0x04; 104 final int ALL_TRANSFORM_BITS = 105 MIRROR_HORIZONTAL_BIT | MIRROR_VERTICAL_BIT | ROTATE_90_BIT; 106 107 // 4x4 GL-style matrices, as returned by SurfaceTexture#getTransformMatrix(). Note they're 108 // transforming texture coordinates ([0,1]^2), so the origin for the transforms is 109 // (0.5, 0.5), not (0,0). 110 final float[] MIRROR_HORIZONTAL_MATRIX = new float[] { 111 -1.0f, 0.0f, 0.0f, 0.0f, 112 0.0f, 1.0f, 0.0f, 0.0f, 113 0.0f, 0.0f, 1.0f, 0.0f, 114 1.0f, 0.0f, 0.0f, 1.0f, 115 }; 116 final float[] MIRROR_VERTICAL_MATRIX = new float[] { 117 1.0f, 0.0f, 0.0f, 0.0f, 118 0.0f, -1.0f, 0.0f, 0.0f, 119 0.0f, 0.0f, 1.0f, 0.0f, 120 0.0f, 1.0f, 0.0f, 1.0f, 121 }; 122 final float[] ROTATE_90_MATRIX = new float[] { 123 0.0f, 1.0f, 0.0f, 0.0f, 124 -1.0f, 0.0f, 0.0f, 0.0f, 125 0.0f, 0.0f, 1.0f, 0.0f, 126 1.0f, 0.0f, 0.0f, 1.0f, 127 }; 128 129 int[] texId = new int[1]; 130 GLES20.glGenTextures(1, texId, 0); 131 132 SurfaceTexture consumer = new SurfaceTexture(texId[0]); 133 consumer.setDefaultBufferSize(16, 16); 134 Surface surface = new Surface(consumer); 135 136 float[] computedTransform = new float[16]; 137 float[] receivedTransform = new float[16]; 138 float[] tmp = new float[16]; 139 for (int transform = 0; transform <= ALL_TRANSFORM_BITS; transform++) { 140 nPushBufferWithTransform(surface, transform); 141 142 // The SurfaceTexture texture transform matrix first does a vertical flip so that 143 // "first row in memory" corresponds to "texture coordinate v=0". 144 System.arraycopy(MIRROR_VERTICAL_MATRIX, 0, computedTransform, 0, 16); 145 146 if ((transform & MIRROR_HORIZONTAL_BIT) != 0) { 147 matrixMultiply(computedTransform, computedTransform, MIRROR_HORIZONTAL_MATRIX, tmp); 148 } 149 if ((transform & MIRROR_VERTICAL_BIT) != 0) { 150 matrixMultiply(computedTransform, computedTransform, MIRROR_VERTICAL_MATRIX, tmp); 151 } 152 if ((transform & ROTATE_90_BIT) != 0) { 153 matrixMultiply(computedTransform, computedTransform, ROTATE_90_MATRIX, tmp); 154 } 155 156 consumer.updateTexImage(); 157 consumer.getTransformMatrix(receivedTransform); 158 159 if (DEBUG) { 160 Log.d(TAG, String.format( 161 "Transform 0x%x:\n" + 162 " expected: % 2.0f % 2.0f % 2.0f % 2.0f\n" + 163 " % 2.0f % 2.0f % 2.0f % 2.0f\n" + 164 " % 2.0f % 2.0f % 2.0f % 2.0f\n" + 165 " % 2.0f % 2.0f % 2.0f % 2.0f\n" + 166 " actual: % 2.0f % 2.0f % 2.0f % 2.0f\n" + 167 " % 2.0f % 2.0f % 2.0f % 2.0f\n" + 168 " % 2.0f % 2.0f % 2.0f % 2.0f\n" + 169 " % 2.0f % 2.0f % 2.0f % 2.0f\n", 170 transform, 171 computedTransform[ 0], computedTransform[ 1], 172 computedTransform[ 2], computedTransform[ 3], 173 computedTransform[ 4], computedTransform[ 5], 174 computedTransform[ 6], computedTransform[ 7], 175 computedTransform[ 8], computedTransform[ 9], 176 computedTransform[10], computedTransform[11], 177 computedTransform[12], computedTransform[13], 178 computedTransform[14], computedTransform[15], 179 receivedTransform[ 0], receivedTransform[ 1], 180 receivedTransform[ 2], receivedTransform[ 3], 181 receivedTransform[ 4], receivedTransform[ 5], 182 receivedTransform[ 6], receivedTransform[ 7], 183 receivedTransform[ 8], receivedTransform[ 9], 184 receivedTransform[10], receivedTransform[11], 185 receivedTransform[12], receivedTransform[13], 186 receivedTransform[14], receivedTransform[15])); 187 } 188 189 for (int i = 0; i < 16; i++) { 190 assertEquals(computedTransform[i], receivedTransform[i], 0.0f); 191 } 192 } 193 } 194 195 @Test 196 public void testSetBuffersDataSpace() { 197 final int DATASPACE_SRGB = 142671872; 198 final int DATASPACE_UNKNOWN = 123; 199 200 int[] texId = new int[1]; 201 GLES20.glGenTextures(1, texId, 0); 202 203 SurfaceTexture consumer = new SurfaceTexture(texId[0]); 204 consumer.setDefaultBufferSize(16, 16); 205 Surface surface = new Surface(consumer); 206 207 assertEquals(nGetBuffersDataSpace(surface), 0); 208 assertEquals(nSetBuffersDataSpace(surface, DATASPACE_SRGB), 0); 209 assertEquals(nGetBuffersDataSpace(surface), DATASPACE_SRGB); 210 211 assertEquals(nSetBuffersDataSpace(null, DATASPACE_SRGB), -22); 212 assertEquals(nGetBuffersDataSpace(null), -22); 213 assertEquals(nGetBuffersDataSpace(surface), DATASPACE_SRGB); 214 215 // set an unsupported data space should return a error code, 216 // the original data space shouldn't change. 217 assertEquals(nSetBuffersDataSpace(surface, DATASPACE_UNKNOWN), -22); 218 assertEquals(nGetBuffersDataSpace(surface), DATASPACE_SRGB); 219 } 220 221 // Multiply 4x4 matrices result = a*b. result can be the same as either a or b, 222 // allowing for result *= b. Another 4x4 matrix tmp must be provided as scratch space. 223 private void matrixMultiply(float[] result, float[] a, float[] b, float[] tmp) { 224 tmp[ 0] = a[ 0]*b[ 0] + a[ 4]*b[ 1] + a[ 8]*b[ 2] + a[12]*b[ 3]; 225 tmp[ 1] = a[ 1]*b[ 0] + a[ 5]*b[ 1] + a[ 9]*b[ 2] + a[13]*b[ 3]; 226 tmp[ 2] = a[ 2]*b[ 0] + a[ 6]*b[ 1] + a[10]*b[ 2] + a[14]*b[ 3]; 227 tmp[ 3] = a[ 3]*b[ 0] + a[ 7]*b[ 1] + a[11]*b[ 2] + a[15]*b[ 3]; 228 229 tmp[ 4] = a[ 0]*b[ 4] + a[ 4]*b[ 5] + a[ 8]*b[ 6] + a[12]*b[ 7]; 230 tmp[ 5] = a[ 1]*b[ 4] + a[ 5]*b[ 5] + a[ 9]*b[ 6] + a[13]*b[ 7]; 231 tmp[ 6] = a[ 2]*b[ 4] + a[ 6]*b[ 5] + a[10]*b[ 6] + a[14]*b[ 7]; 232 tmp[ 7] = a[ 3]*b[ 4] + a[ 7]*b[ 5] + a[11]*b[ 6] + a[15]*b[ 7]; 233 234 tmp[ 8] = a[ 0]*b[ 8] + a[ 4]*b[ 9] + a[ 8]*b[10] + a[12]*b[11]; 235 tmp[ 9] = a[ 1]*b[ 8] + a[ 5]*b[ 9] + a[ 9]*b[10] + a[13]*b[11]; 236 tmp[10] = a[ 2]*b[ 8] + a[ 6]*b[ 9] + a[10]*b[10] + a[14]*b[11]; 237 tmp[11] = a[ 3]*b[ 8] + a[ 7]*b[ 9] + a[11]*b[10] + a[15]*b[11]; 238 239 tmp[12] = a[ 0]*b[12] + a[ 4]*b[13] + a[ 8]*b[14] + a[12]*b[15]; 240 tmp[13] = a[ 1]*b[12] + a[ 5]*b[13] + a[ 9]*b[14] + a[13]*b[15]; 241 tmp[14] = a[ 2]*b[12] + a[ 6]*b[13] + a[10]*b[14] + a[14]*b[15]; 242 tmp[15] = a[ 3]*b[12] + a[ 7]*b[13] + a[11]*b[14] + a[15]*b[15]; 243 244 System.arraycopy(tmp, 0, result, 0, 16); 245 } 246 247 private static native void nPushBufferWithTransform(Surface surface, int transform); 248 private static native int nSetBuffersDataSpace(Surface surface, int dataSpace); 249 private static native int nGetBuffersDataSpace(Surface surface); 250 } 251