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