[Impeller] GPU Tracer for GLES. (flutter/engine#47080)

Trace GPU execution time on GLES using GL_EXT_disjoint_timer_query. This requires a per-app opt in from the Android Manifest with the key `"io.flutter.embedding.android.EnableOpenGLGPUTracing` set to true.
This commit is contained in:
Jonah Williams 2023-10-20 10:20:43 -07:00 committed by GitHub
parent 3d9bc06e13
commit 8031a09e17
23 changed files with 364 additions and 49 deletions

View File

@ -2086,6 +2086,8 @@ ORIGIN: ../../../flutter/impeller/renderer/backend/gles/device_buffer_gles.h + .
ORIGIN: ../../../flutter/impeller/renderer/backend/gles/formats_gles.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/gles/formats_gles.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/gles/gles.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/gles/gpu_tracer_gles.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/gles/gpu_tracer_gles.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/gles/handle_gles.cc + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/gles/handle_gles.h + ../../../flutter/LICENSE
ORIGIN: ../../../flutter/impeller/renderer/backend/gles/pipeline_gles.cc + ../../../flutter/LICENSE
@ -4855,6 +4857,8 @@ FILE: ../../../flutter/impeller/renderer/backend/gles/device_buffer_gles.h
FILE: ../../../flutter/impeller/renderer/backend/gles/formats_gles.cc
FILE: ../../../flutter/impeller/renderer/backend/gles/formats_gles.h
FILE: ../../../flutter/impeller/renderer/backend/gles/gles.h
FILE: ../../../flutter/impeller/renderer/backend/gles/gpu_tracer_gles.cc
FILE: ../../../flutter/impeller/renderer/backend/gles/gpu_tracer_gles.h
FILE: ../../../flutter/impeller/renderer/backend/gles/handle_gles.cc
FILE: ../../../flutter/impeller/renderer/backend/gles/handle_gles.h
FILE: ../../../flutter/impeller/renderer/backend/gles/pipeline_gles.cc

View File

@ -228,6 +228,10 @@ struct Settings {
// must be available to the application.
bool enable_vulkan_validation = false;
// Enable GPU tracing in GLES backends.
// Some devices claim to support the required APIs but crash on their usage.
bool enable_opengl_gpu_tracing = false;
// Data set by platform-specific embedders for use in font initialization.
uint32_t font_initialization_data = 0;

View File

@ -112,8 +112,8 @@ std::shared_ptr<Context> PlaygroundImplGLES::GetContext() const {
return nullptr;
}
auto context =
ContextGLES::Create(std::move(gl), ShaderLibraryMappingsForPlayground());
auto context = ContextGLES::Create(
std::move(gl), ShaderLibraryMappingsForPlayground(), true);
if (!context) {
FML_LOG(ERROR) << "Could not create context.";
return nullptr;

View File

@ -16,6 +16,7 @@ impeller_component("gles_unittests") {
sources = [
"test/capabilities_unittests.cc",
"test/formats_gles_unittests.cc",
"test/gpu_tracer_gles_unittests.cc",
"test/mock_gles.cc",
"test/mock_gles.h",
"test/mock_gles_unittests.cc",
@ -51,6 +52,8 @@ impeller_component("gles") {
"formats_gles.cc",
"formats_gles.h",
"gles.h",
"gpu_tracer_gles.cc",
"gpu_tracer_gles.h",
"handle_gles.cc",
"handle_gles.h",
"pipeline_gles.cc",

View File

@ -3,23 +3,27 @@
// found in the LICENSE file.
#include "impeller/renderer/backend/gles/context_gles.h"
#include <memory>
#include "impeller/base/config.h"
#include "impeller/base/validation.h"
#include "impeller/renderer/backend/gles/command_buffer_gles.h"
#include "impeller/renderer/backend/gles/gpu_tracer_gles.h"
namespace impeller {
std::shared_ptr<ContextGLES> ContextGLES::Create(
std::unique_ptr<ProcTableGLES> gl,
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries) {
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries,
bool enable_gpu_tracing) {
return std::shared_ptr<ContextGLES>(
new ContextGLES(std::move(gl), shader_libraries));
new ContextGLES(std::move(gl), shader_libraries, enable_gpu_tracing));
}
ContextGLES::ContextGLES(std::unique_ptr<ProcTableGLES> gl,
const std::vector<std::shared_ptr<fml::Mapping>>&
shader_libraries_mappings) {
ContextGLES::ContextGLES(
std::unique_ptr<ProcTableGLES> gl,
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries_mappings,
bool enable_gpu_tracing) {
reactor_ = std::make_shared<ReactorGLES>(std::move(gl));
if (!reactor_->IsValid()) {
VALIDATION_LOG << "Could not create valid reactor.";
@ -61,7 +65,8 @@ ContextGLES::ContextGLES(std::unique_ptr<ProcTableGLES> gl,
std::shared_ptr<SamplerLibraryGLES>(new SamplerLibraryGLES(
device_capabilities_->SupportsDecalSamplerAddressMode()));
}
gpu_tracer_ = std::make_shared<GPUTracerGLES>(GetReactor()->GetProcTable(),
enable_gpu_tracing);
is_valid_ = true;
}

View File

@ -4,10 +4,13 @@
#pragma once
#include <thread>
#include <unordered_map>
#include "flutter/fml/macros.h"
#include "impeller/base/backend_cast.h"
#include "impeller/renderer/backend/gles/allocator_gles.h"
#include "impeller/renderer/backend/gles/capabilities_gles.h"
#include "impeller/renderer/backend/gles/gpu_tracer_gles.h"
#include "impeller/renderer/backend/gles/pipeline_library_gles.h"
#include "impeller/renderer/backend/gles/reactor_gles.h"
#include "impeller/renderer/backend/gles/sampler_library_gles.h"
@ -23,7 +26,8 @@ class ContextGLES final : public Context,
public:
static std::shared_ptr<ContextGLES> Create(
std::unique_ptr<ProcTableGLES> gl,
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries);
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries,
bool enable_gpu_tracing);
// |Context|
~ContextGLES() override;
@ -38,12 +42,16 @@ class ContextGLES final : public Context,
bool RemoveReactorWorker(ReactorGLES::WorkerID id);
std::shared_ptr<GPUTracerGLES> GetGPUTracer() const { return gpu_tracer_; }
private:
ReactorGLES::Ref reactor_;
std::shared_ptr<ShaderLibraryGLES> shader_library_;
std::shared_ptr<PipelineLibraryGLES> pipeline_library_;
std::shared_ptr<SamplerLibraryGLES> sampler_library_;
std::shared_ptr<AllocatorGLES> resource_allocator_;
std::shared_ptr<GPUTracerGLES> gpu_tracer_;
// Note: This is stored separately from the ProcTableGLES CapabilitiesGLES
// in order to satisfy the Context::GetCapabilities signature which returns
// a reference.
@ -52,7 +60,8 @@ class ContextGLES final : public Context,
ContextGLES(
std::unique_ptr<ProcTableGLES> gl,
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries);
const std::vector<std::shared_ptr<fml::Mapping>>& shader_libraries,
bool enable_gpu_tracing);
// |Context|
std::string DescribeGpuModel() const override;

View File

@ -0,0 +1,88 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "impeller/renderer/backend/gles/gpu_tracer_gles.h"
#include <thread>
#include "fml/trace_event.h"
namespace impeller {
GPUTracerGLES::GPUTracerGLES(const ProcTableGLES& gl, bool enable_tracing) {
#ifdef IMPELLER_DEBUG
auto desc = gl.GetDescription();
enabled_ =
enable_tracing && desc->HasExtension("GL_EXT_disjoint_timer_query");
#endif // IMPELLER_DEBUG
}
void GPUTracerGLES::MarkFrameStart(const ProcTableGLES& gl) {
if (!enabled_ || active_frame_.has_value() ||
std::this_thread::get_id() != raster_thread_) {
return;
}
// At the beginning of a frame, check the status of all pending
// previous queries.
ProcessQueries(gl);
uint32_t query = 0;
gl.GenQueriesEXT(1, &query);
if (query == 0) {
return;
}
active_frame_ = query;
gl.BeginQueryEXT(GL_TIME_ELAPSED_EXT, query);
}
void GPUTracerGLES::RecordRasterThread() {
raster_thread_ = std::this_thread::get_id();
}
void GPUTracerGLES::ProcessQueries(const ProcTableGLES& gl) {
// For reasons unknown to me, querying the state of more than
// one query object per frame causes crashes on a Pixel 6 pro.
// It does not crash on an S10.
while (!pending_traces_.empty()) {
auto query = pending_traces_.front();
// First check if the query is complete without blocking
// on the result. Incomplete results are left in the pending
// trace vector and will not be checked again for another
// frame.
GLuint available = GL_FALSE;
gl.GetQueryObjectuivEXT(query, GL_QUERY_RESULT_AVAILABLE_EXT, &available);
if (available != GL_TRUE) {
// If a query is not available, then all subsequent queries will be
// unavailable.
return;
}
// Return the timer resolution in nanoseconds.
uint64_t duration = 0;
gl.GetQueryObjectui64vEXT(query, GL_QUERY_RESULT_EXT, &duration);
auto gpu_ms = duration / 1000000.0;
FML_TRACE_COUNTER("flutter", "GPUTracer",
reinterpret_cast<int64_t>(this), // Trace Counter ID
"FrameTimeMS", gpu_ms);
gl.DeleteQueriesEXT(1, &query);
pending_traces_.pop_front();
}
}
void GPUTracerGLES::MarkFrameEnd(const ProcTableGLES& gl) {
if (!enabled_ || std::this_thread::get_id() != raster_thread_ ||
!active_frame_.has_value()) {
return;
}
auto query = active_frame_.value();
gl.EndQueryEXT(GL_TIME_ELAPSED_EXT);
pending_traces_.push_back(query);
active_frame_ = std::nullopt;
}
} // namespace impeller

View File

@ -0,0 +1,51 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#pragma once
#include <deque>
#include <thread>
#include "impeller/renderer/backend/gles/proc_table_gles.h"
namespace impeller {
/// @brief Trace GPU execution times using GL_EXT_disjoint_timer_query on GLES.
///
/// Note: there are a substantial number of GPUs where usage of the this API is
/// known to cause crashes. As a result, this functionality is disabled by
/// default and can only be enabled in debug/profile mode via a specific opt-in
/// flag that is exposed in the Android manifest.
///
/// To enable, add the following metadata to the application's Android manifest:
/// <meta-data
/// android:name="io.flutter.embedding.android.EnableOpenGLGPUTracing"
/// android:value="false" />
class GPUTracerGLES {
public:
GPUTracerGLES(const ProcTableGLES& gl, bool enable_tracing);
~GPUTracerGLES() = default;
/// @brief Record the thread id of the raster thread.
void RecordRasterThread();
/// @brief Record the start of a frame workload, if one hasn't already been
/// started.
void MarkFrameStart(const ProcTableGLES& gl);
/// @brief Record the end of a frame workload.
void MarkFrameEnd(const ProcTableGLES& gl);
private:
void ProcessQueries(const ProcTableGLES& gl);
std::deque<uint32_t> pending_traces_;
std::optional<uint32_t> active_frame_ = std::nullopt;
std::thread::id raster_thread_;
bool enabled_ = false;
};
} // namespace impeller

View File

@ -196,7 +196,13 @@ struct GLProc {
PROC(PushDebugGroupKHR); \
PROC(PopDebugGroupKHR); \
PROC(ObjectLabelKHR); \
PROC(RenderbufferStorageMultisampleEXT);
PROC(RenderbufferStorageMultisampleEXT); \
PROC(GenQueriesEXT); \
PROC(DeleteQueriesEXT); \
PROC(GetQueryObjectui64vEXT); \
PROC(BeginQueryEXT); \
PROC(EndQueryEXT); \
PROC(GetQueryObjectuivEXT);
enum class DebugResourceType {
kTexture,

View File

@ -7,8 +7,10 @@
#include "flutter/fml/trace_event.h"
#include "fml/closure.h"
#include "impeller/base/validation.h"
#include "impeller/renderer/backend/gles/context_gles.h"
#include "impeller/renderer/backend/gles/device_buffer_gles.h"
#include "impeller/renderer/backend/gles/formats_gles.h"
#include "impeller/renderer/backend/gles/gpu_tracer_gles.h"
#include "impeller/renderer/backend/gles/pipeline_gles.h"
#include "impeller/renderer/backend/gles/texture_gles.h"
@ -141,7 +143,8 @@ struct RenderPassData {
const RenderPassData& pass_data,
const std::shared_ptr<Allocator>& transients_allocator,
const ReactorGLES& reactor,
const std::vector<Command>& commands) {
const std::vector<Command>& commands,
const std::shared_ptr<GPUTracerGLES>& tracer) {
TRACE_EVENT0("impeller", "RenderPassGLES::EncodeCommandsInReactor");
if (commands.empty()) {
@ -149,6 +152,9 @@ struct RenderPassData {
}
const auto& gl = reactor.GetProcTable();
#ifdef IMPELLER_DEBUG
tracer->MarkFrameStart(gl);
#endif // IMPELLER_DEBUG
fml::ScopedCleanupClosure pop_pass_debug_marker(
[&gl]() { gl.PopDebugGroup(); });
@ -492,6 +498,11 @@ struct RenderPassData {
attachments.data() // size
);
}
#ifdef IMPELLER_DEBUG
if (is_default_fbo) {
tracer->MarkFrameEnd(gl);
}
#endif // IMPELLER_DEBUG
return true;
}
@ -549,12 +560,13 @@ bool RenderPassGLES::OnEncodeCommands(const Context& context) const {
}
std::shared_ptr<const RenderPassGLES> shared_this = shared_from_this();
auto tracer = ContextGLES::Cast(context).GetGPUTracer();
return reactor_->AddOperation([pass_data,
allocator = context.GetResourceAllocator(),
render_pass = std::move(shared_this)](
const auto& reactor) {
render_pass = std::move(shared_this),
tracer](const auto& reactor) {
auto result = EncodeCommandsInReactor(*pass_data, allocator, reactor,
render_pass->commands_);
render_pass->commands_, tracer);
FML_CHECK(result) << "Must be able to encode GL commands without error.";
});
}

View File

@ -60,6 +60,10 @@ std::unique_ptr<Surface> SurfaceGLES::WrapFBO(
render_target_desc.SetColorAttachment(color0, 0u);
render_target_desc.SetStencilAttachment(stencil0);
#ifdef IMPELLER_DEBUG
gl_context.GetGPUTracer()->RecordRasterThread();
#endif // IMPELLER_DEBUG
return std::unique_ptr<SurfaceGLES>(
new SurfaceGLES(std::move(swap_callback), render_target_desc));
}

View File

@ -0,0 +1,50 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "flutter/testing/testing.h" // IWYU pragma: keep
#include "gtest/gtest.h"
#include "impeller/renderer/backend/gles/gpu_tracer_gles.h"
#include "impeller/renderer/backend/gles/test/mock_gles.h"
namespace impeller {
namespace testing {
#ifdef IMPELLER_DEBUG
TEST(GPUTracerGLES, CanFormatFramebufferErrorMessage) {
auto const extensions = std::vector<const unsigned char*>{
reinterpret_cast<const unsigned char*>("GL_KHR_debug"), //
reinterpret_cast<const unsigned char*>("GL_EXT_disjoint_timer_query"), //
};
auto mock_gles = MockGLES::Init(extensions);
auto tracer =
std::make_shared<GPUTracerGLES>(mock_gles->GetProcTable(), true);
tracer->RecordRasterThread();
tracer->MarkFrameStart(mock_gles->GetProcTable());
tracer->MarkFrameEnd(mock_gles->GetProcTable());
auto calls = mock_gles->GetCapturedCalls();
std::vector<std::string> expected = {"glGenQueriesEXT", "glBeginQueryEXT",
"glEndQueryEXT"};
for (auto i = 0; i < 3; i++) {
EXPECT_EQ(calls[i], expected[i]);
}
// Begin second frame, which prompts the tracer to query the result
// from the previous frame.
tracer->MarkFrameStart(mock_gles->GetProcTable());
calls = mock_gles->GetCapturedCalls();
std::vector<std::string> expected_b = {"glGetQueryObjectuivEXT",
"glGetQueryObjectui64vEXT",
"glDeleteQueriesEXT"};
for (auto i = 0; i < 3; i++) {
EXPECT_EQ(calls[i], expected_b[i]);
}
}
#endif // IMPELLER_DEBUG
} // namespace testing
} // namespace impeller

View File

@ -112,6 +112,53 @@ void mockPushDebugGroupKHR(GLenum source,
static_assert(CheckSameSignature<decltype(mockPushDebugGroupKHR), //
decltype(glPushDebugGroupKHR)>::value);
void mockGenQueriesEXT(GLsizei n, GLuint* ids) {
RecordGLCall("glGenQueriesEXT");
for (auto i = 0; i < n; i++) {
ids[i] = i + 1;
}
}
static_assert(CheckSameSignature<decltype(mockGenQueriesEXT), //
decltype(glGenQueriesEXT)>::value);
void mockBeginQueryEXT(GLenum target, GLuint id) {
RecordGLCall("glBeginQueryEXT");
}
static_assert(CheckSameSignature<decltype(mockBeginQueryEXT), //
decltype(glBeginQueryEXT)>::value);
void mockEndQueryEXT(GLuint id) {
RecordGLCall("glEndQueryEXT");
}
static_assert(CheckSameSignature<decltype(mockEndQueryEXT), //
decltype(glEndQueryEXT)>::value);
void mockGetQueryObjectuivEXT(GLuint id, GLenum target, GLuint* result) {
RecordGLCall("glGetQueryObjectuivEXT");
*result = GL_TRUE;
}
static_assert(CheckSameSignature<decltype(mockGetQueryObjectuivEXT), //
decltype(glGetQueryObjectuivEXT)>::value);
void mockGetQueryObjectui64vEXT(GLuint id, GLenum target, GLuint64* result) {
RecordGLCall("glGetQueryObjectui64vEXT");
*result = 1000u;
}
static_assert(CheckSameSignature<decltype(mockGetQueryObjectui64vEXT), //
decltype(glGetQueryObjectui64vEXT)>::value);
void mockDeleteQueriesEXT(GLsizei size, const GLuint* queries) {
RecordGLCall("glDeleteQueriesEXT");
}
static_assert(CheckSameSignature<decltype(mockDeleteQueriesEXT), //
decltype(glDeleteQueriesEXT)>::value);
std::shared_ptr<MockGLES> MockGLES::Init(
const std::optional<std::vector<const unsigned char*>>& extensions) {
// If we cannot obtain a lock, MockGLES is already being used elsewhere.
@ -136,6 +183,18 @@ const ProcTableGLES::Resolver kMockResolver = [](const char* name) {
return reinterpret_cast<void*>(&mockGetIntegerv);
} else if (strcmp(name, "glGetError") == 0) {
return reinterpret_cast<void*>(&mockGetError);
} else if (strcmp(name, "glGenQueriesEXT") == 0) {
return reinterpret_cast<void*>(&mockGenQueriesEXT);
} else if (strcmp(name, "glBeginQueryEXT") == 0) {
return reinterpret_cast<void*>(&mockBeginQueryEXT);
} else if (strcmp(name, "glEndQueryEXT") == 0) {
return reinterpret_cast<void*>(&mockEndQueryEXT);
} else if (strcmp(name, "glDeleteQueriesEXT") == 0) {
return reinterpret_cast<void*>(&mockDeleteQueriesEXT);
} else if (strcmp(name, "glGetQueryObjectui64vEXT") == 0) {
return reinterpret_cast<void*>(mockGetQueryObjectui64vEXT);
} else if (strcmp(name, "glGetQueryObjectuivEXT") == 0) {
return reinterpret_cast<void*>(mockGetQueryObjectuivEXT);
} else {
return reinterpret_cast<void*>(&doNothing);
}

View File

@ -17,9 +17,8 @@ namespace impeller {
class ContextMTL;
/// @brief Approximate the GPU frame time by computing a difference between the
/// smallest
/// GPUStartTime and largest GPUEndTime for all cmd buffers submitted in
/// a frame workload.
/// smallest GPUStartTime and largest GPUEndTime for all command buffers
/// submitted in a frame workload.
class GPUTracerMTL : public std::enable_shared_from_this<GPUTracerMTL> {
public:
GPUTracerMTL() = default;
@ -27,13 +26,11 @@ class GPUTracerMTL : public std::enable_shared_from_this<GPUTracerMTL> {
~GPUTracerMTL() = default;
/// @brief Record that the current frame has ended. Any additional cmd buffers
/// will be
/// attributed to the "next" frame.
/// will be attributed to the "next" frame.
void MarkFrameEnd();
/// @brief Record the current cmd buffer GPU execution timestamps into an
/// aggregate
/// frame workload metric.
/// aggregate frame workload metric.
void RecordCmdBuffer(id<MTLCommandBuffer> buffer);
private:

View File

@ -477,6 +477,8 @@ Settings SettingsFromCommandLine(const fml::CommandLine& command_line) {
settings.enable_vulkan_validation =
command_line.HasOption(FlagForSwitch(Switch::EnableVulkanValidation));
settings.enable_opengl_gpu_tracing =
command_line.HasOption(FlagForSwitch(Switch::EnableOpenGLGPUTracing));
settings.enable_embedder_api =
command_line.HasOption(FlagForSwitch(Switch::EnableEmbedderAPI));

View File

@ -275,6 +275,10 @@ DEF_SWITCH(EnableVulkanValidation,
"Enable loading Vulkan validation layers. The layers must be "
"available to the application and loadable. On non-Vulkan backends, "
"this flag does nothing.")
DEF_SWITCH(EnableOpenGLGPUTracing,
"enable-opengl-gpu-tracing",
"Enable tracing of GPU execution time when using the Impeller "
"OpenGLES backend.")
DEF_SWITCH(LeakVM,
"leak-vm",
"When the last shell shuts down, the shared VM is leaked by default "

View File

@ -49,7 +49,8 @@ class AndroidContextGLImpeller::ReactorWorker final
};
static std::shared_ptr<impeller::Context> CreateImpellerContext(
const std::shared_ptr<impeller::ReactorGLES::Worker>& worker) {
const std::shared_ptr<impeller::ReactorGLES::Worker>& worker,
bool enable_gpu_tracing) {
auto proc_table = std::make_unique<impeller::ProcTableGLES>(
impeller::egl::CreateProcAddressResolver());
@ -59,19 +60,20 @@ static std::shared_ptr<impeller::Context> CreateImpellerContext(
}
std::vector<std::shared_ptr<fml::Mapping>> shader_mappings = {
std::make_shared<fml::NonOwnedMapping>(impeller_entity_shaders_gles_data,
impeller_entity_shaders_gles_length),
std::make_shared<fml::NonOwnedMapping>(
impeller_framebuffer_blend_shaders_gles_data,
impeller_framebuffer_blend_shaders_gles_length),
std::make_shared<fml::NonOwnedMapping>(
impeller_entity_shaders_gles_data,
impeller_entity_shaders_gles_length),
std::make_shared<fml::NonOwnedMapping>(
impeller_framebuffer_blend_shaders_gles_data,
impeller_framebuffer_blend_shaders_gles_length),
#if IMPELLER_ENABLE_3D
std::make_shared<fml::NonOwnedMapping>(impeller_scene_shaders_gles_data,
impeller_scene_shaders_gles_length),
std::make_shared<fml::NonOwnedMapping>(
impeller_scene_shaders_gles_data, impeller_scene_shaders_gles_length),
#endif // IMPELLER_ENABLE_3D
};
auto context =
impeller::ContextGLES::Create(std::move(proc_table), shader_mappings);
auto context = impeller::ContextGLES::Create(
std::move(proc_table), shader_mappings, enable_gpu_tracing);
if (!context) {
FML_LOG(ERROR) << "Could not create OpenGLES Impeller Context.";
return nullptr;
@ -86,7 +88,8 @@ static std::shared_ptr<impeller::Context> CreateImpellerContext(
}
AndroidContextGLImpeller::AndroidContextGLImpeller(
std::unique_ptr<impeller::egl::Display> display)
std::unique_ptr<impeller::egl::Display> display,
bool enable_gpu_tracing)
: AndroidContext(AndroidRenderingAPI::kOpenGLES),
reactor_worker_(std::shared_ptr<ReactorWorker>(new ReactorWorker())),
display_(std::move(display)) {
@ -147,7 +150,8 @@ AndroidContextGLImpeller::AndroidContextGLImpeller(
return;
}
auto impeller_context = CreateImpellerContext(reactor_worker_);
auto impeller_context =
CreateImpellerContext(reactor_worker_, enable_gpu_tracing);
if (!impeller_context) {
FML_DLOG(ERROR) << "Could not create Impeller context.";

View File

@ -13,8 +13,8 @@ namespace flutter {
class AndroidContextGLImpeller : public AndroidContext {
public:
explicit AndroidContextGLImpeller(
std::unique_ptr<impeller::egl::Display> display);
AndroidContextGLImpeller(std::unique_ptr<impeller::egl::Display> display,
bool enable_gpu_tracing);
~AndroidContextGLImpeller();

View File

@ -45,7 +45,8 @@ TEST(AndroidContextGLImpeller, MSAAFirstAttempt) {
.WillOnce(Return(ByMove(std::move(second_result))));
ON_CALL(*display, ChooseConfig(_))
.WillByDefault(Return(ByMove(std::unique_ptr<Config>())));
auto context = std::make_unique<AndroidContextGLImpeller>(std::move(display));
auto context =
std::make_unique<AndroidContextGLImpeller>(std::move(display), true);
ASSERT_TRUE(context);
}
@ -76,7 +77,8 @@ TEST(AndroidContextGLImpeller, FallbackForEmulator) {
.WillOnce(Return(ByMove(std::move(third_result))));
ON_CALL(*display, ChooseConfig(_))
.WillByDefault(Return(ByMove(std::unique_ptr<Config>())));
auto context = std::make_unique<AndroidContextGLImpeller>(std::move(display));
auto context =
std::make_unique<AndroidContextGLImpeller>(std::move(display), true);
ASSERT_TRUE(context);
}
} // namespace testing

View File

@ -14,7 +14,7 @@ namespace flutter {
class AndroidContextVulkanImpeller : public AndroidContext {
public:
AndroidContextVulkanImpeller(bool enable_validation);
explicit AndroidContextVulkanImpeller(bool enable_validation);
~AndroidContextVulkanImpeller();

View File

@ -45,6 +45,8 @@ public class FlutterLoader {
"io.flutter.embedding.android.EnableVulkanValidation";
private static final String IMPELLER_BACKEND_META_DATA_KEY =
"io.flutter.embedding.android.ImpellerBackend";
private static final String IMPELLER_OPENGL_GPU_TRACING_DATA_KEY =
"io.flutter.embedding.android.EnableOpenGLGPUTracing";
private static final String DISABLE_IMAGE_READER_PLATFORM_VIEWS_KEY =
"io.flutter.embedding.android.DisableImageReaderPlatformViews";
@ -340,6 +342,9 @@ public class FlutterLoader {
ENABLE_VULKAN_VALIDATION_META_DATA_KEY, areValidationLayersOnByDefault())) {
shellArgs.add("--enable-vulkan-validation");
}
if (metaData.getBoolean(IMPELLER_OPENGL_GPU_TRACING_DATA_KEY, false)) {
shellArgs.add("--enable-opengl-gpu-tracing");
}
String backend = metaData.getString(IMPELLER_BACKEND_META_DATA_KEY);
if (backend != null) {
shellArgs.add("--impeller-backend=" + backend);

View File

@ -70,7 +70,8 @@ static std::shared_ptr<flutter::AndroidContext> CreateAndroidContext(
uint8_t msaa_samples,
bool enable_impeller,
const std::optional<std::string>& impeller_backend,
bool enable_vulkan_validation) {
bool enable_vulkan_validation,
bool enable_opengl_gpu_tracing) {
if (use_software_rendering) {
return std::make_shared<AndroidContext>(AndroidRenderingAPI::kSoftware);
}
@ -90,7 +91,8 @@ static std::shared_ptr<flutter::AndroidContext> CreateAndroidContext(
switch (backend) {
case AndroidRenderingAPI::kOpenGLES:
return std::make_unique<AndroidContextGLImpeller>(
std::make_unique<impeller::egl::Display>());
std::make_unique<impeller::egl::Display>(),
enable_opengl_gpu_tracing);
case AndroidRenderingAPI::kVulkan:
return std::make_unique<AndroidContextVulkanImpeller>(
enable_vulkan_validation);
@ -99,7 +101,8 @@ static std::shared_ptr<flutter::AndroidContext> CreateAndroidContext(
enable_vulkan_validation);
if (!vulkan_backend->IsValid()) {
return std::make_unique<AndroidContextGLImpeller>(
std::make_unique<impeller::egl::Display>());
std::make_unique<impeller::egl::Display>(),
enable_opengl_gpu_tracing);
}
return vulkan_backend;
}
@ -131,7 +134,9 @@ PlatformViewAndroid::PlatformViewAndroid(
msaa_samples,
delegate.OnPlatformViewGetSettings().enable_impeller,
delegate.OnPlatformViewGetSettings().impeller_backend,
delegate.OnPlatformViewGetSettings().enable_vulkan_validation)) {}
delegate.OnPlatformViewGetSettings().enable_vulkan_validation,
delegate.OnPlatformViewGetSettings().enable_opengl_gpu_tracing)) {
}
PlatformViewAndroid::PlatformViewAndroid(
PlatformView::Delegate& delegate,

View File

@ -65,11 +65,12 @@ EmbedderSurfaceGLImpeller::EmbedderSurfaceGLImpeller(
gl_dispatch_table_.gl_make_current_callback();
std::vector<std::shared_ptr<fml::Mapping>> shader_mappings = {
std::make_shared<fml::NonOwnedMapping>(impeller_entity_shaders_gles_data,
impeller_entity_shaders_gles_length),
std::make_shared<fml::NonOwnedMapping>(
impeller_entity_shaders_gles_data,
impeller_entity_shaders_gles_length),
#if IMPELLER_ENABLE_3D
std::make_shared<fml::NonOwnedMapping>(impeller_scene_shaders_gles_data,
impeller_scene_shaders_gles_length),
std::make_shared<fml::NonOwnedMapping>(
impeller_scene_shaders_gles_data, impeller_scene_shaders_gles_length),
#endif // IMPELLER_ENABLE_3D
};
auto gl = std::make_unique<impeller::ProcTableGLES>(
@ -78,8 +79,8 @@ EmbedderSurfaceGLImpeller::EmbedderSurfaceGLImpeller(
return;
}
impeller_context_ =
impeller::ContextGLES::Create(std::move(gl), shader_mappings);
impeller_context_ = impeller::ContextGLES::Create(
std::move(gl), shader_mappings, /*enable_gpu_tracing=*/false);
if (!impeller_context_) {
FML_LOG(ERROR) << "Could not create Impeller context.";