• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
8 #include "src/gpu/graphite/ResourceProvider.h"
9 
10 #include "include/core/SkSamplingOptions.h"
11 #include "include/core/SkTileMode.h"
12 #include "include/gpu/graphite/BackendTexture.h"
13 #include "src/gpu/graphite/Buffer.h"
14 #include "src/gpu/graphite/Caps.h"
15 #include "src/gpu/graphite/CommandBuffer.h"
16 #include "src/gpu/graphite/ComputePipeline.h"
17 #include "src/gpu/graphite/ContextPriv.h"
18 #include "src/gpu/graphite/GlobalCache.h"
19 #include "src/gpu/graphite/GraphicsPipeline.h"
20 #include "src/gpu/graphite/GraphicsPipelineDesc.h"
21 #include "src/gpu/graphite/Log.h"
22 #include "src/gpu/graphite/ResourceCache.h"
23 #include "src/gpu/graphite/Sampler.h"
24 #include "src/gpu/graphite/SharedContext.h"
25 #include "src/gpu/graphite/Texture.h"
26 #include "src/sksl/SkSLCompiler.h"
27 
28 namespace skgpu::graphite {
29 
ResourceProvider(SharedContext * sharedContext,SingleOwner * singleOwner)30 ResourceProvider::ResourceProvider(SharedContext* sharedContext,
31                                    SingleOwner* singleOwner)
32         : fSharedContext(sharedContext)
33         , fResourceCache(ResourceCache::Make(singleOwner))
34         , fCompiler(std::make_unique<SkSL::Compiler>(fSharedContext->caps()->shaderCaps())) {}
35 
~ResourceProvider()36 ResourceProvider::~ResourceProvider() {
37     fResourceCache->shutdown();
38 }
39 
findOrCreateGraphicsPipeline(const RuntimeEffectDictionary * runtimeDict,const GraphicsPipelineDesc & pipelineDesc,const RenderPassDesc & renderPassDesc)40 sk_sp<GraphicsPipeline> ResourceProvider::findOrCreateGraphicsPipeline(
41         const RuntimeEffectDictionary* runtimeDict,
42         const GraphicsPipelineDesc& pipelineDesc,
43         const RenderPassDesc& renderPassDesc) {
44     auto globalCache = fSharedContext->globalCache();
45     UniqueKey pipelineKey = fSharedContext->caps()->makeGraphicsPipelineKey(pipelineDesc,
46                                                                             renderPassDesc);
47     sk_sp<GraphicsPipeline> pipeline = globalCache->findGraphicsPipeline(pipelineKey);
48     if (!pipeline) {
49         // Haven't encountered this pipeline, so create a new one. Since pipelines are shared
50         // across Recorders, we could theoretically create equivalent pipelines on different
51         // threads. If this happens, GlobalCache returns the first-through-gate pipeline and we
52         // discard the redundant pipeline. While this is wasted effort in the rare event of a race,
53         // it allows pipeline creation to be performed without locking the global cache.
54         pipeline = this->createGraphicsPipeline(runtimeDict, pipelineDesc, renderPassDesc);
55         if (pipeline) {
56             // TODO: Should we store a null pipeline if we failed to create one so that subsequent
57             // usage immediately sees that the pipeline cannot be created, vs. retrying every time?
58             pipeline = globalCache->addGraphicsPipeline(pipelineKey, std::move(pipeline));
59         }
60     }
61     return pipeline;
62 }
63 
findOrCreateComputePipeline(const ComputePipelineDesc & pipelineDesc)64 sk_sp<ComputePipeline> ResourceProvider::findOrCreateComputePipeline(
65         const ComputePipelineDesc& pipelineDesc) {
66     auto globalCache = fSharedContext->globalCache();
67     UniqueKey pipelineKey = fSharedContext->caps()->makeComputePipelineKey(pipelineDesc);
68     sk_sp<ComputePipeline> pipeline = globalCache->findComputePipeline(pipelineKey);
69     if (!pipeline) {
70         pipeline = this->createComputePipeline(pipelineDesc);
71         if (pipeline) {
72             pipeline = globalCache->addComputePipeline(pipelineKey, std::move(pipeline));
73         }
74     }
75     return pipeline;
76 }
77 
78 ////////////////////////////////////////////////////////////////////////////////////////////////
79 
findOrCreateScratchTexture(SkISize dimensions,const TextureInfo & info,skgpu::Budgeted budgeted)80 sk_sp<Texture> ResourceProvider::findOrCreateScratchTexture(SkISize dimensions,
81                                                             const TextureInfo& info,
82                                                             skgpu::Budgeted budgeted) {
83     SkASSERT(info.isValid());
84 
85     static const ResourceType kType = GraphiteResourceKey::GenerateResourceType();
86 
87     GraphiteResourceKey key;
88     // Scratch textures are not shareable
89     fSharedContext->caps()->buildKeyForTexture(dimensions, info, kType, Shareable::kNo, &key);
90 
91     return this->findOrCreateTextureWithKey(dimensions, info, key, budgeted);
92 }
93 
findOrCreateDepthStencilAttachment(SkISize dimensions,const TextureInfo & info)94 sk_sp<Texture> ResourceProvider::findOrCreateDepthStencilAttachment(SkISize dimensions,
95                                                                     const TextureInfo& info) {
96     SkASSERT(info.isValid());
97 
98     static const ResourceType kType = GraphiteResourceKey::GenerateResourceType();
99 
100     GraphiteResourceKey key;
101     // We always make depth and stencil attachments shareable. Between any render pass the values
102     // are reset. Thus it is safe to be used by multiple different render passes without worry of
103     // stomping on each other's data.
104     fSharedContext->caps()->buildKeyForTexture(dimensions, info, kType, Shareable::kYes, &key);
105 
106     return this->findOrCreateTextureWithKey(dimensions, info, key, skgpu::Budgeted::kYes);
107 }
108 
findOrCreateDiscardableMSAAAttachment(SkISize dimensions,const TextureInfo & info)109 sk_sp<Texture> ResourceProvider::findOrCreateDiscardableMSAAAttachment(SkISize dimensions,
110                                                                        const TextureInfo& info) {
111     SkASSERT(info.isValid());
112 
113     static const ResourceType kType = GraphiteResourceKey::GenerateResourceType();
114 
115     GraphiteResourceKey key;
116     // We always make discardable msaa attachments shareable. Between any render pass we discard
117     // the values of the MSAA texture. Thus it is safe to be used by multiple different render
118     // passes without worry of stomping on each other's data. It is the callings code responsiblity
119     // to populate the discardable MSAA texture with data at the start of the render pass.
120     fSharedContext->caps()->buildKeyForTexture(dimensions, info, kType, Shareable::kYes, &key);
121 
122     return this->findOrCreateTextureWithKey(dimensions, info, key, skgpu::Budgeted::kYes);
123 }
124 
findOrCreateTextureWithKey(SkISize dimensions,const TextureInfo & info,const GraphiteResourceKey & key,skgpu::Budgeted budgeted)125 sk_sp<Texture> ResourceProvider::findOrCreateTextureWithKey(SkISize dimensions,
126                                                             const TextureInfo& info,
127                                                             const GraphiteResourceKey& key,
128                                                             skgpu::Budgeted budgeted) {
129     // If the resource is shareable it should be budgeted since it shouldn't be backing any client
130     // owned object.
131     SkASSERT(key.shareable() == Shareable::kNo || budgeted == skgpu::Budgeted::kYes);
132 
133     if (Resource* resource = fResourceCache->findAndRefResource(key, budgeted)) {
134         return sk_sp<Texture>(static_cast<Texture*>(resource));
135     }
136 
137     auto tex = this->createTexture(dimensions, info, budgeted);
138     if (!tex) {
139         return nullptr;
140     }
141 
142     tex->setKey(key);
143     fResourceCache->insertResource(tex.get());
144 
145     return tex;
146 }
147 
findOrCreateCompatibleSampler(const SkSamplingOptions & smplOptions,SkTileMode xTileMode,SkTileMode yTileMode)148 sk_sp<Sampler> ResourceProvider::findOrCreateCompatibleSampler(const SkSamplingOptions& smplOptions,
149                                                                SkTileMode xTileMode,
150                                                                SkTileMode yTileMode) {
151     static const ResourceType kType = GraphiteResourceKey::GenerateResourceType();
152 
153     GraphiteResourceKey key;
154     {
155         constexpr int kNumTileModeBits   = SkNextLog2_portable(int(SkTileMode::kLastTileMode)+1);
156         constexpr int kNumFilterModeBits = SkNextLog2_portable(int(SkFilterMode::kLast)+1);
157         constexpr int kNumMipmapModeBits = SkNextLog2_portable(int(SkMipmapMode::kLast)+1);
158 
159         constexpr int kTileModeXShift  = 0;
160         constexpr int kTileModeYShift  = kTileModeXShift  + kNumTileModeBits;
161         constexpr int kFilterModeShift = kTileModeYShift  + kNumTileModeBits;
162         constexpr int kMipmapModeShift = kFilterModeShift + kNumFilterModeBits;
163 
164         static_assert(kMipmapModeShift + kNumMipmapModeBits <= 32);
165 
166         // For the key we need only one uint32_t.
167         // TODO: add aniso value when used
168         static_assert(sizeof(uint32_t) == 4);
169 
170         GraphiteResourceKey::Builder builder(&key, kType, 1, Shareable::kYes);
171         uint32_t myKey =
172         (static_cast<uint32_t>(xTileMode) << kTileModeXShift) |
173                      (static_cast<uint32_t>(yTileMode) << kTileModeYShift) |
174                      (static_cast<uint32_t>(smplOptions.filter) << kFilterModeShift) |
175                      (static_cast<uint32_t>(smplOptions.mipmap) << kMipmapModeShift);
176         builder[0] = myKey;
177     }
178 
179     skgpu::Budgeted budgeted = skgpu::Budgeted::kYes;
180     if (Resource* resource = fResourceCache->findAndRefResource(key, budgeted)) {
181         return sk_sp<Sampler>(static_cast<Sampler*>(resource));
182     }
183     sk_sp<Sampler> sampler = this->createSampler(smplOptions, xTileMode, yTileMode);
184     if (!sampler) {
185         return nullptr;
186     }
187 
188     sampler->setKey(key);
189     fResourceCache->insertResource(sampler.get());
190     return sampler;
191 }
192 
findOrCreateBuffer(size_t size,BufferType type,PrioritizeGpuReads prioritizeGpuReads)193 sk_sp<Buffer> ResourceProvider::findOrCreateBuffer(size_t size,
194                                                    BufferType type,
195                                                    PrioritizeGpuReads prioritizeGpuReads) {
196     static const ResourceType kType = GraphiteResourceKey::GenerateResourceType();
197 
198 #ifdef SK_DEBUG
199     // The size should already be aligned.
200     size_t minAlignment = 1;
201     if (type == BufferType::kStorage || type == BufferType::kIndirect ||
202         type == BufferType::kVertexStorage || type == BufferType::kIndexStorage) {
203         minAlignment = std::max(fSharedContext->caps()->requiredStorageBufferAlignment(),
204                                 minAlignment);
205     } else if (type == BufferType::kUniform) {
206         minAlignment = std::max(fSharedContext->caps()->requiredUniformBufferAlignment(),
207                                 minAlignment);
208     } else if (type == BufferType::kXferCpuToGpu || type == BufferType::kXferGpuToCpu) {
209         minAlignment = std::max(fSharedContext->caps()->requiredTransferBufferAlignment(),
210                                 minAlignment);
211     }
212     SkASSERT(size % minAlignment == 0);
213 #endif
214 
215     GraphiteResourceKey key;
216     {
217         // For the key we need ((sizeof(size_t) + (sizeof(uint32_t) - 1)) / (sizeof(uint32_t))
218         // uint32_t's for the size and one uint32_t for the rest.
219         static_assert(sizeof(uint32_t) == 4);
220         static const int kSizeKeyNum32DataCnt = (sizeof(size_t) + 3) / 4;
221         static const int kKeyNum32DataCnt =  kSizeKeyNum32DataCnt + 1;
222 
223         SkASSERT(static_cast<uint32_t>(type) < (1u << 4));
224         SkASSERT(static_cast<uint32_t>(prioritizeGpuReads) < (1u << 1));
225 
226         GraphiteResourceKey::Builder builder(&key, kType, kKeyNum32DataCnt, Shareable::kNo);
227         builder[0] = (static_cast<uint32_t>(type) << 0) |
228                      (static_cast<uint32_t>(prioritizeGpuReads) << 4);
229         size_t szKey = size;
230         for (int i = 0; i < kSizeKeyNum32DataCnt; ++i) {
231             builder[i + 1] = (uint32_t) szKey;
232 
233             // If size_t is 4 bytes, we cannot do a shift of 32 or else we get a warning/error that
234             // shift amount is >= width of the type.
235             if constexpr(kSizeKeyNum32DataCnt > 1) {
236                 szKey = szKey >> 32;
237             }
238         }
239     }
240 
241     skgpu::Budgeted budgeted = skgpu::Budgeted::kYes;
242     if (Resource* resource = fResourceCache->findAndRefResource(key, budgeted)) {
243         return sk_sp<Buffer>(static_cast<Buffer*>(resource));
244     }
245     auto buffer = this->createBuffer(size, type, prioritizeGpuReads);
246     if (!buffer) {
247         return nullptr;
248     }
249 
250     buffer->setKey(key);
251     fResourceCache->insertResource(buffer.get());
252     return buffer;
253 }
254 
createBackendTexture(SkISize dimensions,const TextureInfo & info)255 BackendTexture ResourceProvider::createBackendTexture(SkISize dimensions, const TextureInfo& info) {
256     const auto maxTextureSize = fSharedContext->caps()->maxTextureSize();
257     if (dimensions.isEmpty() ||
258         dimensions.width()  > maxTextureSize ||
259         dimensions.height() > maxTextureSize) {
260         SKGPU_LOG_W("call to createBackendTexture has requested dimensions (%d, %d) larger than the"
261                     " supported gpu max texture size: %d. Or the dimensions are empty.",
262                     dimensions.fWidth, dimensions.fHeight, maxTextureSize);
263         return {};
264     }
265 
266     return this->onCreateBackendTexture(dimensions, info);
267 }
268 
deleteBackendTexture(BackendTexture & texture)269 void ResourceProvider::deleteBackendTexture(BackendTexture& texture) {
270     this->onDeleteBackendTexture(texture);
271     // Invalidate the texture;
272     texture = BackendTexture();
273 }
274 
275 }  // namespace skgpu::graphite
276