Problem
Rendering a widget subtree into a Flutter GPU texture currently requires a full CPU round trip. The only way to get widget content into a gpu.Texture today is
final image = await layer.toImage(...); // GPU render
final bytes = await image.toByteData(format: rawStraightRgba); // GPU to CPU readback
final texture = gpuContext.createTexture(StorageMode.hostVisible, w, h, ...);
texture.overwrite(bytes); // CPU to GPU upload
The readback and the upload are wasted work. On Impeller, the ui.Image returned by toImage already wraps a GPU resident impeller::Texture, and Flutter GPU shares the same impeller::Context as the UI renderer, so the texture is already usable without copying it anywhere.
Proposal
Add gpu.Texture.fromImage(ui.Image image) as the inverse of the existing Texture.asImage(). It would pull the impeller::Texture out of the image's DlImageImpeller and wrap it in a gpu.Texture, reading size and format back from the texture descriptor.
This is a small addition. The extraction already exists in the engine (DlImage::asImpellerImage() then GetImpellerTexture), and the wrapping mirrors Texture::AsImage.
Notes
- Use the async
toImage rather than toImageSync. The deferred image from toImageSync fills its texture on the raster thread after the call returns, so a synchronous wrap could capture an unrendered or null texture.
- Textures from
fromImage should be treated as sample only to start, since the caller does not own the descriptor.
- Fail gracefully for non Impeller images, where
asImpellerImage() returns null.
Problem
Rendering a widget subtree into a Flutter GPU texture currently requires a full CPU round trip. The only way to get widget content into a
gpu.Texturetoday isThe readback and the upload are wasted work. On Impeller, the
ui.Imagereturned bytoImagealready wraps a GPU residentimpeller::Texture, and Flutter GPU shares the sameimpeller::Contextas the UI renderer, so the texture is already usable without copying it anywhere.Proposal
Add
gpu.Texture.fromImage(ui.Image image)as the inverse of the existingTexture.asImage(). It would pull theimpeller::Textureout of the image'sDlImageImpellerand wrap it in agpu.Texture, reading size and format back from the texture descriptor.This is a small addition. The extraction already exists in the engine (
DlImage::asImpellerImage()thenGetImpellerTexture), and the wrapping mirrorsTexture::AsImage.Notes
toImagerather thantoImageSync. The deferred image fromtoImageSyncfills its texture on the raster thread after the call returns, so a synchronous wrap could capture an unrendered or null texture.fromImageshould be treated as sample only to start, since the caller does not own the descriptor.asImpellerImage()returns null.