Adam P
Adam P

Reputation: 85

OpenGL ES 2.0 can't compile shaders Android

I have a problem with shader compiler in OpenGL ES 2.0. Everytime I'm trying to compile shader, it won't compile and I don't really know why. I can create shader, compiling gives me error. Here's code of my Renderer class

import android.content.Context;

import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.util.logging.Logger;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import util.LoggerConfig;
import util.ShaderHelper;
import util.TextResourceReader;

import static android.opengl.GLES20.*;
import static android.opengl.GLUtils.*;
import static android.opengl.Matrix.*;
import android.opengl.GLSurfaceView.Renderer;
import android.util.Log;

public class ProjekcikRenderer implements Renderer {

    private static final int POSITION_COMPONENT_COUNT = 2;
    private static final int BYTES_PER_FLOAT = 4;
    private final FloatBuffer vertexData;
    private final Context context;
    private int program;
    private static final String U_COLOR = "u_COLOR";
    private int uColorLocation;
    private static final String A_POSITION = "a_Position";
    private int aPositionLocation;
    private static final String TAG = "ProjekcikRenderer";

    public ProjekcikRenderer(Context context){
        this.context = context;
        float[] tableVertices = {
            0f, 0f,
            1f, 1f,
            0f, 1f,

            0f, 0f,
            1f, 0f,
            1, 1f
        };

        vertexData = ByteBuffer
                .allocateDirect(tableVertices.length * BYTES_PER_FLOAT)
                .order(ByteOrder.nativeOrder())
                .asFloatBuffer();

        vertexData.put(tableVertices);
    }

    @Override
    public void onSurfaceCreated(GL10 glUnused, EGLConfig config){
        glClearColor(1.0f, 1.0f, 0.5f, 0.0f);
        String vertexShaderSource = null;
        String fragmentShaderSource = null;
        try{
            vertexShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.simple_vertex_shader);
            fragmentShaderSource = TextResourceReader.readTextFileFromResource(context, R.raw.simple_fragment_shader);
        } catch (IOException e){
            throw new RuntimeException("IOException", e);
        } catch (Exception e){
            throw new RuntimeException("Other Exception", e);
        }

        //int vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource);
        int vertexShader = glCreateShader(GL_VERTEX_SHADER);
        Log.d(TAG, "CREATING VERTEX SHADER");
        String s = new String(Integer.toString(vertexShader));
        if(vertexShader == 0){
            if(LoggerConfig.ON){
                Log.w(TAG, "Could not create new VERTEX shader");
            }
            return;
        } else {
            if(LoggerConfig.ON){
                Log.w(TAG, s);
            }
        }
        glShaderSource(vertexShader, vertexShaderSource);
        final int[] compileStatus = new int[1];
        glGetShaderiv(vertexShader, GL_COMPILE_STATUS, compileStatus, 0);
        if(LoggerConfig.ON){
            Log.v(TAG, "Results of compiling source:" + "\n" + vertexShaderSource + "\n" + glGetShaderInfoLog(vertexShader));
        }
        if(compileStatus[0] == 0){
            glDeleteShader(vertexShader);
            if(LoggerConfig.ON){
                Log.w(TAG, "Compilation of shader failed");
            }
            return;
        }
        int fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
        program = linkProgram(vertexShader, fragmentShader);

        if(LoggerConfig.ON){
            validateProgram(program);
        }

        glUseProgram(program);

        uColorLocation = glGetUniformLocation(program, U_COLOR);
        aPositionLocation = glGetAttribLocation(program, A_POSITION);
        vertexData.position(0);
        glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GL_FLOAT, false, 0, vertexData);
        glEnableVertexAttribArray(aPositionLocation);




    }

    @Override
    public void onSurfaceChanged(GL10 glUnused, int width, int height){
        glViewport(0, 0, width, height);
    }

    @Override
    public void onDrawFrame(GL10 glUnused){
        glClear(GL_COLOR_BUFFER_BIT);
        glUniform4f(uColorLocation, 0.0f, 0.0f, 0.0f, 1.0f);
        glDrawArrays(GL_TRIANGLES, 0, 6);
    }

    public static int compileVertexShader(String shaderCode){
        return compileShader(GL_VERTEX_SHADER, shaderCode);
    }

    public static int compileFragmentShader(String shaderCode){
        return compileShader(GL_FRAGMENT_SHADER, shaderCode);
    }

    private static int compileShader(int type, String shaderCode){
        final int shaderObjectId = glCreateShader(type);
        String s = new String(Integer.toString(type));

        if(shaderObjectId == 0){
            if(LoggerConfig.ON){
                Log.w(TAG, "Could not create new shader");
            }
            return 0;
        } else {
            if(LoggerConfig.ON){
                Log.w(TAG, s);
            }
        }
        glShaderSource(shaderObjectId, shaderCode);
        final int[] compileStatus = new int[1];
        glGetShaderiv(shaderObjectId, GL_COMPILE_STATUS, compileStatus, 0);
        if(LoggerConfig.ON){
            Log.v(TAG, "Results of compiling source:" + "\n" + shaderCode + "\n" + glGetShaderInfoLog(shaderObjectId));
        }
        if(compileStatus[0] == 0){
            glDeleteShader(shaderObjectId);
            if(LoggerConfig.ON){
                Log.w(TAG, "Compilation of shader failed");
            }
            return 0;
        }
        return shaderObjectId;
    }

    public static int linkProgram (int vertexShaderId, int fragmentShaderId){
        final int programObjectId = 0;

        glAttachShader(programObjectId, vertexShaderId);
        glAttachShader(programObjectId, fragmentShaderId);
        glLinkProgram(programObjectId);
        if(programObjectId == 0){
            if(LoggerConfig.ON){
                Log.w(TAG, "Could not create new program");
            }
            return 0;
        }
        final int[] linkStatus = new int[1];
        glGetProgramiv(programObjectId, GL_LINK_STATUS, linkStatus, 0);
        if(LoggerConfig.ON){
            Log.v(TAG, "Results of linking program:\n" + glGetProgramInfoLog(programObjectId));
        }
        if(linkStatus[0] == 0){
            glDeleteProgram(programObjectId);
            if(LoggerConfig.ON){
                Log.w(TAG, "Linking of program failed");
            }
            return 0;
        }
        return programObjectId;
    }

    public static boolean validateProgram(int programObjectId){
        glValidateProgram(programObjectId);

        final int[] validateStatus = new int[1];
        glGetProgramiv(programObjectId, GL_VALIDATE_STATUS, validateStatus, 0);
        Log.v(TAG, "Results of validating program: " + validateStatus[0] + "\nLog: " + glGetProgramInfoLog(programObjectId));
        return validateStatus[0] != 0;
    }

}

and here's my vertex shader

attribute vec4 a_Position;

void main(){
    gl_Position = a_Position;
}

And logs

08-12 09:26:46.350    1281-1281/pl.projekcik D/libEGL﹕ loaded /system/lib/egl/libEGL_mali.so
08-12 09:26:46.350    1281-1281/pl.projekcik D/libEGL﹕ loaded /system/lib/egl/libGLESv1_CM_mali.so
08-12 09:26:46.350    1281-1281/pl.projekcik D/libEGL﹕ loaded /system/lib/egl/libGLESv2_mali.so
08-12 09:26:46.370    1281-1281/pl.projekcik D/OpenGLRenderer﹕ Enabling debug mode 0
08-12 09:26:46.400    1281-1308/pl.projekcik D/ProjekcikRenderer﹕ CREATING VERTEX SHADER
08-12 09:26:46.400    1281-1308/pl.projekcik W/ProjekcikRenderer﹕ 1
08-12 09:26:46.400    1281-1308/pl.projekcik V/ProjekcikRenderer﹕ Results of compiling source:
    attribute vec4 a_Position;
    void main(){
    gl_Position = a_Position;
    }
08-12 09:26:46.400    1281-1308/pl.projekcik W/ProjekcikRenderer﹕ Compilation of shader failed
08-12 09:26:46.430    1281-1283/pl.projekcik D/dalvikvm﹕ GC_CONCURRENT freed 225K, 8% free 6284K/6791K, paused 12ms+5ms, total 44ms

Any help would be greatly appreciated. I was using Kevin Brothael's book OpenGL ES 2 for Android, since it's my first time with OpenGL.

EDIT I'm using Android 4.1.1 on Prestigio PMP7880D3G with some "Quad Core GPU". But almost same code (functions used for shader compiling were in additional class ShaderHelper) code didn't work on Android 5.0.2 running on Xperia Z1 Compact.

Upvotes: 1

Views: 4313

Answers (2)

Gil Moshayof
Gil Moshayof

Reputation: 16761

You're missing a call to GLES20.glCompileShader(vertexShader) after you call glShaderSource()

Try to fix your code here:

glShaderSource(vertexShader, vertexShaderSource);
glCompileShader(vertexShader); // <-- this line is missing.

// Now see if the compilation worked.
int[] compiled = new int[1];
glGetShaderiv(vertexShader, GLES20.GL_COMPILE_STATUS, compiled, 0);

if (compiled[0] == 0)
{
    // Handle errors with shader compilation.
}

Here is a code stub I use to generate programs in OpenGL-ES 2.0:

private int loadShader(String strSource, int iType)
    {
        int[] compiled = new int[1];
        int iShader = GLES20.glCreateShader(iType);
        GLES20.glShaderSource(iShader, strSource);
        GLES20.glCompileShader(iShader);
        GLES20.glGetShaderiv(iShader, GLES20.GL_COMPILE_STATUS, compiled, 0);
        if (compiled[0] == 0) {
            Log.d("Load Shader Failed", "Compilation\n" + GLES20.glGetShaderInfoLog(iShader));
            return 0;
        }
        return iShader;
    }

    public int loadProgram(String strVSource, String strFSource)
    {
        int iVShader;
        int iFShader;
        int iProgId;
        int[] link = new int[1];
        iVShader = loadShader(strVSource, GLES20.GL_VERTEX_SHADER);
        if (iVShader == 0)
        {
            Log.d("Load Program", "Vertex Shader Failed");
            return 0;
        }
        iFShader = loadShader(strFSource, GLES20.GL_FRAGMENT_SHADER);
        if(iFShader == 0)
        {
            Log.d("Load Program", "Fragment Shader Failed");
            return 0;
        }

        iProgId = GLES20.glCreateProgram();

        GLES20.glAttachShader(iProgId, iVShader);
        GLES20.glAttachShader(iProgId, iFShader);

        GLES20.glLinkProgram(iProgId);

        GLES20.glGetProgramiv(iProgId, GLES20.GL_LINK_STATUS, link, 0);
        if (link[0] <= 0) {
            Log.d("Load Program", "Linking Failed");
            return 0;
        }
        GLES20.glDeleteShader(iVShader);
        GLES20.glDeleteShader(iFShader);
        return iProgId;
    }

Upvotes: 3

mstorsjo
mstorsjo

Reputation: 13317

First off, are you sure that the rendering context is set up for ES 2.0? If you're using a GLSurfaceView, it will default to ES 1.1 unless something else is requested, but that part of the code isn't included here (although it does seem to be set up right based on the log).

Secondly, contrary to GLSL shaders for desktop OpenGL, variables in shaders in GL ES need to specify the precision. So where you have attribute vec4 a_Position; you need to specify it as e.g. attribute highp vec4 a_Position;. This should hopefully be enough for this particular simple vertex shader to compile.

Upvotes: 0

Related Questions