5package org.qtproject.qt.android;
7import android.annotation.SuppressLint;
8import android.content.Context;
9import android.content.res.TypedArray;
10import android.graphics.PixelFormat;
11import android.graphics.Rect;
12import android.opengl.EGL14;
13import android.opengl.EGLConfig;
14import android.opengl.EGLContext;
15import android.opengl.EGLDisplay;
16import android.opengl.EGLSurface;
17import android.opengl.GLES20;
18import android.os.Build;
19import android.util.Log;
20import android.view.Surface;
21import android.view.SurfaceControl;
22import android.view.SurfaceHolder;
23import android.view.SurfaceView;
25@SuppressLint(
"ViewConstructor")
26class QtSurface extends SurfaceView implements SurfaceHolder.Callback2
28 private final int m_format;
30 private boolean m_backgroundPrimed =
false;
31 private SurfaceControl m_renderControl;
32 private Surface m_renderSurface;
38 setFocusableInTouchMode(
false);
39 setZOrderMediaOverlay(onTop);
40 m_surfaceCallback = surfaceCallback;
41 m_format = imageDepth == 16 ? PixelFormat.RGB_565 :
PixelFormat.RGBA_8888;
42 SurfaceHolder holder = getHolder();
43 holder.setFormat(m_format);
44 holder.addCallback(
this);
48 public void surfaceCreated(SurfaceHolder holder)
51 final Rect frame = holder.getSurfaceFrame();
53 && paintBackgroundColor(holder.getSurface());
54 if (Build.VERSION.SDK_INT >= 29) {
56 final SurfaceControl control =
new SurfaceControl.Builder()
58 .setParent(getSurfaceControl())
59 .setBufferSize(Math.max(1, getWidth()), Math.max(1, getHeight()))
63 initializeRenderSurface(control,
new Surface(control));
64 }
catch (RuntimeException |
Error failure) {
67 }
catch (RuntimeException |
Error cleanupFailure) {
68 failure.addSuppressed(cleanupFailure);
73 if (m_surfaceCallback !=
null)
74 m_surfaceCallback.onSurfaceCreated(
75 m_renderSurface !=
null ? m_renderSurface : holder.getSurface());
78 private void initializeRenderSurface(SurfaceControl control, Surface surface)
80 try (SurfaceControl.Transaction transaction =
new SurfaceControl.Transaction()) {
81 transaction.setVisibility(control,
true).apply();
82 }
catch (RuntimeException |
Error failure) {
85 }
catch (RuntimeException |
Error cleanupFailure) {
86 failure.addSuppressed(cleanupFailure);
90 m_renderControl = control;
91 m_renderSurface = surface;
95 public void surfaceChanged(SurfaceHolder holder,
int format,
int width,
int height)
97 if (m_renderControl !=
null) {
98 try (SurfaceControl.Transaction transaction =
new SurfaceControl.Transaction()) {
99 transaction.setBufferSize(m_renderControl,
width,
height).apply();
103 if (!m_backgroundPrimed && m_renderSurface !=
null &&
width > 0 &&
height > 0)
104 m_backgroundPrimed = paintBackgroundColor(holder.getSurface());
108 public void surfaceRedrawNeeded(SurfaceHolder holder)
114 public void surfaceRedrawNeededAsync(SurfaceHolder holder, Runnable drawingFinished)
117 if (m_renderSurface !=
null)
118 paintBackgroundColor(holder.getSurface());
119 if (m_surfaceCallback !=
null)
120 m_surfaceCallback.onSurfaceRedrawNeeded(drawingFinished);
122 drawingFinished.run();
126 public void surfaceDestroyed(SurfaceHolder holder)
128 final Surface surface = m_renderSurface;
129 final SurfaceControl control = m_renderControl;
130 m_renderSurface =
null;
131 m_renderControl =
null;
132 final Runnable released = () -> {
138 Throwable detachFailure =
null;
140 if (control !=
null) {
141 try (SurfaceControl.Transaction transaction =
new SurfaceControl.Transaction()) {
142 transaction.reparent(control,
null).apply();
145 }
catch (RuntimeException |
Error failure) {
146 detachFailure = failure;
150 if (m_surfaceCallback !=
null)
151 m_surfaceCallback.onSurfaceDestroyed(released);
154 }
catch (RuntimeException |
Error failure) {
155 if (detachFailure ==
null)
157 detachFailure.addSuppressed(failure);
164 private boolean paintBackgroundColor(Surface surface)
166 if (surface ==
null || !surface.isValid()) {
167 Log.w(
QtNative.QtTAG,
"Cannot prime an invalid background Surface");
172 if (
display == EGL14.EGL_NO_DISPLAY)
173 return backgroundEglFailure(
"get display");
175 final int[] version =
new int[2];
176 if (!EGL14.eglInitialize(
display, version, 0, version, 1))
177 return backgroundEglFailure(
"initialize display");
179 final EGLConfig[] configs =
new EGLConfig[1];
180 final int[] matching =
new int[1];
181 final int[] configAttribs = {
182 EGL14.EGL_SURFACE_TYPE, EGL14.EGL_WINDOW_BIT,
183 EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,
184 EGL14.EGL_RED_SIZE, 8,
185 EGL14.EGL_GREEN_SIZE, 8,
186 EGL14.EGL_BLUE_SIZE, 8,
187 EGL14.EGL_ALPHA_SIZE, 8,
191 if (!EGL14.eglChooseConfig(
display, configAttribs, 0, configs, 0, 1, matching, 0))
192 return backgroundEglFailure(
"choose config");
194 if (matching[0] == 0) {
195 Log.w(
QtNative.QtTAG,
"No EGL config for the background Surface");
199 final int[] contextAttribs = { EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE };
200 final EGLContext
context = EGL14.eglCreateContext(
display, configs[0],
201 EGL14.EGL_NO_CONTEXT, contextAttribs, 0);
202 if (context == EGL14.EGL_NO_CONTEXT)
203 return backgroundEglFailure(
"create context");
206 surface,
new int[] { EGL14.EGL_NONE }, 0);
207 if (eglSurface == EGL14.EGL_NO_SURFACE) {
208 backgroundEglFailure(
"create window surface");
209 if (!EGL14.eglDestroyContext(
display, context))
210 backgroundEglFailure(
"destroy context");
215 final EGLDisplay previousDisplay = EGL14.eglGetCurrentDisplay();
216 final EGLContext previousContext = EGL14.eglGetCurrentContext();
217 final EGLSurface previousDraw = EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW);
218 final EGLSurface previousRead = EGL14.eglGetCurrentSurface(EGL14.EGL_READ);
219 boolean madeCurrent =
false;
221 madeCurrent = EGL14.eglMakeCurrent(
display, eglSurface, eglSurface, context);
223 Log.w(
QtNative.QtTAG,
"Cannot bind the background EGL context: 0x"
224 +
Integer.toHexString(EGL14.eglGetError()));
227 final int color = resolveBackgroundColor();
229 ((
color >> 16) & 0xff) / 255
f,
230 ((
color >> 8) & 0xff) / 255
f,
232 ((
color >>> 24) & 0xff) / 255
f);
233 GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
234 if (!EGL14.eglSwapBuffers(
display, eglSurface)) {
235 Log.w(
QtNative.QtTAG,
"Cannot post the background EGL buffer: 0x"
236 +
Integer.toHexString(EGL14.eglGetError()));
242 final EGLDisplay restoreDisplay = previousDisplay.equals(EGL14.EGL_NO_DISPLAY)
244 if (!EGL14.eglMakeCurrent(restoreDisplay, previousDraw,
245 previousRead, previousContext)) {
246 Log.w(
QtNative.QtTAG,
"Cannot restore the UI thread EGL binding: 0x"
247 +
Integer.toHexString(EGL14.eglGetError()));
248 if (!EGL14.eglMakeCurrent(
display, EGL14.EGL_NO_SURFACE,
249 EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT)) {
250 Log.w(
QtNative.QtTAG,
"Cannot release the background EGL binding: 0x"
251 +
Integer.toHexString(EGL14.eglGetError()));
255 if (!EGL14.eglDestroySurface(
display, eglSurface)) {
256 Log.w(
QtNative.QtTAG,
"Cannot destroy the background EGL surface: 0x"
257 +
Integer.toHexString(EGL14.eglGetError()));
259 if (!EGL14.eglDestroyContext(
display, context)) {
260 Log.w(
QtNative.QtTAG,
"Cannot destroy the background EGL context: 0x"
261 +
Integer.toHexString(EGL14.eglGetError()));
266 private static boolean backgroundEglFailure(String operation)
268 Log.w(
QtNative.QtTAG,
"Cannot " + operation +
" for the background EGL buffer: 0x"
269 +
Integer.toHexString(EGL14.eglGetError()));
273 private int resolveBackgroundColor()
275 TypedArray typedArray = getContext().getTheme().obtainStyledAttributes(
277 android.R.attr.windowSplashScreenBackground,
278 android.R.attr.colorBackground
282 final int splash = typedArray.getColor(0, 0);
284 return splash | 0xff000000;
285 return typedArray.getColor(1, 0xff000000) | 0xff000000;
287 typedArray.recycle();
struct wl_display * display
Napi::TypedArray TypedArray
QVideoFrameFormat::PixelFormat PixelFormat
typedef EGLSurface(EGLAPIENTRYP PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC)(EGLDisplay dpy
typedef EGLDisplay(EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC)(EGLenum platform
GLuint color
[setDefaultFactory]