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 "GrBuffer.h"
11 #include "GrCaps.h"
12 #include "GrContext.h"
13 #include "GrGpu.h"
14 #include "GrPathRendering.h"
15 #include "GrRenderTarget.h"
16 #include "GrRenderTargetPriv.h"
17 #include "GrResourceCache.h"
18 #include "GrResourceKey.h"
19 #include "GrSemaphore.h"
20 #include "GrStencilAttachment.h"
21 #include "GrSurfaceProxyPriv.h"
22 #include "GrTexturePriv.h"
23 #include "../private/GrSingleOwner.h"
24 #include "SkMathPriv.h"
25
26 GR_DECLARE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey);
27
28 const int GrResourceProvider::kMinScratchTextureSize = 16;
29
30 #define ASSERT_SINGLE_OWNER \
31 SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
32
GrResourceProvider(GrGpu * gpu,GrResourceCache * cache,GrSingleOwner * owner)33 GrResourceProvider::GrResourceProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* owner)
34 : fCache(cache)
35 , fGpu(gpu)
36 #ifdef SK_DEBUG
37 , fSingleOwner(owner)
38 #endif
39 {
40 fCaps = sk_ref_sp(fGpu->caps());
41
42 GR_DEFINE_STATIC_UNIQUE_KEY(gQuadIndexBufferKey);
43 fQuadIndexBufferKey = gQuadIndexBufferKey;
44 }
45
IsFunctionallyExact(GrTextureProxy * proxy)46 bool GrResourceProvider::IsFunctionallyExact(GrTextureProxy* proxy) {
47 return proxy->priv().isExact() || (SkIsPow2(proxy->width()) && SkIsPow2(proxy->height()));
48 }
49
createMipMappedTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,const GrMipLevel * texels,int mipLevelCount,uint32_t flags,SkDestinationSurfaceColorMode mipColorMode)50 GrTexture* GrResourceProvider::createMipMappedTexture(const GrSurfaceDesc& desc,
51 SkBudgeted budgeted, const GrMipLevel* texels,
52 int mipLevelCount, uint32_t flags,
53 SkDestinationSurfaceColorMode mipColorMode) {
54 ASSERT_SINGLE_OWNER
55
56 if (this->isAbandoned()) {
57 return nullptr;
58 }
59 if (mipLevelCount && !texels) {
60 return nullptr;
61 }
62 for (int i = 0; i < mipLevelCount; ++i) {
63 if (!texels[i].fPixels) {
64 return nullptr;
65 }
66 }
67 if (mipLevelCount > 1 && GrPixelConfigIsSint(desc.fConfig)) {
68 return nullptr;
69 }
70 if ((desc.fFlags & kRenderTarget_GrSurfaceFlag) &&
71 !fGpu->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
72 return nullptr;
73 }
74 if (!GrPixelConfigIsCompressed(desc.fConfig)) {
75 if (mipLevelCount < 2) {
76 flags |= kExact_Flag | kNoCreate_Flag;
77 if (GrTexture* texture = this->refScratchTexture(desc, flags)) {
78 if (!mipLevelCount ||
79 texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
80 texels[0].fPixels, texels[0].fRowBytes)) {
81 if (SkBudgeted::kNo == budgeted) {
82 texture->resourcePriv().makeUnbudgeted();
83 }
84 texture->texturePriv().setMipColorMode(mipColorMode);
85 return texture;
86 }
87 texture->unref();
88 }
89 }
90 }
91
92 SkTArray<GrMipLevel> texelsShallowCopy(mipLevelCount);
93 for (int i = 0; i < mipLevelCount; ++i) {
94 texelsShallowCopy.push_back(texels[i]);
95 }
96 GrTexture* texture = fGpu->createTexture(desc, budgeted, texelsShallowCopy);
97 if (texture) {
98 texture->texturePriv().setMipColorMode(mipColorMode);
99 }
100 return texture;
101 }
102
createTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,const void * srcData,size_t rowBytes,uint32_t flags)103 GrTexture* GrResourceProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
104 const void* srcData, size_t rowBytes, uint32_t flags) {
105 GrMipLevel tempTexels;
106 GrMipLevel* texels = nullptr;
107 int levelCount = 0;
108 if (srcData) {
109 tempTexels.fPixels = srcData;
110 tempTexels.fRowBytes = rowBytes;
111 texels = &tempTexels;
112 levelCount = 1;
113 }
114 return this->createMipMappedTexture(desc, budgeted, texels, levelCount, flags);
115 }
116
createApproxTexture(const GrSurfaceDesc & desc,uint32_t flags)117 GrTexture* GrResourceProvider::createApproxTexture(const GrSurfaceDesc& desc, uint32_t flags) {
118 ASSERT_SINGLE_OWNER
119 SkASSERT(0 == flags || kNoPendingIO_Flag == flags);
120 return this->internalCreateApproxTexture(desc, flags);
121 }
122
internalCreateApproxTexture(const GrSurfaceDesc & desc,uint32_t scratchFlags)123 GrTexture* GrResourceProvider::internalCreateApproxTexture(const GrSurfaceDesc& desc,
124 uint32_t scratchFlags) {
125 ASSERT_SINGLE_OWNER
126 if (this->isAbandoned()) {
127 return nullptr;
128 }
129 // Currently we don't recycle compressed textures as scratch.
130 if (GrPixelConfigIsCompressed(desc.fConfig)) {
131 return nullptr;
132 } else {
133 return this->refScratchTexture(desc, scratchFlags);
134 }
135 }
136
refScratchTexture(const GrSurfaceDesc & inDesc,uint32_t flags)137 GrTexture* GrResourceProvider::refScratchTexture(const GrSurfaceDesc& inDesc,
138 uint32_t flags) {
139 ASSERT_SINGLE_OWNER
140 SkASSERT(!this->isAbandoned());
141 SkASSERT(!GrPixelConfigIsCompressed(inDesc.fConfig));
142
143 SkTCopyOnFirstWrite<GrSurfaceDesc> desc(inDesc);
144
145 if (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
146 if (!(kExact_Flag & flags)) {
147 // bin by pow2 with a reasonable min
148 GrSurfaceDesc* wdesc = desc.writable();
149 wdesc->fWidth = SkTMax(kMinScratchTextureSize, GrNextPow2(desc->fWidth));
150 wdesc->fHeight = SkTMax(kMinScratchTextureSize, GrNextPow2(desc->fHeight));
151 }
152
153 GrScratchKey key;
154 GrTexturePriv::ComputeScratchKey(*desc, &key);
155 uint32_t scratchFlags = 0;
156 if (kNoPendingIO_Flag & flags) {
157 scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
158 } else if (!(desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
159 // If it is not a render target then it will most likely be populated by
160 // writePixels() which will trigger a flush if the texture has pending IO.
161 scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
162 }
163 GrGpuResource* resource = fCache->findAndRefScratchResource(key,
164 GrSurface::WorstCaseSize(*desc),
165 scratchFlags);
166 if (resource) {
167 GrSurface* surface = static_cast<GrSurface*>(resource);
168 GrRenderTarget* rt = surface->asRenderTarget();
169 if (rt && fGpu->caps()->discardRenderTargetSupport()) {
170 rt->discard();
171 }
172 return surface->asTexture();
173 }
174 }
175
176 if (!(kNoCreate_Flag & flags)) {
177 return fGpu->createTexture(*desc, SkBudgeted::kYes);
178 }
179
180 return nullptr;
181 }
182
wrapBackendTexture(const GrBackendTextureDesc & desc,GrWrapOwnership ownership)183 sk_sp<GrTexture> GrResourceProvider::wrapBackendTexture(const GrBackendTextureDesc& desc,
184 GrWrapOwnership ownership) {
185 ASSERT_SINGLE_OWNER
186 if (this->isAbandoned()) {
187 return nullptr;
188 }
189 return fGpu->wrapBackendTexture(desc, ownership);
190 }
191
wrapBackendRenderTarget(const GrBackendRenderTargetDesc & desc)192 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendRenderTarget(
193 const GrBackendRenderTargetDesc& desc)
194 {
195 ASSERT_SINGLE_OWNER
196 return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(desc);
197 }
198
assignUniqueKeyToResource(const GrUniqueKey & key,GrGpuResource * resource)199 void GrResourceProvider::assignUniqueKeyToResource(const GrUniqueKey& key,
200 GrGpuResource* resource) {
201 ASSERT_SINGLE_OWNER
202 if (this->isAbandoned() || !resource) {
203 return;
204 }
205 resource->resourcePriv().setUniqueKey(key);
206 }
207
findAndRefResourceByUniqueKey(const GrUniqueKey & key)208 GrGpuResource* GrResourceProvider::findAndRefResourceByUniqueKey(const GrUniqueKey& key) {
209 ASSERT_SINGLE_OWNER
210 return this->isAbandoned() ? nullptr : fCache->findAndRefUniqueResource(key);
211 }
212
findAndRefTextureByUniqueKey(const GrUniqueKey & key)213 GrTexture* GrResourceProvider::findAndRefTextureByUniqueKey(const GrUniqueKey& key) {
214 ASSERT_SINGLE_OWNER
215 GrGpuResource* resource = this->findAndRefResourceByUniqueKey(key);
216 if (resource) {
217 GrTexture* texture = static_cast<GrSurface*>(resource)->asTexture();
218 SkASSERT(texture);
219 return texture;
220 }
221 return NULL;
222 }
223
224 // MDB TODO (caching): this side-steps the issue of texture proxies with unique IDs
assignUniqueKeyToProxy(const GrUniqueKey & key,GrTextureProxy * proxy)225 void GrResourceProvider::assignUniqueKeyToProxy(const GrUniqueKey& key, GrTextureProxy* proxy) {
226 ASSERT_SINGLE_OWNER
227 SkASSERT(key.isValid());
228 if (this->isAbandoned() || !proxy) {
229 return;
230 }
231
232 GrTexture* texture = proxy->instantiate(this);
233 if (!texture) {
234 return;
235 }
236
237 this->assignUniqueKeyToResource(key, texture);
238 }
239
240 // MDB TODO (caching): this side-steps the issue of texture proxies with unique IDs
findProxyByUniqueKey(const GrUniqueKey & key)241 sk_sp<GrTextureProxy> GrResourceProvider::findProxyByUniqueKey(const GrUniqueKey& key) {
242 ASSERT_SINGLE_OWNER
243
244 sk_sp<GrTexture> texture(this->findAndRefTextureByUniqueKey(key));
245 if (!texture) {
246 return nullptr;
247 }
248
249 return GrSurfaceProxy::MakeWrapped(std::move(texture));
250 }
251
createInstancedIndexBuffer(const uint16_t * pattern,int patternSize,int reps,int vertCount,const GrUniqueKey & key)252 const GrBuffer* GrResourceProvider::createInstancedIndexBuffer(const uint16_t* pattern,
253 int patternSize,
254 int reps,
255 int vertCount,
256 const GrUniqueKey& key) {
257 size_t bufferSize = patternSize * reps * sizeof(uint16_t);
258
259 // This is typically used in GrMeshDrawOps, so we assume kNoPendingIO.
260 GrBuffer* buffer = this->createBuffer(bufferSize, kIndex_GrBufferType, kStatic_GrAccessPattern,
261 kNoPendingIO_Flag);
262 if (!buffer) {
263 return nullptr;
264 }
265 uint16_t* data = (uint16_t*) buffer->map();
266 bool useTempData = (nullptr == data);
267 if (useTempData) {
268 data = new uint16_t[reps * patternSize];
269 }
270 for (int i = 0; i < reps; ++i) {
271 int baseIdx = i * patternSize;
272 uint16_t baseVert = (uint16_t)(i * vertCount);
273 for (int j = 0; j < patternSize; ++j) {
274 data[baseIdx+j] = baseVert + pattern[j];
275 }
276 }
277 if (useTempData) {
278 if (!buffer->updateData(data, bufferSize)) {
279 buffer->unref();
280 return nullptr;
281 }
282 delete[] data;
283 } else {
284 buffer->unmap();
285 }
286 this->assignUniqueKeyToResource(key, buffer);
287 return buffer;
288 }
289
createQuadIndexBuffer()290 const GrBuffer* GrResourceProvider::createQuadIndexBuffer() {
291 static const int kMaxQuads = 1 << 12; // max possible: (1 << 14) - 1;
292 GR_STATIC_ASSERT(4 * kMaxQuads <= 65535);
293 static const uint16_t kPattern[] = { 0, 1, 2, 0, 2, 3 };
294
295 return this->createInstancedIndexBuffer(kPattern, 6, kMaxQuads, 4, fQuadIndexBufferKey);
296 }
297
createPath(const SkPath & path,const GrStyle & style)298 GrPath* GrResourceProvider::createPath(const SkPath& path, const GrStyle& style) {
299 SkASSERT(this->gpu()->pathRendering());
300 return this->gpu()->pathRendering()->createPath(path, style);
301 }
302
createPathRange(GrPathRange::PathGenerator * gen,const GrStyle & style)303 GrPathRange* GrResourceProvider::createPathRange(GrPathRange::PathGenerator* gen,
304 const GrStyle& style) {
305 SkASSERT(this->gpu()->pathRendering());
306 return this->gpu()->pathRendering()->createPathRange(gen, style);
307 }
308
createGlyphs(const SkTypeface * tf,const SkScalerContextEffects & effects,const SkDescriptor * desc,const GrStyle & style)309 GrPathRange* GrResourceProvider::createGlyphs(const SkTypeface* tf,
310 const SkScalerContextEffects& effects,
311 const SkDescriptor* desc,
312 const GrStyle& style) {
313
314 SkASSERT(this->gpu()->pathRendering());
315 return this->gpu()->pathRendering()->createGlyphs(tf, effects, desc, style);
316 }
317
createBuffer(size_t size,GrBufferType intendedType,GrAccessPattern accessPattern,uint32_t flags,const void * data)318 GrBuffer* GrResourceProvider::createBuffer(size_t size, GrBufferType intendedType,
319 GrAccessPattern accessPattern, uint32_t flags,
320 const void* data) {
321 if (this->isAbandoned()) {
322 return nullptr;
323 }
324 if (kDynamic_GrAccessPattern != accessPattern) {
325 return this->gpu()->createBuffer(size, intendedType, accessPattern, data);
326 }
327 if (!(flags & kRequireGpuMemory_Flag) &&
328 this->gpu()->caps()->preferClientSideDynamicBuffers() &&
329 GrBufferTypeIsVertexOrIndex(intendedType) &&
330 kDynamic_GrAccessPattern == accessPattern) {
331 return GrBuffer::CreateCPUBacked(this->gpu(), size, intendedType, data);
332 }
333
334 // bin by pow2 with a reasonable min
335 static const size_t MIN_SIZE = 1 << 12;
336 size_t allocSize = SkTMax(MIN_SIZE, GrNextSizePow2(size));
337
338 GrScratchKey key;
339 GrBuffer::ComputeScratchKeyForDynamicVBO(allocSize, intendedType, &key);
340 uint32_t scratchFlags = 0;
341 if (flags & kNoPendingIO_Flag) {
342 scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
343 } else {
344 scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
345 }
346 GrBuffer* buffer = static_cast<GrBuffer*>(
347 this->cache()->findAndRefScratchResource(key, allocSize, scratchFlags));
348 if (!buffer) {
349 buffer = this->gpu()->createBuffer(allocSize, intendedType, kDynamic_GrAccessPattern);
350 if (!buffer) {
351 return nullptr;
352 }
353 }
354 if (data) {
355 buffer->updateData(data, size);
356 }
357 SkASSERT(!buffer->isCPUBacked()); // We should only cache real VBOs.
358 return buffer;
359 }
360
attachStencilAttachment(GrRenderTarget * rt)361 GrStencilAttachment* GrResourceProvider::attachStencilAttachment(GrRenderTarget* rt) {
362 SkASSERT(rt);
363 if (rt->renderTargetPriv().getStencilAttachment()) {
364 return rt->renderTargetPriv().getStencilAttachment();
365 }
366
367 if (!rt->wasDestroyed() && rt->canAttemptStencilAttachment()) {
368 GrUniqueKey sbKey;
369
370 int width = rt->width();
371 int height = rt->height();
372 #if 0
373 if (this->caps()->oversizedStencilSupport()) {
374 width = SkNextPow2(width);
375 height = SkNextPow2(height);
376 }
377 #endif
378 bool newStencil = false;
379 GrStencilAttachment::ComputeSharedStencilAttachmentKey(width, height,
380 rt->numStencilSamples(), &sbKey);
381 GrStencilAttachment* stencil = static_cast<GrStencilAttachment*>(
382 this->findAndRefResourceByUniqueKey(sbKey));
383 if (!stencil) {
384 // Need to try and create a new stencil
385 stencil = this->gpu()->createStencilAttachmentForRenderTarget(rt, width, height);
386 if (stencil) {
387 this->assignUniqueKeyToResource(sbKey, stencil);
388 newStencil = true;
389 }
390 }
391 if (rt->renderTargetPriv().attachStencilAttachment(stencil)) {
392 if (newStencil) {
393 // Right now we're clearing the stencil attachment here after it is
394 // attached to a RT for the first time. When we start matching
395 // stencil buffers with smaller color targets this will no longer
396 // be correct because it won't be guaranteed to clear the entire
397 // sb.
398 // We used to clear down in the GL subclass using a special purpose
399 // FBO. But iOS doesn't allow a stencil-only FBO. It reports unsupported
400 // FBO status.
401 this->gpu()->clearStencil(rt);
402 }
403 }
404 }
405 return rt->renderTargetPriv().getStencilAttachment();
406 }
407
wrapBackendTextureAsRenderTarget(const GrBackendTextureDesc & desc)408 sk_sp<GrRenderTarget> GrResourceProvider::wrapBackendTextureAsRenderTarget(
409 const GrBackendTextureDesc& desc)
410 {
411 if (this->isAbandoned()) {
412 return nullptr;
413 }
414 return this->gpu()->wrapBackendTextureAsRenderTarget(desc);
415 }
416
makeSemaphore()417 sk_sp<GrSemaphore> SK_WARN_UNUSED_RESULT GrResourceProvider::makeSemaphore() {
418 return fGpu->makeSemaphore();
419 }
420
takeOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore)421 void GrResourceProvider::takeOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) {
422 semaphore->resetGpu(fGpu);
423 }
424
releaseOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore)425 void GrResourceProvider::releaseOwnershipOfSemaphore(sk_sp<GrSemaphore> semaphore) {
426 semaphore->resetGpu(nullptr);
427 }
428