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 **************************************************************************/
29 #include "main/imports.h"
30 #include "main/macros.h"
31 #include "main/mfeatures.h"
32 #include "main/mtypes.h"
33 #include "main/fbobject.h"
34 #include "main/framebuffer.h"
35 #include "main/renderbuffer.h"
36 #include "main/context.h"
37 #include "main/texrender.h"
38 #include "drivers/common/meta.h"
40 #include "intel_context.h"
41 #include "intel_batchbuffer.h"
42 #include "intel_buffers.h"
43 #include "intel_fbo.h"
44 #include "intel_mipmap_tree.h"
45 #include "intel_regions.h"
46 #include "intel_tex.h"
47 #include "intel_span.h"
49 #include "brw_context.h"
52 #define FILE_DEBUG_FLAG DEBUG_FBO
56 * Create a new framebuffer object.
58 static struct gl_framebuffer
*
59 intel_new_framebuffer(struct gl_context
* ctx
, GLuint name
)
61 /* Only drawable state in intel_framebuffer at this time, just use Mesa's
64 return _mesa_new_framebuffer(ctx
, name
);
68 /** Called by gl_renderbuffer::Delete() */
70 intel_delete_renderbuffer(struct gl_renderbuffer
*rb
)
72 GET_CURRENT_CONTEXT(ctx
);
73 struct intel_context
*intel
= intel_context(ctx
);
74 struct intel_renderbuffer
*irb
= intel_renderbuffer(rb
);
78 if (intel
&& irb
->region
) {
79 intel_region_release(&irb
->region
);
87 * Return a pointer to a specific pixel in a renderbuffer.
90 intel_get_pointer(struct gl_context
* ctx
, struct gl_renderbuffer
*rb
,
93 /* By returning NULL we force all software rendering to go through
101 * Called via glRenderbufferStorageEXT() to set the format and allocate
102 * storage for a user-created renderbuffer.
105 intel_alloc_renderbuffer_storage(struct gl_context
* ctx
, struct gl_renderbuffer
*rb
,
106 GLenum internalFormat
,
107 GLuint width
, GLuint height
)
109 struct intel_context
*intel
= intel_context(ctx
);
110 struct intel_renderbuffer
*irb
= intel_renderbuffer(rb
);
113 ASSERT(rb
->Name
!= 0);
115 switch (internalFormat
) {
117 /* Use the same format-choice logic as for textures.
118 * Renderbuffers aren't any different from textures for us,
119 * except they're less useful because you can't texture with
122 rb
->Format
= intel
->ctx
.Driver
.ChooseTextureFormat(ctx
, internalFormat
,
125 case GL_STENCIL_INDEX
:
126 case GL_STENCIL_INDEX1_EXT
:
127 case GL_STENCIL_INDEX4_EXT
:
128 case GL_STENCIL_INDEX8_EXT
:
129 case GL_STENCIL_INDEX16_EXT
:
130 /* These aren't actual texture formats, so force them here. */
131 rb
->Format
= MESA_FORMAT_S8_Z24
;
135 rb
->_BaseFormat
= _mesa_base_fbo_format(ctx
, internalFormat
);
136 rb
->DataType
= intel_mesa_format_to_rb_datatype(rb
->Format
);
137 cpp
= _mesa_get_format_bytes(rb
->Format
);
141 /* free old region */
143 intel_region_release(&irb
->region
);
146 /* allocate new memory region/renderbuffer */
148 /* alloc hardware renderbuffer */
149 DBG("Allocating %d x %d Intel RBO\n", width
, height
);
151 tiling
= I915_TILING_NONE
;
152 if (intel
->use_texture_tiling
) {
153 GLenum base_format
= _mesa_get_format_base_format(rb
->Format
);
155 if (intel
->gen
>= 4 && (base_format
== GL_DEPTH_COMPONENT
||
156 base_format
== GL_DEPTH_STENCIL
))
157 tiling
= I915_TILING_Y
;
159 tiling
= I915_TILING_X
;
162 irb
->region
= intel_region_alloc(intel
->intelScreen
, tiling
, cpp
,
163 width
, height
, GL_TRUE
);
165 return GL_FALSE
; /* out of memory? */
167 ASSERT(irb
->region
->buffer
);
176 #if FEATURE_OES_EGL_image
178 intel_image_target_renderbuffer_storage(struct gl_context
*ctx
,
179 struct gl_renderbuffer
*rb
,
182 struct intel_context
*intel
= intel_context(ctx
);
183 struct intel_renderbuffer
*irb
;
187 screen
= intel
->intelScreen
->driScrnPriv
;
188 image
= screen
->dri2
.image
->lookupEGLImage(screen
, image_handle
,
189 screen
->loaderPrivate
);
193 irb
= intel_renderbuffer(rb
);
195 intel_region_release(&irb
->region
);
196 intel_region_reference(&irb
->region
, image
->region
);
198 rb
->InternalFormat
= image
->internal_format
;
199 rb
->Width
= image
->region
->width
;
200 rb
->Height
= image
->region
->height
;
201 rb
->Format
= image
->format
;
202 rb
->DataType
= image
->data_type
;
203 rb
->_BaseFormat
= _mesa_base_fbo_format(&intel
->ctx
,
204 image
->internal_format
);
209 * Called for each hardware renderbuffer when a _window_ is resized.
210 * Just update fields.
211 * Not used for user-created renderbuffers!
214 intel_alloc_window_storage(struct gl_context
* ctx
, struct gl_renderbuffer
*rb
,
215 GLenum internalFormat
, GLuint width
, GLuint height
)
217 ASSERT(rb
->Name
== 0);
220 rb
->InternalFormat
= internalFormat
;
227 intel_resize_buffers(struct gl_context
*ctx
, struct gl_framebuffer
*fb
,
228 GLuint width
, GLuint height
)
232 _mesa_resize_framebuffer(ctx
, fb
, width
, height
);
234 fb
->Initialized
= GL_TRUE
; /* XXX remove someday */
241 /* Make sure all window system renderbuffers are up to date */
242 for (i
= BUFFER_FRONT_LEFT
; i
<= BUFFER_BACK_RIGHT
; i
++) {
243 struct gl_renderbuffer
*rb
= fb
->Attachment
[i
].Renderbuffer
;
245 /* only resize if size is changing */
246 if (rb
&& (rb
->Width
!= width
|| rb
->Height
!= height
)) {
247 rb
->AllocStorage(ctx
, rb
, rb
->InternalFormat
, width
, height
);
253 /** Dummy function for gl_renderbuffer::AllocStorage() */
255 intel_nop_alloc_storage(struct gl_context
* ctx
, struct gl_renderbuffer
*rb
,
256 GLenum internalFormat
, GLuint width
, GLuint height
)
258 _mesa_problem(ctx
, "intel_op_alloc_storage should never be called.");
264 intel_renderbuffer_set_region(struct intel_context
*intel
,
265 struct intel_renderbuffer
*rb
,
266 struct intel_region
*region
)
268 struct intel_region
*old
;
272 intel_region_reference(&rb
->region
, region
);
273 intel_region_release(&old
);
278 * Create a new intel_renderbuffer which corresponds to an on-screen window,
279 * not a user-created renderbuffer.
281 struct intel_renderbuffer
*
282 intel_create_renderbuffer(gl_format format
)
284 GET_CURRENT_CONTEXT(ctx
);
286 struct intel_renderbuffer
*irb
;
288 irb
= CALLOC_STRUCT(intel_renderbuffer
);
290 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "creating renderbuffer");
294 _mesa_init_renderbuffer(&irb
->Base
, 0);
295 irb
->Base
.ClassID
= INTEL_RB_CLASS
;
296 irb
->Base
._BaseFormat
= _mesa_get_format_base_format(format
);
297 irb
->Base
.Format
= format
;
298 irb
->Base
.InternalFormat
= irb
->Base
._BaseFormat
;
299 irb
->Base
.DataType
= intel_mesa_format_to_rb_datatype(format
);
301 /* intel-specific methods */
302 irb
->Base
.Delete
= intel_delete_renderbuffer
;
303 irb
->Base
.AllocStorage
= intel_alloc_window_storage
;
304 irb
->Base
.GetPointer
= intel_get_pointer
;
311 * Create a new renderbuffer object.
312 * Typically called via glBindRenderbufferEXT().
314 static struct gl_renderbuffer
*
315 intel_new_renderbuffer(struct gl_context
* ctx
, GLuint name
)
317 /*struct intel_context *intel = intel_context(ctx); */
318 struct intel_renderbuffer
*irb
;
320 irb
= CALLOC_STRUCT(intel_renderbuffer
);
322 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "creating renderbuffer");
326 _mesa_init_renderbuffer(&irb
->Base
, name
);
327 irb
->Base
.ClassID
= INTEL_RB_CLASS
;
329 /* intel-specific methods */
330 irb
->Base
.Delete
= intel_delete_renderbuffer
;
331 irb
->Base
.AllocStorage
= intel_alloc_renderbuffer_storage
;
332 irb
->Base
.GetPointer
= intel_get_pointer
;
333 /* span routines set in alloc_storage function */
340 * Called via glBindFramebufferEXT().
343 intel_bind_framebuffer(struct gl_context
* ctx
, GLenum target
,
344 struct gl_framebuffer
*fb
, struct gl_framebuffer
*fbread
)
346 if (target
== GL_FRAMEBUFFER_EXT
|| target
== GL_DRAW_FRAMEBUFFER_EXT
) {
347 intel_draw_buffer(ctx
, fb
);
350 /* don't need to do anything if target == GL_READ_FRAMEBUFFER_EXT */
356 * Called via glFramebufferRenderbufferEXT().
359 intel_framebuffer_renderbuffer(struct gl_context
* ctx
,
360 struct gl_framebuffer
*fb
,
361 GLenum attachment
, struct gl_renderbuffer
*rb
)
363 DBG("Intel FramebufferRenderbuffer %u %u\n", fb
->Name
, rb
? rb
->Name
: 0);
367 _mesa_framebuffer_renderbuffer(ctx
, fb
, attachment
, rb
);
368 intel_draw_buffer(ctx
, fb
);
373 intel_update_wrapper(struct gl_context
*ctx
, struct intel_renderbuffer
*irb
,
374 struct gl_texture_image
*texImage
)
376 if (!intel_span_supports_format(texImage
->TexFormat
)) {
377 DBG("Render to texture BAD FORMAT %s\n",
378 _mesa_get_format_name(texImage
->TexFormat
));
381 DBG("Render to texture %s\n", _mesa_get_format_name(texImage
->TexFormat
));
384 irb
->Base
.Format
= texImage
->TexFormat
;
385 irb
->Base
.DataType
= intel_mesa_format_to_rb_datatype(texImage
->TexFormat
);
386 irb
->Base
.InternalFormat
= texImage
->InternalFormat
;
387 irb
->Base
._BaseFormat
= _mesa_base_fbo_format(ctx
, irb
->Base
.InternalFormat
);
388 irb
->Base
.Width
= texImage
->Width
;
389 irb
->Base
.Height
= texImage
->Height
;
391 irb
->Base
.Delete
= intel_delete_renderbuffer
;
392 irb
->Base
.AllocStorage
= intel_nop_alloc_storage
;
399 * When glFramebufferTexture[123]D is called this function sets up the
400 * gl_renderbuffer wrapper around the texture image.
401 * This will have the region info needed for hardware rendering.
403 static struct intel_renderbuffer
*
404 intel_wrap_texture(struct gl_context
* ctx
, struct gl_texture_image
*texImage
)
406 const GLuint name
= ~0; /* not significant, but distinct for debugging */
407 struct intel_renderbuffer
*irb
;
409 /* make an intel_renderbuffer to wrap the texture image */
410 irb
= CALLOC_STRUCT(intel_renderbuffer
);
412 _mesa_error(ctx
, GL_OUT_OF_MEMORY
, "glFramebufferTexture");
416 _mesa_init_renderbuffer(&irb
->Base
, name
);
417 irb
->Base
.ClassID
= INTEL_RB_CLASS
;
419 if (!intel_update_wrapper(ctx
, irb
, texImage
)) {
428 intel_set_draw_offset_for_image(struct intel_texture_image
*intel_image
,
431 struct intel_mipmap_tree
*mt
= intel_image
->mt
;
432 unsigned int dst_x
, dst_y
;
434 /* compute offset of the particular 2D image within the texture region */
435 intel_miptree_get_image_offset(intel_image
->mt
,
441 mt
->region
->draw_offset
= (dst_y
* mt
->region
->pitch
+ dst_x
) * mt
->cpp
;
442 mt
->region
->draw_x
= dst_x
;
443 mt
->region
->draw_y
= dst_y
;
447 * Called by glFramebufferTexture[123]DEXT() (and other places) to
448 * prepare for rendering into texture memory. This might be called
449 * many times to choose different texture levels, cube faces, etc
450 * before intel_finish_render_texture() is ever called.
453 intel_render_texture(struct gl_context
* ctx
,
454 struct gl_framebuffer
*fb
,
455 struct gl_renderbuffer_attachment
*att
)
457 struct gl_texture_image
*newImage
458 = att
->Texture
->Image
[att
->CubeMapFace
][att
->TextureLevel
];
459 struct intel_renderbuffer
*irb
= intel_renderbuffer(att
->Renderbuffer
);
460 struct intel_texture_image
*intel_image
;
466 intel_image
= intel_texture_image(newImage
);
467 if (!intel_image
->mt
) {
468 /* Fallback on drawing to a texture that doesn't have a miptree
469 * (has a border, width/height 0, etc.)
471 _mesa_reference_renderbuffer(&att
->Renderbuffer
, NULL
);
472 _mesa_render_texture(ctx
, fb
, att
);
476 irb
= intel_wrap_texture(ctx
, newImage
);
478 /* bind the wrapper to the attachment point */
479 _mesa_reference_renderbuffer(&att
->Renderbuffer
, &irb
->Base
);
482 /* fallback to software rendering */
483 _mesa_render_texture(ctx
, fb
, att
);
488 if (!intel_update_wrapper(ctx
, irb
, newImage
)) {
489 _mesa_reference_renderbuffer(&att
->Renderbuffer
, NULL
);
490 _mesa_render_texture(ctx
, fb
, att
);
494 DBG("Begin render texture tid %lx tex=%u w=%d h=%d refcount=%d\n",
496 att
->Texture
->Name
, newImage
->Width
, newImage
->Height
,
499 /* point the renderbufer's region to the texture image region */
500 if (irb
->region
!= intel_image
->mt
->region
) {
502 intel_region_release(&irb
->region
);
503 intel_region_reference(&irb
->region
, intel_image
->mt
->region
);
506 intel_set_draw_offset_for_image(intel_image
, att
->Zoffset
);
507 intel_image
->used_as_render_target
= GL_TRUE
;
510 if (!brw_context(ctx
)->has_surface_tile_offset
&&
511 (intel_image
->mt
->region
->draw_offset
& 4095) != 0) {
512 /* Original gen4 hardware couldn't draw to a non-tile-aligned
513 * destination in a miptree unless you actually setup your
514 * renderbuffer as a miptree and used the fragile
515 * lod/array_index/etc. controls to select the image. So,
516 * instead, we just make a new single-level miptree and render
519 struct intel_context
*intel
= intel_context(ctx
);
520 struct intel_mipmap_tree
*old_mt
= intel_image
->mt
;
521 struct intel_mipmap_tree
*new_mt
;
522 int comp_byte
= 0, texel_bytes
;
524 if (_mesa_is_format_compressed(intel_image
->base
.TexFormat
))
525 comp_byte
= intel_compressed_num_bytes(intel_image
->base
.TexFormat
);
527 texel_bytes
= _mesa_get_format_bytes(intel_image
->base
.TexFormat
);
529 new_mt
= intel_miptree_create(intel
, newImage
->TexObject
->Target
,
530 intel_image
->base
._BaseFormat
,
531 intel_image
->base
.InternalFormat
,
534 intel_image
->base
.Width
,
535 intel_image
->base
.Height
,
536 intel_image
->base
.Depth
,
537 texel_bytes
, comp_byte
, GL_TRUE
);
539 intel_miptree_image_copy(intel
,
545 intel_miptree_release(intel
, &intel_image
->mt
);
546 intel_image
->mt
= new_mt
;
547 intel_set_draw_offset_for_image(intel_image
, att
->Zoffset
);
549 intel_region_release(&irb
->region
);
550 intel_region_reference(&irb
->region
, intel_image
->mt
->region
);
553 /* update drawing region, etc */
554 intel_draw_buffer(ctx
, fb
);
559 * Called by Mesa when rendering to a texture is done.
562 intel_finish_render_texture(struct gl_context
* ctx
,
563 struct gl_renderbuffer_attachment
*att
)
565 struct intel_context
*intel
= intel_context(ctx
);
566 struct gl_texture_object
*tex_obj
= att
->Texture
;
567 struct gl_texture_image
*image
=
568 tex_obj
->Image
[att
->CubeMapFace
][att
->TextureLevel
];
569 struct intel_texture_image
*intel_image
= intel_texture_image(image
);
571 DBG("Finish render texture tid %lx tex=%u\n",
572 _glthread_GetID(), att
->Texture
->Name
);
574 /* Flag that this image may now be validated into the object's miptree. */
576 intel_image
->used_as_render_target
= GL_FALSE
;
578 /* Since we've (probably) rendered to the texture and will (likely) use
579 * it in the texture domain later on in this batchbuffer, flush the
580 * batch. Once again, we wish for a domain tracker in libdrm to cover
581 * usage inside of a batchbuffer like GEM does in the kernel.
583 intel_batchbuffer_emit_mi_flush(intel
->batch
);
587 * Do additional "completeness" testing of a framebuffer object.
590 intel_validate_framebuffer(struct gl_context
*ctx
, struct gl_framebuffer
*fb
)
592 struct intel_context
*intel
= intel_context(ctx
);
593 const struct intel_renderbuffer
*depthRb
=
594 intel_get_renderbuffer(fb
, BUFFER_DEPTH
);
595 const struct intel_renderbuffer
*stencilRb
=
596 intel_get_renderbuffer(fb
, BUFFER_STENCIL
);
599 if (depthRb
&& stencilRb
&& stencilRb
!= depthRb
) {
600 if (fb
->Attachment
[BUFFER_DEPTH
].Type
== GL_TEXTURE
&&
601 fb
->Attachment
[BUFFER_STENCIL
].Type
== GL_TEXTURE
&&
602 (fb
->Attachment
[BUFFER_DEPTH
].Texture
->Name
==
603 fb
->Attachment
[BUFFER_STENCIL
].Texture
->Name
)) {
606 /* we only support combined depth/stencil buffers, not separate
609 DBG("Only supports combined depth/stencil (found %s, %s)\n",
610 depthRb
? _mesa_get_format_name(depthRb
->Base
.Format
): "NULL",
611 stencilRb
? _mesa_get_format_name(stencilRb
->Base
.Format
): "NULL");
612 fb
->_Status
= GL_FRAMEBUFFER_UNSUPPORTED_EXT
;
616 for (i
= 0; i
< Elements(fb
->Attachment
); i
++) {
617 struct gl_renderbuffer
*rb
;
618 struct intel_renderbuffer
*irb
;
620 if (fb
->Attachment
[i
].Type
== GL_NONE
)
623 /* A supported attachment will have a Renderbuffer set either
624 * from being a Renderbuffer or being a texture that got the
625 * intel_wrap_texture() treatment.
627 rb
= fb
->Attachment
[i
].Renderbuffer
;
629 DBG("attachment without renderbuffer\n");
630 fb
->_Status
= GL_FRAMEBUFFER_UNSUPPORTED_EXT
;
634 irb
= intel_renderbuffer(rb
);
636 DBG("software rendering renderbuffer\n");
637 fb
->_Status
= GL_FRAMEBUFFER_UNSUPPORTED_EXT
;
641 if (!intel_span_supports_format(irb
->Base
.Format
) ||
642 !intel
->vtbl
.render_target_supported(irb
->Base
.Format
)) {
643 DBG("Unsupported texture/renderbuffer format attached: %s\n",
644 _mesa_get_format_name(irb
->Base
.Format
));
645 fb
->_Status
= GL_FRAMEBUFFER_UNSUPPORTED_EXT
;
652 * Do one-time context initializations related to GL_EXT_framebuffer_object.
653 * Hook in device driver functions.
656 intel_fbo_init(struct intel_context
*intel
)
658 intel
->ctx
.Driver
.NewFramebuffer
= intel_new_framebuffer
;
659 intel
->ctx
.Driver
.NewRenderbuffer
= intel_new_renderbuffer
;
660 intel
->ctx
.Driver
.BindFramebuffer
= intel_bind_framebuffer
;
661 intel
->ctx
.Driver
.FramebufferRenderbuffer
= intel_framebuffer_renderbuffer
;
662 intel
->ctx
.Driver
.RenderTexture
= intel_render_texture
;
663 intel
->ctx
.Driver
.FinishRenderTexture
= intel_finish_render_texture
;
664 intel
->ctx
.Driver
.ResizeBuffers
= intel_resize_buffers
;
665 intel
->ctx
.Driver
.ValidateFramebuffer
= intel_validate_framebuffer
;
666 intel
->ctx
.Driver
.BlitFramebuffer
= _mesa_meta_BlitFramebuffer
;
668 #if FEATURE_OES_EGL_image
669 intel
->ctx
.Driver
.EGLImageTargetRenderbufferStorage
=
670 intel_image_target_renderbuffer_storage
;