1/*
2 * Copyright 2011 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 "GrContext.h"
9#include "GrGLTexture.h"
10#include "GrGLGpu.h"
11#include "GrResourceProvider.h"
12#include "GrSemaphore.h"
13#include "GrShaderCaps.h"
14#include "SkMakeUnique.h"
15#include "SkTraceMemoryDump.h"
16
17#define GPUGL static_cast<GrGLGpu*>(this->getGpu())
18#define GL_CALL(X) GR_GL_CALL(GPUGL->glInterface(), X)
19
20static inline GrSLType sampler_type(const GrGLTexture::IDDesc& idDesc, GrPixelConfig config,
21                                    const GrGLGpu* gpu) {
22    if (idDesc.fInfo.fTarget == GR_GL_TEXTURE_EXTERNAL) {
23        SkASSERT(gpu->caps()->shaderCaps()->externalTextureSupport());
24        SkASSERT(!GrPixelConfigIsSint(config));
25        return kTextureExternalSampler_GrSLType;
26    } else if (idDesc.fInfo.fTarget == GR_GL_TEXTURE_RECTANGLE) {
27        SkASSERT(gpu->glCaps().rectangleTextureSupport());
28        SkASSERT(!GrPixelConfigIsSint(config));
29        return kTexture2DRectSampler_GrSLType;
30    } else if (GrPixelConfigIsSint(config)) {
31        return kITexture2DSampler_GrSLType;
32    } else {
33        SkASSERT(idDesc.fInfo.fTarget == GR_GL_TEXTURE_2D);
34        return kTexture2DSampler_GrSLType;
35    }
36}
37
38static inline GrSamplerParams::FilterMode highest_filter_mode(const GrGLTexture::IDDesc& idDesc,
39                                                              GrPixelConfig config) {
40    if (GrPixelConfigIsSint(config)) {
41        // Integer textures in GL can use GL_NEAREST_MIPMAP_NEAREST. This is a mode we don't support
42        // and don't currently have a use for.
43        return GrSamplerParams::kNone_FilterMode;
44    }
45    if (idDesc.fInfo.fTarget == GR_GL_TEXTURE_RECTANGLE ||
46        idDesc.fInfo.fTarget == GR_GL_TEXTURE_EXTERNAL) {
47        return GrSamplerParams::kBilerp_FilterMode;
48    }
49    return GrSamplerParams::kMipMap_FilterMode;
50}
51
52// Because this class is virtually derived from GrSurface we must explicitly call its constructor.
53GrGLTexture::GrGLTexture(GrGLGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& desc,
54                         const IDDesc& idDesc)
55    : GrSurface(gpu, desc)
56    , INHERITED(gpu, desc, sampler_type(idDesc, desc.fConfig, gpu),
57                highest_filter_mode(idDesc, desc.fConfig), false) {
58    this->init(desc, idDesc);
59    this->registerWithCache(budgeted);
60}
61
62GrGLTexture::GrGLTexture(GrGLGpu* gpu, SkBudgeted budgeted, const GrSurfaceDesc& desc,
63                         const IDDesc& idDesc,
64                         bool wasMipMapDataProvided)
65    : GrSurface(gpu, desc)
66    , INHERITED(gpu, desc, sampler_type(idDesc, desc.fConfig, gpu),
67                highest_filter_mode(idDesc, desc.fConfig),
68                wasMipMapDataProvided) {
69    this->init(desc, idDesc);
70    this->registerWithCache(budgeted);
71}
72
73GrGLTexture::GrGLTexture(GrGLGpu* gpu, Wrapped, const GrSurfaceDesc& desc, const IDDesc& idDesc)
74    : GrSurface(gpu, desc)
75    , INHERITED(gpu, desc, sampler_type(idDesc, desc.fConfig, gpu),
76                highest_filter_mode(idDesc, desc.fConfig), false) {
77    this->init(desc, idDesc);
78    this->registerWithCacheWrapped();
79}
80
81GrGLTexture::GrGLTexture(GrGLGpu* gpu, const GrSurfaceDesc& desc, const IDDesc& idDesc,
82                         bool wasMipMapDataProvided)
83    : GrSurface(gpu, desc)
84    , INHERITED(gpu, desc, sampler_type(idDesc, desc.fConfig, gpu),
85                highest_filter_mode(idDesc, desc.fConfig),
86                wasMipMapDataProvided) {
87    this->init(desc, idDesc);
88}
89
90void GrGLTexture::init(const GrSurfaceDesc& desc, const IDDesc& idDesc) {
91    SkASSERT(0 != idDesc.fInfo.fID);
92    fTexParams.invalidate();
93    fTexParamsTimestamp = GrGpu::kExpiredTimestamp;
94    fInfo = idDesc.fInfo;
95    fTextureIDOwnership = idDesc.fOwnership;
96}
97
98void GrGLTexture::onRelease() {
99    if (fInfo.fID) {
100        if (GrBackendObjectOwnership::kBorrowed != fTextureIDOwnership) {
101            GL_CALL(DeleteTextures(1, &fInfo.fID));
102        }
103        fInfo.fID = 0;
104    }
105    INHERITED::onRelease();
106}
107
108void GrGLTexture::onAbandon() {
109    fInfo.fTarget = 0;
110    fInfo.fID = 0;
111    INHERITED::onAbandon();
112}
113
114GrBackendObject GrGLTexture::getTextureHandle() const {
115    return reinterpret_cast<GrBackendObject>(&fInfo);
116}
117
118std::unique_ptr<GrExternalTextureData> GrGLTexture::detachBackendTexture() {
119    // Flush any pending writes to this texture
120    this->getContext()->prepareSurfaceForExternalIO(this);
121
122    // Set up a semaphore to be signaled once the data is ready, and flush GL
123    sk_sp<GrSemaphore> semaphore = this->getContext()->resourceProvider()->makeSemaphore();
124    this->getGpu()->insertSemaphore(semaphore);
125    this->getGpu()->flush();
126
127    // Make a copy of our GL-specific information
128    auto data = skstd::make_unique<GrGLExternalTextureData>(fInfo, std::move(semaphore),
129                                                            this->getContext());
130
131    // Ensure the cache can't reach this texture anymore
132    this->detachFromCache();
133
134    // Detach from the GL object, so we don't use it (or try to delete it when we're freed)
135    fInfo.fTarget = 0;
136    fInfo.fID = 0;
137
138    return std::move(data);
139}
140
141void GrGLTexture::setMemoryBacking(SkTraceMemoryDump* traceMemoryDump,
142                                   const SkString& dumpName) const {
143    SkString texture_id;
144    texture_id.appendU32(this->textureID());
145    traceMemoryDump->setMemoryBacking(dumpName.c_str(), "gl_texture",
146                                      texture_id.c_str());
147}
148
149sk_sp<GrGLTexture> GrGLTexture::MakeWrapped(GrGLGpu* gpu, const GrSurfaceDesc& desc,
150                                            const IDDesc& idDesc) {
151    return sk_sp<GrGLTexture>(new GrGLTexture(gpu, kWrapped, desc, idDesc));
152}
153
154