7

私は Android でいくつかの OpenGL を試していますが、3D プログラミングの経験はありません。明らかに、私は自分のプログラムでかなりの数の間違いを犯しました。

問題が発生glGetErrorし、エラー コードが生成されることがわかったときglGetError、描画コードで OpenGL コマンドを呼び出すたびに呼び出しを追加しました。これは機能し、この方法でエラーを見つけましたが、私の意見では、私の描画コードは 2 倍の大きさになり、読みにくくなりました。

これらの明示的な呼び出しをすべて取り除き、glGetError自動的に呼び出す方法はありますか? できれば、OpenGL エラーが発生した場合にどのコマンドが原因であるかを示すエラーでアプリを中止する必要があります。

4

5 に答える 5

2

OpenGL ES では、これ以上のことはできません。OpenGL ES 2.0 をターゲットにしている場合は、シェーダーの開発とパフォーマンスの調整を支援するために、(リファレンス/ターゲット デバイスに応じて) いくつかのベンダー ツールも使用する必要があります。

たとえば java では、 loop で glError を呼び出す必要があります。

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

しかし、これらのチェックを製品コードに残すのは悪い考えです。glError は遅いです。最良のオプションは、前のフレームでエラーが検出されない限り、glError を無効にするロギング クラス内にカプセル化することです。

于 2013-05-16T19:33:12.960 に答える
1

これには、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 メソッド) を監視します。

楽しみ!

于 2016-07-18T10:52:26.780 に答える