Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Conversation

@bdero
Copy link
Member

@bdero bdero commented Nov 6, 2023

Part of http://flutter.dev/go/impeller-dart

Resolves flutter/flutter#130924.
Resolves flutter/flutter#130925.

Create and upload data to host visible device buffers. Commands should allow for binding either HostBuffers (which eventually resolve to DeviceBuffers) or DeviceBuffers. There's a Buffer mixin to allow for expressing this in BufferView, but this may end up changing once I actually add Commands and need to solve the puzzle.

@bdero bdero self-assigned this Nov 6, 2023
export 'src/buffer.dart';
part 'src/formats.dart';
part 'src/context.dart';
part 'src/buffer.dart';
Copy link
Member Author

@bdero bdero Nov 6, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I switched back to this pattern due to circular dependencies. GpuContext depends on DeviceBuffer, DeviceBuffer depends on GpuContext. The constructors for DeviceBuffer are locked down anyhow, so we can remove the DeviceBuffer->GpuContext dependency by pulling the dart handle ref binding into GpuContext, but would prefer to do that as follow-up work. These bindings are an enormous pain as-is. 😅

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just as an FYI, circular imports are A-OK in Dart.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, maybe what I was actually struggling with was getting imports working at all between files in the package. I'm guessing my import URIs were wrong.

///
/// Returns [true] if the write was successful, or [false] if the write
/// failed due to an internal error.
bool overwrite(ByteData sourceBytes, {int destinationOffsetInBytes = 0}) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My inclination would be to leave this out, even if usefull, provided we can accomplish the same functionality by recreating device buffers. Synchronization is something we're going to need to think about quite a bit, as well as performance - but it will be easier to do that with less API.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This sounds like making DeviceBuffers immutable? I totally get what you're saying here -- we don't need this for getting things drawing. But I'm confident that being able to reuse device allocations is going to be important and is something we should just contend with making work immediately. The port of Scene will use this call.

Synchronization is something we're going to need to think about quite a bit, as well as performance - but it will be easier to do that with less API.

We talked about this a bit offline, but synchronization shouldn't be an issue. For MVP, all Flutter GPU submissions will happen on the UI thread, and drawing to a canvas would need to happen with a swap chain. I don't think we should mess with trying to support deferring anything until much later on.

part of flutter_gpu;

/// Specifies where an allocation resides and how it may be used.
enum StorageMode {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does it make sense to expose any sort of StorageMode enum for buffers?

HostBuffers are obviously host visible. DeviceBuffers can't be transient. hostVisible/devicePrivate is the same thing on UMA, and on non-UMA devices I don't know when you'd use hostVisible.

Copy link
Member Author

@bdero bdero Nov 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a great question -- I think for sure we should allow DeviceBuffers to be hostVisible and devicePrivate.

DeviceBuffers can't be transient.

Might make sense to just have a separate enums TextureStorageMode and BufferStorageMode TBH.

hostVisible/devicePrivate is the same thing on UMA either way

Just dumping thoughts here, but while it's true that you get coherency for free either way on UMA (because it's literally the same memory), we're still forced to contend with both architectures in the same interface. So even if devicePrivate doesn't technically exist for some devices on some backends, we should still throw a validation error when the user is trying to write to stuff they previously marked as devicePrivate, lest a developer might release an app that unknowingly fails in a confusing way for some users on some devices.

  • devicePrivate resources aren't readable or writable by the CPU at all -- not even for initialization (e.g. MTLStorageMode.private).
  • hostVisible resources are both readable and writable by the CPU, and the backends can contend with both the unified and separated cases through a unified interface. So: For UMA, use MTLStorageMode.shared. For non-UMA, use MTLStorageMode.managed and transfer data as necessary. CPU writes get queued immediately. The device itself may be instructed to write to these allocations, and so the device should be the source of truth. Any attempt at reading the data on the CPU should be an async callback in case either a Device->Host transfer is necessary (non-UMA) or a blocking sync is necessary (UMA).

on non-UMA devices I don't know when you'd use hostVisible

You must use hostVisible anytime you're authoring a buffer from host data. OTOH, you might use a devicePrivate buffer to store stuff only written to and read by pipelines through storage bindings or attachments.

If you don't need reads/writes from the host, you should prefer devicePrivate so that the backend/driver can choose the best heap for the job (something which maybe we'll improve over time for some backends), especially on discrete GPUs.

}

/// A buffer that can be referenced by commands on the GPU.
mixin Buffer {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its difficult for me to provide an alternative solution here, since I don't know what we'll use buffer view for yet - but an empty interface is always a code smell in Dart.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what we'll use buffer view for yet

BufferView is just for binding a section of a buffer to a command, like how Impeller works today. Vertex buffers, index buffers, uniform buffers, SSBOs.

We definitely don't need HostBuffer for a minimal solution so I'm considering just removing it for now. Would prefer to do so in a later patch though.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment is about the mixin Buffer {}.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well yes -- the Buffer mixin is solely so we can place both kinds of buffers into a BufferView, and you said you're not sure how the "buffer view" is going to be used. And we wouldn't need this mixin if we didn't have a HostBuffer.

Copy link
Contributor

@jonahwilliams jonahwilliams left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@chinmaygarde
Copy link
Member

The licenses need to be updated but otherwise looks good to go. Can we land this?

@bdero
Copy link
Member Author

bdero commented Nov 10, 2023

Yeah I'm gonna try to see if I can work out the import situation in a follow-up

@bdero bdero force-pushed the bdero/flutter-gpu-buffers branch from eeb95c9 to 3424629 Compare November 10, 2023 00:22
@bdero bdero force-pushed the bdero/flutter-gpu-buffers branch from 3424629 to 9c34547 Compare November 10, 2023 22:02
@bdero bdero added the autosubmit Merge PR when tree becomes green via auto submit App label Nov 11, 2023
@auto-submit auto-submit bot merged commit e2e07ea into flutter:main Nov 11, 2023
engine-flutter-autoroll added a commit to engine-flutter-autoroll/flutter that referenced this pull request Nov 11, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

autosubmit Merge PR when tree becomes green via auto submit App e: impeller

Projects

No open projects
Archived in project

Development

Successfully merging this pull request may close these issues.

[Impeller] Flutter GPU: Allow populating DeviceBuffers from Dart. [Impeller] Flutter GPU: Add DeviceBuffers.

3 participants