1 2/* 3 * Copyright 2010 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 10 11#include "SkGrPixelRef.h" 12 13#include "GrContext.h" 14#include "GrTexture.h" 15#include "GrTexturePriv.h" 16#include "SkBitmapCache.h" 17#include "SkGr.h" 18#include "SkRect.h" 19 20SkROLockPixelsPixelRef::SkROLockPixelsPixelRef(const SkImageInfo& info) 21 : INHERITED(info) {} 22 23SkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() {} 24 25bool SkROLockPixelsPixelRef::onNewLockPixels(LockRec* rec) { 26 fBitmap.reset(); 27// SkDebugf("---------- calling readpixels in support of lockpixels\n"); 28 if (!this->onReadPixels(&fBitmap, this->info().colorType(), nullptr)) { 29 SkDebugf("SkROLockPixelsPixelRef::onLockPixels failed!\n"); 30 return false; 31 } 32 fBitmap.lockPixels(); 33 if (nullptr == fBitmap.getPixels()) { 34 return false; 35 } 36 37 rec->fPixels = fBitmap.getPixels(); 38 rec->fColorTable = nullptr; 39 rec->fRowBytes = fBitmap.rowBytes(); 40 return true; 41} 42 43void SkROLockPixelsPixelRef::onUnlockPixels() { 44 fBitmap.unlockPixels(); 45} 46 47bool SkROLockPixelsPixelRef::onLockPixelsAreWritable() const { 48 return false; 49} 50 51/////////////////////////////////////////////////////////////////////////////// 52 53static SkGrPixelRef* copy_to_new_texture_pixelref(GrTexture* texture, SkColorType dstCT, 54 SkColorProfileType dstPT, const SkIRect* subset) { 55 if (nullptr == texture || kUnknown_SkColorType == dstCT) { 56 return nullptr; 57 } 58 GrContext* context = texture->getContext(); 59 if (nullptr == context) { 60 return nullptr; 61 } 62 GrSurfaceDesc desc; 63 64 SkIRect srcRect; 65 66 if (!subset) { 67 desc.fWidth = texture->width(); 68 desc.fHeight = texture->height(); 69 srcRect = SkIRect::MakeWH(texture->width(), texture->height()); 70 } else { 71 SkASSERT(SkIRect::MakeWH(texture->width(), texture->height()).contains(*subset)); 72 // Create a new texture that is the size of subset. 73 desc.fWidth = subset->width(); 74 desc.fHeight = subset->height(); 75 srcRect = *subset; 76 } 77 desc.fFlags = kRenderTarget_GrSurfaceFlag; 78 desc.fConfig = SkImageInfo2GrPixelConfig(dstCT, kPremul_SkAlphaType, dstPT); 79 desc.fTextureStorageAllocator = texture->desc().fTextureStorageAllocator; 80 81 GrTexture* dst = context->textureProvider()->createTexture(desc, SkBudgeted::kNo, nullptr, 0); 82 if (nullptr == dst) { 83 return nullptr; 84 } 85 86 // Blink is relying on the above copy being sent to GL immediately in the case when the source 87 // is a WebGL canvas backing store. We could have a TODO to remove this flush, but we have 88 // a larger TODO to remove SkGrPixelRef entirely. 89 context->copySurface(dst, texture, srcRect, SkIPoint::Make(0,0)); 90 context->flushSurfaceWrites(dst); 91 92 SkImageInfo info = SkImageInfo::Make(desc.fWidth, desc.fHeight, dstCT, kPremul_SkAlphaType, 93 dstPT); 94 SkGrPixelRef* pixelRef = new SkGrPixelRef(info, dst); 95 SkSafeUnref(dst); 96 return pixelRef; 97} 98 99/////////////////////////////////////////////////////////////////////////////// 100 101SkGrPixelRef::SkGrPixelRef(const SkImageInfo& info, GrSurface* surface) : INHERITED(info) { 102 // For surfaces that are both textures and render targets, the texture owns the 103 // render target but not vice versa. So we ref the texture to keep both alive for 104 // the lifetime of this pixel ref. 105 fSurface = SkSafeRef(surface->asTexture()); 106 if (nullptr == fSurface) { 107 fSurface = SkSafeRef(surface); 108 } 109 110 if (fSurface) { 111 SkASSERT(info.width() <= fSurface->width()); 112 SkASSERT(info.height() <= fSurface->height()); 113 } 114} 115 116SkGrPixelRef::~SkGrPixelRef() { 117 SkSafeUnref(fSurface); 118} 119 120GrTexture* SkGrPixelRef::getTexture() { 121 if (fSurface) { 122 return fSurface->asTexture(); 123 } 124 return nullptr; 125} 126 127void SkGrPixelRef::onNotifyPixelsChanged() { 128 GrTexture* texture = this->getTexture(); 129 if (texture) { 130 texture->texturePriv().dirtyMipMaps(true); 131 } 132} 133 134SkPixelRef* SkGrPixelRef::deepCopy(SkColorType dstCT, SkColorProfileType dstPT, 135 const SkIRect* subset) { 136 if (nullptr == fSurface) { 137 return nullptr; 138 } 139 140 // Note that when copying a render-target-backed pixel ref, we 141 // return a texture-backed pixel ref instead. This is because 142 // render-target pixel refs are usually created in conjunction with 143 // a GrTexture owned elsewhere (e.g., SkGpuDevice), and cannot live 144 // independently of that texture. Texture-backed pixel refs, on the other 145 // hand, own their GrTextures, and are thus self-contained. 146 return copy_to_new_texture_pixelref(fSurface->asTexture(), dstCT, dstPT, subset); 147} 148 149static bool tryAllocBitmapPixels(SkBitmap* bitmap) { 150 SkBitmap::Allocator* allocator = SkBitmapCache::GetAllocator(); 151 if (nullptr != allocator) { 152 return allocator->allocPixelRef(bitmap, 0); 153 } else { 154 // DiscardableMemory is not available, fallback to default allocator 155 return bitmap->tryAllocPixels(); 156 } 157} 158 159bool SkGrPixelRef::onReadPixels(SkBitmap* dst, SkColorType colorType, const SkIRect* subset) { 160 if (nullptr == fSurface || fSurface->wasDestroyed()) { 161 return false; 162 } 163 164 GrPixelConfig config; 165 if (kRGBA_8888_SkColorType == colorType) { 166 config = kRGBA_8888_GrPixelConfig; 167 } else if (kBGRA_8888_SkColorType == colorType) { 168 config = kBGRA_8888_GrPixelConfig; 169 } else { 170 return false; 171 } 172 173 SkIRect bounds; 174 if (subset) { 175 bounds = *subset; 176 } else { 177 bounds = SkIRect::MakeWH(this->info().width(), this->info().height()); 178 } 179 180 //Check the cache 181 if(!SkBitmapCache::Find(this->getGenerationID(), bounds, dst)) { 182 //Cache miss 183 184 SkBitmap cachedBitmap; 185 cachedBitmap.setInfo(SkImageInfo::Make(bounds.width(), bounds.height(), colorType, 186 this->info().alphaType(), 187 this->info().profileType())); 188 189 // If we can't alloc the pixels, then fail 190 if (!tryAllocBitmapPixels(&cachedBitmap)) { 191 return false; 192 } 193 194 // Try to read the pixels from the surface 195 void* buffer = cachedBitmap.getPixels(); 196 bool readPixelsOk = fSurface->readPixels(bounds.fLeft, bounds.fTop, 197 bounds.width(), bounds.height(), 198 config, buffer, cachedBitmap.rowBytes()); 199 200 if (!readPixelsOk) { 201 return false; 202 } 203 204 // If we are here, pixels were read correctly from the surface. 205 cachedBitmap.setImmutable(); 206 //Add to the cache 207 SkBitmapCache::Add(this, bounds, cachedBitmap); 208 209 dst->swap(cachedBitmap); 210 } 211 212 return true; 213 214} 215