wmesa.c revision dd7074736fa90f652a22da25b064bb20247b8513
1/* 2 * Windows (Win32/Win64) device driver for Mesa 3 * 4 */ 5 6#include "wmesadef.h" 7#include "colors.h" 8#include <GL/wmesa.h> 9#include "context.h" 10#include "extensions.h" 11#include "framebuffer.h" 12#include "renderbuffer.h" 13#include "drivers/common/driverfuncs.h" 14#include "array_cache/acache.h" 15#include "swrast/swrast.h" 16#include "swrast_setup/swrast_setup.h" 17#include "tnl/tnl.h" 18#include "tnl/t_context.h" 19#include "tnl/t_pipeline.h" 20 21 22/* linked list of our Framebuffers (windows) */ 23static WMesaFramebuffer FirstFramebuffer = NULL; 24 25 26/** 27 * Create a new WMesaFramebuffer object which will correspond to the 28 * given HDC (Window handle). 29 */ 30WMesaFramebuffer 31wmesa_new_framebuffer(HDC hdc, GLvisual *visual) 32{ 33 WMesaFramebuffer pwfb 34 = (WMesaFramebuffer) malloc(sizeof(struct wmesa_framebuffer)); 35 if (pwfb) { 36 _mesa_initialize_framebuffer(&pwfb->Base, visual); 37 pwfb->hdc = hdc; 38 /* insert at head of list */ 39 pwfb->next = FirstFramebuffer; 40 FirstFramebuffer = pwfb; 41 } 42 return pwfb; 43} 44 45 46/** 47 * Given an hdc, return the corresponding WMesaFramebuffer 48 */ 49WMesaFramebuffer 50wmesa_lookup_framebuffer(HDC hdc) 51{ 52 WMesaFramebuffer pwfb; 53 for (pwfb = FirstFramebuffer; pwfb; pwfb = pwfb->next) { 54 if (pwfb->hdc == hdc) 55 return pwfb; 56 } 57 return NULL; 58} 59 60 61/** 62 * Given a GLframebuffer, return the corresponding WMesaFramebuffer. 63 */ 64static WMesaFramebuffer wmesa_framebuffer(GLframebuffer *fb) 65{ 66 return (WMesaFramebuffer) fb; 67} 68 69 70/** 71 * Given a GLcontext, return the corresponding WMesaContext. 72 */ 73static WMesaContext wmesa_context(const GLcontext *ctx) 74{ 75 return (WMesaContext) ctx; 76} 77 78 79/* 80 * Every driver should implement a GetString function in order to 81 * return a meaningful GL_RENDERER string. 82 */ 83static const GLubyte *wmesa_get_string(GLcontext *ctx, GLenum name) 84{ 85 return (name == GL_RENDERER) ? 86 (GLubyte *) "Mesa Windows GDI Driver" : NULL; 87} 88 89 90/* 91 * Determine the pixel format based on the pixel size. 92 */ 93static void wmSetPixelFormat(WMesaContext pwc, HDC hDC) 94{ 95 pwc->cColorBits = GetDeviceCaps(hDC, BITSPIXEL); 96 97 // Only 16 and 32 bit targets are supported now 98 assert(pwc->cColorBits == 0 || 99 pwc->cColorBits == 16 || 100 pwc->cColorBits == 32); 101 102 switch(pwc->cColorBits){ 103 case 8: 104 pwc->pixelformat = PF_INDEX8; 105 break; 106 case 16: 107 pwc->pixelformat = PF_5R6G5B; 108 break; 109 case 32: 110 pwc->pixelformat = PF_8R8G8B; 111 break; 112 default: 113 pwc->pixelformat = PF_BADFORMAT; 114 } 115} 116 117 118/** 119 * Create DIB for back buffer. 120 * We write into this memory with the span routines and then blit it 121 * to the window on a buffer swap. 122 * 123 * XXX we should probably pass a WMesaFramebuffer ptr, not a WMesaContext! 124 */ 125BOOL wmCreateBackingStore(WMesaContext pwc, long lxSize, long lySize) 126{ 127 HDC hdc = pwc->hDC; 128 LPBITMAPINFO pbmi = &(pwc->bmi); 129 HDC hic; 130 131 assert(pwc->db_flag == GL_TRUE); 132 133 pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); 134 pbmi->bmiHeader.biWidth = lxSize; 135 pbmi->bmiHeader.biHeight= -lySize; 136 pbmi->bmiHeader.biPlanes = 1; 137 pbmi->bmiHeader.biBitCount = GetDeviceCaps(pwc->hDC, BITSPIXEL); 138 pbmi->bmiHeader.biCompression = BI_RGB; 139 pbmi->bmiHeader.biSizeImage = 0; 140 pbmi->bmiHeader.biXPelsPerMeter = 0; 141 pbmi->bmiHeader.biYPelsPerMeter = 0; 142 pbmi->bmiHeader.biClrUsed = 0; 143 pbmi->bmiHeader.biClrImportant = 0; 144 145 pwc->cColorBits = pbmi->bmiHeader.biBitCount; 146 pwc->ScanWidth = (lxSize * (pwc->cColorBits / 8) + 3) & ~3; 147 148 hic = CreateIC("display", NULL, NULL, NULL); 149 pwc->dib.hDC = CreateCompatibleDC(hic); 150 151 pwc->hbmDIB = CreateDIBSection(hic, 152 &pwc->bmi, 153 DIB_RGB_COLORS, 154 (void **)&(pwc->pbPixels), 155 0, 156 0); 157 pwc->hOldBitmap = SelectObject(pwc->dib.hDC, pwc->hbmDIB); 158 159 DeleteDC(hic); 160 161 wmSetPixelFormat(pwc, pwc->hDC); 162 return TRUE; 163} 164 165 166/* XXX pass WMesaFramebuffer, not WMesaContext. 167 */ 168static wmDeleteBackingStore(WMesaContext pwc) 169{ 170 if (pwc->hbmDIB) { 171 SelectObject(pwc->dib.hDC, pwc->hOldBitmap); 172 DeleteDC(pwc->dib.hDC); 173 DeleteObject(pwc->hbmDIB); 174 } 175} 176 177 178/** 179 * Find the width and height of the window named by hdc. 180 */ 181static void 182get_window_size(HDC hdc, GLuint *width, GLuint *height) 183{ 184 if (WindowFromDC(hdc)) { 185 RECT rect; 186 GetClientRect(WindowFromDC(hdc), &rect); 187 *width = rect.right - rect.left; 188 *height = rect.bottom - rect.top; 189 } 190 else { /* Memory context */ 191 /* From contributed code - use the size of the desktop 192 * for the size of a memory context (?) */ 193 *width = GetDeviceCaps(hdc, HORZRES); 194 *height = GetDeviceCaps(hdc, VERTRES); 195 } 196} 197 198 199static void 200wmesa_get_buffer_size(GLframebuffer *buffer, GLuint *width, GLuint *height) 201{ 202 WMesaFramebuffer pwfb = wmesa_framebuffer(buffer); 203 get_window_size(pwfb->hdc, width, height); 204} 205 206 207static void wmesa_flush(GLcontext *ctx) 208{ 209 WMesaContext pwc = wmesa_context(ctx); 210 WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->WinSysDrawBuffer); 211 212 /* XXX I guess we're _always_ double buffered and render to the back 213 * buffer. So flushing involves copying the back color buffer to 214 * the front. 215 */ 216 if (pwc->db_flag) { 217 BitBlt(pwc->hDC, 0, 0, pwfb->Base.Width, pwfb->Base.Height, 218 pwc->dib.hDC, 0, 0, SRCCOPY); 219 } 220 else { 221 /* Do nothing for single buffer */ 222 } 223} 224 225 226/**********************************************************************/ 227/***** CLEAR Functions *****/ 228/**********************************************************************/ 229 230/* If we do not implement these, Mesa clears the buffers via the pixel 231 * span writing interface, which is very slow for a clear operation. 232 */ 233 234/* 235 * Set the color index used to clear the color buffer. 236 */ 237static void clear_index(GLcontext *ctx, GLuint index) 238{ 239 WMesaContext pwc = wmesa_context(ctx); 240 /* Note that indexed mode is not supported yet */ 241 pwc->clearColorRef = RGB(0,0,0); 242} 243 244/* 245 * Set the color used to clear the color buffer. 246 */ 247static void clear_color(GLcontext *ctx, const GLfloat color[4]) 248{ 249 WMesaContext pwc = wmesa_context(ctx); 250 GLubyte col[3]; 251 UINT bytesPerPixel = pwc->cColorBits / 8; 252 253 CLAMPED_FLOAT_TO_UBYTE(col[0], color[0]); 254 CLAMPED_FLOAT_TO_UBYTE(col[1], color[1]); 255 CLAMPED_FLOAT_TO_UBYTE(col[2], color[2]); 256 pwc->clearColorRef = RGB(col[0], col[1], col[2]); 257 DeleteObject(pwc->clearPen); 258 DeleteObject(pwc->clearBrush); 259 pwc->clearPen = CreatePen(PS_SOLID, 1, pwc->clearColorRef); 260 pwc->clearBrush = CreateSolidBrush(pwc->clearColorRef); 261} 262 263 264/* 265 * Clear the specified region of the color buffer using the clear color 266 * or index as specified by one of the two functions above. 267 * 268 * This procedure clears either the front and/or the back COLOR buffers. 269 * Only the "left" buffer is cleared since we are not stereo. 270 * Clearing of the other non-color buffers is left to the swrast. 271 */ 272 273static void clear(GLcontext *ctx, 274 GLbitfield mask, 275 GLboolean all, 276 GLint x, GLint y, 277 GLint width, GLint height) 278{ 279#define FLIP(Y) (ctx->DrawBuffer->Height - (Y) - 1) 280 281 WMesaContext pwc = wmesa_context(ctx); 282 int done = 0; 283 284 /* Let swrast do all the work if the masks are not set to 285 * clear all channels. */ 286 if (ctx->Color.ColorMask[0] != 0xff || 287 ctx->Color.ColorMask[1] != 0xff || 288 ctx->Color.ColorMask[2] != 0xff || 289 ctx->Color.ColorMask[3] != 0xff) { 290 _swrast_Clear(ctx, mask, all, x, y, width, height); 291 return; 292 } 293 294 /* Back buffer */ 295 if (mask & BUFFER_BIT_BACK_LEFT) { 296 297 int i, rowSize; 298 UINT bytesPerPixel = pwc->cColorBits / 8; 299 LPBYTE lpb, clearRow; 300 LPWORD lpw; 301 BYTE bColor; 302 WORD wColor; 303 BYTE r, g, b; 304 DWORD dwColor; 305 LPDWORD lpdw; 306 307 /* Try for a fast clear - clearing entire buffer with a single 308 * byte value. */ 309 if (all) { /* entire buffer */ 310 /* Now check for an easy clear value */ 311 switch (bytesPerPixel) { 312 case 1: 313 bColor = BGR8(GetRValue(pwc->clearColorRef), 314 GetGValue(pwc->clearColorRef), 315 GetBValue(pwc->clearColorRef)); 316 memset(pwc->pbPixels, bColor, 317 pwc->ScanWidth * height); 318 done = 1; 319 break; 320 case 2: 321 wColor = BGR16(GetRValue(pwc->clearColorRef), 322 GetGValue(pwc->clearColorRef), 323 GetBValue(pwc->clearColorRef)); 324 if (((wColor >> 8) & 0xff) == (wColor & 0xff)) { 325 memset(pwc->pbPixels, wColor & 0xff, 326 pwc->ScanWidth * height); 327 done = 1; 328 } 329 break; 330 case 3: 331 /* fall through */ 332 case 4: 333 if (GetRValue(pwc->clearColorRef) == 334 GetGValue(pwc->clearColorRef) && 335 GetRValue(pwc->clearColorRef) == 336 GetBValue(pwc->clearColorRef)) { 337 memset(pwc->pbPixels, 338 GetRValue(pwc->clearColorRef), 339 pwc->ScanWidth * height); 340 done = 1; 341 } 342 break; 343 default: 344 break; 345 } 346 } /* all */ 347 348 if (!done) { 349 /* Need to clear a row at a time. Begin by setting the first 350 * row in the area to be cleared to the clear color. */ 351 352 clearRow = pwc->pbPixels + 353 pwc->ScanWidth * FLIP(y) + 354 bytesPerPixel * x; 355 switch (bytesPerPixel) { 356 case 1: 357 lpb = clearRow; 358 bColor = BGR8(GetRValue(pwc->clearColorRef), 359 GetGValue(pwc->clearColorRef), 360 GetBValue(pwc->clearColorRef)); 361 memset(lpb, bColor, width); 362 break; 363 case 2: 364 lpw = (LPWORD)clearRow; 365 wColor = BGR16(GetRValue(pwc->clearColorRef), 366 GetGValue(pwc->clearColorRef), 367 GetBValue(pwc->clearColorRef)); 368 for (i=0; i<width; i++) 369 *lpw++ = wColor; 370 break; 371 case 3: 372 lpb = clearRow; 373 r = GetRValue(pwc->clearColorRef); 374 g = GetGValue(pwc->clearColorRef); 375 b = GetBValue(pwc->clearColorRef); 376 for (i=0; i<width; i++) { 377 *lpb++ = b; 378 *lpb++ = g; 379 *lpb++ = r; 380 } 381 break; 382 case 4: 383 lpdw = (LPDWORD)clearRow; 384 dwColor = BGR32(GetRValue(pwc->clearColorRef), 385 GetGValue(pwc->clearColorRef), 386 GetBValue(pwc->clearColorRef)); 387 for (i=0; i<width; i++) 388 *lpdw++ = dwColor; 389 break; 390 default: 391 break; 392 } /* switch */ 393 394 /* copy cleared row to other rows in buffer */ 395 lpb = clearRow - pwc->ScanWidth; 396 rowSize = width * bytesPerPixel; 397 for (i=1; i<height; i++) { 398 memcpy(lpb, clearRow, rowSize); 399 lpb -= pwc->ScanWidth; 400 } 401 } /* not done */ 402 mask &= ~BUFFER_BIT_BACK_LEFT; 403 } /* back buffer */ 404 405 /* front buffer */ 406 if (mask & BUFFER_BIT_FRONT_LEFT) { 407 HDC DC = pwc->hDC; 408 HPEN Old_Pen = SelectObject(DC, pwc->clearPen); 409 HBRUSH Old_Brush = SelectObject(DC, pwc->clearBrush); 410 Rectangle(DC, 411 x, 412 FLIP(y) + 1, 413 x + width + 1, 414 FLIP(y) - height + 1); 415 SelectObject(DC, Old_Pen); 416 SelectObject(DC, Old_Brush); 417 mask &= ~BUFFER_BIT_FRONT_LEFT; 418 } /* front buffer */ 419 420 /* Call swrast if there is anything left to clear (like DEPTH) */ 421 if (mask) 422 _swrast_Clear(ctx, mask, all, x, y, width, height); 423 424#undef FLIP 425} 426 427 428/**********************************************************************/ 429/***** PIXEL Functions *****/ 430/**********************************************************************/ 431 432#define FLIP(Y) (rb->Height - (Y) - 1) 433 434 435/* SINGLE BUFFER */ 436 437/* These are slow, but work with all non-indexed visual types */ 438 439/* Write a horizontal span of RGBA color pixels with a boolean mask. */ 440static void write_rgba_span_single(const GLcontext *ctx, 441 struct gl_renderbuffer *rb, 442 GLuint n, GLint x, GLint y, 443 const GLubyte rgba[][4], 444 const GLubyte mask[] ) 445{ 446 WMesaContext pwc = wmesa_context(ctx); 447 GLuint i; 448 449 (void) ctx; 450 y=FLIP(y); 451 if (mask) { 452 for (i=0; i<n; i++) 453 if (mask[i]) 454 SetPixel(pwc->hDC, x+i, y, RGB(rgba[i][RCOMP], rgba[i][GCOMP], 455 rgba[i][BCOMP])); 456 } 457 else { 458 for (i=0; i<n; i++) 459 SetPixel(pwc->hDC, x+i, y, RGB(rgba[i][RCOMP], rgba[i][GCOMP], 460 rgba[i][BCOMP])); 461 } 462 463} 464 465/* Write a horizontal span of RGB color pixels with a boolean mask. */ 466static void write_rgb_span_single(const GLcontext *ctx, 467 struct gl_renderbuffer *rb, 468 GLuint n, GLint x, GLint y, 469 const GLubyte rgb[][3], 470 const GLubyte mask[] ) 471{ 472 WMesaContext pwc = wmesa_context(ctx); 473 GLuint i; 474 475 (void) ctx; 476 y=FLIP(y); 477 if (mask) { 478 for (i=0; i<n; i++) 479 if (mask[i]) 480 SetPixel(pwc->hDC, x+i, y, RGB(rgb[i][RCOMP], rgb[i][GCOMP], 481 rgb[i][BCOMP])); 482 } 483 else { 484 for (i=0; i<n; i++) 485 SetPixel(pwc->hDC, x+i, y, RGB(rgb[i][RCOMP], rgb[i][GCOMP], 486 rgb[i][BCOMP])); 487 } 488 489} 490 491/* 492 * Write a horizontal span of pixels with a boolean mask. The current color 493 * is used for all pixels. 494 */ 495static void write_mono_rgba_span_single(const GLcontext *ctx, 496 struct gl_renderbuffer *rb, 497 GLuint n, GLint x, GLint y, 498 const GLchan color[4], 499 const GLubyte mask[]) 500{ 501 GLuint i; 502 WMesaContext pwc = wmesa_context(ctx); 503 COLORREF colorref; 504 505 (void) ctx; 506 colorref = RGB(color[RCOMP], color[GCOMP], color[BCOMP]); 507 y=FLIP(y); 508 if (mask) { 509 for (i=0; i<n; i++) 510 if (mask[i]) 511 SetPixel(pwc->hDC, x+i, y, colorref); 512 } 513 else 514 for (i=0; i<n; i++) 515 SetPixel(pwc->hDC, x+i, y, colorref); 516 517} 518 519/* Write an array of RGBA pixels with a boolean mask. */ 520static void write_rgba_pixels_single(const GLcontext *ctx, 521 struct gl_renderbuffer *rb, 522 GLuint n, 523 const GLint x[], const GLint y[], 524 const GLubyte rgba[][4], 525 const GLubyte mask[] ) 526{ 527 GLuint i; 528 WMesaContext pwc = wmesa_context(ctx); 529 (void) ctx; 530 for (i=0; i<n; i++) 531 if (mask[i]) 532 SetPixel(pwc->hDC, x[i], FLIP(y[i]), 533 RGB(rgba[i][RCOMP], rgba[i][GCOMP], 534 rgba[i][BCOMP])); 535} 536 537 538 539/* 540 * Write an array of pixels with a boolean mask. The current color 541 * is used for all pixels. 542 */ 543static void write_mono_rgba_pixels_single(const GLcontext *ctx, 544 struct gl_renderbuffer *rb, 545 GLuint n, 546 const GLint x[], const GLint y[], 547 const GLchan color[4], 548 const GLubyte mask[] ) 549{ 550 GLuint i; 551 WMesaContext pwc = wmesa_context(ctx); 552 COLORREF colorref; 553 (void) ctx; 554 colorref = RGB(color[RCOMP], color[GCOMP], color[BCOMP]); 555 for (i=0; i<n; i++) 556 if (mask[i]) 557 SetPixel(pwc->hDC, x[i], FLIP(y[i]), colorref); 558} 559 560/* Read a horizontal span of color pixels. */ 561static void read_rgba_span_single(const GLcontext *ctx, 562 struct gl_renderbuffer *rb, 563 GLuint n, GLint x, GLint y, 564 GLubyte rgba[][4] ) 565{ 566 WMesaContext pwc = wmesa_context(ctx); 567 GLuint i; 568 COLORREF Color; 569 y = FLIP(y); 570 for (i=0; i<n; i++) { 571 Color = GetPixel(pwc->hDC, x+i, y); 572 rgba[i][RCOMP] = GetRValue(Color); 573 rgba[i][GCOMP] = GetGValue(Color); 574 rgba[i][BCOMP] = GetBValue(Color); 575 rgba[i][ACOMP] = 255; 576 } 577} 578 579 580/* Read an array of color pixels. */ 581static void read_rgba_pixels_single(const GLcontext *ctx, 582 struct gl_renderbuffer *rb, 583 GLuint n, const GLint x[], const GLint y[], 584 GLubyte rgba[][4]) 585{ 586 WMesaContext pwc = wmesa_context(ctx); 587 GLuint i; 588 COLORREF Color; 589 for (i=0; i<n; i++) { 590 GLint y2 = FLIP(y[i]); 591 Color = GetPixel(pwc->hDC, x[i], y2); 592 rgba[i][RCOMP] = GetRValue(Color); 593 rgba[i][GCOMP] = GetGValue(Color); 594 rgba[i][BCOMP] = GetBValue(Color); 595 rgba[i][ACOMP] = 255; 596 } 597} 598 599/*********************************************************************/ 600 601/* DOUBLE BUFFER 32-bit */ 602 603#define WMSETPIXEL32(pwc, y, x, r, g, b) { \ 604LPDWORD lpdw = ((LPDWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); \ 605*lpdw = BGR32((r),(g),(b)); } 606 607 608 609/* Write a horizontal span of RGBA color pixels with a boolean mask. */ 610static void write_rgba_span_32(const GLcontext *ctx, 611 struct gl_renderbuffer *rb, 612 GLuint n, GLint x, GLint y, 613 const GLubyte rgba[][4], 614 const GLubyte mask[] ) 615{ 616 WMesaContext pwc = wmesa_context(ctx); 617 GLuint i; 618 LPDWORD lpdw; 619 620 (void) ctx; 621 622 y=FLIP(y); 623 lpdw = ((LPDWORD)(pwc->pbPixels + pwc->ScanWidth * y)) + x; 624 if (mask) { 625 for (i=0; i<n; i++) 626 if (mask[i]) 627 lpdw[i] = BGR32(rgba[i][RCOMP], rgba[i][GCOMP], 628 rgba[i][BCOMP]); 629 } 630 else { 631 for (i=0; i<n; i++) 632 *lpdw++ = BGR32(rgba[i][RCOMP], rgba[i][GCOMP], 633 rgba[i][BCOMP]); 634 } 635} 636 637 638/* Write a horizontal span of RGB color pixels with a boolean mask. */ 639static void write_rgb_span_32(const GLcontext *ctx, 640 struct gl_renderbuffer *rb, 641 GLuint n, GLint x, GLint y, 642 const GLubyte rgb[][3], 643 const GLubyte mask[] ) 644{ 645 WMesaContext pwc = wmesa_context(ctx); 646 GLuint i; 647 LPDWORD lpdw; 648 649 (void) ctx; 650 651 y=FLIP(y); 652 lpdw = ((LPDWORD)(pwc->pbPixels + pwc->ScanWidth * y)) + x; 653 if (mask) { 654 for (i=0; i<n; i++) 655 if (mask[i]) 656 lpdw[i] = BGR32(rgb[i][RCOMP], rgb[i][GCOMP], 657 rgb[i][BCOMP]); 658 } 659 else { 660 for (i=0; i<n; i++) 661 *lpdw++ = BGR32(rgb[i][RCOMP], rgb[i][GCOMP], 662 rgb[i][BCOMP]); 663 } 664} 665 666/* 667 * Write a horizontal span of pixels with a boolean mask. The current color 668 * is used for all pixels. 669 */ 670static void write_mono_rgba_span_32(const GLcontext *ctx, 671 struct gl_renderbuffer *rb, 672 GLuint n, GLint x, GLint y, 673 const GLchan color[4], 674 const GLubyte mask[]) 675{ 676 LPDWORD lpdw; 677 DWORD pixel; 678 GLuint i; 679 WMesaContext pwc = wmesa_context(ctx); 680 lpdw = ((LPDWORD)(pwc->pbPixels + pwc->ScanWidth * y)) + x; 681 y=FLIP(y); 682 pixel = BGR32(color[RCOMP], color[GCOMP], color[BCOMP]); 683 if (mask) { 684 for (i=0; i<n; i++) 685 if (mask[i]) 686 lpdw[i] = pixel; 687 } 688 else 689 for (i=0; i<n; i++) 690 *lpdw++ = pixel; 691 692} 693 694/* Write an array of RGBA pixels with a boolean mask. */ 695static void write_rgba_pixels_32(const GLcontext *ctx, 696 struct gl_renderbuffer *rb, 697 GLuint n, const GLint x[], const GLint y[], 698 const GLubyte rgba[][4], 699 const GLubyte mask[]) 700{ 701 GLuint i; 702 WMesaContext pwc = wmesa_context(ctx);; 703 for (i=0; i<n; i++) 704 if (mask[i]) 705 WMSETPIXEL32(pwc, FLIP(y[i]), x[i], 706 rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]); 707} 708 709/* 710 * Write an array of pixels with a boolean mask. The current color 711 * is used for all pixels. 712 */ 713static void write_mono_rgba_pixels_32(const GLcontext *ctx, 714 struct gl_renderbuffer *rb, 715 GLuint n, 716 const GLint x[], const GLint y[], 717 const GLchan color[4], 718 const GLubyte mask[]) 719{ 720 GLuint i; 721 WMesaContext pwc = wmesa_context(ctx); 722 for (i=0; i<n; i++) 723 if (mask[i]) 724 WMSETPIXEL32(pwc, FLIP(y[i]),x[i],color[RCOMP], 725 color[GCOMP], color[BCOMP]); 726} 727 728/* Read a horizontal span of color pixels. */ 729static void read_rgba_span_32(const GLcontext *ctx, 730 struct gl_renderbuffer *rb, 731 GLuint n, GLint x, GLint y, 732 GLubyte rgba[][4] ) 733{ 734 GLuint i; 735 DWORD pixel; 736 LPDWORD lpdw; 737 WMesaContext pwc = wmesa_context(ctx); 738 739 y = FLIP(y); 740 lpdw = ((LPDWORD)(pwc->pbPixels + pwc->ScanWidth * y)) + x; 741 for (i=0; i<n; i++) { 742 pixel = lpdw[i]; 743 rgba[i][RCOMP] = (pixel & 0x00ff0000) >> 16; 744 rgba[i][GCOMP] = (pixel & 0x0000ff00) >> 8; 745 rgba[i][BCOMP] = (pixel & 0x000000ff); 746 rgba[i][ACOMP] = 255; 747 } 748} 749 750 751/* Read an array of color pixels. */ 752static void read_rgba_pixels_32(const GLcontext *ctx, 753 struct gl_renderbuffer *rb, 754 GLuint n, const GLint x[], const GLint y[], 755 GLubyte rgba[][4]) 756{ 757 GLuint i; 758 DWORD pixel; 759 LPDWORD lpdw; 760 WMesaContext pwc = wmesa_context(ctx); 761 762 for (i=0; i<n; i++) { 763 GLint y2 = FLIP(y[i]); 764 lpdw = ((LPDWORD)(pwc->pbPixels + pwc->ScanWidth * y2)) + x[i]; 765 pixel = lpdw[i]; 766 rgba[i][RCOMP] = (pixel & 0x00ff0000) >> 16; 767 rgba[i][GCOMP] = (pixel & 0x0000ff00) >> 8; 768 rgba[i][BCOMP] = (pixel & 0x000000ff); 769 rgba[i][ACOMP] = 255; 770 } 771} 772 773 774/*********************************************************************/ 775 776/* DOUBLE BUFFER 16-bit */ 777 778#define WMSETPIXEL16(pwc, y, x, r, g, b) { \ 779LPWORD lpw = ((LPWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); \ 780*lpw = BGR16((r),(g),(b)); } 781 782 783 784/* Write a horizontal span of RGBA color pixels with a boolean mask. */ 785static void write_rgba_span_16(const GLcontext *ctx, 786 struct gl_renderbuffer *rb, 787 GLuint n, GLint x, GLint y, 788 const GLubyte rgba[][4], 789 const GLubyte mask[] ) 790{ 791 WMesaContext pwc = wmesa_context(ctx); 792 GLuint i; 793 LPWORD lpw; 794 795 (void) ctx; 796 797 y=FLIP(y); 798 lpw = ((LPWORD)(pwc->pbPixels + pwc->ScanWidth * y)) + x; 799 if (mask) { 800 for (i=0; i<n; i++) 801 if (mask[i]) 802 lpw[i] = BGR16(rgba[i][RCOMP], rgba[i][GCOMP], 803 rgba[i][BCOMP]); 804 } 805 else { 806 for (i=0; i<n; i++) 807 *lpw++ = BGR16(rgba[i][RCOMP], rgba[i][GCOMP], 808 rgba[i][BCOMP]); 809 } 810} 811 812 813/* Write a horizontal span of RGB color pixels with a boolean mask. */ 814static void write_rgb_span_16(const GLcontext *ctx, 815 struct gl_renderbuffer *rb, 816 GLuint n, GLint x, GLint y, 817 const GLubyte rgb[][3], 818 const GLubyte mask[] ) 819{ 820 WMesaContext pwc = wmesa_context(ctx); 821 GLuint i; 822 LPWORD lpw; 823 824 (void) ctx; 825 826 y=FLIP(y); 827 lpw = ((LPWORD)(pwc->pbPixels + pwc->ScanWidth * y)) + x; 828 if (mask) { 829 for (i=0; i<n; i++) 830 if (mask[i]) 831 lpw[i] = BGR16(rgb[i][RCOMP], rgb[i][GCOMP], 832 rgb[i][BCOMP]); 833 } 834 else { 835 for (i=0; i<n; i++) 836 *lpw++ = BGR16(rgb[i][RCOMP], rgb[i][GCOMP], 837 rgb[i][BCOMP]); 838 } 839} 840 841/* 842 * Write a horizontal span of pixels with a boolean mask. The current color 843 * is used for all pixels. 844 */ 845static void write_mono_rgba_span_16(const GLcontext *ctx, 846 struct gl_renderbuffer *rb, 847 GLuint n, GLint x, GLint y, 848 const GLchan color[4], 849 const GLubyte mask[]) 850{ 851 LPWORD lpw; 852 WORD pixel; 853 GLuint i; 854 WMesaContext pwc = wmesa_context(ctx); 855 (void) ctx; 856 lpw = ((LPWORD)(pwc->pbPixels + pwc->ScanWidth * y)) + x; 857 y=FLIP(y); 858 pixel = BGR16(color[RCOMP], color[GCOMP], color[BCOMP]); 859 if (mask) { 860 for (i=0; i<n; i++) 861 if (mask[i]) 862 lpw[i] = pixel; 863 } 864 else 865 for (i=0; i<n; i++) 866 *lpw++ = pixel; 867 868} 869 870/* Write an array of RGBA pixels with a boolean mask. */ 871static void write_rgba_pixels_16(const GLcontext *ctx, 872 struct gl_renderbuffer *rb, 873 GLuint n, const GLint x[], const GLint y[], 874 const GLubyte rgba[][4], 875 const GLubyte mask[]) 876{ 877 GLuint i; 878 WMesaContext pwc = wmesa_context(ctx); 879 (void) ctx; 880 for (i=0; i<n; i++) 881 if (mask[i]) 882 WMSETPIXEL16(pwc, FLIP(y[i]), x[i], 883 rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]); 884} 885 886/* 887 * Write an array of pixels with a boolean mask. The current color 888 * is used for all pixels. 889 */ 890static void write_mono_rgba_pixels_16(const GLcontext *ctx, 891 struct gl_renderbuffer *rb, 892 GLuint n, 893 const GLint x[], const GLint y[], 894 const GLchan color[4], 895 const GLubyte mask[]) 896{ 897 GLuint i; 898 WMesaContext pwc = wmesa_context(ctx); 899 (void) ctx; 900 for (i=0; i<n; i++) 901 if (mask[i]) 902 WMSETPIXEL16(pwc, FLIP(y[i]),x[i],color[RCOMP], 903 color[GCOMP], color[BCOMP]); 904} 905 906/* Read a horizontal span of color pixels. */ 907static void read_rgba_span_16(const GLcontext *ctx, 908 struct gl_renderbuffer *rb, 909 GLuint n, GLint x, GLint y, 910 GLubyte rgba[][4] ) 911{ 912 GLuint i, pixel; 913 LPWORD lpw; 914 WMesaContext pwc = wmesa_context(ctx); 915 916 y = FLIP(y); 917 lpw = ((LPWORD)(pwc->pbPixels + pwc->ScanWidth * y)) + x; 918 for (i=0; i<n; i++) { 919 pixel = lpw[i]; 920 /* Windows uses 5,5,5 for 16-bit */ 921 rgba[i][RCOMP] = (pixel & 0x7c00) >> 7; 922 rgba[i][GCOMP] = (pixel & 0x03e0) >> 2; 923 rgba[i][BCOMP] = (pixel & 0x001f) << 3; 924 rgba[i][ACOMP] = 255; 925 } 926} 927 928 929/* Read an array of color pixels. */ 930static void read_rgba_pixels_16(const GLcontext *ctx, 931 struct gl_renderbuffer *rb, 932 GLuint n, const GLint x[], const GLint y[], 933 GLubyte rgba[][4]) 934{ 935 GLuint i, pixel; 936 LPWORD lpw; 937 WMesaContext pwc = wmesa_context(ctx); 938 939 for (i=0; i<n; i++) { 940 GLint y2 = FLIP(y[i]); 941 lpw = ((LPWORD)(pwc->pbPixels + pwc->ScanWidth * y2)) + x[i]; 942 pixel = lpw[i]; 943 /* Windows uses 5,5,5 for 16-bit */ 944 rgba[i][RCOMP] = (pixel & 0x7c00) >> 7; 945 rgba[i][GCOMP] = (pixel & 0x03e0) >> 2; 946 rgba[i][BCOMP] = (pixel & 0x001f) << 3; 947 rgba[i][ACOMP] = 255; 948 } 949} 950 951 952 953 954/**********************************************************************/ 955/***** BUFFER Functions *****/ 956/**********************************************************************/ 957 958 959 960 961static void 962wmesa_delete_renderbuffer(struct gl_renderbuffer *rb) 963{ 964 _mesa_free(rb); 965} 966 967 968/** 969 * This is called by Mesa whenever it determines that the window size 970 * has changed. Do whatever's needed to cope with that. 971 */ 972static GLboolean 973wmesa_renderbuffer_storage(GLcontext *ctx, 974 struct gl_renderbuffer *rb, 975 GLenum internalFormat, 976 GLuint width, 977 GLuint height) 978{ 979 rb->Width = width; 980 rb->Height = height; 981 return GL_TRUE; 982} 983 984void wmesa_set_renderbuffer_funcs(struct gl_renderbuffer *rb, int pixelformat, 985 int double_buffer) 986{ 987 if (double_buffer) { 988 /* Picking the correct span functions is important because 989 * the DIB was allocated with the indicated depth. */ 990 switch(pixelformat) { 991 case PF_5R6G5B: 992 rb->PutRow = write_rgba_span_16; 993 rb->PutRowRGB = write_rgb_span_16; 994 rb->PutMonoRow = write_mono_rgba_span_16; 995 rb->PutValues = write_rgba_pixels_16; 996 rb->PutMonoValues = write_mono_rgba_pixels_16; 997 rb->GetRow = read_rgba_span_16; 998 rb->GetValues = read_rgba_pixels_16; 999 break; 1000 case PF_8R8G8B: 1001 rb->PutRow = write_rgba_span_32; 1002 rb->PutRowRGB = write_rgb_span_32; 1003 rb->PutMonoRow = write_mono_rgba_span_32; 1004 rb->PutValues = write_rgba_pixels_32; 1005 rb->PutMonoValues = write_mono_rgba_pixels_32; 1006 rb->GetRow = read_rgba_span_32; 1007 rb->GetValues = read_rgba_pixels_32; 1008 break; 1009 default: 1010 break; 1011 } 1012 } 1013 else { /* single buffer */ 1014 rb->PutRow = write_rgba_span_single; 1015 rb->PutRowRGB = write_rgb_span_single; 1016 rb->PutMonoRow = write_mono_rgba_span_single; 1017 rb->PutValues = write_rgba_pixels_single; 1018 rb->PutMonoValues = write_mono_rgba_pixels_single; 1019 rb->GetRow = read_rgba_span_single; 1020 rb->GetValues = read_rgba_pixels_single; 1021 } 1022} 1023 1024/** 1025 * Called by ctx->Driver.ResizeBuffers() 1026 * Resize the front/back colorbuffers to match the latest window size. 1027 */ 1028static void 1029wmesa_resize_buffers(GLcontext *ctx, GLframebuffer *buffer, 1030 GLuint width, GLuint height) 1031{ 1032 WMesaContext pwc = wmesa_context(ctx); 1033 WMesaFramebuffer pwfb = wmesa_framebuffer(buffer); 1034 1035 if (pwfb->Base.Width != width || pwfb->Base.Height != height) { 1036 /* Realloc back buffer */ 1037 if (pwc->db_flag) { 1038 wmDeleteBackingStore(pwc); 1039 wmCreateBackingStore(pwc, width, height); 1040 } 1041 } 1042 _mesa_resize_framebuffer(ctx, buffer, width, height); 1043} 1044 1045 1046/** 1047 * Called by glViewport. 1048 * This is a good time for us to poll the current window size and adjust 1049 * our renderbuffers to match the current window size. 1050 * Remember, we have no opportunity to respond to conventional 1051 * resize events since the driver has no event loop. 1052 * Thus, we poll. 1053 * MakeCurrent also ends up making a call here, so that ensures 1054 * we get the viewport set correctly, even if the app does not call 1055 * glViewport and relies on the defaults. 1056 */ 1057static void wmesa_viewport(GLcontext *ctx, 1058 GLint x, GLint y, 1059 GLsizei width, GLsizei height) 1060{ 1061 WMesaContext pwc = wmesa_context(ctx); 1062 GLuint new_width, new_height; 1063 1064 wmesa_get_buffer_size(ctx->WinSysDrawBuffer, &new_width, &new_height); 1065 1066 if (new_width != width || new_height != height) { 1067 /** 1068 * Either the window was resized or the viewport changed - not sure which. 1069 * So call resize buffers to resize them if the window size changed. 1070 */ 1071 wmesa_resize_buffers(ctx, ctx->WinSysDrawBuffer, new_width, new_height); 1072 ctx->NewState |= _NEW_BUFFERS; /* to update scissor / window bounds */ 1073 } 1074} 1075 1076 1077 1078 1079/** 1080 * Called when the driver should update it's state, based on the new_state 1081 * flags. 1082 */ 1083static void wmesa_update_state(GLcontext *ctx, GLuint new_state) 1084{ 1085 _swrast_InvalidateState(ctx, new_state); 1086 _swsetup_InvalidateState(ctx, new_state); 1087 _ac_InvalidateState(ctx, new_state); 1088 _tnl_InvalidateState(ctx, new_state); 1089 1090 /* TODO - need code to update the span functions in case the 1091 * renderer changes the target buffer (like a DB app writing to 1092 * the front buffer). */ 1093 1094#if 0 1095 { /* could check _NEW_BUFFERS bit flag here in new_state */ 1096 /* In progress - Need to make the wmesa context inherit (by containment) 1097 the gl_context, so I can get access to the pixel format */ 1098 struct gl_renderbuffer *rb; 1099 int pixelformat, double_buffer; 1100 1101 rb = ctx->DrawBuffer->Attachment[BUFFER_BACK_LEFT].Renderbuffer; 1102 pixelformat = PF_5R6G5B; // hard code for now - see note above 1103 double_buffer = ctx->DrawBuffer->ColorDrawBuffer[0] == GL_BACK ? 1 : 0; 1104 if (rb) 1105 wmesa_set_renderbuffer_funcs(rb, pixelformat, double_buffer); 1106 } 1107#endif 1108} 1109 1110 1111 1112 1113 1114/**********************************************************************/ 1115/***** WMESA Functions *****/ 1116/**********************************************************************/ 1117 1118WMesaContext WMesaCreateContext(HDC hDC, 1119 HPALETTE* Pal, 1120 GLboolean rgb_flag, 1121 GLboolean db_flag, 1122 GLboolean alpha_flag) 1123{ 1124 WMesaContext c; 1125 struct dd_function_table functions; 1126 GLint red_bits, green_bits, blue_bits, alpha_bits; 1127 GLcontext *ctx; 1128 GLvisual *visual; 1129 1130 (void) Pal; 1131 1132 /* Indexed mode not supported */ 1133 if (!rgb_flag) 1134 return NULL; 1135 1136 /* Allocate wmesa context */ 1137 c = CALLOC_STRUCT(wmesa_context); 1138 if (!c) 1139 return NULL; 1140 1141#if 0 1142 /* I do not understand this contributed code */ 1143 /* Support memory and device contexts */ 1144 if(WindowFromDC(hDC) != NULL) { 1145 c->hDC = GetDC(WindowFromDC(hDC)); // huh ???? 1146 } 1147 else { 1148 c->hDC = hDC; 1149 } 1150#else 1151 c->hDC = hDC; 1152#endif 1153 1154 /* rememember DC and flag settings */ 1155 c->rgb_flag = rgb_flag; 1156 c->db_flag = db_flag; 1157 c->alpha_flag = alpha_flag; 1158 1159 /* Get data for visual */ 1160 /* Dealing with this is actually a bit of overkill because Mesa will end 1161 * up treating all color component size requests less than 8 by using 1162 * a single byte per channel. In addition, the interface to the span 1163 * routines passes colors as an entire byte per channel anyway, so there 1164 * is nothing to be saved by telling the visual to be 16 bits if the device 1165 * is 16 bits. That is, Mesa is going to compute colors down to 8 bits per 1166 * channel anyway. 1167 * But we go through the motions here anyway. 1168 */ 1169 switch (GetDeviceCaps(c->hDC, BITSPIXEL)) { 1170 case 16: 1171 red_bits = green_bits = blue_bits = 5; 1172 alpha_bits = 0; 1173 break; 1174 default: 1175 red_bits = green_bits = blue_bits = 8; 1176 alpha_bits = 8; 1177 break; 1178 } 1179 /* Create visual based on flags */ 1180 visual = _mesa_create_visual(rgb_flag, 1181 db_flag, /* db_flag */ 1182 GL_FALSE, /* stereo */ 1183 red_bits, green_bits, blue_bits, /* color RGB */ 1184 alpha_flag ? alpha_bits : 0, /* color A */ 1185 0, /* index bits */ 1186 DEFAULT_SOFTWARE_DEPTH_BITS, /* depth_bits */ 1187 8, /* stencil_bits */ 1188 16,16,16, /* accum RGB */ 1189 alpha_flag ? 16 : 0, /* accum A */ 1190 1); /* num samples */ 1191 1192 if (!visual) { 1193 _mesa_free(c); 1194 return NULL; 1195 } 1196 1197 /* Set up driver functions */ 1198 _mesa_init_driver_functions(&functions); 1199 functions.GetString = wmesa_get_string; 1200 functions.UpdateState = wmesa_update_state; 1201 functions.GetBufferSize = wmesa_get_buffer_size; 1202 functions.Flush = wmesa_flush; 1203 functions.Clear = clear; 1204 functions.ClearIndex = clear_index; 1205 functions.ClearColor = clear_color; 1206 functions.ResizeBuffers = wmesa_resize_buffers; 1207 functions.Viewport = wmesa_viewport; 1208 1209 /* initialize the Mesa context data */ 1210 ctx = &c->gl_ctx; 1211 _mesa_initialize_context(ctx, visual, NULL, &functions, (void *)c); 1212 1213 _mesa_enable_sw_extensions(ctx); 1214 _mesa_enable_1_3_extensions(ctx); 1215 _mesa_enable_1_4_extensions(ctx); 1216 _mesa_enable_1_5_extensions(ctx); 1217 _mesa_enable_2_0_extensions(ctx); 1218 1219 /* Initialize the software rasterizer and helper modules. */ 1220 if (!_swrast_CreateContext(ctx) || 1221 !_ac_CreateContext(ctx) || 1222 !_tnl_CreateContext(ctx) || 1223 !_swsetup_CreateContext(ctx)) { 1224 _mesa_free_context_data(ctx); 1225 _mesa_free(c); 1226 return NULL; 1227 } 1228 _swsetup_Wakeup(ctx); 1229 TNL_CONTEXT(ctx)->Driver.RunPipeline = _tnl_run_pipeline; 1230 1231 return c; 1232} 1233 1234 1235void WMesaDestroyContext( WMesaContext pwc ) 1236{ 1237 GLcontext *ctx = &pwc->gl_ctx; 1238 GET_CURRENT_CONTEXT(cur_ctx); 1239 1240 if (cur_ctx == ctx) { 1241 /* unbind current if deleting current context */ 1242 WMesaMakeCurrent(NULL, NULL); 1243 } 1244 1245 /* Release for device, not memory contexts */ 1246 if (WindowFromDC(pwc->hDC) != NULL) 1247 { 1248 ReleaseDC(WindowFromDC(pwc->hDC), pwc->hDC); 1249 } 1250 DeleteObject(pwc->clearPen); 1251 DeleteObject(pwc->clearBrush); 1252 1253 if (pwc->db_flag) 1254 wmDeleteBackingStore(pwc); 1255 1256 _swsetup_DestroyContext(ctx); 1257 _tnl_DestroyContext(ctx); 1258 _ac_DestroyContext(ctx); 1259 _swrast_DestroyContext(ctx); 1260 1261 _mesa_free_context_data(ctx); 1262 _mesa_free(pwc); 1263} 1264 1265 1266/** 1267 * Create a new color renderbuffer. 1268 */ 1269struct gl_renderbuffer * 1270wmesa_new_renderbuffer(void) 1271{ 1272 struct gl_renderbuffer *rb = CALLOC_STRUCT(gl_renderbuffer); 1273 if (!rb) 1274 return NULL; 1275 1276 _mesa_init_renderbuffer(rb, (GLuint)0); 1277 1278 rb->_BaseFormat = GL_RGBA; 1279 rb->InternalFormat = GL_RGBA; 1280 rb->DataType = CHAN_TYPE; 1281 rb->Delete = wmesa_delete_renderbuffer; 1282 rb->AllocStorage = wmesa_renderbuffer_storage; 1283 return rb; 1284} 1285 1286 1287void WMesaMakeCurrent(WMesaContext c, HDC hdc) 1288{ 1289 WMesaFramebuffer pwfb; 1290 1291 { 1292 /* return if already current */ 1293 GET_CURRENT_CONTEXT(ctx); 1294 WMesaContext pwc = wmesa_context(ctx); 1295 if (c == pwc && pwc->hDC == hdc) 1296 return; 1297 } 1298 1299 pwfb = wmesa_lookup_framebuffer(hdc); 1300 1301 /* Lazy creation of framebuffers */ 1302 if (c && !pwfb) { 1303 struct gl_renderbuffer *rb; 1304 GLvisual *visual = &c->gl_ctx.Visual; 1305 GLuint width, height; 1306 1307 get_window_size(hdc, &width, &height); 1308 1309 c->clearPen = CreatePen(PS_SOLID, 1, 0); 1310 c->clearBrush = CreateSolidBrush(0); 1311 1312 /* Create back buffer if double buffered */ 1313 if (c->db_flag) { 1314 wmCreateBackingStore(c, width, height); 1315 } 1316 1317 pwfb = wmesa_new_framebuffer(hdc, visual); 1318 1319 /* need a color renderbuffer */ 1320 rb = wmesa_new_renderbuffer(); 1321 if (c->db_flag) 1322 _mesa_add_renderbuffer(&pwfb->Base, BUFFER_BACK_LEFT, rb); 1323 else 1324 _mesa_add_renderbuffer(&pwfb->Base, BUFFER_FRONT_LEFT, rb); 1325 wmesa_set_renderbuffer_funcs(rb, c->pixelformat, c->db_flag); 1326 1327 /* Let Mesa own the Depth, Stencil, and Accum buffers */ 1328 _mesa_add_soft_renderbuffers(&pwfb->Base, 1329 GL_FALSE, /* color */ 1330 visual->depthBits > 0, 1331 visual->stencilBits > 0, 1332 visual->accumRedBits > 0, 1333 c->alpha_flag, 1334 GL_FALSE); 1335 } 1336 1337 if (c && pwfb) 1338 _mesa_make_current(&c->gl_ctx, &pwfb->Base, &pwfb->Base); 1339 else 1340 _mesa_make_current(NULL, NULL, NULL); 1341} 1342 1343 1344void WMesaSwapBuffers( HDC hdc ) 1345{ 1346 GET_CURRENT_CONTEXT(ctx); 1347 WMesaContext pwc = wmesa_context(ctx); 1348 WMesaFramebuffer pwfb = wmesa_lookup_framebuffer(hdc); 1349 1350 if (!pwfb) { 1351 _mesa_problem(NULL, "wmesa: swapbuffers on unknown hdc"); 1352 return; 1353 } 1354 1355 /* If we're swapping the buffer associated with the current context 1356 * we have to flush any pending rendering commands first. 1357 */ 1358 if (pwc->hDC == hdc) { 1359 _mesa_notifySwapBuffers(ctx); 1360 1361 BitBlt(pwc->hDC, 0, 0, pwfb->Base.Width, pwfb->Base.Height, 1362 pwc->dib.hDC, 0, 0, SRCCOPY); 1363 } 1364 else { 1365 /* XXX for now only allow swapping current window */ 1366 _mesa_problem(NULL, "wmesa: can't swap non-current window"); 1367 } 1368} 1369