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