Flutter Impeller
blit_command_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 <initializer_list>
6 #include <tuple>
7 
8 #include "flutter/testing/testing.h" // IWYU pragma: keep
9 #include "gtest/gtest.h"
10 #include "impeller/core/formats.h"
13 #include "impeller/renderer/backend/gles/test/mock_gles.h"
15 
16 namespace impeller {
17 namespace testing {
18 
19 using ::testing::_;
20 using ::testing::Return;
21 
22 class TestReactorGLES : public ReactorGLES {
23  public:
25  : ReactorGLES(std::make_unique<ProcTableGLES>(kMockResolverGLES)) {}
26 
27  ~TestReactorGLES() = default;
28 };
29 
30 class MockWorker final : public ReactorGLES::Worker {
31  public:
32  MockWorker() = default;
33 
34  // |ReactorGLES::Worker|
36  const ReactorGLES& reactor) const override {
37  return true;
38  }
39 };
40 
41 namespace {
42 
43 std::shared_ptr<TextureGLES> CreateTexture(
44  const std::shared_ptr<ReactorGLES>& reactor,
45  PixelFormat format) {
46  TextureDescriptor tex_desc;
47  tex_desc.format = format;
48  tex_desc.size = {10, 10};
49  tex_desc.usage = static_cast<TextureUsageMask>(TextureUsage::kRenderTarget);
50  auto texture = std::make_shared<TextureGLES>(reactor, tex_desc);
51  return texture;
52 }
53 
54 std::shared_ptr<DeviceBufferGLES> CreateBuffer(
55  const std::shared_ptr<ReactorGLES>& reactor) {
56  DeviceBufferDescriptor buffer_desc;
57  buffer_desc.size = 10 * 10 * 4;
58  buffer_desc.storage_mode = StorageMode::kHostVisible;
59  auto allocation = std::make_unique<Allocation>();
60  FML_CHECK(allocation->Truncate(Bytes(buffer_desc.size)));
61  auto buffer = std::make_shared<DeviceBufferGLES>(buffer_desc, reactor,
62  std::move(allocation));
63  return buffer;
64 }
65 
66 BlitCopyBufferToTextureCommandGLES CreateCopyBufferToTextureCommand(
67  const std::shared_ptr<DeviceBufferGLES>& source,
68  const std::shared_ptr<TextureGLES>& dest) {
69  BlitCopyBufferToTextureCommandGLES command;
70  command.source = DeviceBuffer::AsBufferView(source);
71  command.destination = dest;
72  command.destination_region =
73  IRect::MakeSize(dest->GetTextureDescriptor().size);
74  command.mip_level = 0;
75  command.slice = 0;
76  command.label = "TestBlit";
77  return command;
78 }
79 
80 BlitCopyTextureToBufferCommandGLES CreateCopyTextureToBufferCommand(
81  const std::shared_ptr<TextureGLES>& source,
82  const std::shared_ptr<DeviceBufferGLES>& dest) {
83  BlitCopyTextureToBufferCommandGLES command;
84  command.source = source;
85  command.destination = dest;
86  command.source_region = IRect::MakeSize(source->GetTextureDescriptor().size);
87  command.label = "TestBlit";
88  return command;
89 }
90 
91 } // namespace
92 
93 TEST(BlitCommandGLESTest, BlitCopyBufferToTextureCommandGLESRGBA) {
94  auto mock_gles_impl = std::make_unique<MockGLESImpl>();
95  auto& mock_gles_impl_ref = *mock_gles_impl;
96 
97  std::shared_ptr<MockGLES> mock_gl = MockGLES::Init(std::move(mock_gles_impl));
98  auto reactor = std::make_shared<TestReactorGLES>();
99  auto worker = std::make_shared<MockWorker>();
100  reactor->AddWorker(worker);
101 
102  // Dest texture with RGBA format.
103  std::shared_ptr<TextureGLES> dest_texture =
105  std::shared_ptr<DeviceBufferGLES> source_buffer = CreateBuffer(reactor);
107  CreateCopyBufferToTextureCommand(source_buffer, dest_texture);
108 
109  // Expect gl TexSubImage2D with GL_RGBA.
110  EXPECT_CALL(mock_gles_impl_ref,
111  TexSubImage2D(GL_TEXTURE_2D, _, _, _, _, _, GL_RGBA, _, _))
112  .Times(1);
113 
114  EXPECT_TRUE(command.Encode(*reactor));
115 }
116 
117 TEST(BlitCommandGLESTest, BlitCopyBufferToTextureCommandGLESBGRA) {
118  auto mock_gles_impl = std::make_unique<MockGLESImpl>();
119  auto& mock_gles_impl_ref = *mock_gles_impl;
120 
121  // Mock gl to support BGRA.
122  std::shared_ptr<MockGLES> mock_gl = MockGLES::Init(
123  std::move(mock_gles_impl),
124  std::vector<const char*>{"GL_EXT_texture_format_BGRA8888"});
125  auto reactor = std::make_shared<TestReactorGLES>();
126  auto worker = std::make_shared<MockWorker>();
127  reactor->AddWorker(worker);
128 
129  // Dest texture with BGRA format.
130  std::shared_ptr<TextureGLES> dest_texture =
132  std::shared_ptr<DeviceBufferGLES> source_buffer = CreateBuffer(reactor);
134  CreateCopyBufferToTextureCommand(source_buffer, dest_texture);
135 
136  // Expect gl TexSubImage2D with GL_BGRA_EXT.
137  EXPECT_CALL(mock_gles_impl_ref,
138  TexSubImage2D(GL_TEXTURE_2D, _, _, _, _, _, GL_BGRA_EXT, _, _))
139  .Times(1);
140 
141  EXPECT_TRUE(command.Encode(*reactor));
142 }
143 
144 // This test makes sure we bind to GL_FRAMEBUFFER so that it's compatible for
145 // OpenGLES 2 and OpenGLES 3.
146 TEST(BlitCommandGLESTest, BlitCopyTextureToBufferCommandGLESBindsFramebuffer) {
147  auto mock_gles_impl = std::make_unique<MockGLESImpl>();
148  auto& mock_gles_impl_ref = *mock_gles_impl;
149 
150  EXPECT_CALL(mock_gles_impl_ref, GenFramebuffers(1, _))
151  .WillOnce(::testing::SetArgPointee<1>(3));
152  EXPECT_CALL(mock_gles_impl_ref, GenTextures(1, _))
153  .WillOnce(::testing::SetArgPointee<1>(1));
154  EXPECT_CALL(mock_gles_impl_ref, BindFramebuffer(GL_FRAMEBUFFER, 3)).Times(1);
155  EXPECT_CALL(mock_gles_impl_ref, CheckFramebufferStatus(GL_FRAMEBUFFER))
156  .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE));
157  EXPECT_CALL(mock_gles_impl_ref, ReadPixels(_, _, _, _, _, _, _)).Times(1);
158  EXPECT_CALL(mock_gles_impl_ref, BindFramebuffer(GL_FRAMEBUFFER, 0)).Times(1);
159 
160  std::shared_ptr<MockGLES> mock_gl = MockGLES::Init(std::move(mock_gles_impl));
161  auto reactor = std::make_shared<TestReactorGLES>();
162  auto worker = std::make_shared<MockWorker>();
163  reactor->AddWorker(worker);
164 
165  std::shared_ptr<TextureGLES> source_texture =
167  std::shared_ptr<DeviceBufferGLES> dest_buffer = CreateBuffer(reactor);
168 
169  ASSERT_TRUE(reactor->React());
170 
172  CreateCopyTextureToBufferCommand(source_texture, dest_buffer);
173 
174  EXPECT_TRUE(command.Encode(*reactor));
175 
176  source_texture.reset();
177  dest_buffer.reset();
178 
179  ASSERT_TRUE(reactor->React());
180 }
181 
182 TEST(BlitCommandGLESTest, BlitCopyTextureToBufferCommandGLESRGBA) {
183  auto mock_gles_impl = std::make_unique<MockGLESImpl>();
184  auto& mock_gles_impl_ref = *mock_gles_impl;
185 
186  std::shared_ptr<MockGLES> mock_gl = MockGLES::Init(std::move(mock_gles_impl));
187  auto reactor = std::make_shared<TestReactorGLES>();
188  auto worker = std::make_shared<MockWorker>();
189  reactor->AddWorker(worker);
190 
191  // Source texture with RGBA format.
192  std::shared_ptr<TextureGLES> source_texture =
194  std::shared_ptr<DeviceBufferGLES> dest_buffer = CreateBuffer(reactor);
196  CreateCopyTextureToBufferCommand(source_texture, dest_buffer);
197 
198  EXPECT_CALL(mock_gles_impl_ref, CheckFramebufferStatus(_))
199  .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE));
200  // Expect gl ReadPixels with GL_RGBA.
201  EXPECT_CALL(mock_gles_impl_ref, ReadPixels(_, _, _, _, GL_RGBA, _, _))
202  .Times(1);
203 
204  EXPECT_TRUE(command.Encode(*reactor));
205 }
206 
207 TEST(BlitCommandGLESTest, BlitCopyTextureToBufferCommandGLESBGRA) {
208  auto mock_gles_impl = std::make_unique<MockGLESImpl>();
209  auto& mock_gles_impl_ref = *mock_gles_impl;
210 
211  // Mock gl to support BGRA.
212  std::shared_ptr<MockGLES> mock_gl = MockGLES::Init(
213  std::move(mock_gles_impl),
214  std::vector<const char*>{"GL_EXT_texture_format_BGRA8888"});
215  auto reactor = std::make_shared<TestReactorGLES>();
216  auto worker = std::make_shared<MockWorker>();
217  reactor->AddWorker(worker);
218 
219  // Source texture with BGRA format.
220  std::shared_ptr<TextureGLES> source_texture =
222  std::shared_ptr<DeviceBufferGLES> dest_buffer = CreateBuffer(reactor);
224  CreateCopyTextureToBufferCommand(source_texture, dest_buffer);
225 
226  EXPECT_CALL(mock_gles_impl_ref, CheckFramebufferStatus(_))
227  .WillOnce(Return(GL_FRAMEBUFFER_COMPLETE));
228  // Expect gl ReadPixels with GL_BGRA_EXT.
229  EXPECT_CALL(mock_gles_impl_ref, ReadPixels(_, _, _, _, GL_BGRA_EXT, _, _))
230  .Times(1);
231 
232  EXPECT_TRUE(command.Encode(*reactor));
233 }
234 
235 TEST(BlitCommandGLESTest,
236  BlitCopyTextureToBufferCommandGLESUnsupportedPixelFormats) {
237  auto mock_gles_impl = std::make_unique<MockGLESImpl>();
238  auto& mock_gles_impl_ref = *mock_gles_impl;
239 
240  std::shared_ptr<MockGLES> mock_gl = MockGLES::Init(std::move(mock_gles_impl));
241  auto reactor = std::make_shared<TestReactorGLES>();
242  auto worker = std::make_shared<MockWorker>();
243  reactor->AddWorker(worker);
244 
245  std::shared_ptr<DeviceBufferGLES> dest_buffer = CreateBuffer(reactor);
246 
247  std::shared_ptr<TextureGLES> source_texture_D32FloatS8Uint =
249  BlitCopyTextureToBufferCommandGLES command_for_D32FloatS8Uint =
250  CreateCopyTextureToBufferCommand(source_texture_D32FloatS8Uint,
251  dest_buffer);
252 
253  std::shared_ptr<TextureGLES> source_texture_R8G8UNormInt =
255  BlitCopyTextureToBufferCommandGLES command_for_R8G8UNormInt =
256  CreateCopyTextureToBufferCommand(source_texture_R8G8UNormInt,
257  dest_buffer);
258 
259  EXPECT_CALL(mock_gles_impl_ref, CheckFramebufferStatus(_)).Times(0);
260 
261  // GL does not support texture with an unsupported pixel format.
262  EXPECT_FALSE(command_for_D32FloatS8Uint.Encode(*reactor));
263 
264  // GL does not support texture with another unsupported pixel format.
265  EXPECT_FALSE(command_for_R8G8UNormInt.Encode(*reactor));
266 }
267 
268 namespace {
269 
270 std::shared_ptr<TextureGLES> CreateMipTexture(
271  const std::shared_ptr<ReactorGLES>& reactor,
272  PixelFormat format,
273  ISize size,
274  size_t mip_count,
276  TextureDescriptor tex_desc;
277  tex_desc.format = format;
278  tex_desc.size = size;
279  tex_desc.mip_count = mip_count;
280  tex_desc.type = type;
281  tex_desc.usage = static_cast<TextureUsageMask>(TextureUsage::kRenderTarget);
282  auto texture = std::make_shared<TextureGLES>(reactor, tex_desc);
283  return texture;
284 }
285 
286 std::shared_ptr<DeviceBufferGLES> CreateMipBuffer(
287  const std::shared_ptr<ReactorGLES>& reactor,
288  size_t size_bytes) {
289  DeviceBufferDescriptor buffer_desc;
290  buffer_desc.size = size_bytes;
291  buffer_desc.storage_mode = StorageMode::kHostVisible;
292  auto allocation = std::make_unique<Allocation>();
293  FML_CHECK(allocation->Truncate(Bytes(buffer_desc.size)));
294  return std::make_shared<DeviceBufferGLES>(buffer_desc, reactor,
295  std::move(allocation));
296 }
297 
298 } // namespace
299 
300 // An upload to mip 0 of a multi-mip texture should allocate ONLY level 0,
301 // preserving Impeller's snapshot path (which renders into level 0 and then
302 // uses glGenerateMipmap to fill the rest).
303 TEST(BlitCommandGLESTest,
304  BlitCopyBufferToTextureCommandAllocatesOnlyTheRequestedBaseMip) {
305  auto mock_gles_impl = std::make_unique<MockGLESImpl>();
306  auto& mock_gles_impl_ref = *mock_gles_impl;
307  std::shared_ptr<MockGLES> mock_gl = MockGLES::Init(std::move(mock_gles_impl));
308  auto reactor = std::make_shared<TestReactorGLES>();
309  auto worker = std::make_shared<MockWorker>();
310  reactor->AddWorker(worker);
311 
312  auto dest = CreateMipTexture(reactor, PixelFormat::kR8G8B8A8UNormInt,
313  ISize{8, 8}, /*mip_count=*/3);
314  auto source = CreateMipBuffer(reactor, 8 * 8 * 4);
315 
317  command.source = DeviceBuffer::AsBufferView(source);
318  command.destination = dest;
319  command.destination_region = IRect::MakeSize(ISize{8, 8});
320  command.mip_level = 0;
321  command.slice = 0;
322  command.label = "TestBlit";
323 
324  EXPECT_CALL(mock_gles_impl_ref,
325  TexImage2D(GL_TEXTURE_2D, 0, _, 8, 8, _, _, _, nullptr))
326  .Times(1);
327  // Higher mip levels must NOT be allocated by a level-0 upload.
328  EXPECT_CALL(mock_gles_impl_ref,
329  TexImage2D(GL_TEXTURE_2D, 1, _, _, _, _, _, _, nullptr))
330  .Times(0);
331  EXPECT_CALL(mock_gles_impl_ref,
332  TexImage2D(GL_TEXTURE_2D, 2, _, _, _, _, _, _, nullptr))
333  .Times(0);
334  EXPECT_CALL(mock_gles_impl_ref,
335  TexSubImage2D(GL_TEXTURE_2D, 0, _, _, 8, 8, _, _, _))
336  .Times(1);
337 
338  EXPECT_TRUE(command.Encode(*reactor));
339 }
340 
341 // Regression test for the Flutter GPU multi-mip case: when the very first
342 // upload targets a non-zero mip, that level must be allocated by a
343 // glTexImage2D call before glTexSubImage2D, otherwise GLES raises
344 // GL_INVALID_OPERATION. Only the requested level should be allocated; lower
345 // or higher levels stay untouched until they're written themselves.
346 TEST(BlitCommandGLESTest,
347  BlitCopyBufferToTextureCommandAllocatesNonZeroMipLevelOnFirstUpload) {
348  auto mock_gles_impl = std::make_unique<MockGLESImpl>();
349  auto& mock_gles_impl_ref = *mock_gles_impl;
350  std::shared_ptr<MockGLES> mock_gl = MockGLES::Init(std::move(mock_gles_impl));
351  auto reactor = std::make_shared<TestReactorGLES>();
352  auto worker = std::make_shared<MockWorker>();
353  reactor->AddWorker(worker);
354 
355  auto dest = CreateMipTexture(reactor, PixelFormat::kR8G8B8A8UNormInt,
356  ISize{8, 8}, /*mip_count=*/3);
357  auto source = CreateMipBuffer(reactor, 4 * 4 * 4);
358 
360  command.source = DeviceBuffer::AsBufferView(source);
361  command.destination = dest;
362  command.destination_region = IRect::MakeXYWH(0, 0, 4, 4);
363  command.mip_level = 1;
364  command.slice = 0;
365  command.label = "TestBlit";
366 
367  // Only level 1 is allocated, and at the halved 4x4 size.
368  EXPECT_CALL(mock_gles_impl_ref,
369  TexImage2D(GL_TEXTURE_2D, 1, _, 4, 4, _, _, _, nullptr))
370  .Times(1);
371  EXPECT_CALL(mock_gles_impl_ref,
372  TexImage2D(GL_TEXTURE_2D, 0, _, _, _, _, _, _, nullptr))
373  .Times(0);
374  EXPECT_CALL(mock_gles_impl_ref,
375  TexImage2D(GL_TEXTURE_2D, 2, _, _, _, _, _, _, nullptr))
376  .Times(0);
377  EXPECT_CALL(mock_gles_impl_ref,
378  TexSubImage2D(GL_TEXTURE_2D, 1, _, _, 4, 4, _, _, _))
379  .Times(1);
380 
381  EXPECT_TRUE(command.Encode(*reactor));
382 }
383 
384 // Three uploads to mips 0/1/2 of a multi-mip texture each allocate exactly
385 // their own level. This is the same total GL work as the eager approach, but
386 // split across the per-level encodes instead of batched on the first one,
387 // and is the path the new Flutter GPU `Texture.overwrite(mipLevel: ...)` API
388 // exercises.
389 TEST(BlitCommandGLESTest,
390  BlitCopyBufferToTextureCommandAllocatesEachMipLevelOnFirstWrite) {
391  auto mock_gles_impl = std::make_unique<MockGLESImpl>();
392  auto& mock_gles_impl_ref = *mock_gles_impl;
393  std::shared_ptr<MockGLES> mock_gl = MockGLES::Init(std::move(mock_gles_impl));
394  auto reactor = std::make_shared<TestReactorGLES>();
395  auto worker = std::make_shared<MockWorker>();
396  reactor->AddWorker(worker);
397 
398  auto dest = CreateMipTexture(reactor, PixelFormat::kR8G8B8A8UNormInt,
399  ISize{8, 8}, /*mip_count=*/3);
400 
401  // Each level needs its own correctly-sized source buffer.
402  auto source0 = CreateMipBuffer(reactor, 8 * 8 * 4);
403  auto source1 = CreateMipBuffer(reactor, 4 * 4 * 4);
404  auto source2 = CreateMipBuffer(reactor, 2 * 2 * 4);
405 
406  EXPECT_CALL(mock_gles_impl_ref,
407  TexImage2D(GL_TEXTURE_2D, 0, _, 8, 8, _, _, _, nullptr))
408  .Times(1);
409  EXPECT_CALL(mock_gles_impl_ref,
410  TexImage2D(GL_TEXTURE_2D, 1, _, 4, 4, _, _, _, nullptr))
411  .Times(1);
412  EXPECT_CALL(mock_gles_impl_ref,
413  TexImage2D(GL_TEXTURE_2D, 2, _, 2, 2, _, _, _, nullptr))
414  .Times(1);
415  EXPECT_CALL(mock_gles_impl_ref,
416  TexSubImage2D(GL_TEXTURE_2D, 0, _, _, 8, 8, _, _, _))
417  .Times(1);
418  EXPECT_CALL(mock_gles_impl_ref,
419  TexSubImage2D(GL_TEXTURE_2D, 1, _, _, 4, 4, _, _, _))
420  .Times(1);
421  EXPECT_CALL(mock_gles_impl_ref,
422  TexSubImage2D(GL_TEXTURE_2D, 2, _, _, 2, 2, _, _, _))
423  .Times(1);
424 
425  for (const auto& [level, w, source] : std::initializer_list<
426  std::tuple<uint32_t, int32_t, std::shared_ptr<DeviceBufferGLES>>>{
427  {0, 8, source0}, {1, 4, source1}, {2, 2, source2}}) {
429  command.source = DeviceBuffer::AsBufferView(source);
430  command.destination = dest;
431  command.destination_region = IRect::MakeXYWH(0, 0, w, w);
432  command.mip_level = level;
433  command.slice = 0;
434  command.label = "TestBlit";
435  EXPECT_TRUE(command.Encode(*reactor));
436  }
437 }
438 
439 // A second upload to the same `(slice, mip_level)` must not re-issue
440 // glTexImage2D; the per-(slice, mip) bit in TextureGLES guards it.
441 TEST(BlitCommandGLESTest,
442  BlitCopyBufferToTextureCommandDoesNotReallocateOnSubsequentUpload) {
443  auto mock_gles_impl = std::make_unique<MockGLESImpl>();
444  auto& mock_gles_impl_ref = *mock_gles_impl;
445  std::shared_ptr<MockGLES> mock_gl = MockGLES::Init(std::move(mock_gles_impl));
446  auto reactor = std::make_shared<TestReactorGLES>();
447  auto worker = std::make_shared<MockWorker>();
448  reactor->AddWorker(worker);
449 
450  auto dest = CreateMipTexture(reactor, PixelFormat::kR8G8B8A8UNormInt,
451  ISize{4, 4}, /*mip_count=*/2);
452  auto source = CreateMipBuffer(reactor, 4 * 4 * 4);
453 
455  command.source = DeviceBuffer::AsBufferView(source);
456  command.destination = dest;
457  command.destination_region = IRect::MakeSize(ISize{4, 4});
458  command.mip_level = 0;
459  command.slice = 0;
460  command.label = "TestBlit";
461 
462  // Across both encodes, only the first allocates level 0.
463  EXPECT_CALL(mock_gles_impl_ref,
464  TexImage2D(GL_TEXTURE_2D, 0, _, 4, 4, _, _, _, nullptr))
465  .Times(1);
466  EXPECT_CALL(mock_gles_impl_ref,
467  TexImage2D(GL_TEXTURE_2D, 1, _, _, _, _, _, _, nullptr))
468  .Times(0);
469  EXPECT_CALL(mock_gles_impl_ref,
470  TexSubImage2D(GL_TEXTURE_2D, 0, _, _, _, _, _, _, _))
471  .Times(2);
472 
473  EXPECT_TRUE(command.Encode(*reactor));
474  EXPECT_TRUE(command.Encode(*reactor));
475 }
476 
477 // For a cubemap, allocation must target the per-face cubemap target
478 // (`GL_TEXTURE_CUBE_MAP_POSITIVE_X + slice`) rather than `GL_TEXTURE_2D`,
479 // and only the requested `(face, mip_level)` is allocated by a single
480 // upload.
481 TEST(BlitCommandGLESTest,
482  BlitCopyBufferToTextureCommandUsesCubemapFaceTargetForCubemap) {
483  auto mock_gles_impl = std::make_unique<MockGLESImpl>();
484  auto& mock_gles_impl_ref = *mock_gles_impl;
485  std::shared_ptr<MockGLES> mock_gl = MockGLES::Init(std::move(mock_gles_impl));
486  auto reactor = std::make_shared<TestReactorGLES>();
487  auto worker = std::make_shared<MockWorker>();
488  reactor->AddWorker(worker);
489 
490  auto dest =
491  CreateMipTexture(reactor, PixelFormat::kR8G8B8A8UNormInt, ISize{4, 4},
492  /*mip_count=*/2, TextureType::kTextureCube);
493  auto source = CreateMipBuffer(reactor, 4 * 4 * 4);
494 
496  command.source = DeviceBuffer::AsBufferView(source);
497  command.destination = dest;
498  command.destination_region = IRect::MakeSize(ISize{4, 4});
499  command.mip_level = 0;
500  command.slice = 2; // GL_TEXTURE_CUBE_MAP_POSITIVE_Z
501  command.label = "TestBlit";
502 
503  const GLenum face_target = GL_TEXTURE_CUBE_MAP_POSITIVE_X + 2;
504 
505  // The bind target is the cubemap parent, even though allocation/upload
506  // calls use the per-face target.
507  EXPECT_CALL(mock_gles_impl_ref, BindTexture(GL_TEXTURE_CUBE_MAP, _)).Times(1);
508  EXPECT_CALL(mock_gles_impl_ref,
509  TexImage2D(face_target, 0, _, 4, 4, _, _, _, nullptr))
510  .Times(1);
511  // Higher mips for this face are not allocated by a level-0 upload.
512  EXPECT_CALL(mock_gles_impl_ref,
513  TexImage2D(face_target, 1, _, _, _, _, _, _, nullptr))
514  .Times(0);
515  // No other face is touched.
516  EXPECT_CALL(mock_gles_impl_ref, TexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, _,
517  _, _, _, _, _, _, nullptr))
518  .Times(0);
519  EXPECT_CALL(mock_gles_impl_ref,
520  TexImage2D(GL_TEXTURE_2D, _, _, _, _, _, _, _, nullptr))
521  .Times(0);
522  EXPECT_CALL(mock_gles_impl_ref,
523  TexSubImage2D(face_target, 0, _, _, 4, 4, _, _, _))
524  .Times(1);
525 
526  EXPECT_TRUE(command.Encode(*reactor));
527 }
528 
529 } // namespace testing
530 } // namespace impeller
static BufferView AsBufferView(std::shared_ptr< DeviceBuffer > buffer)
Create a buffer view of this entire buffer.
A delegate implemented by a thread on which an OpenGL context is current. There may be multiple worke...
Definition: reactor_gles.h:69
The reactor attempts to make thread-safe usage of OpenGL ES easier to reason about.
Definition: reactor_gles.h:57
bool CanReactorReactOnCurrentThreadNow(const ReactorGLES &reactor) const override
Determines the ability of the worker to service a reaction on the current thread. The OpenGL context ...
TEST(AllocationSizeTest, CanCreateTypedAllocations)
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:99
TextureType
Definition: formats.h:450
Mask< TextureUsage > TextureUsageMask
Definition: formats.h:496
std::shared_ptr< Texture > CreateTexture(const TextureDescriptor &texture_descriptor, const std::vector< uint8_t > &data, const std::shared_ptr< impeller::Context > &context, std::string_view debug_label)
Definition: texture_util.cc:11
Definition: comparable.h:93
std::shared_ptr< ReactorGLES > reactor
std::shared_ptr< MockGLES > mock_gl
bool Encode(const ReactorGLES &reactor) const override
std::shared_ptr< Texture > destination
Definition: blit_command.h:40
bool Encode(const ReactorGLES &reactor) const override
constexpr static TRect MakeXYWH(Type x, Type y, Type width, Type height)
Definition: rect.h:136
constexpr static TRect MakeSize(const TSize< U > &size)
Definition: rect.h:150
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...