Merge "Creating HW bitmaps from RenderNode" into oc-dev am: d63b77c627
am: df26122880
Change-Id: I7af81dd30eac562d50540bfb0ac60ffe4270530d
This commit is contained in:
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user