Home | History | Annotate | Download | only in utils
      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