Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
renderer_dart_unittests.cc
Go to the documentation of this file.
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#define FML_USED_ON_EMBEDDER
6
7#include <memory>
8
9#include "flutter/common/settings.h"
10#include "flutter/common/task_runners.h"
11#include "flutter/lib/gpu/context.h"
12#include "flutter/lib/gpu/shader_library.h"
13#include "flutter/lib/gpu/texture.h"
14#include "flutter/runtime/dart_isolate.h"
15#include "flutter/runtime/dart_vm_lifecycle.h"
16#include "flutter/testing/dart_fixture.h"
17#include "flutter/testing/dart_isolate_runner.h"
18#include "flutter/testing/test_dart_native_resolver.h"
19#include "flutter/testing/testing.h"
20#include "fml/memory/ref_ptr.h"
21#include "impeller/fixtures/texture.frag.h"
22#include "impeller/fixtures/texture.vert.h"
27
28#include "gtest/gtest.h"
29#include "third_party/imgui/imgui.h"
30
31namespace impeller {
32namespace testing {
33
35 auto fixture =
36 flutter::testing::OpenFixtureAsMapping("playground.shaderbundle");
38 backend_type, std::move(fixture));
40}
41
44 public:
46 : settings_(CreateSettingsForFixture()),
47 vm_ref_(flutter::DartVMRef::Create(settings_)) {
49
50 current_task_runner_ = fml::MessageLoop::GetCurrent().GetTaskRunner();
51
52 isolate_ = CreateDartIsolate();
53 assert(isolate_);
54 assert(isolate_->get()->GetPhase() == flutter::DartIsolate::Phase::Running);
55
56 // Set up native callbacks.
57 //
58 // Note: The Dart isolate is configured (by
59 // `RendererDartTest::CreateDartIsolate`) to use the main thread, so
60 // there's no need for additional synchronization.
61 {
62 auto set_display_texture = [this](Dart_NativeArguments args) {
66 assert(texture != nullptr); // Should always be a valid pointer.
67 received_texture_ = texture->GetTexture();
68 };
69 AddNativeCallback("SetDisplayTexture",
70 CREATE_NATIVE_ENTRY(set_display_texture));
71 }
72 }
73
75 // Sneak the context into the Flutter GPU API.
76 assert(GetContext() != nullptr);
78
79 InstantiateTestShaderLibrary(GetContext()->GetBackendType());
80
81 return isolate_.get();
82 }
83
84 /// @brief Run a Dart function that's expected to create a texture and pass
85 /// it back for rendering via `drawToPlayground`.
86 std::shared_ptr<Texture> GetRenderedTextureFromDart(
87 const char* dart_function_name) {
88 bool success =
89 GetIsolate()->RunInIsolateScope([this, &dart_function_name]() -> bool {
94 tonic::ToDart(dart_function_name), 2, args))) {
95 return false;
96 }
97 return true;
98 });
99 if (!success) {
100 FML_LOG(ERROR) << "Failed to invoke dart test function:"
101 << dart_function_name;
102 return nullptr;
103 }
104 if (!received_texture_) {
105 FML_LOG(ERROR) << "Dart test function `" << dart_function_name
106 << "` did not invoke `drawToPlaygroundSurface`.";
107 return nullptr;
108 }
109 return received_texture_;
110 }
111
112 /// @brief Invokes a Dart function.
113 ///
114 /// Returns false if invoking the function failed or if any unhandled
115 /// exceptions were thrown.
116 bool RunDartFunction(const char* dart_function_name) {
117 return GetIsolate()->RunInIsolateScope([&dart_function_name]() -> bool {
120 tonic::ToDart(dart_function_name), 0, nullptr))) {
121 return false;
122 }
123 return true;
124 });
125 }
126
127 /// @brief Invokes a Dart function with the window's width and height as
128 /// arguments.
129 ///
130 /// Returns false if invoking the function failed or if any unhandled
131 /// exceptions were thrown.
132 bool RunDartFunctionWithWindowSize(const char* dart_function_name) {
134 [this, &dart_function_name]() -> bool {
139 tonic::ToDart(dart_function_name), 2, args))) {
140 return false;
141 }
142 return true;
143 });
144 }
145
146 /// @brief Call a dart function that produces a texture and render the result
147 /// in the playground.
148 ///
149 /// If the playground isn't enabled, the function is simply run once
150 /// in order to verify that it doesn't throw any unhandled exceptions.
151 bool RenderDartToPlayground(const char* dart_function_name) {
152 if (!IsPlaygroundEnabled()) {
153 // If the playground is not enabled, run the function instead to at least
154 // verify that it doesn't crash.
155 return RunDartFunctionWithWindowSize(dart_function_name);
156 }
157
158 auto context = GetContext();
159 assert(context != nullptr);
160
161 //------------------------------------------------------------------------------
162 /// Prepare pipeline.
163 ///
164
165 using TextureVS = TextureVertexShader;
166 using TextureFS = TextureFragmentShader;
167 using TexturePipelineBuilder = PipelineBuilder<TextureVS, TextureFS>;
168
169 auto pipeline_desc =
170 TexturePipelineBuilder::MakeDefaultPipelineDescriptor(*context);
171 if (!pipeline_desc.has_value()) {
172 FML_LOG(ERROR) << "Failed to create default pipeline descriptor.";
173 return false;
174 }
175 pipeline_desc->SetSampleCount(SampleCount::kCount4);
176 pipeline_desc->SetStencilAttachmentDescriptors(std::nullopt);
177 pipeline_desc->SetDepthStencilAttachmentDescriptor(std::nullopt);
178 pipeline_desc->SetStencilPixelFormat(PixelFormat::kUnknown);
179 pipeline_desc->SetDepthPixelFormat(PixelFormat::kUnknown);
180
181 auto pipeline =
182 context->GetPipelineLibrary()->GetPipeline(pipeline_desc).Get();
183 if (!pipeline || !pipeline->IsValid()) {
184 FML_LOG(ERROR) << "Failed to create default pipeline.";
185 return false;
186 }
187
188 //------------------------------------------------------------------------------
189 /// Prepare vertex data.
190 ///
191
193
194 // Always stretch out the texture to fill the screen.
195
196 // clang-format off
197 texture_vtx_builder.AddVertices({
198 {{-0.5, -0.5, 0.0}, {0.0, 0.0}}, // 1
199 {{ 0.5, -0.5, 0.0}, {1.0, 0.0}}, // 2
200 {{ 0.5, 0.5, 0.0}, {1.0, 1.0}}, // 3
201 {{-0.5, -0.5, 0.0}, {0.0, 0.0}}, // 1
202 {{ 0.5, 0.5, 0.0}, {1.0, 1.0}}, // 3
203 {{-0.5, 0.5, 0.0}, {0.0, 1.0}}, // 4
204 });
205 // clang-format on
206
207 //------------------------------------------------------------------------------
208 /// Prepare sampler.
209 ///
210
211 const auto& sampler = context->GetSamplerLibrary()->GetSampler({});
212 if (!sampler) {
213 FML_LOG(ERROR) << "Failed to create default sampler.";
214 return false;
215 }
216
217 //------------------------------------------------------------------------------
218 /// Render to playground.
219 ///
220
222 auto texture = GetRenderedTextureFromDart(dart_function_name);
223 if (!texture) {
224 return false;
225 }
226
227 auto buffer = HostBuffer::Create(context->GetResourceAllocator());
228
229 pass.SetVertexBuffer(texture_vtx_builder.CreateVertexBuffer(
230 *context->GetResourceAllocator()));
231
232 TextureVS::UniformBuffer uniforms;
233 uniforms.mvp = Matrix();
234 TextureVS::BindUniformBuffer(pass, buffer->EmplaceUniform(uniforms));
235 TextureFS::BindTextureContents(pass, texture, sampler);
236
237 pass.SetPipeline(pipeline);
238
239 if (!pass.Draw().ok()) {
240 return false;
241 }
242 return true;
243 };
245 }
246
247 private:
248 std::unique_ptr<flutter::testing::AutoIsolateShutdown> CreateDartIsolate() {
249 const auto settings = CreateSettingsForFixture();
251 current_task_runner_, //
252 current_task_runner_, //
253 current_task_runner_, //
254 current_task_runner_ //
255 );
257 vm_ref_, settings, task_runners, "main", {},
259 }
260
261 const flutter::Settings settings_;
262 flutter::DartVMRef vm_ref_;
263 fml::RefPtr<fml::TaskRunner> current_task_runner_;
264 std::unique_ptr<flutter::testing::AutoIsolateShutdown> isolate_;
265
266 std::shared_ptr<Texture> received_texture_;
267};
268
270
271TEST_P(RendererDartTest, CanRunDartInPlaygroundFrame) {
272 SinglePassCallback callback = [&](RenderPass& pass) {
273 ImGui::Begin("Dart test", nullptr);
274 ImGui::Text(
275 "This test executes Dart code during the playground frame callback.");
276 ImGui::End();
277
278 return RunDartFunction("sayHi");
279 };
280 ASSERT_TRUE(OpenPlaygroundHere(callback));
281}
282
283/// These test entries correspond to Dart functions located in
284/// `flutter/impeller/fixtures/dart_tests.dart`
285
286TEST_P(RendererDartTest, CanInstantiateFlutterGPUContext) {
287 ASSERT_TRUE(RunDartFunction("instantiateDefaultContext"));
288}
289
290TEST_P(RendererDartTest, CanCreateShaderLibrary) {
291 ASSERT_TRUE(RunDartFunction("canCreateShaderLibrary"));
292}
293
294TEST_P(RendererDartTest, CanReflectUniformStructs) {
295 ASSERT_TRUE(RunDartFunction("canReflectUniformStructs"));
296}
297
298TEST_P(RendererDartTest, UniformBindFailsForInvalidHostBufferOffset) {
299 ASSERT_TRUE(RunDartFunction("uniformBindFailsForInvalidHostBufferOffset"));
300}
301
302TEST_P(RendererDartTest, CanCreateRenderPassAndSubmit) {
303 ASSERT_TRUE(RenderDartToPlayground("canCreateRenderPassAndSubmit"));
304}
305
306} // namespace testing
307} // namespace impeller
static sk_sp< Effect > Create()
static void SetOverrideContext(std::shared_ptr< impeller::Context > context)
Definition context.cc:21
static void SetOverride(fml::RefPtr< ShaderLibrary > override_shader_library)
Sets a return override for MakeFromAsset for testing purposes.
static fml::RefPtr< ShaderLibrary > MakeFromFlatbuffer(impeller::Context::BackendType backend_type, std::shared_ptr< fml::Mapping > payload)
bool RunInIsolateScope(const std::function< bool(void)> &closure)
virtual Settings CreateSettingsForFixture()
void AddNativeCallback(const std::string &name, Dart_NativeFunction callback)
static void EnsureInitializedForCurrentThread()
fml::RefPtr< fml::TaskRunner > GetTaskRunner() const
static FML_EMBEDDER_ONLY MessageLoop & GetCurrent()
static std::shared_ptr< HostBuffer > Create(const std::shared_ptr< Allocator > &allocator)
bool IsPlaygroundEnabled() const
ISize GetWindowSize() const
std::function< bool(RenderPass &pass)> SinglePassCallback
Definition playground.h:52
std::shared_ptr< Context > GetContext() const
Definition playground.cc:89
bool OpenPlaygroundHere(const Renderer::RenderCallback &render_callback)
Render passes encode render commands directed as one specific render target into an underlying comman...
Definition render_pass.h:33
VertexBuffer CreateVertexBuffer(HostBuffer &host_buffer) const
VertexBufferBuilder & AddVertices(std::initializer_list< VertexType_ > vertices)
bool RunDartFunctionWithWindowSize(const char *dart_function_name)
Invokes a Dart function with the window's width and height as arguments.
std::shared_ptr< Texture > GetRenderedTextureFromDart(const char *dart_function_name)
Run a Dart function that's expected to create a texture and pass it back for rendering via drawToPlay...
bool RenderDartToPlayground(const char *dart_function_name)
Call a dart function that produces a texture and render the result in the playground.
bool RunDartFunction(const char *dart_function_name)
Invokes a Dart function.
flutter::testing::AutoIsolateShutdown * GetIsolate()
struct _Dart_Handle * Dart_Handle
Definition dart_api.h:258
DART_EXPORT DART_WARN_UNUSED_RESULT Dart_Handle Dart_Invoke(Dart_Handle target, Dart_Handle name, int number_of_arguments, Dart_Handle *arguments)
DART_EXPORT Dart_Handle Dart_GetNativeArgument(Dart_NativeArguments args, int index)
struct _Dart_NativeArguments * Dart_NativeArguments
Definition dart_api.h:3010
DART_EXPORT Dart_Handle Dart_RootLibrary(void)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
FlKeyEvent uint64_t FlKeyResponderAsyncCallback callback
static const uint8_t buffer[]
#define FML_LOG(severity)
Definition logging.h:82
FlTexture * texture
std::string GetCurrentTestName()
Gets the name of the currently running test. This is useful in generating logs or assets based on tes...
Definition testing.cc:15
std::string GetDefaultKernelFilePath()
Returns the default path to kernel_blob.bin. This file is within the directory returned by GetFixture...
Definition testing.cc:19
std::unique_ptr< AutoIsolateShutdown > RunDartCodeInIsolate(DartVMRef &vm_ref, const Settings &settings, const TaskRunners &task_runners, std::string entrypoint, const std::vector< std::string > &args, const std::string &kernel_file_path, fml::WeakPtr< IOManager > io_manager, std::shared_ptr< VolatilePathTracker > volatile_path_tracker, std::unique_ptr< PlatformConfiguration > platform_configuration)
std::unique_ptr< fml::Mapping > OpenFixtureAsMapping(const std::string &fixture_name)
Opens a fixture of the given file name and returns a mapping to its contents.
Definition testing.cc:59
static void InstantiateTestShaderLibrary(Context::BackendType backend_type)
TEST_P(AiksTest, CanRenderAdvancedBlendColorFilterWithSaveLayer)
Dart_Handle ToDart(const T &object)
bool CheckAndHandleError(Dart_Handle handle)
Definition dart_error.cc:33
#define INSTANTIATE_PLAYGROUND_SUITE(playground)
int32_t height
int32_t width
A 4x4 matrix using column-major storage.
Definition matrix.h:37
An optional (but highly recommended) utility for creating pipelines from reflected shader information...
#define CREATE_NATIVE_ENTRY(native_entry)
#define ERROR(message)