fc83ea4174aaf63babf3e629977a8dcb82e6b010
[platform/upstream/libSkiaSharp.git] / dm / DMSrcSinkAndroid.cpp
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 #include "DMSrcSink.h"
9 #include "DMSrcSinkAndroid.h"
10
11 #include "AnimationContext.h"
12 #include "DisplayListRenderer.h"
13 #include "IContextFactory.h"
14 #include "RenderNode.h"
15 #include "SkAndroidSDKCanvas.h"
16 #include "SkCanvas.h"
17 #include "SkiaCanvasProxy.h"
18 #include "SkTLazy.h"
19 #include "SkMaskFilter.h"
20 #include "SkPictureRecorder.h"
21 #include "SkStream.h"
22 #include "android/rect.h"
23 #include "android/native_window.h"
24 #include "gui/BufferQueue.h"
25 #include "gui/CpuConsumer.h"
26 #include "gui/IGraphicBufferConsumer.h"
27 #include "gui/IGraphicBufferProducer.h"
28 #include "gui/Surface.h"
29 #include "renderthread/RenderProxy.h"
30 #include "renderthread/TimeLord.h"
31
32 /* These functions are only compiled in the Android Framework. */
33
34 namespace {
35
36 /**
37  * Helper class for setting up android::uirenderer::renderthread::RenderProxy.
38  */
39 class ContextFactory : public android::uirenderer::IContextFactory {
40 public:
41     android::uirenderer::AnimationContext* createAnimationContext
42         (android::uirenderer::renderthread::TimeLord& clock) SK_OVERRIDE {
43         return new android::uirenderer::AnimationContext(clock);
44     }
45 };
46
47 }  // namespace
48
49 namespace DM {
50
51 Error HWUISink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
52     // Do all setup in this function because we don't know the size
53     // for the RenderNode and RenderProxy during the constructor.
54     // In practice this doesn't seem too expensive.
55     const SkISize size = src.size();
56
57     // Based on android::SurfaceTexture_init()
58     android::sp<android::IGraphicBufferProducer> producer;
59     android::sp<android::IGraphicBufferConsumer> consumer;
60     android::BufferQueue::createBufferQueue(&producer, &consumer);
61
62     // Consumer setup
63
64     android::sp<android::CpuConsumer> cpuConsumer =
65         new android::CpuConsumer(consumer, 1);
66     cpuConsumer->setName(android::String8("SkiaTestClient"));
67     cpuConsumer->setDefaultBufferSize(size.width(), size.height());
68
69     // Producer setup
70
71     android::sp<android::Surface> surface = new android::Surface(producer);
72     native_window_set_buffers_dimensions(surface.get(), size.width(), size.height());
73     native_window_set_buffers_format(surface.get(), android::PIXEL_FORMAT_RGBA_8888);
74     native_window_set_usage(surface.get(), GRALLOC_USAGE_SW_READ_OFTEN |
75                                            GRALLOC_USAGE_SW_WRITE_NEVER |
76                                            GRALLOC_USAGE_HW_RENDER);
77
78     // RenderNode setup based on hwui/tests/main.cpp:TreeContentAnimation
79     SkAutoTDelete<android::uirenderer::RenderNode> rootNode
80         (new android::uirenderer::RenderNode());
81     rootNode->incStrong(nullptr);
82
83     // Values set here won't be applied until the framework has called
84     // RenderNode::pushStagingPropertiesChanges() during RenderProxy::syncAndDrawFrame().
85     rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, size.width(), size.height());
86     rootNode->setPropertyFieldsDirty(android::uirenderer::RenderNode::X |
87                                      android::uirenderer::RenderNode::Y);
88     rootNode->mutateStagingProperties().setClipToBounds(false);
89     rootNode->setPropertyFieldsDirty(android::uirenderer::RenderNode::GENERIC);
90
91     // RenderProxy setup based on hwui/tests/main.cpp:TreeContentAnimation
92     ContextFactory factory;
93     SkAutoTDelete<android::uirenderer::renderthread::RenderProxy> proxy
94         (new android::uirenderer::renderthread::RenderProxy(false, rootNode, &factory));
95     proxy->loadSystemProperties();
96
97     proxy->initialize(surface.get());
98
99     float lightX = size.width() / 2.0f;
100     android::uirenderer::Vector3 lightVector { lightX, -200.0f, 800.0f };
101     proxy->setup(size.width(), size.height(), lightVector, 800.0f, 255 * 0.075f, 255 * 0.15f);
102
103     // Do the draw
104
105     SkAutoTDelete<android::uirenderer::DisplayListRenderer> renderer
106         (new android::uirenderer::DisplayListRenderer());
107     renderer->setViewport(size.width(), size.height());
108     renderer->prepare();
109     renderer->clipRect(0, 0, size.width(), size.height(), SkRegion::Op::kReplace_Op);
110
111     Error err = src.draw(renderer->asSkCanvas());
112     if (!err.isEmpty()) {
113         return err;
114     }
115
116     renderer->finish();
117     rootNode->setStagingDisplayList(renderer->finishRecording());
118
119     proxy->syncAndDrawFrame();
120     proxy->fence();
121
122     // Capture pixels
123
124     SkImageInfo destinationConfig =
125         SkImageInfo::Make(size.width(), size.height(),
126                           kRGBA_8888_SkColorType, kPremul_SkAlphaType);
127     dst->allocPixels(destinationConfig);
128     sk_memset32((uint32_t*) dst->getPixels(), SK_ColorRED, size.width() * size.height());
129
130     android::CpuConsumer::LockedBuffer nativeBuffer;
131     android::status_t retval = cpuConsumer->lockNextBuffer(&nativeBuffer);
132     if (retval == android::BAD_VALUE) {
133         SkDebugf("HWUISink::draw() got no buffer; returning transparent");
134         // No buffer ready to read - commonly triggered by dm sending us
135         // a no-op source, or calling code that doesn't do anything on this
136         // backend.
137         dst->eraseColor(SK_ColorTRANSPARENT);
138         return "";
139     } else if (retval) {
140         return SkStringPrintf("Failed to lock buffer to read pixels: %d.", retval);
141     }
142
143     // Move the pixels into the destination SkBitmap
144
145     SK_ALWAYSBREAK(nativeBuffer.format == android::PIXEL_FORMAT_RGBA_8888 &&
146                    "Native buffer not RGBA!");
147     SkImageInfo nativeConfig =
148         SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
149                           kRGBA_8888_SkColorType, kPremul_SkAlphaType);
150
151     // Android stride is in pixels, Skia stride is in bytes
152     SkBitmap nativeWrapper;
153     bool success =
154         nativeWrapper.installPixels(nativeConfig, nativeBuffer.data, nativeBuffer.stride * 4);
155     if (!success) {
156         return "Failed to wrap HWUI buffer in a SkBitmap";
157     }
158
159     SK_ALWAYSBREAK(dst->colorType() == kRGBA_8888_SkColorType &&
160                    "Destination buffer not RGBA!");
161     success =
162         nativeWrapper.readPixels(destinationConfig, dst->getPixels(), dst->rowBytes(), 0, 0);
163     if (!success) {
164         return "Failed to extract pixels from HWUI buffer";
165     }
166
167     cpuConsumer->unlockBuffer(nativeBuffer);
168     return "";
169 }
170
171 /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
172
173 ViaAndroidSDK::ViaAndroidSDK(Sink* sink) : fSink(sink) { }
174
175 Error ViaAndroidSDK::draw(const Src& src,
176                           SkBitmap* bitmap,
177                           SkWStream* stream,
178                           SkString* log) const {
179     struct ProxySrc : public Src {
180         const Src& fSrc;
181         ProxySrc(const Src& src)
182             : fSrc(src) {}
183
184         Error draw(SkCanvas* canvas) const SK_OVERRIDE {
185             // Pass through HWUI's upper layers to get operational transforms
186             SkAutoTDelete<android::Canvas> ac (android::Canvas::create_canvas(canvas));
187             SkAutoTUnref<android::uirenderer::SkiaCanvasProxy> scProxy
188                 (new android::uirenderer::SkiaCanvasProxy(ac));
189
190             // Pass through another proxy to get paint transforms
191             SkAndroidSDKCanvas fc;
192             fc.reset(scProxy);
193
194             fSrc.draw(&fc);
195
196             return "";
197         }
198         SkISize size() const SK_OVERRIDE { return fSrc.size(); }
199         Name name() const SK_OVERRIDE { sk_throw(); return ""; }
200     } proxy(src);
201
202     return fSink->draw(proxy, bitmap, stream, log);
203 }
204
205 }  // namespace DM