CVOpenGLESTextureCache vs glTexSubImage2D na iOS

Moja aplikacja OpenGL używa OpenGL do renderowania tekstury na pełnym ekranie i aktualizuje jej część w regularnych odstępach czasu. Do tej pory używałem glTexImage2D do wypychania mojej początkowej tekstury, a następnie aktualizowałem brudne regiony za pomocą glTexSubImage2D. Aby to zrobić, używam pojedynczego buforowania. To działa dobrze.

Widziałem, że może istnieć inny sposób osiągnięcia tego samego za pomocą CVOpenGLESTextureCache. Tekstury przechowywane w pamięci podręcznej tekstur odwołują się do CVPixelBuffer. Chciałbym wiedzieć, czy mogę zmutować te buforowane tekstury. Próbowałem odtworzyć CVOpenGLESTexture dla każdej aktualizacji, ale dramatycznie zmniejsza to moją szybkość klatek (nie dziwi mnie, ponieważ nigdzie nie określam brudnego obszaru). Może całkowicie źle zrozumiałem przypadek użycia tej pamięci podręcznej tekstur.

Czy ktoś może udzielić wskazówek?

AKTUALIZACJA: Oto kod, którego używam. Pierwsza aktualizacja działa poprawnie. Kolejne aktualizacje nie (nic się nie dzieje). Pomiędzy każdą aktualizacją modyfikuję surową mapę bitową.

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;