Skip to content

Commit 1a925fb

Browse files
lhkbobSkCQ
authored and
SkCQ
committed
[graphite] Add RecorderOptions.fRequireOrderedRecordings
Recorders already were tracking their ordered sequence of Recordings separately from each other. This adds the ability for the client to require (or not) that Recordings be inserted in order on a per-Recorder basis. This allows compositing-like Recorders more flexibility when it's very likely they won't be relying on any internal atlasing (that takes incurs overhead when there aren't ordering assumptions). But as long as these unordered Recorders don't render text, they won't hit that slow path. Bug: b/406292843 Change-Id: I72c907003b07bd79177a81c88dcd6117c216f093 Reviewed-on: https://skia-review.googlesource.com/c/skia/+/973737 Reviewed-by: Jim Van Verth <[email protected]> Auto-Submit: Michael Ludwig <[email protected]> Reviewed-by: Greg Daniel <[email protected]> Commit-Queue: Michael Ludwig <[email protected]>
1 parent 5aab4d2 commit 1a925fb

File tree

7 files changed

+79
-12
lines changed

7 files changed

+79
-12
lines changed

include/gpu/graphite/ContextOptions.h

+11-3
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,18 @@ struct SK_API ContextOptions {
8989
bool fSupportBilerpFromGlyphAtlas = false;
9090

9191
/**
92-
* For the moment, if Recordings are replayed in the order they are recorded, then
93-
* Graphite can make certain assumptions that allow for better performance. Otherwise
94-
* we have to flush some caches at the start of each Recording to ensure that they can
92+
* For the moment, if Recordings from the same Recorder are replayed in the order they are
93+
* recorded, then Graphite can make certain assumptions that allow for better performance.
94+
* Otherwise we have to flush some caches at the start of each Recording to ensure that they can
9595
* be played back properly.
96+
*
97+
* This is the default ordering requirement for a Recorder. It can be overridden by
98+
* setting the same field on the RecorderOptions passed to makeRecorder.
99+
*
100+
* Regardless of this value or a per-Recorder's setting, Recordings from separate Recorders can
101+
* always be inserted in any order but it is the application's responsible to ensure that any
102+
* implicit dependencies between the Recorders are respected (e.g. rendering to an SkSurface
103+
* in one Recorder and sampling from that SkSurface's SkImage view on another Recorder).
96104
*/
97105
bool fRequireOrderedRecordings = false;
98106

include/gpu/graphite/Recorder.h

+7
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "include/private/base/SkTArray.h"
1717

1818
#include <chrono>
19+
#include <optional>
1920

2021
struct AHardwareBuffer;
2122
class SkCanvas;
@@ -70,6 +71,10 @@ struct SK_API RecorderOptions final {
7071
static constexpr size_t kDefaultRecorderBudget = 256 * (1 << 20);
7172
// What is the budget for GPU resources allocated and held by this Recorder.
7273
size_t fGpuBudgetInBytes = kDefaultRecorderBudget;
74+
// If Recordings are known to be played back in the order they are recorded, then Graphite
75+
// may be able to make certain assuptions that improve performance. This is often the case
76+
// if the content being drawn triggers the use of internal atlasing in Graphite (e.g. text).
77+
std::optional<bool> fRequireOrderedRecordings;
7378
};
7479

7580
class SK_API Recorder final {
@@ -281,6 +286,8 @@ class SK_API Recorder final {
281286

282287
uint32_t fUniqueID; // Needed for MessageBox handling for text
283288
uint32_t fNextRecordingID = 1;
289+
const bool fRequireOrderedRecordings;
290+
284291
std::unique_ptr<AtlasProvider> fAtlasProvider;
285292
std::unique_ptr<TokenTracker> fTokenTracker;
286293
std::unique_ptr<sktext::gpu::StrikeCache> fStrikeCache;

include/gpu/graphite/Recording.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ class SK_API Recording final {
7272
bool addCommands(CommandBuffer*, ResourceProvider*);
7373
void addResourceRef(sk_sp<Resource>);
7474

75-
// Used to verify ordering
75+
// Used to verify ordering if recorder ID is not SK_InvalidGenID
7676
uint32_t fUniqueID;
7777
uint32_t fRecorderID;
7878

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
`RecorderOptions.fRequireOrderedRecordings` can now be used to specify a per-`Recorder` ordering
2+
policy for how its `Recordings` must be inserted into a `Context`. If not provided, the `Recorder`
3+
will default to the value in `ContextOptions`.

src/gpu/graphite/QueueManager.cpp

+7-6
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,12 @@ bool QueueManager::addRecording(const InsertRecordingInfo& info, Context* contex
106106
return false;
107107
}
108108

109-
if (fSharedContext->caps()->requireOrderedRecordings()) {
110-
uint32_t* recordingID = fLastAddedRecordingIDs.find(info.fRecording->priv().recorderID());
111-
if (recordingID &&
112-
info.fRecording->priv().uniqueID() != *recordingID+1) {
109+
// Recordings from a Recorder that requires ordered recordings will have a valid recorder ID.
110+
// Recordings that don't have any required order are assigned SK_InvalidID.
111+
uint32_t recorderID = info.fRecording->priv().recorderID();
112+
if (recorderID != SK_InvalidGenID) {
113+
uint32_t* recordingID = fLastAddedRecordingIDs.find(recorderID);
114+
if (recordingID && info.fRecording->priv().uniqueID() != *recordingID + 1) {
113115
if (callback) {
114116
callback->setFailureResult();
115117
}
@@ -118,8 +120,7 @@ bool QueueManager::addRecording(const InsertRecordingInfo& info, Context* contex
118120
}
119121

120122
// Note the new Recording ID.
121-
fLastAddedRecordingIDs.set(info.fRecording->priv().recorderID(),
122-
info.fRecording->priv().uniqueID());
123+
fLastAddedRecordingIDs.set(recorderID, info.fRecording->priv().uniqueID());
123124
}
124125

125126
if (info.fTargetSurface &&

src/gpu/graphite/Recorder.cpp

+6-2
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,9 @@ Recorder::Recorder(sk_sp<SharedContext> sharedContext,
102102
, fTextureDataCache(new TextureDataCache)
103103
, fProxyReadCounts(new ProxyReadCountMap)
104104
, fUniqueID(next_id())
105+
, fRequireOrderedRecordings(options.fRequireOrderedRecordings.has_value()
106+
? *options.fRequireOrderedRecordings
107+
: fSharedContext->caps()->requireOrderedRecordings())
105108
, fAtlasProvider(std::make_unique<AtlasProvider>(this))
106109
, fTokenTracker(std::make_unique<TokenTracker>())
107110
, fStrikeCache(std::make_unique<sktext::gpu::StrikeCache>())
@@ -189,7 +192,8 @@ std::unique_ptr<Recording> Recorder::snap() {
189192
// Recorder doesn't hold a persistent manager and it can be deleted when snap() returns.
190193
ScratchResourceManager scratchManager{fResourceProvider, std::move(fProxyReadCounts)};
191194
std::unique_ptr<Recording> recording(new Recording(fNextRecordingID++,
192-
fUniqueID,
195+
fRequireOrderedRecordings ? fUniqueID
196+
: SK_InvalidGenID,
193197
std::move(nonVolatileLazyProxies),
194198
std::move(volatileLazyProxies),
195199
std::move(fTargetProxyData),
@@ -227,7 +231,7 @@ std::unique_ptr<Recording> Recorder::snap() {
227231
fRuntimeEffectDict->reset();
228232
fProxyReadCounts = std::make_unique<ProxyReadCountMap>();
229233
fTextureDataCache = std::make_unique<TextureDataCache>();
230-
if (!this->priv().caps()->requireOrderedRecordings()) {
234+
if (!fRequireOrderedRecordings) {
231235
fAtlasProvider->invalidateAtlases();
232236
}
233237

tests/graphite/RecorderTest.cpp

+44
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#include "include/gpu/graphite/Context.h"
1111
#include "include/gpu/graphite/Recorder.h"
1212
#include "src/gpu/SkBackingFit.h"
13+
#include "src/gpu/graphite/ContextPriv.h"
1314
#include "src/gpu/graphite/Device.h"
1415
#include "src/gpu/graphite/RecorderPriv.h"
1516

@@ -100,3 +101,46 @@ DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecorderDevicePtrTest, reporter, context,
100101
device1.reset();
101102
device3.reset();
102103
}
104+
105+
// Tests to make sure the Recorders can override the ordering requirement.
106+
DEF_GRAPHITE_TEST_FOR_ALL_CONTEXTS(RecorderOrderingTest, reporter, context,
107+
CtsEnforcement::kNever) {
108+
std::unique_ptr<Recorder> orderedRecorder, unorderedRecorder;
109+
110+
if (context->priv().caps()->requireOrderedRecordings()) {
111+
orderedRecorder = context->makeRecorder();
112+
RecorderOptions opts;
113+
opts.fRequireOrderedRecordings = false;
114+
unorderedRecorder = context->makeRecorder(opts);
115+
} else {
116+
RecorderOptions opts;
117+
opts.fRequireOrderedRecordings = true;
118+
orderedRecorder = context->makeRecorder(opts);
119+
unorderedRecorder = context->makeRecorder();
120+
}
121+
122+
auto insert = [context](Recording* r) {
123+
InsertRecordingInfo info;
124+
info.fRecording = r;
125+
return context->insertRecording(info);
126+
};
127+
128+
std::unique_ptr<Recording> o1 = orderedRecorder->snap();
129+
std::unique_ptr<Recording> o2 = orderedRecorder->snap();
130+
std::unique_ptr<Recording> o3 = orderedRecorder->snap();
131+
132+
std::unique_ptr<Recording> u1 = unorderedRecorder->snap();
133+
std::unique_ptr<Recording> u2 = unorderedRecorder->snap();
134+
135+
// Unordered insertion of an unordered Recorder succeeds.
136+
// NOTE: These Recordings are all out-of-order with respect to orderedRecorder, which had been
137+
// snapped multiple times before unorderedRecorder. That is always allowed.
138+
REPORTER_ASSERT(reporter, insert(u2.get()));
139+
REPORTER_ASSERT(reporter, insert(u1.get()));
140+
141+
// Unordered insertion of an ordered Recorder fails
142+
REPORTER_ASSERT(reporter, insert(o1.get())); // succeeds (first insertion)
143+
REPORTER_ASSERT(reporter, !insert(o3.get())); // fails for out of order
144+
REPORTER_ASSERT(reporter, insert(o2.get())); // succeeds and recovers
145+
REPORTER_ASSERT(reporter, insert(o3.get())); // now in order success
146+
}

0 commit comments

Comments
 (0)