iOS上的CVOpenGLESTextureCache与glTexSubImage2D

iOS上的CVOpenGLESTextureCache与glTexSubImage2D,ios,opengl-es,textures,Ios,Opengl Es,Textures,我的OpenGL应用程序使用OpenGL全屏渲染纹理,并定期更新部分纹理。到目前为止,我一直在使用glTexImage2D推送我的初始纹理,然后用glTexSubImage2D更新脏区域。为此,我使用单缓冲。这很有效 我已经看到,可能有另一种方法可以使用CVOpenGLESTextureCache实现同样的目标。纹理缓存中保存的纹理引用CVPixelBuffer。我想知道我是否可以改变这些缓存的纹理。我试图为每次更新重新创建一个CVOpenGLESTexture,但这会显著降低我的帧速率(毕竟这

我的OpenGL应用程序使用OpenGL全屏渲染纹理,并定期更新部分纹理。到目前为止,我一直在使用glTexImage2D推送我的初始纹理,然后用glTexSubImage2D更新脏区域。为此,我使用单缓冲。这很有效

我已经看到,可能有另一种方法可以使用CVOpenGLESTextureCache实现同样的目标。纹理缓存中保存的纹理引用CVPixelBuffer。我想知道我是否可以改变这些缓存的纹理。我试图为每次更新重新创建一个CVOpenGLESTexture,但这会显著降低我的帧速率(毕竟这并不奇怪,因为我没有在任何地方指定脏区域)。也许我完全误解了这个纹理缓存的用例

有人能提供一些指导吗

更新:这是我正在使用的代码。第一次更新工作正常。后续的更新不会发生(什么也不会发生)。在每次更新之间,我修改原始位图

if (firstUpdate) {

    CVReturn err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, ctx, NULL, &texCache);

    CVPixelBufferRef pixelBuffer;
    CVPixelBufferCreateWithBytes(NULL, width_, height_, kCVPixelFormatType_32BGRA, bitmap, width_*4, NULL, 0, NULL, &pixelBuffer);
    CVPixelBufferLockBaseAddress(pixelBuffer, 0);

    CVOpenGLESTextureRef texture = NULL;
    CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, texCache, pixelBuffer, NULL, GL_TEXTURE_2D, GL_RGBA, width_, height_, GL_BGRA, GL_UNSIGNED_BYTE, 0, &texture);

    texture_[0] = CVOpenGLESTextureGetName(texture);

    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0);
}


CVOpenGLESTextureCacheFlush(texCache, 0);

if (firstUpdate) {
    glBindTexture(GL_TEXTURE_2D, texture_[0]);

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

glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

if (firstUpdate) {
    static const float textureVertices[] = {
        -1.0, -1.0,
        1.0, -1.0,
        -1.0, 1.0,
        1.0, 1.0
    };

    static const float textureCoords[] = {
        0.0, 0.0,
        1.0, 0.0,
        0.0, 1.0,
        1.0, 1.0
    };

    glVertexPointer(2, GL_FLOAT, 0, &textureVertices[0]);
    glTexCoordPointer(2, GL_FLOAT, 0, textureCoords);
}

glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);

firstUpdate = false;

我已经对这些纹理API进行了大量的黑客攻击,最终我能够生成一个使用纹理缓存API通过内存写入纹理的工作示例。这些API在iOS设备上工作,但在模拟器上不工作,因此需要一种特殊的解决方法(基本上只是在模拟器中显式调用glTexSubImage2D()。代码需要加倍缓冲在另一个线程中完成的纹理加载,以避免在渲染过程中进行更新。完整的源代码和计时结果位于。链接的Xcode项目从PNG解码,因此在旧版iPhone硬件上的性能有点差。但是代码可以自由地做任何你想做的事情,所以适应其他像素源应该不难。要仅写入脏区域,请仅写入后台线程中内存缓冲区的该部分。

我已经对这些纹理API进行了大量的黑客攻击,最终我能够使用纹理缓存API生成一个通过内存写入纹理的工作示例。这些API在iOS设备上工作,但在模拟器上不工作,因此需要一种特殊的解决方法(基本上只是在模拟器中显式调用glTexSubImage2D()。代码需要加倍缓冲在另一个线程中完成的纹理加载,以避免在渲染过程中进行更新。完整的源代码和计时结果位于。链接的Xcode项目从PNG解码,因此在旧版iPhone硬件上的性能有点差。但是代码可以自由地做任何你想做的事情,所以适应其他像素源应该不难。要仅写入脏区域,请仅写入后台线程中内存缓冲区的该部分。

是的,您确实不希望为每次更新重新创建缓存的纹理或像素缓冲区,而是创建一次,并将其重新用于更新。在创建这个像素缓冲区和纹理时会有一些开销。一旦你有了纹理,你应该能够通过写入像素缓冲区的字节来更新它,因为这些字节应该直接映射到纹理的内部字节。这就是我所想的,但无法让它工作。。。通过将位图包装在像素缓冲区中,我成功地将初始纹理推送到屏幕上。然后保留纹理缓存、纹理本身和像素缓冲区。我要做的下一件事是更新我的底层位图并重新绘制我的OpenGL四元体。然而,什么也没发生……我已经测试了我能想到的每一种变化,我在Sim卡、iPhone4和iPad2上发现了与您相同的结果。使用CVPixelBufferCreate()或CVPixelBufferCreateWithBytes()创建cv缓冲区似乎并不重要。调用CVPixelBufferCreateWithBytes将上载1帧(用户缓冲区的初始状态),但写入映射数据内存无效。事实上,我发现如果你在每一帧上删除并重新创建纹理,CVOpenGleStextureCacheCheCreateTextureFromImageAPI就会把所有时间都花在glTexImage2D_Exec上进行上传。是的,你真的不想为每次更新重新创建缓存的纹理或像素缓冲区,但是,只需创建一次,然后将其重新用于更新。在创建这个像素缓冲区和纹理时会有一些开销。一旦你有了纹理,你应该能够通过写入像素缓冲区的字节来更新它,因为这些字节应该直接映射到纹理的内部字节。这就是我所想的,但无法让它工作。。。通过将位图包装在像素缓冲区中,我成功地将初始纹理推送到屏幕上。然后保留纹理缓存、纹理本身和像素缓冲区。我要做的下一件事是更新我的底层位图并重新绘制我的OpenGL四元体。然而,什么也没发生……我已经测试了我能想到的每一种变化,我在Sim卡、iPhone4和iPad2上发现了与您相同的结果。使用CVPixelBufferCreate()或CVPixelBufferCreateWithBytes()创建cv缓冲区似乎并不重要。调用CVPixelBufferCreateWithBytes将上载1帧(用户缓冲区的初始状态),但写入映射数据内存无效。事实上,我发现如果在每一帧上删除并重新创建纹理,CVOpenGleStextureCacheCheCreateTextureFromimage()API就会把所有时间都花在glTexImage2D_Exec上进行上传。