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