Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
ResourceProvider.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2021 Google LLC
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
9
31
32namespace skgpu::graphite {
33
34// This is only used when tracing is enabled at compile time.
35[[maybe_unused]] static std::string to_str(const SharedContext* ctx,
36 const GraphicsPipelineDesc& gpDesc,
37 const RenderPassDesc& rpDesc) {
38 const ShaderCodeDictionary* dict = ctx->shaderCodeDictionary();
39 const RenderStep* step = ctx->rendererProvider()->lookup(gpDesc.renderStepID());
40 return GetPipelineLabel(dict, rpDesc, step, gpDesc.paintParamsID());
41}
42
43ResourceProvider::ResourceProvider(SharedContext* sharedContext,\
44 SingleOwner* singleOwner,
45 uint32_t recorderID,
46 size_t resourceBudget)
47 : fSharedContext(sharedContext)
48 , fResourceCache(ResourceCache::Make(singleOwner, recorderID, resourceBudget)) {}
49
50ResourceProvider::~ResourceProvider() {
51 fResourceCache->shutdown();
52}
53
54sk_sp<GraphicsPipeline> ResourceProvider::findOrCreateGraphicsPipeline(
55 const RuntimeEffectDictionary* runtimeDict,
56 const GraphicsPipelineDesc& pipelineDesc,
57 const RenderPassDesc& renderPassDesc) {
58 auto globalCache = fSharedContext->globalCache();
59 UniqueKey pipelineKey = fSharedContext->caps()->makeGraphicsPipelineKey(pipelineDesc,
60 renderPassDesc);
61 sk_sp<GraphicsPipeline> pipeline = globalCache->findGraphicsPipeline(pipelineKey);
62 if (!pipeline) {
63 // Haven't encountered this pipeline, so create a new one. Since pipelines are shared
64 // across Recorders, we could theoretically create equivalent pipelines on different
65 // threads. If this happens, GlobalCache returns the first-through-gate pipeline and we
66 // discard the redundant pipeline. While this is wasted effort in the rare event of a race,
67 // it allows pipeline creation to be performed without locking the global cache.
68 // NOTE: The parameters to TRACE_EVENT are only evaluated inside an if-block when the
69 // category is enabled.
70 TRACE_EVENT1("skia.shaders", "createGraphicsPipeline", "desc",
71 TRACE_STR_COPY(to_str(fSharedContext, pipelineDesc, renderPassDesc).c_str()));
72 pipeline = this->createGraphicsPipeline(runtimeDict, pipelineDesc, renderPassDesc);
73 if (pipeline) {
74 // TODO: Should we store a null pipeline if we failed to create one so that subsequent
75 // usage immediately sees that the pipeline cannot be created, vs. retrying every time?
76 pipeline = globalCache->addGraphicsPipeline(pipelineKey, std::move(pipeline));
77 }
78 }
79 return pipeline;
80}
81
82sk_sp<ComputePipeline> ResourceProvider::findOrCreateComputePipeline(
83 const ComputePipelineDesc& pipelineDesc) {
84 auto globalCache = fSharedContext->globalCache();
85 UniqueKey pipelineKey = fSharedContext->caps()->makeComputePipelineKey(pipelineDesc);
86 sk_sp<ComputePipeline> pipeline = globalCache->findComputePipeline(pipelineKey);
87 if (!pipeline) {
88 pipeline = this->createComputePipeline(pipelineDesc);
89 if (pipeline) {
90 pipeline = globalCache->addComputePipeline(pipelineKey, std::move(pipeline));
91 }
92 }
93 return pipeline;
94}
95
96////////////////////////////////////////////////////////////////////////////////////////////////
97
98sk_sp<Texture> ResourceProvider::findOrCreateScratchTexture(SkISize dimensions,
99 const TextureInfo& info,
100 skgpu::Budgeted budgeted) {
101 SkASSERT(info.isValid());
102
104
106 // Scratch textures are not shareable
107 fSharedContext->caps()->buildKeyForTexture(dimensions, info, kType, Shareable::kNo, &key);
108
109 return this->findOrCreateTextureWithKey(dimensions, info, key, budgeted);
110}
111
112sk_sp<Texture> ResourceProvider::findOrCreateDepthStencilAttachment(SkISize dimensions,
113 const TextureInfo& info) {
114 SkASSERT(info.isValid());
115
117
119 // We always make depth and stencil attachments shareable. Between any render pass the values
120 // are reset. Thus it is safe to be used by multiple different render passes without worry of
121 // stomping on each other's data.
123
124 return this->findOrCreateTextureWithKey(dimensions, info, key, skgpu::Budgeted::kYes);
125}
126
127sk_sp<Texture> ResourceProvider::findOrCreateDiscardableMSAAAttachment(SkISize dimensions,
128 const TextureInfo& info) {
129 SkASSERT(info.isValid());
130
132
134 // We always make discardable msaa attachments shareable. Between any render pass we discard
135 // the values of the MSAA texture. Thus it is safe to be used by multiple different render
136 // passes without worry of stomping on each other's data. It is the callings code's
137 // responsibility to populate the discardable MSAA texture with data at the start of the
138 // render pass.
140
141 return this->findOrCreateTextureWithKey(dimensions, info, key, skgpu::Budgeted::kYes);
142}
143
144sk_sp<Texture> ResourceProvider::findOrCreateTextureWithKey(SkISize dimensions,
145 const TextureInfo& info,
147 skgpu::Budgeted budgeted) {
148 // If the resource is shareable it should be budgeted since it shouldn't be backing any client
149 // owned object.
150 SkASSERT(key.shareable() == Shareable::kNo || budgeted == skgpu::Budgeted::kYes);
151
152 if (Resource* resource = fResourceCache->findAndRefResource(key, budgeted)) {
153 return sk_sp<Texture>(static_cast<Texture*>(resource));
154 }
155
156 auto tex = this->createTexture(dimensions, info, budgeted);
157 if (!tex) {
158 return nullptr;
159 }
160
161 tex->setKey(key);
162 fResourceCache->insertResource(tex.get());
163
164 return tex;
165}
166
167sk_sp<Sampler> ResourceProvider::findOrCreateCompatibleSampler(const SamplerDesc& desc) {
169
170 if (Resource* resource = fResourceCache->findAndRefResource(key, skgpu::Budgeted::kYes)) {
171 return sk_sp<Sampler>(static_cast<Sampler*>(resource));
172 }
173
174 sk_sp<Sampler> sampler = this->createSampler(desc);
175 if (!sampler) {
176 return nullptr;
177 }
178
179 sampler->setKey(key);
180 fResourceCache->insertResource(sampler.get());
181 return sampler;
182}
183
184sk_sp<Buffer> ResourceProvider::findOrCreateBuffer(size_t size,
186 AccessPattern accessPattern,
187 std::string_view label) {
189
191 {
192 // For the key we need ((sizeof(size_t) + (sizeof(uint32_t) - 1)) / (sizeof(uint32_t))
193 // uint32_t's for the size and one uint32_t for the rest.
194 static_assert(sizeof(uint32_t) == 4);
195 static const int kSizeKeyNum32DataCnt = (sizeof(size_t) + 3) / 4;
196 static const int kKeyNum32DataCnt = kSizeKeyNum32DataCnt + 1;
197
198 SkASSERT(static_cast<uint32_t>(type) < (1u << 4));
199 SkASSERT(static_cast<uint32_t>(accessPattern) < (1u << 1));
200
201 GraphiteResourceKey::Builder builder(&key, kType, kKeyNum32DataCnt, Shareable::kNo);
202 builder[0] = (static_cast<uint32_t>(type) << 0) |
203 (static_cast<uint32_t>(accessPattern) << 4);
204 size_t szKey = size;
205 for (int i = 0; i < kSizeKeyNum32DataCnt; ++i) {
206 builder[i + 1] = (uint32_t) szKey;
207
208 // If size_t is 4 bytes, we cannot do a shift of 32 or else we get a warning/error that
209 // shift amount is >= width of the type.
210 if constexpr(kSizeKeyNum32DataCnt > 1) {
211 szKey = szKey >> 32;
212 }
213 }
214 }
215
217 if (Resource* resource = fResourceCache->findAndRefResource(key, budgeted)) {
218 resource->setLabel(std::move(label));
219 return sk_sp<Buffer>(static_cast<Buffer*>(resource));
220 }
221 auto buffer = this->createBuffer(size, type, accessPattern, std::move(label));
222 if (!buffer) {
223 return nullptr;
224 }
225
226 buffer->setKey(key);
227 fResourceCache->insertResource(buffer.get());
228 return buffer;
229}
230
231namespace {
232bool dimensions_are_valid(const int maxTextureSize, const SkISize& dimensions) {
233 if (dimensions.isEmpty() ||
234 dimensions.width() > maxTextureSize ||
235 dimensions.height() > maxTextureSize) {
236 SKGPU_LOG_W("Call to createBackendTexture has requested dimensions (%d, %d) larger than the"
237 " supported gpu max texture size: %d. Or the dimensions are empty.",
238 dimensions.fWidth, dimensions.fHeight, maxTextureSize);
239 return false;
240 }
241 return true;
242}
243}
244
245BackendTexture ResourceProvider::createBackendTexture(SkISize dimensions, const TextureInfo& info) {
246 if (!dimensions_are_valid(fSharedContext->caps()->maxTextureSize(), dimensions)) {
247 return {};
248 }
249 return this->onCreateBackendTexture(dimensions, info);
250}
251
252#ifdef SK_BUILD_FOR_ANDROID
253BackendTexture ResourceProvider::createBackendTexture(AHardwareBuffer* hardwareBuffer,
254 bool isRenderable,
255 bool isProtectedContent,
256 SkISize dimensions,
257 bool fromAndroidWindow) const {
258 if (!dimensions_are_valid(fSharedContext->caps()->maxTextureSize(), dimensions)) {
259 return {};
260 }
261 return this->onCreateBackendTexture(hardwareBuffer,
262 isRenderable,
263 isProtectedContent,
264 dimensions,
265 fromAndroidWindow);
266}
267
268BackendTexture ResourceProvider::onCreateBackendTexture(AHardwareBuffer*,
269 bool isRenderable,
270 bool isProtectedContent,
271 SkISize dimensions,
272 bool fromAndroidWindow) const {
273 return {};
274}
275#endif
276
277void ResourceProvider::deleteBackendTexture(const BackendTexture& texture) {
278 this->onDeleteBackendTexture(texture);
279}
280
281void ResourceProvider::freeGpuResources() {
282 // TODO: Are there Resources that are ref'd by the ResourceProvider or its subclasses that need
283 // be released? If we ever find that we're holding things directly on the ResourceProviders we
284 // call down into the subclasses to allow them to release things.
285
286 fResourceCache->purgeResources();
287}
288
289void ResourceProvider::purgeResourcesNotUsedSince(StdSteadyClock::time_point purgeTime) {
290 fResourceCache->purgeResourcesNotUsedSince(purgeTime);
291}
292
293} // namespace skgpu::graphite
static int step(int x, SkScalar min, SkScalar max)
Definition BlurTest.cpp:215
static void info(const char *fmt,...) SK_PRINTF_LIKE(1
Definition DM.cpp:213
struct AHardwareBuffer AHardwareBuffer
#define SKGPU_LOG_W(fmt,...)
Definition Log.h:40
#define SkASSERT(cond)
Definition SkAssert.h:116
static std::unique_ptr< SkEncoder > Make(SkWStream *dst, const SkPixmap *src, const SkYUVAPixmaps *srcYUVA, const SkColorSpace *srcYUVAColorSpace, const SkJpegEncoder::Options &options)
#define TRACE_STR_COPY(str)
T * get() const
Definition SkRefCnt.h:303
virtual GraphiteResourceKey makeSamplerKey(const SamplerDesc &samplerDesc) const
Definition Caps.cpp:72
virtual UniqueKey makeGraphicsPipelineKey(const GraphicsPipelineDesc &, const RenderPassDesc &) const =0
virtual UniqueKey makeComputePipelineKey(const ComputePipelineDesc &) const =0
virtual void buildKeyForTexture(SkISize dimensions, const TextureInfo &, ResourceType, Shareable, GraphiteResourceKey *) const =0
int maxTextureSize() const
Definition Caps.h:134
UniquePaintParamsID paintParamsID() const
const RenderStep * lookup(uint32_t uniqueID) const
virtual sk_sp< Sampler > createSampler(const SamplerDesc &)=0
virtual BackendTexture onCreateBackendTexture(SkISize dimensions, const TextureInfo &)=0
virtual sk_sp< Buffer > createBuffer(size_t size, BufferType type, AccessPattern, std::string_view label)=0
virtual sk_sp< GraphicsPipeline > createGraphicsPipeline(const RuntimeEffectDictionary *, const GraphicsPipelineDesc &, const RenderPassDesc &)=0
virtual void onDeleteBackendTexture(const BackendTexture &)=0
virtual sk_sp< Texture > createTexture(SkISize, const TextureInfo &, skgpu::Budgeted)=0
sk_sp< ResourceCache > fResourceCache
virtual sk_sp< ComputePipeline > createComputePipeline(const ComputePipelineDesc &)=0
const Caps * caps() const
ShaderCodeDictionary * shaderCodeDictionary()
const RendererProvider * rendererProvider() const
static const uint8_t buffer[]
FlTexture * texture
static std::string to_str(const SharedContext *ctx, const GraphicsPipelineDesc &gpDesc, const RenderPassDesc &rpDesc)
uint32_t ResourceType
std::string GetPipelineLabel(const ShaderCodeDictionary *dict, const RenderPassDesc &renderPassDesc, const RenderStep *renderStep, UniquePaintParamsID paintID)
Budgeted
Definition GpuTypes.h:35
bool isEmpty() const
Definition SkSize.h:31
int32_t fHeight
Definition SkSize.h:18
int32_t fWidth
Definition SkSize.h:17
constexpr int32_t width() const
Definition SkSize.h:36
constexpr int32_t height() const
Definition SkSize.h:37
#define TRACE_EVENT1(category_group, name, arg1_name, arg1_val)