Merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/no-dFdy-trunk into lp:ubuntu-ui-toolkit

Proposed by Tim Peeters
Status: Merged
Approved by: Florian Boucault
Approved revision: 1218
Merged at revision: 1217
Proposed branch: lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/no-dFdy-trunk
Merge into: lp:ubuntu-ui-toolkit
Diff against target: 316 lines (+258/-3)
6 files modified
src/Ubuntu/Components/plugin/plugin.pri (+3/-1)
src/Ubuntu/Components/plugin/plugin.qrc (+2/-0)
src/Ubuntu/Components/plugin/shaders/shape_no_dfdy.frag (+112/-0)
src/Ubuntu/Components/plugin/shaders/shapeoverlay_no_dfdy.frag (+121/-0)
src/Ubuntu/Components/plugin/ucubuntushape.cpp (+10/-1)
src/Ubuntu/Components/plugin/ucubuntushapeoverlay.cpp (+10/-1)
To merge this branch: bzr merge lp:~ubuntu-sdk-team/ubuntu-ui-toolkit/no-dFdy-trunk
Reviewer Review Type Date Requested Status
PS Jenkins bot continuous-integration Approve
Tim Peeters Abstain
Review via email: mp+268405@code.launchpad.net

Commit message

Do not use the GL_OES_standard_derivatives extension in the emulator (and other possible unsupported platforms).

Description of the change

Do not use the GL_OES_standard_derivatives extension in the emulator (and other possible unsupported platforms).

This will make the rendering less pretty on systems that do not support the extension.

To post a comment you must log in.
Revision history for this message
Tim Peeters (tpeeters) wrote :

I discovered a problem with this MR, see this screenshot: https://www.dropbox.com/s/uy6sro2spmyiq53/Screenshot%202015-08-19%2000.32.46.png?dl=0

On the left you see the rendering without the extension (you would see that in the emulator), and on the right, the rendering with extension. The fix that we have for rendering without the extension has a shadow at the bottom of the shape that the correct one only has at the top.

Revision history for this message
Tim Peeters (tpeeters) wrote :

^The image is ugly because I made it inside a vm that scales the screen resolution, but dropbox made it even uglier. Use this link to download the png https://www.dropbox.com/s/uy6sro2spmyiq53/Screenshot%202015-08-19%2000.32.46.png?dl=1

Revision history for this message
Tim Peeters (tpeeters) wrote :

I did not yet verify that this works on the emulator and that it does not break the rendering on devices. We need to do that before landing this.

review: Needs Information
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
1218. By Tim Peeters

remove incorrect inset and dropshadow

Revision history for this message
Tim Peeters (tpeeters) wrote :

The visual issues mentioned above are now avoided by disabling inset and dropshadows when the required extension is not available.

Revision history for this message
Tim Peeters (tpeeters) :
review: Abstain
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/Ubuntu/Components/plugin/plugin.pri'
2--- src/Ubuntu/Components/plugin/plugin.pri 2015-08-12 09:54:40 +0000
3+++ src/Ubuntu/Components/plugin/plugin.pri 2015-08-19 13:59:00 +0000
4@@ -143,5 +143,7 @@
5 OTHER_FILES += \
6 $$PWD/shaders/shape.vert \
7 $$PWD/shaders/shape.frag \
8+ $$PWD/shaders/shape_no_dfdy.frag \
9 $$PWD/shaders/shapeoverlay.vert \
10- $$PWD/shaders/shapeoverlay.frag
11+ $$PWD/shaders/shapeoverlay.frag \
12+ $$PWD/shaders/shapeoverlay_no_dfdy.frag
13
14=== modified file 'src/Ubuntu/Components/plugin/plugin.qrc'
15--- src/Ubuntu/Components/plugin/plugin.qrc 2014-12-01 19:26:16 +0000
16+++ src/Ubuntu/Components/plugin/plugin.qrc 2015-08-19 13:59:00 +0000
17@@ -1,8 +1,10 @@
18 <RCC>
19 <qresource prefix="/uc">
20 <file>shaders/shape.frag</file>
21+ <file>shaders/shape_no_dfdy.frag</file>
22 <file>shaders/shape.vert</file>
23 <file>shaders/shapeoverlay.frag</file>
24+ <file>shaders/shapeoverlay_no_dfdy.frag</file>
25 <file>shaders/shapeoverlay.vert</file>
26 </qresource>
27 </RCC>
28
29=== added file 'src/Ubuntu/Components/plugin/shaders/shape_no_dfdy.frag'
30--- src/Ubuntu/Components/plugin/shaders/shape_no_dfdy.frag 1970-01-01 00:00:00 +0000
31+++ src/Ubuntu/Components/plugin/shaders/shape_no_dfdy.frag 2015-08-19 13:59:00 +0000
32@@ -0,0 +1,112 @@
33+// Copyright © 2015 Canonical Ltd.
34+//
35+// This program is free software; you can redistribute it and/or modify
36+// it under the terms of the GNU Lesser General Public License as published by
37+// the Free Software Foundation; version 3.
38+//
39+// This program is distributed in the hope that it will be useful,
40+// but WITHOUT ANY WARRANTY; without even the implied warranty of
41+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
42+// GNU Lesser General Public License for more details.
43+//
44+// You should have received a copy of the GNU Lesser General Public License
45+// along with this program. If not, see <http://www.gnu.org/licenses/>.
46+//
47+// Author: Loïc Molinari <loic.molinari@canonical.com>
48+
49+// Static flow control (branching on a uniform value) is fast on most GPUs (including ultra-low
50+// power ones) because it allows to use the same shader execution path for an entire draw call. We
51+// rely on that technique here (also known as "uber-shader" solution) to avoid the complexity of
52+// dealing with a multiple shaders solution.
53+// FIXME(loicm) Validate GPU behavior with regards to static flow control.
54+
55+uniform sampler2D shapeTexture;
56+uniform sampler2D sourceTexture;
57+uniform lowp vec2 opacityFactors;
58+uniform lowp float dfdtFactor;
59+uniform lowp float sourceOpacity;
60+uniform lowp float distanceAA;
61+uniform bool textured;
62+uniform mediump int aspect;
63+
64+varying mediump vec2 shapeCoord;
65+varying mediump vec4 sourceCoord;
66+varying lowp vec4 backgroundColor;
67+
68+const mediump int FLAT = 0x08; // 1 << 3
69+const mediump int INSET = 0x10; // 1 << 4
70+const mediump int DROP_SHADOW = 0x20; // 1 << 5
71+
72+void main(void)
73+{
74+ lowp vec4 shapeData = texture2D(shapeTexture, shapeCoord);
75+ lowp vec4 color = backgroundColor;
76+
77+ // FIXME(loicm) Would be better to use a bitfield but bitwise ops have only been integrated in
78+ // GLSL 1.3 (OpenGL 3) and GLSL ES 3 (OpenGL ES 3).
79+ if (textured) {
80+ // Blend the source over the current color.
81+ // FIXME(loicm) sign() is far from optimal. Call texture2D() at beginning of scope.
82+ lowp vec2 axisMask = -sign((sourceCoord.zw * sourceCoord.zw) - vec2(1.0));
83+ lowp float mask = clamp(axisMask.x + axisMask.y, 0.0, 1.0);
84+ lowp vec4 source = texture2D(sourceTexture, sourceCoord.st) * vec4(sourceOpacity * mask);
85+ color = vec4(1.0 - source.a) * color + source;
86+ }
87+
88+ // FIXME: Workaround for systems that do not support dFdy()
89+ lowp float dfdt = -0.0285;
90+
91+#define NO_DFDY 1
92+ // only FLAT aspect is supported when the dFdy function is not available because
93+ // dFdy() is used to determine on which side (top or bottom) in the shape we are.
94+
95+#ifndef NO_DFDY
96+ if (aspect == FLAT) {
97+#endif
98+ // Mask the current color with an anti-aliased and resolution independent shape mask built
99+ // from distance fields.
100+ lowp float distanceMin = abs(dfdt) * -distanceAA + 0.5;
101+ lowp float distanceMax = abs(dfdt) * distanceAA + 0.5;
102+ color *= smoothstep(distanceMin, distanceMax, shapeData.b);
103+#ifndef NO_DFDY
104+
105+ } else if (aspect == INSET) {
106+ // The vertex layout of the shape is made so that the derivative is negative from top to
107+ // middle and positive from middle to bottom.
108+ lowp float shapeSide = dfdt * dfdtFactor <= 0.0 ? 0.0 : 1.0;
109+ // Blend the shape inner shadow over the current color. The shadow color is black, its
110+ // translucency is stored in the texture.
111+ lowp float shadow = shapeData[int(shapeSide)];
112+ color = vec4(1.0 - shadow) * color + vec4(0.0, 0.0, 0.0, shadow);
113+ // Get the anti-aliased and resolution independent shape mask using distance fields.
114+ lowp float distanceMin = abs(dfdt) * -distanceAA + 0.5;
115+ lowp float distanceMax = abs(dfdt) * distanceAA + 0.5;
116+ lowp vec2 mask = smoothstep(distanceMin, distanceMax, shapeData.ba);
117+ // Get the bevel color. The bevel is made of the top mask masked with the bottom mask. A
118+ // gradient from the bottom (1) to the middle (0) of the shape is used to factor out values
119+ // resulting from the mask anti-aliasing. The bevel color is white with 60% opacity.
120+ lowp float bevel = (mask.x * -mask.y) + mask.x; // -ab + a = a(1 - b)
121+ lowp float gradient = clamp((shapeSide * -shapeCoord.t) + shapeSide, 0.0, 1.0);
122+ bevel *= gradient * 0.6;
123+ // Mask the current color then blend the bevel over the resulting color. We simply use
124+ // additive blending since the bevel has already been masked.
125+ color = (color * vec4(mask[int(shapeSide)])) + vec4(bevel);
126+
127+ } else if (aspect == DROP_SHADOW) {
128+ // The vertex layout of the shape is made so that the derivative is negative from top to
129+ // middle and positive from middle to bottom.
130+ lowp int shapeSide = dfdt * dfdtFactor <= 0.0 ? 0 : 1;
131+ // Get the anti-aliased and resolution independent shape mask using distance fields.
132+ lowp float distanceMin = abs(dfdt) * -distanceAA + 0.5;
133+ lowp float distanceMax = abs(dfdt) * distanceAA + 0.5;
134+ lowp float mask = smoothstep(distanceMin, distanceMax, shapeData[shapeSide]);
135+ // Get the shadow color outside of the shape mask.
136+ lowp float shadow = (shapeData.b * -mask) + shapeData.b; // -ab + a = a(1 - b)
137+ // Mask the current color then blend the shadow over the resulting color. We simply use
138+ // additive blending since the shadow has already been masked.
139+ color = (color * vec4(mask)) + vec4(0.0, 0.0, 0.0, shadow);
140+ }
141+#endif
142+
143+ gl_FragColor = color * opacityFactors.xxxy;
144+}
145
146=== added file 'src/Ubuntu/Components/plugin/shaders/shapeoverlay_no_dfdy.frag'
147--- src/Ubuntu/Components/plugin/shaders/shapeoverlay_no_dfdy.frag 1970-01-01 00:00:00 +0000
148+++ src/Ubuntu/Components/plugin/shaders/shapeoverlay_no_dfdy.frag 2015-08-19 13:59:00 +0000
149@@ -0,0 +1,121 @@
150+// Copyright © 2015 Canonical Ltd.
151+//
152+// This program is free software; you can redistribute it and/or modify
153+// it under the terms of the GNU Lesser General Public License as published by
154+// the Free Software Foundation; version 3.
155+//
156+// This program is distributed in the hope that it will be useful,
157+// but WITHOUT ANY WARRANTY; without even the implied warranty of
158+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
159+// GNU Lesser General Public License for more details.
160+//
161+// You should have received a copy of the GNU Lesser General Public License
162+// along with this program. If not, see <http://www.gnu.org/licenses/>.
163+//
164+// Author: Loïc Molinari <loic.molinari@canonical.com>
165+
166+// Static flow control (branching on a uniform value) is fast on most GPUs (including ultra-low
167+// power ones) because it allows to use the same shader execution path for an entire draw call. We
168+// rely on that technique here (also known as "uber-shader" solution) to avoid the complexity of
169+// dealing with a multiple shaders solution.
170+// FIXME(loicm) Validate GPU behavior with regards to static flow control.
171+
172+uniform sampler2D shapeTexture;
173+uniform sampler2D sourceTexture;
174+uniform lowp vec2 opacityFactors;
175+uniform lowp float dfdtFactor;
176+uniform lowp float sourceOpacity;
177+uniform lowp float distanceAA;
178+uniform bool textured;
179+uniform mediump int aspect;
180+
181+varying mediump vec2 shapeCoord;
182+varying mediump vec4 sourceCoord;
183+varying lowp vec4 backgroundColor;
184+varying mediump vec2 overlayCoord;
185+varying lowp vec4 overlayColor;
186+
187+const mediump int FLAT = 0x08; // 1 << 3
188+const mediump int INSET = 0x10; // 1 << 4
189+const mediump int DROP_SHADOW = 0x20; // 1 << 5
190+
191+void main(void)
192+{
193+ lowp vec4 shapeData = texture2D(shapeTexture, shapeCoord);
194+ lowp vec4 color = backgroundColor;
195+
196+ // FIXME(loicm) Would be better to use a bitfield but bitwise ops have only been integrated in
197+ // GLSL 1.3 (OpenGL 3) and GLSL ES 3 (OpenGL ES 3).
198+ if (textured) {
199+ // Blend the source over the current color.
200+ // FIXME(loicm) sign() is far from optimal. Call texture2D() at beginning of scope.
201+ lowp vec2 axisMask = -sign((sourceCoord.zw * sourceCoord.zw) - vec2(1.0));
202+ lowp float mask = clamp(axisMask.x + axisMask.y, 0.0, 1.0);
203+ lowp vec4 source = texture2D(sourceTexture, sourceCoord.st) * vec4(sourceOpacity * mask);
204+ color = vec4(1.0 - source.a) * color + source;
205+ }
206+
207+ // Blend the overlay over the current color.
208+ // FIXME(loicm) sign() is far from optimal.
209+ lowp vec2 overlayAxisMask = -sign((overlayCoord * overlayCoord) - vec2(1.0));
210+ lowp float overlayMask = clamp(overlayAxisMask.x + overlayAxisMask.y, 0.0, 1.0);
211+ lowp vec4 overlay = overlayColor * vec4(overlayMask);
212+ color = vec4(1.0 - overlay.a) * color + overlay;
213+
214+ // FIXME: Workaround for systems that do not support dFdy()
215+ lowp float dfdt = -0.0285;
216+
217+#define NO_DFDY 1
218+ // only FLAT aspect is supported when the dFdy function is not available because
219+ // dFdy() is used to determine on which side (top or bottom) in the shape we are.
220+
221+#ifndef NO_DFDY
222+ if (aspect == FLAT) {
223+#endif
224+ // Mask the current color with an anti-aliased and resolution independent shape mask built
225+ // from distance fields.
226+ lowp float distanceMin = abs(dfdt) * -distanceAA + 0.5;
227+ lowp float distanceMax = abs(dfdt) * distanceAA + 0.5;
228+ color *= smoothstep(distanceMin, distanceMax, shapeData.b);
229+
230+#ifndef NO_DFDY
231+ } else if (aspect == INSET) {
232+ // The vertex layout of the shape is made so that the derivative is negative from top to
233+ // middle and positive from middle to bottom.
234+ lowp float shapeSide = dfdt * dfdtFactor <= 0.0 ? 0.0 : 1.0;
235+ // Blend the shape inner shadow over the current color. The shadow color is black, its
236+ // translucency is stored in the texture.
237+ lowp float shadow = shapeData[int(shapeSide)];
238+ color = vec4(1.0 - shadow) * color + vec4(0.0, 0.0, 0.0, shadow);
239+ // Get the anti-aliased and resolution independent shape mask using distance fields.
240+ lowp float distanceMin = abs(dfdt) * -distanceAA + 0.5;
241+ lowp float distanceMax = abs(dfdt) * distanceAA + 0.5;
242+ lowp vec2 mask = smoothstep(distanceMin, distanceMax, shapeData.ba);
243+ // Get the bevel color. The bevel is made of the top mask masked with the bottom mask. A
244+ // gradient from the bottom (1) to the middle (0) of the shape is used to factor out values
245+ // resulting from the mask anti-aliasing. The bevel color is white with 60% opacity.
246+ lowp float bevel = (mask.x * -mask.y) + mask.x; // -ab + a = a(1 - b)
247+ lowp float gradient = clamp((shapeSide * -shapeCoord.t) + shapeSide, 0.0, 1.0);
248+ bevel *= gradient * 0.6;
249+ // Mask the current color then blend the bevel over the resulting color. We simply use
250+ // additive blending since the bevel has already been masked.
251+ color = (color * vec4(mask[int(shapeSide)])) + vec4(bevel);
252+
253+ } else if (aspect == DROP_SHADOW) {
254+ // The vertex layout of the shape is made so that the derivative is negative from top to
255+ // middle and positive from middle to bottom.
256+ lowp int shapeSide = dfdt * dfdtFactor <= 0.0 ? 0 : 1;
257+ // Get the anti-aliased and resolution independent shape mask using distance fields.
258+ lowp float distanceMin = abs(dfdt) * -distanceAA + 0.5;
259+ lowp float distanceMax = abs(dfdt) * distanceAA + 0.5;
260+ lowp float mask = smoothstep(distanceMin, distanceMax, shapeData[shapeSide]);
261+ // Get the shadow color outside of the shape mask.
262+ lowp float shadow = (shapeData.b * -mask) + shapeData.b; // -ab + a = a(1 - b)
263+ // Mask the current color then blend the shadow over the resulting color. We simply use
264+ // additive blending since the shadow has already been masked.
265+ color = (color * vec4(mask)) + vec4(0.0, 0.0, 0.0, shadow);
266+ }
267+#endif
268+
269+ gl_FragColor = color * opacityFactors.xxxy;
270+}
271
272=== modified file 'src/Ubuntu/Components/plugin/ucubuntushape.cpp'
273--- src/Ubuntu/Components/plugin/ucubuntushape.cpp 2015-08-06 13:16:24 +0000
274+++ src/Ubuntu/Components/plugin/ucubuntushape.cpp 2015-08-19 13:59:00 +0000
275@@ -52,8 +52,17 @@
276
277 ShapeShader::ShapeShader()
278 {
279+ QOpenGLContext* context = QOpenGLContext::currentContext();
280 setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/uc/shaders/shape.vert"));
281- setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/uc/shaders/shape.frag"));
282+
283+ if ( context->isOpenGLES() &&
284+ !context->hasExtension(QByteArrayLiteral("GL_OES_standard_derivatives")) ) {
285+ // dFdy function is not available in fragment shaders
286+ qWarning() << "GL_OES_standard_derivatives not available. Using fallback shader for shape.";
287+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/uc/shaders/shape_no_dfdy.frag"));
288+ } else {
289+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/uc/shaders/shape.frag"));
290+ }
291 }
292
293 char const* const* ShapeShader::attributeNames() const
294
295=== modified file 'src/Ubuntu/Components/plugin/ucubuntushapeoverlay.cpp'
296--- src/Ubuntu/Components/plugin/ucubuntushapeoverlay.cpp 2015-04-30 19:51:26 +0000
297+++ src/Ubuntu/Components/plugin/ucubuntushapeoverlay.cpp 2015-08-19 13:59:00 +0000
298@@ -26,8 +26,17 @@
299
300 ShapeOverlayShader::ShapeOverlayShader()
301 {
302+ QOpenGLContext* context = QOpenGLContext::currentContext();
303 setShaderSourceFile(QOpenGLShader::Vertex, QStringLiteral(":/uc/shaders/shapeoverlay.vert"));
304- setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/uc/shaders/shapeoverlay.frag"));
305+
306+ if ( context->isOpenGLES() &&
307+ !context->hasExtension(QByteArrayLiteral("GL_OES_standard_derivatives")) ) {
308+ // dFdy function is not available in fragment shaders
309+ qWarning() << "GL_OES_standard_derivatives not available. Using fallback shader for shape overlay.";
310+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/uc/shaders/shapeoverlay_no_dfdy.frag"));
311+ } else {
312+ setShaderSourceFile(QOpenGLShader::Fragment, QStringLiteral(":/uc/shaders/shapeoverlay.frag"));
313+ }
314 }
315
316 char const* const* ShapeOverlayShader::attributeNames() const

Subscribers

People subscribed via source and target branches

to status/vote changes: