00001
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005
00006
00007
00008
00009
00010
00011 #include "vgui_accelerate_x11.h"
00012
00013
00014 #if VGUI_MESA
00015
00016
00017
00018
00019
00020
00021 #include <vcl_iostream.h>
00022 #include <vcl_cmath.h>
00023 #include <vcl_cassert.h>
00024 #include <vcl_cstring.h>
00025 #include <vcl_algorithm.h>
00026
00027 #include <X11/Xlib.h>
00028 #include <X11/Xutil.h>
00029
00030
00031
00032
00033
00034
00035
00036 #ifdef HAS_HERMES
00037
00038 struct gl_to_hermes_format_map
00039 {
00040 GLenum gl_format;
00041 GLenum gl_type;
00042 int32 bits_per_pixel;
00043 int32 red_mask;
00044 int32 green_mask;
00045 int32 blue_mask;
00046 int32 alpha_mask;
00047 };
00048
00049
00050 #define endian_swap32(x) (((x&0x000000ff)<<24) | ((x&0x0000ff00)<<8) | ((x&0x00ff0000)>>8) | ((x&0xff000000)>>24))
00051
00052
00053
00054
00055
00056 #if VXL_LITTLE_ENDIAN
00057 # define s(x) x
00058 #else
00059 # define s(x) endian_swap32(x)
00060 #endif
00061 gl_to_hermes_format_map gl_to_hermes_formats[] =
00062 {
00063 {GL_RGBA, GL_UNSIGNED_BYTE, 32, s(0x000000ff), s(0x0000ff00), s(0x00ff0000), 0},
00064 {GL_BGRA, GL_UNSIGNED_BYTE, 32, s(0x00ff0000), s(0x0000ff00), s(0x000000ff), 0},
00065 {GL_ABGR_EXT, GL_UNSIGNED_BYTE, 32, s(0xff000000), s(0x00ff0000), s(0x0000ff00), 0},
00066 {GL_BGR, GL_UNSIGNED_BYTE, 24, s(0x00ff0000), s(0x0000ff00), s(0x000000ff), 0},
00067 {GL_RGB, GL_UNSIGNED_SHORT_5_6_5, 16, (0x0000f800), (0x000007e0), (0x0000001f), 0}
00068
00069 };
00070 #undef s
00071 const int number_of_accelerated_formats = sizeof(gl_to_hermes_formats) / sizeof(gl_to_hermes_formats[0]);
00072 #endif
00073
00074 vgui_accelerate_x11::vgui_accelerate_x11()
00075 {
00076 vcl_cerr << __FILE__ ": Initializing Mesa/X11 accelerator\n";
00077
00078 #ifdef HAS_HERMES
00079 vcl_cerr << __FILE__ ": Initializing Hermes\n";
00080 Hermes_Init();
00081 hermes_clearer = Hermes_ClearerInstance();
00082 hermes_converter = Hermes_ConverterInstance(HERMES_CONVERT_NORMAL);
00083 #endif
00084
00085 aux_buffer = 0;
00086 aux_buffer_size = 0;
00087 }
00088
00089 vgui_accelerate_x11::~vgui_accelerate_x11()
00090 {
00091 vcl_cerr << __FILE__ ": Destroying Mesa/X11 accelerator\n";
00092
00093 delete[] aux_buffer;
00094
00095 #ifdef HAS_HERMES
00096 Hermes_ClearerReturn(hermes_clearer);
00097 Hermes_ConverterReturn(hermes_converter);
00098 Hermes_Done();
00099 #endif
00100 }
00101
00102 bool vgui_accelerate_x11::vgui_glClear( GLbitfield mask )
00103 {
00104 if (!vgui_no_acceleration)
00105 {
00106 #if defined(VGUI_MESA) && defined(HAS_HERMES)
00107 GLint render_mode;
00108 GLboolean rgba_mode;
00109 GLint draw_buffer;
00110 glGetIntegerv (GL_RENDER_MODE, &render_mode);
00111 glGetBooleanv (GL_RGBA_MODE, &rgba_mode);
00112 glGetIntegerv (GL_DRAW_BUFFER, &draw_buffer);
00113 if (render_mode == GL_RENDER && (draw_buffer == GL_BACK || draw_buffer == GL_BACK_LEFT) && rgba_mode == GL_TRUE)
00114 {
00115 if (mask & GL_COLOR_BUFFER_BIT)
00116 {
00117 Pixmap p_dummy;
00118 XImage* backbuffer;
00119 XMesaBuffer mesabuf = XMesaGetCurrentBuffer();
00120 XMesaGetBackBuffer(mesabuf, &p_dummy, &backbuffer);
00121
00122 int x_min, x_max, y_min, y_max;
00123 GLboolean scissor_enabled;
00124 glGetBooleanv(GL_SCISSOR_TEST, &scissor_enabled);
00125 if (scissor_enabled) {
00126 GLint scissor_box[4];
00127 glGetIntegerv(GL_SCISSOR_BOX, scissor_box);
00128 x_min = vcl_max(scissor_box[0], 0);
00129 y_min = vcl_max(scissor_box[1], 0);
00130 x_max = vcl_min(scissor_box[0] + scissor_box[2], backbuffer->width);
00131 y_max = vcl_min(scissor_box[1] + scissor_box[3], backbuffer->height);
00132 } else {
00133 x_min = 0;
00134 y_min = 0;
00135 x_max = backbuffer->width;
00136 y_max = backbuffer->height;
00137 }
00138
00139 GLfloat clear_color[4];
00140 glGetFloatv(GL_COLOR_CLEAR_VALUE, clear_color);
00141
00142 HermesFormat* dest_format =
00143 Hermes_FormatNew(backbuffer->bits_per_pixel,
00144 backbuffer->red_mask, backbuffer->green_mask, backbuffer->blue_mask, 0, 0);
00145 Hermes_ClearerRequest (hermes_clearer, dest_format);
00146 Hermes_ClearerClear(hermes_clearer,backbuffer->data,
00147 x_min, backbuffer->height - y_max,
00148 x_max - x_min, y_max - y_min,
00149 backbuffer->bytes_per_line,
00150 (int32)(clear_color[0]*255.0F),
00151 (int32)(clear_color[1]*255.0F),
00152 (int32)(clear_color[2]*255.0F),
00153 (int32)(clear_color[3]*255.0F));
00154 Hermes_FormatFree(dest_format);
00155 }
00156 GLbitfield leftover = mask & ~(GL_COLOR_BUFFER_BIT);
00157 if (leftover != 0) glClear( leftover );
00158 return true;
00159 }
00160 #endif // If we have been successful then we should never reach this point!!
00161 }
00162
00163
00164 return vgui_accelerate::vgui_glClear( mask );
00165 }
00166
00167 bool vgui_accelerate_x11::vgui_glDrawPixels( GLsizei width, GLsizei height,
00168 GLenum format, GLenum type,
00169 const GLvoid *pixels )
00170 {
00171 if (!vgui_no_acceleration)
00172 {
00173 #if defined(VGUI_MESA) && defined(HAS_HERMES)
00174 GLint render_mode;
00175 GLboolean rgba_mode;
00176 GLint draw_buffer;
00177 GLboolean raster_pos_valid;
00178 GLboolean depth_test_enabled;
00179 GLfloat pixel_zoom_x;
00180 GLfloat pixel_zoom_y;
00181 glGetBooleanv (GL_CURRENT_RASTER_POSITION_VALID, &raster_pos_valid);
00182 if (!raster_pos_valid) return true;
00183 glGetIntegerv (GL_RENDER_MODE, &render_mode);
00184 glGetBooleanv (GL_RGBA_MODE, &rgba_mode);
00185 glGetIntegerv (GL_DRAW_BUFFER, &draw_buffer);
00186 glGetBooleanv (GL_DEPTH_TEST, &depth_test_enabled);
00187 glGetFloatv (GL_ZOOM_X, &pixel_zoom_x);
00188 glGetFloatv (GL_ZOOM_Y, &pixel_zoom_y);
00189 if (render_mode == GL_RENDER && (draw_buffer == GL_BACK || draw_buffer == GL_BACK_LEFT) && rgba_mode == GL_TRUE &&
00190 !depth_test_enabled && pixel_zoom_x > 0 && pixel_zoom_y < 0)
00191 {
00192
00193 bool found_match = false;
00194 int format_index;
00195 for (int i=0; i < number_of_accelerated_formats && !found_match; ++i) {
00196 if (gl_to_hermes_formats[i].gl_format == format && gl_to_hermes_formats[i].gl_type == type) {
00197 found_match = true;
00198 format_index = i;
00199 }
00200 }
00201 if (found_match)
00202 {
00203 HermesFormat* src_format =
00204 Hermes_FormatNew(gl_to_hermes_formats[format_index].bits_per_pixel,
00205 gl_to_hermes_formats[format_index].red_mask,
00206 gl_to_hermes_formats[format_index].green_mask,
00207 gl_to_hermes_formats[format_index].blue_mask,
00208 0, 0);
00209 Pixmap p_dummy;
00210 XImage* backbuffer;
00211 XMesaBuffer mesabuf = XMesaGetCurrentBuffer();
00212 XMesaGetBackBuffer(mesabuf, &p_dummy, &backbuffer);
00213
00214 HermesFormat* dest_format =
00215 Hermes_FormatNew(backbuffer->bits_per_pixel,
00216 backbuffer->red_mask,
00217 backbuffer->green_mask,
00218 backbuffer->blue_mask,
00219 0, 0);
00220
00221
00222 GLint raster_pos[4];
00223 GLint skip_pixels;
00224 GLint skip_rows;
00225 glGetIntegerv (GL_CURRENT_RASTER_POSITION, raster_pos);
00226 glGetIntegerv (GL_UNPACK_SKIP_PIXELS, &skip_pixels);
00227 glGetIntegerv (GL_UNPACK_SKIP_ROWS, &skip_rows);
00228
00229 #if 0 // commented out
00230 vcl_cerr << "bb width " << backbuffer->width << vcl_endl
00231 << "bb height " << backbuffer->height << vcl_endl
00232 << "raspos " << raster_pos[0] << ' ' << raster_pos[1]
00233 << ' ' << raster_pos[2] << ' ' << raster_pos[3] << vcl_endl
00234 << "pz x " << pixel_zoom_x << vcl_endl
00235 << "pz y " << pixel_zoom_y << vcl_endl
00236 << "skip x " << skip_pixels << vcl_endl
00237 << "skip y " << skip_rows << vcl_endl
00238 << "width " << width << vcl_endl
00239 << "height " << height << vcl_endl;
00240 #endif
00241
00242
00243 float dest_x_min, dest_y_min, dest_x_max, dest_y_max;
00244 if (pixel_zoom_x > 0) {
00245 dest_x_min = raster_pos[0];
00246 dest_x_max = raster_pos[0] + pixel_zoom_x * width;
00247 } else {
00248 dest_x_min = raster_pos[0] + 1 + pixel_zoom_x * width;
00249 dest_x_max = raster_pos[0] + 1;
00250 }
00251 if (pixel_zoom_y > 0) {
00252 dest_y_min = raster_pos[1];
00253 dest_y_max = raster_pos[1] + pixel_zoom_y * height;
00254 } else {
00255 dest_y_min = raster_pos[1] + 1 + pixel_zoom_y * height;
00256 dest_y_max = raster_pos[1] + 1;
00257 }
00258
00259 #if 0 // commented out
00260 vcl_cerr << dest_x_min << ' ' << dest_x_max << vcl_endl
00261 << dest_y_min << ' ' << dest_y_max << vcl_endl;
00262 #endif
00263
00264 float window_x_min, window_y_min, window_x_max, window_y_max;
00265 GLboolean scissor_enabled;
00266 glGetBooleanv (GL_SCISSOR_TEST, &scissor_enabled);
00267 if (scissor_enabled) {
00268 GLint scissor_box[4];
00269 glGetIntegerv (GL_SCISSOR_BOX, scissor_box);
00270 window_x_min = vcl_max(scissor_box[0], 0);
00271 window_y_min = vcl_max(scissor_box[1], 0);
00272 window_x_max = vcl_min(scissor_box[0] + scissor_box[2], backbuffer->width);
00273 window_y_max = vcl_min(scissor_box[1] + scissor_box[3], backbuffer->height);
00274 } else {
00275 window_x_min = 0.0;
00276 window_y_min = 0.0;
00277 window_x_max = backbuffer->width;
00278 window_y_max = backbuffer->height;
00279 }
00280
00281 int src_x_min = 0;
00282 int src_y_min = 0;
00283 int src_x_max = width;
00284 int src_y_max = height;
00285
00286 float abs_px_x = vcl_fabs(pixel_zoom_x);
00287 float abs_px_y = vcl_fabs(pixel_zoom_y);
00288
00289 if (dest_x_min < window_x_min) {
00290 int dw = (int)vcl_ceil((window_x_min - dest_x_min)/abs_px_x);
00291 src_x_min += dw;
00292 dest_x_min += dw * abs_px_x;
00293 }
00294 if (dest_x_max > window_x_max) {
00295 int dw = (int)vcl_ceil((dest_x_max - window_x_max)/abs_px_x);
00296 src_x_max -= dw;
00297 dest_x_max -= dw * abs_px_x;
00298 }
00299 if (dest_y_min < window_y_min) {
00300 int dh = (int)vcl_ceil((window_y_min - dest_y_min)/abs_px_y);
00301 src_y_min += dh;
00302 dest_y_min += dh * abs_px_y;
00303 }
00304 if (dest_y_max > window_y_max) {
00305 int dh = (int)vcl_ceil((dest_y_max - window_y_max)/abs_px_y);
00306 src_y_max -= dh;
00307 dest_y_max -= dh * abs_px_y;
00308 }
00309
00310 #if 0 // commented out
00311 vcl_cerr << "clipped dest -\n"
00312 << dest_x_min << ' ' << dest_x_max << vcl_endl
00313 << dest_y_min << ' ' << dest_y_max << vcl_endl
00314 << "clipped src -\n"
00315 << src_x_min << ' ' << src_x_max << vcl_endl
00316 << src_y_min << ' ' << src_y_max << vcl_endl;
00317 #endif
00318
00319
00320
00321 if (pixel_zoom_x > 0)
00322 skip_pixels += src_x_min;
00323 else
00324 skip_pixels += (width - src_x_max);
00325
00326 if (pixel_zoom_y > 0)
00327 skip_rows += src_y_min;
00328 else
00329 skip_rows += (height - src_y_max);
00330
00331
00332 GLint row_length;
00333 glGetIntegerv (GL_UNPACK_ROW_LENGTH, &row_length);
00334 if (row_length == 0) row_length = width;
00335 GLint unpack_alignment;
00336 glGetIntegerv (GL_UNPACK_ALIGNMENT, &unpack_alignment);
00337 int src_pitch = (int)vcl_ceil(double(row_length) * (src_format->bits >> 3) / unpack_alignment);
00338
00339
00340 if (pixel_zoom_y > 0) {
00341
00342
00343
00344 } else {
00345 Hermes_ConverterRequest(hermes_converter, src_format, dest_format);
00346 Hermes_ConverterCopy(hermes_converter,
00347 (void *)pixels,
00348 skip_pixels, skip_rows,
00349 src_x_max - src_x_min, src_y_max - src_y_min,
00350 src_pitch,
00351 backbuffer->data,
00352 (int)(dest_x_min + 0.5F), (int)(backbuffer->height - dest_y_max + 0.5F),
00353 (int)(dest_x_max - dest_x_min + 0.5F), (int)(dest_y_max - dest_y_min + 0.5F),
00354 backbuffer->bytes_per_line);
00355
00356 Hermes_FormatFree(src_format);
00357 Hermes_FormatFree(dest_format);
00358 }
00359 return true;
00360 }
00361 }
00362 #endif // If we have been successful then we should never reach this point!!
00363 }
00364
00365
00366 return vgui_accelerate::vgui_glDrawPixels( width, height, format, type, pixels );
00367 }
00368
00369
00370
00371
00372
00373 bool vgui_accelerate_x11::vgui_choose_cache_format(GLenum* format, GLenum* type)
00374 {
00375 if (!vgui_no_acceleration)
00376 {
00377 #if defined(VGUI_MESA) && defined(HAS_HERMES)
00378
00379
00380
00381 XMesaBuffer mesabuf = XMesaGetCurrentBuffer();
00382
00383 assert(mesabuf != 0);
00384 Pixmap p_dummy;
00385 GLint render_mode;
00386 GLboolean rgba_mode;
00387 GLint draw_buffer;
00388 GLboolean depth_test_enabled;
00389 glGetIntegerv (GL_RENDER_MODE, &render_mode);
00390 glGetBooleanv (GL_RGBA_MODE, &rgba_mode);
00391 glGetIntegerv (GL_DRAW_BUFFER, &draw_buffer);
00392 glGetBooleanv (GL_DEPTH_TEST, &depth_test_enabled);
00393 if (render_mode == GL_RENDER
00394 && (draw_buffer == GL_BACK || draw_buffer == GL_BACK_LEFT)
00395 && rgba_mode == GL_TRUE
00396 && !depth_test_enabled)
00397 {
00398 XImage* backbuffer;
00399 XMesaGetBackBuffer(mesabuf, &p_dummy, &backbuffer);
00400
00401 bool found_match = false;
00402 for (int i=0; i < number_of_accelerated_formats && !found_match; ++i) {
00403 if (gl_to_hermes_formats[i].bits_per_pixel == backbuffer->bits_per_pixel &&
00404 gl_to_hermes_formats[i].red_mask == backbuffer->red_mask &&
00405 gl_to_hermes_formats[i].green_mask == backbuffer->green_mask &&
00406 gl_to_hermes_formats[i].blue_mask == backbuffer->blue_mask) {
00407 (*format) = gl_to_hermes_formats[i].gl_format;
00408 (*type) = gl_to_hermes_formats[i].gl_type;
00409 found_match = true;
00410 }
00411 }
00412 if (found_match) return true;
00413 }
00414 #endif
00415 }
00416
00417
00418 return vgui_accelerate::vgui_choose_cache_format( format, type );
00419 }
00420
00421 bool vgui_accelerate_x11::vgui_copy_back_to_aux ()
00422 {
00423 if (!vgui_no_acceleration)
00424 {
00425 #if defined(VGUI_MESA)
00426 XMesaBuffer mesabuf = XMesaGetCurrentBuffer();
00427 assert(mesabuf != 0);
00428 Pixmap p_dummy;
00429 GLint render_mode;
00430 GLint draw_buffer;
00431 glGetIntegerv (GL_RENDER_MODE, &render_mode);
00432 glGetIntegerv (GL_DRAW_BUFFER, &draw_buffer);
00433 if (render_mode == GL_RENDER && (draw_buffer == GL_BACK || draw_buffer == GL_BACK_LEFT)) {
00434 XImage* backbuffer;
00435 XMesaGetBackBuffer(mesabuf, &p_dummy, &backbuffer);
00436 int blit_size = backbuffer->bytes_per_line * backbuffer->height;
00437
00438 #ifdef DEBUG
00439 vcl_cerr << "blit_size = " << blit_size << '\n';
00440 #endif
00441 if (blit_size != aux_buffer_size) {
00442 delete[] aux_buffer;
00443 aux_buffer = new char[blit_size];
00444 aux_buffer_size = blit_size;
00445 }
00446 vcl_memcpy(aux_buffer, backbuffer->data, blit_size);
00447 return true;
00448 }
00449 #endif
00450 }
00451 return false;
00452 }
00453
00454 bool vgui_accelerate_x11::vgui_copy_aux_to_back ()
00455 {
00456 #if defined(VGUI_MESA)
00457 if (!vgui_no_acceleration) {
00458 XMesaBuffer mesabuf = XMesaGetCurrentBuffer();
00459 assert(mesabuf != 0);
00460 Pixmap p_dummy;
00461 GLint render_mode;
00462 GLint draw_buffer;
00463 glGetIntegerv (GL_RENDER_MODE, &render_mode);
00464 glGetIntegerv (GL_DRAW_BUFFER, &draw_buffer);
00465 if (render_mode == GL_RENDER && (draw_buffer == GL_BACK || draw_buffer == GL_BACK_LEFT)) {
00466 XImage* backbuffer;
00467 XMesaGetBackBuffer(mesabuf, &p_dummy, &backbuffer);
00468 int blit_size = backbuffer->bytes_per_line * backbuffer->height;
00469 assert(aux_buffer_size > 0);
00470 vcl_memcpy(backbuffer->data, aux_buffer, blit_size);
00471 }
00472 return true;
00473 }
00474 #endif
00475 return false;
00476 }
00477
00478 #endif // matches #if VGUI_MESA