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