rtt + multisample resolution + dxt1 compression

My OpenGL 3.3 render to texture needs to be resolved for multisampling and then compressed to DXT1 on the fly. My understanding is that I have to :

  • create a multisample frame buffer
  • render into it
  • blit to a single sample uncompressed texture (glBlitFrameBuffer() ?)
  • copy to a compressed texture with glCopyTexImage2D()

Is it the way to go? I need the whole thing to happen within less than 10ms for a 256x256 texture.
I only see GL_COMPRESSED_RGB for the internal flags of glCopyTexImage2D. How can I ask DXT1 to be used, if supported of course, and not another compression method?
Would there be an all in one example (shader?) out there for this relatively basic need?


This extension introduces new tokens:

    COMPRESSED_RGB_S3TC_DXT1_EXT                   0x83F0
    COMPRESSED_RGBA_S3TC_DXT1_EXT                  0x83F1
    COMPRESSED_RGBA_S3TC_DXT3_EXT                  0x83F2
    COMPRESSED_RGBA_S3TC_DXT5_EXT                  0x83F3

In OpenGL 1.2.1 these tokens are accepted by the <internalformat> parameter
of TexImage2D, CopyTexImage2D, and CompressedTexImage2D and the <format>
parameter of CompressedTexSubImage2D.

I just remembered that from making a list of texture formats. I actually never used compressed formats and can’t tell you anything about the timing.

If it helps somebody, here is my working code for RTT + multisample resolve + compression + storage in texture array slot. Compression is done by glCopyTexSubImage3D() for free if the format is a compressed one, but this is rather slow.
I have 3 fonctions, one for initialization, one called just before RTT, and one just after.

void    Texture::initRTT( int width, int internalFormat, bool zbuf )
    int num_samples = 4;
    rttReady = true;
    // AA frame buffer to render into
    glGenFramebuffers(1, &fboAA);
    glBindFramebuffer(GL_FRAMEBUFFER, fboAA);
    glGenTextures(1, &textureAA);
    glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textureAA);
    glTexImage2DMultisample( GL_TEXTURE_2D_MULTISAMPLE, num_samples, internalFormat, width, width, false );
GLenum DrawBuffers[1] = {GL_COLOR_ATTACHMENT0};    // Set the list of draw buffers.
glDrawBuffers(1, DrawBuffers);                     // "1" is the size of DrawBuffers

    if( zbuf )
        hasZbuf = true;
        glGenTextures(1, &textureDepth);
        glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textureDepth);
        glTexImage2DMultisample( GL_TEXTURE_2D_MULTISAMPLE, num_samples, GL_DEPTH_COMPONENT24, width, width, false );
        glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D_MULTISAMPLE, textureDepth, 0 );

    if( glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE )    sys.abort( "rtt fboAA not ok");

    glGenFramebuffers(1, &fbo);
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, width, width, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);    // Give an empty image to OpenGL ( the last "0" )
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
    if( glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE )    sys.abort( "rtt fbo not ok");

void    Texture::beginRTT( int numSlot, bool zbuf )
    if( rttReady == false )    initRTT( dx_, internalFormat_, zbuf );

    gl.viewport( 0,0,dx_, dx_ );
    glBindFramebuffer(GL_FRAMEBUFFER, fboAA);        // rebind the rtt fb
    gl.clearRTT( zbuf );

void    Texture::endRTT( int numSlot, bool zbuf )
    glBindFramebuffer(GL_READ_FRAMEBUFFER, fboAA);    // resolve MSAA from fboAA to fbo with a blit
    glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
    glBlitFramebuffer( 0,0, dx_-1, dx_-1, 0, 0, dx_-1, dx_-1, GL_COLOR_BUFFER_BIT, GL_LINEAR );

 glBindTexture(GL_TEXTURE_2D_ARRAY, idBind_ );
    //    glBindFramebuffer(GL_FRAMEBUFFER, fbo);        // not necessary?
    glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo);    // store resolved fbo in texture slot
    //glReadBuffer(GL_COLOR_ATTACHMENT0);            // not necessary?
    glCopyTexSubImage3D( GL_TEXTURE_2D_ARRAY, 0, 0, 0, numSlot, 0, 0, dx_, dx_ ); // addapts to texture format (compressed or not)

    glBindFramebuffer(GL_FRAMEBUFFER, 0);                                // rebind the main fb
    gl.viewport( 0,0, sys.getScreenWidth(), sys.getScreenHeight() );    // restore viewport

void    GL::clearRTT( bool zbuf )
    glClearColor( clearColorRTT.r, clearColorRTT.g, clearColorRTT.b, 1.f);

    int flag = GL_COLOR_BUFFER_BIT;
    if( zbuf )    flag += GL_DEPTH_BUFFER_BIT;

    if( !(state_ & GN_ZWRITE) )            glDepthMask( GL_TRUE );    // renable zwrite
    glClear( flag );            // clear
    if( !(state_ & GN_ZWRITE) )            glDepthMask( GL_FALSE );// put back as it was