これには、AOP (アスペクト指向プログラミング) と呼ばれるより良いアプローチがあります。SpringFramework と PostSharp を使用して、過去 (約 7 年前) に C# で使用した経験があります。このアプローチでは、コード インジェクション手法が広く使用されています。
そのため、この問題 (GL エラーのトレース) に直面したとき、AOP の古典的な問題として現れました。コード インジェクションによりパフォーマンスが低下するため、この変更 (GL ロギングの有効化) は一時的なものと想定し、使用したい場合に備えて git パッチに保持します。
1) まず、gradle ビルド スクリプトを変更します。最上位のビルド スクリプトに次を追加します。
buildscript {
dependencies {
classpath 'com.uphyca.gradle:gradle-android-aspectj-plugin:0.9.14'
アプリレベルのスクリプトでこれを追加します:
apply plugin: 'com.uphyca.android-aspectj'
これにより、gradle で aspectj プラグインが有効になります。このプロジェクト (ここでホストされています: https://github.com/uPhyca/gradle-android-aspectj-plugin ) は現在非推奨のようですが、機能しています。ここで新しいバージョンを見ることができます: https://github.com/HujiangTechnology/gradle_plugin_android_aspectjx。私のニーズ (基本的な Java コードの織り込み) では、古いバージョンがうまく機能しました。問題があるかどうかを確認するために再構築します。
2) アスペクトを適用するメソッドをマークするために後で使用するアノテーションを追加します。
package com.example.neutrino.maze;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by Greg Stein on 7/18/2016.
*/
@Retention(RetentionPolicy.CLASS)
@Target({ ElementType.CONSTRUCTOR, ElementType.METHOD })
public @interface GlTrace {
}
3) アスペクトを追加します。
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.getDeclaringType().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.
*
* @param 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) @GlTrace アノテーションで GL コードを実行するメソッドまたはコンストラクターをマークします。
...
@GlTrace
public GlEngine(int quadsNum) {
...
@GlTrace
public void draw(float[] mvpMatrix) {
...
これがすべて完了したら、AndroidStudio でプロジェクトを再実行します。次の出力が得られます。
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
私のプロジェクトでは、GL 呼び出しを使用するメソッドは 2 つしかありません。draw メソッドと GlEngine クラスのコンストラクターです。
これで少し遊んで、迷惑な「エラーなし」メッセージが表示されたら、いくつかの改善を行うことができます: 0) エラーのみを出力します 1) gl* に一致するすべてのメソッド (すべての OpenGl メソッド) を監視します。
楽しみ!