Support readback from hardware bitmaps
Test: hwuimacro readbackFromHBitmap --onscreen. bug:30999911 Change-Id: I369c069c40cb0f9adae5a94501815f29c2d7df0f
This commit is contained in:
@@ -34,8 +34,6 @@ namespace uirenderer {
|
||||
CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect,
|
||||
SkBitmap* bitmap) {
|
||||
ATRACE_CALL();
|
||||
mRenderThread.eglManager().initialize();
|
||||
|
||||
// Setup the source
|
||||
sp<GraphicBuffer> sourceBuffer;
|
||||
sp<Fence> sourceFence;
|
||||
@@ -61,13 +59,19 @@ CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect
|
||||
return CopyResult::Timeout;
|
||||
}
|
||||
|
||||
return copyGraphicBufferInto(sourceBuffer.get(), texTransform, srcRect, bitmap);
|
||||
}
|
||||
|
||||
CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
|
||||
Matrix4& texTransform, const Rect& srcRect, SkBitmap* bitmap) {
|
||||
mRenderThread.eglManager().initialize();
|
||||
// TODO: Can't use Image helper since it forces GL_TEXTURE_2D usage via
|
||||
// GL_OES_EGL_image, which doesn't work since we need samplerExternalOES
|
||||
// to be able to properly sample from the buffer.
|
||||
|
||||
// Create the EGLImage object that maps the GraphicBuffer
|
||||
EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
EGLClientBuffer clientBuffer = (EGLClientBuffer) sourceBuffer->getNativeBuffer();
|
||||
EGLClientBuffer clientBuffer = (EGLClientBuffer) graphicBuffer->getNativeBuffer();
|
||||
EGLint attrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
|
||||
|
||||
EGLImageKHR sourceImage = eglCreateImageKHR(display, EGL_NO_CONTEXT,
|
||||
@@ -78,8 +82,8 @@ CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect
|
||||
return CopyResult::UnknownError;
|
||||
}
|
||||
|
||||
CopyResult copyResult = copyImageInto(sourceImage, texTransform, sourceBuffer->getWidth(),
|
||||
sourceBuffer->getHeight(), srcRect, bitmap);
|
||||
CopyResult copyResult = copyImageInto(sourceImage, texTransform, graphicBuffer->getWidth(),
|
||||
graphicBuffer->getHeight(), srcRect, bitmap);
|
||||
|
||||
// All we're flushing & finishing is the deletion of the texture since
|
||||
// copyImageInto already did a major flush & finish as an implicit
|
||||
@@ -89,6 +93,14 @@ CopyResult OpenGLReadback::copySurfaceInto(Surface& surface, const Rect& srcRect
|
||||
return copyResult;
|
||||
}
|
||||
|
||||
CopyResult OpenGLReadback::copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) {
|
||||
Rect srcRect;
|
||||
Matrix4 transform;
|
||||
transform.loadScale(1, -1, 1);
|
||||
transform.translate(0, -1);
|
||||
return copyGraphicBufferInto(graphicBuffer, transform, srcRect, bitmap);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
@@ -28,6 +28,8 @@ class OpenGLReadback : public Readback {
|
||||
public:
|
||||
virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
|
||||
SkBitmap* bitmap) override;
|
||||
virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer,
|
||||
SkBitmap* bitmap) override;
|
||||
|
||||
protected:
|
||||
explicit OpenGLReadback(renderthread::RenderThread& thread) : Readback(thread) {}
|
||||
@@ -35,6 +37,9 @@ protected:
|
||||
|
||||
virtual CopyResult copyImageInto(EGLImageKHR eglImage, const Matrix4& imgTransform,
|
||||
int imgWidth, int imgHeight, const Rect& srcRect, SkBitmap* bitmap) = 0;
|
||||
private:
|
||||
CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, Matrix4& texTransform,
|
||||
const Rect& srcRect, SkBitmap* bitmap);
|
||||
};
|
||||
|
||||
class OpenGLReadbackImpl : public OpenGLReadback {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <gui/Surface.h>
|
||||
|
||||
namespace android {
|
||||
class GraphicBuffer;
|
||||
namespace uirenderer {
|
||||
|
||||
// Keep in sync with PixelCopy.java codes
|
||||
@@ -42,6 +43,7 @@ public:
|
||||
*/
|
||||
virtual CopyResult copySurfaceInto(Surface& surface, const Rect& srcRect,
|
||||
SkBitmap* bitmap) = 0;
|
||||
virtual CopyResult copyGraphicBufferInto(GraphicBuffer* graphicBuffer, SkBitmap* bitmap) = 0;
|
||||
|
||||
protected:
|
||||
explicit Readback(renderthread::RenderThread& thread) : mRenderThread(thread) {}
|
||||
|
||||
@@ -459,14 +459,15 @@ void Bitmap::setAlphaType(SkAlphaType alphaType) {
|
||||
}
|
||||
|
||||
void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
|
||||
outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
|
||||
if (isHardware()) {
|
||||
//TODO: use readback to get pixels
|
||||
LOG_ALWAYS_FATAL("Not implemented");
|
||||
ALOGW("Warning: attempt to read pixels from hardware bitmap, which is very slow operation");
|
||||
outBitmap->allocPixels(info());
|
||||
uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
|
||||
return;
|
||||
}
|
||||
outBitmap->setInfo(info(), rowBytes());
|
||||
outBitmap->setPixelRef(this);
|
||||
outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
|
||||
}
|
||||
|
||||
void Bitmap::getSkBitmapForShaders(SkBitmap* outBitmap) {
|
||||
|
||||
@@ -27,6 +27,8 @@
|
||||
#include "utils/Macros.h"
|
||||
#include "utils/TimeUtils.h"
|
||||
|
||||
#include <ui/GraphicBuffer.h>
|
||||
|
||||
namespace android {
|
||||
namespace uirenderer {
|
||||
namespace renderthread {
|
||||
@@ -663,6 +665,18 @@ sk_sp<Bitmap> RenderProxy::allocateHardwareBitmap(SkBitmap& bitmap) {
|
||||
return hardwareBitmap;
|
||||
}
|
||||
|
||||
CREATE_BRIDGE3(copyGraphicBufferInto, RenderThread* thread, GraphicBuffer* buffer, SkBitmap* bitmap) {
|
||||
return (void*) args->thread->readback().copyGraphicBufferInto(args->buffer, args->bitmap);
|
||||
}
|
||||
|
||||
int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap) {
|
||||
SETUP_TASK(copyGraphicBufferInto);
|
||||
args->thread = &RenderThread::getInstance();
|
||||
args->bitmap = bitmap;
|
||||
args->buffer = buffer;
|
||||
return static_cast<int>(reinterpret_cast<intptr_t>(staticPostAndWait(task)));
|
||||
}
|
||||
|
||||
void RenderProxy::post(RenderTask* task) {
|
||||
mRenderThread.queue(task);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
#include "DrawFrameTask.h"
|
||||
|
||||
namespace android {
|
||||
class GraphicBuffer;
|
||||
|
||||
namespace uirenderer {
|
||||
|
||||
class DeferredLayerUpdater;
|
||||
@@ -131,6 +133,8 @@ public:
|
||||
ANDROID_API static void prepareToDraw(Bitmap& bitmap);
|
||||
|
||||
static sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& bitmap);
|
||||
|
||||
static int copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap);
|
||||
private:
|
||||
RenderThread& mRenderThread;
|
||||
CanvasContext* mContext;
|
||||
|
||||
63
libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp
Normal file
63
libs/hwui/tests/common/scenes/ReadbackFromHardwareBitmap.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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 "TestSceneBase.h"
|
||||
|
||||
class ReadbackFromHardware;
|
||||
|
||||
static TestScene::Registrar _SaveLayer(TestScene::Info{
|
||||
"readbackFromHBitmap",
|
||||
"Allocates hardware bitmap and readback data from it.",
|
||||
TestScene::simpleCreateScene<ReadbackFromHardware>
|
||||
});
|
||||
|
||||
class ReadbackFromHardware : public TestScene {
|
||||
public:
|
||||
static sk_sp<Bitmap> createHardwareBitmap() {
|
||||
SkBitmap skBitmap;
|
||||
SkImageInfo info = SkImageInfo::Make(400, 400, kN32_SkColorType, kPremul_SkAlphaType);
|
||||
skBitmap.allocPixels(info);
|
||||
skBitmap.eraseColor(Color::Red_500);
|
||||
SkCanvas canvas(skBitmap);
|
||||
SkPaint paint;
|
||||
paint.setColor(Color::Blue_500);
|
||||
canvas.drawRect(SkRect::MakeXYWH(30, 30, 30, 150), paint);
|
||||
canvas.drawRect(SkRect::MakeXYWH(30, 30, 100, 30), paint);
|
||||
canvas.drawRect(SkRect::MakeXYWH(30, 100, 70, 30), paint);
|
||||
return Bitmap::allocateHardwareBitmap(skBitmap);
|
||||
}
|
||||
|
||||
void createContent(int width, int height, Canvas& canvas) override {
|
||||
canvas.drawColor(Color::White, SkBlendMode::kSrcOver); // background
|
||||
|
||||
sk_sp<Bitmap> hardwareBitmap(createHardwareBitmap());
|
||||
|
||||
SkBitmap readback;
|
||||
hardwareBitmap->getSkBitmap(&readback);
|
||||
|
||||
SkBitmap canvasBitmap;
|
||||
sk_sp<Bitmap> heapBitmap(TestUtils::createBitmap(hardwareBitmap->width(),
|
||||
hardwareBitmap->height(), &canvasBitmap));
|
||||
|
||||
SkCanvas skCanvas(canvasBitmap);
|
||||
skCanvas.drawBitmap(readback, 0, 0);
|
||||
canvas.drawBitmap(*heapBitmap, 0, 0, nullptr);
|
||||
|
||||
canvas.drawBitmap(*hardwareBitmap, 0, 500, nullptr);
|
||||
}
|
||||
|
||||
void doFrame(int frameNr) override { }
|
||||
};
|
||||
Reference in New Issue
Block a user