Merge "sdm:scalar:intialize scaling params."
diff --git a/Android.mk b/Android.mk
index 60a48f5..6eef2fc 100644
--- a/Android.mk
+++ b/Android.mk
@@ -3,7 +3,7 @@
ifneq ($(TARGET_IS_HEADLESS), true)
display-hals += libcopybit liblight libmemtrack hdmi_cec \
- $(sdm-libs)/hwc $(sdm-libs)/hwc2
+ $(sdm-libs)/hwc $(sdm-libs)/hwc2 gpu_tonemapper
endif
ifneq ($(TARGET_USES_GRALLOC1), true)
diff --git a/common.mk b/common.mk
index d44a664..6476dfd 100644
--- a/common.mk
+++ b/common.mk
@@ -17,6 +17,7 @@
common_includes := $(display_top)/libqdutils
common_includes += $(display_top)/libqservice
+common_includes += $(display_top)/gpu_tonemapper
ifneq ($(TARGET_IS_HEADLESS), true)
common_includes += $(display_top)/libcopybit
endif
diff --git a/gpu_tonemapper/Android.mk b/gpu_tonemapper/Android.mk
new file mode 100644
index 0000000..9ae3840
--- /dev/null
+++ b/gpu_tonemapper/Android.mk
@@ -0,0 +1,23 @@
+LOCAL_PATH := $(call my-dir)
+include $(LOCAL_PATH)/../common.mk
+include $(CLEAR_VARS)
+
+LOCAL_COPY_HEADERS_TO := $(common_header_export_path)
+LOCAL_COPY_HEADERS := TonemapFactory.h Tonemapper.h
+LOCAL_SHARED_LIBRARIES := libEGL libGLESv2 libui libutils liblog
+include $(BUILD_COPY_HEADERS)
+
+LOCAL_MODULE := libgpu_tonemapper
+LOCAL_MODULE_TAGS := optional
+LOCAL_C_INCLUDES := $(TARGET_OUT_HEADERS)/qcom/display/
+
+LOCAL_CFLAGS := -Wno-missing-field-initializers -Wall \
+ -Wno-unused-parameter -std=c++11 -DLOG_TAG=\"GPU_TONEMAPPER\"
+
+LOCAL_SRC_FILES := TonemapFactory.cpp \
+ glengine.cpp \
+ EGLImageBuffer.cpp \
+ EGLImageWrapper.cpp \
+ Tonemapper.cpp
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/gpu_tonemapper/EGLImageBuffer.cpp b/gpu_tonemapper/EGLImageBuffer.cpp
new file mode 100644
index 0000000..e64e16f
--- /dev/null
+++ b/gpu_tonemapper/EGLImageBuffer.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright 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 "EGLImageBuffer.h"
+#include <cutils/native_handle.h>
+#include <gralloc_priv.h>
+#include <ui/GraphicBuffer.h>
+#include <map>
+#include "EGLImageWrapper.h"
+#include "glengine.h"
+#define EGL_PROTECTED_CONTENT_EXT 0x32C0
+
+//-----------------------------------------------------------------------------
+EGLImageKHR create_eglImage(android::sp<android::GraphicBuffer> graphicBuffer)
+//-----------------------------------------------------------------------------
+{
+ bool isProtected = (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+ EGLint attrs[] = {EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
+ isProtected ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
+ isProtected ? EGL_TRUE : EGL_NONE, EGL_NONE};
+
+ EGLImageKHR eglImage = eglCreateImageKHR(
+ eglGetCurrentDisplay(), (EGLContext)EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+ (EGLClientBuffer)(graphicBuffer->getNativeBuffer()), attrs);
+
+ return eglImage;
+}
+
+//-----------------------------------------------------------------------------
+EGLImageBuffer::EGLImageBuffer(android::sp<android::GraphicBuffer> graphicBuffer)
+//-----------------------------------------------------------------------------
+{
+ // this->graphicBuffer = graphicBuffer;
+ this->eglImageID = create_eglImage(graphicBuffer);
+ this->width = graphicBuffer->getWidth();
+ this->height = graphicBuffer->getHeight();
+
+ textureID = 0;
+ renderbufferID = 0;
+ framebufferID = 0;
+}
+
+//-----------------------------------------------------------------------------
+EGLImageBuffer::~EGLImageBuffer()
+//-----------------------------------------------------------------------------
+{
+ if (textureID != 0) {
+ GL(glDeleteTextures(1, &textureID));
+ textureID = 0;
+ }
+
+ if (renderbufferID != 0) {
+ GL(glDeleteRenderbuffers(1, &renderbufferID));
+ renderbufferID = 0;
+ }
+
+ if (framebufferID != 0) {
+ GL(glDeleteFramebuffers(1, &framebufferID));
+ framebufferID = 0;
+ }
+}
+
+//-----------------------------------------------------------------------------
+int EGLImageBuffer::getWidth()
+//-----------------------------------------------------------------------------
+{
+ return width;
+}
+
+//-----------------------------------------------------------------------------
+int EGLImageBuffer::getHeight()
+//-----------------------------------------------------------------------------
+{
+ return height;
+}
+
+//-----------------------------------------------------------------------------
+unsigned int EGLImageBuffer::getTexture()
+//-----------------------------------------------------------------------------
+{
+ if (textureID == 0) {
+ bindAsTexture();
+ }
+
+ return textureID;
+}
+
+//-----------------------------------------------------------------------------
+unsigned int EGLImageBuffer::getFramebuffer()
+//-----------------------------------------------------------------------------
+{
+ if (framebufferID == 0) {
+ bindAsFramebuffer();
+ }
+
+ return framebufferID;
+}
+
+//-----------------------------------------------------------------------------
+void EGLImageBuffer::bindAsTexture()
+//-----------------------------------------------------------------------------
+{
+ if (textureID == 0) {
+ GL(glGenTextures(1, &textureID));
+ int target = 0x8D65;
+ GL(glBindTexture(target, textureID));
+ GL(glTexParameteri(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
+ GL(glTexParameteri(target, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
+ GL(glTexParameteri(target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
+ GL(glTexParameteri(target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
+
+ GL(glEGLImageTargetTexture2DOES(0x8D65, eglImageID));
+ }
+
+ GL(glBindTexture(0x8D65, textureID));
+}
+
+//-----------------------------------------------------------------------------
+void EGLImageBuffer::bindAsFramebuffer()
+//-----------------------------------------------------------------------------
+{
+ if (renderbufferID == 0) {
+ GL(glGenFramebuffers(1, &framebufferID));
+ GL(glGenRenderbuffers(1, &renderbufferID));
+
+ GL(glBindRenderbuffer(GL_RENDERBUFFER, renderbufferID));
+ GL(glEGLImageTargetRenderbufferStorageOES(GL_RENDERBUFFER, eglImageID));
+
+ GL(glBindFramebuffer(GL_FRAMEBUFFER, framebufferID));
+ GL(glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER,
+ renderbufferID));
+ GLenum result = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (result != GL_FRAMEBUFFER_COMPLETE) {
+ ALOGI("%s Framebuffer Invalid***************", __FUNCTION__);
+ }
+ }
+
+ GL(glBindFramebuffer(GL_FRAMEBUFFER, framebufferID));
+}
diff --git a/gpu_tonemapper/EGLImageBuffer.h b/gpu_tonemapper/EGLImageBuffer.h
new file mode 100644
index 0000000..23af573
--- /dev/null
+++ b/gpu_tonemapper/EGLImageBuffer.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright 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.
+ */
+
+#ifndef __EGLIMAGE_BUFFER_H__
+#define __EGLIMAGE_BUFFER_H__
+
+#include <cutils/native_handle.h>
+#include <gralloc_priv.h>
+#include <ui/GraphicBuffer.h>
+#include "engine.h"
+
+class EGLImageBuffer {
+ // android::sp<android::GraphicBuffer> graphicBuffer;
+ void *eglImageID;
+ int width;
+ int height;
+ uint textureID;
+ uint renderbufferID;
+ uint framebufferID;
+
+ public:
+ int getWidth();
+ int getHeight();
+ EGLImageBuffer(android::sp<android::GraphicBuffer>);
+ unsigned int getTexture();
+ unsigned int getFramebuffer();
+ void bindAsTexture();
+ void bindAsFramebuffer();
+ ~EGLImageBuffer();
+ static EGLImageBuffer *from(const private_handle_t *src);
+ static void clear();
+};
+
+#endif //__EGLIMAGE_BUFFER_H__
\ No newline at end of file
diff --git a/gpu_tonemapper/EGLImageWrapper.cpp b/gpu_tonemapper/EGLImageWrapper.cpp
new file mode 100644
index 0000000..eb0a2ca
--- /dev/null
+++ b/gpu_tonemapper/EGLImageWrapper.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright 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 "EGLImageWrapper.h"
+#include <cutils/native_handle.h>
+#include <gralloc_priv.h>
+#include <ui/GraphicBuffer.h>
+
+std::map<int, EGLImageBuffer *> EGLImageWrapper::eglImageBufferMap;
+
+//-----------------------------------------------------------------------------
+EGLImageBuffer *EGLImageWrapper::wrap(const void *pvt_handle)
+//-----------------------------------------------------------------------------
+{
+ const private_handle_t *src = static_cast<const private_handle_t *>(pvt_handle);
+
+ EGLImageBuffer *result = 0;
+ std::map<int, EGLImageBuffer *>::iterator it = eglImageBufferMap.find(src->fd);
+ if (it == eglImageBufferMap.end()) {
+ native_handle_t *native_handle = const_cast<private_handle_t *>(src);
+
+ int flags = android::GraphicBuffer::USAGE_HW_TEXTURE |
+ android::GraphicBuffer::USAGE_SW_READ_NEVER |
+ android::GraphicBuffer::USAGE_SW_WRITE_NEVER;
+ if (src->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
+ flags |= android::GraphicBuffer::USAGE_PROTECTED;
+ }
+
+ android::sp<android::GraphicBuffer> graphicBuffer =
+ new android::GraphicBuffer(src->width, src->height, src->format, flags,
+ src->width /*src->stride*/, native_handle, false);
+
+ result = new EGLImageBuffer(graphicBuffer);
+
+ eglImageBufferMap[src->fd] = result;
+ } else {
+ result = it->second;
+ }
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+void EGLImageWrapper::destroy()
+//-----------------------------------------------------------------------------
+{
+ std::map<int, EGLImageBuffer *>::iterator it = eglImageBufferMap.begin();
+ for (; it != eglImageBufferMap.end(); it++) {
+ delete it->second;
+ }
+ eglImageBufferMap.clear();
+}
\ No newline at end of file
diff --git a/gpu_tonemapper/EGLImageWrapper.h b/gpu_tonemapper/EGLImageWrapper.h
new file mode 100644
index 0000000..d7fc84b
--- /dev/null
+++ b/gpu_tonemapper/EGLImageWrapper.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright 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.
+ */
+
+#ifndef __TONEMAPPER_EGLIMAGEWRAPPER_H__
+#define __TONEMAPPER_EGLIMAGEWRAPPER_H__
+
+#include <map>
+#include "EGLImageBuffer.h"
+
+class EGLImageWrapper {
+ static std::map<int, EGLImageBuffer *> eglImageBufferMap;
+
+ public:
+ static EGLImageBuffer *wrap(const void *pvt_handle);
+ static void destroy();
+};
+
+#endif //__TONEMAPPER_EGLIMAGEWRAPPER_H__
\ No newline at end of file
diff --git a/gpu_tonemapper/TonemapFactory.cpp b/gpu_tonemapper/TonemapFactory.cpp
new file mode 100644
index 0000000..81e9f7f
--- /dev/null
+++ b/gpu_tonemapper/TonemapFactory.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright 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 "TonemapFactory.h"
+#include <utils/Log.h>
+#include "EGLImageWrapper.h"
+#include "Tonemapper.h"
+#include "engine.h"
+
+//----------------------------------------------------------------------------------------------------------------------------------------------------------
+Tonemapper *TonemapperFactory_GetInstance(int type, void *colorMap, int colorMapSize,
+ void *lutXform, int lutXformSize)
+//----------------------------------------------------------------------------------------------------------------------------------------------------------
+{
+ // initializes the engine - does nothing if already initialized
+ engine_initialize();
+
+ // build the tonemapper
+ Tonemapper *tonemapper = Tonemapper::build(type, colorMap, colorMapSize, lutXform, lutXformSize);
+
+ return tonemapper;
+}
+
+//------------------------------------------
+void TonemapperFactory_Destroy()
+//------------------------------------------
+{
+ // clear EGLImage mappings
+ EGLImageWrapper::destroy();
+ // shutdown the engine
+ engine_shutdown();
+}
diff --git a/gpu_tonemapper/TonemapFactory.h b/gpu_tonemapper/TonemapFactory.h
new file mode 100644
index 0000000..1004170
--- /dev/null
+++ b/gpu_tonemapper/TonemapFactory.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright 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.
+ */
+
+#ifndef __TONEMAPPER_TONEMAPPERFACTORY_H__
+#define __TONEMAPPER_TONEMAPPERFACTORY_H__
+
+#include "Tonemapper.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// returns an instance of Tonemapper
+Tonemapper *TonemapperFactory_GetInstance(int type, void *colorMap, int colorMapSize,
+ void *lutXform, int lutXformSize);
+
+// destroy tonemap session
+void TonemapperFactory_Destroy();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //__TONEMAPPER_TONEMAPPERFACTORY_H__
diff --git a/gpu_tonemapper/Tonemapper.cpp b/gpu_tonemapper/Tonemapper.cpp
new file mode 100644
index 0000000..957c133
--- /dev/null
+++ b/gpu_tonemapper/Tonemapper.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright 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 <utils/Log.h>
+
+#include "EGLImageWrapper.h"
+#include "Tonemapper.h"
+#include "engine.h"
+#include "forward_tonemap.inl"
+#include "fullscreen_vertex_shader.inl"
+#include "rgba_inverse_tonemap.inl"
+
+//-----------------------------------------------------------------------------
+Tonemapper::Tonemapper()
+//-----------------------------------------------------------------------------
+{
+ tonemapTexture = 0;
+ lutXformTexture = 0;
+ programID = 0;
+}
+
+//-----------------------------------------------------------------------------
+Tonemapper::~Tonemapper()
+//-----------------------------------------------------------------------------
+{
+ engine_deleteInputBuffer(tonemapTexture);
+ engine_deleteInputBuffer(lutXformTexture);
+ engine_deleteProgram(programID);
+}
+
+//-----------------------------------------------------------------------------
+Tonemapper *Tonemapper::build(int type, void *colorMap, int colorMapSize, void *lutXform,
+ int lutXformSize)
+//-----------------------------------------------------------------------------
+{
+ if (colorMapSize <= 0) {
+ ALOGE("Invalid Color Map size = %d", colorMapSize);
+ return NULL;
+ }
+ engine_bind();
+
+ // build new tonemapper
+ Tonemapper *tonemapper = new Tonemapper();
+ // load the 3d lut
+ tonemapper->tonemapTexture = engine_load3DTexture(colorMap, colorMapSize, 0);
+ // load the non-uniform xform
+ tonemapper->lutXformTexture = engine_load1DTexture(lutXform, lutXformSize, 0);
+ bool bUseXform = (tonemapper->lutXformTexture != 0) && (lutXformSize != 0);
+
+ // create the program
+ const char *fragmentShaders[3];
+ int fragmentShaderCount = 0;
+ const char *version = "#version 300 es\n";
+ const char *define = "#define USE_NONUNIFORM_SAMPLING\n";
+
+ fragmentShaders[fragmentShaderCount++] = version;
+
+ // non-uniform sampling
+ if (bUseXform) {
+ fragmentShaders[fragmentShaderCount++] = define;
+ }
+
+ if (type == TONEMAP_INVERSE) { // inverse tonemapping
+ fragmentShaders[fragmentShaderCount++] = rgba_inverse_tonemap_shader;
+ } else { // forward tonemapping
+ fragmentShaders[fragmentShaderCount++] = forward_tonemap_shader;
+ }
+
+ tonemapper->programID =
+ engine_loadProgram(1, &fullscreen_vertex_shader, fragmentShaderCount, fragmentShaders);
+
+ return tonemapper;
+}
+
+//-----------------------------------------------------------------------------
+int Tonemapper::blit(const void *dst, const void *src, int srcFenceFd)
+//-----------------------------------------------------------------------------
+{
+ // make current
+ engine_bind();
+
+ // create eglimages if required
+ EGLImageBuffer *dst_buffer = EGLImageWrapper::wrap(dst);
+ EGLImageBuffer *src_buffer = EGLImageWrapper::wrap(src);
+
+ // bind the program
+ engine_setProgram(programID);
+
+ // set destination
+ engine_setDestination(dst_buffer->getFramebuffer(), 0, 0, dst_buffer->getWidth(),
+ dst_buffer->getHeight());
+ // set source
+ engine_setExternalInputBuffer(0, src_buffer->getTexture());
+ // set 3d lut
+ engine_set3DInputBuffer(1, tonemapTexture);
+ // set non-uniform xform
+ engine_set2DInputBuffer(2, lutXformTexture);
+
+ // perform
+ int fenceFD = engine_blit(srcFenceFd);
+
+ return fenceFD;
+}
diff --git a/gpu_tonemapper/Tonemapper.h b/gpu_tonemapper/Tonemapper.h
new file mode 100644
index 0000000..9c41670
--- /dev/null
+++ b/gpu_tonemapper/Tonemapper.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright 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.
+ */
+
+#ifndef __TONEMAPPER_TONEMAP_H__
+#define __TONEMAPPER_TONEMAP_H__
+
+#define TONEMAP_FORWARD 0
+#define TONEMAP_INVERSE 1
+
+class Tonemapper {
+ private:
+ unsigned int tonemapTexture;
+ unsigned int lutXformTexture;
+ unsigned int programID;
+ Tonemapper();
+
+ public:
+ ~Tonemapper();
+ static Tonemapper *build(int type, void *colorMap, int colorMapSize, void *lutXform,
+ int lutXformSize);
+ int blit(const void *dst, const void *src, int srcFenceFd);
+};
+
+#endif //__TONEMAPPER_TONEMAP_H__
diff --git a/gpu_tonemapper/engine.h b/gpu_tonemapper/engine.h
new file mode 100644
index 0000000..5635ee3
--- /dev/null
+++ b/gpu_tonemapper/engine.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright 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.
+ */
+
+#ifndef __TONEMAPPER_ENGINE_H__
+#define __TONEMAPPER_ENGINE_H__
+
+bool engine_initialize();
+void engine_bind();
+void engine_shutdown();
+
+unsigned int engine_loadProgram(int, const char **, int, const char **);
+void engine_setProgram(int);
+void engine_deleteProgram(unsigned int);
+
+unsigned int engine_load3DTexture(void *data, int sz, int format);
+unsigned int engine_load1DTexture(void *xform, int xformSize, int format);
+void engine_deleteInputBuffer(unsigned int);
+
+void engine_set2DInputBuffer(int binding, unsigned int textureID);
+void engine_set3DInputBuffer(int binding, unsigned int textureID);
+void engine_setExternalInputBuffer(int binding, unsigned int textureID);
+void engine_setDestination(int id, int x, int y, int w, int h);
+
+int engine_blit(int);
+
+#endif //__TONEMAPPER_ENGINE_H__
\ No newline at end of file
diff --git a/gpu_tonemapper/forward_tonemap.inl b/gpu_tonemapper/forward_tonemap.inl
new file mode 100644
index 0000000..a008949
--- /dev/null
+++ b/gpu_tonemapper/forward_tonemap.inl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright 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.
+ */
+
+const char* forward_tonemap_shader = ""
+ "#extension GL_OES_EGL_image_external_essl3 : require \n"
+ "precision highp float; \n"
+ "precision highp sampler2D; \n"
+ "layout(binding = 0) uniform samplerExternalOES externalTexture; \n"
+ "layout(binding = 1) uniform sampler3D tonemapper; \n"
+ "layout(binding = 2) uniform sampler2D xform; \n"
+ "in vec2 uv; \n"
+ "out vec4 fs_color; \n"
+ "void main() \n"
+ "{ \n"
+ "vec4 rgb = texture(externalTexture, uv); \n"
+ "#if defined(USE_NONUNIFORM_SAMPLING) \n"
+ "float r = texture(xform, vec2(r, 0.0f)).r; \n"
+ "float g = texture(xform, vec2(g, 0.0f)).g; \n"
+ "float b = texture(xform, vec2(b, 0.0f)).b; \n"
+ "#else \n"
+ "float r = rgb.r; \n"
+ "float g = rgb.g; \n"
+ "float b = rgb.b; \n"
+ "#endif \n"
+ "fs_color.rgb = texture(tonemapper, vec3(r, g, b)).rgb; \n"
+ "} \n";
diff --git a/gpu_tonemapper/fullscreen_vertex_shader.inl b/gpu_tonemapper/fullscreen_vertex_shader.inl
new file mode 100644
index 0000000..9a70c2b
--- /dev/null
+++ b/gpu_tonemapper/fullscreen_vertex_shader.inl
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright 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.
+ */
+
+const char* fullscreen_vertex_shader = " "
+"#version 300 es \n"
+"precision highp float; \n"
+"layout(location = 0) in vec2 iUV; \n"
+"out vec2 uv; \n"
+"void main() \n"
+"{ \n"
+" vec2 positions[3]; \n"
+" positions[0] = vec2(-1.0f, 3.0f); \n"
+" positions[1] = vec2(-1.0f, -1.0f); \n"
+" positions[2] = vec2(3.0f, -1.0f); \n"
+" vec2 uvs[3]; \n"
+" uvs[0] = vec2(0.0f, -1.0f); \n"
+" uvs[1] = vec2(0.0f, 1.0f); \n"
+" uvs[2] = vec2(2.0f, 1.0f); \n"
+" gl_Position = vec4(positions[gl_VertexID], -1.0f, 1.0f); \n"
+" uv = uvs[gl_VertexID]; \n"
+"} \n";
diff --git a/gpu_tonemapper/glengine.cpp b/gpu_tonemapper/glengine.cpp
new file mode 100644
index 0000000..e5c8e68
--- /dev/null
+++ b/gpu_tonemapper/glengine.cpp
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright 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 "glengine.h"
+#include <utils/Log.h>
+#include "engine.h"
+
+void checkGlError(const char *, int);
+void checkEglError(const char *, int);
+
+static EGLDisplay eglDisplay;
+static EGLContext eglContext;
+static EGLSurface eglSurface;
+
+static bool isEngineInitialized = false;
+
+//-----------------------------------------------------------------------------
+// Make Current
+void engine_bind()
+//-----------------------------------------------------------------------------
+{
+ EGL(eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext));
+}
+
+//-----------------------------------------------------------------------------
+// initialize GL
+//
+bool engine_initialize()
+//-----------------------------------------------------------------------------
+{
+ if (isEngineInitialized)
+ return true;
+
+ EGLBoolean result = false;
+
+ // display
+ eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ EGL(eglBindAPI(EGL_OPENGL_ES_API));
+
+ // initialize
+ EGL(eglInitialize(eglDisplay, 0, 0));
+
+ // config
+ EGLConfig eglConfig;
+ EGLint eglConfigAttribList[] = {EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
+ EGL_RED_SIZE, 8,
+ EGL_GREEN_SIZE, 8,
+ EGL_BLUE_SIZE, 8,
+ EGL_ALPHA_SIZE, 8,
+ EGL_NONE};
+ int numConfig = 0;
+ EGL(eglChooseConfig(eglDisplay, eglConfigAttribList, &eglConfig, 1, &numConfig));
+
+ // context
+ EGLint eglContextAttribList[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
+ eglContext = eglCreateContext(eglDisplay, eglConfig, NULL, eglContextAttribList);
+
+ // surface
+ EGLint eglSurfaceAttribList[] = {EGL_WIDTH, 1, EGL_HEIGHT, 1, EGL_NONE, EGL_NONE};
+ eglSurface = eglCreatePbufferSurface(eglDisplay, eglConfig, eglSurfaceAttribList);
+
+ result = (EGL_TRUE == eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext));
+
+ isEngineInitialized = result;
+
+ ALOGI("In %s result = %d context = %p", __FUNCTION__, result, (void *)eglContext);
+
+ return result;
+}
+
+//-----------------------------------------------------------------------------
+// Shutdown.
+void engine_shutdown()
+//-----------------------------------------------------------------------------
+{
+ EGL(eglMakeCurrent(eglDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT));
+ EGL(eglDestroySurface(eglDisplay, eglSurface));
+ EGL(eglDestroyContext(eglDisplay, eglContext));
+ EGL(eglTerminate(eglDisplay));
+ eglDisplay = EGL_NO_DISPLAY;
+ eglContext = EGL_NO_CONTEXT;
+ eglSurface = EGL_NO_SURFACE;
+ isEngineInitialized = false;
+}
+
+//-----------------------------------------------------------------------------
+void engine_deleteInputBuffer(unsigned int id)
+//-----------------------------------------------------------------------------
+{
+ if (id != 0) {
+ GL(glDeleteTextures(1, &id));
+ }
+}
+
+//-----------------------------------------------------------------------------
+void engine_deleteProgram(unsigned int id)
+//-----------------------------------------------------------------------------
+{
+ if (id != 0) {
+ GL(glDeleteProgram(id));
+ }
+}
+
+//-----------------------------------------------------------------------------
+unsigned int engine_load3DTexture(void *colorMapData, int sz, int format)
+//-----------------------------------------------------------------------------
+{
+ GLuint texture = 0;
+ GL(glGenTextures(1, &texture));
+ GL(glBindTexture(GL_TEXTURE_3D, texture));
+ GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
+ GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
+ GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE));
+ GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
+ GL(glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
+
+ GL(glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB10_A2, sz, sz, sz, 0, GL_RGBA,
+ GL_UNSIGNED_INT_2_10_10_10_REV, colorMapData));
+
+ return texture;
+}
+//-----------------------------------------------------------------------------
+unsigned int engine_load1DTexture(void *data, int sz, int format)
+//-----------------------------------------------------------------------------
+{
+ GLuint texture = 0;
+ if ((data != 0) && (sz != 0)) {
+ GL(glGenTextures(1, &texture));
+ GL(glBindTexture(GL_TEXTURE_2D, texture));
+ GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
+ GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
+ GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
+ GL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
+
+ GL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2, sz, 1, 0, GL_RGBA,
+ GL_UNSIGNED_INT_2_10_10_10_REV, data));
+ }
+ return texture;
+}
+
+//-----------------------------------------------------------------------------
+void dumpShaderLog(int shader)
+//-----------------------------------------------------------------------------
+{
+ int success;
+ GLchar infoLog[512];
+ GL(glGetShaderiv(shader, GL_COMPILE_STATUS, &success));
+ if (!success) {
+ glGetShaderInfoLog(shader, 512, NULL, infoLog);
+ ALOGI("Shader Failed to compile: %s\n", infoLog);
+ }
+}
+
+//-----------------------------------------------------------------------------
+GLuint engine_loadProgram(int vertexEntries, const char **vertex, int fragmentEntries,
+ const char **fragment)
+//-----------------------------------------------------------------------------
+{
+ GLuint progId = glCreateProgram();
+
+ int vertId = glCreateShader(GL_VERTEX_SHADER);
+ int fragId = glCreateShader(GL_FRAGMENT_SHADER);
+
+ GL(glShaderSource(vertId, vertexEntries, vertex, 0));
+ GL(glCompileShader(vertId));
+ dumpShaderLog(vertId);
+
+ GL(glShaderSource(fragId, fragmentEntries, fragment, 0));
+ GL(glCompileShader(fragId));
+ dumpShaderLog(fragId);
+
+ GL(glAttachShader(progId, vertId));
+ GL(glAttachShader(progId, fragId));
+
+ GL(glLinkProgram(progId));
+
+ GL(glDetachShader(progId, vertId));
+ GL(glDetachShader(progId, fragId));
+
+ GL(glDeleteShader(vertId));
+ GL(glDeleteShader(fragId));
+
+ return progId;
+}
+
+//-----------------------------------------------------------------------------
+void WaitOnNativeFence(int fd)
+//-----------------------------------------------------------------------------
+{
+ if (fd != -1) {
+ EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fd, EGL_NONE};
+
+ EGLSyncKHR sync = eglCreateSyncKHR(eglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+
+ if (sync == EGL_NO_SYNC_KHR) {
+ ALOGE("%s - Failed to Create sync from source fd", __FUNCTION__);
+ } else {
+ // the gpu will wait for this sync - not this cpu thread.
+ EGL(eglWaitSyncKHR(eglDisplay, sync, 0));
+ EGL(eglDestroySyncKHR(eglDisplay, sync));
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+int CreateNativeFence()
+//-----------------------------------------------------------------------------
+{
+ int fd = -1;
+
+ EGLSyncKHR sync = eglCreateSyncKHR(eglDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
+ GL(glFlush());
+ if (sync == EGL_NO_SYNC_KHR) {
+ ALOGE("%s - Failed to Create Native Fence sync", __FUNCTION__);
+ } else {
+ fd = eglDupNativeFenceFDANDROID(eglDisplay, sync);
+ if (fd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+ ALOGE("%s - Failed to dup sync", __FUNCTION__);
+ }
+ EGL(eglDestroySyncKHR(eglDisplay, sync));
+ }
+
+ return fd;
+}
+
+//-----------------------------------------------------------------------------
+void engine_setDestination(int id, int x, int y, int w, int h)
+//-----------------------------------------------------------------------------
+{
+ GL(glBindFramebuffer(GL_FRAMEBUFFER, id));
+ GL(glViewport(x, y, w, h));
+}
+
+//-----------------------------------------------------------------------------
+void engine_setProgram(int id)
+//-----------------------------------------------------------------------------
+{
+ GL(glUseProgram(id));
+}
+
+//-----------------------------------------------------------------------------
+void engine_set2DInputBuffer(int binding, unsigned int id)
+//-----------------------------------------------------------------------------
+{
+ GL(glActiveTexture(GL_TEXTURE0 + binding));
+ GL(glBindTexture(GL_TEXTURE_2D, id));
+}
+
+//-----------------------------------------------------------------------------
+void engine_set3DInputBuffer(int binding, unsigned int id)
+//-----------------------------------------------------------------------------
+{
+ GL(glActiveTexture(GL_TEXTURE0 + binding));
+ GL(glBindTexture(GL_TEXTURE_3D, id));
+}
+
+//-----------------------------------------------------------------------------
+void engine_setExternalInputBuffer(int binding, unsigned int id)
+//-----------------------------------------------------------------------------
+{
+ GL(glActiveTexture(GL_TEXTURE0 + binding));
+ GL(glBindTexture(0x8D65, id));
+}
+
+//-----------------------------------------------------------------------------
+int engine_blit(int srcFenceFd)
+//-----------------------------------------------------------------------------
+{
+ int fd = -1;
+ WaitOnNativeFence(srcFenceFd);
+ float fullscreen_vertices[]{0.0f, 2.0f, 0.0f, 0.0f, 2.0f, 0.0f};
+ GL(glEnableVertexAttribArray(0));
+ GL(glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, fullscreen_vertices));
+ GL(glDrawArrays(GL_TRIANGLES, 0, 3));
+ fd = CreateNativeFence();
+ GL(glFlush());
+ return fd;
+}
+
+//-----------------------------------------------------------------------------
+void checkGlError(const char *file, int line)
+//-----------------------------------------------------------------------------
+{
+ for (GLint error = glGetError(); error; error = glGetError()) {
+ char *pError;
+ switch (error) {
+ case GL_NO_ERROR:
+ pError = (char *)"GL_NO_ERROR";
+ break;
+ case GL_INVALID_ENUM:
+ pError = (char *)"GL_INVALID_ENUM";
+ break;
+ case GL_INVALID_VALUE:
+ pError = (char *)"GL_INVALID_VALUE";
+ break;
+ case GL_INVALID_OPERATION:
+ pError = (char *)"GL_INVALID_OPERATION";
+ break;
+ case GL_OUT_OF_MEMORY:
+ pError = (char *)"GL_OUT_OF_MEMORY";
+ break;
+ case GL_INVALID_FRAMEBUFFER_OPERATION:
+ pError = (char *)"GL_INVALID_FRAMEBUFFER_OPERATION";
+ break;
+
+ default:
+ ALOGE("glError (0x%x) %s:%d\n", error, file, line);
+ return;
+ }
+
+ ALOGE("glError (%s) %s:%d\n", pError, file, line);
+ return;
+ }
+ return;
+}
+
+//-----------------------------------------------------------------------------
+void checkEglError(const char *file, int line)
+//-----------------------------------------------------------------------------
+{
+ for (int i = 0; i < 5; i++) {
+ const EGLint error = eglGetError();
+ if (error == EGL_SUCCESS) {
+ break;
+ }
+
+ char *pError;
+ switch (error) {
+ case EGL_SUCCESS:
+ pError = (char *)"EGL_SUCCESS";
+ break;
+ case EGL_NOT_INITIALIZED:
+ pError = (char *)"EGL_NOT_INITIALIZED";
+ break;
+ case EGL_BAD_ACCESS:
+ pError = (char *)"EGL_BAD_ACCESS";
+ break;
+ case EGL_BAD_ALLOC:
+ pError = (char *)"EGL_BAD_ALLOC";
+ break;
+ case EGL_BAD_ATTRIBUTE:
+ pError = (char *)"EGL_BAD_ATTRIBUTE";
+ break;
+ case EGL_BAD_CONTEXT:
+ pError = (char *)"EGL_BAD_CONTEXT";
+ break;
+ case EGL_BAD_CONFIG:
+ pError = (char *)"EGL_BAD_CONFIG";
+ break;
+ case EGL_BAD_CURRENT_SURFACE:
+ pError = (char *)"EGL_BAD_CURRENT_SURFACE";
+ break;
+ case EGL_BAD_DISPLAY:
+ pError = (char *)"EGL_BAD_DISPLAY";
+ break;
+ case EGL_BAD_SURFACE:
+ pError = (char *)"EGL_BAD_SURFACE";
+ break;
+ case EGL_BAD_MATCH:
+ pError = (char *)"EGL_BAD_MATCH";
+ break;
+ case EGL_BAD_PARAMETER:
+ pError = (char *)"EGL_BAD_PARAMETER";
+ break;
+ case EGL_BAD_NATIVE_PIXMAP:
+ pError = (char *)"EGL_BAD_NATIVE_PIXMAP";
+ break;
+ case EGL_BAD_NATIVE_WINDOW:
+ pError = (char *)"EGL_BAD_NATIVE_WINDOW";
+ break;
+ case EGL_CONTEXT_LOST:
+ pError = (char *)"EGL_CONTEXT_LOST";
+ break;
+ default:
+ ALOGE("eglError (0x%x) %s:%d\n", error, file, line);
+ return;
+ }
+ ALOGE("eglError (%s) %s:%d\n", pError, file, line);
+ return;
+ }
+ return;
+}
diff --git a/gpu_tonemapper/glengine.h b/gpu_tonemapper/glengine.h
new file mode 100644
index 0000000..c5b166c
--- /dev/null
+++ b/gpu_tonemapper/glengine.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright 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.
+ */
+
+#ifndef __TONEMAPPER_GLENGINE_H__
+#define __TONEMAPPER_GLENGINE_H__
+#include <EGL/egl.h>
+#define EGL_EGLEXT_PROTOTYPES
+#include <EGL/eglext.h>
+#include <GLES3/gl31.h>
+#define GL_GLEXT_PROTOTYPES
+#include <GLES2/gl2ext.h>
+#include <GLES3/gl3ext.h>
+
+#if defined(CHECK_GL_ERRORS)
+#define GL(func) func;
+#define EGL(func) func;
+#else
+#define GL(func) \
+ func; \
+ checkGlError(__FILE__, __LINE__);
+#define EGL(func) \
+ func; \
+ checkEglError(__FILE__, __LINE__);
+#endif
+
+void checkGlError(const char *file, int line);
+void checkEglError(const char *file, int line);
+
+#endif //__TONEMAPPER_GLENGINE_H__
\ No newline at end of file
diff --git a/gpu_tonemapper/rgba_inverse_tonemap.inl b/gpu_tonemapper/rgba_inverse_tonemap.inl
new file mode 100644
index 0000000..399e2f8
--- /dev/null
+++ b/gpu_tonemapper/rgba_inverse_tonemap.inl
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright 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.
+ */
+
+const char* rgba_inverse_tonemap_shader = ""
+ "#extension GL_OES_EGL_image_external_essl3 : require \n"
+ "precision highp float; \n"
+ "precision highp sampler2D; \n"
+ "layout(binding = 0) uniform samplerExternalOES externalTexture; \n"
+ "layout(binding = 1) uniform sampler3D tonemapper; \n"
+ "layout(binding = 2) uniform sampler2D xform; \n"
+ "in vec2 uv; \n"
+ "out vec4 fs_color; \n"
+ "void main() \n"
+ "{ \n"
+ "vec2 flipped = uv; \n"
+ "flipped.y = 1.0 - flipped.y; \n"
+ "flipped.x = flipped.x; \n"
+ "vec4 rgb_premulalpha = texture(externalTexture, flipped); \n"
+ "fs_color = rgb_premulalpha; \n"
+ "if( rgb_premulalpha.a > 0.0 ) { \n"
+ "vec3 rgb = rgb_premulalpha.rgb/rgb_premulalpha.a; \n"
+ "#if defined(USE_NONUNIFORM_SAMPLING) \n"
+ "float r = texture(xform, vec2(rgb.r, 0.0f)).r; \n"
+ "float g = texture(xform, vec2(rgb.g, 0.0f)).g; \n"
+ "float b = texture(xform, vec2(rgb.b, 0.0f)).b; \n"
+ "#else \n"
+ "float r = rgb.r; \n"
+ "float g = rgb.g; \n"
+ "float b = rgb.b; \n"
+ "#endif \n"
+ "fs_color.rgb = texture(tonemapper, vec3(r, g, b)).rgb * rgb_premulalpha.a; \n"
+ "fs_color.a = rgb_premulalpha.a; \n"
+ "} \n"
+ "} \n";
diff --git a/libmemtrack/kgsl.c b/libmemtrack/kgsl.c
index 9ec69f0..c3aa86e 100644
--- a/libmemtrack/kgsl.c
+++ b/libmemtrack/kgsl.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2013, 2016 The Android Open Source Project
+ * Copyright (C) 2013 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.
diff --git a/libqdutils/display_config.cpp b/libqdutils/display_config.cpp
index c1335b1..4880cdc 100644
--- a/libqdutils/display_config.cpp
+++ b/libqdutils/display_config.cpp
@@ -357,7 +357,7 @@
inParcel.writeInt32(mode);
err = binder->dispatch(IQService::CONTROL_PARTIAL_UPDATE, &inParcel, &outParcel);
if(err != 0) {
- ALOGE("%s() failed with err %d", __FUNCTION__, err);
+ ALOGE_IF(getBinder(), "%s() failed with err %d", __FUNCTION__, err);
} else {
return outParcel.readInt32();
}
diff --git a/sdm/include/core/layer_buffer.h b/sdm/include/core/layer_buffer.h
index 4f80f86..4b42e7b 100644
--- a/sdm/include/core/layer_buffer.h
+++ b/sdm/include/core/layer_buffer.h
@@ -30,21 +30,12 @@
#define __LAYER_BUFFER_H__
#include <stdint.h>
+#include <color_metadata.h>
#include "sdm_types.h"
namespace sdm {
-/*! @brief This enum represents display layer color space conversion (CSC) matrix types.
-
- @sa Layer
-*/
-enum LayerCSC {
- kCSCLimitedRange601, //!< 601 limited range color space.
- kCSCFullRange601, //!< 601 full range color space.
- kCSCLimitedRange709, //!< 709 limited range color space.
-};
-
/*! @brief This enum represents display layer inverse gamma correction (IGC) types.
@sa Layer
@@ -212,6 +203,9 @@
uint32_t secure_camera : 1; //!< This flag shall be set by the client to indicate that the
//!< buffer is associated with secure camera session. A secure
//!< camera layer can co-exist with non-secure layer(s).
+
+ uint32_t hdr : 1; //!< This flag shall be set by the client to indicate that the
+ //!< the content is HDR.
};
uint32_t flags = 0; //!< For initialization purpose only.
@@ -234,7 +228,7 @@
//!< Unaligned height of the Layer that this buffer is for.
uint32_t size = 0; //!< Size of a single buffer (even if multiple clubbed together)
LayerBufferFormat format = kFormatRGBA8888; //!< Format of the buffer content.
- LayerCSC csc = kCSCFullRange601; //!< Color Space of the layer.
+ ColorMetaData color_metadata = {}; //!< CSC + Range + Transfer + Matrix + HDR Info
LayerIGC igc = kIGCNotSpecified; //!< IGC that will be applied on this layer.
LayerBufferPlane planes[4] = {};
//!< Array of planes that this buffer contains. RGB buffer formats
@@ -273,6 +267,13 @@
//!< Specifies the buffer id.
};
+// This enum represents buffer layout types.
+enum BufferLayout {
+ kLinear, //!< Linear data
+ kUBWC, //!< UBWC aligned data
+ kTPTiled //!< Tightly Packed data
+};
+
} // namespace sdm
#endif // __LAYER_BUFFER_H__
diff --git a/sdm/include/core/layer_stack.h b/sdm/include/core/layer_stack.h
index 2741f71..701e3ca 100644
--- a/sdm/include/core/layer_stack.h
+++ b/sdm/include/core/layer_stack.h
@@ -179,6 +179,36 @@
};
};
+/*! @brief This structure defines flags associated with the layer requests. The 1-bit flag can be
+ set to ON(1) or OFF(0).
+
+ @sa Layer
+*/
+struct LayerRequestFlags {
+ union {
+ struct {
+ uint32_t tone_map : 1; //!< This flag will be set by SDM when the layer needs tone map
+ uint32_t secure: 1; //!< This flag will be set by SDM when the layer must be secure
+ };
+ uint32_t request_flags = 0; //!< For initialization purpose only.
+ //!< Shall not be refered directly.
+ };
+};
+
+/*! @brief This structure defines LayerRequest.
+ Includes width/height/format of the LayerRequest.
+
+ SDM shall set the properties of LayerRequest to be used by the client
+
+ @sa LayerRequest
+*/
+struct LayerRequest {
+ LayerRequestFlags flags; // Flags associated with this request
+ LayerBufferFormat format = kFormatRGBA8888; // Requested format
+ uint32_t width = 0;
+ uint32_t height = 0;
+};
+
/*! @brief This structure defines flags associated with a layer stack. The 1-bit flag can be set to
ON(1) or OFF(0).
@@ -219,6 +249,8 @@
uint32_t post_processed_output : 1; // If output_buffer should contain post processed output
// This applies only to primary displays currently
+
+ uint32_t hdr_present : 1; //!< Set if stack has HDR content
};
uint32_t flags = 0; //!< For initialization purpose only.
@@ -264,7 +296,7 @@
@sa LayerArray
*/
struct Layer {
- LayerBuffer *input_buffer = NULL; //!< Pointer to the buffer to be composed.
+ LayerBuffer input_buffer = {}; //!< Buffer to be composed.
//!< If this remains unchanged between two
//!< consecutive Prepare() calls and
//!< geometry_changed flag is not set for the
@@ -322,6 +354,11 @@
//!< no content is associated with the layer.
LayerFlags flags; //!< Flags associated with this layer.
+
+ LayerRequest request = {}; //!< o/p - request on this Layer by SDM.
+
+ Lut3d lut_3d = {}; //!< o/p - Populated by SDM when tone mapping is
+ //!< needed on this layer.
};
/*! @brief This structure defines a layer stack that contains layers which need to be composed and
diff --git a/sdm/include/private/hw_info_types.h b/sdm/include/private/hw_info_types.h
index b960955..cd57f32 100644
--- a/sdm/include/private/hw_info_types.h
+++ b/sdm/include/private/hw_info_types.h
@@ -128,6 +128,8 @@
uint32_t num_rotator = 0;
bool has_downscale = false;
std::string device_path = "";
+ float min_downscale = 2.0f;
+ bool downscale_compression = false;
void Reset() { *this = HWRotatorInfo(); }
};
@@ -429,15 +431,12 @@
uint32_t app_layer_count = 0; // Total number of app layers. Must not be 0.
uint32_t gpu_target_index = 0; // GPU target layer index. 0 if not present.
+ std::vector<Layer> hw_layers = {}; // Layers which need to be programmed on the HW
+
uint32_t index[kMaxSDELayers]; // Indexes of the layers from the layer stack which need to be
// programmed on hardware.
- LayerRect updated_src_rect[kMaxSDELayers]; // Updated layer src rects in s3d mode
- LayerRect updated_dst_rect[kMaxSDELayers]; // Updated layer dst rects in s3d mode
- bool updating[kMaxSDELayers] = {0}; // Updated by strategy, considering plane_alpha+updating
uint32_t roi_index[kMaxSDELayers] = {0}; // Stores the ROI index where the layers are visible.
- uint32_t count = 0; // Total number of layers which need to be set on hardware.
-
int sync_handle = -1;
std::vector<LayerRect> left_frame_roi; // Left ROI.
diff --git a/sdm/include/private/resource_interface.h b/sdm/include/private/resource_interface.h
index 3f34e91..48b7a02 100644
--- a/sdm/include/private/resource_interface.h
+++ b/sdm/include/private/resource_interface.h
@@ -51,7 +51,7 @@
virtual void Purge(Handle display_ctx) = 0;
virtual DisplayError SetMaxMixerStages(Handle display_ctx, uint32_t max_mixer_stages) = 0;
virtual DisplayError ValidateScaling(const LayerRect &crop, const LayerRect &dst,
- bool rotate90, bool ubwc_tiled,
+ bool rotate90, BufferLayout layout,
bool use_rotator_downscale) = 0;
virtual DisplayError ValidateCursorConfig(Handle display_ctx, const Layer *layer,
bool is_top) = 0;
diff --git a/sdm/include/private/strategy_interface.h b/sdm/include/private/strategy_interface.h
index 122a3c6..90e1064 100644
--- a/sdm/include/private/strategy_interface.h
+++ b/sdm/include/private/strategy_interface.h
@@ -53,6 +53,7 @@
const HWMixerAttributes &mixer_attributes,
const DisplayConfigVariableInfo &fb_config) = 0;
virtual DisplayError SetCompositionState(LayerComposition composition_type, bool enable) = 0;
+ virtual DisplayError Purge() = 0;
protected:
virtual ~StrategyInterface() { }
diff --git a/sdm/include/utils/constants.h b/sdm/include/utils/constants.h
index 31129c1..72b1bed 100644
--- a/sdm/include/utils/constants.h
+++ b/sdm/include/utils/constants.h
@@ -71,6 +71,8 @@
const int kMaxRotatePerLayer = 2;
const uint32_t kMaxBlitTargetLayers = 2;
const int kPageSize = 4096;
+ const uint32_t kGridSize = 129; // size used for non-linear transformation before Tone-mapping
+ const uint32_t kLutDim = 17; // Dim of the 3d LUT for tone-mapping.
typedef void * Handle;
diff --git a/sdm/include/utils/formats.h b/sdm/include/utils/formats.h
index 67548f3..dd819dc 100644
--- a/sdm/include/utils/formats.h
+++ b/sdm/include/utils/formats.h
@@ -37,6 +37,7 @@
bool IsUBWCFormat(LayerBufferFormat format);
bool Is10BitFormat(LayerBufferFormat format);
const char *GetFormatString(const LayerBufferFormat &format);
+BufferLayout GetBufferLayout(LayerBufferFormat format);
} // namespace sdm
diff --git a/sdm/libs/core/Android.mk b/sdm/libs/core/Android.mk
index f97ff33..8600c55 100644
--- a/sdm/libs/core/Android.mk
+++ b/sdm/libs/core/Android.mk
@@ -4,7 +4,7 @@
LOCAL_MODULE := libsdmcore
LOCAL_MODULE_TAGS := optional
-LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes)
+LOCAL_C_INCLUDES := $(common_includes) $(kernel_includes) $(common_header_export_path)
LOCAL_CFLAGS := -Wno-unused-parameter -DLOG_TAG=\"SDM\" $(common_flags)
LOCAL_HW_INTF_PATH := fb
LOCAL_SHARED_LIBRARIES := libdl libsdmutils
diff --git a/sdm/libs/core/comp_manager.cpp b/sdm/libs/core/comp_manager.cpp
index d1530dc..199be86 100644
--- a/sdm/libs/core/comp_manager.cpp
+++ b/sdm/libs/core/comp_manager.cpp
@@ -33,6 +33,12 @@
namespace sdm {
+static bool NeedsScaledComposition(const DisplayConfigVariableInfo &fb_config,
+ const HWMixerAttributes &mixer_attributes) {
+ return ((fb_config.x_pixels != mixer_attributes.width) ||
+ (fb_config.y_pixels != mixer_attributes.height));
+}
+
DisplayError CompManager::Init(const HWResourceInfo &hw_res_info,
ExtensionInterface *extension_intf,
BufferAllocator *buffer_allocator,
@@ -122,6 +128,7 @@
max_sde_ext_layers_ = UINT32(Debug::GetExtMaxlayers());
}
+ display_comp_ctx->scaled_composition = NeedsScaledComposition(fb_config, mixer_attributes);
DLOGV_IF(kTagCompManager, "registered display bit mask 0x%x, configured display bit mask 0x%x, " \
"display type %d", registered_displays_.to_ulong(), configured_displays_.to_ulong(),
display_comp_ctx->display_type);
@@ -200,6 +207,8 @@
}
}
+ display_comp_ctx->scaled_composition = NeedsScaledComposition(fb_config, mixer_attributes);
+
return error;
}
@@ -212,9 +221,13 @@
constraints->use_cursor = false;
constraints->max_layers = max_layers_;
- // Limit 2 layer SDE Comp if its not a Primary Display
+ // Limit 2 layer SDE Comp if its not a Primary Display.
+ // Safe mode is the policy for External display on a low end device.
if (!display_comp_ctx->is_primary_panel) {
+ bool low_end_hw = ((hw_res_info_.num_vig_pipe + hw_res_info_.num_rgb_pipe +
+ hw_res_info_.num_dma_pipe) <= kSafeModeThreshold);
constraints->max_layers = max_sde_ext_layers_;
+ constraints->safe_mode = (low_end_hw && !hw_res_info_.separate_rotator) ? true : safe_mode_;
}
// If a strategy fails after successfully allocating resources, then set safe mode
@@ -369,6 +382,8 @@
reinterpret_cast<DisplayCompositionContext *>(display_ctx);
resource_intf_->Purge(display_comp_ctx->display_resource_ctx);
+
+ display_comp_ctx->strategy->Purge();
}
void CompManager::ProcessIdleTimeout(Handle display_ctx) {
@@ -426,8 +441,8 @@
DisplayError CompManager::ValidateScaling(const LayerRect &crop, const LayerRect &dst,
bool rotate90) {
- return resource_intf_->ValidateScaling(crop, dst, rotate90, Debug::IsUbwcTiledFrameBuffer(),
- true /* use_rotator_downscale */);
+ BufferLayout layout = Debug::IsUbwcTiledFrameBuffer() ? kUBWC : kLinear;
+ return resource_intf_->ValidateScaling(crop, dst, rotate90, layout, true);
}
DisplayError CompManager::ValidateCursorPosition(Handle display_ctx, HWLayers *hw_layers,
@@ -447,7 +462,8 @@
bool supported = false;
int32_t gpu_index = -1;
- if (!layer_stack->flags.cursor_present) {
+ // HW Cursor cannot be used, if Display configuration needs scaled composition.
+ if (display_comp_ctx->scaled_composition || !layer_stack->flags.cursor_present) {
return supported;
}
diff --git a/sdm/libs/core/comp_manager.h b/sdm/libs/core/comp_manager.h
index ebb257b..49a7ce0 100644
--- a/sdm/libs/core/comp_manager.h
+++ b/sdm/libs/core/comp_manager.h
@@ -77,6 +77,7 @@
private:
static const int kMaxThermalLevel = 3;
+ static const int kSafeModeThreshold = 4;
void PrepareStrategyConstraints(Handle display_ctx, HWLayers *hw_layers);
@@ -94,6 +95,7 @@
bool is_primary_panel = false;
bool valid_cursor = false;
PUConstraints pu_constraints = {};
+ bool scaled_composition = false;
};
Locker locker_;
diff --git a/sdm/libs/core/display_base.cpp b/sdm/libs/core/display_base.cpp
index 843ed6e..77b6edc 100644
--- a/sdm/libs/core/display_base.cpp
+++ b/sdm/libs/core/display_base.cpp
@@ -104,6 +104,8 @@
display_attributes_, hw_panel_info_);
if (!color_mgr_) {
DLOGW("Unable to create ColorManagerProxy for display = %d", display_type_);
+ } else if (InitializeColorModes() != kErrorNone) {
+ DLOGW("InitColorModes failed for display = %d", display_type_);
}
return kErrorNone;
@@ -119,6 +121,9 @@
DisplayError DisplayBase::Deinit() {
lock_guard<recursive_mutex> obj(recursive_mutex_);
+ color_modes_.clear();
+ color_mode_map_.clear();
+
if (color_mgr_) {
delete color_mgr_;
color_mgr_ = NULL;
@@ -216,6 +221,12 @@
return error;
}
+ error = HandleHDR(layer_stack);
+ if (error != kErrorNone) {
+ DLOGW("HandleHDR failed");
+ return error;
+ }
+
if (color_mgr_ && color_mgr_->NeedsPartialUpdateDisable()) {
DisablePartialUpdateOneFrame();
}
@@ -282,6 +293,8 @@
}
}
+ CommitLayerParams(layer_stack);
+
if (comp_manager_->Commit(display_comp_ctx_, &hw_layers_)) {
if (error != kErrorNone) {
return error;
@@ -301,6 +314,8 @@
return error;
}
+ PostCommitLayerParams(layer_stack);
+
if (partial_update_control_) {
comp_manager_->ControlPartialUpdate(display_comp_ctx_, true /* enable */);
}
@@ -320,8 +335,7 @@
if (!active_) {
return kErrorPermission;
}
-
- hw_layers_.info.count = 0;
+ hw_layers_.info.hw_layers.clear();
error = hw_intf_->Flush();
if (error == kErrorNone) {
comp_manager_->Purge(display_comp_ctx_);
@@ -396,7 +410,7 @@
switch (state) {
case kStateOff:
- hw_layers_.info.count = 0;
+ hw_layers_.info.hw_layers.clear();
error = hw_intf_->Flush();
if (error == kErrorNone) {
comp_manager_->Purge(display_comp_ctx_);
@@ -497,7 +511,7 @@
uint32_t num_hw_layers = 0;
if (hw_layers_.info.stack) {
- num_hw_layers = hw_layers_.info.count;
+ num_hw_layers = UINT32(hw_layers_.info.hw_layers.size());
}
if (num_hw_layers == 0) {
@@ -531,9 +545,9 @@
}
}
- const char *header = "\n| Idx | Comp Type | Split | WB | Pipe | W x H | Format | Src Rect (L T R B) | Dst Rect (L T R B) | Z | Flags | Deci(HxV) | CS |"; //NOLINT
- const char *newline = "\n|-----|-------------|--------|----|-------|-------------|--------------------------|---------------------|---------------------|----|------------|-----------|----|"; //NOLINT
- const char *format = "\n| %3s | %11s " "| %6s " "| %2s | 0x%03x | %4d x %4d | %24s " "| %4d %4d %4d %4d " "| %4d %4d %4d %4d " "| %2s | %10s " "| %9s | %2s |"; //NOLINT
+ const char *header = "\n| Idx | Comp Type | Split | WB | Pipe | W x H | Format | Src Rect (L T R B) | Dst Rect (L T R B) | Z | Flags | Deci(HxV) | CS | Range|"; //NOLINT
+ const char *newline = "\n|-----|-------------|--------|----|-------|-------------|--------------------------|---------------------|---------------------|----|------------|-----------|----|------|"; //NOLINT
+ const char *format = "\n| %3s | %11s " "| %6s " "| %2s | 0x%03x | %4d x %4d | %24s " "| %4d %4d %4d %4d " "| %4d %4d %4d %4d " "| %2s | %10s " "| %9s | %2s | %2s |"; //NOLINT
DumpImpl::AppendString(buffer, length, "\n");
DumpImpl::AppendString(buffer, length, newline);
@@ -542,13 +556,16 @@
for (uint32_t i = 0; i < num_hw_layers; i++) {
uint32_t layer_index = hw_layers_.info.index[i];
- Layer *layer = hw_layers_.info.stack->layers.at(layer_index);
- LayerBuffer *input_buffer = layer->input_buffer;
+ // sdm-layer from client layer stack
+ Layer *sdm_layer = hw_layers_.info.stack->layers.at(layer_index);
+ // hw-layer from hw layers info
+ Layer &hw_layer = hw_layers_.info.hw_layers.at(i);
+ LayerBuffer *input_buffer = &hw_layer.input_buffer;
HWLayerConfig &layer_config = hw_layers_.config[i];
HWRotatorSession &hw_rotator_session = layer_config.hw_rotator_session;
char idx[8] = { 0 };
- const char *comp_type = GetName(layer->composition);
+ const char *comp_type = GetName(sdm_layer->composition);
const char *buffer_format = GetFormatString(input_buffer->format);
const char *rotate_split[2] = { "Rot-1", "Rot-2" };
const char *comp_split[2] = { "Comp-1", "Comp-2" };
@@ -568,7 +585,7 @@
input_buffer->height, buffer_format, INT(src_roi.left),
INT(src_roi.top), INT(src_roi.right), INT(src_roi.bottom),
INT(dst_roi.left), INT(dst_roi.top), INT(dst_roi.right),
- INT(dst_roi.bottom), "-", "- ", "- ", "-");
+ INT(dst_roi.bottom), "-", "- ", "- ", "-", "-");
// print the below only once per layer block, fill with spaces for rest.
idx[0] = 0;
@@ -584,7 +601,8 @@
char decimation[16] = { 0 };
char flags[16] = { 0 };
char z_order[8] = { 0 };
- char csc[8] = { 0 };
+ char color_primary[8] = { 0 };
+ char range[8] = { 0 };
HWPipeInfo &pipe = (count == 0) ? layer_config.left_pipe : layer_config.right_pipe;
@@ -596,17 +614,19 @@
LayerRect &dst_roi = pipe.dst_roi;
snprintf(z_order, sizeof(z_order), "%d", pipe.z_order);
- snprintf(flags, sizeof(flags), "0x%08x", layer->flags.flags);
+ snprintf(flags, sizeof(flags), "0x%08x", hw_layer.flags.flags);
snprintf(decimation, sizeof(decimation), "%3d x %3d", pipe.horizontal_decimation,
pipe.vertical_decimation);
- snprintf(csc, sizeof(csc), "%d", layer->input_buffer->csc);
+ ColorMetaData &color_metadata = hw_layer.input_buffer.color_metadata;
+ snprintf(color_primary, sizeof(color_primary), "%d", color_metadata.colorPrimaries);
+ snprintf(range, sizeof(range), "%d", color_metadata.range);
DumpImpl::AppendString(buffer, length, format, idx, comp_type, comp_split[count],
"-", pipe.pipe_id, input_buffer->width, input_buffer->height,
buffer_format, INT(src_roi.left), INT(src_roi.top),
INT(src_roi.right), INT(src_roi.bottom), INT(dst_roi.left),
INT(dst_roi.top), INT(dst_roi.right), INT(dst_roi.bottom),
- z_order, flags, decimation, csc);
+ z_order, flags, decimation, color_primary, range);
// print the below only once per layer block, fill with spaces for rest.
idx[0] = 0;
@@ -650,11 +670,6 @@
return kErrorNotSupported;
}
- DisplayError error = color_mgr_->ColorMgrGetNumOfModes(&num_color_modes_);
- if (error != kErrorNone || !num_color_modes_) {
- return kErrorNotSupported;
- }
-
DLOGV_IF(kTagQDCM, "Number of modes from color manager = %d", num_color_modes_);
*mode_count = num_color_modes_;
@@ -672,30 +687,6 @@
return kErrorNotSupported;
}
- if (!color_modes_.size()) {
- color_modes_.resize(num_color_modes_);
-
- DisplayError error = color_mgr_->ColorMgrGetModes(&num_color_modes_, color_modes_.data());
- if (error != kErrorNone) {
- DLOGE("Failed");
- return error;
- }
-
- for (uint32_t i = 0; i < num_color_modes_; i++) {
- DLOGV_IF(kTagQDCM, "Color Mode[%d]: Name = %s mode_id = %d", i, color_modes_[i].name,
- color_modes_[i].id);
- auto it = color_mode_map_.find(color_modes_[i].name);
- if (it != color_mode_map_.end()) {
- if (it->second->id < color_modes_[i].id) {
- color_mode_map_.erase(it);
- color_mode_map_.insert(std::make_pair(color_modes_[i].name, &color_modes_[i]));
- }
- } else {
- color_mode_map_.insert(std::make_pair(color_modes_[i].name, &color_modes_[i]));
- }
- }
- }
-
for (uint32_t i = 0; i < num_color_modes_; i++) {
DLOGV_IF(kTagQDCM, "Color Mode[%d]: Name = %s mode_id = %d", i, color_modes_[i].name,
color_modes_[i].id);
@@ -711,6 +702,21 @@
return kErrorNotSupported;
}
+ DisplayError error = kErrorNone;
+ // Set client requests when not in HDR Mode.
+ if (!hdr_playback_mode_) {
+ error = SetColorModeInternal(color_mode);
+ if (error != kErrorNone) {
+ return error;
+ }
+ }
+ // Store the new color mode request by client
+ current_color_mode_ = color_mode;
+
+ return error;
+}
+
+DisplayError DisplayBase::SetColorModeInternal(const std::string &color_mode) {
DLOGV_IF(kTagQDCM, "Color Mode = %s", color_mode.c_str());
ColorModeMap::iterator it = color_mode_map_.find(color_mode);
@@ -721,7 +727,7 @@
SDEDisplayMode *sde_display_mode = it->second;
- DLOGD("Color Mode Name = %s corresponding mode_id = %d", sde_display_mode->name,
+ DLOGV_IF(kTagQDCM, "Color Mode Name = %s corresponding mode_id = %d", sde_display_mode->name,
sde_display_mode->id);
DisplayError error = kErrorNone;
error = color_mgr_->ColorMgrSetMode(sde_display_mode->id);
@@ -1074,4 +1080,136 @@
return comp_manager_->SetCompositionState(display_comp_ctx_, composition_type, enable);
}
+void DisplayBase::CommitLayerParams(LayerStack *layer_stack) {
+ // Copy the acquire fence from clients layers to HWLayers
+ uint32_t hw_layers_count = UINT32(hw_layers_.info.hw_layers.size());
+
+ for (uint32_t i = 0; i < hw_layers_count; i++) {
+ Layer *sdm_layer = layer_stack->layers.at(hw_layers_.info.index[i]);
+ Layer &hw_layer = hw_layers_.info.hw_layers.at(i);
+
+ hw_layer.input_buffer.planes[0].fd = sdm_layer->input_buffer.planes[0].fd;
+ hw_layer.input_buffer.planes[0].offset = sdm_layer->input_buffer.planes[0].offset;
+ hw_layer.input_buffer.planes[0].stride = sdm_layer->input_buffer.planes[0].stride;
+ hw_layer.input_buffer.size = sdm_layer->input_buffer.size;
+ hw_layer.input_buffer.acquire_fence_fd = sdm_layer->input_buffer.acquire_fence_fd;
+ }
+
+ return;
+}
+
+void DisplayBase::PostCommitLayerParams(LayerStack *layer_stack) {
+ // Copy the release fence from HWLayers to clients layers
+ uint32_t hw_layers_count = UINT32(hw_layers_.info.hw_layers.size());
+
+ std::vector<uint32_t> fence_dup_flag = {};
+
+ for (uint32_t i = 0; i < hw_layers_count; i++) {
+ uint32_t sdm_layer_index = hw_layers_.info.index[i];
+ Layer *sdm_layer = layer_stack->layers.at(sdm_layer_index);
+ Layer &hw_layer = hw_layers_.info.hw_layers.at(i);
+
+ // Copy the release fence only once for a SDM Layer.
+ // In S3D use case, two hw layers can share the same input buffer, So make sure to merge the
+ // output fence fd and assign it to layer's input buffer release fence fd.
+ if (std::find(fence_dup_flag.begin(), fence_dup_flag.end(), sdm_layer_index) ==
+ fence_dup_flag.end()) {
+ sdm_layer->input_buffer.release_fence_fd = hw_layer.input_buffer.release_fence_fd;
+ fence_dup_flag.push_back(sdm_layer_index);
+ } else {
+ int temp = -1;
+ buffer_sync_handler_->SyncMerge(hw_layer.input_buffer.release_fence_fd,
+ sdm_layer->input_buffer.release_fence_fd, &temp);
+
+ if (hw_layer.input_buffer.release_fence_fd >= 0) {
+ Sys::close_(hw_layer.input_buffer.release_fence_fd);
+ hw_layer.input_buffer.release_fence_fd = -1;
+ }
+
+ if (sdm_layer->input_buffer.release_fence_fd >= 0) {
+ Sys::close_(sdm_layer->input_buffer.release_fence_fd);
+ sdm_layer->input_buffer.release_fence_fd = -1;
+ }
+
+ sdm_layer->input_buffer.release_fence_fd = temp;
+ }
+
+ // Reset the sync fence fds of HWLayer
+ hw_layer.input_buffer.acquire_fence_fd = -1;
+ hw_layer.input_buffer.release_fence_fd = -1;
+ }
+
+ return;
+}
+
+DisplayError DisplayBase::InitializeColorModes() {
+ if (!color_mgr_) {
+ return kErrorNotSupported;
+ }
+
+ DisplayError error = color_mgr_->ColorMgrGetNumOfModes(&num_color_modes_);
+ if (error != kErrorNone || !num_color_modes_) {
+ DLOGV_IF(kTagQDCM, "GetNumModes failed = %d count = %d", error, num_color_modes_);
+ return kErrorNotSupported;
+ }
+ DLOGI("Number of Color Modes = %d", num_color_modes_);
+
+ if (!color_modes_.size()) {
+ color_modes_.resize(num_color_modes_);
+
+ DisplayError error = color_mgr_->ColorMgrGetModes(&num_color_modes_, color_modes_.data());
+ if (error != kErrorNone) {
+ color_modes_.clear();
+ DLOGE("Failed");
+ return error;
+ }
+
+ for (uint32_t i = 0; i < num_color_modes_; i++) {
+ DLOGV_IF(kTagQDCM, "Color Mode[%d]: Name = %s mode_id = %d", i, color_modes_[i].name,
+ color_modes_[i].id);
+ auto it = color_mode_map_.find(color_modes_[i].name);
+ if (it != color_mode_map_.end()) {
+ if (it->second->id < color_modes_[i].id) {
+ color_mode_map_.erase(it);
+ color_mode_map_.insert(std::make_pair(color_modes_[i].name, &color_modes_[i]));
+ }
+ } else {
+ color_mode_map_.insert(std::make_pair(color_modes_[i].name, &color_modes_[i]));
+ }
+ }
+ }
+
+ return kErrorNone;
+}
+
+DisplayError DisplayBase::HandleHDR(LayerStack *layer_stack) {
+ DisplayError error = kErrorNone;
+
+ if (!color_mgr_) {
+ // TODO(user): Handle the case where color_mgr is not present
+ return kErrorNone;
+ }
+
+ if (!layer_stack->flags.hdr_present) {
+ // HDR playback off - set prev mode
+ if (hdr_playback_mode_) {
+ hdr_playback_mode_ = false;
+ DLOGI("Setting color mode = %s", current_color_mode_.c_str());
+ error = SetColorModeInternal(current_color_mode_);
+ // TODO(user): Enable DPPS
+ }
+ } else {
+ // hdr is present
+ if (!hdr_playback_mode_ && !layer_stack->flags.animating) {
+ // hdr is starting
+ hdr_playback_mode_ = true;
+ DLOGI("Setting HDR color mode = %s", hdr_color_mode_.c_str());
+ error = SetColorModeInternal(hdr_color_mode_);
+ }
+ // TODO(user): Disable DPPS
+ }
+
+ return error;
+}
+
} // namespace sdm
diff --git a/sdm/libs/core/display_base.h b/sdm/libs/core/display_base.h
index ae1171d..85a1bc2 100644
--- a/sdm/libs/core/display_base.h
+++ b/sdm/libs/core/display_base.h
@@ -112,6 +112,9 @@
protected:
DisplayError BuildLayerStackStats(LayerStack *layer_stack);
virtual DisplayError ValidateGPUTargetParams();
+ void CommitLayerParams(LayerStack *layer_stack);
+ void PostCommitLayerParams(LayerStack *layer_stack);
+ DisplayError HandleHDR(LayerStack *layer_stack);
// DumpImpl method
void AppendDump(char *buffer, uint32_t length);
@@ -122,6 +125,8 @@
uint32_t *new_mixer_height);
DisplayError ReconfigureMixer(uint32_t width, uint32_t height);
bool NeedsDownScale(const LayerRect &src_rect, const LayerRect &dst_rect, bool needs_rotation);
+ DisplayError InitializeColorModes();
+ DisplayError SetColorModeInternal(const std::string &color_mode);
recursive_mutex recursive_mutex_;
DisplayType display_type_;
@@ -153,6 +158,9 @@
DisplayConfigVariableInfo fb_config_ = {};
uint32_t req_mixer_width_ = 0;
uint32_t req_mixer_height_ = 0;
+ std::string current_color_mode_ = "hal_native";
+ std::string hdr_color_mode_ = "hal_hdr";
+ bool hdr_playback_mode_ = false;
};
} // namespace sdm
diff --git a/sdm/libs/core/display_hdmi.cpp b/sdm/libs/core/display_hdmi.cpp
index a577348..46d1a20 100644
--- a/sdm/libs/core/display_hdmi.cpp
+++ b/sdm/libs/core/display_hdmi.cpp
@@ -259,9 +259,9 @@
// 2. Layer stack containing only one secure layer along with one s3d layer
for (uint32_t i = 0; i < layer_count; i++) {
Layer *layer = layer_stack->layers.at(i);
- LayerBuffer *layer_buffer = layer->input_buffer;
+ LayerBuffer &layer_buffer = layer->input_buffer;
- if (layer_buffer->s3d_format != kS3dFormatNone) {
+ if (layer_buffer.s3d_format != kS3dFormatNone) {
s3d_layer_count++;
if (s3d_layer_count > 1 || layer->flags.skip) {
s3d_mode = kS3DModeNone;
@@ -269,11 +269,11 @@
}
std::map<LayerBufferS3DFormat, HWS3DMode>::iterator it =
- s3d_format_to_mode_.find(layer_buffer->s3d_format);
+ s3d_format_to_mode_.find(layer_buffer.s3d_format);
if (it != s3d_format_to_mode_.end()) {
s3d_mode = it->second;
}
- } else if (layer_buffer->flags.secure && layer_count > 2) {
+ } else if (layer_buffer.flags.secure && layer_count > 2) {
s3d_mode = kS3DModeNone;
break;
}
diff --git a/sdm/libs/core/fb/hw_device.cpp b/sdm/libs/core/fb/hw_device.cpp
index f7aebe2..e2b684f 100644
--- a/sdm/libs/core/fb/hw_device.cpp
+++ b/sdm/libs/core/fb/hw_device.cpp
@@ -227,11 +227,11 @@
DisplayError error = kErrorNone;
HWLayersInfo &hw_layer_info = hw_layers->info;
- LayerStack *stack = hw_layer_info.stack;
+ uint32_t hw_layer_count = UINT32(hw_layer_info.hw_layers.size());
DLOGV_IF(kTagDriverConfig, "************************** %s Validate Input ***********************",
device_name_);
- DLOGV_IF(kTagDriverConfig, "SDE layer count is %d", hw_layer_info.count);
+ DLOGV_IF(kTagDriverConfig, "SDE layer count is %d", hw_layer_count);
mdp_layer_commit_v1 &mdp_commit = mdp_disp_commit_.commit_v1;
uint32_t &mdp_layer_count = mdp_commit.input_layer_cnt;
@@ -241,55 +241,54 @@
DLOGI_IF(kTagDriverConfig, "right_roi: x = %d, y = %d, w = %d, h = %d", mdp_commit.right_roi.x,
mdp_commit.right_roi.y, mdp_commit.right_roi.w, mdp_commit.right_roi.h);
- for (uint32_t i = 0; i < hw_layer_info.count; i++) {
- uint32_t layer_index = hw_layer_info.index[i];
- Layer *layer = stack->layers.at(layer_index);
- LayerBuffer *input_buffer = layer->input_buffer;
+ for (uint32_t i = 0; i < hw_layer_count; i++) {
+ const Layer &layer = hw_layer_info.hw_layers.at(i);
+ LayerBuffer input_buffer = layer.input_buffer;
HWPipeInfo *left_pipe = &hw_layers->config[i].left_pipe;
HWPipeInfo *right_pipe = &hw_layers->config[i].right_pipe;
HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
bool is_rotator_used = (hw_rotator_session->hw_block_count != 0);
- bool is_cursor_pipe_used = (hw_layer_info.use_hw_cursor & layer->flags.cursor);
+ bool is_cursor_pipe_used = (hw_layer_info.use_hw_cursor & layer.flags.cursor);
for (uint32_t count = 0; count < 2; count++) {
HWPipeInfo *pipe_info = (count == 0) ? left_pipe : right_pipe;
HWRotateInfo *hw_rotate_info = &hw_rotator_session->hw_rotate_info[count];
if (hw_rotate_info->valid) {
- input_buffer = &hw_rotator_session->output_buffer;
+ input_buffer = hw_rotator_session->output_buffer;
}
if (pipe_info->valid) {
mdp_input_layer &mdp_layer = mdp_in_layers_[mdp_layer_count];
mdp_layer_buffer &mdp_buffer = mdp_layer.buffer;
- mdp_buffer.width = input_buffer->width;
- mdp_buffer.height = input_buffer->height;
+ mdp_buffer.width = input_buffer.width;
+ mdp_buffer.height = input_buffer.height;
mdp_buffer.comp_ratio.denom = 1000;
mdp_buffer.comp_ratio.numer = UINT32(hw_layers->config[i].compression * 1000);
- if (layer->flags.solid_fill) {
+ if (layer.flags.solid_fill) {
mdp_buffer.format = MDP_ARGB_8888;
} else {
- error = SetFormat(input_buffer->format, &mdp_buffer.format);
+ error = SetFormat(input_buffer.format, &mdp_buffer.format);
if (error != kErrorNone) {
return error;
}
}
- mdp_layer.alpha = layer->plane_alpha;
+ mdp_layer.alpha = layer.plane_alpha;
mdp_layer.z_order = UINT16(pipe_info->z_order);
mdp_layer.transp_mask = 0xffffffff;
- SetBlending(layer->blending, &mdp_layer.blend_op);
+ SetBlending(layer.blending, &mdp_layer.blend_op);
mdp_layer.pipe_ndx = pipe_info->pipe_id;
mdp_layer.horz_deci = pipe_info->horizontal_decimation;
mdp_layer.vert_deci = pipe_info->vertical_decimation;
SetRect(pipe_info->src_roi, &mdp_layer.src_rect);
SetRect(pipe_info->dst_roi, &mdp_layer.dst_rect);
- SetMDPFlags(layer, is_rotator_used, is_cursor_pipe_used, &mdp_layer.flags);
- SetCSC(layer->input_buffer->csc, &mdp_layer.color_space);
+ SetMDPFlags(&layer, is_rotator_used, is_cursor_pipe_used, &mdp_layer.flags);
+ SetCSC(layer.input_buffer.color_metadata, &mdp_layer.color_space);
if (pipe_info->flags & kIGC) {
- SetIGC(layer->input_buffer, mdp_layer_count);
+ SetIGC(&layer.input_buffer, mdp_layer_count);
}
if (pipe_info->flags & kMultiRect) {
mdp_layer.flags |= MDP_LAYER_MULTIRECT_ENABLE;
@@ -297,7 +296,7 @@
mdp_layer.flags |= MDP_LAYER_MULTIRECT_PARALLEL_MODE;
}
}
- mdp_layer.bg_color = layer->solid_fill_color;
+ mdp_layer.bg_color = layer.solid_fill_color;
// HWScaleData to MDP driver
hw_scale_->SetHWScaleData(pipe_info->scale_data, mdp_layer_count, &mdp_commit,
@@ -336,7 +335,7 @@
mdp_out_layer_.buffer.comp_ratio.denom = 1000;
mdp_out_layer_.buffer.comp_ratio.numer = UINT32(hw_layers->output_compression * 1000);
#ifdef OUT_LAYER_COLOR_SPACE
- SetCSC(output_buffer->csc, &mdp_out_layer_.color_space);
+ SetCSC(output_buffer->color_metadata, &mdp_out_layer_.color_space);
#endif
SetFormat(output_buffer->format, &mdp_out_layer_.buffer.format);
@@ -427,18 +426,18 @@
DTRACE_SCOPED();
HWLayersInfo &hw_layer_info = hw_layers->info;
- LayerStack *stack = hw_layer_info.stack;
+ uint32_t hw_layer_count = UINT32(hw_layer_info.hw_layers.size());
DLOGV_IF(kTagDriverConfig, "*************************** %s Commit Input ************************",
device_name_);
- DLOGV_IF(kTagDriverConfig, "SDE layer count is %d", hw_layer_info.count);
+ DLOGV_IF(kTagDriverConfig, "SDE layer count is %d", hw_layer_count);
mdp_layer_commit_v1 &mdp_commit = mdp_disp_commit_.commit_v1;
uint32_t mdp_layer_index = 0;
- for (uint32_t i = 0; i < hw_layer_info.count; i++) {
- uint32_t layer_index = hw_layer_info.index[i];
- LayerBuffer *input_buffer = stack->layers.at(layer_index)->input_buffer;
+ for (uint32_t i = 0; i < hw_layer_count; i++) {
+ const Layer &layer = hw_layer_info.hw_layers.at(i);
+ LayerBuffer *input_buffer = const_cast<LayerBuffer *>(&layer.input_buffer);
HWPipeInfo *left_pipe = &hw_layers->config[i].left_pipe;
HWPipeInfo *right_pipe = &hw_layers->config[i].right_pipe;
HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
@@ -521,6 +520,7 @@
return kErrorHardware;
}
+ LayerStack *stack = hw_layer_info.stack;
stack->retire_fence_fd = mdp_commit.retire_fence;
#ifdef VIDEO_MODE_DEFER_RETIRE_FENCE
if (hw_panel_info_.mode == kModeVideo) {
@@ -531,12 +531,9 @@
// MDP returns only one release fence for the entire layer stack. Duplicate this fence into all
// layers being composed by MDP.
- std::vector<uint32_t> fence_dup_flag;
- fence_dup_flag.clear();
-
- for (uint32_t i = 0; i < hw_layer_info.count; i++) {
- uint32_t layer_index = hw_layer_info.index[i];
- LayerBuffer *input_buffer = stack->layers.at(layer_index)->input_buffer;
+ for (uint32_t i = 0; i < hw_layer_count; i++) {
+ const Layer &layer = hw_layer_info.hw_layers.at(i);
+ LayerBuffer *input_buffer = const_cast<LayerBuffer *>(&layer.input_buffer);
HWRotatorSession *hw_rotator_session = &hw_layers->config[i].hw_rotator_session;
if (hw_rotator_session->hw_block_count) {
@@ -545,14 +542,8 @@
continue;
}
- // Make sure the release fence is duplicated only once for each buffer.
- if (std::find(fence_dup_flag.begin(), fence_dup_flag.end(), layer_index) ==
- fence_dup_flag.end()) {
- input_buffer->release_fence_fd = Sys::dup_(mdp_commit.release_fence);
- fence_dup_flag.push_back(layer_index);
- }
+ input_buffer->release_fence_fd = Sys::dup_(mdp_commit.release_fence);
}
- fence_dup_flag.clear();
hw_layer_info.sync_handle = Sys::dup_(mdp_commit.release_fence);
@@ -726,7 +717,7 @@
void HWDevice::SetMDPFlags(const Layer *layer, const bool &is_rotator_used,
bool is_cursor_pipe_used, uint32_t *mdp_flags) {
- const LayerBuffer *input_buffer = layer->input_buffer;
+ const LayerBuffer &input_buffer = layer->input_buffer;
// Flips will be taken care by rotator, if layer uses rotator for downscale/rotation. So ignore
// flip flags for MDP.
@@ -739,18 +730,18 @@
*mdp_flags |= MDP_LAYER_FLIP_LR;
}
- if (input_buffer->flags.interlace) {
+ if (input_buffer.flags.interlace) {
*mdp_flags |= MDP_LAYER_DEINTERLACE;
}
}
- if (input_buffer->flags.secure_camera) {
+ if (input_buffer.flags.secure_camera) {
*mdp_flags |= MDP_LAYER_SECURE_CAMERA_SESSION;
- } else if (input_buffer->flags.secure) {
+ } else if (input_buffer.flags.secure) {
*mdp_flags |= MDP_LAYER_SECURE_SESSION;
}
- if (input_buffer->flags.secure_display) {
+ if (input_buffer.flags.secure_display) {
*mdp_flags |= MDP_LAYER_SECURE_DISPLAY_SESSION;
}
@@ -1070,11 +1061,24 @@
mdp_disp_commit_.commit_v1.dest_scaler = mdp_dest_scalar_data_.data();
}
-void HWDevice::SetCSC(LayerCSC source, mdp_color_space *color_space) {
- switch (source) {
- case kCSCLimitedRange601: *color_space = MDP_CSC_ITU_R_601; break;
- case kCSCFullRange601: *color_space = MDP_CSC_ITU_R_601_FR; break;
- case kCSCLimitedRange709: *color_space = MDP_CSC_ITU_R_709; break;
+void HWDevice::SetCSC(const ColorMetaData &color_metadata, mdp_color_space *color_space) {
+ switch (color_metadata.colorPrimaries) {
+ case ColorPrimaries_BT601_6_525:
+ case ColorPrimaries_BT601_6_625:
+ *color_space = ((color_metadata.range == Range_Full) ? MDP_CSC_ITU_R_601_FR :
+ MDP_CSC_ITU_R_601);
+ break;
+ case ColorPrimaries_BT709_5:
+ *color_space = MDP_CSC_ITU_R_709;
+ break;
+#if defined MDP_CSC_ITU_R_2020 && defined MDP_CSC_ITU_R_2020_FR
+ case ColorPrimaries_BT2020:
+ *color_space = static_cast<mdp_color_space>((color_metadata.range == Range_Full) ?
+ MDP_CSC_ITU_R_2020_FR : MDP_CSC_ITU_R_2020);
+ break;
+#endif
+ default:
+ break;
}
}
@@ -1106,7 +1110,7 @@
DTRACE_SCOPED();
HWLayersInfo &hw_layer_info = hw_layers->info;
- uint32_t count = hw_layer_info.count;
+ uint32_t count = UINT32(hw_layer_info.hw_layers.size());
uint32_t cursor_index = count - 1;
HWPipeInfo *left_pipe = &hw_layers->config[cursor_index].left_pipe;
diff --git a/sdm/libs/core/fb/hw_device.h b/sdm/libs/core/fb/hw_device.h
index 72c7a13..aa73177 100644
--- a/sdm/libs/core/fb/hw_device.h
+++ b/sdm/libs/core/fb/hw_device.h
@@ -129,7 +129,7 @@
int ParseLine(const char *input, const char *delim, char *tokens[],
const uint32_t max_token, uint32_t *count);
void ResetDisplayParams();
- void SetCSC(const LayerCSC source, mdp_color_space *color_space);
+ void SetCSC(const ColorMetaData &color_metadata, mdp_color_space *color_space);
void SetIGC(const LayerBuffer *layer_buffer, uint32_t index);
bool EnableHotPlugDetection(int enable);
diff --git a/sdm/libs/core/fb/hw_info.cpp b/sdm/libs/core/fb/hw_info.cpp
index ef450c0..08a7188 100644
--- a/sdm/libs/core/fb/hw_info.cpp
+++ b/sdm/libs/core/fb/hw_info.cpp
@@ -386,18 +386,20 @@
}
}
- DLOGI("MDSS Rotator: Count = %d, Downscale = %d", hw_resource->hw_rot_info.num_rotator,
- hw_resource->hw_rot_info.has_downscale);
+ DLOGI("MDSS Rotator: Count = %d, Downscale = %d, Min_downscale = %f",
+ hw_resource->hw_rot_info.num_rotator, hw_resource->hw_rot_info.has_downscale,
+ hw_resource->hw_rot_info.min_downscale);
return kErrorNone;
}
DisplayError HWInfo::GetV4L2RotatorInfo(HWResourceInfo *hw_resource) {
+ string v4l2_path = "/sys/class/video4linux/video";
const uint32_t kMaxV4L2Nodes = 64;
bool found = false;
for (uint32_t i = 0; (i < kMaxV4L2Nodes) && (false == found); i++) {
- string path = "/sys/class/video4linux/video" + to_string(i) + "/name";
+ string path = v4l2_path + to_string(i) + "/name";
Sys::fstream fs(path, fstream::in);
if (!fs.is_open()) {
continue;
@@ -410,13 +412,34 @@
hw_resource->hw_rot_info.num_rotator++;
hw_resource->hw_rot_info.type = HWRotatorInfo::ROT_TYPE_V4L2;
hw_resource->hw_rot_info.has_downscale = true;
+
+ string caps_path = v4l2_path + to_string(i) + "/device/caps";
+ Sys::fstream caps_fs(caps_path, fstream::in);
+
+ if (caps_fs.is_open()) {
+ uint32_t token_count = 0;
+ const uint32_t max_count = 10;
+ char *tokens[max_count] = { NULL };
+ string caps;
+ while (Sys::getline_(caps_fs, caps)) {
+ if (!ParseString(caps.c_str(), tokens, max_count, ":, =\n", &token_count)) {
+ if (!strncmp(tokens[0], "downscale_compression", strlen("downscale_compression"))) {
+ hw_resource->hw_rot_info.downscale_compression = UINT8(atoi(tokens[1]));
+ } else if (!strncmp(tokens[0], "min_downscale", strlen("min_downscale"))) {
+ hw_resource->hw_rot_info.min_downscale = FLOAT(atof(tokens[1]));
+ }
+ }
+ }
+ }
+
// We support only 1 rotator
found = true;
}
}
- DLOGI("V4L2 Rotator: Count = %d, Downscale = %d", hw_resource->hw_rot_info.num_rotator,
- hw_resource->hw_rot_info.has_downscale);
+ DLOGI("V4L2 Rotator: Count = %d, Downscale = %d, Min_downscale = %f, Downscale_compression = %d",
+ hw_resource->hw_rot_info.num_rotator, hw_resource->hw_rot_info.has_downscale,
+ hw_resource->hw_rot_info.min_downscale, hw_resource->hw_rot_info.downscale_compression);
return kErrorNone;
}
diff --git a/sdm/libs/core/fb/hw_primary.cpp b/sdm/libs/core/fb/hw_primary.cpp
index 6f62143..b484d5e 100644
--- a/sdm/libs/core/fb/hw_primary.cpp
+++ b/sdm/libs/core/fb/hw_primary.cpp
@@ -65,6 +65,10 @@
#define MDP_COMMIT_AVR_ONE_SHOT_MODE 0x10
#endif
+#ifndef MDP_COMMIT_PARTIAL_UPDATE_DUAL_ROI
+#define MDP_COMMIT_PARTIAL_UPDATE_DUAL_ROI 0x20
+#endif
+
namespace sdm {
using std::string;
@@ -101,6 +105,8 @@
EnableHotPlugDetection(1);
InitializeConfigs();
+ avr_prop_disabled_ = Debug::IsAVRDisabled();
+
return error;
}
@@ -223,10 +229,11 @@
return kErrorHardware;
}
- // If driver doesn't return width/height information, default to 160 dpi
+ // If driver doesn't return width/height information, default to 320 dpi
if (INT(var_screeninfo.width) <= 0 || INT(var_screeninfo.height) <= 0) {
- var_screeninfo.width = UINT32(((FLOAT(var_screeninfo.xres) * 25.4f)/160.0f) + 0.5f);
- var_screeninfo.height = UINT32(((FLOAT(var_screeninfo.yres) * 25.4f)/160.0f) + 0.5f);
+ var_screeninfo.width = UINT32(((FLOAT(var_screeninfo.xres) * 25.4f)/320.0f) + 0.5f);
+ var_screeninfo.height = UINT32(((FLOAT(var_screeninfo.yres) * 25.4f)/320.0f) + 0.5f);
+ DLOGW("Driver doesn't report panel physical width and height - defaulting to 320dpi");
}
display_attributes_.x_pixels = var_screeninfo.xres;
@@ -291,6 +298,10 @@
DisplayError HWPrimary::SetRefreshRate(uint32_t refresh_rate) {
char node_path[kMaxStringLength] = {0};
+ if (hw_resource_.has_avr && !avr_prop_disabled_) {
+ return kErrorNotSupported;
+ }
+
if (refresh_rate == display_attributes_.fps) {
return kErrorNone;
}
@@ -373,6 +384,7 @@
// Update second roi information in right_roi
if (hw_layer_info.left_frame_roi.size() == 2) {
+ mdp_commit.flags |= MDP_COMMIT_PARTIAL_UPDATE_DUAL_ROI;
right_roi = hw_layer_info.left_frame_roi.at(1);
}
@@ -398,7 +410,7 @@
mdp_out_layer_.buffer.comp_ratio.numer = UINT32(hw_layers->output_compression * 1000);
mdp_out_layer_.buffer.fence = -1;
#ifdef OUT_LAYER_COLOR_SPACE
- SetCSC(output_buffer->csc, &mdp_out_layer_.color_space);
+ SetCSC(output_buffer->color_metadata, &mdp_out_layer_.color_space);
#endif
SetFormat(output_buffer->format, &mdp_out_layer_.buffer.format);
mdp_commit.flags |= MDP_COMMIT_CWB_EN;
diff --git a/sdm/libs/core/fb/hw_primary.h b/sdm/libs/core/fb/hw_primary.h
index ae45318..bd6ea2f 100644
--- a/sdm/libs/core/fb/hw_primary.h
+++ b/sdm/libs/core/fb/hw_primary.h
@@ -85,6 +85,7 @@
const char *kBrightnessNode = "/sys/class/leds/lcd-backlight/brightness";
const char *kAutoRefreshNode = "/sys/devices/virtual/graphics/fb0/msm_cmd_autorefresh_en";
bool auto_refresh_ = false;
+ bool avr_prop_disabled_ = false;
};
} // namespace sdm
diff --git a/sdm/libs/core/resource_default.cpp b/sdm/libs/core/resource_default.cpp
index 54a6658..31d8704 100644
--- a/sdm/libs/core/resource_default.cpp
+++ b/sdm/libs/core/resource_default.cpp
@@ -228,14 +228,14 @@
DLOGV_IF(kTagResources, "==== Resource reserving start: hw_block = %d ====", hw_block_id);
- if (layer_info.count > 1) {
+ if (layer_info.hw_layers.size() > 1) {
DLOGV_IF(kTagResources, "More than one FB layers");
return kErrorResources;
}
- Layer *layer = layer_info.stack->layers.at(layer_info.index[0]);
+ const Layer &layer = layer_info.hw_layers.at(0);
- if (layer->composition != kCompositionGPUTarget) {
+ if (layer.composition != kCompositionGPUTarget) {
DLOGV_IF(kTagResources, "Not an FB layer");
return kErrorParameters;
}
@@ -539,9 +539,9 @@
HWLayers *hw_layers) {
HWLayersInfo &layer_info = hw_layers->info;
DisplayError error = kErrorNone;
- Layer *layer = layer_info.stack->layers.at(layer_info.index[0]);
+ const Layer &layer = layer_info.hw_layers.at(0);
- error = ValidateLayerParams(layer);
+ error = ValidateLayerParams(&layer);
if (error != kErrorNone) {
return error;
}
@@ -550,16 +550,16 @@
HWPipeInfo &left_pipe = layer_config->left_pipe;
HWPipeInfo &right_pipe = layer_config->right_pipe;
- LayerRect src_rect = layer->src_rect;
- LayerRect dst_rect = layer->dst_rect;
+ LayerRect src_rect = layer.src_rect;
+ LayerRect dst_rect = layer.dst_rect;
error = ValidateDimensions(src_rect, dst_rect);
if (error != kErrorNone) {
return error;
}
- bool ubwc_tiled = IsUBWCFormat(layer->input_buffer->format);
- error = ValidateScaling(src_rect, dst_rect, false /*rotated90 */, ubwc_tiled,
+ BufferLayout layout = GetBufferLayout(layer.input_buffer.format);
+ error = ValidateScaling(src_rect, dst_rect, false /*rotated90 */, layout,
false /* use_rotator_downscale */);
if (error != kErrorNone) {
return error;
@@ -575,7 +575,7 @@
return error;
}
- error = AlignPipeConfig(layer, &left_pipe, &right_pipe);
+ error = AlignPipeConfig(&layer, &left_pipe, &right_pipe);
if (error != kErrorNone) {
return error;
}
@@ -584,8 +584,8 @@
left_pipe.z_order = 0;
DLOGV_IF(kTagResources, "==== FB layer Config ====");
- Log(kTagResources, "input layer src_rect", layer->src_rect);
- Log(kTagResources, "input layer dst_rect", layer->dst_rect);
+ Log(kTagResources, "input layer src_rect", layer.src_rect);
+ Log(kTagResources, "input layer dst_rect", layer.dst_rect);
Log(kTagResources, "cropped src_rect", src_rect);
Log(kTagResources, "cropped dst_rect", dst_rect);
Log(kTagResources, "left pipe src", layer_config->left_pipe.src_roi);
@@ -665,10 +665,10 @@
DisplayError ResourceDefault::ValidateLayerParams(const Layer *layer) {
const LayerRect &src = layer->src_rect;
const LayerRect &dst = layer->dst_rect;
- const LayerBuffer *input_buffer = layer->input_buffer;
+ const LayerBuffer &input_buffer = layer->input_buffer;
- if (input_buffer->format == kFormatInvalid) {
- DLOGV_IF(kTagResources, "Invalid input buffer format %d", input_buffer->format);
+ if (input_buffer.format == kFormatInvalid) {
+ DLOGV_IF(kTagResources, "Invalid input buffer format %d", input_buffer.format);
return kErrorNotSupported;
}
@@ -679,7 +679,7 @@
}
// Make sure source in integral only if it is a non secure layer.
- if (!input_buffer->flags.secure &&
+ if (!input_buffer.flags.secure &&
((src.left - roundf(src.left) != 0.0f) ||
(src.top - roundf(src.top) != 0.0f) ||
(src.right - roundf(src.right) != 0.0f) ||
@@ -716,7 +716,7 @@
return kErrorNone;
}
-DisplayError ResourceDefault::ValidatePipeParams(HWPipeInfo *pipe_info, bool ubwc_tiled) {
+DisplayError ResourceDefault::ValidatePipeParams(HWPipeInfo *pipe_info, LayerBufferFormat format) {
DisplayError error = kErrorNone;
const LayerRect &src_rect = pipe_info->src_roi;
@@ -727,7 +727,8 @@
return error;
}
- error = ValidateScaling(src_rect, dst_rect, false /* rotated90 */, ubwc_tiled,
+ BufferLayout layout = GetBufferLayout(format);
+ error = ValidateScaling(src_rect, dst_rect, false /* rotated90 */, layout,
false /* use_rotator_downscale */);
if (error != kErrorNone) {
return error;
@@ -737,7 +738,7 @@
}
DisplayError ResourceDefault::ValidateScaling(const LayerRect &crop, const LayerRect &dst,
- bool rotate90, bool ubwc_tiled,
+ bool rotate90, BufferLayout layout,
bool use_rotator_downscale) {
DisplayError error = kErrorNone;
@@ -749,7 +750,7 @@
return error;
}
- error = ValidateDownScaling(scale_x, scale_y, ubwc_tiled);
+ error = ValidateDownScaling(scale_x, scale_y, (layout != kLinear));
if (error != kErrorNone) {
return error;
}
@@ -884,8 +885,7 @@
return kErrorNotSupported;
}
- bool ubwc_tiled = IsUBWCFormat(layer->input_buffer->format);
- error = ValidatePipeParams(left_pipe, ubwc_tiled);
+ error = ValidatePipeParams(left_pipe, layer->input_buffer.format);
if (error != kErrorNone) {
goto PipeConfigExit;
}
@@ -894,7 +894,7 @@
// Make sure the left and right ROI are conjunct
right_pipe->src_roi.left = left_pipe->src_roi.right;
right_pipe->dst_roi.left = left_pipe->dst_roi.right;
- error = ValidatePipeParams(right_pipe, ubwc_tiled);
+ error = ValidatePipeParams(right_pipe, layer->input_buffer.format);
}
PipeConfigExit:
diff --git a/sdm/libs/core/resource_default.h b/sdm/libs/core/resource_default.h
index 9f08155..9fab0d0 100644
--- a/sdm/libs/core/resource_default.h
+++ b/sdm/libs/core/resource_default.h
@@ -57,8 +57,8 @@
virtual DisplayError PostCommit(Handle display_ctx, HWLayers *hw_layers);
virtual void Purge(Handle display_ctx);
virtual DisplayError SetMaxMixerStages(Handle display_ctx, uint32_t max_mixer_stages);
- virtual DisplayError ValidateScaling(const LayerRect &crop, const LayerRect &dst,
- bool rotate90, bool ubwc_tiled, bool use_rotator_downscale);
+ virtual DisplayError ValidateScaling(const LayerRect &crop, const LayerRect &dst, bool rotate90,
+ BufferLayout layout, bool use_rotator_downscale);
DisplayError ValidateCursorConfig(Handle display_ctx, const Layer *layer, bool is_top);
DisplayError ValidateCursorPosition(Handle display_ctx, HWLayers *hw_layers, int x, int y);
DisplayError SetMaxBandwidthMode(HWBwModes mode);
@@ -121,7 +121,7 @@
bool CalculateCropRects(const LayerRect &scissor, LayerRect *crop, LayerRect *dst);
DisplayError ValidateLayerParams(const Layer *layer);
DisplayError ValidateDimensions(const LayerRect &crop, const LayerRect &dst);
- DisplayError ValidatePipeParams(HWPipeInfo *pipe_info, bool ubwc_tiled);
+ DisplayError ValidatePipeParams(HWPipeInfo *pipe_info, LayerBufferFormat format);
DisplayError ValidateDownScaling(float scale_x, float scale_y, bool ubwc_tiled);
DisplayError ValidateUpScaling(float scale_x, float scale_y);
DisplayError GetScaleFactor(const LayerRect &crop, const LayerRect &dst, float *scale_x,
diff --git a/sdm/libs/core/strategy.cpp b/sdm/libs/core/strategy.cpp
index 106e9e1..c987fd0 100644
--- a/sdm/libs/core/strategy.cpp
+++ b/sdm/libs/core/strategy.cpp
@@ -137,14 +137,13 @@
LayerStack *layer_stack = hw_layers_info_->stack;
for (uint32_t i = 0; i < hw_layers_info_->app_layer_count; i++) {
layer_stack->layers.at(i)->composition = kCompositionGPU;
+ layer_stack->layers.at(i)->request.flags.request_flags = 0; // Reset layer request
}
if (!extn_start_success_) {
// When mixer resolution and panel resolutions are same (1600x2560) and FB resolution is
// 1080x1920 FB_Target destination coordinates(mapped to FB resolution 1080x1920) need to
// be mapped to destination coordinates of mixer resolution(1600x2560).
- hw_layers_info_->count = 0;
- uint32_t &hw_layer_count = hw_layers_info_->count;
Layer *gpu_target_layer = layer_stack->layers.at(hw_layers_info_->gpu_target_index);
float layer_mixer_width = FLOAT(mixer_attributes_.width);
float layer_mixer_height = FLOAT(mixer_attributes_.height);
@@ -153,11 +152,11 @@
LayerRect src_domain = (LayerRect){0.0f, 0.0f, fb_width, fb_height};
LayerRect dst_domain = (LayerRect){0.0f, 0.0f, layer_mixer_width, layer_mixer_height};
- hw_layers_info_->updated_src_rect[hw_layer_count] = gpu_target_layer->src_rect;
- MapRect(src_domain, dst_domain, gpu_target_layer->dst_rect,
- &hw_layers_info_->updated_dst_rect[hw_layer_count]);
-
- hw_layers_info_->index[hw_layer_count++] = hw_layers_info_->gpu_target_index;
+ Layer layer = *gpu_target_layer;
+ hw_layers_info_->index[0] = hw_layers_info_->gpu_target_index;
+ MapRect(src_domain, dst_domain, layer.dst_rect, &layer.dst_rect);
+ hw_layers_info_->hw_layers.clear();
+ hw_layers_info_->hw_layers.push_back(layer);
}
tried_default_ = true;
@@ -246,4 +245,13 @@
return kErrorNone;
}
+DisplayError Strategy::Purge() {
+ if (strategy_intf_) {
+ return strategy_intf_->Purge();
+ }
+
+ return kErrorNone;
+}
+
+
} // namespace sdm
diff --git a/sdm/libs/core/strategy.h b/sdm/libs/core/strategy.h
index 3fadd0d..a84d139 100644
--- a/sdm/libs/core/strategy.h
+++ b/sdm/libs/core/strategy.h
@@ -49,6 +49,7 @@
const HWMixerAttributes &mixer_attributes,
const DisplayConfigVariableInfo &fb_config);
DisplayError SetCompositionState(LayerComposition composition_type, bool enable);
+ DisplayError Purge();
private:
void GenerateROI();
diff --git a/sdm/libs/hwc/Android.mk b/sdm/libs/hwc/Android.mk
index 259a727..d2828b4 100644
--- a/sdm/libs/hwc/Android.mk
+++ b/sdm/libs/hwc/Android.mk
@@ -15,7 +15,7 @@
LOCAL_SHARED_LIBRARIES := libsdmcore libqservice libbinder libhardware libhardware_legacy \
libutils libcutils libsync libmemalloc libqdutils libdl \
- libpowermanager libsdmutils libc++
+ libpowermanager libsdmutils libgpu_tonemapper libc++
LOCAL_SRC_FILES := hwc_session.cpp \
hwc_display.cpp \
@@ -28,7 +28,8 @@
hwc_buffer_sync_handler.cpp \
hwc_color_manager.cpp \
blit_engine_c2d.cpp \
- cpuhint.cpp
+ cpuhint.cpp \
+ hwc_tonemapper.cpp
include $(BUILD_SHARED_LIBRARY)
endif
diff --git a/sdm/libs/hwc/blit_engine_c2d.cpp b/sdm/libs/hwc/blit_engine_c2d.cpp
index e5cf81c..4efe2f1 100644
--- a/sdm/libs/hwc/blit_engine_c2d.cpp
+++ b/sdm/libs/hwc/blit_engine_c2d.cpp
@@ -207,17 +207,17 @@
for (uint32_t i = blit_target_start_index_-2; (i > 0) && (count < num_blit_target_); i--) {
Layer *layer = layer_stack->layers.at(i);
- LayerBuffer *layer_buffer = layer->input_buffer;
+ LayerBuffer &layer_buffer = layer->input_buffer;
if (layer->composition == kCompositionBlit) {
int index = blit_target_start_index_ + count;
- layer_buffer->release_fence_fd =
- layer_stack->layers.at(index)->input_buffer->release_fence_fd;
- fence_fd = layer_buffer->release_fence_fd;
- close(layer_buffer->acquire_fence_fd);
- layer_buffer->acquire_fence_fd = -1;
- layer_stack->layers.at(index)->input_buffer->release_fence_fd = -1;
- fd = layer_stack->layers.at(index)->input_buffer->acquire_fence_fd;
- layer_stack->layers.at(index)->input_buffer->acquire_fence_fd = -1;
+ layer_buffer.release_fence_fd =
+ layer_stack->layers.at(index)->input_buffer.release_fence_fd;
+ fence_fd = layer_buffer.release_fence_fd;
+ close(layer_buffer.acquire_fence_fd);
+ layer_buffer.acquire_fence_fd = -1;
+ layer_stack->layers.at(index)->input_buffer.release_fence_fd = -1;
+ fd = layer_stack->layers.at(index)->input_buffer.acquire_fence_fd;
+ layer_stack->layers.at(index)->input_buffer.acquire_fence_fd = -1;
count++;
}
}
@@ -262,7 +262,7 @@
Layer *layer = layer_stack->layers.at(i);
// No 10 bit support for C2D
- if (Is10BitFormat(layer->input_buffer->format)) {
+ if (Is10BitFormat(layer->input_buffer.format)) {
return -1;
}
@@ -281,9 +281,9 @@
blit_target_start_index_ = ++i;
num_blit_target_ = layer_count - blit_target_start_index_;
- LayerBuffer *layer_buffer = layer_stack->layers.at(gpu_target_index)->input_buffer;
- int fbwidth = INT(layer_buffer->unaligned_width);
- int fbheight = INT(layer_buffer->unaligned_height);
+ LayerBuffer &layer_buffer = layer_stack->layers.at(gpu_target_index)->input_buffer;
+ int fbwidth = INT(layer_buffer.unaligned_width);
+ int fbheight = INT(layer_buffer.unaligned_height);
if ((fbwidth < 0) || (fbheight < 0)) {
return -1;
}
@@ -293,17 +293,17 @@
for (uint32_t j = 0; j < num_blit_target_; j++, k++) {
Layer *layer = layer_stack->layers.at(k);
- LayerBuffer *layer_buffer = layer->input_buffer;
+ LayerBuffer &layer_buffer = layer->input_buffer;
int aligned_w = 0;
int aligned_h = 0;
// Set the buffer height and width
AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(fbwidth, fbheight/3,
INT(HAL_PIXEL_FORMAT_RGBA_8888), 0, aligned_w, aligned_h);
- layer_buffer->width = aligned_w;
- layer_buffer->height = aligned_h;
- layer_buffer->unaligned_width = fbwidth;
- layer_buffer->unaligned_height = fbheight/3;
+ layer_buffer.width = aligned_w;
+ layer_buffer.height = aligned_h;
+ layer_buffer.unaligned_width = fbwidth;
+ layer_buffer.unaligned_height = fbheight/3;
layer->plane_alpha = 0xFF;
layer->blending = kBlendingOpaque;
@@ -380,16 +380,16 @@
Layer *layer = layer_stack->layers.at(j + content_list->numHwLayers);
private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_];
// Set the fd information
- layer->input_buffer->width = target_aligned_width;
- layer->input_buffer->height = target_aligned_height;
- layer->input_buffer->unaligned_width = target_width;
- layer->input_buffer->unaligned_height = target_height;
+ layer->input_buffer.width = target_aligned_width;
+ layer->input_buffer.height = target_aligned_height;
+ layer->input_buffer.unaligned_width = target_width;
+ layer->input_buffer.unaligned_height = target_height;
if (target_buffer->flags & private_handle_t::PRIV_FLAGS_UBWC_ALIGNED) {
- layer->input_buffer->format = kFormatRGBA8888Ubwc;
+ layer->input_buffer.format = kFormatRGBA8888Ubwc;
}
- layer->input_buffer->planes[0].fd = target_buffer->fd;
- layer->input_buffer->planes[0].offset = 0;
- layer->input_buffer->planes[0].stride = target_buffer->width;
+ layer->input_buffer.planes[0].fd = target_buffer->fd;
+ layer->input_buffer.planes[0].offset = 0;
+ layer->input_buffer.planes[0].stride = target_buffer->width;
}
}
@@ -439,7 +439,7 @@
for (uint32_t k = 0; k <= i; k++) {
Layer *bottom_layer = layer_stack->layers.at(k);
- LayerBuffer *layer_buffer = bottom_layer->input_buffer;
+ LayerBuffer &layer_buffer = bottom_layer->input_buffer;
// if layer below the blit layer does not intersect, ignore that layer
LayerRect inter_sect = Intersection(layer->dst_rect, bottom_layer->dst_rect);
if (bottom_layer->composition != kCompositionHybrid && !IsValid(inter_sect)) {
@@ -452,12 +452,12 @@
}
// For each layer marked as Hybrid, wait for acquire fence and then blit using the C2D
- if (layer_buffer->acquire_fence_fd >= 0) {
+ if (layer_buffer.acquire_fence_fd >= 0) {
// Wait for acquire fence on the App buffers.
- if (sync_wait(layer_buffer->acquire_fence_fd, 1000) < 0) {
+ if (sync_wait(layer_buffer.acquire_fence_fd, 1000) < 0) {
DLOGE("sync_wait error!! error no = %d err str = %s", errno, strerror(errno));
}
- layer_buffer->acquire_fence_fd = -1;
+ layer_buffer.acquire_fence_fd = -1;
}
hwc_layer_1_t *hwc_layer = &content_list->hwLayers[k];
LayerRect &src_rect = bottom_layer->blit_regions.at(processed_blit);
@@ -488,8 +488,8 @@
uint32_t layer_count = UINT32(layer_stack->layers.size());
for (uint32_t k = blit_target_start_index_; k < layer_count; k++) {
Layer *layer = layer_stack->layers.at(k);
- LayerBuffer *layer_buffer = layer->input_buffer;
- layer_buffer->acquire_fence_fd = fd;
+ LayerBuffer &layer_buffer = layer->input_buffer;
+ layer_buffer.acquire_fence_fd = fd;
}
}
@@ -500,7 +500,7 @@
LayerRect blit_rect, LayerRect blit_dest_Rect) {
private_handle_t *target_buffer = blit_target_buffer_[current_blit_target_index_];
const private_handle_t *hnd = static_cast<const private_handle_t *>(hwc_layer->handle);
- LayerBuffer *layer_buffer = layer->input_buffer;
+ LayerBuffer &layer_buffer = layer->input_buffer;
// Set the Copybit Source
copybit_image_t src;
@@ -539,7 +539,7 @@
region.count = 1;
region.rect = ®ion_rect;
RegionIterator copybitRegion(region);
- int acquireFd = layer_buffer->acquire_fence_fd;
+ int acquireFd = layer_buffer.acquire_fence_fd;
// FRAMEBUFFER_WIDTH/HEIGHT for c2d is the target buffer w/h
blit_engine_c2d_->set_parameter(blit_engine_c2d_, COPYBIT_FRAMEBUFFER_WIDTH,
diff --git a/sdm/libs/hwc/hwc_display.cpp b/sdm/libs/hwc/hwc_display.cpp
index 3327ed9..305ed66 100644
--- a/sdm/libs/hwc/hwc_display.cpp
+++ b/sdm/libs/hwc/hwc_display.cpp
@@ -41,9 +41,10 @@
#include <utility>
#include <vector>
-#include "hwc_display.h"
-#include "hwc_debugger.h"
#include "blit_engine_c2d.h"
+#include "hwc_debugger.h"
+#include "hwc_display.h"
+#include "hwc_tonemapper.h"
#ifdef QTI_BSP
#include <hardware/display_defs.h>
@@ -55,7 +56,7 @@
static void ApplyDeInterlaceAdjustment(Layer *layer) {
// De-interlacing adjustment
- if (layer->input_buffer->flags.interlace) {
+ if (layer->input_buffer.flags.interlace) {
float height = (layer->src_rect.bottom - layer->src_rect.top) / 2.0f;
layer->src_rect.top = ROUND_UP_ALIGN_DOWN(layer->src_rect.top / 2.0f, 2);
layer->src_rect.bottom = layer->src_rect.top + floorf(height);
@@ -98,6 +99,9 @@
}
}
+ tone_mapper_ = new HWCToneMapper();
+ tone_mapper_->Init();
+
display_intf_->GetRefreshRateRange(&min_refresh_rate_, &max_refresh_rate_);
current_refresh_rate_ = max_refresh_rate_;
@@ -127,6 +131,9 @@
blit_engine_ = NULL;
}
+ delete tone_mapper_;
+ tone_mapper_ = NULL;
+
return 0;
}
@@ -172,6 +179,7 @@
// Do not flush until a buffer is successfully submitted again.
flush_on_error = false;
state = kStateOff;
+ tone_mapper_->Terminate();
break;
case HWC_POWER_MODE_NORMAL:
@@ -273,6 +281,10 @@
blit_engine_->SetFrameDumpConfig(count);
}
+ if (tone_mapper_) {
+ tone_mapper_->SetFrameDumpConfig(count);
+ }
+
DLOGI("num_frame_dump %d, input_layer_dump_enable %d", dump_frame_count_, dump_input_layers_);
}
@@ -323,8 +335,6 @@
for (size_t i = 0; i < num_hw_layers + blit_target_count; i++) {
Layer *layer = new Layer();
- LayerBuffer *layer_buffer = new LayerBuffer();
- layer->input_buffer = layer_buffer;
layer_stack_.layers.push_back(layer);
}
@@ -333,7 +343,6 @@
void HWCDisplay::FreeLayerStack() {
for (Layer *layer : layer_stack_.layers) {
- delete layer->input_buffer;
delete layer;
}
layer_stack_ = {};
@@ -342,10 +351,10 @@
int HWCDisplay::PrepareLayerParams(hwc_layer_1_t *hwc_layer, Layer* layer) {
const private_handle_t *pvt_handle = static_cast<const private_handle_t *>(hwc_layer->handle);
- LayerBuffer *layer_buffer = layer->input_buffer;
+ LayerBuffer &layer_buffer = layer->input_buffer;
if (pvt_handle) {
- layer_buffer->format = GetSDMFormat(pvt_handle->format, pvt_handle->flags);
+ layer_buffer.format = GetSDMFormat(pvt_handle->format, pvt_handle->flags);
int aligned_width, aligned_height;
int unaligned_width, unaligned_height;
@@ -354,10 +363,10 @@
AdrenoMemInfo::getInstance().getUnalignedWidthAndHeight(pvt_handle, unaligned_width,
unaligned_height);
- layer_buffer->width = UINT32(aligned_width);
- layer_buffer->height = UINT32(aligned_height);
- layer_buffer->unaligned_width = UINT32(unaligned_width);
- layer_buffer->unaligned_height = UINT32(unaligned_height);
+ layer_buffer.width = UINT32(aligned_width);
+ layer_buffer.height = UINT32(aligned_height);
+ layer_buffer.unaligned_width = UINT32(unaligned_width);
+ layer_buffer.unaligned_height = UINT32(unaligned_height);
if (SetMetaData(pvt_handle, layer) != kErrorNone) {
return -EINVAL;
@@ -365,14 +374,14 @@
if (pvt_handle->bufferType == BUFFER_TYPE_VIDEO) {
layer_stack_.flags.video_present = true;
- layer_buffer->flags.video = true;
+ layer_buffer.flags.video = true;
}
// TZ Protected Buffer - L1
if (pvt_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
layer_stack_.flags.secure_present = true;
- layer_buffer->flags.secure = true;
+ layer_buffer.flags.secure = true;
if (pvt_handle->flags & private_handle_t::PRIV_FLAGS_CAMERA_WRITE) {
- layer_buffer->flags.secure_camera = true;
+ layer_buffer.flags.secure_camera = true;
}
}
// Gralloc Usage Protected Buffer - L3 - which needs to be treated as Secure & avoid fallback
@@ -380,7 +389,7 @@
layer_stack_.flags.secure_present = true;
}
if (pvt_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_DISPLAY) {
- layer_buffer->flags.secure_display = true;
+ layer_buffer.flags.secure_display = true;
}
// check if this is special solid_fill layer without input_buffer.
@@ -409,11 +418,11 @@
AdrenoMemInfo::getInstance().getAlignedWidthAndHeight(INT(x_pixels), INT(y_pixels), format,
usage, aligned_width, aligned_height);
- layer_buffer->width = UINT32(aligned_width);
- layer_buffer->height = UINT32(aligned_height);
- layer_buffer->unaligned_width = x_pixels;
- layer_buffer->unaligned_height = y_pixels;
- layer_buffer->format = GetSDMFormat(format, flags);
+ layer_buffer.width = UINT32(aligned_width);
+ layer_buffer.height = UINT32(aligned_height);
+ layer_buffer.unaligned_width = x_pixels;
+ layer_buffer.unaligned_height = y_pixels;
+ layer_buffer.format = GetSDMFormat(format, flags);
}
}
@@ -422,13 +431,13 @@
void HWCDisplay::CommitLayerParams(hwc_layer_1_t *hwc_layer, Layer *layer) {
const private_handle_t *pvt_handle = static_cast<const private_handle_t *>(hwc_layer->handle);
- LayerBuffer *layer_buffer = layer->input_buffer;
+ LayerBuffer &layer_buffer = layer->input_buffer;
if (pvt_handle) {
- layer_buffer->planes[0].fd = pvt_handle->fd;
- layer_buffer->planes[0].offset = pvt_handle->offset;
- layer_buffer->planes[0].stride = UINT32(pvt_handle->width);
- layer_buffer->size = pvt_handle->size;
+ layer_buffer.planes[0].fd = pvt_handle->fd;
+ layer_buffer.planes[0].offset = pvt_handle->offset;
+ layer_buffer.planes[0].stride = UINT32(pvt_handle->width);
+ layer_buffer.size = pvt_handle->size;
}
// if swapinterval property is set to 0 then close and reset the acquireFd
@@ -436,7 +445,7 @@
close(hwc_layer->acquireFenceFd);
hwc_layer->acquireFenceFd = -1;
}
- layer_buffer->acquire_fence_fd = hwc_layer->acquireFenceFd;
+ layer_buffer.acquire_fence_fd = hwc_layer->acquireFenceFd;
}
int HWCDisplay::PrePrepareLayerStack(hwc_display_contents_1_t *content_list) {
@@ -521,7 +530,7 @@
// - incoming planeAlpha,
// - blending to Coverage.
if (hwc_layer.flags & kDimLayer) {
- layer->input_buffer->format = kFormatARGB8888;
+ layer->input_buffer.format = kFormatARGB8888;
layer->solid_fill_color = 0xff000000;
#ifdef QTI_BSP
// Get ARGB color from HWC Dim Layer color
@@ -544,15 +553,15 @@
// TODO(user): Remove below block.
// For solid fill, only dest rect need to be specified.
if (layer->flags.solid_fill) {
- LayerBuffer *input_buffer = layer->input_buffer;
- input_buffer->width = UINT32(layer->dst_rect.right - layer->dst_rect.left);
- input_buffer->height = UINT32(layer->dst_rect.bottom - layer->dst_rect.top);
- input_buffer->unaligned_width = input_buffer->width;
- input_buffer->unaligned_height = input_buffer->height;
+ LayerBuffer &input_buffer = layer->input_buffer;
+ input_buffer.width = UINT32(layer->dst_rect.right - layer->dst_rect.left);
+ input_buffer.height = UINT32(layer->dst_rect.bottom - layer->dst_rect.top);
+ input_buffer.unaligned_width = input_buffer.width;
+ input_buffer.unaligned_height = input_buffer.height;
layer->src_rect.left = 0;
layer->src_rect.top = 0;
- layer->src_rect.right = input_buffer->width;
- layer->src_rect.bottom = input_buffer->height;
+ layer->src_rect.right = input_buffer.width;
+ layer->src_rect.bottom = input_buffer.height;
}
layer->plane_alpha = hwc_layer.planeAlpha;
@@ -577,7 +586,7 @@
PrepareDynamicRefreshRate(layer);
- layer->input_buffer->buffer_id = reinterpret_cast<uint64_t>(hwc_layer.handle);
+ layer->input_buffer.buffer_id = reinterpret_cast<uint64_t>(hwc_layer.handle);
}
// Prepare the Blit Target
@@ -665,7 +674,7 @@
// Align HWC and client's dispaly ID in case of HDMI as primary
meta_data->s3dComp.displayId =
display_intf_->IsPrimaryDisplay() ? HWC_DISPLAY_PRIMARY: id_;
- SetLayerS3DMode(layer->input_buffer->s3d_format,
+ SetLayerS3DMode(layer->input_buffer.s3d_format,
&meta_data->s3dComp.s3dMode);
}
}
@@ -705,6 +714,15 @@
}
}
+ if (layer_stack_.flags.hdr_present) {
+ status = tone_mapper_->HandleToneMap(content_list, &layer_stack_);
+ if (status != 0) {
+ DLOGE("Error handling HDR in ToneMapper");
+ }
+ } else {
+ tone_mapper_->Terminate();
+ }
+
DisplayError error = kErrorUndefined;
if (status == 0) {
error = display_intf_->Commit(&layer_stack_);
@@ -741,6 +759,11 @@
display_intf_->Flush();
}
+
+ if (tone_mapper_ && tone_mapper_->IsActive()) {
+ tone_mapper_->PostCommit(&layer_stack_);
+ }
+
// Set the release fence fd to the blit engine
if (use_blit_comp_ && blit_engine_->BlitActive()) {
blit_engine_->PostCommit(&layer_stack_);
@@ -749,17 +772,17 @@
for (size_t i = 0; i < num_hw_layers; i++) {
hwc_layer_1_t &hwc_layer = content_list->hwLayers[i];
Layer *layer = layer_stack_.layers.at(i);
- LayerBuffer *layer_buffer = layer->input_buffer;
+ LayerBuffer &layer_buffer = layer->input_buffer;
if (!flush_) {
// If swapinterval property is set to 0 or for single buffer layers, do not update f/w
// release fences and discard fences from driver
if (swap_interval_zero_ || layer->flags.single_buffer) {
hwc_layer.releaseFenceFd = -1;
- close(layer_buffer->release_fence_fd);
- layer_buffer->release_fence_fd = -1;
+ close(layer_buffer.release_fence_fd);
+ layer_buffer.release_fence_fd = -1;
} else if (layer->composition != kCompositionGPU) {
- hwc_layer.releaseFenceFd = layer_buffer->release_fence_fd;
+ hwc_layer.releaseFenceFd = layer_buffer.release_fence_fd;
}
// During animation on external/virtual display, SDM will use the cached
@@ -1226,14 +1249,36 @@
void HWCDisplay::ApplyScanAdjustment(hwc_rect_t *display_frame) {
}
-DisplayError HWCDisplay::SetCSC(ColorSpace_t source, LayerCSC *target) {
- switch (source) {
- case ITU_R_601: *target = kCSCLimitedRange601; break;
- case ITU_R_601_FR: *target = kCSCFullRange601; break;
- case ITU_R_709: *target = kCSCLimitedRange709; break;
- default:
- DLOGE("Unsupported CSC: %d", source);
- return kErrorNotSupported;
+DisplayError HWCDisplay::SetCSC(const MetaData_t *meta_data, ColorMetaData *color_metadata) {
+ if (meta_data->operation & COLOR_METADATA) {
+#ifdef USE_COLOR_METADATA
+ *color_metadata = meta_data->color;
+#endif
+ } else if (meta_data->operation & UPDATE_COLOR_SPACE) {
+ ColorSpace_t csc = meta_data->colorSpace;
+ color_metadata->range = Range_Limited;
+
+ if (csc == ITU_R_601_FR || csc == ITU_R_2020_FR) {
+ color_metadata->range = Range_Full;
+ }
+
+ switch (csc) {
+ case ITU_R_601:
+ case ITU_R_601_FR:
+ // display driver uses 601 irrespective of 525 or 625
+ color_metadata->colorPrimaries = ColorPrimaries_BT601_6_525;
+ break;
+ case ITU_R_709:
+ color_metadata->colorPrimaries = ColorPrimaries_BT709_5;
+ break;
+ case ITU_R_2020:
+ case ITU_R_2020_FR:
+ color_metadata->colorPrimaries = ColorPrimaries_BT2020;
+ break;
+ default:
+ DLOGE("Unsupported CSC: %d", csc);
+ return kErrorNotSupported;
+ }
}
return kErrorNone;
@@ -1253,20 +1298,25 @@
DisplayError HWCDisplay::SetMetaData(const private_handle_t *pvt_handle, Layer *layer) {
const MetaData_t *meta_data = reinterpret_cast<MetaData_t *>(pvt_handle->base_metadata);
- LayerBuffer *layer_buffer = layer->input_buffer;
+ LayerBuffer &layer_buffer = layer->input_buffer;
if (!meta_data) {
return kErrorNone;
}
- if (meta_data->operation & UPDATE_COLOR_SPACE) {
- if (SetCSC(meta_data->colorSpace, &layer_buffer->csc) != kErrorNone) {
- return kErrorNotSupported;
- }
+ if (SetCSC(meta_data, &layer_buffer.color_metadata) != kErrorNone) {
+ return kErrorNotSupported;
+ }
+
+ if (layer_buffer.color_metadata.colorPrimaries == ColorPrimaries_BT2020 &&
+ (layer_buffer.color_metadata.transfer == Transfer_SMPTE_ST2084 ||
+ layer_buffer.color_metadata.transfer == Transfer_HLG)) {
+ layer_buffer.flags.hdr = true;
+ layer_stack_.flags.hdr_present = true;
}
if (meta_data->operation & SET_IGC) {
- if (SetIGC(meta_data->igc, &layer_buffer->igc) != kErrorNone) {
+ if (SetIGC(meta_data->igc, &layer_buffer.igc) != kErrorNone) {
return kErrorNotSupported;
}
}
@@ -1276,11 +1326,11 @@
}
if ((meta_data->operation & PP_PARAM_INTERLACED) && meta_data->interlaced) {
- layer_buffer->flags.interlace = true;
+ layer_buffer.flags.interlace = true;
}
if (meta_data->operation & LINEAR_FORMAT) {
- layer_buffer->format = GetSDMFormat(INT32(meta_data->linearFormat), 0);
+ layer_buffer.format = GetSDMFormat(INT32(meta_data->linearFormat), 0);
}
if (meta_data->operation & SET_SINGLE_BUFFER_MODE) {
@@ -1294,7 +1344,7 @@
std::map<int, LayerBufferS3DFormat>::iterator it =
s3d_format_hwc_to_sdm_.find(INT32(meta_data->s3dFormat));
if (it != s3d_format_hwc_to_sdm_.end()) {
- layer->input_buffer->s3d_format = it->second;
+ layer->input_buffer.s3d_format = it->second;
} else {
DLOGW("Invalid S3D format %d", meta_data->s3dFormat);
}
@@ -1398,8 +1448,8 @@
// need play in dedicate resolution and fps, if DRC switch the
// mode to an non S3D supported mode, it would break S3D playback.
// Need figure out a way to make S3D and DRC co-exist.
- if (layer->flags.updating && (layer->input_buffer->flags.video == true) &&
- (layer->input_buffer->s3d_format == kS3dFormatNone)) {
+ if (layer->flags.updating && (layer->input_buffer.flags.video == true) &&
+ (layer->input_buffer.s3d_format == kS3dFormatNone)) {
updating_count++;
}
}
diff --git a/sdm/libs/hwc/hwc_display.h b/sdm/libs/hwc/hwc_display.h
index 7dab6d5..dad78b6 100644
--- a/sdm/libs/hwc/hwc_display.h
+++ b/sdm/libs/hwc/hwc_display.h
@@ -36,6 +36,7 @@
namespace sdm {
class BlitEngine;
+class HWCToneMapper;
// Subclasses set this to their type. This has to be different from DisplayType.
// This is to avoid RTTI and dynamic_cast
@@ -170,7 +171,7 @@
const char *GetDisplayString();
void MarkLayersForGPUBypass(hwc_display_contents_1_t *content_list);
virtual void ApplyScanAdjustment(hwc_rect_t *display_frame);
- DisplayError SetCSC(ColorSpace_t source, LayerCSC *target);
+ DisplayError SetCSC(const MetaData_t *meta_data, ColorMetaData *color_metadata);
DisplayError SetIGC(IGC_t source, LayerIGC *target);
DisplayError SetMetaData(const private_handle_t *pvt_handle, Layer *layer);
bool NeedsFrameBufferRefresh(hwc_display_contents_1_t *content_list);
@@ -217,6 +218,7 @@
LayerRect display_rect_;
std::map<int, LayerBufferS3DFormat> s3d_format_hwc_to_sdm_;
bool animating_ = false;
+ HWCToneMapper *tone_mapper_ = NULL;
private:
void DumpInputBuffers(hwc_display_contents_1_t *content_list);
diff --git a/sdm/libs/hwc/hwc_display_external.cpp b/sdm/libs/hwc/hwc_display_external.cpp
index 8a3a591..5b277c7 100644
--- a/sdm/libs/hwc/hwc_display_external.cpp
+++ b/sdm/libs/hwc/hwc_display_external.cpp
@@ -277,7 +277,7 @@
}
void HWCDisplayExternal::PrepareDynamicRefreshRate(Layer *layer) {
- if (layer->input_buffer->flags.video) {
+ if (layer->input_buffer.flags.video) {
if (layer->frame_rate != 0) {
metadata_refresh_rate_ = SanitizeRefreshRate(layer->frame_rate);
} else {
diff --git a/sdm/libs/hwc/hwc_display_virtual.cpp b/sdm/libs/hwc/hwc_display_virtual.cpp
index a4d343b..0279fc2 100644
--- a/sdm/libs/hwc/hwc_display_virtual.cpp
+++ b/sdm/libs/hwc/hwc_display_virtual.cpp
@@ -292,6 +292,11 @@
output_buffer_->flags.secure = 0;
output_buffer_->flags.video = 0;
+ const MetaData_t *meta_data = reinterpret_cast<MetaData_t *>(output_handle->base_metadata);
+ if (meta_data && SetCSC(meta_data, &output_buffer_->color_metadata) != kErrorNone) {
+ return kErrorNotSupported;
+ }
+
// TZ Protected Buffer - L1
if (output_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
output_buffer_->flags.secure = 1;
diff --git a/sdm/libs/hwc/hwc_tonemapper.cpp b/sdm/libs/hwc/hwc_tonemapper.cpp
new file mode 100644
index 0000000..694acc0
--- /dev/null
+++ b/sdm/libs/hwc/hwc_tonemapper.cpp
@@ -0,0 +1,290 @@
+/*
+* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include <alloc_controller.h>
+#include <gr.h>
+#include <gralloc_priv.h>
+#include <memalloc.h>
+#include <sync/sync.h>
+
+#include <TonemapFactory.h>
+
+#include <core/buffer_allocator.h>
+
+#include <utils/constants.h>
+#include <utils/debug.h>
+#include <utils/formats.h>
+#include <utils/rect.h>
+
+#include <vector>
+
+#include "hwc_debugger.h"
+#include "hwc_tonemapper.h"
+
+#define __CLASS__ "HWCToneMapper"
+
+namespace sdm {
+
+int HWCToneMapper::Init() {
+ for (uint32_t i = 0; i < kNumIntermediateBuffers; i++) {
+ intermediate_buffer_[i] = NULL;
+ release_fence_fd_[i] = -1;
+ }
+ return 0;
+}
+
+void HWCToneMapper::DeInit() {
+ return;
+}
+
+int HWCToneMapper::HandleToneMap(hwc_display_contents_1_t *content_list, LayerStack *layer_stack) {
+ uint32_t layer_count = UINT32(layer_stack->layers.size());
+ std::vector<uint32_t> tonemap_layer_index = {};
+ Layer *layer = NULL;
+ uint32_t i = 0;
+ uint32_t gpu_count = 0;
+ int fence_fd = -1;
+ int acquire_fd = -1;
+ int merged_fd = -1;
+ hwc_layer_1_t *hwc_layer = NULL;
+ const private_handle_t *dst_hnd = NULL;
+ const private_handle_t *src_hnd = NULL;
+
+ for (; i < layer_count; i++) {
+ layer = layer_stack->layers.at(i);
+ if (layer->request.flags.tone_map) {
+ tonemap_layer_index.push_back(i);
+ break;
+ }
+ if (layer->composition == kCompositionGPU) {
+ gpu_count++;
+ }
+ }
+
+ if (tonemap_layer_index.empty()) {
+ return 0;
+ }
+ // gpu count can be 0 when a layer is on FB and in next cycle it doesn't update and SDM marks
+ // it as SDE comp
+ if (gpu_count == 0) {
+ // TODO(akumarkr): Remove goto when added multiple instance support
+ // intermediate buffer can be null
+ goto update_fd;
+ }
+
+ if (intermediate_buffer_[0] == NULL) {
+ DLOGI("format = %d width = %d height = %d", layer->request.format, layer->request.width,
+ layer->request.height);
+ // TODO(akumarkr): use flags from LayerRequestFlags for format change etc.,
+ uint32_t usage = GRALLOC_USAGE_PRIVATE_IOMMU_HEAP | GRALLOC_USAGE_HW_TEXTURE |
+ GRALLOC_USAGE_PRIVATE_ALLOC_UBWC;
+ AllocateIntermediateBuffers(layer->input_buffer.width, layer->input_buffer.height,
+ HAL_PIXEL_FORMAT_RGBA_8888, usage);
+ }
+ current_intermediate_buffer_index_ =
+ (current_intermediate_buffer_index_ + 1) % kNumIntermediateBuffers;
+
+ if (!gpu_tone_mapper_) {
+ Color10Bit *grid_entries = NULL;
+ int grid_size = 0;
+ if (layer->lut_3d.validGridEntries) {
+ grid_entries = layer->lut_3d.gridEntries;
+ grid_size = INT(layer->lut_3d.gridSize);
+ }
+ gpu_tone_mapper_ = TonemapperFactory_GetInstance(TONEMAP_INVERSE, layer->lut_3d.lutEntries,
+ layer->lut_3d.dim, grid_entries, grid_size);
+ if (gpu_tone_mapper_ == NULL) {
+ DLOGE("Get Tonemapper failed");
+ return -1;
+ }
+ }
+
+ hwc_layer = &content_list->hwLayers[i];
+ dst_hnd = intermediate_buffer_[current_intermediate_buffer_index_];
+ src_hnd = static_cast<const private_handle_t *>(hwc_layer->handle);
+ acquire_fd = dup(layer->input_buffer.acquire_fence_fd);
+ buffer_sync_handler_.SyncMerge(acquire_fd, release_fence_fd_[current_intermediate_buffer_index_],
+ &merged_fd);
+ if (acquire_fd >= 0) {
+ CloseFd(&acquire_fd);
+ }
+
+ if (release_fence_fd_[current_intermediate_buffer_index_] >= 0) {
+ CloseFd(&release_fence_fd_[current_intermediate_buffer_index_]);
+ }
+ DTRACE_BEGIN("GPU_TM_BLIT");
+ fence_fd = gpu_tone_mapper_->blit(reinterpret_cast<const void *>(dst_hnd),
+ reinterpret_cast<const void *>(src_hnd), merged_fd);
+ DTRACE_END();
+
+
+ DumpToneMapOutput(&fence_fd);
+
+update_fd:
+ // Acquire fence will be closed by HWC Display
+ // Fence returned by GPU will be closed in PostCommit
+ layer->input_buffer.acquire_fence_fd = fence_fd;
+ layer->input_buffer.planes[0].fd = intermediate_buffer_[current_intermediate_buffer_index_]->fd;
+
+ active_ = true;
+
+ tonemap_layer_index.clear();
+
+ return 0;
+}
+
+int HWCToneMapper::AllocateIntermediateBuffers(uint32_t width, uint32_t height, uint32_t format,
+ uint32_t usage) {
+ int status = 0;
+ if (width <= 0 || height <= 0) {
+ return false;
+ }
+
+ for (uint32_t i = 0; i < kNumIntermediateBuffers; i++) {
+ status = alloc_buffer(&intermediate_buffer_[i], INT(width), INT(height), INT(format),
+ INT(usage));
+ if (status < 0) {
+ DLOGE("Allocation of Intermediate Buffer failed");
+ FreeIntermediateBuffers();
+ break;
+ }
+ }
+
+ return status;
+}
+void HWCToneMapper::FreeIntermediateBuffers() {
+ if (!intermediate_buffer_[0]) {
+ return;
+ }
+ for (uint32_t i = 0; i < kNumIntermediateBuffers; i++) {
+ private_handle_t *buffer = intermediate_buffer_[i];
+ if (buffer) {
+ // Free the valid fence
+ if (release_fence_fd_[i] >= 0) {
+ CloseFd(&release_fence_fd_[i]);
+ }
+ free_buffer(buffer);
+ intermediate_buffer_[i] = NULL;
+ }
+ }
+}
+
+void HWCToneMapper::PostCommit(LayerStack *layer_stack) {
+ uint32_t layer_count = UINT32(layer_stack->layers.size());
+ std::vector<uint32_t> tonemap_layer_index = {};
+ Layer *layer = NULL;
+ int rel_fence_fd = -1;
+ bool has_tonemap = false;
+ uint32_t i;
+
+ for (i = 0; i < layer_count; i++) {
+ layer = layer_stack->layers.at(i);
+ if (layer->request.flags.tone_map) {
+ tonemap_layer_index.push_back(i);
+ has_tonemap = true;
+ break;
+ }
+ }
+
+ if (has_tonemap) {
+ LayerBuffer &layer_buffer = layer->input_buffer;
+
+ rel_fence_fd = layer_buffer.release_fence_fd;
+ // close the fd returned by GPU Tonemapper
+ CloseFd(&layer_buffer.acquire_fence_fd);
+
+ SetReleaseFence(rel_fence_fd);
+ }
+
+ active_ = false;
+}
+
+void HWCToneMapper::SetReleaseFence(int fd) {
+ CloseFd(&release_fence_fd_[current_intermediate_buffer_index_]);
+ // used to give to GPU tonemapper along with input layer fd
+ release_fence_fd_[current_intermediate_buffer_index_] = dup(fd);
+}
+
+void HWCToneMapper::CloseFd(int *fd) {
+ if (*fd >= 0) {
+ close(*fd);
+ *fd = -1;
+ }
+}
+
+void HWCToneMapper::Terminate() {
+ if (!gpu_tone_mapper_) {
+ return;
+ }
+ // fix this on multiple instance: only delete obj and call ToneMapperDestroy on deInit.
+ delete gpu_tone_mapper_;
+ gpu_tone_mapper_ = NULL;
+
+ TonemapperFactory_Destroy();
+ FreeIntermediateBuffers();
+ active_ = false;
+}
+
+void HWCToneMapper::SetFrameDumpConfig(uint32_t count) {
+ DLOGI("Dump FrameConfig count = %d", count);
+ dump_frame_count_ = count;
+ dump_frame_index_ = 0;
+}
+
+void HWCToneMapper::DumpToneMapOutput(int *acquire_fd) {
+ if (!dump_frame_count_) {
+ return;
+ }
+
+ private_handle_t *target_buffer = intermediate_buffer_[current_intermediate_buffer_index_];
+
+ if (*acquire_fd >= 0) {
+ int error = sync_wait(*acquire_fd, 1000);
+ if (error < 0) {
+ DLOGW("sync_wait error errno = %d, desc = %s", errno, strerror(errno));
+ return;
+ }
+ }
+
+ char dump_file_name[PATH_MAX];
+ size_t result = 0;
+ snprintf(dump_file_name, sizeof(dump_file_name), "/data/misc/display/frame_dump_primary"
+ "/tonemap_%d.raw", (dump_frame_index_));
+ FILE* fp = fopen(dump_file_name, "w+");
+ if (fp) {
+ DLOGI("base addr = %x", target_buffer->base);
+ result = fwrite(reinterpret_cast<void *>(target_buffer->base), target_buffer->size, 1, fp);
+ fclose(fp);
+ }
+ dump_frame_count_--;
+ dump_frame_index_++;
+ CloseFd(acquire_fd);
+}
+
+} // namespace sdm
diff --git a/sdm/libs/hwc/hwc_tonemapper.h b/sdm/libs/hwc/hwc_tonemapper.h
new file mode 100644
index 0000000..7ed5373
--- /dev/null
+++ b/sdm/libs/hwc/hwc_tonemapper.h
@@ -0,0 +1,81 @@
+/*
+* Copyright (c) 2016, The Linux Foundation. All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are
+* met:
+* * Redistributions of source code must retain the above copyright
+* notice, this list of conditions and the following disclaimer.
+* * Redistributions in binary form must reproduce the above
+* copyright notice, this list of conditions and the following
+* disclaimer in the documentation and/or other materials provided
+* with the distribution.
+* * Neither the name of The Linux Foundation nor the names of its
+* contributors may be used to endorse or promote products derived
+* from this software without specific prior written permission.
+*
+* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __HWC_TONEMAPPER_H__
+#define __HWC_TONEMAPPER_H__
+
+#include <fcntl.h>
+#include <sys/mman.h>
+
+#include <hardware/hwcomposer.h>
+
+#include <core/layer_stack.h>
+#include <utils/sys.h>
+
+#include "hwc_buffer_sync_handler.h"
+
+class Tonemapper;
+
+namespace sdm {
+
+class HWCToneMapper {
+ public:
+ HWCToneMapper() {}
+ ~HWCToneMapper() {}
+
+ int Init();
+ void DeInit();
+ int HandleToneMap(hwc_display_contents_1_t *content_list, LayerStack *layer_stack);
+ void Terminate();
+ void PostCommit(LayerStack *layer_stack);
+ bool IsActive() { return active_; }
+ void SetFrameDumpConfig(uint32_t count);
+
+ private:
+ int AllocateIntermediateBuffers(uint32_t width, uint32_t height, uint32_t format, uint32_t usage);
+ void FreeIntermediateBuffers();
+ void SetReleaseFence(int fence_fd);
+ void CloseFd(int *fd);
+ void DumpToneMapOutput(int *acquire_fence);
+
+ static const uint32_t kNumIntermediateBuffers = 2;
+ bool active_ = false;
+
+ private_handle_t *intermediate_buffer_[kNumIntermediateBuffers] = {NULL, NULL};
+ uint32_t current_intermediate_buffer_index_ = 0;
+ int release_fence_fd_[kNumIntermediateBuffers];
+
+ HWCBufferSyncHandler buffer_sync_handler_ = {};
+ Tonemapper *gpu_tone_mapper_ = NULL;
+ uint32_t dump_frame_count_ = 0;
+ uint32_t dump_frame_index_ = 0;
+};
+
+} // namespace sdm
+#endif // __HWC_TONEMAPPER_H__
diff --git a/sdm/libs/hwc2/hwc_display.cpp b/sdm/libs/hwc2/hwc_display.cpp
index 0f2b900..f603f18 100644
--- a/sdm/libs/hwc2/hwc_display.cpp
+++ b/sdm/libs/hwc2/hwc_display.cpp
@@ -49,7 +49,7 @@
static void ApplyDeInterlaceAdjustment(Layer *layer) {
// De-interlacing adjustment
- if (layer->input_buffer->flags.interlace) {
+ if (layer->input_buffer.flags.interlace) {
float height = (layer->src_rect.bottom - layer->src_rect.top) / 2.0f;
layer->src_rect.top = ROUND_UP_ALIGN_DOWN(layer->src_rect.top / 2.0f, 2);
layer->src_rect.bottom = layer->src_rect.top + floorf(height);
@@ -341,14 +341,14 @@
layer->composition = kCompositionGPU;
if (swap_interval_zero_) {
- if (layer->input_buffer->acquire_fence_fd >= 0) {
- close(layer->input_buffer->acquire_fence_fd);
- layer->input_buffer->acquire_fence_fd = -1;
+ if (layer->input_buffer.acquire_fence_fd >= 0) {
+ close(layer->input_buffer.acquire_fence_fd);
+ layer->input_buffer.acquire_fence_fd = -1;
}
}
const private_handle_t *handle =
- reinterpret_cast<const private_handle_t *>(layer->input_buffer->buffer_id);
+ reinterpret_cast<const private_handle_t *>(layer->input_buffer.buffer_id);
if (handle) {
if (handle->bufferType == BUFFER_TYPE_VIDEO) {
layer_stack_.flags.video_present = true;
@@ -363,6 +363,13 @@
}
}
+ if (layer->color_metadata.colorPrimaries == ColorPrimaries_BT2020 &&
+ (layer->color_metadata.transfer == Transfer_SMPTE_ST2084 ||
+ layer->color_metadata.transfer == Transfer_HLG)) {
+ layer->flags.hdr = true;
+ layer_stack_.flags.hdr_present = true;
+ }
+
if (layer->flags.skip) {
layer_stack_.flags.skip_present = true;
}
@@ -383,7 +390,7 @@
ApplyDeInterlaceAdjustment(layer);
// SDM requires these details even for solid fill
if (layer->flags.solid_fill) {
- LayerBuffer *layer_buffer = layer->input_buffer;
+ LayerBuffer *layer_buffer = &layer->input_buffer;
layer_buffer->width = UINT32(layer->dst_rect.right - layer->dst_rect.left);
layer_buffer->height = UINT32(layer->dst_rect.bottom - layer->dst_rect.top);
layer_buffer->unaligned_width = layer_buffer->width;
@@ -906,7 +913,7 @@
// TODO(user): No way to set the client target release fence on SF
int32_t &client_target_release_fence =
- client_target_->GetSDMLayer()->input_buffer->release_fence_fd;
+ client_target_->GetSDMLayer()->input_buffer.release_fence_fd;
if (client_target_release_fence >= 0) {
close(client_target_release_fence);
client_target_release_fence = -1;
@@ -915,7 +922,7 @@
for (auto hwc_layer : layer_set_) {
hwc_layer->ResetGeometryChanges();
Layer *layer = hwc_layer->GetSDMLayer();
- LayerBuffer *layer_buffer = layer->input_buffer;
+ LayerBuffer *layer_buffer = &layer->input_buffer;
if (!flush_) {
// If swapinterval property is set to 0 or for single buffer layers, do not update f/w
@@ -1120,8 +1127,8 @@
for (uint32_t i = 0; i < layer_stack_.layers.size(); i++) {
auto layer = layer_stack_.layers.at(i);
const private_handle_t *pvt_handle =
- reinterpret_cast<const private_handle_t *>(layer->input_buffer->buffer_id);
- auto acquire_fence_fd = layer->input_buffer->acquire_fence_fd;
+ reinterpret_cast<const private_handle_t *>(layer->input_buffer.buffer_id);
+ auto acquire_fence_fd = layer->input_buffer.acquire_fence_fd;
if (acquire_fence_fd >= 0) {
int error = sync_wait(acquire_fence_fd, 1000);
@@ -1325,11 +1332,11 @@
// TODO(user): How does the dirty region get set on the client target? File bug on Google
client_target_layer->composition = kCompositionGPUTarget;
- client_target_layer->input_buffer->format = GetSDMFormat(format, flags);
- client_target_layer->input_buffer->width = UINT32(aligned_width);
- client_target_layer->input_buffer->height = UINT32(aligned_height);
- client_target_layer->input_buffer->unaligned_width = x_pixels;
- client_target_layer->input_buffer->unaligned_height = y_pixels;
+ client_target_layer->input_buffer.format = GetSDMFormat(format, flags);
+ client_target_layer->input_buffer.width = UINT32(aligned_width);
+ client_target_layer->input_buffer.height = UINT32(aligned_height);
+ client_target_layer->input_buffer.unaligned_width = x_pixels;
+ client_target_layer->input_buffer.unaligned_height = y_pixels;
client_target_layer->plane_alpha = 255;
DLOGI("New framebuffer resolution (%dx%d)", fb_config.x_pixels, fb_config.y_pixels);
@@ -1476,12 +1483,11 @@
if (solid_fill_layer_ == NULL) {
// Create a dummy layer here
solid_fill_layer_ = new Layer();
- solid_fill_layer_->input_buffer = new LayerBuffer();
}
uint32_t primary_width = 0, primary_height = 0;
GetMixerResolution(&primary_width, &primary_height);
- LayerBuffer *layer_buffer = solid_fill_layer_->input_buffer;
+ LayerBuffer *layer_buffer = &solid_fill_layer_->input_buffer;
layer_buffer->width = primary_width;
layer_buffer->height = primary_height;
layer_buffer->unaligned_width = primary_width;
@@ -1506,9 +1512,6 @@
solid_fill_layer_->flags.solid_fill = true;
} else {
// delete the dummy layer
- if (solid_fill_layer_) {
- delete solid_fill_layer_->input_buffer;
- }
delete solid_fill_layer_;
solid_fill_layer_ = NULL;
}
@@ -1523,7 +1526,7 @@
void HWCDisplay::SolidFillCommit() {
if (solid_fill_enable_ && solid_fill_layer_) {
- LayerBuffer *layer_buffer = solid_fill_layer_->input_buffer;
+ LayerBuffer *layer_buffer = &solid_fill_layer_->input_buffer;
if (layer_buffer->release_fence_fd > 0) {
close(layer_buffer->release_fence_fd);
layer_buffer->release_fence_fd = -1;
@@ -1627,13 +1630,13 @@
void HWCDisplay::CloseAcquireFds() {
for (auto hwc_layer : layer_set_) {
auto layer = hwc_layer->GetSDMLayer();
- if (layer->input_buffer->acquire_fence_fd >= 0) {
- close(layer->input_buffer->acquire_fence_fd);
- layer->input_buffer->acquire_fence_fd = -1;
+ if (layer->input_buffer.acquire_fence_fd >= 0) {
+ close(layer->input_buffer.acquire_fence_fd);
+ layer->input_buffer.acquire_fence_fd = -1;
}
}
int32_t &client_target_acquire_fence =
- client_target_->GetSDMLayer()->input_buffer->acquire_fence_fd;
+ client_target_->GetSDMLayer()->input_buffer.acquire_fence_fd;
if (client_target_acquire_fence >= 0) {
close(client_target_acquire_fence);
client_target_acquire_fence = -1;
@@ -1655,10 +1658,10 @@
os << "\tdevice(SDM) composition: " <<
to_string(layer->GetDeviceSelectedCompositionType()).c_str() << std::endl;
os << "\tplane_alpha: " << std::to_string(sdm_layer->plane_alpha).c_str() << std::endl;
- os << "\tformat: " << GetFormatString(sdm_layer->input_buffer->format) << std::endl;
+ os << "\tformat: " << GetFormatString(sdm_layer->input_buffer.format) << std::endl;
os << "\ttransform: rot: " << transform.rotation << " flip_h: " << transform.flip_horizontal <<
" flip_v: "<< transform.flip_vertical << std::endl;
- os << "\tbuffer_id: " << std::hex << "0x" << sdm_layer->input_buffer->buffer_id << std::dec
+ os << "\tbuffer_id: " << std::hex << "0x" << sdm_layer->input_buffer.buffer_id << std::dec
<< std::endl;
}
return os.str();
diff --git a/sdm/libs/hwc2/hwc_display_virtual.cpp b/sdm/libs/hwc2/hwc_display_virtual.cpp
index 5436faa..1197c7b 100644
--- a/sdm/libs/hwc2/hwc_display_virtual.cpp
+++ b/sdm/libs/hwc2/hwc_display_virtual.cpp
@@ -204,6 +204,11 @@
output_buffer_->flags.secure = 0;
output_buffer_->flags.video = 0;
+ const MetaData_t *meta_data = reinterpret_cast<MetaData_t *>(output_handle->base_metadata);
+ if (meta_data && SetCSC(meta_data, &output_buffer_->color_metadata) != kErrorNone) {
+ return HWC2::Error::BadParameter;
+ }
+
// TZ Protected Buffer - L1
if (output_handle->flags & private_handle_t::PRIV_FLAGS_SECURE_BUFFER) {
output_buffer_->flags.secure = 1;
diff --git a/sdm/libs/hwc2/hwc_layers.cpp b/sdm/libs/hwc2/hwc_layers.cpp
index f4ae584..2ed21df 100644
--- a/sdm/libs/hwc2/hwc_layers.cpp
+++ b/sdm/libs/hwc2/hwc_layers.cpp
@@ -28,10 +28,44 @@
std::atomic<hwc2_layer_t> HWCLayer::next_id_(1);
+DisplayError SetCSC(const MetaData_t *meta_data, ColorMetaData *color_metadata) {
+ if (meta_data->operation & COLOR_METADATA) {
+#ifdef USE_COLOR_METADATA
+ *color_metadata = meta_data->color;
+#endif
+ } else if (meta_data->operation & UPDATE_COLOR_SPACE) {
+ ColorSpace_t csc = meta_data->colorSpace;
+ color_metadata->range = Range_Limited;
+
+ if (csc == ITU_R_601_FR || csc == ITU_R_2020_FR) {
+ color_metadata->range = Range_Full;
+ }
+
+ switch (csc) {
+ case ITU_R_601:
+ case ITU_R_601_FR:
+ // video and display driver uses 601_525
+ color_metadata->colorPrimaries = ColorPrimaries_BT601_6_525;
+ break;
+ case ITU_R_709:
+ color_metadata->colorPrimaries = ColorPrimaries_BT709_5;
+ break;
+ case ITU_R_2020:
+ case ITU_R_2020_FR:
+ color_metadata->colorPrimaries = ColorPrimaries_BT2020;
+ break;
+ default:
+ DLOGE("Unsupported CSC: %d", csc);
+ return kErrorNotSupported;
+ }
+ }
+
+ return kErrorNone;
+}
+
// Layer operations
HWCLayer::HWCLayer(hwc2_display_t display_id) : id_(next_id_++), display_id_(display_id) {
layer_ = new Layer();
- layer_->input_buffer = new LayerBuffer();
// Fences are deferred, so the first time this layer is presented, return -1
// TODO(user): Verify that fences are properly obtained on suspend/resume
release_fences_.push(-1);
@@ -45,9 +79,6 @@
}
close(ion_fd_);
if (layer_) {
- if (layer_->input_buffer) {
- delete (layer_->input_buffer);
- }
delete layer_;
}
}
@@ -74,7 +105,7 @@
ion_fd_ = dup(handle->fd);
}
- LayerBuffer *layer_buffer = layer_->input_buffer;
+ LayerBuffer *layer_buffer = &layer_->input_buffer;
int aligned_width, aligned_height;
int unaligned_width, unaligned_height;
@@ -151,7 +182,7 @@
HWC2::Error HWCLayer::SetLayerColor(hwc_color_t color) {
layer_->solid_fill_color = GetUint32Color(color);
- layer_->input_buffer->format = kFormatARGB8888;
+ layer_->input_buffer.format = kFormatARGB8888;
DLOGV_IF(kTagCompManager, "[%" PRIu64 "][%" PRIu64 "] Layer color set to %x", display_id_, id_,
layer_->solid_fill_color);
return HWC2::Error::None;
@@ -440,16 +471,14 @@
DisplayError HWCLayer::SetMetaData(const private_handle_t *pvt_handle, Layer *layer) {
const MetaData_t *meta_data = reinterpret_cast<MetaData_t *>(pvt_handle->base_metadata);
- LayerBuffer *layer_buffer = layer->input_buffer;
+ LayerBuffer *layer_buffer = &layer->input_buffer;
if (!meta_data) {
return kErrorNone;
}
- if (meta_data->operation & UPDATE_COLOR_SPACE) {
- if (SetCSC(meta_data->colorSpace, &layer_buffer->csc) != kErrorNone) {
- return kErrorNotSupported;
- }
+ if (sdm::SetCSC(meta_data, &layer_buffer->color_metadata) != kErrorNone) {
+ return kErrorNotSupported;
}
if (meta_data->operation & SET_IGC) {
@@ -477,25 +506,6 @@
return kErrorNone;
}
-DisplayError HWCLayer::SetCSC(ColorSpace_t source, LayerCSC *target) {
- switch (source) {
- case ITU_R_601:
- *target = kCSCLimitedRange601;
- break;
- case ITU_R_601_FR:
- *target = kCSCFullRange601;
- break;
- case ITU_R_709:
- *target = kCSCLimitedRange709;
- break;
- default:
- DLOGE("Unsupported CSC: %d", source);
- return kErrorNotSupported;
- }
-
- return kErrorNone;
-}
-
DisplayError HWCLayer::SetIGC(IGC_t source, LayerIGC *target) {
switch (source) {
case IGC_NotSpecified:
diff --git a/sdm/libs/hwc2/hwc_layers.h b/sdm/libs/hwc2/hwc_layers.h
index ed93a5a..6a80b1b 100644
--- a/sdm/libs/hwc2/hwc_layers.h
+++ b/sdm/libs/hwc2/hwc_layers.h
@@ -37,6 +37,8 @@
namespace sdm {
+DisplayError SetCSC(const MetaData_t *meta_data, ColorMetaData *color_metadata);
+
enum GeometryChanges {
kNone = 0x000,
kBlendMode = 0x001,
@@ -100,7 +102,7 @@
LayerBufferFormat GetSDMFormat(const int32_t &source, const int flags);
LayerBufferS3DFormat GetS3DFormat(uint32_t s3d_format);
DisplayError SetMetaData(const private_handle_t *pvt_handle, Layer *layer);
- DisplayError SetCSC(ColorSpace_t source, LayerCSC *target);
+ DisplayError SetCSC(const MetaData_t *meta_data, ColorMetaData *color_metadata);
DisplayError SetIGC(IGC_t source, LayerIGC *target);
uint32_t RoundToStandardFPS(float fps);
};
diff --git a/sdm/libs/utils/formats.cpp b/sdm/libs/utils/formats.cpp
index 546c0c7..8e9d0b8 100644
--- a/sdm/libs/utils/formats.cpp
+++ b/sdm/libs/utils/formats.cpp
@@ -114,5 +114,14 @@
}
}
+BufferLayout GetBufferLayout(LayerBufferFormat format) {
+ switch (format) {
+ case kFormatYCbCr420TP10Ubwc:
+ return kTPTiled;
+ default:
+ return (IsUBWCFormat(format) ? kUBWC : kLinear);
+ }
+}
+
} // namespace sdm