Imagination PowerVR SDK Blog

glDrawTexfOES Problem

pvrvframe

#1

Hi, all.

Firstly, I am Japanes, so I am not good at English, sorry.

I develop a graphics porgram using OGLES-1.1_WINDOWS_PCEMULATION_2.05.25.0804 on WindowsXP.
And, I have a problem.
I can draw a sprite using glDrawTexfOES when format of texture is GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG or GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG.
But, the program hung when format of texture is not GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG or GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG.

Is there someone who have same problem?

A test code is below.



#include <windows.h>
#include <assert.h>
#include <GLES/gl.h>
#include <EGL/egl.h>

#include "PVRTglesExt.h"
#include "PVRTTexture.h"

#ifndef VRETURN
#define VRETURN(b)    if(!(b)) { assert(false); return false; }
#endif

#define _READ(fp, b, size)    VRETURN(fread(b, 1, size, fp) == size);
#define _SKIP(fp, offset)    VRETURN(fseek(fp, offset, SEEK_CUR) == 0);

namespace {
    // Get configs
    inline bool _GetConfigs(
        const PVR_Texture_Header& header,
        GLenum* format,
        GLenum* type,
        int* bpp)
    {
        bool ret = true;

        PVRTuint32 fmt = header.dwpfFlags & PVRTEX_PIXELTYPE;

        switch (fmt) {
        case OGL_RGBA_4444:
            *format = GL_RGBA;
            *type = GL_UNSIGNED_SHORT_4_4_4_4;
            *bpp = 2;
            break;
        case OGL_RGBA_8888:
            *format = GL_RGBA;
            *type = GL_UNSIGNED_BYTE;
            *bpp = 4;
            break;
        case OGL_RGB_565:
            *format = GL_RGB;
            *type = GL_UNSIGNED_SHORT_5_6_5;
            *bpp = 2;
            break;
        case OGL_PVRTC2:
            *format = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
            *type = GL_UNSIGNED_BYTE;    // Not use
            *bpp = 0;    // Not use
            break;
        case OGL_PVRTC4:
            *format = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
            *type = GL_UNSIGNED_BYTE;    // Not use
            *bpp = 0;    // Not use
            break;
        case OGL_RGBA_5551:
        case OGL_RGB_555:
        case OGL_RGB_888:
        case OGL_I_8:
        case OGL_AI_88:
            // TODO
            assert(false);
            ret = false;
            break;
        }

        return ret;
    }

    // Return whether compressed format
    inline bool _IsComressedFormat(const PVR_Texture_Header& header)
    {
        PVRTuint32 fmt = header.dwpfFlags & PVRTEX_PIXELTYPE;

        bool ret = ((fmt == OGL_PVRTC2)
                    || (fmt == OGL_PVRTC4));

        return ret;
    }

    // Get biyesize
    inline unsigned int _GetBytes(
        const PVR_Texture_Header& header,
        PVRTuint32 width,
        PVRTuint32 height)
    {
        unsigned int ret = 0;

        if (_IsComressedFormat(header)) {
            PVRTuint32 fmt = header.dwpfFlags & PVRTEX_PIXELTYPE;

            if (fmt == OGL_PVRTC2) {
                ret = (PVRT_MAX(width, PVRTC2_MIN_TEXWIDTH) * PVRT_MAX(height, PVRTC2_MIN_TEXHEIGHT) * header.dwBitCount + 7) / 8;
            }
            else {
                ret = (PVRT_MAX(width, PVRTC4_MIN_TEXWIDTH) * PVRT_MAX(height, PVRTC4_MIN_TEXHEIGHT) * header.dwBitCount + 7) / 8;
            }
        }
        else {
            ret = (width * height * header.dwBitCount + 7) / 8;
        }

        return ret;
    }

    struct SPvr {
        int width;
        int height;
        unsigned int size;
        int bpp;
        GLenum format;
        GLenum type;
        void* data;
        GLuint name;

        SPvr()
        {
            width = 0;
            height = 0;
            size = 0;
            bpp = 0;
            format = 0;
            type = 0;
            data = NULL;
            name = 0;
        }
        ~SPvr() { Clear(); }

        void Clear()
        {
            if (data != NULL) {
                free(data);
            }

            if (name > 0) {
                glDeleteTextures(1, &name);
            }

            width = 0;
            height = 0;
            size = 0;
            bpp = 0;
            format = 0;
            type = 0;
            data = NULL;
            name = 0;
        }
    };

    class CFilePtr {
    public:
        CFilePtr(FILE* fp) { m_FP = fp; }
        ~CFilePtr()
        {
            if (m_FP != NULL) {
                fclose(m_FP);
            }
        }

    private:
        FILE* m_FP;
    };

    bool _ReadPvr(
        const char* path,
        SPvr* pvr)
    {
        FILE* fp = fopen(path, "rb");
        CFilePtr filePtr(fp);
        VRETURN(fp != NULL);

        PVR_Texture_Header header;
        _READ(fp, &header, sizeof(header));

        // Check error
        {
            VRETURN(header.dwPVR == PVRTEX_IDENTIFIER);

            VRETURN(
                (header.dwHeaderSize == sizeof(header))
                && (header.dwNumSurfs > 0));

            // Only accept untwiddled data UNLESS texture format is PVRTC
            VRETURN(
                !(((header.dwpfFlags & PVRTEX_TWIDDLE) == PVRTEX_TWIDDLE)
                    && ((header.dwpfFlags & PVRTEX_PIXELTYPE) != OGL_PVRTC2)
                    && ((header.dwpfFlags & PVRTEX_PIXELTYPE) != OGL_PVRTC4)));

            // Prohibit cubemap
            VRETURN(
                ((header.dwpfFlags & PVRTEX_CUBEMAP) == 0)
                && (header.dwNumSurfs == 1));
        }

        // Get configs
        VRETURN(_GetConfigs(
                    header,
                    &pvr->format,
                    &pvr->type,
                    &pvr->bpp));

        pvr->width = header.dwWidth;
        pvr->height = header.dwHeight;

        // Texture size
        pvr->size = _GetBytes(header, header.dwWidth, header.dwHeight);
        VRETURN(pvr->size > 0);

        // Alloc buffer
        pvr->data = malloc(pvr->size);
        VRETURN(pvr->data != NULL);

        // Read pixels
        _READ(fp, pvr->data, pvr->size);

        // TODO
        // mipmap

        return true;
    }
}    // namespace

namespace {
    bool _isPVRCompressedFormat(GLenum format)
    {
        return ((format == GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG)
                || (format == GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG));
    }

    SPvr* s_pPvr = NULL;
}    // namespace

#define VGOTO(b, label)    if (!(b)) { assert(false); goto label; }

bool init()
{
    s_pPvr = new SPvr;
    
    bool ret = _ReadPvr("data/foo.pvr", s_pPvr);
    VGOTO(ret, __EXIT__);

    GLenum format = s_pPvr->format;
    GLenum type = s_pPvr->type;

    glGenTextures(1, &s_pPvr->name);
    ret = (s_pPvr->name > 0);
    VGOTO(ret, __EXIT__);

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, s_pPvr->name);

    if (_isPVRCompressedFormat(format)) {
        int w = s_pPvr->width;
        int h = s_pPvr->height;
        int size = s_pPvr->size;

        glCompressedTexImage2D(
            GL_TEXTURE_2D,
            0,
            format,
            w,
            h,
            0,
            size,
            s_pPvr->data);
    }
    else {
        int w = s_pPvr->width;
        int h = s_pPvr->height;

        glPixelStorei(GL_UNPACK_ALIGNMENT, s_pPvr->bpp);

        glTexImage2D(
            GL_TEXTURE_2D,
            0,
            format,
            w,
            h,
            0,
            format,
            type,
            s_pPvr->data);
    }

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

__EXIT__:
    return ret;
}

namespace {
    void _Ortho(
        GLfloat left, GLfloat right, GLfloat bottom, GLfloat top,
        GLfloat fNear, GLfloat fFar)
    {
        GLfloat mat[16];

        memset(mat, 0, sizeof(mat));

        mat[0] = 2 / (right - left);
        mat[5] = 2 / (top - bottom);
        mat[10] = 2 / (fNear - fFar);
        mat[15] = 1;

        mat[12] = (right + left) / (left - right);
        mat[13] = (top + bottom) / (bottom - top);
        mat[14] = (fFar + fNear) / (fNear - fFar);

        glMultMatrixf(mat);
    }

    void _drawRect(
        int x, int y,
        int width,
        int height)
    {
        struct SVtx {
            GLfloat pos[2];
            GLfloat uv[2];
            int color;
        };
        SVtx vtx[4];

        vtx[0].uv[0] = 0.0f;
        vtx[0].uv[1] = 0.0f;

        vtx[1].uv[0] = 0.0f;
        vtx[1].uv[1] = 1.0f;

        vtx[2].uv[0] = 1.0f;
        vtx[2].uv[1] = 0.0f;

        vtx[3].uv[0] = 1.0f;
        vtx[3].uv[1] = 1.0f;

        vtx[0].color = 0xffffffff;
        vtx[1].color = 0xffffffff;
        vtx[2].color = 0xffffffff;
        vtx[3].color = 0xffffffff;

        unsigned char* p = reinterpret_cast<unsigned char*>(vtx);

        static const int OFFSET_VTX_POS = 0;
        static const int OFFSET_VTX_UV = sizeof(GLfloat) * 2;
        static const int OFFSET_VTX_CLR = sizeof(GLfloat) * 4;

        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
        glEnableClientState(GL_COLOR_ARRAY);

        glVertexPointer(2, GL_FLOAT, sizeof(SVtx), p + OFFSET_VTX_POS);
        glTexCoordPointer(2, GL_FLOAT, sizeof(SVtx), p + OFFSET_VTX_UV);
        glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(SVtx), p + OFFSET_VTX_CLR);
   
        vtx[0].pos[0] = x;
        vtx[0].pos[1] = y;

        vtx[1].pos[0] = x;
        vtx[1].pos[1] = y + height;

        vtx[2].pos[0] = x + width;
        vtx[2].pos[1] = y;

        vtx[3].pos[0] = x + width;
        vtx[3].pos[1] = y + height;
       
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    }

    typedef void (APIENTRY * PFNGLDRAWTEXFOES) (GLfloat x, GLfloat y, GLfloat z, GLfloat width, GLfloat height);
    PFNGLDRAWTEXFOES glDrawTexfOES = NULL;

    void _drawSprite(
        int screenH,
        const GLint* rcSrc,
        const GLint* rcDst)
    {
        if (glDrawTexfOES == NULL) {
            glDrawTexfOES = (PFNGLDRAWTEXFOES)eglGetProcAddress("glDrawTexfOES");
        }

        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_TEXTURE_COORD_ARRAY);
        glDisableClientState(GL_COLOR_ARRAY);

        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

        glMatrixMode(GL_TEXTURE);
        glLoadIdentity();
        glScalef(-1.0f, -1.0f, 0.0f);

        glEnable(GL_TEXTURE_2D);

        glTexParameteriv(
            GL_TEXTURE_2D,
            GL_TEXTURE_CROP_RECT_OES,
            rcSrc);

        GLfloat w = rcDst[2];
        GLfloat h = rcDst[3];
        GLfloat x = rcDst[0];
        GLfloat y = screenH - rcDst[1] - h;

        (*glDrawTexfOES)(
            x, y, 0.0f,
            w, h);
    }
}    // namespace

void doFrame(int w, int h)
{
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    _Ortho(0, w, h, 0, -1, 1);

    glMatrixMode(GL_TEXTURE);
    glLoadIdentity();

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();

    glViewport(0, 0, w, h);

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, s_pPvr->name);
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);

#if 0
    _drawRect(100, 100, 128, 128);
#else
    GLint rcSrc[] = {
        0, 0,
        s_pPvr->width,
        s_pPvr->height,
    };
    GLint rcDst[] = {
        100, 100,
        128, 128,
    };

    _drawSprite(
        h,
        rcSrc,
        rcDst);
#endif
}

void end()
{
    if (s_pPvr != NULL) {
        delete s_pPvr;
    }
}



Regards.

#2

Do the demos and training courses from the SDK run successfully for you? If they do not then there may be a problem with PVRVFrame on your system.





I can’t see anything immediately wrong with your code. When you say “hung” what do you mean? Does the application crash out - if so after which line above?


#3

Hi, Gordon.

Thank you for your reply.

My program hungs below code

glTexParameteriv(
            GL_TEXTURE_2D,
            GL_TEXTURE_CROP_RECT_OES,
            rcSrc);

When texture format is not GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG or GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG, my program hungs.

I will try the demos and training courses in the SDK again.

Regards.


#4

Ok - I spoke to the engineer who works on PVRVFrame and he says that this issue has come up previously with another developer and is fixed for the next major release in the new year. We should have a version available sooner that will include the fix so please check for updates, however.


#5

Hi, Gordon.

I look forward to new update at the new year.
Thank you.

Regards.


#6

…zerosoft2009-12-10 17:49:01


#7
zerosoft wrote:
I noticed that you have assigned wrong values for texture format and texture type for the first 3 cases.

The original code is correct.

#8

sorry my mistake…


nak, disregard my previous commentzerosoft2009-12-10 16:58:30


#9

I thinks that it is too difficult for me to understand . But I will try !!!!




chieuhado2010-10-19 08:23:30