Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions impeller/aiks/canvas.cc
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <utility>

#include "flutter/fml/logging.h"
#include "flutter/fml/trace_event.h"
#include "impeller/aiks/image_filter.h"
#include "impeller/aiks/paint_pass_delegate.h"
#include "impeller/entity/contents/atlas_contents.h"
Expand Down Expand Up @@ -532,6 +533,7 @@ size_t Canvas::GetStencilDepth() const {
void Canvas::SaveLayer(const Paint& paint,
std::optional<Rect> bounds,
const std::shared_ptr<ImageFilter>& backdrop_filter) {
TRACE_EVENT0("flutter", "Canvas::saveLayer");
Save(true, paint.blend_mode, backdrop_filter);

auto& new_layer_pass = GetCurrentPass();
Expand Down
2 changes: 1 addition & 1 deletion impeller/base/validation.cc
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ void ImpellerValidationBreak(const char* message) {
} else {
FML_LOG(ERROR) << stream.str();
}
#endif // IMPELLER_DEBUG
#endif // IMPELLER_ENABLE_VALIDATION
}

} // namespace impeller
1 change: 1 addition & 0 deletions impeller/renderer/backend/vulkan/allocator_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,7 @@ class AllocatedTextureSourceVK final : public TextureSourceVK {
vk::Device device,
bool supports_memoryless_textures)
: TextureSourceVK(desc), resource_(std::move(resource_manager)) {
FML_DCHECK(desc.format != PixelFormat::kUnknown);
TRACE_EVENT0("impeller", "CreateDeviceTexture");
vk::ImageCreateInfo image_info;
image_info.flags = ToVKImageCreateFlags(desc.type);
Expand Down
4 changes: 4 additions & 0 deletions impeller/renderer/backend/vulkan/surface_context_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ bool SurfaceContextVK::SetWindowSurface(vk::UniqueSurfaceKHR surface) {
VALIDATION_LOG << "Could not create swapchain.";
return false;
}
if (!swapchain->IsValid()) {
VALIDATION_LOG << "Could not create valid swapchain.";
return false;
}
swapchain_ = std::move(swapchain);
return true;
}
Expand Down
1 change: 1 addition & 0 deletions impeller/renderer/backend/vulkan/swapchain_impl_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ SwapchainImplVK::SwapchainImplVK(
vk::SwapchainKHR old_swapchain,
vk::SurfaceTransformFlagBitsKHR last_transform) {
if (!context) {
VALIDATION_LOG << "Cannot create a swapchain without a context.";
return;
}

Expand Down
2 changes: 2 additions & 0 deletions impeller/renderer/backend/vulkan/swapchain_vk.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "impeller/renderer/backend/vulkan/swapchain_vk.h"

#include "flutter/fml/trace_event.h"
#include "impeller/base/validation.h"
#include "impeller/renderer/backend/vulkan/swapchain_impl_vk.h"

namespace impeller {
Expand All @@ -14,6 +15,7 @@ std::shared_ptr<SwapchainVK> SwapchainVK::Create(
vk::UniqueSurfaceKHR surface) {
auto impl = SwapchainImplVK::Create(context, std::move(surface));
if (!impl || !impl->IsValid()) {
VALIDATION_LOG << "Failed to create SwapchainVK implementation.";
return nullptr;
}
return std::shared_ptr<SwapchainVK>(new SwapchainVK(std::move(impl)));
Expand Down
4 changes: 2 additions & 2 deletions impeller/tools/impeller.gni
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ declare_args() {
(is_linux || is_win || is_android) && target_os != "fuchsia"

# Whether the Vulkan backend is enabled.
impeller_enable_vulkan =
(is_linux || is_win || is_android) && target_os != "fuchsia"
impeller_enable_vulkan = (is_linux || is_win || is_android ||
enable_unittests) && target_os != "fuchsia"

# Whether to use a prebuilt impellerc.
# If this is the empty string, impellerc will be built.
Expand Down
3 changes: 2 additions & 1 deletion lib/gpu/context.cc
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,8 @@ Dart_Handle InternalFlutterGpu_Context_InitializeDefault(Dart_Handle wrapper) {
// Grab the Impeller context from the IO manager.
std::promise<std::shared_ptr<impeller::Context>> context_promise;
auto impeller_context_future = context_promise.get_future();
dart_state->GetTaskRunners().GetIOTaskRunner()->PostTask(
fml::TaskRunner::RunNowOrPostTask(
dart_state->GetTaskRunners().GetIOTaskRunner(),
fml::MakeCopyable([promise = std::move(context_promise),
io_manager = dart_state->GetIOManager()]() mutable {
promise.set_value(io_manager ? io_manager->GetImpellerContext()
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added lib/ui/fixtures/impeller_heart_end.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions shell/common/shell.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1695,6 +1695,11 @@ bool Shell::OnServiceProtocolScreenshotSKP(
const ServiceProtocol::Handler::ServiceProtocolMap& params,
rapidjson::Document* response) {
FML_DCHECK(task_runners_.GetRasterTaskRunner()->RunsTasksOnCurrentThread());
if (settings_.enable_impeller) {
ServiceProtocolFailureError(
response, "Cannot capture SKP screenshot with Impeller enabled.");
return false;
}
auto screenshot = rasterizer_->ScreenshotLastLayerTree(
Rasterizer::ScreenshotType::SkiaPicture, true);
if (screenshot.data) {
Expand Down
4 changes: 4 additions & 0 deletions shell/gpu/gpu_surface_vulkan.cc
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ sk_sp<SkSurface> GPUSurfaceVulkan::CreateSurfaceFromVulkanImage(
const VkImage image,
const VkFormat format,
const SkISize& size) {
#ifdef SK_VULKAN
GrVkImageInfo image_info = {
.fImage = image,
.fImageTiling = VK_IMAGE_TILING_OPTIMAL,
Expand All @@ -130,6 +131,9 @@ sk_sp<SkSurface> GPUSurfaceVulkan::CreateSurfaceFromVulkanImage(
SkColorSpace::MakeSRGB(), // color space
&surface_properties // surface properties
);
#else
return nullptr;
#endif // SK_VULKAN
}

SkColorType GPUSurfaceVulkan::ColorTypeFromFormat(const VkFormat format) {
Expand Down
5 changes: 5 additions & 0 deletions shell/gpu/gpu_surface_vulkan_impeller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,11 @@ std::unique_ptr<SurfaceFrame> GPUSurfaceVulkanImpeller::AcquireFrame(
auto& context_vk = impeller::SurfaceContextVK::Cast(*impeller_context_);
std::unique_ptr<impeller::Surface> surface = context_vk.AcquireNextSurface();

if (!surface) {
FML_LOG(ERROR) << "No surface available.";
return nullptr;
}

SurfaceFrame::SubmitCallback submit_callback =
fml::MakeCopyable([renderer = impeller_renderer_, //
aiks_context = aiks_context_, //
Expand Down
32 changes: 31 additions & 1 deletion shell/testing/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,15 @@
# found in the LICENSE file.

import("//build/fuchsia/sdk.gni")
import("//flutter/impeller/tools/impeller.gni")
import("//flutter/shell/gpu/gpu.gni")

shell_gpu_configuration("tester_gpu_configuration") {
enable_software = true
enable_gl = true
enable_vulkan = true
enable_metal = false
}

executable("testing") {
output_name = "flutter_tester"
Expand All @@ -13,8 +22,9 @@ executable("testing") {
]

sources = [ "tester_main.cc" ]
libs = []
if (is_win) {
libs = [
libs += [
"psapi.lib",
"user32.lib",
"FontSub.lib",
Expand All @@ -36,6 +46,26 @@ executable("testing") {
"//third_party/skia",
]

if (impeller_supports_rendering) {
deps += [
":tester_gpu_configuration",
"//flutter/impeller",
"//third_party/swiftshader",
]

if (is_win) {
libs += [ "$root_out_dir/vk_swiftshader.dll" ]
} else if (is_mac) {
libs += [ "$root_out_dir/libvk_swiftshader.dylib" ]
} else if (is_linux) {
libs += [ "$root_out_dir/libvk_swiftshader.so" ]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: I think we have these swiftshader lib names copied around in 3 or 4 places at this point (including in some source files). Not sure if there's one good place we could consolidate them.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ended up moving this to //flutter/vulkan/swiftshader_path.h

} else {
assert(
false,
"Only Windows, Mac, and Linux are supported for this target with Impeller.")
}
}

metadata = {
entitlement_file_path = [ "flutter_tester" ]
}
Expand Down
114 changes: 109 additions & 5 deletions shell/testing/tester_main.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,45 @@
#include "third_party/dart/runtime/include/dart_api.h"
#include "third_party/skia/include/core/SkSurface.h"

#if IMPELLER_SUPPORTS_RENDERING
#include <vulkan/vulkan.h> // nogncheck
#include "impeller/core/formats.h" // nogncheck
#include "impeller/entity/vk/entity_shaders_vk.h" // nogncheck
#include "impeller/entity/vk/modern_shaders_vk.h" // nogncheck
#include "impeller/renderer/backend/vulkan/context_vk.h" // nogncheck
#include "impeller/renderer/backend/vulkan/surface_context_vk.h" // nogncheck
#include "impeller/renderer/context.h" // nogncheck
#include "impeller/renderer/surface.h" // nogncheck
#include "impeller/renderer/vk/compute_shaders_vk.h" // nogncheck
#include "shell/gpu/gpu_surface_vulkan_impeller.h" // nogncheck
#if IMPELLER_ENABLE_3D
#include "impeller/scene/shaders/vk/scene_shaders_vk.h" // nogncheck
#endif // IMPELLER_ENABLE_3D

static std::vector<std::shared_ptr<fml::Mapping>> ShaderLibraryMappings() {
return {
std::make_shared<fml::NonOwnedMapping>(impeller_entity_shaders_vk_data,
impeller_entity_shaders_vk_length),
std::make_shared<fml::NonOwnedMapping>(
impeller_modern_shaders_vk_data, impeller_modern_shaders_vk_length),
#if IMPELLER_ENABLE_3D
std::make_shared<fml::NonOwnedMapping>(
impeller_scene_shaders_vk_data, impeller_scene_shaders_vk_length),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for taking care of Scene. 🙏

#endif // IMPELLER_ENABLE_3D
std::make_shared<fml::NonOwnedMapping>(
impeller_compute_shaders_vk_data,
impeller_compute_shaders_vk_length),
};
}

#else
namespace impeller {
class Context;
class ContextVK;
class SurfaceContextVK;
} // namespace impeller
#endif // IMPELLER_SUPPORTS_RENDERING

#if defined(FML_OS_WIN)
#include <combaseapi.h>
#endif // defined(FML_OS_WIN)
Expand Down Expand Up @@ -81,11 +120,32 @@ class TesterGPUSurfaceSoftware : public GPUSurfaceSoftware {
class TesterPlatformView : public PlatformView,
public GPUSurfaceSoftwareDelegate {
public:
TesterPlatformView(Delegate& delegate, const TaskRunners& task_runners)
: PlatformView(delegate, task_runners) {}
TesterPlatformView(Delegate& delegate,
const TaskRunners& task_runners,
const std::shared_ptr<impeller::Context>& impeller_context,
const std::shared_ptr<impeller::SurfaceContextVK>&
impeller_surface_context)
: PlatformView(delegate, task_runners),
impeller_context_(impeller_context),
impeller_surface_context_(impeller_surface_context) {}

// |PlatformView|
std::shared_ptr<impeller::Context> GetImpellerContext() const override {
return impeller_context_;
}

// |PlatformView|
std::unique_ptr<Surface> CreateRenderingSurface() override {
#if IMPELLER_SUPPORTS_RENDERING
if (delegate_.OnPlatformViewGetSettings().enable_impeller) {
FML_DCHECK(impeller_context_);
auto surface =
std::make_unique<GPUSurfaceVulkanImpeller>(impeller_surface_context_);
FML_DCHECK(surface->IsValid());
return surface;
}
#endif // IMPELLER_SUPPORTS_RENDERING
FML_DCHECK(!impeller_context_);
auto surface = std::make_unique<TesterGPUSurfaceSoftware>(
this, true /* render to surface */);
FML_DCHECK(surface->IsValid());
Expand Down Expand Up @@ -126,6 +186,8 @@ class TesterPlatformView : public PlatformView,

private:
sk_sp<SkSurface> sk_surface_ = nullptr;
std::shared_ptr<impeller::Context> impeller_context_;
std::shared_ptr<impeller::SurfaceContextVK> impeller_surface_context_;
std::shared_ptr<TesterExternalViewEmbedder> external_view_embedder_ =
std::make_shared<TesterExternalViewEmbedder>();
};
Expand Down Expand Up @@ -235,10 +297,52 @@ int RunTester(const flutter::Settings& settings,
io_task_runner // io
);

std::shared_ptr<impeller::ContextVK> impeller_context;
std::shared_ptr<impeller::SurfaceContextVK> impeller_surface_context;

#if IMPELLER_SUPPORTS_RENDERING
if (settings.enable_impeller) {
impeller::ContextVK::Settings context_settings;
context_settings.proc_address_callback =
reinterpret_cast<PFN_vkGetInstanceProcAddr>(&::vkGetInstanceProcAddr);
context_settings.shader_libraries_data = ShaderLibraryMappings();
context_settings.cache_directory = fml::paths::GetCachesDirectory();
context_settings.enable_validation = settings.enable_vulkan_validation;

impeller_context = impeller::ContextVK::Create(std::move(context_settings));
if (!impeller_context || !impeller_context->IsValid()) {
VALIDATION_LOG << "Could not create Vulkan context.";
return -1;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return -1;
return EXIT_FAILURE;

}

impeller::vk::SurfaceKHR vk_surface;
impeller::vk::HeadlessSurfaceCreateInfoEXT surface_create_info;
auto res = impeller_context->GetInstance().createHeadlessSurfaceEXT(
&surface_create_info, // surface create info
nullptr, // allocator
&vk_surface // surface
);
if (res != impeller::vk::Result::eSuccess) {
VALIDATION_LOG << "Could not create surface for tester "
<< impeller::vk::to_string(res);
return -1;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return -1;
return EXIT_FAILURE;

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done here and elsewhere

}

impeller::vk::UniqueSurfaceKHR surface{vk_surface,
impeller_context->GetInstance()};
impeller_surface_context = impeller_context->CreateSurfaceContext();
if (!impeller_surface_context->SetWindowSurface(std::move(surface))) {
VALIDATION_LOG << "Could not set up surface for context.";
return -1;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
return -1;
return EXIT_FAILURE;

}
}
#endif // IMPELLER_SUPPORTS_RENDERING

Shell::CreateCallback<PlatformView> on_create_platform_view =
[](Shell& shell) {
return std::make_unique<TesterPlatformView>(shell,
shell.GetTaskRunners());
[impeller_context, impeller_surface_context](Shell& shell) {
return std::make_unique<TesterPlatformView>(
shell, shell.GetTaskRunners(), impeller_context,
impeller_surface_context);
};

Shell::CreateCallback<Rasterizer> on_create_rasterizer = [](Shell& shell) {
Expand Down
10 changes: 9 additions & 1 deletion testing/dart/canvas_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import 'package:vector_math/vector_math_64.dart';

typedef CanvasCallback = void Function(Canvas canvas);

bool get impellerEnabled => Platform.executableArguments.contains('--enable-impeller');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider factoring this definition out into a .dart file under testing/dart, and importing it where needed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done


Future<Image> createImage(int width, int height) {
final Completer<Image> completer = Completer<Image>();
decodeImageFromPixels(
Expand Down Expand Up @@ -190,7 +192,7 @@ void main() {
expect(image.height, equals(100));

final bool areEqual =
await fuzzyGoldenImageCompare(image, 'canvas_test_toImage.png');
await fuzzyGoldenImageCompare(image, '${impellerEnabled ? 'impeller_' : ''}canvas_test_toImage.png');
expect(areEqual, true);
});

Expand Down Expand Up @@ -438,6 +440,12 @@ void main() {
recorder = PictureRecorder();
canvas = Canvas(recorder);

if (impellerEnabled) {
// Impeller tries to automagically scale this. See
// https://github.com/flutter/flutter/issues/128885
canvas.drawImage(image, Offset.zero, Paint());
return;
}
// On a slower CI machine, the raster thread may get behind the UI thread
// here. However, once the image is in an error state it will immediately
// throw on subsequent attempts.
Expand Down
Loading