Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 64bb63f0 authored by Tom Hudson's avatar Tom Hudson Committed by Android (Google) Code Review
Browse files

Merge "Remove direct dependency of external/skia on frameworks/native"

parents 342b89e2 b2f5bd2d
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ hwui_src_files := \
    utils/LinearAllocator.cpp \
    utils/NinePatchImpl.cpp \
    utils/StringUtils.cpp \
    utils/TestWindowContext.cpp \
    AmbientShadow.cpp \
    AnimationContext.cpp \
    Animator.cpp \
+209 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#include "TestWindowContext.h"

#include "AnimationContext.h"
#include "DisplayListCanvas.h"
#include "IContextFactory.h"
#include "RenderNode.h"
#include "SkTypes.h"
#include "gui/BufferQueue.h"
#include "gui/CpuConsumer.h"
#include "gui/IGraphicBufferConsumer.h"
#include "gui/IGraphicBufferProducer.h"
#include "gui/Surface.h"
#include "renderthread/RenderProxy.h"


namespace {

/**
 * Helper class for setting up android::uirenderer::renderthread::RenderProxy.
 */
class ContextFactory : public android::uirenderer::IContextFactory {
public:
    android::uirenderer::AnimationContext* createAnimationContext
        (android::uirenderer::renderthread::TimeLord& clock) override {
        return new android::uirenderer::AnimationContext(clock);
    }
};

} // anonymous namespace

namespace android {
namespace uirenderer {

/**
  Android strong pointers (android::sp) can't hold forward-declared classes,
  so we have to use pointer-to-implementation here if we want to hide the
  details from our non-framework users.
*/

class TestWindowContext::TestWindowData {

public:

    TestWindowData(SkISize size) : mSize(size) {
        android::BufferQueue::createBufferQueue(&mProducer, &mConsumer);
        mCpuConsumer = new android::CpuConsumer(mConsumer, 1);
        mCpuConsumer->setName(android::String8("TestWindowContext"));
        mCpuConsumer->setDefaultBufferSize(mSize.width(), mSize.height());
        mAndroidSurface = new android::Surface(mProducer);
        native_window_set_buffers_dimensions(mAndroidSurface.get(),
                                             mSize.width(), mSize.height());
        native_window_set_buffers_format(mAndroidSurface.get(),
                                         android::PIXEL_FORMAT_RGBA_8888);
        native_window_set_usage(mAndroidSurface.get(),
                                GRALLOC_USAGE_SW_READ_OFTEN |
                                GRALLOC_USAGE_SW_WRITE_NEVER |
                                GRALLOC_USAGE_HW_RENDER);
        mRootNode.reset(new android::uirenderer::RenderNode());
        mRootNode->incStrong(nullptr);
        mRootNode->mutateStagingProperties().setLeftTopRightBottom
            (0, 0, mSize.width(), mSize.height());
        mRootNode->mutateStagingProperties().setClipToBounds(false);
        mRootNode->setPropertyFieldsDirty(android::uirenderer::RenderNode::GENERIC);
        ContextFactory factory;
        mProxy.reset
            (new android::uirenderer::renderthread::RenderProxy(false,
                                                                mRootNode.get(),
                                                                &factory));
        mProxy->loadSystemProperties();
        mProxy->initialize(mAndroidSurface.get());
        float lightX = mSize.width() / 2.0f;
        android::uirenderer::Vector3 lightVector { lightX, -200.0f, 800.0f };
        mProxy->setup(mSize.width(), mSize.height(), 800.0f,
                             255 * 0.075f, 255 * 0.15f);
        mProxy->setLightCenter(lightVector);
        mCanvas.reset(new
            android::uirenderer::DisplayListCanvas(mSize.width(),
                                                   mSize.height()));
    }

    SkCanvas* prepareToDraw() {
        //mCanvas->reset(mSize.width(), mSize.height());
        mCanvas->clipRect(0, 0, mSize.width(), mSize.height(),
                               SkRegion::Op::kReplace_Op);
        return mCanvas->asSkCanvas();
    }

    void finishDrawing() {
        mRootNode->setStagingDisplayList(mCanvas->finishRecording());
        mProxy->syncAndDrawFrame();
        // Surprisingly, calling mProxy->fence() here appears to make no difference to
        // the timings we record.
    }

    void fence() {
        mProxy->fence();
    }

    bool capturePixels(SkBitmap* bmp) {
        SkImageInfo destinationConfig =
            SkImageInfo::Make(mSize.width(), mSize.height(),
                              kRGBA_8888_SkColorType, kPremul_SkAlphaType);
        bmp->allocPixels(destinationConfig);
        sk_memset32((uint32_t*) bmp->getPixels(), SK_ColorRED,
                    mSize.width() * mSize.height());

        android::CpuConsumer::LockedBuffer nativeBuffer;
        android::status_t retval = mCpuConsumer->lockNextBuffer(&nativeBuffer);
        if (retval == android::BAD_VALUE) {
            SkDebugf("write_canvas_png() got no buffer; returning transparent");
            // No buffer ready to read - commonly triggered by dm sending us
            // a no-op source, or calling code that doesn't do anything on this
            // backend.
            bmp->eraseColor(SK_ColorTRANSPARENT);
            return false;
        } else if (retval) {
            SkDebugf("Failed to lock buffer to read pixels: %d.", retval);
            return false;
        }

        // Move the pixels into the destination SkBitmap

        SK_ALWAYSBREAK(nativeBuffer.format == android::PIXEL_FORMAT_RGBA_8888 &&
                       "Native buffer not RGBA!");
        SkImageInfo nativeConfig =
            SkImageInfo::Make(nativeBuffer.width, nativeBuffer.height,
                              kRGBA_8888_SkColorType, kPremul_SkAlphaType);

        // Android stride is in pixels, Skia stride is in bytes
        SkBitmap nativeWrapper;
        bool success =
            nativeWrapper.installPixels(nativeConfig, nativeBuffer.data, nativeBuffer.stride * 4);
        if (!success) {
            SkDebugf("Failed to wrap HWUI buffer in a SkBitmap");
            return false;
        }

        SK_ALWAYSBREAK(bmp->colorType() == kRGBA_8888_SkColorType &&
                       "Destination buffer not RGBA!");
        success =
            nativeWrapper.readPixels(destinationConfig, bmp->getPixels(), bmp->rowBytes(), 0, 0);
        if (!success) {
            SkDebugf("Failed to extract pixels from HWUI buffer");
            return false;
        }

        mCpuConsumer->unlockBuffer(nativeBuffer);

        return true;
    }

private:

    std::unique_ptr<android::uirenderer::RenderNode> mRootNode;
    std::unique_ptr<android::uirenderer::renderthread::RenderProxy> mProxy;
    std::unique_ptr<android::uirenderer::DisplayListCanvas> mCanvas;
    android::sp<android::IGraphicBufferProducer> mProducer;
    android::sp<android::IGraphicBufferConsumer> mConsumer;
    android::sp<android::CpuConsumer> mCpuConsumer;
    android::sp<android::Surface> mAndroidSurface;
    SkISize mSize;
};


TestWindowContext::TestWindowContext() :
    mData (nullptr) { }

void TestWindowContext::initialize(int width, int height)  {
    mData = new TestWindowData(SkISize::Make(width, height));
}

SkCanvas* TestWindowContext::prepareToDraw() {
    return mData ? mData->prepareToDraw() : nullptr;
}

void TestWindowContext::finishDrawing() {
    if (mData) {
        mData->finishDrawing();
    }
}

void TestWindowContext::fence() {
    if (mData) {
        mData->fence();
    }
}

bool TestWindowContext::capturePixels(SkBitmap* bmp) {
    return mData ? mData->capturePixels(bmp) : false;
}

} // namespace uirenderer
} // namespace android
+67 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2015 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
#ifndef TESTWINDOWCONTEXT_H_
#define TESTWINDOWCONTEXT_H_

#include <cutils/compiler.h>

class SkBitmap;
class SkCanvas;

namespace android {

namespace uirenderer {

/**
  Wraps all libui/libgui classes and types that external tests depend on,
  exposing only primitive Skia types.
*/

class ANDROID_API TestWindowContext {

public:

    TestWindowContext();

    /// We need to know the size of the window.
    void initialize(int width, int height);

    /// Returns a canvas to draw into; NULL if not yet initialize()d.
    SkCanvas* prepareToDraw();

    /// Flushes all drawing commands to HWUI; no-op if not yet initialize()d.
    void finishDrawing();

    /// Blocks until HWUI has processed all pending drawing commands;
    /// no-op if not yet initialize()d.
    void fence();

    /// Returns false if not yet initialize()d.
    bool capturePixels(SkBitmap* bmp);

private:
    /// Hidden implementation.
    class TestWindowData;

    TestWindowData* mData;

};

}  // namespace uirenderer
}  // namespace android

#endif  // TESTWINDOWCONTEXT_H_