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