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_Gpu.h"
9
10#include "SkCanvas.h"
11#include "SkGpuDevice.h"
12#include "SkImage_Base.h"
13#include "SkImage_Gpu.h"
14#include "SkImagePriv.h"
15#include "SkSurface_Base.h"
16
17#if SK_SUPPORT_GPU
18
19///////////////////////////////////////////////////////////////////////////////
20
21SkSurface_Gpu::SkSurface_Gpu(SkGpuDevice* device)
22    : INHERITED(device->width(), device->height(), &device->surfaceProps())
23    , fDevice(SkRef(device)) {
24}
25
26SkSurface_Gpu::~SkSurface_Gpu() {
27    fDevice->unref();
28}
29
30SkCanvas* SkSurface_Gpu::onNewCanvas() {
31    SkCanvas::InitFlags flags = SkCanvas::kDefault_InitFlags;
32    // When we think this works...
33//    flags |= SkCanvas::kConservativeRasterClip_InitFlag;
34
35    return SkNEW_ARGS(SkCanvas, (fDevice, &this->props(), flags));
36}
37
38SkSurface* SkSurface_Gpu::onNewSurface(const SkImageInfo& info) {
39    GrRenderTarget* rt = fDevice->accessRenderTarget();
40    int sampleCount = rt->numSamples();
41    // TODO: Make caller specify this (change virtual signature of onNewSurface).
42    static const Budgeted kBudgeted = kNo_Budgeted;
43    return SkSurface::NewRenderTarget(fDevice->context(), kBudgeted, info, sampleCount,
44                                      &this->props());
45}
46
47SkImage* SkSurface_Gpu::onNewImageSnapshot(Budgeted budgeted) {
48    const SkImageInfo info = fDevice->imageInfo();
49    const int sampleCount = fDevice->accessRenderTarget()->numSamples();
50    SkImage* image = NULL;
51    GrTexture* tex = fDevice->accessRenderTarget()->asTexture();
52    if (tex) {
53        image = SkNEW_ARGS(SkImage_Gpu,
54                           (info.width(), info.height(), info.alphaType(),
55                            tex, sampleCount, budgeted));
56    }
57    if (image) {
58        as_IB(image)->initWithProps(this->props());
59    }
60    return image;
61}
62
63void SkSurface_Gpu::onDraw(SkCanvas* canvas, SkScalar x, SkScalar y,
64                              const SkPaint* paint) {
65    canvas->drawBitmap(fDevice->accessBitmap(false), x, y, paint);
66}
67
68// Create a new render target and, if necessary, copy the contents of the old
69// render target into it. Note that this flushes the SkGpuDevice but
70// doesn't force an OpenGL flush.
71void SkSurface_Gpu::onCopyOnWrite(ContentChangeMode mode) {
72    GrRenderTarget* rt = fDevice->accessRenderTarget();
73    // are we sharing our render target with the image? Note this call should never create a new
74    // image because onCopyOnWrite is only called when there is a cached image.
75    SkImage* image = this->getCachedImage(kNo_Budgeted);
76    SkASSERT(image);
77    if (rt->asTexture() == image->getTexture()) {
78        this->fDevice->replaceRenderTarget(SkSurface::kRetain_ContentChangeMode == mode);
79        SkTextureImageApplyBudgetedDecision(image);
80    } else if (kDiscard_ContentChangeMode == mode) {
81        this->SkSurface_Gpu::onDiscard();
82    }
83}
84
85void SkSurface_Gpu::onDiscard() {
86    fDevice->accessRenderTarget()->discard();
87}
88
89///////////////////////////////////////////////////////////////////////////////
90
91SkSurface* SkSurface::NewRenderTargetDirect(GrRenderTarget* target, const SkSurfaceProps* props) {
92    SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(target, props));
93    if (!device) {
94        return NULL;
95    }
96    return SkNEW_ARGS(SkSurface_Gpu, (device));
97}
98
99SkSurface* SkSurface::NewRenderTarget(GrContext* ctx, Budgeted budgeted, const SkImageInfo& info,
100                                      int sampleCount, const SkSurfaceProps* props) {
101    SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(ctx, budgeted, info, sampleCount, props,
102                                                         SkGpuDevice::kNeedClear_Flag));
103    if (!device) {
104        return NULL;
105    }
106    return SkNEW_ARGS(SkSurface_Gpu, (device));
107}
108
109SkSurface* SkSurface::NewWrappedRenderTarget(GrContext* context, GrBackendTextureDesc desc,
110                                             const SkSurfaceProps* props) {
111    if (NULL == context) {
112        return NULL;
113    }
114    if (!SkToBool(desc.fFlags & kRenderTarget_GrBackendTextureFlag)) {
115        return NULL;
116    }
117    SkAutoTUnref<GrSurface> surface(context->textureProvider()->wrapBackendTexture(desc));
118    if (!surface) {
119        return NULL;
120    }
121    SkAutoTUnref<SkGpuDevice> device(SkGpuDevice::Create(surface->asRenderTarget(), props,
122                                                         SkGpuDevice::kNeedClear_Flag));
123    if (!device) {
124        return NULL;
125    }
126    return SkNEW_ARGS(SkSurface_Gpu, (device));
127}
128
129#endif
130