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