How to make this code work on Mesa3d? - opengl

This GLSL code compile and run warningless in ATI's OpenGL:
void main()
{
vec4 tmp = gl_ModelViewMatrix * gl_Vertex;
tmp.xyz = tmp.xyz / (1 - tmp.w);
tmp.w = 1;
gl_Position = gl_ProjectionMatrix * tmp;
gl_FrontColor = gl_Color;
}
Why does it fail with mesa? How to decrypt that error message and make it Mesa's implementation compliant?
Compilation log:
0:1(88): error: Could not implicitly convert operands to arithmetic operator
0:1(89): error: Operands to arithmetic operators must be numeric
0:1(97): error: type mismatch

Try changing your 1s to 1.0s.

Related

GLSL-ES3(webGL2): how to test extensions from fragment shader?

In webGL1 it was possible to test the availability of a GLSL extension from a fragment shader using (for instance) #ifdef GL_EXT_shader_texture_lod .
It seems to no longer be working in webGL2 (=GLSL-ES3.0): Extensions are not the same, but for instance #ifdef GL_EXT_color_buffer_float seems false despite https://webglreport.com/?v=2 tells that the extension is there.
Or what am I doing wrong ?
It's up to the extension whether or not it adds a flag to GLSL
EXT_shader_texture_lod is specifically an extension that effects GLSL. It's spec says it adds that macro
The GLSL macro GL_EXT_shader_texture_lod is defined as 1.
EXT_color_buffer_float is not an extension that affects GLSL. It's spec does not mention any GLSL macros. No change from WebGL1
Those flags though are mostly nonsense in WebGL anyway. You can trivially do your own string manipulation
const shaderTextureLodExt = gl.getExtension('EXT_shader_texture_lod');
const shader = `
#if ${shaderTextureLodExt ? 1 : 0}
... code if shader texture lod exists
#else
... code if shader texture lod does not exist
#endif
...
`;
Or a thousand other ways to manipulate shader strings.
Here's another
const colorBufferFloatExt = gl.getExtension('EXT_color_buffer_float');
function replaceIfDefs(s) {
return `
${colorBufferExtension ? '#define EXTENSION_color_buffer_float' : ''}
${s.replace(/GL_EXT_color_buffer_float/g 'EXTENSION_color_buffer_float')}
`;
}
const shader = replaceIfDefs(`
#ifdef GL_EXT_color_buffer_float
...
#endif
...
`);
etc...
Also since there never was a GL_EXT_color_buffer_float even in OpenGL there isn't much point in calling the macro GL_EXT_color_buffer_float. In fact it would arguably be a bad idea because it would end up looking like an official specified macro even though it's not. Best to chose your own name that doesn't start with GL_ .
Also consider that using #ifdef might not even be a good idea since you can just use string manipulation. For example
const colorBufferFloatExt = gl.getExtension('EXT_color_buffer_float');
const snippet = colorBufferFloatExt
? `
float decode_float(vec4 v) {
return v;
}
`
: `
float decode_float(vec4 v) {
vec4 bits = v * 255.0;
float sign = mix(-1.0, 1.0, step(bits[3], 128.0));
float expo = floor(mod(bits[3] + 0.1, 128.0)) * 2.0 +
floor((bits[2] + 0.1) / 128.0) - 127.0;
float sig = bits[0] +
bits[1] * 256.0 +
floor(mod(bits[2] + 0.1, 128.0)) * 256.0 * 256.0;
return sign * (1.0 + sig / 8388607.0) * pow(2.0, expo);
}
`;
const shader = `
precision highp float;
${snippet}
uniform sampler2D data;
uniform vec2 dataSize;
void main(
vec4 d = texture2D(data, gl_FragCoord.xy / dataSize);
vec4 v = decode_float(d) * 2.0;
gl_FragColor = v;
}
`;
...etc...

how to use a fragment shader without main function

i found a shader to do a drop shadow from http://madebyevan.com/shaders/fast-rounded-rectangle-shadows/
// License: CC0 (http://creativecommons.org/publicdomain/zero/1.0/)
// This approximates the error function, needed for the gaussian integral
vec4 erf(vec4 x) {
vec4 s = sign(x), a = abs(x);
x = 1.0 + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a;
x *= x;
return s - s / (x * x);
}
// Return the mask for the shadow of a box from lower to upper
float boxShadow(vec2 lower, vec2 upper, vec2 point, float sigma) {
vec4 query = vec4(point - lower, upper - point);
vec4 integral = 0.5 + 0.5 * erf(query * (sqrt(0.5) / sigma));
return (integral.z - integral.x) * (integral.w - integral.y);
}
i thought that a shader need a main function and should return color.
My question is how to use the function boxShadow in c++ code with opengl given a box
thanks
A function can be defined in a shader just as you would do with a C function. I mean, the code for the function is in the same "unit" as the rest of the shader.
#version XX-YY
//MyFunc(.....)
whateverreturn MyFunc(.....)
{
do something and return a whateverreturn
}
void main(void)
{
//use MyFunc
whateverreturn var = MyFunc(....)
}
A bit different case is when you have a function that can be part of several shaders, but it isn't a "full" shader, it has no main() function. This function lives in a file or in string-array or something similar.
Say you have the function in a specific file:
#version XX-YY
//MyFunc(.....)
whateverreturn MyFunc(.....)
{
do something and return a whateverreturn
}
And the file with the shader where you want to use it:
#version XX-YY
//declare the function
whateverreturn MyFunc(.....);
void main(void)
{
//use MyFunc
whateverreturn var = MyFunc(....)
}
Like you do with any common GLSL code, use glShaderSource and glCompileShader.
Now the key step is how to integrate the code within a full (with 'main') shader: just use glAttachShader (again, like you do with VS or FS) before glLinkProgram and that'as all.

How to do dynamic loop in WebGL GLSL [duplicate]

I have the a webgl blur shader:
precision mediump float;
precision mediump int;
uniform sampler2D u_image;
uniform float blur;
uniform int u_horizontalpass; // 0 or 1 to indicate vertical or horizontal pass
uniform float sigma; // The sigma value for the gaussian function: higher value means more blur
// A good value for 9x9 is around 3 to 5
// A good value for 7x7 is around 2.5 to 4
// A good value for 5x5 is around 2 to 3.5
// ... play around with this based on what you need :)
varying vec4 v_texCoord;
const vec2 texOffset = vec2(1.0, 1.0);
// uniform vec2 texOffset;
const float PI = 3.14159265;
void main() {
vec2 p = v_texCoord.st;
float numBlurPixelsPerSide = blur / 2.0;
// Incremental Gaussian Coefficent Calculation (See GPU Gems 3 pp. 877 - 889)
vec3 incrementalGaussian;
incrementalGaussian.x = 1.0 / (sqrt(2.0 * PI) * sigma);
incrementalGaussian.y = exp(-0.5 / (sigma * sigma));
incrementalGaussian.z = incrementalGaussian.y * incrementalGaussian.y;
vec4 avgValue = vec4(0.0, 0.0, 0.0, 0.0);
float coefficientSum = 0.0;
// Take the central sample first...
avgValue += texture2D(u_image, p) * incrementalGaussian.x;
coefficientSum += incrementalGaussian.x;
incrementalGaussian.xy *= incrementalGaussian.yz;
// Go through the remaining 8 vertical samples (4 on each side of the center)
for (float i = 1.0; i <= numBlurPixelsPerSide; i += 1.0) {
avgValue += texture2D(u_image, p - i * texOffset) * incrementalGaussian.x;
avgValue += texture2D(u_image, p + i * texOffset) * incrementalGaussian.x;
coefficientSum += 2.0 * incrementalGaussian.x;
incrementalGaussian.xy *= incrementalGaussian.yz;
}
gl_FragColor = avgValue / coefficientSum;
}
When I build, I get the following error message:
webgl-renderer.js?2eb3:137 Uncaught could not compile shader:ERROR:
0:38: 'i' : Loop index cannot be compared with non-constant expression
I have also tried to use just the uniform float blur to compare i to. Is there any way to fix this?
The problem is further detailed here: https://www.khronos.org/webgl/public-mailing-list/archives/1012/msg00063.php
The solution that I've found looking around is to only use a constant expression when comparing a loop var. This doesn't fit with what I need to do which is vary how many times I'm looping based on the blur radius.
Any thoughts on this?
This happens because on some hardware, GLSL loops are un-rolled into native GPU instructions. This means there needs to be a hard upper limit to the number of passes through the for loop, that governs how many copies of the loop's inner code will be generated. If you replace numBlurPixelsPerSide with a const float or even a #define directive, and the shader compiler can then determine the number of passes at compile time, and generate the code accordingly. But with a uniform there, the upper limit is not known at compile time.
There's an interesting wrinkle in this rule: You're allowed to break or call an early return out of a for loop, even though the max iterations must be discernible at compile time. For example, consider this tiny Mandelbrot shader. This is hardly the prettiest fractal on GLSL Sandbox, but I chose it for its small size:
precision mediump float;
uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
varying vec2 surfacePosition;
const float max_its = 100.;
float mandelbrot(vec2 z){
vec2 c = z;
for(float i=0.;i<max_its;i++){ // for loop is here.
if(dot(z,z)>4.) return i; // conditional early return here.
z = vec2(z.x*z.x-z.y*z.y,2.*z.x*z.y)+c;
}
return max_its;
}
void main( void ) {
vec2 p = surfacePosition;
gl_FragColor = vec4(mandelbrot(p)/max_its);
}
In this example, max_its is a const so the compiler knows the upper limit and can un-roll this loop if it needs to. Inside the loop, a return statement offers a way to leave the loop early for pixels that are outside of the Mandelbrot set.
You still don't want to set the max iterations too high, as this can produce a lot of GPU instructions and possibly hurt performance.
Try something like this:
const float MAX_ITERATIONS = 100.0;
// Go through the remaining 8 vertical samples (4 on each side of the center)
for (float i = 1.0; i <= MAX_ITERATIONS; i += 1.0) {
if (i >= numBlurPixelsPerSide){break;}
avgValue += texture2D(u_image, p - i * texOffset) * incrementalGaussian.x;
avgValue += texture2D(u_image, p + i * texOffset) * incrementalGaussian.x;
coefficientSum += 2.0 * incrementalGaussian.x;
incrementalGaussian.xy *= incrementalGaussian.yz;
}
Sometimes you can use my very simple solving of issue.
My fragment of the shader source code:
const int cloudPointsWidth = %s;
for ( int i = 0; i < cloudPointsWidth; i++ ) {
//TO DO something
}
You can see '%' : syntax error above. But I am replace %s to a number in my javascript code before use my shader. For example:
vertexCode = vertexCode.replace( '%s', 10 );
vertexCode is my shader source code.
Everytime if I want to change cloudPointsWidth, I am destroying my old shader and creating new shader with new cloudPointsWidth .
Hope sometimes my solving can to help you.
You can just do a for loop with large constant number and use a break.
for(int i = 0; i < 1000000; ++i)
{
// your code here
if(i >= n){
break;
}
}
I've had similar problem with image downsampling shader. The code is basically the same:
for (int dx = -2 * SCALE_FACTOR; dx < 2 * SCALE_FACTOR; dx += 2) {
for (int dy = -2 * SCALE_FACTOR; dy < 2 * SCALE_FACTOR; dy += 2) {
/* accumulate fragment's color */
}
}
What I've ended up doing is using preprocessor and creating separate shader programs for every SCALE_FACTOR used (luckily, only 4 was needed). To achieve that, a small helper function was implemented to add #define ... statements to shader code:
function insertDefines (shaderCode, defines) {
var defineString = '';
for (var define in defines) {
if (defines.hasOwnProperty(define)) {
defineString +=
'#define ' + define + ' ' + defines[define] + '\n';
}
}
var versionIdx = shaderCode.indexOf('#version');
if (versionIdx == -1) {
return defineString + shaderCode;
}
var nextLineIdx = shaderCode.indexOf('\n', versionIdx) + 1;
return shaderCode.slice(0, nextLineIdx) +
defineString +
shaderCode.slice(nextLineIdx);
}
The implementation is a bit tricky because if the code already has #version preprocessor statement in it, all other statements have to follow it.
Then I've added a check for SCALE_FACROR being defined:
#ifndef SCALE_FACTOR
# error SCALE_FACTOR is undefined
#endif
And in my javascript code I've done something like this:
var SCALE_FACTORS = [4, 8, 16, 32],
shaderCode, // the code of my shader
shaderPrograms = SCALE_FACTORS.map(function (factor) {
var codeWithDefines = insertDefines(shaderCode, { SCALE_FACTOR: factor });
/* compile shaders, link program, return */
});
I use opengl es3 on android and solve this problem by using extension above the beginning of program like this:
#extension GL_EXT_gpu_shader5 : require
I don't know whether it work on webGL, but you can try it.
Hope it can help.
You can also use template litterals to set the length of the loop
onBeforeCompile(shader) {
const array = [1,2,3,4,5];
shader.uniforms.myArray = { value: array };
let token = "#include <begin_vertex>";
const insert = `
uniform float myArray[${array.length}];
for ( int i = 0; i < ${array.length}; i++ ) {
float test = myArray[ i ];
}
`;
shader.vertexShader = shader.vertexShader.replace(token, token + insert);
}

WebGL: Loop index cannot be compared with non-constant expression

I have the a webgl blur shader:
precision mediump float;
precision mediump int;
uniform sampler2D u_image;
uniform float blur;
uniform int u_horizontalpass; // 0 or 1 to indicate vertical or horizontal pass
uniform float sigma; // The sigma value for the gaussian function: higher value means more blur
// A good value for 9x9 is around 3 to 5
// A good value for 7x7 is around 2.5 to 4
// A good value for 5x5 is around 2 to 3.5
// ... play around with this based on what you need :)
varying vec4 v_texCoord;
const vec2 texOffset = vec2(1.0, 1.0);
// uniform vec2 texOffset;
const float PI = 3.14159265;
void main() {
vec2 p = v_texCoord.st;
float numBlurPixelsPerSide = blur / 2.0;
// Incremental Gaussian Coefficent Calculation (See GPU Gems 3 pp. 877 - 889)
vec3 incrementalGaussian;
incrementalGaussian.x = 1.0 / (sqrt(2.0 * PI) * sigma);
incrementalGaussian.y = exp(-0.5 / (sigma * sigma));
incrementalGaussian.z = incrementalGaussian.y * incrementalGaussian.y;
vec4 avgValue = vec4(0.0, 0.0, 0.0, 0.0);
float coefficientSum = 0.0;
// Take the central sample first...
avgValue += texture2D(u_image, p) * incrementalGaussian.x;
coefficientSum += incrementalGaussian.x;
incrementalGaussian.xy *= incrementalGaussian.yz;
// Go through the remaining 8 vertical samples (4 on each side of the center)
for (float i = 1.0; i <= numBlurPixelsPerSide; i += 1.0) {
avgValue += texture2D(u_image, p - i * texOffset) * incrementalGaussian.x;
avgValue += texture2D(u_image, p + i * texOffset) * incrementalGaussian.x;
coefficientSum += 2.0 * incrementalGaussian.x;
incrementalGaussian.xy *= incrementalGaussian.yz;
}
gl_FragColor = avgValue / coefficientSum;
}
When I build, I get the following error message:
webgl-renderer.js?2eb3:137 Uncaught could not compile shader:ERROR:
0:38: 'i' : Loop index cannot be compared with non-constant expression
I have also tried to use just the uniform float blur to compare i to. Is there any way to fix this?
The problem is further detailed here: https://www.khronos.org/webgl/public-mailing-list/archives/1012/msg00063.php
The solution that I've found looking around is to only use a constant expression when comparing a loop var. This doesn't fit with what I need to do which is vary how many times I'm looping based on the blur radius.
Any thoughts on this?
This happens because on some hardware, GLSL loops are un-rolled into native GPU instructions. This means there needs to be a hard upper limit to the number of passes through the for loop, that governs how many copies of the loop's inner code will be generated. If you replace numBlurPixelsPerSide with a const float or even a #define directive, and the shader compiler can then determine the number of passes at compile time, and generate the code accordingly. But with a uniform there, the upper limit is not known at compile time.
There's an interesting wrinkle in this rule: You're allowed to break or call an early return out of a for loop, even though the max iterations must be discernible at compile time. For example, consider this tiny Mandelbrot shader. This is hardly the prettiest fractal on GLSL Sandbox, but I chose it for its small size:
precision mediump float;
uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;
varying vec2 surfacePosition;
const float max_its = 100.;
float mandelbrot(vec2 z){
vec2 c = z;
for(float i=0.;i<max_its;i++){ // for loop is here.
if(dot(z,z)>4.) return i; // conditional early return here.
z = vec2(z.x*z.x-z.y*z.y,2.*z.x*z.y)+c;
}
return max_its;
}
void main( void ) {
vec2 p = surfacePosition;
gl_FragColor = vec4(mandelbrot(p)/max_its);
}
In this example, max_its is a const so the compiler knows the upper limit and can un-roll this loop if it needs to. Inside the loop, a return statement offers a way to leave the loop early for pixels that are outside of the Mandelbrot set.
You still don't want to set the max iterations too high, as this can produce a lot of GPU instructions and possibly hurt performance.
Try something like this:
const float MAX_ITERATIONS = 100.0;
// Go through the remaining 8 vertical samples (4 on each side of the center)
for (float i = 1.0; i <= MAX_ITERATIONS; i += 1.0) {
if (i >= numBlurPixelsPerSide){break;}
avgValue += texture2D(u_image, p - i * texOffset) * incrementalGaussian.x;
avgValue += texture2D(u_image, p + i * texOffset) * incrementalGaussian.x;
coefficientSum += 2.0 * incrementalGaussian.x;
incrementalGaussian.xy *= incrementalGaussian.yz;
}
Sometimes you can use my very simple solving of issue.
My fragment of the shader source code:
const int cloudPointsWidth = %s;
for ( int i = 0; i < cloudPointsWidth; i++ ) {
//TO DO something
}
You can see '%' : syntax error above. But I am replace %s to a number in my javascript code before use my shader. For example:
vertexCode = vertexCode.replace( '%s', 10 );
vertexCode is my shader source code.
Everytime if I want to change cloudPointsWidth, I am destroying my old shader and creating new shader with new cloudPointsWidth .
Hope sometimes my solving can to help you.
You can just do a for loop with large constant number and use a break.
for(int i = 0; i < 1000000; ++i)
{
// your code here
if(i >= n){
break;
}
}
I've had similar problem with image downsampling shader. The code is basically the same:
for (int dx = -2 * SCALE_FACTOR; dx < 2 * SCALE_FACTOR; dx += 2) {
for (int dy = -2 * SCALE_FACTOR; dy < 2 * SCALE_FACTOR; dy += 2) {
/* accumulate fragment's color */
}
}
What I've ended up doing is using preprocessor and creating separate shader programs for every SCALE_FACTOR used (luckily, only 4 was needed). To achieve that, a small helper function was implemented to add #define ... statements to shader code:
function insertDefines (shaderCode, defines) {
var defineString = '';
for (var define in defines) {
if (defines.hasOwnProperty(define)) {
defineString +=
'#define ' + define + ' ' + defines[define] + '\n';
}
}
var versionIdx = shaderCode.indexOf('#version');
if (versionIdx == -1) {
return defineString + shaderCode;
}
var nextLineIdx = shaderCode.indexOf('\n', versionIdx) + 1;
return shaderCode.slice(0, nextLineIdx) +
defineString +
shaderCode.slice(nextLineIdx);
}
The implementation is a bit tricky because if the code already has #version preprocessor statement in it, all other statements have to follow it.
Then I've added a check for SCALE_FACROR being defined:
#ifndef SCALE_FACTOR
# error SCALE_FACTOR is undefined
#endif
And in my javascript code I've done something like this:
var SCALE_FACTORS = [4, 8, 16, 32],
shaderCode, // the code of my shader
shaderPrograms = SCALE_FACTORS.map(function (factor) {
var codeWithDefines = insertDefines(shaderCode, { SCALE_FACTOR: factor });
/* compile shaders, link program, return */
});
I use opengl es3 on android and solve this problem by using extension above the beginning of program like this:
#extension GL_EXT_gpu_shader5 : require
I don't know whether it work on webGL, but you can try it.
Hope it can help.
You can also use template litterals to set the length of the loop
onBeforeCompile(shader) {
const array = [1,2,3,4,5];
shader.uniforms.myArray = { value: array };
let token = "#include <begin_vertex>";
const insert = `
uniform float myArray[${array.length}];
for ( int i = 0; i < ${array.length}; i++ ) {
float test = myArray[ i ];
}
`;
shader.vertexShader = shader.vertexShader.replace(token, token + insert);
}

DirectX HLSL shader implicit truncation of vector type error

Hi I'm getting an error in one my pixel shaders, implicit truncation of vector type.
Here is the code causing the error:
float3 colour = 0;
float3 ppColour = SceneTexture.Sample(PointSample, ppIn.UV);
float4 col = SceneTexture.Sample(PointSample, ppIn.UV);
float intensity = 0.0f;
float r = SceneTexture.Sample(PointSample, ppIn.UV).r;
float g = SceneTexture.Sample(PointSample, ppIn.UV).g;
float b = SceneTexture.Sample(PointSample, ppIn.UV).b;
float a = SceneTexture.Sample(PointSample, ppIn.UV).a;
intensity = r + g + b + a;
if (intensity > 5.0f)
{
for (int count = 0; count < 13; count++)
{
colour += SceneTexture.Sample(TrilinearSampler, ppIn.UV + PixelKernel[count] * BlurStrength) * BlurWeights[count];
}
return float4(colour, 1.0f);
}
return float4(ppColour, 1.0f);
If I comment out intensity = r + g + b + a; then the project compiles. Can anyone see what I'm doing wrong, thanks.
The reason you get this error is, that you are mulitplying/adding up float3's and float4's. You should 'cast' float3 to float4 with float4(float3, 1.0f) or float4.xyz (which makes it float3)
Inferring some of the 'extra' stuff that is required to actually compile the shader (uniforms, inputs, and making the code into an actual function), I get the following output when trying to compile it:
test.ps(16,9): warning X3206: implicit truncation of vector type
test.ps(29,11): warning X3206: implicit truncation of vector type
test.ps(29,11): error X4014: cannot have gradient operations inside loops with divergent flow control
As you can see, the truncations messages are just warnings, not errors, unless you are using /WX to compile. The issue with these warnings, is that you are assigning the result of a texture sample to a float3, but the return is actually a float4. You can either select the appropriate components with a swizzle, or, change the variable type. For example:
float4 ppColour = SceneTexture.Sample(PointSample, ppIn.UV);
The reason for the actual error, is that you cannot do sample interpolation in dynamic loops, or loops inside conditional statements. In this case, your loop is inside the if (intensity > 5.0) conditional. You have two options, either you can remove the conditional, or, you can use SampleLevel instead of Sample:
colour += SceneTexture.SampleLevel(TrilinearSampler, ppIn.UV + PixelKernel[count] * BlurStrength, 0) * BlurWeights[count];
Note: using SampleLevel like this will always sample the top mip-level.