Finished compression on Linux

* TODO: figure it out on Mac X OS, add deinterlace shader and maybe
  other shaders for decoding other codecs (v210 etc.)
This commit is contained in:
Martin Pulec
2011-10-11 14:05:46 +02:00
parent 99b0bc30ba
commit 38403bd760
11 changed files with 292 additions and 47 deletions

View File

@@ -71,7 +71,8 @@
*/
enum dxt_format {
DXT_FORMAT_RGB = 0,
DXT_FORMAT_YUV = 1
DXT_FORMAT_YUV = 1,
DXT_FORMAT_YUV422 = 2
};
/**
@@ -150,4 +151,4 @@ dxt_image_destroy(DXT_IMAGE_TYPE* image);
int
dxt_image_compressed_destroy(unsigned char* image_compressed);
#endif // DXT_COMMON_H
#endif // DXT_COMMON_H

View File

@@ -51,15 +51,60 @@ struct dxt_encoder
// Compressed texture
GLuint texture_compressed_id;
GLuint texture_yuv422;
// Framebuffer
GLuint fbo_id;
// Program and shader handles
GLhandleARB program_compress;
GLhandleARB shader_fragment_compress;
GLhandleARB shader_vertex_compress;
GLhandleARB shader_vertex_compress;
GLhandleARB yuv422_to_444_program;
GLhandleARB yuv422_to_444_fp;
GLuint fbo444_id;
};
int dxt_prepare_yuv422_shader(struct dxt_encoder *encoder);
int dxt_prepare_yuv422_shader(struct dxt_encoder *encoder) {
encoder->yuv422_to_444_fp = 0;
encoder->yuv422_to_444_fp = dxt_shader_create_from_source(fp_yuv422_to_yuv_444, GL_FRAGMENT_SHADER_ARB);
if ( encoder->yuv422_to_444_fp == 0) {
printf("Failed to compile YUV422->YUV444 fragment program!\n");
return 0;
}
encoder->yuv422_to_444_program = glCreateProgramObjectARB();
glAttachObjectARB(encoder->yuv422_to_444_program, encoder->shader_vertex_compress);
glAttachObjectARB(encoder->yuv422_to_444_program, encoder->yuv422_to_444_fp);
glLinkProgramARB(encoder->yuv422_to_444_program);
char log[32768];
glGetInfoLogARB(encoder->yuv422_to_444_program, 32768, NULL, (GLchar*)log);
if ( strlen(log) > 0 )
printf("Link Log: %s\n", log);
glGenTextures(1, &encoder->texture_yuv422);
glBindTexture(GL_TEXTURE_2D, encoder->texture_yuv422);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, encoder->width / 2, encoder->height,
0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glUseProgramObjectARB(encoder->yuv422_to_444_program);
glUniform1i(glGetUniformLocation(encoder->yuv422_to_444_program, "image"), 0);
glUniform2f(glGetUniformLocation(encoder->yuv422_to_444_program, "imageSize"), encoder->width, encoder->height);
// Create fbo
glGenFramebuffersEXT(1, &encoder->fbo444_id);
return 1;
}
/** Documented at declaration */
struct dxt_encoder*
dxt_encoder_create(enum dxt_type type, int width, int height, enum dxt_format format)
@@ -73,7 +118,7 @@ dxt_encoder_create(enum dxt_type type, int width, int height, enum dxt_format fo
encoder->format = format;
// Create empty data
GLubyte * data = NULL;
/*GLubyte * data = NULL;
int data_size = 0;
dxt_encoder_buffer_allocate(encoder, &data, &data_size);
// Create empty compressed texture
@@ -88,7 +133,7 @@ dxt_encoder_create(enum dxt_type type, int width, int height, enum dxt_format fo
else
glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, encoder->width, encoder->height, 0, data_size, data);
// Free empty data
dxt_encoder_buffer_free(data);
dxt_encoder_buffer_free(data);*/
// Create fbo
glGenFramebuffersEXT(1, &encoder->fbo_id);
@@ -134,29 +179,43 @@ dxt_encoder_create(enum dxt_type type, int width, int height, enum dxt_format fo
glGetInfoLogARB(encoder->program_compress, 32768, NULL, (GLchar*)log);
if ( strlen(log) > 0 )
printf("Link Log: %s\n", log);
glGenTextures(1, &encoder->texture_id);
glBindTexture(GL_TEXTURE_2D, encoder->texture_id);
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);
glTexImage2D(GL_TEXTURE_2D, 0, DXT_IMAGE_GL_FORMAT, encoder->width, encoder->height, 0, GL_RGBA, DXT_IMAGE_GL_TYPE, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, DXT_IMAGE_GL_FORMAT, encoder->width, encoder->height, 0, GL_RGBA, GL_BYTE, NULL);
glViewport(0, 0, encoder->width / 4, encoder->height / 4);
glDisable(GL_DEPTH_TEST);
//glActiveTexture(GL_TEXTURE0);
glEnable(GL_TEXTURE_2D);
if(format == DXT_FORMAT_YUV422) {
if(!dxt_prepare_yuv422_shader(encoder))
return NULL;
}
glBindTexture(GL_TEXTURE_2D, encoder->texture_id);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, encoder->width / 4, encoder->height / 4);
glDisable(GL_DEPTH_TEST);
// User compress program and set image size parameters
glUseProgramObjectARB(encoder->program_compress);
glUniform1i(glGetUniformLocation(encoder->program_compress, "imageFormat"), encoder->format);
glUniform1i(glGetUniformLocation(encoder->program_compress, "image"), 0);
if(format == DXT_FORMAT_YUV422) {
glUniform1i(glGetUniformLocation(encoder->program_compress, "imageFormat"), DXT_FORMAT_YUV);
} else {
glUniform1i(glGetUniformLocation(encoder->program_compress, "imageFormat"), encoder->format);
}
glUniform2f(glGetUniformLocation(encoder->program_compress, "imageSize"), encoder->width, encoder->height);
// Render to framebuffer
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, encoder->fbo_id);
return encoder;
}
@@ -187,9 +246,41 @@ int
dxt_encoder_compress(struct dxt_encoder* encoder, DXT_IMAGE_TYPE* image, unsigned char* image_compressed)
{
TIMER_INIT();
TIMER_START();
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, encoder->width, encoder->height, GL_RGBA, DXT_IMAGE_GL_TYPE, image);
if(encoder->format == DXT_FORMAT_YUV422) {
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, encoder->fbo444_id);
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, encoder->texture_id, 0);
//assert(GL_FRAMEBUFFER_COMPLETE_EXT == glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT));
glBindTexture(GL_TEXTURE_2D, encoder->texture_yuv422);
glPushAttrib(GL_VIEWPORT_BIT);
glViewport( 0, 0, encoder->width, encoder->height);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, encoder->width / 2, encoder->height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, image);
glUseProgramObjectARB(encoder->yuv422_to_444_program);
//glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0); glVertex2f(-1.0, -1.0);
glTexCoord2f(1.0, 0.0); glVertex2f(1.0, -1.0);
glTexCoord2f(1.0, 1.0); glVertex2f(1.0, 1.0);
glTexCoord2f(0.0, 1.0); glVertex2f(-1.0, 1.0);
glEnd();
glPopAttrib();
//glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glUseProgramObjectARB(encoder->program_compress);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, encoder->fbo_id);
glBindTexture(GL_TEXTURE_2D, encoder->texture_id);
//gl_check_error();
} else {
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, encoder->width, encoder->height, GL_RGBA, DXT_IMAGE_GL_TYPE, image);
}
#ifdef DEBUG
glFinish();
#endif

View File

@@ -0,0 +1,17 @@
#version 130
#extension GL_EXT_gpu_shader4 : enable
#define lerp mix
in vec4 TEX0;
uniform sampler2D image;
uniform vec2 imageSize;
out vec4 color;
void main()
{
color.rgba = texture(image, TEX0.xy).grba; // store Y0UVY1 ro rgba
if(TEX0.x * imageSize.x / 2 - floor(TEX0.x * imageSize.x / 2) > 0.25)
color.r = color.a; // use Y1 instead of Y0
}

View File

@@ -107,7 +107,8 @@ src/video_display/sage_wrapper.o: src/video_display/sage_wrapper.cxx
../dxt_compress/dxt_glsl.h:../dxt_compress/compress_vp.glsl \
../dxt_compress/compress_dxt1_fp.glsl ../dxt_compress/compress_dxt5ycocg_fp.glsl \
../dxt_compress/display_fp.glsl ../dxt_compress/display_dxt5ycocg_fp.glsl
../dxt_compress/display_fp.glsl ../dxt_compress/display_dxt5ycocg_fp.glsl \
../dxt_compress/yuv422_to_yuv444.glsl
echo "/**" > $@
echo " * GLSL source codes for DXT compressions" >> $@
echo " *" >> $@
@@ -133,6 +134,10 @@ src/video_display/sage_wrapper.o: src/video_display/sage_wrapper.cxx
echo "static const char fp_display_dxt5ycocg[] = " >> $@
cat ../dxt_compress/display_dxt5ycocg_fp.glsl | sed 's/\(.*\)/ \"\1\\n\"/' >> $@
echo ";" >> $@
# yuv 422 to yuv 444 shader
echo "static const char fp_yuv422_to_yuv_444[] = " >> $@
cat ../dxt_compress/yuv422_to_yuv444.glsl | sed 's/\(.*\)/ \"\1\\n\"/' >> $@
echo ";" >> $@
# -------------------------------------------------------------------------------------------------

View File

@@ -203,6 +203,7 @@ if test ! $no_x ; then
fi
fi
X_LIBS+=" -lX11"
X_OBJ="src/x11_common.o"
CFLAGS+=""
HAVE_X11=yes
fi
@@ -688,7 +689,7 @@ AC_CHECK_HEADER(GL/glx.h, FOUND_GLX_H=yes)
AC_CHECK_LIB(GL, glXCreateNewContext, FOUND_GLX_L=yes)
if test "$HAVE_X11" = yes -a "$FOUND_GLEW_L" = yes -a "$FOUND_GLEW_H" = yes -a "$FOUND_GLX_L" = yes -a "$FOUND_GLX_H" = yes \
-a ! expr "$host_os" : ".*darwin.*" > /dev/null # not mac, just for now
-a `expr "$host_os" : ".*darwin.*"` -eq 0 # not mac, just for now
then
LIBS+=" -lGLEW -lGL -lX11"
AC_DEFINE([HAVE_DXT_GLSL], [1], [Build with DXT_GLSL support])

View File

@@ -54,8 +54,10 @@
#include <stdlib.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <GL/glew.h>
#include <GL/gl.h>
#include <GL/glx.h>
#include "x11_common.h"
/*
* GLX context creation overtaken from:
@@ -66,8 +68,9 @@ struct video_compress {
struct dxt_encoder *encoder;
struct video_frame out;
char *decoded, *repacked;
char *decoded;
unsigned int configured:1;
unsigned int interlaced_input:1;
};
static void configure_with(struct video_compress *s, struct video_frame *frame);
@@ -338,6 +341,8 @@ static void configure_with(struct video_compress *s, struct video_frame *frame)
codec_t tmp = s->out.color_spec;
enum dxt_format format;
assert(frame->width % 4 == 0 && frame->height % 4 == 0);
glx_init();
memcpy(&s->out, frame, sizeof(struct video_frame));
@@ -358,19 +363,23 @@ static void configure_with(struct video_compress *s, struct video_frame *frame)
case Vuy2:
case DVS8:
s->out.decoder = (decoder_t) memcpy;
format = DXT_FORMAT_YUV;
format = DXT_FORMAT_YUV422;
break;
case v210:
s->out.decoder = (decoder_t) vc_copylinev210;
format = DXT_FORMAT_YUV;
format = DXT_FORMAT_YUV422;
break;
case DVS10:
s->out.decoder = (decoder_t) vc_copylineDVS10;
format = DXT_FORMAT_YUV;
format = DXT_FORMAT_YUV422;
break;
/*case DXT1:
case DXT1:
case DXT5:
fprintf(stderr, "Input frame is already comperssed!");
exit(128);*/
exit(128);
default:
fprintf(stderr, "Unknown codec: %d\n", s->out.color_spec);
exit(128);
}
s->out.src_bpp = get_bpp(s->out.color_spec);
s->out.src_linesize = s->out.width * s->out.src_bpp;
@@ -378,11 +387,14 @@ static void configure_with(struct video_compress *s, struct video_frame *frame)
(format == DXT_FORMAT_RGB ? 4 /*RGBA*/: 2/*YUV 422*/);
/* We will deinterlace the output frame */
if(s->out.aux & AUX_INTERLACED)
s->interlaced_input = TRUE;
else
s->interlaced_input = FALSE;
s->out.aux &= ~AUX_INTERLACED;
s->out.color_spec = tmp;
if(s->out.color_spec == DXT1) {
s->encoder = dxt_encoder_create(DXT_TYPE_DXT1, frame->width, frame->height, format);
s->out.aux |= AUX_RGB;
@@ -393,9 +405,13 @@ static void configure_with(struct video_compress *s, struct video_frame *frame)
s->out.data_len = frame->width * frame->height;
}
if(!s->encoder) {
fprintf(stderr, "[DXT GLSL] Failed to create encoder.\n");
exit(128);
}
s->out.data = (char *) malloc(s->out.data_len);
s->decoded = malloc(4 * frame->width * frame->height);
s->repacked = malloc(4 * frame->width * frame->height);
s->configured = TRUE;
}
@@ -407,7 +423,17 @@ struct video_compress * dxt_glsl_init(char * opts)
s = (struct video_compress *) malloc(sizeof(struct video_compress));
s->out.data = NULL;
s->decoded = NULL;
s->repacked = NULL;
x11_enter_thread();
if(opts && strcmp(opts, "help") == 0) {
printf("DXT GLSL comperssion usage:\n");
printf("\t-cg:DXT1\n");
printf("\t\tcompress with DXT1\n");
printf("\t-cg:DXT5_YCoCg\n");
printf("\t\tcompress with DXT5_YCoCg\n");
return NULL;
}
if(opts) {
if(strcasecmp(opts, "DXT5_YCoCg") == 0) {
@@ -437,35 +463,22 @@ struct video_frame * dxt_glsl_compress(void *arg, struct video_frame * tx)
configure_with(s, tx);
line1 = (unsigned char *)tx->data;
line2 = s->decoded;
line1 = (unsigned char *) tx->data;
line2 = (unsigned char *) s->decoded;
for (x = 0; x < tx->height; ++x) {
for (x = 0; x < (int) tx->height; ++x) {
s->out.decoder(line2, line1, s->out.src_linesize,
s->out.rshift, s->out.gshift, s->out.bshift);
line1 += s->out.src_linesize;
line2 += s->out.dst_linesize;
}
if(tx->color_spec == RGBA ||
tx->color_spec == R10k) {
dxt_encoder_compress(s->encoder, s->decoded, s->out.data);
} else {
const count = s->out.width * s->out.height;
/* Repack the data to YUV 4:4:4 Format */
for (x = 0; x < count; x += 2) {
s->repacked[4 * x] = s->decoded[2 * x + 1]; //Y1
s->repacked[4 * x + 1] = s->decoded[2 * x]; //U1
s->repacked[4 * x + 2] = s->decoded[2 * x + 2]; //V1
//s->repacked[4 * x + 3] = 255; //Alpha
if(s->interlaced_input)
vc_deinterlace((unsigned char *) s->decoded, s->out.dst_linesize, tx->height);
s->repacked[4 * x + 4] = s->decoded[2 * x + 3]; //Y2
s->repacked[4 * x + 5] = s->decoded[2 * x]; //U1
s->repacked[4 * x + 6] = s->decoded[2 * x + 2]; //V1
//s->repacked[4 * x + 7] = 255; //Alpha
}
dxt_encoder_compress(s->encoder, s->repacked, s->out.data);
}
dxt_encoder_compress(s->encoder,
(unsigned char *) s->decoded,
(unsigned char *) s->out.data);
return &s->out;
}

View File

@@ -164,6 +164,8 @@ static void usage(void)
printf("\n");
printf("\t-c \tcompress video\n");
printf("\n");
printf("\t-cg \tcompress video with OpenGL (see -cg:help for more options)\n");
printf("\n");
printf("\t-i \tiHDTV compatibility mode\n");
printf("\n");
printf("\taddress(es) \tdestination address\n");

View File

@@ -60,7 +60,7 @@
#include <GL/gl.h>
#include <GL/glext.h>
#include <GL/glut.h>
#include "x11_common.h"
#ifdef FREEGLUT
#include <GL/freeglut_ext.h>
#endif /* FREEGLUT */
@@ -219,6 +219,10 @@ void gl_check_error()
void * display_gl_init(char *fmt, unsigned int flags) {
UNUSED(flags);
struct state_gl *s;
#ifndef HAVE_MACOSX
x11_enter_thread();
#endif
glutInit(&uv_argc, uv_argv);
s = (struct state_gl *) calloc(1,sizeof(struct state_gl));

View File

@@ -64,6 +64,7 @@
void NSApplicationLoad();
#else /* HAVE_MACOSX */
#include <sys/io.h>
#include "x11_common.h"
#endif /* HAVE_MACOSX */
#include <sys/time.h>
@@ -611,6 +612,10 @@ void *display_sdl_init(char *fmt, unsigned int flags)
s = (struct state_sdl *)calloc(1, sizeof(struct state_sdl));
s->magic = MAGIC_SDL;
#ifndef HAVE_MACOSX
x11_enter_thread();
#endif
if (fmt != NULL) {
if (strcmp(fmt, "help") == 0) {
show_help();

View File

@@ -0,0 +1,58 @@
/*
* FILE: x11_common.c
* AUTHORS: Martin Benes <martinbenesh@gmail.com>
* Lukas Hejtmanek <xhejtman@ics.muni.cz>
* Petr Holub <hopet@ics.muni.cz>
* Milos Liska <xliska@fi.muni.cz>
* Jiri Matela <matela@ics.muni.cz>
* Dalibor Matura <255899@mail.muni.cz>
* Ian Wesley-Smith <iwsmith@cct.lsu.edu>
*
* Copyright (c) 2005-2010 CESNET z.s.p.o.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by CESNET z.s.p.o.
*
* 4. Neither the name of the CESNET nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
#include "config.h"
#include <pthread.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
static pthread_once_t XInitThreadsHasRun = PTHREAD_ONCE_INIT;
void x11_enter_thread(void)
{
pthread_once(&XInitThreadsHasRun, XInitThreads);
}

View File

@@ -0,0 +1,48 @@
/*
* FILE: x11_common.h
* AUTHORS: Martin Benes <martinbenesh@gmail.com>
* Lukas Hejtmanek <xhejtman@ics.muni.cz>
* Petr Holub <hopet@ics.muni.cz>
* Milos Liska <xliska@fi.muni.cz>
* Jiri Matela <matela@ics.muni.cz>
* Dalibor Matura <255899@mail.muni.cz>
* Ian Wesley-Smith <iwsmith@cct.lsu.edu>
*
* Copyright (c) 2005-2010 CESNET z.s.p.o.
*
* Redistribution and use in source and binary forms, with or without
* modification, is permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
*
* This product includes software developed by CESNET z.s.p.o.
*
* 4. Neither the name of the CESNET nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING,
* BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
void x11_enter_thread(void);