[Impeller] Support user defined structs in buffers, clean up compute tests (flutter/engine#37084)

This commit is contained in:
Dan Field
2022-10-27 13:46:47 -07:00
committed by GitHub
parent 33a7935560
commit c356bc69ba
9 changed files with 185 additions and 22 deletions

View File

@@ -603,6 +603,29 @@ std::vector<StructMember> 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 && //

View File

@@ -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;
}

View File

@@ -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",
]

View File

@@ -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<fml::Mapping> ComputePlaygroundTest::OpenAssetAsMapping(
std::string asset_name) const {
return flutter::testing::OpenFixtureAsMapping(asset_name);
}
std::shared_ptr<RuntimeStage> 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<RuntimeStage>(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

View File

@@ -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 <memory>
#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<PlaygroundBackend> {
public:
ComputePlaygroundTest();
virtual ~ComputePlaygroundTest();
void SetUp() override;
void TearDown() override;
// |Playground|
std::unique_ptr<fml::Mapping> OpenAssetAsMapping(
std::string asset_name) const override;
std::shared_ptr<RuntimeStage> 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<ComputePlaygroundTest::ParamType>& \
info) { return PlaygroundBackendToString(info.param); });
} // namespace impeller

View File

@@ -77,7 +77,7 @@ Playground::Playground()
Playground::~Playground() = default;
std::shared_ptr<Context> 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<Renderer>(std::move(context));
auto renderer = std::make_unique<Renderer>(context_);
if (!renderer->IsValid()) {
return;
}
@@ -123,6 +129,7 @@ void Playground::SetupWindow(PlaygroundBackend backend) {
}
void Playground::TeardownWindow() {
context_.reset();
renderer_.reset();
impl_.reset();
}

View File

@@ -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<GLFWInitializer> glfw_initializer_;
std::unique_ptr<PlaygroundImpl> impl_;
std::shared_ptr<Context> context_;
std::unique_ptr<Renderer> renderer_;
Point cursor_position_;
ISize window_size_ = ISize{1024, 768};

View File

@@ -23,7 +23,8 @@ void PlaygroundTest::SetUp() {
return;
}
SetupWindow(GetParam());
SetupContext(GetParam());
SetupWindow();
start_time_ = fml::TimePoint::Now().ToEpochDelta();
}

View File

@@ -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();
}));