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,SkDestinationSurfaceColorMode mipColorMode)64 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
65 const GrMipLevel texels[], int mipLevelCount,
66 SkDestinationSurfaceColorMode mipColorMode) {
67 ASSERT_SINGLE_OWNER
68
69 SkASSERT(mipLevelCount > 0);
70
71 if (this->isAbandoned()) {
72 return nullptr;
73 }
74
75 GrMipMapped mipMapped = mipLevelCount > 1 ? GrMipMapped::kYes : GrMipMapped::kNo;
76 if (!fCaps->validateSurfaceDesc(desc, mipMapped)) {
77 return nullptr;
78 }
79
80 sk_sp<GrTexture> tex(fGpu->createTexture(desc, budgeted, texels, mipLevelCount));
81 if (tex) {
82 tex->texturePriv().setMipColorMode(mipColorMode);
83 }
84
85 return tex;
86 }
87
getExactScratch(const GrSurfaceDesc & desc,SkBudgeted budgeted,uint32_t flags)88 sk_sp<GrTexture> GrResourceProvider::getExactScratch(const GrSurfaceDesc& desc,
89 SkBudgeted budgeted, uint32_t flags) {
90 sk_sp<GrTexture> tex(this->refScratchTexture(desc, flags));
91 if (tex && SkBudgeted::kNo == budgeted) {
92 tex->resourcePriv().makeUnbudgeted();
93 }
94
95 return tex;
96 }
97
createTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,SkBackingFit fit,const GrMipLevel & mipLevel)98 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc,
99 SkBudgeted budgeted,
100 SkBackingFit fit,
101 const GrMipLevel& mipLevel) {
102 ASSERT_SINGLE_OWNER
103
104 if (this->isAbandoned()) {
105 return nullptr;
106 }
107
108 if (!mipLevel.fPixels) {
109 return nullptr;
110 }
111
112 if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) {
113 return nullptr;
114 }
115
116 GrContext* context = fGpu->getContext();
117 GrProxyProvider* proxyProvider = context->contextPriv().proxyProvider();
118
119 SkColorType colorType;
120 if (GrPixelConfigToColorType(desc.fConfig, &colorType)) {
121 // DDL TODO: remove this use of createInstantiatedProxy and convert it to a testing-only
122 // method.
123 sk_sp<GrTextureProxy> proxy = proxyProvider->createInstantiatedProxy(desc,
124 fit,
125 budgeted);
126 if (!proxy) {
127 return nullptr;
128 }
129 // We use an ephemeral surface context to do the write pixels. Here it isn't clear what
130 // color space to tag it with. That's ok because GrSurfaceContext::writePixels doesn't
131 // do any color space conversions. Though, that is likely to change. However, if the
132 // pixel config is sRGB then the passed color space here must have sRGB gamma or
133 // GrSurfaceContext creation fails.
134 sk_sp<SkColorSpace> colorSpace;
135 if (GrPixelConfigIsSRGB(desc.fConfig)) {
136 colorSpace = SkColorSpace::MakeSRGB();
137 }
138 auto srcInfo = SkImageInfo::Make(desc.fWidth, desc.fHeight, colorType,
139 kUnknown_SkAlphaType, colorSpace);
140 sk_sp<GrSurfaceContext> sContext = context->contextPriv().makeWrappedSurfaceContext(
141 std::move(proxy), std::move(colorSpace));
142 if (!sContext) {
143 return nullptr;
144 }
145 SkAssertResult(sContext->writePixels(srcInfo, mipLevel.fPixels, mipLevel.fRowBytes, 0, 0));
146 return sk_ref_sp(sContext->asTextureProxy()->priv().peekTexture());
147 } else {
148 return fGpu->createTexture(desc, budgeted, &mipLevel, 1);
149 }
150 }
151
createTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,uint32_t flags)152 sk_sp<GrTexture> GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
153 uint32_t flags) {
154 ASSERT_SINGLE_OWNER
155 if (this->isAbandoned()) {
156 return nullptr;
157 }
158
159 if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) {
160 return nullptr;
161 }
162
163 sk_sp<GrTexture> tex = this->getExactScratch(desc, budgeted, flags);
164 if (tex) {
165 return tex;
166 }
167
168 return fGpu->createTexture(desc, budgeted);
169 }
170
createApproxTexture(const GrSurfaceDesc & desc,uint32_t flags)171 sk_sp<GrTexture> GrResourceProvider::createApproxTexture(const GrSurfaceDesc& desc,
172 uint32_t flags) {
173 ASSERT_SINGLE_OWNER
174 SkASSERT(0 == flags || kNoPendingIO_Flag == flags);
175
176 if (this->isAbandoned()) {
177 return nullptr;
178 }
179
180 if (!fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo)) {
181 return nullptr;
182 }
183
184 if (auto tex = this->refScratchTexture(desc, flags)) {
185 return tex;
186 }
187
188 SkTCopyOnFirstWrite<GrSurfaceDesc> copyDesc(desc);
189
190 // bin by pow2 with a reasonable min
191 if (!SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag) &&
192 (fGpu->caps()->reuseScratchTextures() || (desc.fFlags & kRenderTarget_GrSurfaceFlag))) {
193 GrSurfaceDesc* wdesc = copyDesc.writable();
194 wdesc->fWidth = SkTMax(kMinScratchTextureSize, GrNextPow2(desc.fWidth));
195 wdesc->fHeight = SkTMax(kMinScratchTextureSize, GrNextPow2(desc.fHeight));
196 }
197
198 if (auto tex = this->refScratchTexture(*copyDesc, flags)) {
199 return tex;
200 }
201
202 return fGpu->createTexture(*copyDesc, SkBudgeted::kYes);
203 }
204
refScratchTexture(const GrSurfaceDesc & desc,uint32_t flags)205 sk_sp<GrTexture> GrResourceProvider::refScratchTexture(const GrSurfaceDesc& desc,
206 uint32_t flags) {
207 ASSERT_SINGLE_OWNER
208 SkASSERT(!this->isAbandoned());
209 SkASSERT(fCaps->validateSurfaceDesc(desc, GrMipMapped::kNo));
210
211 // We could make initial clears work with scratch textures but it is a rare case so we just opt
212 // to fall back to making a new texture.
213 if (!SkToBool(desc.fFlags & kPerformInitialClear_GrSurfaceFlag) &&
214 (fGpu->caps()->reuseScratchTextures() || (desc.fFlags & kRenderTarget_GrSurfaceFlag))) {
215
216 GrScratchKey key;
217 GrTexturePriv::ComputeScratchKey(desc, &key);
218 uint32_t scratchFlags = 0;
219 if (kNoPendingIO_Flag & flags) {
220 scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
221 } else if (!(desc.fFlags & kRenderTarget_GrSurfaceFlag)) {
222 // If it is not a render target then it will most likely be populated by
223 // writePixels() which will trigger a flush if the texture has pending IO.
224 scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
225 }
226 GrGpuResource* resource = fCache->findAndRefScratchResource(key,
227 GrSurface::WorstCaseSize(desc),
228 scratchFlags);
229 if (resource) {
230 GrSurface* surface = static_cast<GrSurface*>(resource);
231 return sk_sp<GrTexture>(surface->asTexture());
232 }
233 }
234
235 return nullptr;
236 }
237
wrapBackendTexture(const GrBackendTexture & tex,GrWrapOwnership ownership)238 sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTexture& tex,
239 GrWrapOwnership ownership) {
240 ASSERT_SINGLE_OWNER
241 if (this->isAbandoned()) {
242 return nullptr;
243 }
244 return fGpu->wrapBackendTexture(tex, ownership);
245 }
246
wrapRenderableBackendTexture(const GrBackendTexture & tex,int sampleCnt,GrWrapOwnership ownership)247 sk_sp<GrTexture> GrResourceProvider::wrapRenderableBackendTexture(const GrBackendTexture& tex,
248 int sampleCnt,
249 GrWrapOwnership ownership) {
250 ASSERT_SINGLE_OWNER
251 if (this->isAbandoned()) {
252 return nullptr;
253 }
254 return fGpu->wrapRenderableBackendTexture(tex, sampleCnt, ownership);
255 }
256
wrapBackendRenderTarget(const GrBackendRenderTarget & backendRT)257 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget(
258 const GrBackendRenderTarget& backendRT)
259 {
260 ASSERT_SINGLE_OWNER
261 return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(backendRT);
262 }
263
assignUniqueKeyToResource(const GrUniqueKey & key,GrGpuResource * resource)264 void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key,
265 GrGpuResource* resource) {
266 ASSERT_SINGLE_OWNER
267 if (this->isAbandoned() || !resource) {
268 return;
269 }
270 resource->resourcePriv().setUniqueKey(key);
271 }
272
findResourceByUniqueKey(const GrUniqueKey & key)273 sk_sp<GrGpuResource> GrResourceProvider::findResourceByUniqueKey(const GrUniqueKey& key) {
274 ASSERT_SINGLE_OWNER
275 return this->isAbandoned() ? nullptr
276 : sk_sp<GrGpuResource>(fCache->findAndRefUniqueResource(key));
277 }
278
findOrMakeStaticBuffer(GrBufferType intendedType,size_t size,const void * data,const GrUniqueKey & key)279 sk_sp<const GrBuffer> GrResourceProvider::findOrMakeStaticBuffer(GrBufferType intendedType,
280 size_t size,
281 const void* data,
282 const GrUniqueKey& key) {
283 if (auto buffer = this->findByUniqueKey<GrBuffer>(key)) {
284 return buffer;
285 }
286 if (auto buffer = this->createBuffer(size, intendedType, kStatic_GrAccessPattern, 0,
287 data)) {
288 // We shouldn't bin and/or cachestatic buffers.
289 SkASSERT(buffer->sizeInBytes() == size);
290 SkASSERT(!buffer->resourcePriv().getScratchKey().isValid());
291 SkASSERT(!buffer->resourcePriv().hasPendingIO_debugOnly());
292 buffer->resourcePriv().setUniqueKey(key);
293 return sk_sp<const GrBuffer>(buffer);
294 }
295 return nullptr;
296 }
297
createPatternedIndexBuffer(const uint16_t * pattern,int patternSize,int reps,int vertCount,const GrUniqueKey & key)298 sk_sp<const GrBuffer> GrResourceProvider::createPatternedIndexBuffer(const uint16_t* pattern,
299 int patternSize,
300 int reps,
301 int vertCount,
302 const GrUniqueKey& key) {
303 size_t bufferSize = patternSize * reps * sizeof(uint16_t);
304
305 // This is typically used in GrMeshDrawOps, so we assume kNoPendingIO.
306 sk_sp<GrBuffer> buffer(this->createBuffer(bufferSize, kIndex_GrBufferType,
307 kStatic_GrAccessPattern, kNoPendingIO_Flag));
308 if (!buffer) {
309 return nullptr;
310 }
311 uint16_t* data = (uint16_t*) buffer->map();
312 SkAutoTArray<uint16_t> temp;
313 if (!data) {
314 temp.reset(reps * patternSize);
315 data = temp.get();
316 }
317 for (int i = 0; i < reps; ++i) {
318 int baseIdx = i * patternSize;
319 uint16_t baseVert = (uint16_t)(i * vertCount);
320 for (int j = 0; j < patternSize; ++j) {
321 data[baseIdx+j] = baseVert + pattern[j];
322 }
323 }
324 if (temp.get()) {
325 if (!buffer->updateData(data, bufferSize)) {
326 return nullptr;
327 }
328 } else {
329 buffer->unmap();
330 }
331 this->assignUniqueKeyToResource(key, buffer.get());
332 return std::move(buffer);
333 }
334
335 static constexpr int kMaxQuads = 1 << 12; // max possible: (1 << 14) - 1;
336
createQuadIndexBuffer()337 sk_sp<const GrBuffer> GrResourceProvider::createQuadIndexBuffer() {
338 GR_STATIC_ASSERT(4 * kMaxQuads <= 65535);
339 static const uint16_t kPattern[] = { 0, 1, 2, 2, 1, 3 };
340 return this->createPatternedIndexBuffer(kPattern, 6, kMaxQuads, 4, fQuadIndexBufferKey);
341 }
342
QuadCountOfQuadBuffer()343 int GrResourceProvider::QuadCountOfQuadBuffer() { return kMaxQuads; }
344
createPath(const SkPath & path,const GrStyle & style)345 sk_sp<GrPath> GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) {
346 if (this->isAbandoned()) {
347 return nullptr;
348 }
349
350 SkASSERT(this->gpu()->pathRendering());
351 return this->gpu()->pathRendering()->createPath(path, style);
352 }
353
createPathRange(GrPathRange::PathGenerator * gen,const GrStyle & style)354 sk_sp<GrPathRange> GrResourceProvider::createPathRange(GrPathRange::PathGenerator* gen,
355 const GrStyle& style) {
356 if (this->isAbandoned()) {
357 return nullptr;
358 }
359
360 SkASSERT(this->gpu()->pathRendering());
361 return this->gpu()->pathRendering()->createPathRange(gen, style);
362 }
363
createGlyphs(const SkTypeface * tf,const SkScalerContextEffects & effects,const SkDescriptor * desc,const GrStyle & style)364 sk_sp<GrPathRange> GrResourceProvider::createGlyphs(const SkTypeface* tf,
365 const SkScalerContextEffects& effects,
366 const SkDescriptor* desc,
367 const GrStyle& style) {
368
369 SkASSERT(this->gpu()->pathRendering());
370 return this->gpu()->pathRendering()->createGlyphs(tf, effects, desc, style);
371 }
372
createBuffer(size_t size,GrBufferType intendedType,GrAccessPattern accessPattern,uint32_t flags,const void * data)373 GrBuffer* GrResourceProvider::createBuffer(size_t size, GrBufferType intendedType,
374 GrAccessPattern accessPattern, uint32_t flags,
375 const void* data) {
376 if (this->isAbandoned()) {
377 return nullptr;
378 }
379 if (kDynamic_GrAccessPattern != accessPattern) {
380 return this->gpu()->createBuffer(size, intendedType, accessPattern, data);
381 }
382 if (!(flags & kRequireGpuMemory_Flag) &&
383 this->gpu()->caps()->preferClientSideDynamicBuffers() &&
384 GrBufferTypeIsVertexOrIndex(intendedType) &&
385 kDynamic_GrAccessPattern == accessPattern) {
386 return GrBuffer::CreateCPUBacked(this->gpu(), size, intendedType, data);
387 }
388
389 // bin by pow2 with a reasonable min
390 static const size_t MIN_SIZE = 1 << 12;
391 size_t allocSize = SkTMax(MIN_SIZE, GrNextSizePow2(size));
392
393 GrScratchKey key;
394 GrBuffer::ComputeScratchKeyForDynamicVBO(allocSize, intendedType, &key);
395 uint32_t scratchFlags = 0;
396 if (flags & kNoPendingIO_Flag) {
397 scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
398 } else {
399 scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
400 }
401 GrBuffer* buffer = static_cast<GrBuffer*>(
402 this->cache()->findAndRefScratchResource(key, allocSize, scratchFlags));
403 if (!buffer) {
404 buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern);
405 if (!buffer) {
406 return nullptr;
407 }
408 }
409 if (data) {
410 buffer->updateData(data, size);
411 }
412 SkASSERT(!buffer->isCPUBacked()); // We should only cache real VBOs.
413 return buffer;
414 }
415
attachStencilAttachment(GrRenderTarget * rt)416 bool GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt) {
417 SkASSERT(rt);
418 if (rt->renderTargetPriv().getStencilAttachment()) {
419 return true;
420 }
421
422 if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) {
423 GrUniqueKey sbKey;
424
425 int width = rt->width();
426 int height = rt->height();
427 #if 0
428 if (this->caps()->oversizedStencilSupport()) {
429 width = SkNextPow2(width);
430 height = SkNextPow2(height);
431 }
432 #endif
433 SkDEBUGCODE(bool newStencil = false;)
434 GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height,
435 rt->numStencilSamples(), &sbKey);
436 auto stencil = this->findByUniqueKey<GrStencilAttachment>(sbKey);
437 if (!stencil) {
438 // Need to try and create a new stencil
439 stencil.reset(this->gpu()->createStencilAttachmentForRenderTarget(rt, width, height));
440 if (stencil) {
441 this->assignUniqueKeyToResource(sbKey, stencil.get());
442 SkDEBUGCODE(newStencil = true;)
443 }
444 }
445 if (rt->renderTargetPriv().attachStencilAttachment(std::move(stencil))) {
446 #ifdef SK_DEBUG
447 // Fill the SB with an inappropriate value. opLists that use the
448 // SB should clear it properly.
449 if (newStencil) {
450 SkASSERT(rt->renderTargetPriv().getStencilAttachment()->isDirty());
451 this->gpu()->clearStencil(rt, 0xFFFF);
452 SkASSERT(rt->renderTargetPriv().getStencilAttachment()->isDirty());
453 }
454 #endif
455 }
456 }
457 return SkToBool(rt->renderTargetPriv().getStencilAttachment());
458 }
459
wrapBackendTextureAsRenderTarget(const GrBackendTexture & tex,int sampleCnt)460 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendTextureAsRenderTarget(
461 const GrBackendTexture& tex, int sampleCnt)
462 {
463 if (this->isAbandoned()) {
464 return nullptr;
465 }
466 return fGpu->wrapBackendTextureAsRenderTarget(tex, sampleCnt);
467 }
468
makeSemaphore(bool isOwned)469 sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore(bool isOwned) {
470 return fGpu->makeSemaphore(isOwned);
471 }
472
wrapBackendSemaphore(const GrBackendSemaphore & semaphore,SemaphoreWrapType wrapType,GrWrapOwnership ownership)473 sk_sp<GrSemaphore> GrResourceProvider::wrapBackendSemaphore(const GrBackendSemaphore& semaphore,
474 SemaphoreWrapType wrapType,
475 GrWrapOwnership ownership) {
476 ASSERT_SINGLE_OWNER
477 return this->isAbandoned() ? nullptr : fGpu->wrapBackendSemaphore(semaphore,
478 wrapType,
479 ownership);
480 }
481
takeOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore)482 void GrResourceProvider::takeOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) {
483 semaphore->resetGpu(fGpu);
484 }
485
releaseOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore)486 void GrResourceProvider::releaseOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) {
487 semaphore->resetGpu(nullptr);
488 }
489