-
Notifications
You must be signed in to change notification settings - Fork 6k
[Flutter GPU] Add DeviceBuffer. #47699
Conversation
| export 'src/buffer.dart'; | ||
| part 'src/formats.dart'; | ||
| part 'src/context.dart'; | ||
| part 'src/buffer.dart'; |
There was a problem hiding this comment.
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. 😅
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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}) { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 { |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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, useMTLStorageMode.managedand 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 {} |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 {}.
There was a problem hiding this comment.
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.
jonahwilliams
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM
|
The licenses need to be updated but otherwise looks good to go. Can we land this? |
|
Yeah I'm gonna try to see if I can work out the import situation in a follow-up |
eeb95c9 to
3424629
Compare
3424629 to
9c34547
Compare
…138280) flutter/engine@1c29ce1...e2e07ea 2023-11-11 [email protected] [Flutter GPU] Add DeviceBuffer. (flutter/engine#47699) If this roll has caused a breakage, revert this CL and stop the roller using the controls here: https://autoroll.skia.org/r/flutter-engine-flutter-autoroll Please CC [email protected],[email protected],[email protected] on the revert to ensure that a human is aware of the problem. To file a bug in Flutter: https://github.com/flutter/flutter/issues/new/choose To report a problem with the AutoRoller itself, please file a bug: https://issues.skia.org/issues/new?component=1389291&template=1850622 Documentation for the AutoRoller is here: https://skia.googlesource.com/buildbot/+doc/main/autoroll/README.md
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
Buffermixin to allow for expressing this inBufferView, but this may end up changing once I actually add Commands and need to solve the puzzle.