Using compute shader in Android 5 (Open GL ES 3.1) - android

I am learning about OpenGL ES and in particular, compute shaders in OpenGL ES 3.1, specifically, in Android 5.0.1.
I have 3 shaders defined (compute, vertex, and fragment) and attached to two different programs, one for the compute shader and one for the vertex and fragment shaders.
I have no problem when I only use the vertex and fragment shaders but now that I added the compute shader I get the following error:
02-11 20:02:10.375 13243-13264/com.example.daan.daggl2 I/VERSION﹕ OpenGL ES 3.1 NVIDIA 349.00
02-11 20:02:10.472 13243-13264/com.example.daan.daggl2 A/libc﹕ Fatal signal 11 (SIGSEGV), code 1, fault addr 0x0 in tid 13264 (GLThread 9847)
I'm trying to figure out what I'm missing but I'm new to this topic and I'm not sure where to begin looking for the problem.
The object's constructor is:
public Triangle() {
buffers = new int[1];
GLES31.glGenBuffers(1, buffers, 0);
gVBO = buffers[0];
// set up the vertex and fragment shaders
int vertexShader = MyGLRenderer.loadShader(
GLES31.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(
GLES31.GL_FRAGMENT_SHADER, fragmentShaderCode);
program = GLES31.glCreateProgram();
GLES31.glAttachShader(program, vertexShader);
GLES31.glAttachShader(program, fragmentShader);
GLES31.glLinkProgram(program);
checkGLError("LinkProgram/program");
// set up the compute shader
int computeShader = MyGLRenderer.loadShader(
GLES31.GL_COMPUTE_SHADER, computeShaderCode);
computeProgram = GLES31.glCreateProgram();
GLES31.glAttachShader(computeProgram, computeShader);
GLES31.glLinkProgram(computeProgram);
checkGLError("LinkProgram/computeProgram");
}
The draw function:
public void draw(float[] mvpMatrix, float[] color) {
GLES31.glUseProgram(computeProgram);
checkGLError("UseProgram/computeProgram");
int radiusId = GLES31.glGetUniformLocation(
computeProgram, "radius");
indexBufferBinding = 0;
GLES31.glUniform1f(radiusId, (float) radius);
GLES31.glBindBufferBase(
GLES31.GL_SHADER_STORAGE_BUFFER, indexBufferBinding, gVBO);
checkGLError("glBindBuffer/gVBO");
GLES31.glDispatchCompute(2, 2, 1);
GLES31.glBindBufferBase(
GLES31.GL_SHADER_STORAGE_BUFFER, indexBufferBinding, 0);
// See note 1 below
//GLES31.glMemoryBarrier(
// GLES31.GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT);
GLES31.glMemoryBarrier(
GLES31.GL_SHADER_STORAGE_BARRIER_BIT);
checkGLError("glMemoryBarrier/1");
GLES31.glBindBuffer(GLES31.GL_ARRAY_BUFFER, gVBO);
checkGLError("glBindBuffer/gVBO");
GLES31.glUseProgram(program);
int posId = GLES31.glGetAttribLocation(
program, "a_v4Position");
int fillId = GLES31.glGetAttribLocation(
program, "a_v4FillColor");
int mvpMatrixId = GLES31.glGetUniformLocation(
program, "mvp_matrix");
GLES31.glEnableVertexAttribArray(posId);
GLES31.glEnableVertexAttribArray(fillId);
GLES31.glUniformMatrix4fv(mvpMatrixId, 1, false, mvpMatrix, 0);
// See note 2 below
GLES31.glDrawArrays(GLES31.GL_POINTS, 0, 3);
}
For reference, the shaders are at the end of the post.
Notes:
I can't find GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT in the Android documentation. Shouldn't it be there? The documentation mentions it.
The draw call crashes the application. Up until before glDrawArrays() everything seems fine.
Any ideas on what to look for are appreciated.
Vertex Shader:
private final String vertexShaderCode =
"uniform mat4 mvp_matrix;" +
"attribute vec4 a_v4Position;" +
"attribute vec4 a_v4FillColor;" +
"varying vec4 v_v4FillColor;" +
"void main(void) {" +
" v_v4FillColor = a_v4FillColor;" +
" gl_Position = mvp_matrix * a_v4Position;" +
"}";
Fragment Shader:
private final String fragmentShaderCode =
"precision mediump float;" +
"varying vec4 v_v4FillColor;" +
"void main(void) {" +
" gl_FragColor = v_v4FillColor;" +
"}";
Compute Shader:
private final String computeShaderCode =
"#version 310 es" +
"\n" +
"uniform float radius;" +
"struct Vector3f { float x; float y; float z; float w; };" +
"struct AttribData { Vector3f v; Vector3f c; };" +
"layout(std140, binding = 0) buffer destBuffer { AttribData data[]; } outBuffer;" +
"layout (local_size_x = 8, local_size_y = 8, local_size_z = 1) in;" +
"void main() {" +
" ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);" +
" uint gWidth = gl_WorkGroupSize.x * gl_NumWorkGroups.x;" +
" uint gHeigth = gl_WorkGroupSize.y * gl_NumWorkGroups.y;" +
" uint gSize = uint(gWidth) * uint(gHeigth);" +
" uint offset = uint(storePos.y)*gWidth + uint(storePos.x);" +
" float alpha = 2.0 * 3.1159265359 * (float(offset) / float(gSize));" +
" outBuffer.data[offset].v.x = float(sin(alpha)) * float(radius);" +
" outBuffer.data[offset].v.y = float(cos(alpha)) * float(radius);" +
" outBuffer.data[offset].v.z = 0.0;" +
" outBuffer.data[offset].v.w = 1.0;" +
" outBuffer.data[offset].c.x = float(storePos.x) / float(gWidth);" +
" outBuffer.data[offset].c.y = 0.0;" +
" outBuffer.data[offset].c.z = 1.0;" +
" outBuffer.data[offset].c.w = 1.0;" +
"}";

Yes, GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT is missing in the Android Java bindings. There's a tradition of the Java OpenGL bindings in Android being incomplete. There are still things missing from the 3.0 bindings as well.
In this case, since it's just an enum value, you can easily work around it by defining the value itself. The C/C++ definition is:
#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
So in Java, you can add a definition like this to your code:
static final int GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT = 0x00000001;
As for the crash, I'm not totally sure. I notice that there's no glVertexAttribPointer() calls in the posted code. If they are indeed not in your code, that would certainly be a problem.

Related

OpenGL ES shader compilation

I am trying to create applications with opengl. Debugging on a real device.
I create the context like this::
GLSurfaceView baseView = new GLSurfaceView(this);
baseView.setEGLContextClientVersion(3);
baseView.setRenderer(new GameView());
I compile shaders like this:
int program = GLES20.glCreateProgram();
int idShad = (type == 0) ? GLES20.GL_VERTEX_SHADER : GLES20.GL_FRAGMENT_SHADER;
int shader = GLES20.glCreateShader(idShad);
GLES20.glShaderSource(shader, source);
GLES20.glCompileShader(shader);
int[] isCompiled = new int[1];
glGetShaderiv(shader, GL_COMPILE_STATUS, isCompiled, 0);
if (isCompiled[0] == GL_FALSE) {
String infoLog = "";
infoLog = glGetShaderInfoLog(shader);
glDeleteShader(shader);
String typeShader = (type == 0) ? "Vertex Shader" : "Fragment Shader";
Log.e("OpenGl", "Cannot compile " + typeShader + ": " + infoLog);
System.exit(-1);
}
glAttachShader(program, shader);
But I always getting this error:
Cannot compile: Vertex Shader: 0:3: L0001: Typename expected, found '�'
I get it when loading from a file and when creating a line in the code
For any code, even an empty shader, here are examples:
public static final String baseMatrixVX =
"#version 300 es\n"
+ "void main() {\n"
+ "}\0";
public static final String texMatrixVX =
"#version 330\n"
+ "layout(location = 0) in vec3 pos;\n"
+ "layout(location = 1) in vec3 color;\n"
+ "layout(location = 2) in vec2 tex;\n"
+ "out vec3 colorOut;\n"
+ "out vec2 texOut;\n"
+ "uniform bool enabledCam;\n"
+ "uniform mat4 projection;\n"
+ "uniform mat4 cam;\n"
+ "uniform mat4 model;\n"
+ "void main() {\n"
+ "if (enabledCam) {\n"
+ " gl_Position = projection * model * cam * vec4(pos, 1.0f);\n"
+ "} else {\n"
+ " gl_Position = projection * model * vec4(pos, 1.0f);\n"
+ "}\n"
+ "colorOut = vec3(color);\n"
+ "texOut = tex;\n"
+ "}\0";
What am I doing wrong?
P.S device supports opengle es 3 and above
It turned out that the problem is in the last character \0.
Should be used instead \n

Issues with HALF_FLOAT on Mali GPUs

I have reports from my users about issues with rendering of half-floats data on certain devices with Mali GPUs (Huawei Honor 9 and Samsung Galaxy S10+ w/ Mali G71 and G76 respectively).
It results in garbled rendering on these devices while works correctly on Adreno and PowerVR GPUs.
I've double checked code and it seems to be correct:
...
if (model.hasHalfFloats()) {
GLES20.glVertexAttribPointer(shaderOutline.getRm_Vertex(), 3, GLES20.GL_FLOAT, false, 18, 0);
GLES20.glVertexAttribPointer(shaderOutline.getRm_Normal(), 3, getGL_HALF_FLOAT(), false, 18, 12);
} else {
GLES20.glVertexAttribPointer(shaderOutline.getRm_Vertex(), 3, GLES20.GL_FLOAT, false, 24, 0);
GLES20.glVertexAttribPointer(shaderOutline.getRm_Normal(), 3, GLES20.GL_FLOAT, false, 24, 12);
}
...
/**
* Returns either OES extension for GL 16-bit floats (if used in ES 2.0) or ES 3.0 constant.
*/
protected int getGL_HALF_FLOAT() {
if(isES3()) {
return GLES30.GL_HALF_FLOAT;
} else {
return GL_HALF_FLOAT_OES;
}
}
Code seems to correctly detect OpenGL ES 3 and use GLES30.GL_HALF_FLOAT value in getGL_HALF_FLOAT().
Sample shader code:
vertexShaderCode = "attribute vec4 rm_Vertex;\r\n" +
"attribute mediump vec3 rm_Normal;\r\n" +
"uniform mat4 view_proj_matrix;\r\n" +
"uniform float uThickness1;\r\n" +
"void main( void )\r\n" +
"{\r\n" +
" vec4 pos = vec4(rm_Vertex.xyz, 1.0);\r\n" +
" float dist = (view_proj_matrix * pos).w;\r\n" +
" vec4 normal = vec4(rm_Normal, 0.0);\r\n" +
" pos += normal * uThickness1 * dist;\r\n" +
" gl_Position = view_proj_matrix * pos;\r\n" +
"}";
fragmentShaderCode = "precision mediump float;\r\n" +
"uniform vec4 uColor;\r\n" +
"void main( void )\r\n" +
"{\r\n" +
" gl_FragColor = uColor;\r\n" +
"}";
I think you have an alignment problem. From this snippet (and your vertex shader):
GLES20.glVertexAttribPointer(shaderOutline.getRm_Normal(), 3, getGL_HALF_FLOAT(), false, 18, 12);
I can infer that you're attempting a vertex structure like so:
float fPos[3];
half fNormal[3];
You have come up with a vertex stride of 18 which has presumably been arrived at by adding up the individual sizes of the elements (3*sizeof(float))+(3*sizeof(half)) = 12 + 6 = 18.
However, the stride should be 20 because otherwise your vertices are misaligned. The 4-byte floats must start on a 4-byte boundary, but that is not the case.
From the GLES3 spec:
Clients must align data elements consistently with the requirements of the client platform, with an additional base-level requirement that an offset within a buffer to a datum comprising N basic machine units be a multiple of N

Error in Compiling Fragment Shader Program in OpenGL es , Android

I'm new to OpenGL and today I was trying to compile some shader programs for GPGPU usage of OpenGL in android OS.
I have two questions:
1) I only want to program fragment shader, Is it necessary to program the vertex shader too?
2) I face some Errors while compiling my shader source code.
My source code is defined as :
final String src = "#version 310 es\n" +
"uniform sampler2D texUnit;\n" +
"uniform int sequence;\n" +
"void main(void)\n" +
"{\n" +
"const vec3 DotValue = {0.299f , 0.587f , 0.114f};\n" +
"vec2 texCoord = gl_TexCoord[0].xy;\n" +
"vec4 CurrentPixelData = texture2D(texUnit, texCoord);\n" +
"float temp = CurrentPixelData.x * DotValue.x + CurrentPixelData.y * DotValue.y + CurrentPixelData.z * DotValue.z;\n" +
"vec4 result = {temp,temp,temp,CurrentPixelData.w};\n" +
"gl_FragColor = result;\n" +
"}\n";
and the code for creating the shader is:
int fragment = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
GLES20.glShaderSource(fragment,src);
GLES20.glCompileShader(fragment);
int[] compiled = new int[1];
GLES20.glGetShaderiv(fragment, GLES20.GL_COMPILE_STATUS, compiled, 0); //compile[0] != 0 : compiled successfully
if (compiled[0] == 0) {
Log.e(TAG, "Could not compile shader: ");
Log.e(TAG, GLES20.glGetShaderInfoLog(fragment));
GLES20.glDeleteShader(fragment);
fragment = 0;
} else {
Log.i(TAG, "Compiled shader with source length " + src.length());
}
But when i try to debug my application, there are several errors about shader compilation in the logcat:
0:6: L0001: Expected token ';', found '{'
0:7: L0002: Undeclared variable 'gl_TexCoord'
0:8: L0002: No matching function for call to 'texture2D'
0:9: L0002: Undeclared variable 'CurrentPixelData'
0:10: L0001: Expected token ';', found '{'
0:11: L0002: Undeclared variable 'gl_FragColor'
Can anyone help me what is wrong with my code?
Thanks in advance.
You do need both a vertex shader and a fragment shader.
The syntax errors are already highlighted by the shader compilation log you captured. Providing some more detail on them:
You need to use constructor syntax to initialize vectors:
const vec3 DotValue = vec3(0.299 , 0.587, 0.114);
gl_TexCoord is not a built-in variable. You may have seen it in code samples for desktop OpenGL, where it used to exist. But it's deprecated even there, and never was present in OpenGL ES. You need to pass the texture coordinates into the shader yourself.
texture2D() is not a built-in function. The function for sampling a 2D texture used to be named like this in older GLSL version, but is now overloaded for various sampler types under the name texture():
vec4 CurrentPixelData = texture(texUnit, texCoord);
Looks like just a follow-up error from the previous one.
Same as error 1:
vec4 result = vec4(temp, temp, temp, CurrentPixelData.w);
gl_FragColor used to be a built-in variable in older GLSL versions, but is now deprecated and removed. You need to define your own variable with the qualifier out to define the variable(s) used as shader outputs.
You must write a vertex shader. gl_Position must be assigned values to create triangles and then pixels (fragments).
If you're using texture mapping, you need to assign a varying variable with the texture coordinate assigned to the vertex.
Later, these coordinates are interpolated for each fragment.
The most basic vertex shader would be:
const char* simpleVertexShader=
"attribute vec4 position;"
"attribute vec4 inputTextureCoordinate;
"varying vec2 textureCoordinate;"
"void main(){"
"gl_Position = position;"
"textureCoordinate = inputTextureCoordinate.xy;"
"}";
In you're fragment shader you have syntax error in vec3 and vec4 init.
It should be done like this:
"const vec3 DotValue = vec3(0.299 , 0.587 , 0.114);\n"
and
"vec4 result = vec4(temp,temp,temp,CurrentPixelData.w);\n"
Notice the float literals don't need the 'f' postfix in glsl.
Your fixed code:
final String src = "#version 310 es\n" +
"precision highp float;"
"uniform sampler2D texUnit;\n" +
"varying vec2 textureCoordinate" +
"void main(void)\n" +
"{\n" +
"const vec3 DotValue = vec3(0.299 , 0.587 , 0.114);\n" +
"vec2 texCoord = textureCoordinate;\n" +
"vec4 CurrentPixelData = texture2D(texUnit, texCoord);\n" +
"float temp = CurrentPixelData.x * DotValue.x + CurrentPixelData.y * DotValue.y + CurrentPixelData.z * DotValue.z;\n" +
"vec4 result = vec4(temp,temp,temp,CurrentPixelData.w);\n" +
"gl_FragColor = result;\n" +
"}\n";
It would be a lot easier for you if you start with a good openGL tutorial.
Good Luck!

How to implement simple 2D translation on OpenGL ES 2.0 using OpenTK for android

I am trying to add the translation to a simple example of drawing a triangle using OpenGL ES 2.0 for Android. I have created translation matrix with 0 translation in all directions which should be the identity matrix. When I remove the multiplication from vertex shader triangle renders fine. However when I try to add some transformation(even identity) nothing is rendered. I think it is something about sending matrix data to the shader. GL.UniformMatrix 4 only takes float as attributes and I cant convert Matrix4 to float array. At the end I desperately created float array for identity matrix and passed it using GL.UniformMAtrix4 however nothing is rendered again.
Can anyone with the experience help me out please.
Matrix4 uvMat = Matrix4.CreateTranslation(0.0f,0.0f,0.0f);
// Vertex and fragment shaders
string vertexShaderSrc = "attribute vec4 vPosition; \n" +
"uniform mat4 uvMat; \n" +
"void main() \n" +
"{ \n" +
" gl_Position = uvMat*vPosition; \n" +
"} \n";
string fragmentShaderSrc = "precision mediump float;\n" +
"void main() \n" +
"{ \n" +
" gl_FragColor = vec4 (1.0, 0.0, 0.0, 1.0); \n" +
"} \n";
int vertexShader = LoadShader (All.VertexShader, vertexShaderSrc );
int fragmentShader = LoadShader (All.FragmentShader, fragmentShaderSrc );
program = GL.CreateProgram();
if (program == 0)
throw new InvalidOperationException ("Unable to create program");
GL.AttachShader (program, vertexShader);
GL.AttachShader (program, fragmentShader);
GL.BindAttribLocation (program, 0, "vPosition");
GL.LinkProgram (program);
float[] matTrans = new float[] {1,0,0,0,
0,1,0,0,
0,0,1,0,
0,0,0,1};
int uniMatLoc = GL.GetUniformLocation (program, "uvMat");
Console.WriteLine (uniMatLoc.ToString());
GL.UniformMatrix4 (uniMatLoc, 16, false, matTrans);
The second argument to UniformMatrix4 is the number of matrices, not the number of elements in the matrix. So the call should be:
GL.UniformMatrix4(uniMatLoc, 1, false, matTrans);

Draw Pixel using OpenGLEs for Android

How can I draw a pixel(2D view)for Android using OpenGlEs?
It is simple when we use for drawing
draw(Canvas canvas)
{
...
}
So using it we draw
canvas.drawPoint(i, j, paint);
But in OpenGlEs I still haven't got any function like it.
Please reply
Thank in Advance
GLES20Renderer.programLight = GLES20.glCreateProgram();
int vertexShaderLight = GLES20Renderer.loadShader(GLES20.GL_VERTEX_SHADER, GLES20Renderer.vertexShaderCodeLight);
int fragmentShaderLight = GLES20Renderer.loadShader(GLES20.GL_FRAGMENT_SHADER, GLES20Renderer.fragmentShaderCodeLight);
GLES20.glAttachShader(GLES20Renderer.programLight, vertexShaderLight);
GLES20.glAttachShader(GLES20Renderer.programLight, fragmentShaderLight);
GLES20.glLinkProgram(GLES20Renderer.programLight);
uPLocationLight = GLES20.glGetUniformLocation(GLES20Renderer.programLight, "uP");
uVPositionLocationLight = GLES20.glGetUniformLocation(GLES20Renderer.programLight, "uVPosition");
GLES20.glUseProgram(GLES20Renderer.programLight);
GLES20.glUniform4f(uVPositionLocationLight, LightPosInEyeSpace[0], LightPosInEyeSpace[1], LightPosInEyeSpace[2], LightPosInEyeSpace[3]);
GLES20.glUniformMatrix4fv(uPLocationLight, 1, false, ProjectionMatrix, 0);
GLES20.glDrawArrays(GLES20.GL_POINTS, 0, 1);
private static final String vertexShaderCodeLight =
"uniform vec4 uVPosition; \n"
+ "uniform mat4 uP; \n"
+ "void main(){ \n"
+ " gl_PointSize = 15.0; \n"
+ " gl_Position = uP * uVPosition; \n"
+ "} \n";
private static final String fragmentShaderCodeLight =
"#ifdef GL_FRAGMENT_PRECISION_HIGH \n"
+ "precision highp float; \n"
+ "#else \n"
+ "precision mediump float; \n"
+ "#endif \n"
+ "void main(){ \n"
+ " gl_FragColor = vec4(1.0,1.0,1.0,1.0); \n"
+ "} \n";
glDrawElements(GL_POINTS, 0, num_points, point_array);
You can also use glDrawArrays if you use glVertexPointer first.
Use glPointParameter, glPointSize, and glColor to modify the appearance of the points. Using glPointSizePointer lets you specify an array of point sizes, which is handy for particle effects.

Categories

Resources