2 * Mesa 3-D graphics library
4 * Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
13 * The above copyright notice and this permission notice shall be included
14 * in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22 * OTHER DEALINGS IN THE SOFTWARE.
27 * Functions for allocating/managing software-based renderbuffers.
28 * Also, routines for reading/writing software-based renderbuffer data as
29 * ubytes, ushorts, uints, etc.
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_context.h"
41 #include "swrast/s_renderbuffer.h"
45 * This is a software fallback for the gl_renderbuffer->AllocStorage
47 * Device drivers will typically override this function for the buffers
48 * which it manages (typically color buffers, Z and stencil).
49 * Other buffers (like software accumulation and aux buffers) which the driver
50 * doesn't manage can be handled with this function.
52 * This one multi-purpose function can allocate stencil, depth, accum, color
53 * or color-index buffers!
56 soft_renderbuffer_storage(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
,
57 GLenum internalFormat
,
58 GLuint width
, GLuint height
)
60 struct swrast_renderbuffer
*srb
= swrast_renderbuffer(rb
);
63 switch (internalFormat
) {
72 rb
->Format
= MESA_FORMAT_BGR_UNORM8
;
83 if (_mesa_little_endian())
84 rb
->Format
= MESA_FORMAT_R8G8B8A8_UNORM
;
86 rb
->Format
= MESA_FORMAT_A8B8G8R8_UNORM
;
90 /* for accum buffer */
91 rb
->Format
= MESA_FORMAT_RGBA_SNORM16
;
93 case GL_STENCIL_INDEX
:
94 case GL_STENCIL_INDEX1_EXT
:
95 case GL_STENCIL_INDEX4_EXT
:
96 case GL_STENCIL_INDEX8_EXT
:
97 case GL_STENCIL_INDEX16_EXT
:
98 rb
->Format
= MESA_FORMAT_S_UINT8
;
100 case GL_DEPTH_COMPONENT
:
101 case GL_DEPTH_COMPONENT16
:
102 rb
->Format
= MESA_FORMAT_Z_UNORM16
;
104 case GL_DEPTH_COMPONENT24
:
105 rb
->Format
= MESA_FORMAT_Z24_UNORM_X8_UINT
;
107 case GL_DEPTH_COMPONENT32
:
108 rb
->Format
= MESA_FORMAT_Z_UNORM32
;
110 case GL_DEPTH_STENCIL_EXT
:
111 case GL_DEPTH24_STENCIL8_EXT
:
112 rb
->Format
= MESA_FORMAT_S8_UINT_Z24_UNORM
;
115 /* unsupported format */
119 bpp
= _mesa_get_format_bytes(rb
->Format
);
121 /* free old buffer storage */
125 srb
->RowStride
= width
* bpp
;
127 if (width
> 0 && height
> 0) {
128 /* allocate new buffer storage */
129 srb
->Buffer
= malloc(srb
->RowStride
* height
);
131 if (srb
->Buffer
== NULL
) {
134 _mesa_error(ctx
, GL_OUT_OF_MEMORY
,
135 "software renderbuffer allocation (%d x %d x %d)",
143 rb
->_BaseFormat
= _mesa_base_fbo_format(ctx
, internalFormat
);
146 internalFormat
== GL_RGBA16_SNORM
&&
147 rb
->_BaseFormat
== 0) {
148 /* NOTE: This is a special case just for accumulation buffers.
149 * This is a very limited use case- there's no snorm texturing or
150 * rendering going on.
152 rb
->_BaseFormat
= GL_RGBA
;
155 /* the internalFormat should have been error checked long ago */
156 assert(rb
->_BaseFormat
);
164 * Called via gl_renderbuffer::Delete()
167 soft_renderbuffer_delete(struct gl_context
*ctx
, struct gl_renderbuffer
*rb
)
169 struct swrast_renderbuffer
*srb
= swrast_renderbuffer(rb
);
173 _mesa_delete_renderbuffer(ctx
, rb
);
178 _swrast_map_soft_renderbuffer(struct gl_context
*ctx
,
179 struct gl_renderbuffer
*rb
,
180 GLuint x
, GLuint y
, GLuint w
, GLuint h
,
186 struct swrast_renderbuffer
*srb
= swrast_renderbuffer(rb
);
187 GLubyte
*map
= srb
->Buffer
;
188 int cpp
= _mesa_get_format_bytes(rb
->Format
);
189 int stride
= rb
->Width
* cpp
;
200 *out_stride
= stride
;
205 _swrast_unmap_soft_renderbuffer(struct gl_context
*ctx
,
206 struct gl_renderbuffer
*rb
)
213 * Allocate a software-based renderbuffer. This is called via the
214 * ctx->Driver.NewRenderbuffer() function when the user creates a new
216 * This would not be used for hardware-based renderbuffers.
218 struct gl_renderbuffer
*
219 _swrast_new_soft_renderbuffer(struct gl_context
*ctx
, GLuint name
)
221 struct swrast_renderbuffer
*srb
= CALLOC_STRUCT(swrast_renderbuffer
);
223 _mesa_init_renderbuffer(&srb
->Base
, name
);
224 srb
->Base
.AllocStorage
= soft_renderbuffer_storage
;
225 srb
->Base
.Delete
= soft_renderbuffer_delete
;
232 * Add software-based color renderbuffers to the given framebuffer.
233 * This is a helper routine for device drivers when creating a
234 * window system framebuffer (not a user-created render/framebuffer).
235 * Once this function is called, you can basically forget about this
236 * renderbuffer; core Mesa will handle all the buffer management and
240 add_color_renderbuffers(struct gl_context
*ctx
, struct gl_framebuffer
*fb
,
241 GLuint rgbBits
, GLuint alphaBits
,
242 GLboolean frontLeft
, GLboolean backLeft
,
243 GLboolean frontRight
, GLboolean backRight
)
247 if (rgbBits
> 16 || alphaBits
> 16) {
249 "Unsupported bit depth in add_color_renderbuffers");
253 assert(MAX_COLOR_ATTACHMENTS
>= 4);
255 for (b
= BUFFER_FRONT_LEFT
; b
<= BUFFER_BACK_RIGHT
; b
++) {
256 struct gl_renderbuffer
*rb
;
258 if (b
== BUFFER_FRONT_LEFT
&& !frontLeft
)
260 else if (b
== BUFFER_BACK_LEFT
&& !backLeft
)
262 else if (b
== BUFFER_FRONT_RIGHT
&& !frontRight
)
264 else if (b
== BUFFER_BACK_RIGHT
&& !backRight
)
267 assert(fb
->Attachment
[b
].Renderbuffer
== NULL
);
269 rb
= ctx
->Driver
.NewRenderbuffer(ctx
, 0);
271 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "Allocating color buffer");
275 rb
->InternalFormat
= GL_RGBA
;
277 rb
->AllocStorage
= soft_renderbuffer_storage
;
278 _mesa_attach_and_own_rb(fb
, b
, rb
);
286 * Add a software-based depth renderbuffer to the given framebuffer.
287 * This is a helper routine for device drivers when creating a
288 * window system framebuffer (not a user-created render/framebuffer).
289 * Once this function is called, you can basically forget about this
290 * renderbuffer; core Mesa will handle all the buffer management and
294 add_depth_renderbuffer(struct gl_context
*ctx
, struct gl_framebuffer
*fb
,
297 struct gl_renderbuffer
*rb
;
299 if (depthBits
> 32) {
301 "Unsupported depthBits in add_depth_renderbuffer");
305 assert(fb
->Attachment
[BUFFER_DEPTH
].Renderbuffer
== NULL
);
307 rb
= _swrast_new_soft_renderbuffer(ctx
, 0);
309 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "Allocating depth buffer");
313 if (depthBits
<= 16) {
314 rb
->InternalFormat
= GL_DEPTH_COMPONENT16
;
316 else if (depthBits
<= 24) {
317 rb
->InternalFormat
= GL_DEPTH_COMPONENT24
;
320 rb
->InternalFormat
= GL_DEPTH_COMPONENT32
;
323 rb
->AllocStorage
= soft_renderbuffer_storage
;
324 _mesa_attach_and_own_rb(fb
, BUFFER_DEPTH
, rb
);
331 * Add a software-based stencil renderbuffer to the given framebuffer.
332 * This is a helper routine for device drivers when creating a
333 * window system framebuffer (not a user-created render/framebuffer).
334 * Once this function is called, you can basically forget about this
335 * renderbuffer; core Mesa will handle all the buffer management and
339 add_stencil_renderbuffer(struct gl_context
*ctx
, struct gl_framebuffer
*fb
,
342 struct gl_renderbuffer
*rb
;
344 if (stencilBits
> 16) {
346 "Unsupported stencilBits in add_stencil_renderbuffer");
350 assert(fb
->Attachment
[BUFFER_STENCIL
].Renderbuffer
== NULL
);
352 rb
= _swrast_new_soft_renderbuffer(ctx
, 0);
354 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "Allocating stencil buffer");
358 assert(stencilBits
<= 8);
359 rb
->InternalFormat
= GL_STENCIL_INDEX8
;
361 rb
->AllocStorage
= soft_renderbuffer_storage
;
362 _mesa_attach_and_own_rb(fb
, BUFFER_STENCIL
, rb
);
369 add_depth_stencil_renderbuffer(struct gl_context
*ctx
,
370 struct gl_framebuffer
*fb
)
372 struct gl_renderbuffer
*rb
;
374 assert(fb
->Attachment
[BUFFER_DEPTH
].Renderbuffer
== NULL
);
375 assert(fb
->Attachment
[BUFFER_STENCIL
].Renderbuffer
== NULL
);
377 rb
= _swrast_new_soft_renderbuffer(ctx
, 0);
379 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "Allocating depth+stencil buffer");
383 rb
->InternalFormat
= GL_DEPTH_STENCIL
;
385 rb
->AllocStorage
= soft_renderbuffer_storage
;
386 _mesa_attach_and_own_rb(fb
, BUFFER_DEPTH
, rb
);
387 _mesa_attach_and_reference_rb(fb
, BUFFER_STENCIL
, rb
);
394 * Add a software-based accumulation renderbuffer to the given framebuffer.
395 * This is a helper routine for device drivers when creating a
396 * window system framebuffer (not a user-created render/framebuffer).
397 * Once this function is called, you can basically forget about this
398 * renderbuffer; core Mesa will handle all the buffer management and
402 add_accum_renderbuffer(struct gl_context
*ctx
, struct gl_framebuffer
*fb
,
403 GLuint redBits
, GLuint greenBits
,
404 GLuint blueBits
, GLuint alphaBits
)
406 struct gl_renderbuffer
*rb
;
408 if (redBits
> 16 || greenBits
> 16 || blueBits
> 16 || alphaBits
> 16) {
410 "Unsupported accumBits in add_accum_renderbuffer");
414 assert(fb
->Attachment
[BUFFER_ACCUM
].Renderbuffer
== NULL
);
416 rb
= _swrast_new_soft_renderbuffer(ctx
, 0);
418 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "Allocating accum buffer");
422 rb
->InternalFormat
= GL_RGBA16_SNORM
;
423 rb
->AllocStorage
= soft_renderbuffer_storage
;
424 _mesa_attach_and_own_rb(fb
, BUFFER_ACCUM
, rb
);
432 * Add a software-based aux renderbuffer to the given framebuffer.
433 * This is a helper routine for device drivers when creating a
434 * window system framebuffer (not a user-created render/framebuffer).
435 * Once this function is called, you can basically forget about this
436 * renderbuffer; core Mesa will handle all the buffer management and
439 * NOTE: color-index aux buffers not supported.
442 add_aux_renderbuffers(struct gl_context
*ctx
, struct gl_framebuffer
*fb
,
443 GLuint colorBits
, GLuint numBuffers
)
447 if (colorBits
> 16) {
449 "Unsupported colorBits in add_aux_renderbuffers");
453 assert(numBuffers
<= MAX_AUX_BUFFERS
);
455 for (i
= 0; i
< numBuffers
; i
++) {
456 struct gl_renderbuffer
*rb
= _swrast_new_soft_renderbuffer(ctx
, 0);
458 assert(fb
->Attachment
[BUFFER_AUX0
+ i
].Renderbuffer
== NULL
);
461 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "Allocating aux buffer");
465 assert (colorBits
<= 8);
466 rb
->InternalFormat
= GL_RGBA
;
468 rb
->AllocStorage
= soft_renderbuffer_storage
;
469 _mesa_attach_and_own_rb(fb
, BUFFER_AUX0
+ i
, rb
);
476 * Create/attach software-based renderbuffers to the given framebuffer.
477 * This is a helper routine for device drivers. Drivers can just as well
478 * call the individual _mesa_add_*_renderbuffer() routines directly.
481 _swrast_add_soft_renderbuffers(struct gl_framebuffer
*fb
,
489 GLboolean frontLeft
= GL_TRUE
;
490 GLboolean backLeft
= fb
->Visual
.doubleBufferMode
;
491 GLboolean frontRight
= fb
->Visual
.stereoMode
;
492 GLboolean backRight
= fb
->Visual
.stereoMode
&& fb
->Visual
.doubleBufferMode
;
495 assert(fb
->Visual
.redBits
== fb
->Visual
.greenBits
);
496 assert(fb
->Visual
.redBits
== fb
->Visual
.blueBits
);
497 add_color_renderbuffers(NULL
, fb
,
499 fb
->Visual
.alphaBits
,
501 frontRight
, backRight
);
505 /* This is pretty much for debugging purposes only since there's a perf
506 * hit for using combined depth/stencil in swrast.
508 if (depth
&& fb
->Visual
.depthBits
== 24 &&
509 stencil
&& fb
->Visual
.stencilBits
== 8) {
510 /* use combined depth/stencil buffer */
511 add_depth_stencil_renderbuffer(NULL
, fb
);
515 (void) add_depth_stencil_renderbuffer
;
519 assert(fb
->Visual
.depthBits
> 0);
520 add_depth_renderbuffer(NULL
, fb
, fb
->Visual
.depthBits
);
524 assert(fb
->Visual
.stencilBits
> 0);
525 add_stencil_renderbuffer(NULL
, fb
, fb
->Visual
.stencilBits
);
530 assert(fb
->Visual
.accumRedBits
> 0);
531 assert(fb
->Visual
.accumGreenBits
> 0);
532 assert(fb
->Visual
.accumBlueBits
> 0);
533 add_accum_renderbuffer(NULL
, fb
,
534 fb
->Visual
.accumRedBits
,
535 fb
->Visual
.accumGreenBits
,
536 fb
->Visual
.accumBlueBits
,
537 fb
->Visual
.accumAlphaBits
);
541 assert(fb
->Visual
.numAuxBuffers
> 0);
542 add_aux_renderbuffers(NULL
, fb
, fb
->Visual
.redBits
,
543 fb
->Visual
.numAuxBuffers
);
556 map_attachment(struct gl_context
*ctx
,
557 struct gl_framebuffer
*fb
,
558 gl_buffer_index buffer
)
560 struct gl_texture_object
*texObj
= fb
->Attachment
[buffer
].Texture
;
561 struct gl_renderbuffer
*rb
= fb
->Attachment
[buffer
].Renderbuffer
;
562 struct swrast_renderbuffer
*srb
= swrast_renderbuffer(rb
);
565 /* map texture image (render to texture) */
566 const GLuint level
= fb
->Attachment
[buffer
].TextureLevel
;
567 const GLuint face
= fb
->Attachment
[buffer
].CubeMapFace
;
568 const GLuint slice
= fb
->Attachment
[buffer
].Zoffset
;
569 struct gl_texture_image
*texImage
= texObj
->Image
[face
][level
];
571 ctx
->Driver
.MapTextureImage(ctx
, texImage
, slice
,
572 0, 0, texImage
->Width
, texImage
->Height
,
573 GL_MAP_READ_BIT
| GL_MAP_WRITE_BIT
,
574 &srb
->Map
, &srb
->RowStride
);
578 /* Map ordinary renderbuffer */
579 ctx
->Driver
.MapRenderbuffer(ctx
, rb
,
580 0, 0, rb
->Width
, rb
->Height
,
581 GL_MAP_READ_BIT
| GL_MAP_WRITE_BIT
,
582 &srb
->Map
, &srb
->RowStride
,
591 unmap_attachment(struct gl_context
*ctx
,
592 struct gl_framebuffer
*fb
,
593 gl_buffer_index buffer
)
595 struct gl_texture_object
*texObj
= fb
->Attachment
[buffer
].Texture
;
596 struct gl_renderbuffer
*rb
= fb
->Attachment
[buffer
].Renderbuffer
;
597 struct swrast_renderbuffer
*srb
= swrast_renderbuffer(rb
);
600 /* unmap texture image (render to texture) */
601 const GLuint level
= fb
->Attachment
[buffer
].TextureLevel
;
602 const GLuint face
= fb
->Attachment
[buffer
].CubeMapFace
;
603 const GLuint slice
= fb
->Attachment
[buffer
].Zoffset
;
604 struct gl_texture_image
*texImage
= texObj
->Image
[face
][level
];
606 ctx
->Driver
.UnmapTextureImage(ctx
, texImage
, slice
);
610 /* unmap ordinary renderbuffer */
611 ctx
->Driver
.UnmapRenderbuffer(ctx
, rb
);
619 * Determine what type to use (ubyte vs. float) for span colors for the
620 * given renderbuffer.
621 * See also _swrast_write_rgba_span().
624 find_renderbuffer_colortype(struct gl_renderbuffer
*rb
)
626 struct swrast_renderbuffer
*srb
= swrast_renderbuffer(rb
);
627 GLuint rbMaxBits
= _mesa_get_format_max_bits(rb
->Format
);
628 GLenum rbDatatype
= _mesa_get_format_datatype(rb
->Format
);
630 if (rbDatatype
== GL_UNSIGNED_NORMALIZED
&& rbMaxBits
<= 8) {
631 /* the buffer's values fit in GLubyte values */
632 srb
->ColorType
= GL_UNSIGNED_BYTE
;
635 /* use floats otherwise */
636 srb
->ColorType
= GL_FLOAT
;
642 * Map the renderbuffers we'll use for tri/line/point rendering.
645 _swrast_map_renderbuffers(struct gl_context
*ctx
)
647 struct gl_framebuffer
*fb
= ctx
->DrawBuffer
;
648 struct gl_renderbuffer
*depthRb
, *stencilRb
;
651 depthRb
= fb
->Attachment
[BUFFER_DEPTH
].Renderbuffer
;
653 /* map depth buffer */
654 map_attachment(ctx
, fb
, BUFFER_DEPTH
);
657 stencilRb
= fb
->Attachment
[BUFFER_STENCIL
].Renderbuffer
;
658 if (stencilRb
&& stencilRb
!= depthRb
) {
659 /* map stencil buffer */
660 map_attachment(ctx
, fb
, BUFFER_STENCIL
);
663 for (buf
= 0; buf
< fb
->_NumColorDrawBuffers
; buf
++) {
664 if (fb
->_ColorDrawBufferIndexes
[buf
] != BUFFER_NONE
) {
665 map_attachment(ctx
, fb
, fb
->_ColorDrawBufferIndexes
[buf
]);
666 find_renderbuffer_colortype(fb
->_ColorDrawBuffers
[buf
]);
673 * Unmap renderbuffers after rendering.
676 _swrast_unmap_renderbuffers(struct gl_context
*ctx
)
678 struct gl_framebuffer
*fb
= ctx
->DrawBuffer
;
679 struct gl_renderbuffer
*depthRb
, *stencilRb
;
682 depthRb
= fb
->Attachment
[BUFFER_DEPTH
].Renderbuffer
;
684 /* map depth buffer */
685 unmap_attachment(ctx
, fb
, BUFFER_DEPTH
);
688 stencilRb
= fb
->Attachment
[BUFFER_STENCIL
].Renderbuffer
;
689 if (stencilRb
&& stencilRb
!= depthRb
) {
690 /* map stencil buffer */
691 unmap_attachment(ctx
, fb
, BUFFER_STENCIL
);
694 for (buf
= 0; buf
< fb
->_NumColorDrawBuffers
; buf
++) {
695 if (fb
->_ColorDrawBufferIndexes
[buf
] != BUFFER_NONE
) {
696 unmap_attachment(ctx
, fb
, fb
->_ColorDrawBufferIndexes
[buf
]);