How to implement GLSurfaceView.EGLContextFactory in Android application to create an OpenGL ES context so that we can check the OpenGL ES version?

huangapple go评论61阅读模式
英文:

How to implement GLSurfaceView.EGLContextFactory in Android application to create an OpenGL ES context so that we can check the OpenGL ES version?

问题

我的问题是:如何通过实现GLSurfaceView.EGLContextFactory来打印物理设备支持的最大OpenGL ES版本

我正在按照这里的教程设置Android应用程序中使用OpenGL ES的环境。

我的代码结构与教程中的要求完全相同:

  1. 我的主要活动类设置如下:class MainActivity: Activity(),其中Activity来自android.app.Activity包。

  2. MainActivity内部,有一个来自android.opengl.GLSurfaceView包的GLSurfaceView实例。

  3. 创建了一个名为MyGLSurfaceView的类,用于实现或继承自GLSurfaceView。在其中,它有一个GLSurfaceView.Renderer的实例。

  4. 创建了一个名为MyGLRenderer的类,用于实现或继承自GLSurfaceView.Renderer

  5. 在与所需的OpenGL ES类位于同一包中创建了一个名为Model的类,以创建环境。

因此,Model类需要访问来自android.content.Context包的Android Context,以执行一些工作,如访问文件。

这里中告诉我要编写:

private const val EGL_CONTEXT_CLIENT_VERSION = 0x3098
private const val glVersion = 3.0
private class ContextFactory : GLSurfaceView.EGLContextFactory {

override fun createContext(egl: EGL10, display: EGLDisplay, eglConfig: EGLConfig): 
EGLContext {

    Log.w(TAG, "creating OpenGL ES $glVersion context")
    return egl.eglCreateContext(
            display,
            eglConfig,
            EGL10.EGL_NO_CONTEXT,
            intArrayOf(EGL_CONTEXT_CLIENT_VERSION, glVersion.toInt(), EGL10.EGL_NONE)
    ) // returns null if 3.0 is not supported
    }
}

但是,我仍然不明白如何实现这段代码。因为我已经在MyGLSurfaceView的构造函数中创建了OpenGL ES上下文,就像这样:

init {

    // 创建OpenGL ES 2.0上下文
    setEGLContextClientVersion(2)

    renderer = MyGLRenderer(context)
    
    // 为GLSurfaceView设置渲染器
    setRenderer(renderer)
}

文档中说,我必须先创建OpenGL ES上下文,然后再读取设备支持的版本,比如它能运行的最大版本。

问题是GLSurfaceView.EGLContextFactory是一个静态接口,这意味着它是一个全局或共享对象,需要首先实现它,即从该类继承并覆盖createContext()方法和destroyContext()方法。

我应该如何实现GLSurfaceView.EGLContextFactory?我应该将其声明为MyGLSurfaceView的嵌套类吗?

我尝试过像这样创建一个名为ContextFactory的嵌套类,它实现了GLSurfaceView.EGLContextFactory接口:

private const val EGL_CONTEXT_CLIENT_VERSION = 0x3098
private const val glVersion = 3.0
const val TAG = "ContextFactory"

class MyGLSurfaceView(context: Context) : GLSurfaceView(context) {
    private val renderer: MyGLRenderer

    init {

        // 创建OpenGL ES 2.0上下文
        setEGLContextClientVersion(2)

        renderer = MyGLRenderer(context)
        //renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY
        // 为GLSurfaceView设置渲染器
        setRenderer(renderer)
        glGetString(glVersion.toInt())
        //我假设`ContextFactory`已经被实例化,因为它实现了`静态接口`,所以我不需要在构造函数中创建另一个实例。所以,我直接尝试读取我的设备支持的`最大OpenGL ES版本`。
    }
}

但是,在logcat中,在warn类别中显示:

Rcall to OpenGL ES API with no current context (logged once per thread)
Reading a NULL string not supported here.

MyGLSurfaceView类看起来像这样:

import android.content.Context
import android.opengl.GLES20.glGetString
import android.opengl.GLSurfaceView
import android.util.Log
import javax.microedition.khronos.egl.EGL10
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.egl.EGLContext
import javax.microedition.khronos.egl.EGLDisplay

private const val EGL_CONTEXT_CLIENT_VERSION = 0x3098
private const val glVersion = 3.0
const val TAG = "ContextFactory"

class MyGLSurfaceView(context: Context) : GLSurfaceView(context) {
    private val renderer: MyGLRenderer

    init {
        setEGLContextClientVersion(2)
        renderer = MyGLRenderer(context)
        setRenderer(renderer)
        glGetString(glVersion.toInt())
    }

    private class ContextFactory : GLSurfaceView.EGLContextFactory {
        override fun createContext(egl: EGL10?, display: EGLDisplay?, eglConfig: 
        EGLConfig?): EGLContext? {
            Log.w(TAG, "creating OpenGL ES $glVersion context")
            if (egl != null) {
                return egl.eglCreateContext(
                    display,
                    eglConfig,
                    EGL10.EGL_NO_CONTEXT,
                    intArrayOf(EGL_CONTEXT_CLIENT_VERSION, glVersion.toInt(), 
                    EGL10.EGL_NONE)
                )
            }
            return null
        }

        override fun destroyContext(p0: EGL10?, p1: EGLDisplay?, p2: EGLContext?) {
            TODO("Not yet implemented")
        }
    }
}
英文:

My question is How could I print the maximum OpenGL ES version supported by a physical device by implementing GLSurfaceView.EGLContextFactory ?

I was following a tutorial here on how to setup
the environment in an Android application using OpenGL ES.

The way I structure my code is exactly like the tutorial tells me.

  1. My Main Activity is setup like this class MainActivity: Activity() whereby Activity is
    from android.app.Activity package.

  2. Inside MainActivity there is an instance of GLSurfaceView from android.opengl.GLSurfaceView package.

  3. A class named MyGLSurfaceView is created to implement or inherits from GLSurfaceView.
    Inside it, it has an instance of GLSurfaceView.Renderer.

  4. A class named MyGLRenderer is created to implement or inherits from GLSurfaceView.Renderer.

  5. A class named Model is created in the same package with the required OpenGL ES class to create the environment.

so, Model class needs to access Android Context from android.content.Context package to do some work, like to access a file.

In here, it tells me to write:

private const val EGL_CONTEXT_CLIENT_VERSION = 0x3098
private const val glVersion = 3.0
private class ContextFactory : GLSurfaceView.EGLContextFactory {

override fun createContext(egl: EGL10, display: EGLDisplay, eglConfig: EGLConfig): 
EGLContext {

    Log.w(TAG, "creating OpenGL ES $glVersion context")
    return egl.eglCreateContext(
            display,
            eglConfig,
            EGL10.EGL_NO_CONTEXT,
            intArrayOf(EGL_CONTEXT_CLIENT_VERSION, glVersion.toInt(), EGL10.EGL_NONE)
    ) // returns null if 3.0 is not supported
    }
}

But, I still do not understand how to implement this code. Because, I already created OpenGL ES context inside the constructor of MyGLSurfaceView like so:

init {

    // Create an OpenGL ES 2.0 context
    setEGLContextClientVersion(2)

    renderer = MyGLRenderer(context)
    
    // Set the Renderer for drawing on the GLSurfaceView
    setRenderer(renderer)
    }

It says there, in the documentation that I must create the OpenGL ES context first before
reading the version that the device can support, like the maximum version it can run.

The problem is GLSurfaceView.EGLContextFactory is a static interface which means it is a
global or shared object and need to be implemented first, i.e inherits from that class and overriding the createContext() method and destroyContext().

How should I implement GLSurfaceView.EGLContextFactory? should I declare it as nested class of MyGLSurfaceView.

I have tried like this by creating a nested class called ContextFactory which implements the interface GLSurfaceView.EGLContextFactory:

private const val EGL_CONTEXT_CLIENT_VERSION=0x3098
private const val glVersion=3.0
const val TAG="ContextFactory"
class MyGLSurfaceView(context: Context):GLSurfaceView(context) {
private val renderer: MyGLRenderer

init {

    // Create an OpenGL ES 2.0 context
    setEGLContextClientVersion(2)

    renderer = MyGLRenderer(context)
    //renderMode = GLSurfaceView.RENDERMODE_WHEN_DIRTY
    // Set the Renderer for drawing on the GLSurfaceView
    setRenderer(renderer)
    glGetString(glVersion.toInt())
    //I am assuming `ContextFactory` has already been instantiated since it implements
    //a `static interface` so, I do not need to create another instance of it here in 
    // the constructor. So, I just directly trying to read `maximum OpenGL ES version` 
    //supported in my device.
    }

but in the logcat inside warn category it says:

Rcall to OpenGL ES API with no current context (logged once per thread)
Reading a NULL string not supported here.

MyGLSurfaceView class looks like this:

 import android.content.Context
 import android.opengl.GLES20.glGetString
 import android.opengl.GLSurfaceView
 import android.util.Log
 import javax.microedition.khronos.egl.EGL10
 import javax.microedition.khronos.egl.EGLConfig
 import javax.microedition.khronos.egl.EGLContext
 import javax.microedition.khronos.egl.EGLDisplay

 private const val EGL_CONTEXT_CLIENT_VERSION=0x3098
 private const val glVersion=3.0
 const val TAG="ContextFactory"
 class MyGLSurfaceView(context: Context):GLSurfaceView(context) {
     private val renderer: MyGLRenderer

    init {
        setEGLContextClientVersion(2)
        renderer = MyGLRenderer(context)
        setRenderer(renderer)
        glGetString(glVersion.toInt())
    }

    private class ContextFactory: GLSurfaceView.EGLContextFactory{
        override fun createContext(egl: EGL10?, display: EGLDisplay?, eglConfig: 
        EGLConfig?): EGLContext? {
            Log.w(TAG, "creating OpenGL ES $glVersion context")
            if (egl != null) {
                return egl.eglCreateContext(
                    display,
                    eglConfig,
                    EGL10.EGL_NO_CONTEXT,
                    intArrayOf(EGL_CONTEXT_CLIENT_VERSION, glVersion.toInt(), 
                    EGL10.EGL_NONE)
                )
            }
            return null
        }

        override fun destroyContext(p0: EGL10?, p1: EGLDisplay?, p2: EGLContext?) {
            TODO("Not yet implemented")
        }
    }
}

答案1

得分: 0

首先创建一个继承自 GLSurfaceView.EGLContextFactory 接口的类,如下所示:

import android.opengl.GLSurfaceView
import android.util.Log
import javax.microedition.khronos.egl.EGL10 //确保从 javax 导入而不是 android.opengles.* 包
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.egl.EGLContext
import javax.microedition.khronos.egl.EGLDisplay

private const val EGL_CONTEXT_CLIENT_VERSION = 0x3098
private const val glVersion = 3.3

class ContextFactory : GLSurfaceView.EGLContextFactory {
    override fun createContext(egl: EGL10, display: EGLDisplay, eglConfig: EGLConfig): EGLContext {
        // 如果不支持3.0,则返回null
        Log.w("OpenGl version", "creating OpenGL ES $glVersion context")
        return egl.eglCreateContext(
            display,
            eglConfig,
            EGL10.EGL_NO_CONTEXT,
            intArrayOf(EGL_CONTEXT_CLIENT_VERSION, glVersion.toInt(), EGL10.EGL_NONE)
        )
    }

    override fun destroyContext(egl: EGL10, display: EGLDisplay, context: EGLContext) {
        egl.eglDestroyContext(display, context)
    }
}

MyGLSurfaceView 类中:

class MyGLSurfaceView(context: Context) : GLSurfaceView(context) {
    private val renderer: MyGLRenderer
    private var previousX: Float = 0f
    private var previousY: Float = 0f

    init {
        //setEGLContextClientVersion(2)
        setEGLContextFactory(ContextFactory()) //需要使用这个函数而不是上面的一个
        renderer = MyGLRenderer(context)
        setRenderer(renderer)
    }
}

如果程序崩溃,这意味着它不支持ContextFactory类中指定的当前版本。如果它可以平稳运行,那么它支持当前指定的版本。

还有一点,GLSurfaceView.EGLContextFactory 其实是一个普通接口,不是我之前认为的 staticglobal 接口。

英文:

First create a class that inherits from GLSurfaceView.EGLContextFactory interface like so:

import android.opengl.GLSurfaceView
import android.util.Log
import javax.microedition.khronos.egl.EGL10 //make sure to import from 
//javax not from `android.opengles.*` package
import javax.microedition.khronos.egl.EGLConfig
import javax.microedition.khronos.egl.EGLContext
import javax.microedition.khronos.egl.EGLDisplay


private const val EGL_CONTEXT_CLIENT_VERSION = 0x3098
private const val glVersion = 3.3

class ContextFactory : GLSurfaceView.EGLContextFactory {
    override fun createContext(egl: EGL10, display: EGLDisplay, eglConfig: 
        EGLConfig): EGLContext {
         // returns null if 3.0 is not supported
        Log.w("OpenGl version", "creating OpenGL ES $glVersion context")
        return egl.eglCreateContext(
            display,
            eglConfig,
            EGL10.EGL_NO_CONTEXT,
            intArrayOf(EGL_CONTEXT_CLIENT_VERSION, glVersion.toInt(), 
            EGL10.EGL_NONE)
        ) //
    }

    override fun destroyContext(egl: EGL10, display: EGLDisplay, context: 
        EGLContext) {
        egl.eglDestroyContext(display, context)
    }
}

in MyGLSurfaceView class:

class MyGLSurfaceView(context: Context) : GLSurfaceView(context) {
     private val renderer: MyGLRenderer
     private var previousX: Float = 0f
     private var previousY: Float = 0f

init {
    //setEGLContextClientVersion(2)
    setEGLContextFactory(ContextFactory()) //need to use this function 
    //instead of the above one
    renderer = MyGLRenderer(context)
    setRenderer(renderer)
}

if the program crashes, it means, it doesn't support the current version that was specified in the ContextFactory class. If it can run smoothly, it means it supports the currently specified version.

One more thing GLSurfaceView.EGLContextFactory is actually a normal interface, not a static or global interface when I thought previously.

huangapple
  • 本文由 发表于 2023年7月14日 08:45:36
  • 转载请务必保留本文链接:https://go.coder-hub.com/76684060.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定