intel_fbo.c revision e339b669a14f37698b842c0c51c1f5e4001ef12f
1/**************************************************************************
2 *
3 * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas.
4 * All Rights Reserved.
5 *
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:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
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.
25 *
26 **************************************************************************/
27
28
29#include "main/imports.h"
30#include "main/macros.h"
31#include "main/mtypes.h"
32#include "main/fbobject.h"
33#include "main/framebuffer.h"
34#include "main/renderbuffer.h"
35#include "main/context.h"
36#include "main/texrender.h"
37#include "drivers/common/meta.h"
38
39#include "intel_context.h"
40#include "intel_batchbuffer.h"
41#include "intel_buffers.h"
42#include "intel_fbo.h"
43#include "intel_mipmap_tree.h"
44#include "intel_regions.h"
45#include "intel_tex.h"
46#include "intel_span.h"
47
48#define FILE_DEBUG_FLAG DEBUG_FBO
49
50
51/**
52 * Create a new framebuffer object.
53 */
54static struct gl_framebuffer *
55intel_new_framebuffer(struct gl_context * ctx, GLuint name)
56{
57   /* Only drawable state in intel_framebuffer at this time, just use Mesa's
58    * class
59    */
60   return _mesa_new_framebuffer(ctx, name);
61}
62
63
64/** Called by gl_renderbuffer::Delete() */
65static void
66intel_delete_renderbuffer(struct gl_renderbuffer *rb)
67{
68   GET_CURRENT_CONTEXT(ctx);
69   struct intel_context *intel = intel_context(ctx);
70   struct intel_renderbuffer *irb = intel_renderbuffer(rb);
71
72   ASSERT(irb);
73
74   if (intel && irb->region) {
75      intel_region_release(&irb->region);
76   }
77
78   free(irb);
79}
80
81
82/**
83 * Return a pointer to a specific pixel in a renderbuffer.
84 */
85static void *
86intel_get_pointer(struct gl_context * ctx, struct gl_renderbuffer *rb,
87                  GLint x, GLint y)
88{
89   /* By returning NULL we force all software rendering to go through
90    * the span routines.
91    */
92   return NULL;
93}
94
95
96/**
97 * Called via glRenderbufferStorageEXT() to set the format and allocate
98 * storage for a user-created renderbuffer.
99 */
100static GLboolean
101intel_alloc_renderbuffer_storage(struct gl_context * ctx, struct gl_renderbuffer *rb,
102                                 GLenum internalFormat,
103                                 GLuint width, GLuint height)
104{
105   struct intel_context *intel = intel_context(ctx);
106   struct intel_renderbuffer *irb = intel_renderbuffer(rb);
107   int cpp, tiling;
108
109   ASSERT(rb->Name != 0);
110
111   switch (internalFormat) {
112   case GL_RED:
113   case GL_R8:
114      rb->Format = MESA_FORMAT_R8;
115      break;
116   case GL_R16:
117      rb->Format = MESA_FORMAT_R16;
118      break;
119   case GL_RG:
120   case GL_RG8:
121      rb->Format = MESA_FORMAT_RG88;
122      break;
123   case GL_RG16:
124      rb->Format = MESA_FORMAT_RG1616;
125      break;
126   case GL_R3_G3_B2:
127   case GL_RGB4:
128   case GL_RGB5:
129      rb->Format = MESA_FORMAT_RGB565;
130      break;
131   case GL_RGB:
132   case GL_RGB8:
133   case GL_RGB10:
134   case GL_RGB12:
135   case GL_RGB16:
136      rb->Format = MESA_FORMAT_XRGB8888;
137      break;
138   case GL_RGBA:
139   case GL_RGBA2:
140   case GL_RGBA4:
141   case GL_RGB5_A1:
142   case GL_RGBA8:
143   case GL_RGB10_A2:
144   case GL_RGBA12:
145   case GL_RGBA16:
146      rb->Format = MESA_FORMAT_ARGB8888;
147      break;
148   case GL_ALPHA:
149   case GL_ALPHA8:
150      rb->Format = MESA_FORMAT_A8;
151      break;
152   case GL_DEPTH_COMPONENT16:
153      rb->Format = MESA_FORMAT_Z16;
154      break;
155   case GL_STENCIL_INDEX:
156   case GL_STENCIL_INDEX1_EXT:
157   case GL_STENCIL_INDEX4_EXT:
158   case GL_STENCIL_INDEX8_EXT:
159   case GL_STENCIL_INDEX16_EXT:
160   case GL_DEPTH_COMPONENT:
161   case GL_DEPTH_COMPONENT24:
162   case GL_DEPTH_COMPONENT32:
163   case GL_DEPTH_STENCIL_EXT:
164   case GL_DEPTH24_STENCIL8_EXT:
165      /* alloc a depth+stencil buffer */
166      rb->Format = MESA_FORMAT_S8_Z24;
167      break;
168   default:
169      _mesa_problem(ctx,
170                    "Unexpected format in intel_alloc_renderbuffer_storage");
171      return GL_FALSE;
172   }
173
174   rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat);
175   rb->DataType = intel_mesa_format_to_rb_datatype(rb->Format);
176   cpp = _mesa_get_format_bytes(rb->Format);
177
178   intel_flush(ctx);
179
180   /* free old region */
181   if (irb->region) {
182      intel_region_release(&irb->region);
183   }
184
185   /* allocate new memory region/renderbuffer */
186
187   /* alloc hardware renderbuffer */
188   DBG("Allocating %d x %d Intel RBO\n", width, height);
189
190   tiling = I915_TILING_NONE;
191
192   /* Gen6 requires depth must be tiling */
193   if (intel->gen >= 6 && rb->Format == MESA_FORMAT_S8_Z24)
194       tiling = I915_TILING_Y;
195
196   irb->region = intel_region_alloc(intel->intelScreen, tiling, cpp,
197				    width, height, GL_TRUE);
198   if (!irb->region)
199      return GL_FALSE;       /* out of memory? */
200
201   ASSERT(irb->region->buffer);
202
203   rb->Width = width;
204   rb->Height = height;
205
206   return GL_TRUE;
207}
208
209
210#if FEATURE_OES_EGL_image
211static void
212intel_image_target_renderbuffer_storage(struct gl_context *ctx,
213					struct gl_renderbuffer *rb,
214					void *image_handle)
215{
216   struct intel_context *intel = intel_context(ctx);
217   struct intel_renderbuffer *irb;
218   __DRIscreen *screen;
219   __DRIimage *image;
220
221   screen = intel->intelScreen->driScrnPriv;
222   image = screen->dri2.image->lookupEGLImage(screen, image_handle,
223					      screen->loaderPrivate);
224   if (image == NULL)
225      return;
226
227   irb = intel_renderbuffer(rb);
228   if (irb->region)
229      intel_region_release(&irb->region);
230   intel_region_reference(&irb->region, image->region);
231
232   rb->InternalFormat = image->internal_format;
233   rb->Width = image->region->width;
234   rb->Height = image->region->height;
235   rb->Format = image->format;
236   rb->DataType = image->data_type;
237   rb->_BaseFormat = _mesa_base_fbo_format(&intel->ctx,
238					   image->internal_format);
239}
240#endif
241
242/**
243 * Called for each hardware renderbuffer when a _window_ is resized.
244 * Just update fields.
245 * Not used for user-created renderbuffers!
246 */
247static GLboolean
248intel_alloc_window_storage(struct gl_context * ctx, struct gl_renderbuffer *rb,
249                           GLenum internalFormat, GLuint width, GLuint height)
250{
251   ASSERT(rb->Name == 0);
252   rb->Width = width;
253   rb->Height = height;
254   rb->InternalFormat = internalFormat;
255
256   return GL_TRUE;
257}
258
259
260static void
261intel_resize_buffers(struct gl_context *ctx, struct gl_framebuffer *fb,
262		     GLuint width, GLuint height)
263{
264   int i;
265
266   _mesa_resize_framebuffer(ctx, fb, width, height);
267
268   fb->Initialized = GL_TRUE; /* XXX remove someday */
269
270   if (fb->Name != 0) {
271      return;
272   }
273
274
275   /* Make sure all window system renderbuffers are up to date */
276   for (i = BUFFER_FRONT_LEFT; i <= BUFFER_BACK_RIGHT; i++) {
277      struct gl_renderbuffer *rb = fb->Attachment[i].Renderbuffer;
278
279      /* only resize if size is changing */
280      if (rb && (rb->Width != width || rb->Height != height)) {
281	 rb->AllocStorage(ctx, rb, rb->InternalFormat, width, height);
282      }
283   }
284}
285
286
287/** Dummy function for gl_renderbuffer::AllocStorage() */
288static GLboolean
289intel_nop_alloc_storage(struct gl_context * ctx, struct gl_renderbuffer *rb,
290                        GLenum internalFormat, GLuint width, GLuint height)
291{
292   _mesa_problem(ctx, "intel_op_alloc_storage should never be called.");
293   return GL_FALSE;
294}
295
296
297void
298intel_renderbuffer_set_region(struct intel_context *intel,
299			      struct intel_renderbuffer *rb,
300			      struct intel_region *region)
301{
302   struct intel_region *old;
303
304   old = rb->region;
305   rb->region = NULL;
306   intel_region_reference(&rb->region, region);
307   intel_region_release(&old);
308}
309
310
311/**
312 * Create a new intel_renderbuffer which corresponds to an on-screen window,
313 * not a user-created renderbuffer.
314 */
315struct intel_renderbuffer *
316intel_create_renderbuffer(gl_format format)
317{
318   GET_CURRENT_CONTEXT(ctx);
319
320   struct intel_renderbuffer *irb;
321
322   irb = CALLOC_STRUCT(intel_renderbuffer);
323   if (!irb) {
324      _mesa_error(ctx, GL_OUT_OF_MEMORY, "creating renderbuffer");
325      return NULL;
326   }
327
328   _mesa_init_renderbuffer(&irb->Base, 0);
329   irb->Base.ClassID = INTEL_RB_CLASS;
330
331   switch (format) {
332   case MESA_FORMAT_RGB565:
333      irb->Base._BaseFormat = GL_RGB;
334      break;
335   case MESA_FORMAT_XRGB8888:
336      irb->Base._BaseFormat = GL_RGB;
337      break;
338   case MESA_FORMAT_ARGB8888:
339      irb->Base._BaseFormat = GL_RGBA;
340      break;
341   case MESA_FORMAT_Z16:
342      irb->Base._BaseFormat = GL_DEPTH_COMPONENT;
343      break;
344   case MESA_FORMAT_X8_Z24:
345      irb->Base._BaseFormat = GL_DEPTH_COMPONENT;
346      break;
347   case MESA_FORMAT_S8_Z24:
348      irb->Base._BaseFormat = GL_DEPTH_STENCIL;
349      break;
350   case MESA_FORMAT_A8:
351      irb->Base._BaseFormat = GL_ALPHA;
352      break;
353   case MESA_FORMAT_R8:
354      irb->Base._BaseFormat = GL_RED;
355      break;
356   case MESA_FORMAT_RG88:
357      irb->Base._BaseFormat = GL_RG;
358      break;
359   default:
360      _mesa_problem(NULL,
361                    "Unexpected intFormat in intel_create_renderbuffer");
362      free(irb);
363      return NULL;
364   }
365
366   irb->Base.Format = format;
367   irb->Base.InternalFormat = irb->Base._BaseFormat;
368   irb->Base.DataType = intel_mesa_format_to_rb_datatype(format);
369
370   /* intel-specific methods */
371   irb->Base.Delete = intel_delete_renderbuffer;
372   irb->Base.AllocStorage = intel_alloc_window_storage;
373   irb->Base.GetPointer = intel_get_pointer;
374
375   return irb;
376}
377
378
379/**
380 * Create a new renderbuffer object.
381 * Typically called via glBindRenderbufferEXT().
382 */
383static struct gl_renderbuffer *
384intel_new_renderbuffer(struct gl_context * ctx, GLuint name)
385{
386   /*struct intel_context *intel = intel_context(ctx); */
387   struct intel_renderbuffer *irb;
388
389   irb = CALLOC_STRUCT(intel_renderbuffer);
390   if (!irb) {
391      _mesa_error(ctx, GL_OUT_OF_MEMORY, "creating renderbuffer");
392      return NULL;
393   }
394
395   _mesa_init_renderbuffer(&irb->Base, name);
396   irb->Base.ClassID = INTEL_RB_CLASS;
397
398   /* intel-specific methods */
399   irb->Base.Delete = intel_delete_renderbuffer;
400   irb->Base.AllocStorage = intel_alloc_renderbuffer_storage;
401   irb->Base.GetPointer = intel_get_pointer;
402   /* span routines set in alloc_storage function */
403
404   return &irb->Base;
405}
406
407
408/**
409 * Called via glBindFramebufferEXT().
410 */
411static void
412intel_bind_framebuffer(struct gl_context * ctx, GLenum target,
413                       struct gl_framebuffer *fb, struct gl_framebuffer *fbread)
414{
415   if (target == GL_FRAMEBUFFER_EXT || target == GL_DRAW_FRAMEBUFFER_EXT) {
416      intel_draw_buffer(ctx, fb);
417   }
418   else {
419      /* don't need to do anything if target == GL_READ_FRAMEBUFFER_EXT */
420   }
421}
422
423
424/**
425 * Called via glFramebufferRenderbufferEXT().
426 */
427static void
428intel_framebuffer_renderbuffer(struct gl_context * ctx,
429                               struct gl_framebuffer *fb,
430                               GLenum attachment, struct gl_renderbuffer *rb)
431{
432   DBG("Intel FramebufferRenderbuffer %u %u\n", fb->Name, rb ? rb->Name : 0);
433
434   intel_flush(ctx);
435
436   _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
437   intel_draw_buffer(ctx, fb);
438}
439
440
441static GLboolean
442intel_update_wrapper(struct gl_context *ctx, struct intel_renderbuffer *irb,
443		     struct gl_texture_image *texImage)
444{
445   if (!intel_span_supports_format(texImage->TexFormat)) {
446      DBG("Render to texture BAD FORMAT %s\n",
447	  _mesa_get_format_name(texImage->TexFormat));
448      return GL_FALSE;
449   } else {
450      DBG("Render to texture %s\n", _mesa_get_format_name(texImage->TexFormat));
451   }
452
453   irb->Base.Format = texImage->TexFormat;
454   irb->Base.DataType = intel_mesa_format_to_rb_datatype(texImage->TexFormat);
455   irb->Base.InternalFormat = texImage->InternalFormat;
456   irb->Base._BaseFormat = _mesa_base_fbo_format(ctx, irb->Base.InternalFormat);
457   irb->Base.Width = texImage->Width;
458   irb->Base.Height = texImage->Height;
459
460   irb->Base.Delete = intel_delete_renderbuffer;
461   irb->Base.AllocStorage = intel_nop_alloc_storage;
462
463   return GL_TRUE;
464}
465
466
467/**
468 * When glFramebufferTexture[123]D is called this function sets up the
469 * gl_renderbuffer wrapper around the texture image.
470 * This will have the region info needed for hardware rendering.
471 */
472static struct intel_renderbuffer *
473intel_wrap_texture(struct gl_context * ctx, struct gl_texture_image *texImage)
474{
475   const GLuint name = ~0;   /* not significant, but distinct for debugging */
476   struct intel_renderbuffer *irb;
477
478   /* make an intel_renderbuffer to wrap the texture image */
479   irb = CALLOC_STRUCT(intel_renderbuffer);
480   if (!irb) {
481      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture");
482      return NULL;
483   }
484
485   _mesa_init_renderbuffer(&irb->Base, name);
486   irb->Base.ClassID = INTEL_RB_CLASS;
487
488   if (!intel_update_wrapper(ctx, irb, texImage)) {
489      free(irb);
490      return NULL;
491   }
492
493   return irb;
494}
495
496
497/**
498 * Called by glFramebufferTexture[123]DEXT() (and other places) to
499 * prepare for rendering into texture memory.  This might be called
500 * many times to choose different texture levels, cube faces, etc
501 * before intel_finish_render_texture() is ever called.
502 */
503static void
504intel_render_texture(struct gl_context * ctx,
505                     struct gl_framebuffer *fb,
506                     struct gl_renderbuffer_attachment *att)
507{
508   struct gl_texture_image *newImage
509      = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
510   struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer);
511   struct intel_texture_image *intel_image;
512   GLuint dst_x, dst_y;
513
514   (void) fb;
515
516   ASSERT(newImage);
517
518   intel_image = intel_texture_image(newImage);
519   if (!intel_image->mt) {
520      /* Fallback on drawing to a texture that doesn't have a miptree
521       * (has a border, width/height 0, etc.)
522       */
523      _mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
524      _mesa_render_texture(ctx, fb, att);
525      return;
526   }
527   else if (!irb) {
528      irb = intel_wrap_texture(ctx, newImage);
529      if (irb) {
530         /* bind the wrapper to the attachment point */
531         _mesa_reference_renderbuffer(&att->Renderbuffer, &irb->Base);
532      }
533      else {
534         /* fallback to software rendering */
535         _mesa_render_texture(ctx, fb, att);
536         return;
537      }
538   }
539
540   if (!intel_update_wrapper(ctx, irb, newImage)) {
541       _mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
542       _mesa_render_texture(ctx, fb, att);
543       return;
544   }
545
546   DBG("Begin render texture tid %lx tex=%u w=%d h=%d refcount=%d\n",
547       _glthread_GetID(),
548       att->Texture->Name, newImage->Width, newImage->Height,
549       irb->Base.RefCount);
550
551   /* point the renderbufer's region to the texture image region */
552   if (irb->region != intel_image->mt->region) {
553      if (irb->region)
554	 intel_region_release(&irb->region);
555      intel_region_reference(&irb->region, intel_image->mt->region);
556   }
557
558   /* compute offset of the particular 2D image within the texture region */
559   intel_miptree_get_image_offset(intel_image->mt,
560				  att->TextureLevel,
561				  att->CubeMapFace,
562				  att->Zoffset,
563				  &dst_x, &dst_y);
564
565   intel_image->mt->region->draw_offset = (dst_y * intel_image->mt->region->pitch +
566					   dst_x) * intel_image->mt->cpp;
567   intel_image->mt->region->draw_x = dst_x;
568   intel_image->mt->region->draw_y = dst_y;
569   intel_image->used_as_render_target = GL_TRUE;
570
571   /* update drawing region, etc */
572   intel_draw_buffer(ctx, fb);
573}
574
575
576/**
577 * Called by Mesa when rendering to a texture is done.
578 */
579static void
580intel_finish_render_texture(struct gl_context * ctx,
581                            struct gl_renderbuffer_attachment *att)
582{
583   struct intel_context *intel = intel_context(ctx);
584   struct gl_texture_object *tex_obj = att->Texture;
585   struct gl_texture_image *image =
586      tex_obj->Image[att->CubeMapFace][att->TextureLevel];
587   struct intel_texture_image *intel_image = intel_texture_image(image);
588
589   DBG("Finish render texture tid %lx tex=%u\n",
590       _glthread_GetID(), att->Texture->Name);
591
592   /* Flag that this image may now be validated into the object's miptree. */
593   intel_image->used_as_render_target = GL_FALSE;
594
595   /* Since we've (probably) rendered to the texture and will (likely) use
596    * it in the texture domain later on in this batchbuffer, flush the
597    * batch.  Once again, we wish for a domain tracker in libdrm to cover
598    * usage inside of a batchbuffer like GEM does in the kernel.
599    */
600   intel_batchbuffer_emit_mi_flush(intel->batch);
601}
602
603/**
604 * Do additional "completeness" testing of a framebuffer object.
605 */
606static void
607intel_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
608{
609   const struct intel_renderbuffer *depthRb =
610      intel_get_renderbuffer(fb, BUFFER_DEPTH);
611   const struct intel_renderbuffer *stencilRb =
612      intel_get_renderbuffer(fb, BUFFER_STENCIL);
613   int i;
614
615   if (depthRb && stencilRb && stencilRb != depthRb) {
616      if (ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Type == GL_TEXTURE &&
617	  ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Type == GL_TEXTURE &&
618	  (ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Texture->Name ==
619	   ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Texture->Name)) {
620	 /* OK */
621      } else {
622	 /* we only support combined depth/stencil buffers, not separate
623	  * stencil buffers.
624	  */
625	 DBG("Only supports combined depth/stencil (found %s, %s)\n",
626	     depthRb ? _mesa_get_format_name(depthRb->Base.Format): "NULL",
627	     stencilRb ? _mesa_get_format_name(stencilRb->Base.Format): "NULL");
628	 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
629      }
630   }
631
632   for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) {
633      struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[i];
634      struct intel_renderbuffer *irb = intel_renderbuffer(rb);
635
636      if (rb == NULL)
637	 continue;
638
639      if (irb == NULL) {
640	 DBG("software rendering renderbuffer\n");
641	 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
642	 continue;
643      }
644
645      if (!intel_span_supports_format(irb->Base.Format)) {
646	 DBG("Unsupported texture/renderbuffer format attached: %s\n",
647	     _mesa_get_format_name(irb->Base.Format));
648	 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
649      }
650   }
651}
652
653
654/**
655 * Do one-time context initializations related to GL_EXT_framebuffer_object.
656 * Hook in device driver functions.
657 */
658void
659intel_fbo_init(struct intel_context *intel)
660{
661   intel->ctx.Driver.NewFramebuffer = intel_new_framebuffer;
662   intel->ctx.Driver.NewRenderbuffer = intel_new_renderbuffer;
663   intel->ctx.Driver.BindFramebuffer = intel_bind_framebuffer;
664   intel->ctx.Driver.FramebufferRenderbuffer = intel_framebuffer_renderbuffer;
665   intel->ctx.Driver.RenderTexture = intel_render_texture;
666   intel->ctx.Driver.FinishRenderTexture = intel_finish_render_texture;
667   intel->ctx.Driver.ResizeBuffers = intel_resize_buffers;
668   intel->ctx.Driver.ValidateFramebuffer = intel_validate_framebuffer;
669   intel->ctx.Driver.BlitFramebuffer = _mesa_meta_BlitFramebuffer;
670
671#if FEATURE_OES_EGL_image
672   intel->ctx.Driver.EGLImageTargetRenderbufferStorage =
673      intel_image_target_renderbuffer_storage;
674#endif
675}
676