Skip to content

Commit 9029dc6

Browse files
author
Jonah Williams
authored
[Impeller] use sync fence for image uploads. (flutter/engine#56609)
Fixes flutter#158963 If the GLES version is at least 3, then we can attach a sync fence to the texture gles object. If this operation succeeds, then we can use gl.Flush instad of gl.Finish. Then, when binding the texture - if a sync fence is present we wait and then remove the fence.
1 parent ce204dc commit 9029dc6

24 files changed

+252
-28
lines changed

engine/src/flutter/impeller/renderer/backend/gles/BUILD.gn

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ impeller_component("gles_unittests") {
2525
"test/reactor_unittests.cc",
2626
"test/specialization_constants_unittests.cc",
2727
"test/surface_gles_unittests.cc",
28+
"test/texture_gles_unittests.cc",
2829
]
2930
deps = [
3031
":gles",

engine/src/flutter/impeller/renderer/backend/gles/command_buffer_gles.cc

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ void CommandBufferGLES::OnWaitUntilCompleted() {
4343
reactor_->GetProcTable().Finish();
4444
}
4545

46+
// |CommandBuffer|
47+
void CommandBufferGLES::OnWaitUntilScheduled() {
48+
reactor_->GetProcTable().Flush();
49+
}
50+
4651
// |CommandBuffer|
4752
std::shared_ptr<RenderPass> CommandBufferGLES::OnCreateRenderPass(
4853
RenderTarget target) {

engine/src/flutter/impeller/renderer/backend/gles/command_buffer_gles.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ class CommandBufferGLES final : public CommandBuffer {
3737
// |CommandBuffer|
3838
void OnWaitUntilCompleted() override;
3939

40+
// |CommandBuffer|
41+
void OnWaitUntilScheduled() override;
42+
4043
// |CommandBuffer|
4144
std::shared_ptr<RenderPass> OnCreateRenderPass(RenderTarget target) override;
4245

engine/src/flutter/impeller/renderer/backend/gles/context_gles.cc

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
#include "impeller/base/validation.h"
1010
#include "impeller/renderer/backend/gles/command_buffer_gles.h"
1111
#include "impeller/renderer/backend/gles/gpu_tracer_gles.h"
12+
#include "impeller/renderer/backend/gles/handle_gles.h"
1213
#include "impeller/renderer/backend/gles/render_pass_gles.h"
14+
#include "impeller/renderer/backend/gles/texture_gles.h"
1315
#include "impeller/renderer/command_queue.h"
1416

1517
namespace impeller {
@@ -157,4 +159,15 @@ void ContextGLES::ResetThreadLocalState() const {
157159
});
158160
}
159161

162+
// |Context|
163+
bool ContextGLES::AddTrackingFence(
164+
const std::shared_ptr<Texture>& texture) const {
165+
if (!reactor_->GetProcTable().FenceSync.IsAvailable()) {
166+
return false;
167+
}
168+
HandleGLES fence = reactor_->CreateHandle(HandleType::kFence);
169+
TextureGLES::Cast(*texture).SetFence(fence);
170+
return true;
171+
}
172+
160173
} // namespace impeller

engine/src/flutter/impeller/renderer/backend/gles/context_gles.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,9 @@ class ContextGLES final : public Context,
9393
// |Context|
9494
void Shutdown() override;
9595

96+
// |Context|
97+
bool AddTrackingFence(const std::shared_ptr<Texture>& texture) const override;
98+
9699
// |Context|
97100
void ResetThreadLocalState() const override;
98101

engine/src/flutter/impeller/renderer/backend/gles/handle_gles.cc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ std::string HandleTypeToString(HandleType type) {
2222
return "RenderBuffer";
2323
case HandleType::kFrameBuffer:
2424
return "Framebuffer";
25+
case HandleType::kFence:
26+
return "Fence";
2527
}
2628
FML_UNREACHABLE();
2729
}

engine/src/flutter/impeller/renderer/backend/gles/handle_gles.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ enum class HandleType {
2222
kProgram,
2323
kRenderBuffer,
2424
kFrameBuffer,
25+
kFence,
2526
};
2627

2728
std::string HandleTypeToString(HandleType type);

engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.cc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,8 @@ static std::optional<GLenum> ToDebugIdentifier(DebugResourceType type) {
334334
return GL_RENDERBUFFER;
335335
case DebugResourceType::kFrameBuffer:
336336
return GL_FRAMEBUFFER;
337+
case DebugResourceType::kFence:
338+
return GL_SYNC_FENCE;
337339
}
338340
FML_UNREACHABLE();
339341
}
@@ -354,6 +356,8 @@ static bool ResourceIsLive(const ProcTableGLES& gl,
354356
return gl.IsRenderbuffer(name);
355357
case DebugResourceType::kFrameBuffer:
356358
return gl.IsFramebuffer(name);
359+
case DebugResourceType::kFence:
360+
return true;
357361
}
358362
FML_UNREACHABLE();
359363
}

engine/src/flutter/impeller/renderer/backend/gles/proc_table_gles.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -258,7 +258,11 @@ void(glDepthRange)(GLdouble n, GLdouble f);
258258
PROC(ClearDepth); \
259259
PROC(DepthRange);
260260

261-
#define FOR_EACH_IMPELLER_GLES3_PROC(PROC) PROC(BlitFramebuffer);
261+
#define FOR_EACH_IMPELLER_GLES3_PROC(PROC) \
262+
PROC(FenceSync); \
263+
PROC(DeleteSync); \
264+
PROC(WaitSync); \
265+
PROC(BlitFramebuffer);
262266

263267
#define FOR_EACH_IMPELLER_EXT_PROC(PROC) \
264268
PROC(DebugMessageControlKHR); \
@@ -282,6 +286,7 @@ enum class DebugResourceType {
282286
kShader,
283287
kRenderBuffer,
284288
kFrameBuffer,
289+
kFence,
285290
};
286291

287292
class ProcTableGLES {

engine/src/flutter/impeller/renderer/backend/gles/reactor_gles.cc

Lines changed: 58 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -13,51 +13,59 @@
1313

1414
namespace impeller {
1515

16-
static std::optional<GLuint> CreateGLHandle(const ProcTableGLES& gl,
17-
HandleType type) {
18-
GLuint handle = GL_NONE;
16+
// static
17+
std::optional<ReactorGLES::GLStorage> ReactorGLES::CreateGLHandle(
18+
const ProcTableGLES& gl,
19+
HandleType type) {
20+
GLStorage handle = GLStorage{.handle = GL_NONE};
1921
switch (type) {
2022
case HandleType::kUnknown:
2123
return std::nullopt;
2224
case HandleType::kTexture:
23-
gl.GenTextures(1u, &handle);
25+
gl.GenTextures(1u, &handle.handle);
2426
return handle;
2527
case HandleType::kBuffer:
26-
gl.GenBuffers(1u, &handle);
28+
gl.GenBuffers(1u, &handle.handle);
2729
return handle;
2830
case HandleType::kProgram:
29-
return gl.CreateProgram();
31+
return GLStorage{.handle = gl.CreateProgram()};
3032
case HandleType::kRenderBuffer:
31-
gl.GenRenderbuffers(1u, &handle);
33+
gl.GenRenderbuffers(1u, &handle.handle);
3234
return handle;
3335
case HandleType::kFrameBuffer:
34-
gl.GenFramebuffers(1u, &handle);
36+
gl.GenFramebuffers(1u, &handle.handle);
3537
return handle;
38+
case HandleType::kFence:
39+
return GLStorage{.sync = gl.FenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0)};
3640
}
3741
return std::nullopt;
3842
}
3943

40-
static bool CollectGLHandle(const ProcTableGLES& gl,
41-
HandleType type,
42-
GLuint handle) {
44+
// static
45+
bool ReactorGLES::CollectGLHandle(const ProcTableGLES& gl,
46+
HandleType type,
47+
ReactorGLES::GLStorage handle) {
4348
switch (type) {
4449
case HandleType::kUnknown:
4550
return false;
4651
case HandleType::kTexture:
47-
gl.DeleteTextures(1u, &handle);
52+
gl.DeleteTextures(1u, &handle.handle);
4853
return true;
4954
case HandleType::kBuffer:
50-
gl.DeleteBuffers(1u, &handle);
55+
gl.DeleteBuffers(1u, &handle.handle);
5156
return true;
5257
case HandleType::kProgram:
53-
gl.DeleteProgram(handle);
58+
gl.DeleteProgram(handle.handle);
5459
return true;
5560
case HandleType::kRenderBuffer:
56-
gl.DeleteRenderbuffers(1u, &handle);
61+
gl.DeleteRenderbuffers(1u, &handle.handle);
5762
return true;
5863
case HandleType::kFrameBuffer:
59-
gl.DeleteFramebuffers(1u, &handle);
64+
gl.DeleteFramebuffers(1u, &handle.handle);
6065
return true;
66+
case HandleType::kFence:
67+
gl.DeleteSync(handle.sync);
68+
break;
6169
}
6270
return false;
6371
}
@@ -116,24 +124,48 @@ const ProcTableGLES& ReactorGLES::GetProcTable() const {
116124
return *proc_table_;
117125
}
118126

119-
std::optional<GLuint> ReactorGLES::GetGLHandle(const HandleGLES& handle) const {
127+
std::optional<ReactorGLES::GLStorage> ReactorGLES::GetHandle(
128+
const HandleGLES& handle) const {
120129
ReaderLock handles_lock(handles_mutex_);
121130
if (auto found = handles_.find(handle); found != handles_.end()) {
122131
if (found->second.pending_collection) {
123132
VALIDATION_LOG
124133
<< "Attempted to acquire a handle that was pending collection.";
125134
return std::nullopt;
126135
}
127-
if (!found->second.name.has_value()) {
136+
std::optional<ReactorGLES::GLStorage> name = found->second.name;
137+
if (!name.has_value()) {
128138
VALIDATION_LOG << "Attempt to acquire a handle outside of an operation.";
129139
return std::nullopt;
130140
}
131-
return found->second.name;
141+
return name;
132142
}
133143
VALIDATION_LOG << "Attempted to acquire an invalid GL handle.";
134144
return std::nullopt;
135145
}
136146

147+
std::optional<GLuint> ReactorGLES::GetGLHandle(const HandleGLES& handle) const {
148+
if (handle.type == HandleType::kFence) {
149+
return std::nullopt;
150+
}
151+
std::optional<ReactorGLES::GLStorage> gl_handle = GetHandle(handle);
152+
if (gl_handle.has_value()) {
153+
return gl_handle->handle;
154+
}
155+
return std::nullopt;
156+
}
157+
158+
std::optional<GLsync> ReactorGLES::GetGLFence(const HandleGLES& handle) const {
159+
if (handle.type != HandleType::kFence) {
160+
return std::nullopt;
161+
}
162+
std::optional<ReactorGLES::GLStorage> gl_handle = GetHandle(handle);
163+
if (gl_handle.has_value()) {
164+
return gl_handle->sync;
165+
}
166+
return std::nullopt;
167+
}
168+
137169
bool ReactorGLES::AddOperation(Operation operation) {
138170
if (!operation) {
139171
return false;
@@ -171,9 +203,9 @@ HandleGLES ReactorGLES::CreateHandle(HandleType type, GLuint external_handle) {
171203
}
172204
WriterLock handles_lock(handles_mutex_);
173205

174-
std::optional<GLuint> gl_handle;
206+
std::optional<ReactorGLES::GLStorage> gl_handle;
175207
if (external_handle != GL_NONE) {
176-
gl_handle = external_handle;
208+
gl_handle = ReactorGLES::GLStorage{.handle = external_handle};
177209
} else if (CanReactOnCurrentThread()) {
178210
gl_handle = CreateGLHandle(GetProcTable(), type);
179211
}
@@ -215,6 +247,8 @@ static DebugResourceType ToDebugResourceType(HandleType type) {
215247
return DebugResourceType::kRenderBuffer;
216248
case HandleType::kFrameBuffer:
217249
return DebugResourceType::kFrameBuffer;
250+
case HandleType::kFence:
251+
return DebugResourceType::kFence;
218252
}
219253
FML_UNREACHABLE();
220254
}
@@ -253,9 +287,10 @@ bool ReactorGLES::ConsolidateHandles() {
253287
handle.second.name = gl_handle;
254288
}
255289
// Set pending debug labels.
256-
if (handle.second.pending_debug_label.has_value()) {
290+
if (handle.second.pending_debug_label.has_value() &&
291+
handle.first.type != HandleType::kFence) {
257292
if (gl.SetDebugLabel(ToDebugResourceType(handle.first.type),
258-
handle.second.name.value(),
293+
handle.second.name.value().handle,
259294
handle.second.pending_debug_label.value())) {
260295
handle.second.pending_debug_label = std::nullopt;
261296
}

0 commit comments

Comments
 (0)