blob: feda58f36634c8326598c63871cd26ad7ffddc52 [file] [log] [blame]
// Copyright 2013 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.
#include "impeller/toolkit/interop/playground_test.h"
#include "impeller/toolkit/interop/impeller.hpp"
#if IMPELLER_ENABLE_METAL
#include "impeller/toolkit/interop/backend/metal/context_mtl.h"
#include "impeller/toolkit/interop/backend/metal/surface_mtl.h"
#endif // IMPELLER_ENABLE_METAL
#if IMPELLER_ENABLE_OPENGLES
#include "impeller/toolkit/interop/backend/gles/context_gles.h"
#include "impeller/toolkit/interop/backend/gles/surface_gles.h"
#endif // IMPELLER_ENABLE_METAL
#if IMPELLER_ENABLE_VULKAN
#include "impeller/toolkit/interop/backend/vulkan/context_vk.h"
#include "impeller/toolkit/interop/backend/vulkan/surface_vk.h"
#endif // IMPELLER_ENABLE_VULKAN
namespace IMPELLER_HPP_NAMESPACE {
ProcTable gGlobalProcTable;
} // namespace IMPELLER_HPP_NAMESPACE
namespace impeller::interop::testing {
static void SetupImpellerHPPProcTableOnce() {
static std::once_flag sOnceFlag;
std::call_once(sOnceFlag, []() {
std::map<std::string, void*> proc_map;
#define IMPELLER_HPP_PROC(name) \
proc_map[#name] = reinterpret_cast<void*>(&name);
IMPELLER_HPP_EACH_PROC(IMPELLER_HPP_PROC)
#undef IMPELLER_HPP_PROC
hpp::gGlobalProcTable.Initialize(
[&](auto name) { return proc_map.at(name); });
});
}
PlaygroundTest::PlaygroundTest() {
SetupImpellerHPPProcTableOnce();
}
PlaygroundTest::~PlaygroundTest() = default;
// |PlaygroundTest|
void PlaygroundTest::SetUp() {
::impeller::PlaygroundTest::SetUp();
}
// |PlaygroundTest|
void PlaygroundTest::TearDown() {
::impeller::PlaygroundTest::TearDown();
}
ScopedObject<Context> PlaygroundTest::CreateContext() const {
switch (GetBackend()) {
case PlaygroundBackend::kMetal:
return Adopt<Context>(
ImpellerContextCreateMetalNew(ImpellerGetVersion()));
case PlaygroundBackend::kOpenGLES: {
Playground::GLProcAddressResolver playground_gl_proc_address_callback =
CreateGLProcAddressResolver();
ImpellerProcAddressCallback gl_proc_address_callback =
[](const char* proc_name, void* user_data) -> void* {
return (*reinterpret_cast<Playground::GLProcAddressResolver*>(
user_data))(proc_name);
};
return Adopt<Context>(ImpellerContextCreateOpenGLESNew(
ImpellerGetVersion(), gl_proc_address_callback,
&playground_gl_proc_address_callback));
}
case PlaygroundBackend::kVulkan:
ImpellerContextVulkanSettings settings = {};
struct UserData {
Playground::VKProcAddressResolver resolver;
} user_data;
user_data.resolver = CreateVKProcAddressResolver();
settings.user_data = &user_data;
settings.enable_vulkan_validation = switches_.enable_vulkan_validation;
settings.proc_address_callback = [](void* instance, //
const char* proc_name, //
void* user_data //
) -> void* {
auto resolver = reinterpret_cast<UserData*>(user_data)->resolver;
if (resolver) {
return resolver(instance, proc_name);
} else {
return nullptr;
}
};
return Adopt<Context>(
ImpellerContextCreateVulkanNew(ImpellerGetVersion(), &settings));
}
FML_UNREACHABLE();
}
static ScopedObject<Surface> CreateSharedSurface(
PlaygroundBackend backend,
Context& context,
std::shared_ptr<impeller::Surface> shared_surface) {
switch (backend) {
#if IMPELLER_ENABLE_METAL
case PlaygroundBackend::kMetal:
return Adopt<Surface>(new SurfaceMTL(context, std::move(shared_surface)));
#endif
#if IMPELLER_ENABLE_OPENGLES
case PlaygroundBackend::kOpenGLES:
return Adopt<Surface>(
new SurfaceGLES(context, std::move(shared_surface)));
#endif
#if IMPELLER_ENABLE_VULKAN
case PlaygroundBackend::kVulkan:
return Adopt<Surface>(new SurfaceVK(context, std::move(shared_surface)));
#endif
default:
return nullptr;
}
FML_UNREACHABLE();
}
bool PlaygroundTest::OpenPlaygroundHere(InteropPlaygroundCallback callback) {
auto interop_context = GetInteropContext();
if (!interop_context) {
return false;
}
return Playground::OpenPlaygroundHere([&](RenderTarget& target) -> bool {
auto impeller_surface = std::make_shared<impeller::Surface>(target);
auto surface = CreateSharedSurface(GetBackend(), //
*interop_context.Get(), //
std::move(impeller_surface) //
);
if (!surface) {
VALIDATION_LOG << "Could not wrap test surface as an interop surface.";
return false;
}
return callback(interop_context, surface);
});
}
static ScopedObject<Context> CreateSharedContext(
PlaygroundBackend backend,
std::shared_ptr<impeller::Context> shared_context) {
switch (backend) {
#if IMPELLER_ENABLE_METAL
case PlaygroundBackend::kMetal:
return ContextMTL::Create(shared_context);
#endif
#if IMPELLER_ENABLE_OPENGLES
case PlaygroundBackend::kOpenGLES:
return ContextGLES::Create(std::move(shared_context));
#endif
#if IMPELLER_ENABLE_VULKAN
case PlaygroundBackend::kVulkan:
return ContextVK::Create(std::move(shared_context));
#endif
default:
return nullptr;
}
FML_UNREACHABLE();
}
ScopedObject<Context> PlaygroundTest::GetInteropContext() {
if (interop_context_) {
return interop_context_;
}
auto context = CreateSharedContext(GetBackend(), GetContext());
if (!context) {
return nullptr;
}
interop_context_ = std::move(context);
return interop_context_;
}
hpp::Context PlaygroundTest::GetHPPContext() {
auto c_context = GetInteropContext().GetC();
ImpellerContextRetain(c_context);
return hpp::Context{c_context, hpp::AdoptTag::kAdopt};
}
std::unique_ptr<hpp::Mapping> PlaygroundTest::OpenAssetAsHPPMapping(
std::string asset_name) const {
std::shared_ptr<fml::Mapping> data =
OpenAssetAsMapping(std::move(asset_name));
if (!data) {
return nullptr;
}
return std::make_unique<hpp::Mapping>(data->GetMapping(), //
data->GetSize(), //
[data]() {} //
);
}
hpp::Texture PlaygroundTest::OpenAssetAsHPPTexture(std::string asset_name) {
auto compressed_data = OpenAssetAsMapping(std::move(asset_name));
if (!compressed_data) {
return {nullptr, hpp::AdoptTag::kAdopt};
}
auto compressed_image =
LoadFixtureImageCompressed(std::move(compressed_data));
if (!compressed_image) {
return {nullptr, hpp::AdoptTag::kAdopt};
}
auto decompressed_image = DecodeImageRGBA(compressed_image);
if (!decompressed_image.has_value()) {
return {nullptr, hpp::AdoptTag::kAdopt};
}
auto rgba_decompressed_image =
std::make_shared<DecompressedImage>(decompressed_image->ConvertToRGBA());
if (!rgba_decompressed_image || !rgba_decompressed_image->IsValid()) {
return {nullptr, hpp::AdoptTag::kAdopt};
}
auto context = GetHPPContext();
if (!context) {
return {nullptr, hpp::AdoptTag::kAdopt};
}
auto rgba_mapping = std::make_unique<hpp::Mapping>(
rgba_decompressed_image->GetAllocation()->GetMapping(),
rgba_decompressed_image->GetAllocation()->GetSize(),
[rgba_decompressed_image]() {});
return hpp::Texture::WithContents(
context,
ImpellerTextureDescriptor{
.pixel_format = kImpellerPixelFormatRGBA8888,
.size = {rgba_decompressed_image->GetSize().width,
rgba_decompressed_image->GetSize().height},
.mip_count = 1u,
},
std::move(rgba_mapping));
}
} // namespace impeller::interop::testing