1 /*
2 * Copyright 2015 Google Inc.
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 "GrResourceProvider.h"
9 #include "../private/GrSingleOwner.h"
10 #include "GrBackendSemaphore.h"
11 #include "GrCaps.h"
12 #include "GrContext.h"
13 #include "GrContextPriv.h"
14 #include "GrGpu.h"
15 #include "GrGpuBuffer.h"
16 #include "GrPath.h"
17 #include "GrPathRendering.h"
18 #include "GrProxyProvider.h"
19 #include "GrRenderTargetPriv.h"
20 #include "GrResourceCache.h"
21 #include "GrResourceKey.h"
22 #include "GrSemaphore.h"
23 #include "GrStencilAttachment.h"
24 #include "GrTexturePriv.h"
25 #include "SkGr.h"
26 #include "SkMathPriv.h"
27
28 const uint32_t GrResourceProvider::kMinScratchTextureSize = 16;
29
30 #define ASSERT_SINGLE_OWNER \
31 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
32
GrResourceProvider(GrGpu * gpu,GrResourceCache * cache,GrSingleOwner * owner,bool explicitlyAllocateGPUResources)33 GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner,
34 bool explicitlyAllocateGPUResources)
35 : fCache(cache)
36 , fGpu(gpu)
37 , fExplicitlyAllocateGPUResources(explicitlyAllocateGPUResources)
38 #ifdef SK_DEBUG
39 , fSingleOwner(owner)
40 #endif
41 {
42 fCaps = sk_ref_sp(fGpu->caps());
43 }
44
createTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,const GrMipLevel texels[],int mipLevelCount)45 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
46 const GrMipLevel texels[], int mipLevelCount) {
47 ASSERT_SINGLE_OWNER
48
49 SkASSERT(mipLevelCount > 0);
50
51 if (this->isAbandoned()) {
52 return nullptr;
53 }
54
55 GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo;
56 if (!fCaps->validateSurfaceDesc(desc, mipMapped)) {
57 return nullptr;
58 }
59
60 return fGpu->createTexture(desc, budgeted, texels, mipLevelCount);
61 }
62
getExactScratch(const GrSurfaceDesc & desc,SkBudgeted budgeted,Flags flags)63 sk_sp<GrTexture> GrResourceProvider::getExactScratch(const GrSurfaceDesc& desc,
64 SkBudgeted budgeted, Flags flags) {
65 sk_sp<GrTexture> tex(this->refScratchTexture(desc, flags));
66 if (tex && SkBudgeted::kNo == budgeted) {
67 tex->resourcePriv().makeUnbudgeted();
68 }
69
70 return tex;
71 }
72
createTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,SkBackingFit fit,const GrMipLevel & mipLevel,Flags flags)73 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
74 SkBudgeted budgeted,
75 SkBackingFit fit,
76 const GrMipLevel& mipLevel,
77 Flags flags) {
78 ASSERT_SINGLE_OWNER
79
80 if (this->isAbandoned()) {
81 return nullptr;
82 }
83
84 if (!mipLevel.fPixels) {
85 return nullptr;
86 }
87
88 if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) {
89 return nullptr;
90 }
91
92 GrContext* context = fGpu->getContext();
93 GrProxyProvider* proxyProvider = context->priv().proxyProvider();
94
95 SkColorType colorType;
96 if (GrPixelConfigToColorType(desc.fConfig, &colorType)) {
97 sk_sp<GrTexture> tex = (SkBackingFit::kApprox == fit)
98 ? this->createApproxTexture(desc, flags)
99 : this->createTexture(desc, budgeted, flags);
100 if (!tex) {
101 return nullptr;
102 }
103
104 sk_sp<GrTextureProxy> proxy = proxyProvider->createWrapped(std::move(tex),
105 kTopLeft_GrSurfaceOrigin);
106 if (!proxy) {
107 return nullptr;
108 }
109 auto srcInfo = SkImageInfo::Make(desc.fWidth, desc.fHeight, colorType,
110 kUnknown_SkAlphaType);
111 sk_sp<GrSurfaceContext> sContext = context->priv().makeWrappedSurfaceContext(
112 std::move(proxy));
113 if (!sContext) {
114 return nullptr;
115 }
116 SkAssertResult(sContext->writePixels(srcInfo, mipLevel.fPixels, mipLevel.fRowBytes, 0, 0));
117 return sk_ref_sp(sContext->asTextureProxy()->peekTexture());
118 } else {
119 return fGpu->createTexture(desc, budgeted, &mipLevel, 1);
120 }
121 }
122
createTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,Flags flags)123 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
124 Flags flags) {
125 ASSERT_SINGLE_OWNER
126 if (this->isAbandoned()) {
127 return nullptr;
128 }
129
130 if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) {
131 return nullptr;
132 }
133
134 // Compressed textures are read-only so they don't support re-use for scratch.
135 if (!GrPixelConfigIsCompressed(desc.fConfig)) {
136 sk_sp<GrTexture> tex = this->getExactScratch(desc, budgeted, flags);
137 if (tex) {
138 return tex;
139 }
140 }
141
142 return fGpu->createTexture(desc, budgeted);
143 }
144
createApproxTexture(const GrSurfaceDesc & desc,Flags flags)145 sk_sp<GrTexture> GrResourceProvider::createApproxTexture(const GrSurfaceDesc& desc,
146 Flags flags) {
147 ASSERT_SINGLE_OWNER
148 SkASSERT(Flags::kNone == flags || Flags::kNoPendingIO == flags);
149
150 if (this->isAbandoned()) {
151 return nullptr;
152 }
153
154 // Currently we don't recycle compressed textures as scratch.
155 if (GrPixelConfigIsCompressed(desc.fConfig)) {
156 return nullptr;
157 }
158
159 if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) {
160 return nullptr;
161 }
162
163 if (auto tex = this->refScratchTexture(desc, flags)) {
164 return tex;
165 }
166
167 SkTCopyOnFirstWrite<GrSurfaceDesc> copyDesc(desc);
168
169 // bin by pow2 with a reasonable min
170 if (!SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag) &&
171 (fGpu->caps()->reuseScratchTextures() || (desc.fFlags & kRenderTarget_GrSurfaceFlag))) {
172 GrSurfaceDesc* wdesc = copyDesc.writable();
173 wdesc->fWidth = SkTMax(kMinScratchTextureSize, GrNextPow2(desc.fWidth));
174 wdesc->fHeight = SkTMax(kMinScratchTextureSize, GrNextPow2(desc.fHeight));
175 }
176
177 if (auto tex = this->refScratchTexture(*copyDesc, flags)) {
178 return tex;
179 }
180
181 return fGpu->createTexture(*copyDesc, SkBudgeted::kYes);
182 }
183
refScratchTexture(const GrSurfaceDesc & desc,Flags flags)184 sk_sp<GrTexture> GrResourceProvider::refScratchTexture(const GrSurfaceDesc& desc, Flags flags) {
185 ASSERT_SINGLE_OWNER
186 SkASSERT(!this->isAbandoned());
187 SkASSERT(!GrPixelConfigIsCompressed(desc.fConfig));
188 SkASSERT(fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo));
189
190 // We could make initial clears work with scratch textures but it is a rare case so we just opt
191 // to fall back to making a new texture.
192 if (!SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag) &&
193 (fGpu->caps()->reuseScratchTextures() || (desc.fFlags & kRenderTarget_GrSurfaceFlag))) {
194
195 GrScratchKey key;
196 GrTexturePriv::ComputeScratchKey(desc, &key);
197 auto scratchFlags = GrResourceCache::ScratchFlags::kNone;
198 if (Flags::kNoPendingIO & flags) {
199 scratchFlags |= GrResourceCache::ScratchFlags::kRequireNoPendingIO;
200 } else if (!(desc.fFlags & kRenderTarget_GrSurfaceFlag)) {
201 // If it is not a render target then it will most likely be populated by
202 // writePixels() which will trigger a flush if the texture has pending IO.
203 scratchFlags |= GrResourceCache::ScratchFlags::kPreferNoPendingIO;
204 }
205 GrGpuResource* resource = fCache->findAndRefScratchResource(key,
206 GrSurface::WorstCaseSize(desc),
207 scratchFlags);
208 if (resource) {
209 GrSurface* surface = static_cast<GrSurface*>(resource);
210 return sk_sp<GrTexture>(surface->asTexture());
211 }
212 }
213
214 return nullptr;
215 }
216
wrapBackendTexture(const GrBackendTexture & tex,GrWrapOwnership ownership,GrWrapCacheable cacheable,GrIOType ioType)217 sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTexture& tex,
218 GrWrapOwnership ownership,
219 GrWrapCacheable cacheable,
220 GrIOType ioType) {
221 ASSERT_SINGLE_OWNER
222 if (this->isAbandoned()) {
223 return nullptr;
224 }
225 return fGpu->wrapBackendTexture(tex, ownership, cacheable, ioType);
226 }
227
wrapRenderableBackendTexture(const GrBackendTexture & tex,int sampleCnt,GrWrapOwnership ownership,GrWrapCacheable cacheable)228 sk_sp<GrTexture> GrResourceProvider::wrapRenderableBackendTexture(const GrBackendTexture& tex,
229 int sampleCnt,
230 GrWrapOwnership ownership,
231 GrWrapCacheable cacheable) {
232 ASSERT_SINGLE_OWNER
233 if (this->isAbandoned()) {
234 return nullptr;
235 }
236 return fGpu->wrapRenderableBackendTexture(tex, sampleCnt, ownership, cacheable);
237 }
238
wrapBackendRenderTarget(const GrBackendRenderTarget & backendRT)239 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget(
240 const GrBackendRenderTarget& backendRT)
241 {
242 ASSERT_SINGLE_OWNER
243 return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(backendRT);
244 }
245
wrapVulkanSecondaryCBAsRenderTarget(const SkImageInfo & imageInfo,const GrVkDrawableInfo & vkInfo)246 sk_sp<GrRenderTarget> GrResourceProvider::wrapVulkanSecondaryCBAsRenderTarget(
247 const SkImageInfo& imageInfo, const GrVkDrawableInfo& vkInfo) {
248 ASSERT_SINGLE_OWNER
249 return this->isAbandoned() ? nullptr : fGpu->wrapVulkanSecondaryCBAsRenderTarget(imageInfo,
250 vkInfo);
251
252 }
253
assignUniqueKeyToResource(const GrUniqueKey & key,GrGpuResource * resource)254 void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key,
255 GrGpuResource* resource) {
256 ASSERT_SINGLE_OWNER
257 if (this->isAbandoned() || !resource) {
258 return;
259 }
260 resource->resourcePriv().setUniqueKey(key);
261 }
262
findResourceByUniqueKey(const GrUniqueKey & key)263 sk_sp<GrGpuResource> GrResourceProvider::findResourceByUniqueKey(const GrUniqueKey& key) {
264 ASSERT_SINGLE_OWNER
265 return this->isAbandoned() ? nullptr
266 : sk_sp<GrGpuResource>(fCache->findAndRefUniqueResource(key));
267 }
268
findOrMakeStaticBuffer(GrGpuBufferType intendedType,size_t size,const void * data,const GrUniqueKey & key)269 sk_sp<const GrGpuBuffer> GrResourceProvider::findOrMakeStaticBuffer(GrGpuBufferType intendedType,
270 size_t size,
271 const void* data,
272 const GrUniqueKey& key) {
273 if (auto buffer = this->findByUniqueKey<GrGpuBuffer>(key)) {
274 return std::move(buffer);
275 }
276 if (auto buffer = this->createBuffer(size, intendedType, kStatic_GrAccessPattern, data)) {
277 // We shouldn't bin and/or cache static buffers.
278 SkASSERT(buffer->size() == size);
279 SkASSERT(!buffer->resourcePriv().getScratchKey().isValid());
280 SkASSERT(!buffer->resourcePriv().hasPendingIO_debugOnly());
281 buffer->resourcePriv().setUniqueKey(key);
282 return sk_sp<const GrGpuBuffer>(buffer);
283 }
284 return nullptr;
285 }
286
createPatternedIndexBuffer(const uint16_t * pattern,int patternSize,int reps,int vertCount,const GrUniqueKey * key)287 sk_sp<const GrGpuBuffer> GrResourceProvider::createPatternedIndexBuffer(const uint16_t* pattern,
288 int patternSize,
289 int reps,
290 int vertCount,
291 const GrUniqueKey* key) {
292 size_t bufferSize = patternSize * reps * sizeof(uint16_t);
293
294 // This is typically used in GrMeshDrawOps, so we assume kNoPendingIO.
295 sk_sp<GrGpuBuffer> buffer(
296 this->createBuffer(bufferSize, GrGpuBufferType::kIndex, kStatic_GrAccessPattern));
297 if (!buffer) {
298 return nullptr;
299 }
300 uint16_t* data = (uint16_t*) buffer->map();
301 SkAutoTArray<uint16_t> temp;
302 if (!data) {
303 temp.reset(reps * patternSize);
304 data = temp.get();
305 }
306 for (int i = 0; i < reps; ++i) {
307 int baseIdx = i * patternSize;
308 uint16_t baseVert = (uint16_t)(i * vertCount);
309 for (int j = 0; j < patternSize; ++j) {
310 data[baseIdx+j] = baseVert + pattern[j];
311 }
312 }
313 if (temp.get()) {
314 if (!buffer->updateData(data, bufferSize)) {
315 return nullptr;
316 }
317 } else {
318 buffer->unmap();
319 }
320 if (key) {
321 SkASSERT(key->isValid());
322 this->assignUniqueKeyToResource(*key, buffer.get());
323 }
324 return std::move(buffer);
325 }
326
327 static constexpr int kMaxQuads = 1 << 12; // max possible: (1 << 14) - 1;
328
createQuadIndexBuffer()329 sk_sp<const GrGpuBuffer> GrResourceProvider::createQuadIndexBuffer() {
330 GR_STATIC_ASSERT(4 * kMaxQuads <= 65535);
331 static const uint16_t kPattern[] = { 0, 1, 2, 2, 1, 3 };
332 return this->createPatternedIndexBuffer(kPattern, 6, kMaxQuads, 4, nullptr);
333 }
334
QuadCountOfQuadBuffer()335 int GrResourceProvider::QuadCountOfQuadBuffer() { return kMaxQuads; }
336
createPath(const SkPath & path,const GrStyle & style)337 sk_sp<GrPath> GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) {
338 if (this->isAbandoned()) {
339 return nullptr;
340 }
341
342 SkASSERT(this->gpu()->pathRendering());
343 return this->gpu()->pathRendering()->createPath(path, style);
344 }
345
createBuffer(size_t size,GrGpuBufferType intendedType,GrAccessPattern accessPattern,const void * data)346 sk_sp<GrGpuBuffer> GrResourceProvider::createBuffer(size_t size, GrGpuBufferType intendedType,
347 GrAccessPattern accessPattern,
348 const void* data) {
349 if (this->isAbandoned()) {
350 return nullptr;
351 }
352 if (kDynamic_GrAccessPattern != accessPattern) {
353 return this->gpu()->createBuffer(size, intendedType, accessPattern, data);
354 }
355 // bin by pow2 with a reasonable min
356 static const size_t MIN_SIZE = 1 << 12;
357 size_t allocSize = SkTMax(MIN_SIZE, GrNextSizePow2(size));
358
359 GrScratchKey key;
360 GrGpuBuffer::ComputeScratchKeyForDynamicVBO(allocSize, intendedType, &key);
361 auto buffer =
362 sk_sp<GrGpuBuffer>(static_cast<GrGpuBuffer*>(this->cache()->findAndRefScratchResource(
363 key, allocSize, GrResourceCache::ScratchFlags::kNone)));
364 if (!buffer) {
365 buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern);
366 if (!buffer) {
367 return nullptr;
368 }
369 }
370 if (data) {
371 buffer->updateData(data, size);
372 }
373 return buffer;
374 }
375
attachStencilAttachment(GrRenderTarget * rt)376 bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt) {
377 SkASSERT(rt);
378 if (rt->renderTargetPriv().getStencilAttachment()) {
379 return true;
380 }
381
382 if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) {
383 GrUniqueKey sbKey;
384
385 int width = rt->width();
386 int height = rt->height();
387 #if 0
388 if (this->caps()->oversizedStencilSupport()) {
389 width = SkNextPow2(width);
390 height = SkNextPow2(height);
391 }
392 #endif
393 GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height,
394 rt->numStencilSamples(), &sbKey);
395 auto stencil = this->findByUniqueKey<GrStencilAttachment>(sbKey);
396 if (!stencil) {
397 // Need to try and create a new stencil
398 stencil.reset(this->gpu()->createStencilAttachmentForRenderTarget(rt, width, height));
399 if (!stencil) {
400 return false;
401 }
402 this->assignUniqueKeyToResource(sbKey, stencil.get());
403 }
404 rt->renderTargetPriv().attachStencilAttachment(std::move(stencil));
405 }
406 return SkToBool(rt->renderTargetPriv().getStencilAttachment());
407 }
408
wrapBackendTextureAsRenderTarget(const GrBackendTexture & tex,int sampleCnt)409 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendTextureAsRenderTarget(
410 const GrBackendTexture& tex, int sampleCnt)
411 {
412 if (this->isAbandoned()) {
413 return nullptr;
414 }
415 return fGpu->wrapBackendTextureAsRenderTarget(tex, sampleCnt);
416 }
417
makeSemaphore(bool isOwned)418 sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(bool isOwned) {
419 return fGpu->makeSemaphore(isOwned);
420 }
421
wrapBackendSemaphore(const GrBackendSemaphore & semaphore,SemaphoreWrapType wrapType,GrWrapOwnership ownership)422 sk_sp<GrSemaphore> GrResourceProvider::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
423 SemaphoreWrapType wrapType,
424 GrWrapOwnership ownership) {
425 ASSERT_SINGLE_OWNER
426 return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore,
427 wrapType,
428 ownership);
429 }
430