Basic Image Compute shader

Hi,

I am tryng to use Compute shader to create texture image. I read quite a lot of tutorial and forum. But i still got trouble to anderstand the processing and how correctly implement it on
android mobile phonne with ARM mali G72 GPU.

The goal is to feed the texture color using compute shader and than display the output image texture created using imageStore in fragment shader for display.

So i initialize the texture like this :

tex_output = new int[1];
GLES20.glGenTextures(1, tex_output,0);
checkGlError();
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
checkGlError();
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tex_output[0]);
checkGlError();
GLES31.glTexStorage2D(GLES20.GL_TEXTURE_2D, 1, GLES31.GL_RGBA8, 256, 256);
checkGlError();
GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
checkGlError(); 

i am using this compute shader :

  "#version 320 es",

  "layout(local_size_x = 16, local_size_y = 16) in;",
  "layout(rgba8, binding = 0) uniform writeonly highp image2D img_output;",
  //"layout(rgba32f,location = 0, binding = 0) writeonly uniform highp image2D img_output;",

  "void main() {",
      // gl_LocalInvocationID.xy * gl_WorkGroupID.xy == gl_GlobalInvocationID
  "    ivec2 coords = ivec2(gl_GlobalInvocationID.xy);",

      // Pour mettre en evidence. Les groupes de travail locaux on dessine un damier.
  "    vec4 pixel;",
  "    if ( ((gl_WorkGroupID.x & 1u) != 1u) != ((gl_WorkGroupID.y & 1u) == 1u)) {",
  "      pixel = vec4(0.0,1.0,0.0,1.0);",
  "    }else {",
  "      pixel = vec4(0.0,0.0,1.0,1.0);",
  "    }",
  "    imageStore(img_output, coords, pixel);",
  "}"

for the rendering i use the compute program :

GLES20.glUseProgram(programComp);

GLES31.glBindImageTexture(0, tex_output[0], 0, false, 0, GLES31.GL_WRITE_ONLY, GLES31.GL_RGBA8);

Log.e(TAG, "     glDispatchCompute ");
GLES31.glDispatchCompute(16,16,1);

Log.e(TAG, "     glMemoryBarrier ");
GLES31.glMemoryBarrier( GLES31.GL_SHADER_IMAGE_ACCESS_BARRIER_BIT);

and the vertex/fragment shader program inside the same glDraw() function :

GLES20.glUseProgram(program);

GLES20.glEnableVertexAttribArray(positionHandle);
GLES20.glEnableVertexAttribArray(textureCoordsHandle);

GLES20.glUniform1i(textureHandle, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, tex_output[0]);

GLES20.glUniformMatrix4fv(mvpMatrixHandle, 1, false, mMVPMatrix, 0);
// Load position data.
vertexBuffer.position(0);
GLES20.glVertexAttribPointer(positionHandle, POSITION_COORDS_PER_VERTEX, GLES20.GL_FLOAT,
                             false, VERTEX_STRIDE_BYTES, vertexBuffer);
// Load texture data.
vertexBuffer.position(POSITION_COORDS_PER_VERTEX);
GLES20.glVertexAttribPointer(textureCoordsHandle, TEXTURE_COORDS_PER_VERTEX, GLES20.GL_FLOAT,
                             false, VERTEX_STRIDE_BYTES, vertexBuffer);
// Render.
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, vertexData.length / COORDS_PER_VERTEX);

GLES20.glDisableVertexAttribArray(positionHandle);
GLES20.glDisableVertexAttribArray(textureCoordsHandle);

vertex shader :

  "uniform mat4 uMvpMatrix;",

  // 3D position data.
  "attribute vec3 aPosition;",
  // 2D UV vertices.
  "attribute vec2 aTexCoords;",

  "varying vec2 vTexCoords;",
  "varying vec2 vCoords2;",
  "vec2 vCoords;",

  // Standard transformation.
  "void main() {",
      "  gl_Position = uMvpMatrix * vec4(aPosition, 1.0);",
      "  vTexCoords = aTexCoords;",
      "  vCoords  = aPosition.xy / vec2(" + SIZE + ", " + SIZE + ");",
      "  vCoords2 = vec4(vCoords,1.0,1.0).xy;",
  "}"

fragment shader :

  "precision mediump float;",

  // Standard texture rendering shader with extra alpha channel.
  "uniform sampler2D uTexture;",

  "varying vec2 vTexCoords;",
  "varying vec2 vCoords2;",

  "void main() {",
      // Simple ring shader that is white between the radii and transparent elsewhere.
      "  float r = length(vCoords2);",
      // Blend the edges of the ring at .55 +/- .05 and .85 +/- .05.
      "  float alpha = smoothstep(0.25, 0.3, r) * (1.0 - smoothstep(0.8, 0.9, r));",
      "  vec4  reticle = alpha * vec4(0.0,1.0,0.0,1.0);",
      "  gl_FragColor = texture2D(uTexture, vTexCoords)*0.75 + reticle;",
  "}"

So i can see my reticule displayed, that for i use it ;)). But nothing else, the texture is transparent.

if i use internalformat GL_RGBA32F insted of GL_RGBA8 and if i remove the

GLES20.glGenerateMipmap(GLES20.GL_TEXTURE_2D);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D,GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

I can get a black transparent texture displayed ?

I spend the all day yestaday tryng to make it work whitout succes. And i still not anderstand the process of image compute shader.

For me it is a way to read,write, modified texture using compute shader. So we do not need to retreive the texture data to CPU to do modification. Modification are made directly on the openGL texture object. So no need to read to CPU memorie do the modification and than send it back to the GPU.

Thanks in advance for the help.

This should be GL_TEXTURE_FETCH_BARRIER_BIT. The flags describe how the memory will be accessed after the barrier.

Other than that: do you check the compilation and linking status? Those processes don’t generate errors (in the sense of glGetError) for invalid code.

hi,

here is my create compute shader function. can be usefull for other ;))

  public static int CompileComputeShader(String[] computeCode){
  // prepare shaders and OpenGL program
  int ComputeShader = GLES20.glCreateShader(GLES31.GL_COMPUTE_SHADER);
  if (ComputeShader == 0){
      Log.e(TAG,"glCreateComputeShader ERROR "+ComputeShader);
  }else{
      Log.e(TAG,"glCreateComputeShader SUCCES "+ComputeShader);
  }
  checkGlError();
  GLES20.glShaderSource(ComputeShader, TextUtils.join("\n", computeCode));
  checkGlError();
  GLES20.glCompileShader(ComputeShader);
  int[] compiled = new int[1];
  GLES20.glGetShaderiv(ComputeShader, GLES20.GL_COMPILE_STATUS, compiled, 0);
  if (compiled[0] == 0) {
      Log.e(TAG, "Could not compile shader GL_COMPUTE_SHADER ");
      Log.e(TAG, GLES20.glGetShaderInfoLog(ComputeShader));
      GLES20.glDeleteShader(ComputeShader);
  }else{
      Log.e(TAG, "Compile shader GL_COMPUTE_SHADER SUCCES "+compiled[0]);
  }
  checkGlError();

  int program = GLES20.glCreateProgram();
  checkGlError();
  GLES20.glAttachShader(program, ComputeShader);
  checkGlError();

  // Link and check for errors.
  GLES31.glLinkProgram(program);
  int[] link = new int[1];
  GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, link, 0);
  if (link[0] == 0) {
      Log.e(TAG, "Could not link shader GL_COMPUTE_SHADER ");
      Log.e(TAG, GLES20.glGetProgramInfoLog(program));
      GLES20.glDeleteShader(ComputeShader);
  }else{
      Log.e(TAG, "link shader GL_COMPUTE_SHADER SUCCES "+link[0]);
  }
  checkGlError();

  GLES20.glDeleteShader(ComputeShader);

  return program;

}

Thank again ;)). My image compute shader is not linked succefully. I used to check compilation but never linkage, oups ;))

So i think this is the problem. The image compute shader i never excecuted.

Do you know the problem ?

Ok i have found the error ;))

Max number of total work group invocations exceeded

So the problem is solve ;)) ;)) thanks again GClements ;))

By the way:
GL_SHADER_IMAGE_ACCESS_BARRIER_BIT and GL_TEXTURE_FETCH_BARRIER_BIT

Both are working on my phonne.

Stupid error of beginer ;)) Aniway the code may be usefull for other ;))