Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit d4aec01

Browse files
authored
[Impeller] Support user defined structs in buffers, clean up compute tests (#37084)
1 parent 408b9b1 commit d4aec01

File tree

9 files changed

+185
-22
lines changed

9 files changed

+185
-22
lines changed

impeller/compiler/reflector.cc

+23
Original file line numberDiff line numberDiff line change
@@ -603,6 +603,29 @@ std::vector<StructMember> Reflector::ReadStructMembers(
603603

604604
FML_CHECK(current_byte_offset == struct_member_offset);
605605

606+
// A user defined struct.
607+
if (member.basetype == spirv_cross::SPIRType::BaseType::Struct) {
608+
const size_t size =
609+
GetReflectedStructSize(ReadStructMembers(member.self));
610+
uint32_t stride = GetArrayStride<0>(struct_type, member, i);
611+
if (stride == 0) {
612+
stride = size;
613+
}
614+
uint32_t element_padding = stride - size;
615+
result.emplace_back(StructMember{
616+
compiler_->get_name(member.self), // type
617+
BaseTypeToString(member.basetype), // basetype
618+
GetMemberNameAtIndex(struct_type, i), // name
619+
struct_member_offset, // offset
620+
size, // size
621+
stride * array_elements.value_or(1), // byte_length
622+
array_elements, // array_elements
623+
element_padding, // element_padding
624+
});
625+
current_byte_offset += stride * array_elements.value_or(1);
626+
continue;
627+
}
628+
606629
// Tightly packed 4x4 Matrix is special cased as we know how to work with
607630
// those.
608631
if (member.basetype == spirv_cross::SPIRType::BaseType::Float && //

impeller/fixtures/sample.comp

+9-3
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
layout(local_size_x = 128) in;
22
layout(std430) buffer;
33

4+
struct SomeStruct {
5+
vec2 vf;
6+
uint i;
7+
};
8+
49
layout(binding = 0) writeonly buffer Output {
510
vec4 elements[];
611
} output_data;
@@ -12,6 +17,7 @@ layout(binding = 1) readonly buffer Input0 {
1217
} input_data0;
1318

1419
layout(binding = 2) readonly buffer Input1 {
20+
SomeStruct some_struct;
1521
uvec2 fixed_array[4];
1622
vec4 elements[];
1723
} input_data1;
@@ -30,7 +36,7 @@ void main()
3036
}
3137

3238
output_data.elements[ident] = input_data0.elements[ident] * input_data1.elements[ident];
33-
output_data.elements[ident].x += input_data0.fixed_array[1].x;
34-
output_data.elements[ident].y += input_data1.fixed_array[0].y;
35-
output_data.elements[ident].z += input_data0.some_int;
39+
output_data.elements[ident].x += input_data0.fixed_array[1].x + input_data1.some_struct.i;
40+
output_data.elements[ident].y += input_data1.fixed_array[0].y + input_data1.some_struct.vf.x;
41+
output_data.elements[ident].z += input_data0.some_int + input_data1.some_struct.vf.y;
3642
}

impeller/playground/BUILD.gn

+2
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ impeller_component("playground_test") {
6262
testonly = true
6363

6464
sources = [
65+
"compute_playground_test.cc",
66+
"compute_playground_test.h",
6567
"playground_test.cc",
6668
"playground_test.h",
6769
]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/fml/time/time_point.h"
6+
7+
#include "impeller/playground/compute_playground_test.h"
8+
9+
namespace impeller {
10+
11+
ComputePlaygroundTest::ComputePlaygroundTest() = default;
12+
13+
ComputePlaygroundTest::~ComputePlaygroundTest() = default;
14+
15+
void ComputePlaygroundTest::SetUp() {
16+
if (!Playground::SupportsBackend(GetParam())) {
17+
GTEST_SKIP_("Playground doesn't support this backend type.");
18+
return;
19+
}
20+
21+
if (!Playground::ShouldOpenNewPlaygrounds()) {
22+
GTEST_SKIP_("Skipping due to user action.");
23+
return;
24+
}
25+
26+
SetupContext(GetParam());
27+
28+
start_time_ = fml::TimePoint::Now().ToEpochDelta();
29+
}
30+
31+
void ComputePlaygroundTest::TearDown() {
32+
TeardownWindow();
33+
}
34+
35+
// |Playground|
36+
std::unique_ptr<fml::Mapping> ComputePlaygroundTest::OpenAssetAsMapping(
37+
std::string asset_name) const {
38+
return flutter::testing::OpenFixtureAsMapping(asset_name);
39+
}
40+
41+
std::shared_ptr<RuntimeStage> ComputePlaygroundTest::OpenAssetAsRuntimeStage(
42+
const char* asset_name) const {
43+
auto fixture = flutter::testing::OpenFixtureAsMapping(asset_name);
44+
if (!fixture || fixture->GetSize() == 0) {
45+
return nullptr;
46+
}
47+
auto stage = std::make_unique<RuntimeStage>(std::move(fixture));
48+
if (!stage->IsValid()) {
49+
return nullptr;
50+
}
51+
return stage;
52+
}
53+
54+
static std::string FormatWindowTitle(const std::string& test_name) {
55+
std::stringstream stream;
56+
stream << "Impeller Playground for '" << test_name
57+
<< "' (Press ESC or 'q' to quit)";
58+
return stream.str();
59+
}
60+
61+
// |Playground|
62+
std::string ComputePlaygroundTest::GetWindowTitle() const {
63+
return FormatWindowTitle(flutter::testing::GetCurrentTestName());
64+
}
65+
66+
Scalar ComputePlaygroundTest::GetSecondsElapsed() const {
67+
return (fml::TimePoint::Now().ToEpochDelta() - start_time_).ToSecondsF();
68+
}
69+
70+
} // namespace impeller
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#pragma once
6+
7+
#include <memory>
8+
9+
#include "flutter/fml/macros.h"
10+
#include "flutter/fml/time/time_delta.h"
11+
#include "flutter/testing/testing.h"
12+
#include "impeller/geometry/scalar.h"
13+
#include "impeller/playground/playground.h"
14+
15+
namespace impeller {
16+
17+
class ComputePlaygroundTest
18+
: public Playground,
19+
public ::testing::TestWithParam<PlaygroundBackend> {
20+
public:
21+
ComputePlaygroundTest();
22+
23+
virtual ~ComputePlaygroundTest();
24+
25+
void SetUp() override;
26+
27+
void TearDown() override;
28+
29+
// |Playground|
30+
std::unique_ptr<fml::Mapping> OpenAssetAsMapping(
31+
std::string asset_name) const override;
32+
33+
std::shared_ptr<RuntimeStage> OpenAssetAsRuntimeStage(
34+
const char* asset_name) const;
35+
36+
// |Playground|
37+
std::string GetWindowTitle() const override;
38+
39+
/// @brief Get the amount of time elapsed from the start of the playground
40+
/// test's execution.
41+
Scalar GetSecondsElapsed() const;
42+
43+
private:
44+
fml::TimeDelta start_time_;
45+
46+
FML_DISALLOW_COPY_AND_ASSIGN(ComputePlaygroundTest);
47+
};
48+
49+
#define INSTANTIATE_COMPUTE_SUITE(playground) \
50+
INSTANTIATE_TEST_SUITE_P( \
51+
Compute, playground, ::testing::Values(PlaygroundBackend::kMetal), \
52+
[](const ::testing::TestParamInfo<ComputePlaygroundTest::ParamType>& \
53+
info) { return PlaygroundBackendToString(info.param); });
54+
55+
} // namespace impeller

impeller/playground/playground.cc

+12-5
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ Playground::Playground()
7777
Playground::~Playground() = default;
7878

7979
std::shared_ptr<Context> Playground::GetContext() const {
80-
return renderer_ ? renderer_->GetContext() : nullptr;
80+
return context_;
8181
}
8282

8383
bool Playground::SupportsBackend(PlaygroundBackend backend) {
@@ -104,25 +104,32 @@ bool Playground::SupportsBackend(PlaygroundBackend backend) {
104104
FML_UNREACHABLE();
105105
}
106106

107-
void Playground::SetupWindow(PlaygroundBackend backend) {
107+
void Playground::SetupContext(PlaygroundBackend backend) {
108108
FML_CHECK(SupportsBackend(backend));
109109

110110
impl_ = PlaygroundImpl::Create(backend);
111111
if (!impl_) {
112112
return;
113113
}
114-
auto context = impl_->GetContext();
115-
if (!context) {
114+
115+
context_ = impl_->GetContext();
116+
}
117+
118+
void Playground::SetupWindow() {
119+
if (!context_) {
120+
FML_LOG(WARNING)
121+
<< "Asked to setup a window with no context (call SetupContext first).";
116122
return;
117123
}
118-
auto renderer = std::make_unique<Renderer>(std::move(context));
124+
auto renderer = std::make_unique<Renderer>(context_);
119125
if (!renderer->IsValid()) {
120126
return;
121127
}
122128
renderer_ = std::move(renderer);
123129
}
124130

125131
void Playground::TeardownWindow() {
132+
context_.reset();
126133
renderer_.reset();
127134
impl_.reset();
128135
}

impeller/playground/playground.h

+4-1
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ class Playground {
3838

3939
static bool ShouldOpenNewPlaygrounds();
4040

41-
void SetupWindow(PlaygroundBackend backend);
41+
void SetupContext(PlaygroundBackend backend);
42+
43+
void SetupWindow();
4244

4345
void TeardownWindow();
4446

@@ -81,6 +83,7 @@ class Playground {
8183
struct GLFWInitializer;
8284
std::unique_ptr<GLFWInitializer> glfw_initializer_;
8385
std::unique_ptr<PlaygroundImpl> impl_;
86+
std::shared_ptr<Context> context_;
8487
std::unique_ptr<Renderer> renderer_;
8588
Point cursor_position_;
8689
ISize window_size_ = ISize{1024, 768};

impeller/playground/playground_test.cc

+2-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ void PlaygroundTest::SetUp() {
2323
return;
2424
}
2525

26-
SetupWindow(GetParam());
26+
SetupContext(GetParam());
27+
SetupWindow();
2728

2829
start_time_ = fml::TimePoint::Now().ToEpochDelta();
2930
}

impeller/renderer/compute_unittests.cc

+8-12
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
#include "flutter/testing/testing.h"
88
#include "impeller/base/strings.h"
99
#include "impeller/fixtures/sample.comp.h"
10-
#include "impeller/playground/playground_test.h"
10+
#include "impeller/playground/compute_playground_test.h"
1111
#include "impeller/renderer/command_buffer.h"
1212
#include "impeller/renderer/compute_command.h"
1313
#include "impeller/renderer/compute_pipeline_builder.h"
@@ -17,17 +17,10 @@
1717
namespace impeller {
1818
namespace testing {
1919

20-
using ComputeTest = PlaygroundTest;
21-
INSTANTIATE_PLAYGROUND_SUITE(ComputeTest);
20+
using ComputeTest = ComputePlaygroundTest;
21+
INSTANTIATE_COMPUTE_SUITE(ComputeTest);
2222

2323
TEST_P(ComputeTest, CanCreateComputePass) {
24-
if (GetParam() == PlaygroundBackend::kOpenGLES) {
25-
GTEST_SKIP_("Compute is not supported on GL.");
26-
}
27-
if (GetParam() == PlaygroundBackend::kVulkan) {
28-
GTEST_SKIP_("Compute is not supported on Vulkan yet.");
29-
}
30-
3124
using CS = SampleComputeShader;
3225
auto context = GetContext();
3326
ASSERT_TRUE(context);
@@ -63,6 +56,7 @@ TEST_P(ComputeTest, CanCreateComputePass) {
6356
input_0.fixed_array[1] = IPoint32(2, 2);
6457
input_1.fixed_array[0] = UintPoint32(3, 3);
6558
input_0.some_int = 5;
59+
input_1.some_struct = CS::SomeStruct{.vf = Point(3, 4), .i = 42};
6660

6761
DeviceBufferDescriptor buffer_desc;
6862
buffer_desc.storage_mode = StorageMode::kHostVisible;
@@ -97,8 +91,10 @@ TEST_P(ComputeTest, CanCreateComputePass) {
9791
for (size_t i = 0; i < kCount; i++) {
9892
Vector4 vector = output->elements[i];
9993
Vector4 computed = input_0.elements[i] * input_1.elements[i];
100-
EXPECT_EQ(vector, Vector4(computed.x + 2, computed.y + 3,
101-
computed.z + 5, computed.w));
94+
EXPECT_EQ(vector, Vector4(computed.x + 2 + input_1.some_struct.i,
95+
computed.y + 3 + input_1.some_struct.vf.x,
96+
computed.z + 5 + input_1.some_struct.vf.y,
97+
computed.w));
10298
}
10399
latch.Signal();
104100
}));

0 commit comments

Comments
 (0)