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
9#include "VisualBench.h"
10
11#include "GrContext.h"
12#include "ProcStats.h"
13#include "SkApplication.h"
14#include "SkCanvas.h"
15#include "SkCommandLineFlags.h"
16#include "SkGraphics.h"
17#include "SkGr.h"
18#include "SkOSFile.h"
19#include "SkStream.h"
20#include "Stats.h"
21#include "VisualDebugModule.h"
22#include "VisualLightweightBenchModule.h"
23#include "VisualInteractiveModule.h"
24#include "gl/GrGLInterface.h"
25
26#include <stdlib.h>
27
28DEFINE_bool2(fullscreen, f, true, "Run fullscreen.");
29DEFINE_string(mode, "classic", "one of: classic interactive debugger");
30DEFINE_bool2(dif, d, false, "Use device-independent fonts.");
31
32VisualBench::VisualBench(void* hwnd, int argc, char** argv)
33    : INHERITED(hwnd) {
34    SkDebugf("Command line arguments: ");
35    for (int i = 1; i < argc; ++i) {
36        SkDebugf("%s ", argv[i]);
37    }
38    SkDebugf("\n");
39
40    SkCommandLineFlags::Parse(argc, argv);
41
42    if (FLAGS_nvpr && !FLAGS_msaa) {
43        SkDebugf("Got nvpr without msaa. Exiting.\n");
44        exit(-1);
45    }
46
47    // these have to happen after commandline parsing
48    if (FLAGS_dif) {
49        const SkSurfaceProps& props(INHERITED::getSurfaceProps());
50        uint32_t flags = SkSurfaceProps::kUseDeviceIndependentFonts_Flag | props.flags();
51        INHERITED::setSurfaceProps(SkSurfaceProps(flags, props.pixelGeometry()));
52    }
53    fModule.reset(new VisualLightweightBenchModule(this));
54
55    if (FLAGS_mode.count()) {
56        SkASSERT(FLAGS_mode.count() == 1);
57        SkString mode(FLAGS_mode[0]);
58        if (mode == SkString("interactive")) {
59            fModule.reset(new VisualInteractiveModule(this));
60        } else if (mode == SkString("debugger")) {
61            fModule.reset(new VisualDebugModule(this));
62        }
63    }
64
65    this->setTitle();
66    this->setupBackend();
67}
68
69VisualBench::~VisualBench() {
70    this->tearDownContext();
71}
72
73void VisualBench::setTitle() {
74    SkString title("VisualBench");
75    INHERITED::setTitle(title.c_str());
76}
77
78SkSurface* VisualBench::createSurface() {
79    if (!fSurface) {
80        SkSurfaceProps props(INHERITED::getSurfaceProps());
81        fSurface.reset(SkSurface::NewRenderTargetDirect(fRenderTarget, &props));
82    }
83
84    // The caller will wrap the SkSurface in an SkAutoTUnref
85    return SkRef(fSurface.get());
86}
87
88bool VisualBench::setupBackend() {
89    this->setVisibleP(true);
90    this->setClipToBounds(false);
91
92    if (FLAGS_fullscreen) {
93        if (!this->makeFullscreen()) {
94            SkDebugf("Could not go fullscreen!");
95        }
96    }
97
98    this->resetContext();
99    return true;
100}
101
102void VisualBench::resetContext() {
103    this->tearDownContext();
104    this->setupContext();
105}
106
107void VisualBench::setupContext() {
108    int screenSamples = FLAGS_offscreen ? 0 : FLAGS_msaa;
109    if (!this->attach(kNativeGL_BackEndType, screenSamples, &fAttachmentInfo)) {
110        SkDebugf("Not possible to create backend.\n");
111        INHERITED::detach();
112        SkFAIL("Could not create backend\n");
113    }
114
115    this->setVsync(false);
116
117    fSurface.reset(nullptr);
118
119    fInterface.reset(GrGLCreateNativeInterface());
120
121    // TODO use the GLContext creation factories and also set this all up in configs
122    if (!FLAGS_nvpr) {
123        fInterface.reset(GrGLInterfaceRemoveNVPR(fInterface));
124    }
125    SkASSERT(fInterface);
126
127    // setup contexts
128    fContext.reset(GrContext::Create(kOpenGL_GrBackend, (GrBackendContext)fInterface.get()));
129    SkASSERT(fContext);
130
131    // setup rendertargets
132    this->setupRenderTarget();
133}
134
135void VisualBench::tearDownContext() {
136    if (fContext) {
137        // We abandon the context in case SkWindow has kept a ref to the surface
138        fContext->abandonContext();
139        fContext.reset();
140        fSurface.reset();
141        fInterface.reset();
142        this->detach();
143    }
144}
145
146void VisualBench::setupRenderTarget() {
147    if (fContext) {
148        fRenderTarget.reset(this->renderTarget(fAttachmentInfo, fInterface, fContext));
149    }
150}
151
152void VisualBench::draw(SkCanvas* canvas) {
153    fModule->draw(canvas);
154
155    // Invalidate the window to force a redraw. Poor man's animation mechanism.
156    this->inval(nullptr);
157}
158
159void VisualBench::clear(SkCanvas* canvas, SkColor color, int frames) {
160    canvas->clear(color);
161    for (int i = 0; i < frames - 1; ++i) {
162        canvas->flush();
163        this->present();
164        canvas->clear(color);
165    }
166}
167
168void VisualBench::onSizeChange() {
169    this->setupRenderTarget();
170}
171
172bool VisualBench::onHandleChar(SkUnichar unichar) {
173    static const auto kEscKey = 27;
174    if (kEscKey == unichar) {
175        this->closeWindow();
176        return true;
177    }
178
179    return fModule->onHandleChar(unichar);
180}
181
182// Externally declared entry points
183void application_init() {
184    SkGraphics::Init();
185    SkEvent::Init();
186}
187
188void application_term() {
189    SkEvent::Term();
190}
191
192SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) {
193    return new VisualBench(hwnd, argc, argv);
194}
195
196