summaryrefslogtreecommitdiff
path: root/libs/hwui/Texture.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/hwui/Texture.cpp')
-rw-r--r--libs/hwui/Texture.cpp89
1 files changed, 70 insertions, 19 deletions
diff --git a/libs/hwui/Texture.cpp b/libs/hwui/Texture.cpp
index cfc2744e61b2..8b71086e1625 100644
--- a/libs/hwui/Texture.cpp
+++ b/libs/hwui/Texture.cpp
@@ -17,10 +17,13 @@
#include "Caches.h"
#include "Texture.h"
#include "utils/GLUtils.h"
+#include "utils/MathUtils.h"
#include "utils/TraceUtils.h"
#include <utils/Log.h>
+#include <math/mat4.h>
+
#include <SkCanvas.h>
namespace android {
@@ -48,12 +51,7 @@ static int bytesPerPixel(GLint glFormat) {
}
}
-bool Texture::isLinear() const {
- return mInternalFormat == GL_RGBA16F;
-}
-
void Texture::setWrapST(GLenum wrapS, GLenum wrapT, bool bindTexture, bool force) {
-
if (force || wrapS != mWrapS || wrapT != mWrapT) {
mWrapS = wrapS;
mWrapT = wrapT;
@@ -94,7 +92,7 @@ void Texture::deleteTexture() {
}
}
-bool Texture::updateSize(uint32_t width, uint32_t height, GLint internalFormat,
+bool Texture::updateLayout(uint32_t width, uint32_t height, GLint internalFormat,
GLint format, GLenum target) {
if (mWidth == width
&& mHeight == height
@@ -122,7 +120,7 @@ void Texture::resetCachedParams() {
void Texture::upload(GLint internalFormat, uint32_t width, uint32_t height,
GLenum format, GLenum type, const void* pixels) {
GL_CHECKPOINT(MODERATE);
- bool needsAlloc = updateSize(width, height, internalFormat, format, GL_TEXTURE_2D);
+ bool needsAlloc = updateLayout(width, height, internalFormat, format, GL_TEXTURE_2D);
if (!mId) {
glGenTextures(1, &mId);
needsAlloc = true;
@@ -224,7 +222,6 @@ void Texture::colorTypeToGlFormatAndType(const Caches& caches, SkColorType color
*outType = GL_UNSIGNED_BYTE;
break;
case kGray_8_SkColorType:
- // TODO: Handle sRGB
*outFormat = GL_LUMINANCE;
*outInternalFormat = GL_LUMINANCE;
*outType = GL_UNSIGNED_BYTE;
@@ -252,15 +249,14 @@ SkBitmap Texture::uploadToN32(const SkBitmap& bitmap, bool hasLinearBlending,
return rgbaBitmap;
}
-bool Texture::hasUnsupportedColorType(const SkImageInfo& info, bool hasLinearBlending,
- SkColorSpace* sRGB) {
- bool needSRGB = info.colorSpace() == sRGB;
+bool Texture::hasUnsupportedColorType(const SkImageInfo& info, bool hasLinearBlending) {
return info.colorType() == kARGB_4444_SkColorType
|| info.colorType() == kIndex_8_SkColorType
- || (info.colorType() == kRGB_565_SkColorType && hasLinearBlending && needSRGB);
+ || (info.colorType() == kRGB_565_SkColorType
+ && hasLinearBlending
+ && info.colorSpace()->isSRGB());
}
-
void Texture::upload(Bitmap& bitmap) {
if (!bitmap.readyToDraw()) {
ALOGE("Cannot generate texture from bitmap");
@@ -284,23 +280,59 @@ void Texture::upload(Bitmap& bitmap) {
setDefaultParams = true;
}
- sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeSRGB();
- bool needSRGB = bitmap.info().colorSpace() == sRGB.get();
+ bool hasLinearBlending = mCaches.extensions().hasLinearBlending();
+ bool needSRGB = transferFunctionCloseToSRGB(bitmap.info().colorSpace());
GLint internalFormat, format, type;
- colorTypeToGlFormatAndType(mCaches, bitmap.colorType(), needSRGB, &internalFormat, &format, &type);
+ colorTypeToGlFormatAndType(mCaches, bitmap.colorType(),
+ needSRGB && hasLinearBlending, &internalFormat, &format, &type);
+
+ mConnector.reset();
+
+ // RGBA16F is always extended sRGB, alpha masks don't have color profiles
+ if (internalFormat != GL_RGBA16F && internalFormat != GL_ALPHA) {
+ SkColorSpace* colorSpace = bitmap.info().colorSpace();
+ // If the bitmap is sRGB we don't need conversion
+ if (colorSpace != nullptr && !colorSpace->isSRGB()) {
+ SkMatrix44 xyzMatrix(SkMatrix44::kUninitialized_Constructor);
+ if (!colorSpace->toXYZD50(&xyzMatrix)) {
+ ALOGW("Incompatible color space!");
+ } else {
+ SkColorSpaceTransferFn fn;
+ if (!colorSpace->isNumericalTransferFn(&fn)) {
+ ALOGW("Incompatible color space, no numerical transfer function!");
+ } else {
+ float data[16];
+ xyzMatrix.asColMajorf(data);
+
+ ColorSpace::TransferParameters p =
+ {fn.fG, fn.fA, fn.fB, fn.fC, fn.fD, fn.fE, fn.fF};
+ ColorSpace src("Unnamed", mat4f((const float*) &data[0]).upperLeft(), p);
+ mConnector.reset(new ColorSpaceConnector(src, ColorSpace::sRGB()));
+
+ // A non-sRGB color space might have a transfer function close enough to sRGB
+ // that we can save shader instructions by using an sRGB sampler
+ // This is only possible if we have hardware support for sRGB textures
+ if (needSRGB && internalFormat == GL_RGBA
+ && mCaches.extensions().hasSRGB() && !bitmap.isHardware()) {
+ internalFormat = GL_SRGB8_ALPHA8;
+ }
+ }
+ }
+ }
+ }
GLenum target = bitmap.isHardware() ? GL_TEXTURE_EXTERNAL_OES : GL_TEXTURE_2D;
- needsAlloc |= updateSize(bitmap.width(), bitmap.height(), internalFormat, format, target);
+ needsAlloc |= updateLayout(bitmap.width(), bitmap.height(), internalFormat, format, target);
blend = !bitmap.isOpaque();
mCaches.textureState().bindTexture(mTarget, mId);
// TODO: Handle sRGB gray bitmaps
- bool hasLinearBlending = mCaches.extensions().hasLinearBlending();
- if (CC_UNLIKELY(hasUnsupportedColorType(bitmap.info(), hasLinearBlending, sRGB.get()))) {
+ if (CC_UNLIKELY(hasUnsupportedColorType(bitmap.info(), hasLinearBlending))) {
SkBitmap skBitmap;
bitmap.getSkBitmap(&skBitmap);
+ sk_sp<SkColorSpace> sRGB = SkColorSpace::MakeSRGB();
SkBitmap rgbaBitmap = uploadToN32(skBitmap, hasLinearBlending, std::move(sRGB));
uploadToTexture(needsAlloc, internalFormat, format, type, rgbaBitmap.rowBytesAsPixels(),
rgbaBitmap.bytesPerPixel(), rgbaBitmap.width(),
@@ -333,9 +365,28 @@ void Texture::wrap(GLuint id, uint32_t width, uint32_t height,
mFormat = format;
mInternalFormat = internalFormat;
mTarget = target;
+ mConnector.reset();
// We're wrapping an existing texture, so don't double count this memory
notifySizeChanged(0);
}
+TransferFunctionType Texture::getTransferFunctionType() const {
+ if (mConnector.get() != nullptr && mInternalFormat != GL_SRGB8_ALPHA8) {
+ const ColorSpace::TransferParameters& p = mConnector->getSource().getTransferParameters();
+ if (MathUtils::isZero(p.e) && MathUtils::isZero(p.f)) {
+ if (MathUtils::areEqual(p.a, 1.0f) && MathUtils::isZero(p.b)
+ && MathUtils::isZero(p.c) && MathUtils::isZero(p.d)) {
+ if (MathUtils::areEqual(p.g, 1.0f)) {
+ return TransferFunctionType::None;
+ }
+ return TransferFunctionType::Gamma;
+ }
+ return TransferFunctionType::Limited;
+ }
+ return TransferFunctionType::Full;
+ }
+ return TransferFunctionType::None;
+}
+
}; // namespace uirenderer
}; // namespace android