michael@0: michael@0: /* michael@0: * Copyright 2010 Google Inc. michael@0: * michael@0: * Use of this source code is governed by a BSD-style license that can be michael@0: * found in the LICENSE file. michael@0: */ michael@0: michael@0: michael@0: michael@0: #include "SkGrPixelRef.h" michael@0: #include "GrContext.h" michael@0: #include "GrTexture.h" michael@0: #include "SkGr.h" michael@0: #include "SkRect.h" michael@0: michael@0: // since we call lockPixels recursively on fBitmap, we need a distinct mutex, michael@0: // to avoid deadlock with the default one provided by SkPixelRef. michael@0: SK_DECLARE_STATIC_MUTEX(gROLockPixelsPixelRefMutex); michael@0: michael@0: SkROLockPixelsPixelRef::SkROLockPixelsPixelRef(const SkImageInfo& info) michael@0: : INHERITED(info, &gROLockPixelsPixelRefMutex) {} michael@0: michael@0: SkROLockPixelsPixelRef::~SkROLockPixelsPixelRef() {} michael@0: michael@0: bool SkROLockPixelsPixelRef::onNewLockPixels(LockRec* rec) { michael@0: fBitmap.reset(); michael@0: // SkDebugf("---------- calling readpixels in support of lockpixels\n"); michael@0: if (!this->onReadPixels(&fBitmap, NULL)) { michael@0: SkDebugf("SkROLockPixelsPixelRef::onLockPixels failed!\n"); michael@0: return false; michael@0: } michael@0: fBitmap.lockPixels(); michael@0: if (NULL == fBitmap.getPixels()) { michael@0: return false; michael@0: } michael@0: michael@0: rec->fPixels = fBitmap.getPixels(); michael@0: rec->fColorTable = NULL; michael@0: rec->fRowBytes = fBitmap.rowBytes(); michael@0: return true; michael@0: } michael@0: michael@0: void SkROLockPixelsPixelRef::onUnlockPixels() { michael@0: fBitmap.unlockPixels(); michael@0: } michael@0: michael@0: bool SkROLockPixelsPixelRef::onLockPixelsAreWritable() const { michael@0: return false; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: static SkGrPixelRef* copyToTexturePixelRef(GrTexture* texture, SkBitmap::Config dstConfig, michael@0: const SkIRect* subset) { michael@0: if (NULL == texture) { michael@0: return NULL; michael@0: } michael@0: GrContext* context = texture->getContext(); michael@0: if (NULL == context) { michael@0: return NULL; michael@0: } michael@0: GrTextureDesc desc; michael@0: michael@0: SkIPoint pointStorage; michael@0: SkIPoint* topLeft; michael@0: if (subset != NULL) { michael@0: SkASSERT(SkIRect::MakeWH(texture->width(), texture->height()).contains(*subset)); michael@0: // Create a new texture that is the size of subset. michael@0: desc.fWidth = subset->width(); michael@0: desc.fHeight = subset->height(); michael@0: pointStorage.set(subset->x(), subset->y()); michael@0: topLeft = &pointStorage; michael@0: } else { michael@0: desc.fWidth = texture->width(); michael@0: desc.fHeight = texture->height(); michael@0: topLeft = NULL; michael@0: } michael@0: desc.fFlags = kRenderTarget_GrTextureFlagBit | kNoStencil_GrTextureFlagBit; michael@0: desc.fConfig = SkBitmapConfig2GrPixelConfig(dstConfig); michael@0: michael@0: SkImageInfo info; michael@0: if (!GrPixelConfig2ColorType(desc.fConfig, &info.fColorType)) { michael@0: return NULL; michael@0: } michael@0: info.fWidth = desc.fWidth; michael@0: info.fHeight = desc.fHeight; michael@0: info.fAlphaType = kPremul_SkAlphaType; michael@0: michael@0: GrTexture* dst = context->createUncachedTexture(desc, NULL, 0); michael@0: if (NULL == dst) { michael@0: return NULL; michael@0: } michael@0: michael@0: context->copyTexture(texture, dst->asRenderTarget(), topLeft); michael@0: michael@0: // TODO: figure out if this is responsible for Chrome canvas errors michael@0: #if 0 michael@0: // The render texture we have created (to perform the copy) isn't fully michael@0: // functional (since it doesn't have a stencil buffer). Release it here michael@0: // so the caller doesn't try to render to it. michael@0: // TODO: we can undo this release when dynamic stencil buffer attach/ michael@0: // detach has been implemented michael@0: dst->releaseRenderTarget(); michael@0: #endif michael@0: michael@0: SkGrPixelRef* pixelRef = SkNEW_ARGS(SkGrPixelRef, (info, dst)); michael@0: SkSafeUnref(dst); michael@0: return pixelRef; michael@0: } michael@0: michael@0: /////////////////////////////////////////////////////////////////////////////// michael@0: michael@0: SkGrPixelRef::SkGrPixelRef(const SkImageInfo& info, GrSurface* surface, michael@0: bool transferCacheLock) : INHERITED(info) { michael@0: // TODO: figure out if this is responsible for Chrome canvas errors michael@0: #if 0 michael@0: // The GrTexture has a ref to the GrRenderTarget but not vice versa. michael@0: // If the GrTexture exists take a ref to that (rather than the render michael@0: // target) michael@0: fSurface = surface->asTexture(); michael@0: #else michael@0: fSurface = NULL; michael@0: #endif michael@0: if (NULL == fSurface) { michael@0: fSurface = surface; michael@0: } michael@0: fUnlock = transferCacheLock; michael@0: SkSafeRef(surface); michael@0: michael@0: if (fSurface) { michael@0: SkASSERT(info.fWidth <= fSurface->width()); michael@0: SkASSERT(info.fHeight <= fSurface->height()); michael@0: } michael@0: } michael@0: michael@0: SkGrPixelRef::~SkGrPixelRef() { michael@0: if (fUnlock) { michael@0: GrContext* context = fSurface->getContext(); michael@0: GrTexture* texture = fSurface->asTexture(); michael@0: if (NULL != context && NULL != texture) { michael@0: context->unlockScratchTexture(texture); michael@0: } michael@0: } michael@0: SkSafeUnref(fSurface); michael@0: } michael@0: michael@0: GrTexture* SkGrPixelRef::getTexture() { michael@0: if (NULL != fSurface) { michael@0: return fSurface->asTexture(); michael@0: } michael@0: return NULL; michael@0: } michael@0: michael@0: SkPixelRef* SkGrPixelRef::deepCopy(SkBitmap::Config dstConfig, const SkIRect* subset) { michael@0: if (NULL == fSurface) { michael@0: return NULL; michael@0: } michael@0: michael@0: // Note that when copying a render-target-backed pixel ref, we michael@0: // return a texture-backed pixel ref instead. This is because michael@0: // render-target pixel refs are usually created in conjunction with michael@0: // a GrTexture owned elsewhere (e.g., SkGpuDevice), and cannot live michael@0: // independently of that texture. Texture-backed pixel refs, on the other michael@0: // hand, own their GrTextures, and are thus self-contained. michael@0: return copyToTexturePixelRef(fSurface->asTexture(), dstConfig, subset); michael@0: } michael@0: michael@0: bool SkGrPixelRef::onReadPixels(SkBitmap* dst, const SkIRect* subset) { michael@0: if (NULL == fSurface || !fSurface->isValid()) { michael@0: return false; michael@0: } michael@0: michael@0: int left, top, width, height; michael@0: if (NULL != subset) { michael@0: left = subset->fLeft; michael@0: width = subset->width(); michael@0: top = subset->fTop; michael@0: height = subset->height(); michael@0: } else { michael@0: left = 0; michael@0: width = this->info().fWidth; michael@0: top = 0; michael@0: height = this->info().fHeight; michael@0: } michael@0: if (!dst->allocPixels(SkImageInfo::MakeN32Premul(width, height))) { michael@0: SkDebugf("SkGrPixelRef::onReadPixels failed to alloc bitmap for result!\n"); michael@0: return false; michael@0: } michael@0: SkAutoLockPixels al(*dst); michael@0: void* buffer = dst->getPixels(); michael@0: return fSurface->readPixels(left, top, width, height, michael@0: kSkia8888_GrPixelConfig, michael@0: buffer, dst->rowBytes()); michael@0: }