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

查看:33
本文介绍了如何在 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:

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

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