diff options
author | Arun Kumar K.R <akumarkr@codeaurora.org> | 2016-11-11 14:37:20 -0800 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2016-12-16 11:26:15 -0800 |
commit | 2b75da399a3cf0c1299e62bf5a6738a052928529 (patch) | |
tree | 9736b352a188bce646381a443f51bd5cee34171e | |
parent | 9c19cdd969786ebccbc3fb7b93d7d1c9b6fbc506 (diff) | |
download | android_hardware_qcom_sdm710_display-2b75da399a3cf0c1299e62bf5a6738a052928529.tar.gz android_hardware_qcom_sdm710_display-2b75da399a3cf0c1299e62bf5a6738a052928529.tar.bz2 android_hardware_qcom_sdm710_display-2b75da399a3cf0c1299e62bf5a6738a052928529.zip |
gpu_tonemapper: Include gpu tonemapper
GPU tonemapper library which is used by HWC to tone
map the layers from one Gamut to another based on the
3D LUT.
Change-Id: Iccaa38e40989e832fd3891a24eca494aba696d9a
Crs-fixed: 1094964
-rw-r--r-- | Android.mk | 2 | ||||
-rw-r--r-- | common.mk | 1 | ||||
-rw-r--r-- | gpu_tonemapper/Android.mk | 23 | ||||
-rw-r--r-- | gpu_tonemapper/EGLImageBuffer.cpp | 155 | ||||
-rw-r--r-- | gpu_tonemapper/EGLImageBuffer.h | 50 | ||||
-rw-r--r-- | gpu_tonemapper/EGLImageWrapper.cpp | 68 | ||||
-rw-r--r-- | gpu_tonemapper/EGLImageWrapper.h | 34 | ||||
-rw-r--r-- | gpu_tonemapper/TonemapFactory.cpp | 48 | ||||
-rw-r--r-- | gpu_tonemapper/TonemapFactory.h | 40 | ||||
-rw-r--r-- | gpu_tonemapper/Tonemapper.cpp | 118 | ||||
-rw-r--r-- | gpu_tonemapper/Tonemapper.h | 40 | ||||
-rw-r--r-- | gpu_tonemapper/engine.h | 42 | ||||
-rw-r--r-- | gpu_tonemapper/forward_tonemap.inl | 42 | ||||
-rw-r--r-- | gpu_tonemapper/fullscreen_vertex_shader.inl | 37 | ||||
-rw-r--r-- | gpu_tonemapper/glengine.cpp | 398 | ||||
-rw-r--r-- | gpu_tonemapper/glengine.h | 45 | ||||
-rw-r--r-- | gpu_tonemapper/rgba_inverse_tonemap.inl | 50 |
17 files changed, 1192 insertions, 1 deletions
@@ -3,7 +3,7 @@ display-hals := include libqservice libqdutils $(sdm-libs)/utils $(sdm-libs)/cor 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) @@ -17,6 +17,7 @@ endif 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 00000000..9ae3840a --- /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 00000000..e64e16fd --- /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 00000000..23af5732 --- /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 00000000..eb0a2ca5 --- /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 00000000..d7fc84ba --- /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 00000000..81e9f7fc --- /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 00000000..10041705 --- /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 00000000..957c1335 --- /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 00000000..9c41670d --- /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 00000000..5635ee39 --- /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 00000000..a008949e --- /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 00000000..9a70c2b3 --- /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 00000000..e5c8e68a --- /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 00000000..c5b166cc --- /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 00000000..399e2f8b --- /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"; |