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