mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
[Flutter GPU] Add DeviceBuffer.flush & GpuContext.getMinimumUniformByteAlignment. (flutter/engine#53620)
Part of https://github.com/flutter/flutter/issues/150953. Provide a way to get the required minimum uniform byte alignment when referencing uniform blocks in a device buffer. Allow the user to explicitly flush DeviceBuffers (necessary for devices without shared memory).
This commit is contained in:
parent
54b7424efd
commit
759d173073
@ -9,6 +9,7 @@
|
||||
#include "flutter/lib/gpu/formats.h"
|
||||
#include "flutter/lib/ui/ui_dart_state.h"
|
||||
#include "fml/make_copyable.h"
|
||||
#include "impeller/core/platform.h"
|
||||
#include "tonic/converter/dart_converter.h"
|
||||
|
||||
namespace flutter {
|
||||
@ -105,3 +106,8 @@ extern int InternalFlutterGpu_Context_GetDefaultDepthStencilFormat(
|
||||
->GetCapabilities()
|
||||
->GetDefaultDepthStencilFormat()));
|
||||
}
|
||||
|
||||
extern int InternalFlutterGpu_Context_GetMinimumUniformByteAlignment(
|
||||
flutter::gpu::Context* wrapper) {
|
||||
return impeller::DefaultUniformAlignment();
|
||||
}
|
||||
|
||||
@ -70,6 +70,10 @@ FLUTTER_GPU_EXPORT
|
||||
extern int InternalFlutterGpu_Context_GetDefaultDepthStencilFormat(
|
||||
flutter::gpu::Context* wrapper);
|
||||
|
||||
FLUTTER_GPU_EXPORT
|
||||
extern int InternalFlutterGpu_Context_GetMinimumUniformByteAlignment(
|
||||
flutter::gpu::Context* wrapper);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#endif // FLUTTER_LIB_GPU_CONTEXT_H_
|
||||
|
||||
@ -99,3 +99,12 @@ bool InternalFlutterGpu_DeviceBuffer_Overwrite(
|
||||
return device_buffer->Overwrite(tonic::DartByteData(source_byte_data),
|
||||
destination_offset_in_bytes);
|
||||
}
|
||||
|
||||
bool InternalFlutterGpu_DeviceBuffer_Flush(
|
||||
flutter::gpu::DeviceBuffer* device_buffer,
|
||||
int offset_in_bytes,
|
||||
int size_in_bytes) {
|
||||
device_buffer->GetBuffer()->Flush(
|
||||
impeller::Range(offset_in_bytes, size_in_bytes));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -62,6 +62,12 @@ extern bool InternalFlutterGpu_DeviceBuffer_Overwrite(
|
||||
Dart_Handle source_byte_data,
|
||||
int destination_offset_in_bytes);
|
||||
|
||||
FLUTTER_GPU_EXPORT
|
||||
extern bool InternalFlutterGpu_DeviceBuffer_Flush(
|
||||
flutter::gpu::DeviceBuffer* wrapper,
|
||||
int offset_in_bytes,
|
||||
int size_in_bytes);
|
||||
|
||||
} // extern "C"
|
||||
|
||||
#endif // FLUTTER_LIB_GPU_DEVICE_BUFFER_H_
|
||||
|
||||
@ -93,11 +93,15 @@ base class DeviceBuffer extends NativeFieldWrapperClass1 with Buffer {
|
||||
symbol: 'InternalFlutterGpu_DeviceBuffer_InitializeWithHostData')
|
||||
external bool _initializeWithHostData(GpuContext gpuContext, ByteData data);
|
||||
|
||||
/// Overwrite a range of bytes in the already created [DeviceBuffer].
|
||||
/// Overwrite a range of bytes within an existing [DeviceBuffer].
|
||||
///
|
||||
/// This method can only be used if the [DeviceBuffer] was created with
|
||||
/// [StorageMode.hostVisible]. An exception will be thrown otherwise.
|
||||
///
|
||||
/// After new writes have been staged, the [DeviceBuffer.flush] should be
|
||||
/// called prior to accessing the data. Otherwise, the updated data will not
|
||||
/// be copied to the GPU on devices that don't have host coherent memory.
|
||||
///
|
||||
/// The entire length of [sourceBytes] will be copied into the [DeviceBuffer],
|
||||
/// starting at byte index [destinationOffsetInBytes] in the [DeviceBuffer].
|
||||
/// If performing this copy would result in an out of bounds write to the
|
||||
@ -119,6 +123,37 @@ base class DeviceBuffer extends NativeFieldWrapperClass1 with Buffer {
|
||||
@Native<Bool Function(Pointer<Void>, Handle, Int)>(
|
||||
symbol: 'InternalFlutterGpu_DeviceBuffer_Overwrite')
|
||||
external bool _overwrite(ByteData bytes, int destinationOffsetInBytes);
|
||||
|
||||
/// Flush the contents of the [DeviceBuffer] to the GPU.
|
||||
///
|
||||
/// This method can only be used if the [DeviceBuffer] was created with
|
||||
/// [StorageMode.hostVisible]. An exception will be thrown otherwise.
|
||||
///
|
||||
/// If [lengthInBytes] is set to -1, the entire buffer will be flushed.
|
||||
///
|
||||
/// On devices with coherent host memory (memory shared between the CPU and
|
||||
/// GPU), this method is a no-op.
|
||||
void flush({int offsetInBytes = 0, int lengthInBytes = -1}) {
|
||||
if (storageMode != StorageMode.hostVisible) {
|
||||
throw Exception(
|
||||
'DeviceBuffer.flush can only be used with DeviceBuffers that are host visible');
|
||||
}
|
||||
if (offsetInBytes < 0 || offsetInBytes >= sizeInBytes) {
|
||||
throw Exception('offsetInBytes must be within the bounds of the buffer');
|
||||
}
|
||||
if (lengthInBytes < -1) {
|
||||
throw Exception('lengthInBytes must be either positive or -1');
|
||||
}
|
||||
if (lengthInBytes != -1 && offsetInBytes + lengthInBytes > sizeInBytes) {
|
||||
throw Exception(
|
||||
'The provided range must not be too large to fit within the buffer');
|
||||
}
|
||||
_flush(offsetInBytes, lengthInBytes);
|
||||
}
|
||||
|
||||
@Native<Void Function(Pointer<Void>, Int, Int)>(
|
||||
symbol: 'InternalFlutterGpu_DeviceBuffer_Flush')
|
||||
external void _flush(int offsetInBytes, int lengthInBytes);
|
||||
}
|
||||
|
||||
/// [HostBuffer] is a [Buffer] which is allocated on the host (native CPU
|
||||
|
||||
@ -40,6 +40,12 @@ base class GpuContext extends NativeFieldWrapperClass1 {
|
||||
return PixelFormat.values[_getDefaultDepthStencilFormat()];
|
||||
}
|
||||
|
||||
/// The minimum alignment required when referencing uniform blocks stored in a
|
||||
/// `DeviceBuffer`.
|
||||
int get minimumUniformByteAlignment {
|
||||
return _getMinimumUniformByteAlignment();
|
||||
}
|
||||
|
||||
/// Allocates a new region of GPU-resident memory.
|
||||
///
|
||||
/// The [storageMode] must be either [StorageMode.hostVisible] or
|
||||
@ -124,6 +130,10 @@ base class GpuContext extends NativeFieldWrapperClass1 {
|
||||
@Native<Int Function(Pointer<Void>)>(
|
||||
symbol: 'InternalFlutterGpu_Context_GetDefaultDepthStencilFormat')
|
||||
external int _getDefaultDepthStencilFormat();
|
||||
|
||||
@Native<Int Function(Pointer<Void>)>(
|
||||
symbol: 'InternalFlutterGpu_Context_GetMinimumUniformByteAlignment')
|
||||
external int _getMinimumUniformByteAlignment();
|
||||
}
|
||||
|
||||
/// The default graphics context.
|
||||
|
||||
@ -67,6 +67,11 @@ void main() async {
|
||||
}
|
||||
});
|
||||
|
||||
test('GpuContext.minimumUniformByteAlignment', () async {
|
||||
final int alignment = gpu.gpuContext.minimumUniformByteAlignment;
|
||||
expect(alignment, greaterThanOrEqualTo(16));
|
||||
}, skip: !impellerEnabled);
|
||||
|
||||
test('HostBuffer.emplace', () async {
|
||||
final gpu.HostBuffer hostBuffer = gpu.gpuContext.createHostBuffer();
|
||||
|
||||
@ -96,6 +101,7 @@ void main() async {
|
||||
|
||||
final bool success = deviceBuffer!
|
||||
.overwrite(Int8List.fromList(<int>[0, 1, 2, 3]).buffer.asByteData());
|
||||
deviceBuffer.flush();
|
||||
expect(success, true);
|
||||
}, skip: !impellerEnabled);
|
||||
|
||||
@ -107,6 +113,7 @@ void main() async {
|
||||
final bool success = deviceBuffer!.overwrite(
|
||||
Int8List.fromList(<int>[0, 1, 2, 3]).buffer.asByteData(),
|
||||
destinationOffsetInBytes: 1);
|
||||
deviceBuffer.flush();
|
||||
expect(success, false);
|
||||
}, skip: !impellerEnabled);
|
||||
|
||||
@ -120,6 +127,7 @@ void main() async {
|
||||
deviceBuffer!.overwrite(
|
||||
Int8List.fromList(<int>[0, 1, 2, 3]).buffer.asByteData(),
|
||||
destinationOffsetInBytes: -1);
|
||||
deviceBuffer.flush();
|
||||
fail('Exception not thrown for negative destination offset.');
|
||||
} catch (e) {
|
||||
expect(
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user