Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

iOS: How to Render-To-1-channel-Texture in GLES2

I'm pretty sure now after hours of bashing that this cannot be done.

This is my code so far (BELOW) for rendering to a texture; it does the job, but is very wasteful. I only want a single 8-bit channel, possibly 16-bit greyscale. I don't want a useless R G and B channel.

But if I try to switch GL_RGBA /*GL_ALPHA*/ in glTexImage2D, glCheckFramebufferStatus catches a 'frame buffer incomplete' error: 36054 0x8CD6 GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT

guys on IRC suggest GL_R but Xcode doesn't offer autocompleteion for that, so it looks like maybe it is one of those things pruned out of GL for GLES

but that seems really bizarre! this is a mobile device. Surely something that reduces by a factor of four the amount of bits needed to perform an operation... surely this would be one of the last things to take out.

?!?

can anyone bury this one definitively? Is it possible to render onto a single channel texture in GLES2.0?

+ (void)  blurTexture: (GLuint)     in_texId
             POTWidth: (GLuint)     in_W
            POTHeight: (GLuint)     in_H
       returningTexId: (GLuint*)    out_pTexId
{
    // search HELP: 'Using a Framebuffer Object as a Texture'
    // http://stackoverflow.com/questions/3613889/gl-framebuffer-incomplete-attachment-when-trying-to-attach-texture

    // Create the destination texture, and attach it to the framebuffer’s color attachment point.

    // create the texture
    GLuint id_texDest;
    {
        // fragshader will use 0 
        glActiveTexture( GL_TEXTURE0 );

        // Ask GL to give us a texture-ID for us to use
        glGenTextures( 1, & id_texDest );
        glBindTexture( GL_TEXTURE_2D, id_texDest );


        // actually allocate memory for this texture
        GLuint pixCount = in_W * in_H;

        typedef struct { uint8_t r, g, b, a } rgba;

        rgba * alphas = calloc( pixCount, sizeof( rgba ) );

        // XOR texture
        int pix=0;
        for ( int x = 0;  x < in_W;  x++ )
        {
            for ( int y = 0;  y < in_H;  y++ )
            {
                //alphas[ pix ].r = (y < 256) ? x^y : 0;
                //alphas[ pix ].g = (y < 512) ? 127 : 0;
                //alphas[ pix ].b = (y < 768) ? 127 : 0;
                alphas[ pix ].a = (y < 512) ? x^y : 0; // half mottled, half black

                pix++;
            }
        }

        // set some params on the ACTIVE texture
        glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR/*_MIPMAP_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 );

        // WRITE/COPY from P into active texture  
        glTexImage2D( GL_TEXTURE_2D, 0,
                     GL_RGBA /*GL_ALPHA*/, in_W, in_H, 0, 
                     GL_RGBA /*GL_ALPHA*/, 
                     GL_UNSIGNED_BYTE, 
                     (void *) alphas );

        //glGenerateMipmap( GL_TEXTURE_2D );

        free( alphas );

        glLogAndFlushErrors();

    }


    GLuint textureFrameBuffer;
    {
        GLint oldFBO;
        glGetIntegerv( GL_FRAMEBUFFER_BINDING, & oldFBO );

        // create framebuffer
        glGenFramebuffers( 1, & textureFrameBuffer );
        glBindFramebuffer( GL_FRAMEBUFFER, textureFrameBuffer );

        // attach renderbuffer
        glFramebufferTexture2D( GL_FRAMEBUFFER, 
                               GL_COLOR_ATTACHMENT0, 
                               GL_TEXTURE_2D, 
                               id_texDest, 
                               0 );

        //glDisable( GL_DEPTH_TEST );

        // Test the framebuffer for completeness. This test only needs to be performed when the framebuffer’s configuration changes.
        GLenum status = glCheckFramebufferStatus( GL_FRAMEBUFFER ) ;
        NSAssert1( status == GL_FRAMEBUFFER_COMPLETE, @"failed to make complete framebuffer object %x", status );

        // 36054  0x8CD6  GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT

        // unbind frame buffer
        glBindFramebuffer( GL_FRAMEBUFFER, oldFBO );
    }




    glLogAndFlushErrors();

    // clear texture bitmap to backcolor
    {
        GLint oldFBO;
        glGetIntegerv( GL_FRAMEBUFFER_BINDING, & oldFBO );

        glBindFramebuffer( GL_FRAMEBUFFER, textureFrameBuffer );
        glLogAndFlushErrors();

        {
            float j = 0.1f;
            glClearColor( j, j, j, j );
            glLogAndFlushErrors();
            glClear( GL_COLOR_BUFFER_BIT );
            glLogAndFlushErrors();
        }

        glBindFramebuffer( GL_FRAMEBUFFER, oldFBO );
    }

    glDeleteFramebuffers( 1, & textureFrameBuffer );

    * out_pTexId = id_texDest;

    glLogAndFlushErrors();
}
like image 658
P i Avatar asked May 20 '11 18:05

P i


1 Answers

Since iOS 5.0, you can render to both 1 and 2 channel textures using GL_EXT_texture_rg.

http://www.khronos.org/registry/gles/extensions/EXT/EXT_texture_rg.txt

http://developer.apple.com/library/ios/#releasenotes/General/WhatsNewIniPhoneOS/Articles/iOS5.html#//apple_ref/doc/uid/TP30915195-SW47

Edit: I've tested this and it works, but only on A5 and above (iPad2/3/4/mini, iPhone4S/5, iPod touch 5th gen). Unfortunately it's not available on A4 and older where it's needed most (iPhone4, iPod touch 4th gen, 3GS, iPad1).

like image 154
sup Avatar answered Oct 15 '22 07:10

sup