From a95f4fa051c2da37201a832854c690024837597a Mon Sep 17 00:00:00 2001 From: Dan Field Date: Thu, 27 Oct 2022 10:05:50 -0700 Subject: [PATCH 1/2] Reflector updates for structs --- impeller/compiler/reflector.cc | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/impeller/compiler/reflector.cc b/impeller/compiler/reflector.cc index a791d3b18dc13..181fc3ecd5b69 100644 --- a/impeller/compiler/reflector.cc +++ b/impeller/compiler/reflector.cc @@ -603,6 +603,29 @@ std::vector Reflector::ReadStructMembers( FML_CHECK(current_byte_offset == struct_member_offset); + // A user defined struct. + if (member.basetype == spirv_cross::SPIRType::BaseType::Struct) { + const size_t size = + GetReflectedStructSize(ReadStructMembers(member.self)); + uint32_t stride = GetArrayStride<0>(struct_type, member, i); + if (stride == 0) { + stride = size; + } + uint32_t element_padding = stride - size; + result.emplace_back(StructMember{ + compiler_->get_name(member.self), // type + BaseTypeToString(member.basetype), // basetype + GetMemberNameAtIndex(struct_type, i), // name + struct_member_offset, // offset + size, // size + stride * array_elements.value_or(1), // byte_length + array_elements, // array_elements + element_padding, // element_padding + }); + current_byte_offset += stride * array_elements.value_or(1); + continue; + } + // Tightly packed 4x4 Matrix is special cased as we know how to work with // those. if (member.basetype == spirv_cross::SPIRType::BaseType::Float && // From e240776ba62538608c280c469de9fbb3ee1de954 Mon Sep 17 00:00:00 2001 From: Dan Field Date: Thu, 27 Oct 2022 10:38:25 -0700 Subject: [PATCH 2/2] Support user defined structs in buffers, avoid having compute playground try to create renderer --- impeller/fixtures/sample.comp | 12 +++- impeller/playground/BUILD.gn | 2 + .../playground/compute_playground_test.cc | 70 +++++++++++++++++++ impeller/playground/compute_playground_test.h | 55 +++++++++++++++ impeller/playground/playground.cc | 17 +++-- impeller/playground/playground.h | 5 +- impeller/playground/playground_test.cc | 3 +- impeller/renderer/compute_unittests.cc | 20 +++--- 8 files changed, 162 insertions(+), 22 deletions(-) create mode 100644 impeller/playground/compute_playground_test.cc create mode 100644 impeller/playground/compute_playground_test.h diff --git a/impeller/fixtures/sample.comp b/impeller/fixtures/sample.comp index 101f3f6103fab..a0a0f1661a01e 100644 --- a/impeller/fixtures/sample.comp +++ b/impeller/fixtures/sample.comp @@ -1,6 +1,11 @@ layout(local_size_x = 128) in; layout(std430) buffer; +struct SomeStruct { + vec2 vf; + uint i; +}; + layout(binding = 0) writeonly buffer Output { vec4 elements[]; } output_data; @@ -12,6 +17,7 @@ layout(binding = 1) readonly buffer Input0 { } input_data0; layout(binding = 2) readonly buffer Input1 { + SomeStruct some_struct; uvec2 fixed_array[4]; vec4 elements[]; } input_data1; @@ -30,7 +36,7 @@ void main() } output_data.elements[ident] = input_data0.elements[ident] * input_data1.elements[ident]; - output_data.elements[ident].x += input_data0.fixed_array[1].x; - output_data.elements[ident].y += input_data1.fixed_array[0].y; - output_data.elements[ident].z += input_data0.some_int; + output_data.elements[ident].x += input_data0.fixed_array[1].x + input_data1.some_struct.i; + output_data.elements[ident].y += input_data1.fixed_array[0].y + input_data1.some_struct.vf.x; + output_data.elements[ident].z += input_data0.some_int + input_data1.some_struct.vf.y; } diff --git a/impeller/playground/BUILD.gn b/impeller/playground/BUILD.gn index 104a04253fd08..68ba55aa46045 100644 --- a/impeller/playground/BUILD.gn +++ b/impeller/playground/BUILD.gn @@ -62,6 +62,8 @@ impeller_component("playground_test") { testonly = true sources = [ + "compute_playground_test.cc", + "compute_playground_test.h", "playground_test.cc", "playground_test.h", ] diff --git a/impeller/playground/compute_playground_test.cc b/impeller/playground/compute_playground_test.cc new file mode 100644 index 0000000000000..8405bb668706f --- /dev/null +++ b/impeller/playground/compute_playground_test.cc @@ -0,0 +1,70 @@ +// 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 "flutter/fml/time/time_point.h" + +#include "impeller/playground/compute_playground_test.h" + +namespace impeller { + +ComputePlaygroundTest::ComputePlaygroundTest() = default; + +ComputePlaygroundTest::~ComputePlaygroundTest() = default; + +void ComputePlaygroundTest::SetUp() { + if (!Playground::SupportsBackend(GetParam())) { + GTEST_SKIP_("Playground doesn't support this backend type."); + return; + } + + if (!Playground::ShouldOpenNewPlaygrounds()) { + GTEST_SKIP_("Skipping due to user action."); + return; + } + + SetupContext(GetParam()); + + start_time_ = fml::TimePoint::Now().ToEpochDelta(); +} + +void ComputePlaygroundTest::TearDown() { + TeardownWindow(); +} + +// |Playground| +std::unique_ptr ComputePlaygroundTest::OpenAssetAsMapping( + std::string asset_name) const { + return flutter::testing::OpenFixtureAsMapping(asset_name); +} + +std::shared_ptr ComputePlaygroundTest::OpenAssetAsRuntimeStage( + const char* asset_name) const { + auto fixture = flutter::testing::OpenFixtureAsMapping(asset_name); + if (!fixture || fixture->GetSize() == 0) { + return nullptr; + } + auto stage = std::make_unique(std::move(fixture)); + if (!stage->IsValid()) { + return nullptr; + } + return stage; +} + +static std::string FormatWindowTitle(const std::string& test_name) { + std::stringstream stream; + stream << "Impeller Playground for '" << test_name + << "' (Press ESC or 'q' to quit)"; + return stream.str(); +} + +// |Playground| +std::string ComputePlaygroundTest::GetWindowTitle() const { + return FormatWindowTitle(flutter::testing::GetCurrentTestName()); +} + +Scalar ComputePlaygroundTest::GetSecondsElapsed() const { + return (fml::TimePoint::Now().ToEpochDelta() - start_time_).ToSecondsF(); +} + +} // namespace impeller diff --git a/impeller/playground/compute_playground_test.h b/impeller/playground/compute_playground_test.h new file mode 100644 index 0000000000000..93cff4ce2f86a --- /dev/null +++ b/impeller/playground/compute_playground_test.h @@ -0,0 +1,55 @@ +// 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. + +#pragma once + +#include + +#include "flutter/fml/macros.h" +#include "flutter/fml/time/time_delta.h" +#include "flutter/testing/testing.h" +#include "impeller/geometry/scalar.h" +#include "impeller/playground/playground.h" + +namespace impeller { + +class ComputePlaygroundTest + : public Playground, + public ::testing::TestWithParam { + public: + ComputePlaygroundTest(); + + virtual ~ComputePlaygroundTest(); + + void SetUp() override; + + void TearDown() override; + + // |Playground| + std::unique_ptr OpenAssetAsMapping( + std::string asset_name) const override; + + std::shared_ptr OpenAssetAsRuntimeStage( + const char* asset_name) const; + + // |Playground| + std::string GetWindowTitle() const override; + + /// @brief Get the amount of time elapsed from the start of the playground + /// test's execution. + Scalar GetSecondsElapsed() const; + + private: + fml::TimeDelta start_time_; + + FML_DISALLOW_COPY_AND_ASSIGN(ComputePlaygroundTest); +}; + +#define INSTANTIATE_COMPUTE_SUITE(playground) \ + INSTANTIATE_TEST_SUITE_P( \ + Compute, playground, ::testing::Values(PlaygroundBackend::kMetal), \ + [](const ::testing::TestParamInfo& \ + info) { return PlaygroundBackendToString(info.param); }); + +} // namespace impeller diff --git a/impeller/playground/playground.cc b/impeller/playground/playground.cc index 92eae2852fee4..4cfb98b93e80e 100644 --- a/impeller/playground/playground.cc +++ b/impeller/playground/playground.cc @@ -77,7 +77,7 @@ Playground::Playground() Playground::~Playground() = default; std::shared_ptr Playground::GetContext() const { - return renderer_ ? renderer_->GetContext() : nullptr; + return context_; } bool Playground::SupportsBackend(PlaygroundBackend backend) { @@ -104,18 +104,24 @@ bool Playground::SupportsBackend(PlaygroundBackend backend) { FML_UNREACHABLE(); } -void Playground::SetupWindow(PlaygroundBackend backend) { +void Playground::SetupContext(PlaygroundBackend backend) { FML_CHECK(SupportsBackend(backend)); impl_ = PlaygroundImpl::Create(backend); if (!impl_) { return; } - auto context = impl_->GetContext(); - if (!context) { + + context_ = impl_->GetContext(); +} + +void Playground::SetupWindow() { + if (!context_) { + FML_LOG(WARNING) + << "Asked to setup a window with no context (call SetupContext first)."; return; } - auto renderer = std::make_unique(std::move(context)); + auto renderer = std::make_unique(context_); if (!renderer->IsValid()) { return; } @@ -123,6 +129,7 @@ void Playground::SetupWindow(PlaygroundBackend backend) { } void Playground::TeardownWindow() { + context_.reset(); renderer_.reset(); impl_.reset(); } diff --git a/impeller/playground/playground.h b/impeller/playground/playground.h index 82e1edf2946eb..842c988394631 100644 --- a/impeller/playground/playground.h +++ b/impeller/playground/playground.h @@ -38,7 +38,9 @@ class Playground { static bool ShouldOpenNewPlaygrounds(); - void SetupWindow(PlaygroundBackend backend); + void SetupContext(PlaygroundBackend backend); + + void SetupWindow(); void TeardownWindow(); @@ -81,6 +83,7 @@ class Playground { struct GLFWInitializer; std::unique_ptr glfw_initializer_; std::unique_ptr impl_; + std::shared_ptr context_; std::unique_ptr renderer_; Point cursor_position_; ISize window_size_ = ISize{1024, 768}; diff --git a/impeller/playground/playground_test.cc b/impeller/playground/playground_test.cc index fab9d75a55e22..c34b30d63f256 100644 --- a/impeller/playground/playground_test.cc +++ b/impeller/playground/playground_test.cc @@ -23,7 +23,8 @@ void PlaygroundTest::SetUp() { return; } - SetupWindow(GetParam()); + SetupContext(GetParam()); + SetupWindow(); start_time_ = fml::TimePoint::Now().ToEpochDelta(); } diff --git a/impeller/renderer/compute_unittests.cc b/impeller/renderer/compute_unittests.cc index ede06d592fdb0..7017364903e82 100644 --- a/impeller/renderer/compute_unittests.cc +++ b/impeller/renderer/compute_unittests.cc @@ -7,7 +7,7 @@ #include "flutter/testing/testing.h" #include "impeller/base/strings.h" #include "impeller/fixtures/sample.comp.h" -#include "impeller/playground/playground_test.h" +#include "impeller/playground/compute_playground_test.h" #include "impeller/renderer/command_buffer.h" #include "impeller/renderer/compute_command.h" #include "impeller/renderer/compute_pipeline_builder.h" @@ -17,17 +17,10 @@ namespace impeller { namespace testing { -using ComputeTest = PlaygroundTest; -INSTANTIATE_PLAYGROUND_SUITE(ComputeTest); +using ComputeTest = ComputePlaygroundTest; +INSTANTIATE_COMPUTE_SUITE(ComputeTest); TEST_P(ComputeTest, CanCreateComputePass) { - if (GetParam() == PlaygroundBackend::kOpenGLES) { - GTEST_SKIP_("Compute is not supported on GL."); - } - if (GetParam() == PlaygroundBackend::kVulkan) { - GTEST_SKIP_("Compute is not supported on Vulkan yet."); - } - using CS = SampleComputeShader; auto context = GetContext(); ASSERT_TRUE(context); @@ -63,6 +56,7 @@ TEST_P(ComputeTest, CanCreateComputePass) { input_0.fixed_array[1] = IPoint32(2, 2); input_1.fixed_array[0] = UintPoint32(3, 3); input_0.some_int = 5; + input_1.some_struct = CS::SomeStruct{.vf = Point(3, 4), .i = 42}; DeviceBufferDescriptor buffer_desc; buffer_desc.storage_mode = StorageMode::kHostVisible; @@ -97,8 +91,10 @@ TEST_P(ComputeTest, CanCreateComputePass) { for (size_t i = 0; i < kCount; i++) { Vector4 vector = output->elements[i]; Vector4 computed = input_0.elements[i] * input_1.elements[i]; - EXPECT_EQ(vector, Vector4(computed.x + 2, computed.y + 3, - computed.z + 5, computed.w)); + EXPECT_EQ(vector, Vector4(computed.x + 2 + input_1.some_struct.i, + computed.y + 3 + input_1.some_struct.vf.x, + computed.z + 5 + input_1.some_struct.vf.y, + computed.w)); } latch.Signal(); }));