blob: 91efa30aeee2d292b7b2782d5c45740b32ec26d2 [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"
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040019#include "IContextFactory.h"
Derek Sollenberger3d5278b2016-01-14 14:22:53 -050020#include "RecordingCanvas.h"
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040021#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
Ben Wagnered87fa22016-02-19 17:56:44 -050030#include <cutils/memory.h>
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040031
32namespace {
33
34/**
35 * Helper class for setting up android::uirenderer::renderthread::RenderProxy.
36 */
37class ContextFactory : public android::uirenderer::IContextFactory {
38public:
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
47namespace android {
48namespace 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
56class TestWindowContext::TestWindowData {
57
58public:
59
Chih-Hung Hsiehd53e3be2016-05-03 10:02:51 -070060 explicit TestWindowData(SkISize size) : mSize(size) {
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040061 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 };
John Reckab1080c2016-06-21 16:24:20 -070089 mProxy->setup(800.0f, 255 * 0.075f, 255 * 0.15f);
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040090 mProxy->setLightCenter(lightVector);
Derek Sollenberger3d5278b2016-01-14 14:22:53 -050091 mCanvas.reset(new android::uirenderer::RecordingCanvas(mSize.width(), mSize.height()));
Mike Reed834653bc2016-12-14 14:57:40 -050092
93 mCanvas->save(SaveFlags::MatrixClip); // balanced in prepareToDraw()
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040094 }
95
96 SkCanvas* prepareToDraw() {
97 //mCanvas->reset(mSize.width(), mSize.height());
Mike Reed834653bc2016-12-14 14:57:40 -050098 mCanvas->restore(); // balancing inital save in constructor
99 mCanvas->save(SaveFlags::MatrixClip);
100 mCanvas->clipRect(0, 0, mSize.width(), mSize.height(), SkClipOp::kIntersect);
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400101 return mCanvas->asSkCanvas();
102 }
103
104 void finishDrawing() {
John Reck51f2d602016-04-06 07:50:47 -0700105 mRootNode->setStagingDisplayList(mCanvas->finishRecording(), nullptr);
106 mProxy->syncAndDrawFrame(nullptr);
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400107 // Surprisingly, calling mProxy->fence() here appears to make no difference to
108 // the timings we record.
109 }
110
111 void fence() {
112 mProxy->fence();
113 }
114
115 bool capturePixels(SkBitmap* bmp) {
Mike Reedab12c1f2016-11-03 12:54:10 -0400116 sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeNamed(SkColorSpace::kSRGB_Named);
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400117 SkImageInfo destinationConfig =
118 SkImageInfo::Make(mSize.width(), mSize.height(),
Romain Guy253f2c22016-09-28 17:34:42 -0700119 kRGBA_8888_SkColorType, kPremul_SkAlphaType, colorSpace);
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400120 bmp->allocPixels(destinationConfig);
Ben Wagnered87fa22016-02-19 17:56:44 -0500121 android_memset32((uint32_t*) bmp->getPixels(), SK_ColorRED,
122 mSize.width() * mSize.height() * 4);
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400123
124 android::CpuConsumer::LockedBuffer nativeBuffer;
125 android::status_t retval = mCpuConsumer->lockNextBuffer(&nativeBuffer);
126 if (retval == android::BAD_VALUE) {
127 SkDebugf("write_canvas_png() got no buffer; returning transparent");
128 // No buffer ready to read - commonly triggered by dm sending us
129 // a no-op source, or calling code that doesn't do anything on this
130 // backend.
131 bmp->eraseColor(SK_ColorTRANSPARENT);
132 return false;
133 } else if (retval) {
134 SkDebugf("Failed to lock buffer to read pixels: %d.", retval);
135 return false;
136 }
137
138 // Move the pixels into the destination SkBitmap
139
Derek Sollenbergera3f16d42016-01-25 10:29:35 -0500140 LOG_ALWAYS_FATAL_IF(nativeBuffer.format != android::PIXEL_FORMAT_RGBA_8888,
141 "Native buffer not RGBA!");
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400142 SkImageInfo nativeConfig =
143 SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
144 kRGBA_8888_SkColorType, kPremul_SkAlphaType);
145
146 // Android stride is in pixels, Skia stride is in bytes
147 SkBitmap nativeWrapper;
148 bool success =
149 nativeWrapper.installPixels(nativeConfig, nativeBuffer.data, nativeBuffer.stride * 4);
150 if (!success) {
151 SkDebugf("Failed to wrap HWUI buffer in a SkBitmap");
152 return false;
153 }
154
Derek Sollenbergera3f16d42016-01-25 10:29:35 -0500155 LOG_ALWAYS_FATAL_IF(bmp->colorType() != kRGBA_8888_SkColorType,
156 "Destination buffer not RGBA!");
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400157 success =
158 nativeWrapper.readPixels(destinationConfig, bmp->getPixels(), bmp->rowBytes(), 0, 0);
159 if (!success) {
160 SkDebugf("Failed to extract pixels from HWUI buffer");
161 return false;
162 }
163
164 mCpuConsumer->unlockBuffer(nativeBuffer);
165
166 return true;
167 }
168
169private:
170
171 std::unique_ptr<android::uirenderer::RenderNode> mRootNode;
172 std::unique_ptr<android::uirenderer::renderthread::RenderProxy> mProxy;
Derek Sollenberger3d5278b2016-01-14 14:22:53 -0500173 std::unique_ptr<android::uirenderer::RecordingCanvas> mCanvas;
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400174 android::sp<android::IGraphicBufferProducer> mProducer;
175 android::sp<android::IGraphicBufferConsumer> mConsumer;
176 android::sp<android::CpuConsumer> mCpuConsumer;
177 android::sp<android::Surface> mAndroidSurface;
178 SkISize mSize;
179};
180
181
182TestWindowContext::TestWindowContext() :
183 mData (nullptr) { }
184
Tom Hudson58862c92015-12-10 16:46:57 -0500185TestWindowContext::~TestWindowContext() {
186 delete mData;
187}
188
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400189void TestWindowContext::initialize(int width, int height) {
190 mData = new TestWindowData(SkISize::Make(width, height));
191}
192
193SkCanvas* TestWindowContext::prepareToDraw() {
194 return mData ? mData->prepareToDraw() : nullptr;
195}
196
197void TestWindowContext::finishDrawing() {
198 if (mData) {
199 mData->finishDrawing();
200 }
201}
202
203void TestWindowContext::fence() {
204 if (mData) {
205 mData->fence();
206 }
207}
208
209bool TestWindowContext::capturePixels(SkBitmap* bmp) {
210 return mData ? mData->capturePixels(bmp) : false;
211}
212
213} // namespace uirenderer
214} // namespace android
215