前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >OpenGL ES 3.0 怎样将着色器程序二进制化

OpenGL ES 3.0 怎样将着色器程序二进制化

作者头像
字节流动
发布2023-09-04 17:58:54
3850
发布2023-09-04 17:58:54
举报
文章被收录于专栏:字节流动字节流动

之前有位 VIP 读者提问:C++ 如何将 OpenGL ES 的着色器程序二进制(保存),然后在其他地方加载使用?现在写篇文章介绍下。

将着色器程序二进制化(Shader Program Binary)有哪些好处?

  1. 快速加载和解析:使用二进制形式的着色器程序可以更快地加载和解析,因为不需要进行编译和链接的过程。二进制数据可以直接加载到显卡驱动程序中进行处理,节省了编译和链接的时间。
  2. 保护源代码:由于二进制形式的着色器程序不包含可读的源代码,因此更难以逆向工程或进行代码分析。
  3. 减少驱动程序开销:由于二进制形式的着色器程序已经经过编译和优化,因此它们可以减少驱动程序在运行时进行编译和优化的开销。
  4. 可移植性:二进制着色器程序可以在不同的平台和设备之间进行共享和传输。由于二进制数据是平台无关的,可以在不同的OpenGL实现上使用相同的二进制着色器程序,提高了应用程序的可移植性。

需要注意的是,二进制化着色器程序的可移植性可能会受到一些限制,例如 OpenGL 版本、GPU 架构等因素。因此,在使用二进制化着色器程序时,需要确保目标平台和设备支持相应的二进制格式。

获取着色器程序的二进制形式

OpenGL ES 3.0 版本支持获取着色器程序的二进制形式,使用 glGetProgramBinary 函数,它的函数原型如下:

代码语言:javascript
复制
void glGetProgramBinary(GLuint program, GLsizei bufSize, GLsizei* length, GLenum* binaryFormat, void* binary);

该函数接受五个参数:

program:要获取二进制表示的程序对象的标识符。 bufSize:二进制数据缓冲区的大小(以字节为单位)。 length:用于存储实际获取的二进制数据大小的变量指针。该变量会被设置为实际获取的二进制数据的大小(以字节为单位)。 binaryFormat:用于存储实际获取的二进制数据的格式的变量指针。 binary:用于存储实际获取的二进制数据的缓冲区。

要使用 glGetProgramBinary 函数,首先需要创建一个适当的缓冲区来存储二进制数据。可以使用 glGetProgramiv 函数来查询二进制数据的大小,然后根据返回的大小创建足够大的缓冲区。然后,可以调用 glGetProgramBinary 函数来获取二进制数据。

实现代码(需要注意二进制的格式):

代码语言:javascript
复制
    //检查是否支持获取二进制 program
    GLint programBinaryFormats = 0;
    glGetIntegerv(GL_NUM_PROGRAM_BINARY_FORMATS, &programBinaryFormats);
    if(programBinaryFormats <= GL_NONE) {
        //不支持获取二进制 program, game over
    }
    LOGCATE("BinaryProgramExample programBinaryFormats=%d", programBinaryFormats);

    // 编译链接着色器程序
    m_ProgramObj = GLUtils::CreateProgram(vShaderStr, fShaderStr, m_VertexShader, m_FragmentShader);


    if(programBinaryFormats > GL_NONE) {
        GLint length = 0;
        glGetProgramiv(m_ProgramObj, GL_PROGRAM_BINARY_LENGTH, &length);

        std::vector<unsigned char> buffer(length);
        GLenum format = 0;
        glGetProgramBinary(m_ProgramObj, length, nullptr, &format, buffer.data());

        ///sdcard/Android/data/com.byteflow.app/files/Download/shader_program.bin_format_34624
        char binaryFilePath[256] = {0};
        sprintf(binaryFilePath, "%s/shader_program.bin_format_%d", DEFAULT_OGL_ASSETS_DIR, format);
        FILE *fp = fopen(binaryFilePath, "wb");
        LOGCATE("BinaryProgramExample fp=%p, file=%s, binFormat=%d", fp, binaryFilePath, format);
        if(fp) {
            fwrite(buffer.data(), length, 1, fp);
            fclose(fp);
        }
    }

加载二进制数据到着色器对象

glProgramBinary 函数用于将二进制数据加载到 OpenGL ES 中的着色器程序对象。它的函数原型如下:

代码语言:javascript
复制
void glProgramBinary(GLuint program, GLenum binaryFormat, const void* binary, GLsizei length);

该函数接受四个参数:

program:要加载二进制数据的程序对象的标识符。 binaryFormat:二进制数据的格式。 binary:指向二进制数据的指针。 length:二进制数据的长度(以字节为单位)。 使用 glProgramBinary 函数需要遵循以下步骤:

  • 创建程序对象:使用 glCreateProgram 函数创建一个新的程序对象。
  • 分配存储空间:查询二进制数据的大小(例如使用 glGetProgramiv 函数和 GL_PROGRAM_BINARY_LENGTH 参数),然后为二进制数据分配足够的存储空间。
  • 加载二进制数据:将二进制数据读取到分配的存储空间中,例如从文件加载二进制数据。
  • 调用glProgramBinary:使用glProgramBinary函数将二进制数据加载到程序对象中。
  • 验证加载结果:使用glGetProgramiv函数和GL_LINK_STATUS参数检查程序对象是否成功加载。

加载二进制到着色器程序的实现代码:

代码语言:javascript
复制
void BinaryProgramExample::LoadBinary2Program(GLuint *pProgram, char *binFilePath) {
    FILE *fp = fopen(binFilePath, "rb");
    LOGCATE("BinaryProgramExample LoadBinary2Program fp=%p, file=%s", fp, binFilePath);
    if(fp) {
        fseek(fp, 0L, SEEK_END);
        int size = ftell(fp);
        rewind(fp);
        unsigned char *buffer = new unsigned char[size];
        fread(buffer, size, 1, fp);
        fclose(fp);

        *pProgram = glCreateProgram();
        std::string path(binFilePath);
        int pos = path.find("format_");
        std::string strFormat = path.substr(pos + 7);
        int format = std::stoi(strFormat);
        LOGCATE("BinaryProgramExample format=%d", format);
        glProgramBinary(*pProgram, format, buffer, size);

        //检查是否加载成功
        GLint status;
        glGetProgramiv(*pProgram, GL_LINK_STATUS, &status);
        if(GL_FALSE == status) {
            //加载失败
            LOGCATE("BinaryProgramExample glProgramBinary fail.");
            glDeleteProgram(*pProgram);
            *pProgram = GL_NONE;
        }

        delete[] buffer;
    }
}

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-07-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 字节流动 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 获取着色器程序的二进制形式
  • 加载二进制数据到着色器对象
相关产品与服务
腾讯云代码分析
腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档