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 "GrTextureProvider.h"
9 
10 #include "GrCaps.h"
11 #include "GrTexturePriv.h"
12 #include "GrResourceCache.h"
13 #include "GrGpu.h"
14 #include "../private/GrSingleOwner.h"
15 #include "SkMathPriv.h"
16 #include "SkTArray.h"
17 
18 #define ASSERT_SINGLE_OWNER \
19     SkDEBUGCODE(GrSingleOwner::AutoEnforce debug_SingleOwner(fSingleOwner);)
20 
21 enum ScratchTextureFlags {
22     kExact_ScratchTextureFlag           = 0x1,
23     kNoPendingIO_ScratchTextureFlag     = 0x2,
24     kNoCreate_ScratchTextureFlag        = 0x4,
25 };
26 
GrTextureProvider(GrGpu * gpu,GrResourceCache * cache,GrSingleOwner * singleOwner)27 GrTextureProvider::GrTextureProvider(GrGpu* gpu, GrResourceCache* cache, GrSingleOwner* singleOwner)
28     : fCache(cache)
29     , fGpu(gpu)
30 #ifdef SK_DEBUG
31     , fSingleOwner(singleOwner)
32 #endif
33     {
34 }
35 
createMipMappedTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,const GrMipLevel * texels,int mipLevelCount)36 GrTexture* GrTextureProvider::createMipMappedTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
37                                                      const GrMipLevel* texels, int mipLevelCount) {
38     ASSERT_SINGLE_OWNER
39 
40     if (this->isAbandoned()) {
41         return nullptr;
42     }
43     if (mipLevelCount && !texels) {
44         return nullptr;
45     }
46     for (int i = 0; i < mipLevelCount; ++i) {
47         if (!texels[i].fPixels) {
48             return nullptr;
49         }
50     }
51 
52     if ((desc.fFlags & kRenderTarget_GrSurfaceFlag) &&
53         !fGpu->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
54         return nullptr;
55     }
56     if (!GrPixelConfigIsCompressed(desc.fConfig)) {
57         if (mipLevelCount < 2) {
58             static const uint32_t kFlags = kExact_ScratchTextureFlag |
59                                            kNoCreate_ScratchTextureFlag;
60             if (GrTexture* texture = this->refScratchTexture(desc, kFlags)) {
61                 if (!mipLevelCount ||
62                     texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
63                                          texels[0].fPixels, texels[0].fRowBytes)) {
64                     if (SkBudgeted::kNo == budgeted) {
65                         texture->resourcePriv().makeUnbudgeted();
66                     }
67                     return texture;
68                 }
69                 texture->unref();
70             }
71         }
72     }
73 
74     SkTArray<GrMipLevel> texelsShallowCopy(mipLevelCount);
75     for (int i = 0; i < mipLevelCount; ++i) {
76         texelsShallowCopy.push_back(texels[i]);
77     }
78     return fGpu->createTexture(desc, budgeted, texelsShallowCopy);
79 }
80 
createTexture(const GrSurfaceDesc & desc,SkBudgeted budgeted,const void * srcData,size_t rowBytes)81 GrTexture* GrTextureProvider::createTexture(const GrSurfaceDesc& desc, SkBudgeted budgeted,
82                                             const void* srcData, size_t rowBytes) {
83     GrMipLevel tempTexels;
84     GrMipLevel* texels = nullptr;
85     int levelCount = 0;
86     if (srcData) {
87       tempTexels.fPixels = srcData;
88       tempTexels.fRowBytes = rowBytes;
89       texels = &tempTexels;
90       levelCount = 1;
91     }
92     return this->createMipMappedTexture(desc, budgeted, texels, levelCount);
93 }
94 
createApproxTexture(const GrSurfaceDesc & desc)95 GrTexture* GrTextureProvider::createApproxTexture(const GrSurfaceDesc& desc) {
96     ASSERT_SINGLE_OWNER
97     return this->internalCreateApproxTexture(desc, 0);
98 }
99 
internalCreateApproxTexture(const GrSurfaceDesc & desc,uint32_t scratchFlags)100 GrTexture* GrTextureProvider::internalCreateApproxTexture(const GrSurfaceDesc& desc,
101                                                           uint32_t scratchFlags) {
102     ASSERT_SINGLE_OWNER
103     if (this->isAbandoned()) {
104         return nullptr;
105     }
106     // Currently we don't recycle compressed textures as scratch.
107     if (GrPixelConfigIsCompressed(desc.fConfig)) {
108         return nullptr;
109     } else {
110         return this->refScratchTexture(desc, scratchFlags);
111     }
112 }
113 
refScratchTexture(const GrSurfaceDesc & inDesc,uint32_t flags)114 GrTexture* GrTextureProvider::refScratchTexture(const GrSurfaceDesc& inDesc,
115                                                 uint32_t flags) {
116     ASSERT_SINGLE_OWNER
117     SkASSERT(!this->isAbandoned());
118     SkASSERT(!GrPixelConfigIsCompressed(inDesc.fConfig));
119 
120     SkTCopyOnFirstWrite<GrSurfaceDesc> desc(inDesc);
121 
122     if (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
123         if (!(kExact_ScratchTextureFlag & flags)) {
124             // bin by pow2 with a reasonable min
125             const int kMinSize = 16;
126             GrSurfaceDesc* wdesc = desc.writable();
127             wdesc->fWidth  = SkTMax(kMinSize, GrNextPow2(desc->fWidth));
128             wdesc->fHeight = SkTMax(kMinSize, GrNextPow2(desc->fHeight));
129         }
130 
131         GrScratchKey key;
132         GrTexturePriv::ComputeScratchKey(*desc, &key);
133         uint32_t scratchFlags = 0;
134         if (kNoPendingIO_ScratchTextureFlag & flags) {
135             scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
136         } else  if (!(desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
137             // If it is not a render target then it will most likely be populated by
138             // writePixels() which will trigger a flush if the texture has pending IO.
139             scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
140         }
141         GrGpuResource* resource = fCache->findAndRefScratchResource(key,
142                                                                    GrSurface::WorstCaseSize(*desc),
143                                                                    scratchFlags);
144         if (resource) {
145             GrSurface* surface = static_cast<GrSurface*>(resource);
146             GrRenderTarget* rt = surface->asRenderTarget();
147             if (rt && fGpu->caps()->discardRenderTargetSupport()) {
148                 rt->discard();
149             }
150             return surface->asTexture();
151         }
152     }
153 
154     if (!(kNoCreate_ScratchTextureFlag & flags)) {
155         return fGpu->createTexture(*desc, SkBudgeted::kYes);
156     }
157 
158     return nullptr;
159 }
160 
wrapBackendTexture(const GrBackendTextureDesc & desc,GrWrapOwnership ownership)161 GrTexture* GrTextureProvider::wrapBackendTexture(const GrBackendTextureDesc& desc,
162                                                  GrWrapOwnership ownership) {
163     ASSERT_SINGLE_OWNER
164     if (this->isAbandoned()) {
165         return nullptr;
166     }
167     return fGpu->wrapBackendTexture(desc, ownership);
168 }
169 
wrapBackendRenderTarget(const GrBackendRenderTargetDesc & desc)170 GrRenderTarget* GrTextureProvider::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) {
171     ASSERT_SINGLE_OWNER
172     return this->isAbandoned() ? nullptr : fGpu->wrapBackendRenderTarget(desc,
173                                                                          kBorrow_GrWrapOwnership);
174 }
175 
assignUniqueKeyToResource(const GrUniqueKey & key,GrGpuResource * resource)176 void GrTextureProvider::assignUniqueKeyToResource(const GrUniqueKey& key, GrGpuResource* resource) {
177     ASSERT_SINGLE_OWNER
178     if (this->isAbandoned() || !resource) {
179         return;
180     }
181     resource->resourcePriv().setUniqueKey(key);
182 }
183 
existsResourceWithUniqueKey(const GrUniqueKey & key) const184 bool GrTextureProvider::existsResourceWithUniqueKey(const GrUniqueKey& key) const {
185     ASSERT_SINGLE_OWNER
186     return this->isAbandoned() ? false : fCache->hasUniqueKey(key);
187 }
188 
findAndRefResourceByUniqueKey(const GrUniqueKey & key)189 GrGpuResource* GrTextureProvider::findAndRefResourceByUniqueKey(const GrUniqueKey& key) {
190     ASSERT_SINGLE_OWNER
191     return this->isAbandoned() ? nullptr : fCache->findAndRefUniqueResource(key);
192 }
193 
findAndRefTextureByUniqueKey(const GrUniqueKey & key)194 GrTexture* GrTextureProvider::findAndRefTextureByUniqueKey(const GrUniqueKey& key) {
195     ASSERT_SINGLE_OWNER
196     GrGpuResource* resource = this->findAndRefResourceByUniqueKey(key);
197     if (resource) {
198         GrTexture* texture = static_cast<GrSurface*>(resource)->asTexture();
199         SkASSERT(texture);
200         return texture;
201     }
202     return NULL;
203 }
204