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(GrContext*, const SkImage::Info&, int sampleCount);
18    SkSurface_Gpu(GrContext*, GrRenderTarget*);
19    virtual ~SkSurface_Gpu();
20
21    virtual SkCanvas* onNewCanvas() SK_OVERRIDE;
22    virtual SkSurface* onNewSurface(const SkImage::Info&) SK_OVERRIDE;
23    virtual SkImage* onNewImageSnapshot() SK_OVERRIDE;
24    virtual void onDraw(SkCanvas*, SkScalar x, SkScalar y,
25                        const SkPaint*) SK_OVERRIDE;
26    virtual void onCopyOnWrite(ContentChangeMode) SK_OVERRIDE;
27
28private:
29    SkGpuDevice* fDevice;
30
31    typedef SkSurface_Base INHERITED;
32};
33
34SK_DEFINE_INST_COUNT(SkSurface_Gpu)
35
36///////////////////////////////////////////////////////////////////////////////
37
38SkSurface_Gpu::SkSurface_Gpu(GrContext* ctx, const SkImage::Info& info,
39                             int sampleCount)
40        : INHERITED(info.fWidth, info.fHeight) {
41    bool isOpaque;
42    SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
43
44    fDevice = SkNEW_ARGS(SkGpuDevice, (ctx, config, info.fWidth, info.fHeight, sampleCount));
45
46    if (!isOpaque) {
47        fDevice->clear(0x0);
48    }
49}
50
51SkSurface_Gpu::SkSurface_Gpu(GrContext* ctx, GrRenderTarget* renderTarget)
52        : INHERITED(renderTarget->width(), renderTarget->height()) {
53    fDevice = SkNEW_ARGS(SkGpuDevice, (ctx, renderTarget));
54
55    if (kRGB_565_GrPixelConfig != renderTarget->config()) {
56        fDevice->clear(0x0);
57    }
58}
59
60SkSurface_Gpu::~SkSurface_Gpu() {
61    SkSafeUnref(fDevice);
62}
63
64SkCanvas* SkSurface_Gpu::onNewCanvas() {
65    return SkNEW_ARGS(SkCanvas, (fDevice));
66}
67
68SkSurface* SkSurface_Gpu::onNewSurface(const SkImage::Info& info) {
69    GrRenderTarget* rt = fDevice->accessRenderTarget();
70    int sampleCount = rt->numSamples();
71    return SkSurface::NewRenderTarget(fDevice->context(), info, sampleCount);
72}
73
74SkImage* SkSurface_Gpu::onNewImageSnapshot() {
75    return SkImage::NewTexture(fDevice->accessBitmap(false));
76}
77
78void SkSurface_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
79                              const SkPaint* paint) {
80    canvas->drawBitmap(fDevice->accessBitmap(false), x, y, paint);
81}
82
83// Create a new SkGpuDevice and, if necessary, copy the contents of the old
84// device into it. Note that this flushes the SkGpuDevice but
85// doesn't force an OpenGL flush.
86void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
87    GrRenderTarget* rt = fDevice->accessRenderTarget();
88    // are we sharing our render target with the image?
89    SkASSERT(NULL != this->getCachedImage());
90    if (rt->asTexture() == SkTextureImageGetTexture(this->getCachedImage())) {
91        SkGpuDevice* newDevice = static_cast<SkGpuDevice*>(
92            fDevice->createCompatibleDevice(fDevice->config(), fDevice->width(),
93            fDevice->height(), fDevice->isOpaque()));
94        SkAutoTUnref<SkGpuDevice> aurd(newDevice);
95        if (kRetain_ContentChangeMode == mode) {
96            fDevice->context()->copyTexture(rt->asTexture(),
97                reinterpret_cast<GrRenderTarget*>(newDevice->accessRenderTarget()));
98        }
99        SkASSERT(NULL != this->getCachedCanvas());
100        SkASSERT(this->getCachedCanvas()->getDevice() == fDevice);
101        this->getCachedCanvas()->setDevice(newDevice);
102        SkRefCnt_SafeAssign(fDevice, newDevice);
103    }
104}
105
106///////////////////////////////////////////////////////////////////////////////
107
108SkSurface* SkSurface::NewRenderTargetDirect(GrContext* ctx,
109                                            GrRenderTarget* target) {
110    if (NULL == ctx || NULL == target) {
111        return NULL;
112    }
113
114    return SkNEW_ARGS(SkSurface_Gpu, (ctx, target));
115}
116
117SkSurface* SkSurface::NewRenderTarget(GrContext* ctx, const SkImage::Info& info, int sampleCount) {
118    if (NULL == ctx) {
119        return NULL;
120    }
121
122    bool isOpaque;
123    SkBitmap::Config config = SkImageInfoToBitmapConfig(info, &isOpaque);
124
125    GrTextureDesc desc;
126    desc.fFlags = kRenderTarget_GrTextureFlagBit | kCheckAllocation_GrTextureFlagBit;
127    desc.fWidth = info.fWidth;
128    desc.fHeight = info.fHeight;
129    desc.fConfig = SkBitmapConfig2GrPixelConfig(config);
130    desc.fSampleCnt = sampleCount;
131
132    SkAutoTUnref<GrTexture> tex(ctx->createUncachedTexture(desc, NULL, 0));
133    if (NULL == tex) {
134        return NULL;
135    }
136
137    return SkNEW_ARGS(SkSurface_Gpu, (ctx, tex->asRenderTarget()));
138}
139