Merge branch 'mesa_7_6_branch' into mesa_7_7_branch
[mesa.git] / src / mesa / drivers / dri / swrast / swrast.c
1 /*
2 * Copyright (C) 2008 George Sapountzis <gsap7@yahoo.gr>
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included
12 * in all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 */
21
22 /*
23 * DRI software rasterizer
24 *
25 * This is the mesa swrast module packaged into a DRI driver structure.
26 *
27 * The front-buffer is allocated by the loader. The loader provides read/write
28 * callbacks for access to the front-buffer. The driver uses a scratch row for
29 * front-buffer rendering to avoid repeated calls to the loader.
30 *
31 * The back-buffer is allocated by the driver and is private.
32 */
33
34 #include "main/context.h"
35 #include "main/extensions.h"
36 #include "main/formats.h"
37 #include "main/framebuffer.h"
38 #include "main/imports.h"
39 #include "main/renderbuffer.h"
40 #include "swrast/swrast.h"
41 #include "swrast_setup/swrast_setup.h"
42 #include "tnl/tnl.h"
43 #include "tnl/t_context.h"
44 #include "tnl/t_pipeline.h"
45 #include "vbo/vbo.h"
46 #include "drivers/common/driverfuncs.h"
47 #include "drivers/common/meta.h"
48 #include "utils.h"
49
50 #include "swrast_priv.h"
51
52
53 /**
54 * Screen and config-related functions
55 */
56
57 static void
58 setupLoaderExtensions(__DRIscreen *psp,
59 const __DRIextension **extensions)
60 {
61 int i;
62
63 for (i = 0; extensions[i]; i++) {
64 if (strcmp(extensions[i]->name, __DRI_SWRAST_LOADER) == 0)
65 psp->swrast_loader = (__DRIswrastLoaderExtension *) extensions[i];
66 }
67 }
68
69 static __DRIconfig **
70 swrastFillInModes(__DRIscreen *psp,
71 unsigned pixel_bits, unsigned depth_bits,
72 unsigned stencil_bits, GLboolean have_back_buffer)
73 {
74 __DRIconfig **configs;
75 unsigned depth_buffer_factor;
76 unsigned back_buffer_factor;
77 GLenum fb_format;
78 GLenum fb_type;
79
80 /* GLX_SWAP_COPY_OML is only supported because the Intel driver doesn't
81 * support pageflipping at all.
82 */
83 static const GLenum back_buffer_modes[] = {
84 GLX_NONE, GLX_SWAP_UNDEFINED_OML
85 };
86
87 uint8_t depth_bits_array[4];
88 uint8_t stencil_bits_array[4];
89 uint8_t msaa_samples_array[1];
90
91 depth_bits_array[0] = 0;
92 depth_bits_array[1] = 0;
93 depth_bits_array[2] = depth_bits;
94 depth_bits_array[3] = depth_bits;
95
96 /* Just like with the accumulation buffer, always provide some modes
97 * with a stencil buffer.
98 */
99 stencil_bits_array[0] = 0;
100 stencil_bits_array[1] = (stencil_bits == 0) ? 8 : stencil_bits;
101 stencil_bits_array[2] = 0;
102 stencil_bits_array[3] = (stencil_bits == 0) ? 8 : stencil_bits;
103
104 msaa_samples_array[0] = 0;
105
106 depth_buffer_factor = 4;
107 back_buffer_factor = 2;
108
109 switch (pixel_bits) {
110 case 8:
111 fb_format = GL_RGB;
112 fb_type = GL_UNSIGNED_BYTE_2_3_3_REV;
113 break;
114 case 16:
115 fb_format = GL_RGB;
116 fb_type = GL_UNSIGNED_SHORT_5_6_5;
117 break;
118 case 24:
119 fb_format = GL_BGR;
120 fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
121 break;
122 case 32:
123 fb_format = GL_BGRA;
124 fb_type = GL_UNSIGNED_INT_8_8_8_8_REV;
125 break;
126 default:
127 fprintf(stderr, "[%s:%u] bad depth %d\n", __func__, __LINE__,
128 pixel_bits);
129 return NULL;
130 }
131
132 configs = driCreateConfigs(fb_format, fb_type,
133 depth_bits_array, stencil_bits_array,
134 depth_buffer_factor, back_buffer_modes,
135 back_buffer_factor, msaa_samples_array, 1);
136 if (configs == NULL) {
137 fprintf(stderr, "[%s:%u] Error creating FBConfig!\n", __func__,
138 __LINE__);
139 return NULL;
140 }
141
142 return configs;
143 }
144
145 static __DRIscreen *
146 driCreateNewScreen(int scrn, const __DRIextension **extensions,
147 const __DRIconfig ***driver_configs, void *data)
148 {
149 static const __DRIextension *emptyExtensionList[] = { NULL };
150 __DRIscreen *psp;
151 __DRIconfig **configs8, **configs16, **configs24, **configs32;
152
153 (void) data;
154
155 TRACE;
156
157 psp = _mesa_calloc(sizeof(*psp));
158 if (!psp)
159 return NULL;
160
161 setupLoaderExtensions(psp, extensions);
162
163 psp->num = scrn;
164 psp->extensions = emptyExtensionList;
165
166 configs8 = swrastFillInModes(psp, 8, 8, 0, 1);
167 configs16 = swrastFillInModes(psp, 16, 16, 0, 1);
168 configs24 = swrastFillInModes(psp, 24, 24, 8, 1);
169 configs32 = swrastFillInModes(psp, 32, 24, 8, 1);
170
171 configs16 = driConcatConfigs(configs8, configs16);
172 configs24 = driConcatConfigs(configs16, configs24);
173 *driver_configs = (const __DRIconfig **)
174 driConcatConfigs(configs24, configs32);
175
176 driInitExtensions( NULL, NULL, GL_FALSE );
177
178 return psp;
179 }
180
181 static void driDestroyScreen(__DRIscreen *psp)
182 {
183 TRACE;
184
185 if (psp) {
186 _mesa_free(psp);
187 }
188 }
189
190 static const __DRIextension **driGetExtensions(__DRIscreen *psp)
191 {
192 TRACE;
193
194 return psp->extensions;
195 }
196
197
198 /**
199 * Framebuffer and renderbuffer-related functions.
200 */
201
202 static GLuint
203 choose_pixel_format(const GLvisual *v)
204 {
205 if (v->rgbMode) {
206 int depth = v->rgbBits;
207
208 if (depth == 32
209 && v->redMask == 0xff0000
210 && v->greenMask == 0x00ff00
211 && v->blueMask == 0x0000ff)
212 return PF_A8R8G8B8;
213 else if (depth == 24
214 && v->redMask == 0xff0000
215 && v->greenMask == 0x00ff00
216 && v->blueMask == 0x0000ff)
217 return PF_X8R8G8B8;
218 else if (depth == 16
219 && v->redMask == 0xf800
220 && v->greenMask == 0x07e0
221 && v->blueMask == 0x001f)
222 return PF_R5G6B5;
223 else if (depth == 8
224 && v->redMask == 0x07
225 && v->greenMask == 0x38
226 && v->blueMask == 0xc0)
227 return PF_R3G3B2;
228 }
229 else {
230 if (v->indexBits == 8)
231 return PF_CI8;
232 }
233
234 _mesa_problem( NULL, "unexpected format in %s", __FUNCTION__ );
235 return 0;
236 }
237
238 static void
239 swrast_delete_renderbuffer(struct gl_renderbuffer *rb)
240 {
241 TRACE;
242
243 _mesa_free(rb->Data);
244 _mesa_free(rb);
245 }
246
247 static GLboolean
248 swrast_alloc_front_storage(GLcontext *ctx, struct gl_renderbuffer *rb,
249 GLenum internalFormat, GLuint width, GLuint height)
250 {
251 struct swrast_renderbuffer *xrb = swrast_renderbuffer(rb);
252 unsigned mask = PITCH_ALIGN_BITS - 1;
253
254 TRACE;
255
256 rb->Data = NULL;
257 rb->Width = width;
258 rb->Height = height;
259
260 /* always pad to PITCH_ALIGN_BITS */
261 xrb->pitch = ((width * xrb->bpp + mask) & ~mask) / 8;
262
263 return GL_TRUE;
264 }
265
266 static GLboolean
267 swrast_alloc_back_storage(GLcontext *ctx, struct gl_renderbuffer *rb,
268 GLenum internalFormat, GLuint width, GLuint height)
269 {
270 struct swrast_renderbuffer *xrb = swrast_renderbuffer(rb);
271
272 TRACE;
273
274 _mesa_free(rb->Data);
275
276 swrast_alloc_front_storage(ctx, rb, internalFormat, width, height);
277
278 rb->Data = _mesa_malloc(height * xrb->pitch);
279
280 return GL_TRUE;
281 }
282
283 static struct swrast_renderbuffer *
284 swrast_new_renderbuffer(const GLvisual *visual, GLboolean front)
285 {
286 struct swrast_renderbuffer *xrb = _mesa_calloc(sizeof *xrb);
287 GLuint pixel_format;
288
289 TRACE;
290
291 if (!xrb)
292 return NULL;
293
294 _mesa_init_renderbuffer(&xrb->Base, 0);
295
296 pixel_format = choose_pixel_format(visual);
297
298 xrb->Base.Delete = swrast_delete_renderbuffer;
299 if (front) {
300 xrb->Base.AllocStorage = swrast_alloc_front_storage;
301 swrast_set_span_funcs_front(xrb, pixel_format);
302 }
303 else {
304 xrb->Base.AllocStorage = swrast_alloc_back_storage;
305 swrast_set_span_funcs_back(xrb, pixel_format);
306 }
307
308 switch (pixel_format) {
309 case PF_A8R8G8B8:
310 xrb->Base.Format = MESA_FORMAT_ARGB8888;
311 xrb->Base.InternalFormat = GL_RGBA;
312 xrb->Base._BaseFormat = GL_RGBA;
313 xrb->Base.DataType = GL_UNSIGNED_BYTE;
314 xrb->bpp = 32;
315 break;
316 case PF_X8R8G8B8:
317 xrb->Base.Format = MESA_FORMAT_ARGB8888; /* XXX */
318 xrb->Base.InternalFormat = GL_RGB;
319 xrb->Base._BaseFormat = GL_RGB;
320 xrb->Base.DataType = GL_UNSIGNED_BYTE;
321 xrb->bpp = 32;
322 break;
323 case PF_R5G6B5:
324 xrb->Base.Format = MESA_FORMAT_RGB565;
325 xrb->Base.InternalFormat = GL_RGB;
326 xrb->Base._BaseFormat = GL_RGB;
327 xrb->Base.DataType = GL_UNSIGNED_BYTE;
328 xrb->bpp = 16;
329 break;
330 case PF_R3G3B2:
331 xrb->Base.Format = MESA_FORMAT_RGB332;
332 xrb->Base.InternalFormat = GL_RGB;
333 xrb->Base._BaseFormat = GL_RGB;
334 xrb->Base.DataType = GL_UNSIGNED_BYTE;
335 xrb->bpp = 8;
336 break;
337 case PF_CI8:
338 xrb->Base.Format = MESA_FORMAT_CI8;
339 xrb->Base.InternalFormat = GL_COLOR_INDEX8_EXT;
340 xrb->Base._BaseFormat = GL_COLOR_INDEX;
341 xrb->Base.DataType = GL_UNSIGNED_BYTE;
342 xrb->bpp = 8;
343 break;
344 default:
345 return NULL;
346 }
347
348 return xrb;
349 }
350
351 static __DRIdrawable *
352 driCreateNewDrawable(__DRIscreen *screen,
353 const __DRIconfig *config, void *data)
354 {
355 __DRIdrawable *buf;
356 struct swrast_renderbuffer *frontrb, *backrb;
357
358 TRACE;
359
360 buf = _mesa_calloc(sizeof *buf);
361 if (!buf)
362 return NULL;
363
364 buf->loaderPrivate = data;
365
366 buf->driScreenPriv = screen;
367
368 buf->row = _mesa_malloc(MAX_WIDTH * 4);
369
370 /* basic framebuffer setup */
371 _mesa_initialize_framebuffer(&buf->Base, &config->modes);
372
373 /* add front renderbuffer */
374 frontrb = swrast_new_renderbuffer(&config->modes, GL_TRUE);
375 _mesa_add_renderbuffer(&buf->Base, BUFFER_FRONT_LEFT, &frontrb->Base);
376
377 /* add back renderbuffer */
378 if (config->modes.doubleBufferMode) {
379 backrb = swrast_new_renderbuffer(&config->modes, GL_FALSE);
380 _mesa_add_renderbuffer(&buf->Base, BUFFER_BACK_LEFT, &backrb->Base);
381 }
382
383 /* add software renderbuffers */
384 _mesa_add_soft_renderbuffers(&buf->Base,
385 GL_FALSE, /* color */
386 config->modes.haveDepthBuffer,
387 config->modes.haveStencilBuffer,
388 config->modes.haveAccumBuffer,
389 GL_FALSE, /* alpha */
390 GL_FALSE /* aux bufs */);
391
392 return buf;
393 }
394
395 static void
396 driDestroyDrawable(__DRIdrawable *buf)
397 {
398 TRACE;
399
400 if (buf) {
401 struct gl_framebuffer *fb = &buf->Base;
402
403 _mesa_free(buf->row);
404
405 fb->DeletePending = GL_TRUE;
406 _mesa_reference_framebuffer(&fb, NULL);
407 }
408 }
409
410 static void driSwapBuffers(__DRIdrawable *buf)
411 {
412 GET_CURRENT_CONTEXT(ctx);
413
414 struct swrast_renderbuffer *frontrb =
415 swrast_renderbuffer(buf->Base.Attachment[BUFFER_FRONT_LEFT].Renderbuffer);
416 struct swrast_renderbuffer *backrb =
417 swrast_renderbuffer(buf->Base.Attachment[BUFFER_BACK_LEFT].Renderbuffer);
418
419 __DRIscreen *screen = buf->driScreenPriv;
420
421 TRACE;
422
423 /* check for signle-buffered */
424 if (backrb == NULL)
425 return;
426
427 /* check if swapping currently bound buffer */
428 if (ctx && ctx->DrawBuffer == &(buf->Base)) {
429 /* flush pending rendering */
430 _mesa_notifySwapBuffers(ctx);
431 }
432
433 screen->swrast_loader->putImage(buf, __DRI_SWRAST_IMAGE_OP_SWAP,
434 0, 0,
435 frontrb->Base.Width,
436 frontrb->Base.Height,
437 backrb->Base.Data,
438 buf->loaderPrivate);
439 }
440
441
442 /**
443 * General device driver functions.
444 */
445
446 static void
447 get_window_size( GLframebuffer *fb, GLsizei *w, GLsizei *h )
448 {
449 __DRIdrawable *buf = swrast_drawable(fb);
450 __DRIscreen *screen = buf->driScreenPriv;
451 int x, y;
452
453 screen->swrast_loader->getDrawableInfo(buf,
454 &x, &y, w, h,
455 buf->loaderPrivate);
456 }
457
458 static void
459 swrast_check_and_update_window_size( GLcontext *ctx, GLframebuffer *fb )
460 {
461 GLsizei width, height;
462
463 get_window_size(fb, &width, &height);
464 if (fb->Width != width || fb->Height != height) {
465 _mesa_resize_framebuffer(ctx, fb, width, height);
466 }
467 }
468
469 static const GLubyte *
470 get_string(GLcontext *ctx, GLenum pname)
471 {
472 (void) ctx;
473 switch (pname) {
474 case GL_VENDOR:
475 return (const GLubyte *) "Mesa Project";
476 case GL_RENDERER:
477 return (const GLubyte *) "Software Rasterizer";
478 default:
479 return NULL;
480 }
481 }
482
483 static void
484 update_state( GLcontext *ctx, GLuint new_state )
485 {
486 /* not much to do here - pass it on */
487 _swrast_InvalidateState( ctx, new_state );
488 _swsetup_InvalidateState( ctx, new_state );
489 _vbo_InvalidateState( ctx, new_state );
490 _tnl_InvalidateState( ctx, new_state );
491 }
492
493 static void
494 viewport(GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h)
495 {
496 GLframebuffer *draw = ctx->WinSysDrawBuffer;
497 GLframebuffer *read = ctx->WinSysReadBuffer;
498
499 swrast_check_and_update_window_size(ctx, draw);
500 swrast_check_and_update_window_size(ctx, read);
501 }
502
503 static void
504 swrast_init_driver_functions(struct dd_function_table *driver)
505 {
506 driver->GetString = get_string;
507 driver->UpdateState = update_state;
508 driver->GetBufferSize = NULL;
509 driver->Viewport = viewport;
510 }
511
512
513 /**
514 * Context-related functions.
515 */
516
517 static __DRIcontext *
518 driCreateNewContext(__DRIscreen *screen, const __DRIconfig *config,
519 __DRIcontext *shared, void *data)
520 {
521 __DRIcontext *ctx;
522 GLcontext *mesaCtx;
523 struct dd_function_table functions;
524
525 TRACE;
526
527 ctx = _mesa_calloc(sizeof *ctx);
528 if (!ctx)
529 return NULL;
530
531 ctx->loaderPrivate = data;
532
533 ctx->driScreenPriv = screen;
534
535 /* build table of device driver functions */
536 _mesa_init_driver_functions(&functions);
537 swrast_init_driver_functions(&functions);
538
539 if (!_mesa_initialize_context(&ctx->Base, &config->modes,
540 shared ? &shared->Base : NULL,
541 &functions, (void *) ctx)) {
542 _mesa_free(ctx);
543 return NULL;
544 }
545
546 mesaCtx = &ctx->Base;
547
548 /* do bounds checking to prevent segfaults and server crashes! */
549 mesaCtx->Const.CheckArrayBounds = GL_TRUE;
550
551 /* create module contexts */
552 _swrast_CreateContext( mesaCtx );
553 _vbo_CreateContext( mesaCtx );
554 _tnl_CreateContext( mesaCtx );
555 _swsetup_CreateContext( mesaCtx );
556 _swsetup_Wakeup( mesaCtx );
557
558 /* use default TCL pipeline */
559 {
560 TNLcontext *tnl = TNL_CONTEXT(mesaCtx);
561 tnl->Driver.RunPipeline = _tnl_run_pipeline;
562 }
563
564 _mesa_enable_sw_extensions(mesaCtx);
565 _mesa_enable_1_3_extensions(mesaCtx);
566 _mesa_enable_1_4_extensions(mesaCtx);
567 _mesa_enable_1_5_extensions(mesaCtx);
568 _mesa_enable_2_0_extensions(mesaCtx);
569 _mesa_enable_2_1_extensions(mesaCtx);
570
571 _mesa_meta_init(mesaCtx);
572
573 return ctx;
574 }
575
576 static void
577 driDestroyContext(__DRIcontext *ctx)
578 {
579 GLcontext *mesaCtx;
580 TRACE;
581
582 if (ctx) {
583 mesaCtx = &ctx->Base;
584 _mesa_meta_free(mesaCtx);
585 _swsetup_DestroyContext( mesaCtx );
586 _swrast_DestroyContext( mesaCtx );
587 _tnl_DestroyContext( mesaCtx );
588 _vbo_DestroyContext( mesaCtx );
589 _mesa_destroy_context( mesaCtx );
590 }
591 }
592
593 static int
594 driCopyContext(__DRIcontext *dst, __DRIcontext *src, unsigned long mask)
595 {
596 TRACE;
597
598 _mesa_copy_context(&src->Base, &dst->Base, mask);
599 return GL_TRUE;
600 }
601
602 static int driBindContext(__DRIcontext *ctx,
603 __DRIdrawable *draw,
604 __DRIdrawable *read)
605 {
606 GLcontext *mesaCtx;
607 GLframebuffer *mesaDraw;
608 GLframebuffer *mesaRead;
609 TRACE;
610
611 if (ctx) {
612 if (!draw || !read)
613 return GL_FALSE;
614
615 mesaCtx = &ctx->Base;
616 mesaDraw = &draw->Base;
617 mesaRead = &read->Base;
618
619 /* check for same context and buffer */
620 if (mesaCtx == _mesa_get_current_context()
621 && mesaCtx->DrawBuffer == mesaDraw
622 && mesaCtx->ReadBuffer == mesaRead) {
623 return GL_TRUE;
624 }
625
626 _glapi_check_multithread();
627
628 swrast_check_and_update_window_size(mesaCtx, mesaDraw);
629 if (read != draw)
630 swrast_check_and_update_window_size(mesaCtx, mesaRead);
631
632 _mesa_make_current( mesaCtx,
633 mesaDraw,
634 mesaRead );
635 }
636 else {
637 /* unbind */
638 _mesa_make_current( NULL, NULL, NULL );
639 }
640
641 return GL_TRUE;
642 }
643
644 static int driUnbindContext(__DRIcontext *ctx)
645 {
646 TRACE;
647 (void) ctx;
648 return GL_TRUE;
649 }
650
651
652 static const __DRIcoreExtension driCoreExtension = {
653 { __DRI_CORE, __DRI_CORE_VERSION },
654 NULL, /* driCreateNewScreen */
655 driDestroyScreen,
656 driGetExtensions,
657 driGetConfigAttrib,
658 driIndexConfigAttrib,
659 NULL, /* driCreateNewDrawable */
660 driDestroyDrawable,
661 driSwapBuffers,
662 driCreateNewContext,
663 driCopyContext,
664 driDestroyContext,
665 driBindContext,
666 driUnbindContext
667 };
668
669 static const __DRIswrastExtension driSWRastExtension = {
670 { __DRI_SWRAST, __DRI_SWRAST_VERSION },
671 driCreateNewScreen,
672 driCreateNewDrawable
673 };
674
675 /* This is the table of extensions that the loader will dlsym() for. */
676 PUBLIC const __DRIextension *__driDriverExtensions[] = {
677 &driCoreExtension.base,
678 &driSWRastExtension.base,
679 NULL
680 };