Flutter Impeller
context.h
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 #ifndef FLUTTER_IMPELLER_RENDERER_CONTEXT_H_
6 #define FLUTTER_IMPELLER_RENDERER_CONTEXT_H_
7 
8 #include <future>
9 #include <memory>
10 #include <string>
11 
12 #include "fml/closure.h"
13 #include "impeller/base/flags.h"
16 #include "impeller/core/formats.h"
20 
21 namespace flutter::testing {
22 class DlSurfaceInstanceImpeller;
23 }
24 
25 namespace impeller {
26 
27 class ShaderLibrary;
28 class CommandBuffer;
29 class PipelineLibrary;
30 
31 /// A wrapper for provided a deferred initialization of impeller to various
32 /// engine subsystems.
34  public:
35  explicit ImpellerContextFuture(
36  std::future<std::shared_ptr<impeller::Context>> context);
37 
38  std::shared_ptr<impeller::Context> GetContext();
39 
40  private:
41  std::mutex mutex_;
42  std::future<std::shared_ptr<impeller::Context>> future_;
43  std::shared_ptr<impeller::Context> context_;
44  bool did_wait_ = false;
45 };
46 
47 //------------------------------------------------------------------------------
48 /// @brief To do anything rendering related with Impeller, you need a
49 /// context.
50 ///
51 /// Contexts are expensive to construct and typically you only need
52 /// one in the process. The context represents a connection to a
53 /// graphics or compute accelerator on the device.
54 ///
55 /// If there are multiple context in a process, it would typically
56 /// be for separation of concerns (say, use with multiple engines in
57 /// Flutter), talking to multiple accelerators, or talking to the
58 /// same accelerator using different client APIs (Metal, Vulkan,
59 /// OpenGL ES, etc..).
60 ///
61 /// Contexts are thread-safe. They may be created, used, and
62 /// collected (though not from a thread used by an internal pool) on
63 /// any thread. They may also be accessed simultaneously from
64 /// multiple threads.
65 ///
66 /// Contexts are abstract and a concrete instance must be created
67 /// using one of the subclasses of `Context` in
68 /// `//impeller/renderer/backend`.
69 class Context {
70  public:
71  enum class BackendType {
72  kMetal,
73  kOpenGLES,
74  kVulkan,
75  };
76 
77  /// The maximum number of tasks that should ever be stored for
78  /// `StoreTaskForGPU`.
79  ///
80  /// This number was arbitrarily chosen. The idea is that this is a somewhat
81  /// rare situation where tasks happen to get executed in that tiny amount of
82  /// time while an app is being backgrounded but still executing.
83  static constexpr int32_t kMaxTasksAwaitingGPU = 1024;
84 
85  //----------------------------------------------------------------------------
86  /// @brief Destroys an Impeller context.
87  ///
88  virtual ~Context();
89 
90  //----------------------------------------------------------------------------
91  /// @brief Get the graphics backend of an Impeller context.
92  ///
93  /// This is useful for cases where a renderer needs to track and
94  /// lookup backend-specific resources, like shaders or uniform
95  /// layout information.
96  ///
97  /// It's not recommended to use this as a substitute for
98  /// per-backend capability checking. Instead, check for specific
99  /// capabilities via `GetCapabilities()`.
100  ///
101  /// @return The graphics backend of the `Context`.
102  ///
103  virtual BackendType GetBackendType() const = 0;
104 
105  // TODO(129920): Refactor and move to capabilities.
106  virtual std::string DescribeGpuModel() const = 0;
107 
108  //----------------------------------------------------------------------------
109  /// @brief Determines if a context is valid. If the caller ever receives
110  /// an invalid context, they must discard it and construct a new
111  /// context. There is no recovery mechanism to repair a bad
112  /// context.
113  ///
114  /// It is convention in Impeller to never return an invalid
115  /// context from a call that returns an pointer to a context. The
116  /// call implementation performs validity checks itself and return
117  /// a null context instead of a pointer to an invalid context.
118  ///
119  /// How a context goes invalid is backend specific. It could
120  /// happen due to device loss, or any other unrecoverable error.
121  ///
122  /// @return If the context is valid.
123  ///
124  virtual bool IsValid() const = 0;
125 
126  //----------------------------------------------------------------------------
127  /// @brief Get the capabilities of Impeller context. All optionally
128  /// supported feature of the platform, client-rendering API, and
129  /// device can be queried using the `Capabilities`.
130  ///
131  /// @return The capabilities. Can never be `nullptr` for a valid context.
132  ///
133  virtual const std::shared_ptr<const Capabilities>& GetCapabilities()
134  const = 0;
135 
136  // TODO(129920): Refactor and move to capabilities.
137  virtual bool UpdateOffscreenLayerPixelFormat(PixelFormat format);
138 
139  //----------------------------------------------------------------------------
140  /// @brief Returns the allocator used to create textures and buffers on
141  /// the device.
142  ///
143  /// @return The resource allocator. Can never be `nullptr` for a valid
144  /// context.
145  ///
146  virtual std::shared_ptr<Allocator> GetResourceAllocator() const = 0;
147 
148  //----------------------------------------------------------------------------
149  /// @brief Returns the library of shaders used to specify the
150  /// programmable stages of a pipeline.
151  ///
152  /// @return The shader library. Can never be `nullptr` for a valid
153  /// context.
154  ///
155  virtual std::shared_ptr<ShaderLibrary> GetShaderLibrary() const = 0;
156 
157  //----------------------------------------------------------------------------
158  /// @brief Returns the library of combined image samplers used in
159  /// shaders.
160  ///
161  /// @return The sampler library. Can never be `nullptr` for a valid
162  /// context.
163  ///
164  virtual std::shared_ptr<SamplerLibrary> GetSamplerLibrary() const = 0;
165 
166  //----------------------------------------------------------------------------
167  /// @brief Returns the library of pipelines used by render or compute
168  /// commands.
169  ///
170  /// @return The pipeline library. Can never be `nullptr` for a valid
171  /// context.
172  ///
173  virtual std::shared_ptr<PipelineLibrary> GetPipelineLibrary() const = 0;
174 
175  //----------------------------------------------------------------------------
176  /// @brief Create a new command buffer. Command buffers can be used to
177  /// encode graphics, blit, or compute commands to be submitted to
178  /// the device.
179  ///
180  /// A command buffer can only be used on a single thread.
181  /// Multi-threaded render, blit, or compute passes must create a
182  /// new command buffer on each thread.
183  ///
184  /// @return A new command buffer.
185  ///
186  virtual std::shared_ptr<CommandBuffer> CreateCommandBuffer() const = 0;
187 
188  /// @brief Return the graphics queue for submitting command buffers.
189  virtual std::shared_ptr<CommandQueue> GetCommandQueue() const = 0;
190 
191  //----------------------------------------------------------------------------
192  /// @brief Force all pending asynchronous work to finish. This is
193  /// achieved by deleting all owned concurrent message loops.
194  ///
195  virtual void Shutdown() = 0;
196 
197  /// Stores a task on the `ContextMTL` that is awaiting access for the GPU.
198  ///
199  /// The task will be executed in the event that the GPU access has changed to
200  /// being available or that the task has been canceled. The task should
201  /// operate with the `SyncSwitch` to make sure the GPU is accessible.
202  ///
203  /// If the queue of pending tasks is cleared without GPU access, then the
204  /// failure callback will be invoked and the primary task function will not
205  ///
206  /// Threadsafe.
207  ///
208  /// `task` will be executed on the platform thread.
209  virtual void StoreTaskForGPU(const fml::closure& task,
210  const fml::closure& failure) {
211  FML_CHECK(false && "not supported in this context");
212  }
213 
214  /// Run backend specific additional setup and create common shader variants.
215  ///
216  /// This bootstrap is intended to improve the performance of several
217  /// first frame benchmarks that are tracked in the flutter device lab.
218  /// The workload includes initializing commonly used but not default
219  /// shader variants, as well as forcing driver initialization.
221 
222  /// Dispose resources that are cached on behalf of the current thread.
223  ///
224  /// Some backends such as Vulkan may cache resources that can be reused while
225  /// executing a rendering operation. This API can be called after the
226  /// operation completes in order to clear the cache.
228 
229  /// @brief Enqueue command_buffer for submission by the end of the frame.
230  ///
231  /// Certain backends may immediately flush the command buffer if batch
232  /// submission is not supported. This functionality is not thread safe
233  /// and should only be used via the ContentContext for rendering a
234  /// 2D workload.
235  ///
236  /// Returns true if submission has succeeded. If the buffer is enqueued
237  /// then no error may be returned until FlushCommandBuffers is called.
238  [[nodiscard]] virtual bool EnqueueCommandBuffer(
239  std::shared_ptr<CommandBuffer> command_buffer);
240 
241  /// @brief Flush all pending command buffers.
242  ///
243  /// Returns whether or not submission was successful. This functionality
244  /// is not threadsafe and should only be used via the ContentContext for
245  /// rendering a 2D workload.
246  [[nodiscard]] virtual bool FlushCommandBuffers();
247 
248  virtual bool AddTrackingFence(const std::shared_ptr<Texture>& texture) const;
249 
250  virtual std::shared_ptr<const IdleWaiter> GetIdleWaiter() const;
251 
252  //----------------------------------------------------------------------------
253  /// Resets any thread local state that may interfere with embedders.
254  ///
255  /// Today, only the OpenGL backend can trample on thread local state that the
256  /// embedder can access. This call puts the GL state in a sane "clean" state.
257  ///
258  /// Impeller itself is resilient to a dirty thread local state table.
259  ///
260  virtual void ResetThreadLocalState() const;
261 
262  /// @brief Retrieve the runtime stage for this context type.
263  ///
264  /// This is used by the engine shell and other subsystems for loading the
265  /// correct shader types.
267 
268  /// @brief Submit the command buffer that renders to the onscreen surface.
269  virtual bool SubmitOnscreen(std::shared_ptr<CommandBuffer> cmd_buffer);
270 
271  const Flags& GetFlags() const { return flags_; }
272 
273  protected:
274  explicit Context(const Flags& flags);
275 
277  std::vector<std::function<void()>> per_frame_task_;
278 
279  private:
280  Context(const Context&) = delete;
281 
282  Context& operator=(const Context&) = delete;
283 
284  /// @brief Wait until all previously submitted command buffers are
285  /// processed and displayed by the GPU.
286  ///
287  /// WARNING: This method call is unnecessary for nearly all use cases
288  /// since asynchronous workloads are the expected norm and calling
289  /// this method can negatively affect application performance.
290  /// Its only use is for cases like benchmarking where proper
291  /// performance metrics can only be collected by including
292  /// all background processing of the GPU.
293  ///
294  /// Outstanding unflushed command buffers are not committed, submitted,
295  /// or enqueued by this method and such buffers should have already been
296  /// flushed before this method is called. The method will only wait for
297  /// work to be done that has already been submitted to the GPU.
298  ///
299  /// @return True if the queue was successfully processed, otherwise
300  /// false if there was an error or if the backend does not
301  /// support synchronous reporting of completion. Implementations
302  /// intended entirely for testing might simply return false,
303  /// but they would not be used for benchmarking or other
304  /// situations where we might measure GPU performance.
305  virtual bool FinishQueue() = 0;
306 
308 };
309 
310 } // namespace impeller
311 
312 #endif // FLUTTER_IMPELLER_RENDERER_CONTEXT_H_
To do anything rendering related with Impeller, you need a context.
Definition: context.h:69
virtual std::shared_ptr< const IdleWaiter > GetIdleWaiter() const
Definition: context.cc:42
virtual bool AddTrackingFence(const std::shared_ptr< Texture > &texture) const
Definition: context.cc:50
virtual std::shared_ptr< SamplerLibrary > GetSamplerLibrary() const =0
Returns the library of combined image samplers used in shaders.
virtual std::shared_ptr< CommandBuffer > CreateCommandBuffer() const =0
Create a new command buffer. Command buffers can be used to encode graphics, blit,...
friend class flutter::testing::DlSurfaceInstanceImpeller
Definition: context.h:307
virtual std::shared_ptr< PipelineLibrary > GetPipelineLibrary() const =0
Returns the library of pipelines used by render or compute commands.
virtual bool SubmitOnscreen(std::shared_ptr< CommandBuffer > cmd_buffer)
Submit the command buffer that renders to the onscreen surface.
Definition: context.cc:54
virtual std::shared_ptr< ShaderLibrary > GetShaderLibrary() const =0
Returns the library of shaders used to specify the programmable stages of a pipeline.
const Flags & GetFlags() const
Definition: context.h:271
static constexpr int32_t kMaxTasksAwaitingGPU
Definition: context.h:83
virtual const std::shared_ptr< const Capabilities > & GetCapabilities() const =0
Get the capabilities of Impeller context. All optionally supported feature of the platform,...
std::vector< std::function< void()> > per_frame_task_
Definition: context.h:277
virtual bool UpdateOffscreenLayerPixelFormat(PixelFormat format)
Definition: context.cc:29
virtual BackendType GetBackendType() const =0
Get the graphics backend of an Impeller context.
virtual void Shutdown()=0
Force all pending asynchronous work to finish. This is achieved by deleting all owned concurrent mess...
Context(const Flags &flags)
Definition: context.cc:27
virtual void DisposeThreadLocalCachedResources()
Definition: context.h:227
virtual bool FlushCommandBuffers()
Flush all pending command buffers.
Definition: context.cc:38
virtual std::shared_ptr< CommandQueue > GetCommandQueue() const =0
Return the graphics queue for submitting command buffers.
virtual RuntimeStageBackend GetRuntimeStageBackend() const =0
Retrieve the runtime stage for this context type.
virtual void StoreTaskForGPU(const fml::closure &task, const fml::closure &failure)
Definition: context.h:209
virtual void InitializeCommonlyUsedShadersIfNeeded() const
Definition: context.h:220
virtual std::shared_ptr< Allocator > GetResourceAllocator() const =0
Returns the allocator used to create textures and buffers on the device.
virtual std::string DescribeGpuModel() const =0
virtual ~Context()
Destroys an Impeller context.
virtual bool IsValid() const =0
Determines if a context is valid. If the caller ever receives an invalid context, they must discard i...
virtual void ResetThreadLocalState() const
Definition: context.cc:46
virtual bool EnqueueCommandBuffer(std::shared_ptr< CommandBuffer > command_buffer)
Enqueue command_buffer for submission by the end of the frame.
Definition: context.cc:33
ImpellerContextFuture(std::future< std::shared_ptr< impeller::Context >> context)
Definition: context.cc:12
std::shared_ptr< impeller::Context > GetContext()
Definition: context.cc:16
PixelFormat
The Pixel formats supported by Impeller. The naming convention denotes the usage of the component,...
Definition: formats.h:99
std::shared_ptr< ContextGLES > context
std::shared_ptr< CommandBuffer > command_buffer