• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "IContextFactory.h"
20 #include "RecordingCanvas.h"
21 #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 
30 #include <cutils/memory.h>
31 
32 namespace {
33 
34 /**
35  * Helper class for setting up android::uirenderer::renderthread::RenderProxy.
36  */
37 class ContextFactory : public android::uirenderer::IContextFactory {
38 public:
createAnimationContext(android::uirenderer::renderthread::TimeLord & clock)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 
47 namespace android {
48 namespace 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 
56 class TestWindowContext::TestWindowData {
57 public:
TestWindowData(SkISize size)58     explicit TestWindowData(SkISize size) : mSize(size) {
59         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);
64         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);
69         mRootNode.reset(new android::uirenderer::RenderNode());
70         mRootNode->incStrong(nullptr);
71         mRootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, mSize.width(),
72                                                                    mSize.height());
73         mRootNode->mutateStagingProperties().setClipToBounds(false);
74         mRootNode->setPropertyFieldsDirty(android::uirenderer::RenderNode::GENERIC);
75         ContextFactory factory;
76         mProxy.reset(new android::uirenderer::renderthread::RenderProxy(false, mRootNode.get(),
77                                                                         &factory));
78         mProxy->loadSystemProperties();
79         mProxy->initialize(mAndroidSurface.get());
80         float lightX = mSize.width() / 2.0f;
81         android::uirenderer::Vector3 lightVector{lightX, -200.0f, 800.0f};
82         mProxy->setup(800.0f, 255 * 0.075f, 255 * 0.15f);
83         mProxy->setLightCenter(lightVector);
84         mCanvas.reset(new android::uirenderer::RecordingCanvas(mSize.width(), mSize.height()));
85     }
86 
prepareToDraw()87     SkCanvas* prepareToDraw() {
88         // mCanvas->reset(mSize.width(), mSize.height());
89         mCanvas->clipRect(0, 0, mSize.width(), mSize.height(), SkClipOp::kReplace_deprecated);
90         return mCanvas->asSkCanvas();
91     }
92 
finishDrawing()93     void finishDrawing() {
94         mRootNode->setStagingDisplayList(mCanvas->finishRecording());
95         mProxy->syncAndDrawFrame();
96         // Surprisingly, calling mProxy->fence() here appears to make no difference to
97         // the timings we record.
98     }
99 
fence()100     void fence() { mProxy->fence(); }
101 
capturePixels(SkBitmap * bmp)102     bool capturePixels(SkBitmap* bmp) {
103         sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeSRGB();
104         SkImageInfo destinationConfig =
105                 SkImageInfo::Make(mSize.width(), mSize.height(), kRGBA_8888_SkColorType,
106                                   kPremul_SkAlphaType, colorSpace);
107         bmp->allocPixels(destinationConfig);
108         android_memset32((uint32_t*)bmp->getPixels(), SK_ColorRED,
109                          mSize.width() * mSize.height() * 4);
110 
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 
127         LOG_ALWAYS_FATAL_IF(nativeBuffer.format != android::PIXEL_FORMAT_RGBA_8888,
128                             "Native buffer not RGBA!");
129         SkImageInfo nativeConfig = SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
130                                                      kRGBA_8888_SkColorType, kPremul_SkAlphaType);
131 
132         // Android stride is in pixels, Skia stride is in bytes
133         SkBitmap nativeWrapper;
134         bool success = nativeWrapper.installPixels(nativeConfig, nativeBuffer.data,
135                                                    nativeBuffer.stride * 4);
136         if (!success) {
137             SkDebugf("Failed to wrap HWUI buffer in a SkBitmap");
138             return false;
139         }
140 
141         LOG_ALWAYS_FATAL_IF(bmp->colorType() != kRGBA_8888_SkColorType,
142                             "Destination buffer not RGBA!");
143         success = nativeWrapper.readPixels(destinationConfig, bmp->getPixels(), bmp->rowBytes(), 0,
144                                            0);
145         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 
155 private:
156     std::unique_ptr<android::uirenderer::RenderNode> mRootNode;
157     std::unique_ptr<android::uirenderer::renderthread::RenderProxy> mProxy;
158     std::unique_ptr<android::uirenderer::RecordingCanvas> mCanvas;
159     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 
TestWindowContext()166 TestWindowContext::TestWindowContext() : mData(nullptr) {}
167 
~TestWindowContext()168 TestWindowContext::~TestWindowContext() {
169     delete mData;
170 }
171 
initialize(int width,int height)172 void TestWindowContext::initialize(int width, int height) {
173     mData = new TestWindowData(SkISize::Make(width, height));
174 }
175 
prepareToDraw()176 SkCanvas* TestWindowContext::prepareToDraw() {
177     return mData ? mData->prepareToDraw() : nullptr;
178 }
179 
finishDrawing()180 void TestWindowContext::finishDrawing() {
181     if (mData) {
182         mData->finishDrawing();
183     }
184 }
185 
fence()186 void TestWindowContext::fence() {
187     if (mData) {
188         mData->fence();
189     }
190 }
191 
capturePixels(SkBitmap * bmp)192 bool TestWindowContext::capturePixels(SkBitmap* bmp) {
193     return mData ? mData->capturePixels(bmp) : false;
194 }
195 
196 }  // namespace uirenderer
197 }  // namespace android
198