android 下使用Direct Texture

本文详细介绍了如何在Android环境中使用DirectTexture技术优化纹理渲染性能。通过直接使用硬件纹理,避免了数据拷贝过程,显著提升了渲染效率。文章包含了关键代码片段、库依赖、配置指令及实际应用示例。
要使用Direct Texture,需要有一份android系统的源码
部分C++代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <EGL/egl.h>
#include <EGL/eglext.h>
#include <android/native_window.h>
#include <ui/GraphicBuffer.h>
#include <dlfcn.h>
#include <jni.h>
#include "render_native.h"
 
int Graphics::initGL(){
 
     const char* const driver_absolute_path = "/system/lib/egl/libEGL_mali.so";
    // On Gingerbread you have to load symbols manually from Mali driver because
    // Android EGL library has a bug.
    // From  ICE CREAM SANDWICH you can freely use the eglGetProcAddress function.
    // You might be able to get away with just eglGetProcAddress (no dlopen). Tr y it,  else revert to the following code
    void* dso = dlopen(driver_absolute_path, RTLD_LAZY);
    if (dso != 0)
    {
        LOGI("dlopen: SUCCEEDED");
        _eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC)dlsym(dso, "eglCreateImageKHR");
        _eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) dlsym(dso, "eglDestroyImageKHR");
    }
    else
    {
        LOGI("dlopen: FAILED! Loading functions in common way!");
        _eglCreateImageKHR = (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress("eglCreateImageKHR");
        _eglDestroyImageKHR = (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress("eglDestroyImageKHR");
    }
 
    if(_eglCreateImageKHR == NULL)
    {
        LOGE("Error: Failed to find eglCreateImageKHR at %s:%in", __FILE__, __LINE__);
        exit(1);
    }
    if(_eglDestroyImageKHR == NULL)
    {
        LOGE("Error: Failed to find eglDestroyImageKHR at %s:%in", __FILE__, __LINE__);
        exit(1);
    }
        _glEGLImageTargetTexture2DOES = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) eglGetProcAddress("glEGLImageTargetTexture2DOES");
    if(_glEGLImageTargetTexture2DOES == NULL)
    {
        LOGI("Error: Failed to find glEGLImageTargetTexture2DOES at %s:%in", __FILE__, __LINE__);
        return 0;
    }
     
    graphicBuffer = new GraphicBuffer( emu_width,emu_height,
            HAL_PIXEL_FORMAT_RGBA_8888,
            GraphicBuffer::USAGE_HW_TEXTURE |
            GraphicBuffer::USAGE_HW_2D |
            GRALLOC_USAGE_SW_READ_OFTEN |
            GRALLOC_USAGE_SW_WRITE_OFTEN);
             
    status_t err = graphicBuffer->initCheck();
    if (err != NO_ERROR)
    {
        LOGI("Error: %sn", strerror(-err));
        return 0;
    }
     
    GGLSurface t;
    //   graphicBuffer->lock(GraphicBuffer::USAGE_SW_WRITE_OFTEN, &addr);
    graphicBuffer->lock(&t, GRALLOC_USAGE_SW_WRITE_OFTEN);
           
    memset(t.data,128,t.stride*t.height);
    graphicBuffer->unlock();
     
     
    // Retrieve andorid native buffer
    android_native_buffer_t* anb =graphicBuffer->getNativeBuffer();
    // create the new EGLImageKHR
    const EGLint attrs[] =
    {
        EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
        EGL_NONE, EGL_NONE
    };
     
    mEngine.mTexture.pEGLImage = _eglCreateImageKHR(eglGetCurrentDisplay(),
                                mEngine.nContext, EGL_NATIVE_BUFFER_ANDROID, (EGLClientBuffer)anb, attrs);
    if(mEngine.mTexture.pEGLImage == EGL_NO_IMAGE_KHR)
    {
        LOGI("Error: eglCreateImage() failed at %s:%in", __FILE__, __LINE__);
        return 0;
    }
    checkGlError("eglCreateImageKHR");
    LOGI("create Program.......");
    GLuint gProgram = createProgram(vertex_source, fragment_source);
     checkGlError("createProgram");
     if (!gProgram) {
             LOGE("Could not create program.");
             return false;
          }
     glUseProgram(gProgram);
     vPosition = glGetAttribLocation(gProgram, "glVertex");
         checkGlError("glGetAttribLocation glVertex");
     glEnableVertexAttribArray(vPosition);
 
    a_texCoord0 = glGetAttribLocation(gProgram, "a_texCoord0");
        checkGlError("glGetAttribLocation texCoord0");
     glEnableVertexAttribArray(a_texCoord0);
 
     s_tex0 = glGetUniformLocation(gProgram, "s_texture0");
        checkGlError("glGetAttribLocation texture");
         
     
     
        LOGI("glGen Textures.......");
    glGenTextures(1, &texID);
     
    glDisable(GL_BLEND);
    glDisable(GL_DEPTH_TEST);
    glDisable(GL_STENCIL_TEST);
    glDisable(GL_DITHER);
    checkGlError("glDisable");
//  glEnable(GL_TEXTURE_2D);
//  checkGlError("glEnable(GL_TEXTURE_2D)");
    glGenTextures(1,&texID);
    checkGlError("glGenTextures");
     glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texID);
//  glPixelStorei(GL_PACK_ALIGNMENT, 1);
//      glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST  );
         
//       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, mEngine.mTexture.nTextureWidth, mEngine.mTexture.nTextureHeight, 0,GL_RGBA, GL_UNSIGNED_BYTE, NULL);
     
//  glFinish();
    _glEGLImageTargetTexture2DOES(GL_TEXTURE_2D,mEngine.mTexture.pEGLImage);
         
     float w = float(emu_width)  / float(mEngine.mTexture.nTextureWidth);
     float h = float(emu_height) / float(mEngine.mTexture.nTextureHeight);
 
         g_pos=initFloatBuffer(vertices,12);
        g_texvbo=initFloatBuffer(texCoords,8);
         
        glViewport(0, 0,  mEngine.nScreen_Width, mEngine.nScreen_Height);
        return 1;
 
}
 
void Graphics::renderFrame() {
 
//  texture=(unsigned char*)ture;
    glClearColor(0.5f, 0.5f, 0.5f, 1);
    glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
 
     glUniform1i(s_tex0, 0);
     glBindBuffer(GL_ARRAY_BUFFER, g_pos);
     glVertexAttribPointer(vPosition, 3, GL_FLOAT, GL_FALSE, 0, 0);
     glBindBuffer(GL_ARRAY_BUFFER, g_texvbo);
     glVertexAttribPointer(a_texCoord0, 2, GL_FLOAT, GL_FALSE, 0, 0);
    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
     
  eglSwapBuffers(mEngine.nDisplay, mEngine.nSurface);
  
 
void* Graphics::begin(){
    GGLSurface t;
     graphicBuffer->lock(&t,GRALLOC_USAGE_SW_WRITE_OFTEN);
    return t.data;
}
void Graphics::end(){
     graphicBuffer->unlock();
     renderFrame();
}
 
 
使用时如下:
Graphics  render;
 
 
void *buffer=render.begin();
把数据填充到buffer里
render.end();
 
编译时包含头文件
LOCAL_C_INCLUDES +=
    $(ANDROID_SRC_HOME)/frameworks/base/core/jni/android/graphics 
    $(ANDROID_SRC_HOME)/frameworks/base/include/
    $(ANDROID_SRC_HOME)/hardware/libhardware/include
    $(ANDROID_SRC_HOME)/system/core/include
    $(ANDROID_SRC_HOME)/frameworks/base/native/include/
    $(ANDROID_SRC_HOME)/frameworks/base/opengl/include/
 
链接选项:
LOCAL_LDLIBS    := -llog -lGLESv2 -lEGL -landroid  -lui -landroid_runtime  -ljnigraphics
 
android  Opengles 里虽然没有PBO, 但是用Direct Texture能实现类似的功能。
 
direct textures 的使用介绍
http://snorp.net/2011/12/16/android-direct-texture.html
 
eglCreateImageKHR扩展的介绍
http://www.khronos.org/registry/egl/extensions/KHR/EGL_KHR_image_base.txt

描述:在opengles 编程时如果用glTexImage2D /glTexSubImage2D API的话,当渲染的图片很大时,速度会变得很慢的,因为运行时会发生数据拷贝的过程,而使用opengles 的扩展glEGLImageTargetTexture2DOES可以解决这个问题,用这个扩展要用到另一个扩展 eglCreateImageKHR 。

在 OpenGL ES 中使用 DMA Buffer 通常涉及到与底层图形驱动程序的交互,这在标准的 OpenGL ES API 中并不直接支持。DMA(Direct Memory Access)通常用于在硬件设备和系统内存之间高效传输数据,而不需要 CPU 的干预。在图形应用中,DMA 可以用于将纹理数据或帧缓冲数据直接传输到 GPU 或从 GPU 传输出来。 在 Android 平台上,DMA Buffer 的使用通常与 `GraphicBuffer` 或 `AHardwareBuffer` 相关联。以下是一个使用 `AHardwareBuffer` 与 OpenGL ES 结合的示例流程,展示如何创建 `AHardwareBuffer` 并将其映射为 OpenGL ES 纹理。 ### 创建 AHardwareBuffer ```cpp #include <android/hardware_buffer.h> #include <EGL/egl.h> #include <GLES3/gl31.h> AHardwareBuffer* createHardwareBuffer(int width, int height, int format, int usage) { AHardwareBuffer_Desc desc; desc.width = width; desc.height = height; desc.layers = 1; desc.format = format; desc.usage = usage; desc.stride = 0; // 由系统自动计算 desc.rfu0 = 0; desc.rfu1 = 0; AHardwareBuffer* buffer = nullptr; AHardwareBuffer_allocate(&desc, &buffer); return buffer; } ``` ### 将 AHardwareBuffer 映射为 OpenGL ES 纹理 ```cpp GLuint createTextureFromHardwareBuffer(AHardwareBuffer* hardwareBuffer) { GLuint textureId; glGenTextures(1, &textureId); glBindTexture(GL_TEXTURE_2D, textureId); // 将 AHardwareBuffer 绑定为外部纹理 glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, eglGetImageForHardwareBuffer(hardwareBuffer)); // 设置纹理参数 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); return textureId; } EGLImageKHR eglGetImageForHardwareBuffer(AHardwareBuffer* hardwareBuffer) { EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); EGLint attribs[] = { EGL_DMA_BUF_PLANE0_FD_EXT, AHardwareBuffer_getNativeHandle(hardwareBuffer)->fds[0], EGL_DMA_BUF_PLANE0_PITCH_EXT, AHardwareBuffer_getNativeHandle(hardwareBuffer)->ints[0], EGL_NONE }; return eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, (EGLClientBuffer)hardwareBuffer, attribs); } ``` ### 使用纹理进行渲染 ```cpp void renderTexture(GLuint textureId) { // 绑定着色器程序 glUseProgram(shaderProgram); // 绑定纹理 glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, textureId); glUniform1i(textureUniform, 0); // 绘制四边形 glBindVertexArray(vao); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } ``` ### 释放资源 ```cpp void releaseHardwareBuffer(AHardwareBuffer* buffer) { AHardwareBuffer_release(buffer); } ``` ### 注意事项 - 上述代码假设你已经正确设置了 EGL 上下文,并且支持 `EGL_EXT_image_dma_buf_import` 扩展。 - `AHardwareBuffer` 的使用需要 Android API 级别 26(Android 8.0)或更高。 - `eglGetImageForHardwareBuffer` 函数中的 `EGL_DMA_BUF_PLANE0_FD_EXT` 和 `EGL_DMA_BUF_PLANE0_PITCH_EXT` 是扩展属性,需要确保你的 EGL 实现支持这些属性。 - 在使用 `AHardwareBuffer` 时,需要注意内存同步问题,确保在 GPU 使用完缓冲区后再进行 CPU 操作。 通过上述方法,可以在 OpenGL ES 中利用 DMA Buffer 提高数据传输效率,尤其是在处理大尺寸纹理或帧缓冲时[^1]。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值