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

Commit f9264f0

Browse files
authored
[Impeller] Flutter GPU: Add HostBuffer. (#44696)
Resolves flutter/flutter#132516. Add `impeller::HostBuffer` wrapper to Flutter GPU. * Allows for lazy batch uploads of sparse host data to the GPU. * Handles platform alignment requirements. * API returns buffer view handles that will be fed to commands.
1 parent 58dc868 commit f9264f0

File tree

10 files changed

+209
-10
lines changed

10 files changed

+209
-10
lines changed

ci/licenses_golden/licenses_flutter

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1731,7 +1731,10 @@ ORIGIN: ../../../flutter/lib/gpu/context.cc + ../../../flutter/LICENSE
17311731
ORIGIN: ../../../flutter/lib/gpu/context.h + ../../../flutter/LICENSE
17321732
ORIGIN: ../../../flutter/lib/gpu/export.cc + ../../../flutter/LICENSE
17331733
ORIGIN: ../../../flutter/lib/gpu/export.h + ../../../flutter/LICENSE
1734+
ORIGIN: ../../../flutter/lib/gpu/host_buffer.cc + ../../../flutter/LICENSE
1735+
ORIGIN: ../../../flutter/lib/gpu/host_buffer.h + ../../../flutter/LICENSE
17341736
ORIGIN: ../../../flutter/lib/gpu/lib/gpu.dart + ../../../flutter/LICENSE
1737+
ORIGIN: ../../../flutter/lib/gpu/lib/src/buffer.dart + ../../../flutter/LICENSE
17351738
ORIGIN: ../../../flutter/lib/gpu/lib/src/context.dart + ../../../flutter/LICENSE
17361739
ORIGIN: ../../../flutter/lib/gpu/lib/src/smoketest.dart + ../../../flutter/LICENSE
17371740
ORIGIN: ../../../flutter/lib/gpu/smoketest.cc + ../../../flutter/LICENSE
@@ -4459,7 +4462,10 @@ FILE: ../../../flutter/lib/gpu/context.cc
44594462
FILE: ../../../flutter/lib/gpu/context.h
44604463
FILE: ../../../flutter/lib/gpu/export.cc
44614464
FILE: ../../../flutter/lib/gpu/export.h
4465+
FILE: ../../../flutter/lib/gpu/host_buffer.cc
4466+
FILE: ../../../flutter/lib/gpu/host_buffer.h
44624467
FILE: ../../../flutter/lib/gpu/lib/gpu.dart
4468+
FILE: ../../../flutter/lib/gpu/lib/src/buffer.dart
44634469
FILE: ../../../flutter/lib/gpu/lib/src/context.dart
44644470
FILE: ../../../flutter/lib/gpu/lib/src/smoketest.dart
44654471
FILE: ../../../flutter/lib/gpu/smoketest.cc

impeller/fixtures/dart_tests.dart

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Use of this source code is governed by a BSD-style license that can be
33
// found in the LICENSE file.
44

5+
import 'dart:typed_data';
56
import 'dart:ui' as ui;
67
import '../../lib/gpu/lib/gpu.dart' as gpu;
78

@@ -17,3 +18,18 @@ void instantiateDefaultContext() {
1718
// ignore: unused_local_variable
1819
final gpu.GpuContext context = gpu.gpuContext;
1920
}
21+
22+
@pragma('vm:entry-point')
23+
void canEmplaceHostBuffer() {
24+
final gpu.HostBuffer hostBuffer = gpu.HostBuffer();
25+
26+
final gpu.BufferView view0 = hostBuffer
27+
.emplace(Int8List.fromList(<int>[0, 1, 2, 3]).buffer.asByteData());
28+
assert(view0.offsetInBytes == 0);
29+
assert(view0.lengthInBytes == 4);
30+
31+
final gpu.BufferView view1 = hostBuffer
32+
.emplace(Int8List.fromList(<int>[0, 1, 2, 3]).buffer.asByteData());
33+
assert(view1.offsetInBytes >= 4);
34+
assert(view1.lengthInBytes == 4);
35+
}

impeller/renderer/renderer_dart_unittests.cc

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,5 +111,19 @@ TEST_P(RendererDartTest, CanInstantiateFlutterGPUContext) {
111111
ASSERT_TRUE(result);
112112
}
113113

114+
TEST_P(RendererDartTest, CanEmplaceHostBuffer) {
115+
auto isolate = GetIsolate();
116+
bool result = isolate->RunInIsolateScope([]() -> bool {
117+
if (tonic::CheckAndHandleError(
118+
::Dart_Invoke(Dart_RootLibrary(),
119+
tonic::ToDart("canEmplaceHostBuffer"), 0, nullptr))) {
120+
return false;
121+
}
122+
return true;
123+
});
124+
125+
ASSERT_TRUE(result);
126+
}
127+
114128
} // namespace testing
115129
} // namespace impeller

lib/gpu/BUILD.gn

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ source_set("gpu") {
3636
"context.h",
3737
"export.cc",
3838
"export.h",
39+
"host_buffer.cc",
40+
"host_buffer.h",
3941
"smoketest.cc",
4042
"smoketest.h",
4143
]

lib/gpu/context.cc

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,21 +15,25 @@ namespace flutter {
1515

1616
IMPLEMENT_WRAPPERTYPEINFO(gpu, Context);
1717

18-
std::shared_ptr<impeller::Context> Context::override_context_;
18+
std::shared_ptr<impeller::Context> Context::default_context_;
1919

2020
void Context::SetOverrideContext(std::shared_ptr<impeller::Context> context) {
21-
override_context_ = std::move(context);
21+
default_context_ = std::move(context);
2222
}
2323

24-
std::shared_ptr<impeller::Context> Context::GetOverrideContext() {
25-
return override_context_;
24+
std::shared_ptr<impeller::Context> Context::GetDefaultContext() {
25+
return default_context_;
2626
}
2727

2828
Context::Context(std::shared_ptr<impeller::Context> context)
2929
: context_(std::move(context)) {}
3030

3131
Context::~Context() = default;
3232

33+
std::shared_ptr<impeller::Context> Context::GetContext() {
34+
return context_;
35+
}
36+
3337
} // namespace flutter
3438

3539
//----------------------------------------------------------------------------
@@ -40,7 +44,7 @@ Dart_Handle InternalFlutterGpu_Context_InitializeDefault(Dart_Handle wrapper) {
4044
auto dart_state = flutter::UIDartState::Current();
4145

4246
std::shared_ptr<impeller::Context> impeller_context =
43-
flutter::Context::GetOverrideContext();
47+
flutter::Context::GetDefaultContext();
4448

4549
if (!impeller_context) {
4650
if (!dart_state->IsImpellerEnabled()) {

lib/gpu/context.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,19 @@ class Context : public RefCountedDartWrappable<Context> {
1818
public:
1919
static void SetOverrideContext(std::shared_ptr<impeller::Context> context);
2020

21-
static std::shared_ptr<impeller::Context> GetOverrideContext();
21+
static std::shared_ptr<impeller::Context> GetDefaultContext();
2222

2323
explicit Context(std::shared_ptr<impeller::Context> context);
2424
~Context() override;
2525

26-
protected:
26+
std::shared_ptr<impeller::Context> GetContext();
27+
28+
private:
2729
/// An Impeller context that takes precedent over the IO state context when
2830
/// set. This is used to inject the context when running with the Impeller
2931
/// playground, which doesn't instantiate an Engine instance.
30-
static std::shared_ptr<impeller::Context> override_context_;
32+
static std::shared_ptr<impeller::Context> default_context_;
3133

32-
private:
3334
std::shared_ptr<impeller::Context> context_;
3435

3536
FML_DISALLOW_COPY_AND_ASSIGN(Context);

lib/gpu/host_buffer.cc

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#include "flutter/lib/gpu/host_buffer.h"
6+
7+
#include "impeller/core/host_buffer.h"
8+
#include "impeller/core/platform.h"
9+
#include "third_party/tonic/typed_data/dart_byte_data.h"
10+
11+
namespace flutter {
12+
13+
IMPLEMENT_WRAPPERTYPEINFO(gpu, HostBuffer);
14+
15+
HostBuffer::HostBuffer() : host_buffer_(impeller::HostBuffer::Create()) {}
16+
17+
HostBuffer::~HostBuffer() = default;
18+
19+
size_t HostBuffer::EmplaceBytes(const tonic::DartByteData& byte_data) {
20+
auto view =
21+
host_buffer_->Emplace(byte_data.data(), byte_data.length_in_bytes(),
22+
impeller::DefaultUniformAlignment());
23+
return view.range.offset;
24+
}
25+
26+
} // namespace flutter
27+
28+
//----------------------------------------------------------------------------
29+
/// Exports
30+
///
31+
32+
void InternalFlutterGpu_HostBuffer_Initialize(Dart_Handle wrapper) {
33+
auto res = fml::MakeRefCounted<flutter::HostBuffer>();
34+
res->AssociateWithDartWrapper(wrapper);
35+
}
36+
37+
size_t InternalFlutterGpu_HostBuffer_EmplaceBytes(flutter::HostBuffer* wrapper,
38+
Dart_Handle byte_data) {
39+
return wrapper->EmplaceBytes(tonic::DartByteData(byte_data));
40+
}

lib/gpu/host_buffer.h

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
#pragma once
6+
7+
#include "flutter/lib/gpu/export.h"
8+
#include "flutter/lib/ui/dart_wrapper.h"
9+
#include "impeller/core/host_buffer.h"
10+
#include "third_party/tonic/typed_data/dart_byte_data.h"
11+
12+
namespace flutter {
13+
14+
class HostBuffer : public RefCountedDartWrappable<HostBuffer> {
15+
DEFINE_WRAPPERTYPEINFO();
16+
FML_FRIEND_MAKE_REF_COUNTED(HostBuffer);
17+
18+
public:
19+
explicit HostBuffer();
20+
21+
~HostBuffer() override;
22+
23+
size_t EmplaceBytes(const tonic::DartByteData& byte_data);
24+
25+
private:
26+
std::shared_ptr<impeller::HostBuffer> host_buffer_;
27+
28+
FML_DISALLOW_COPY_AND_ASSIGN(HostBuffer);
29+
};
30+
31+
} // namespace flutter
32+
33+
//----------------------------------------------------------------------------
34+
/// Exports
35+
///
36+
37+
extern "C" {
38+
39+
FLUTTER_GPU_EXPORT
40+
extern void InternalFlutterGpu_HostBuffer_Initialize(Dart_Handle wrapper);
41+
42+
FLUTTER_GPU_EXPORT
43+
extern size_t InternalFlutterGpu_HostBuffer_EmplaceBytes(
44+
flutter::HostBuffer* wrapper,
45+
Dart_Handle byte_data);
46+
47+
} // extern "C"

lib/gpu/lib/gpu.dart

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,5 +11,7 @@
1111
/// * [Flutter GPU Wiki page](https://github.com/flutter/flutter/wiki/Flutter-GPU).
1212
library flutter_gpu;
1313

14-
export 'src/context.dart';
1514
export 'src/smoketest.dart';
15+
16+
export 'src/context.dart';
17+
export 'src/buffer.dart';

lib/gpu/lib/src/buffer.dart

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// Copyright 2013 The Flutter Authors. All rights reserved.
2+
// Use of this source code is governed by a BSD-style license that can be
3+
// found in the LICENSE file.
4+
5+
import 'dart:ffi';
6+
import 'dart:nativewrappers';
7+
import 'dart:typed_data';
8+
9+
/// A reference to a byte range within a GPU-resident [Buffer].
10+
class BufferView {
11+
/// The buffer of this view.
12+
final HostBuffer buffer;
13+
14+
/// The start of the view, in bytes starting from the beginning of the
15+
/// [buffer].
16+
final int offsetInBytes;
17+
18+
/// The length of the view.
19+
final int lengthInBytes;
20+
21+
/// Create a new view into a buffer on the GPU.
22+
const BufferView(this.buffer,
23+
{required this.offsetInBytes, required this.lengthInBytes});
24+
}
25+
26+
/// [HostBuffer] is a [Buffer] which is allocated on the host (native CPU
27+
/// resident memory) and lazily uploaded to the GPU. A [HostBuffer] can be
28+
/// safely mutated or extended at any time on the host, and will be
29+
/// automatically re-uploaded to the GPU the next time a GPU operation needs to
30+
/// access it.
31+
///
32+
/// This is useful for efficiently chunking sparse data uploads, especially
33+
/// ephemeral uniform data that needs to change from frame to frame.
34+
///
35+
/// Different platforms have different data alignment requirements for accessing
36+
/// device buffer data. The [HostBuffer] takes these requirements into account
37+
/// and automatically inserts padding between emplaced data if necessary.
38+
base class HostBuffer extends NativeFieldWrapperClass1 {
39+
/// Creates a new HostBuffer.
40+
HostBuffer() {
41+
_initialize();
42+
}
43+
44+
/// Wrap with native counterpart.
45+
@Native<Void Function(Handle)>(
46+
symbol: 'InternalFlutterGpu_HostBuffer_Initialize')
47+
external void _initialize();
48+
49+
/// Append byte data to the end of the [HostBuffer] and produce a [BufferView]
50+
/// that references the new data in the buffer.
51+
///
52+
/// This method automatically inserts padding in-between emplace calls in the
53+
/// buffer if necessary to abide by platform-specific uniform alignment
54+
/// requirements.
55+
///
56+
/// The updated buffer will be uploaded to the GPU if the returned
57+
/// [BufferView] is used by a rendering command.
58+
BufferView emplace(ByteData bytes) {
59+
int resultOffset = _emplaceBytes(bytes);
60+
return BufferView(this,
61+
offsetInBytes: resultOffset, lengthInBytes: bytes.lengthInBytes);
62+
}
63+
64+
@Native<Uint64 Function(Pointer<Void>, Handle)>(
65+
symbol: 'InternalFlutterGpu_HostBuffer_EmplaceBytes')
66+
external int _emplaceBytes(ByteData bytes);
67+
}

0 commit comments

Comments
 (0)