OpenGL RTT interface; X11 Pbuffer implementation (GL_ARB_pixel_buffer_object coming soon)

This commit is contained in:
Glenn Maynard
2006-07-26 03:39:01 +00:00
parent 33b2507ddd
commit 7f434a638f
4 changed files with 196 additions and 0 deletions
@@ -8,6 +8,9 @@
#include "DisplayResolutions.h"
#include "LocalizedString.h"
#include "RageDisplay_OGL_Helpers.h"
using namespace RageDisplay_OGL_Helpers;
#include <stack>
#include <math.h> // ceil()
#define GLX_GLXEXT_PROTOTYPES
@@ -312,6 +315,174 @@ bool LowLevelWindow_X11::SupportsThreadedRendering()
return g_pBackgroundContext != NULL;
}
class RenderTarget_X11: public RenderTarget
{
public:
RenderTarget_X11( LowLevelWindow_X11 *pWind );
~RenderTarget_X11();
void Create( const RenderTargetParam &param, int &iTextureWidthOut, int &iTextureHeightOut );
unsigned GetTexture() const { return m_iTexHandle; }
void StartRenderingTo();
void FinishRenderingTo();
/* Copying from the Pbuffer to the texture flips Y. */
virtual bool InvertY() const { return true; }
private:
int m_iWidth, m_iHeight;
LowLevelWindow_X11 *m_pWind;
GLXPbuffer m_iPbuffer;
GLXContext m_pPbufferContext;
unsigned int m_iTexHandle;
GLXContext m_pOldContext;
GLXDrawable m_pOldDrawable;
};
RenderTarget_X11::RenderTarget_X11( LowLevelWindow_X11 *pWind )
{
m_pWind = pWind;
m_iPbuffer = 0;
m_pPbufferContext = NULL;
m_iTexHandle = 0;
m_pOldContext = NULL;
m_pOldDrawable = 0;
}
RenderTarget_X11::~RenderTarget_X11()
{
if( m_pPbufferContext )
glXDestroyContext( X11Helper::Dpy, m_pPbufferContext );
if( m_iPbuffer )
glXDestroyPbuffer( X11Helper::Dpy, m_iPbuffer );
if( m_iTexHandle )
glDeleteTextures( 1, reinterpret_cast<GLuint*>(&m_iTexHandle) );
}
/* Note that although the texture size may need to be a power of 2, the Pbuffer
* does not. */
void RenderTarget_X11::Create( const RenderTargetParam &param, int &iTextureWidthOut, int &iTextureHeightOut )
{
//ASSERT( param.iWidth == power_of_two(param.iWidth) && param.iHeight == power_of_two(param.iHeight) );
m_iWidth = param.iWidth;
m_iHeight = param.iHeight;
int pConfigAttribs[] =
{
GLX_DRAWABLE_TYPE, GLX_PBUFFER_BIT,
GLX_RENDER_TYPE, GLX_RGBA_BIT,
GLX_RED_SIZE, 8,
GLX_GREEN_SIZE, 8,
GLX_BLUE_SIZE, 8,
GLX_ALPHA_SIZE, param.bWithAlpha? 8:GLX_DONT_CARE,
GLX_DOUBLEBUFFER, False,
GLX_DEPTH_SIZE, param.bWithDepthBuffer? 16:GLX_DONT_CARE,
None
};
int iConfigs;
GLXFBConfig *pConfigs = glXChooseFBConfig( X11Helper::Dpy, DefaultScreen(X11Helper::Dpy), pConfigAttribs, &iConfigs );
ASSERT( pConfigs );
const int pPbufferAttribs[] =
{
GLX_PBUFFER_WIDTH, param.iWidth,
GLX_PBUFFER_HEIGHT, param.iHeight,
None
};
for( int i = 0; i < iConfigs; ++i )
{
m_iPbuffer = glXCreatePbuffer( X11Helper::Dpy, pConfigs[i], pPbufferAttribs );
if( m_iPbuffer == 0 )
continue;
XVisualInfo *pVisual = glXGetVisualFromFBConfig( X11Helper::Dpy, pConfigs[i] );
m_pPbufferContext = glXCreateContext( X11Helper::Dpy, pVisual, g_pContext, True );
ASSERT( m_pPbufferContext );
XFree( pVisual );
break;
}
ASSERT( m_iPbuffer );
// allocate OpenGL texture resource
glGenTextures( 1, reinterpret_cast<GLuint*>(&m_iTexHandle) );
glBindTexture( GL_TEXTURE_2D, m_iTexHandle );
LOG->Trace( "n %i, %ix%i", m_iTexHandle, param.iWidth, param.iHeight );
while( glGetError() != GL_NO_ERROR )
;
int iTextureWidth = power_of_two( param.iWidth );
int iTextureHeight = power_of_two( param.iHeight );
iTextureWidthOut = iTextureWidth;
iTextureHeightOut = iTextureHeight;
glTexImage2D( GL_TEXTURE_2D, 0, param.bWithAlpha? GL_RGBA8:GL_RGB8,
iTextureWidth, iTextureHeight, 0, param.bWithAlpha? GL_RGBA:GL_RGB, GL_UNSIGNED_BYTE, NULL );
GLenum error = glGetError();
ASSERT_M( error == GL_NO_ERROR, GLToString(error) );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_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 );
}
void RenderTarget_X11::StartRenderingTo()
{
m_pOldContext = glXGetCurrentContext();
m_pOldDrawable = glXGetCurrentDrawable();
glXMakeCurrent( X11Helper::Dpy, m_iPbuffer, m_pPbufferContext );
glViewport( 0, 0, m_iWidth, m_iHeight );
}
void RenderTarget_X11::FinishRenderingTo()
{
glFlush();
glBindTexture( GL_TEXTURE_2D, m_iTexHandle );
while( glGetError() != GL_NO_ERROR )
;
glCopyTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 0, 0, m_iWidth, m_iHeight );
GLenum error = glGetError();
ASSERT_M( error == GL_NO_ERROR, GLToString(error) );
glBindTexture( GL_TEXTURE_2D, 0 );
glXMakeCurrent( X11Helper::Dpy, m_pOldDrawable, m_pOldContext );
m_pOldContext = NULL;
m_pOldDrawable = 0;
}
bool LowLevelWindow_X11::SupportsRenderToTexture() const
{
/* Server must support pbuffers: */
const int iScreen = DefaultScreen( X11Helper::Dpy );
float fVersion = strtof( glXQueryServerString(X11Helper::Dpy, iScreen, GLX_VERSION), NULL );
if( fVersion < 1.3f )
return false;
return true;
}
RenderTarget *LowLevelWindow_X11::CreateRenderTarget( const RenderTargetParam &param, int &iTextureWidthOut, int &iTextureHeightOut )
{
RenderTarget_X11 *pTarget = new RenderTarget_X11( this );
pTarget->Create( param, iTextureWidthOut, iTextureHeightOut );
return pTarget;
}
void LowLevelWindow_X11::BeginConcurrentRenderingMainThread()
{
/* Move the main thread, which is going to be loading textures, etc. but