1ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy/*
2ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy * Copyright (C) 2010 The Android Open Source Project
3ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy *
4ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy * Licensed under the Apache License, Version 2.0 (the "License");
5ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy * you may not use this file except in compliance with the License.
6ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy * You may obtain a copy of the License at
7ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy *
8ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy *      http://www.apache.org/licenses/LICENSE-2.0
9ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy *
10ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy * Unless required by applicable law or agreed to in writing, software
11ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy * distributed under the License is distributed on an "AS IS" BASIS,
12ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy * See the License for the specific language governing permissions and
14ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy * limitations under the License.
15ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy */
16ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy
17ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy#include <utils/String8.h>
18ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy
19a60c3889718f4513a6c9d8b80f655db5d6346905Romain Guy#include "Caches.h"
20ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy#include "ProgramCache.h"
21253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy#include "Properties.h"
22ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy
23ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guynamespace android {
24ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guynamespace uirenderer {
25ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy
26ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy///////////////////////////////////////////////////////////////////////////////
27707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy// Defines
28707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy///////////////////////////////////////////////////////////////////////////////
29707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy
30707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy#define MODULATE_OP_NO_MODULATE 0
31707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy#define MODULATE_OP_MODULATE 1
32707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy#define MODULATE_OP_MODULATE_A8 2
33707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy
34b48800428906ae455c2b63acacd44e390e1fee49Romain Guy#define STR(x) STR1(x)
35b48800428906ae455c2b63acacd44e390e1fee49Romain Guy#define STR1(x) #x
36b48800428906ae455c2b63acacd44e390e1fee49Romain Guy
37707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy///////////////////////////////////////////////////////////////////////////////
38ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy// Vertex shaders snippets
39ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy///////////////////////////////////////////////////////////////////////////////
40ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy
418bd68c6b7d4d6d3137edf1cbdc0e0de266c5b9eeChris Craikconst char* gVS_Header_Start =
428bd68c6b7d4d6d3137edf1cbdc0e0de266c5b9eeChris Craik        "#version 100\n"
43ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy        "attribute vec4 position;\n";
44ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guyconst char* gVS_Header_Attributes_TexCoords =
45ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy        "attribute vec2 texCoords;\n";
46ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guyconst char* gVS_Header_Attributes_Colors =
47ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy        "attribute vec4 colors;\n";
4891a8c7c62913c2597e3bf5a6d59d2ed5fc7ba4e0Chris Craikconst char* gVS_Header_Attributes_VertexAlphaParameters =
496ebdc114e0d72137394f02bc8ffe9d7a782a65c4Chris Craik        "attribute float vtxAlpha;\n";
50aa6c24c21c727a196451332448d4e3b11a80be69Romain Guyconst char* gVS_Header_Uniforms_TextureTransform =
51aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy        "uniform mat4 mainTextureTransform;\n";
52ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guyconst char* gVS_Header_Uniforms =
5339284b763a09688468ed3799ebd2ebb76ea5dfd5Romain Guy        "uniform mat4 projection;\n" \
54ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy        "uniform mat4 transform;\n";
55b48800428906ae455c2b63acacd44e390e1fee49Romain Guyconst char* gVS_Header_Uniforms_HasGradient =
56b48800428906ae455c2b63acacd44e390e1fee49Romain Guy        "uniform mat4 screenSpace;\n";
57889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guyconst char* gVS_Header_Uniforms_HasBitmap =
58889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guy        "uniform mat4 textureTransform;\n"
5980bbfb19eefe3cb9be8833b136381cece069e24dRomain Guy        "uniform mediump vec2 textureDimension;\n";
60deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craikconst char* gVS_Header_Uniforms_HasRoundRectClip =
61deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        "uniform mat4 roundRectInvTransform;\n";
62ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guyconst char* gVS_Header_Varyings_HasTexture =
63ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy        "varying vec2 outTexCoords;\n";
64ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guyconst char* gVS_Header_Varyings_HasColors =
65ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy        "varying vec4 outColors;\n";
6691a8c7c62913c2597e3bf5a6d59d2ed5fc7ba4e0Chris Craikconst char* gVS_Header_Varyings_HasVertexAlpha =
676ebdc114e0d72137394f02bc8ffe9d7a782a65c4Chris Craik        "varying float alpha;\n";
6863553478130f78d44c8fbeaebc610e19925544a5Romain Guyconst char* gVS_Header_Varyings_HasBitmap =
6963553478130f78d44c8fbeaebc610e19925544a5Romain Guy        "varying highp vec2 outBitmapTexCoords;\n";
7042e1e0d482d774cf18a55773e434f02edb9e4462Romain Guyconst char* gVS_Header_Varyings_HasGradient[6] = {
71ee916f14cbd1fe1422c063ce2ef7b185e2bc5c6fRomain Guy        // Linear
72253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy        "varying highp vec2 linear;\n",
73253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy        "varying float linear;\n",
74211efea7376371ee755edd2ad03e83ef6eea464eRomain Guy
75ee916f14cbd1fe1422c063ce2ef7b185e2bc5c6fRomain Guy        // Circular
76253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy        "varying highp vec2 circular;\n",
77253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy        "varying highp vec2 circular;\n",
78211efea7376371ee755edd2ad03e83ef6eea464eRomain Guy
79ee916f14cbd1fe1422c063ce2ef7b185e2bc5c6fRomain Guy        // Sweep
80253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy        "varying highp vec2 sweep;\n",
81253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy        "varying highp vec2 sweep;\n",
82ee916f14cbd1fe1422c063ce2ef7b185e2bc5c6fRomain Guy};
83deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craikconst char* gVS_Header_Varyings_HasRoundRectClip =
8468a73e8700c3bb30395e4ebf1b6e5a9b81699a5aChris Craik        "varying highp vec2 roundRectPos;\n";
85ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guyconst char* gVS_Main =
86ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy        "\nvoid main(void) {\n";
87ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guyconst char* gVS_Main_OutTexCoords =
88ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy        "    outTexCoords = texCoords;\n";
89ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guyconst char* gVS_Main_OutColors =
90ff316ec7a76e52572a2e89b691e6b3bba0cafba3Romain Guy        "    outColors = colors;\n";
91aa6c24c21c727a196451332448d4e3b11a80be69Romain Guyconst char* gVS_Main_OutTransformedTexCoords =
92aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy        "    outTexCoords = (mainTextureTransform * vec4(texCoords, 0.0, 1.0)).xy;\n";
9342e1e0d482d774cf18a55773e434f02edb9e4462Romain Guyconst char* gVS_Main_OutGradient[6] = {
94ee916f14cbd1fe1422c063ce2ef7b185e2bc5c6fRomain Guy        // Linear
95253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy        "    linear = vec2((screenSpace * position).x, 0.5);\n",
96253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy        "    linear = (screenSpace * position).x;\n",
97211efea7376371ee755edd2ad03e83ef6eea464eRomain Guy
98ee916f14cbd1fe1422c063ce2ef7b185e2bc5c6fRomain Guy        // Circular
99253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy        "    circular = (screenSpace * position).xy;\n",
100253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy        "    circular = (screenSpace * position).xy;\n",
101211efea7376371ee755edd2ad03e83ef6eea464eRomain Guy
102ee916f14cbd1fe1422c063ce2ef7b185e2bc5c6fRomain Guy        // Sweep
103253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy        "    sweep = (screenSpace * position).xy;\n",
104a1d12dd619c86c9ac121a3095ff5e5633c11e876Chet Haase        "    sweep = (screenSpace * position).xy;\n"
105ee916f14cbd1fe1422c063ce2ef7b185e2bc5c6fRomain Guy};
106889f8d1403761d5668115ced6cbb3f767cfe966dRomain Guyconst char* gVS_Main_OutBitmapTexCoords =
107707b2f78ccaa09965d7e030fda3a883ce9b75ea8Romain Guy        "    outBitmapTexCoords = (textureTransform * position).xy * textureDimension;\n";
108ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guyconst char* gVS_Main_Position =
109deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        "    vec4 transformedPosition = projection * transform * position;\n"
110deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        "    gl_Position = transformedPosition;\n";
111bf75945e7a1ae7c1000682716643c942c1e19ba6Chris Craik
11291a8c7c62913c2597e3bf5a6d59d2ed5fc7ba4e0Chris Craikconst char* gVS_Main_VertexAlpha =
1136ebdc114e0d72137394f02bc8ffe9d7a782a65c4Chris Craik        "    alpha = vtxAlpha;\n";
114bf75945e7a1ae7c1000682716643c942c1e19ba6Chris Craik
115deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craikconst char* gVS_Main_HasRoundRectClip =
116deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        "    roundRectPos = (roundRectInvTransform * transformedPosition).xy;\n";
117ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guyconst char* gVS_Footer =
118ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy        "}\n\n";
119ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy
120ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy///////////////////////////////////////////////////////////////////////////////
121ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy// Fragment shaders snippets
122ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy///////////////////////////////////////////////////////////////////////////////
123ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy
1248bd68c6b7d4d6d3137edf1cbdc0e0de266c5b9eeChris Craikconst char* gFS_Header_Start =
1258bd68c6b7d4d6d3137edf1cbdc0e0de266c5b9eeChris Craik        "#version 100\n";
126a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guyconst char* gFS_Header_Extension_FramebufferFetch =
127a5aed0d58962a24c44728ffc46dc9e1ba2f9fda5Romain Guy        "#extension GL_NV_shader_framebuffer_fetch : enable\n\n";
128aa6c24c21c727a196451332448d4e3b11a80be69Romain Guyconst char* gFS_Header_Extension_ExternalTexture =
129aa6c24c21c727a196451332448d4e3b11a80be69Romain Guy        "#extension GL_OES_EGL_image_external : require\n\n";
130ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guyconst char* gFS_Header =
131ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy        "precision mediump float;\n\n";
132ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guyconst char* gFS_Uniforms_Color =
133ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy        "uniform vec4 color;\n";
134ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guyconst char* gFS_Uniforms_TextureSampler =
135a938f569ce206c1ed68d736181016b5b708c0084Romain Guy        "uniform sampler2D baseSampler;\n";
136aa6c24c21c727a196451332448d4e3b11a80be69Romain Guyconst char* gFS_Uniforms_ExternalTextureSampler =
137a938f569ce206c1ed68d736181016b5b708c0084Romain Guy        "uniform samplerExternalOES baseSampler;\n";
138b48800428906ae455c2b63acacd44e390e1fee49Romain Guyconst char* gFS_Uniforms_GradientSampler[2] = {
139253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy        "uniform vec2 screenSize;\n"
140b48800428906ae455c2b63acacd44e390e1fee49Romain Guy        "uniform sampler2D gradientSampler;\n",
141253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy
142253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy        "uniform vec2 screenSize;\n"
143b48800428906ae455c2b63acacd44e390e1fee49Romain Guy        "uniform vec4 startColor;\n"
144211efea7376371ee755edd2ad03e83ef6eea464eRomain Guy        "uniform vec4 endColor;\n"
145ee916f14cbd1fe1422c063ce2ef7b185e2bc5c6fRomain Guy};
146ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guyconst char* gFS_Uniforms_BitmapSampler =
147ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy        "uniform sampler2D bitmapSampler;\n";
1489c97e48fbe389180b4b64845f093c53c92c374f3sergeyvconst char* gFS_Uniforms_BitmapExternalSampler =
1499c97e48fbe389180b4b64845f093c53c92c374f3sergeyv        "uniform samplerExternalOES bitmapSampler;\n";
15076d3a1b8d035d27bc80b0f2fc480a903bd001514Derek Sollenbergerconst char* gFS_Uniforms_ColorOp[3] = {
151ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy        // None
152ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy        "",
153ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy        // Matrix
154ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy        "uniform mat4 colorMatrix;\n"
155ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy        "uniform vec4 colorMatrixVector;\n",
156ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy        // PorterDuff
157db1938e0e6ef816e228c815adccebd5cb05f2aa8Romain Guy        "uniform vec4 colorBlend;\n"
158ac670c0433d19397d4e36ced2110475b6f54fe26Romain Guy};
1594121063313ac0d6f69f6253cac821d0c1c122086Romain Guy
160deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craikconst char* gFS_Uniforms_HasRoundRectClip =
161deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        "uniform vec4 roundRectInnerRectLTRB;\n"
162deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik        "uniform float roundRectRadius;\n";
163deeda3d337aed1eee218b89a7aba5992ced371f0Chris Craik
164caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guyconst char* gFS_Uniforms_ColorSpaceConversion =
165caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        // TODO: Should we use a 3D LUT to combine the matrix and transfer functions?
166caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        // 32x32x32 fp16 LUTs (for scRGB output) are large and heavy to generate...
167caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        "uniform mat3 colorSpaceMatrix;\n";
168caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy
169caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guyconst char* gFS_Uniforms_TransferFunction[4] = {
170caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        // In this order: g, a, b, c, d, e, f
171caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        // See ColorSpace::TransferParameters
172caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        // We'll use hardware sRGB conversion as much as possible
173caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        "",
174caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        "uniform float transferFunction[7];\n",
175caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        "uniform float transferFunction[5];\n",
176caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        "uniform float transferFunctionGamma;\n"
177caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy};
178caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy
179636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guyconst char* gFS_OETF[2] = {
180caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        R"__SHADER__(
181caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        vec4 OETF(const vec4 linear) {
182caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy            return linear;
183caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        }
184caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        )__SHADER__",
185caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        // We expect linear data to be scRGB so we mirror the gamma function
186caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        R"__SHADER__(
187caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        vec4 OETF(const vec4 linear) {
188caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy            return vec4(sign(linear.rgb) * OETF_sRGB(abs(linear.rgb)), linear.a);
189caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        }
190caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        )__SHADER__"
191caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy};
192caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy
193caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guyconst char* gFS_ColorConvert[3] = {
194caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        // Just OETF
195caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        R"__SHADER__(
196caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        vec4 colorConvert(const vec4 color) {
197caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy            return OETF(color);
198caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        }
199caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        )__SHADER__",
200caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        // Full color conversion for opaque bitmaps
201caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        R"__SHADER__(
202caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        vec4 colorConvert(const vec4 color) {
203caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy            return OETF(vec4(colorSpaceMatrix * EOTF_Parametric(color.rgb), color.a));
204caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        }
205caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        )__SHADER__",
206caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        // Full color conversion for translucent bitmaps
207caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        // Note: 0.5/256=0.0019
208caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        R"__SHADER__(
209caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        vec4 colorConvert(in vec4 color) {
210caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy            color.rgb /= color.a + 0.0019;
211caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy            color = OETF(vec4(colorSpaceMatrix * EOTF_Parametric(color.rgb), color.a));
212caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy            color.rgb *= color.a + 0.0019;
213caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy            return color;
214caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        }
215caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        )__SHADER__",
216636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy};
217636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy
218caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guyconst char* gFS_sRGB_TransferFunctions = R"__SHADER__(
219636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy        float OETF_sRGB(const float linear) {
220636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy            // IEC 61966-2-1:1999
221636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy            return linear <= 0.0031308 ? linear * 12.92 : (pow(linear, 1.0 / 2.4) * 1.055) - 0.055;
222636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy        }
223636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy
224636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy        vec3 OETF_sRGB(const vec3 linear) {
225636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy            return vec3(OETF_sRGB(linear.r), OETF_sRGB(linear.g), OETF_sRGB(linear.b));
226636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy        }
227636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy
228636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy        float EOTF_sRGB(float srgb) {
229636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy            // IEC 61966-2-1:1999
230636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy            return srgb <= 0.04045 ? srgb / 12.92 : pow((srgb + 0.055) / 1.055, 2.4);
231636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy        }
232636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy)__SHADER__";
233636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy
234caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guyconst char* gFS_TransferFunction[4] = {
235caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        // Conversion done by the texture unit (sRGB)
236caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        R"__SHADER__(
237caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        vec3 EOTF_Parametric(const vec3 x) {
238caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy            return x;
239caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        }
240caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        )__SHADER__",
241caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        // Full transfer function
242caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        // TODO: We should probably use a 1D LUT (256x1 with texelFetch() since input is 8 bit)
243caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        // TODO: That would cause 3 dependent texture fetches. Is it worth it?
244caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        R"__SHADER__(
245caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        float EOTF_Parametric(float x) {
246caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy            return x <= transferFunction[4]
247caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy                  ? transferFunction[3] * x + transferFunction[6]
248caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy                  : pow(transferFunction[1] * x + transferFunction[2], transferFunction[0])
249caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy                          + transferFunction[5];
250caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        }
251caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy
252caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        vec3 EOTF_Parametric(const vec3 x) {
253caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy            return vec3(EOTF_Parametric(x.r), EOTF_Parametric(x.g), EOTF_Parametric(x.b));
254caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        }
255caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        )__SHADER__",
256caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        // Limited transfer function, e = f = 0.0
257caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        R"__SHADER__(
258caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        float EOTF_Parametric(float x) {
259caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy            return x <= transferFunction[4]
260caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy                  ? transferFunction[3] * x
261caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy                  : pow(transferFunction[1] * x + transferFunction[2], transferFunction[0]);
262caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        }
263caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy
264caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        vec3 EOTF_Parametric(const vec3 x) {
265caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy            return vec3(EOTF_Parametric(x.r), EOTF_Parametric(x.g), EOTF_Parametric(x.b));
266caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        }
267caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        )__SHADER__",
268caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        // Gamma transfer function, e = f = 0.0
269caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        R"__SHADER__(
270caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        vec3 EOTF_Parametric(const vec3 x) {
271caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy            return vec3(pow(x.r, transferFunctionGamma),
272caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy                        pow(x.g, transferFunctionGamma),
273caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy                        pow(x.b, transferFunctionGamma));
274caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        }
275caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy        )__SHADER__"
276caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy};
277caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy
278253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy// Dithering must be done in the quantization space
279253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy// When we are writing to an sRGB framebuffer, we must do the following:
280636afc1877882dc9cf73b49f8a68c73cc418d8cdRomain Guy//     EOTF(OETF(color) + dither)
2810d86d7ebc2b83f0bdd28bb99e57289215947f2e0Romain Guy// The dithering pattern is generated with a triangle noise generator in the range [-1.0,1.0]
282253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy// TODO: Handle linear fp16 render targets
283caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guyconst char* gFS_GradientFunctions = R"__SHADER__(
2849fe7e16399aa9739b63ce9add1d04fd8ef00678fRomain Guy        float triangleNoise(const highp vec2 n) {
2859fe7e16399aa9739b63ce9add1d04fd8ef00678fRomain Guy            highp vec2 p = fract(n * vec2(5.3987, 5.4421));
2869fe7e16399aa9739b63ce9add1d04fd8ef00678fRomain Guy            p += dot(p.yx, p.xy + vec2(21.5351, 14.3137));
2879fe7e16399aa9739b63ce9add1d04fd8ef00678fRomain Guy            highp float xy = p.x * p.y;
2889fe7e16399aa9739b63ce9add1d04fd8ef00678fRomain Guy            return fract(xy * 95.4307) + fract(xy * 75.04961) - 1.0;
2899fe7e16399aa9739b63ce9add1d04fd8ef00678fRomain Guy        }
2909fe7e16399aa9739b63ce9add1d04fd8ef00678fRomain Guy)__SHADER__";
291caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guy
292caaaa66e57293e4a6f312649bf472eab84d5c7feRomain Guyconst char* gFS_GradientPreamble[2] = {
293253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy        // Linear framebuffer
2946183c97e5f317ad52ad16fe50e40129e2c7b2150Romain Guy        R"__SHADER__(
2956183c97e5f317ad52ad16fe50e40129e2c7b2150Romain Guy        vec4 dither(const vec4 color) {
2966183c97e5f317ad52ad16fe50e40129e2c7b2150Romain Guy            return color + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);
2976183c97e5f317ad52ad16fe50e40129e2c7b2150Romain Guy        }
2986183c97e5f317ad52ad16fe50e40129e2c7b2150Romain Guy        )__SHADER__",
299253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy        // sRGB framebuffer
3006183c97e5f317ad52ad16fe50e40129e2c7b2150Romain Guy        R"__SHADER__(
3016183c97e5f317ad52ad16fe50e40129e2c7b2150Romain Guy        vec4 dither(const vec4 color) {
3026183c97e5f317ad52ad16fe50e40129e2c7b2150Romain Guy            vec3 dithered = sqrt(color.rgb) + (triangleNoise(gl_FragCoord.xy * screenSize.xy) / 255.0);
3036183c97e5f317ad52ad16fe50e40129e2c7b2150Romain Guy            return vec4(dithered * dithered, color.a);
3046183c97e5f317ad52ad16fe50e40129e2c7b2150Romain Guy        }
3056183c97e5f317ad52ad16fe50e40129e2c7b2150Romain Guy        )__SHADER__",
306253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy};
307253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy
308253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy// Uses luminance coefficients from Rec.709 to choose the appropriate gamma
309253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy// The gamma() function assumes that bright text will be displayed on a dark
310253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy// background and that dark text will be displayed on bright background
311253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy// The gamma coefficient is chosen to thicken or thin the text accordingly
312253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy// The dot product used to compute the luminance could be approximated with
313253f2c213f6ecda63b6872aee77bd30d5ec07c82Romain Guy// a simple max(color.r, color.g, color.b)
3149fe7e16399aa9739b63ce9add1d04fd8ef00678fRomain Guyconst char* gFS_Gamma_Preamble = R"__SHADER__(
3159fe7e16399aa9739b63ce9add1d04fd8ef00678fRomain Guy        #define GAMMA (%.2f)
3169fe7e16399aa9739b63ce9add1d04fd8ef00678fRomain Guy        #define GAMMA_INV (%.2f)
317