Support readback from hardware bitmaps

Test: hwuimacro readbackFromHBitmap --onscreen.
bug:30999911
Change-Id: I369c069c40cb0f9adae5a94501815f29c2d7df0f
This commit is contained in:
sergeyv
2016-11-17 17:54:57 -08:00
parent a79a655e4b
commit 59eecb526a
7 changed files with 109 additions and 8 deletions

View File

@@ -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);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

View File

@@ -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 {

View File

@@ -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) {}

View File

@@ -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) {

View File

@@ -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);
}

View File

@@ -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;

View 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 { }
};