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 
28 DEFINE_bool2(fullscreen, f, true, "Run fullscreen.");
29 DEFINE_string(mode, "classic", "one of: classic interactive debugger");
30 DEFINE_bool2(dif, d, false, "Use device-independent fonts.");
31 
VisualBench(void * hwnd,int argc,char ** argv)32 VisualBench::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 
~VisualBench()69 VisualBench::~VisualBench() {
70     this->tearDownContext();
71 }
72 
setTitle()73 void VisualBench::setTitle() {
74     SkString title("VisualBench");
75     INHERITED::setTitle(title.c_str());
76 }
77 
createSurface()78 SkSurface* 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 
setupBackend()88 bool 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 
resetContext()102 void VisualBench::resetContext() {
103     this->tearDownContext();
104     this->setupContext();
105 }
106 
setupContext()107 void 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 
tearDownContext()135 void 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 
setupRenderTarget()146 void VisualBench::setupRenderTarget() {
147     if (fContext) {
148         fRenderTarget.reset(this->renderTarget(fAttachmentInfo, fInterface, fContext));
149     }
150 }
151 
draw(SkCanvas * canvas)152 void 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 
clear(SkCanvas * canvas,SkColor color,int frames)159 void 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 
onSizeChange()168 void VisualBench::onSizeChange() {
169     this->setupRenderTarget();
170 }
171 
onHandleChar(SkUnichar unichar)172 bool 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
application_init()183 void application_init() {
184     SkGraphics::Init();
185     SkEvent::Init();
186 }
187 
application_term()188 void application_term() {
189     SkEvent::Term();
190 }
191 
create_sk_window(void * hwnd,int argc,char ** argv)192 SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) {
193     return new VisualBench(hwnd, argc, argv);
194 }
195 
196