Sto riscontrando un problema molto difficile nella creazione di un programma shader su Android. quando chiamo glCreateShader o glCreateProgram ogni restituisce sempre 0.glCreateShader e glCreateProgram falliscono su Android
ho coperto tutte le mie basi per quanto riguarda la risoluzione dei problemi:
Ho controllato per assicurarsi che ho avuto un contesto OGL (io lo faccio, ho provato questo cancellando il frame buffer con vari colori, che funzionavano).
ho cercato glGetError ma restituito nulla (GL_NO_ERROR)
Io non sono un esperto di OpenGL o Android in modo non so di qualsiasi altra cosa che potrebbe causare questo.
Ho eseguito la mia app su un tablet nexus 7 e utilizzo OpenGL ES 2.0 e ho scelto come target l'ultima versione di Android (versione 17).
Infine, ho il mio codice per mostrare così:
Ecco il mio codice standard che imposta l'applicazione:
public class Platform implements ILinkable<Activity> {
class GameLoop extends GLSurfaceView implements GLSurfaceView.Renderer {
class Graphics2D implements IGraphics2D {
int width = 0;
int height = 0;
public void setWidth (int width) { this.width = width; }
public void setHeight(int height) { this.height = height; }
public int getWidth() { return width; }
public int getHeight() { return height; }
}
class Time implements ITime {
float frametime = 0;
float totaltime = 0;
long temptime = 0;
boolean running = true;
public void beginTimeCount() {
temptime = System.nanoTime();
}
public void endTimeCount() {
frametime = (System.nanoTime() - temptime)/1000000;
totaltime += frametime;
}
public float getFrameTime() { return frametime; }
public float getTotalTime() { return totaltime; }
}
Graphics2D graphics2d = new Graphics2D();
Time time = new Time();
boolean running = true;
public GameLoop(Context context) {
super(context);
setEGLContextClientVersion(2);
setRenderer(this);
//setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
}
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
GLES20.glClearColor(0.5f, 0.0f, 0.5f, 1.0f);
}
public void onDrawFrame(GL10 unused) {
if (running) {
time.beginTimeCount();
for (IUpdateable u : Platform.this.root.update)
u.onUpdate(time);
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
for (IDrawable2D d : Platform.this.root.draw2d) {
d.onDraw2D(graphics2d);
}
for (IDrawable3D d : Platform.this.root.draw3d)
d.onDraw3D();
time.endTimeCount();
}
}
public void onSurfaceChanged(GL10 unused, int width, int height) {
GLES20.glViewport(0,0, width, height);
graphics2d.setWidth(width);
graphics2d.setHeight(height);
for (IDrawable2D d : Platform.this.root.draw2d)
d.onSize2D(graphics2d);
}
public void onPause() {
super.onPause();
running = false;
}
public void onResume() {
super.onResume();
running = true;
}
}
private GameLoop gameloop;
public Node root;
public Platform() {
this.root = new Node();
}
public void link(Activity activity) {
this.gameloop = new GameLoop(activity);
activity.requestWindowFeature(Window.FEATURE_NO_TITLE);
activity.setContentView(this.gameloop);
}
public void unlink(Activity activity) {
this.gameloop = null;
activity.setContentView(null);
}
}
e questo è l'attività principale:
public class MainActivity extends Activity {
private Game game;
private Platform platform;
public MainActivity() {
platform = new Platform();
game = new Game();
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
platform.link(this);
game.link(platform.root);
game.onStart();
}
public void onDestroy() {
super.onDestroy();
game.onStop();
game.unlink(platform.root);
platform.unlink(this);
}
}
e questo è il codice che crea gli shader e il programma:
public static int loadShader(int shaderType, String source) throws FmtException {
int[] gotVar = new int[]{ 0 };
int shader = GLES20.glCreateShader(shaderType);
if (shader == 0)
throw new FmtException(FmtException.GLES,"could not create shader: %s",getError());
GLES20.glShaderSource(shader, source);
GLES20.glCompileShader(shader);
GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, gotVar, 0);
if (gotVar[0] == 0) {
GLES20.glGetShaderiv(shader, GLES20.GL_INFO_LOG_LENGTH, gotVar, 0);
if (gotVar[0] != 0) {
GLES20.glDeleteShader(shader);
throw new FmtException(FmtException.GLES, "could not compile shader %d:\n%s\n",shaderType, GLES20.glGetShaderInfoLog(shader));
}
}
return shader;
}
public static int createProgram(String pVertexSource, String pFragmentSource) throws FmtException {
int[] gotVar = new int[]{ GLES20.GL_FALSE };
int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, pVertexSource);
int pixelShader = loadShader(GLES20.GL_FRAGMENT_SHADER, pFragmentSource);
int program = GLES20.glCreateProgram();
if (program == 0)
throw new FmtException(FmtException.GLES, "could not create program: %s",getError());
GLES20.glAttachShader(program, vertexShader);
GLES20.glAttachShader(program, pixelShader);
GLES20.glLinkProgram(program);
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, gotVar, 0);
if (gotVar[0] != GLES20.GL_TRUE) {
GLES20.glGetProgramiv(program, GLES20.GL_INFO_LOG_LENGTH, gotVar, 0);
if (gotVar[0] != 0) {
GLES20.glDeleteProgram(program);
throw new FmtException(FmtException.GLES, "could not link program:\n%s\n", GLES20.glGetProgramInfoLog(program));
}
}
return program;
}
qualsiasi aiuto o suggerimento sarebbe molto apprezzato.
Dove si sarebbe chiamata 'createProgram()' nella tua codice? So per certo che 'createProgram()' restituisce 0 quando chiamato al di fuori del thread GL. – Reigertje
@Brianberg Viene chiamato nel metodo di classe Game onStart(), quindi viene chiamato nel metodo onCreate() di MainActivity. – Jim
Sì, questo è fuori dal thread GL. Assicurati che tutti i metodi di GLES20 siano richiamati all'interno del thread GL, altrimenti non funzionano. Questo è all'interno di 'onSurfaceChanged()', 'onSurfaceCreated()' e/o 'onDrawFrame()'. – Reigertje