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