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: 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: 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 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 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 100 void fence() { mProxy->fence(); } 101 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 166 TestWindowContext::TestWindowContext() : mData(nullptr) {} 167 168 TestWindowContext::~TestWindowContext() { 169 delete mData; 170 } 171 172 void TestWindowContext::initialize(int width, int height) { 173 mData = new TestWindowData(SkISize::Make(width, height)); 174 } 175 176 SkCanvas* TestWindowContext::prepareToDraw() { 177 return mData ? mData->prepareToDraw() : nullptr; 178 } 179 180 void TestWindowContext::finishDrawing() { 181 if (mData) { 182 mData->finishDrawing(); 183 } 184 } 185 186 void TestWindowContext::fence() { 187 if (mData) { 188 mData->fence(); 189 } 190 } 191 192 bool TestWindowContext::capturePixels(SkBitmap* bmp) { 193 return mData ? mData->capturePixels(bmp) : false; 194 } 195 196 } // namespace uirenderer 197 } // namespace android 198