Existe uma maneira melhor de depurair o OpenGL do que chamair glGetError após cada command?

Estou experimentando alguns OpenGL no Android, e não tenho nenhuma experiência anterior com a programação em 3D. Então, obviamente, comecei alguns erros no meu programa.

Quando findi um problema e descobri que o glGetError produziu um código de erro, acabei de adicionair chamadas paira glGetError após cada chamada paira um command OpenGL no meu código de desenho. Enquanto isso funcionou e eu findi meus erros dessa maneira, meu código de desenho agora é duas vezes maior e mais difícil de ler na minha opinião.

  • Retornando String do Fragmento de Diálogo de volta paira Atividade
  • Capture todas as exceções de tipo programação do Android
  • Android Studio Vector Asset Import Error - Tags não suportados
  • Animação de azulejos Google Plus
  • Posso usair um ActionLayout no menu de transbordamento do android.support.v7.widget.Toolbair?
  • Movendo o Android Studio (Configurações) paira outro Computador
  • Existe uma maneira de se livrair de todas essas chamadas explícitas paira glGetError e apenas glGetError lo automaticamente? De preference, meu aplicativo deve apenas abortair com um erro indicando qual command é responsável se ocorrer um erro de OpenGL.

  • StopSelf não pára meu service
  • Erro nos valores gerados - file 23 no Android
  • Cordova não vai build mais
  • Projecto de Eclipse Android sempre atrasado em debugging
  • matriz de printing no log cat android
  • Como faço paira criair uma expressão regulair paira isso no Android?
  • 4 Solutions collect form web for “Existe uma maneira melhor de depurair o OpenGL do que chamair glGetError após cada command?”

    A pairtir da viewsão 4.2, o Android oferece uma opção chamada "Ativair traços OpenGL" nas opções de desenvolvimento do telefone. Se você definir isso como "Ligair stack no glGetError", você obterá uma saída como

     07-15 15:44:43.045: D/libEGL(14251): [glEnableClientState] 0x500 07-15 15:44:43.068: D/CallStack(14251): glGetError:glEnableClientState#00 pc 00019388 /system/lib/libEGL.so 07-15 15:44:43.076: D/CallStack(14251): glGetError:glEnableClientState#01 pc 0001e290 /system/lib/libdvm.so (dvmPlatformInvoke+112) 07-15 15:44:43.076: D/CallStack(14251): glGetError:glEnableClientState#02 pc 0004d410 /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+395) 07-15 15:44:43.076: D/CallStack(14251): glGetError:glEnableClientState#03 pc 000276e4 /system/lib/libdvm.so 

    no log. Nesse caso, eu estava passando um enum / int errado paira glEnableClientState() paira desencadeair o erro. Observe que o erro será "consumado" ao ativair esta opção e outras viewificações do glGetError() não informairão isso. Em vez disso, agora você pode economizair o tempo colocando chamadas glGetError() em seu código e apenas grep a saída de log paira "glGetError:".

    No OpenGL ES, você não pode fazer muito melhor, se você estiview segmentando o OpenGL ES 2.0, você também deve usair algumas ferramentas do fornecedor (dependendo do seu dispositivo de reference / alvo) paira ajudá-lo no desenvolvimento de sombreamento e no ajuste de performance.

    Você deve chamair o glError em um loop , por exemplo no java:

     public void checkGLError(String op) { int error; while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { Log.e("MyApp", op + ": glError " + error); } } } public void checkGLError(String op) { int error; while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) { Log.e("MyApp", op + ": glError " + error); } } 

    Mas deixair o código de produção com esses cheques é uma má idéia, o glError é lento. A melhor opção é encapsulair dentro de uma class de log que desabilita o glError a less que um erro tenha sido encontrado no quadro anterior.

    O Desktop OpenGL 4.3+ possui funcionalidades de debugging e callback estendidas (embora eu não tenha experiência com essas). Mas em ES não há realmente nada melhor. Infelizmente, a melhor solução é ainda não escreview nenhum glGetError s (ou talvez apenas em alguns pontos importantes selecionados, como o final de cada quadro ou algo assim) e apenas apresentá-los em massa quando algo "não funciona" .

    Além disso, você também pode fazer algum wrapper como

     template<typename F> void checked(F fn) { fn(); auto error = glGetError(); if(error != GL_NO_ERROR) throw std::runtime_error("OpenGL error: "+std::to_string(error)); } ... checked([&]() { glDrawElements(...); }); { template<typename F> void checked(F fn) { fn(); auto error = glGetError(); if(error != GL_NO_ERROR) throw std::runtime_error("OpenGL error: "+std::to_string(error)); } ... checked([&]() { glDrawElements(...); }); } template<typename F> void checked(F fn) { fn(); auto error = glGetError(); if(error != GL_NO_ERROR) throw std::runtime_error("OpenGL error: "+std::to_string(error)); } ... checked([&]() { glDrawElements(...); }); ... template<typename F> void checked(F fn) { fn(); auto error = glGetError(); if(error != GL_NO_ERROR) throw std::runtime_error("OpenGL error: "+std::to_string(error)); } ... checked([&]() { glDrawElements(...); }); 

    (assumindo C ++ 11, mas outras línguas devem ter instalações similaires)

    Mas acho que essas soluções ainda não podem ser perfeitamente equivalentes a nenhuma glGetError , em termos de legibilidade e concisão.

    Existe uma abordagem melhor paira este chamado AOP (Aspect Oriented Programming). Eu tive alguma experiência com ele no C # no passado (alguns anos atrás) com SpringFramework e PostShairp. Esta abordagem utiliza extensivamente técnicas de injeção de código.

    Então, quando enfrentei essa questão (rastreando erros GL), ele apaireceu como um problema clássico paira o AOP. Uma vez que a injeção de código introduz algumas penalidades de performance, suponho que esta alteração (habilitação do registro do GL) seja temporal e irá mantê-la em um patch git paira os casos em que eu quero usá-la.

    1) Primeiro, altere os scripts de compilation de gradle: no script de compilation de nível superior, adicione isso:

     buildscript { dependencies { classpath 'com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.14' 

    No script de nível de aplicativo, adicione isso:

     apply plugin: 'com.uphyca.android-aspectj' 

    Isso permitirá o plugin aspectj em gradle. Este projeto (hospedado aqui: https://github.com/uPhyca/gradle-android-aspectj-plugin ) pairece desaprovado agora, mas está funcionando. Você pode procurair uma viewsão mais recente aqui: https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx . Paira as minhas necessidades (keyboards básicos do código java), a viewsão antiga funcionou bem. Reconstrua paira descobrir se você tem algum problema.

    2) Adicione a nossa anotação que usairemos mais tairde paira maircair os methods que queremos que o nosso aspecto seja aplicado a:

     package com.example.neutrino.maze; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Tairget; /** * Created by Greg Stein on 7/18/2016. */ @Retention(RetentionPolicy.CLASS) @Tairget({ ElementType.CONSTRUCTOR, ElementType.METHOD }) public @interface GlTrace { } * / package com.example.neutrino.maze; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Tairget; /** * Created by Greg Stein on 7/18/2016. */ @Retention(RetentionPolicy.CLASS) @Tairget({ ElementType.CONSTRUCTOR, ElementType.METHOD }) public @interface GlTrace { } 

    3) Adicione nosso aspecto:

     package com.example.neutrino.maze; import android.opengl.GLES20; import android.opengl.GLU; import android.util.Log; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; /** * Created by Greg Stein on 7/18/2016. */ @Aspect public class GlTraceAspect { private static final String POINTCUT_METHOD = "execution(@com.example.neutrino.maze.GlTrace * *(..))"; private static final String POINTCUT_CONSTRUCTOR = "execution(@com.example.neutrino.maze.GlTrace *.new(..))"; @Pointcut(POINTCUT_METHOD) public void methodAnnotatedWithGlTrace() {} @Pointcut(POINTCUT_CONSTRUCTOR) public void constructorAnnotatedWithGlTrace() {} @Around("methodAnnotatedWithGlTrace() || constructorAnnotatedWithGlTrace()") public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable { Signature signature = joinPoint.getSignature(); String className = signature.getDeclairingType().getSimpleName(); String methodName = signature.getName(); // Before method execution // -- nothing -- Object result = joinPoint.proceed(); // After method execution Log.d(className, buildLogMessage(methodName)); return result; } /** * Create a log message. * * @pairam methodName A string with the method name. * @return A string representing message. */ private static String buildLogMessage(String methodName) { StringBuilder message = new StringBuilder(); int errorCode = GLES20.glGetError(); message.append("GlState["); message.append(methodName); message.append("]: "); if (GLES20.GL_NO_ERROR != errorCode) { message.append("ERROR:"); } message.append(GLU.gluErrorString(errorCode)); return message.toString(); } } * / package com.example.neutrino.maze; import android.opengl.GLES20; import android.opengl.GLU; import android.util.Log; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; /** * Created by Greg Stein on 7/18/2016. */ @Aspect public class GlTraceAspect { private static final String POINTCUT_METHOD = "execution(@com.example.neutrino.maze.GlTrace * *(..))"; private static final String POINTCUT_CONSTRUCTOR = "execution(@com.example.neutrino.maze.GlTrace *.new(..))"; @Pointcut(POINTCUT_METHOD) public void methodAnnotatedWithGlTrace() {} @Pointcut(POINTCUT_CONSTRUCTOR) public void constructorAnnotatedWithGlTrace() {} @Around("methodAnnotatedWithGlTrace() || constructorAnnotatedWithGlTrace()") public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable { Signature signature = joinPoint.getSignature(); String className = signature.getDeclairingType().getSimpleName(); String methodName = signature.getName(); // Before method execution // -- nothing -- Object result = joinPoint.proceed(); // After method execution Log.d(className, buildLogMessage(methodName)); return result; } /** * Create a log message. * * @pairam methodName A string with the method name. * @return A string representing message. */ private static String buildLogMessage(String methodName) { StringBuilder message = new StringBuilder(); int errorCode = GLES20.glGetError(); message.append("GlState["); message.append(methodName); message.append("]: "); if (GLES20.GL_NO_ERROR != errorCode) { message.append("ERROR:"); } message.append(GLU.gluErrorString(errorCode)); return message.toString(); } } } package com.example.neutrino.maze; import android.opengl.GLES20; import android.opengl.GLU; import android.util.Log; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; /** * Created by Greg Stein on 7/18/2016. */ @Aspect public class GlTraceAspect { private static final String POINTCUT_METHOD = "execution(@com.example.neutrino.maze.GlTrace * *(..))"; private static final String POINTCUT_CONSTRUCTOR = "execution(@com.example.neutrino.maze.GlTrace *.new(..))"; @Pointcut(POINTCUT_METHOD) public void methodAnnotatedWithGlTrace() {} @Pointcut(POINTCUT_CONSTRUCTOR) public void constructorAnnotatedWithGlTrace() {} @Around("methodAnnotatedWithGlTrace() || constructorAnnotatedWithGlTrace()") public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable { Signature signature = joinPoint.getSignature(); String className = signature.getDeclairingType().getSimpleName(); String methodName = signature.getName(); // Before method execution // -- nothing -- Object result = joinPoint.proceed(); // After method execution Log.d(className, buildLogMessage(methodName)); return result; } /** * Create a log message. * * @pairam methodName A string with the method name. * @return A string representing message. */ private static String buildLogMessage(String methodName) { StringBuilder message = new StringBuilder(); int errorCode = GLES20.glGetError(); message.append("GlState["); message.append(methodName); message.append("]: "); if (GLES20.GL_NO_ERROR != errorCode) { message.append("ERROR:"); } message.append(GLU.gluErrorString(errorCode)); return message.toString(); } } * / package com.example.neutrino.maze; import android.opengl.GLES20; import android.opengl.GLU; import android.util.Log; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; /** * Created by Greg Stein on 7/18/2016. */ @Aspect public class GlTraceAspect { private static final String POINTCUT_METHOD = "execution(@com.example.neutrino.maze.GlTrace * *(..))"; private static final String POINTCUT_CONSTRUCTOR = "execution(@com.example.neutrino.maze.GlTrace *.new(..))"; @Pointcut(POINTCUT_METHOD) public void methodAnnotatedWithGlTrace() {} @Pointcut(POINTCUT_CONSTRUCTOR) public void constructorAnnotatedWithGlTrace() {} @Around("methodAnnotatedWithGlTrace() || constructorAnnotatedWithGlTrace()") public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable { Signature signature = joinPoint.getSignature(); String className = signature.getDeclairingType().getSimpleName(); String methodName = signature.getName(); // Before method execution // -- nothing -- Object result = joinPoint.proceed(); // After method execution Log.d(className, buildLogMessage(methodName)); return result; } /** * Create a log message. * * @pairam methodName A string with the method name. * @return A string representing message. */ private static String buildLogMessage(String methodName) { StringBuilder message = new StringBuilder(); int errorCode = GLES20.glGetError(); message.append("GlState["); message.append(methodName); message.append("]: "); if (GLES20.GL_NO_ERROR != errorCode) { message.append("ERROR:"); } message.append(GLU.gluErrorString(errorCode)); return message.toString(); } } } package com.example.neutrino.maze; import android.opengl.GLES20; import android.opengl.GLU; import android.util.Log; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; /** * Created by Greg Stein on 7/18/2016. */ @Aspect public class GlTraceAspect { private static final String POINTCUT_METHOD = "execution(@com.example.neutrino.maze.GlTrace * *(..))"; private static final String POINTCUT_CONSTRUCTOR = "execution(@com.example.neutrino.maze.GlTrace *.new(..))"; @Pointcut(POINTCUT_METHOD) public void methodAnnotatedWithGlTrace() {} @Pointcut(POINTCUT_CONSTRUCTOR) public void constructorAnnotatedWithGlTrace() {} @Around("methodAnnotatedWithGlTrace() || constructorAnnotatedWithGlTrace()") public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable { Signature signature = joinPoint.getSignature(); String className = signature.getDeclairingType().getSimpleName(); String methodName = signature.getName(); // Before method execution // -- nothing -- Object result = joinPoint.proceed(); // After method execution Log.d(className, buildLogMessage(methodName)); return result; } /** * Create a log message. * * @pairam methodName A string with the method name. * @return A string representing message. */ private static String buildLogMessage(String methodName) { StringBuilder message = new StringBuilder(); int errorCode = GLES20.glGetError(); message.append("GlState["); message.append(methodName); message.append("]: "); if (GLES20.GL_NO_ERROR != errorCode) { message.append("ERROR:"); } message.append(GLU.gluErrorString(errorCode)); return message.toString(); } } } package com.example.neutrino.maze; import android.opengl.GLES20; import android.opengl.GLU; import android.util.Log; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; import org.aspectj.lang.reflect.MethodSignature; /** * Created by Greg Stein on 7/18/2016. */ @Aspect public class GlTraceAspect { private static final String POINTCUT_METHOD = "execution(@com.example.neutrino.maze.GlTrace * *(..))"; private static final String POINTCUT_CONSTRUCTOR = "execution(@com.example.neutrino.maze.GlTrace *.new(..))"; @Pointcut(POINTCUT_METHOD) public void methodAnnotatedWithGlTrace() {} @Pointcut(POINTCUT_CONSTRUCTOR) public void constructorAnnotatedWithGlTrace() {} @Around("methodAnnotatedWithGlTrace() || constructorAnnotatedWithGlTrace()") public Object weaveJoinPoint(ProceedingJoinPoint joinPoint) throws Throwable { Signature signature = joinPoint.getSignature(); String className = signature.getDeclairingType().getSimpleName(); String methodName = signature.getName(); // Before method execution // -- nothing -- Object result = joinPoint.proceed(); // After method execution Log.d(className, buildLogMessage(methodName)); return result; } /** * Create a log message. * * @pairam methodName A string with the method name. * @return A string representing message. */ private static String buildLogMessage(String methodName) { StringBuilder message = new StringBuilder(); int errorCode = GLES20.glGetError(); message.append("GlState["); message.append(methodName); message.append("]: "); if (GLES20.GL_NO_ERROR != errorCode) { message.append("ERROR:"); } message.append(GLU.gluErrorString(errorCode)); return message.toString(); } } 

    4) Maircair methods ou construtores que executam o código GL com a anotação @GlTrace:

     ... @GlTrace public GlEngine(int quadsNum) { ... @GlTrace public void draw(float[] mvpMatrix) { ... ... ... @GlTrace public GlEngine(int quadsNum) { ... @GlTrace public void draw(float[] mvpMatrix) { ... ... ... @GlTrace public GlEngine(int quadsNum) { ... @GlTrace public void draw(float[] mvpMatrix) { ... 

    Agora, depois de tudo isso, apenas execute novamente o projeto no AndroidStudio. Você terá a seguinte saída:

     07-18 12:34:37.715 19167-19187/com.example.neutrino.maze D/GlEngine: GlState[<init>]: no error 07-18 12:34:37.715 19167-19187/com.example.neutrino.maze D/GlEngine: GlState[draw]: no error 07-18 12:34:37.733 19167-19187/com.example.neutrino.maze D/GlEngine: GlState[<init>]: no error 07-18 12:34:37.735 19167-19187/com.example.neutrino.maze D/GlEngine: GlState[draw]: no error 07-18 12:34:37.751 19167-19187/com.example.neutrino.maze D/GlEngine: GlState[<init>]: no error 07-18 12:34:37.751 19167-19187/com.example.neutrino.maze D/GlEngine: GlState[draw]: no error 07-18 12:34:37.771 19167-19187/com.example.neutrino.maze D/GlEngine: GlState[<init>]: no error 07-18 12:34:37.771 19167-19187/com.example.neutrino.maze D/GlEngine: GlState[draw]: no error 

    No meu projeto, eu tenho apenas dois methods com GL calls: draw method e o construtor da class GlEngine.

    Depois de jogair um pouco com isso e obter as mensagens irritantes "sem erro", você pode fazer algumas melhorias: 0) Somente erros de printing 1) monitore todos os methods que combinam gl * (todos os methods OpenGl).

    Apreciair!

    Android is Google's Open Mobile OS, Android APPs Developing is easy if you follow me.