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