a0a74d5f8e
Allows skia to remove legacy flag for older names - SK_SUPPORT_EXOTIC_CLIPOPS - SK_SUPPORT_LEGACY_CLIPOP_EXOTIC_NAMES Test: CtsGraphicsTestCases Change-Id: I78478d94d059641a9381579cae6d28f9f0685ad1
212 lines
7.6 KiB
C++
212 lines
7.6 KiB
C++
/*
|
|
* 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 "IContextFactory.h"
|
|
#include "RecordingCanvas.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"
|
|
|
|
#include <cutils/memory.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:
|
|
|
|
explicit 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(800.0f, 255 * 0.075f, 255 * 0.15f);
|
|
mProxy->setLightCenter(lightVector);
|
|
mCanvas.reset(new android::uirenderer::RecordingCanvas(mSize.width(), mSize.height()));
|
|
}
|
|
|
|
SkCanvas* prepareToDraw() {
|
|
//mCanvas->reset(mSize.width(), mSize.height());
|
|
mCanvas->clipRect(0, 0, mSize.width(), mSize.height(), SkClipOp::kReplace_deprecated);
|
|
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) {
|
|
sk_sp<SkColorSpace> colorSpace = SkColorSpace::MakeSRGB();
|
|
SkImageInfo destinationConfig =
|
|
SkImageInfo::Make(mSize.width(), mSize.height(),
|
|
kRGBA_8888_SkColorType, kPremul_SkAlphaType, colorSpace);
|
|
bmp->allocPixels(destinationConfig);
|
|
android_memset32((uint32_t*) bmp->getPixels(), SK_ColorRED,
|
|
mSize.width() * mSize.height() * 4);
|
|
|
|
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
|
|
|
|
LOG_ALWAYS_FATAL_IF(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;
|
|
}
|
|
|
|
LOG_ALWAYS_FATAL_IF(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::RecordingCanvas> 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) { }
|
|
|
|
TestWindowContext::~TestWindowContext() {
|
|
delete mData;
|
|
}
|
|
|
|
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
|
|
|