Merge "Creating HW bitmaps from RenderNode" into oc-dev am: d63b77c627

am: df26122880

Change-Id: I7af81dd30eac562d50540bfb0ac60ffe4270530d
This commit is contained in:
John Reck
2017-05-25 19:09:23 +00:00
committed by android-build-merger
4 changed files with 160 additions and 0 deletions

View File

@@ -894,6 +894,15 @@ public final class ThreadedRenderer {
}
}
/**
* Creates a {@link android.graphics.Bitmap.Config#HARDWARE} bitmap from the given
* RenderNode. Note that the RenderNode should be created as a root node (so x/y of 0,0), and
* not the RenderNode from a View.
**/
public static Bitmap createHardwareBitmap(RenderNode node, int width, int height) {
return nCreateHardwareBitmap(node.getNativeDisplayList(), width, height);
}
@Override
protected void finalize() throws Throwable {
try {
@@ -1037,4 +1046,6 @@ public final class ThreadedRenderer {
private static native int nCopySurfaceInto(Surface surface,
int srcLeft, int srcTop, int srcRight, int srcBottom, Bitmap bitmap);
private static native Bitmap nCreateHardwareBitmap(long renderNode, int width, int height);
}

View File

@@ -25,6 +25,10 @@
#include <GraphicsJNI.h>
#include <ScopedPrimitiveArray.h>
#include <gui/BufferItemConsumer.h>
#include <gui/BufferQueue.h>
#include <gui/Surface.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <private/EGL/cache.h>
@@ -839,6 +843,75 @@ static jint android_view_ThreadedRenderer_copySurfaceInto(JNIEnv* env,
return RenderProxy::copySurfaceInto(surface, left, top, right, bottom, &bitmap);
}
class ContextFactory : public IContextFactory {
public:
virtual AnimationContext* createAnimationContext(renderthread::TimeLord& clock) {
return new AnimationContext(clock);
}
};
static jobject android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode(JNIEnv* env,
jobject clazz, jlong renderNodePtr, jint jwidth, jint jheight) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
if (jwidth <= 0 || jheight <= 0) {
ALOGW("Invalid width %d or height %d", jwidth, jheight);
return nullptr;
}
uint32_t width = jwidth;
uint32_t height = jheight;
// Create a Surface wired up to a BufferItemConsumer
sp<IGraphicBufferProducer> producer;
sp<IGraphicBufferConsumer> rawConsumer;
BufferQueue::createBufferQueue(&producer, &rawConsumer);
rawConsumer->setMaxBufferCount(1);
sp<BufferItemConsumer> consumer = new BufferItemConsumer(rawConsumer,
GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_NEVER | GRALLOC_USAGE_SW_WRITE_NEVER);
consumer->setDefaultBufferSize(width, height);
sp<Surface> surface = new Surface(producer);
// Render into the surface
{
ContextFactory factory;
RenderProxy proxy{false, renderNode, &factory};
proxy.loadSystemProperties();
proxy.setSwapBehavior(SwapBehavior::kSwap_discardBuffer);
proxy.initialize(surface);
// Shadows can't be used via this interface, so just set the light source
// to all 0s.
proxy.setup(0, 0, 0);
proxy.setLightCenter((Vector3){0, 0, 0});
nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
UiFrameInfoBuilder(proxy.frameInfo())
.setVsync(vsync, vsync)
.addFlag(FrameInfoFlags::SurfaceCanvas);
proxy.syncAndDrawFrame();
}
// Yank out the GraphicBuffer
BufferItem bufferItem;
status_t err;
if ((err = consumer->acquireBuffer(&bufferItem, 0, true)) != OK) {
ALOGW("Failed to acquireBuffer, error %d (%s)", err, strerror(-err));
return nullptr;
}
sp<GraphicBuffer> buffer = bufferItem.mGraphicBuffer;
// We don't really care if this fails or not since we're just going to destroy this anyway
consumer->releaseBuffer(bufferItem);
if (!buffer.get()) {
ALOGW("GraphicBuffer is null?");
return nullptr;
}
if (buffer->getWidth() != width || buffer->getHeight() != height) {
ALOGW("GraphicBuffer size mismatch, got %dx%d expected %dx%d",
buffer->getWidth(), buffer->getHeight(), width, height);
// Continue I guess?
}
sk_sp<Bitmap> bitmap = Bitmap::createFrom(buffer);
return createBitmap(env, bitmap.release(), android::bitmap::kBitmapCreateFlag_Mutable);
}
// ----------------------------------------------------------------------------
// FrameMetricsObserver
// ----------------------------------------------------------------------------
@@ -934,6 +1007,8 @@ static const JNINativeMethod gMethods[] = {
(void*)android_view_ThreadedRenderer_removeFrameMetricsObserver },
{ "nCopySurfaceInto", "(Landroid/view/Surface;IIIILandroid/graphics/Bitmap;)I",
(void*)android_view_ThreadedRenderer_copySurfaceInto },
{ "nCreateHardwareBitmap", "(JII)Landroid/graphics/Bitmap;",
(void*)android_view_ThreadedRenderer_createHardwareBitmapFromRenderNode },
};
int register_android_view_ThreadedRenderer(JNIEnv* env) {

View File

@@ -112,6 +112,15 @@
</intent-filter>
</activity>
<activity
android:name="DrawIntoHwBitmapActivity"
android:label="Bitmaps/DrawIntoHwBitmap">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="com.android.test.hwui.TEST" />
</intent-filter>
</activity>
<activity
android:name="PathOffsetActivity"
android:label="Path/Offset">

View File

@@ -0,0 +1,65 @@
/*
* Copyright (C) 2017 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.
*/
package com.android.test.hwui;
import static android.graphics.GraphicBuffer.USAGE_HW_TEXTURE;
import static android.graphics.GraphicBuffer.USAGE_SW_READ_NEVER;
import static android.graphics.GraphicBuffer.USAGE_SW_WRITE_NEVER;
import static android.graphics.GraphicBuffer.USAGE_SW_WRITE_RARELY;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.GraphicBuffer;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.SurfaceTexture;
import android.os.Bundle;
import android.view.DisplayListCanvas;
import android.view.RenderNode;
import android.view.Surface;
import android.view.ThreadedRenderer;
import android.widget.ImageView;
public class DrawIntoHwBitmapActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ImageView view = new ImageView(this);
view.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
setContentView(view);
view.setImageBitmap(createBitmap());
}
Bitmap createBitmap() {
RenderNode node = RenderNode.create("HwuiCanvas", null);
node.setLeftTopRightBottom(0, 0, 500, 500);
node.setClipToBounds(false);
DisplayListCanvas canvas = node.start(500, 500);
Paint p = new Paint();
p.setColor(Color.BLACK);
p.setTextSize(20 * getResources().getDisplayMetrics().density);
canvas.drawColor(0xFF2196F3);
p.setColor(0xFFBBDEFB);
canvas.drawRect(0, 0, 500, 100, p);
p.setColor(Color.BLACK);
canvas.drawText("Hello, World!", 0, 90, p);
node.end(canvas);
return ThreadedRenderer.createHardwareBitmap(node, 500, 500);
}
}