Move all non-GL HW Bitmap work off RT

Bug: 78288006
Test: hwuiunit passes, systrace showed work distribution as expected,
and photos using HW bitmaps still works

Change-Id: Id3285b637b5d74d3c5891ed3051ac1e44015987a
This commit is contained in:
John Reck
2018-04-19 17:05:35 -07:00
parent 1e51071240
commit b90d4cb3be
4 changed files with 118 additions and 95 deletions

View File

@@ -222,24 +222,6 @@ void SkiaOpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* func
#define FENCE_TIMEOUT 2000000000
class AutoEglFence {
public:
AutoEglFence(EGLDisplay display) : mDisplay(display) {
fence = eglCreateSyncKHR(mDisplay, EGL_SYNC_FENCE_KHR, NULL);
}
~AutoEglFence() {
if (fence != EGL_NO_SYNC_KHR) {
eglDestroySyncKHR(mDisplay, fence);
}
}
EGLSyncKHR fence = EGL_NO_SYNC_KHR;
private:
EGLDisplay mDisplay = EGL_NO_DISPLAY;
};
class AutoEglImage {
public:
AutoEglImage(EGLDisplay display, EGLClientBuffer clientBuffer) : mDisplay(display) {
@@ -273,73 +255,102 @@ private:
GLuint mTexture = 0;
};
sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThread& renderThread,
SkBitmap& skBitmap) {
renderThread.requireGlContext();
struct FormatInfo {
sk_sp<GrContext> grContext = sk_ref_sp(renderThread.getGrContext());
const SkImageInfo& info = skBitmap.info();
PixelFormat pixelFormat;
GLint format, type;
bool isSupported = false;
bool valid = true;
};
static bool gpuSupportsHalfFloatTextures(renderthread::RenderThread& renderThread) {
static bool isSupported = renderThread.queue().runSync([&renderThread]() -> bool {
renderThread.requireGlContext();
sk_sp<GrContext> grContext = sk_ref_sp(renderThread.getGrContext());
return grContext->colorTypeSupportedAsImage(kRGBA_F16_SkColorType);
});
return isSupported;
}
static FormatInfo determineFormat(renderthread::RenderThread& renderThread,
const SkBitmap& skBitmap) {
FormatInfo formatInfo;
// TODO: add support for linear blending (when ANDROID_ENABLE_LINEAR_BLENDING is defined)
switch (info.colorType()) {
switch (skBitmap.info().colorType()) {
case kRGBA_8888_SkColorType:
isSupported = true;
formatInfo.isSupported = true;
// ARGB_4444 is upconverted to RGBA_8888
case kARGB_4444_SkColorType:
pixelFormat = PIXEL_FORMAT_RGBA_8888;
format = GL_RGBA;
type = GL_UNSIGNED_BYTE;
formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
formatInfo.format = GL_RGBA;
formatInfo.type = GL_UNSIGNED_BYTE;
break;
case kRGBA_F16_SkColorType:
isSupported = grContext->colorTypeSupportedAsImage(kRGBA_F16_SkColorType);
if (isSupported) {
type = GL_HALF_FLOAT;
pixelFormat = PIXEL_FORMAT_RGBA_FP16;
formatInfo.isSupported = gpuSupportsHalfFloatTextures(renderThread);
if (formatInfo.isSupported) {
formatInfo.type = GL_HALF_FLOAT;
formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_FP16;
} else {
type = GL_UNSIGNED_BYTE;
pixelFormat = PIXEL_FORMAT_RGBA_8888;
formatInfo.type = GL_UNSIGNED_BYTE;
formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
}
format = GL_RGBA;
formatInfo.format = GL_RGBA;
break;
case kRGB_565_SkColorType:
isSupported = true;
pixelFormat = PIXEL_FORMAT_RGB_565;
format = GL_RGB;
type = GL_UNSIGNED_SHORT_5_6_5;
formatInfo.isSupported = true;
formatInfo.pixelFormat = PIXEL_FORMAT_RGB_565;
formatInfo.format = GL_RGB;
formatInfo.type = GL_UNSIGNED_SHORT_5_6_5;
break;
case kGray_8_SkColorType:
isSupported = true;
pixelFormat = PIXEL_FORMAT_RGBA_8888;
format = GL_LUMINANCE;
type = GL_UNSIGNED_BYTE;
formatInfo.isSupported = true;
formatInfo.pixelFormat = PIXEL_FORMAT_RGBA_8888;
formatInfo.format = GL_LUMINANCE;
formatInfo.type = GL_UNSIGNED_BYTE;
break;
default:
ALOGW("unable to create hardware bitmap of colortype: %d", info.colorType());
return nullptr;
ALOGW("unable to create hardware bitmap of colortype: %d", skBitmap.info().colorType());
formatInfo.valid = false;
}
return formatInfo;
}
SkBitmap bitmap;
if (isSupported) {
bitmap = skBitmap;
static SkBitmap makeHwCompatible(const FormatInfo& format, const SkBitmap& source) {
if (format.isSupported) {
return source;
} else {
SkBitmap bitmap;
const SkImageInfo& info = source.info();
bitmap.allocPixels(
SkImageInfo::MakeN32(info.width(), info.height(), info.alphaType(), nullptr));
bitmap.eraseColor(0);
if (info.colorType() == kRGBA_F16_SkColorType) {
// Drawing RGBA_F16 onto ARGB_8888 is not supported
skBitmap.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
source.readPixels(bitmap.info().makeColorSpace(SkColorSpace::MakeSRGB()),
bitmap.getPixels(), bitmap.rowBytes(), 0, 0);
} else {
SkCanvas canvas(bitmap);
canvas.drawBitmap(skBitmap, 0.0f, 0.0f, nullptr);
canvas.drawBitmap(source, 0.0f, 0.0f, nullptr);
}
return bitmap;
}
}
sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThread& thread,
const SkBitmap& sourceBitmap) {
ATRACE_CALL();
LOG_ALWAYS_FATAL_IF(thread.isCurrent(), "Must not be called on RenderThread");
FormatInfo format = determineFormat(thread, sourceBitmap);
if (!format.valid) {
return nullptr;
}
SkBitmap bitmap = makeHwCompatible(format, sourceBitmap);
sp<GraphicBuffer> buffer = new GraphicBuffer(
info.width(), info.height(), pixelFormat,
static_cast<uint32_t>(bitmap.width()), static_cast<uint32_t>(bitmap.height()),
format.pixelFormat,
GraphicBuffer::USAGE_HW_TEXTURE | GraphicBuffer::USAGE_SW_WRITE_NEVER |
GraphicBuffer::USAGE_SW_READ_NEVER,
std::string("Bitmap::allocateSkiaHardwareBitmap pid [") + std::to_string(getpid()) +
@@ -351,8 +362,11 @@ sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr
return nullptr;
}
// upload the bitmap into a texture
EGLDisplay display = eglGetCurrentDisplay();
EGLDisplay display = thread.queue().runSync([&]() -> EGLDisplay {
thread.requireGlContext();
return eglGetCurrentDisplay();
});
LOG_ALWAYS_FATAL_IF(display == EGL_NO_DISPLAY, "Failed to get EGL_DEFAULT_DISPLAY! err=%s",
uirenderer::renderthread::EglManager::eglErrorString());
// We use an EGLImage to access the content of the GraphicBuffer
@@ -364,35 +378,40 @@ sk_sp<Bitmap> SkiaOpenGLPipeline::allocateHardwareBitmap(renderthread::RenderThr
uirenderer::renderthread::EglManager::eglErrorString());
return nullptr;
}
AutoSkiaGlTexture glTexture;
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
GL_CHECKPOINT(MODERATE);
// glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we provide.
// But asynchronous in sense that driver may upload texture onto hardware buffer when we first
// use it in drawing
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, info.width(), info.height(), format, type,
bitmap.getPixels());
GL_CHECKPOINT(MODERATE);
{
ATRACE_FORMAT("CPU -> gralloc transfer (%dx%d)", bitmap.width(), bitmap.height());
EGLSyncKHR fence = thread.queue().runSync([&]() -> EGLSyncKHR {
thread.requireGlContext();
sk_sp<GrContext> grContext = sk_ref_sp(thread.getGrContext());
AutoSkiaGlTexture glTexture;
glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, autoImage.image);
GL_CHECKPOINT(MODERATE);
// The fence is used to wait for the texture upload to finish
// properly. We cannot rely on glFlush() and glFinish() as
// some drivers completely ignore these API calls
AutoEglFence autoFence(display);
if (autoFence.fence == EGL_NO_SYNC_KHR) {
LOG_ALWAYS_FATAL("Could not create sync fence %#x", eglGetError());
return nullptr;
// glTexSubImage2D is synchronous in sense that it memcpy() from pointer that we
// provide.
// But asynchronous in sense that driver may upload texture onto hardware buffer when we
// first
// use it in drawing
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, bitmap.width(), bitmap.height(), format.format,
format.type, bitmap.getPixels());
GL_CHECKPOINT(MODERATE);
EGLSyncKHR uploadFence =
eglCreateSyncKHR(eglGetCurrentDisplay(), EGL_SYNC_FENCE_KHR, NULL);
LOG_ALWAYS_FATAL_IF(uploadFence == EGL_NO_SYNC_KHR, "Could not create sync fence %#x",
eglGetError());
glFlush();
grContext->resetContext(kTextureBinding_GrGLBackendState);
return uploadFence;
});
EGLint waitStatus = eglClientWaitSyncKHR(display, fence, 0, FENCE_TIMEOUT);
LOG_ALWAYS_FATAL_IF(waitStatus != EGL_CONDITION_SATISFIED_KHR,
"Failed to wait for the fence %#x", eglGetError());
eglDestroySyncKHR(display, fence);
}
// The flag EGL_SYNC_FLUSH_COMMANDS_BIT_KHR will trigger a
// pipeline flush (similar to what a glFlush() would do.)
EGLint waitStatus = eglClientWaitSyncKHR(display, autoFence.fence,
EGL_SYNC_FLUSH_COMMANDS_BIT_KHR, FENCE_TIMEOUT);
if (waitStatus != EGL_CONDITION_SATISFIED_KHR) {
LOG_ALWAYS_FATAL("Failed to wait for the fence %#x", eglGetError());
return nullptr;
}
grContext->resetContext(kTextureBinding_GrGLBackendState);
return sk_sp<Bitmap>(new Bitmap(buffer.get(), bitmap.info()));
}

View File

@@ -49,8 +49,10 @@ public:
bool isContextReady() override;
static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
// May be called by any thread except RenderThread.
static sk_sp<Bitmap> allocateHardwareBitmap(renderthread::RenderThread& thread,
SkBitmap& skBitmap);
const SkBitmap& skBitmap);
private:
renderthread::EglManager& mEglManager;

View File

@@ -21,6 +21,7 @@
#include "Properties.h"
#include "Readback.h"
#include "Rect.h"
#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "pipeline/skia/VectorDrawableAtlas.h"
#include "renderstate/RenderState.h"
#include "renderthread/CanvasContext.h"
@@ -323,7 +324,13 @@ void RenderProxy::prepareToDraw(Bitmap& bitmap) {
sk_sp<Bitmap> RenderProxy::allocateHardwareBitmap(SkBitmap& bitmap) {
auto& thread = RenderThread::getInstance();
return thread.queue().runSync([&]() -> auto { return thread.allocateHardwareBitmap(bitmap); });
if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaGL) {
return skiapipeline::SkiaOpenGLPipeline::allocateHardwareBitmap(thread, bitmap);
} else {
return thread.queue().runSync([&]() -> auto {
return thread.allocateHardwareBitmap(bitmap);
});
}
}
int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap) {

View File

@@ -24,8 +24,8 @@
#include "hwui/Bitmap.h"
#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "pipeline/skia/SkiaOpenGLReadback.h"
#include "pipeline/skia/SkiaVulkanReadback.h"
#include "pipeline/skia/SkiaVulkanPipeline.h"
#include "pipeline/skia/SkiaVulkanReadback.h"
#include "renderstate/RenderState.h"
#include "utils/FatVector.h"
#include "utils/TimeUtils.h"
@@ -98,14 +98,11 @@ public:
DummyVsyncSource(RenderThread* renderThread) : mRenderThread(renderThread) {}
virtual void requestNextVsync() override {
mRenderThread->queue().postDelayed(16_ms, [this]() {
mRenderThread->drainDisplayEventQueue();
});
mRenderThread->queue().postDelayed(16_ms,
[this]() { mRenderThread->drainDisplayEventQueue(); });
}
virtual nsecs_t latestVsyncEvent() override {
return systemTime(CLOCK_MONOTONIC);
}
virtual nsecs_t latestVsyncEvent() override { return systemTime(CLOCK_MONOTONIC); }
private:
RenderThread* mRenderThread;
@@ -152,13 +149,13 @@ void RenderThread::initializeDisplayEventReceiver() {
auto receiver = std::make_unique<DisplayEventReceiver>();
status_t status = receiver->initCheck();
LOG_ALWAYS_FATAL_IF(status != NO_ERROR,
"Initialization of DisplayEventReceiver "
"failed with status: %d",
status);
"Initialization of DisplayEventReceiver "
"failed with status: %d",
status);
// Register the FD
mLooper->addFd(receiver->getFd(), 0, Looper::EVENT_INPUT,
RenderThread::displayEventReceiverCallback, this);
RenderThread::displayEventReceiverCallback, this);
mVsyncSource = new DisplayEventReceiverWrapper(std::move(receiver));
} else {
mVsyncSource = new DummyVsyncSource(this);
@@ -372,8 +369,6 @@ void RenderThread::pushBackFrameCallback(IFrameCallback* callback) {
sk_sp<Bitmap> RenderThread::allocateHardwareBitmap(SkBitmap& skBitmap) {
auto renderType = Properties::getRenderPipelineType();
switch (renderType) {
case RenderPipelineType::SkiaGL:
return skiapipeline::SkiaOpenGLPipeline::allocateHardwareBitmap(*this, skBitmap);
case RenderPipelineType::SkiaVulkan:
return skiapipeline::SkiaVulkanPipeline::allocateHardwareBitmap(*this, skBitmap);
default: