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