TestWindowContext.cpp revision 51f2d606dcbfba3cc5b03dfea37c1304b91c232f
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 "DisplayListCanvas.h"
20#include "IContextFactory.h"
21#include "RecordingCanvas.h"
22#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
31
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
60    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(mSize.width(), mSize.height(), 800.0f,
90                             255 * 0.075f, 255 * 0.15f);
91        mProxy->setLightCenter(lightVector);
92#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
97    }
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() {
107        mRootNode->setStagingDisplayList(mCanvas->finishRecording(), nullptr);
108        mProxy->syncAndDrawFrame(nullptr);
109        // 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);
122        sk_memset32((uint32_t*) bmp->getPixels(), SK_ColorRED,
123                    mSize.width() * mSize.height());
124
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
141        LOG_ALWAYS_FATAL_IF(nativeBuffer.format != android::PIXEL_FORMAT_RGBA_8888,
142                            "Native buffer not RGBA!");
143        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
156        LOG_ALWAYS_FATAL_IF(bmp->colorType() != kRGBA_8888_SkColorType,
157                            "Destination buffer not RGBA!");
158        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;
174#if HWUI_NEW_OPS
175    std::unique_ptr<android::uirenderer::RecordingCanvas> mCanvas;
176#else
177    std::unique_ptr<android::uirenderer::DisplayListCanvas> mCanvas;
178#endif
179    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
190TestWindowContext::~TestWindowContext() {
191    delete mData;
192}
193
194void 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
221