1 /*
2  * Copyright (C) 2019 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 com.android.server.wallpaper;
18 
19 import static android.opengl.EGL14.EGL_ALPHA_SIZE;
20 import static android.opengl.EGL14.EGL_BLUE_SIZE;
21 import static android.opengl.EGL14.EGL_CONFIG_CAVEAT;
22 import static android.opengl.EGL14.EGL_CONTEXT_CLIENT_VERSION;
23 import static android.opengl.EGL14.EGL_DEFAULT_DISPLAY;
24 import static android.opengl.EGL14.EGL_DEPTH_SIZE;
25 import static android.opengl.EGL14.EGL_GREEN_SIZE;
26 import static android.opengl.EGL14.EGL_HEIGHT;
27 import static android.opengl.EGL14.EGL_NONE;
28 import static android.opengl.EGL14.EGL_NO_CONTEXT;
29 import static android.opengl.EGL14.EGL_NO_DISPLAY;
30 import static android.opengl.EGL14.EGL_NO_SURFACE;
31 import static android.opengl.EGL14.EGL_OPENGL_ES2_BIT;
32 import static android.opengl.EGL14.EGL_RED_SIZE;
33 import static android.opengl.EGL14.EGL_RENDERABLE_TYPE;
34 import static android.opengl.EGL14.EGL_STENCIL_SIZE;
35 import static android.opengl.EGL14.EGL_WIDTH;
36 import static android.opengl.EGL14.eglChooseConfig;
37 import static android.opengl.EGL14.eglCreateContext;
38 import static android.opengl.EGL14.eglCreatePbufferSurface;
39 import static android.opengl.EGL14.eglDestroyContext;
40 import static android.opengl.EGL14.eglDestroySurface;
41 import static android.opengl.EGL14.eglGetDisplay;
42 import static android.opengl.EGL14.eglGetError;
43 import static android.opengl.EGL14.eglInitialize;
44 import static android.opengl.EGL14.eglMakeCurrent;
45 import static android.opengl.EGL14.eglTerminate;
46 import static android.opengl.GLES20.GL_MAX_TEXTURE_SIZE;
47 import static android.opengl.GLES20.glGetIntegerv;
48 
49 import android.opengl.EGLConfig;
50 import android.opengl.EGLContext;
51 import android.opengl.EGLDisplay;
52 import android.opengl.EGLSurface;
53 import android.opengl.GLUtils;
54 import android.os.SystemProperties;
55 import android.util.Log;
56 
57 class GLHelper {
58     private static final String TAG = GLHelper.class.getSimpleName();
59     private static final int sMaxTextureSize;
60 
61     static {
62         int maxTextureSize = SystemProperties.getInt("sys.max_texture_size", 0);
63         sMaxTextureSize = maxTextureSize > 0 ? maxTextureSize : retrieveTextureSizeFromGL();
64     }
65 
retrieveTextureSizeFromGL()66     private static int retrieveTextureSizeFromGL() {
67         try {
68             String err;
69 
70             // Before we can retrieve info from GL,
71             // we have to create EGLContext, EGLConfig and EGLDisplay first.
72             // We will fail at querying info from GL once one of above failed.
73             // When this happens, we will use defValue instead.
74             EGLDisplay eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
75             if (eglDisplay == null || eglDisplay == EGL_NO_DISPLAY) {
76                 err = "eglGetDisplay failed: " + GLUtils.getEGLErrorString(eglGetError());
77                 throw new RuntimeException(err);
78             }
79 
80             if (!eglInitialize(eglDisplay, null, 0 /* majorOffset */, null, 1 /* minorOffset */)) {
81                 err = "eglInitialize failed: " + GLUtils.getEGLErrorString(eglGetError());
82                 throw new RuntimeException(err);
83             }
84 
85             EGLConfig eglConfig = null;
86             int[] configsCount = new int[1];
87             EGLConfig[] configs = new EGLConfig[1];
88             int[] configSpec = new int[] {
89                     EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
90                     EGL_RED_SIZE, 8,
91                     EGL_GREEN_SIZE, 8,
92                     EGL_BLUE_SIZE, 8,
93                     EGL_ALPHA_SIZE, 0,
94                     EGL_DEPTH_SIZE, 0,
95                     EGL_STENCIL_SIZE, 0,
96                     EGL_CONFIG_CAVEAT, EGL_NONE,
97                     EGL_NONE
98             };
99 
100             if (!eglChooseConfig(eglDisplay, configSpec, 0 /* attrib_listOffset */,
101                     configs, 0  /* configOffset */, 1 /* config_size */,
102                     configsCount, 0 /* num_configOffset */)) {
103                 err = "eglChooseConfig failed: " + GLUtils.getEGLErrorString(eglGetError());
104                 throw new RuntimeException(err);
105             } else if (configsCount[0] > 0) {
106                 eglConfig = configs[0];
107             }
108 
109             if (eglConfig == null) {
110                 throw new RuntimeException("eglConfig not initialized!");
111             }
112 
113             int[] attr_list = new int[] {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
114             EGLContext eglContext = eglCreateContext(
115                     eglDisplay, eglConfig, EGL_NO_CONTEXT, attr_list, 0 /* offset */);
116 
117             if (eglContext == null || eglContext == EGL_NO_CONTEXT) {
118                 err = "eglCreateContext failed: " + GLUtils.getEGLErrorString(eglGetError());
119                 throw new RuntimeException(err);
120             }
121 
122             // We create a push buffer temporarily for querying info from GL.
123             int[] attrs = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE};
124             EGLSurface eglSurface =
125                     eglCreatePbufferSurface(eglDisplay, eglConfig, attrs, 0 /* offset */);
126             eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);
127 
128             // Now, we are ready to query the info from GL.
129             int[] maxSize = new int[1];
130             glGetIntegerv(GL_MAX_TEXTURE_SIZE, maxSize, 0 /* offset */);
131 
132             // We have got the info we want, release all egl resources.
133             eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
134             eglDestroySurface(eglDisplay, eglSurface);
135             eglDestroyContext(eglDisplay, eglContext);
136             eglTerminate(eglDisplay);
137             return maxSize[0];
138         } catch (RuntimeException e) {
139             Log.w(TAG, "Retrieve from GL failed", e);
140             return Integer.MAX_VALUE;
141         }
142     }
143 
getMaxTextureSize()144     static int getMaxTextureSize() {
145         return sMaxTextureSize;
146     }
147 }
148 
149