[Flutter GPU] Add surface API for framework presentation#187358
Conversation
81855ad to
b9288a4
Compare
b9288a4 to
47f537c
Compare
There was a problem hiding this comment.
Code Review
This pull request introduces GpuSurface and SurfaceFrame to the Flutter GPU library, allowing applications to manage a pool of presentable render targets. It also adds completion callback support to CommandBuffer and includes comprehensive unit tests. The review feedback suggests invalidating the colorTexture when a frame is presented or discarded to prevent accidental post-lease usage, and pruning inactive, old-sized texture records during a surface resize to avoid a potential GPU memory leak.
47f537c to
1a9cf59
Compare
1a9cf59 to
41527d3
Compare
Is there a reason that present() does not imply submit()? |
| _checkDimensions(width, height); | ||
| final String? error = _resize(width, height); | ||
| if (error != null) { | ||
| throw Exception(error); |
| /// [SurfaceFrame.colorTexture], call [SurfaceFrame.present] with the command | ||
| /// buffer that contains the final writes, submit that command buffer, and draw | ||
| /// [currentImage]. | ||
| base class GpuSurface extends NativeFieldWrapperClass1 { |
There was a problem hiding this comment.
Don't you want final for this?
| /// [present] to publish the frame as the surface's current image. If the frame | ||
| /// will not be presented, call [discard] so the surface can reuse its backing | ||
| /// texture. | ||
| base class SurfaceFrame { |
| /// for future frames. | ||
| /// | ||
| /// The returned [ui.Image] is also available from [GpuSurface.currentImage]. | ||
| ui.Image present(CommandBuffer commandBuffer) { |
There was a problem hiding this comment.
should this submit the command buffer? (mentioned in comment on issue)
There was a problem hiding this comment.
I kept submit explicit so one command buffer can produce multiple presented surface frames, for example rendering two GpuSurfaces and then submitting their shared command buffer once.
|
|
||
| bool CommandBuffer::Submit( | ||
| const impeller::CommandBuffer::CompletionCallback& completion_callback) { | ||
| if (submitted_) { |
There was a problem hiding this comment.
I'd suggest adding a unit test for these c++ level changes.
| std::shared_ptr<Surface::TextureRecord> Surface::CreateTextureRecord() const { | ||
| #if !IMPELLER_SUPPORTS_RENDERING | ||
| FML_LOG(ERROR) << "Flutter GPU surfaces require Impeller rendering support."; | ||
| return nullptr; |
There was a problem hiding this comment.
why do we even compile this without impeller?
There was a problem hiding this comment.
Agreed, and I filed #187424 to track splitting the Flutter GPU build so most implementation code is compiled only when Impeller rendering is available.
| resizedFrame.discard(); | ||
| }, skip: !(impellerEnabled && flutterGpuEnabled)); | ||
|
|
||
| test('Can render clear color into GpuSurface', () async { |
There was a problem hiding this comment.
seems like a golden test would be good for this as well?
There was a problem hiding this comment.
Done in 7ec7a99, the existing surface golden test was renamed to make that coverage explicit.
This reverts commit 8e36788.
|
Resolved new conflicts |
|
auto label is removed for flutter/flutter/187358, Failed to enqueue flutter/flutter/187358 with HTTP 400: Pull request Required status check "Check Code Freeze" is expected.. |
|
Any idea why this is happening? Is the action broken? 🤔 |
Fixes #187357
Adds a Flutter GPU surface API for rendering into a presentable color texture and drawing the latest presented image through Flutter. The surface owns the backing texture pool, tracks acquired frames, keeps the current image out of reuse, and waits for producer command buffer completion before a presented texture can be reused.
The API is shaped as a small family so later destinations (a Flutter canvas, and eventually the window swapchain) can share one per-frame contract.
GpuSurfaceandGpuSurfaceFrameare the destination-agnostic base types. This PR ships the first concrete destination,GpuImageSurface, which Flutter draws as aui.Image.Two parts of the contract are uniform across all future destinations, even though the image destination never exercises them.
acquireNextFrameis nullable, because a window swapchain can skip a frame.presentreturns aGpuPresentStatus, because a window swapchain can report that it needs reconfiguring. For an image surface, acquire always returns a frame and present always reports success, and the published image is read fromGpuImageSurface.currentImage.The API keeps depth, stencil, MSAA, and intermediate attachments renderer-owned.
GpuSurfaceFrame.colorTextureis only the final color target handed back to Flutter as aui.Image.A minimal example.
Depth and stencil remain normal renderer-owned attachments.
Tests cover surface acquisition, presentation, current image behavior, discard, resize, and rendering a clear color into a surface.
Pre-launch Checklist
///).