1
2/*
3 * Copyright 2015 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#include "GrTextureProvider.h"
10#include "GrTexturePriv.h"
11#include "GrResourceCache.h"
12#include "GrGpu.h"
13
14enum ScratchTextureFlags {
15    kExact_ScratchTextureFlag           = 0x1,
16    kNoPendingIO_ScratchTextureFlag     = 0x2,
17    kNoCreate_ScratchTextureFlag        = 0x4,
18};
19
20GrTexture* GrTextureProvider::createTexture(const GrSurfaceDesc& desc, bool budgeted,
21                                            const void* srcData, size_t rowBytes) {
22    if (this->isAbandoned()) {
23        return NULL;
24    }
25    if ((desc.fFlags & kRenderTarget_GrSurfaceFlag) &&
26        !fGpu->caps()->isConfigRenderable(desc.fConfig, desc.fSampleCnt > 0)) {
27        return NULL;
28    }
29    if (!GrPixelConfigIsCompressed(desc.fConfig)) {
30        static const uint32_t kFlags = kExact_ScratchTextureFlag |
31                                       kNoCreate_ScratchTextureFlag;
32        if (GrTexture* texture = this->internalRefScratchTexture(desc, kFlags)) {
33            if (!srcData || texture->writePixels(0, 0, desc.fWidth, desc.fHeight, desc.fConfig,
34                                                 srcData, rowBytes)) {
35                if (!budgeted) {
36                    texture->resourcePriv().makeUnbudgeted();
37                }
38                return texture;
39            }
40            texture->unref();
41        }
42    }
43    return fGpu->createTexture(desc, budgeted, srcData, rowBytes);
44}
45
46GrTexture* GrTextureProvider::refScratchTexture(const GrSurfaceDesc& desc, ScratchTexMatch match,
47                                                bool calledDuringFlush) {
48    if (this->isAbandoned()) {
49        return NULL;
50    }
51    // Currently we don't recycle compressed textures as scratch.
52    if (GrPixelConfigIsCompressed(desc.fConfig)) {
53        return NULL;
54    } else {
55        uint32_t flags = 0;
56        if (kExact_ScratchTexMatch == match) {
57            flags |= kExact_ScratchTextureFlag;
58        }
59        if (calledDuringFlush) {
60            flags |= kNoPendingIO_ScratchTextureFlag;
61        }
62        return this->internalRefScratchTexture(desc, flags);
63    }
64}
65
66GrTexture* GrTextureProvider::internalRefScratchTexture(const GrSurfaceDesc& inDesc,
67                                                        uint32_t flags) {
68    SkASSERT(!this->isAbandoned());
69    SkASSERT(!GrPixelConfigIsCompressed(inDesc.fConfig));
70
71    SkTCopyOnFirstWrite<GrSurfaceDesc> desc(inDesc);
72
73    if (fGpu->caps()->reuseScratchTextures() || (desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
74        if (!(kExact_ScratchTextureFlag & flags)) {
75            // bin by pow2 with a reasonable min
76            static const int MIN_SIZE = 16;
77            GrSurfaceDesc* wdesc = desc.writable();
78            wdesc->fWidth  = SkTMax(MIN_SIZE, GrNextPow2(desc->fWidth));
79            wdesc->fHeight = SkTMax(MIN_SIZE, GrNextPow2(desc->fHeight));
80        }
81
82        GrScratchKey key;
83        GrTexturePriv::ComputeScratchKey(*desc, &key);
84        uint32_t scratchFlags = 0;
85        if (kNoPendingIO_ScratchTextureFlag & flags) {
86            scratchFlags = GrResourceCache::kRequireNoPendingIO_ScratchFlag;
87        } else  if (!(desc->fFlags & kRenderTarget_GrSurfaceFlag)) {
88            // If it is not a render target then it will most likely be populated by
89            // writePixels() which will trigger a flush if the texture has pending IO.
90            scratchFlags = GrResourceCache::kPreferNoPendingIO_ScratchFlag;
91        }
92        GrGpuResource* resource = fCache->findAndRefScratchResource(key, scratchFlags);
93        if (resource) {
94            GrSurface* surface = static_cast<GrSurface*>(resource);
95            GrRenderTarget* rt = surface->asRenderTarget();
96            if (rt && fGpu->caps()->discardRenderTargetSupport()) {
97                rt->discard();
98            }
99            return surface->asTexture();
100        }
101    }
102
103    if (!(kNoCreate_ScratchTextureFlag & flags)) {
104        return fGpu->createTexture(*desc, true, NULL, 0);
105    }
106
107    return NULL;
108}
109
110GrTexture* GrTextureProvider::wrapBackendTexture(const GrBackendTextureDesc& desc) {
111    if (this->isAbandoned()) {
112        return NULL;
113    }
114    return fGpu->wrapBackendTexture(desc);
115}
116
117GrRenderTarget* GrTextureProvider::wrapBackendRenderTarget(const GrBackendRenderTargetDesc& desc) {
118    return this->isAbandoned() ? NULL : fGpu->wrapBackendRenderTarget(desc);
119}
120
121void GrTextureProvider::assignUniqueKeyToResource(const GrUniqueKey& key, GrGpuResource* resource) {
122    if (this->isAbandoned() || !resource) {
123        return;
124    }
125    resource->resourcePriv().setUniqueKey(key);
126}
127
128bool GrTextureProvider::existsResourceWithUniqueKey(const GrUniqueKey& key) const {
129    return this->isAbandoned() ? false : fCache->hasUniqueKey(key);
130}
131
132GrGpuResource* GrTextureProvider::findAndRefResourceByUniqueKey(const GrUniqueKey& key) {
133    return this->isAbandoned() ? NULL : fCache->findAndRefUniqueResource(key);
134}
135