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