mirror of
https://github.com/flutter/flutter.git
synced 2025-06-03 00:51:18 +00:00
[Impeller] fix scaling of trampoline import of GLES textures into Vulkan. (#161331)
Not sure if this just needs the dpr transform or the entire canvas transform. Fixes https://github.com/flutter/flutter/issues/159688 ## Before  ## After 
This commit is contained in:
parent
a38abc864c
commit
96dffbeda5
@ -13,6 +13,7 @@ import androidx.core.view.WindowInsetsControllerCompat
|
||||
import com.example.android_engine_test.extensions.NativeDriverSupportPlugin
|
||||
import com.example.android_engine_test.fixtures.BlueOrangeGradientPlatformViewFactory
|
||||
import com.example.android_engine_test.fixtures.ChangingColorButtonPlatformViewFactory
|
||||
import com.example.android_engine_test.fixtures.OtherFaceTexturePlugin
|
||||
import com.example.android_engine_test.fixtures.SmileyFaceTexturePlugin
|
||||
import io.flutter.embedding.android.FlutterActivity
|
||||
import io.flutter.embedding.engine.FlutterEngine
|
||||
@ -25,6 +26,7 @@ class MainActivity : FlutterActivity() {
|
||||
.plugins
|
||||
.apply {
|
||||
add(SmileyFaceTexturePlugin())
|
||||
add(OtherFaceTexturePlugin())
|
||||
add(NativeDriverSupportPlugin())
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,91 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
@file:Suppress("PackageName")
|
||||
|
||||
package com.example.android_engine_test.fixtures
|
||||
|
||||
import android.graphics.Color
|
||||
import android.graphics.Paint
|
||||
import android.os.Build
|
||||
import android.view.Surface
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin
|
||||
import io.flutter.embedding.engine.plugins.FlutterPlugin.FlutterPluginBinding
|
||||
import io.flutter.plugin.common.MethodCall
|
||||
import io.flutter.plugin.common.MethodChannel
|
||||
import io.flutter.plugin.common.MethodChannel.MethodCallHandler
|
||||
import io.flutter.view.TextureRegistry.SurfaceTextureEntry
|
||||
|
||||
class OtherFaceTexturePlugin :
|
||||
FlutterPlugin,
|
||||
MethodCallHandler {
|
||||
private val tag = "OtherFaceTexturePlugin"
|
||||
private lateinit var channel: MethodChannel
|
||||
private lateinit var binding: FlutterPluginBinding
|
||||
private lateinit var surfaceTextureEntry: SurfaceTextureEntry
|
||||
|
||||
private var surface: Surface? = null
|
||||
|
||||
override fun onAttachedToEngine(binding: FlutterPluginBinding) {
|
||||
this.binding = binding
|
||||
channel = MethodChannel(binding.binaryMessenger, "other_face_texture")
|
||||
channel.setMethodCallHandler(this)
|
||||
surfaceTextureEntry = binding.textureRegistry.createSurfaceTexture()
|
||||
}
|
||||
|
||||
override fun onDetachedFromEngine(binding: FlutterPluginBinding) {
|
||||
channel.setMethodCallHandler(null)
|
||||
surfaceTextureEntry.release()
|
||||
}
|
||||
|
||||
override fun onMethodCall(
|
||||
call: MethodCall,
|
||||
result: MethodChannel.Result
|
||||
) {
|
||||
if (call.method == "initTexture") {
|
||||
val height = call.argument<Int>("height") ?: 1
|
||||
val width = call.argument<Int>("width") ?: 1
|
||||
surfaceTextureEntry.surfaceTexture().setDefaultBufferSize(width, height)
|
||||
result.success(updateTexture())
|
||||
} else {
|
||||
result.notImplemented()
|
||||
}
|
||||
}
|
||||
|
||||
private fun updateTexture(): Long {
|
||||
var surface = this.surface
|
||||
if (surface == null) {
|
||||
surface = Surface(surfaceTextureEntry.surfaceTexture())
|
||||
this.surface = surface
|
||||
}
|
||||
drawOnSurface(surface!!)
|
||||
return surfaceTextureEntry.id()
|
||||
}
|
||||
|
||||
private fun drawOnSurface(surface: Surface) {
|
||||
val canvas =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
surface.lockHardwareCanvas()
|
||||
} else {
|
||||
surface.lockCanvas(null)
|
||||
}
|
||||
|
||||
// Yellow background
|
||||
canvas.drawRGB(255, 230, 15)
|
||||
|
||||
val paint = Paint()
|
||||
paint.style = Paint.Style.FILL
|
||||
|
||||
// Black eyes
|
||||
paint.color = Color.BLACK
|
||||
canvas.drawCircle(225f, 225f, 25f, paint) // Left eye
|
||||
canvas.drawCircle(425f, 225f, 25f, paint) // Right eye
|
||||
|
||||
// Black mouth
|
||||
paint.color = Color.BLACK
|
||||
canvas.drawCircle(300f, 300f, 50f, paint) // Simple mouth
|
||||
|
||||
surface.unlockCanvasAndPost(canvas)
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:android_driver_extensions/extension.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_driver/driver_extension.dart';
|
||||
|
||||
import 'src/allow_list_devices.dart';
|
||||
|
||||
const MethodChannel _channel = MethodChannel('other_face_texture');
|
||||
Future<int> _fetchTexture(int width, int height) async {
|
||||
final int? result = await _channel.invokeMethod<int>('initTexture', <String, int>{
|
||||
'width': width,
|
||||
'height': height,
|
||||
});
|
||||
return result!;
|
||||
}
|
||||
|
||||
void main() async {
|
||||
ensureAndroidOrIosDevice();
|
||||
enableFlutterDriverExtension(commands: <CommandExtension>[nativeDriverCommands]);
|
||||
|
||||
// Run on full screen.
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersive);
|
||||
|
||||
// Fetch the texture ID.
|
||||
final Future<int> textureId = _fetchTexture(512, 512);
|
||||
runApp(MainApp(textureId));
|
||||
}
|
||||
|
||||
final class MainApp extends StatelessWidget {
|
||||
const MainApp(this.textureId, {super.key});
|
||||
final Future<int> textureId;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
debugShowCheckedModeBanner: false,
|
||||
home: FutureBuilder<int>(
|
||||
future: textureId,
|
||||
builder: (BuildContext context, AsyncSnapshot<int> snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return Texture(textureId: snapshot.data!);
|
||||
}
|
||||
return const CircularProgressIndicator();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
// Copyright 2014 The Flutter Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
import 'package:android_driver_extensions/native_driver.dart';
|
||||
import 'package:android_driver_extensions/skia_gold.dart';
|
||||
import 'package:flutter_driver/flutter_driver.dart';
|
||||
import 'package:test/test.dart';
|
||||
|
||||
import '_luci_skia_gold_prelude.dart';
|
||||
|
||||
void main() async {
|
||||
// To test the golden file generation locally, comment out the following line.
|
||||
// autoUpdateGoldenFiles = true;
|
||||
|
||||
const String appName = 'com.example.android_engine_test';
|
||||
late final FlutterDriver flutterDriver;
|
||||
late final NativeDriver nativeDriver;
|
||||
|
||||
setUpAll(() async {
|
||||
if (isLuci) {
|
||||
await enableSkiaGoldComparator();
|
||||
}
|
||||
flutterDriver = await FlutterDriver.connect();
|
||||
nativeDriver = await AndroidNativeDriver.connect(flutterDriver);
|
||||
await nativeDriver.configureForScreenshotTesting();
|
||||
});
|
||||
|
||||
tearDownAll(() async {
|
||||
await nativeDriver.close();
|
||||
await flutterDriver.close();
|
||||
});
|
||||
|
||||
test('should screenshot and match an external smiley face texture', () async {
|
||||
await flutterDriver.waitFor(find.byType('Texture'));
|
||||
|
||||
// On Android: Background the app, trim memory, and restore the app.
|
||||
if (nativeDriver case final AndroidNativeDriver nativeDriver) {
|
||||
print('Backgrounding the app, trimming memory, and resuming the app.');
|
||||
await nativeDriver.backgroundApp();
|
||||
|
||||
print('Trimming memory.');
|
||||
await nativeDriver.simulateLowMemory(appName: appName);
|
||||
|
||||
print('Resuming the app.');
|
||||
await nativeDriver.resumeApp(appName: appName);
|
||||
}
|
||||
|
||||
await expectLater(
|
||||
nativeDriver.screenshot(),
|
||||
matchesGoldenFile('external_texture_other_face.android.png'),
|
||||
);
|
||||
}, timeout: Timeout.none);
|
||||
}
|
@ -122,15 +122,17 @@ void SurfaceTextureExternalTextureVKImpeller::ProcessFrame(
|
||||
VALIDATION_LOG << "Invalid external texture.";
|
||||
return;
|
||||
}
|
||||
SkMatrix matrix = context.canvas->GetTransform();
|
||||
SkRect mapped_bounds = matrix.mapRect(bounds);
|
||||
|
||||
const auto& surface_context =
|
||||
SurfaceContextVK::Cast(*context.aiks_context->GetContext());
|
||||
const auto& context_vk = ContextVK::Cast(*surface_context.GetParent());
|
||||
|
||||
auto dst_texture =
|
||||
GetCachedTextureSource(surface_context.GetParent(), //
|
||||
ISize::MakeWH(bounds.width(), bounds.height()) //
|
||||
);
|
||||
auto dst_texture = GetCachedTextureSource(
|
||||
surface_context.GetParent(), //
|
||||
ISize::MakeWH(mapped_bounds.width(), mapped_bounds.height()) //
|
||||
);
|
||||
if (!dst_texture || !dst_texture->IsValid()) {
|
||||
VALIDATION_LOG << "Could not fetch trampoline texture target.";
|
||||
return;
|
||||
@ -224,7 +226,10 @@ void SurfaceTextureExternalTextureVKImpeller::DrawFrame(
|
||||
PaintContext& context,
|
||||
const SkRect& bounds,
|
||||
const DlImageSampling sampling) const {
|
||||
context.canvas->DrawImage(dl_image_, SkPoint{0, 0}, sampling, context.paint);
|
||||
context.canvas->DrawImageRect(
|
||||
dl_image_,
|
||||
SkRect::MakeSize(SkSize::Make(dl_image_->width(), dl_image_->height())),
|
||||
bounds, sampling, context.paint);
|
||||
}
|
||||
|
||||
} // namespace flutter
|
||||
|
Loading…
Reference in New Issue
Block a user