|
|
|
@@ -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 ¶m, 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 ¶m, 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 ¶m, 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
|
|
|
|
|