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 #include "GrContext.h" 13 #include "GrTexture.h" 14 #include "SkGr.h" 15 #include "SkRect.h" 16 17 // since we call lockPixels recursively on fBitmap, we need a distinct mutex, 18 // to avoid deadlock with the default one provided by SkPixelRef. 19 SK_DECLARE_STATIC_MUTEX(gROLockPixelsPixelRefMutex); 20 21 SkROLockPixelsPixelRef::SkROLockPixelsPixelRef(const SkImageInfo& info) 22 : INHERITED(info, &gROLockPixelsPixelRefMutex) {} 23 24 SkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() {} 25 26 void* SkROLockPixelsPixelRef::onLockPixels(SkColorTable** ctable) { 27 if (ctable) { 28 *ctable = NULL; 29 } 30 fBitmap.reset(); 31 // SkDebugf("---------- calling readpixels in support of lockpixels\n"); 32 if (!this->onReadPixels(&fBitmap, NULL)) { 33 SkDebugf("SkROLockPixelsPixelRef::onLockPixels failed!\n"); 34 return NULL; 35 } 36 fBitmap.lockPixels(); 37 return fBitmap.getPixels(); 38 } 39 40 void SkROLockPixelsPixelRef::onUnlockPixels() { 41 fBitmap.unlockPixels(); 42 } 43 44 bool SkROLockPixelsPixelRef::onLockPixelsAreWritable() const { 45 return false; 46 } 47 48 /////////////////////////////////////////////////////////////////////////////// 49 50 static SkGrPixelRef* copyToTexturePixelRef(GrTexture* texture, SkBitmap::Config dstConfig, 51 const SkIRect* subset) { 52 if (NULL == texture) { 53 return NULL; 54 } 55 GrContext* context = texture->getContext(); 56 if (NULL == context) { 57 return NULL; 58 } 59 GrTextureDesc desc; 60 61 SkIPoint pointStorage; 62 SkIPoint* topLeft; 63 if (subset != NULL) { 64 SkASSERT(SkIRect::MakeWH(texture->width(), texture->height()).contains(*subset)); 65 // Create a new texture that is the size of subset. 66 desc.fWidth = subset->width(); 67 desc.fHeight = subset->height(); 68 pointStorage.set(subset->x(), subset->y()); 69 topLeft = &pointStorage; 70 } else { 71 desc.fWidth = texture->width(); 72 desc.fHeight = texture->height(); 73 topLeft = NULL; 74 } 75 desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; 76 desc.fConfig = SkBitmapConfig2GrPixelConfig(dstConfig); 77 78 SkImageInfo info; 79 if (!GrPixelConfig2ColorType(desc.fConfig, &info.fColorType)) { 80 return NULL; 81 } 82 info.fWidth = desc.fWidth; 83 info.fHeight = desc.fHeight; 84 info.fAlphaType = kPremul_SkAlphaType; 85 86 GrTexture* dst = context->createUncachedTexture(desc, NULL, 0); 87 if (NULL == dst) { 88 return NULL; 89 } 90 91 context->copyTexture(texture, dst->asRenderTarget(), topLeft); 92 93 // TODO: figure out if this is responsible for Chrome canvas errors 94 #if 0 95 // The render texture we have created (to perform the copy) isn't fully 96 // functional (since it doesn't have a stencil buffer). Release it here 97 // so the caller doesn't try to render to it. 98 // TODO: we can undo this release when dynamic stencil buffer attach/ 99 // detach has been implemented 100 dst->releaseRenderTarget(); 101 #endif 102 103 SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (info, dst)); 104 SkSafeUnref(dst); 105 return pixelRef; 106 } 107 108 /////////////////////////////////////////////////////////////////////////////// 109 110 SkGrPixelRef::SkGrPixelRef(const SkImageInfo& info, GrSurface* surface, 111 bool transferCacheLock) : INHERITED(info) { 112 // TODO: figure out if this is responsible for Chrome canvas errors 113 #if 0 114 // The GrTexture has a ref to the GrRenderTarget but not vice versa. 115 // If the GrTexture exists take a ref to that (rather than the render 116 // target) 117 fSurface = surface->asTexture(); 118 #else 119 fSurface = NULL; 120 #endif 121 if (NULL == fSurface) { 122 fSurface = surface; 123 } 124 fUnlock = transferCacheLock; 125 SkSafeRef(surface); 126 } 127 128 SkGrPixelRef::~SkGrPixelRef() { 129 if (fUnlock) { 130 GrContext* context = fSurface->getContext(); 131 GrTexture* texture = fSurface->asTexture(); 132 if (NULL != context && NULL != texture) { 133 context->unlockScratchTexture(texture); 134 } 135 } 136 SkSafeUnref(fSurface); 137 } 138 139 GrTexture* SkGrPixelRef::getTexture() { 140 if (NULL != fSurface) { 141 return fSurface->asTexture(); 142 } 143 return NULL; 144 } 145 146 SkPixelRef* SkGrPixelRef::deepCopy(SkBitmap::Config dstConfig, const SkIRect* subset) { 147 if (NULL == fSurface) { 148 return NULL; 149 } 150 151 // Note that when copying a render-target-backed pixel ref, we 152 // return a texture-backed pixel ref instead. This is because 153 // render-target pixel refs are usually created in conjunction with 154 // a GrTexture owned elsewhere (e.g., SkGpuDevice), and cannot live 155 // independently of that texture. Texture-backed pixel refs, on the other 156 // hand, own their GrTextures, and are thus self-contained. 157 return copyToTexturePixelRef(fSurface->asTexture(), dstConfig, subset); 158 } 159 160 bool SkGrPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) { 161 if (NULL == fSurface || !fSurface->isValid()) { 162 return false; 163 } 164 165 int left, top, width, height; 166 if (NULL != subset) { 167 left = subset->fLeft; 168 width = subset->width(); 169 top = subset->fTop; 170 height = subset->height(); 171 } else { 172 left = 0; 173 width = fSurface->width(); 174 top = 0; 175 height = fSurface->height(); 176 } 177 dst->setConfig(SkBitmap::kARGB_8888_Config, width, height); 178 if (!dst->allocPixels()) { 179 SkDebugf("SkGrPixelRef::onReadPixels failed to alloc bitmap for result!\n"); 180 return false; 181 } 182 SkAutoLockPixels al(*dst); 183 void* buffer = dst->getPixels(); 184 return fSurface->readPixels(left, top, width, height, 185 kSkia8888_GrPixelConfig, 186 buffer, dst->rowBytes()); 187 } 188