• 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 "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 
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     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 
prepareToDraw()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 
finishDrawing()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 
fence()113     void fence() {
114         mProxy->fence();
115     }
116 
capturePixels(SkBitmap * bmp)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 
170 private:
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 
TestWindowContext()187 TestWindowContext::TestWindowContext() :
188     mData (nullptr) { }
189 
~TestWindowContext()190 TestWindowContext::~TestWindowContext() {
191     delete mData;
192 }
193 
initialize(int width,int height)194 void TestWindowContext::initialize(int width, int height)  {
195     mData = new TestWindowData(SkISize::Make(width, height));
196 }
197 
prepareToDraw()198 SkCanvas* TestWindowContext::prepareToDraw() {
199     return mData ? mData->prepareToDraw() : nullptr;
200 }
201 
finishDrawing()202 void TestWindowContext::finishDrawing() {
203     if (mData) {
204         mData->finishDrawing();
205     }
206 }
207 
fence()208 void TestWindowContext::fence() {
209     if (mData) {
210         mData->fence();
211     }
212 }
213 
capturePixels(SkBitmap * bmp)214 bool TestWindowContext::capturePixels(SkBitmap* bmp) {
215     return mData ? mData->capturePixels(bmp) : false;
216 }
217 
218 } // namespace uirenderer
219 } // namespace android
220 
221