【问题标题】:Threading textures load process for android opengl gameandroid opengl游戏的线程纹理加载过程
【发布时间】:2011-09-13 04:23:14
【问题描述】:

我有大量 JPG 格式的纹理。 而且我需要在实际绘图开始之前将它们预加载到opengl内存中。 我问了一个问题,有人告诉我这样做的方法是将 JPEG 解包与 glTexImage2D(...) 调用分离到另一个线程。 问题是我不太确定该怎么做。

执行 glTexImage2D 所需的 OpenGL(处理程序?)仅在 GLSurfaceView.Renderer 的 onSurfaceCreated 和 OnDrawFrame 方法中可用。

我无法解压缩所有纹理,然后在 onSurfaceCreated(...) 将它们加载到 opnegl 中, 因为它们可能不适合有限的虚拟机内存(20-40MB?)

这意味着我必须一个一个地解压并加载它们,但在这种情况下我无法获得 opengl 指针。

谁能给我和opengl游戏纹理加载线程的例子?

这一定是一些典型的程序,我在任何地方都无法获得任何信息。

【问题讨论】:

  • 你能解决这个问题吗?如何?所选答案不完整。

标签: android opengl-es textures


【解决方案1】:

如“OpenGLES preloading textures in other thread”中所述,有两个单独的步骤:位图创建和位图上传。在大多数情况下,您只需在辅助线程上创建位图就可以了——这相当容易。

如果您在上传纹理时遇到丢帧现象,请从后台线程调用texImage2D。为此,您需要创建一个新的 OpenGL 上下文,该上下文与您的渲染线程共享它的纹理,因为每个线程都需要它自己的 OpenGL 上下文。

EGLContext textureContext = egl.eglCreateContext(display, eglConfig, renderContext, null);

获取eglCreateContext 的参数有点棘手。您需要在您的 SurfaceView 上使用 setEGLContextFactory 来挂钩 EGLContext 创建:

@Override
public EGLContext createContext(final EGL10 egl, final EGLDisplay display, final EGLConfig eglConfig) {
     EGLContext renderContext = egl.eglCreateContext(display, eglConfig, EGL10.EGL_NO_CONTEXT, null);

     // create your texture context here

     return renderContext;
}

然后你就可以开始一个纹理加载线程了:

public void run() {
    int pbufferAttribs[] = { EGL10.EGL_WIDTH, 1, EGL10.EGL_HEIGHT, 1, EGL14.EGL_TEXTURE_TARGET,
            EGL14.EGL_NO_TEXTURE, EGL14.EGL_TEXTURE_FORMAT, EGL14.EGL_NO_TEXTURE,
            EGL10.EGL_NONE };

    EGLSurface localSurface = egl.eglCreatePbufferSurface(display, eglConfig, pbufferAttribs);
    egl.eglMakeCurrent(display, localSurface, localSurface, textureContext);

    int textureId = loadTexture(R.drawable.waterfalls);

    // here you can pass the textureId to your 
    // render thread to be used with glBindTexture
}

我在https://github.com/perpetual-mobile/SharedGLContextsTest 创建了上述代码sn-ps 的工作演示。

此解决方案基于互联网上的许多来源。这三个影响最大的:

【讨论】:

  • 这通常在多台设备上测试时有效,但是在少数情况下这种方法没有任何区别。例如,在华为 P8 Lite 上,上传过程中出现明显的丢帧现象。我怀疑这是由于不支持多线程的有限硬件/驱动程序造成的。对于上传速度较慢的大型纹理,另一种方法是使用 texSubImage2D 以块的形式预加载。
【解决方案2】:

你的主线程只需要上传例程,它可以访问 OpenGL 并调用 glTexImage2D。另一个线程将图像从文件加载(并解码)到内存。当辅助线程加载下一张图片时,主线程将之前加载的图片上传到纹理中。所以你只需要两张图片的内存,一张是当前从文件中加载的,一张是当前上传到 GL 中的(这是之前加载的)。当然你需要一点同步,以防止加载线程覆盖内存,即主线程当前发送给 GL 的内存,并防止主线程发送未完成的数据。

【讨论】:

  • 从你所说的,我得出结论,我可以简单地从 GLRenderer 的构造函数中保存 OpenGL 指针并在纹理加载函数中使用它。所以计划是:1)在开始时设置一些闪屏布局 2)创建 GLSurfaceView,但不显示它 3)启动 AsyncTask,它将在解压一个纹理后发布 ProgressUpdate 并调用将使用保存的 OpenGL 指针的 loadtexture 方法,也许,更新初始屏幕上的进度小部件。 4) 完成后,将布局切换到 GLSurfaceView。我将尝试实施并报告成功。
  • 这样不行。 OnSurfaceCreated() 仅在将 GLSurfaceView 设置为当前布局后调用,即使我尝试使用实际显示 GLSurfaceView 后保存的 gl 指针,指针也不起作用(glGenTextures() 返回零)。这就是主要问题——解压后如何将其加载回OpenGL?
  • @Victor 我必须告诉你,我对 Android 没有任何经验,所以所有这些话都不能告诉我任何事情。但是建议的方法是进行此类纹理流式传输时的选择方法,Android 实现由您决定。必须有一种方法可以在初始化函数之外调用 GL 函数。只要确保只在主线程中使用 OpenGL。
【解决方案3】:

“必须有一种方法可以在初始化函数之外调用 GL 函数。” - 是的。只需将指针复制到 gl 并在任何地方使用即可。

“请确保只在主线程中使用 OpenGL。”很重要。您不能在您的游戏引擎(可能在另一个线程中)中调用与 gl 线程不同步的纹理加载函数。在此处设置一个标志以指示您的 gl 线程加载新纹理(例如,您可以在 OnDrawFrame(GL gl) 中放置一个函数,该函数检查是否必须加载新纹理。

【讨论】:

  • 是的,我完全按照你说的做了。我也认为 Christian Rau 说了同样的话。我在一个单独的线程中有一个解压缩例程,一个标志和一个用于解压缩像素的共享缓冲区。在 OnDrawFrame(GL gl) 中有一个代码检查标志并在需要时调用 TexImage2D。
  • 持有对 gl 对象的引用并在以后(当线程返回时)使用它会导致此错误:在没有当前上下文的情况下调用 OpenGL ES API(每个线程记录一次)
【解决方案4】:

为此找到了一个解决方案,这实际上非常简单:加载位图后(在单独的线程中),将其存储在实例变量中,并在draw 方法中检查它是否已初始化,如果是,加载纹理。像这样的:

if (bitmap != null && textureId == -1) {
    initTexture(gl, bitmap);
}

【讨论】:

    【解决方案5】:

    要添加到Rodja's answer,如果您需要 OpenGL ES 2.0 上下文,请使用以下命令创建上下文:

    final int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
    int[] contextAttributes = 
        { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };
    EGLContext renderContext = egl.eglCreateContext(
        display, config, EGL10.EGL_NO_CONTEXT, contextAttributes);
    

    您仍然需要调用setEGLContextClientVersion(2),因为默认配置选择器也使用它。

    这是基于Attribute list in eglCreateContext

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-09-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多