【问题标题】:How can i run GLES20.glReadPixels on separate thread in android?如何在 android 的单独线程上运行 GLES20.glReadPixels?
【发布时间】:2018-07-24 07:13:13
【问题描述】:

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

【问题讨论】:

    标签: android opengl-es-2.0 glreadpixels arcore gles20


    【解决方案1】:

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

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

    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;
        }
    }
    

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

    【讨论】:

    • 不客气,如果能帮助您解决问题,请记得选择我的答案。
    猜你喜欢
    • 1970-01-01
    • 2018-09-20
    • 2019-03-09
    • 2021-12-12
    • 1970-01-01
    • 1970-01-01
    • 2016-03-16
    • 1970-01-01
    • 2015-10-22
    相关资源
    最近更新 更多