如何在Android的单独线程上运行GLES20.glReadPixels? [英] How can i run GLES20.glReadPixels on separate thread in android?

查看:186
本文介绍了如何在Android的单独线程上运行GLES20.glReadPixels?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在与ARCore一起对图像进行分类并将对象放在图像上.但是,似乎ARCore相机没有提供任何获取像素缓冲区的方法.然后我遇到了如何使用ARCore用相机拍照然后我们可以使用 GLES20.glReadPixels 从OpenGL复制帧.如果我一次通过每个帧,我的分类器就可以正常工作,但是当我将 GLES20.glReadPixels 放入一个单独的线程中以获取像素缓冲区时,我将得到全零.所以基本上它给了我黑色图像. 因此,有一种方法可以在单独的线程上运行 GLES20.glReadPixels .

I am currently working with ARCore to classify images and put objects on the images. But it seems like ARCore camera doesn't provide any way to get the pixelbuffer. then i came accross How to take picture with camera using ARCore and according this we can copy the frame from OpenGL using GLES20.glReadPixels. if i pass each frame at a time my classifier works fine but when i put GLES20.glReadPixels to get the pixel buffer in a separate thread i am getting all zeros. so basically it gives me black image. So is there a way to run GLES20.glReadPixels on a separate thread.

推荐答案

OpenGL,对于Android平台,OpenGL ES被设计为面向单个线程的库.这并不意味着您不能在OpenGL ES中使用多个线程,但这不是使用OpenGL的标准方法.

OpenGL, and for Android platform OpenGL ES was designed to be a single thread oriented library. This does not mean that you can not work with multiple threads with OpenGL ES, but this is not a standard way to work with OpenGL.

根据我的经验,我需要异步加载纹理.为此,需要在另一个线程中创建一个OpenGL上下文.请注意,并非所有设备都支持创建两个OpenGL上下文的功能.我创建以下类来管理异步纹理加载.我认为您可以轻松地将其转换为您的需求.

In my experience, I needed to load texture asynchronously. To do this it is needed to create an OpenGL context in another thread. Note that no every device supports the capability to create two OpenGL contexts. I create the following class to manage async texture loading. I think you can easily convert this to your needs.

public class AsyncOperationManager {

    public boolean asyncMode;

    public interface AsyncTextureInfoLoader {
        TextureInfo load(Texture texture);
    }

    public class TextureLoaderThread extends Thread {
        public TextureLoaderThread() {
            super("GLThread-AsyncOperation");
        }

        public Handler handler;

        @SuppressLint("HandlerLeak")
        public void run() {
            Looper.prepare();

            int pbufferAttribs[] = { EGL10.EGL_WIDTH, 1, EGL10.EGL_HEIGHT, 1, EGL_TEXTURE_TARGET, EGL_NO_TEXTURE, EGL_TEXTURE_FORMAT, EGL_NO_TEXTURE, EGL10.EGL_NONE };

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

            handler = new Handler() {
                public void handleMessage(Message msg) {
                    MessageContent content = (MessageContent) msg.obj;
                    long start2 = Clock.now();
                    Logger.debug("context switch for async texture load stopped ");

                    long start1 = Clock.now();
                    Logger.debug("async texture load stopped ");
                    content.texture.updateInfo(content.execute.load(content.texture));
                    Logger.debug("async texture load ended in %s ms", (Clock.now() - start1));

                    Logger.debug("context switch for async texture load ended in %s ms", (Clock.now() - start2));

                    if (content.listener != null)
                        content.listener.onTextureReady(content.texture);
                }
            };

            Looper.loop();
        }
    }

    final static int EGL_TEXTURE_TARGET = 12417;
    final static int EGL_NO_TEXTURE = 12380;
    final static int EGL_TEXTURE_FORMAT = 12416;

    private static AsyncOperationManager instance = new AsyncOperationManager();

    public static AsyncOperationManager instance() {
        return instance;
    }

    private EGLContext textureContext;
    private EGL10 egl;
    private EGLDisplay display;
    private EGLConfig eglConfig;
    protected EGLSurface surfaceForTextureLoad;
    private TextureLoaderThread textureLoaderThread;

    public AsyncOperationManager() {
    }

    public void init(EGL10 egl, EGLContext renderContext, EGLDisplay display, EGLConfig eglConfig) {
        // la versione usata è la 2!
        int[] attrib_list = { XenonEGL.EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };

        this.egl = egl;
        this.display = display;
        this.eglConfig = eglConfig;

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

        if (textureContext != EGL10.EGL_NO_CONTEXT) {
            Logger.info("Context for async operation asyncMode.");
            asyncMode = true;
            // creiamo il thread per le operazioni async su opengl
            textureLoaderThread = new TextureLoaderThread();
            textureLoaderThread.start();
        } else {
            asyncMode = false;
            Logger.fatal("Try to enable context for async operation, but failed.");
        }
    }

    public int EGL_CONTEXT_CLIENT_VERSION = 0x3098;

    public void init(android.opengl.EGLContext renderContext, android.opengl.EGLDisplay display, android.opengl.EGLConfig eglConfig) {
        // la versione usata è la 2!
        int[] attrib_list = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE };

        if (textureContext != EGL10.EGL_NO_CONTEXT) {
            Logger.info("Context for async operation asyncMode.");
            asyncMode = true;
            textureLoaderThread = new TextureLoaderThread();
            textureLoaderThread.start();
        } else {
            asyncMode = false;
            Logger.fatal("Try to enable context for async operation, but failed.");
        }
    }


    public boolean destroy(EGL10 egl) {
        return egl.eglDestroyContext(display, textureContext);
    }

    public boolean destroy() {
        return false;
    }

    public class MessageContent {
        public MessageContent(Texture textureValue, AsyncTextureInfoLoader executeValue, TextureAsyncLoaderListener listenerValue) {
            texture = textureValue;
            execute = executeValue;
            listener = listenerValue;
        }

        public Texture texture;

        public AsyncTextureInfoLoader execute;

        public TextureAsyncLoaderListener listener;
    }

    public boolean isEnabled() {
        return asyncMode;
    }

    public TextureInfo load(final Texture texture, final AsyncTextureInfoLoader execute, final TextureAsyncLoaderListener listener) {
        if (asyncMode) {
            MessageContent content = new MessageContent(texture, execute, listener);
            Message msg = textureLoaderThread.handler.obtainMessage(25, content);
            textureLoaderThread.handler.sendMessage(msg);

            return null;
        } else {
            Logger.error("async operations on textures are disabled! This device support multiple opengl context?");
            Logger.warn("run texture update in single thread!");
            execute.load(texture);
            if (listener != null)
                listener.onTextureReady(texture);

            return texture.info;
        }
    }

    public void init() {
        asyncMode = false;
    }
}

有关此参数的更多信息,我建议您阅读:

For more information about this argument, i suggest you to read:

  • Loading-textures-in-a-background-thread-on-Android
  • 5843-Texture-Sharing
  • why-is-eglmakecurrent-failing-with-egl-bad-match

这篇关于如何在Android的单独线程上运行GLES20.glReadPixels?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆