• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "flutter/shell/platform/android/android_external_texture_gl.h"
6 
7 #include <GLES/glext.h>
8 
9 #include "flutter/shell/platform/android/platform_view_android_jni.h"
10 #include "third_party/skia/include/gpu/GrBackendSurface.h"
11 
12 namespace flutter {
13 
AndroidExternalTextureGL(int64_t id,const fml::jni::JavaObjectWeakGlobalRef & surfaceTexture)14 AndroidExternalTextureGL::AndroidExternalTextureGL(
15     int64_t id,
16     const fml::jni::JavaObjectWeakGlobalRef& surfaceTexture)
17     : Texture(id), surface_texture_(surfaceTexture), transform(SkMatrix::I()) {}
18 
~AndroidExternalTextureGL()19 AndroidExternalTextureGL::~AndroidExternalTextureGL() {
20   if (state_ == AttachmentState::attached) {
21     glDeleteTextures(1, &texture_name_);
22   }
23 }
24 
OnGrContextCreated()25 void AndroidExternalTextureGL::OnGrContextCreated() {
26   state_ = AttachmentState::uninitialized;
27 }
28 
MarkNewFrameAvailable()29 void AndroidExternalTextureGL::MarkNewFrameAvailable() {
30   new_frame_ready_ = true;
31 }
32 
Paint(SkCanvas & canvas,const SkRect & bounds,bool freeze,GrContext * context)33 void AndroidExternalTextureGL::Paint(SkCanvas& canvas,
34                                      const SkRect& bounds,
35                                      bool freeze,
36                                      GrContext* context) {
37   if (state_ == AttachmentState::detached) {
38     return;
39   }
40   if (state_ == AttachmentState::uninitialized) {
41     glGenTextures(1, &texture_name_);
42     Attach(static_cast<jint>(texture_name_));
43     state_ = AttachmentState::attached;
44   }
45   if (!freeze && new_frame_ready_) {
46     Update();
47     new_frame_ready_ = false;
48   }
49   GrGLTextureInfo textureInfo = {GL_TEXTURE_EXTERNAL_OES, texture_name_,
50                                  GL_RGBA8_OES};
51   GrBackendTexture backendTexture(1, 1, GrMipMapped::kNo, textureInfo);
52   sk_sp<SkImage> image = SkImage::MakeFromTexture(
53       canvas.getGrContext(), backendTexture, kTopLeft_GrSurfaceOrigin,
54       kRGBA_8888_SkColorType, kPremul_SkAlphaType, nullptr);
55   if (image) {
56     SkAutoCanvasRestore autoRestore(&canvas, true);
57     canvas.translate(bounds.x(), bounds.y());
58     canvas.scale(bounds.width(), bounds.height());
59     if (!transform.isIdentity()) {
60       SkMatrix transformAroundCenter(transform);
61 
62       transformAroundCenter.preTranslate(-0.5, -0.5);
63       transformAroundCenter.postScale(1, -1);
64       transformAroundCenter.postTranslate(0.5, 0.5);
65       canvas.concat(transformAroundCenter);
66     }
67     canvas.drawImage(image, 0, 0);
68   }
69 }
70 
71 // The bounds we set for the canvas are post composition.
72 // To fill the canvas we need to ensure that the transformation matrix
73 // on the `SurfaceTexture` will be scaled to fill. We rescale and preseve
74 // the scaled aspect ratio.
ScaleToFill(float scaleX,float scaleY)75 SkSize ScaleToFill(float scaleX, float scaleY) {
76   const double epsilon = std::numeric_limits<double>::epsilon();
77   // scaleY is negative.
78   const double minScale = fmin(scaleX, fabs(scaleY));
79   const double rescale = 1.0f / (minScale + epsilon);
80   return SkSize::Make(scaleX * rescale, scaleY * rescale);
81 }
82 
UpdateTransform()83 void AndroidExternalTextureGL::UpdateTransform() {
84   JNIEnv* env = fml::jni::AttachCurrentThread();
85   fml::jni::ScopedJavaLocalRef<jobject> surfaceTexture =
86       surface_texture_.get(env);
87   fml::jni::ScopedJavaLocalRef<jfloatArray> transformMatrix(
88       env, env->NewFloatArray(16));
89   SurfaceTextureGetTransformMatrix(env, surfaceTexture.obj(),
90                                    transformMatrix.obj());
91   float* m = env->GetFloatArrayElements(transformMatrix.obj(), nullptr);
92   float scaleX = m[0], scaleY = m[5];
93   const SkSize scaled = ScaleToFill(scaleX, scaleY);
94   SkScalar matrix3[] = {
95       scaled.fWidth, m[1],           m[2],   //
96       m[4],          scaled.fHeight, m[6],   //
97       m[8],          m[9],           m[10],  //
98   };
99   env->ReleaseFloatArrayElements(transformMatrix.obj(), m, JNI_ABORT);
100   transform.set9(matrix3);
101 }
102 
OnGrContextDestroyed()103 void AndroidExternalTextureGL::OnGrContextDestroyed() {
104   if (state_ == AttachmentState::attached) {
105     Detach();
106   }
107   state_ = AttachmentState::detached;
108 }
109 
Attach(jint textureName)110 void AndroidExternalTextureGL::Attach(jint textureName) {
111   JNIEnv* env = fml::jni::AttachCurrentThread();
112   fml::jni::ScopedJavaLocalRef<jobject> surfaceTexture =
113       surface_texture_.get(env);
114   if (!surfaceTexture.is_null()) {
115     SurfaceTextureAttachToGLContext(env, surfaceTexture.obj(), textureName);
116   }
117 }
118 
Update()119 void AndroidExternalTextureGL::Update() {
120   JNIEnv* env = fml::jni::AttachCurrentThread();
121   fml::jni::ScopedJavaLocalRef<jobject> surfaceTexture =
122       surface_texture_.get(env);
123   if (!surfaceTexture.is_null()) {
124     SurfaceTextureUpdateTexImage(env, surfaceTexture.obj());
125     UpdateTransform();
126   }
127 }
128 
Detach()129 void AndroidExternalTextureGL::Detach() {
130   JNIEnv* env = fml::jni::AttachCurrentThread();
131   fml::jni::ScopedJavaLocalRef<jobject> surfaceTexture =
132       surface_texture_.get(env);
133   if (!surfaceTexture.is_null()) {
134     SurfaceTextureDetachFromGLContext(env, surfaceTexture.obj());
135   }
136 }
137 
138 }  // namespace flutter
139