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