st_cb_fbo.c revision bb567357bc1366df7115e0daa68c2470e3bf6ba6
1/**************************************************************************
2 *
3 * Copyright 2007 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/**
30 * Framebuffer/renderbuffer functions.
31 *
32 * \author Brian Paul
33 */
34
35
36#include "main/imports.h"
37#include "main/context.h"
38#include "main/fbobject.h"
39#include "main/framebuffer.h"
40#include "main/renderbuffer.h"
41
42#include "pipe/p_context.h"
43#include "pipe/p_defines.h"
44#include "pipe/p_screen.h"
45#include "st_context.h"
46#include "st_cb_fbo.h"
47#include "st_cb_texture.h"
48#include "st_format.h"
49#include "st_public.h"
50#include "st_texture.h"
51
52#include "util/u_rect.h"
53
54
55/**
56 * Compute the renderbuffer's Red/Green/EtcBit fields from the pipe format.
57 */
58static int
59init_renderbuffer_bits(struct st_renderbuffer *strb,
60                       enum pipe_format pipeFormat)
61{
62   struct pipe_format_info info;
63
64   if (!st_get_format_info( pipeFormat, &info )) {
65      assert( 0 );
66   }
67
68   strb->Base._ActualFormat = info.base_format;
69   strb->Base.RedBits = info.red_bits;
70   strb->Base.GreenBits = info.green_bits;
71   strb->Base.BlueBits = info.blue_bits;
72   strb->Base.AlphaBits = info.alpha_bits;
73   strb->Base.DepthBits = info.depth_bits;
74   strb->Base.StencilBits = info.stencil_bits;
75   strb->Base.DataType = st_format_datatype(pipeFormat);
76
77   return info.size;
78}
79
80/**
81 * gl_renderbuffer::AllocStorage()
82 * This is called to allocate the original drawing surface, and
83 * during window resize.
84 */
85static GLboolean
86st_renderbuffer_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb,
87                              GLenum internalFormat,
88                              GLuint width, GLuint height)
89{
90   struct pipe_context *pipe = ctx->st->pipe;
91   struct st_renderbuffer *strb = st_renderbuffer(rb);
92   enum pipe_format format;
93
94   if (strb->format != PIPE_FORMAT_NONE)
95      format = strb->format;
96   else
97      format = st_choose_renderbuffer_format(pipe->screen, internalFormat);
98
99   /* init renderbuffer fields */
100   strb->Base.Width  = width;
101   strb->Base.Height = height;
102   init_renderbuffer_bits(strb, format);
103
104   strb->defined = GL_FALSE;  /* undefined contents now */
105
106   if(strb->software) {
107      struct pipe_format_block block;
108      size_t size;
109
110      _mesa_free(strb->data);
111
112      assert(strb->format != PIPE_FORMAT_NONE);
113      pf_get_block(strb->format, &block);
114
115      strb->stride = pf_get_stride(&block, width);
116      size = pf_get_2d_size(&block, strb->stride, height);
117
118      strb->data = _mesa_malloc(size);
119
120      return strb->data != NULL;
121   }
122   else {
123      struct pipe_texture template;
124      unsigned surface_usage;
125
126      /* Free the old surface and texture
127       */
128      pipe_surface_reference( &strb->surface, NULL );
129      pipe_texture_reference( &strb->texture, NULL );
130
131      /* Setup new texture template.
132       */
133      memset(&template, 0, sizeof(template));
134      template.target = PIPE_TEXTURE_2D;
135      template.format = format;
136      pf_get_block(format, &template.block);
137      template.width[0] = width;
138      template.height[0] = height;
139      template.depth[0] = 1;
140      template.last_level = 0;
141      template.nr_samples = rb->NumSamples;
142      if (pf_is_depth_stencil(format)) {
143         template.tex_usage = PIPE_TEXTURE_USAGE_DEPTH_STENCIL;
144      }
145      else {
146         template.tex_usage = (PIPE_TEXTURE_USAGE_DISPLAY_TARGET |
147                               PIPE_TEXTURE_USAGE_RENDER_TARGET);
148      }
149
150      /* Probably need dedicated flags for surface usage too:
151       */
152      surface_usage = (PIPE_BUFFER_USAGE_GPU_READ |
153                       PIPE_BUFFER_USAGE_GPU_WRITE);
154#if 0
155                       PIPE_BUFFER_USAGE_CPU_READ |
156                       PIPE_BUFFER_USAGE_CPU_WRITE);
157#endif
158
159      strb->texture = pipe->screen->texture_create( pipe->screen,
160                                                    &template );
161
162      if (!strb->texture)
163         return FALSE;
164
165      strb->surface = pipe->screen->get_tex_surface( pipe->screen,
166                                                     strb->texture,
167                                                     0, 0, 0,
168                                                     surface_usage );
169      if (strb->surface) {
170         assert(strb->surface->texture);
171         assert(strb->surface->format);
172         assert(strb->surface->width == width);
173         assert(strb->surface->height == height);
174      }
175
176      return strb->surface != NULL;
177   }
178}
179
180
181/**
182 * gl_renderbuffer::Delete()
183 */
184static void
185st_renderbuffer_delete(struct gl_renderbuffer *rb)
186{
187   struct st_renderbuffer *strb = st_renderbuffer(rb);
188   ASSERT(strb);
189   pipe_surface_reference(&strb->surface, NULL);
190   pipe_texture_reference(&strb->texture, NULL);
191   _mesa_free(strb->data);
192   _mesa_free(strb);
193}
194
195
196/**
197 * gl_renderbuffer::GetPointer()
198 */
199static void *
200null_get_pointer(GLcontext * ctx, struct gl_renderbuffer *rb,
201                 GLint x, GLint y)
202{
203   /* By returning NULL we force all software rendering to go through
204    * the span routines.
205    */
206#if 0
207   assert(0);  /* Should never get called with softpipe */
208#endif
209   return NULL;
210}
211
212
213/**
214 * Called via ctx->Driver.NewFramebuffer()
215 */
216static struct gl_framebuffer *
217st_new_framebuffer(GLcontext *ctx, GLuint name)
218{
219   /* XXX not sure we need to subclass gl_framebuffer for pipe */
220   return _mesa_new_framebuffer(ctx, name);
221}
222
223
224/**
225 * Called via ctx->Driver.NewRenderbuffer()
226 */
227static struct gl_renderbuffer *
228st_new_renderbuffer(GLcontext *ctx, GLuint name)
229{
230   struct st_renderbuffer *strb = ST_CALLOC_STRUCT(st_renderbuffer);
231   if (strb) {
232      _mesa_init_renderbuffer(&strb->Base, name);
233      strb->Base.Delete = st_renderbuffer_delete;
234      strb->Base.AllocStorage = st_renderbuffer_alloc_storage;
235      strb->Base.GetPointer = null_get_pointer;
236      strb->format = PIPE_FORMAT_NONE;
237      return &strb->Base;
238   }
239   return NULL;
240}
241
242
243/**
244 * Allocate a renderbuffer for a an on-screen window (not a user-created
245 * renderbuffer).  The window system code determines the format.
246 */
247struct gl_renderbuffer *
248st_new_renderbuffer_fb(enum pipe_format format, int samples, boolean sw)
249{
250   struct st_renderbuffer *strb;
251
252   strb = ST_CALLOC_STRUCT(st_renderbuffer);
253   if (!strb) {
254      _mesa_error(NULL, GL_OUT_OF_MEMORY, "creating renderbuffer");
255      return NULL;
256   }
257
258   _mesa_init_renderbuffer(&strb->Base, 0);
259   strb->Base.ClassID = 0x4242; /* just a unique value */
260   strb->Base.NumSamples = samples;
261   strb->format = format;
262   init_renderbuffer_bits(strb, format);
263   strb->software = sw;
264
265   switch (format) {
266   case PIPE_FORMAT_A8R8G8B8_UNORM:
267   case PIPE_FORMAT_B8G8R8A8_UNORM:
268   case PIPE_FORMAT_X8R8G8B8_UNORM:
269   case PIPE_FORMAT_B8G8R8X8_UNORM:
270   case PIPE_FORMAT_A1R5G5B5_UNORM:
271   case PIPE_FORMAT_A4R4G4B4_UNORM:
272   case PIPE_FORMAT_R5G6B5_UNORM:
273      strb->Base.InternalFormat = GL_RGBA;
274      strb->Base._BaseFormat = GL_RGBA;
275      break;
276   case PIPE_FORMAT_Z16_UNORM:
277      strb->Base.InternalFormat = GL_DEPTH_COMPONENT16;
278      strb->Base._BaseFormat = GL_DEPTH_COMPONENT;
279      break;
280   case PIPE_FORMAT_Z32_UNORM:
281      strb->Base.InternalFormat = GL_DEPTH_COMPONENT32;
282      strb->Base._BaseFormat = GL_DEPTH_COMPONENT;
283      break;
284   case PIPE_FORMAT_S8Z24_UNORM:
285   case PIPE_FORMAT_Z24S8_UNORM:
286   case PIPE_FORMAT_X8Z24_UNORM:
287   case PIPE_FORMAT_Z24X8_UNORM:
288      strb->Base.InternalFormat = GL_DEPTH24_STENCIL8_EXT;
289      strb->Base._BaseFormat = GL_DEPTH_STENCIL_EXT;
290      break;
291   case PIPE_FORMAT_S8_UNORM:
292      strb->Base.InternalFormat = GL_STENCIL_INDEX8_EXT;
293      strb->Base._BaseFormat = GL_STENCIL_INDEX;
294      break;
295   case PIPE_FORMAT_R16G16B16A16_SNORM:
296      strb->Base.InternalFormat = GL_RGBA16;
297      strb->Base._BaseFormat = GL_RGBA;
298      break;
299   default:
300      _mesa_problem(NULL,
301		    "Unexpected format in st_new_renderbuffer_fb");
302      _mesa_free(strb);
303      return NULL;
304   }
305
306   /* st-specific methods */
307   strb->Base.Delete = st_renderbuffer_delete;
308   strb->Base.AllocStorage = st_renderbuffer_alloc_storage;
309   strb->Base.GetPointer = null_get_pointer;
310
311   /* surface is allocated in st_renderbuffer_alloc_storage() */
312   strb->surface = NULL;
313
314   return &strb->Base;
315}
316
317
318
319
320/**
321 * Called via ctx->Driver.BindFramebufferEXT().
322 */
323static void
324st_bind_framebuffer(GLcontext *ctx, GLenum target,
325                    struct gl_framebuffer *fb, struct gl_framebuffer *fbread)
326{
327
328}
329
330/**
331 * Called by ctx->Driver.FramebufferRenderbuffer
332 */
333static void
334st_framebuffer_renderbuffer(GLcontext *ctx,
335                            struct gl_framebuffer *fb,
336                            GLenum attachment,
337                            struct gl_renderbuffer *rb)
338{
339   /* XXX no need for derivation? */
340   _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
341}
342
343
344/**
345 * Called by ctx->Driver.RenderTexture
346 */
347static void
348st_render_texture(GLcontext *ctx,
349                  struct gl_framebuffer *fb,
350                  struct gl_renderbuffer_attachment *att)
351{
352   struct pipe_screen *screen = ctx->st->pipe->screen;
353   struct st_renderbuffer *strb;
354   struct gl_renderbuffer *rb;
355   struct pipe_texture *pt = st_get_texobj_texture(att->Texture);
356   struct st_texture_object *stObj;
357   const struct gl_texture_image *texImage =
358      att->Texture->Image[att->CubeMapFace][att->TextureLevel];
359
360   if (!pt)
361      return;
362
363   /* create new renderbuffer which wraps the texture image */
364   rb = st_new_renderbuffer(ctx, 0);
365   if (!rb) {
366      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()");
367      return;
368   }
369
370   _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
371   assert(rb->RefCount == 1);
372   rb->AllocStorage = NULL; /* should not get called */
373   strb = st_renderbuffer(rb);
374
375   assert(strb->Base.RefCount > 0);
376
377   /* get the texture for the texture object */
378   stObj = st_texture_object(att->Texture);
379
380   /* point renderbuffer at texobject */
381   strb->rtt = stObj;
382   strb->rtt_level = att->TextureLevel;
383   strb->rtt_face = att->CubeMapFace;
384   strb->rtt_slice = att->Zoffset;
385
386   rb->Width = texImage->Width2;
387   rb->Height = texImage->Height2;
388   rb->_BaseFormat = texImage->_BaseFormat;
389   /*printf("***** render to texture level %d: %d x %d\n", att->TextureLevel, rb->Width, rb->Height);*/
390
391   /*printf("***** pipe texture %d x %d\n", pt->width[0], pt->height[0]);*/
392
393   pipe_texture_reference( &strb->texture, pt );
394
395   pipe_surface_reference(&strb->surface, NULL);
396
397   /* new surface for rendering into the texture */
398   strb->surface = screen->get_tex_surface(screen,
399                                           strb->texture,
400                                           strb->rtt_face,
401                                           strb->rtt_level,
402                                           strb->rtt_slice,
403                                           PIPE_BUFFER_USAGE_GPU_READ |
404                                           PIPE_BUFFER_USAGE_GPU_WRITE);
405
406   init_renderbuffer_bits(strb, pt->format);
407
408   /*
409   printf("RENDER TO TEXTURE obj=%p pt=%p surf=%p  %d x %d\n",
410          att->Texture, pt, strb->surface, rb->Width, rb->Height);
411   */
412
413   /* Invalidate buffer state so that the pipe's framebuffer state
414    * gets updated.
415    * That's where the new renderbuffer (which we just created) gets
416    * passed to the pipe as a (color/depth) render target.
417    */
418   st_invalidate_state(ctx, _NEW_BUFFERS);
419}
420
421
422/**
423 * Called via ctx->Driver.FinishRenderTexture.
424 */
425static void
426st_finish_render_texture(GLcontext *ctx,
427                         struct gl_renderbuffer_attachment *att)
428{
429   struct st_renderbuffer *strb = st_renderbuffer(att->Renderbuffer);
430
431   if (!strb)
432      return;
433
434   st_flush( ctx->st, PIPE_FLUSH_RENDER_CACHE, NULL );
435
436   if (strb->surface)
437      pipe_surface_reference( &strb->surface, NULL );
438
439   strb->rtt = NULL;
440
441   /*
442   printf("FINISH RENDER TO TEXTURE surf=%p\n", strb->surface);
443   */
444
445   _mesa_reference_renderbuffer(&att->Renderbuffer, NULL);
446
447   /* restore previous framebuffer state */
448   st_invalidate_state(ctx, _NEW_BUFFERS);
449}
450
451
452/**
453 * Validate a renderbuffer attachment for a particular usage.
454 */
455
456static GLboolean
457st_validate_attachment(struct pipe_screen *screen,
458		       const struct gl_renderbuffer_attachment *att,
459		       GLuint usage)
460{
461   const struct st_texture_object *stObj =
462      st_texture_object(att->Texture);
463
464   /**
465    * Only validate texture attachments for now, since
466    * st_renderbuffer_alloc_storage makes sure that
467    * the format is supported.
468    */
469
470   if (att->Type != GL_TEXTURE)
471      return GL_TRUE;
472
473   if (!stObj)
474      return GL_FALSE;
475
476   return screen->is_format_supported(screen, stObj->pt->format,
477				      PIPE_TEXTURE_2D,
478				      usage, 0);
479}
480
481/**
482 * Check that the framebuffer configuration is valid in terms of what
483 * the driver can support.
484 *
485 * For Gallium we only supports combined Z+stencil, not separate buffers.
486 */
487static void
488st_validate_framebuffer(GLcontext *ctx, struct gl_framebuffer *fb)
489{
490   struct pipe_screen *screen = ctx->st->pipe->screen;
491   const struct gl_renderbuffer *depthRb =
492      fb->Attachment[BUFFER_DEPTH].Renderbuffer;
493   const struct gl_renderbuffer *stencilRb =
494      fb->Attachment[BUFFER_STENCIL].Renderbuffer;
495   GLuint i;
496
497   if (stencilRb && depthRb && stencilRb != depthRb) {
498      fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
499      return;
500   }
501
502   if (!st_validate_attachment(screen,
503			       &fb->Attachment[BUFFER_DEPTH],
504			       PIPE_TEXTURE_USAGE_DEPTH_STENCIL)) {
505      fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
506      return;
507   }
508   if (!st_validate_attachment(screen,
509			       &fb->Attachment[BUFFER_STENCIL],
510			       PIPE_TEXTURE_USAGE_DEPTH_STENCIL)) {
511      fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
512      return;
513   }
514   for (i = 0; i < ctx->Const.MaxColorAttachments; i++) {
515      if (!st_validate_attachment(screen,
516				  &fb->Attachment[BUFFER_COLOR0 + i],
517				  PIPE_TEXTURE_USAGE_RENDER_TARGET)) {
518	 fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
519	 return;
520      }
521   }
522}
523
524
525/**
526 * Copy back color buffer to front color buffer.
527 */
528static void
529copy_back_to_front(struct st_context *st,
530                   struct gl_framebuffer *fb,
531                   gl_buffer_index frontIndex,
532                   gl_buffer_index backIndex)
533
534{
535   struct st_framebuffer *stfb = (struct st_framebuffer *) fb;
536   struct pipe_surface *surf_front, *surf_back;
537
538   (void) st_get_framebuffer_surface(stfb, frontIndex, &surf_front);
539   (void) st_get_framebuffer_surface(stfb, backIndex, &surf_back);
540
541   if (surf_front && surf_back) {
542      if (st->pipe->surface_copy) {
543         st->pipe->surface_copy(st->pipe,
544                                surf_front, 0, 0,  /* dest */
545                                surf_back, 0, 0,   /* src */
546                                fb->Width, fb->Height);
547      } else {
548         util_surface_copy(st->pipe, FALSE,
549                           surf_front, 0, 0,
550                           surf_back, 0, 0,
551                           fb->Width, fb->Height);
552      }
553   }
554}
555
556
557/**
558 * Check if we're drawing into, or read from, a front color buffer.  If the
559 * front buffer is missing, create it now.
560 *
561 * The back color buffer must exist since we'll use its format/samples info
562 * for creating the front buffer.
563 *
564 * \param frontIndex  either BUFFER_FRONT_LEFT or BUFFER_FRONT_RIGHT
565 * \param backIndex  either BUFFER_BACK_LEFT or BUFFER_BACK_RIGHT
566 */
567static void
568check_create_front_buffer(GLcontext *ctx, struct gl_framebuffer *fb,
569                          gl_buffer_index frontIndex,
570                          gl_buffer_index backIndex)
571{
572   if (fb->Attachment[frontIndex].Renderbuffer == NULL) {
573      GLboolean create = GL_FALSE;
574
575      /* check if drawing to or reading from front buffer */
576      if (fb->_ColorReadBufferIndex == frontIndex) {
577         create = GL_TRUE;
578      }
579      else {
580         GLuint b;
581         for (b = 0; b < fb->_NumColorDrawBuffers; b++) {
582            if (fb->_ColorDrawBufferIndexes[b] == frontIndex) {
583               create = GL_TRUE;
584               break;
585            }
586         }
587      }
588
589      if (create) {
590         struct st_renderbuffer *back;
591         struct gl_renderbuffer *front;
592         enum pipe_format colorFormat;
593         uint samples;
594
595         if (0)
596            _mesa_debug(ctx, "Allocate new front buffer\n");
597
598         /* get back renderbuffer info */
599         back = st_renderbuffer(fb->Attachment[backIndex].Renderbuffer);
600         colorFormat = back->format;
601         samples = back->Base.NumSamples;
602
603         /* create front renderbuffer */
604         front = st_new_renderbuffer_fb(colorFormat, samples, FALSE);
605         _mesa_add_renderbuffer(fb, frontIndex, front);
606
607         /* alloc texture/surface for new front buffer */
608         front->AllocStorage(ctx, front, front->InternalFormat,
609                             fb->Width, fb->Height);
610
611         /* initialize the front color buffer contents by copying
612          * the back buffer.
613          */
614         copy_back_to_front(ctx->st, fb, frontIndex, backIndex);
615      }
616   }
617}
618
619
620/**
621 * If front left/right color buffers are missing, create them now.
622 */
623static void
624check_create_front_buffers(GLcontext *ctx, struct gl_framebuffer *fb)
625{
626   /* check if we need to create the front left buffer now */
627   check_create_front_buffer(ctx, fb, BUFFER_FRONT_LEFT, BUFFER_BACK_LEFT);
628
629   if (fb->Visual.stereoMode) {
630      check_create_front_buffer(ctx, fb, BUFFER_FRONT_RIGHT, BUFFER_BACK_RIGHT);
631   }
632
633   st_invalidate_state(ctx, _NEW_BUFFERS);
634}
635
636
637/**
638 * Called via glDrawBuffer.
639 */
640static void
641st_DrawBuffers(GLcontext *ctx, GLsizei count, const GLenum *buffers)
642{
643   (void) count;
644   (void) buffers;
645   check_create_front_buffers(ctx, ctx->DrawBuffer);
646}
647
648
649/**
650 * Called via glReadBuffer.
651 */
652static void
653st_ReadBuffer(GLcontext *ctx, GLenum buffer)
654{
655   (void) buffer;
656   check_create_front_buffers(ctx, ctx->ReadBuffer);
657}
658
659
660void st_init_fbo_functions(struct dd_function_table *functions)
661{
662   functions->NewFramebuffer = st_new_framebuffer;
663   functions->NewRenderbuffer = st_new_renderbuffer;
664   functions->BindFramebuffer = st_bind_framebuffer;
665   functions->FramebufferRenderbuffer = st_framebuffer_renderbuffer;
666   functions->RenderTexture = st_render_texture;
667   functions->FinishRenderTexture = st_finish_render_texture;
668   functions->ValidateFramebuffer = st_validate_framebuffer;
669   /* no longer needed by core Mesa, drivers handle resizes...
670   functions->ResizeBuffers = st_resize_buffers;
671   */
672
673   functions->DrawBuffers = st_DrawBuffers;
674   functions->ReadBuffer = st_ReadBuffer;
675}
676