wmesa.c revision c3f2c287cec8457a9830fd04901e4c13e99fd260
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/**
436 ** Front Buffer reading/writing
437 ** These are slow, but work with all non-indexed visual types.
438 **/
439
440/* Write a horizontal span of RGBA color pixels with a boolean mask. */
441static void write_rgba_span_front(const GLcontext *ctx,
442				   struct gl_renderbuffer *rb,
443				   GLuint n, GLint x, GLint y,
444				   const GLubyte rgba[][4],
445				   const GLubyte mask[] )
446{
447    WMesaContext pwc = wmesa_context(ctx);
448    GLuint i;
449
450    (void) ctx;
451    y=FLIP(y);
452    if (mask) {
453	for (i=0; i<n; i++)
454	    if (mask[i])
455		SetPixel(pwc->hDC, x+i, y, RGB(rgba[i][RCOMP], rgba[i][GCOMP],
456					       rgba[i][BCOMP]));
457    }
458    else {
459	for (i=0; i<n; i++)
460	    SetPixel(pwc->hDC, x+i, y, RGB(rgba[i][RCOMP], rgba[i][GCOMP],
461					   rgba[i][BCOMP]));
462    }
463
464}
465
466/* Write a horizontal span of RGB color pixels with a boolean mask. */
467static void write_rgb_span_front(const GLcontext *ctx,
468				  struct gl_renderbuffer *rb,
469				  GLuint n, GLint x, GLint y,
470				  const GLubyte rgb[][3],
471				  const GLubyte mask[] )
472{
473    WMesaContext pwc = wmesa_context(ctx);
474    GLuint i;
475
476    (void) ctx;
477    y=FLIP(y);
478    if (mask) {
479	for (i=0; i<n; i++)
480	    if (mask[i])
481		SetPixel(pwc->hDC, x+i, y, RGB(rgb[i][RCOMP], rgb[i][GCOMP],
482					       rgb[i][BCOMP]));
483    }
484    else {
485	for (i=0; i<n; i++)
486	    SetPixel(pwc->hDC, x+i, y, RGB(rgb[i][RCOMP], rgb[i][GCOMP],
487					   rgb[i][BCOMP]));
488    }
489
490}
491
492/*
493 * Write a horizontal span of pixels with a boolean mask.  The current color
494 * is used for all pixels.
495 */
496static void write_mono_rgba_span_front(const GLcontext *ctx,
497					struct gl_renderbuffer *rb,
498					GLuint n, GLint x, GLint y,
499					const GLchan color[4],
500					const GLubyte mask[])
501{
502    GLuint i;
503    WMesaContext pwc = wmesa_context(ctx);
504    COLORREF colorref;
505
506    (void) ctx;
507    colorref = RGB(color[RCOMP], color[GCOMP], color[BCOMP]);
508    y=FLIP(y);
509    if (mask) {
510	for (i=0; i<n; i++)
511	    if (mask[i])
512		SetPixel(pwc->hDC, x+i, y, colorref);
513    }
514    else
515	for (i=0; i<n; i++)
516	    SetPixel(pwc->hDC, x+i, y, colorref);
517
518}
519
520/* Write an array of RGBA pixels with a boolean mask. */
521static void write_rgba_pixels_front(const GLcontext *ctx,
522				     struct gl_renderbuffer *rb,
523				     GLuint n,
524				     const GLint x[], const GLint y[],
525				     const GLubyte rgba[][4],
526				     const GLubyte mask[] )
527{
528    GLuint i;
529    WMesaContext pwc = wmesa_context(ctx);
530    (void) ctx;
531    for (i=0; i<n; i++)
532	if (mask[i])
533	    SetPixel(pwc->hDC, x[i], FLIP(y[i]),
534		     RGB(rgba[i][RCOMP], rgba[i][GCOMP],
535			 rgba[i][BCOMP]));
536}
537
538
539
540/*
541 * Write an array of pixels with a boolean mask.  The current color
542 * is used for all pixels.
543 */
544static void write_mono_rgba_pixels_front(const GLcontext *ctx,
545					  struct gl_renderbuffer *rb,
546					  GLuint n,
547					  const GLint x[], const GLint y[],
548					  const GLchan color[4],
549					  const GLubyte mask[] )
550{
551    GLuint i;
552    WMesaContext pwc = wmesa_context(ctx);
553    COLORREF colorref;
554    (void) ctx;
555    colorref = RGB(color[RCOMP], color[GCOMP], color[BCOMP]);
556    for (i=0; i<n; i++)
557	if (mask[i])
558	    SetPixel(pwc->hDC, x[i], FLIP(y[i]), colorref);
559}
560
561/* Read a horizontal span of color pixels. */
562static void read_rgba_span_front(const GLcontext *ctx,
563				  struct gl_renderbuffer *rb,
564				  GLuint n, GLint x, GLint y,
565				  GLubyte rgba[][4] )
566{
567    WMesaContext pwc = wmesa_context(ctx);
568    GLuint i;
569    COLORREF Color;
570    y = FLIP(y);
571    for (i=0; i<n; i++) {
572	Color = GetPixel(pwc->hDC, x+i, y);
573	rgba[i][RCOMP] = GetRValue(Color);
574	rgba[i][GCOMP] = GetGValue(Color);
575	rgba[i][BCOMP] = GetBValue(Color);
576	rgba[i][ACOMP] = 255;
577    }
578}
579
580
581/* Read an array of color pixels. */
582static void read_rgba_pixels_front(const GLcontext *ctx,
583				    struct gl_renderbuffer *rb,
584				    GLuint n, const GLint x[], const GLint y[],
585				    GLubyte rgba[][4])
586{
587    WMesaContext pwc = wmesa_context(ctx);
588    GLuint i;
589    COLORREF Color;
590    for (i=0; i<n; i++) {
591        GLint y2 = FLIP(y[i]);
592        Color = GetPixel(pwc->hDC, x[i], y2);
593        rgba[i][RCOMP] = GetRValue(Color);
594        rgba[i][GCOMP] = GetGValue(Color);
595        rgba[i][BCOMP] = GetBValue(Color);
596        rgba[i][ACOMP] = 255;
597    }
598}
599
600/*********************************************************************/
601
602/* DOUBLE BUFFER 32-bit */
603
604#define WMSETPIXEL32(pwc, y, x, r, g, b) { \
605LPDWORD lpdw = ((LPDWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); \
606*lpdw = BGR32((r),(g),(b)); }
607
608
609
610/* Write a horizontal span of RGBA color pixels with a boolean mask. */
611static void write_rgba_span_32(const GLcontext *ctx,
612			       struct gl_renderbuffer *rb,
613			       GLuint n, GLint x, GLint y,
614			       const GLubyte rgba[][4],
615			       const GLubyte mask[] )
616{
617    WMesaContext pwc = wmesa_context(ctx);
618    GLuint i;
619    LPDWORD lpdw;
620
621    (void) ctx;
622
623    y=FLIP(y);
624    lpdw = ((LPDWORD)(pwc->pbPixels + pwc->ScanWidth * y)) + x;
625    if (mask) {
626	for (i=0; i<n; i++)
627	    if (mask[i])
628                lpdw[i] = BGR32(rgba[i][RCOMP], rgba[i][GCOMP],
629				rgba[i][BCOMP]);
630    }
631    else {
632	for (i=0; i<n; i++)
633                *lpdw++ = BGR32(rgba[i][RCOMP], rgba[i][GCOMP],
634				rgba[i][BCOMP]);
635    }
636}
637
638
639/* Write a horizontal span of RGB color pixels with a boolean mask. */
640static void write_rgb_span_32(const GLcontext *ctx,
641			      struct gl_renderbuffer *rb,
642			      GLuint n, GLint x, GLint y,
643			      const GLubyte rgb[][3],
644			      const GLubyte mask[] )
645{
646    WMesaContext pwc = wmesa_context(ctx);
647    GLuint i;
648    LPDWORD lpdw;
649
650    (void) ctx;
651
652    y=FLIP(y);
653    lpdw = ((LPDWORD)(pwc->pbPixels + pwc->ScanWidth * y)) + x;
654    if (mask) {
655	for (i=0; i<n; i++)
656	    if (mask[i])
657                lpdw[i] = BGR32(rgb[i][RCOMP], rgb[i][GCOMP],
658				rgb[i][BCOMP]);
659    }
660    else {
661	for (i=0; i<n; i++)
662                *lpdw++ = BGR32(rgb[i][RCOMP], rgb[i][GCOMP],
663				rgb[i][BCOMP]);
664    }
665}
666
667/*
668 * Write a horizontal span of pixels with a boolean mask.  The current color
669 * is used for all pixels.
670 */
671static void write_mono_rgba_span_32(const GLcontext *ctx,
672				    struct gl_renderbuffer *rb,
673				    GLuint n, GLint x, GLint y,
674				    const GLchan color[4],
675				    const GLubyte mask[])
676{
677    LPDWORD lpdw;
678    DWORD pixel;
679    GLuint i;
680    WMesaContext pwc = wmesa_context(ctx);
681    lpdw = ((LPDWORD)(pwc->pbPixels + pwc->ScanWidth * y)) + x;
682    y=FLIP(y);
683    pixel = BGR32(color[RCOMP], color[GCOMP], color[BCOMP]);
684    if (mask) {
685	for (i=0; i<n; i++)
686	    if (mask[i])
687                lpdw[i] = pixel;
688    }
689    else
690	for (i=0; i<n; i++)
691                *lpdw++ = pixel;
692
693}
694
695/* Write an array of RGBA pixels with a boolean mask. */
696static void write_rgba_pixels_32(const GLcontext *ctx,
697				 struct gl_renderbuffer *rb,
698				 GLuint n, const GLint x[], const GLint y[],
699				 const GLubyte rgba[][4],
700				 const GLubyte mask[])
701{
702    GLuint i;
703    WMesaContext pwc = wmesa_context(ctx);;
704    for (i=0; i<n; i++)
705	if (mask[i])
706	    WMSETPIXEL32(pwc, FLIP(y[i]), x[i],
707			 rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]);
708}
709
710/*
711 * Write an array of pixels with a boolean mask.  The current color
712 * is used for all pixels.
713 */
714static void write_mono_rgba_pixels_32(const GLcontext *ctx,
715				      struct gl_renderbuffer *rb,
716				      GLuint n,
717				      const GLint x[], const GLint y[],
718				      const GLchan color[4],
719				      const GLubyte mask[])
720{
721    GLuint i;
722    WMesaContext pwc = wmesa_context(ctx);
723    for (i=0; i<n; i++)
724	if (mask[i])
725	    WMSETPIXEL32(pwc, FLIP(y[i]),x[i],color[RCOMP],
726			 color[GCOMP], color[BCOMP]);
727}
728
729/* Read a horizontal span of color pixels. */
730static void read_rgba_span_32(const GLcontext *ctx,
731			      struct gl_renderbuffer *rb,
732			      GLuint n, GLint x, GLint y,
733			      GLubyte rgba[][4] )
734{
735    GLuint i;
736    DWORD pixel;
737    LPDWORD lpdw;
738    WMesaContext pwc = wmesa_context(ctx);
739
740    y = FLIP(y);
741    lpdw = ((LPDWORD)(pwc->pbPixels + pwc->ScanWidth * y)) + x;
742    for (i=0; i<n; i++) {
743	pixel = lpdw[i];
744	rgba[i][RCOMP] = (pixel & 0x00ff0000) >> 16;
745	rgba[i][GCOMP] = (pixel & 0x0000ff00) >> 8;
746	rgba[i][BCOMP] = (pixel & 0x000000ff);
747	rgba[i][ACOMP] = 255;
748    }
749}
750
751
752/* Read an array of color pixels. */
753static void read_rgba_pixels_32(const GLcontext *ctx,
754				struct gl_renderbuffer *rb,
755				GLuint n, const GLint x[], const GLint y[],
756				GLubyte rgba[][4])
757{
758    GLuint i;
759    DWORD pixel;
760    LPDWORD lpdw;
761    WMesaContext pwc = wmesa_context(ctx);
762
763    for (i=0; i<n; i++) {
764	GLint y2 = FLIP(y[i]);
765	lpdw = ((LPDWORD)(pwc->pbPixels + pwc->ScanWidth * y2)) + x[i];
766	pixel = lpdw[i];
767	rgba[i][RCOMP] = (pixel & 0x00ff0000) >> 16;
768	rgba[i][GCOMP] = (pixel & 0x0000ff00) >> 8;
769	rgba[i][BCOMP] = (pixel & 0x000000ff);
770	rgba[i][ACOMP] = 255;
771  }
772}
773
774
775/*********************************************************************/
776
777/* DOUBLE BUFFER 16-bit */
778
779#define WMSETPIXEL16(pwc, y, x, r, g, b) { \
780LPWORD lpw = ((LPWORD)((pwc)->pbPixels + (pwc)->ScanWidth * (y)) + (x)); \
781*lpw = BGR16((r),(g),(b)); }
782
783
784
785/* Write a horizontal span of RGBA color pixels with a boolean mask. */
786static void write_rgba_span_16(const GLcontext *ctx,
787			       struct gl_renderbuffer *rb,
788			       GLuint n, GLint x, GLint y,
789			       const GLubyte rgba[][4],
790			       const GLubyte mask[] )
791{
792    WMesaContext pwc = wmesa_context(ctx);
793    GLuint i;
794    LPWORD lpw;
795
796    (void) ctx;
797
798    y=FLIP(y);
799    lpw = ((LPWORD)(pwc->pbPixels + pwc->ScanWidth * y)) + x;
800    if (mask) {
801	for (i=0; i<n; i++)
802	    if (mask[i])
803                lpw[i] = BGR16(rgba[i][RCOMP], rgba[i][GCOMP],
804			       rgba[i][BCOMP]);
805    }
806    else {
807	for (i=0; i<n; i++)
808                *lpw++ = BGR16(rgba[i][RCOMP], rgba[i][GCOMP],
809			       rgba[i][BCOMP]);
810    }
811}
812
813
814/* Write a horizontal span of RGB color pixels with a boolean mask. */
815static void write_rgb_span_16(const GLcontext *ctx,
816			      struct gl_renderbuffer *rb,
817			      GLuint n, GLint x, GLint y,
818			      const GLubyte rgb[][3],
819			      const GLubyte mask[] )
820{
821    WMesaContext pwc = wmesa_context(ctx);
822    GLuint i;
823    LPWORD lpw;
824
825    (void) ctx;
826
827    y=FLIP(y);
828    lpw = ((LPWORD)(pwc->pbPixels + pwc->ScanWidth * y)) + x;
829    if (mask) {
830	for (i=0; i<n; i++)
831	    if (mask[i])
832                lpw[i] = BGR16(rgb[i][RCOMP], rgb[i][GCOMP],
833			       rgb[i][BCOMP]);
834    }
835    else {
836	for (i=0; i<n; i++)
837                *lpw++ = BGR16(rgb[i][RCOMP], rgb[i][GCOMP],
838			       rgb[i][BCOMP]);
839    }
840}
841
842/*
843 * Write a horizontal span of pixels with a boolean mask.  The current color
844 * is used for all pixels.
845 */
846static void write_mono_rgba_span_16(const GLcontext *ctx,
847				    struct gl_renderbuffer *rb,
848				    GLuint n, GLint x, GLint y,
849				    const GLchan color[4],
850				    const GLubyte mask[])
851{
852    LPWORD lpw;
853    WORD pixel;
854    GLuint i;
855    WMesaContext pwc = wmesa_context(ctx);
856    (void) ctx;
857    lpw = ((LPWORD)(pwc->pbPixels + pwc->ScanWidth * y)) + x;
858    y=FLIP(y);
859    pixel = BGR16(color[RCOMP], color[GCOMP], color[BCOMP]);
860    if (mask) {
861	for (i=0; i<n; i++)
862	    if (mask[i])
863                lpw[i] = pixel;
864    }
865    else
866	for (i=0; i<n; i++)
867                *lpw++ = pixel;
868
869}
870
871/* Write an array of RGBA pixels with a boolean mask. */
872static void write_rgba_pixels_16(const GLcontext *ctx,
873				 struct gl_renderbuffer *rb,
874				 GLuint n, const GLint x[], const GLint y[],
875				 const GLubyte rgba[][4],
876				 const GLubyte mask[])
877{
878    GLuint i;
879    WMesaContext pwc = wmesa_context(ctx);
880    (void) ctx;
881    for (i=0; i<n; i++)
882	if (mask[i])
883	    WMSETPIXEL16(pwc, FLIP(y[i]), x[i],
884			 rgba[i][RCOMP], rgba[i][GCOMP], rgba[i][BCOMP]);
885}
886
887/*
888 * Write an array of pixels with a boolean mask.  The current color
889 * is used for all pixels.
890 */
891static void write_mono_rgba_pixels_16(const GLcontext *ctx,
892				      struct gl_renderbuffer *rb,
893				      GLuint n,
894				      const GLint x[], const GLint y[],
895				      const GLchan color[4],
896				      const GLubyte mask[])
897{
898    GLuint i;
899    WMesaContext pwc = wmesa_context(ctx);
900    (void) ctx;
901    for (i=0; i<n; i++)
902	if (mask[i])
903	    WMSETPIXEL16(pwc, FLIP(y[i]),x[i],color[RCOMP],
904			 color[GCOMP], color[BCOMP]);
905}
906
907/* Read a horizontal span of color pixels. */
908static void read_rgba_span_16(const GLcontext *ctx,
909			      struct gl_renderbuffer *rb,
910			      GLuint n, GLint x, GLint y,
911			      GLubyte rgba[][4] )
912{
913    GLuint i, pixel;
914    LPWORD lpw;
915    WMesaContext pwc = wmesa_context(ctx);
916
917    y = FLIP(y);
918    lpw = ((LPWORD)(pwc->pbPixels + pwc->ScanWidth * y)) + x;
919    for (i=0; i<n; i++) {
920	pixel = lpw[i];
921	/* Windows uses 5,5,5 for 16-bit */
922	rgba[i][RCOMP] = (pixel & 0x7c00) >> 7;
923	rgba[i][GCOMP] = (pixel & 0x03e0) >> 2;
924	rgba[i][BCOMP] = (pixel & 0x001f) << 3;
925	rgba[i][ACOMP] = 255;
926    }
927}
928
929
930/* Read an array of color pixels. */
931static void read_rgba_pixels_16(const GLcontext *ctx,
932				struct gl_renderbuffer *rb,
933				GLuint n, const GLint x[], const GLint y[],
934				GLubyte rgba[][4])
935{
936    GLuint i, pixel;
937    LPWORD lpw;
938    WMesaContext pwc = wmesa_context(ctx);
939
940    for (i=0; i<n; i++) {
941	GLint y2 = FLIP(y[i]);
942	lpw = ((LPWORD)(pwc->pbPixels + pwc->ScanWidth * y2)) + x[i];
943	pixel = lpw[i];
944	/* Windows uses 5,5,5 for 16-bit */
945	rgba[i][RCOMP] = (pixel & 0x7c00) >> 7;
946	rgba[i][GCOMP] = (pixel & 0x03e0) >> 2;
947	rgba[i][BCOMP] = (pixel & 0x001f) << 3;
948	rgba[i][ACOMP] = 255;
949  }
950}
951
952
953
954
955/**********************************************************************/
956/*****                   BUFFER Functions                         *****/
957/**********************************************************************/
958
959
960
961
962static void
963wmesa_delete_renderbuffer(struct gl_renderbuffer *rb)
964{
965    _mesa_free(rb);
966}
967
968
969/**
970 * This is called by Mesa whenever it determines that the window size
971 * has changed.  Do whatever's needed to cope with that.
972 */
973static GLboolean
974wmesa_renderbuffer_storage(GLcontext *ctx,
975			   struct gl_renderbuffer *rb,
976			   GLenum internalFormat,
977			   GLuint width,
978			   GLuint height)
979{
980    rb->Width = width;
981    rb->Height = height;
982    return GL_TRUE;
983}
984
985
986/**
987 * Plug in the Get/PutRow/Values functions for a renderbuffer depending
988 * on if we're drawing to the front or back color buffer.
989 */
990void wmesa_set_renderbuffer_funcs(struct gl_renderbuffer *rb, int pixelformat,
991                                  int double_buffer)
992{
993    if (double_buffer) {
994        /* back buffer */
995	/* Picking the correct span functions is important because
996	 * the DIB was allocated with the indicated depth. */
997	switch(pixelformat) {
998	case PF_5R6G5B:
999	    rb->PutRow = write_rgba_span_16;
1000	    rb->PutRowRGB = write_rgb_span_16;
1001	    rb->PutMonoRow = write_mono_rgba_span_16;
1002	    rb->PutValues = write_rgba_pixels_16;
1003	    rb->PutMonoValues = write_mono_rgba_pixels_16;
1004	    rb->GetRow = read_rgba_span_16;
1005	    rb->GetValues = read_rgba_pixels_16;
1006            rb->RedBits = 5;
1007            rb->GreenBits = 6;
1008            rb->BlueBits = 5;
1009	    break;
1010	case PF_8R8G8B:
1011	    rb->PutRow = write_rgba_span_32;
1012	    rb->PutRowRGB = write_rgb_span_32;
1013	    rb->PutMonoRow = write_mono_rgba_span_32;
1014	    rb->PutValues = write_rgba_pixels_32;
1015	    rb->PutMonoValues = write_mono_rgba_pixels_32;
1016	    rb->GetRow = read_rgba_span_32;
1017	    rb->GetValues = read_rgba_pixels_32;
1018            rb->RedBits = 8;
1019            rb->GreenBits = 8;
1020            rb->BlueBits = 8;
1021	    break;
1022	default:
1023	    break;
1024	}
1025    }
1026    else {
1027        /* front buffer (actual Windows window) */
1028	rb->PutRow = write_rgba_span_front;
1029	rb->PutRowRGB = write_rgb_span_front;
1030	rb->PutMonoRow = write_mono_rgba_span_front;
1031	rb->PutValues = write_rgba_pixels_front;
1032	rb->PutMonoValues = write_mono_rgba_pixels_front;
1033	rb->GetRow = read_rgba_span_front;
1034	rb->GetValues = read_rgba_pixels_front;
1035        rb->RedBits = 8; /* XXX fix these (565?) */
1036        rb->GreenBits = 8;
1037        rb->BlueBits = 8;
1038    }
1039}
1040
1041/**
1042 * Called by ctx->Driver.ResizeBuffers()
1043 * Resize the front/back colorbuffers to match the latest window size.
1044 */
1045static void
1046wmesa_resize_buffers(GLcontext *ctx, GLframebuffer *buffer,
1047                     GLuint width, GLuint height)
1048{
1049    WMesaContext pwc = wmesa_context(ctx);
1050    WMesaFramebuffer pwfb = wmesa_framebuffer(buffer);
1051
1052    if (pwfb->Base.Width != width || pwfb->Base.Height != height) {
1053	/* Realloc back buffer */
1054	if (pwc->db_flag) {
1055	    wmDeleteBackingStore(pwc);
1056	    wmCreateBackingStore(pwc, width, height);
1057	}
1058    }
1059    _mesa_resize_framebuffer(ctx, buffer, width, height);
1060}
1061
1062
1063/**
1064 * Called by glViewport.
1065 * This is a good time for us to poll the current window size and adjust
1066 * our renderbuffers to match the current window size.
1067 * Remember, we have no opportunity to respond to conventional
1068 * resize events since the driver has no event loop.
1069 * Thus, we poll.
1070 * MakeCurrent also ends up making a call here, so that ensures
1071 * we get the viewport set correctly, even if the app does not call
1072 * glViewport and relies on the defaults.
1073 */
1074static void wmesa_viewport(GLcontext *ctx,
1075			   GLint x, GLint y,
1076			   GLsizei width, GLsizei height)
1077{
1078    WMesaContext pwc = wmesa_context(ctx);
1079    GLuint new_width, new_height;
1080
1081    wmesa_get_buffer_size(ctx->WinSysDrawBuffer, &new_width, &new_height);
1082
1083    /**
1084     * Resize buffers if the window size changed.
1085     */
1086    wmesa_resize_buffers(ctx, ctx->WinSysDrawBuffer, new_width, new_height);
1087    ctx->NewState |= _NEW_BUFFERS;  /* to update scissor / window bounds */
1088}
1089
1090
1091
1092
1093/**
1094 * Called when the driver should update it's state, based on the new_state
1095 * flags.
1096 */
1097static void wmesa_update_state(GLcontext *ctx, GLuint new_state)
1098{
1099    _swrast_InvalidateState(ctx, new_state);
1100    _swsetup_InvalidateState(ctx, new_state);
1101    _ac_InvalidateState(ctx, new_state);
1102    _tnl_InvalidateState(ctx, new_state);
1103
1104    /* TODO - need code to update the span functions in case the
1105     * renderer changes the target buffer (like a DB app writing to
1106     * the front buffer). */
1107
1108#if 0
1109    {  /* could check _NEW_BUFFERS bit flag here  in new_state */
1110	/* In progress - Need to make the wmesa context inherit (by containment)
1111	the gl_context, so I can get access to the pixel format */
1112	struct gl_renderbuffer *rb;
1113	int pixelformat, double_buffer;
1114
1115	rb = ctx->DrawBuffer->Attachment[BUFFER_BACK_LEFT].Renderbuffer;
1116	pixelformat = PF_5R6G5B;  // hard code for now - see note above
1117        double_buffer = ctx->DrawBuffer->ColorDrawBuffer[0] == GL_BACK ? 1 : 0;
1118	if (rb)
1119        wmesa_set_renderbuffer_funcs(rb, pixelformat, double_buffer);
1120    }
1121#endif
1122}
1123
1124
1125
1126
1127
1128/**********************************************************************/
1129/*****                   WMESA Functions                          *****/
1130/**********************************************************************/
1131
1132WMesaContext WMesaCreateContext(HDC hDC,
1133				HPALETTE* Pal,
1134				GLboolean rgb_flag,
1135				GLboolean db_flag,
1136				GLboolean alpha_flag)
1137{
1138    WMesaContext c;
1139    struct dd_function_table functions;
1140    GLint red_bits, green_bits, blue_bits, alpha_bits;
1141    GLcontext *ctx;
1142    GLvisual *visual;
1143
1144    (void) Pal;
1145
1146    /* Indexed mode not supported */
1147    if (!rgb_flag)
1148	return NULL;
1149
1150    /* Allocate wmesa context */
1151    c = CALLOC_STRUCT(wmesa_context);
1152    if (!c)
1153	return NULL;
1154
1155#if 0
1156    /* I do not understand this contributed code */
1157    /* Support memory and device contexts */
1158    if(WindowFromDC(hDC) != NULL) {
1159	c->hDC = GetDC(WindowFromDC(hDC)); // huh ????
1160    }
1161    else {
1162	c->hDC = hDC;
1163    }
1164#else
1165    c->hDC = hDC;
1166#endif
1167
1168    /* rememember DC and flag settings */
1169    c->rgb_flag = rgb_flag;
1170    c->db_flag = db_flag;
1171    c->alpha_flag = alpha_flag;
1172
1173    /* Get data for visual */
1174    /* Dealing with this is actually a bit of overkill because Mesa will end
1175     * up treating all color component size requests less than 8 by using
1176     * a single byte per channel.  In addition, the interface to the span
1177     * routines passes colors as an entire byte per channel anyway, so there
1178     * is nothing to be saved by telling the visual to be 16 bits if the device
1179     * is 16 bits.  That is, Mesa is going to compute colors down to 8 bits per
1180     * channel anyway.
1181     * But we go through the motions here anyway.
1182     */
1183    switch (GetDeviceCaps(c->hDC, BITSPIXEL)) {
1184    case 16:
1185	red_bits = green_bits = blue_bits = 5;
1186	alpha_bits = 0;
1187	break;
1188    default:
1189	red_bits = green_bits = blue_bits = 8;
1190	alpha_bits = 8;
1191	break;
1192    }
1193    /* Create visual based on flags */
1194    visual = _mesa_create_visual(rgb_flag,
1195                                 db_flag,    /* db_flag */
1196                                 GL_FALSE,   /* stereo */
1197                                 red_bits, green_bits, blue_bits, /* color RGB */
1198                                 alpha_flag ? alpha_bits : 0, /* color A */
1199                                 0,          /* index bits */
1200                                 DEFAULT_SOFTWARE_DEPTH_BITS, /* depth_bits */
1201                                 8,          /* stencil_bits */
1202                                 16,16,16,   /* accum RGB */
1203                                 alpha_flag ? 16 : 0, /* accum A */
1204                                 1);         /* num samples */
1205
1206    if (!visual) {
1207	_mesa_free(c);
1208	return NULL;
1209    }
1210
1211    /* Set up driver functions */
1212    _mesa_init_driver_functions(&functions);
1213    functions.GetString = wmesa_get_string;
1214    functions.UpdateState = wmesa_update_state;
1215    functions.GetBufferSize = wmesa_get_buffer_size;
1216    functions.Flush = wmesa_flush;
1217    functions.Clear = clear;
1218    functions.ClearIndex = clear_index;
1219    functions.ClearColor = clear_color;
1220    functions.ResizeBuffers = wmesa_resize_buffers;
1221    functions.Viewport = wmesa_viewport;
1222
1223    /* initialize the Mesa context data */
1224    ctx = &c->gl_ctx;
1225    _mesa_initialize_context(ctx, visual, NULL, &functions, (void *)c);
1226
1227    _mesa_enable_sw_extensions(ctx);
1228    _mesa_enable_1_3_extensions(ctx);
1229    _mesa_enable_1_4_extensions(ctx);
1230    _mesa_enable_1_5_extensions(ctx);
1231    _mesa_enable_2_0_extensions(ctx);
1232
1233    /* Initialize the software rasterizer and helper modules. */
1234    if (!_swrast_CreateContext(ctx) ||
1235        !_ac_CreateContext(ctx) ||
1236        !_tnl_CreateContext(ctx) ||
1237	!_swsetup_CreateContext(ctx)) {
1238	_mesa_free_context_data(ctx);
1239	_mesa_free(c);
1240	return NULL;
1241    }
1242    _swsetup_Wakeup(ctx);
1243    TNL_CONTEXT(ctx)->Driver.RunPipeline = _tnl_run_pipeline;
1244
1245    return c;
1246}
1247
1248
1249void WMesaDestroyContext( WMesaContext pwc )
1250{
1251    GLcontext *ctx = &pwc->gl_ctx;
1252    GET_CURRENT_CONTEXT(cur_ctx);
1253
1254    if (cur_ctx == ctx) {
1255        /* unbind current if deleting current context */
1256        WMesaMakeCurrent(NULL, NULL);
1257    }
1258
1259    /* Release for device, not memory contexts */
1260    if (WindowFromDC(pwc->hDC) != NULL)
1261    {
1262      ReleaseDC(WindowFromDC(pwc->hDC), pwc->hDC);
1263    }
1264    DeleteObject(pwc->clearPen);
1265    DeleteObject(pwc->clearBrush);
1266
1267    if (pwc->db_flag)
1268	wmDeleteBackingStore(pwc);
1269
1270    _swsetup_DestroyContext(ctx);
1271    _tnl_DestroyContext(ctx);
1272    _ac_DestroyContext(ctx);
1273    _swrast_DestroyContext(ctx);
1274
1275    _mesa_free_context_data(ctx);
1276    _mesa_free(pwc);
1277}
1278
1279
1280/**
1281 * Create a new color renderbuffer.
1282 */
1283struct gl_renderbuffer *
1284wmesa_new_renderbuffer(void)
1285{
1286    struct gl_renderbuffer *rb = CALLOC_STRUCT(gl_renderbuffer);
1287    if (!rb)
1288        return NULL;
1289
1290    _mesa_init_renderbuffer(rb, (GLuint)0);
1291
1292    rb->_BaseFormat = GL_RGBA;
1293    rb->InternalFormat = GL_RGBA;
1294    rb->DataType = CHAN_TYPE;
1295    rb->Delete = wmesa_delete_renderbuffer;
1296    rb->AllocStorage = wmesa_renderbuffer_storage;
1297    return rb;
1298}
1299
1300
1301void WMesaMakeCurrent(WMesaContext c, HDC hdc)
1302{
1303    WMesaFramebuffer pwfb;
1304
1305    {
1306        /* return if already current */
1307        GET_CURRENT_CONTEXT(ctx);
1308        WMesaContext pwc = wmesa_context(ctx);
1309        if (c == pwc && pwc->hDC == hdc)
1310            return;
1311    }
1312
1313    pwfb = wmesa_lookup_framebuffer(hdc);
1314
1315    /* Lazy creation of framebuffers */
1316    if (c && !pwfb) {
1317        struct gl_renderbuffer *rb;
1318        GLvisual *visual = &c->gl_ctx.Visual;
1319        GLuint width, height;
1320
1321        get_window_size(hdc, &width, &height);
1322
1323	c->clearPen = CreatePen(PS_SOLID, 1, 0);
1324	c->clearBrush = CreateSolidBrush(0);
1325
1326	/* Create back buffer if double buffered */
1327	if (c->db_flag) {
1328	    wmCreateBackingStore(c, width, height);
1329	}
1330
1331        pwfb = wmesa_new_framebuffer(hdc, visual);
1332
1333        /* need a color renderbuffer */
1334        /* XXX we need to make two renderbuffers if double-buffering,
1335         * one for front color buffer and one for the back.
1336         */
1337        rb = wmesa_new_renderbuffer();
1338        if (c->db_flag)
1339            _mesa_add_renderbuffer(&pwfb->Base, BUFFER_BACK_LEFT, rb);
1340        else
1341            _mesa_add_renderbuffer(&pwfb->Base, BUFFER_FRONT_LEFT, rb);
1342        wmesa_set_renderbuffer_funcs(rb, c->pixelformat, c->db_flag);
1343
1344        /* Let Mesa own the Depth, Stencil, and Accum buffers */
1345        _mesa_add_soft_renderbuffers(&pwfb->Base,
1346                                     GL_FALSE, /* color */
1347                                     visual->depthBits > 0,
1348                                     visual->stencilBits > 0,
1349                                     visual->accumRedBits > 0,
1350                                     c->alpha_flag,
1351                                     GL_FALSE);
1352    }
1353
1354    if (c && pwfb)
1355	_mesa_make_current(&c->gl_ctx, &pwfb->Base, &pwfb->Base);
1356    else
1357        _mesa_make_current(NULL, NULL, NULL);
1358}
1359
1360
1361void WMesaSwapBuffers( HDC hdc )
1362{
1363    GET_CURRENT_CONTEXT(ctx);
1364    WMesaContext pwc = wmesa_context(ctx);
1365    WMesaFramebuffer pwfb = wmesa_lookup_framebuffer(hdc);
1366
1367    if (!pwfb) {
1368        _mesa_problem(NULL, "wmesa: swapbuffers on unknown hdc");
1369        return;
1370    }
1371
1372    /* If we're swapping the buffer associated with the current context
1373     * we have to flush any pending rendering commands first.
1374     */
1375    if (pwc->hDC == hdc) {
1376	_mesa_notifySwapBuffers(ctx);
1377
1378	BitBlt(pwc->hDC, 0, 0, pwfb->Base.Width, pwfb->Base.Height,
1379	       pwc->dib.hDC, 0, 0, SRCCOPY);
1380    }
1381    else {
1382        /* XXX for now only allow swapping current window */
1383        _mesa_problem(NULL, "wmesa: can't swap non-current window");
1384    }
1385}
1386