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, TextRenderMode trm); 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, TextRenderMode trm) 37 : INHERITED(renderTarget->width(), renderTarget->height()) { 38 int flags = 0; 39 flags |= cached ? SkGpuDevice::kCached_Flag : 0; 40 flags |= (kDistanceField_TextRenderMode == trm) ? SkGpuDevice::kDFFonts_Flag : 0; 41 fDevice = SkGpuDevice::Create(renderTarget, flags); 42 43 if (kRGB_565_GrPixelConfig != renderTarget->config()) { 44 fDevice->clear(0x0); 45 } 46} 47 48SkSurface_Gpu::~SkSurface_Gpu() { 49 SkSafeUnref(fDevice); 50} 51 52SkCanvas* SkSurface_Gpu::onNewCanvas() { 53 return SkNEW_ARGS(SkCanvas, (fDevice)); 54} 55 56SkSurface* SkSurface_Gpu::onNewSurface(const SkImageInfo& info) { 57 GrRenderTarget* rt = fDevice->accessRenderTarget(); 58 int sampleCount = rt->numSamples(); 59 return SkSurface::NewRenderTarget(fDevice->context(), info, sampleCount); 60} 61 62SkImage* SkSurface_Gpu::onNewImageSnapshot() { 63 return SkImage::NewTexture(fDevice->accessBitmap(false)); 64} 65 66void SkSurface_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y, 67 const SkPaint* paint) { 68 canvas->drawBitmap(fDevice->accessBitmap(false), x, y, paint); 69} 70 71// Create a new SkGpuDevice and, if necessary, copy the contents of the old 72// device into it. Note that this flushes the SkGpuDevice but 73// doesn't force an OpenGL flush. 74void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) { 75 GrRenderTarget* rt = fDevice->accessRenderTarget(); 76 // are we sharing our render target with the image? 77 SkASSERT(NULL != this->getCachedImage()); 78 if (rt->asTexture() == SkTextureImageGetTexture(this->getCachedImage())) { 79 // We call createCompatibleDevice because it uses the texture cache. This isn't 80 // necessarily correct (http://skbug.com/2252), but never using the cache causes 81 // a Chromium regression. (http://crbug.com/344020) 82 SkGpuDevice* newDevice = static_cast<SkGpuDevice*>( 83 fDevice->createCompatibleDevice(fDevice->imageInfo())); 84 SkAutoTUnref<SkGpuDevice> aurd(newDevice); 85 if (kRetain_ContentChangeMode == mode) { 86 fDevice->context()->copyTexture(rt->asTexture(), newDevice->accessRenderTarget()); 87 } 88 SkASSERT(NULL != this->getCachedCanvas()); 89 SkASSERT(this->getCachedCanvas()->getDevice() == fDevice); 90 91 this->getCachedCanvas()->setRootDevice(newDevice); 92 SkRefCnt_SafeAssign(fDevice, newDevice); 93 } else if (kDiscard_ContentChangeMode == mode) { 94 this->SkSurface_Gpu::onDiscard(); 95 } 96} 97 98void SkSurface_Gpu::onDiscard() { 99 fDevice->accessRenderTarget()->discard(); 100} 101 102/////////////////////////////////////////////////////////////////////////////// 103 104SkSurface* SkSurface::NewRenderTargetDirect(GrRenderTarget* target, TextRenderMode trm) { 105 if (NULL == target) { 106 return NULL; 107 } 108 return SkNEW_ARGS(SkSurface_Gpu, (target, false, trm)); 109} 110 111SkSurface* SkSurface::NewRenderTarget(GrContext* ctx, const SkImageInfo& info, int sampleCount, 112 TextRenderMode trm) { 113 if (NULL == ctx) { 114 return NULL; 115 } 116 117 GrTextureDesc desc; 118 desc.fFlags = kRenderTarget_GrTextureFlagBit | kCheckAllocation_GrTextureFlagBit; 119 desc.fWidth = info.width(); 120 desc.fHeight = info.height(); 121 desc.fConfig = SkImageInfo2GrPixelConfig(info); 122 desc.fSampleCnt = sampleCount; 123 124 SkAutoTUnref<GrTexture> tex(ctx->createUncachedTexture(desc, NULL, 0)); 125 if (NULL == tex) { 126 return NULL; 127 } 128 129 return SkNEW_ARGS(SkSurface_Gpu, (tex->asRenderTarget(), false, trm)); 130} 131 132SkSurface* SkSurface::NewScratchRenderTarget(GrContext* ctx, const SkImageInfo& info, 133 int sampleCount, TextRenderMode trm) { 134 if (NULL == ctx) { 135 return NULL; 136 } 137 138 GrTextureDesc desc; 139 desc.fFlags = kRenderTarget_GrTextureFlagBit | kCheckAllocation_GrTextureFlagBit; 140 desc.fWidth = info.width(); 141 desc.fHeight = info.height(); 142 desc.fConfig = SkImageInfo2GrPixelConfig(info); 143 desc.fSampleCnt = sampleCount; 144 145 SkAutoTUnref<GrTexture> tex(ctx->lockAndRefScratchTexture(desc, GrContext::kExact_ScratchTexMatch)); 146 147 if (NULL == tex) { 148 return NULL; 149 } 150 151 return SkNEW_ARGS(SkSurface_Gpu, (tex->asRenderTarget(), true, trm)); 152} 153