1 /*
2 * Copyright (C) 2015 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16 #include "TestWindowContext.h"
17
18 #include "AnimationContext.h"
19 #include "IContextFactory.h"
20 #include "RecordingCanvas.h"
21 #include "RenderNode.h"
22 #include "SkTypes.h"
23 #include "gui/BufferQueue.h"
24 #include "gui/CpuConsumer.h"
25 #include "gui/IGraphicBufferConsumer.h"
26 #include "gui/IGraphicBufferProducer.h"
27 #include "gui/Surface.h"
28 #include "renderthread/RenderProxy.h"
29
30 #include <cutils/memory.h>
31
32 namespace {
33
34 /**
35 * Helper class for setting up android::uirenderer::renderthread::RenderProxy.
36 */
37 class ContextFactory : public android::uirenderer::IContextFactory {
38 public:
createAnimationContext(android::uirenderer::renderthread::TimeLord & clock)39 android::uirenderer::AnimationContext* createAnimationContext
40 (android::uirenderer::renderthread::TimeLord& clock) override {
41 return new android::uirenderer::AnimationContext(clock);
42 }
43 };
44
45 } // anonymous namespace
46
47 namespace android {
48 namespace uirenderer {
49
50 /**
51 Android strong pointers (android::sp) can't hold forward-declared classes,
52 so we have to use pointer-to-implementation here if we want to hide the
53 details from our non-framework users.
54 */
55
56 class TestWindowContext::TestWindowData {
57
58 public:
59
TestWindowData(SkISize size)60 explicit TestWindowData(SkISize size) : mSize(size) {
61 android::BufferQueue::createBufferQueue(&mProducer, &mConsumer);
62 mCpuConsumer = new android::CpuConsumer(mConsumer, 1);
63 mCpuConsumer->setName(android::String8("TestWindowContext"));
64 mCpuConsumer->setDefaultBufferSize(mSize.width(), mSize.height());
65 mAndroidSurface = new android::Surface(mProducer);
66 native_window_set_buffers_dimensions(mAndroidSurface.get(),
67 mSize.width(), mSize.height());
68 native_window_set_buffers_format(mAndroidSurface.get(),
69 android::PIXEL_FORMAT_RGBA_8888);
70 native_window_set_usage(mAndroidSurface.get(),
71 GRALLOC_USAGE_SW_READ_OFTEN |
72 GRALLOC_USAGE_SW_WRITE_NEVER |
73 GRALLOC_USAGE_HW_RENDER);
74 mRootNode.reset(new android::uirenderer::RenderNode());
75 mRootNode->incStrong(nullptr);
76 mRootNode->mutateStagingProperties().setLeftTopRightBottom
77 (0, 0, mSize.width(), mSize.height());
78 mRootNode->mutateStagingProperties().setClipToBounds(false);
79 mRootNode->setPropertyFieldsDirty(android::uirenderer::RenderNode::GENERIC);
80 ContextFactory factory;
81 mProxy.reset
82 (new android::uirenderer::renderthread::RenderProxy(false,
83 mRootNode.get(),
84 &factory));
85 mProxy->loadSystemProperties();
86 mProxy->initialize(mAndroidSurface.get());
87 float lightX = mSize.width() / 2.0f;
88 android::uirenderer::Vector3 lightVector { lightX, -200.0f, 800.0f };
89 mProxy->setup(800.0f, 255 * 0.075f, 255 * 0.15f);
90 mProxy->setLightCenter(lightVector);
91 mCanvas.reset(new android::uirenderer::RecordingCanvas(mSize.width(), mSize.height()));
92 }
93
prepareToDraw()94 SkCanvas* prepareToDraw() {
95 //mCanvas->reset(mSize.width(), mSize.height());
96 mCanvas->clipRect(0, 0, mSize.width(), mSize.height(), SkClipOp::kReplace_deprecated);
97 return mCanvas->asSkCanvas();
98 }
99
finishDrawing()100 void finishDrawing() {
101 mRootNode->setStagingDisplayList(mCanvas->finishRecording());
102 mProxy->syncAndDrawFrame();
103 // Surprisingly, calling mProxy->fence() here appears to make no difference to
104 // the timings we record.
105 }
106
fence()107 void fence() {
108 mProxy->fence();
109 }
110
capturePixels(SkBitmap * bmp)111 bool capturePixels(SkBitmap* bmp) {
112 sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeSRGB();
113 SkImageInfo destinationConfig =
114 SkImageInfo::Make(mSize.width(), mSize.height(),
115 kRGBA_8888_SkColorType, kPremul_SkAlphaType, colorSpace);
116 bmp->allocPixels(destinationConfig);
117 android_memset32((uint32_t*) bmp->getPixels(), SK_ColorRED,
118 mSize.width() * mSize.height() * 4);
119
120 android::CpuConsumer::LockedBuffer nativeBuffer;
121 android::status_t retval = mCpuConsumer->lockNextBuffer(&nativeBuffer);
122 if (retval == android::BAD_VALUE) {
123 SkDebugf("write_canvas_png() got no buffer; returning transparent");
124 // No buffer ready to read - commonly triggered by dm sending us
125 // a no-op source, or calling code that doesn't do anything on this
126 // backend.
127 bmp->eraseColor(SK_ColorTRANSPARENT);
128 return false;
129 } else if (retval) {
130 SkDebugf("Failed to lock buffer to read pixels: %d.", retval);
131 return false;
132 }
133
134 // Move the pixels into the destination SkBitmap
135
136 LOG_ALWAYS_FATAL_IF(nativeBuffer.format != android::PIXEL_FORMAT_RGBA_8888,
137 "Native buffer not RGBA!");
138 SkImageInfo nativeConfig =
139 SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
140 kRGBA_8888_SkColorType, kPremul_SkAlphaType);
141
142 // Android stride is in pixels, Skia stride is in bytes
143 SkBitmap nativeWrapper;
144 bool success =
145 nativeWrapper.installPixels(nativeConfig, nativeBuffer.data, nativeBuffer.stride * 4);
146 if (!success) {
147 SkDebugf("Failed to wrap HWUI buffer in a SkBitmap");
148 return false;
149 }
150
151 LOG_ALWAYS_FATAL_IF(bmp->colorType() != kRGBA_8888_SkColorType,
152 "Destination buffer not RGBA!");
153 success =
154 nativeWrapper.readPixels(destinationConfig, bmp->getPixels(), bmp->rowBytes(), 0, 0);
155 if (!success) {
156 SkDebugf("Failed to extract pixels from HWUI buffer");
157 return false;
158 }
159
160 mCpuConsumer->unlockBuffer(nativeBuffer);
161
162 return true;
163 }
164
165 private:
166
167 std::unique_ptr<android::uirenderer::RenderNode> mRootNode;
168 std::unique_ptr<android::uirenderer::renderthread::RenderProxy> mProxy;
169 std::unique_ptr<android::uirenderer::RecordingCanvas> mCanvas;
170 android::sp<android::IGraphicBufferProducer> mProducer;
171 android::sp<android::IGraphicBufferConsumer> mConsumer;
172 android::sp<android::CpuConsumer> mCpuConsumer;
173 android::sp<android::Surface> mAndroidSurface;
174 SkISize mSize;
175 };
176
177
TestWindowContext()178 TestWindowContext::TestWindowContext() :
179 mData (nullptr) { }
180
~TestWindowContext()181 TestWindowContext::~TestWindowContext() {
182 delete mData;
183 }
184
initialize(int width,int height)185 void TestWindowContext::initialize(int width, int height) {
186 mData = new TestWindowData(SkISize::Make(width, height));
187 }
188
prepareToDraw()189 SkCanvas* TestWindowContext::prepareToDraw() {
190 return mData ? mData->prepareToDraw() : nullptr;
191 }
192
finishDrawing()193 void TestWindowContext::finishDrawing() {
194 if (mData) {
195 mData->finishDrawing();
196 }
197 }
198
fence()199 void TestWindowContext::fence() {
200 if (mData) {
201 mData->fence();
202 }
203 }
204
capturePixels(SkBitmap * bmp)205 bool TestWindowContext::capturePixels(SkBitmap* bmp) {
206 return mData ? mData->capturePixels(bmp) : false;
207 }
208
209 } // namespace uirenderer
210 } // namespace android
211
212