nir: Use helper macros for dealing with VLAs.
[mesa.git] / src / mesa / drivers / windows / gdi / wmesa.c
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 <winuser.h>
10 #include "main/context.h"
11 #include "main/api_exec.h"
12 #include "main/extensions.h"
13 #include "main/framebuffer.h"
14 #include "main/renderbuffer.h"
15 #include "main/macros.h"
16 #include "main/version.h"
17 #include "main/vtxfmt.h"
18 #include "drivers/common/driverfuncs.h"
19 #include "drivers/common/meta.h"
20 #include "vbo/vbo.h"
21 #include "swrast/swrast.h"
22 #include "swrast/s_renderbuffer.h"
23 #include "swrast_setup/swrast_setup.h"
24 #include "tnl/tnl.h"
25 #include "tnl/t_context.h"
26 #include "tnl/t_pipeline.h"
27
28
29 /* linked list of our Framebuffers (windows) */
30 static WMesaFramebuffer FirstFramebuffer = NULL;
31
32
33 /**
34 * Create a new WMesaFramebuffer object which will correspond to the
35 * given HDC (Window handle).
36 */
37 static WMesaFramebuffer
38 wmesa_new_framebuffer(HDC hdc, struct gl_config *visual)
39 {
40 WMesaFramebuffer pwfb
41 = malloc(sizeof(struct wmesa_framebuffer));
42 if (pwfb) {
43 _mesa_initialize_window_framebuffer(&pwfb->Base, visual);
44 pwfb->hDC = hdc;
45 /* insert at head of list */
46 pwfb->next = FirstFramebuffer;
47 FirstFramebuffer = pwfb;
48 }
49 return pwfb;
50 }
51
52 /**
53 * Given an hdc, free the corresponding WMesaFramebuffer
54 */
55 static void
56 wmesa_free_framebuffer(HDC hdc)
57 {
58 WMesaFramebuffer pwfb, prev;
59 for (pwfb = FirstFramebuffer; pwfb; pwfb = pwfb->next) {
60 if (pwfb->hDC == hdc)
61 break;
62 prev = pwfb;
63 }
64 if (pwfb) {
65 struct gl_framebuffer *fb;
66 if (pwfb == FirstFramebuffer)
67 FirstFramebuffer = pwfb->next;
68 else
69 prev->next = pwfb->next;
70 fb = &pwfb->Base;
71 _mesa_reference_framebuffer(&fb, NULL);
72 }
73 }
74
75 /**
76 * Given an hdc, return the corresponding WMesaFramebuffer
77 */
78 static WMesaFramebuffer
79 wmesa_lookup_framebuffer(HDC hdc)
80 {
81 WMesaFramebuffer pwfb;
82 for (pwfb = FirstFramebuffer; pwfb; pwfb = pwfb->next) {
83 if (pwfb->hDC == hdc)
84 return pwfb;
85 }
86 return NULL;
87 }
88
89
90 /**
91 * Given a struct gl_framebuffer, return the corresponding WMesaFramebuffer.
92 */
93 static WMesaFramebuffer wmesa_framebuffer(struct gl_framebuffer *fb)
94 {
95 return (WMesaFramebuffer) fb;
96 }
97
98
99 /**
100 * Given a struct gl_context, return the corresponding WMesaContext.
101 */
102 static WMesaContext wmesa_context(const struct gl_context *ctx)
103 {
104 return (WMesaContext) ctx;
105 }
106
107
108 /*
109 * Every driver should implement a GetString function in order to
110 * return a meaningful GL_RENDERER string.
111 */
112 static const GLubyte *wmesa_get_string(struct gl_context *ctx, GLenum name)
113 {
114 return (name == GL_RENDERER) ?
115 (GLubyte *) "Mesa Windows GDI Driver" : NULL;
116 }
117
118
119 /*
120 * Determine the pixel format based on the pixel size.
121 */
122 static void wmSetPixelFormat(WMesaFramebuffer pwfb, HDC hDC)
123 {
124 pwfb->cColorBits = GetDeviceCaps(hDC, BITSPIXEL);
125
126 /* Only 16 and 32 bit targets are supported now */
127 assert(pwfb->cColorBits == 0 ||
128 pwfb->cColorBits == 16 ||
129 pwfb->cColorBits == 24 ||
130 pwfb->cColorBits == 32);
131
132 switch(pwfb->cColorBits){
133 case 8:
134 pwfb->pixelformat = PF_INDEX8;
135 break;
136 case 16:
137 pwfb->pixelformat = PF_5R6G5B;
138 break;
139 case 24:
140 case 32:
141 pwfb->pixelformat = PF_8R8G8B;
142 break;
143 default:
144 pwfb->pixelformat = PF_BADFORMAT;
145 }
146 }
147
148
149 /**
150 * Create DIB for back buffer.
151 * We write into this memory with the span routines and then blit it
152 * to the window on a buffer swap.
153 */
154 static BOOL wmCreateBackingStore(WMesaFramebuffer pwfb, long lxSize, long lySize)
155 {
156 LPBITMAPINFO pbmi = &(pwfb->bmi);
157 HDC hic;
158
159 pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
160 pbmi->bmiHeader.biWidth = lxSize;
161 pbmi->bmiHeader.biHeight= -lySize;
162 pbmi->bmiHeader.biPlanes = 1;
163 pbmi->bmiHeader.biBitCount = GetDeviceCaps(pwfb->hDC, BITSPIXEL);
164 pbmi->bmiHeader.biCompression = BI_RGB;
165 pbmi->bmiHeader.biSizeImage = 0;
166 pbmi->bmiHeader.biXPelsPerMeter = 0;
167 pbmi->bmiHeader.biYPelsPerMeter = 0;
168 pbmi->bmiHeader.biClrUsed = 0;
169 pbmi->bmiHeader.biClrImportant = 0;
170
171 pwfb->cColorBits = pbmi->bmiHeader.biBitCount;
172 pwfb->ScanWidth = (lxSize * (pwfb->cColorBits / 8) + 3) & ~3;
173
174 hic = CreateIC("display", NULL, NULL, NULL);
175 pwfb->dib_hDC = CreateCompatibleDC(hic);
176
177 pwfb->hbmDIB = CreateDIBSection(hic,
178 &pwfb->bmi,
179 DIB_RGB_COLORS,
180 (void **)&(pwfb->pbPixels),
181 0,
182 0);
183 pwfb->hOldBitmap = SelectObject(pwfb->dib_hDC, pwfb->hbmDIB);
184
185 DeleteDC(hic);
186
187 wmSetPixelFormat(pwfb, pwfb->hDC);
188 return TRUE;
189 }
190
191
192 static void wmDeleteBackingStore(WMesaFramebuffer pwfb)
193 {
194 if (pwfb->hbmDIB) {
195 SelectObject(pwfb->dib_hDC, pwfb->hOldBitmap);
196 DeleteDC(pwfb->dib_hDC);
197 DeleteObject(pwfb->hbmDIB);
198 }
199 }
200
201
202 /**
203 * Find the width and height of the window named by hdc.
204 */
205 static void
206 get_window_size(HDC hdc, GLuint *width, GLuint *height)
207 {
208 if (WindowFromDC(hdc)) {
209 RECT rect;
210 GetClientRect(WindowFromDC(hdc), &rect);
211 *width = rect.right - rect.left;
212 *height = rect.bottom - rect.top;
213 }
214 else { /* Memory context */
215 /* From contributed code - use the size of the desktop
216 * for the size of a memory context (?) */
217 *width = GetDeviceCaps(hdc, HORZRES);
218 *height = GetDeviceCaps(hdc, VERTRES);
219 }
220 }
221
222
223 static void
224 wmesa_get_buffer_size(struct gl_framebuffer *buffer, GLuint *width, GLuint *height)
225 {
226 WMesaFramebuffer pwfb = wmesa_framebuffer(buffer);
227 get_window_size(pwfb->hDC, width, height);
228 }
229
230
231 static void wmesa_flush(struct gl_context *ctx)
232 {
233 WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->WinSysDrawBuffer);
234
235 if (ctx->Visual.doubleBufferMode == 1) {
236 BitBlt(pwfb->hDC, 0, 0, pwfb->Base.Width, pwfb->Base.Height,
237 pwfb->dib_hDC, 0, 0, SRCCOPY);
238 }
239 else {
240 /* Do nothing for single buffer */
241 }
242 }
243
244
245 /**********************************************************************/
246 /***** CLEAR Functions *****/
247 /**********************************************************************/
248
249 /*
250 * Clear the color/depth/stencil buffers.
251 */
252 static void clear(struct gl_context *ctx, GLbitfield mask)
253 {
254 #define FLIP(Y) (ctx->DrawBuffer->Height - (Y) - 1)
255 const GLint x = ctx->DrawBuffer->_Xmin;
256 const GLint y = ctx->DrawBuffer->_Ymin;
257 const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
258 const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
259
260 WMesaContext pwc = wmesa_context(ctx);
261 WMesaFramebuffer pwfb = wmesa_framebuffer(ctx->DrawBuffer);
262 int done = 0;
263
264 /* Let swrast do all the work if the masks are not set to
265 * clear all channels. */
266 if (!ctx->Color.ColorMask[0][0] ||
267 !ctx->Color.ColorMask[0][1] ||
268 !ctx->Color.ColorMask[0][2] ||
269 !ctx->Color.ColorMask[0][3]) {
270 _swrast_Clear(ctx, mask);
271 return;
272 }
273
274 if (mask & BUFFER_BITS_COLOR) {
275 /* setup the clearing color */
276 const union gl_color_union color = ctx->Color.ClearColor;
277 GLubyte col[3];
278 UNCLAMPED_FLOAT_TO_UBYTE(col[0], color.f[0]);
279 UNCLAMPED_FLOAT_TO_UBYTE(col[1], color.f[1]);
280 UNCLAMPED_FLOAT_TO_UBYTE(col[2], color.f[2]);
281 pwc->clearColorRef = RGB(col[0], col[1], col[2]);
282 DeleteObject(pwc->clearPen);
283 DeleteObject(pwc->clearBrush);
284 pwc->clearPen = CreatePen(PS_SOLID, 1, pwc->clearColorRef);
285 pwc->clearBrush = CreateSolidBrush(pwc->clearColorRef);
286 }
287
288 /* Back buffer */
289 if (mask & BUFFER_BIT_BACK_LEFT) {
290
291 int i, rowSize;
292 UINT bytesPerPixel = pwfb->cColorBits / 8;
293 LPBYTE lpb, clearRow;
294 LPWORD lpw;
295 BYTE bColor;
296 WORD wColor;
297 BYTE r, g, b;
298 DWORD dwColor;
299 LPDWORD lpdw;
300
301 /* Try for a fast clear - clearing entire buffer with a single
302 * byte value. */
303 if (width == ctx->DrawBuffer->Width &&
304 height == ctx->DrawBuffer->Height) { /* entire buffer */
305 /* Now check for an easy clear value */
306 switch (bytesPerPixel) {
307 case 1:
308 bColor = BGR8(GetRValue(pwc->clearColorRef),
309 GetGValue(pwc->clearColorRef),
310 GetBValue(pwc->clearColorRef));
311 memset(pwfb->pbPixels, bColor,
312 pwfb->ScanWidth * height);
313 done = 1;
314 break;
315 case 2:
316 wColor = BGR16(GetRValue(pwc->clearColorRef),
317 GetGValue(pwc->clearColorRef),
318 GetBValue(pwc->clearColorRef));
319 if (((wColor >> 8) & 0xff) == (wColor & 0xff)) {
320 memset(pwfb->pbPixels, wColor & 0xff,
321 pwfb->ScanWidth * height);
322 done = 1;
323 }
324 break;
325 case 3:
326 /* fall through */
327 case 4:
328 if (GetRValue(pwc->clearColorRef) ==
329 GetGValue(pwc->clearColorRef) &&
330 GetRValue(pwc->clearColorRef) ==
331 GetBValue(pwc->clearColorRef)) {
332 memset(pwfb->pbPixels,
333 GetRValue(pwc->clearColorRef),
334 pwfb->ScanWidth * height);
335 done = 1;
336 }
337 break;
338 default:
339 break;
340 }
341 } /* all */
342
343 if (!done) {
344 /* Need to clear a row at a time. Begin by setting the first
345 * row in the area to be cleared to the clear color. */
346
347 clearRow = pwfb->pbPixels +
348 pwfb->ScanWidth * FLIP(y) +
349 bytesPerPixel * x;
350 switch (bytesPerPixel) {
351 case 1:
352 lpb = clearRow;
353 bColor = BGR8(GetRValue(pwc->clearColorRef),
354 GetGValue(pwc->clearColorRef),
355 GetBValue(pwc->clearColorRef));
356 memset(lpb, bColor, width);
357 break;
358 case 2:
359 lpw = (LPWORD)clearRow;
360 wColor = BGR16(GetRValue(pwc->clearColorRef),
361 GetGValue(pwc->clearColorRef),
362 GetBValue(pwc->clearColorRef));
363 for (i=0; i<width; i++)
364 *lpw++ = wColor;
365 break;
366 case 3:
367 lpb = clearRow;
368 r = GetRValue(pwc->clearColorRef);
369 g = GetGValue(pwc->clearColorRef);
370 b = GetBValue(pwc->clearColorRef);
371 for (i=0; i<width; i++) {
372 *lpb++ = b;
373 *lpb++ = g;
374 *lpb++ = r;
375 }
376 break;
377 case 4:
378 lpdw = (LPDWORD)clearRow;
379 dwColor = BGR32(GetRValue(pwc->clearColorRef),
380 GetGValue(pwc->clearColorRef),
381 GetBValue(pwc->clearColorRef));
382 for (i=0; i<width; i++)
383 *lpdw++ = dwColor;
384 break;
385 default:
386 break;
387 } /* switch */
388
389 /* copy cleared row to other rows in buffer */
390 lpb = clearRow - pwfb->ScanWidth;
391 rowSize = width * bytesPerPixel;
392 for (i=1; i<height; i++) {
393 memcpy(lpb, clearRow, rowSize);
394 lpb -= pwfb->ScanWidth;
395 }
396 } /* not done */
397 mask &= ~BUFFER_BIT_BACK_LEFT;
398 } /* back buffer */
399
400 /* front buffer */
401 if (mask & BUFFER_BIT_FRONT_LEFT) {
402 HDC DC = pwc->hDC;
403 HPEN Old_Pen = SelectObject(DC, pwc->clearPen);
404 HBRUSH Old_Brush = SelectObject(DC, pwc->clearBrush);
405 Rectangle(DC,
406 x,
407 FLIP(y) + 1,
408 x + width + 1,
409 FLIP(y) - height + 1);
410 SelectObject(DC, Old_Pen);
411 SelectObject(DC, Old_Brush);
412 mask &= ~BUFFER_BIT_FRONT_LEFT;
413 } /* front buffer */
414
415 /* Call swrast if there is anything left to clear (like DEPTH) */
416 if (mask)
417 _swrast_Clear(ctx, mask);
418
419 #undef FLIP
420 }
421
422
423
424 /**********************************************************************/
425 /***** BUFFER Functions *****/
426 /**********************************************************************/
427
428
429
430
431 static void
432 wmesa_delete_renderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
433 {
434 _mesa_delete_renderbuffer(ctx, rb);
435 }
436
437
438 /**
439 * This is called by Mesa whenever it determines that the window size
440 * has changed. Do whatever's needed to cope with that.
441 */
442 static GLboolean
443 wmesa_renderbuffer_storage(struct gl_context *ctx,
444 struct gl_renderbuffer *rb,
445 GLenum internalFormat,
446 GLuint width,
447 GLuint height)
448 {
449 rb->Width = width;
450 rb->Height = height;
451 return GL_TRUE;
452 }
453
454
455 /**
456 * Called by ctx->Driver.ResizeBuffers()
457 * Resize the front/back colorbuffers to match the latest window size.
458 */
459 static void
460 wmesa_resize_buffers(struct gl_context *ctx, struct gl_framebuffer *buffer,
461 GLuint width, GLuint height)
462 {
463 WMesaFramebuffer pwfb = wmesa_framebuffer(buffer);
464
465 if (pwfb->Base.Width != width || pwfb->Base.Height != height) {
466 /* Realloc back buffer */
467 if (ctx->Visual.doubleBufferMode == 1) {
468 wmDeleteBackingStore(pwfb);
469 wmCreateBackingStore(pwfb, width, height);
470 }
471 }
472 _mesa_resize_framebuffer(ctx, buffer, width, height);
473 }
474
475
476 /**
477 * Called by glViewport.
478 * This is a good time for us to poll the current window size and adjust
479 * our renderbuffers to match the current window size.
480 * Remember, we have no opportunity to respond to conventional
481 * resize events since the driver has no event loop.
482 * Thus, we poll.
483 * MakeCurrent also ends up making a call here, so that ensures
484 * we get the viewport set correctly, even if the app does not call
485 * glViewport and relies on the defaults.
486 */
487 static void wmesa_viewport(struct gl_context *ctx)
488 {
489 GLuint new_width, new_height;
490
491 wmesa_get_buffer_size(ctx->WinSysDrawBuffer, &new_width, &new_height);
492
493 /**
494 * Resize buffers if the window size changed.
495 */
496 wmesa_resize_buffers(ctx, ctx->WinSysDrawBuffer, new_width, new_height);
497 ctx->NewState |= _NEW_BUFFERS; /* to update scissor / window bounds */
498 }
499
500
501
502
503 /**
504 * Called when the driver should update it's state, based on the new_state
505 * flags.
506 */
507 static void wmesa_update_state(struct gl_context *ctx, GLuint new_state)
508 {
509 _swrast_InvalidateState(ctx, new_state);
510 _swsetup_InvalidateState(ctx, new_state);
511 _vbo_InvalidateState(ctx, new_state);
512 _tnl_InvalidateState(ctx, new_state);
513
514 /* TODO - This code is not complete yet because I
515 * don't know what to do for all state updates.
516 */
517
518 if (new_state & _NEW_BUFFERS) {
519 }
520 }
521
522
523
524
525
526 /**********************************************************************/
527 /***** WMESA Functions *****/
528 /**********************************************************************/
529
530 WMesaContext WMesaCreateContext(HDC hDC,
531 HPALETTE* Pal,
532 GLboolean rgb_flag,
533 GLboolean db_flag,
534 GLboolean alpha_flag)
535 {
536 WMesaContext c;
537 struct dd_function_table functions;
538 GLint red_bits, green_bits, blue_bits, alpha_bits;
539 struct gl_context *ctx;
540 struct gl_config *visual;
541
542 (void) Pal;
543
544 /* Indexed mode not supported */
545 if (!rgb_flag)
546 return NULL;
547
548 /* Allocate wmesa context */
549 c = CALLOC_STRUCT(wmesa_context);
550 if (!c)
551 return NULL;
552
553 #if 0
554 /* I do not understand this contributed code */
555 /* Support memory and device contexts */
556 if(WindowFromDC(hDC) != NULL) {
557 c->hDC = GetDC(WindowFromDC(hDC)); /* huh ???? */
558 }
559 else {
560 c->hDC = hDC;
561 }
562 #else
563 c->hDC = hDC;
564 #endif
565
566 /* Get data for visual */
567 /* Dealing with this is actually a bit of overkill because Mesa will end
568 * up treating all color component size requests less than 8 by using
569 * a single byte per channel. In addition, the interface to the span
570 * routines passes colors as an entire byte per channel anyway, so there
571 * is nothing to be saved by telling the visual to be 16 bits if the device
572 * is 16 bits. That is, Mesa is going to compute colors down to 8 bits per
573 * channel anyway.
574 * But we go through the motions here anyway.
575 */
576 switch (GetDeviceCaps(c->hDC, BITSPIXEL)) {
577 case 16:
578 red_bits = green_bits = blue_bits = 5;
579 alpha_bits = 0;
580 break;
581 default:
582 red_bits = green_bits = blue_bits = 8;
583 alpha_bits = 8;
584 break;
585 }
586 /* Create visual based on flags */
587 visual = _mesa_create_visual(db_flag, /* db_flag */
588 GL_FALSE, /* stereo */
589 red_bits, green_bits, blue_bits, /* color RGB */
590 alpha_flag ? alpha_bits : 0, /* color A */
591 DEFAULT_SOFTWARE_DEPTH_BITS, /* depth_bits */
592 8, /* stencil_bits */
593 16,16,16, /* accum RGB */
594 alpha_flag ? 16 : 0, /* accum A */
595 1); /* num samples */
596
597 if (!visual) {
598 free(c);
599 return NULL;
600 }
601
602 /* Set up driver functions */
603 _mesa_init_driver_functions(&functions);
604 functions.GetString = wmesa_get_string;
605 functions.UpdateState = wmesa_update_state;
606 functions.Flush = wmesa_flush;
607 functions.Clear = clear;
608 functions.ResizeBuffers = wmesa_resize_buffers;
609 functions.Viewport = wmesa_viewport;
610
611 /* initialize the Mesa context data */
612 ctx = &c->gl_ctx;
613 _mesa_initialize_context(ctx, API_OPENGL_COMPAT, visual,
614 NULL, &functions);
615
616 /* visual no longer needed - it was copied by _mesa_initialize_context() */
617 _mesa_destroy_visual(visual);
618
619 _mesa_enable_sw_extensions(ctx);
620
621 _mesa_meta_init(ctx);
622
623 /* Initialize the software rasterizer and helper modules. */
624 if (!_swrast_CreateContext(ctx) ||
625 !_vbo_CreateContext(ctx) ||
626 !_tnl_CreateContext(ctx) ||
627 !_swsetup_CreateContext(ctx)) {
628 _mesa_free_context_data(ctx);
629 free(c);
630 return NULL;
631 }
632 _swsetup_Wakeup(ctx);
633 TNL_CONTEXT(ctx)->Driver.RunPipeline = _tnl_run_pipeline;
634
635 _mesa_compute_version(ctx);
636
637 /* Exec table initialization requires the version to be computed */
638 _mesa_initialize_dispatch_tables(ctx);
639 _mesa_initialize_vbo_vtxfmt(ctx);
640
641 return c;
642 }
643
644
645 void WMesaDestroyContext( WMesaContext pwc )
646 {
647 struct gl_context *ctx = &pwc->gl_ctx;
648 WMesaFramebuffer pwfb;
649 GET_CURRENT_CONTEXT(cur_ctx);
650
651 if (cur_ctx == ctx) {
652 /* unbind current if deleting current context */
653 WMesaMakeCurrent(NULL, NULL);
654 }
655
656 /* clean up frame buffer resources */
657 pwfb = wmesa_lookup_framebuffer(pwc->hDC);
658 if (pwfb) {
659 if (ctx->Visual.doubleBufferMode == 1)
660 wmDeleteBackingStore(pwfb);
661 wmesa_free_framebuffer(pwc->hDC);
662 }
663
664 /* Release for device, not memory contexts */
665 if (WindowFromDC(pwc->hDC) != NULL)
666 {
667 ReleaseDC(WindowFromDC(pwc->hDC), pwc->hDC);
668 }
669 DeleteObject(pwc->clearPen);
670 DeleteObject(pwc->clearBrush);
671
672 _mesa_meta_free(ctx);
673
674 _swsetup_DestroyContext(ctx);
675 _tnl_DestroyContext(ctx);
676 _vbo_DestroyContext(ctx);
677 _swrast_DestroyContext(ctx);
678
679 _mesa_free_context_data(ctx);
680 free(pwc);
681 }
682
683
684 /**
685 * Create a new color renderbuffer.
686 */
687 static struct gl_renderbuffer *
688 wmesa_new_renderbuffer(void)
689 {
690 struct gl_renderbuffer *rb = CALLOC_STRUCT(gl_renderbuffer);
691 if (!rb)
692 return NULL;
693
694 _mesa_init_renderbuffer(rb, (GLuint)0);
695
696 rb->_BaseFormat = GL_RGBA;
697 rb->InternalFormat = GL_RGBA;
698 rb->Delete = wmesa_delete_renderbuffer;
699 rb->AllocStorage = wmesa_renderbuffer_storage;
700 return rb;
701 }
702
703
704 void WMesaMakeCurrent(WMesaContext c, HDC hdc)
705 {
706 WMesaFramebuffer pwfb;
707
708 {
709 /* return if already current */
710 GET_CURRENT_CONTEXT(ctx);
711 WMesaContext pwc = wmesa_context(ctx);
712 if (pwc && c == pwc && pwc->hDC == hdc)
713 return;
714 }
715
716 pwfb = wmesa_lookup_framebuffer(hdc);
717
718 /* Lazy creation of framebuffers */
719 if (c && !pwfb && hdc) {
720 struct gl_renderbuffer *rb;
721 struct gl_config *visual = &c->gl_ctx.Visual;
722 GLuint width, height;
723
724 get_window_size(hdc, &width, &height);
725
726 c->clearPen = CreatePen(PS_SOLID, 1, 0);
727 c->clearBrush = CreateSolidBrush(0);
728
729 pwfb = wmesa_new_framebuffer(hdc, visual);
730
731 /* Create back buffer if double buffered */
732 if (visual->doubleBufferMode == 1) {
733 wmCreateBackingStore(pwfb, width, height);
734 }
735
736 /* make render buffers */
737 if (visual->doubleBufferMode == 1) {
738 rb = wmesa_new_renderbuffer();
739 _mesa_add_renderbuffer(&pwfb->Base, BUFFER_BACK_LEFT, rb);
740 }
741 rb = wmesa_new_renderbuffer();
742 _mesa_add_renderbuffer(&pwfb->Base, BUFFER_FRONT_LEFT, rb);
743
744 /* Let Mesa own the Depth, Stencil, and Accum buffers */
745 _swrast_add_soft_renderbuffers(&pwfb->Base,
746 GL_FALSE, /* color */
747 visual->depthBits > 0,
748 visual->stencilBits > 0,
749 visual->accumRedBits > 0,
750 visual->alphaBits >0,
751 GL_FALSE);
752 }
753
754 if (c && pwfb)
755 _mesa_make_current(&c->gl_ctx, &pwfb->Base, &pwfb->Base);
756 else
757 _mesa_make_current(NULL, NULL, NULL);
758 }
759
760
761 void WMesaSwapBuffers( HDC hdc )
762 {
763 GET_CURRENT_CONTEXT(ctx);
764 WMesaContext pwc = wmesa_context(ctx);
765 WMesaFramebuffer pwfb = wmesa_lookup_framebuffer(hdc);
766
767 if (!pwfb) {
768 _mesa_problem(NULL, "wmesa: swapbuffers on unknown hdc");
769 return;
770 }
771
772 /* If we're swapping the buffer associated with the current context
773 * we have to flush any pending rendering commands first.
774 */
775 if (pwc->hDC == hdc) {
776 _mesa_notifySwapBuffers(ctx);
777
778 BitBlt(pwfb->hDC, 0, 0, pwfb->Base.Width, pwfb->Base.Height,
779 pwfb->dib_hDC, 0, 0, SRCCOPY);
780 }
781 else {
782 /* XXX for now only allow swapping current window */
783 _mesa_problem(NULL, "wmesa: can't swap non-current window");
784 }
785 }
786
787 void WMesaShareLists(WMesaContext ctx_to_share, WMesaContext ctx)
788 {
789 _mesa_share_state(&ctx->gl_ctx, &ctx_to_share->gl_ctx);
790 }
791