Flutter Impeller
command_buffer_gles_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 #include <atomic>
6 #include <memory>
7 #include <vector>
8 
9 #include "flutter/fml/mapping.h"
10 #include "flutter/testing/testing.h" // IWYU pragma: keep
11 #include "gmock/gmock.h"
12 #include "gtest/gtest.h"
13 #include "impeller/core/formats.h"
16 #include "impeller/renderer/backend/gles/test/mock_gles.h"
21 
22 namespace impeller {
23 namespace testing {
24 namespace {
25 
26 using ::testing::_;
27 using ::testing::NiceMock;
28 
29 class ToggleWorker final : public ReactorGLES::Worker {
30  public:
31  explicit ToggleWorker(bool allowed) : allowed_(allowed) {}
32 
33  bool CanReactorReactOnCurrentThreadNow(
34  const ReactorGLES& reactor) const override {
35  return allowed_.load();
36  }
37 
38  void SetAllowed(bool allowed) { allowed_.store(allowed); }
39 
40  private:
41  std::atomic<bool> allowed_;
42 };
43 
44 std::shared_ptr<ContextGLES> CreateFakeGLESContext() {
45  auto gl = std::make_unique<ProcTableGLES>(kMockResolverGLES);
46  return ContextGLES::Create(Flags{}, std::move(gl),
47  std::vector<std::shared_ptr<fml::Mapping>>{},
48  /*enable_gpu_tracing=*/false);
49 }
50 
51 } // namespace
52 
54  SubmitWithoutCurrentContextIsAcceptedAndCompletesAfterReaction) {
55  auto mock_gles = MockGLES::Init();
56  auto context = CreateFakeGLESContext();
57  auto context_base = std::static_pointer_cast<Context>(context);
58  auto worker = std::make_shared<ToggleWorker>(false);
59  context->AddReactorWorker(worker);
60 
61  auto command_buffer = context_base->CreateCommandBuffer();
62  ASSERT_TRUE(command_buffer);
63 
64  bool callback_called = false;
66  auto status = context_base->GetCommandQueue()->Submit(
67  {command_buffer}, [&](CommandBuffer::Status status) {
68  callback_called = true;
69  callback_status = status;
70  });
71 
72  EXPECT_TRUE(status.ok());
73  EXPECT_FALSE(callback_called);
74 
75  worker->SetAllowed(true);
76  EXPECT_TRUE(context->GetReactor()->React());
77  EXPECT_TRUE(callback_called);
78  EXPECT_EQ(callback_status, CommandBuffer::Status::kCompleted);
79 }
80 
81 TEST(CommandBufferGLES, SubmitWithoutCallbackIsAcceptedWithoutCurrentContext) {
82  auto mock_gles = MockGLES::Init();
83  auto context = CreateFakeGLESContext();
84  auto context_base = std::static_pointer_cast<Context>(context);
85  auto worker = std::make_shared<ToggleWorker>(false);
86  context->AddReactorWorker(worker);
87 
88  auto command_buffer = context_base->CreateCommandBuffer();
89  ASSERT_TRUE(command_buffer);
90 
91  EXPECT_TRUE(context_base->GetCommandQueue()->Submit({command_buffer}).ok());
92 }
93 
94 TEST(CommandBufferGLES, DeferredSubmitCallbackErrorsIfReactorIsDestroyed) {
95  bool callback_called = false;
97 
98  {
99  auto mock_gles = MockGLES::Init();
100  auto context = CreateFakeGLESContext();
101  auto context_base = std::static_pointer_cast<Context>(context);
102  auto worker = std::make_shared<ToggleWorker>(false);
103  context->AddReactorWorker(worker);
104 
105  auto command_buffer = context_base->CreateCommandBuffer();
106  ASSERT_TRUE(command_buffer);
107  auto status = context_base->GetCommandQueue()->Submit(
108  {command_buffer}, [&](CommandBuffer::Status status) {
109  callback_called = true;
110  callback_status = status;
111  });
112 
113  EXPECT_TRUE(status.ok());
114  EXPECT_FALSE(callback_called);
115  }
116 
117  EXPECT_TRUE(callback_called);
118  EXPECT_EQ(callback_status, CommandBuffer::Status::kError);
119 }
120 
121 TEST(CommandBufferGLES, DeferredSubmitCompletesAfterPreviouslyQueuedWork) {
122  auto mock_gles = MockGLES::Init();
123  auto context = CreateFakeGLESContext();
124  auto context_base = std::static_pointer_cast<Context>(context);
125  auto worker = std::make_shared<ToggleWorker>(false);
126  context->AddReactorWorker(worker);
127 
128  std::vector<int> order;
129  ASSERT_TRUE(context->GetReactor()->AddOperation(
130  [&](const ReactorGLES& reactor) { order.push_back(1); },
131  /*defer=*/true));
132 
133  auto command_buffer = context_base->CreateCommandBuffer();
134  ASSERT_TRUE(command_buffer);
135  auto status = context_base->GetCommandQueue()->Submit(
136  {command_buffer},
137  [&](CommandBuffer::Status status) { order.push_back(2); });
138 
139  EXPECT_TRUE(status.ok());
140  EXPECT_TRUE(order.empty());
141 
142  worker->SetAllowed(true);
143  EXPECT_TRUE(context->GetReactor()->React());
144  EXPECT_THAT(order, ::testing::ElementsAre(1, 2));
145 }
146 
147 TEST(CommandBufferGLES, LaterCurrentSubmitDrainsPreviouslyDeferredWork) {
148  auto mock_gles = MockGLES::Init();
149  auto context = CreateFakeGLESContext();
150  auto context_base = std::static_pointer_cast<Context>(context);
151  auto worker = std::make_shared<ToggleWorker>(false);
152  context->AddReactorWorker(worker);
153 
154  std::vector<int> order;
155  ASSERT_TRUE(context->GetReactor()->AddOperation(
156  [&](const ReactorGLES& reactor) { order.push_back(1); },
157  /*defer=*/true));
158 
159  auto deferred_command_buffer = context_base->CreateCommandBuffer();
160  ASSERT_TRUE(deferred_command_buffer);
161  EXPECT_TRUE(
162  context_base->GetCommandQueue()->Submit({deferred_command_buffer}).ok());
163  EXPECT_TRUE(order.empty());
164 
165  worker->SetAllowed(true);
166  auto current_command_buffer = context_base->CreateCommandBuffer();
167  ASSERT_TRUE(current_command_buffer);
168  EXPECT_TRUE(
169  context_base->GetCommandQueue()
170  ->Submit({current_command_buffer},
171  [&](CommandBuffer::Status status) { order.push_back(2); })
172  .ok());
173  EXPECT_THAT(order, ::testing::ElementsAre(1, 2));
174 }
175 
176 TEST(CommandBufferGLES, BufferToTextureBlitCanBeSubmittedBeforeContextCurrent) {
177  auto mock_gles_impl = std::make_unique<NiceMock<MockGLESImpl>>();
178  auto& mock_gles_impl_ref = *mock_gles_impl;
179  auto mock_gles = MockGLES::Init(std::move(mock_gles_impl));
180  auto context = CreateFakeGLESContext();
181  auto context_base = std::static_pointer_cast<Context>(context);
182  auto worker = std::make_shared<ToggleWorker>(false);
183  context->AddReactorWorker(worker);
184 
185  constexpr GLuint kTextureHandle = 1234;
186  bool texture_generated = false;
187  bool texture_uploaded = false;
188  EXPECT_CALL(mock_gles_impl_ref, GenTextures(1, _))
189  .WillOnce([&](GLsizei size, GLuint* textures) {
190  texture_generated = true;
191  textures[0] = kTextureHandle;
192  });
193  EXPECT_CALL(mock_gles_impl_ref, BindTexture(GL_TEXTURE_2D, kTextureHandle))
194  .Times(::testing::AtLeast(1));
195  EXPECT_CALL(mock_gles_impl_ref,
196  TexImage2D(GL_TEXTURE_2D, 0, _, 2, 2, 0, _, _, nullptr))
197  .Times(1);
198  EXPECT_CALL(mock_gles_impl_ref,
199  TexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 2, 2, _, _, _))
200  .WillOnce([&](GLenum target, GLint level, GLint xoffset, GLint yoffset,
201  GLsizei width, GLsizei height, GLenum format, GLenum type,
202  const void* pixels) { texture_uploaded = true; });
203 
204  TextureDescriptor texture_descriptor;
205  texture_descriptor.size = {2, 2};
206  texture_descriptor.format = PixelFormat::kR8G8B8A8UNormInt;
207  auto texture = context_base->GetResourceAllocator()->CreateTexture(
208  texture_descriptor, /*threadsafe=*/true);
209  ASSERT_TRUE(texture);
210 
211  const uint8_t pixels[16] = {};
212  auto buffer =
213  context_base->GetResourceAllocator()->CreateBufferWithCopy(pixels, 16);
214  ASSERT_TRUE(buffer);
215 
216  auto command_buffer = context_base->CreateCommandBuffer();
217  ASSERT_TRUE(command_buffer);
218  auto blit_pass = command_buffer->CreateBlitPass();
219  ASSERT_TRUE(blit_pass);
220 
221  EXPECT_TRUE(blit_pass->AddCopy(BufferView(buffer, Range(0, 16)), texture,
222  IRect::MakeXYWH(0, 0, 2, 2),
223  "Deferred texture overwrite"));
224  EXPECT_TRUE(blit_pass->EncodeCommands());
225  EXPECT_TRUE(context_base->GetCommandQueue()->Submit({command_buffer}).ok());
226  EXPECT_FALSE(texture_generated);
227  EXPECT_FALSE(texture_uploaded);
228 
229  worker->SetAllowed(true);
230  EXPECT_TRUE(context->GetReactor()->React());
231  EXPECT_TRUE(texture_generated);
232  EXPECT_TRUE(texture_uploaded);
233 }
234 
235 } // namespace testing
236 } // namespace impeller
static std::shared_ptr< ContextGLES > Create(const Flags &flags, std::unique_ptr< ProcTableGLES > gl, const std::vector< std::shared_ptr< fml::Mapping >> &shader_libraries, bool enable_gpu_tracing)
Definition: context_gles.cc:21
The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about.
Definition: reactor_gles.h:57
TEST(AllocationSizeTest, CanCreateTypedAllocations)
std::shared_ptr< ReactorGLES > reactor
std::shared_ptr< ContextGLES > context
std::shared_ptr< CommandBuffer > command_buffer
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:136
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...