Flutter Impeller
render_pass_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 <memory>
6 #include "flutter/testing/testing.h" // IWYU pragma: keep
7 #include "gmock/gmock.h"
8 #include "gtest/gtest.h"
14 #include "impeller/renderer/backend/gles/test/mock_gles.h"
19 
20 namespace impeller {
21 namespace testing {
22 
23 using ::testing::_;
24 using ::testing::Args;
25 using ::testing::ElementsAreArray;
26 using ::testing::NiceMock;
27 using ::testing::Return;
28 using ::testing::SetArgPointee;
29 using ::testing::TestWithParam;
30 
31 class TestReactorGLES : public ReactorGLES {
32  public:
34  : ReactorGLES(std::make_unique<ProcTableGLES>(kMockResolverGLES)) {}
35 
36  ~TestReactorGLES() = default;
37 };
38 
39 class MockWorker final : public ReactorGLES::Worker {
40  public:
41  MockWorker() = default;
42 
43  // |ReactorGLES::Worker|
45  const ReactorGLES& reactor) const override {
46  return true;
47  }
48 };
49 
52  std::array<GLenum, 3> expected_attachments;
53 };
54 
56  : public TestWithParam<DiscardFrameBufferParams> {};
57 
58 namespace {
59 std::shared_ptr<ContextGLES> CreateFakeGLESContext() {
60  auto dummy_gl_procs = std::make_unique<ProcTableGLES>(kMockResolverGLES);
61  auto dummy_shader_library = std::vector<std::shared_ptr<fml::Mapping>>{};
62  auto flags = Flags{};
63  return ContextGLES::Create(flags, std::move(dummy_gl_procs),
64  dummy_shader_library, false);
65 }
66 } // namespace
67 
69  auto mock_gl_impl = std::make_unique<NiceMock<MockGLESImpl>>();
70  auto& mock_gl_impl_ref = *mock_gl_impl;
71  auto mock_gl =
72  MockGLES::Init(std::move(mock_gl_impl), {{"GL_EXT_discard_framebuffer"}},
73  "OpenGL ES 2.0");
74 
75  auto context = CreateFakeGLESContext();
76  auto dummy_worker = std::make_shared<MockWorker>();
77  context->AddReactorWorker(dummy_worker);
78  auto reactor = context->GetReactor();
79 
80  const auto command_buffer =
81  std::static_pointer_cast<Context>(context)->CreateCommandBuffer();
82  auto render_target = RenderTarget{};
83  const auto description = TextureDescriptor{
84  .format = PixelFormat::kR8G8B8A8UNormInt, .size = {10, 10}};
85 
86  const auto& test_params = GetParam();
87  auto framebuffer_texture =
88  TextureGLES::WrapFBO(reactor, description, test_params.frame_buffer_id);
89 
90  auto color_attachment = ColorAttachment{Attachment{
91  .texture = framebuffer_texture, .store_action = StoreAction::kDontCare}};
92  render_target.SetColorAttachment(color_attachment, 0);
93  const auto render_pass = command_buffer->CreateRenderPass(render_target);
94 
95  EXPECT_CALL(mock_gl_impl_ref, GetIntegerv(GL_FRAMEBUFFER_BINDING, _))
96  .WillOnce(SetArgPointee<1>(test_params.frame_buffer_id));
97 
98  EXPECT_CALL(mock_gl_impl_ref, DiscardFramebufferEXT(GL_FRAMEBUFFER, _, _))
99  .With(Args<2, 1>(ElementsAreArray(test_params.expected_attachments)))
100  .Times(1);
101  ASSERT_TRUE(render_pass->EncodeCommands());
102  ASSERT_TRUE(reactor->React());
103 }
104 
106  FrameBufferObject,
108  ::testing::ValuesIn(std::vector<DiscardFrameBufferParams>{
109  {.frame_buffer_id = 0,
110  .expected_attachments = {GL_COLOR_EXT, GL_DEPTH_EXT, GL_STENCIL_EXT}},
111  {.frame_buffer_id = 1,
112  .expected_attachments = {GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT,
113  GL_STENCIL_ATTACHMENT}}}),
114  [](const ::testing::TestParamInfo<DiscardFrameBufferParams>& info) {
115  return (info.param.frame_buffer_id == 0) ? "Default" : "NonDefault";
116  });
117 
119  auto mock_gl_impl = std::make_unique<NiceMock<MockGLESImpl>>();
120  auto& mock_gl_impl_ref = *mock_gl_impl;
121  auto mock_gl =
122  MockGLES::Init(std::move(mock_gl_impl), std::nullopt, "OpenGL ES 3.0");
123 
124  auto context = CreateFakeGLESContext();
125  auto dummy_worker = std::make_shared<MockWorker>();
126  context->AddReactorWorker(dummy_worker);
127  auto reactor = context->GetReactor();
128 
129  const auto command_buffer =
130  std::static_pointer_cast<Context>(context)->CreateCommandBuffer();
131  auto render_target = RenderTarget{};
132  const auto description = TextureDescriptor{
133  .format = PixelFormat::kR8G8B8A8UNormInt, .size = {10, 10}};
134 
135  const auto& test_params = GetParam();
136  auto framebuffer_texture =
137  TextureGLES::WrapFBO(reactor, description, test_params.frame_buffer_id);
138 
139  auto color_attachment = ColorAttachment{Attachment{
140  .texture = framebuffer_texture, .store_action = StoreAction::kDontCare}};
141  render_target.SetColorAttachment(color_attachment, 0);
142  const auto render_pass = command_buffer->CreateRenderPass(render_target);
143 
144  EXPECT_CALL(mock_gl_impl_ref, GetIntegerv(GL_FRAMEBUFFER_BINDING, _))
145  .WillOnce(SetArgPointee<1>(test_params.frame_buffer_id));
146 
147  // InvalidateFramebuffer should be called instead of DiscardFramebufferEXT
148  EXPECT_CALL(mock_gl_impl_ref, InvalidateFramebuffer(GL_FRAMEBUFFER, _, _))
149  .With(Args<2, 1>(ElementsAreArray(test_params.expected_attachments)))
150  .Times(1);
151  EXPECT_CALL(mock_gl_impl_ref, DiscardFramebufferEXT(GL_FRAMEBUFFER, _, _))
152  .Times(0);
153 
154  ASSERT_TRUE(render_pass->EncodeCommands());
155  ASSERT_TRUE(reactor->React());
156 }
157 
158 TEST(RenderPassGLESTest, ResolvingMultisampleTextureCachesResolveFBO) {
159  auto mock_gl_impl = std::make_unique<NiceMock<MockGLESImpl>>();
160  auto& mock_gl_impl_ref = *mock_gl_impl;
161  // Make sure implicit resolving isn't supported so we go down explicit path.
162  auto mock_gl =
163  MockGLES::Init(std::move(mock_gl_impl), std::nullopt, "OpenGL ES 3.0");
164 
165  auto context = CreateFakeGLESContext();
166  auto dummy_worker = std::make_shared<MockWorker>();
167  context->AddReactorWorker(dummy_worker);
168  auto reactor = context->GetReactor();
169 
170  const auto command_buffer =
171  std::static_pointer_cast<Context>(context)->CreateCommandBuffer();
172 
173  const auto msaa_desc =
176  .size = {10, 10},
178  .sample_count = SampleCount::kCount4};
179  const auto resolve_desc =
181  .type = TextureType::kTexture2D,
183  .size = {10, 10},
185  .sample_count = SampleCount::kCount1};
186 
187  auto msaa_tex = std::make_shared<TextureGLES>(reactor, msaa_desc);
188  auto resolve_tex = std::make_shared<TextureGLES>(reactor, resolve_desc);
189 
190  auto render_target = RenderTarget{};
191  auto color_attachment = ColorAttachment{Attachment{
192  .texture = msaa_tex,
193  .resolve_texture = resolve_tex,
194  .load_action = LoadAction::kClear,
195  .store_action = StoreAction::kMultisampleResolve,
196  }};
197  color_attachment.clear_color = Color::Black();
198  render_target.SetColorAttachment(color_attachment, 0);
199 
200  EXPECT_CALL(mock_gl_impl_ref, CheckFramebufferStatus(_))
201  .WillRepeatedly(Return(GL_FRAMEBUFFER_COMPLETE));
202 
203  // Expect GenFramebuffers is called exactly once for the offscreen FBO,
204  // and exactly once for the resolve FBO over two passes.
205  EXPECT_CALL(mock_gl_impl_ref, GenFramebuffers(_, _)).Times(2);
206 
207  {
208  const auto render_pass = command_buffer->CreateRenderPass(render_target);
209  ASSERT_TRUE(render_pass->EncodeCommands());
210  ASSERT_TRUE(reactor->React());
211  }
212  {
213  const auto render_pass2 = command_buffer->CreateRenderPass(render_target);
214  ASSERT_TRUE(render_pass2->EncodeCommands());
215  ASSERT_TRUE(reactor->React());
216  }
217 }
218 
219 } // namespace testing
220 } // 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
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
static std::shared_ptr< TextureGLES > WrapFBO(std::shared_ptr< ReactorGLES > reactor, TextureDescriptor desc, GLuint fbo)
Create a texture by wrapping an external framebuffer object whose lifecycle is owned by the caller.
Definition: texture_gles.cc:78
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)
TEST_P(AiksTest, DrawAtlasNoColor)
INSTANTIATE_TEST_SUITE_P(FrameBufferObject, RenderPassGLESWithDiscardFrameBufferExtTest, ::testing::ValuesIn(std::vector< DiscardFrameBufferParams >{ {.frame_buffer_id=0,.expected_attachments={GL_COLOR_EXT, GL_DEPTH_EXT, GL_STENCIL_EXT}}, {.frame_buffer_id=1,.expected_attachments={GL_COLOR_ATTACHMENT0, GL_DEPTH_ATTACHMENT, GL_STENCIL_ATTACHMENT}}}), [](const ::testing::TestParamInfo< DiscardFrameBufferParams > &info) { return(info.param.frame_buffer_id==0) ? "Default" :"NonDefault";})
Definition: comparable.h:93
std::shared_ptr< Texture > texture
Definition: formats.h:661
static constexpr Color Black()
Definition: color.h:266
A lightweight object that describes the attributes of a texture that can then used an allocator to cr...