TestWindowContext.cpp revision d53e3bed1ca4a14b2a86d53eaef6969bd043176e
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#include <cutils/memory.h>
32
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
61    explicit TestWindowData(SkISize size) : mSize(size) {
62        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 };
90        mProxy->setup(mSize.width(), mSize.height(), 800.0f,
91                             255 * 0.075f, 255 * 0.15f);
92        mProxy->setLightCenter(lightVector);
93#if HWUI_NEW_OPS
94        mCanvas.reset(new android::uirenderer::RecordingCanvas(mSize.width(), mSize.height()));
95#else
96        mCanvas.reset(new android::uirenderer::DisplayListCanvas(mSize.width(), mSize.height()));
97#endif
98    }
99
100    SkCanvas* prepareToDraw() {
101        //mCanvas->reset(mSize.width(), mSize.height());
102        mCanvas->clipRect(0, 0, mSize.width(), mSize.height(),
103                               SkRegion::Op::kReplace_Op);
104        return mCanvas->asSkCanvas();
105    }
106
107    void finishDrawing() {
108        mRootNode->setStagingDisplayList(mCanvas->finishRecording(), nullptr);
109        mProxy->syncAndDrawFrame(nullptr);
110        // Surprisingly, calling mProxy->fence() here appears to make no difference to
111        // the timings we record.
112    }
113
114    void fence() {
115        mProxy->fence();
116    }
117
118    bool capturePixels(SkBitmap* bmp) {
119        SkImageInfo destinationConfig =
120            SkImageInfo::Make(mSize.width(), mSize.height(),
121                              kRGBA_8888_SkColorType, kPremul_SkAlphaType);
122        bmp->allocPixels(destinationConfig);
123        android_memset32((uint32_t*) bmp->getPixels(), SK_ColorRED,
124                         mSize.width() * mSize.height() * 4);
125
126        android::CpuConsumer::LockedBuffer nativeBuffer;
127        android::status_t retval = mCpuConsumer->lockNextBuffer(&nativeBuffer);
128        if (retval == android::BAD_VALUE) {
129            SkDebugf("write_canvas_png() got no buffer; returning transparent");
130            // No buffer ready to read - commonly triggered by dm sending us
131            // a no-op source, or calling code that doesn't do anything on this
132            // backend.
133            bmp->eraseColor(SK_ColorTRANSPARENT);
134            return false;
135        } else if (retval) {
136            SkDebugf("Failed to lock buffer to read pixels: %d.", retval);
137            return false;
138        }
139
140        // Move the pixels into the destination SkBitmap
141
142        LOG_ALWAYS_FATAL_IF(nativeBuffer.format != android::PIXEL_FORMAT_RGBA_8888,
143                            "Native buffer not RGBA!");
144        SkImageInfo nativeConfig =
145            SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
146                              kRGBA_8888_SkColorType, kPremul_SkAlphaType);
147
148        // Android stride is in pixels, Skia stride is in bytes
149        SkBitmap nativeWrapper;
150        bool success =
151            nativeWrapper.installPixels(nativeConfig, nativeBuffer.data, nativeBuffer.stride * 4);
152        if (!success) {
153            SkDebugf("Failed to wrap HWUI buffer in a SkBitmap");
154            return false;
155        }
156
157        LOG_ALWAYS_FATAL_IF(bmp->colorType() != kRGBA_8888_SkColorType,
158                            "Destination buffer not RGBA!");
159        success =
160            nativeWrapper.readPixels(destinationConfig, bmp->getPixels(), bmp->rowBytes(), 0, 0);
161        if (!success) {
162            SkDebugf("Failed to extract pixels from HWUI buffer");
163            return false;
164        }
165
166        mCpuConsumer->unlockBuffer(nativeBuffer);
167
168        return true;
169    }
170
171private:
172
173    std::unique_ptr<android::uirenderer::RenderNode> mRootNode;
174    std::unique_ptr<android::uirenderer::renderthread::RenderProxy> mProxy;
175#if HWUI_NEW_OPS
176    std::unique_ptr<android::uirenderer::RecordingCanvas> mCanvas;
177#else
178    std::unique_ptr<android::uirenderer::DisplayListCanvas> mCanvas;
179#endif
180    android::sp<android::IGraphicBufferProducer> mProducer;
181    android::sp<android::IGraphicBufferConsumer> mConsumer;
182    android::sp<android::CpuConsumer> mCpuConsumer;
183    android::sp<android::Surface> mAndroidSurface;
184    SkISize mSize;
185};
186
187
188TestWindowContext::TestWindowContext() :
189    mData (nullptr) { }
190
191TestWindowContext::~TestWindowContext() {
192    delete mData;
193}
194
195void TestWindowContext::initialize(int width, int height)  {
196    mData = new TestWindowData(SkISize::Make(width, height));
197}
198
199SkCanvas* TestWindowContext::prepareToDraw() {
200    return mData ? mData->prepareToDraw() : nullptr;
201}
202
203void TestWindowContext::finishDrawing() {
204    if (mData) {
205        mData->finishDrawing();
206    }
207}
208
209void TestWindowContext::fence() {
210    if (mData) {
211        mData->fence();
212    }
213}
214
215bool TestWindowContext::capturePixels(SkBitmap* bmp) {
216    return mData ? mData->capturePixels(bmp) : false;
217}
218
219} // namespace uirenderer
220} // namespace android
221
222