s_renderbuffer.c revision 6c1e27ba219e41ae2641cca0d3c67462bdba8631
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_context.h" 41#include "swrast/s_renderbuffer.h" 42 43 44/** 45 * This is a software fallback for the gl_renderbuffer->AllocStorage 46 * function. 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. 51 * 52 * This one multi-purpose function can allocate stencil, depth, accum, color 53 * or color-index buffers! 54 */ 55static GLboolean 56soft_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb, 57 GLenum internalFormat, 58 GLuint width, GLuint height) 59{ 60 struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); 61 GLuint bpp; 62 63 switch (internalFormat) { 64 case GL_RGB: 65 case GL_R3_G3_B2: 66 case GL_RGB4: 67 case GL_RGB5: 68 case GL_RGB8: 69 case GL_RGB10: 70 case GL_RGB12: 71 case GL_RGB16: 72 rb->Format = MESA_FORMAT_RGB888; 73 break; 74 case GL_RGBA: 75 case GL_RGBA2: 76 case GL_RGBA4: 77 case GL_RGB5_A1: 78 case GL_RGBA8: 79#if 1 80 case GL_RGB10_A2: 81 case GL_RGBA12: 82#endif 83 if (_mesa_little_endian()) 84 rb->Format = MESA_FORMAT_RGBA8888_REV; 85 else 86 rb->Format = MESA_FORMAT_RGBA8888; 87 break; 88 case GL_RGBA16: 89 case GL_RGBA16_SNORM: 90 /* for accum buffer */ 91 rb->Format = MESA_FORMAT_SIGNED_RGBA_16; 92 break; 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_S8; 99 break; 100 case GL_DEPTH_COMPONENT: 101 case GL_DEPTH_COMPONENT16: 102 rb->Format = MESA_FORMAT_Z16; 103 break; 104 case GL_DEPTH_COMPONENT24: 105 rb->Format = MESA_FORMAT_X8_Z24; 106 break; 107 case GL_DEPTH_COMPONENT32: 108 rb->Format = MESA_FORMAT_Z32; 109 break; 110 case GL_DEPTH_STENCIL_EXT: 111 case GL_DEPTH24_STENCIL8_EXT: 112 rb->Format = MESA_FORMAT_Z24_S8; 113 break; 114 default: 115 /* unsupported format */ 116 return GL_FALSE; 117 } 118 119 bpp = _mesa_get_format_bytes(rb->Format); 120 121 /* free old buffer storage */ 122 if (srb->Buffer) { 123 free(srb->Buffer); 124 srb->Buffer = NULL; 125 } 126 127 srb->RowStride = width * bpp; 128 129 if (width > 0 && height > 0) { 130 /* allocate new buffer storage */ 131 srb->Buffer = malloc(srb->RowStride * height); 132 133 if (srb->Buffer == NULL) { 134 rb->Width = 0; 135 rb->Height = 0; 136 _mesa_error(ctx, GL_OUT_OF_MEMORY, 137 "software renderbuffer allocation (%d x %d x %d)", 138 width, height, bpp); 139 return GL_FALSE; 140 } 141 } 142 143 rb->Width = width; 144 rb->Height = height; 145 rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat); 146 147 if (rb->Name == 0 && 148 internalFormat == GL_RGBA16_SNORM && 149 rb->_BaseFormat == 0) { 150 /* NOTE: This is a special case just for accumulation buffers. 151 * This is a very limited use case- there's no snorm texturing or 152 * rendering going on. 153 */ 154 rb->_BaseFormat = GL_RGBA; 155 } 156 else { 157 /* the internalFormat should have been error checked long ago */ 158 ASSERT(rb->_BaseFormat); 159 } 160 161 return GL_TRUE; 162} 163 164 165/** 166 * Called via gl_renderbuffer::Delete() 167 */ 168static void 169soft_renderbuffer_delete(struct gl_renderbuffer *rb) 170{ 171 struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); 172 173 if (srb->Buffer) { 174 free(srb->Buffer); 175 srb->Buffer = NULL; 176 } 177 free(srb); 178} 179 180 181void 182_swrast_map_soft_renderbuffer(struct gl_context *ctx, 183 struct gl_renderbuffer *rb, 184 GLuint x, GLuint y, GLuint w, GLuint h, 185 GLbitfield mode, 186 GLubyte **out_map, 187 GLint *out_stride) 188{ 189 struct swrast_renderbuffer *srb = swrast_renderbuffer(rb); 190 GLubyte *map = srb->Buffer; 191 int cpp = _mesa_get_format_bytes(rb->Format); 192 int stride = rb->Width * cpp; 193 194 if (!map) { 195 *out_map = NULL; 196 *out_stride = 0; 197 } 198 199 map += y * stride; 200 map += x * cpp; 201 202 *out_map = map; 203 *out_stride = stride; 204} 205 206 207void 208_swrast_unmap_soft_renderbuffer(struct gl_context *ctx, 209 struct gl_renderbuffer *rb) 210{ 211} 212 213 214 215/** 216 * Allocate a software-based renderbuffer. This is called via the 217 * ctx->Driver.NewRenderbuffer() function when the user creates a new 218 * renderbuffer. 219 * This would not be used for hardware-based renderbuffers. 220 */ 221struct gl_renderbuffer * 222_swrast_new_soft_renderbuffer(struct gl_context *ctx, GLuint name) 223{ 224 struct swrast_renderbuffer *srb = CALLOC_STRUCT(swrast_renderbuffer); 225 if (srb) { 226 _mesa_init_renderbuffer(&srb->Base, name); 227 srb->Base.AllocStorage = soft_renderbuffer_storage; 228 srb->Base.Delete = soft_renderbuffer_delete; 229 } 230 return &srb->Base; 231} 232 233 234/** 235 * Add software-based color renderbuffers to the given framebuffer. 236 * This is a helper routine for device drivers when creating a 237 * window system framebuffer (not a user-created render/framebuffer). 238 * Once this function is called, you can basically forget about this 239 * renderbuffer; core Mesa will handle all the buffer management and 240 * rendering! 241 */ 242static GLboolean 243add_color_renderbuffers(struct gl_context *ctx, struct gl_framebuffer *fb, 244 GLuint rgbBits, GLuint alphaBits, 245 GLboolean frontLeft, GLboolean backLeft, 246 GLboolean frontRight, GLboolean backRight) 247{ 248 gl_buffer_index b; 249 250 if (rgbBits > 16 || alphaBits > 16) { 251 _mesa_problem(ctx, 252 "Unsupported bit depth in add_color_renderbuffers"); 253 return GL_FALSE; 254 } 255 256 assert(MAX_COLOR_ATTACHMENTS >= 4); 257 258 for (b = BUFFER_FRONT_LEFT; b <= BUFFER_BACK_RIGHT; b++) { 259 struct gl_renderbuffer *rb; 260 261 if (b == BUFFER_FRONT_LEFT && !frontLeft) 262 continue; 263 else if (b == BUFFER_BACK_LEFT && !backLeft) 264 continue; 265 else if (b == BUFFER_FRONT_RIGHT && !frontRight) 266 continue; 267 else if (b == BUFFER_BACK_RIGHT && !backRight) 268 continue; 269 270 assert(fb->Attachment[b].Renderbuffer == NULL); 271 272 rb = ctx->Driver.NewRenderbuffer(ctx, 0); 273 if (!rb) { 274 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating color buffer"); 275 return GL_FALSE; 276 } 277 278 rb->InternalFormat = GL_RGBA; 279 280 rb->AllocStorage = soft_renderbuffer_storage; 281 _mesa_add_renderbuffer(fb, b, rb); 282 } 283 284 return GL_TRUE; 285} 286 287 288/** 289 * Add a software-based depth renderbuffer to the given framebuffer. 290 * This is a helper routine for device drivers when creating a 291 * window system framebuffer (not a user-created render/framebuffer). 292 * Once this function is called, you can basically forget about this 293 * renderbuffer; core Mesa will handle all the buffer management and 294 * rendering! 295 */ 296static GLboolean 297add_depth_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, 298 GLuint depthBits) 299{ 300 struct gl_renderbuffer *rb; 301 302 if (depthBits > 32) { 303 _mesa_problem(ctx, 304 "Unsupported depthBits in add_depth_renderbuffer"); 305 return GL_FALSE; 306 } 307 308 assert(fb->Attachment[BUFFER_DEPTH].Renderbuffer == NULL); 309 310 rb = _swrast_new_soft_renderbuffer(ctx, 0); 311 if (!rb) { 312 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating depth buffer"); 313 return GL_FALSE; 314 } 315 316 if (depthBits <= 16) { 317 rb->InternalFormat = GL_DEPTH_COMPONENT16; 318 } 319 else if (depthBits <= 24) { 320 rb->InternalFormat = GL_DEPTH_COMPONENT24; 321 } 322 else { 323 rb->InternalFormat = GL_DEPTH_COMPONENT32; 324 } 325 326 rb->AllocStorage = soft_renderbuffer_storage; 327 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb); 328 329 return GL_TRUE; 330} 331 332 333/** 334 * Add a software-based stencil renderbuffer to the given framebuffer. 335 * This is a helper routine for device drivers when creating a 336 * window system framebuffer (not a user-created render/framebuffer). 337 * Once this function is called, you can basically forget about this 338 * renderbuffer; core Mesa will handle all the buffer management and 339 * rendering! 340 */ 341static GLboolean 342add_stencil_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, 343 GLuint stencilBits) 344{ 345 struct gl_renderbuffer *rb; 346 347 if (stencilBits > 16) { 348 _mesa_problem(ctx, 349 "Unsupported stencilBits in add_stencil_renderbuffer"); 350 return GL_FALSE; 351 } 352 353 assert(fb->Attachment[BUFFER_STENCIL].Renderbuffer == NULL); 354 355 rb = _swrast_new_soft_renderbuffer(ctx, 0); 356 if (!rb) { 357 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating stencil buffer"); 358 return GL_FALSE; 359 } 360 361 assert(stencilBits <= 8); 362 rb->InternalFormat = GL_STENCIL_INDEX8; 363 364 rb->AllocStorage = soft_renderbuffer_storage; 365 _mesa_add_renderbuffer(fb, BUFFER_STENCIL, rb); 366 367 return GL_TRUE; 368} 369 370 371static GLboolean 372add_depth_stencil_renderbuffer(struct gl_context *ctx, 373 struct gl_framebuffer *fb) 374{ 375 struct gl_renderbuffer *rb; 376 377 assert(fb->Attachment[BUFFER_DEPTH].Renderbuffer == NULL); 378 assert(fb->Attachment[BUFFER_STENCIL].Renderbuffer == NULL); 379 380 rb = _swrast_new_soft_renderbuffer(ctx, 0); 381 if (!rb) { 382 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating depth+stencil buffer"); 383 return GL_FALSE; 384 } 385 386 rb->InternalFormat = GL_DEPTH_STENCIL; 387 388 rb->AllocStorage = soft_renderbuffer_storage; 389 _mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb); 390 _mesa_add_renderbuffer(fb, BUFFER_STENCIL, rb); 391 392 return GL_TRUE; 393} 394 395 396/** 397 * Add a software-based accumulation renderbuffer to the given framebuffer. 398 * This is a helper routine for device drivers when creating a 399 * window system framebuffer (not a user-created render/framebuffer). 400 * Once this function is called, you can basically forget about this 401 * renderbuffer; core Mesa will handle all the buffer management and 402 * rendering! 403 */ 404static GLboolean 405add_accum_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb, 406 GLuint redBits, GLuint greenBits, 407 GLuint blueBits, GLuint alphaBits) 408{ 409 struct gl_renderbuffer *rb; 410 411 if (redBits > 16 || greenBits > 16 || blueBits > 16 || alphaBits > 16) { 412 _mesa_problem(ctx, 413 "Unsupported accumBits in add_accum_renderbuffer"); 414 return GL_FALSE; 415 } 416 417 assert(fb->Attachment[BUFFER_ACCUM].Renderbuffer == NULL); 418 419 rb = _swrast_new_soft_renderbuffer(ctx, 0); 420 if (!rb) { 421 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating accum buffer"); 422 return GL_FALSE; 423 } 424 425 rb->InternalFormat = GL_RGBA16_SNORM; 426 rb->AllocStorage = soft_renderbuffer_storage; 427 _mesa_add_renderbuffer(fb, BUFFER_ACCUM, rb); 428 429 return GL_TRUE; 430} 431 432 433 434/** 435 * Add a software-based aux renderbuffer to the given framebuffer. 436 * This is a helper routine for device drivers when creating a 437 * window system framebuffer (not a user-created render/framebuffer). 438 * Once this function is called, you can basically forget about this 439 * renderbuffer; core Mesa will handle all the buffer management and 440 * rendering! 441 * 442 * NOTE: color-index aux buffers not supported. 443 */ 444static GLboolean 445add_aux_renderbuffers(struct gl_context *ctx, struct gl_framebuffer *fb, 446 GLuint colorBits, GLuint numBuffers) 447{ 448 GLuint i; 449 450 if (colorBits > 16) { 451 _mesa_problem(ctx, 452 "Unsupported colorBits in add_aux_renderbuffers"); 453 return GL_FALSE; 454 } 455 456 assert(numBuffers <= MAX_AUX_BUFFERS); 457 458 for (i = 0; i < numBuffers; i++) { 459 struct gl_renderbuffer *rb = _swrast_new_soft_renderbuffer(ctx, 0); 460 461 assert(fb->Attachment[BUFFER_AUX0 + i].Renderbuffer == NULL); 462 463 if (!rb) { 464 _mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating aux buffer"); 465 return GL_FALSE; 466 } 467 468 assert (colorBits <= 8); 469 rb->InternalFormat = GL_RGBA; 470 471 rb->AllocStorage = soft_renderbuffer_storage; 472 _mesa_add_renderbuffer(fb, BUFFER_AUX0 + i, rb); 473 } 474 return GL_TRUE; 475} 476 477 478/** 479 * Create/attach software-based renderbuffers to the given framebuffer. 480 * This is a helper routine for device drivers. Drivers can just as well 481 * call the individual _mesa_add_*_renderbuffer() routines directly. 482 */ 483void 484_swrast_add_soft_renderbuffers(struct gl_framebuffer *fb, 485 GLboolean color, 486 GLboolean depth, 487 GLboolean stencil, 488 GLboolean accum, 489 GLboolean alpha, 490 GLboolean aux) 491{ 492 GLboolean frontLeft = GL_TRUE; 493 GLboolean backLeft = fb->Visual.doubleBufferMode; 494 GLboolean frontRight = fb->Visual.stereoMode; 495 GLboolean backRight = fb->Visual.stereoMode && fb->Visual.doubleBufferMode; 496 497 if (color) { 498 assert(fb->Visual.redBits == fb->Visual.greenBits); 499 assert(fb->Visual.redBits == fb->Visual.blueBits); 500 add_color_renderbuffers(NULL, fb, 501 fb->Visual.redBits, 502 fb->Visual.alphaBits, 503 frontLeft, backLeft, 504 frontRight, backRight); 505 } 506 507#if 0 508 /* This is pretty much for debugging purposes only since there's a perf 509 * hit for using combined depth/stencil in swrast. 510 */ 511 if (depth && fb->Visual.depthBits == 24 && 512 stencil && fb->Visual.stencilBits == 8) { 513 /* use combined depth/stencil buffer */ 514 add_depth_stencil_renderbuffer(NULL, fb); 515 } 516 else 517#else 518 (void) add_depth_stencil_renderbuffer; 519#endif 520 { 521 if (depth) { 522 assert(fb->Visual.depthBits > 0); 523 add_depth_renderbuffer(NULL, fb, fb->Visual.depthBits); 524 } 525 526 if (stencil) { 527 assert(fb->Visual.stencilBits > 0); 528 add_stencil_renderbuffer(NULL, fb, fb->Visual.stencilBits); 529 } 530 } 531 532 if (accum) { 533 assert(fb->Visual.accumRedBits > 0); 534 assert(fb->Visual.accumGreenBits > 0); 535 assert(fb->Visual.accumBlueBits > 0); 536 add_accum_renderbuffer(NULL, fb, 537 fb->Visual.accumRedBits, 538 fb->Visual.accumGreenBits, 539 fb->Visual.accumBlueBits, 540 fb->Visual.accumAlphaBits); 541 } 542 543 if (aux) { 544 assert(fb->Visual.numAuxBuffers > 0); 545 add_aux_renderbuffers(NULL, fb, fb->Visual.redBits, 546 fb->Visual.numAuxBuffers); 547 } 548 549#if 0 550 if (multisample) { 551 /* maybe someday */ 552 } 553#endif 554} 555