summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/jni/android/graphics/Shader.cpp9
-rw-r--r--libs/hwui/hwui/Bitmap.cpp41
-rw-r--r--libs/hwui/hwui/Bitmap.h12
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp83
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h2
-rw-r--r--libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp1
-rw-r--r--libs/hwui/pipeline/skia/SkiaPipeline.cpp10
-rw-r--r--libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp28
-rw-r--r--libs/hwui/renderthread/RenderProxy.cpp12
-rw-r--r--libs/hwui/renderthread/RenderProxy.h2
-rw-r--r--libs/hwui/renderthread/RenderThread.cpp19
-rw-r--r--libs/hwui/renderthread/RenderThread.h3
12 files changed, 192 insertions, 30 deletions
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 214d97c213e4..b529e3745647 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -60,14 +60,17 @@ static void Shader_safeUnref(JNIEnv* env, jobject o, jlong shaderHandle) {
static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jobject jbitmap,
jint tileModeX, jint tileModeY) {
const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
- SkBitmap bitmap;
+ sk_sp<SkImage> image;
if (jbitmap) {
// Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
// we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
- android::bitmap::toBitmap(env, jbitmap).getSkBitmapForShaders(&bitmap);
+ image = android::bitmap::toBitmap(env, jbitmap).makeImage(nullptr);
}
- sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
+ if (!image.get()) {
+ SkBitmap bitmap;
+ image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
+ }
sk_sp<SkShader> baseShader = image->makeShader(
(SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY);
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index d765584a7530..b0e486d874ca 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -16,6 +16,7 @@
#include "Bitmap.h"
#include "Caches.h"
+#include "pipeline/skia/SkiaOpenGLPipeline.h"
#include "renderthread/EglManager.h"
#include "renderthread/RenderThread.h"
#include "renderthread/RenderProxy.h"
@@ -34,11 +35,15 @@
#include <private/gui/ComposerService.h>
#include <binder/IServiceManager.h>
#include <ui/PixelFormat.h>
+#include <GrTexture.h>
#include <SkCanvas.h>
+#include <SkImagePriv.h>
namespace android {
+Mutex Bitmap::gLock;
+
static bool computeAllocationSize(size_t rowBytes, int height, size_t* size) {
int32_t rowBytes32 = SkToS32(rowBytes);
int64_t bigSize = (int64_t) height * rowBytes32;
@@ -317,8 +322,7 @@ sk_sp<Bitmap> Bitmap::createFrom(sp<GraphicBuffer> graphicBuffer) {
return nullptr;
}
SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
- kRGBA_8888_SkColorType, kPremul_SkAlphaType,
- SkColorSpace::MakeSRGB());
+ kRGBA_8888_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB());
return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
}
@@ -393,6 +397,7 @@ Bitmap::Bitmap(GraphicBuffer* buffer, const SkImageInfo& info)
mPixelStorage.hardware.buffer = buffer;
buffer->incStrong(buffer);
mRowBytes = bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride();
+ setImmutable(); // HW bitmaps are always immutable
}
Bitmap::~Bitmap() {
@@ -486,7 +491,13 @@ void Bitmap::setAlphaType(SkAlphaType alphaType) {
void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
if (isHardware()) {
- outBitmap->allocPixels(info());
+ if (uirenderer::Properties::isSkiaEnabled()) {
+ // TODO: add color correctness for Skia pipeline - pass null color space for now
+ outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(),
+ info().colorType(), info().alphaType(), nullptr));
+ } else {
+ outBitmap->allocPixels(info());
+ }
uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
return;
}
@@ -512,4 +523,28 @@ GraphicBuffer* Bitmap::graphicBuffer() {
return nullptr;
}
+sk_sp<SkImage> Bitmap::makeImage(const uirenderer::renderthread::RenderThread* renderThread) {
+ AutoMutex _lock(gLock); //TODO: implement lock free solution
+ auto image = mImage;
+ //TODO: use new API SkImage::isValid() instead of SkImage::getTexture()->getContext()
+ if (!image.get() || (image->getTexture() && nullptr == image->getTexture()->getContext())) {
+ if (isHardware() && uirenderer::RenderPipelineType::SkiaGL
+ == uirenderer::Properties::getRenderPipelineType()) {
+ //TODO: add Vulkan support
+ if (renderThread) {
+ image = uirenderer::skiapipeline::SkiaOpenGLPipeline::makeTextureImage(
+ *renderThread, this);
+ } else {
+ image = uirenderer::renderthread::RenderProxy::makeTextureImage(this);
+ }
+ } else {
+ SkBitmap skiaBitmap;
+ getSkBitmapForShaders(&skiaBitmap);
+ image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
+ }
+ mImage = image;
+ }
+ return image;
+}
+
} // namespace android
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index da45f7697f56..621e43979969 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -22,6 +22,8 @@
#include <SkPixelRef.h>
#include <cutils/compiler.h>
#include <ui/GraphicBuffer.h>
+#include <utils/Mutex.h>
+#include <SkImage.h>
namespace android {
@@ -111,6 +113,13 @@ public:
}
GraphicBuffer* graphicBuffer();
+
+ // makeImage creates or returns a cached SkImage. Can be invoked from UI or render thread.
+ // If invoked on the render thread, then RenderThread* argument is required.
+ // If not invoked on the render thread, then RenderThread* must be nullptr.
+ // makeImage is wrapping a gralloc buffer with an EGLImage and is passing a texture to Skia.
+ // This is a temporary implementation until Skia can wrap the gralloc buffer in a SkImage.
+ sk_sp<SkImage> makeImage(const uirenderer::renderthread::RenderThread*);
protected:
virtual bool onNewLockPixels(LockRec* rec) override;
virtual void onUnlockPixels() override { };
@@ -145,6 +154,9 @@ private:
GraphicBuffer* buffer;
} hardware;
} mPixelStorage;
+
+ sk_sp<SkImage> mImage;
+ static Mutex gLock;
};
} //namespace android \ No newline at end of file
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index ae1313101f3c..4885873e232d 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -28,6 +28,8 @@
#include <cutils/properties.h>
#include <strings.h>
+#include <SkImagePriv.h>
+#include <gl/GrGLTypes.h>
using namespace android::uirenderer::renderthread;
@@ -197,6 +199,87 @@ void SkiaOpenGLPipeline::invokeFunctor(const RenderThread& thread, Functor* func
}
}
+static void deleteImageTexture(void* context) {
+ EGLImageKHR EGLimage = reinterpret_cast<EGLImageKHR>(context);
+ if (EGLimage != EGL_NO_IMAGE_KHR) {
+ EGLDisplay display = eglGetCurrentDisplay();
+ if (EGL_NO_DISPLAY == display) {
+ display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ }
+ eglDestroyImageKHR(display, EGLimage);
+ }
+}
+
+sk_sp<SkImage> SkiaOpenGLPipeline::makeTextureImage(
+ const uirenderer::renderthread::RenderThread& renderThread, Bitmap* bitmap) {
+ renderThread.eglManager().initialize();
+
+ GraphicBuffer* buffer = bitmap->graphicBuffer();
+ EGLDisplay display = eglGetCurrentDisplay();
+ if (EGL_NO_DISPLAY == display) {
+ display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ }
+ LOG_ALWAYS_FATAL_IF(!bitmap->isHardware(),
+ "Texture image requires a HW bitmap.");
+ // We use an EGLImage to access the content of the GraphicBuffer
+ // The EGL image is later bound to a 2D texture
+ EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer->getNativeBuffer();
+ EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
+ EGLImageKHR EGLimage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ clientBuffer, imageAttrs);
+ if (EGLimage == EGL_NO_IMAGE_KHR) {
+ ALOGW("Could not create EGL image, err =%s",
+ uirenderer::renderthread::EglManager::eglErrorString());
+ return nullptr;
+ }
+
+ GLuint textureId = 0;
+ glGenTextures(1, &textureId);
+ glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
+ glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, EGLimage);
+
+ GLenum status = GL_NO_ERROR;
+ while ((status = glGetError()) != GL_NO_ERROR) {
+ ALOGW("glEGLImageTargetTexture2DOES failed (%#x)", status);
+ eglDestroyImageKHR(display, EGLimage);
+ return nullptr;
+ }
+
+ sk_sp<GrContext> grContext = sk_ref_sp(renderThread.getGrContext());
+ grContext->resetContext();
+
+ GrGLTextureInfo textureInfo;
+ textureInfo.fTarget = GL_TEXTURE_EXTERNAL_OES;
+ textureInfo.fID = textureId;
+
+ GrBackendTextureDesc textureDescription;
+ textureDescription.fWidth = bitmap->info().width();
+ textureDescription.fHeight = bitmap->info().height();
+ textureDescription.fOrigin = kTopLeft_GrSurfaceOrigin;
+ textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&textureInfo);
+ PixelFormat format = buffer->getPixelFormat();
+ switch (format) {
+ case PIXEL_FORMAT_RGBA_8888:
+ textureDescription.fConfig = kRGBA_8888_GrPixelConfig;
+ break;
+ case PIXEL_FORMAT_RGBA_FP16:
+ textureDescription.fConfig = kRGBA_half_GrPixelConfig;
+ break;
+ default:
+ eglDestroyImageKHR(display, EGLimage);
+ return nullptr;
+ }
+
+ // TODO: add color correctness - pass null color space for now
+ sk_sp<SkImage> image = SkImage::MakeFromTexture(grContext.get(), textureDescription,
+ bitmap->info().alphaType(), nullptr, deleteImageTexture, EGLimage);
+ if (!image.get()) {
+ eglDestroyImageKHR(display, EGLimage);
+ return nullptr;
+ }
+ return image;
+}
+
} /* namespace skiapipeline */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 36685ddb17a7..f3ce189df574 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -46,6 +46,8 @@ public:
bool isContextReady() override;
static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
+ static sk_sp<SkImage> makeTextureImage(
+ const uirenderer::renderthread::RenderThread& renderThread, Bitmap* bitmap);
private:
renderthread::EglManager& mEglManager;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index a18d26471a29..1a6e70949992 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -61,6 +61,7 @@ CopyResult SkiaOpenGLReadback::copyImageInto(EGLImageKHR eglImage, const Matrix4
textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture);
CopyResult copyResult = CopyResult::UnknownError;
+ // TODO: add color correctness - pass null color space for now
sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), textureDescription));
if (image) {
SkAutoLockPixels alp(*bitmap);
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 10c1865ac50c..349d4ccfa04d 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -155,11 +155,11 @@ void SkiaPipeline::prepareToDraw(const RenderThread& thread, Bitmap* bitmap) {
GrContext* context = thread.getGrContext();
if (context) {
ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height());
- SkBitmap skiaBitmap;
- bitmap->getSkBitmap(&skiaBitmap);
- sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
- SkImage_pinAsTexture(image.get(), context);
- SkImage_unpinAsTexture(image.get(), context);
+ auto image = bitmap->makeImage(&thread);
+ if (image.get() && !bitmap->isHardware()) {
+ SkImage_pinAsTexture(image.get(), context);
+ SkImage_unpinAsTexture(image.get(), context);
+ }
}
}
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 559d268b71f7..5d7bbfa11c7d 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -168,11 +168,8 @@ inline static const SkPaint* nonAAPaint(const SkPaint* origPaint, SkPaint* tmpPa
}
void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
- SkBitmap skBitmap;
- bitmap.getSkBitmap(&skBitmap);
-
- sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode);
- if (!skBitmap.isImmutable()) {
+ sk_sp<SkImage> image = bitmap.makeImage(nullptr);
+ if (!bitmap.isImmutable()) {
mDisplayList->mMutableImages.push_back(image.get());
}
SkPaint tmpPaint;
@@ -181,12 +178,10 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, cons
void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix,
const SkPaint* paint) {
- SkBitmap bitmap;
- hwuiBitmap.getSkBitmap(&bitmap);
SkAutoCanvasRestore acr(&mRecorder, true);
concat(matrix);
- sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
- if (!bitmap.isImmutable()) {
+ sk_sp<SkImage> image = hwuiBitmap.makeImage(nullptr);
+ if (!hwuiBitmap.isImmutable()) {
mDisplayList->mMutableImages.push_back(image.get());
}
SkPaint tmpPaint;
@@ -196,12 +191,10 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix,
void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop,
float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight,
float dstBottom, const SkPaint* paint) {
- SkBitmap bitmap;
- hwuiBitmap.getSkBitmap(&bitmap);
SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
- if (!bitmap.isImmutable()) {
+ sk_sp<SkImage> image = hwuiBitmap.makeImage(nullptr);
+ if (!hwuiBitmap.isImmutable()) {
mDisplayList->mMutableImages.push_back(image.get());
}
SkPaint tmpPaint;
@@ -210,11 +203,8 @@ void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float sr
void SkiaRecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk,
float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
- SkBitmap bitmap;
- hwuiBitmap.getSkBitmap(&bitmap);
-
SkCanvas::Lattice lattice;
- NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
+ NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height());
lattice.fFlags = nullptr;
int numFlags = 0;
@@ -231,8 +221,8 @@ void SkiaRecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch
lattice.fBounds = nullptr;
SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
- sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
- if (!bitmap.isImmutable()) {
+ sk_sp<SkImage> image = hwuiBitmap.makeImage(nullptr);
+ if (!hwuiBitmap.isImmutable()) {
mDisplayList->mMutableImages.push_back(image.get());
}
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index a1f1717e6b96..5c2ec0ea3c88 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -693,6 +693,18 @@ int RenderProxy::copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap)
}
}
+CREATE_BRIDGE2(makeTextureImage, RenderThread* thread, Bitmap* bitmap) {
+ return args->thread->makeTextureImage(args->bitmap).release();
+}
+
+sk_sp<SkImage> RenderProxy::makeTextureImage(Bitmap* bitmap) {
+ SETUP_TASK(makeTextureImage);
+ args->bitmap = bitmap;
+ args->thread = &RenderThread::getInstance();
+ sk_sp<SkImage> hardwareImage(reinterpret_cast<SkImage*>(staticPostAndWait(task)));
+ return hardwareImage;
+}
+
void RenderProxy::post(RenderTask* task) {
mRenderThread.queue(task);
}
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index a60ed55c70d2..97ad796b6065 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -135,6 +135,8 @@ public:
static sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& bitmap);
static int copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap);
+
+ static sk_sp<SkImage> makeTextureImage(Bitmap* bitmap);
private:
RenderThread& mRenderThread;
CanvasContext* mContext;
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 1450ec98dabf..d62b55633e2d 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -17,6 +17,7 @@
#include "RenderThread.h"
#include "../renderstate/RenderState.h"
+#include "../pipeline/skia/SkiaOpenGLPipeline.h"
#include "../pipeline/skia/SkiaOpenGLReadback.h"
#include "CanvasContext.h"
#include "EglManager.h"
@@ -433,6 +434,24 @@ RenderTask* RenderThread::nextTask(nsecs_t* nextWakeup) {
return next;
}
+sk_sp<SkImage> RenderThread::makeTextureImage(Bitmap* bitmap) {
+ auto renderType = Properties::getRenderPipelineType();
+ sk_sp<SkImage> hardwareImage;
+ switch (renderType) {
+ case RenderPipelineType::SkiaGL:
+ hardwareImage = skiapipeline::SkiaOpenGLPipeline::makeTextureImage(*this, bitmap);
+ break;
+ case RenderPipelineType::SkiaVulkan:
+ //TODO: add Vulkan support
+ break;
+ default:
+ LOG_ALWAYS_FATAL("makeTextureImage: canvas context type %d not supported",
+ (int32_t) renderType);
+ break;
+ }
+ return hardwareImage;
+}
+
} /* namespace renderthread */
} /* namespace uirenderer */
} /* namespace android */
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 9bc5985e5b16..34542c6021ec 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -33,6 +33,7 @@
namespace android {
+class Bitmap;
class DisplayEventReceiver;
namespace uirenderer {
@@ -104,6 +105,8 @@ public:
VulkanManager& vulkanManager() { return *mVkManager; }
+ sk_sp<SkImage> makeTextureImage(Bitmap* bitmap);
+
protected:
virtual bool threadLoop() override;