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
+17
View File
@@ -33,6 +33,23 @@ namespace RageDisplay_OGL_Helpers
RString GLToString( GLenum e );
};
class RenderTarget
{
public:
virtual ~RenderTarget() { }
virtual unsigned GetTexture() const = 0;
/* Render to this RenderTarget. */
virtual void StartRenderingTo() = 0;
/* Stop rendering to this RenderTarget. Update the texture, if necessary, and
* make it available. */
virtual void FinishRenderingTo() = 0;
virtual bool InvertY() const { return false; }
};
class LowLevelWindow;
struct GLExt_t
{
@@ -8,6 +8,8 @@
class DisplayResolution;
typedef set<DisplayResolution> DisplayResolutions;
class VideoModeParams;
class RenderTarget;
struct RenderTargetParam;
class LowLevelWindow
{
@@ -30,6 +32,9 @@ public:
virtual const VideoModeParams &GetActualVideoModeParams() const = 0;
virtual bool SupportsRenderToTexture() const { return false; }
virtual RenderTarget *CreateRenderTarget( const RenderTargetParam &param, int &iTextureWidthOut, int &iTextureHeightOut ) { return NULL; }
virtual bool SupportsThreadedRendering() { return false; }
virtual void BeginConcurrentRenderingMainThread() { }
virtual void EndConcurrentRenderingMainThread() { }
@@ -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
@@ -22,6 +22,9 @@ public:
void GetDisplayResolutions( DisplayResolutions &out ) const;
float GetMonitorAspectRatio() const;
bool SupportsRenderToTexture() const;
RenderTarget *CreateRenderTarget( const RenderTargetParam &param, int &iTextureWidthOut, int &iTextureHeightOut );
bool SupportsThreadedRendering();
void BeginConcurrentRenderingMainThread();
void EndConcurrentRenderingMainThread();