Chromium Code Reviews| Index: dm/DMSrcSinkAndroid.cpp |
| diff --git a/dm/DMSrcSinkAndroid.cpp b/dm/DMSrcSinkAndroid.cpp |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..632c163e9e563da30a5591eba14a5a475b4093f5 |
| --- /dev/null |
| +++ b/dm/DMSrcSinkAndroid.cpp |
| @@ -0,0 +1,158 @@ |
| +/* |
| + * Copyright 2015 Google Inc. |
| + * |
| + * Use of this source code is governed by a BSD-style license that can be |
| + * found in the LICENSE file. |
| + */ |
| + |
| +#include "DMSrcSink.h" |
| +#include "DMSrcSinkAndroid.h" |
| + |
| +#include "AnimationContext.h" |
| +#include "DisplayListRenderer.h" |
| +#include "IContextFactory.h" |
| +#include "RenderNode.h" |
| +#include "android/rect.h" |
|
djsollen
2015/02/23 16:30:19
do we need all of these includes?
tomhudson
2015/02/23 17:43:21
Approximately yes; I've tried removing those that
|
| +#include "android/native_window.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 "renderthread/TimeLord.h" |
| + |
| +namespace DM { |
| + |
| +/* These functions are only compiled in the Android Framework. */ |
|
mtklein
2015/02/23 16:46:09
Might wrap everything with #ifdef SK_BUILD_FOR_AND
tomhudson
2015/02/23 17:43:20
I'm torn between doing that, which is redundant wi
|
| + |
| +class ContextFactory : public android::uirenderer::IContextFactory { |
| +public: |
| + android::uirenderer::AnimationContext* createAnimationContext |
| + (android::uirenderer::renderthread::TimeLord& clock) SK_OVERRIDE { |
| + return new android::uirenderer::AnimationContext(clock); |
| + } |
| +}; |
| + |
| +Error HWUISink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const { |
| + // Do all setup in this function because we don't know the size |
| + // for the RenderNode and RenderProxy during the constructor. |
| + // In practice this doesn't seem too expensive. |
| + const SkISize size = src.size(); |
| + |
| + // Based on android::SurfaceTexture_init() |
| + android::sp<android::IGraphicBufferProducer> producer; |
| + android::sp<android::IGraphicBufferConsumer> consumer; |
| + android::BufferQueue::createBufferQueue(&producer, &consumer); |
| + |
| + // Consumer setup |
| + |
| + android::sp<android::CpuConsumer> cpuConsumer = |
| + new android::CpuConsumer(consumer, 1); |
| + cpuConsumer->setName(android::String8("SkiaTestClient")); |
| + cpuConsumer->setDefaultBufferSize(size.width(), size.height()); |
| + |
| + // Producer setup |
| + |
| + android::sp<android::Surface> surface = new android::Surface(producer); |
| + native_window_set_buffers_dimensions(surface.get(), size.width(), size.height()); |
| + native_window_set_buffers_format(surface.get(), android::PIXEL_FORMAT_RGBA_8888); |
| + native_window_set_usage(surface.get(), GRALLOC_USAGE_SW_READ_OFTEN | |
| + GRALLOC_USAGE_SW_WRITE_NEVER | |
| + GRALLOC_USAGE_HW_RENDER); |
| + |
| + // RenderNode setup based on hwui/tests/main.cpp:TreeContentAnimation |
| + SkAutoTDelete<android::uirenderer::RenderNode> rootNode |
| + (new android::uirenderer::RenderNode()); |
| + rootNode->incStrong(nullptr); |
| + |
| + // Values set here won't be applied until the framework has called |
| + // RenderNode::pushStagingPropertiesChanges() during RenderProxy::syncAndDrawFrame(). |
| + rootNode->mutateStagingProperties().setLeftTopRightBottom(0, 0, size.width(), size.height()); |
| + rootNode->setPropertyFieldsDirty(android::uirenderer::RenderNode::X | |
| + android::uirenderer::RenderNode::Y); |
| + rootNode->mutateStagingProperties().setClipToBounds(false); |
| + rootNode->setPropertyFieldsDirty(android::uirenderer::RenderNode::GENERIC); |
| + |
| + // RenderProxy setup based on hwui/tests/main.cpp:TreeContentAnimation |
| + ContextFactory factory; |
| + SkAutoTDelete<android::uirenderer::renderthread::RenderProxy> proxy |
| + (new android::uirenderer::renderthread::RenderProxy(false, rootNode, &factory)); |
| + proxy->loadSystemProperties(); |
| + |
| + proxy->initialize(surface.get()); |
| + |
| + float lightX = size.width() / 2.0f; |
| + android::uirenderer::Vector3 lightVector { lightX, dp(-200.0f), dp(800.0f) }; |
| + proxy->setup(size.width(), size.height(), lightVector, dp(800.0f), 255 * 0.075f, 255 * 0.15f, |
| + kDensity); |
| + |
| + // Do the draw |
| + |
| + SkAutoTDelete<android::uirenderer::DisplayListRenderer> renderer |
| + (new android::uirenderer::DisplayListRenderer()); |
| + renderer->setViewport(size.width(), size.height()); |
| + renderer->prepare(); |
| + renderer->clipRect(0, 0, size.width(), size.height(), SkRegion::Op::kReplace_Op); |
| + |
| + Error err = src.draw(renderer->asSkCanvas()); |
| + if (!err.isEmpty()) { |
| + return err; |
| + } |
| + |
| + renderer->finish(); |
| + rootNode->setStagingDisplayList(renderer->finishRecording()); |
| + |
| + proxy->syncAndDrawFrame(); |
| + proxy->fence(); |
| + |
| + // Capture pixels |
| + |
| + SkImageInfo destinationConfig = |
| + SkImageInfo::Make(size.width(), size.height(), |
| + kRGBA_8888_SkColorType, kPremul_SkAlphaType); |
| + dst->allocPixels(destinationConfig); |
| + sk_memset32((uint32_t*) dst->getPixels(), SK_ColorRED, size.width() * size.height()); |
| + |
| + android::CpuConsumer::LockedBuffer nativeBuffer; |
| + android::status_t retval = cpuConsumer->lockNextBuffer(&nativeBuffer); |
| + if (retval == android::BAD_VALUE) { |
| + SkDebugf("HWUISink::draw() 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. |
| + dst->eraseColor(SK_ColorTRANSPARENT); |
| + return ""; |
| + } else if (retval) { |
| + return SkStringPrintf("Failed to lock buffer to read pixels: %d.", retval); |
| + } |
| + |
| + // 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) { |
| + return SkStringPrintf("Failed to wrap HWUI buffer in a SkBitmap"); |
|
mtklein
2015/02/23 16:46:09
This is fine, but without parameters, you can also
tomhudson
2015/02/23 17:43:21
Done. (Good catch; there used to be parameters.)
|
| + } |
| + |
| + SK_ALWAYSBREAK(dst->colorType() == kRGBA_8888_SkColorType && |
| + "Destination buffer not RGBA!"); |
| + success = |
| + nativeWrapper.readPixels(destinationConfig, dst->getPixels(), dst->rowBytes(), 0, 0); |
| + if (!success) { |
| + return SkStringPrintf("Failed to extract pixels from HWUI buffer"); |
|
mtklein
2015/02/23 16:46:09
Ditto.
tomhudson
2015/02/23 17:43:21
Done.
|
| + } |
| + |
| + cpuConsumer->unlockBuffer(nativeBuffer); |
| + return ""; |
| +} |
| + |
| +} // namespace DM |