glCopyTexSubImage2D #2

  • Follow


Hi Folks,

I'm finding that glCopyTexSubImage2D seems to fail to work properly
on Linux, yet it works fine on Windows. The failure seems to occur
if there is another window partially overlapping the window with
the GL context I'm working on. For example if there is another
window overlapping the bottom left of my drawing area, then the
image is only displayed to the right of this window and up to a
height level with the top of the window. Above this everything
is just black (background colour). If there is no other window
overlapping the drawing area, everything works fine. Any ideas?

- Keith
0
Reply Keith 12/23/2006 4:31:32 PM

Keith S. wrote:

> Hi Folks,
> 
> I'm finding that glCopyTexSubImage2D seems to fail to work
> properly on Linux, yet it works fine on Windows. The failure
> seems to occur if there is another window partially overlapping
> the window with the GL context I'm working on. For example if
> there is another window overlapping the bottom left of my
> drawing area, then the image is only displayed to the right of
> this window and up to a height level with the top of the
> window. Above this everything is just black (background
> colour). If there is no other window overlapping the drawing
> area, everything works fine. Any ideas?

This is just the expected bahviour, or in other words: OpenGL
makes no implications of the sanity of data within a rendering
framebuffer.

If something obstructs your rendering window the driver is clever
enough to omit the overlapped areas, increasing performance.
BTW: This might happen under Windows, too.

The solution is to use a PBuffer or a Framebuffer Object.

Wolfgang Draxinger
-- 
E-Mail address works, Jabber: hexarith@jabber.org, ICQ: 134682867

0
Reply Wolfgang 12/23/2006 7:01:03 PM


Wolfgang Draxinger wrote:
> 
> This is just the expected bahviour, or in other words: OpenGL
> makes no implications of the sanity of data within a rendering
> framebuffer.
> 
> If something obstructs your rendering window the driver is clever
> enough to omit the overlapped areas, increasing performance.
> BTW: This might happen under Windows, too.
> 
> The solution is to use a PBuffer or a Framebuffer Object.

thanks Wolfgang,

indeed on Solaris only the obstructed area is just blanked out, seems
like the Linux driver uses a dumber algorithm. Unfortunately Qt
does not make life easy for using pbuffers - some chipsets e.g. Intel
855GM supposedly support them, but Qt does not think so as they do not
support the WGL_ARB_render_texture extension.

- Keith
0
Reply Keith 12/23/2006 8:30:27 PM

Keith S. wrote:
> Hi Folks,
> 
> I'm finding that glCopyTexSubImage2D seems to fail to work properly
> on Linux, yet it works fine on Windows.

No, it will fail on Windows too, depending on
your setup.

> Any ideas?
> 

Don't do it.


-- 
<\___/>
/ O O \
\_____/  FTB.    For email, remove my socks.


We�re judging how a candidate will handle a nuclear
crisis by how well his staff creates campaign ads.
It�s a completely nonsensical process.
0
Reply fungus 12/23/2006 9:19:52 PM

Keith S. wrote:

> indeed on Solaris only the obstructed area is just blanked out,
> seems like the Linux driver uses a dumber algorithm.
> Unfortunately Qt does not make life easy for using pbuffers -
> some chipsets e.g. Intel 855GM supposedly support them, but Qt
> does not think so as they do not support the
> WGL_ARB_render_texture extension.

You're not limited to use only the OpenGL functionality Qt gives
you. It's perfectly possible to load extensions in parallel.
GLEW e.g. will work just fine.

Creating the PBuffer is a bit trickier, since you need the
XDisplay and a XVisual for that. Easiest way is to use
functions, querying the currently set
context/visual/display/screen and create a PBuffer from that. I
once posted here a quick and dirty PBuffer class doing that for
both Win32 and GLX. I just repost them here for reference.
However the code is a bit old and contains some workaround for
an issue of GLEW headers battling with GLX headers for the
PBuffer function entry point identifiers. GLX >=1.3 support for
PBuffers built in, while under Windows you need extensions, so
this should still work.

<code lang="C++" filename="pbuffer.h">

#ifndef PBUFFER_H
#define PBUFFER_H

#ifdef WIN32
#include <GL/wglew.h>
#endif

#ifdef GLX
#include <GL/glx.h>
#endif

class PBuffer
{
public:
        PBuffer(int width, int height);
        virtual ~PBuffer();

        void Use();
        void Release();

        int const get_width() const { return width; }
        int const get_height() const { return height; }

private:
        void Create();
        void Destroy();

protected:
        int width;
        int height;

        bool initialized;

#ifdef WIN32
        HPBUFFERARB     hPB;
        HGLRC           hPBRC;
        HDC             hPBDC;

        HDC             hGLDC;
        HGLRC           hGLRC;
#endif

#ifdef GLX
        Display         *dpy;
        int             scrnum;
        GLXContext      PBRC;
        GLXPbuffer      PBDC;

        GLXContext      FBRC;
        GLXDrawable     FBDC;
#endif
};

#endif/*PBUFFER_H*/

</code>

<code lang="C++" filename="pbuffer.cpp">
#include <stdexcept>
#include "pbuffer.h"

using namespace std;

#ifdef WIN32

PBuffer::PBuffer(int width, int height)
{
        initialized=false;

        this->width=width;
        this->height=height;

        hGLDC = wglGetCurrentDC();
        hGLRC = wglGetCurrentContext();

        Create();
}

PBuffer::~PBuffer()
{
        Destroy();
}

void PBuffer::Use()
{
        // make sure the pbuffer has been initialized
        if (!initialized)
        {
                throw runtime_error("pbuffer is not initialized");
        }
        // make sure we haven't lost our pbuffer due to a display mode
change

        int flag = 0;
        wglQueryPbufferARB(hPB, WGL_PBUFFER_LOST_ARB, &flag);
        if (flag)
        {
                throw runtime_error("pbuffer became invalid");
        }

        wglMakeCurrent(hPBDC, hPBRC);

        glViewport(0, 0, width, height);

        glDrawBuffer(GL_FRONT);
        glReadBuffer(GL_FRONT);
}

void PBuffer::Release()
{
        // make sure the pbuffer has been initialized
        if ( !initialized )
        {
                throw runtime_error("pbuffer is not initialized");
        }
        // make sure we haven't lost our pbuffer due to a display mode
change
        int flag = 0;
        wglQueryPbufferARB(hPB, WGL_PBUFFER_LOST_ARB, &flag);
        if (flag)
        {
                throw runtime_error("pbuffer became invalid");
        }

        wglMakeCurrent(hGLDC, hGLRC);
}

void PBuffer::Create()
{
        if(initialized)
        {
                Destroy();
        }

        if (hGLDC == NULL)
        {
                throw runtime_error("unable to get device context");
        }
        if (hGLRC == NULL)
        {
                throw runtime_error("unable to get render context");
        }
        // define the minimum pixel format requirements we will need for
our pbuffer
        // a pbuffer is just like a frame buffer, it can have a depth
buffer associated
        // with it and it can be double buffered.
        int attr[] =
        {
                WGL_SUPPORT_OPENGL_ARB, TRUE, // pbuffer will be used with gl
                WGL_DRAW_TO_PBUFFER_ARB, TRUE, // enable render to pbuffer
                WGL_RED_BITS_ARB, 16, // at least 8 bits for RED channel
                WGL_GREEN_BITS_ARB, 16, // at least 8 bits for GREEN channel
                WGL_BLUE_BITS_ARB, 16, // at least 8 bits for BLUE channel
                WGL_ALPHA_BITS_ARB, 16, // at least 8 bits for ALPHA channel
                WGL_DEPTH_BITS_ARB, 24, // at least 24 bits for depth buffer
                WGL_DOUBLE_BUFFER_ARB, FALSE, // we dont require double
buffering
                0 // zero terminates the list
        };

        // choose a pixel format that meets our minimum requirements
        unsigned int count = 0;
        int pixelFormat;
        wglChoosePixelFormatARB(hGLDC,(const int*)attr, NULL,
1,&pixelFormat,&count);
        if(count == 0)
        {
                throw runtime_error("no matching pbuffer pixel format found");
        }

        int attribs[]={0,0};

        // allocate the pbuffer
        hPB = wglCreatePbufferARB(hGLDC, pixelFormat, width, height,
attribs);
        hPBDC = wglGetPbufferDCARB(hPB);
        hPBRC = wglCreateContext(hPBDC);

        wglShareLists(hGLRC, hPBRC);

        initialized=true;
}

void PBuffer::Destroy()
{
        // make sure the pbuffer has been initialized
        if ( !initialized )
        {
                throw runtime_error("pbuffer is not initialized");
        }

        Release();

        wglDeleteContext(hPBRC);
        wglReleasePbufferDCARB(hPB, hPBDC);
        wglDestroyPbufferARB(hPB);

        initialized = false;
}
#endif

#ifdef GLX
PBuffer::PBuffer(int width, int height)
{
        initialized=false;

        this->width=width;
        this->height=height;

        dpy = glXGetCurrentDisplay();
        scrnum = DefaultScreen( dpy );
        FBRC = glXGetCurrentContext();
        FBDC = glXGetCurrentDrawable();

        Create();
}

PBuffer::~PBuffer()
{
        Destroy();
}

void PBuffer::Use()
{
        // make sure the pbuffer has been initialized
        if (!initialized)
        {
                throw runtime_error("pbuffer is not initialized");
        }
        // make sure we haven't lost our pbuffer due to a display mode
change

        // resize view port. generally you'll want to set this to the
        // size of your pbuffer so that you render to the entire pbuffer
        // but there are cases where you might want to render to just a
        // sub-region of the pbuffer.
        glXMakeContextCurrent(dpy, PBDC, PBDC, PBRC);

        glViewport(0, 0, width, height);

        glDrawBuffer(GL_FRONT);
        glReadBuffer(GL_FRONT);
}

void PBuffer::Release()
{
        // make sure the pbuffer has been initialized
        if ( !initialized )
        {
                throw runtime_error("pbuffer is not initialized");
        }
        // make sure we haven't lost our pbuffer due to a display mode
change

        glXMakeContextCurrent(dpy, FBDC, FBDC, FBRC);
}

void PBuffer::Create()
{
        if(initialized)
        {
                Destroy();
        }

        if (dpy == NULL)
        {
                throw runtime_error("unable to get device context");
        }
        if (!FBDC)
        {
                throw runtime_error("unable to get render context");
        }
        // define the minimum pixel format requirements we will need for
our pbuffer
        // a pbuffer is just like a frame buffer, it can have a depth
buffer associated
        // with it and it can be double buffered.
        /*int attr[] =
        {
                GLX_RENDER_TYPE, GLX_RGBA_BIT,
                GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT,
                GLX_DOUBLEBUFFER, False,
                GLX_RED_SIZE, 1,
                GLX_GREEN_SIZE, 1,
                GLX_BLUE_SIZE, 1,
                GLX_ALPHA_SIZE, 1,
                GLX_DEPTH_SIZE, 1,
                0 // zero terminates the list
        };*/

        int attrib[] =
        {
                GLX_DOUBLEBUFFER,  False,
                GLX_RED_SIZE,      8,
                GLX_GREEN_SIZE,    8,
                GLX_BLUE_SIZE,     8,
                GLX_ALPHA_SIZE,    8,
                GLX_STENCIL_SIZE,  1,
                GLX_DEPTH_SIZE,    24,
                GLX_RENDER_TYPE,   GLX_RGBA_BIT,
                GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT | GLX_WINDOW_BIT,
                None
        };

        int PBattrib[] =
        {
                GLX_PBUFFER_WIDTH,   width,
                GLX_PBUFFER_HEIGHT,  height,
                GLX_LARGEST_PBUFFER, False,
        None
        };

        // choose a pixel format that meets our minimum requirements
        int count = 0;
        //GLXFBConfigSGIX *config=
        //      glXChooseFBConfigSGIX(dpy, scrnum, attrib, &count);

        GLXFBConfig *config=
                glXChooseFBConfig(dpy, scrnum, attrib, &count);

        if(config == NULL || count == 0)
        {
                throw runtime_error("no matching pbuffer pixel format found");
        }

        // allocate the pbuffer
        //PBDC=glXCreateGLXPbufferSGIX(dpy, config[0], width, height,
PBattrib);
        //PBRC=glXCreateContextWithConfigSGIX(dpy, config[0],
GLX_RGBA_TYPE_SGIX, FBRC, true);

        PBDC=glXCreatePbuffer(dpy, config[0], PBattrib);
        PBRC=glXCreateNewContext(dpy, config[0], GLX_RGBA_TYPE, FBRC,
true);

        XFree(config);

        initialized=true;
}

void PBuffer::Destroy()
{
        // make sure the pbuffer has been initialized
        if ( !initialized )
        {
                throw runtime_error("pbuffer is not initialized");
        }

        Release();

        glXDestroyContext(dpy, PBRC);
        glXDestroyPbuffer(dpy, PBDC);

        initialized = false;
}

#endif
</code>


Wolfgang Draxinger
-- 
E-Mail address works, Jabber: hexarith@jabber.org, ICQ: 134682867

0
Reply Wolfgang 12/23/2006 9:32:19 PM

Wolfgang Draxinger wrote:

> You're not limited to use only the OpenGL functionality Qt gives
> you. It's perfectly possible to load extensions in parallel.
> GLEW e.g. will work just fine.
> 
> Creating the PBuffer is a bit trickier, since you need the
> XDisplay and a XVisual for that. Easiest way is to use
> functions, querying the currently set
> context/visual/display/screen and create a PBuffer from that. I
> once posted here a quick and dirty PBuffer class doing that for
> both Win32 and GLX. I just repost them here for reference.
> However the code is a bit old and contains some workaround for
> an issue of GLEW headers battling with GLX headers for the
> PBuffer function entry point identifiers. GLX >=1.3 support for
> PBuffers built in, while under Windows you need extensions, so
> this should still work.

Thanks Wolfgang, this looks promising. After getting glew set up
and adding #include <GL/glew.h> to the header file it all compiles
OK. I've got a couple of questions:

                 WGL_RED_BITS_ARB, 16, // at least 8 bits for RED channel
                 WGL_GREEN_BITS_ARB, 16, // at least 8 bits for GREEN channel
                 WGL_BLUE_BITS_ARB, 16, // at least 8 bits for BLUE channel
                 WGL_ALPHA_BITS_ARB, 16, // at least 8 bits for ALPHA channel

why 16 and not 8? If I use 16 here I get a crash since no matching
pbuffer pixel format is found.

Second question is can I just do:

     PBuffer pbuffer(width(), height());
     pbuffer.Use();

.... draw stuff

     glReadBuffer(GL_FRONT);
     glCopyTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 0, 0, 0, 0, width(), height());
     pbuffer.Release();

or is there something else needs doing to make the pbuffer the current context,
as I don't get anything in the texture?

- Keith



0
Reply Keith 12/24/2006 11:35:00 AM

Keith S. wrote:

> Thanks Wolfgang, this looks promising. After getting glew set
> up and adding #include <GL/glew.h> to the header file it all
> compiles OK. I've got a couple of questions:
> 
>                  WGL_RED_BITS_ARB, 16, // at least 8 bits for
>                  RED channel WGL_GREEN_BITS_ARB, 16, // at
>                  least 8 bits for GREEN channel
>                  WGL_BLUE_BITS_ARB, 16, // at least 8 bits for
>                  BLUE channel WGL_ALPHA_BITS_ARB, 16, // at
>                  least 8 bits for ALPHA channel
> 
> why 16 and not 8? If I use 16 here I get a crash since no
> matching pbuffer pixel format is found.

Oh, sorry, see the comments, where still 8 bit per channel are
mentioned. I once did some tests with non-consumer HW, that
supports up tp 16 bit per channel (not to be mistaken with float
buffers - a 3Dlabs card IIRC).
I took the code from this project and forget to change those
values back - another example why to use globaly declated, user
readable constants instead of magic numbers. Better first query
the capabilities of the hardware and set apropriatley.

Yes, your assumption on how to use the code is correct, though
the whole class is a Q'n'D hack (has no error checks, and such).
Important is, that once you've got things rendered into the
PBuffer you use PBuffer::Release to re-MakeCurrent the the
context being current before the PBuffer was used.

Also don't create the PBuffer class instance on the stack. The
only usefull place to have it on the stack would be the display
callback. But creating a PBuffer is a expensive operation.
Instead create the class instance with "new" once the OpenGL
context has been initialized.

Wolfgang Draxinger
-- 
E-Mail address works, Jabber: hexarith@jabber.org, ICQ: 134682867

0
Reply Wolfgang 12/24/2006 1:47:56 PM

Wolfgang Draxinger wrote:

> Oh, sorry, see the comments, where still 8 bit per channel are
> mentioned. I once did some tests with non-consumer HW, that
> supports up tp 16 bit per channel (not to be mistaken with float
> buffers - a 3Dlabs card IIRC).
> I took the code from this project and forget to change those
> values back - another example why to use globaly declated, user
> readable constants instead of magic numbers. Better first query
> the capabilities of the hardware and set apropriatley.
> 
> Yes, your assumption on how to use the code is correct, though
> the whole class is a Q'n'D hack (has no error checks, and such).
> Important is, that once you've got things rendered into the
> PBuffer you use PBuffer::Release to re-MakeCurrent the the
> context being current before the PBuffer was used.
> 
> Also don't create the PBuffer class instance on the stack. The
> only usefull place to have it on the stack would be the display
> callback. But creating a PBuffer is a expensive operation.
> Instead create the class instance with "new" once the OpenGL
> context has been initialized.

Thanks Wolfgang good tips. It appears to work, although there are
X errors:

X Error: BadDrawable (invalid Pixmap or Window parameter) 9
   Major opcode:  14
   Minor opcode:  0
   Resource id:  0x0

every time the display is refreshed...

- Keith
0
Reply Keith 12/24/2006 2:34:02 PM

Keith S. wrote:

> Thanks Wolfgang good tips. It appears to work, although there
> are X errors:
> 
> X Error: BadDrawable (invalid Pixmap or Window parameter) 9
>    Major opcode:  14
>    Minor opcode:  0
>    Resource id:  0x0
> 
> every time the display is refreshed...

As already told, this class has virtually none error handling,
which probably causes these messages. The posted code is and
remains a quick'n'dirty hack.

Wolfgang Draxinger
-- 
E-Mail address works, Jabber: hexarith@jabber.org, ICQ: 134682867

0
Reply Wolfgang 12/24/2006 4:54:41 PM

Wolfgang Draxinger wrote:

> As already told, this class has virtually none error handling,
> which probably causes these messages. The posted code is and
> remains a quick'n'dirty hack.

I discovered the reason after adding in some more error checking...
the glXCreatePbuffer call fails. Not sure if this means the ATI
9200 driver doesn't provide pbuffer support or what.

- Keith
0
Reply Keith 12/24/2006 5:14:30 PM

Keith S. wrote:

> I discovered the reason after adding in some more error
> checking... the glXCreatePbuffer call fails. Not sure if this
> means the ATI 9200 driver doesn't provide pbuffer support or
> what.

Yre you using the open source DRI drivers? Those don't support
PBuffers. Eventually I'll try to add this at some time into DRI,
since IMHO that's an important feature.

Wolfgang Draxinger
-- 
E-Mail address works, Jabber: hexarith@jabber.org, ICQ: 134682867

0
Reply Wolfgang 12/24/2006 5:56:25 PM

Wolfgang Draxinger wrote:

> Yre you using the open source DRI drivers? Those don't support
> PBuffers. Eventually I'll try to add this at some time into DRI,
> since IMHO that's an important feature.

No the ATI one - and checking, that doesn't have pbuffer support
for the radeon cards, only the FireGL ones.

Code works fine on a Solaris box with an Expert3D card though :)

- Keith
0
Reply Keith 12/24/2006 6:12:20 PM

Keith S. wrote:

> No the ATI one - and checking, that doesn't have pbuffer
> support for the radeon cards, only the FireGL ones.

The propritary ATI drivers also have PBuffers for Radeon, at
least they have it for Radeon 9800 cards, which is the card on
with I developed that PBuffer class in the first place, before I
used it in another project.

Wolfgang Draxinger
-- 
E-Mail address works, Jabber: hexarith@jabber.org, ICQ: 134682867

0
Reply Wolfgang 12/25/2006 12:36:36 AM

12 Replies
261 Views

(page loaded in 0.18 seconds)

Similiar Articles:








7/23/2012 4:15:34 PM


Reply: