OpenGL 2.0 glGetUniformLocation:draw()中的glError 1282

时间:2015-12-12 13:02:54

标签: java android opengl-es

我已经制作了一个游戏,可以正确地绘制openGL形状,以便在大部分游戏中进行屏幕显示。但由于某种原因,在游戏中随机间隔我得到了1282 glGetUniformLocation错误。奇怪的是,它有效一段时间却失败了吗?

这是堆栈跟踪

class A{ int i = 1; public: A():i{1}{} };

int main()
{
    constexpr A a{};
}

这是在Shape.java draw()函数中生成错误(我认为)的部分。

Shape.java

12-12 12:31:54.781: E/AndroidRuntime(2531): FATAL EXCEPTION: GLThread 86993
12-12 12:31:54.781: E/AndroidRuntime(2531): Process: com.laytonlabs.android.levelup, PID: 2531
12-12 12:31:54.781: E/AndroidRuntime(2531): java.lang.RuntimeException: glGetUniformLocation: glError 1282
12-12 12:31:54.781: E/AndroidRuntime(2531):     at com.laytonlabs.android.levelup.MyGLRenderer.checkGlError(MyGLRenderer.java:460)
12-12 12:31:54.781: E/AndroidRuntime(2531):     at com.laytonlabs.android.levelup.shapes.Shape.draw(Shape.java:240)
12-12 12:31:54.781: E/AndroidRuntime(2531):     at com.laytonlabs.android.levelup.MyGLRenderer.drawShapes(MyGLRenderer.java:350)
12-12 12:31:54.781: E/AndroidRuntime(2531):     at com.laytonlabs.android.levelup.MyGLRenderer.drawFixedShapes(MyGLRenderer.java:324)
12-12 12:31:54.781: E/AndroidRuntime(2531):     at com.laytonlabs.android.levelup.MyGLRenderer.onDrawFrame(MyGLRenderer.java:205)
12-12 12:31:54.781: E/AndroidRuntime(2531):     at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1531)
12-12 12:31:54.781: E/AndroidRuntime(2531):     at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1248)

以下是错误堆栈中引用的java类的完整代码。

MyGLRenderer.java

mMVPMatrixHandle = GLES20.glGetUniformLocation(mProgram, "uMVPMatrix");
MyGLRenderer.checkGlError("glGetUniformLocation");

Shape.java

package com.laytonlabs.android.levelup;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

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

import com.laytonlabs.android.levelup.game.Cell;
import com.laytonlabs.android.levelup.game.CurrentAnswer;
import com.laytonlabs.android.levelup.game.Equation;
import com.laytonlabs.android.levelup.game.Game;
import com.laytonlabs.android.levelup.game.Level;
import com.laytonlabs.android.levelup.game.Score;
import com.laytonlabs.android.levelup.game.Stage;
import com.laytonlabs.android.levelup.game.Time;
import com.laytonlabs.android.levelup.shapes.Color;
import com.laytonlabs.android.levelup.shapes.EquationRectangle;
import com.laytonlabs.android.levelup.shapes.Hexagon;
import com.laytonlabs.android.levelup.shapes.InputSquare;
import com.laytonlabs.android.levelup.shapes.Shape;
import com.laytonlabs.android.levelup.shapes.StatsRectangle;

import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.util.Log;

public class MyGLRenderer implements GLSurfaceView.Renderer {

    private static final String TAG = "MyGLRenderer";
    private static StatsRectangle levelRectangle;
    private static StatsRectangle timeRectangle;
    private static StatsRectangle scoreRectangle;
    private static EquationRectangle equationRectangle;
    private static EquationRectangle answerRectangle;
    private ArrayList<Shape> gridShapes;
    private ArrayList<Shape> bottomRowShapes;
    private static ArrayList<Shape> inputShapes;

    // mMVPMatrix is an abbreviation for "Model View Projection Matrix"
    private final float[] mMVPMatrix = new float[16];
    private final float[] mMVPFixed = new float[16];
    private final float[] mProjectionMatrix = new float[16];
    private final float[] mViewMatrix = new float[16];
    private final float[] mGridModelMatrix = new float[16];
    private float[] mFixedModelMatrix = new float[16];
    private float[] mTempMatrix = new float[16];

    private float mMovementY;
    private float mBottomRowScale; 
    private static String mAnswerText = CurrentAnswer.getLabel();
    private boolean isCorrectGuess = false;
    private boolean renderCorrectGuess = false;
    private boolean isWrongGuess = false;
    private boolean renderOutput = false;

    //To limit the number of renders per second
    private long startTime;
    private long endTime;
    private long timeElapsed;
    private int currentFrame = 0;              // active frame
    private int outputCurrentFrame = 0;              // active frame
    private final int FPS = 33;                // Frames per second
    private final int FPS_ANIMATION_10 = 10;
    private final int FPS_ANIMATION_20 = 20;

    //Reducer values, these are used for animation scenes
    private float mFPSMovementY;
    private float mFPSBottomRowScale;

    private int gridLevel = 0; //The cell layout level in the grid.
    private int rowLevel = 1; //The current row in the grid user is selected.

    //Constants for grid presentation 
    private final float CELL_SCALE = 0.3f;
    private final float CELL_OFFSET_Y = 0.7f;

    @Override
    public void onSurfaceCreated(GL10 unused, EGLConfig config) {

        // Set the background frame color
        GLES20.glClearColor(Color.DARK_GREY[0], Color.DARK_GREY[1], Color.DARK_GREY[2], Color.DARK_GREY[3]);

        startTime = System.currentTimeMillis();

        //TODO Add code that sets current answer to whatever the current answer is.

        //Initialise fixed shapes
        equationRectangle = new EquationRectangle(-0.35f);
        answerRectangle = new EquationRectangle(-0.5f);

        equationRectangle.setShapes(0.2f, Equation.get());
        answerRectangle.setShapes(0.3f, mAnswerText);

        //TODO - Change the below calculations to be align_left, align_centre, align_right, etc.
        levelRectangle = new StatsRectangle(0 - (Screen.DEFAULT_WIDTH/3), Color.TURQUOISE, Color.TURQUOISE);
        timeRectangle = new StatsRectangle(0, Color.PURPLE, Color.PURPLE);
        scoreRectangle = new StatsRectangle(0 + (Screen.DEFAULT_WIDTH/3), Color.TURQUOISE, Color.TURQUOISE);

        levelRectangle.setShapes(-1f, Level.getLabel());
        scoreRectangle.setShapes(-1f, Score.getScoreLabel());
        timeRectangle.setShapes(-1f, Time.getTimeRemainingLabel());

        setGridShapes();
        //Complete the bottom row for inputting guesses
        bottomRowShapes = new ArrayList<Shape>();
        setBottomRowShapes();
        buildInputGrid();
        setBottomRowScale(1.0f);
        setFPSBottomRowScale(getBottomRowScale() / FPS_ANIMATION_20);
        setFPSMovementY((CELL_OFFSET_Y*CELL_SCALE) / FPS_ANIMATION_20);
    }

    private void buildInputGrid() {
        inputShapes = new ArrayList<Shape>();

        inputShapes.add(new InputSquare(0.16f, -3.0f, 1.15f, "1")); //1
        inputShapes.add(new InputSquare(0.16f, -1.8f, 1.15f, "2")); //2
        inputShapes.add(new InputSquare(0.16f, -0.6f, 1.15f, "3")); //3
        inputShapes.add(new InputSquare(0.16f,  0.6f, 1.15f, "4")); //4
        inputShapes.add(new InputSquare(0.16f,  1.8f, 1.15f, "5")); //5
        inputShapes.add(new InputSquare(0.16f,  3.0f, 1.15f, "6")); //6
        inputShapes.add(new InputSquare(0.16f, -2.4f,     0, "7")); //7
        inputShapes.add(new InputSquare(0.16f, -1.2f,     0, "8")); //8
        inputShapes.add(new InputSquare(0.16f,     0,     0, "9")); //9
        inputShapes.add(new InputSquare(0.16f,  1.2f,     0, "0")); //0
        inputShapes.add(new InputSquare(0.16f,  2.4f,     0, "x")); //X - This is to clear input
    }

    @Override
    public void onDrawFrame(GL10 unused) {

        //We dont need continuous rendering, only needed for animation and time switching
        endTime = System.currentTimeMillis();
        timeElapsed = endTime - startTime;
        if (timeElapsed < FPS) {
            try {
                Log.d(TAG, "Sleeping until "+FPS+" millsecs pass");
                Thread.sleep(FPS - timeElapsed);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        startTime = endTime;

        //Update the timers by deducting timeRemaining
        Time.update();

        Matrix.setIdentityM(mGridModelMatrix, 0); // initialize to identity matrix
        //Setup the equation display before we start moving the grid around
        Matrix.setIdentityM(mFixedModelMatrix, 0); // initialize to identity matrix

        // Draw background color
        GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);

        // Enable transparency options for colors.
        GLES20.glEnable(GLES20.GL_BLEND);
        GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);

        // Set the camera position (View matrix)
        Matrix.setLookAtM(mViewMatrix, 0, 0, 0, 3, 0f, 0f, 0f, 0f, 1.0f, 0.0f);

        // Calculate the projection and view transformation
        Matrix.multiplyMM(mMVPMatrix, 0, mProjectionMatrix, 0, mViewMatrix, 0);

        //Clone this for use with fixed and grid MVPs
        mTempMatrix = mMVPMatrix.clone();

        // Create a rotation for the triangle

        // Use the following code to generate constant rotation.
        // Leave this code out when using TouchEvents.
        // long time = SystemClock.uptimeMillis() % 4000L;
        // float angle = 0.090f * ((int) time);

        drawGridShapes();

        drawFixedShapes();
    }

    private void drawGridShapes() {     
        //Start the grid drawing at bottom of screen.
        Matrix.translateM(mGridModelMatrix, 0, 0, -0.1f, 0);

        //Move the grid down or up the screen depending on touch events.
        Matrix.translateM(mGridModelMatrix, 0, 0, mMovementY, 0);

        // Combine the rotation matrix with the projection and camera view
        // Note that the mMVPMatrix factor *must be first* in order
        // for the matrix multiplication product to be correct.
        //Matrix.multiplyMM(scratch, 0, mMVPMatrix, 0, mRotationMatrix, 0);

        //Add the movement to the matrix
        Matrix.multiplyMM(mMVPMatrix, 0, mTempMatrix, 0, mGridModelMatrix, 0);

        if (isCorrectGuess()) {
            renderCorrectGuess = true; //This is to change the answer text to green inside drawFixedShapes
            currentFrame++;                    // step to next frame
            setMovementY(getMovementY() - getFPSMovementY());
            setBottomRowScale(getBottomRowScale() - getFPSBottomRowScale());
            if (currentFrame >= FPS_ANIMATION_20) {            // if end of sequence
                currentFrame = 0;               // restart sequence
                setBottomRowScale(1.0f);        // Reset the scale
                removeBottomRow();
                setCorrectGuess(false);         //Mark as false so animation stops and user can make new guess
            }
        }

        //Draw all grid shapes
        if (isCorrectGuess()) {
            drawAllShapesAndShrinkBottomRow(mMVPMatrix);
        } else {
            drawAllShapes(getGridShapes(), mMVPMatrix);
        }
    }

    private void drawAllShapes(ArrayList<Shape> shapes, float[] mMVPMatrix) {
        for (Shape shape : shapes) {
            Log.d(TAG, "Scale Hexagon ("+shape.toString()+") Aft ("+shape.getCentreX()+", "+shape.getCentreY()+")");
            drawShapes(shape, mMVPMatrix);
        }
    }

    private void drawAllShapesAndShrinkBottomRow(float[] mMVPMatrix) {
        float[] mMVPScaled = mMVPMatrix.clone();

        Matrix.scaleM(mMVPScaled, 0, getBottomRowScale(), getBottomRowScale(), 0);

        int lastCellIndex = getBottomRowLastCellIndex();

        //Apply scaling to the bottom row and just move the other rows.
        for (int i = 0; i < getGridShapes().size(); i++) {
            if (i <= lastCellIndex) {
                drawShapes(getGridShapes().get(i), mMVPScaled);
            } else {
                drawShapes(getGridShapes().get(i), mMVPMatrix);
            }
        }
    }

    private void drawFixedShapes() {

        Matrix.multiplyMM(mMVPFixed, 0, mTempMatrix, 0, mFixedModelMatrix, 0);

        if (isRenderOutput()) {
            //Show the equation using the values from the selected cell.
            equationRectangle.setShapes(0.2f, Equation.get());
            answerRectangle.setShapes(0.3f, mAnswerText);

            setRenderOutput(false);
        }

        //Update the time if time has changed
        if (!timeRectangle.toString().equals(Time.getTimeRemainingLabel())) {
            //If the time remaining is almost up then change text to red.
            if (Time.isTimeAlmostUp()) {
                timeRectangle.setShapes(-1f, Time.getTimeRemainingLabel(), Color.RED);
            } else {
                timeRectangle.setShapes(-1f, Time.getTimeRemainingLabel());
            }
        }

        //Animation for changing color of the text
        if (isWrongGuess()) {
            if (outputCurrentFrame == 0) {
                answerRectangle.setShapes(0.3f, mAnswerText, Color.RED);
            }
            outputCurrentFrame++;
            if (outputCurrentFrame >= FPS_ANIMATION_10) {
                outputCurrentFrame = 0;
                setAnswerText("");
                answerRectangle.setShapes(0.3f, mAnswerText);
                setWrongGuess(false);           
            }
        } else if (renderCorrectGuess) {
            if (outputCurrentFrame == 0) {
                answerRectangle.setShapes(0.3f, mAnswerText, Color.GREEN);
                levelRectangle.setShapes(-1f, Level.getLabel(), Color.YELLOW);
                scoreRectangle.setShapes(-1f, Score.getScoreLabel(), Color.YELLOW);
                timeRectangle.setShapes(-1f, Time.getTimeRemainingLabel(), Color.YELLOW);
            }
            outputCurrentFrame++;
            if (outputCurrentFrame >= FPS_ANIMATION_20) {
                outputCurrentFrame = 0;
                answerRectangle.setShapes(0.3f, mAnswerText);
                levelRectangle.setShapes(-1f, Level.getLabel());
                scoreRectangle.setShapes(-1f, Score.getScoreLabel());
                timeRectangle.setShapes(-1f, Time.getTimeRemainingLabel());
                setGridShapes();
                renderCorrectGuess = false;     
            }
        }

        drawShapes(answerRectangle, mMVPFixed);
        drawShapes(equationRectangle, mMVPFixed);
        drawShapes(levelRectangle, mMVPFixed);
        drawShapes(timeRectangle, mMVPFixed);
        drawShapes(scoreRectangle, mMVPFixed);

        //Draw all input grid shapess
        drawAllShapes(inputShapes, mMVPFixed);
    }

    public static void printStack() {
        Log.e(TAG,"Level: " + Level.getLabel());
        Log.e(TAG,"Score: " + Score.getScoreLabel());
        Log.e(TAG,"Time: " + Time.getTimeRemainingLabel());
        Log.e(TAG,"mAnswerText: " + mAnswerText);
        Log.e(TAG,"Equation: " + Equation.get());
        for (int i = 0; i < inputShapes.size(); i++) {
            Log.e(TAG,"inputShapes[" + i + "]: " + inputShapes.get(i).toString());
        }
    }

    private void drawShapes(Shape parentShape, float[] mMVPMatrix) {
        parentShape.draw(mMVPMatrix);

        if (parentShape.getShapes() == null) {
            return;
        }

        for (Shape nestedShapes : parentShape.getShapes()) {
            nestedShapes.draw(mMVPMatrix);
        }
    }

    private ArrayList<Shape> getGridShapes() {
        return gridShapes;
    }

    private int getBottomRowLastCellIndex() {
        int lastCellIndex = 0;
        Shape prevShape = null;
        for (int i = 0; i < getGridShapes().size(); i++) {
            if (prevShape == null || getGridShapes().get(i).getCentreY() == prevShape.getCentreY()) {
                lastCellIndex = i;
                prevShape = getGridShapes().get(i);
            } else {
                return lastCellIndex;
            }
        }
        return lastCellIndex;
    }

    private void removeBottomRow() {
        for (int i = getBottomRowLastCellIndex(); i >= 0 ; i--) {
            getGridShapes().remove(i);
        }
        //Reset the bottom row shapes
        setBottomRowShapes();
    }

    public ArrayList<Shape> getBottomRowShapes() {
        return bottomRowShapes;
    }

    private void setBottomRowShapes() {
        ArrayList<Shape> tempRowShapes = new ArrayList<Shape>();

        //Apply scaling to the bottom row and just move the other rows.
        for (int i = 0; i <= getBottomRowLastCellIndex(); i++) {
            tempRowShapes.add(getGridShapes().get(i));
        }
        bottomRowShapes = tempRowShapes;
    }

    @Override
    public void onSurfaceChanged(GL10 unused, int width, int height) {
        // Adjust the viewport based on geometry changes,
        // such as screen rotation
        GLES20.glViewport(0, 0, width, height);

        //Log.d("MyGLRenderer", "Width: " + width + " Height: " + height);

        float ratio = (float) width / height;

        Log.d("Screen","Width: "+ width +" - Height: "+ height +" - Ratio: "+ ratio);

        // this projection matrix is applied to object coordinates
        // in the onDrawFrame() method
        if (ratio > 1) {
            ratio = Screen.DEFAULT_LANDSCAPE_RATIO;
        } else {
            ratio = Screen.DEFAULT_PORTRAIT_RATIO;
        }

        Matrix.frustumM(mProjectionMatrix, 0, -ratio, ratio, -1, 1, 3, 7);

        //TODO Store the current answer, the current answer Text and the current Equation. 
    }

    public static int loadShader(int type, String shaderCode){

        // create a vertex shader type (GLES20.GL_VERTEX_SHADER)
        // or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
        int shader = GLES20.glCreateShader(type);

        // add the source code to the shader and compile it
        GLES20.glShaderSource(shader, shaderCode);
        GLES20.glCompileShader(shader);

        return shader;
    }

    public static void checkGlError(String glOperation) {
        int error;
        while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
            Log.e(TAG, glOperation + ": 1glError " + error);
            printStack();
            //TODO - Print out the fixed shapes values to see if something wierd is being displayed after a while.
            throw new RuntimeException(glOperation + ": glError " + error);
        }
    }

    public float getMovementY() {
        return mMovementY;
    }

    public void setMovementY(float movementY) {
        mMovementY = movementY;
    }

    public float[] getProjectionMatrix() {
        return mProjectionMatrix;
    }

    public float[] getGridModelMatrix() {
        return mGridModelMatrix;
    }

    public float[] getFixedModelMatrix() {
        return mFixedModelMatrix;
    }

    public String getAnswerText() {
        return mAnswerText;
    }

    public void setAnswerText(String guessInput) {
        if (guessInput == "") {
            this.mAnswerText = getInputUnderscores();
            return;
        }

        this.mAnswerText = this.mAnswerText.replaceFirst("_", guessInput);
    }

    public void resetAnswerText() {
        this.mAnswerText = CurrentAnswer.getLabel();
    }

    private String getInputUnderscores() {
        if (Equation.getExpectedAnswer() <= 0) {
            return "";
        }

        return Equation.getExpectedAnswerLabel().replaceAll("[0-9]", "_");
    }

    public ArrayList<Shape> getInputShapes() {
        return inputShapes;
    }

1 个答案:

答案 0 :(得分:2)

glGetUniformLocation会发出GL_INVALID_OPERATION错误的原因只有两个:因为程序不是程序对象,或者因为它没有成功链接。

我看不到你实际上test whether glLinkProgram was successful的代码。您永远不会调用glGetProgramiv(program, GL_LINK_STATUS)来测试程序是否正确链接。显然,链接在某些时候失败了。

错误处理的一般代码(在C ++中)将是:

//Link the program.
glLinkProgram(program);

GLint isLinked = 0;
glGetProgramiv(program, GL_LINK_STATUS, &isLinked);
if(isLinked == GL_FALSE)
{
    GLint maxLength = 0;
    glGetProgramiv(program, GL_INFO_LOG_LENGTH, &maxLength);

    //The maxLength includes the NULL character
    std::vector<GLchar> infoLog(maxLength);
    glGetProgramInfoLog(program, maxLength, &maxLength, &infoLog[0]);

    //The program is useless now. So delete it.
    glDeleteProgram(program);

    //Provide the infolog in whatever manner you deem best.
    //Exit with failure.
    return;
}