1 /**************************************************************************
3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
32 #include "framebuffer.h"
33 #include "renderbuffer.h"
35 #include "texformat.h"
36 #include "texrender.h"
38 #include "intel_context.h"
39 #include "intel_buffers.h"
40 #include "intel_depthstencil.h"
41 #include "intel_fbo.h"
42 #include "intel_mipmap_tree.h"
43 #include "intel_regions.h"
44 #include "intel_span.h"
47 #define FILE_DEBUG_FLAG DEBUG_FBO
49 #define INTEL_RB_CLASS 0x12345678
52 /* XXX FBO: move this to intel_context.h (inlined) */
54 * Return a gl_renderbuffer ptr casted to intel_renderbuffer.
55 * NULL will be returned if the rb isn't really an intel_renderbuffer.
56 * This is determiend by checking the ClassID.
58 struct intel_renderbuffer
*
59 intel_renderbuffer(struct gl_renderbuffer
*rb
)
61 struct intel_renderbuffer
*irb
= (struct intel_renderbuffer
*) rb
;
62 if (irb
&& irb
->Base
.ClassID
== INTEL_RB_CLASS
) {
63 /*_mesa_warning(NULL, "Returning non-intel Rb\n");*/
71 struct intel_renderbuffer
*
72 intel_get_renderbuffer(struct gl_framebuffer
*fb
, GLuint attIndex
)
74 return intel_renderbuffer(fb
->Attachment
[attIndex
].Renderbuffer
);
79 intel_flip_renderbuffers(struct intel_framebuffer
*intel_fb
)
81 int current_page
= intel_fb
->pf_current_page
;
82 int next_page
= (current_page
+ 1) % intel_fb
->pf_num_pages
;
83 struct gl_renderbuffer
*tmp_rb
;
85 /* Exchange renderbuffers if necessary but make sure their reference counts
88 if (intel_fb
->color_rb
[current_page
] &&
89 intel_fb
->Base
.Attachment
[BUFFER_FRONT_LEFT
].Renderbuffer
!=
90 &intel_fb
->color_rb
[current_page
]->Base
) {
92 _mesa_reference_renderbuffer(&tmp_rb
,
93 intel_fb
->Base
.Attachment
[BUFFER_FRONT_LEFT
].Renderbuffer
);
94 tmp_rb
= &intel_fb
->color_rb
[current_page
]->Base
;
95 _mesa_reference_renderbuffer(
96 &intel_fb
->Base
.Attachment
[BUFFER_FRONT_LEFT
].Renderbuffer
, tmp_rb
);
97 _mesa_reference_renderbuffer(&tmp_rb
, NULL
);
100 if (intel_fb
->color_rb
[next_page
] &&
101 intel_fb
->Base
.Attachment
[BUFFER_BACK_LEFT
].Renderbuffer
!=
102 &intel_fb
->color_rb
[next_page
]->Base
) {
104 _mesa_reference_renderbuffer(&tmp_rb
,
105 intel_fb
->Base
.Attachment
[BUFFER_BACK_LEFT
].Renderbuffer
);
106 tmp_rb
= &intel_fb
->color_rb
[next_page
]->Base
;
107 _mesa_reference_renderbuffer(
108 &intel_fb
->Base
.Attachment
[BUFFER_BACK_LEFT
].Renderbuffer
, tmp_rb
);
109 _mesa_reference_renderbuffer(&tmp_rb
, NULL
);
114 struct intel_region
*
115 intel_get_rb_region(struct gl_framebuffer
*fb
, GLuint attIndex
)
117 struct intel_renderbuffer
*irb
= intel_get_renderbuffer(fb
, attIndex
);
128 * Create a new framebuffer object.
130 static struct gl_framebuffer
*
131 intel_new_framebuffer(GLcontext
* ctx
, GLuint name
)
133 /* Only drawable state in intel_framebuffer at this time, just use Mesa's
136 return _mesa_new_framebuffer(ctx
, name
);
141 intel_delete_renderbuffer(struct gl_renderbuffer
*rb
)
143 GET_CURRENT_CONTEXT(ctx
);
144 struct intel_context
*intel
= intel_context(ctx
);
145 struct intel_renderbuffer
*irb
= intel_renderbuffer(rb
);
149 if (irb
->PairedStencil
|| irb
->PairedDepth
) {
150 intel_unpair_depth_stencil(ctx
, irb
);
153 if (intel
&& irb
->region
) {
154 intel_region_release(&irb
->region
);
163 * Return a pointer to a specific pixel in a renderbuffer.
166 intel_get_pointer(GLcontext
* ctx
, struct gl_renderbuffer
*rb
,
169 /* By returning NULL we force all software rendering to go through
178 * Called via glRenderbufferStorageEXT() to set the format and allocate
179 * storage for a user-created (or priv buffer) renderbuffer.
182 intel_alloc_renderbuffer_storage(GLcontext
* ctx
, struct gl_renderbuffer
*rb
,
183 GLenum internalFormat
,
184 GLuint width
, GLuint height
)
186 struct intel_context
*intel
= intel_context(ctx
);
187 struct intel_renderbuffer
*irb
= intel_renderbuffer(rb
);
188 GLboolean softwareBuffer
= GL_FALSE
;
191 switch (internalFormat
) {
195 rb
->_ActualFormat
= GL_RGB5
;
196 rb
->DataType
= GL_UNSIGNED_BYTE
;
215 rb
->_ActualFormat
= GL_RGBA8
;
216 rb
->DataType
= GL_UNSIGNED_BYTE
;
223 case GL_STENCIL_INDEX
:
224 case GL_STENCIL_INDEX1_EXT
:
225 case GL_STENCIL_INDEX4_EXT
:
226 case GL_STENCIL_INDEX8_EXT
:
227 case GL_STENCIL_INDEX16_EXT
:
228 /* alloc a depth+stencil buffer */
229 rb
->_ActualFormat
= GL_DEPTH24_STENCIL8_EXT
;
230 rb
->DataType
= GL_UNSIGNED_INT_24_8_EXT
;
234 case GL_DEPTH_COMPONENT16
:
235 rb
->_ActualFormat
= GL_DEPTH_COMPONENT16
;
236 rb
->DataType
= GL_UNSIGNED_SHORT
;
240 case GL_DEPTH_COMPONENT
:
241 case GL_DEPTH_COMPONENT24
:
242 case GL_DEPTH_COMPONENT32
:
243 rb
->_ActualFormat
= GL_DEPTH24_STENCIL8_EXT
;
244 rb
->DataType
= GL_UNSIGNED_INT_24_8_EXT
;
248 case GL_DEPTH_STENCIL_EXT
:
249 case GL_DEPTH24_STENCIL8_EXT
:
250 rb
->_ActualFormat
= GL_DEPTH24_STENCIL8_EXT
;
251 rb
->DataType
= GL_UNSIGNED_INT_24_8_EXT
;
258 "Unexpected format (%x) in intel_alloc_renderbuffer_storage", internalFormat
);
264 /* free old region */
266 intel_region_release(&irb
->region
);
269 /* allocate new memory region/renderbuffer */
270 if (softwareBuffer
) {
271 return _mesa_soft_renderbuffer_storage(ctx
, rb
, internalFormat
,
275 /* Choose a pitch to match hardware requirements:
277 GLuint pitch
= ((cpp
* width
+ 63) & ~63) / cpp
;
279 /* alloc hardware renderbuffer */
280 DBG("Allocating %d x %d Intel RBO (pitch %d)\n", width
,
283 irb
->region
= intel_region_alloc(intel
->intelScreen
, cpp
, pitch
, height
);
285 return GL_FALSE
; /* out of memory? */
287 ASSERT(irb
->region
->buffer
);
293 /* update the surface's size too */
294 rb
->surface
->width
= width
;
295 rb
->surface
->height
= height
;
298 /* This sets the Get/PutRow/Value functions */
299 intel_set_span_functions(&irb
->Base
);
308 * Called for each hardware renderbuffer when a _window_ is resized.
309 * Just update fields.
310 * Not used for user-created renderbuffers!
313 intel_alloc_window_storage(GLcontext
* ctx
, struct gl_renderbuffer
*rb
,
314 GLenum internalFormat
, GLuint width
, GLuint height
)
316 ASSERT(rb
->Name
== 0);
319 rb
->_ActualFormat
= internalFormat
;
325 intel_resize_buffers(GLcontext
*ctx
, struct gl_framebuffer
*fb
,
326 GLuint width
, GLuint height
)
328 struct intel_framebuffer
*intel_fb
= (struct intel_framebuffer
*)fb
;
331 _mesa_resize_framebuffer(ctx
, fb
, width
, height
);
333 fb
->Initialized
= GL_TRUE
; /* XXX remove someday */
339 /* Make sure all window system renderbuffers are up to date */
340 for (i
= 0; i
< 3; i
++) {
341 struct gl_renderbuffer
*rb
= &intel_fb
->color_rb
[i
]->Base
;
343 /* only resize if size is changing */
344 if (rb
&& (rb
->Width
!= width
|| rb
->Height
!= height
)) {
345 rb
->AllocStorage(ctx
, rb
, rb
->InternalFormat
, width
, height
);
351 intel_nop_alloc_storage(GLcontext
* ctx
, struct gl_renderbuffer
*rb
,
352 GLenum internalFormat
, GLuint width
, GLuint height
)
354 _mesa_problem(ctx
, "intel_op_alloc_storage should never be called.");
361 * Create a new intel_renderbuffer which corresponds to an on-screen window,
362 * not a user-created renderbuffer.
363 * \param width the screen width
364 * \param height the screen height
366 struct intel_renderbuffer
*
367 intel_create_renderbuffer(GLenum intFormat
, GLsizei width
, GLsizei height
,
368 int offset
, int pitch
, int cpp
, void *map
)
370 GET_CURRENT_CONTEXT(ctx
);
372 struct intel_renderbuffer
*irb
;
373 const GLuint name
= 0;
375 irb
= CALLOC_STRUCT(intel_renderbuffer
);
377 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "creating renderbuffer");
381 _mesa_init_renderbuffer(&irb
->Base
, name
);
382 irb
->Base
.ClassID
= INTEL_RB_CLASS
;
386 irb
->Base
._ActualFormat
= GL_RGB5
;
387 irb
->Base
._BaseFormat
= GL_RGBA
;
388 irb
->Base
.RedBits
= 5;
389 irb
->Base
.GreenBits
= 6;
390 irb
->Base
.BlueBits
= 5;
391 irb
->Base
.DataType
= GL_UNSIGNED_BYTE
;
395 irb
->Base
._ActualFormat
= GL_RGBA8
;
396 irb
->Base
._BaseFormat
= GL_RGBA
;
397 irb
->Base
.RedBits
= 8;
398 irb
->Base
.GreenBits
= 8;
399 irb
->Base
.BlueBits
= 8;
400 irb
->Base
.AlphaBits
= 8;
401 irb
->Base
.DataType
= GL_UNSIGNED_BYTE
;
404 case GL_STENCIL_INDEX8_EXT
:
405 irb
->Base
._ActualFormat
= GL_STENCIL_INDEX8_EXT
;
406 irb
->Base
._BaseFormat
= GL_STENCIL_INDEX
;
407 irb
->Base
.StencilBits
= 8;
408 irb
->Base
.DataType
= GL_UNSIGNED_BYTE
;
411 case GL_DEPTH_COMPONENT16
:
412 irb
->Base
._ActualFormat
= GL_DEPTH_COMPONENT16
;
413 irb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
414 irb
->Base
.DepthBits
= 16;
415 irb
->Base
.DataType
= GL_UNSIGNED_SHORT
;
418 case GL_DEPTH_COMPONENT24
:
419 irb
->Base
._ActualFormat
= GL_DEPTH24_STENCIL8_EXT
;
420 irb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
421 irb
->Base
.DepthBits
= 24;
422 irb
->Base
.DataType
= GL_UNSIGNED_INT
;
425 case GL_DEPTH24_STENCIL8_EXT
:
426 irb
->Base
._ActualFormat
= GL_DEPTH24_STENCIL8_EXT
;
427 irb
->Base
._BaseFormat
= GL_DEPTH_STENCIL_EXT
;
428 irb
->Base
.DepthBits
= 24;
429 irb
->Base
.StencilBits
= 8;
430 irb
->Base
.DataType
= GL_UNSIGNED_INT_24_8_EXT
;
435 "Unexpected intFormat in intel_create_renderbuffer");
439 irb
->Base
.InternalFormat
= intFormat
;
441 /* intel-specific methods */
442 irb
->Base
.Delete
= intel_delete_renderbuffer
;
443 irb
->Base
.AllocStorage
= intel_alloc_window_storage
;
444 irb
->Base
.GetPointer
= intel_get_pointer
;
445 /* This sets the Get/PutRow/Value functions */
446 intel_set_span_functions(&irb
->Base
);
449 irb
->pfPitch
= pitch
/ cpp
; /* in pixels */
452 irb
->region
= intel_region_create_static(intel
,
454 offset
, map
, cpp
, width
, height
);
462 * Create a new renderbuffer which corresponds to an X window buffer
463 * (color, depth, stencil, etc) - not a user-created GL renderbuffer.
464 * The internal format is set at creation time and does not change.
466 struct gl_renderbuffer
*
467 intel_new_renderbuffer_fb(GLcontext
* ctx
, GLuint intFormat
)
469 struct intel_renderbuffer
*irb
;
471 irb
= CALLOC_STRUCT(intel_renderbuffer
);
473 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "creating renderbuffer");
477 _mesa_init_renderbuffer(&irb
->Base
, 0);
478 irb
->Base
.ClassID
= INTEL_RB_CLASS
;
479 irb
->Base
.InternalFormat
= intFormat
;
481 /* intel-specific methods */
482 irb
->Base
.Delete
= intel_delete_renderbuffer
;
483 irb
->Base
.AllocStorage
= intel_alloc_renderbuffer_storage
;
484 irb
->Base
.GetPointer
= intel_get_pointer
;
485 /* span routines set in alloc_storage function */
487 irb
->Base
.surface
= intel_new_surface(intFormat
);
488 irb
->Base
.surface
->rb
= irb
;
494 * Create a new renderbuffer object.
495 * Typically called via glBindRenderbufferEXT().
497 static struct gl_renderbuffer
*
498 intel_new_renderbuffer(GLcontext
* ctx
, GLuint name
)
500 /*struct intel_context *intel = intel_context(ctx); */
501 struct intel_renderbuffer
*irb
;
503 irb
= CALLOC_STRUCT(intel_renderbuffer
);
505 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "creating renderbuffer");
509 _mesa_init_renderbuffer(&irb
->Base
, name
);
510 irb
->Base
.ClassID
= INTEL_RB_CLASS
;
512 /* intel-specific methods */
513 irb
->Base
.Delete
= intel_delete_renderbuffer
;
514 irb
->Base
.AllocStorage
= intel_alloc_renderbuffer_storage
;
515 irb
->Base
.GetPointer
= intel_get_pointer
;
516 /* span routines set in alloc_storage function */
518 irb
->Base
.surface
= intel_new_surface(0 /*unknown format*/);
519 irb
->Base
.surface
->rb
= irb
;
526 * Called via glBindFramebufferEXT().
529 intel_bind_framebuffer(GLcontext
* ctx
, GLenum target
,
530 struct gl_framebuffer
*fb
, struct gl_framebuffer
*fbread
)
532 if (target
== GL_FRAMEBUFFER_EXT
|| target
== GL_DRAW_FRAMEBUFFER_EXT
) {
533 intel_draw_buffer(ctx
, fb
);
534 /* Integer depth range depends on depth buffer bits */
535 ctx
->Driver
.DepthRange(ctx
, ctx
->Viewport
.Near
, ctx
->Viewport
.Far
);
538 /* don't need to do anything if target == GL_READ_FRAMEBUFFER_EXT */
544 * Called via glFramebufferRenderbufferEXT().
547 intel_framebuffer_renderbuffer(GLcontext
* ctx
,
548 struct gl_framebuffer
*fb
,
549 GLenum attachment
, struct gl_renderbuffer
*rb
)
551 DBG("Intel FramebufferRenderbuffer %u %u\n", fb
->Name
, rb
? rb
->Name
: 0);
555 _mesa_framebuffer_renderbuffer(ctx
, fb
, attachment
, rb
);
556 intel_draw_buffer(ctx
, fb
);
561 * When glFramebufferTexture[123]D is called this function sets up the
562 * gl_renderbuffer wrapper around the texture image.
563 * This will have the region info needed for hardware rendering.
565 static struct intel_renderbuffer
*
566 intel_wrap_texture(GLcontext
* ctx
, struct gl_texture_image
*texImage
)
568 const GLuint name
= ~0; /* not significant, but distinct for debugging */
569 struct intel_renderbuffer
*irb
;
571 /* make an intel_renderbuffer to wrap the texture image */
572 irb
= CALLOC_STRUCT(intel_renderbuffer
);
574 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glFramebufferTexture");
578 _mesa_init_renderbuffer(&irb
->Base
, name
);
579 irb
->Base
.ClassID
= INTEL_RB_CLASS
;
581 if (texImage
->TexFormat
== &_mesa_texformat_argb8888
) {
582 irb
->Base
._ActualFormat
= GL_RGBA8
;
583 irb
->Base
._BaseFormat
= GL_RGBA
;
584 DBG("Render to RGBA8 texture OK\n");
586 else if (texImage
->TexFormat
== &_mesa_texformat_rgb565
) {
587 irb
->Base
._ActualFormat
= GL_RGB5
;
588 irb
->Base
._BaseFormat
= GL_RGB
;
589 DBG("Render to RGB5 texture OK\n");
591 else if (texImage
->TexFormat
== &_mesa_texformat_z16
) {
592 irb
->Base
._ActualFormat
= GL_DEPTH_COMPONENT16
;
593 irb
->Base
._BaseFormat
= GL_DEPTH_COMPONENT
;
594 DBG("Render to DEPTH16 texture OK\n");
597 DBG("Render to texture BAD FORMAT %d\n",
598 texImage
->TexFormat
->MesaFormat
);
603 irb
->Base
.InternalFormat
= irb
->Base
._ActualFormat
;
604 irb
->Base
.Width
= texImage
->Width
;
605 irb
->Base
.Height
= texImage
->Height
;
606 irb
->Base
.DataType
= GL_UNSIGNED_BYTE
; /* FBO XXX fix */
607 irb
->Base
.RedBits
= texImage
->TexFormat
->RedBits
;
608 irb
->Base
.GreenBits
= texImage
->TexFormat
->GreenBits
;
609 irb
->Base
.BlueBits
= texImage
->TexFormat
->BlueBits
;
610 irb
->Base
.AlphaBits
= texImage
->TexFormat
->AlphaBits
;
611 irb
->Base
.DepthBits
= texImage
->TexFormat
->DepthBits
;
613 irb
->Base
.Delete
= intel_delete_renderbuffer
;
614 irb
->Base
.AllocStorage
= intel_nop_alloc_storage
;
615 intel_set_span_functions(&irb
->Base
);
617 irb
->RenderToTexture
= GL_TRUE
;
624 * Called by glFramebufferTexture[123]DEXT() (and other places) to
625 * prepare for rendering into texture memory. This might be called
626 * many times to choose different texture levels, cube faces, etc
627 * before intel_finish_render_texture() is ever called.
630 intel_render_texture(GLcontext
* ctx
,
631 struct gl_framebuffer
*fb
,
632 struct gl_renderbuffer_attachment
*att
)
634 struct gl_texture_image
*newImage
635 = att
->Texture
->Image
[att
->CubeMapFace
][att
->TextureLevel
];
636 struct intel_renderbuffer
*irb
= intel_renderbuffer(att
->Renderbuffer
);
637 struct intel_texture_image
*intel_image
;
645 irb
= intel_wrap_texture(ctx
, newImage
);
647 /* bind the wrapper to the attachment point */
648 _mesa_reference_renderbuffer(&att
->Renderbuffer
, &irb
->Base
);
651 /* fallback to software rendering */
652 _mesa_render_texture(ctx
, fb
, att
);
657 DBG("Begin render texture tid %x tex=%u w=%d h=%d refcount=%d\n",
659 att
->Texture
->Name
, newImage
->Width
, newImage
->Height
,
662 /* point the renderbufer's region to the texture image region */
663 intel_image
= intel_texture_image(newImage
);
664 if (irb
->region
!= intel_image
->mt
->region
) {
666 intel_region_release(&irb
->region
);
667 intel_region_reference(&irb
->region
, intel_image
->mt
->region
);
670 /* compute offset of the particular 2D image within the texture region */
671 imageOffset
= intel_miptree_image_offset(intel_image
->mt
,
675 if (att
->Texture
->Target
== GL_TEXTURE_3D
) {
676 const GLuint
*offsets
= intel_miptree_depth_offsets(intel_image
->mt
,
678 imageOffset
+= offsets
[att
->Zoffset
];
681 /* store that offset in the region */
682 intel_image
->mt
->region
->draw_offset
= imageOffset
;
684 /* update drawing region, etc */
685 intel_draw_buffer(ctx
, fb
);
690 * Called by Mesa when rendering to a texture is done.
693 intel_finish_render_texture(GLcontext
* ctx
,
694 struct gl_renderbuffer_attachment
*att
)
696 struct intel_renderbuffer
*irb
= intel_renderbuffer(att
->Renderbuffer
);
698 DBG("End render texture (tid %x) tex %u\n", _glthread_GetID(), att
->Texture
->Name
);
701 /* just release the region */
702 intel_region_release(&irb
->region
);
704 else if (att
->Renderbuffer
) {
705 /* software fallback */
706 _mesa_finish_render_texture(ctx
, att
);
707 /* XXX FBO: Need to unmap the buffer (or in intelSpanRenderStart???) */
713 * Do one-time context initializations related to GL_EXT_framebuffer_object.
714 * Hook in device driver functions.
717 intel_fbo_init(struct intel_context
*intel
)
719 intel
->ctx
.Driver
.NewFramebuffer
= intel_new_framebuffer
;
720 intel
->ctx
.Driver
.NewRenderbuffer
= intel_new_renderbuffer
;
721 intel
->ctx
.Driver
.BindFramebuffer
= intel_bind_framebuffer
;
722 intel
->ctx
.Driver
.FramebufferRenderbuffer
= intel_framebuffer_renderbuffer
;
723 intel
->ctx
.Driver
.RenderTexture
= intel_render_texture
;
724 intel
->ctx
.Driver
.FinishRenderTexture
= intel_finish_render_texture
;
725 intel
->ctx
.Driver
.ResizeBuffers
= intel_resize_buffers
;