blob: 66e3a83da6fb8b83f34a5f8d0a560b4cbad849d6 [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 <future>
#include "flutter/fml/make_copyable.h"
#include "flutter/impeller/fixtures/simple.vert.h"
#include "flutter/testing/testing.h"
#include "impeller/base/allocation.h"
#include "impeller/base/validation.h"
#include "impeller/playground/playground.h"
#include "impeller/renderer/pipeline_descriptor.h"
#include "impeller/renderer/pipeline_library.h"
#include "impeller/renderer/shader_library.h"
#include "impeller/runtime_stage/runtime_stage.h"
#include "impeller/runtime_stage/runtime_stage_playground.h"
namespace impeller {
namespace testing {
using RuntimeStageTest = RuntimeStagePlayground;
INSTANTIATE_PLAYGROUND_SUITE(RuntimeStageTest);
TEST(RuntimeStageTest, CanReadValidBlob) {
auto fixture =
flutter::testing::OpenFixtureAsMapping("ink_sparkle.frag.iplr");
ASSERT_TRUE(fixture);
ASSERT_GT(fixture->GetSize(), 0u);
RuntimeStage stage(std::move(fixture));
ASSERT_TRUE(stage.IsValid());
ASSERT_EQ(stage.GetShaderStage(), ShaderStage::kFragment);
}
TEST(RuntimeStageTest, CanRejectInvalidBlob) {
ScopedValidationDisable disable_validation;
auto fixture =
flutter::testing::OpenFixtureAsMapping("ink_sparkle.frag.iplr");
ASSERT_TRUE(fixture);
auto junk_allocation = std::make_shared<Allocation>();
ASSERT_TRUE(junk_allocation->Truncate(fixture->GetSize(), false));
// Not meant to be secure. Just reject obviously bad blobs using magic
// numbers.
::memset(junk_allocation->GetBuffer(), 127, junk_allocation->GetLength());
RuntimeStage stage(CreateMappingFromAllocation(std::move(junk_allocation)));
ASSERT_FALSE(stage.IsValid());
}
TEST(RuntimeStageTest, CanReadUniforms) {
auto fixture =
flutter::testing::OpenFixtureAsMapping("ink_sparkle.frag.iplr");
ASSERT_TRUE(fixture);
ASSERT_GT(fixture->GetSize(), 0u);
RuntimeStage stage(std::move(fixture));
ASSERT_TRUE(stage.IsValid());
ASSERT_EQ(stage.GetUniforms().size(), 17u);
{
auto uni = stage.GetUniform("u_color");
ASSERT_NE(uni, nullptr);
ASSERT_EQ(uni->dimensions.rows, 4u);
ASSERT_EQ(uni->dimensions.cols, 1u);
ASSERT_EQ(uni->location, 0u);
ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
}
{
auto uni = stage.GetUniform("u_alpha");
ASSERT_NE(uni, nullptr);
ASSERT_EQ(uni->dimensions.rows, 1u);
ASSERT_EQ(uni->dimensions.cols, 1u);
ASSERT_EQ(uni->location, 1u);
ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
}
{
auto uni = stage.GetUniform("u_sparkle_color");
ASSERT_NE(uni, nullptr);
ASSERT_EQ(uni->dimensions.rows, 4u);
ASSERT_EQ(uni->dimensions.cols, 1u);
ASSERT_EQ(uni->location, 2u);
ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
}
{
auto uni = stage.GetUniform("u_sparkle_alpha");
ASSERT_NE(uni, nullptr);
ASSERT_EQ(uni->dimensions.rows, 1u);
ASSERT_EQ(uni->dimensions.cols, 1u);
ASSERT_EQ(uni->location, 3u);
ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
}
{
auto uni = stage.GetUniform("u_blur");
ASSERT_NE(uni, nullptr);
ASSERT_EQ(uni->dimensions.rows, 1u);
ASSERT_EQ(uni->dimensions.cols, 1u);
ASSERT_EQ(uni->location, 4u);
ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
}
{
auto uni = stage.GetUniform("u_radius_scale");
ASSERT_NE(uni, nullptr);
ASSERT_EQ(uni->dimensions.rows, 1u);
ASSERT_EQ(uni->dimensions.cols, 1u);
ASSERT_EQ(uni->location, 6u);
ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
}
{
auto uni = stage.GetUniform("u_max_radius");
ASSERT_NE(uni, nullptr);
ASSERT_EQ(uni->dimensions.rows, 1u);
ASSERT_EQ(uni->dimensions.cols, 1u);
ASSERT_EQ(uni->location, 7u);
ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
}
{
auto uni = stage.GetUniform("u_resolution_scale");
ASSERT_NE(uni, nullptr);
ASSERT_EQ(uni->dimensions.rows, 2u);
ASSERT_EQ(uni->dimensions.cols, 1u);
ASSERT_EQ(uni->location, 8u);
ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
}
{
auto uni = stage.GetUniform("u_noise_scale");
ASSERT_NE(uni, nullptr);
ASSERT_EQ(uni->dimensions.rows, 2u);
ASSERT_EQ(uni->dimensions.cols, 1u);
ASSERT_EQ(uni->location, 9u);
ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
}
{
auto uni = stage.GetUniform("u_noise_phase");
ASSERT_NE(uni, nullptr);
ASSERT_EQ(uni->dimensions.rows, 1u);
ASSERT_EQ(uni->dimensions.cols, 1u);
ASSERT_EQ(uni->location, 10u);
ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
}
{
auto uni = stage.GetUniform("u_circle1");
ASSERT_NE(uni, nullptr);
ASSERT_EQ(uni->dimensions.rows, 2u);
ASSERT_EQ(uni->dimensions.cols, 1u);
ASSERT_EQ(uni->location, 11u);
ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
}
{
auto uni = stage.GetUniform("u_circle2");
ASSERT_NE(uni, nullptr);
ASSERT_EQ(uni->dimensions.rows, 2u);
ASSERT_EQ(uni->dimensions.cols, 1u);
ASSERT_EQ(uni->location, 12u);
ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
}
{
auto uni = stage.GetUniform("u_circle3");
ASSERT_NE(uni, nullptr);
ASSERT_EQ(uni->dimensions.rows, 2u);
ASSERT_EQ(uni->dimensions.cols, 1u);
ASSERT_EQ(uni->location, 13u);
ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
}
{
auto uni = stage.GetUniform("u_rotation1");
ASSERT_NE(uni, nullptr);
ASSERT_EQ(uni->dimensions.rows, 2u);
ASSERT_EQ(uni->dimensions.cols, 1u);
ASSERT_EQ(uni->location, 14u);
ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
}
{
auto uni = stage.GetUniform("u_rotation2");
ASSERT_NE(uni, nullptr);
ASSERT_EQ(uni->dimensions.rows, 2u);
ASSERT_EQ(uni->dimensions.cols, 1u);
ASSERT_EQ(uni->location, 15u);
ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
}
{
auto uni = stage.GetUniform("u_rotation3");
ASSERT_NE(uni, nullptr);
ASSERT_EQ(uni->dimensions.rows, 2u);
ASSERT_EQ(uni->dimensions.cols, 1u);
ASSERT_EQ(uni->location, 16u);
ASSERT_EQ(uni->type, RuntimeUniformType::kFloat);
}
}
TEST_P(RuntimeStageTest, CanRegisterStage) {
if (GetParam() != PlaygroundBackend::kMetal) {
GTEST_SKIP_("Skipped: https://github.com/flutter/flutter/issues/105538");
}
auto fixture =
flutter::testing::OpenFixtureAsMapping("ink_sparkle.frag.iplr");
ASSERT_TRUE(fixture);
ASSERT_GT(fixture->GetSize(), 0u);
RuntimeStage stage(std::move(fixture));
ASSERT_TRUE(stage.IsValid());
std::promise<bool> registration;
auto future = registration.get_future();
auto library = GetContext()->GetShaderLibrary();
library->RegisterFunction(
stage.GetEntrypoint(), //
stage.GetShaderStage(), //
stage.GetCodeMapping(), //
fml::MakeCopyable([reg = std::move(registration)](bool result) mutable {
reg.set_value(result);
}));
ASSERT_TRUE(future.get());
auto function =
library->GetFunction(stage.GetEntrypoint(), ShaderStage::kFragment);
ASSERT_NE(function, nullptr);
}
TEST_P(RuntimeStageTest, CanCreatePipelineFromRuntimeStage) {
if (GetParam() != PlaygroundBackend::kMetal) {
GTEST_SKIP_("Skipped: https://github.com/flutter/flutter/issues/105538");
}
auto stage = CreateStageFromFixture("ink_sparkle.frag.iplr");
ASSERT_NE(stage, nullptr);
ASSERT_TRUE(RegisterStage(*stage));
auto library = GetContext()->GetShaderLibrary();
using VS = SimpleVertexShader;
PipelineDescriptor desc;
desc.SetLabel("Runtime Stage InkSparkle");
desc.AddStageEntrypoint(
library->GetFunction(VS::kEntrypointName, ShaderStage::kVertex));
desc.AddStageEntrypoint(
library->GetFunction(stage->GetEntrypoint(), ShaderStage::kFragment));
auto vertex_descriptor = std::make_shared<VertexDescriptor>();
ASSERT_TRUE(vertex_descriptor->SetStageInputs(VS::kAllShaderStageInputs));
desc.SetVertexDescriptor(std::move(vertex_descriptor));
ColorAttachmentDescriptor color0;
color0.format = PixelFormat::kDefaultColor;
StencilAttachmentDescriptor stencil0;
stencil0.stencil_compare = CompareFunction::kEqual;
desc.SetColorAttachmentDescriptor(0u, color0);
desc.SetStencilAttachmentDescriptors(stencil0);
desc.SetStencilPixelFormat(PixelFormat::kDefaultStencil);
auto pipeline = GetContext()
->GetPipelineLibrary()
->GetRenderPipeline(std::move(desc))
.get();
ASSERT_NE(pipeline, nullptr);
}
} // namespace testing
} // namespace impeller