[graphite] Add PrecompileContext object
This CL introduces an object that can be created on the main thread and then moved to a precompilation thread. This is substantially safer than passing the Context to a precompilation thread.
It also holds a ResourceProvider so eliminates the need to allocate a new one for each Precompile call.
Bug: b/358074434
Bug: b/373849852
Change-Id: I4ba4530655d65224dcd68e1b1a3e2a0d477bd5fd
Reviewed-on: https://skia-review.googlesource.com/c/skia/+/919738
Reviewed-by: Michael Ludwig <michaelludwig@google.com>
Commit-Queue: Robert Phillips <robertphillips@google.com>
diff --git a/dm/DMSrcSink.cpp b/dm/DMSrcSink.cpp
index 115ecb9..b53988d 100644
--- a/dm/DMSrcSink.cpp
+++ b/dm/DMSrcSink.cpp
@@ -113,11 +113,12 @@
#include "tools/graphite/GraphiteTestContext.h"
#if defined(SK_ENABLE_PRECOMPILE)
+#include "src/gpu/graphite/AndroidSpecificPrecompile.h"
#include "src/gpu/graphite/Caps.h"
#include "src/gpu/graphite/ContextPriv.h"
#include "src/gpu/graphite/GraphicsPipeline.h"
#include "src/gpu/graphite/GraphicsPipelineDesc.h"
-#include "src/gpu/graphite/PublicPrecompile.h"
+#include "src/gpu/graphite/PrecompileContextPriv.h"
#include "src/gpu/graphite/RecorderPriv.h"
#include "src/gpu/graphite/RenderPassDesc.h"
#include "src/gpu/graphite/RendererProvider.h"
@@ -2253,6 +2254,10 @@
}
}
+ if (!fPrecompileContext) {
+ fPrecompileContext = context->makePrecompileContext();
+ }
+
sk_sp<SkSurface> surface = this->makeSurface(fRecorder.get(), src.size());
if (!surface) {
return Result::Fatal("Could not create a surface.");
@@ -2279,24 +2284,25 @@
return Result::Ok();
}
-Result GraphitePrecompileTestingSink::resetAndRecreatePipelines(
- skgpu::graphite::Context* context) const {
+Result GraphitePrecompileTestingSink::resetAndRecreatePipelines() const {
using namespace skgpu::graphite;
- SkASSERT(fRecorder);
+ SkASSERT(fRecorder && fPrecompileContext);
+
+ GlobalCache* globalCache = fPrecompileContext->priv().globalCache();
RuntimeEffectDictionary* rteDict = fRecorder->priv().runtimeEffectDictionary();
std::vector<skgpu::UniqueKey> origKeys;
- UniqueKeyUtils::FetchUniqueKeys(context->priv().globalCache(), &origKeys);
+ UniqueKeyUtils::FetchUniqueKeys(fPrecompileContext.get(), &origKeys);
- SkDEBUGCODE(int numBeforeReset = context->priv().globalCache()->numGraphicsPipelines();)
+ SkDEBUGCODE(int numBeforeReset = globalCache->numGraphicsPipelines();)
SkASSERT(numBeforeReset == (int) origKeys.size());
- context->priv().globalCache()->resetGraphicsPipelines();
+ fPrecompileContext->priv().globalCache()->resetGraphicsPipelines();
- SkASSERT(context->priv().globalCache()->numGraphicsPipelines() == 0);
+ SkASSERT(globalCache->numGraphicsPipelines() == 0);
for (const skgpu::UniqueKey& k : origKeys) {
// TODO: add a separate path that decomposes the keys into PaintOptions
@@ -2304,43 +2310,41 @@
GraphicsPipelineDesc pipelineDesc;
RenderPassDesc renderPassDesc;
- if (!UniqueKeyUtils::ExtractKeyDescs(context, k, &pipelineDesc, &renderPassDesc)) {
+ if (!UniqueKeyUtils::ExtractKeyDescs(fPrecompileContext.get(), k,
+ &pipelineDesc, &renderPassDesc)) {
continue;
}
- Precompile(context, rteDict, pipelineDesc, renderPassDesc);
+ AndroidSpecificPrecompile(fPrecompileContext.get(), rteDict,
+ pipelineDesc, renderPassDesc);
}
- SkDEBUGCODE(int postRecreate = context->priv().globalCache()->numGraphicsPipelines();)
+ SkDEBUGCODE(int postRecreate = globalCache->numGraphicsPipelines();)
SkASSERT(numBeforeReset == postRecreate);
{
std::vector<skgpu::UniqueKey> recreatedKeys;
- UniqueKeyUtils::FetchUniqueKeys(context->priv().globalCache(), &recreatedKeys);
+ UniqueKeyUtils::FetchUniqueKeys(fPrecompileContext.get(), &recreatedKeys);
for (const skgpu::UniqueKey& origKey : origKeys) {
if(std::find(recreatedKeys.begin(), recreatedKeys.end(), origKey) ==
recreatedKeys.end()) {
- sk_sp<GraphicsPipeline> pipeline =
- context->priv().globalCache()->findGraphicsPipeline(origKey);
+ sk_sp<GraphicsPipeline> pipeline = globalCache->findGraphicsPipeline(origKey);
SkASSERT(!pipeline);
#ifdef SK_DEBUG
- const RendererProvider* rendererProvider = context->priv().rendererProvider();
- const ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
-
{
GraphicsPipelineDesc originalPipelineDesc;
RenderPassDesc originalRenderPassDesc;
- UniqueKeyUtils::ExtractKeyDescs(context, origKey,
+ UniqueKeyUtils::ExtractKeyDescs(fPrecompileContext.get(), origKey,
&originalPipelineDesc,
&originalRenderPassDesc);
SkDebugf("------- Missing key from rebuilt keys:\n");
origKey.dump("original key:");
- UniqueKeyUtils::DumpDescs(rendererProvider, dict,
+ UniqueKeyUtils::DumpDescs(fPrecompileContext.get(),
originalPipelineDesc,
originalRenderPassDesc);
}
@@ -2351,13 +2355,13 @@
GraphicsPipelineDesc recreatedPipelineDesc;
RenderPassDesc recreatedRenderPassDesc;
- UniqueKeyUtils::ExtractKeyDescs(context, recreatedKey,
+ UniqueKeyUtils::ExtractKeyDescs(fPrecompileContext.get(), recreatedKey,
&recreatedPipelineDesc,
&recreatedRenderPassDesc);
SkDebugf("%d ----\n", count++);
recreatedKey.dump("recreated key:");
- UniqueKeyUtils::DumpDescs(rendererProvider, dict,
+ UniqueKeyUtils::DumpDescs(fPrecompileContext.get(),
recreatedPipelineDesc,
recreatedRenderPassDesc);
}
@@ -2403,7 +2407,7 @@
// Call resetAndRecreatePipelines to clear out all the Pipelines in the global cache and then
// regenerate them using the Precompilation system.
- result = this->resetAndRecreatePipelines(context);
+ result = this->resetAndRecreatePipelines();
if (!result.isOk()) {
fRecorder.reset();
return result;
diff --git a/dm/DMSrcSink.h b/dm/DMSrcSink.h
index 0f0bfa7..4881afb 100644
--- a/dm/DMSrcSink.h
+++ b/dm/DMSrcSink.h
@@ -13,6 +13,7 @@
#include "include/core/SkCanvas.h"
#include "include/core/SkPicture.h"
#include "include/docs/SkMultiPictureDocument.h"
+#include "include/gpu/graphite/PrecompileContext.h"
#include "tools/flags/CommonFlagsConfig.h"
#include "tools/gpu/MemoryCache.h"
@@ -616,9 +617,10 @@
Result drawSrc(const Src&,
skgpu::graphite::Context*,
skiatest::graphite::GraphiteTestContext*) const;
- Result resetAndRecreatePipelines(skgpu::graphite::Context*) const;
+ Result resetAndRecreatePipelines() const;
mutable std::unique_ptr<skgpu::graphite::Recorder> fRecorder;
+ mutable std::unique_ptr<skgpu::graphite::PrecompileContext> fPrecompileContext;
};
#endif // SK_ENABLE_PRECOMPILE
#endif // SK_GRAPHITE
diff --git a/gn/graphite.gni b/gn/graphite.gni
index 665d077..e8de6980 100644
--- a/gn/graphite.gni
+++ b/gn/graphite.gni
@@ -16,6 +16,7 @@
"$_include/GraphiteTypes.h",
"$_include/Image.h",
"$_include/ImageProvider.h",
+ "$_include/PrecompileContext.h",
"$_include/Recorder.h",
"$_include/Recording.h",
"$_include/Surface.h",
@@ -101,6 +102,8 @@
"$_src/PathAtlas.cpp",
"$_src/PathAtlas.h",
"$_src/PipelineData.h",
+ "$_src/PrecompileContext.cpp",
+ "$_src/PrecompileContextPriv.h",
"$_src/ProxyCache.cpp",
"$_src/ProxyCache.h",
"$_src/QueueManager.cpp",
@@ -378,9 +381,9 @@
]
skia_graphite_precompile_sources = [
+ "$_src/AndroidSpecificPrecompile.h",
"$_src/PrecompileInternal.h",
"$_src/PublicPrecompile.cpp",
- "$_src/PublicPrecompile.h",
"$_src/precompile/PaintOption.cpp",
"$_src/precompile/PaintOption.h",
"$_src/precompile/PaintOptions.cpp",
diff --git a/include/gpu/graphite/BUILD.bazel b/include/gpu/graphite/BUILD.bazel
index e5bbbf1..8369dd0 100644
--- a/include/gpu/graphite/BUILD.bazel
+++ b/include/gpu/graphite/BUILD.bazel
@@ -16,6 +16,7 @@
"GraphiteTypes.h",
"Image.h",
"ImageProvider.h",
+ "PrecompileContext.h",
"Recorder.h",
"Recording.h",
"Surface.h",
diff --git a/include/gpu/graphite/Context.h b/include/gpu/graphite/Context.h
index 2112412..d751c70 100644
--- a/include/gpu/graphite/Context.h
+++ b/include/gpu/graphite/Context.h
@@ -33,7 +33,7 @@
class ContextPriv;
class GlobalCache;
class PaintOptions;
-class PlotUploadTracker;
+class PrecompileContext;
class QueueManager;
class Recording;
class ResourceProvider;
@@ -53,6 +53,11 @@
std::unique_ptr<Recorder> makeRecorder(const RecorderOptions& = {});
+ /** Creates a helper object that can be moved to a different thread and used
+ * for precompilation.
+ */
+ std::unique_ptr<PrecompileContext> makePrecompileContext();
+
bool insertRecording(const InsertRecordingInfo&);
bool submit(SyncToCpu = SyncToCpu::kNo);
diff --git a/include/gpu/graphite/PrecompileContext.h b/include/gpu/graphite/PrecompileContext.h
new file mode 100644
index 0000000..47810e9
--- /dev/null
+++ b/include/gpu/graphite/PrecompileContext.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef skgpu_graphite_PrecompileContext_DEFINED
+#define skgpu_graphite_PrecompileContext_DEFINED
+
+#include "include/core/SkRefCnt.h"
+#include "include/private/base/SingleOwner.h"
+
+#include <memory>
+
+namespace skgpu::graphite {
+
+class SharedContext;
+class PrecompileContextPriv;
+class ResourceProvider;
+
+class SK_API PrecompileContext {
+public:
+ ~PrecompileContext();
+
+ // Provides access to functions that aren't part of the public API.
+ PrecompileContextPriv priv();
+ const PrecompileContextPriv priv() const; // NOLINT(readability-const-return-type)
+
+private:
+ friend class PrecompileContextPriv;
+ friend class Context; // for ctor
+
+ PrecompileContext(sk_sp<SharedContext>);
+
+ mutable SingleOwner fSingleOwner;
+ sk_sp<SharedContext> fSharedContext;
+ std::unique_ptr<ResourceProvider> fResourceProvider;
+};
+
+} // namespace skgpu::graphite
+
+#endif // skgpu_graphite_PrecompileContext_DEFINED
diff --git a/include/gpu/graphite/precompile/Precompile.h b/include/gpu/graphite/precompile/Precompile.h
index a26c73e..f138539 100644
--- a/include/gpu/graphite/precompile/Precompile.h
+++ b/include/gpu/graphite/precompile/Precompile.h
@@ -15,6 +15,7 @@
class Context;
class PaintOptions;
+class PrecompileContext;
/**
* Describes the required properties of a RenderPass that will be combined with the
@@ -33,11 +34,17 @@
* drawing. Graphite will always be able to perform an inline compilation if some SkPaint
* combination was omitted from precompilation.
*
- * @param context the Context to which the actual draws will be submitted
+ * @param precompileContext thread-safe helper holding required portions of the Context
* @param paintOptions captures a set of SkPaints that will be drawn
* @param drawTypes communicates which primitives those paints will be drawn with
* @param renderPassProperties describes the RenderPasses needed for the desired Pipelines
*/
+void SK_API Precompile(PrecompileContext* precompileContext,
+ const PaintOptions& paintOptions,
+ DrawTypeFlags drawTypes,
+ SkSpan<const RenderPassProperties> renderPassProperties);
+
+// Deprecated. Please use PrecompileContext version.
void SK_API Precompile(Context* context,
const PaintOptions& paintOptions,
DrawTypeFlags drawTypes,
diff --git a/relnotes/precompilecontext.md b/relnotes/precompilecontext.md
new file mode 100644
index 0000000..c6c64f5
--- /dev/null
+++ b/relnotes/precompilecontext.md
@@ -0,0 +1,21 @@
+
+A new PrecompileContext object has been added to assist Precompilation. The old API of the form:\
+ bool Precompile(Context*, ...);\
+has been deprecated and replaced with the API:\
+ bool Precompile(PrecompileContext*, ...)\
+The new PrecompileContext object can be obtained via the Context::makePrecompileContext call.
+
+As an example of a possible Compilation/Precompilation threading model, one could employ 4 threads:
+
+2 for creating Recordings (\<r1\> and \<r2\>) \
+1 for precompiling (\<p1\>) \
+and the main thread - which owns the Context and submits Recordings.
+
+Start up for this scenario would look like:
+
+ the main thread moves a PrecompileContext to <p1> and begins precompiling there\
+ the main thread creates two Recorders and moves them to <r1> and <r2> to create Recordings\
+ the main thread continues on - calling Context::insertRecording on the posted Recordings.
+
+The PrecompileContext can safely outlive the Context that created it, but it will
+effectively be shut down at that point.
diff --git a/src/gpu/graphite/PublicPrecompile.h b/src/gpu/graphite/AndroidSpecificPrecompile.h
similarity index 68%
rename from src/gpu/graphite/PublicPrecompile.h
rename to src/gpu/graphite/AndroidSpecificPrecompile.h
index 142cd6d..8b4beee 100644
--- a/src/gpu/graphite/PublicPrecompile.h
+++ b/src/gpu/graphite/AndroidSpecificPrecompile.h
@@ -10,8 +10,8 @@
#include "include/gpu/graphite/GraphiteTypes.h"
-// TODO: this header should be moved to include/gpu/graphite once the precompilation API
-// is made public
+// TODO: this header should be moved to include/gpu/graphite once the Android-specific
+// precompilation API is made public
namespace skgpu::graphite {
class Context;
@@ -19,16 +19,16 @@
class PaintOptions;
struct RenderPassDesc;
class RuntimeEffectDictionary;
-
+class PrecompileContext;
/*
* TODO: Rather than passing in a pipelineDesc and renderPassDesc we need to add an
* opaque serializable object that contains the same information.
*/
-bool Precompile(Context*,
- RuntimeEffectDictionary* rteDict,
- const GraphicsPipelineDesc& pipelineDesc,
- const RenderPassDesc& renderPassDesc);
+bool AndroidSpecificPrecompile(PrecompileContext*,
+ RuntimeEffectDictionary* rteDict,
+ const GraphicsPipelineDesc& pipelineDesc,
+ const RenderPassDesc& renderPassDesc);
} // namespace skgpu::graphite
diff --git a/src/gpu/graphite/BUILD.bazel b/src/gpu/graphite/BUILD.bazel
index 5efc831..b1db7f6 100644
--- a/src/gpu/graphite/BUILD.bazel
+++ b/src/gpu/graphite/BUILD.bazel
@@ -136,6 +136,8 @@
"TextureProxyView.h",
"TextureUtils.cpp",
"TextureUtils.h",
+ "PrecompileContext.cpp",
+ "PrecompileContextPriv.h",
"Uniform.h",
"UniformManager.cpp",
"UniformManager.h",
@@ -155,7 +157,7 @@
"FactoryFunctions.h",
"PrecompileInternal.h",
"PublicPrecompile.cpp",
- "PublicPrecompile.h",
+ "AndroidSpecificPrecompile.h",
]
split_srcs_and_hdrs(
diff --git a/src/gpu/graphite/Context.cpp b/src/gpu/graphite/Context.cpp
index c1fe543..cdd792d 100644
--- a/src/gpu/graphite/Context.cpp
+++ b/src/gpu/graphite/Context.cpp
@@ -12,6 +12,7 @@
#include "include/core/SkTraceMemoryDump.h"
#include "include/effects/SkRuntimeEffect.h"
#include "include/gpu/graphite/BackendTexture.h"
+#include "include/gpu/graphite/PrecompileContext.h"
#include "include/gpu/graphite/Recorder.h"
#include "include/gpu/graphite/Recording.h"
#include "include/gpu/graphite/Surface.h"
@@ -146,6 +147,12 @@
return recorder;
}
+std::unique_ptr<PrecompileContext> Context::makePrecompileContext() {
+ ASSERT_SINGLE_OWNER
+
+ return std::unique_ptr<PrecompileContext>(new PrecompileContext(fSharedContext));
+}
+
std::unique_ptr<Recorder> Context::makeInternalRecorder() const {
ASSERT_SINGLE_OWNER
diff --git a/src/gpu/graphite/ContextPriv.h b/src/gpu/graphite/ContextPriv.h
index 24cd25a..d95d972 100644
--- a/src/gpu/graphite/ContextPriv.h
+++ b/src/gpu/graphite/ContextPriv.h
@@ -37,12 +37,14 @@
ShaderCodeDictionary* shaderCodeDictionary() {
return fContext->fSharedContext->shaderCodeDictionary();
}
+#if defined(GPU_TEST_UTILS)
const GlobalCache* globalCache() const {
return fContext->fSharedContext->globalCache();
}
GlobalCache* globalCache() {
return fContext->fSharedContext->globalCache();
}
+#endif
const RendererProvider* rendererProvider() const {
return fContext->fSharedContext->rendererProvider();
}
diff --git a/src/gpu/graphite/PrecompileContext.cpp b/src/gpu/graphite/PrecompileContext.cpp
new file mode 100644
index 0000000..e355279
--- /dev/null
+++ b/src/gpu/graphite/PrecompileContext.cpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "include/gpu/graphite/PrecompileContext.h"
+
+#include "src/gpu/graphite/ResourceProvider.h"
+#include "src/gpu/graphite/SharedContext.h"
+
+namespace skgpu::graphite {
+
+#define ASSERT_SINGLE_OWNER SKGPU_ASSERT_SINGLE_OWNER(&fSingleOwner)
+
+PrecompileContext::~PrecompileContext() {
+ ASSERT_SINGLE_OWNER
+}
+
+PrecompileContext::PrecompileContext(sk_sp<SharedContext> sharedContext)
+ : fSharedContext(sharedContext) {
+
+ // ResourceProviders are not thread-safe. Here we create a ResourceProvider
+ // specifically for the thread on which precompilation will occur.
+ static constexpr size_t kEmptyBudget = 0;
+ fResourceProvider = fSharedContext->makeResourceProvider(
+ &fSingleOwner,
+ SK_InvalidGenID,
+ kEmptyBudget,
+ /* avoidBufferAlloc= */ true);
+}
+
+} // namespace skgpu::graphite
diff --git a/src/gpu/graphite/PrecompileContextPriv.h b/src/gpu/graphite/PrecompileContextPriv.h
new file mode 100644
index 0000000..93c24b3
--- /dev/null
+++ b/src/gpu/graphite/PrecompileContextPriv.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2024 Google LLC
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#ifndef skgpu_graphite_PrecompileContextPriv_DEFINED
+#define skgpu_graphite_PrecompileContextPriv_DEFINED
+
+#include "include/gpu/graphite/PrecompileContext.h"
+
+class Caps;
+
+namespace skgpu::graphite {
+
+/**
+ * Class that adds methods to PrecompileContext that are only intended for use internal to Skia.
+ * This class is purely a privileged window into PrecompileContext. It should never have additional
+ * data members or virtual methods.
+ */
+class PrecompileContextPriv {
+public:
+ const Caps* caps() const { return fPrecompileContext->fSharedContext->caps(); }
+ const ShaderCodeDictionary* shaderCodeDictionary() const {
+ return fPrecompileContext->fSharedContext->shaderCodeDictionary();
+ }
+ ShaderCodeDictionary* shaderCodeDictionary() {
+ return fPrecompileContext->fSharedContext->shaderCodeDictionary();
+ }
+ const RendererProvider* rendererProvider() const {
+ return fPrecompileContext->fSharedContext->rendererProvider();
+ }
+ SharedContext* sharedContext() {
+ return fPrecompileContext->fSharedContext.get();
+ }
+ ResourceProvider* resourceProvider() {
+ return fPrecompileContext->fResourceProvider.get();
+ }
+#if defined(GPU_TEST_UTILS)
+ GlobalCache* globalCache() {
+ return fPrecompileContext->fSharedContext->globalCache();
+ }
+#endif
+
+private:
+ friend class PrecompileContext; // to construct/copy this type.
+
+ explicit PrecompileContextPriv(PrecompileContext* precompileContext)
+ : fPrecompileContext(precompileContext) {}
+
+ PrecompileContextPriv& operator=(const PrecompileContextPriv&) = delete;
+
+ // No taking addresses of this type.
+ const PrecompileContextPriv* operator&() const;
+ PrecompileContextPriv *operator&();
+
+ PrecompileContext* fPrecompileContext;
+};
+
+inline PrecompileContextPriv PrecompileContext::priv() { return PrecompileContextPriv(this); }
+
+// NOLINTNEXTLINE(readability-const-return-type)
+inline const PrecompileContextPriv PrecompileContext::priv() const {
+ return PrecompileContextPriv(const_cast<PrecompileContext *>(this));
+}
+
+} // namespace skgpu::graphite
+
+#endif // skgpu_graphite_PrecompileContextPriv_DEFINED
diff --git a/src/gpu/graphite/PublicPrecompile.cpp b/src/gpu/graphite/PublicPrecompile.cpp
index 46788e5..776a97e 100644
--- a/src/gpu/graphite/PublicPrecompile.cpp
+++ b/src/gpu/graphite/PublicPrecompile.cpp
@@ -5,12 +5,12 @@
* found in the LICENSE file.
*/
-#include "src/gpu/graphite/PublicPrecompile.h"
-
#include "include/core/SkColorSpace.h"
#include "include/core/SkColorType.h"
+#include "include/gpu/graphite/PrecompileContext.h"
#include "include/gpu/graphite/precompile/Precompile.h"
#include "include/gpu/graphite/precompile/PrecompileColorFilter.h"
+#include "src/gpu/graphite/AndroidSpecificPrecompile.h"
#include "src/gpu/graphite/Caps.h"
#include "src/gpu/graphite/ContextPriv.h"
#include "src/gpu/graphite/ContextUtils.h"
@@ -18,6 +18,7 @@
#include "src/gpu/graphite/GraphicsPipelineDesc.h"
#include "src/gpu/graphite/KeyContext.h"
#include "src/gpu/graphite/Log.h"
+#include "src/gpu/graphite/PrecompileContextPriv.h"
#include "src/gpu/graphite/PrecompileInternal.h"
#include "src/gpu/graphite/RenderPassDesc.h"
#include "src/gpu/graphite/Renderer.h"
@@ -80,11 +81,11 @@
namespace skgpu::graphite {
-bool Precompile(Context* context,
- RuntimeEffectDictionary* rteDict,
- const GraphicsPipelineDesc& pipelineDesc,
- const RenderPassDesc& renderPassDesc) {
- ResourceProvider* resourceProvider = context->priv().resourceProvider();
+bool AndroidSpecificPrecompile(PrecompileContext* precompileContext,
+ RuntimeEffectDictionary* rteDict,
+ const GraphicsPipelineDesc& pipelineDesc,
+ const RenderPassDesc& renderPassDesc) {
+ ResourceProvider* resourceProvider = precompileContext->priv().resourceProvider();
sk_sp<GraphicsPipeline> pipeline = resourceProvider->findOrCreateGraphicsPipeline(
rteDict,
@@ -99,28 +100,26 @@
return true;
}
-void Precompile(Context* context, const PaintOptions& options, DrawTypeFlags drawTypes,
+/* Deprecated */
+void Precompile(Context* context,
+ const PaintOptions& options,
+ DrawTypeFlags drawTypes,
+ SkSpan<const RenderPassProperties> renderPassProperties) {
+ std::unique_ptr<PrecompileContext> precompileContext = context->makePrecompileContext();
+
+ Precompile(precompileContext.get(), options, drawTypes, renderPassProperties);
+}
+
+void Precompile(PrecompileContext* precompileContext,
+ const PaintOptions& options,
+ DrawTypeFlags drawTypes,
SkSpan<const RenderPassProperties> renderPassProperties) {
- ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
- const Caps* caps = context->priv().caps();
+ ShaderCodeDictionary* dict = precompileContext->priv().shaderCodeDictionary();
+ const Caps* caps = precompileContext->priv().caps();
auto rtEffectDict = std::make_unique<RuntimeEffectDictionary>();
- // Here we are creating a ResourceProvider for each call to 'Precompile'. The issue is that
- // 'Precompile' can be called from any number of threads but the ResourceProvider and
- // its nested ResourceCache were never intended to be thread-safe. This allocation fixes
- // the thread-safety issue but at the cost of excessive (re)allocations.
- // TODO(b/373849852): implement a better solution to the Precompile thread-safety problem.
- SharedContext* sharedContext = context->priv().sharedContext();
- SingleOwner singleOwner;
- static constexpr size_t kDefaultBudgetInBytes = 0;
- std::unique_ptr<ResourceProvider> tmpResourceProvider = sharedContext->makeResourceProvider(
- &singleOwner,
- SK_InvalidGenID,
- kDefaultBudgetInBytes,
- /* avoidBufferAlloc= */ true);
-
for (const RenderPassProperties& rpp : renderPassProperties) {
// TODO: Allow the client to pass in mipmapping and protection too?
TextureInfo info = caps->getDefaultSampledTextureInfo(rpp.fDstCT,
@@ -162,8 +161,9 @@
for (Coverage coverage : { Coverage::kNone, Coverage::kSingleChannel }) {
PrecompileCombinations(
- context->priv().rendererProvider(),
- tmpResourceProvider.get(), options, keyContext,
+ precompileContext->priv().rendererProvider(),
+ precompileContext->priv().resourceProvider(),
+ options, keyContext,
static_cast<DrawTypeFlags>(drawTypes & ~(DrawTypeFlags::kBitmapText_Color |
DrawTypeFlags::kBitmapText_LCD |
DrawTypeFlags::kSDFText_LCD |
@@ -179,8 +179,8 @@
tmp.setShaders({});
// ARGB text doesn't emit coverage and always has a primitive blender
- PrecompileCombinations(context->priv().rendererProvider(),
- tmpResourceProvider.get(),
+ PrecompileCombinations(precompileContext->priv().rendererProvider(),
+ precompileContext->priv().resourceProvider(),
tmp,
keyContext,
DrawTypeFlags::kBitmapText_Color,
@@ -192,8 +192,9 @@
if (drawTypes & (DrawTypeFlags::kBitmapText_LCD | DrawTypeFlags::kSDFText_LCD)) {
// LCD-based text always emits LCD coverage but never has primitiveBlenders
PrecompileCombinations(
- context->priv().rendererProvider(),
- tmpResourceProvider.get(), options, keyContext,
+ precompileContext->priv().rendererProvider(),
+ precompileContext->priv().resourceProvider(),
+ options, keyContext,
static_cast<DrawTypeFlags>(drawTypes & (DrawTypeFlags::kBitmapText_LCD |
DrawTypeFlags::kSDFText_LCD)),
/* withPrimitiveBlender= */ false,
@@ -205,8 +206,9 @@
// drawVertices w/ colors use a primitiveBlender while those w/o don't. It never
// emits coverage.
for (bool withPrimitiveBlender : { true, false }) {
- PrecompileCombinations(context->priv().rendererProvider(),
- tmpResourceProvider.get(), options, keyContext,
+ PrecompileCombinations(precompileContext->priv().rendererProvider(),
+ precompileContext->priv().resourceProvider(),
+ options, keyContext,
DrawTypeFlags::kDrawVertices,
withPrimitiveBlender,
Coverage::kNone,
diff --git a/tests/graphite/precompile/ChromePrecompileTest.cpp b/tests/graphite/precompile/ChromePrecompileTest.cpp
index 7e3b2db..f626e0e 100644
--- a/tests/graphite/precompile/ChromePrecompileTest.cpp
+++ b/tests/graphite/precompile/ChromePrecompileTest.cpp
@@ -10,6 +10,7 @@
#if defined(SK_GRAPHITE)
#include "include/gpu/graphite/Context.h"
+#include "include/gpu/graphite/PrecompileContext.h"
#include "include/gpu/graphite/precompile/PaintOptions.h"
#include "include/gpu/graphite/precompile/Precompile.h"
#include "include/gpu/graphite/precompile/PrecompileColorFilter.h"
@@ -17,6 +18,7 @@
#include "src/gpu/graphite/ContextPriv.h"
#include "src/gpu/graphite/ContextUtils.h"
#include "src/gpu/graphite/GraphicsPipelineDesc.h"
+#include "src/gpu/graphite/PrecompileContextPriv.h"
#include "src/gpu/graphite/RenderPassDesc.h"
#include "src/gpu/graphite/RendererProvider.h"
#include "tools/graphite/UniqueKeyUtils.h"
@@ -102,7 +104,7 @@
// the expected string is in the generated set.
// Additionally, verify that overgeneration is within expected tolerances.
// If you add an additional RenderStep you may need to increase the tolerance values.
-void run_test(Context* context,
+void run_test(PrecompileContext* precompileContext,
skiatest::Reporter* reporter,
const char* expectedString, size_t caseID,
const PaintOptions& paintOptions,
@@ -110,24 +112,24 @@
const RenderPassProperties& renderPassSettings,
unsigned int allowedOvergeneration) {
- context->priv().globalCache()->resetGraphicsPipelines();
+ precompileContext->priv().globalCache()->resetGraphicsPipelines();
- Precompile(context, paintOptions, drawType, { &renderPassSettings, 1 });
+ Precompile(precompileContext, paintOptions, drawType, { &renderPassSettings, 1 });
std::vector<std::string> generated;
{
- const RendererProvider* rendererProvider = context->priv().rendererProvider();
- const ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
+ const RendererProvider* rendererProvider = precompileContext->priv().rendererProvider();
+ const ShaderCodeDictionary* dict = precompileContext->priv().shaderCodeDictionary();
std::vector<skgpu::UniqueKey> generatedKeys;
- UniqueKeyUtils::FetchUniqueKeys(context->priv().globalCache(), &generatedKeys);
+ UniqueKeyUtils::FetchUniqueKeys(precompileContext, &generatedKeys);
for (const skgpu::UniqueKey& key : generatedKeys) {
GraphicsPipelineDesc pipelineDesc;
RenderPassDesc renderPassDesc;
- UniqueKeyUtils::ExtractKeyDescs(context, key, &pipelineDesc, &renderPassDesc);
+ UniqueKeyUtils::ExtractKeyDescs(precompileContext, key, &pipelineDesc, &renderPassDesc);
const RenderStep* renderStep = rendererProvider->lookup(pipelineDesc.renderStepID());
generated.push_back(GetPipelineLabel(dict, renderPassDesc, renderStep,
@@ -181,7 +183,8 @@
DEF_GRAPHITE_TEST_FOR_CONTEXTS(ChromePrecompileTest, is_dawn_metal_context_type,
reporter, context, /* testContext */, CtsEnforcement::kNever) {
- const Caps* caps = context->priv().caps();
+ std::unique_ptr<PrecompileContext> precompileContext = context->makePrecompileContext();
+ const skgpu::graphite::Caps* caps = precompileContext->priv().caps();
TextureInfo textureInfo = caps->getDefaultSampledTextureInfo(kBGRA_8888_SkColorType,
skgpu::Mipmapped::kNo,
@@ -382,7 +385,7 @@
allowedOvergeneration *= 2; // due to ExpandResolveTextureLoadOp
}
- run_test(context, reporter,
+ run_test(precompileContext.get(), reporter,
kCases[i], i,
paintOptions, drawTypeFlags, renderPassSettings, allowedOvergeneration);
}
diff --git a/tests/graphite/precompile/PaintParamsKeyTest.cpp b/tests/graphite/precompile/PaintParamsKeyTest.cpp
index b3b54ff..fce421b 100644
--- a/tests/graphite/precompile/PaintParamsKeyTest.cpp
+++ b/tests/graphite/precompile/PaintParamsKeyTest.cpp
@@ -35,6 +35,7 @@
#include "include/gpu/graphite/Image.h"
#include "include/gpu/graphite/Recorder.h"
#include "include/gpu/graphite/Surface.h"
+#include "include/gpu/graphite/PrecompileContext.h"
#include "include/gpu/graphite/precompile/Precompile.h"
#include "include/gpu/graphite/precompile/PrecompileBlender.h"
#include "include/gpu/graphite/precompile/PrecompileColorFilter.h"
@@ -53,6 +54,7 @@
#include "src/gpu/graphite/KeyHelpers.h"
#include "src/gpu/graphite/PaintParams.h"
#include "src/gpu/graphite/PipelineData.h"
+#include "src/gpu/graphite/PrecompileContextPriv.h"
#include "src/gpu/graphite/RecorderPriv.h"
#include "src/gpu/graphite/RenderPassDesc.h"
#include "src/gpu/graphite/Renderer.h"
@@ -1814,13 +1816,11 @@
}
#ifdef SK_DEBUG
-void dump_keys(Context* context,
+void dump_keys(PrecompileContext* precompileContext,
const std::vector<skgpu::UniqueKey>& needleKeys,
const std::vector<skgpu::UniqueKey>& hayStackKeys,
const char* needleName,
const char* haystackName) {
- const RendererProvider* rendererProvider = context->priv().rendererProvider();
- const ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
SkDebugf("-------------------------- %zu %s pipelines\n", needleKeys.size(), needleName);
@@ -1830,7 +1830,7 @@
GraphicsPipelineDesc originalPipelineDesc;
RenderPassDesc originalRenderPassDesc;
- UniqueKeyUtils::ExtractKeyDescs(context, k,
+ UniqueKeyUtils::ExtractKeyDescs(precompileContext, k,
&originalPipelineDesc,
&originalRenderPassDesc);
@@ -1838,7 +1838,7 @@
label.appendf("--- %s key %d (%s in %s):\n",
needleName, count++, found ? "found" : "not-found", haystackName);
k.dump(label.c_str());
- UniqueKeyUtils::DumpDescs(rendererProvider, dict,
+ UniqueKeyUtils::DumpDescs(precompileContext,
originalPipelineDesc,
originalRenderPassDesc);
}
@@ -1847,6 +1847,7 @@
void check_draw(skiatest::Reporter* reporter,
Context* context,
+ PrecompileContext* precompileContext,
skiatest::graphite::GraphiteTestContext* testContext,
Recorder* recorder,
const SkPaint& paint,
@@ -1857,9 +1858,9 @@
std::vector<skgpu::UniqueKey> precompileKeys, drawKeys;
- UniqueKeyUtils::FetchUniqueKeys(context->priv().globalCache(), &precompileKeys);
+ UniqueKeyUtils::FetchUniqueKeys(precompileContext, &precompileKeys);
- context->priv().globalCache()->resetGraphicsPipelines();
+ precompileContext->priv().globalCache()->resetGraphicsPipelines();
{
// TODO: vary the colorType of the target surface too
@@ -1939,7 +1940,7 @@
testContext->syncedSubmit(context);
}
- UniqueKeyUtils::FetchUniqueKeys(context->priv().globalCache(), &drawKeys);
+ UniqueKeyUtils::FetchUniqueKeys(precompileContext, &drawKeys);
// Actually using the SkPaint with the specified type of draw shouldn't have added
// any additional pipelines
@@ -1957,8 +1958,8 @@
precompileKeys.size(), drawKeys.size(), missingPipelines);
#ifdef SK_DEBUG
if (missingPipelines) {
- dump_keys(context, drawKeys, precompileKeys, "draw", "precompile");
- dump_keys(context, precompileKeys, drawKeys, "precompile", "draw");
+ dump_keys(precompileContext, drawKeys, precompileKeys, "draw", "precompile");
+ dump_keys(precompileContext, precompileKeys, drawKeys, "precompile", "draw");
}
#endif // SK_DEBUG
@@ -2112,6 +2113,7 @@
// Precompile system will, at least, generate all the pipelines a real draw would generate.
void precompile_vs_real_draws_subtest(skiatest::Reporter* reporter,
Context* context,
+ PrecompileContext* precompileContext,
skiatest::graphite::GraphiteTestContext* testContext,
Recorder* recorder,
const SkPaint& paint,
@@ -2120,9 +2122,11 @@
sk_sp<SkShader> clipShader,
DrawTypeFlags dt,
bool /* verbose */) {
- context->priv().globalCache()->resetGraphicsPipelines();
+ GlobalCache* globalCache = precompileContext->priv().globalCache();
- const Caps* caps = context->priv().caps();
+ globalCache->resetGraphicsPipelines();
+
+ const skgpu::graphite::Caps* caps = context->priv().caps();
const SkColorType kColorType = kBGRA_8888_SkColorType;
@@ -2151,21 +2155,23 @@
? &kDepth_Stencil_4
: &kDepth_1;
- int before = context->priv().globalCache()->numGraphicsPipelines();
- Precompile(context, paintOptions, dt,
+ int before = globalCache->numGraphicsPipelines();
+ Precompile(precompileContext, paintOptions, dt,
dt == kNonSimpleShape ? SkSpan(pathProperties, 1) : SkSpan(&kDepth_1, 1));
if (gNeedSKPPaintOption) {
// The skp draws a rect w/ a default SkPaint
PaintOptions skpPaintOptions;
- Precompile(context, skpPaintOptions, DrawTypeFlags::kSimpleShape, { kDepth_1 });
+ Precompile(precompileContext, skpPaintOptions, DrawTypeFlags::kSimpleShape,
+ { kDepth_1 });
}
- int after = context->priv().globalCache()->numGraphicsPipelines();
+ int after = globalCache->numGraphicsPipelines();
REPORTER_ASSERT(reporter, before == 0);
REPORTER_ASSERT(reporter, after > before);
check_draw(reporter,
context,
+ precompileContext,
testContext,
recorder,
paint,
@@ -2176,6 +2182,7 @@
void run_test(skiatest::Reporter* reporter,
Context* context,
+ PrecompileContext* precompileContext,
skiatest::graphite::GraphiteTestContext* testContext,
const KeyContext& precompileKeyContext,
ShaderType s,
@@ -2210,7 +2217,8 @@
extract_vs_build_subtest(reporter, context, testContext, precompileKeyContext, recorder.get(),
paint, paintOptions, s, bm, cf, mf, imageFilter, clip, clipShader, dt,
seed, &rand, verbose);
- precompile_vs_real_draws_subtest(reporter, context, testContext, recorder.get(),
+ precompile_vs_real_draws_subtest(reporter, context, precompileContext,
+ testContext, recorder.get(),
paint, paintOptions, clip, clipShader, dt, verbose);
}
@@ -2222,6 +2230,7 @@
testContext,
true,
CtsEnforcement::kNever) {
+ std::unique_ptr<PrecompileContext> precompileContext = context->makePrecompileContext();
std::unique_ptr<RuntimeEffectDictionary> rtDict = std::make_unique<RuntimeEffectDictionary>();
#if 1
@@ -2257,6 +2266,7 @@
run_test(reporter,
context,
+ precompileContext.get(),
testContext,
create_key_context(context, rtDict.get()),
shaderType,
@@ -2283,6 +2293,7 @@
testContext,
true,
CtsEnforcement::kNever) {
+ std::unique_ptr<PrecompileContext> precompileContext = context->makePrecompileContext();
std::unique_ptr<RuntimeEffectDictionary> rtDict = std::make_unique<RuntimeEffectDictionary>();
KeyContext precompileKeyContext(create_key_context(context, rtDict.get()));
@@ -2400,7 +2411,8 @@
++current;
#endif
- run_test(reporter, context, testContext, precompileKeyContext,
+ run_test(reporter, context, precompileContext.get(),
+ testContext, precompileKeyContext,
shader, blender, cf, mf, imageFilter, clip, dt,
kDefaultSeed, /* verbose= */ false);
}
diff --git a/tests/graphite/precompile/ThreadedPrecompileTest.cpp b/tests/graphite/precompile/ThreadedPrecompileTest.cpp
index d8c0900..bd3eb37 100644
--- a/tests/graphite/precompile/ThreadedPrecompileTest.cpp
+++ b/tests/graphite/precompile/ThreadedPrecompileTest.cpp
@@ -9,6 +9,7 @@
#if defined(SK_GRAPHITE)
+#include "include/gpu/graphite/PrecompileContext.h"
#include "include/gpu/graphite/precompile/PaintOptions.h"
#include "include/gpu/graphite/precompile/Precompile.h"
#include "include/gpu/graphite/precompile/PrecompileShader.h"
@@ -49,7 +50,7 @@
return paintOptions;
}
-void precompile_gradients(Context* context,
+void precompile_gradients(std::unique_ptr<PrecompileContext> precompileContext,
skiatest::Reporter* reporter,
int threadID) {
constexpr RenderPassProperties kProps = { DepthStencilFlags::kDepth,
@@ -58,11 +59,13 @@
for (auto createOptionsMtd : { linear, radial, sweep, conical }) {
PaintOptions paintOptions = createOptionsMtd();
- Precompile(context,
+ Precompile(precompileContext.get(),
paintOptions,
DrawTypeFlags::kBitmapText_Mask,
{ &kProps, 1 });
}
+
+ precompileContext.reset();
}
} // anonymous namespace
@@ -75,11 +78,12 @@
CtsEnforcement::kNever) {
constexpr int kNumThreads = 4;
+
std::thread threads[kNumThreads];
for (int i = 0; i < kNumThreads; ++i) {
- threads[i] = std::thread([context, reporter, i]() {
- precompile_gradients(context, reporter, i);
- });
+ std::unique_ptr<PrecompileContext> precompileContext = context->makePrecompileContext();
+
+ threads[i] = std::thread(precompile_gradients, std::move(precompileContext), reporter, i);
}
for (auto& thread : threads) {
diff --git a/tools/graphite/UniqueKeyUtils.cpp b/tools/graphite/UniqueKeyUtils.cpp
index 1581a4c..79900e8 100644
--- a/tools/graphite/UniqueKeyUtils.cpp
+++ b/tools/graphite/UniqueKeyUtils.cpp
@@ -11,6 +11,7 @@
#include "src/gpu/graphite/Caps.h"
#include "src/gpu/graphite/ContextPriv.h"
#include "src/gpu/graphite/GraphicsPipelineDesc.h"
+#include "src/gpu/graphite/PrecompileContextPriv.h"
#include "src/gpu/graphite/RenderPassDesc.h"
#include "src/gpu/graphite/RendererProvider.h"
@@ -20,8 +21,10 @@
namespace UniqueKeyUtils {
-void FetchUniqueKeys(GlobalCache* globalCache,
+void FetchUniqueKeys(PrecompileContext* precompileContext,
std::vector<UniqueKey>* keys) {
+ GlobalCache* globalCache = precompileContext->priv().globalCache();
+
keys->reserve(globalCache->numGraphicsPipelines());
globalCache->forEachGraphicsPipeline([keys](const UniqueKey& key,
const GraphicsPipeline* pipeline) {
@@ -30,10 +33,12 @@
}
#ifdef SK_DEBUG
-void DumpDescs(const RendererProvider* rendererProvider,
- const ShaderCodeDictionary* dict,
+void DumpDescs(PrecompileContext* precompileContext,
const GraphicsPipelineDesc& pipelineDesc,
const RenderPassDesc& rpd) {
+ const RendererProvider* rendererProvider = precompileContext->priv().rendererProvider();
+ const ShaderCodeDictionary* dict = precompileContext->priv().shaderCodeDictionary();
+
const RenderStep* rs = rendererProvider->lookup(pipelineDesc.renderStepID());
SkDebugf("GraphicsPipelineDesc: %u %s\n", pipelineDesc.paintParamsID().asUInt(), rs->name());
@@ -57,12 +62,12 @@
}
#endif // SK_DEBUG
-bool ExtractKeyDescs(Context* context,
+bool ExtractKeyDescs(PrecompileContext* precompileContext,
const UniqueKey& origKey,
GraphicsPipelineDesc* pipelineDesc,
RenderPassDesc* renderPassDesc) {
- const Caps* caps = context->priv().caps();
- const RendererProvider* rendererProvider = context->priv().rendererProvider();
+ const skgpu::graphite::Caps* caps = precompileContext->priv().caps();
+ const RendererProvider* rendererProvider = precompileContext->priv().rendererProvider();
bool extracted = caps->extractGraphicsDescs(origKey, pipelineDesc, renderPassDesc,
rendererProvider);
@@ -72,14 +77,12 @@
}
#ifdef SK_DEBUG
- const ShaderCodeDictionary* dict = context->priv().shaderCodeDictionary();
-
UniqueKey newKey = caps->makeGraphicsPipelineKey(*pipelineDesc, *renderPassDesc);
if (origKey != newKey) {
SkDebugf("------- The UniqueKey didn't round trip!\n");
origKey.dump("original key:");
newKey.dump("reassembled key:");
- DumpDescs(rendererProvider, dict, *pipelineDesc, *renderPassDesc);
+ DumpDescs(precompileContext, *pipelineDesc, *renderPassDesc);
SkDebugf("------------------------\n");
}
SkASSERT(origKey == newKey);
diff --git a/tools/graphite/UniqueKeyUtils.h b/tools/graphite/UniqueKeyUtils.h
index 2bef2e2..227d2a0 100644
--- a/tools/graphite/UniqueKeyUtils.h
+++ b/tools/graphite/UniqueKeyUtils.h
@@ -20,6 +20,7 @@
class Context;
class GlobalCache;
class GraphicsPipelineDesc;
+ class PrecompileContext;
struct RenderPassDesc;
class RendererProvider;
class ShaderCodeDictionary;
@@ -27,12 +28,11 @@
namespace UniqueKeyUtils {
-void FetchUniqueKeys(skgpu::graphite::GlobalCache* globalCache,
+void FetchUniqueKeys(skgpu::graphite::PrecompileContext*,
std::vector<skgpu::UniqueKey>* keys);
#ifdef SK_DEBUG
-void DumpDescs(const skgpu::graphite::RendererProvider*,
- const skgpu::graphite::ShaderCodeDictionary*,
+void DumpDescs(skgpu::graphite::PrecompileContext*,
const skgpu::graphite::GraphicsPipelineDesc&,
const skgpu::graphite::RenderPassDesc&);
#endif
@@ -40,7 +40,7 @@
// This helper breaks a UniqueKey down into its GraphicsPipelineDesc
// and a RenderPassDesc and checks that the reassembled pieces match the
// original.
-bool ExtractKeyDescs(skgpu::graphite::Context*,
+bool ExtractKeyDescs(skgpu::graphite::PrecompileContext*,
const skgpu::UniqueKey&,
skgpu::graphite::GraphicsPipelineDesc*,
skgpu::graphite::RenderPassDesc*);