blob: e0b2593323b2034ffed7554482b042517d2f554f [file] [log] [blame]
Tom Hudsonb2f5bd22015-10-15 16:41:55 -04001/*
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 "DisplayListCanvas.h"
20#include "IContextFactory.h"
Derek Sollenberger3d5278b2016-01-14 14:22:53 -050021#include "RecordingCanvas.h"
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040022#include "RenderNode.h"
23#include "SkTypes.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
Ben Wagnered87fa22016-02-19 17:56:44 -050031#include <cutils/memory.h>
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040032
33namespace {
34
35/**
36 * Helper class for setting up android::uirenderer::renderthread::RenderProxy.
37 */
38class ContextFactory : public android::uirenderer::IContextFactory {
39public:
40 android::uirenderer::AnimationContext* createAnimationContext
41 (android::uirenderer::renderthread::TimeLord& clock) override {
42 return new android::uirenderer::AnimationContext(clock);
43 }
44};
45
46} // anonymous namespace
47
48namespace android {
49namespace uirenderer {
50
51/**
52 Android strong pointers (android::sp) can't hold forward-declared classes,
53 so we have to use pointer-to-implementation here if we want to hide the
54 details from our non-framework users.
55*/
56
57class TestWindowContext::TestWindowData {
58
59public:
60
Chih-Hung Hsiehd53e3be2016-05-03 10:02:51 -070061 explicit TestWindowData(SkISize size) : mSize(size) {
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040062 android::BufferQueue::createBufferQueue(&mProducer, &mConsumer);
63 mCpuConsumer = new android::CpuConsumer(mConsumer, 1);
64 mCpuConsumer->setName(android::String8("TestWindowContext"));
65 mCpuConsumer->setDefaultBufferSize(mSize.width(), mSize.height());
66 mAndroidSurface = new android::Surface(mProducer);
67 native_window_set_buffers_dimensions(mAndroidSurface.get(),
68 mSize.width(), mSize.height());
69 native_window_set_buffers_format(mAndroidSurface.get(),
70 android::PIXEL_FORMAT_RGBA_8888);
71 native_window_set_usage(mAndroidSurface.get(),
72 GRALLOC_USAGE_SW_READ_OFTEN |
73 GRALLOC_USAGE_SW_WRITE_NEVER |
74 GRALLOC_USAGE_HW_RENDER);
75 mRootNode.reset(new android::uirenderer::RenderNode());
76 mRootNode->incStrong(nullptr);
77 mRootNode->mutateStagingProperties().setLeftTopRightBottom
78 (0, 0, mSize.width(), mSize.height());
79 mRootNode->mutateStagingProperties().setClipToBounds(false);
80 mRootNode->setPropertyFieldsDirty(android::uirenderer::RenderNode::GENERIC);
81 ContextFactory factory;
82 mProxy.reset
83 (new android::uirenderer::renderthread::RenderProxy(false,
84 mRootNode.get(),
85 &factory));
86 mProxy->loadSystemProperties();
87 mProxy->initialize(mAndroidSurface.get());
88 float lightX = mSize.width() / 2.0f;
89 android::uirenderer::Vector3 lightVector { lightX, -200.0f, 800.0f };
John Reckab1080c2016-06-21 16:24:20 -070090 mProxy->setup(800.0f, 255 * 0.075f, 255 * 0.15f);
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040091 mProxy->setLightCenter(lightVector);
Derek Sollenberger3d5278b2016-01-14 14:22:53 -050092#if HWUI_NEW_OPS
93 mCanvas.reset(new android::uirenderer::RecordingCanvas(mSize.width(), mSize.height()));
94#else
95 mCanvas.reset(new android::uirenderer::DisplayListCanvas(mSize.width(), mSize.height()));
96#endif
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040097 }
98
99 SkCanvas* prepareToDraw() {
100 //mCanvas->reset(mSize.width(), mSize.height());
101 mCanvas->clipRect(0, 0, mSize.width(), mSize.height(),
102 SkRegion::Op::kReplace_Op);
103 return mCanvas->asSkCanvas();
104 }
105
106 void finishDrawing() {
John Reck51f2d602016-04-06 07:50:47 -0700107 mRootNode->setStagingDisplayList(mCanvas->finishRecording(), nullptr);
108 mProxy->syncAndDrawFrame(nullptr);
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400109 // Surprisingly, calling mProxy->fence() here appears to make no difference to
110 // the timings we record.
111 }
112
113 void fence() {
114 mProxy->fence();
115 }
116
117 bool capturePixels(SkBitmap* bmp) {
118 SkImageInfo destinationConfig =
119 SkImageInfo::Make(mSize.width(), mSize.height(),
120 kRGBA_8888_SkColorType, kPremul_SkAlphaType);
121 bmp->allocPixels(destinationConfig);
Ben Wagnered87fa22016-02-19 17:56:44 -0500122 android_memset32((uint32_t*) bmp->getPixels(), SK_ColorRED,
123 mSize.width() * mSize.height() * 4);
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400124
125 android::CpuConsumer::LockedBuffer nativeBuffer;
126 android::status_t retval = mCpuConsumer->lockNextBuffer(&nativeBuffer);
127 if (retval == android::BAD_VALUE) {
128 SkDebugf("write_canvas_png() got no buffer; returning transparent");
129 // No buffer ready to read - commonly triggered by dm sending us
130 // a no-op source, or calling code that doesn't do anything on this
131 // backend.
132 bmp->eraseColor(SK_ColorTRANSPARENT);
133 return false;
134 } else if (retval) {
135 SkDebugf("Failed to lock buffer to read pixels: %d.", retval);
136 return false;
137 }
138
139 // Move the pixels into the destination SkBitmap
140
Derek Sollenbergera3f16d42016-01-25 10:29:35 -0500141 LOG_ALWAYS_FATAL_IF(nativeBuffer.format != android::PIXEL_FORMAT_RGBA_8888,
142 "Native buffer not RGBA!");
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400143 SkImageInfo nativeConfig =
144 SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
145 kRGBA_8888_SkColorType, kPremul_SkAlphaType);
146
147 // Android stride is in pixels, Skia stride is in bytes
148 SkBitmap nativeWrapper;
149 bool success =
150 nativeWrapper.installPixels(nativeConfig, nativeBuffer.data, nativeBuffer.stride * 4);
151 if (!success) {
152 SkDebugf("Failed to wrap HWUI buffer in a SkBitmap");
153 return false;
154 }
155
Derek Sollenbergera3f16d42016-01-25 10:29:35 -0500156 LOG_ALWAYS_FATAL_IF(bmp->colorType() != kRGBA_8888_SkColorType,
157 "Destination buffer not RGBA!");
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400158 success =
159 nativeWrapper.readPixels(destinationConfig, bmp->getPixels(), bmp->rowBytes(), 0, 0);
160 if (!success) {
161 SkDebugf("Failed to extract pixels from HWUI buffer");
162 return false;
163 }
164
165 mCpuConsumer->unlockBuffer(nativeBuffer);
166
167 return true;
168 }
169
170private:
171
172 std::unique_ptr<android::uirenderer::RenderNode> mRootNode;
173 std::unique_ptr<android::uirenderer::renderthread::RenderProxy> mProxy;
Derek Sollenberger3d5278b2016-01-14 14:22:53 -0500174#if HWUI_NEW_OPS
175 std::unique_ptr<android::uirenderer::RecordingCanvas> mCanvas;
176#else
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400177 std::unique_ptr<android::uirenderer::DisplayListCanvas> mCanvas;
Derek Sollenberger3d5278b2016-01-14 14:22:53 -0500178#endif
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400179 android::sp<android::IGraphicBufferProducer> mProducer;
180 android::sp<android::IGraphicBufferConsumer> mConsumer;
181 android::sp<android::CpuConsumer> mCpuConsumer;
182 android::sp<android::Surface> mAndroidSurface;
183 SkISize mSize;
184};
185
186
187TestWindowContext::TestWindowContext() :
188 mData (nullptr) { }
189
Tom Hudson58862c92015-12-10 16:46:57 -0500190TestWindowContext::~TestWindowContext() {
191 delete mData;
192}
193
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400194void TestWindowContext::initialize(int width, int height) {
195 mData = new TestWindowData(SkISize::Make(width, height));
196}
197
198SkCanvas* TestWindowContext::prepareToDraw() {
199 return mData ? mData->prepareToDraw() : nullptr;
200}
201
202void TestWindowContext::finishDrawing() {
203 if (mData) {
204 mData->finishDrawing();
205 }
206}
207
208void TestWindowContext::fence() {
209 if (mData) {
210 mData->fence();
211 }
212}
213
214bool TestWindowContext::capturePixels(SkBitmap* bmp) {
215 return mData ? mData->capturePixels(bmp) : false;
216}
217
218} // namespace uirenderer
219} // namespace android
220