SkImage_Gpu.cpp revision 2d5b7147032e3806b5895667a899440119707c2d
1/*
2 * Copyright 2012 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 "SkAutoPixmapStorage.h"
9#include "GrCaps.h"
10#include "GrContext.h"
11#include "GrDrawContext.h"
12#include "GrImageIDTextureAdjuster.h"
13#include "effects/GrYUVEffect.h"
14#include "SkCanvas.h"
15#include "SkBitmapCache.h"
16#include "SkGrPriv.h"
17#include "SkImage_Gpu.h"
18#include "SkMipMap.h"
19#include "SkPixelRef.h"
20
21SkImage_Gpu::SkImage_Gpu(int w, int h, uint32_t uniqueID, SkAlphaType at, GrTexture* tex,
22                         sk_sp<SkColorSpace> colorSpace, SkBudgeted budgeted)
23    : INHERITED(w, h, uniqueID)
24    , fTexture(SkRef(tex))
25    , fAlphaType(at)
26    , fBudgeted(budgeted)
27    , fColorSpace(std::move(colorSpace))
28    , fAddedRasterVersionToCache(false)
29{
30    SkASSERT(tex->width() == w);
31    SkASSERT(tex->height() == h);
32}
33
34SkImage_Gpu::~SkImage_Gpu() {
35    if (fAddedRasterVersionToCache.load()) {
36        SkNotifyBitmapGenIDIsStale(this->uniqueID());
37    }
38}
39
40extern void SkTextureImageApplyBudgetedDecision(SkImage* image) {
41    if (image->isTextureBacked()) {
42        ((SkImage_Gpu*)image)->applyBudgetDecision();
43    }
44}
45
46SkImageInfo SkImage_Gpu::onImageInfo() const {
47    SkColorType ct;
48    if (!GrPixelConfigToColorType(fTexture->config(), &ct)) {
49        ct = kUnknown_SkColorType;
50    }
51    return SkImageInfo::Make(fTexture->width(), fTexture->height(), ct, fAlphaType, fColorSpace);
52}
53
54static SkImageInfo make_info(int w, int h, bool isOpaque, sk_sp<SkColorSpace> colorSpace) {
55    return SkImageInfo::MakeN32(w, h, isOpaque ? kOpaque_SkAlphaType : kPremul_SkAlphaType,
56                                std::move(colorSpace));
57}
58
59bool SkImage_Gpu::getROPixels(SkBitmap* dst, CachingHint chint) const {
60    if (SkBitmapCache::Find(this->uniqueID(), dst)) {
61        SkASSERT(dst->getGenerationID() == this->uniqueID());
62        SkASSERT(dst->isImmutable());
63        SkASSERT(dst->getPixels());
64        return true;
65    }
66
67    if (!dst->tryAllocPixels(make_info(this->width(), this->height(), this->isOpaque(),
68                                       this->fColorSpace))) {
69        return false;
70    }
71    if (!fTexture->readPixels(0, 0, dst->width(), dst->height(), kSkia8888_GrPixelConfig,
72                              dst->getPixels(), dst->rowBytes())) {
73        return false;
74    }
75
76    dst->pixelRef()->setImmutableWithID(this->uniqueID());
77    if (kAllow_CachingHint == chint) {
78        SkBitmapCache::Add(this->uniqueID(), *dst);
79        fAddedRasterVersionToCache.store(true);
80    }
81    return true;
82}
83
84GrTexture* SkImage_Gpu::asTextureRef(GrContext* ctx, const GrTextureParams& params,
85                                     SkSourceGammaTreatment gammaTreatment) const {
86    GrTextureAdjuster adjuster(this->peekTexture(), this->bounds(), this->uniqueID(),
87                               this->onImageInfo().colorSpace());
88    return adjuster.refTextureSafeForParams(params, gammaTreatment, nullptr);
89}
90
91bool SkImage_Gpu::isOpaque() const {
92    return GrPixelConfigIsOpaque(fTexture->config()) || fAlphaType == kOpaque_SkAlphaType;
93}
94
95static void apply_premul(const SkImageInfo& info, void* pixels, size_t rowBytes) {
96    switch (info.colorType()) {
97        case kRGBA_8888_SkColorType:
98        case kBGRA_8888_SkColorType:
99            break;
100        default:
101            return; // nothing to do
102    }
103
104    // SkColor is not necesarily RGBA or BGRA, but it is one of them on little-endian,
105    // and in either case, the alpha-byte is always in the same place, so we can safely call
106    // SkPreMultiplyColor()
107    //
108    SkColor* row = (SkColor*)pixels;
109    for (int y = 0; y < info.height(); ++y) {
110        for (int x = 0; x < info.width(); ++x) {
111            row[x] = SkPreMultiplyColor(row[x]);
112        }
113    }
114}
115
116bool SkImage_Gpu::onReadPixels(const SkImageInfo& info, void* pixels, size_t rowBytes,
117                               int srcX, int srcY, CachingHint) const {
118    GrPixelConfig config = SkImageInfo2GrPixelConfig(info, *fTexture->getContext()->caps());
119    uint32_t flags = 0;
120    if (kUnpremul_SkAlphaType == info.alphaType() && kPremul_SkAlphaType == fAlphaType) {
121        // let the GPU perform this transformation for us
122        flags = GrContext::kUnpremul_PixelOpsFlag;
123    }
124    if (!fTexture->readPixels(srcX, srcY, info.width(), info.height(), config,
125                              pixels, rowBytes, flags)) {
126        return false;
127    }
128    // do we have to manually fix-up the alpha channel?
129    //      src         dst
130    //      unpremul    premul      fix manually
131    //      premul      unpremul    done by kUnpremul_PixelOpsFlag
132    // all other combos need to change.
133    //
134    // Should this be handled by Ganesh? todo:?
135    //
136    if (kPremul_SkAlphaType == info.alphaType() && kUnpremul_SkAlphaType == fAlphaType) {
137        apply_premul(info, pixels, rowBytes);
138    }
139    return true;
140}
141
142sk_sp<SkImage> SkImage_Gpu::onMakeSubset(const SkIRect& subset) const {
143    GrContext* ctx = fTexture->getContext();
144    GrSurfaceDesc desc = fTexture->desc();
145    desc.fWidth = subset.width();
146    desc.fHeight = subset.height();
147
148    sk_sp<GrTexture> subTx(ctx->textureProvider()->createTexture(desc, fBudgeted));
149    if (!subTx) {
150        return nullptr;
151    }
152    ctx->copySurface(subTx.get(), fTexture, subset, SkIPoint::Make(0, 0));
153    return sk_make_sp<SkImage_Gpu>(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID,
154                                   fAlphaType, subTx.get(), fColorSpace, fBudgeted);
155}
156
157///////////////////////////////////////////////////////////////////////////////////////////////////
158
159static sk_sp<SkImage> new_wrapped_texture_common(GrContext* ctx, const GrBackendTextureDesc& desc,
160                                                 SkAlphaType at, sk_sp<SkColorSpace> colorSpace,
161                                                 GrWrapOwnership ownership,
162                                                 SkImage::TextureReleaseProc releaseProc,
163                                                 SkImage::ReleaseContext releaseCtx) {
164    if (desc.fWidth <= 0 || desc.fHeight <= 0) {
165        return nullptr;
166    }
167    SkAutoTUnref<GrTexture> tex(ctx->textureProvider()->wrapBackendTexture(desc, ownership));
168    if (!tex) {
169        return nullptr;
170    }
171    if (releaseProc) {
172        tex->setRelease(releaseProc, releaseCtx);
173    }
174
175    const SkBudgeted budgeted = SkBudgeted::kNo;
176    return sk_make_sp<SkImage_Gpu>(desc.fWidth, desc.fHeight, kNeedNewImageUniqueID,
177                                   at, tex, colorSpace, budgeted);
178}
179
180sk_sp<SkImage> SkImage::MakeFromTexture(GrContext* ctx, const GrBackendTextureDesc& desc,
181                                        SkAlphaType at, sk_sp<SkColorSpace> cs,
182                                        TextureReleaseProc releaseP, ReleaseContext releaseC) {
183    return new_wrapped_texture_common(ctx, desc, at, std::move(cs), kBorrow_GrWrapOwnership,
184                                      releaseP, releaseC);
185}
186
187sk_sp<SkImage> SkImage::MakeFromAdoptedTexture(GrContext* ctx, const GrBackendTextureDesc& desc,
188                                               SkAlphaType at, sk_sp<SkColorSpace> cs) {
189    return new_wrapped_texture_common(ctx, desc, at, std::move(cs), kAdopt_GrWrapOwnership,
190                                      nullptr, nullptr);
191}
192
193static sk_sp<SkImage> make_from_yuv_textures_copy(GrContext* ctx, SkYUVColorSpace colorSpace,
194                                                  bool nv12,
195                                                  const GrBackendObject yuvTextureHandles[],
196                                                  const SkISize yuvSizes[],
197                                                  GrSurfaceOrigin origin,
198                                                  sk_sp<SkColorSpace> imageColorSpace) {
199    const SkBudgeted budgeted = SkBudgeted::kYes;
200
201    if (yuvSizes[0].fWidth <= 0 || yuvSizes[0].fHeight <= 0 || yuvSizes[1].fWidth <= 0 ||
202        yuvSizes[1].fHeight <= 0) {
203        return nullptr;
204    }
205    if (!nv12 && (yuvSizes[2].fWidth <= 0 || yuvSizes[2].fHeight <= 0)) {
206        return nullptr;
207    }
208
209    const GrPixelConfig kConfig = nv12 ? kRGBA_8888_GrPixelConfig : kAlpha_8_GrPixelConfig;
210
211    GrBackendTextureDesc yDesc;
212    yDesc.fConfig = kConfig;
213    yDesc.fOrigin = origin;
214    yDesc.fSampleCnt = 0;
215    yDesc.fTextureHandle = yuvTextureHandles[0];
216    yDesc.fWidth = yuvSizes[0].fWidth;
217    yDesc.fHeight = yuvSizes[0].fHeight;
218
219    GrBackendTextureDesc uDesc;
220    uDesc.fConfig = kConfig;
221    uDesc.fOrigin = origin;
222    uDesc.fSampleCnt = 0;
223    uDesc.fTextureHandle = yuvTextureHandles[1];
224    uDesc.fWidth = yuvSizes[1].fWidth;
225    uDesc.fHeight = yuvSizes[1].fHeight;
226
227    sk_sp<GrTexture> yTex(
228        ctx->textureProvider()->wrapBackendTexture(yDesc, kBorrow_GrWrapOwnership));
229    sk_sp<GrTexture> uTex(
230        ctx->textureProvider()->wrapBackendTexture(uDesc, kBorrow_GrWrapOwnership));
231    sk_sp<GrTexture> vTex;
232    if (nv12) {
233        vTex = uTex;
234    } else {
235        GrBackendTextureDesc vDesc;
236        vDesc.fConfig = kConfig;
237        vDesc.fOrigin = origin;
238        vDesc.fSampleCnt = 0;
239        vDesc.fTextureHandle = yuvTextureHandles[2];
240        vDesc.fWidth = yuvSizes[2].fWidth;
241        vDesc.fHeight = yuvSizes[2].fHeight;
242
243        vTex = sk_sp<GrTexture>(
244            ctx->textureProvider()->wrapBackendTexture(vDesc, kBorrow_GrWrapOwnership));
245    }
246    if (!yTex || !uTex || !vTex) {
247        return nullptr;
248    }
249
250    const int width = yuvSizes[0].fWidth;
251    const int height = yuvSizes[0].fHeight;
252
253    // Needs to be a render target in order to draw to it for the yuv->rgb conversion.
254    sk_sp<GrDrawContext> drawContext(ctx->makeDrawContext(SkBackingFit::kExact,
255                                                          width, height,
256                                                          kRGBA_8888_GrPixelConfig,
257                                                          std::move(imageColorSpace),
258                                                          0,
259                                                          origin));
260    if (!drawContext) {
261        return nullptr;
262    }
263
264    GrPaint paint;
265    paint.setPorterDuffXPFactory(SkXfermode::kSrc_Mode);
266    paint.addColorFragmentProcessor(
267        GrYUVEffect::MakeYUVToRGB(yTex.get(), uTex.get(), vTex.get(), yuvSizes, colorSpace, nv12));
268
269    const SkRect rect = SkRect::MakeWH(SkIntToScalar(width), SkIntToScalar(height));
270
271    drawContext->drawRect(GrNoClip(), paint, SkMatrix::I(), rect);
272    ctx->flushSurfaceWrites(drawContext->accessRenderTarget());
273    return sk_make_sp<SkImage_Gpu>(width, height, kNeedNewImageUniqueID,
274                                   kOpaque_SkAlphaType, drawContext->asTexture().get(),
275                                   sk_ref_sp(drawContext->getColorSpace()), budgeted);
276}
277
278sk_sp<SkImage> SkImage::MakeFromYUVTexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
279                                                const GrBackendObject yuvTextureHandles[3],
280                                                const SkISize yuvSizes[3], GrSurfaceOrigin origin,
281                                                sk_sp<SkColorSpace> imageColorSpace) {
282    return make_from_yuv_textures_copy(ctx, colorSpace, false, yuvTextureHandles, yuvSizes, origin,
283                                       std::move(imageColorSpace));
284}
285
286sk_sp<SkImage> SkImage::MakeFromNV12TexturesCopy(GrContext* ctx, SkYUVColorSpace colorSpace,
287                                                 const GrBackendObject yuvTextureHandles[2],
288                                                 const SkISize yuvSizes[2],
289                                                 GrSurfaceOrigin origin,
290                                                 sk_sp<SkColorSpace> imageColorSpace) {
291    return make_from_yuv_textures_copy(ctx, colorSpace, true, yuvTextureHandles, yuvSizes, origin,
292                                       std::move(imageColorSpace));
293}
294
295static sk_sp<SkImage> create_image_from_maker(GrTextureMaker* maker, SkAlphaType at, uint32_t id) {
296    SkAutoTUnref<GrTexture> texture(maker->refTextureForParams(GrTextureParams::ClampNoFilter(),
297                                                               SkSourceGammaTreatment::kRespect));
298    if (!texture) {
299        return nullptr;
300    }
301    return sk_make_sp<SkImage_Gpu>(texture->width(), texture->height(), id, at, texture,
302                                   sk_ref_sp(maker->getColorSpace()), SkBudgeted::kNo);
303}
304
305sk_sp<SkImage> SkImage::makeTextureImage(GrContext *context) const {
306    if (!context) {
307        return nullptr;
308    }
309    if (GrTexture* peek = as_IB(this)->peekTexture()) {
310        return peek->getContext() == context ? sk_ref_sp(const_cast<SkImage*>(this)) : nullptr;
311    }
312    // No way to check whether a image is premul or not?
313    SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
314
315    if (SkImageCacherator* cacher = as_IB(this)->peekCacherator()) {
316        GrImageTextureMaker maker(context, cacher, this, kDisallow_CachingHint);
317        return create_image_from_maker(&maker, at, this->uniqueID());
318    }
319
320    if (const SkBitmap* bmp = as_IB(this)->onPeekBitmap()) {
321        GrBitmapTextureMaker maker(context, *bmp);
322        return create_image_from_maker(&maker, at, this->uniqueID());
323    }
324    return nullptr;
325}
326
327sk_sp<SkImage> SkImage::makeNonTextureImage() const {
328    if (!this->isTextureBacked()) {
329        return sk_ref_sp(const_cast<SkImage*>(this));
330    }
331    SkImageInfo info = as_IB(this)->onImageInfo();
332    size_t rowBytes = info.minRowBytes();
333    size_t size = info.getSafeSize(rowBytes);
334    auto data = SkData::MakeUninitialized(size);
335    if (!data) {
336        return nullptr;
337    }
338    SkPixmap pm(info, data->writable_data(), rowBytes);
339    if (!this->readPixels(pm, 0, 0, kDisallow_CachingHint)) {
340        return nullptr;
341    }
342    return MakeRasterData(info, data, rowBytes);
343}
344
345sk_sp<SkImage> SkImage::MakeTextureFromPixmap(GrContext* ctx, const SkPixmap& pixmap,
346                                              SkBudgeted budgeted) {
347    if (!ctx) {
348        return nullptr;
349    }
350    SkAutoTUnref<GrTexture> texture(GrUploadPixmapToTexture(ctx, pixmap, budgeted));
351    if (!texture) {
352        return nullptr;
353    }
354    return sk_make_sp<SkImage_Gpu>(texture->width(), texture->height(), kNeedNewImageUniqueID,
355                                   pixmap.alphaType(), texture,
356                                   sk_ref_sp(pixmap.info().colorSpace()), budgeted);
357}
358
359///////////////////////////////////////////////////////////////////////////////////////////////////
360
361namespace {
362struct MipMapLevelData {
363    void* fPixelData;
364    size_t fRowBytes;
365};
366
367struct DeferredTextureImage {
368    uint32_t    fContextUniqueID;
369    // We don't store a SkImageInfo because it contains a ref-counted SkColorSpace.
370    int         fWidth;
371    int         fHeight;
372    SkColorType fColorType;
373    SkAlphaType fAlphaType;
374    void*       fColorSpace;
375    size_t      fColorSpaceSize;
376    int         fColorTableCnt;
377    uint32_t*   fColorTableData;
378    int         fMipMapLevelCount;
379    // The fMipMapLevelData array may contain more than 1 element.
380    // It contains fMipMapLevelCount elements.
381    // That means this struct's size is not known at compile-time.
382    MipMapLevelData fMipMapLevelData[1];
383};
384}  // anonymous namespace
385
386size_t SkImage::getDeferredTextureImageData(const GrContextThreadSafeProxy& proxy,
387                                            const DeferredTextureImageUsageParams params[],
388                                            int paramCnt, void* buffer) const {
389    // Extract relevant min/max values from the params array.
390    int lowestPreScaleMipLevel = params[0].fPreScaleMipLevel;
391    SkFilterQuality highestFilterQuality = params[0].fQuality;
392    for (int i = 1; i < paramCnt; ++i) {
393        if (lowestPreScaleMipLevel > params[i].fPreScaleMipLevel)
394            lowestPreScaleMipLevel = params[i].fPreScaleMipLevel;
395        if (highestFilterQuality < params[i].fQuality)
396            highestFilterQuality = params[i].fQuality;
397    }
398
399    const bool fillMode = SkToBool(buffer);
400    if (fillMode && !SkIsAlign8(reinterpret_cast<intptr_t>(buffer))) {
401        return 0;
402    }
403
404    // Calculate scaling parameters.
405    bool isScaled = lowestPreScaleMipLevel != 0;
406
407    SkISize scaledSize;
408    if (isScaled) {
409        // SkMipMap::ComputeLevelSize takes an index into an SkMipMap. SkMipMaps don't contain the
410        // base level, so to get an SkMipMap index we must subtract one from the GL MipMap level.
411        scaledSize = SkMipMap::ComputeLevelSize(this->width(), this->height(),
412                                                lowestPreScaleMipLevel - 1);
413    } else {
414        scaledSize = SkISize::Make(this->width(), this->height());
415    }
416
417    // We never want to scale at higher than SW medium quality, as SW medium matches GPU high.
418    SkFilterQuality scaleFilterQuality = highestFilterQuality;
419    if (scaleFilterQuality > kMedium_SkFilterQuality) {
420        scaleFilterQuality = kMedium_SkFilterQuality;
421    }
422
423    const int maxTextureSize = proxy.fCaps->maxTextureSize();
424    if (scaledSize.width() > maxTextureSize || scaledSize.height() > maxTextureSize) {
425        return 0;
426    }
427
428    SkAutoPixmapStorage pixmap;
429    SkImageInfo info;
430    size_t pixelSize = 0;
431    size_t ctSize = 0;
432    int ctCount = 0;
433    if (!isScaled && this->peekPixels(&pixmap)) {
434        info = pixmap.info();
435        pixelSize = SkAlign8(pixmap.getSafeSize());
436        if (pixmap.ctable()) {
437            ctCount = pixmap.ctable()->count();
438            ctSize = SkAlign8(pixmap.ctable()->count() * 4);
439        }
440    } else {
441        // Here we're just using presence of data to know whether there is a codec behind the image.
442        // In the future we will access the cacherator and get the exact data that we want to (e.g.
443        // yuv planes) upload.
444        sk_sp<SkData> data(this->refEncoded());
445        if (!data && !this->peekPixels(nullptr)) {
446            return 0;
447        }
448        SkAlphaType at = this->isOpaque() ? kOpaque_SkAlphaType : kPremul_SkAlphaType;
449        info = SkImageInfo::MakeN32(scaledSize.width(), scaledSize.height(), at);
450        pixelSize = SkAlign8(SkAutoPixmapStorage::AllocSize(info, nullptr));
451        if (fillMode) {
452            pixmap.alloc(info);
453            if (isScaled) {
454                if (!this->scalePixels(pixmap, scaleFilterQuality,
455                                       SkImage::kDisallow_CachingHint)) {
456                    return 0;
457                }
458            } else {
459                if (!this->readPixels(pixmap, 0, 0, SkImage::kDisallow_CachingHint)) {
460                    return 0;
461                }
462            }
463            SkASSERT(!pixmap.ctable());
464        }
465    }
466    int mipMapLevelCount = 1;
467    size_t size = 0;
468    size_t dtiSize = SkAlign8(sizeof(DeferredTextureImage));
469    size += dtiSize;
470    size += mipMapLevelCount * sizeof(MipMapLevelData);
471    size_t pixelOffset = size;
472    size += pixelSize;
473    size_t ctOffset = size;
474    size += ctSize;
475    size_t colorSpaceOffset = 0;
476    size_t colorSpaceSize = 0;
477    if (info.colorSpace()) {
478        colorSpaceOffset = size;
479        colorSpaceSize = info.colorSpace()->writeToMemory(nullptr);
480        size += colorSpaceSize;
481    }
482    if (!fillMode) {
483        return size;
484    }
485    intptr_t bufferAsInt = reinterpret_cast<intptr_t>(buffer);
486    void* pixels = reinterpret_cast<void*>(bufferAsInt + pixelOffset);
487    SkPMColor* ct = nullptr;
488    if (ctSize) {
489        ct = reinterpret_cast<SkPMColor*>(bufferAsInt + ctOffset);
490    }
491
492    memcpy(pixels, pixmap.addr(), pixmap.getSafeSize());
493    if (ctSize) {
494        memcpy(ct, pixmap.ctable()->readColors(), ctSize);
495    }
496
497    SkASSERT(info == pixmap.info());
498    size_t rowBytes = pixmap.rowBytes();
499    DeferredTextureImage* dti = new (buffer) DeferredTextureImage();
500    dti->fContextUniqueID = proxy.fContextUniqueID;
501    dti->fWidth = info.width();
502    dti->fHeight = info.height();
503    dti->fColorType = info.colorType();
504    dti->fAlphaType = info.alphaType();
505    dti->fColorTableCnt = ctCount;
506    dti->fColorTableData = ct;
507    dti->fMipMapLevelCount = mipMapLevelCount;
508    dti->fMipMapLevelData[0].fPixelData = pixels;
509    dti->fMipMapLevelData[0].fRowBytes = rowBytes;
510    if (colorSpaceSize) {
511        dti->fColorSpace = reinterpret_cast<void*>(bufferAsInt + colorSpaceOffset);
512        dti->fColorSpaceSize = colorSpaceSize;
513        info.colorSpace()->writeToMemory(dti->fColorSpace);
514    } else {
515        dti->fColorSpace = nullptr;
516        dti->fColorSpaceSize = 0;
517    }
518    return size;
519}
520
521sk_sp<SkImage> SkImage::MakeFromDeferredTextureImageData(GrContext* context, const void* data,
522                                                         SkBudgeted budgeted) {
523    if (!data) {
524        return nullptr;
525    }
526    const DeferredTextureImage* dti = reinterpret_cast<const DeferredTextureImage*>(data);
527
528    if (!context || context->uniqueID() != dti->fContextUniqueID) {
529        return nullptr;
530    }
531    SkAutoTUnref<SkColorTable> colorTable;
532    if (dti->fColorTableCnt) {
533        SkASSERT(dti->fColorTableData);
534        colorTable.reset(new SkColorTable(dti->fColorTableData, dti->fColorTableCnt));
535    }
536    SkASSERT(dti->fMipMapLevelCount == 1);
537    sk_sp<SkColorSpace> colorSpace;
538    if (dti->fColorSpaceSize) {
539        colorSpace = SkColorSpace::Deserialize(dti->fColorSpace, dti->fColorSpaceSize);
540    }
541    SkImageInfo info = SkImageInfo::Make(dti->fWidth, dti->fHeight,
542                                         dti->fColorType, dti->fAlphaType, colorSpace);
543    SkPixmap pixmap;
544    pixmap.reset(info, dti->fMipMapLevelData[0].fPixelData,
545                 dti->fMipMapLevelData[0].fRowBytes, colorTable.get());
546    return SkImage::MakeTextureFromPixmap(context, pixmap, budgeted);
547}
548
549///////////////////////////////////////////////////////////////////////////////////////////////////
550
551GrTexture* GrDeepCopyTexture(GrTexture* src, SkBudgeted budgeted) {
552    GrContext* ctx = src->getContext();
553
554    GrSurfaceDesc desc = src->desc();
555    GrTexture* dst = ctx->textureProvider()->createTexture(desc, budgeted, nullptr, 0);
556    if (!dst) {
557        return nullptr;
558    }
559
560    const SkIRect srcR = SkIRect::MakeWH(desc.fWidth, desc.fHeight);
561    const SkIPoint dstP = SkIPoint::Make(0, 0);
562    ctx->copySurface(dst, src, srcR, dstP);
563    ctx->flushSurfaceWrites(dst);
564    return dst;
565}
566
567sk_sp<SkImage> SkImage::MakeTextureFromMipMap(GrContext* ctx, const SkImageInfo& info,
568                                              const GrMipLevel* texels, int mipLevelCount,
569                                              SkBudgeted budgeted) {
570    if (!ctx) {
571        return nullptr;
572    }
573    SkAutoTUnref<GrTexture> texture(GrUploadMipMapToTexture(ctx, info, texels, mipLevelCount));
574    if (!texture) {
575        return nullptr;
576    }
577    return sk_make_sp<SkImage_Gpu>(texture->width(), texture->height(), kNeedNewImageUniqueID,
578                                   info.alphaType(), texture, sk_ref_sp(info.colorSpace()),
579                                   budgeted);
580}
581