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