mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Made it so you can whitelist what events you want to listen to (#17108)
This commit is contained in:
parent
733933ad5c
commit
fddb0c272e
@ -107,6 +107,9 @@ FILE: ../../../flutter/flow/view_holder.cc
|
||||
FILE: ../../../flutter/flow/view_holder.h
|
||||
FILE: ../../../flutter/flutter_frontend_server/bin/starter.dart
|
||||
FILE: ../../../flutter/flutter_frontend_server/lib/server.dart
|
||||
FILE: ../../../flutter/fml/ascii_trie.cc
|
||||
FILE: ../../../flutter/fml/ascii_trie.h
|
||||
FILE: ../../../flutter/fml/ascii_trie_unittests.cc
|
||||
FILE: ../../../flutter/fml/backtrace.cc
|
||||
FILE: ../../../flutter/fml/backtrace.h
|
||||
FILE: ../../../flutter/fml/backtrace_stub.cc
|
||||
|
||||
@ -91,6 +91,7 @@ struct Settings {
|
||||
bool enable_checked_mode = false;
|
||||
bool start_paused = false;
|
||||
bool trace_skia = false;
|
||||
std::string trace_whitelist;
|
||||
bool trace_startup = false;
|
||||
bool trace_systrace = false;
|
||||
bool dump_skp_on_shader_compilation = false;
|
||||
|
||||
@ -10,6 +10,8 @@ import("//flutter/testing/testing.gni")
|
||||
|
||||
source_set("fml") {
|
||||
sources = [
|
||||
"ascii_trie.cc",
|
||||
"ascii_trie.h",
|
||||
"backtrace.h",
|
||||
"base32.cc",
|
||||
"base32.h",
|
||||
@ -236,6 +238,7 @@ executable("fml_unittests") {
|
||||
testonly = true
|
||||
|
||||
sources = [
|
||||
"ascii_trie_unittests.cc",
|
||||
"backtrace_unittests.cc",
|
||||
"base32_unittest.cc",
|
||||
"command_line_unittest.cc",
|
||||
|
||||
48
fml/ascii_trie.cc
Normal file
48
fml/ascii_trie.cc
Normal file
@ -0,0 +1,48 @@
|
||||
// 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/fml/ascii_trie.h"
|
||||
#include "flutter/fml/logging.h"
|
||||
|
||||
namespace fml {
|
||||
typedef AsciiTrie::TrieNode TrieNode;
|
||||
typedef AsciiTrie::TrieNodePtr TrieNodePtr;
|
||||
|
||||
namespace {
|
||||
void Add(TrieNodePtr* trie, const char* entry) {
|
||||
int ch = entry[0];
|
||||
FML_DCHECK(ch < AsciiTrie::kMaxAsciiValue);
|
||||
if (ch != 0) {
|
||||
if (!*trie) {
|
||||
*trie = std::make_unique<TrieNode>();
|
||||
}
|
||||
Add(&(*trie)->children[ch], entry + 1);
|
||||
}
|
||||
}
|
||||
|
||||
TrieNodePtr MakeTrie(const std::vector<std::string>& entries) {
|
||||
TrieNodePtr result;
|
||||
for (const std::string& entry : entries) {
|
||||
Add(&result, entry.c_str());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void AsciiTrie::Fill(const std::vector<std::string>& entries) {
|
||||
node_ = MakeTrie(entries);
|
||||
}
|
||||
|
||||
bool AsciiTrie::Query(TrieNode* trie, const char* query) {
|
||||
FML_DCHECK(trie);
|
||||
const char* char_position = query;
|
||||
TrieNode* trie_position = trie;
|
||||
TrieNode* child;
|
||||
int ch;
|
||||
while ((ch = *char_position) && (child = trie_position->children[ch].get())) {
|
||||
char_position++;
|
||||
trie_position = child;
|
||||
}
|
||||
return !child && trie_position != trie;
|
||||
}
|
||||
} // namespace fml
|
||||
39
fml/ascii_trie.h
Normal file
39
fml/ascii_trie.h
Normal file
@ -0,0 +1,39 @@
|
||||
// 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.
|
||||
|
||||
#ifndef FLUTTER_FML_ASCIITRIE_H_
|
||||
#define FLUTTER_FML_ASCIITRIE_H_
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace fml {
|
||||
|
||||
/// A trie for looking for ASCII prefixes.
|
||||
class AsciiTrie {
|
||||
public:
|
||||
struct TrieNode;
|
||||
typedef std::unique_ptr<TrieNode> TrieNodePtr;
|
||||
/// The max Ascii value.
|
||||
static const int kMaxAsciiValue = 128;
|
||||
|
||||
/// Clear and insert all the entries into the trie.
|
||||
void Fill(const std::vector<std::string>& entries);
|
||||
|
||||
/// Returns true if \p argument is prefixed by the contents of the trie.
|
||||
inline bool Query(const char* argument) {
|
||||
return !node_ || Query(node_.get(), argument);
|
||||
}
|
||||
|
||||
struct TrieNode {
|
||||
TrieNodePtr children[kMaxAsciiValue];
|
||||
};
|
||||
|
||||
private:
|
||||
static bool Query(TrieNode* trie, const char* query);
|
||||
TrieNodePtr node_;
|
||||
};
|
||||
} // namespace fml
|
||||
|
||||
#endif
|
||||
36
fml/ascii_trie_unittests.cc
Normal file
36
fml/ascii_trie_unittests.cc
Normal file
@ -0,0 +1,36 @@
|
||||
// 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/fml/ascii_trie.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
using fml::AsciiTrie;
|
||||
|
||||
TEST(AsciiTableTest, Simple) {
|
||||
AsciiTrie trie;
|
||||
auto entries = std::vector<std::string>{"foo"};
|
||||
trie.Fill(entries);
|
||||
ASSERT_TRUE(trie.Query("foobar"));
|
||||
ASSERT_FALSE(trie.Query("google"));
|
||||
}
|
||||
|
||||
TEST(AsciiTableTest, ExactMatch) {
|
||||
AsciiTrie trie;
|
||||
auto entries = std::vector<std::string>{"foo"};
|
||||
trie.Fill(entries);
|
||||
ASSERT_TRUE(trie.Query("foo"));
|
||||
}
|
||||
|
||||
TEST(AsciiTableTest, Empty) {
|
||||
AsciiTrie trie;
|
||||
ASSERT_TRUE(trie.Query("foo"));
|
||||
}
|
||||
|
||||
TEST(AsciiTableTest, MultipleEntries) {
|
||||
AsciiTrie trie;
|
||||
auto entries = std::vector<std::string>{"foo", "bar"};
|
||||
trie.Fill(entries);
|
||||
ASSERT_TRUE(trie.Query("foozzz"));
|
||||
ASSERT_TRUE(trie.Query("barzzz"));
|
||||
}
|
||||
@ -8,6 +8,7 @@
|
||||
#include <atomic>
|
||||
#include <utility>
|
||||
|
||||
#include "flutter/fml/ascii_trie.h"
|
||||
#include "flutter/fml/build_config.h"
|
||||
#include "flutter/fml/logging.h"
|
||||
|
||||
@ -22,6 +23,27 @@ namespace tracing {
|
||||
|
||||
#if TIMELINE_ENABLED
|
||||
|
||||
namespace {
|
||||
AsciiTrie gWhitelist;
|
||||
|
||||
inline void FlutterTimelineEvent(const char* label,
|
||||
int64_t timestamp0,
|
||||
int64_t timestamp1_or_async_id,
|
||||
Dart_Timeline_Event_Type type,
|
||||
intptr_t argument_count,
|
||||
const char** argument_names,
|
||||
const char** argument_values) {
|
||||
if (gWhitelist.Query(label)) {
|
||||
Dart_TimelineEvent(label, timestamp0, timestamp1_or_async_id, type,
|
||||
argument_count, argument_names, argument_values);
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void TraceSetWhitelist(const std::vector<std::string>& whitelist) {
|
||||
gWhitelist.Fill(whitelist);
|
||||
}
|
||||
|
||||
size_t TraceNonce() {
|
||||
static std::atomic_size_t gLastItem;
|
||||
return ++gLastItem;
|
||||
@ -42,7 +64,7 @@ void TraceTimelineEvent(TraceArg category_group,
|
||||
c_values[i] = values[i].c_str();
|
||||
}
|
||||
|
||||
Dart_TimelineEvent(
|
||||
FlutterTimelineEvent(
|
||||
name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
identifier, // timestamp1_or_async_id
|
||||
@ -54,13 +76,13 @@ void TraceTimelineEvent(TraceArg category_group,
|
||||
}
|
||||
|
||||
void TraceEvent0(TraceArg category_group, TraceArg name) {
|
||||
Dart_TimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
0, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Begin, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
FlutterTimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
0, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Begin, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
);
|
||||
}
|
||||
|
||||
@ -70,13 +92,13 @@ void TraceEvent1(TraceArg category_group,
|
||||
TraceArg arg1_val) {
|
||||
const char* arg_names[] = {arg1_name};
|
||||
const char* arg_values[] = {arg1_val};
|
||||
Dart_TimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
0, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Begin, // event type
|
||||
1, // argument_count
|
||||
arg_names, // argument_names
|
||||
arg_values // argument_values
|
||||
FlutterTimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
0, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Begin, // event type
|
||||
1, // argument_count
|
||||
arg_names, // argument_names
|
||||
arg_values // argument_values
|
||||
);
|
||||
}
|
||||
|
||||
@ -88,24 +110,24 @@ void TraceEvent2(TraceArg category_group,
|
||||
TraceArg arg2_val) {
|
||||
const char* arg_names[] = {arg1_name, arg2_name};
|
||||
const char* arg_values[] = {arg1_val, arg2_val};
|
||||
Dart_TimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
0, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Begin, // event type
|
||||
2, // argument_count
|
||||
arg_names, // argument_names
|
||||
arg_values // argument_values
|
||||
FlutterTimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
0, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Begin, // event type
|
||||
2, // argument_count
|
||||
arg_names, // argument_names
|
||||
arg_values // argument_values
|
||||
);
|
||||
}
|
||||
|
||||
void TraceEventEnd(TraceArg name) {
|
||||
Dart_TimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
0, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_End, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
FlutterTimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
0, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_End, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
);
|
||||
}
|
||||
|
||||
@ -119,47 +141,47 @@ void TraceEventAsyncComplete(TraceArg category_group,
|
||||
std::swap(begin, end);
|
||||
}
|
||||
|
||||
Dart_TimelineEvent(name, // label
|
||||
begin.ToEpochDelta().ToMicroseconds(), // timestamp0
|
||||
identifier, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Async_Begin, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
FlutterTimelineEvent(name, // label
|
||||
begin.ToEpochDelta().ToMicroseconds(), // timestamp0
|
||||
identifier, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Async_Begin, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
);
|
||||
Dart_TimelineEvent(name, // label
|
||||
end.ToEpochDelta().ToMicroseconds(), // timestamp0
|
||||
identifier, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Async_End, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
FlutterTimelineEvent(name, // label
|
||||
end.ToEpochDelta().ToMicroseconds(), // timestamp0
|
||||
identifier, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Async_End, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
);
|
||||
}
|
||||
|
||||
void TraceEventAsyncBegin0(TraceArg category_group,
|
||||
TraceArg name,
|
||||
TraceIDArg id) {
|
||||
Dart_TimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
id, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Async_Begin, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
FlutterTimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
id, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Async_Begin, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
);
|
||||
}
|
||||
|
||||
void TraceEventAsyncEnd0(TraceArg category_group,
|
||||
TraceArg name,
|
||||
TraceIDArg id) {
|
||||
Dart_TimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
id, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Async_End, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
FlutterTimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
id, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Async_End, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
);
|
||||
}
|
||||
|
||||
@ -170,13 +192,13 @@ void TraceEventAsyncBegin1(TraceArg category_group,
|
||||
TraceArg arg1_val) {
|
||||
const char* arg_names[] = {arg1_name};
|
||||
const char* arg_values[] = {arg1_val};
|
||||
Dart_TimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
id, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Async_Begin, // event type
|
||||
1, // argument_count
|
||||
arg_names, // argument_names
|
||||
arg_values // argument_values
|
||||
FlutterTimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
id, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Async_Begin, // event type
|
||||
1, // argument_count
|
||||
arg_names, // argument_names
|
||||
arg_values // argument_values
|
||||
);
|
||||
}
|
||||
|
||||
@ -187,66 +209,68 @@ void TraceEventAsyncEnd1(TraceArg category_group,
|
||||
TraceArg arg1_val) {
|
||||
const char* arg_names[] = {arg1_name};
|
||||
const char* arg_values[] = {arg1_val};
|
||||
Dart_TimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
id, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Async_End, // event type
|
||||
1, // argument_count
|
||||
arg_names, // argument_names
|
||||
arg_values // argument_values
|
||||
FlutterTimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
id, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Async_End, // event type
|
||||
1, // argument_count
|
||||
arg_names, // argument_names
|
||||
arg_values // argument_values
|
||||
);
|
||||
}
|
||||
|
||||
void TraceEventInstant0(TraceArg category_group, TraceArg name) {
|
||||
Dart_TimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
0, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Instant, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
FlutterTimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
0, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Instant, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
);
|
||||
}
|
||||
|
||||
void TraceEventFlowBegin0(TraceArg category_group,
|
||||
TraceArg name,
|
||||
TraceIDArg id) {
|
||||
Dart_TimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
id, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Flow_Begin, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
FlutterTimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
id, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Flow_Begin, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
);
|
||||
}
|
||||
|
||||
void TraceEventFlowStep0(TraceArg category_group,
|
||||
TraceArg name,
|
||||
TraceIDArg id) {
|
||||
Dart_TimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
id, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Flow_Step, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
FlutterTimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
id, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Flow_Step, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
);
|
||||
}
|
||||
|
||||
void TraceEventFlowEnd0(TraceArg category_group, TraceArg name, TraceIDArg id) {
|
||||
Dart_TimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
id, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Flow_End, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
FlutterTimelineEvent(name, // label
|
||||
Dart_TimelineGetMicros(), // timestamp0
|
||||
id, // timestamp1_or_async_id
|
||||
Dart_Timeline_Event_Flow_End, // event type
|
||||
0, // argument_count
|
||||
nullptr, // argument_names
|
||||
nullptr // argument_values
|
||||
);
|
||||
}
|
||||
|
||||
#else // TIMELINE_ENABLED
|
||||
|
||||
void TraceSetWhitelist(const std::vector<std::string>& whitelist) {}
|
||||
|
||||
size_t TraceNonce() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -112,6 +112,8 @@ namespace tracing {
|
||||
using TraceArg = const char*;
|
||||
using TraceIDArg = int64_t;
|
||||
|
||||
void TraceSetWhitelist(const std::vector<std::string>& whitelist);
|
||||
|
||||
void TraceTimelineEvent(TraceArg category_group,
|
||||
TraceArg name,
|
||||
TraceIDArg id,
|
||||
|
||||
@ -180,6 +180,16 @@ static void RecordStartupTimestamp() {
|
||||
}
|
||||
}
|
||||
|
||||
static void Tokenize(const std::string& input,
|
||||
std::vector<std::string>* results,
|
||||
char delimiter) {
|
||||
std::istringstream ss(input);
|
||||
std::string token;
|
||||
while (std::getline(ss, token, delimiter)) {
|
||||
results->push_back(token);
|
||||
}
|
||||
}
|
||||
|
||||
// Though there can be multiple shells, some settings apply to all components in
|
||||
// the process. These have to be setup before the shell or any of its
|
||||
// sub-components can be initialized. In a perfect world, this would be empty.
|
||||
@ -205,6 +215,12 @@ static void PerformInitializationTasks(const Settings& settings) {
|
||||
InitSkiaEventTracer(settings.trace_skia);
|
||||
}
|
||||
|
||||
if (!settings.trace_whitelist.empty()) {
|
||||
std::vector<std::string> prefixes;
|
||||
Tokenize(settings.trace_whitelist, &prefixes, ',');
|
||||
fml::tracing::TraceSetWhitelist(prefixes);
|
||||
}
|
||||
|
||||
if (!settings.skia_deterministic_rendering_on_cpu) {
|
||||
SkGraphics::Init();
|
||||
} else {
|
||||
|
||||
@ -272,6 +272,9 @@ Settings SettingsFromCommandLine(const fml::CommandLine& command_line) {
|
||||
settings.trace_skia =
|
||||
command_line.HasOption(FlagForSwitch(Switch::TraceSkia));
|
||||
|
||||
command_line.GetOptionValue(FlagForSwitch(Switch::TraceWhitelist),
|
||||
&settings.trace_whitelist);
|
||||
|
||||
settings.trace_systrace =
|
||||
command_line.HasOption(FlagForSwitch(Switch::TraceSystrace));
|
||||
|
||||
|
||||
@ -129,6 +129,11 @@ DEF_SWITCH(TraceSkia,
|
||||
"Trace Skia calls. This is useful when debugging the GPU threed."
|
||||
"By default, Skia tracing is not enabled to reduce the number of "
|
||||
"traced events")
|
||||
DEF_SWITCH(
|
||||
TraceWhitelist,
|
||||
"trace-whitelist",
|
||||
"Filters out all trace events except those that are specified in this "
|
||||
"comma separated list of whitelisted prefixes.")
|
||||
DEF_SWITCH(DumpSkpOnShaderCompilation,
|
||||
"dump-skp-on-shader-compilation",
|
||||
"Automatically dump the skp that triggers new shader compilations. "
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user