#include "packsingle.h"
#include "glxclient.h"
#include <extensions/extutil.h>
#include <extensions/Xext.h>
#include <string.h>
#include "glapi.h"
#include "glxextensions.h"
#include "simple_list.h"
#define SET_BIT(m,b) (m[ (b) / 8 ] |= (1U << ((b) % 8)))
#define CLR_BIT(m,b) (m[ (b) / 8 ] &= ~(1U << ((b) % 8)))
#define IS_SET(m,b) ((m[ (b) / 8 ] & (1U << ((b) % 8))) != 0)
#define CONCAT(a,b) a ## b
#define GLX(n) "GLX_" # n, 4 + sizeof( # n ) - 1, CONCAT(n,_bit)
#define VER(a,b) a, b
#define Y 1
#define N 0
#define EXT_ENABLED(bit,supported) ((bit < 255) && IS_SET( supported, bit ))
static const struct {
const char * const name;
unsigned name_len;
unsigned char bit;
unsigned char version_major;
unsigned char version_minor;
unsigned char client_support;
unsigned char direct_support;
unsigned char client_only;
unsigned char direct_only;
} known_glx_extensions[] = {
{ GLX(ARB_get_proc_address), VER(1,4), Y, N, Y, N },
{ GLX(ARB_multisample), VER(1,4), Y, N, N, N },
{ GLX(ARB_render_texture), VER(0,0), N, N, N, N },
{ GLX(ATI_pixel_format_float), VER(0,0), N, N, N, N },
{ GLX(EXT_import_context), VER(0,0), Y, Y, N, N },
{ GLX(EXT_visual_info), VER(0,0), Y, Y, N, N },
{ GLX(EXT_visual_rating), VER(0,0), Y, Y, N, N },
{ GLX(MESA_agp_offset), VER(0,0), N, N, N, Y },
{ GLX(MESA_allocate_memory), VER(0,0), Y, N, N, Y },
{ GLX(MESA_copy_sub_buffer), VER(0,0), N, N, N, N },
{ GLX(MESA_pixmap_colormap), VER(0,0), N, N, N, N },
{ GLX(MESA_release_buffers), VER(0,0), N, N, N, N },
{ GLX(MESA_set_3dfx_mode), VER(0,0), N, N, N, N },
{ GLX(MESA_swap_control), VER(0,0), Y, N, N, Y },
{ GLX(MESA_swap_frame_usage), VER(0,0), Y, N, N, Y },
{ GLX(NV_float_buffer), VER(0,0), N, N, N, N },
{ GLX(NV_render_depth_texture), VER(0,0), N, N, N, N },
{ GLX(NV_render_texture_rectangle), VER(0,0), N, N, N, N },
{ GLX(NV_vertex_array_range), VER(0,0), N, N, N, Y },
{ GLX(OML_swap_method), VER(0,0), Y, N, N, N },
{ GLX(OML_sync_control), VER(0,0), Y, N, N, Y },
{ GLX(SGI_cushion), VER(0,0), N, N, N, N },
{ GLX(SGI_make_current_read), VER(1,3), Y, N, N, N },
{ GLX(SGI_swap_control), VER(0,0), Y, N, N, N },
{ GLX(SGI_video_sync), VER(0,0), Y, N, N, Y },
{ GLX(SGIS_blended_overlay), VER(0,0), N, N, N, N },
{ GLX(SGIS_color_range), VER(0,0), N, N, N, N },
{ GLX(SGIS_multisample), VER(0,0), Y, N, N, N },
{ GLX(SGIX_dm_buffer), VER(0,0), N, N, N, N },
{ GLX(SGIX_fbconfig), VER(1,3), Y, N, N, N },
{ GLX(SGIX_pbuffer), VER(1,3), N, N, N, N },
{ GLX(SGIX_swap_barrier), VER(0,0), N, N, N, N },
{ GLX(SGIX_swap_group), VER(0,0), N, N, N, N },
{ GLX(SGIX_video_resize), VER(0,0), N, N, N, N },
{ GLX(SGIX_video_source), VER(0,0), N, N, N, N },
{ GLX(SGIX_visual_select_group), VER(0,0), Y, N, N, N },
{ GLX(SUN_get_transparent_index), VER(0,0), N, N, N, N },
{ NULL }
};
static unsigned char client_support[8];
static unsigned char client_only[8];
static unsigned char direct_only[8];
static unsigned char direct_support[8];
static const char * __glXGLXClientExtensions = NULL;
static void __glXExtensionsCtr( void );
static void __glXExtensionsCtrScreen( __GLXscreenConfigs *psc );
static void __glXProcessServerString( const char * server_string,
unsigned char * server_support );
static void
set_glx_extension( const char * name, unsigned name_len, GLboolean state,
unsigned char * supported )
{
unsigned i;
for ( i = 0 ; known_glx_extensions[i].name != NULL ; i++ ) {
if ( (name_len == known_glx_extensions[i].name_len)
&& (strncmp( known_glx_extensions[i].name, name, name_len ) == 0) ) {
if ( state ) {
SET_BIT( supported, known_glx_extensions[i].bit );
}
else {
CLR_BIT( supported, known_glx_extensions[i].bit );
}
return;
}
}
}
#define NUL '\0'
#define SEPARATOR ' '
static void
__glXProcessServerString( const char * server_string,
unsigned char * server_support )
{
unsigned base;
unsigned len;
(void) memset( server_support, 0, 8 );
for ( base = 0 ; server_string[ base ] != NUL ; ) {
for ( len = 0
; (server_string[ base + len ] != SEPARATOR)
&& (server_string[ base + len ] != NUL)
; len++ ) {
}
set_glx_extension( & server_string[ base ], len, GL_TRUE,
server_support );
for ( base += len ;
(server_string[ base ] == SEPARATOR)
&& (server_string[ base ] != NUL)
; base++ ) {
}
}
}
void
__glXScrEnableExtension( __GLXscreenConfigs *psc, const char * name )
{
__glXExtensionsCtr();
__glXExtensionsCtrScreen(psc);
set_glx_extension( name, strlen( name ), GL_TRUE, psc->direct_support );
}
static void
__glXExtensionsCtr( void )
{
unsigned i;
static GLboolean ext_list_first_time = GL_TRUE;
if ( ext_list_first_time ) {
ext_list_first_time = GL_FALSE;
(void) memset( client_support, 0, sizeof( client_support ) );
(void) memset( direct_support, 0, sizeof( direct_support ) );
(void) memset( client_only, 0, sizeof( client_only ) );
(void) memset( direct_only, 0, sizeof( direct_only ) );
for ( i = 0 ; known_glx_extensions[i].name != NULL ; i++ ) {
const unsigned bit = known_glx_extensions[i].bit;
if ( known_glx_extensions[i].client_support ) {
SET_BIT( client_support, bit );
}
if ( known_glx_extensions[i].direct_support ) {
SET_BIT( direct_support, bit );
}
if ( known_glx_extensions[i].client_only ) {
SET_BIT( client_only, bit );
}
if ( known_glx_extensions[i].direct_only ) {
SET_BIT( direct_only, bit );
}
}
}
}
static void
__glXExtensionsCtrScreen( __GLXscreenConfigs *psc )
{
if (psc->ext_list_first_time) {
psc->ext_list_first_time = GL_FALSE;
(void) memcpy( psc->direct_support, direct_support,
sizeof( direct_support ) );
}
}
GLboolean
__glXExtensionBitIsEnabled( __GLXscreenConfigs *psc, unsigned bit )
{
GLboolean enabled = GL_FALSE;
if ( psc != NULL ) {
__glXExtensionsCtr();
__glXExtensionsCtrScreen( psc );
enabled = EXT_ENABLED( bit, psc->direct_support );
}
return enabled;
}
static char *
__glXGetStringFromTable( const unsigned char * supported )
{
unsigned i;
unsigned ext_str_len;
char * ext_str;
char * point;
ext_str_len = 0;
for ( i = 0 ; known_glx_extensions[i].name != NULL ; i++ ) {
if ( EXT_ENABLED( known_glx_extensions[i].bit, supported ) ) {
ext_str_len += known_glx_extensions[i].name_len + 1;
}
}
ext_str = Xmalloc( ext_str_len + 1 );
if ( ext_str != NULL ) {
point = ext_str;
for ( i = 0 ; known_glx_extensions[i].name != NULL ; i++ ) {
if ( EXT_ENABLED( known_glx_extensions[i].bit, supported ) ) {
(void) memcpy( point, known_glx_extensions[i].name,
known_glx_extensions[i].name_len );
point += known_glx_extensions[i].name_len;
*point = ' ';
point++;
}
}
*point = '\0';
}
return ext_str;
}
const char *
__glXGetClientExtensions( void )
{
if ( __glXGLXClientExtensions == NULL ) {
__glXExtensionsCtr();
__glXGLXClientExtensions = __glXGetStringFromTable( client_support );
}
return __glXGLXClientExtensions;
}
static char *
MergeUsableExtensions(const char *clientGLXexts,
const char *serverGLXexts,
GLboolean direct) {
char *result = NULL;
size_t resultLength = 0;
size_t resultOffset = 0;
int exti;
resultLength = 20;
result = Xmalloc(resultLength);
if(NULL == result) {
perror("Xmalloc");
abort();
}
for(exti = 0; known_glx_extensions[exti].name; ++exti) {
const char *name = known_glx_extensions[exti].name;
int nameLength = strlen(name);
GLboolean add = GL_FALSE;
if(known_glx_extensions[exti].client_only
&& strstr(clientGLXexts, name)) {
add = GL_TRUE;
}
if(strstr(serverGLXexts, name)
&& strstr(clientGLXexts, name)) {
add = GL_TRUE;
}
if(known_glx_extensions[exti].direct_only && !direct)
continue;
if(add) {
size_t requestLength = nameLength + 1 + 1;
if(resultLength < (requestLength + resultOffset)) {
resultLength = requestLength + resultLength * 2;
result = Xrealloc(result, resultLength);
if(NULL == result) {
perror("Xrealloc");
abort();
}
}
memcpy(result + resultOffset, name, nameLength);
result[resultOffset + nameLength] = ' ';
resultOffset += nameLength + 1;
}
}
result[resultOffset] = '\0';
return result;
}
void
__glXCalculateUsableExtensions( __GLXscreenConfigs *psc,
GLboolean display_is_direct_capable,
int minor_version )
{
const char *clientGLXexts;
__glXExtensionsCtr();
__glXExtensionsCtrScreen( psc );
clientGLXexts = __glXGetClientExtensions();
if ( minor_version >= 3 ) {
}
if ( display_is_direct_capable ) {
psc->effectiveGLXexts = MergeUsableExtensions(clientGLXexts,
psc->serverGLXexts,
GL_TRUE);
}
else {
psc->effectiveGLXexts = MergeUsableExtensions(clientGLXexts,
psc->serverGLXexts,
GL_FALSE);
}
}