mesa: remove gl_renderbuffer:RowStride field
[mesa.git] / src / mesa / swrast / s_renderbuffer.c
1 /*
2 * Mesa 3-D graphics library
3 * Version: 6.5
4 *
5 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a
8 * copy of this software and associated documentation files (the "Software"),
9 * to deal in the Software without restriction, including without limitation
10 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
11 * and/or sell copies of the Software, and to permit persons to whom the
12 * Software is furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included
15 * in all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
21 * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
22 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23 */
24
25
26 /**
27 * Functions for allocating/managing software-based renderbuffers.
28 * Also, routines for reading/writing software-based renderbuffer data as
29 * ubytes, ushorts, uints, etc.
30 */
31
32
33 #include "main/glheader.h"
34 #include "main/imports.h"
35 #include "main/context.h"
36 #include "main/fbobject.h"
37 #include "main/formats.h"
38 #include "main/mtypes.h"
39 #include "main/renderbuffer.h"
40 #include "swrast/s_renderbuffer.h"
41
42
43
44 /**
45 * This is the default software fallback for gl_renderbuffer's span
46 * access functions.
47 *
48 * The assumptions are that rb->Data will be a pointer to (0,0), that pixels
49 * are packed in the type of rb->Format, and that subsequent rows appear
50 * rb->RowStride pixels later.
51 */
52 void
53 _swrast_set_renderbuffer_accessors(struct gl_renderbuffer *rb)
54 {
55 switch (rb->Format) {
56 case MESA_FORMAT_RGB888:
57 rb->DataType = GL_UNSIGNED_BYTE;
58 break;
59
60 case MESA_FORMAT_RGBA8888:
61 case MESA_FORMAT_RGBA8888_REV:
62 rb->DataType = GL_UNSIGNED_BYTE;
63 break;
64
65 case MESA_FORMAT_R8:
66 rb->DataType = GL_UNSIGNED_BYTE;
67
68 break;
69
70 case MESA_FORMAT_GR88:
71 rb->DataType = GL_UNSIGNED_BYTE;
72 break;
73
74 case MESA_FORMAT_R16:
75 rb->DataType = GL_UNSIGNED_SHORT;
76
77 break;
78
79 case MESA_FORMAT_RG1616:
80 rb->DataType = GL_UNSIGNED_SHORT;
81 break;
82
83 case MESA_FORMAT_SIGNED_RGBA_16:
84 rb->DataType = GL_SHORT;
85 break;
86
87 case MESA_FORMAT_S8:
88 rb->DataType = GL_UNSIGNED_BYTE;
89 break;
90
91 case MESA_FORMAT_Z16:
92 rb->DataType = GL_UNSIGNED_SHORT;
93 break;
94
95 case MESA_FORMAT_Z32:
96 case MESA_FORMAT_X8_Z24:
97 case MESA_FORMAT_Z24_X8:
98 rb->DataType = GL_UNSIGNED_INT;
99 break;
100
101 case MESA_FORMAT_Z24_S8:
102 case MESA_FORMAT_S8_Z24:
103 rb->DataType = GL_UNSIGNED_INT_24_8_EXT;
104 break;
105
106 case MESA_FORMAT_RGBA_FLOAT32:
107 rb->DataType = GL_FLOAT;
108 break;
109
110 case MESA_FORMAT_INTENSITY_FLOAT32:
111 rb->DataType = GL_FLOAT;
112 break;
113
114 case MESA_FORMAT_LUMINANCE_FLOAT32:
115 rb->DataType = GL_FLOAT;
116 break;
117
118 case MESA_FORMAT_ALPHA_FLOAT32:
119 rb->DataType = GL_FLOAT;
120 break;
121
122 case MESA_FORMAT_RG_FLOAT32:
123 rb->DataType = GL_FLOAT;
124 break;
125
126 case MESA_FORMAT_R_FLOAT32:
127 rb->DataType = GL_FLOAT;
128 break;
129
130 default:
131 break;
132 }
133 }
134
135 /**
136 * This is a software fallback for the gl_renderbuffer->AllocStorage
137 * function.
138 * Device drivers will typically override this function for the buffers
139 * which it manages (typically color buffers, Z and stencil).
140 * Other buffers (like software accumulation and aux buffers) which the driver
141 * doesn't manage can be handled with this function.
142 *
143 * This one multi-purpose function can allocate stencil, depth, accum, color
144 * or color-index buffers!
145 */
146 static GLboolean
147 soft_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
148 GLenum internalFormat,
149 GLuint width, GLuint height)
150 {
151 switch (internalFormat) {
152 case GL_RGB:
153 case GL_R3_G3_B2:
154 case GL_RGB4:
155 case GL_RGB5:
156 case GL_RGB8:
157 case GL_RGB10:
158 case GL_RGB12:
159 case GL_RGB16:
160 rb->Format = MESA_FORMAT_RGB888;
161 break;
162 case GL_RGBA:
163 case GL_RGBA2:
164 case GL_RGBA4:
165 case GL_RGB5_A1:
166 case GL_RGBA8:
167 #if 1
168 case GL_RGB10_A2:
169 case GL_RGBA12:
170 #endif
171 if (_mesa_little_endian())
172 rb->Format = MESA_FORMAT_RGBA8888_REV;
173 else
174 rb->Format = MESA_FORMAT_RGBA8888;
175 break;
176 case GL_RGBA16:
177 case GL_RGBA16_SNORM:
178 /* for accum buffer */
179 rb->Format = MESA_FORMAT_SIGNED_RGBA_16;
180 break;
181 case GL_STENCIL_INDEX:
182 case GL_STENCIL_INDEX1_EXT:
183 case GL_STENCIL_INDEX4_EXT:
184 case GL_STENCIL_INDEX8_EXT:
185 case GL_STENCIL_INDEX16_EXT:
186 rb->Format = MESA_FORMAT_S8;
187 break;
188 case GL_DEPTH_COMPONENT:
189 case GL_DEPTH_COMPONENT16:
190 rb->Format = MESA_FORMAT_Z16;
191 break;
192 case GL_DEPTH_COMPONENT24:
193 rb->Format = MESA_FORMAT_X8_Z24;
194 break;
195 case GL_DEPTH_COMPONENT32:
196 rb->Format = MESA_FORMAT_Z32;
197 break;
198 case GL_DEPTH_STENCIL_EXT:
199 case GL_DEPTH24_STENCIL8_EXT:
200 rb->Format = MESA_FORMAT_Z24_S8;
201 break;
202 default:
203 /* unsupported format */
204 return GL_FALSE;
205 }
206
207 _swrast_set_renderbuffer_accessors(rb);
208
209 ASSERT(rb->DataType);
210
211 /* free old buffer storage */
212 if (rb->Data) {
213 free(rb->Data);
214 rb->Data = NULL;
215 }
216
217 rb->RowStrideBytes = width * _mesa_get_format_bytes(rb->Format);
218
219 if (width > 0 && height > 0) {
220 /* allocate new buffer storage */
221 rb->Data = malloc(width * height * _mesa_get_format_bytes(rb->Format));
222
223 if (rb->Data == NULL) {
224 rb->Width = 0;
225 rb->Height = 0;
226 _mesa_error(ctx, GL_OUT_OF_MEMORY,
227 "software renderbuffer allocation (%d x %d x %d)",
228 width, height, _mesa_get_format_bytes(rb->Format));
229 return GL_FALSE;
230 }
231 }
232
233 rb->Width = width;
234 rb->Height = height;
235 rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat);
236
237 if (rb->Name == 0 &&
238 internalFormat == GL_RGBA16_SNORM &&
239 rb->_BaseFormat == 0) {
240 /* NOTE: This is a special case just for accumulation buffers.
241 * This is a very limited use case- there's no snorm texturing or
242 * rendering going on.
243 */
244 rb->_BaseFormat = GL_RGBA;
245 }
246 else {
247 /* the internalFormat should have been error checked long ago */
248 ASSERT(rb->_BaseFormat);
249 }
250
251 return GL_TRUE;
252 }
253
254
255 void
256 _swrast_map_soft_renderbuffer(struct gl_context *ctx,
257 struct gl_renderbuffer *rb,
258 GLuint x, GLuint y, GLuint w, GLuint h,
259 GLbitfield mode,
260 GLubyte **out_map,
261 GLint *out_stride)
262 {
263 GLubyte *map = rb->Data;
264 int cpp = _mesa_get_format_bytes(rb->Format);
265 int stride = rb->Width * cpp;
266
267 ASSERT(rb->Data);
268
269 map += y * stride;
270 map += x * cpp;
271
272 *out_map = map;
273 *out_stride = stride;
274 }
275
276
277 void
278 _swrast_unmap_soft_renderbuffer(struct gl_context *ctx,
279 struct gl_renderbuffer *rb)
280 {
281 }
282
283
284
285 /**
286 * Allocate a software-based renderbuffer. This is called via the
287 * ctx->Driver.NewRenderbuffer() function when the user creates a new
288 * renderbuffer.
289 * This would not be used for hardware-based renderbuffers.
290 */
291 struct gl_renderbuffer *
292 _swrast_new_soft_renderbuffer(struct gl_context *ctx, GLuint name)
293 {
294 struct gl_renderbuffer *rb = _mesa_new_renderbuffer(ctx, name);
295 if (rb) {
296 rb->AllocStorage = soft_renderbuffer_storage;
297 }
298 return rb;
299 }
300
301
302 /**
303 * Add software-based color renderbuffers to the given framebuffer.
304 * This is a helper routine for device drivers when creating a
305 * window system framebuffer (not a user-created render/framebuffer).
306 * Once this function is called, you can basically forget about this
307 * renderbuffer; core Mesa will handle all the buffer management and
308 * rendering!
309 */
310 static GLboolean
311 add_color_renderbuffers(struct gl_context *ctx, struct gl_framebuffer *fb,
312 GLuint rgbBits, GLuint alphaBits,
313 GLboolean frontLeft, GLboolean backLeft,
314 GLboolean frontRight, GLboolean backRight)
315 {
316 gl_buffer_index b;
317
318 if (rgbBits > 16 || alphaBits > 16) {
319 _mesa_problem(ctx,
320 "Unsupported bit depth in add_color_renderbuffers");
321 return GL_FALSE;
322 }
323
324 assert(MAX_COLOR_ATTACHMENTS >= 4);
325
326 for (b = BUFFER_FRONT_LEFT; b <= BUFFER_BACK_RIGHT; b++) {
327 struct gl_renderbuffer *rb;
328
329 if (b == BUFFER_FRONT_LEFT && !frontLeft)
330 continue;
331 else if (b == BUFFER_BACK_LEFT && !backLeft)
332 continue;
333 else if (b == BUFFER_FRONT_RIGHT && !frontRight)
334 continue;
335 else if (b == BUFFER_BACK_RIGHT && !backRight)
336 continue;
337
338 assert(fb->Attachment[b].Renderbuffer == NULL);
339
340 rb = _mesa_new_renderbuffer(ctx, 0);
341 if (!rb) {
342 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating color buffer");
343 return GL_FALSE;
344 }
345
346 rb->InternalFormat = GL_RGBA;
347
348 rb->AllocStorage = soft_renderbuffer_storage;
349 _mesa_add_renderbuffer(fb, b, rb);
350 }
351
352 return GL_TRUE;
353 }
354
355
356 /**
357 * Add a software-based depth renderbuffer to the given framebuffer.
358 * This is a helper routine for device drivers when creating a
359 * window system framebuffer (not a user-created render/framebuffer).
360 * Once this function is called, you can basically forget about this
361 * renderbuffer; core Mesa will handle all the buffer management and
362 * rendering!
363 */
364 static GLboolean
365 add_depth_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
366 GLuint depthBits)
367 {
368 struct gl_renderbuffer *rb;
369
370 if (depthBits > 32) {
371 _mesa_problem(ctx,
372 "Unsupported depthBits in add_depth_renderbuffer");
373 return GL_FALSE;
374 }
375
376 assert(fb->Attachment[BUFFER_DEPTH].Renderbuffer == NULL);
377
378 rb = _mesa_new_renderbuffer(ctx, 0);
379 if (!rb) {
380 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating depth buffer");
381 return GL_FALSE;
382 }
383
384 if (depthBits <= 16) {
385 rb->InternalFormat = GL_DEPTH_COMPONENT16;
386 }
387 else if (depthBits <= 24) {
388 rb->InternalFormat = GL_DEPTH_COMPONENT24;
389 }
390 else {
391 rb->InternalFormat = GL_DEPTH_COMPONENT32;
392 }
393
394 rb->AllocStorage = soft_renderbuffer_storage;
395 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb);
396
397 return GL_TRUE;
398 }
399
400
401 /**
402 * Add a software-based stencil renderbuffer to the given framebuffer.
403 * This is a helper routine for device drivers when creating a
404 * window system framebuffer (not a user-created render/framebuffer).
405 * Once this function is called, you can basically forget about this
406 * renderbuffer; core Mesa will handle all the buffer management and
407 * rendering!
408 */
409 static GLboolean
410 add_stencil_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
411 GLuint stencilBits)
412 {
413 struct gl_renderbuffer *rb;
414
415 if (stencilBits > 16) {
416 _mesa_problem(ctx,
417 "Unsupported stencilBits in add_stencil_renderbuffer");
418 return GL_FALSE;
419 }
420
421 assert(fb->Attachment[BUFFER_STENCIL].Renderbuffer == NULL);
422
423 rb = _mesa_new_renderbuffer(ctx, 0);
424 if (!rb) {
425 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating stencil buffer");
426 return GL_FALSE;
427 }
428
429 assert(stencilBits <= 8);
430 rb->InternalFormat = GL_STENCIL_INDEX8;
431
432 rb->AllocStorage = soft_renderbuffer_storage;
433 _mesa_add_renderbuffer(fb, BUFFER_STENCIL, rb);
434
435 return GL_TRUE;
436 }
437
438
439 static GLboolean
440 add_depth_stencil_renderbuffer(struct gl_context *ctx,
441 struct gl_framebuffer *fb)
442 {
443 struct gl_renderbuffer *rb;
444
445 assert(fb->Attachment[BUFFER_DEPTH].Renderbuffer == NULL);
446 assert(fb->Attachment[BUFFER_STENCIL].Renderbuffer == NULL);
447
448 rb = _mesa_new_renderbuffer(ctx, 0);
449 if (!rb) {
450 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating depth+stencil buffer");
451 return GL_FALSE;
452 }
453
454 rb->InternalFormat = GL_DEPTH_STENCIL;
455
456 rb->AllocStorage = soft_renderbuffer_storage;
457 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb);
458 _mesa_add_renderbuffer(fb, BUFFER_STENCIL, rb);
459
460 return GL_TRUE;
461 }
462
463
464 /**
465 * Add a software-based accumulation renderbuffer to the given framebuffer.
466 * This is a helper routine for device drivers when creating a
467 * window system framebuffer (not a user-created render/framebuffer).
468 * Once this function is called, you can basically forget about this
469 * renderbuffer; core Mesa will handle all the buffer management and
470 * rendering!
471 */
472 static GLboolean
473 add_accum_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
474 GLuint redBits, GLuint greenBits,
475 GLuint blueBits, GLuint alphaBits)
476 {
477 struct gl_renderbuffer *rb;
478
479 if (redBits > 16 || greenBits > 16 || blueBits > 16 || alphaBits > 16) {
480 _mesa_problem(ctx,
481 "Unsupported accumBits in add_accum_renderbuffer");
482 return GL_FALSE;
483 }
484
485 assert(fb->Attachment[BUFFER_ACCUM].Renderbuffer == NULL);
486
487 rb = _mesa_new_renderbuffer(ctx, 0);
488 if (!rb) {
489 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating accum buffer");
490 return GL_FALSE;
491 }
492
493 rb->InternalFormat = GL_RGBA16_SNORM;
494 rb->AllocStorage = soft_renderbuffer_storage;
495 _mesa_add_renderbuffer(fb, BUFFER_ACCUM, rb);
496
497 return GL_TRUE;
498 }
499
500
501
502 /**
503 * Add a software-based aux renderbuffer to the given framebuffer.
504 * This is a helper routine for device drivers when creating a
505 * window system framebuffer (not a user-created render/framebuffer).
506 * Once this function is called, you can basically forget about this
507 * renderbuffer; core Mesa will handle all the buffer management and
508 * rendering!
509 *
510 * NOTE: color-index aux buffers not supported.
511 */
512 static GLboolean
513 add_aux_renderbuffers(struct gl_context *ctx, struct gl_framebuffer *fb,
514 GLuint colorBits, GLuint numBuffers)
515 {
516 GLuint i;
517
518 if (colorBits > 16) {
519 _mesa_problem(ctx,
520 "Unsupported colorBits in add_aux_renderbuffers");
521 return GL_FALSE;
522 }
523
524 assert(numBuffers <= MAX_AUX_BUFFERS);
525
526 for (i = 0; i < numBuffers; i++) {
527 struct gl_renderbuffer *rb = _mesa_new_renderbuffer(ctx, 0);
528
529 assert(fb->Attachment[BUFFER_AUX0 + i].Renderbuffer == NULL);
530
531 if (!rb) {
532 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating aux buffer");
533 return GL_FALSE;
534 }
535
536 assert (colorBits <= 8);
537 rb->InternalFormat = GL_RGBA;
538
539 rb->AllocStorage = soft_renderbuffer_storage;
540 _mesa_add_renderbuffer(fb, BUFFER_AUX0 + i, rb);
541 }
542 return GL_TRUE;
543 }
544
545
546 /**
547 * Create/attach software-based renderbuffers to the given framebuffer.
548 * This is a helper routine for device drivers. Drivers can just as well
549 * call the individual _mesa_add_*_renderbuffer() routines directly.
550 */
551 void
552 _swrast_add_soft_renderbuffers(struct gl_framebuffer *fb,
553 GLboolean color,
554 GLboolean depth,
555 GLboolean stencil,
556 GLboolean accum,
557 GLboolean alpha,
558 GLboolean aux)
559 {
560 GLboolean frontLeft = GL_TRUE;
561 GLboolean backLeft = fb->Visual.doubleBufferMode;
562 GLboolean frontRight = fb->Visual.stereoMode;
563 GLboolean backRight = fb->Visual.stereoMode && fb->Visual.doubleBufferMode;
564
565 if (color) {
566 assert(fb->Visual.redBits == fb->Visual.greenBits);
567 assert(fb->Visual.redBits == fb->Visual.blueBits);
568 add_color_renderbuffers(NULL, fb,
569 fb->Visual.redBits,
570 fb->Visual.alphaBits,
571 frontLeft, backLeft,
572 frontRight, backRight);
573 }
574
575 #if 0
576 /* This is pretty much for debugging purposes only since there's a perf
577 * hit for using combined depth/stencil in swrast.
578 */
579 if (depth && fb->Visual.depthBits == 24 &&
580 stencil && fb->Visual.stencilBits == 8) {
581 /* use combined depth/stencil buffer */
582 add_depth_stencil_renderbuffer(NULL, fb);
583 }
584 else
585 #else
586 (void) add_depth_stencil_renderbuffer;
587 #endif
588 {
589 if (depth) {
590 assert(fb->Visual.depthBits > 0);
591 add_depth_renderbuffer(NULL, fb, fb->Visual.depthBits);
592 }
593
594 if (stencil) {
595 assert(fb->Visual.stencilBits > 0);
596 add_stencil_renderbuffer(NULL, fb, fb->Visual.stencilBits);
597 }
598 }
599
600 if (accum) {
601 assert(fb->Visual.accumRedBits > 0);
602 assert(fb->Visual.accumGreenBits > 0);
603 assert(fb->Visual.accumBlueBits > 0);
604 add_accum_renderbuffer(NULL, fb,
605 fb->Visual.accumRedBits,
606 fb->Visual.accumGreenBits,
607 fb->Visual.accumBlueBits,
608 fb->Visual.accumAlphaBits);
609 }
610
611 if (aux) {
612 assert(fb->Visual.numAuxBuffers > 0);
613 add_aux_renderbuffers(NULL, fb, fb->Visual.redBits,
614 fb->Visual.numAuxBuffers);
615 }
616
617 #if 0
618 if (multisample) {
619 /* maybe someday */
620 }
621 #endif
622 }