From abcfab4d68d53900ef33320bb2622696c14d14b0 Mon Sep 17 00:00:00 2001 From: kkinnunen Date: Sun, 22 Feb 2015 22:53:44 -0800 Subject: [PATCH] Swap render target instead of creating a new gpu device for surface copy-on-write Swap render target of the gpu device instead of creating a new gpu device when making a copy-on-write upon surface modification. This removes the SkCanvas::setRootDevice which contains problematic code when trying to increase the use of SkImages internally in Skia. BUG=skia:3388 Review URL: https://codereview.chromium.org/925343002 --- include/core/SkCanvas.h | 9 ------ src/core/SkCanvas.cpp | 53 ------------------------------- src/gpu/SkGpuDevice.cpp | 77 ++++++++++++++++++++++++++++++++++----------- src/gpu/SkGpuDevice.h | 5 +++ src/image/SkSurface_Gpu.cpp | 24 +++----------- 5 files changed, 68 insertions(+), 100 deletions(-) diff --git a/include/core/SkCanvas.h b/include/core/SkCanvas.h index 0ec167e..a57f4cd 100644 --- a/include/core/SkCanvas.h +++ b/include/core/SkCanvas.h @@ -1306,15 +1306,6 @@ private: SkBaseDevice* init(SkBaseDevice*, InitFlags); /** - * DEPRECATED - * - * Specify a device for this canvas to draw into. If it is not null, its - * reference count is incremented. If the canvas was already holding a - * device, its reference count is decremented. The new device is returned. - */ - SkBaseDevice* setRootDevice(SkBaseDevice* device); - - /** * Gets the size/origin of the top level layer in global canvas coordinates. We don't want this * to be public because it exposes decisions about layer sizes that are internal to the canvas. */ diff --git a/src/core/SkCanvas.cpp b/src/core/SkCanvas.cpp index c523ca0..221ed93 100644 --- a/src/core/SkCanvas.cpp +++ b/src/core/SkCanvas.cpp @@ -608,59 +608,6 @@ SkBaseDevice* SkCanvas::getTopDevice(bool updateMatrixClip) const { return fMCRec->fTopLayer->fDevice; } -SkBaseDevice* SkCanvas::setRootDevice(SkBaseDevice* device) { - // return root device - SkDeque::F2BIter iter(fMCStack); - MCRec* rec = (MCRec*)iter.next(); - SkASSERT(rec && rec->fLayer); - SkBaseDevice* rootDevice = rec->fLayer->fDevice; - - if (rootDevice == device) { - return device; - } - - if (device) { - device->onAttachToCanvas(this); - device->initForRootLayer(fProps.pixelGeometry()); - } - if (rootDevice) { - rootDevice->onDetachFromCanvas(); - } - - SkRefCnt_SafeAssign(rec->fLayer->fDevice, device); - rootDevice = device; - - fDeviceCMDirty = true; - - /* Now we update our initial region to have the bounds of the new device, - and then intersect all of the clips in our stack with these bounds, - to ensure that we can't draw outside of the device's bounds (and trash - memory). - - NOTE: this is only a partial-fix, since if the new device is larger than - the previous one, we don't know how to "enlarge" the clips in our stack, - so drawing may be artificially restricted. Without keeping a history of - all calls to canvas->clipRect() and canvas->clipPath(), we can't exactly - reconstruct the correct clips, so this approximation will have to do. - The caller really needs to restore() back to the base if they want to - accurately take advantage of the new device bounds. - */ - - SkIRect bounds; - if (device) { - bounds.set(0, 0, device->width(), device->height()); - } else { - bounds.setEmpty(); - } - // now jam our 1st clip to be bounds, and intersect the rest with that - rec->fRasterClip.setRect(bounds); - while ((rec = (MCRec*)iter.next()) != NULL) { - (void)rec->fRasterClip.op(bounds, SkRegion::kIntersect_Op); - } - - return device; -} - bool SkCanvas::readPixels(SkBitmap* bitmap, int x, int y) { if (kUnknown_SkColorType == bitmap->colorType() || bitmap->getTexture()) { return false; diff --git a/src/gpu/SkGpuDevice.cpp b/src/gpu/SkGpuDevice.cpp index 5781a58..ad63393 100644 --- a/src/gpu/SkGpuDevice.cpp +++ b/src/gpu/SkGpuDevice.cpp @@ -7,41 +7,40 @@ #include "SkGpuDevice.h" -#include "effects/GrBicubicEffect.h" -#include "effects/GrDashingEffect.h" -#include "effects/GrTextureDomain.h" -#include "effects/GrSimpleTextureEffect.h" - -#include "GrContext.h" #include "GrBitmapTextContext.h" +#include "GrContext.h" #include "GrDistanceFieldTextContext.h" +#include "GrGpu.h" +#include "GrGpuResourcePriv.h" #include "GrLayerHoister.h" #include "GrRecordReplaceDraw.h" #include "GrStrokeInfo.h" #include "GrTracing.h" -#include "GrGpu.h" - -#include "SkGrTexturePixelRef.h" - #include "SkCanvasPriv.h" #include "SkDeviceImageFilterProxy.h" #include "SkDrawProcs.h" +#include "SkErrorInternals.h" #include "SkGlyphCache.h" +#include "SkGrTexturePixelRef.h" #include "SkImageFilter.h" #include "SkLayerInfo.h" #include "SkMaskFilter.h" #include "SkPathEffect.h" #include "SkPicture.h" #include "SkPictureData.h" -#include "SkRecord.h" #include "SkRRect.h" +#include "SkRecord.h" #include "SkStroke.h" #include "SkSurface.h" +#include "SkSurface_Gpu.h" #include "SkTLazy.h" #include "SkUtils.h" #include "SkVertState.h" #include "SkXfermode.h" -#include "SkErrorInternals.h" +#include "effects/GrBicubicEffect.h" +#include "effects/GrDashingEffect.h" +#include "effects/GrSimpleTextureEffect.h" +#include "effects/GrTextureDomain.h" #if SK_SUPPORT_GPU @@ -164,9 +163,8 @@ SkGpuDevice::SkGpuDevice(GrRenderTarget* rt, const SkSurfaceProps* props, unsign fTextContext = fContext->createTextContext(fRenderTarget, this->getLeakyProperties(), useDFT); } -SkGpuDevice* SkGpuDevice::Create(GrContext* context, SkSurface::Budgeted budgeted, - const SkImageInfo& origInfo, int sampleCount, - const SkSurfaceProps* props, unsigned flags) { +GrRenderTarget* SkGpuDevice::CreateRenderTarget(GrContext* context, SkSurface::Budgeted budgeted, + const SkImageInfo& origInfo, int sampleCount) { if (kUnknown_SkColorType == origInfo.colorType() || origInfo.width() < 0 || origInfo.height() < 0) { return NULL; @@ -195,13 +193,24 @@ SkGpuDevice* SkGpuDevice::Create(GrContext* context, SkSurface::Budgeted budgete desc.fHeight = info.height(); desc.fConfig = SkImageInfo2GrPixelConfig(info); desc.fSampleCnt = sampleCount; + GrTexture* texture = context->createTexture(desc, SkToBool(budgeted), NULL, 0); + if (NULL == texture) { + return NULL; + } + SkASSERT(NULL != texture->asRenderTarget()); + return texture->asRenderTarget(); +} - SkAutoTUnref texture(context->createTexture(desc, SkToBool(budgeted), NULL, 0)); - if (!texture) { +SkGpuDevice* SkGpuDevice::Create(GrContext* context, SkSurface::Budgeted budgeted, + const SkImageInfo& info, int sampleCount, + const SkSurfaceProps* props, unsigned flags) { + + SkAutoTUnref rt(CreateRenderTarget(context, budgeted, info, sampleCount)); + if (NULL == rt) { return NULL; } - return SkNEW_ARGS(SkGpuDevice, (texture->asRenderTarget(), props, flags)); + return SkNEW_ARGS(SkGpuDevice, (rt, props, flags)); } SkGpuDevice::~SkGpuDevice() { @@ -302,6 +311,38 @@ void SkGpuDevice::clearAll() { fNeedClear = false; } +void SkGpuDevice::replaceRenderTarget(bool shouldRetainContent) { + // Caller must have accessed the render target, because it knows the rt must be replaced. + SkASSERT(!fNeedClear); + + SkSurface::Budgeted budgeted = + fRenderTarget->resourcePriv().isBudgeted() ? SkSurface::kYes_Budgeted + : SkSurface::kNo_Budgeted; + + SkAutoTUnref newRT(CreateRenderTarget( + fRenderTarget->getContext(), budgeted, this->imageInfo(), fRenderTarget->numSamples())); + + if (NULL == newRT) { + return; + } + + if (shouldRetainContent) { + if (fRenderTarget->wasDestroyed()) { + return; + } + this->context()->copySurface(newRT, fRenderTarget); + } + + SkASSERT(fRenderTarget != newRT); + + fRenderTarget->unref(); + fRenderTarget = newRT.detach(); + + SkASSERT(fRenderTarget->surfacePriv().info() == fLegacyBitmap.info()); + SkPixelRef* pr = SkNEW_ARGS(SkGrPixelRef, (fRenderTarget->surfacePriv().info(), fRenderTarget)); + fLegacyBitmap.setPixelRef(pr)->unref(); +} + /////////////////////////////////////////////////////////////////////////////// SK_COMPILE_ASSERT(SkShader::kNone_BitmapType == 0, shader_type_mismatch); diff --git a/src/gpu/SkGpuDevice.h b/src/gpu/SkGpuDevice.h index 4830c02..cd2dcdc 100644 --- a/src/gpu/SkGpuDevice.h +++ b/src/gpu/SkGpuDevice.h @@ -62,6 +62,8 @@ public: // set all pixels to 0 void clearAll(); + void replaceRenderTarget(bool shouldRetainContent); + GrRenderTarget* accessRenderTarget() SK_OVERRIDE; SkImageInfo imageInfo() const SK_OVERRIDE { @@ -199,6 +201,9 @@ private: static SkPicture::AccelData::Key ComputeAccelDataKey(); + static GrRenderTarget* CreateRenderTarget(GrContext*, SkSurface::Budgeted, const SkImageInfo&, + int sampleCount); + typedef SkBaseDevice INHERITED; }; diff --git a/src/image/SkSurface_Gpu.cpp b/src/image/SkSurface_Gpu.cpp index a1c31f3..b94e4e3 100644 --- a/src/image/SkSurface_Gpu.cpp +++ b/src/image/SkSurface_Gpu.cpp @@ -7,7 +7,6 @@ #include "SkSurface_Gpu.h" -#include "GrGpuResourcePriv.h" #include "SkCanvas.h" #include "SkGpuDevice.h" #include "SkImage_Base.h" @@ -24,7 +23,7 @@ SkSurface_Gpu::SkSurface_Gpu(SkGpuDevice* device) } SkSurface_Gpu::~SkSurface_Gpu() { - SkSafeUnref(fDevice); + fDevice->unref(); } SkCanvas* SkSurface_Gpu::onNewCanvas() { @@ -59,8 +58,8 @@ void SkSurface_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, canvas->drawBitmap(fDevice->accessBitmap(false), x, y, paint); } -// Create a new SkGpuDevice and, if necessary, copy the contents of the old -// device into it. Note that this flushes the SkGpuDevice but +// Create a new render target and, if necessary, copy the contents of the old +// render target into it. Note that this flushes the SkGpuDevice but // doesn't force an OpenGL flush. void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) { GrRenderTarget* rt = fDevice->accessRenderTarget(); @@ -69,22 +68,7 @@ void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) { SkImage* image = this->getCachedImage(kNo_Budgeted); SkASSERT(image); if (rt->asTexture() == SkTextureImageGetTexture(image)) { - GrRenderTarget* oldRT = this->fDevice->accessRenderTarget(); - SkSurface::Budgeted budgeted = oldRT->resourcePriv().isBudgeted() ? kYes_Budgeted : - kNo_Budgeted; - SkAutoTUnref newDevice( - SkGpuDevice::Create(oldRT->getContext(), budgeted, fDevice->imageInfo(), - oldRT->numSamples(), &this->props(), 0)); - if (kRetain_ContentChangeMode == mode && !oldRT->wasDestroyed() && newDevice) { - oldRT->getContext()->copySurface(newDevice->accessRenderTarget(), oldRT); - } - - SkASSERT(this->getCachedCanvas()); - SkASSERT(this->getCachedCanvas()->getDevice() == fDevice); - - this->getCachedCanvas()->setRootDevice(newDevice); - SkRefCnt_SafeAssign(fDevice, newDevice.get()); - + this->fDevice->replaceRenderTarget(SkSurface::kRetain_ContentChangeMode == mode); SkTextureImageApplyBudgetedDecision(image); } else if (kDiscard_ContentChangeMode == mode) { this->SkSurface_Gpu::onDiscard(); -- 2.7.4