blob: 8ac6e1f2d39a66705bde091d9bb12af741c02fe1 [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"
20#include "RenderNode.h"
21#include "SkTypes.h"
22#include "gui/BufferQueue.h"
23#include "gui/CpuConsumer.h"
24#include "gui/IGraphicBufferConsumer.h"
25#include "gui/IGraphicBufferProducer.h"
26#include "gui/Surface.h"
John Reckd9d7f122018-05-03 14:40:56 -070027#include "hwui/Canvas.h"
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040028#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:
John Reck1bcacfd2017-11-03 10:12:19 -070039 android::uirenderer::AnimationContext* createAnimationContext(
40 android::uirenderer::renderthread::TimeLord& clock) override {
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040041 return new android::uirenderer::AnimationContext(clock);
42 }
43};
44
John Reck1bcacfd2017-11-03 10:12:19 -070045} // anonymous namespace
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040046
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 {
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040057public:
Chih-Hung Hsiehd53e3be2016-05-03 10:02:51 -070058 explicit TestWindowData(SkISize size) : mSize(size) {
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040059 android::BufferQueue::createBufferQueue(&mProducer, &mConsumer);
60 mCpuConsumer = new android::CpuConsumer(mConsumer, 1);
61 mCpuConsumer->setName(android::String8("TestWindowContext"));
62 mCpuConsumer->setDefaultBufferSize(mSize.width(), mSize.height());
63 mAndroidSurface = new android::Surface(mProducer);
John Reck1bcacfd2017-11-03 10:12:19 -070064 native_window_set_buffers_dimensions(mAndroidSurface.get(), mSize.width(), mSize.height());
65 native_window_set_buffers_format(mAndroidSurface.get(), android::PIXEL_FORMAT_RGBA_8888);
66 native_window_set_usage(mAndroidSurface.get(), GRALLOC_USAGE_SW_READ_OFTEN |
67 GRALLOC_USAGE_SW_WRITE_NEVER |
68 GRALLOC_USAGE_HW_RENDER);
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040069 mRootNode.reset(new android::uirenderer::RenderNode());
70 mRootNode->incStrong(nullptr);
John Reck1bcacfd2017-11-03 10:12:19 -070071 mRootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, mSize.width(),
72 mSize.height());
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040073 mRootNode->mutateStagingProperties().setClipToBounds(false);
74 mRootNode->setPropertyFieldsDirty(android::uirenderer::RenderNode::GENERIC);
75 ContextFactory factory;
John Reck1bcacfd2017-11-03 10:12:19 -070076 mProxy.reset(new android::uirenderer::renderthread::RenderProxy(false, mRootNode.get(),
77 &factory));
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040078 mProxy->loadSystemProperties();
79 mProxy->initialize(mAndroidSurface.get());
80 float lightX = mSize.width() / 2.0f;
John Reck1bcacfd2017-11-03 10:12:19 -070081 android::uirenderer::Vector3 lightVector{lightX, -200.0f, 800.0f};
John Reckab1080c2016-06-21 16:24:20 -070082 mProxy->setup(800.0f, 255 * 0.075f, 255 * 0.15f);
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040083 mProxy->setLightCenter(lightVector);
John Reckd9d7f122018-05-03 14:40:56 -070084 mCanvas.reset(Canvas::create_recording_canvas(mSize.width(), mSize.height(), mRootNode.get()));
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040085 }
86
87 SkCanvas* prepareToDraw() {
John Reck1bcacfd2017-11-03 10:12:19 -070088 // mCanvas->reset(mSize.width(), mSize.height());
Mike Reeda0a74d52017-03-13 13:26:00 -040089 mCanvas->clipRect(0, 0, mSize.width(), mSize.height(), SkClipOp::kReplace_deprecated);
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040090 return mCanvas->asSkCanvas();
91 }
92
93 void finishDrawing() {
John Reck2de950d2017-01-25 10:58:30 -080094 mRootNode->setStagingDisplayList(mCanvas->finishRecording());
95 mProxy->syncAndDrawFrame();
Tom Hudsonb2f5bd22015-10-15 16:41:55 -040096 // Surprisingly, calling mProxy->fence() here appears to make no difference to
97 // the timings we record.
98 }
99
John Reck1bcacfd2017-11-03 10:12:19 -0700100 void fence() { mProxy->fence(); }
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400101
102 bool capturePixels(SkBitmap* bmp) {
Matt Sarett89ddb1f2017-02-10 13:31:56 -0500103 sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeSRGB();
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400104 SkImageInfo destinationConfig =
John Reck1bcacfd2017-11-03 10:12:19 -0700105 SkImageInfo::Make(mSize.width(), mSize.height(), kRGBA_8888_SkColorType,
106 kPremul_SkAlphaType, colorSpace);
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400107 bmp->allocPixels(destinationConfig);
John Reck1bcacfd2017-11-03 10:12:19 -0700108 android_memset32((uint32_t*)bmp->getPixels(), SK_ColorRED,
Ben Wagnered87fa22016-02-19 17:56:44 -0500109 mSize.width() * mSize.height() * 4);
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400110
111 android::CpuConsumer::LockedBuffer nativeBuffer;
112 android::status_t retval = mCpuConsumer->lockNextBuffer(&nativeBuffer);
113 if (retval == android::BAD_VALUE) {
114 SkDebugf("write_canvas_png() got no buffer; returning transparent");
115 // No buffer ready to read - commonly triggered by dm sending us
116 // a no-op source, or calling code that doesn't do anything on this
117 // backend.
118 bmp->eraseColor(SK_ColorTRANSPARENT);
119 return false;
120 } else if (retval) {
121 SkDebugf("Failed to lock buffer to read pixels: %d.", retval);
122 return false;
123 }
124
125 // Move the pixels into the destination SkBitmap
126
Derek Sollenbergera3f16d42016-01-25 10:29:35 -0500127 LOG_ALWAYS_FATAL_IF(nativeBuffer.format != android::PIXEL_FORMAT_RGBA_8888,
128 "Native buffer not RGBA!");
John Reck1bcacfd2017-11-03 10:12:19 -0700129 SkImageInfo nativeConfig = SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
130 kRGBA_8888_SkColorType, kPremul_SkAlphaType);
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400131
132 // Android stride is in pixels, Skia stride is in bytes
133 SkBitmap nativeWrapper;
John Reck1bcacfd2017-11-03 10:12:19 -0700134 bool success = nativeWrapper.installPixels(nativeConfig, nativeBuffer.data,
135 nativeBuffer.stride * 4);
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400136 if (!success) {
137 SkDebugf("Failed to wrap HWUI buffer in a SkBitmap");
138 return false;
139 }
140
Derek Sollenbergera3f16d42016-01-25 10:29:35 -0500141 LOG_ALWAYS_FATAL_IF(bmp->colorType() != kRGBA_8888_SkColorType,
142 "Destination buffer not RGBA!");
John Reck1bcacfd2017-11-03 10:12:19 -0700143 success = nativeWrapper.readPixels(destinationConfig, bmp->getPixels(), bmp->rowBytes(), 0,
144 0);
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400145 if (!success) {
146 SkDebugf("Failed to extract pixels from HWUI buffer");
147 return false;
148 }
149
150 mCpuConsumer->unlockBuffer(nativeBuffer);
151
152 return true;
153 }
154
155private:
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400156 std::unique_ptr<android::uirenderer::RenderNode> mRootNode;
157 std::unique_ptr<android::uirenderer::renderthread::RenderProxy> mProxy;
John Reckd9d7f122018-05-03 14:40:56 -0700158 std::unique_ptr<android::Canvas> mCanvas;
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400159 android::sp<android::IGraphicBufferProducer> mProducer;
160 android::sp<android::IGraphicBufferConsumer> mConsumer;
161 android::sp<android::CpuConsumer> mCpuConsumer;
162 android::sp<android::Surface> mAndroidSurface;
163 SkISize mSize;
164};
165
John Reck1bcacfd2017-11-03 10:12:19 -0700166TestWindowContext::TestWindowContext() : mData(nullptr) {}
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400167
Tom Hudson58862c92015-12-10 16:46:57 -0500168TestWindowContext::~TestWindowContext() {
169 delete mData;
170}
171
John Reck1bcacfd2017-11-03 10:12:19 -0700172void TestWindowContext::initialize(int width, int height) {
Tom Hudsonb2f5bd22015-10-15 16:41:55 -0400173 mData = new TestWindowData(SkISize::Make(width, height));
174}
175
176SkCanvas* TestWindowContext::prepareToDraw() {
177 return mData ? mData->prepareToDraw() : nullptr;
178}
179
180void TestWindowContext::finishDrawing() {
181 if (mData) {
182 mData->finishDrawing();
183 }
184}
185
186void TestWindowContext::fence() {
187 if (mData) {
188 mData->fence();
189 }
190}
191
192bool TestWindowContext::capturePixels(SkBitmap* bmp) {
193 return mData ? mData->capturePixels(bmp) : false;
194}
195
John Reck1bcacfd2017-11-03 10:12:19 -0700196} // namespace uirenderer
197} // namespace android