1/*
2 * Copyright 2013 Google Inc.
3 *
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 *
8 */
9
10#include "SkExample.h"
11
12#include "gl/GrGLUtil.h"
13#include "gl/GrGLDefines.h"
14#include "gl/GrGLInterface.h"
15#include "SkApplication.h"
16#include "SkCommandLineFlags.h"
17#include "SkGpuDevice.h"
18#include "SkGraphics.h"
19
20DEFINE_string2(match, m, NULL, "[~][^]substring[$] [...] of test name to run.\n" \
21                               "Multiple matches may be separated by spaces.\n" \
22                               "~ causes a matching test to always be skipped\n" \
23                               "^ requires the start of the test to match\n" \
24                               "$ requires the end of the test to match\n" \
25                               "^ and $ requires an exact match\n" \
26                               "If a test does not match any list entry,\n" \
27                               "it is skipped unless some list entry starts with ~");
28
29void application_init() {
30    SkGraphics::Init();
31    SkEvent::Init();
32}
33
34void application_term() {
35    SkEvent::Term();
36    SkGraphics::Term();
37}
38
39SkExampleWindow::SkExampleWindow(void* hwnd)
40    : INHERITED(hwnd) {
41    fRegistry = SkExample::Registry::Head();
42    fCurrExample = fRegistry->factory()(this);
43
44    if (FLAGS_match.count()) {
45        // Start with the a matching sample if possible.
46        bool found = this->findNextMatch();
47        if (!found) {
48            SkDebugf("No matching SkExample found.\n");
49        }
50    }
51}
52
53void SkExampleWindow::tearDownBackend() {
54  if (kGPU_DeviceType == fType) {
55        SkSafeUnref(fContext);
56        fContext = NULL;
57
58        SkSafeUnref(fInterface);
59        fInterface = NULL;
60
61        SkSafeUnref(fRenderTarget);
62        fRenderTarget = NULL;
63
64        detach();
65    }
66}
67
68bool SkExampleWindow::setupBackend(DeviceType type) {
69    fType = type;
70
71    this->setColorType(kRGBA_8888_SkColorType);
72    this->setVisibleP(true);
73    this->setClipToBounds(false);
74
75    bool result = attach(kNativeGL_BackEndType, 0 /*msaa*/, &fAttachmentInfo);
76    if (false == result) {
77        SkDebugf("Not possible to create backend.\n");
78        detach();
79        return false;
80    }
81
82    fInterface = GrGLCreateNativeInterface();
83
84    SkASSERT(NULL != fInterface);
85
86    fContext = GrContext::Create(kOpenGL_GrBackend, (GrBackendContext)fInterface);
87    SkASSERT(NULL != fContext);
88
89    setupRenderTarget();
90
91    return true;
92}
93
94void SkExampleWindow::setupRenderTarget() {
95    GrBackendRenderTargetDesc desc;
96    desc.fWidth = SkScalarRoundToInt(width());
97    desc.fHeight = SkScalarRoundToInt(height());
98    desc.fConfig = kSkia8888_GrPixelConfig;
99    desc.fOrigin = kBottomLeft_GrSurfaceOrigin;
100    desc.fSampleCnt = fAttachmentInfo.fSampleCount;
101    desc.fStencilBits = fAttachmentInfo.fStencilBits;
102
103    GrGLint buffer;
104    GR_GL_GetIntegerv(fInterface, GR_GL_FRAMEBUFFER_BINDING, &buffer);
105    desc.fRenderTargetHandle = buffer;
106
107    fRenderTarget = fContext->wrapBackendRenderTarget(desc);
108
109    fContext->setRenderTarget(fRenderTarget);
110}
111
112SkCanvas* SkExampleWindow::createCanvas() {
113    if (fType == kGPU_DeviceType) {
114        if (NULL != fContext && NULL != fRenderTarget) {
115            SkAutoTUnref<SkBaseDevice> device(new SkGpuDevice(fContext, fRenderTarget));
116            return new SkCanvas(device);
117        }
118        tearDownBackend();
119        setupBackend(kRaster_DeviceType);
120    }
121    return INHERITED::createCanvas();
122}
123
124void SkExampleWindow::draw(SkCanvas* canvas) {
125    if (NULL != fCurrExample) {
126        fCurrExample->draw(canvas);
127    }
128    if (fType == kGPU_DeviceType) {
129
130        SkASSERT(NULL != fContext);
131        fContext->flush();
132    }
133    if (fType == kRaster_DeviceType) {
134        // need to send the raster bits to the (gpu) window
135        fContext->setRenderTarget(fRenderTarget);
136        const SkBitmap& bm = getBitmap();
137        fRenderTarget->writePixels(0, 0, bm.width(), bm.height(),
138                                      kSkia8888_GrPixelConfig,
139                                      bm.getPixels(),
140                                      bm.rowBytes());
141    }
142    INHERITED::present();
143}
144
145void SkExampleWindow::onSizeChange() {
146    setupRenderTarget();
147}
148
149#ifdef SK_BUILD_FOR_WIN
150void SkExampleWindow::onHandleInval(const SkIRect& rect) {
151    RECT winRect;
152    winRect.top = rect.top();
153    winRect.bottom = rect.bottom();
154    winRect.right = rect.right();
155    winRect.left = rect.left();
156    InvalidateRect((HWND)this->getHWND(), &winRect, false);
157}
158#endif
159
160bool SkExampleWindow::findNextMatch() {
161    bool found = false;
162    // Avoid infinite loop by knowing where we started.
163    const SkExample::Registry* begin = fRegistry;
164    while (!found) {
165        fRegistry = fRegistry->next();
166        if (NULL == fRegistry) {  // Reached the end of the registered samples. GOTO head.
167            fRegistry = SkExample::Registry::Head();
168        }
169        SkExample* next = fRegistry->factory()(this);
170        if (!SkCommandLineFlags::ShouldSkip(FLAGS_match, next->getName().c_str())) {
171            fCurrExample = next;
172            found = true;
173        }
174        if (begin == fRegistry) {  // We looped through every sample without finding anything.
175            break;
176        }
177    }
178    return found;
179}
180
181bool SkExampleWindow::onHandleChar(SkUnichar unichar) {
182    if ('n' == unichar) {
183        bool found = findNextMatch();
184        if (!found) {
185            SkDebugf("No SkExample that matches your query\n");
186        }
187    }
188    return true;
189}
190
191SkOSWindow* create_sk_window(void* hwnd, int argc, char** argv) {
192    SkCommandLineFlags::Parse(argc, argv);
193    return new SkExampleWindow(hwnd);
194}
195