Merge "Enable wide color gamut rendering"

This commit is contained in:
TreeHugger Robot
2017-06-02 20:07:49 +00:00
committed by Android (Google) Code Review
22 changed files with 274 additions and 37 deletions

View File

@@ -33,17 +33,24 @@
#include <ui/DisplayInfo.h>
#include <ui/PixelFormat.h>
#include <system/graphics.h>
// TODO: Fix Skia.
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#include <SkImageEncoder.h>
#include <SkData.h>
#include <SkColorSpace.h>
#pragma GCC diagnostic pop
using namespace android;
static uint32_t DEFAULT_DISPLAY_ID = ISurfaceComposer::eDisplayIdMain;
#define COLORSPACE_UNKNOWN 0
#define COLORSPACE_SRGB 1
#define COLORSPACE_DISPLAY_P3 2
static void usage(const char* pname)
{
fprintf(stderr,
@@ -67,6 +74,31 @@ static SkColorType flinger2skia(PixelFormat f)
}
}
static sk_sp<SkColorSpace> dataSpaceToColorSpace(android_dataspace d)
{
switch (d) {
case HAL_DATASPACE_V0_SRGB:
return SkColorSpace::MakeSRGB();
case HAL_DATASPACE_DISPLAY_P3:
return SkColorSpace::MakeRGB(
SkColorSpace::kSRGB_RenderTargetGamma, SkColorSpace::kDCIP3_D65_Gamut);
default:
return nullptr;
}
}
static uint32_t dataSpaceToInt(android_dataspace d)
{
switch (d) {
case HAL_DATASPACE_V0_SRGB:
return COLORSPACE_SRGB;
case HAL_DATASPACE_DISPLAY_P3:
return COLORSPACE_DISPLAY_P3;
default:
return COLORSPACE_UNKNOWN;
}
}
static status_t notifyMediaScanner(const char* fileName) {
String8 cmd("am broadcast -a android.intent.action.MEDIA_SCANNER_SCAN_FILE -d file://");
String8 fileUrl("\"");
@@ -139,6 +171,7 @@ int main(int argc, char** argv)
void const* base = NULL;
uint32_t w, s, h, f;
android_dataspace d;
size_t size = 0;
// Maps orientations from DisplayInfo to ISurfaceComposer
@@ -177,13 +210,15 @@ int main(int argc, char** argv)
h = screenshot.getHeight();
s = screenshot.getStride();
f = screenshot.getFormat();
d = screenshot.getDataSpace();
size = screenshot.getSize();
}
if (base != NULL) {
if (png) {
const SkImageInfo info =
SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType);
SkImageInfo::Make(w, h, flinger2skia(f), kPremul_SkAlphaType,
dataSpaceToColorSpace(d));
SkPixmap pixmap(info, base, s * bytesPerPixel(f));
struct FDWStream final : public SkWStream {
size_t fBytesWritten = 0;
@@ -200,9 +235,11 @@ int main(int argc, char** argv)
notifyMediaScanner(fn);
}
} else {
uint32_t c = dataSpaceToInt(d);
write(fd, &w, 4);
write(fd, &h, 4);
write(fd, &f, 4);
write(fd, &c, 4);
size_t Bpp = bytesPerPixel(f);
for (size_t y=0 ; y<h ; y++) {
write(fd, base, w*Bpp);

View File

@@ -358,7 +358,6 @@ public final class ThreadedRenderer {
private long mNativeProxy;
private boolean mInitialized = false;
private RenderNode mRootNode;
private Choreographer mChoreographer;
private boolean mRootNodeNeedsUpdate;
private boolean mEnabled;
@@ -425,8 +424,6 @@ public final class ThreadedRenderer {
/**
* Indicates whether threaded rendering is currently requested but not
* necessarily enabled yet.
*
* @return True to request threaded rendering, false otherwise.
*/
void setRequested(boolean requested) {
mRequested = requested;
@@ -596,6 +593,13 @@ public final class ThreadedRenderer {
nSetOpaque(mNativeProxy, opaque && !mHasInsets);
}
/**
* Enable/disable wide gamut rendering on this renderer.
*/
void setWideGamut(boolean wideGamut) {
nSetWideGamut(mNativeProxy, wideGamut);
}
/**
* Gets the current width of the surface. This is the width that the surface
* was last set to in a call to {@link #setup(int, int, View.AttachInfo, Rect)}.
@@ -933,11 +937,11 @@ public final class ThreadedRenderer {
if (mInitialized) return;
mInitialized = true;
mAppContext = context.getApplicationContext();
initSched(context, renderProxy);
initSched(renderProxy);
initGraphicsStats();
}
private void initSched(Context context, long renderProxy) {
private void initSched(long renderProxy) {
try {
int tid = nGetRenderThreadTid(renderProxy);
ActivityManager.getService().setRenderThread(tid);
@@ -1007,6 +1011,7 @@ public final class ThreadedRenderer {
private static native void nSetLightCenter(long nativeProxy,
float lightX, float lightY, float lightZ);
private static native void nSetOpaque(long nativeProxy, boolean opaque);
private static native void nSetWideGamut(long nativeProxy, boolean wideGamut);
private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
private static native void nDestroy(long nativeProxy, long rootRenderNode);
private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);

View File

@@ -35,6 +35,7 @@ import android.app.ResourcesManager;
import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.res.CompatibilityInfo;
import android.content.res.Configuration;
@@ -960,8 +961,12 @@ public final class ViewRootImpl implements ViewParent,
final boolean hasSurfaceInsets = insets.left != 0 || insets.right != 0
|| insets.top != 0 || insets.bottom != 0;
final boolean translucent = attrs.format != PixelFormat.OPAQUE || hasSurfaceInsets;
final boolean wideGamut =
attrs.getColorMode() == ActivityInfo.COLOR_MODE_WIDE_COLOR_GAMUT;
mAttachInfo.mThreadedRenderer = ThreadedRenderer.create(mContext, translucent,
attrs.getTitle().toString());
mAttachInfo.mThreadedRenderer.setWideGamut(wideGamut);
if (mAttachInfo.mThreadedRenderer != null) {
mAttachInfo.mHardwareAccelerated =
mAttachInfo.mHardwareAccelerationRequested = true;

View File

@@ -2090,6 +2090,7 @@ public interface WindowManager extends ViewManager {
out.writeInt(needsMenuKey);
out.writeInt(accessibilityIdOfAnchor);
TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
out.writeInt(mColorMode);
out.writeLong(hideTimeoutMilliseconds);
}
@@ -2144,6 +2145,7 @@ public interface WindowManager extends ViewManager {
needsMenuKey = in.readInt();
accessibilityIdOfAnchor = in.readInt();
accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mColorMode = in.readInt();
hideTimeoutMilliseconds = in.readLong();
}
@@ -2189,6 +2191,8 @@ public interface WindowManager extends ViewManager {
@TestApi
public static final int ACCESSIBILITY_TITLE_CHANGED = 1 << 25;
/** {@hide} */
public static final int COLOR_MODE_CHANGED = 1 << 26;
/** {@hide} */
public static final int EVERYTHING_CHANGED = 0xffffffff;
// internal buffer to backup/restore parameters under compatibility mode.
@@ -2366,6 +2370,11 @@ public interface WindowManager extends ViewManager {
changes |= ACCESSIBILITY_TITLE_CHANGED;
}
if (mColorMode != o.mColorMode) {
mColorMode = o.mColorMode;
changes |= COLOR_MODE_CHANGED;
}
// This can't change, it's only set at window creation time.
hideTimeoutMilliseconds = o.hideTimeoutMilliseconds;

View File

@@ -221,11 +221,20 @@ static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz,
return NULL;
}
}
sk_sp<SkColorSpace> colorSpace;
if (screenshot->getDataSpace() == HAL_DATASPACE_DISPLAY_P3) {
colorSpace = SkColorSpace::MakeRGB(
SkColorSpace::kSRGB_RenderTargetGamma, SkColorSpace::kDCIP3_D65_Gamut);
} else {
colorSpace = SkColorSpace::MakeSRGB();
}
SkImageInfo screenshotInfo = SkImageInfo::Make(screenshot->getWidth(),
screenshot->getHeight(),
colorType,
alphaType,
GraphicsJNI::defaultColorSpace());
colorSpace);
const size_t rowBytes =
screenshot->getStride() * android::bytesPerPixel(screenshot->getFormat());

View File

@@ -681,6 +681,12 @@ static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
proxy->setOpaque(opaque);
}
static void android_view_ThreadedRenderer_setWideGamut(JNIEnv* env, jobject clazz,
jlong proxyPtr, jboolean wideGamut) {
RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
proxy->setWideGamut(wideGamut);
}
static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
@@ -982,6 +988,7 @@ static const JNINativeMethod gMethods[] = {
{ "nSetup", "(JFII)V", (void*) android_view_ThreadedRenderer_setup },
{ "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter },
{ "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
{ "nSetWideGamut", "(JZ)V", (void*) android_view_ThreadedRenderer_setWideGamut },
{ "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
{ "nDestroy", "(JJ)V", (void*) android_view_ThreadedRenderer_destroy },
{ "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },

View File

@@ -155,7 +155,8 @@ void SkiaOpenGLPipeline::onStop() {
}
}
bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior) {
bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,
ColorMode colorMode) {
if (mEglSurface != EGL_NO_SURFACE) {
mEglManager.destroySurface(mEglSurface);
@@ -163,7 +164,8 @@ bool SkiaOpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior)
}
if (surface) {
mEglSurface = mEglManager.createSurface(surface);
const bool wideColorGamut = colorMode == ColorMode::WideColorGamut;
mEglSurface = mEglManager.createSurface(surface, wideColorGamut);
}
if (mEglSurface != EGL_NO_SURFACE) {

View File

@@ -40,7 +40,8 @@ public:
FrameInfo* currentFrameInfo, bool* requireSwap) override;
bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override;
DeferredLayerUpdater* createTextureLayer() override;
bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior) override;
bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior,
renderthread::ColorMode colorMode) override;
void onStop() override;
bool isSurfaceReady() override;
bool isContextReady() override;

View File

@@ -131,13 +131,15 @@ DeferredLayerUpdater* SkiaVulkanPipeline::createTextureLayer() {
void SkiaVulkanPipeline::onStop() {
}
bool SkiaVulkanPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior) {
bool SkiaVulkanPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior,
ColorMode colorMode) {
if (mVkSurface) {
mVkManager.destroySurface(mVkSurface);
mVkSurface = nullptr;
}
if (surface) {
// TODO: handle color mode
mVkSurface = mVkManager.createSurface(surface);
}

View File

@@ -41,7 +41,8 @@ public:
FrameInfo* currentFrameInfo, bool* requireSwap) override;
bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override;
DeferredLayerUpdater* createTextureLayer() override;
bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior) override;
bool setSurface(Surface* window, renderthread::SwapBehavior swapBehavior,
renderthread::ColorMode colorMode) override;
void onStop() override;
bool isSurfaceReady() override;
bool isContextReady() override;

View File

@@ -186,7 +186,8 @@ void CanvasContext::setSurface(Surface* surface) {
mNativeSurface = surface;
bool hasSurface = mRenderPipeline->setSurface(surface, mSwapBehavior);
ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::Srgb;
bool hasSurface = mRenderPipeline->setSurface(surface, mSwapBehavior, colorMode);
mFrameNumber = -1;
@@ -241,6 +242,10 @@ void CanvasContext::setOpaque(bool opaque) {
mOpaque = opaque;
}
void CanvasContext::setWideGamut(bool wideGamut) {
mWideColorGamut = wideGamut;
}
bool CanvasContext::makeCurrent() {
if (mStopped) return false;

View File

@@ -128,6 +128,7 @@ public:
uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
void setLightCenter(const Vector3& lightCenter);
void setOpaque(bool opaque);
void setWideGamut(bool wideGamut);
bool makeCurrent();
void prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
int64_t syncQueued, RenderNode* target);
@@ -240,6 +241,7 @@ private:
nsecs_t mLastDropVsync = 0;
bool mOpaque;
bool mWideColorGamut = false;
BakedOpRenderer::LightInfo mLightInfo;
FrameBuilder::LightGeometry mLightGeometry = { {0, 0, 0}, 0 };

View File

@@ -76,12 +76,16 @@ const char* EglManager::eglErrorString() {
static struct {
bool bufferAge = false;
bool setDamage = false;
bool noConfigContext = false;
bool pixelFormatFloat = false;
bool glColorSpace = false;
} EglExtensions;
EglManager::EglManager(RenderThread& thread)
: mRenderThread(thread)
, mEglDisplay(EGL_NO_DISPLAY)
, mEglConfig(nullptr)
, mEglConfigWideGamut(nullptr)
, mEglContext(EGL_NO_CONTEXT)
, mPBufferSurface(EGL_NO_SURFACE)
, mCurrentSurface(EGL_NO_SURFACE) {
@@ -116,7 +120,7 @@ void EglManager::initialize() {
}
}
loadConfig();
loadConfigs();
createContext();
createPBufferSurface();
makeCurrent(mPBufferSurface);
@@ -143,6 +147,7 @@ void EglManager::initialize() {
void EglManager::initExtensions() {
auto extensions = StringUtils::split(
eglQueryString(mEglDisplay, EGL_EXTENSIONS));
// For our purposes we don't care if EGL_BUFFER_AGE is a result of
// EGL_EXT_buffer_age or EGL_KHR_partial_update as our usage is covered
// under EGL_KHR_partial_update and we don't need the expanded scope
@@ -152,13 +157,17 @@ void EglManager::initExtensions() {
EglExtensions.setDamage = extensions.has("EGL_KHR_partial_update");
LOG_ALWAYS_FATAL_IF(!extensions.has("EGL_KHR_swap_buffers_with_damage"),
"Missing required extension EGL_KHR_swap_buffers_with_damage");
EglExtensions.glColorSpace = extensions.has("EGL_KHR_gl_colorspace");
EglExtensions.noConfigContext = extensions.has("EGL_KHR_no_config_context");
EglExtensions.pixelFormatFloat = extensions.has("EGL_EXT_pixel_format_float");
}
bool EglManager::hasEglContext() {
return mEglDisplay != EGL_NO_DISPLAY;
}
void EglManager::loadConfig() {
void EglManager::loadConfigs() {
ALOGD("Swap behavior %d", static_cast<int>(mSwapBehavior));
EGLint swapBehavior = (mSwapBehavior == SwapBehavior::Preserved)
? EGL_SWAP_BEHAVIOR_PRESERVED_BIT : 0;
@@ -175,19 +184,44 @@ void EglManager::loadConfig() {
EGL_NONE
};
EGLint num_configs = 1;
if (!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, num_configs, &num_configs)
|| num_configs != 1) {
EGLint numConfigs = 1;
if (!eglChooseConfig(mEglDisplay, attribs, &mEglConfig, numConfigs, &numConfigs)
|| numConfigs != 1) {
if (mSwapBehavior == SwapBehavior::Preserved) {
// Try again without dirty regions enabled
ALOGW("Failed to choose config with EGL_SWAP_BEHAVIOR_PRESERVED, retrying without...");
mSwapBehavior = SwapBehavior::Discard;
loadConfig();
loadConfigs();
return; // the call to loadConfigs() we just made picks the wide gamut config
} else {
// Failed to get a valid config
LOG_ALWAYS_FATAL("Failed to choose config, error = %s", eglErrorString());
}
}
if (EglExtensions.pixelFormatFloat) {
// If we reached this point, we have a valid swap behavior
EGLint attribs16F[] = {
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
EGL_COLOR_COMPONENT_TYPE_EXT, EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT,
EGL_RED_SIZE, 16,
EGL_GREEN_SIZE, 16,
EGL_BLUE_SIZE, 16,
EGL_ALPHA_SIZE, 16,
EGL_DEPTH_SIZE, 0,
EGL_STENCIL_SIZE, Stencil::getStencilSize(),
EGL_SURFACE_TYPE, EGL_WINDOW_BIT | swapBehavior,
EGL_NONE
};
numConfigs = 1;
if (!eglChooseConfig(mEglDisplay, attribs16F, &mEglConfigWideGamut, numConfigs, &numConfigs)
|| numConfigs != 1) {
LOG_ALWAYS_FATAL(
"Device claims wide gamut support, cannot find matching config, error = %s",
eglErrorString());
}
}
}
void EglManager::createContext() {
@@ -195,7 +229,9 @@ void EglManager::createContext() {
EGL_CONTEXT_CLIENT_VERSION, GLES_VERSION,
EGL_NONE
};
mEglContext = eglCreateContext(mEglDisplay, mEglConfig, EGL_NO_CONTEXT, attribs);
mEglContext = eglCreateContext(mEglDisplay,
EglExtensions.noConfigContext ? ((EGLConfig) nullptr) : mEglConfig,
EGL_NO_CONTEXT, attribs);
LOG_ALWAYS_FATAL_IF(mEglContext == EGL_NO_CONTEXT,
"Failed to create context, error = %s", eglErrorString());
}
@@ -210,18 +246,60 @@ void EglManager::createPBufferSurface() {
}
}
EGLSurface EglManager::createSurface(EGLNativeWindowType window) {
EGLSurface EglManager::createSurface(EGLNativeWindowType window, bool wideColorGamut) {
initialize();
wideColorGamut = wideColorGamut && EglExtensions.glColorSpace
&& EglExtensions.pixelFormatFloat && EglExtensions.noConfigContext;
// The color space we want to use depends on whether linear blending is turned
// on and whether the app has requested wide color gamut rendering. When wide
// color gamut rendering is off, the app simply renders in the display's native
// color gamut.
//
// When wide gamut rendering is off:
// - Blending is done by default in gamma space, which requires using a
// linear EGL color space (the GPU uses the color values as is)
// - If linear blending is on, we must use the sRGB EGL color space (the
// GPU will perform sRGB to linear and linear to SRGB conversions before
// and after blending)
//
// When wide gamut rendering is on we cannot rely on the GPU performing
// linear blending for us. We use two different color spaces to tag the
// surface appropriately for SurfaceFlinger:
// - Gamma blending (default) requires the use of the scRGB-nl color space
// - Linear blending requires the use of the scRGB color space
// Not all Android targets support the EGL_GL_COLOR_SPACE_KHR extension
// We insert to placeholders to set EGL_GL_COLORSPACE_KHR and its value.
// According to section 3.4.1 of the EGL specification, the attributes
// list is considered empty if the first entry is EGL_NONE
EGLint attribs[] = {
#ifdef ANDROID_ENABLE_LINEAR_BLENDING
EGL_GL_COLORSPACE_KHR, EGL_GL_COLORSPACE_SRGB_KHR,
EGL_COLORSPACE, EGL_COLORSPACE_sRGB,
#endif
EGL_NONE, EGL_NONE,
EGL_NONE
};
EGLSurface surface = eglCreateWindowSurface(mEglDisplay, mEglConfig, window, attribs);
if (EglExtensions.glColorSpace) {
attribs[0] = EGL_GL_COLORSPACE_KHR;
#ifdef ANDROID_ENABLE_LINEAR_BLENDING
if (wideColorGamut) {
attribs[1] = EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT;
} else {
attribs[1] = EGL_GL_COLORSPACE_SRGB_KHR;
}
#else
if (wideColorGamut) {
// TODO: this should be using scRGB-nl, not scRGB, we need an extension for this
// TODO: in the meantime SurfaceFlinger just assumes that scRGB is scRGB-nl
attribs[1] = EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT;
} else {
attribs[1] = EGL_GL_COLORSPACE_LINEAR_KHR;
}
#endif
}
EGLSurface surface = eglCreateWindowSurface(mEglDisplay,
wideColorGamut ? mEglConfigWideGamut : mEglConfig, window, attribs);
LOG_ALWAYS_FATAL_IF(surface == EGL_NO_SURFACE,
"Failed to create EGLSurface for window %p, eglErr = %s",
(void*) window, eglErrorString());

View File

@@ -39,7 +39,7 @@ public:
bool hasEglContext();
EGLSurface createSurface(EGLNativeWindowType window);
EGLSurface createSurface(EGLNativeWindowType window, bool wideColorGamut);
void destroySurface(EGLSurface surface);
void destroy();
@@ -68,7 +68,7 @@ private:
void initExtensions();
void createPBufferSurface();
void loadConfig();
void loadConfigs();
void createContext();
EGLint queryBufferAge(EGLSurface surface);
@@ -76,6 +76,7 @@ private:
EGLDisplay mEglDisplay;
EGLConfig mEglConfig;
EGLConfig mEglConfigWideGamut;
EGLContext mEglContext;
EGLSurface mPBufferSurface;

View File

@@ -44,6 +44,12 @@ enum class MakeCurrentResult {
Succeeded
};
enum class ColorMode {
Srgb,
WideColorGamut,
// Hdr
};
class Frame;
class IRenderPipeline {
@@ -61,7 +67,7 @@ public:
FrameInfo* currentFrameInfo, bool* requireSwap) = 0;
virtual bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) = 0;
virtual DeferredLayerUpdater* createTextureLayer() = 0;
virtual bool setSurface(Surface* window, SwapBehavior swapBehavior) = 0;
virtual bool setSurface(Surface* window, SwapBehavior swapBehavior, ColorMode colorMode) = 0;
virtual void onStop() = 0;
virtual bool isSurfaceReady() = 0;
virtual bool isContextReady() = 0;

View File

@@ -146,7 +146,7 @@ void OpenGLPipeline::onStop() {
}
}
bool OpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior) {
bool OpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior, ColorMode colorMode) {
if (mEglSurface != EGL_NO_SURFACE) {
mEglManager.destroySurface(mEglSurface);
@@ -154,7 +154,8 @@ bool OpenGLPipeline::setSurface(Surface* surface, SwapBehavior swapBehavior) {
}
if (surface) {
mEglSurface = mEglManager.createSurface(surface);
const bool wideColorGamut = colorMode == ColorMode::WideColorGamut;
mEglSurface = mEglManager.createSurface(surface, wideColorGamut);
}
if (mEglSurface != EGL_NO_SURFACE) {

View File

@@ -44,7 +44,7 @@ public:
FrameInfo* currentFrameInfo, bool* requireSwap) override;
bool copyLayerInto(DeferredLayerUpdater* layer, SkBitmap* bitmap) override;
DeferredLayerUpdater* createTextureLayer() override;
bool setSurface(Surface* window, SwapBehavior swapBehavior) override;
bool setSurface(Surface* window, SwapBehavior swapBehavior, ColorMode colorMode) override;
void onStop() override;
bool isSurfaceReady() override;
bool isContextReady() override;

View File

@@ -227,6 +227,18 @@ void RenderProxy::setOpaque(bool opaque) {
post(task);
}
CREATE_BRIDGE2(setWideGamut, CanvasContext* context, bool wideGamut) {
args->context->setWideGamut(args->wideGamut);
return nullptr;
}
void RenderProxy::setWideGamut(bool wideGamut) {
SETUP_TASK(setWideGamut);
args->context = mContext;
args->wideGamut = wideGamut;
post(task);
}
int64_t* RenderProxy::frameInfo() {
return mDrawFrameTask.frameInfo();
}

View File

@@ -69,7 +69,7 @@ namespace DumpFlags {
*/
class ANDROID_API RenderProxy {
public:
ANDROID_API RenderProxy(bool translucent, RenderNode* rootNode, IContextFactory* contextFactory);
ANDROID_API RenderProxy(bool opaque, RenderNode* rootNode, IContextFactory* contextFactory);
ANDROID_API virtual ~RenderProxy();
// Won't take effect until next EGLSurface creation
@@ -85,6 +85,7 @@ public:
uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
ANDROID_API void setLightCenter(const Vector3& lightCenter);
ANDROID_API void setOpaque(bool opaque);
ANDROID_API void setWideGamut(bool wideGamut);
ANDROID_API int64_t* frameInfo();
ANDROID_API int syncAndDrawFrame();
ANDROID_API void destroy();

View File

@@ -100,7 +100,7 @@ final class Screenshooter {
// Rotate the screenshot to the current orientation
if (rotation != ROTATION_FREEZE_0) {
Bitmap unrotatedScreenShot = Bitmap.createBitmap(displayWidth, displayHeight,
Bitmap.Config.ARGB_8888);
Bitmap.Config.ARGB_8888, screenShot.hasAlpha(), screenShot.getColorSpace());
Canvas canvas = new Canvas(unrotatedScreenShot);
canvas.translate(unrotatedScreenShot.getWidth() / 2,
unrotatedScreenShot.getHeight() / 2);

View File

@@ -578,7 +578,8 @@ class GlobalScreenshot {
if (requiresRotation) {
// Rotate the screenshot to the current orientation
Bitmap ss = Bitmap.createBitmap(mDisplayMetrics.widthPixels,
mDisplayMetrics.heightPixels, Bitmap.Config.ARGB_8888);
mDisplayMetrics.heightPixels, Bitmap.Config.ARGB_8888,
mScreenBitmap.hasAlpha(), mScreenBitmap.getColorSpace());
Canvas c = new Canvas(ss);
c.translate(ss.getWidth() / 2, ss.getHeight() / 2);
c.rotate(degrees);

View File

@@ -21,6 +21,7 @@ import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.util.MathUtils;
import android.util.Slog;
import android.util.SparseArray;
@@ -48,6 +49,10 @@ public class DisplayTransformManager {
*/
public static final int LEVEL_COLOR_MATRIX_INVERT_COLOR = 300;
private static final int SURFACE_FLINGER_TRANSACTION_COLOR_MATRIX = 1015;
private static final int SURFACE_FLINGER_TRANSACTION_DALTONIZER = 1014;
private static final int SURFACE_FLINGER_TRANSACTION_SATURATION = 1022;
/**
* Map of level -> color transformation matrix.
*/
@@ -66,6 +71,10 @@ public class DisplayTransformManager {
@GuardedBy("mDaltonizerModeLock")
private int mDaltonizerMode = -1;
private final Object mSaturationLock = new Object();
@GuardedBy("mSaturationLock")
private float mSaturation = 1.0f;
/* package */ DisplayTransformManager() {
}
@@ -155,6 +164,30 @@ public class DisplayTransformManager {
}
}
/**
* Returns the current saturation.
*/
public float getSaturation() {
synchronized (mSaturationLock) {
return mSaturation;
}
}
/**
* Sets the saturation level of the display. The default value is 1.0.
*
* @param saturation A value between 0 (0% saturation, grayscale) and 2 (100% extra saturation)
*/
public void setSaturation(float saturation) {
synchronized (mSaturationLock) {
saturation = MathUtils.constrain(saturation, 0.0f, 2.0f);
if (mSaturation != saturation) {
mSaturation = saturation;
applySaturation(saturation);
}
}
}
/**
* Propagates the provided color transformation matrix to the SurfaceFlinger.
*/
@@ -172,7 +205,7 @@ public class DisplayTransformManager {
data.writeInt(0);
}
try {
flinger.transact(1015, data, null, 0);
flinger.transact(SURFACE_FLINGER_TRANSACTION_COLOR_MATRIX, data, null, 0);
} catch (RemoteException ex) {
Slog.e(TAG, "Failed to set color transform", ex);
} finally {
@@ -191,7 +224,7 @@ public class DisplayTransformManager {
data.writeInterfaceToken("android.ui.ISurfaceComposer");
data.writeInt(mode);
try {
flinger.transact(1014, data, null, 0);
flinger.transact(SURFACE_FLINGER_TRANSACTION_DALTONIZER, data, null, 0);
} catch (RemoteException ex) {
Slog.e(TAG, "Failed to set Daltonizer mode", ex);
} finally {
@@ -199,4 +232,23 @@ public class DisplayTransformManager {
}
}
}
/**
* Propagates the provided saturation to the SurfaceFlinger.
*/
private static void applySaturation(float saturation) {
final IBinder flinger = ServiceManager.getService("SurfaceFlinger");
if (flinger != null) {
final Parcel data = Parcel.obtain();
data.writeInterfaceToken("android.ui.ISurfaceComposer");
data.writeFloat(saturation);
try {
flinger.transact(SURFACE_FLINGER_TRANSACTION_SATURATION, data, null, 0);
} catch (RemoteException ex) {
Slog.e(TAG, "Failed to set saturation", ex);
} finally {
data.recycle();
}
}
}
}