1/*
2 * Copyright 2015 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#ifndef WrappedBenchmark_DEFINED
9#define WrappedBenchmark_DEFINED
10
11#include "Benchmark.h"
12#include "SkDevice.h"
13#include "SkSurface.h"
14#include "GrContext.h"
15#include "GrRenderTarget.h"
16
17// Wrap some other benchmark to allow specialization to either
18// cpu or gpu backends. The derived class will override 'setupOffScreen'
19// to create an offscreen surface in which the actual rendering will occur.
20class WrappedBenchmark : public Benchmark {
21public:
22    // Takes ownership of caller's ref on `bench`.
23    explicit WrappedBenchmark(const SkSurfaceProps& surfaceProps, Benchmark* bench)
24        : fSurfaceProps(surfaceProps)
25        , fBench(bench) {}
26
27    const SkSurfaceProps& surfaceProps() const { return fSurfaceProps; }
28
29    const char* onGetName()       override { return fBench->getName(); }
30    const char* onGetUniqueName() override { return fBench->getUniqueName(); }
31
32    void onDelayedSetup() override { fBench->delayedSetup(); }
33    void onPerCanvasPreDraw(SkCanvas* canvas) override {
34        this->setupOffScreen(canvas);
35        fOffScreen->getCanvas()->clear(SK_ColorWHITE);
36        fBench->perCanvasPreDraw(fOffScreen->getCanvas());
37    }
38    void onPreDraw(SkCanvas* canvas) override {
39        SkASSERT(fOffScreen.get());
40        fBench->preDraw(fOffScreen->getCanvas());
41    }
42    void onPostDraw(SkCanvas* canvas) override {
43        SkASSERT(fOffScreen.get());
44        fBench->postDraw(fOffScreen->getCanvas());
45    }
46    void onPerCanvasPostDraw(SkCanvas* canvas) override {
47        SkASSERT(fOffScreen.get());
48        fBench->perCanvasPostDraw(fOffScreen->getCanvas());
49    }
50
51    void onDraw(int loops, SkCanvas* canvas) override {
52        SkASSERT(fOffScreen.get());
53        fBench->draw(loops, fOffScreen->getCanvas());
54        this->blitToScreen(canvas);
55    }
56
57    virtual SkIPoint onGetSize() override { return fBench->getSize(); }
58
59protected:
60    virtual void setupOffScreen(SkCanvas*)=0;
61
62    void blitToScreen(SkCanvas* canvas) {
63        int w = SkTMin(fBench->getSize().fX, fOffScreen->width());
64        int h = SkTMin(fBench->getSize().fY, fOffScreen->width());
65        this->onBlitToScreen(canvas, w, h);
66    }
67
68    virtual void onBlitToScreen(SkCanvas* canvas, int w, int h) = 0;
69
70    SkSurfaceProps          fSurfaceProps;
71    SkAutoTUnref<SkSurface> fOffScreen;
72    SkAutoTUnref<Benchmark> fBench;
73};
74
75// Create a raster surface for off screen rendering
76class CpuWrappedBenchmark : public WrappedBenchmark {
77public:
78    explicit CpuWrappedBenchmark(const SkSurfaceProps& surfaceProps, Benchmark* bench)
79        : INHERITED(surfaceProps, bench) {}
80
81private:
82    void setupOffScreen(SkCanvas* canvas) override {
83        fOffScreen.reset(SkSurface::NewRaster(canvas->imageInfo(), &this->surfaceProps()));
84    }
85
86    void onBlitToScreen(SkCanvas* canvas, int w, int h) override {
87        SkAutoTUnref<SkImage> image(fOffScreen->newImageSnapshot());
88        SkPaint blitPaint;
89        blitPaint.setXfermodeMode(SkXfermode::kSrc_Mode);
90        canvas->drawImageRect(image, SkIRect::MakeWH(w, h),
91                              SkRect::MakeWH(SkIntToScalar(w), SkIntToScalar(h)), &blitPaint);
92    }
93
94    typedef WrappedBenchmark INHERITED;
95};
96
97// Create an MSAA & NVPR-enabled GPU backend
98class GpuWrappedBenchmark : public WrappedBenchmark {
99public:
100    explicit GpuWrappedBenchmark(const SkSurfaceProps& surfaceProps, Benchmark* bench,
101                                 int numSamples)
102        : INHERITED(surfaceProps, bench)
103        , fNumSamples(numSamples) {}
104
105private:
106    void setupOffScreen(SkCanvas* canvas) override {
107        fOffScreen.reset(SkSurface::NewRenderTarget(canvas->getGrContext(),
108                                                    SkBudgeted::kNo,
109                                                    canvas->imageInfo(),
110                                                    fNumSamples,
111                                                    &this->surfaceProps()));
112    }
113
114    void onBlitToScreen(SkCanvas* canvas, int w, int h) override {
115        // We call copySurface directly on the underlying GPU surfaces for a more efficient blit.
116        GrRenderTarget* dst, *src;
117
118        SkCanvas::LayerIter canvasIter(canvas, false);
119        SkAssertResult((dst = canvasIter.device()->accessRenderTarget()));
120
121        SkCanvas::LayerIter offscreenIter(fOffScreen->getCanvas(), false);
122        SkAssertResult((src = offscreenIter.device()->accessRenderTarget()));
123
124        SkASSERT(dst->getContext() == src->getContext());
125
126        dst->getContext()->copySurface(dst, src, SkIRect::MakeWH(w, h), SkIPoint::Make(0, 0));
127
128#ifdef SK_DEBUG
129        // This method should not be called while layers are saved.
130        canvasIter.next();
131        SkASSERT(canvasIter.done());
132
133        offscreenIter.next();
134        SkASSERT(offscreenIter.done());
135#endif
136    }
137
138    int fNumSamples;
139    typedef WrappedBenchmark INHERITED;
140};
141
142#endif //WrappedBenchmark_DEFINED
143