[PROPSYS]
[reactos.git] / reactos / dll / opengl / opengl32 / swimpl.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS
4 * FILE: dll/opengl/opengl32/swimpl.c
5 * PURPOSE: OpenGL32 DLL, opengl software implementation
6 */
7
8 #include "opengl32.h"
9
10 /* MESA includes */
11 #include <main/context.h>
12 #include <main/framebuffer.h>
13 #include <main/renderbuffer.h>
14 #include <main/shared.h>
15 #include <main/viewport.h>
16 #include <swrast/s_context.h>
17 #include <swrast/s_renderbuffer.h>
18 #include <swrast_setup/swrast_setup.h>
19 #include <tnl/t_pipeline.h>
20 #include <tnl/tnl.h>
21 #include <drivers/common/driverfuncs.h>
22 #include <drivers/common/meta.h>
23
24 WINE_DEFAULT_DEBUG_CHANNEL(opengl32);
25
26 #define WIDTH_BYTES_ALIGN32(cx, bpp) ((((cx) * (bpp) + 31) & ~31) >> 3)
27
28 static const struct
29 {
30 gl_format mesa;
31 BYTE color_bits;
32 BYTE red_bits, red_shift; DWORD red_mask;
33 BYTE green_bits, green_shift; DWORD green_mask;
34 BYTE blue_bits, blue_shift; DWORD blue_mask;
35 BYTE alpha_bits, alpha_shift; DWORD alpha_mask;
36 BYTE accum_bits;
37 BYTE depth_bits;
38 BYTE stencil_bits;
39 DWORD bmp_compression;
40 } pixel_formats[] =
41 {
42 { MESA_FORMAT_ARGB8888, 32, 8, 8, 0x00FF0000, 8, 16, 0x0000FF00, 8, 24, 0x000000FF, 8, 0, 0xFF000000, 16, 32, 8, BI_BITFIELDS },
43 { MESA_FORMAT_ARGB8888, 32, 8, 8, 0x00FF0000, 8, 16, 0x0000FF00, 8, 24, 0x000000FF, 8, 0, 0xFF000000, 16, 16, 8, BI_BITFIELDS },
44 { MESA_FORMAT_RGBA8888_REV, 32, 8, 8, 0x000000FF, 8, 16, 0x0000FF00, 8, 24, 0x00FF0000, 8, 0, 0xFF000000, 16, 32, 8, BI_BITFIELDS },
45 { MESA_FORMAT_RGBA8888_REV, 32, 8, 8, 0x000000FF, 8, 16, 0x0000FF00, 8, 24, 0x00FF0000, 8, 0, 0xFF000000, 16, 16, 8, BI_BITFIELDS },
46 { MESA_FORMAT_RGBA8888, 32, 8, 0, 0xFF000000, 8, 8, 0x00FF0000, 8, 16, 0x0000FF00, 8, 24, 0x000000FF, 16, 32, 8, BI_BITFIELDS },
47 { MESA_FORMAT_RGBA8888, 32, 8, 0, 0xFF000000, 8, 8, 0x00FF0000, 8, 16, 0x0000FF00, 8, 24, 0x000000FF, 16, 16, 8, BI_BITFIELDS },
48 { MESA_FORMAT_ARGB8888_REV, 32, 8, 16, 0x0000FF00, 8, 8, 0x00FF0000, 8, 0, 0xFF000000, 8, 24, 0x000000FF, 16, 32, 8, BI_BITFIELDS },
49 { MESA_FORMAT_ARGB8888_REV, 32, 8, 16, 0x0000FF00, 8, 8, 0x00FF0000, 8, 0, 0xFF000000, 8, 24, 0x000000FF, 16, 16, 8, BI_BITFIELDS },
50 { MESA_FORMAT_RGB888, 24, 8, 0, 0x00000000, 8, 8, 0x00000000, 8, 16, 0x00000000, 0, 0, 0x00000000, 16, 32, 8, BI_RGB },
51 { MESA_FORMAT_RGB888, 24, 8, 0, 0x00000000, 8, 8, 0x00000000, 8, 16, 0x00000000, 0, 0, 0x00000000, 16, 16, 8, BI_RGB },
52 // { MESA_FORMAT_BGR888, 24, 8, 16, 8, 8, 8, 0, 0, 0, 16, 32, 8 },
53 // { MESA_FORMAT_BGR888, 24, 8, 16, 8, 8, 8, 0, 0, 0, 16, 16, 8 },
54 { MESA_FORMAT_RGB565, 16, 5, 0, 0x00000000, 6, 5, 0x00000000, 5, 11, 0x00000000, 0, 0, 0x00000000, 16, 32, 8, BI_BITFIELDS },
55 { MESA_FORMAT_RGB565, 16, 5, 0, 0x0000F800, 6, 5, 0x000007E0, 5, 11, 0x0000001F, 0, 0, 0x00000000, 16, 16, 8, BI_BITFIELDS },
56 };
57
58 #define SW_BACK_RENDERBUFFER_CLASS 0x8911
59 #define SW_FRONT_RENDERBUFFER_CLASS 0x8910
60 struct sw_front_renderbuffer
61 {
62 struct swrast_renderbuffer swrast;
63
64 HDC hdcmem;
65 GLuint x, y, w, h;
66 HBITMAP hbmp;
67 BOOL write;
68 };
69
70 #define SW_FB_DOUBLEBUFFERED 0x1
71 #define SW_FB_DIRTY_SIZE 0x2
72 struct sw_framebuffer
73 {
74 HDC hdc;
75 INT sw_format;
76 UINT format_index;
77 DWORD flags;
78 /* The mesa objects */
79 struct gl_config *gl_visual; /* Describes the buffers */
80 struct gl_framebuffer *gl_buffer; /* The mesa representation of frame buffer */
81 struct sw_front_renderbuffer frontbuffer;
82 struct swrast_renderbuffer backbuffer;
83 /* The bitmapi info we will use for rendering to display */
84 BITMAPINFO bmi;
85 };
86
87 struct sw_context
88 {
89 struct gl_context mesa; /* Base class - this must be first */
90 /* This is to keep track of the size of the front buffer */
91 HHOOK hook;
92 /* Framebuffer currently owning the context */
93 struct sw_framebuffer framebuffer;
94 };
95
96 /* mesa opengl32 "driver" specific */
97 static const GLubyte *
98 sw_get_string( struct gl_context *ctx, GLenum name )
99 {
100 (void) ctx;
101 if(name == GL_RENDERER)
102 {
103 static const GLubyte renderer[] = { 'R','e','a','c','t','O','S',' ',
104 'S','o','f','t','w','a','r','e',' ',
105 'I','m','p','l','e','m','e','n','t','a','t','i','o','n',0 };
106 return renderer;
107 }
108 /* Don't claim to support the fancy extensions that mesa supports, they will be slow anyway */
109 if(name == GL_EXTENSIONS)
110 {
111 static const GLubyte extensions[] = { 0 };
112 return extensions;
113 }
114 return NULL;
115 }
116
117 static void
118 sw_update_state( struct gl_context *ctx, GLuint new_state )
119 {
120 /* easy - just propogate */
121 _swrast_InvalidateState( ctx, new_state );
122 _swsetup_InvalidateState( ctx, new_state );
123 _tnl_InvalidateState( ctx, new_state );
124 _vbo_InvalidateState( ctx, new_state );
125 }
126
127 /* Renderbuffer routines */
128 static GLboolean
129 sw_bb_renderbuffer_storage(struct gl_context* ctx, struct gl_renderbuffer *rb,
130 GLenum internalFormat,
131 GLuint width, GLuint height)
132 {
133 struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
134 struct sw_framebuffer* fb = CONTAINING_RECORD(srb, struct sw_framebuffer, backbuffer);
135 UINT widthBytes = WIDTH_BYTES_ALIGN32(width, pixel_formats[fb->format_index].color_bits);
136 srb->Base.Format = pixel_formats[fb->format_index].mesa;
137
138 if(srb->Buffer)
139 srb->Buffer = HeapReAlloc(GetProcessHeap(), 0, srb->Buffer, widthBytes*height);
140 else
141 srb->Buffer = HeapAlloc(GetProcessHeap(), 0, widthBytes*height);
142 if(!srb->Buffer)
143 {
144 srb->Base.Format = MESA_FORMAT_NONE;
145 return GL_FALSE;
146 }
147 srb->Base.Width = width;
148 srb->Base.Height = height;
149 srb->RowStride = widthBytes;
150 return GL_TRUE;
151 }
152
153 static void
154 sw_bb_renderbuffer_delete(struct gl_renderbuffer *rb)
155 {
156 struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
157
158 if (srb->Buffer)
159 {
160 HeapFree(GetProcessHeap(), 0, srb->Buffer);
161 srb->Buffer = NULL;
162 }
163 }
164
165 static void
166 sw_fb_renderbuffer_delete(struct gl_renderbuffer *rb)
167 {
168 struct sw_front_renderbuffer* srb = (struct sw_front_renderbuffer*)rb;
169
170 if (srb->hbmp)
171 {
172 srb->hbmp = SelectObject(srb->hdcmem, srb->hbmp);
173 DeleteDC(srb->hdcmem);
174 DeleteObject(srb->hbmp);
175 srb->hdcmem = NULL;
176 srb->hbmp = NULL;
177 srb->swrast.Buffer = NULL;
178 }
179 }
180
181 static GLboolean
182 sw_fb_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
183 GLenum internalFormat,
184 GLuint width, GLuint height)
185 {
186 struct sw_front_renderbuffer* srb = (struct sw_front_renderbuffer*)rb;
187 struct sw_framebuffer* fb = CONTAINING_RECORD(srb, struct sw_framebuffer, frontbuffer);
188 HDC hdc = IntGetCurrentDC();
189
190 /* Don't bother if the size doesn't change */
191 if(rb->Width == width && rb->Height == height)
192 return GL_TRUE;
193
194 /* Delete every objects which could have been used before */
195 sw_fb_renderbuffer_delete(&srb->swrast.Base);
196
197 /* So the app wants to use the frontbuffer, allocate a DIB for it */
198 srb->hbmp = CreateDIBSection(
199 hdc,
200 &fb->bmi,
201 DIB_RGB_COLORS,
202 (void**)&srb->swrast.Buffer,
203 NULL, 0);
204 if(!srb->hbmp)
205 {
206 ERR("Failed to create the DIB section for the front buffer, %lu.\n", GetLastError());
207 return GL_FALSE;
208 }
209 /* Create the DC and attach the DIB section to it */
210 srb->hdcmem = CreateCompatibleDC(hdc);
211 assert(srb->hdcmem != NULL);
212 srb->hbmp = SelectObject(srb->hdcmem, srb->hbmp);
213 assert(srb->hbmp != NULL);
214 /* Set formats, width and height */
215 srb->swrast.Base.Format = pixel_formats[fb->format_index].mesa;
216 srb->swrast.Base.Width = width;
217 srb->swrast.Base.Height = height;
218 return GL_TRUE;
219 }
220
221 static
222 void
223 sw_init_renderbuffers(struct sw_framebuffer *fb)
224 {
225 _mesa_init_renderbuffer(&fb->frontbuffer.swrast.Base, 0);
226 fb->frontbuffer.swrast.Base.ClassID = SW_FRONT_RENDERBUFFER_CLASS;
227 fb->frontbuffer.swrast.Base.AllocStorage = sw_fb_renderbuffer_storage;
228 fb->frontbuffer.swrast.Base.Delete = sw_fb_renderbuffer_delete;
229 fb->frontbuffer.swrast.Base.InternalFormat = GL_RGBA;
230 fb->frontbuffer.swrast.Base._BaseFormat = GL_RGBA;
231 _mesa_remove_renderbuffer(fb->gl_buffer, BUFFER_FRONT_LEFT);
232 _mesa_add_renderbuffer(fb->gl_buffer, BUFFER_FRONT_LEFT, &fb->frontbuffer.swrast.Base);
233
234 if(fb->flags & SW_FB_DOUBLEBUFFERED)
235 {
236 _mesa_init_renderbuffer(&fb->backbuffer.Base, 0);
237 fb->backbuffer.Base.ClassID = SW_BACK_RENDERBUFFER_CLASS;
238 fb->backbuffer.Base.AllocStorage = sw_bb_renderbuffer_storage;
239 fb->backbuffer.Base.Delete = sw_bb_renderbuffer_delete;
240 fb->backbuffer.Base.InternalFormat = GL_RGBA;
241 fb->backbuffer.Base._BaseFormat = GL_RGBA;
242 _mesa_remove_renderbuffer(fb->gl_buffer, BUFFER_BACK_LEFT);
243 _mesa_add_renderbuffer(fb->gl_buffer, BUFFER_BACK_LEFT, &fb->backbuffer.Base);
244 }
245
246
247 }
248
249 static void
250 sw_MapRenderbuffer(struct gl_context *ctx,
251 struct gl_renderbuffer *rb,
252 GLuint x, GLuint y, GLuint w, GLuint h,
253 GLbitfield mode,
254 GLubyte **mapOut, GLint *rowStrideOut)
255 {
256 if(rb->ClassID == SW_FRONT_RENDERBUFFER_CLASS)
257 {
258 /* This is our front buffer */
259 struct sw_front_renderbuffer* srb = (struct sw_front_renderbuffer*)rb;
260 struct sw_framebuffer* fb = CONTAINING_RECORD(srb, struct sw_framebuffer, frontbuffer);
261 /* Set the stride */
262 *rowStrideOut = WIDTH_BYTES_ALIGN32(rb->Width, pixel_formats[fb->format_index].color_bits);
263 /* Remember where we "mapped" */
264 srb->x = x; srb->y = y; srb->w = w; srb->h = h;
265 /* Remember if we should write it later */
266 srb->write = !!(mode & GL_MAP_WRITE_BIT);
267 /* Get the bits, if needed */
268 if(mode & GL_MAP_READ_BIT)
269 {
270 BitBlt(srb->hdcmem, srb->x, srb->y, srb->w, srb->h,
271 IntGetCurrentDC(), srb->x, srb->y, SRCCOPY);
272 }
273 /* And return it */
274 *mapOut = (BYTE*)srb->swrast.Buffer + *rowStrideOut*y + x*pixel_formats[fb->format_index].color_bits/8;
275 return;
276 }
277
278 if(rb->ClassID == SW_BACK_RENDERBUFFER_CLASS)
279 {
280 /* This is our front buffer */
281 struct swrast_renderbuffer* srb = (struct swrast_renderbuffer*)rb;
282 const GLuint bpp = _mesa_get_format_bytes(rb->Format);
283 /* Set the stride */
284 *rowStrideOut = srb->RowStride;
285 *mapOut = (BYTE*)srb->Buffer + srb->RowStride*y + x*bpp;
286 return;
287 }
288
289 /* Let mesa rasterizer take care of this */
290 _swrast_map_soft_renderbuffer(ctx, rb, x, y, w, h, mode,
291 mapOut, rowStrideOut);
292 }
293
294 static void
295 sw_UnmapRenderbuffer(struct gl_context *ctx, struct gl_renderbuffer *rb)
296 {
297 if (rb->ClassID== SW_FRONT_RENDERBUFFER_CLASS)
298 {
299 /* This is our front buffer */
300 struct sw_front_renderbuffer* srb = (struct sw_front_renderbuffer*)rb;
301 if(srb->write)
302 {
303 /* Copy the bits to our display */
304 BitBlt(IntGetCurrentDC(),
305 srb->x, srb->y, srb->w, srb->h,
306 srb->hdcmem, srb->x, srb->y, SRCCOPY);
307 srb->write = FALSE;
308 }
309 return;
310 }
311
312 if(rb->ClassID == SW_BACK_RENDERBUFFER_CLASS)
313 return; /* nothing to do */
314
315 /* Let mesa rasterizer take care of this */
316 _swrast_unmap_soft_renderbuffer(ctx, rb);
317 }
318
319 /* WGL <-> mesa glue */
320 static UINT index_from_format(struct wgl_dc_data* dc_data, INT format, BOOL* doubleBuffered)
321 {
322 UINT index;
323 INT nb_win_compat = 0, start_win_compat = 0;
324 HDC hdc;
325 INT bpp;
326
327 *doubleBuffered = FALSE;
328
329 if(!(dc_data->flags & WGL_DC_OBJ_DC))
330 return format - 1; /* OBJ_MEMDC, not double buffered */
331
332 hdc = GetDC(dc_data->owner.hwnd);
333
334 /* Find the window compatible formats */
335 bpp = GetDeviceCaps(hdc, BITSPIXEL);
336 for(index = 0; index<sizeof(pixel_formats)/sizeof(pixel_formats[0]); index++)
337 {
338 if(pixel_formats[index].color_bits == bpp)
339 {
340 if(!start_win_compat)
341 start_win_compat = index+1;
342 nb_win_compat++;
343 }
344 }
345 ReleaseDC(dc_data->owner.hwnd, hdc);
346
347 /* Double buffered format */
348 if(format < (start_win_compat + nb_win_compat))
349 {
350 if(format >= start_win_compat)
351 *doubleBuffered = TRUE;
352 return format-1;
353 }
354 /* Shift */
355 return format - nb_win_compat - 1;
356 }
357
358 INT sw_DescribePixelFormat(HDC hdc, INT format, UINT size, PIXELFORMATDESCRIPTOR* descr)
359 {
360 UINT index;
361 INT nb_win_compat = 0, start_win_compat = 0;
362 INT ret = sizeof(pixel_formats)/sizeof(pixel_formats[0]);
363
364 if(GetObjectType(hdc) == OBJ_DC)
365 {
366 /* Find the window compatible formats */
367 INT bpp = GetDeviceCaps(hdc, BITSPIXEL);
368 for(index = 0; index<sizeof(pixel_formats)/sizeof(pixel_formats[0]); index++)
369 {
370 if(pixel_formats[index].color_bits == bpp)
371 {
372 if(!start_win_compat)
373 start_win_compat = index+1;
374 nb_win_compat++;
375 }
376 }
377 /* Add the double buffered formats */
378 ret += nb_win_compat;
379 }
380
381 index = (UINT)format - 1;
382 if(!descr)
383 return ret;
384 if((format > ret) || (size != sizeof(*descr)))
385 return 0;
386
387 /* Set flags */
388 descr->dwFlags = PFD_SUPPORT_GDI | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_BITMAP | PFD_GENERIC_FORMAT;
389 /* See if this is a format compatible with the window */
390 if(format >= start_win_compat && format < (start_win_compat + nb_win_compat*2) )
391 {
392 /* It is */
393 descr->dwFlags |= PFD_DRAW_TO_WINDOW;
394 /* See if this should be double buffered */
395 if(format < (start_win_compat + nb_win_compat))
396 {
397 /* No GDI, no bitmap */
398 descr->dwFlags &= ~(PFD_SUPPORT_GDI | PFD_DRAW_TO_BITMAP);
399 descr->dwFlags |= PFD_DOUBLEBUFFER;
400 }
401 }
402 /* Normalize the index */
403 if(format >= start_win_compat + nb_win_compat)
404 index -= nb_win_compat;
405
406 /* Fill the rest of the structure */
407 descr->nSize = sizeof(*descr);
408 descr->nVersion = 1;
409 descr->iPixelType = PFD_TYPE_RGBA;
410 descr->cColorBits = pixel_formats[index].color_bits;
411 descr->cRedBits = pixel_formats[index].red_bits;
412 descr->cRedShift = pixel_formats[index].red_shift;
413 descr->cGreenBits = pixel_formats[index].green_bits;
414 descr->cGreenShift = pixel_formats[index].green_shift;
415 descr->cBlueBits = pixel_formats[index].blue_bits;
416 descr->cBlueShift = pixel_formats[index].blue_shift;
417 descr->cAlphaBits = pixel_formats[index].alpha_bits;
418 descr->cAlphaShift = pixel_formats[index].alpha_shift;
419 descr->cAccumBits = pixel_formats[index].accum_bits;
420 descr->cAccumRedBits = pixel_formats[index].accum_bits / 4;
421 descr->cAccumGreenBits = pixel_formats[index].accum_bits / 4;
422 descr->cAccumBlueBits = pixel_formats[index].accum_bits / 4;
423 descr->cAccumAlphaBits = pixel_formats[index].accum_bits / 4;
424 descr->cDepthBits = pixel_formats[index].depth_bits;
425 descr->cStencilBits = pixel_formats[index].stencil_bits;
426 descr->cAuxBuffers = 0;
427 descr->iLayerType = PFD_MAIN_PLANE;
428 return ret;
429 }
430
431 BOOL sw_SetPixelFormat(HDC hdc, struct wgl_dc_data* dc_data, INT format)
432 {
433 struct sw_framebuffer* fb;
434 BOOL doubleBuffered;
435
436 assert(dc_data->sw_data == NULL);
437
438 /* So, someone is crazy enough to ask for sw implementation. Announce it. */
439 TRACE("OpenGL software implementation START!\n");
440
441 /* allocate our structure */
442 fb = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, FIELD_OFFSET(struct sw_framebuffer, bmi.bmiColors[2]));
443 if(!fb)
444 return FALSE;
445 /* Get the format index */
446 fb->format_index = index_from_format(dc_data, format, &doubleBuffered);
447 fb->flags = doubleBuffered ? SW_FB_DOUBLEBUFFERED : 0;
448 /* Set the bitmap info describing the framebuffer */
449 fb->bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
450 fb->bmi.bmiHeader.biPlanes = 1;
451 fb->bmi.bmiHeader.biBitCount = pixel_formats[fb->format_index].color_bits;
452 fb->bmi.bmiHeader.biCompression = pixel_formats[fb->format_index].bmp_compression;
453 fb->bmi.bmiHeader.biSizeImage = 0;
454 fb->bmi.bmiHeader.biXPelsPerMeter = 0;
455 fb->bmi.bmiHeader.biYPelsPerMeter = 0;
456 fb->bmi.bmiHeader.biClrUsed = 0;
457 fb->bmi.bmiHeader.biClrImportant = 0;
458 *((DWORD*)&fb->bmi.bmiColors[0]) = pixel_formats[fb->format_index].red_mask;
459 *((DWORD*)&fb->bmi.bmiColors[1]) = pixel_formats[fb->format_index].green_mask;
460 *((DWORD*)&fb->bmi.bmiColors[2]) = pixel_formats[fb->format_index].blue_mask;
461 /* Save the HDC */
462 fb->hdc = hdc;
463
464 /* Allocate the visual structure describing the format */
465 fb->gl_visual = _mesa_create_visual(
466 !!(fb->flags & SW_FB_DOUBLEBUFFERED),
467 GL_FALSE, /* No stereoscopic support */
468 pixel_formats[fb->format_index].red_bits,
469 pixel_formats[fb->format_index].green_bits,
470 pixel_formats[fb->format_index].blue_bits,
471 pixel_formats[fb->format_index].alpha_bits,
472 pixel_formats[fb->format_index].depth_bits,
473 pixel_formats[fb->format_index].stencil_bits,
474 pixel_formats[fb->format_index].accum_bits,
475 pixel_formats[fb->format_index].accum_bits,
476 pixel_formats[fb->format_index].accum_bits,
477 pixel_formats[fb->format_index].alpha_bits ?
478 pixel_formats[fb->format_index].accum_bits : 0);
479
480 if(!fb->gl_visual)
481 {
482 ERR("Failed to allocate a GL visual.\n");
483 HeapFree(GetProcessHeap(), 0, fb);
484 return FALSE;
485 }
486
487 /* Allocate the framebuffer structure */
488 fb->gl_buffer = _mesa_create_framebuffer(fb->gl_visual);
489 if (!fb->gl_buffer) {
490 ERR("Failed to allocate the mesa framebuffer structure.\n");
491 _mesa_destroy_visual( fb->gl_visual );
492 HeapFree(GetProcessHeap(), 0, fb);
493 return FALSE;
494 }
495
496 /* Add the depth/stencil/accum buffers */
497 _swrast_add_soft_renderbuffers(fb->gl_buffer,
498 GL_FALSE, /* color */
499 fb->gl_visual->haveDepthBuffer,
500 fb->gl_visual->haveStencilBuffer,
501 fb->gl_visual->haveAccumBuffer,
502 GL_FALSE, /* alpha */
503 GL_FALSE /* aux */ );
504
505 /* Initialize our render buffers */
506 sw_init_renderbuffers(fb);
507
508 /* Everything went fine */
509 dc_data->sw_data = fb;
510 return TRUE;
511 }
512
513 DHGLRC sw_CreateContext(struct wgl_dc_data* dc_data)
514 {
515 struct sw_context* sw_ctx;
516 struct sw_framebuffer* fb = dc_data->sw_data;
517 struct dd_function_table mesa_drv_functions;
518 TNLcontext *tnl;
519
520 /* We use the mesa memory routines for this function */
521 sw_ctx = CALLOC_STRUCT(sw_context);
522 if(!sw_ctx)
523 return NULL;
524
525 /* Set mesa default functions */
526 _mesa_init_driver_functions(&mesa_drv_functions);
527 /* Override */
528 mesa_drv_functions.GetString = sw_get_string;
529 mesa_drv_functions.UpdateState = sw_update_state;
530 mesa_drv_functions.GetBufferSize = NULL;
531
532 /* Initialize the context */
533 if(!_mesa_initialize_context(&sw_ctx->mesa,
534 fb->gl_visual,
535 NULL,
536 &mesa_drv_functions,
537 (void *) sw_ctx))
538 {
539 ERR("Failed to initialize the mesa context.\n");
540 free(sw_ctx);
541 return NULL;
542 }
543
544 /* Initialize the "meta driver" */
545 _mesa_meta_init(&sw_ctx->mesa);
546
547 /* Initialize helpers */
548 if(!_swrast_CreateContext(&sw_ctx->mesa) ||
549 !_vbo_CreateContext(&sw_ctx->mesa) ||
550 !_tnl_CreateContext(&sw_ctx->mesa) ||
551 !_swsetup_CreateContext(&sw_ctx->mesa))
552 {
553 ERR("Failed initializing helpers.\n");
554 _mesa_free_context_data(&sw_ctx->mesa);
555 free(sw_ctx);
556 return NULL;
557 }
558
559 /* Wake up! */
560 _swsetup_Wakeup(&sw_ctx->mesa);
561
562 /* Use TnL defaults */
563 tnl = TNL_CONTEXT(&sw_ctx->mesa);
564 tnl->Driver.RunPipeline = _tnl_run_pipeline;
565
566 /* To map the display into user memory */
567 sw_ctx->mesa.Driver.MapRenderbuffer = sw_MapRenderbuffer;
568 sw_ctx->mesa.Driver.UnmapRenderbuffer = sw_UnmapRenderbuffer;
569
570 return (DHGLRC)sw_ctx;
571 }
572
573 BOOL sw_DeleteContext(DHGLRC dhglrc)
574 {
575 struct sw_context* sw_ctx = (struct sw_context*)dhglrc;
576 /* Those get clobbered by _mesa_free_context_data via _glapi_set{context,dispath_table} */
577 void* icd_save = IntGetCurrentICDPrivate();
578 const GLDISPATCHTABLE* table_save = IntGetCurrentDispatchTable();
579
580 /* Destroy everything */
581 _mesa_meta_free( &sw_ctx->mesa );
582
583 _swsetup_DestroyContext( &sw_ctx->mesa );
584 _tnl_DestroyContext( &sw_ctx->mesa );
585 _vbo_DestroyContext( &sw_ctx->mesa );
586 _swrast_DestroyContext( &sw_ctx->mesa );
587
588 _mesa_free_context_data( &sw_ctx->mesa );
589 free( sw_ctx );
590
591 /* Restore this */
592 IntSetCurrentDispatchTable(table_save);
593 IntSetCurrentICDPrivate(icd_save);
594
595 return TRUE;
596 }
597
598 PROC sw_GetProcAddress(LPCSTR name)
599 {
600 /* We don't support any extensions */
601 WARN("Asking for proc address %s, returning NULL.\n", name);
602 return NULL;
603 }
604
605 BOOL sw_CopyContext(DHGLRC dhglrcSrc, DHGLRC dhglrcDst, UINT mask)
606 {
607 FIXME("Software wglCopyContext is UNIMPLEMENTED, mask %lx.\n", mask);
608 return FALSE;
609 }
610
611 BOOL sw_ShareLists(DHGLRC dhglrcSrc, DHGLRC dhglrcDst)
612 {
613 struct sw_context* sw_ctx_src = (struct sw_context*)dhglrcSrc;
614 struct sw_context* sw_ctx_dst = (struct sw_context*)dhglrcDst;
615
616 /* See if it was already shared */
617 if(sw_ctx_dst->mesa.Shared->RefCount > 1)
618 return FALSE;
619
620 /* Unreference the old, share the new */
621 _mesa_reference_shared_state(&sw_ctx_dst->mesa,
622 &sw_ctx_dst->mesa.Shared,
623 sw_ctx_src->mesa.Shared);
624
625 return TRUE;
626 }
627
628 static
629 LRESULT CALLBACK
630 sw_call_window_proc(
631 int nCode,
632 WPARAM wParam,
633 LPARAM lParam )
634 {
635 struct wgl_dc_data* dc_data = IntGetCurrentDcData();
636 struct sw_context* ctx = (struct sw_context*)IntGetCurrentDHGLRC();
637 struct sw_framebuffer* fb;
638 PCWPSTRUCT pParams = (PCWPSTRUCT)lParam;
639
640 if((!dc_data) || (!ctx))
641 return 0;
642
643 if(!(dc_data->flags & WGL_DC_OBJ_DC))
644 return 0;
645
646 if((nCode < 0) || (dc_data->owner.hwnd != pParams->hwnd) || (dc_data->sw_data == NULL))
647 return CallNextHookEx(ctx->hook, nCode, wParam, lParam);
648
649 fb = dc_data->sw_data;
650
651 if (pParams->message == WM_WINDOWPOSCHANGED)
652 {
653 /* We handle WM_WINDOWPOSCHANGED instead of WM_SIZE because according to
654 * http://blogs.msdn.com/oldnewthing/archive/2008/01/15/7113860.aspx
655 * WM_SIZE is generated from WM_WINDOWPOSCHANGED by DefWindowProc so it
656 * can be masked out by the application. */
657 LPWINDOWPOS lpWindowPos = (LPWINDOWPOS)pParams->lParam;
658 if((lpWindowPos->flags & SWP_SHOWWINDOW) ||
659 !(lpWindowPos->flags & SWP_NOMOVE) ||
660 !(lpWindowPos->flags & SWP_NOSIZE))
661 {
662 /* Size in WINDOWPOS includes the window frame, so get the size
663 * of the client area via GetClientRect. */
664 RECT client_rect;
665 UINT width, height;
666 GetClientRect(pParams->hwnd, &client_rect);
667 width = client_rect.right - client_rect.left;
668 height = client_rect.bottom - client_rect.top;
669 /* Do not reallocate for minimized windows */
670 if(width <= 0 || height <= 0)
671 goto end;
672 /* Update framebuffer size */
673 fb->bmi.bmiHeader.biWidth = width;
674 fb->bmi.bmiHeader.biHeight = height;
675 /* Propagate to mesa */
676 _mesa_resize_framebuffer(&ctx->mesa, fb->gl_buffer, width, height);
677 }
678 }
679
680 end:
681 return CallNextHookEx(ctx->hook, nCode, wParam, lParam);
682 }
683
684 BOOL sw_SetContext(struct wgl_dc_data* dc_data, DHGLRC dhglrc)
685 {
686 struct sw_context* sw_ctx = (struct sw_context*)dhglrc;
687 struct sw_framebuffer* fb = dc_data->sw_data;
688 UINT width, height;
689
690 /* Update state */
691 sw_update_state(&sw_ctx->mesa, 0);
692
693 /* Get framebuffer size */
694 if(dc_data->flags & WGL_DC_OBJ_DC)
695 {
696 HWND hwnd = dc_data->owner.hwnd;
697 RECT client_rect;
698 if(!hwnd)
699 {
700 ERR("Physical DC without a window!\n");
701 return FALSE;
702 }
703 if(!GetClientRect(hwnd, &client_rect))
704 {
705 ERR("GetClientRect failed!\n");
706 return FALSE;
707 }
708 /* This is a physical DC. Setup the hook */
709 sw_ctx->hook = SetWindowsHookEx(WH_CALLWNDPROC,
710 sw_call_window_proc,
711 NULL,
712 GetCurrentThreadId());
713 /* Calculate width & height */
714 width = client_rect.right - client_rect.left;
715 height = client_rect.bottom - client_rect.top;
716 }
717 else /* OBJ_MEMDC */
718 {
719 BITMAP bm;
720 HBITMAP hbmp;
721 HDC hdc = dc_data->owner.hdc;
722
723 if(fb->flags & SW_FB_DOUBLEBUFFERED)
724 {
725 ERR("Memory DC called with a double buffered format.\n");
726 return FALSE;
727 }
728
729 hbmp = GetCurrentObject( hdc, OBJ_BITMAP );
730 if(!hbmp)
731 {
732 ERR("No Bitmap!\n");
733 return FALSE;
734 }
735 if(GetObject(hbmp, sizeof(bm), &bm) == 0)
736 {
737 ERR("GetObject failed!\n");
738 return FALSE;
739 }
740 width = bm.bmWidth;
741 height = bm.bmHeight;
742 }
743
744 if(!width) width = 1;
745 if(!height) height = 1;
746
747 fb->bmi.bmiHeader.biWidth = width;
748 fb->bmi.bmiHeader.biHeight = height;
749
750 /* Also make the mesa context current to mesa */
751 if(!_mesa_make_current(&sw_ctx->mesa, fb->gl_buffer, fb->gl_buffer))
752 {
753 ERR("_mesa_make_current filaed!\n");
754 return FALSE;
755 }
756
757 /* Set the viewport if this is the first time we initialize this context */
758 if(sw_ctx->mesa.Viewport.X == 0 &&
759 sw_ctx->mesa.Viewport.Y == 0 &&
760 sw_ctx->mesa.Viewport.Width == 0 &&
761 sw_ctx->mesa.Viewport.Height == 0)
762 {
763 _mesa_set_viewport(&sw_ctx->mesa, 0, 0, width, height);
764 }
765
766 /* update the framebuffer size */
767 _mesa_resize_framebuffer(&sw_ctx->mesa, fb->gl_buffer, width, height);
768
769 /* We're good */
770 return TRUE;
771 }
772
773 void sw_ReleaseContext(DHGLRC dhglrc)
774 {
775 struct sw_context* sw_ctx = (struct sw_context*)dhglrc;
776
777 /* Forward to mesa */
778 _mesa_make_current(NULL, NULL, NULL);
779
780 /* Unhook */
781 if(sw_ctx->hook)
782 {
783 UnhookWindowsHookEx(sw_ctx->hook);
784 sw_ctx->hook = NULL;
785 }
786 }
787
788 BOOL sw_SwapBuffers(HDC hdc, struct wgl_dc_data* dc_data)
789 {
790 struct sw_framebuffer* fb = dc_data->sw_data;
791 struct sw_context* sw_ctx = (struct sw_context*)IntGetCurrentDHGLRC();
792
793 /* Notify mesa */
794 if(sw_ctx)
795 _mesa_notifySwapBuffers(&sw_ctx->mesa);
796
797 if(!(fb->flags & SW_FB_DOUBLEBUFFERED))
798 return TRUE;
799
800 /* Upload to the display */
801 return (SetDIBitsToDevice(hdc,
802 0,
803 0,
804 fb->bmi.bmiHeader.biWidth,
805 fb->bmi.bmiHeader.biHeight,
806 0,
807 0,
808 0,
809 fb->bmi.bmiHeader.biHeight,
810 fb->backbuffer.Buffer,
811 &fb->bmi,
812 DIB_RGB_COLORS) != 0);
813 }