1/* 2 * Copyright 2012 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8#include "SkSurface_Base.h" 9#include "SkImagePriv.h" 10#include "SkCanvas.h" 11#include "SkGpuDevice.h" 12 13class SkSurface_Gpu : public SkSurface_Base { 14public: 15 SK_DECLARE_INST_COUNT(SkSurface_Gpu) 16 17 SkSurface_Gpu(GrRenderTarget*, bool cached, const SkSurfaceProps*, bool doClear); 18 virtual ~SkSurface_Gpu(); 19 20 virtual SkCanvas* onNewCanvas() SK_OVERRIDE; 21 virtual SkSurface* onNewSurface(const SkImageInfo&) SK_OVERRIDE; 22 virtual SkImage* onNewImageSnapshot() SK_OVERRIDE; 23 virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y, 24 const SkPaint*) SK_OVERRIDE; 25 virtual void onCopyOnWrite(ContentChangeMode) SK_OVERRIDE; 26 virtual void onDiscard() SK_OVERRIDE; 27 28private: 29 SkGpuDevice* fDevice; 30 31 typedef SkSurface_Base INHERITED; 32}; 33 34/////////////////////////////////////////////////////////////////////////////// 35 36SkSurface_Gpu::SkSurface_Gpu(GrRenderTarget* renderTarget, bool cached, const SkSurfaceProps* props, 37 bool doClear) 38 : INHERITED(renderTarget->width(), renderTarget->height(), props) 39{ 40 int deviceFlags = 0; 41 deviceFlags |= cached ? SkGpuDevice::kCached_Flag : 0; 42 deviceFlags |= this->props().isUseDistanceFieldFonts() ? SkGpuDevice::kDFFonts_Flag : 0; 43 fDevice = SkGpuDevice::Create(renderTarget, this->props(), deviceFlags); 44 45 if (kRGB_565_GrPixelConfig != renderTarget->config() && doClear) { 46 fDevice->clear(0x0); 47 } 48} 49 50SkSurface_Gpu::~SkSurface_Gpu() { 51 SkSafeUnref(fDevice); 52} 53 54SkCanvas* SkSurface_Gpu::onNewCanvas() { 55 SkCanvas::InitFlags flags = SkCanvas::kDefault_InitFlags; 56 // When we think this works... 57// flags |= SkCanvas::kConservativeRasterClip_InitFlag; 58 59 return SkNEW_ARGS(SkCanvas, (fDevice, &this->props(), flags)); 60} 61 62SkSurface* SkSurface_Gpu::onNewSurface(const SkImageInfo& info) { 63 GrRenderTarget* rt = fDevice->accessRenderTarget(); 64 int sampleCount = rt->numSamples(); 65 return SkSurface::NewRenderTarget(fDevice->context(), info, sampleCount, &this->props()); 66} 67 68SkImage* SkSurface_Gpu::onNewImageSnapshot() { 69 return SkImage::NewTexture(fDevice->accessBitmap(false)); 70} 71 72void SkSurface_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, 73 const SkPaint* paint) { 74 canvas->drawBitmap(fDevice->accessBitmap(false), x, y, paint); 75} 76 77// Create a new SkGpuDevice and, if necessary, copy the contents of the old 78// device into it. Note that this flushes the SkGpuDevice but 79// doesn't force an OpenGL flush. 80void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) { 81 GrRenderTarget* rt = fDevice->accessRenderTarget(); 82 // are we sharing our render target with the image? 83 SkASSERT(this->getCachedImage()); 84 if (rt->asTexture() == SkTextureImageGetTexture(this->getCachedImage())) { 85 // We call createCompatibleDevice because it uses the texture cache. This isn't 86 // necessarily correct (http://skbug.com/2252), but never using the cache causes 87 // a Chromium regression. (http://crbug.com/344020) 88 SkGpuDevice* newDevice = static_cast<SkGpuDevice*>( 89 fDevice->createCompatibleDevice(fDevice->imageInfo())); 90 SkAutoTUnref<SkGpuDevice> aurd(newDevice); 91 if (kRetain_ContentChangeMode == mode) { 92 fDevice->context()->copyTexture(rt->asTexture(), newDevice->accessRenderTarget()); 93 } 94 SkASSERT(this->getCachedCanvas()); 95 SkASSERT(this->getCachedCanvas()->getDevice() == fDevice); 96 97 this->getCachedCanvas()->setRootDevice(newDevice); 98 SkRefCnt_SafeAssign(fDevice, newDevice); 99 } else if (kDiscard_ContentChangeMode == mode) { 100 this->SkSurface_Gpu::onDiscard(); 101 } 102} 103 104void SkSurface_Gpu::onDiscard() { 105 fDevice->accessRenderTarget()->discard(); 106} 107 108/////////////////////////////////////////////////////////////////////////////// 109 110SkSurface* SkSurface::NewRenderTargetDirect(GrRenderTarget* target, const SkSurfaceProps* props) { 111 if (NULL == target) { 112 return NULL; 113 } 114 return SkNEW_ARGS(SkSurface_Gpu, (target, false, props, false)); 115} 116 117SkSurface* SkSurface::NewRenderTarget(GrContext* ctx, const SkImageInfo& info, int sampleCount, 118 const SkSurfaceProps* props) { 119 if (NULL == ctx) { 120 return NULL; 121 } 122 123 GrTextureDesc desc; 124 desc.fFlags = kRenderTarget_GrTextureFlagBit | kCheckAllocation_GrTextureFlagBit; 125 desc.fWidth = info.width(); 126 desc.fHeight = info.height(); 127 desc.fConfig = SkImageInfo2GrPixelConfig(info); 128 desc.fSampleCnt = sampleCount; 129 130 SkAutoTUnref<GrTexture> tex(ctx->createUncachedTexture(desc, NULL, 0)); 131 if (NULL == tex) { 132 return NULL; 133 } 134 135 return SkNEW_ARGS(SkSurface_Gpu, (tex->asRenderTarget(), false, props, true)); 136} 137 138SkSurface* SkSurface::NewScratchRenderTarget(GrContext* ctx, const SkImageInfo& info, 139 int sampleCount, const SkSurfaceProps* props) { 140 if (NULL == ctx) { 141 return NULL; 142 } 143 144 GrTextureDesc desc; 145 desc.fFlags = kRenderTarget_GrTextureFlagBit | kCheckAllocation_GrTextureFlagBit; 146 desc.fWidth = info.width(); 147 desc.fHeight = info.height(); 148 desc.fConfig = SkImageInfo2GrPixelConfig(info); 149 desc.fSampleCnt = sampleCount; 150 151 SkAutoTUnref<GrTexture> tex(ctx->lockAndRefScratchTexture(desc, GrContext::kExact_ScratchTexMatch)); 152 153 if (NULL == tex) { 154 return NULL; 155 } 156 157 return SkNEW_ARGS(SkSurface_Gpu, (tex->asRenderTarget(), true, props, true)); 158} 159