gallium: add a CAP for mixed colorbuffer format support
[profile/ivi/mesa.git] / src / mesa / state_tracker / st_cb_fbo.c
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/macros.h"
41 #include "main/mfeatures.h"
42 #include "main/renderbuffer.h"
43
44 #include "pipe/p_context.h"
45 #include "pipe/p_defines.h"
46 #include "pipe/p_screen.h"
47 #include "st_context.h"
48 #include "st_cb_fbo.h"
49 #include "st_cb_flush.h"
50 #include "st_format.h"
51 #include "st_texture.h"
52 #include "st_manager.h"
53
54 #include "util/u_format.h"
55 #include "util/u_inlines.h"
56 #include "util/u_surface.h"
57
58
59 /**
60  * gl_renderbuffer::AllocStorage()
61  * This is called to allocate the original drawing surface, and
62  * during window resize.
63  */
64 static GLboolean
65 st_renderbuffer_alloc_storage(struct gl_context * ctx,
66                               struct gl_renderbuffer *rb,
67                               GLenum internalFormat,
68                               GLuint width, GLuint height)
69 {
70    struct st_context *st = st_context(ctx);
71    struct pipe_context *pipe = st->pipe;
72    struct pipe_screen *screen = st->pipe->screen;
73    struct st_renderbuffer *strb = st_renderbuffer(rb);
74    enum pipe_format format;
75    struct pipe_surface surf_tmpl;
76
77    if (strb->format != PIPE_FORMAT_NONE)
78       format = strb->format;
79    else
80       format = st_choose_renderbuffer_format(screen, internalFormat,
81                                              rb->NumSamples);
82
83    if (format == PIPE_FORMAT_NONE) {
84       return FALSE;
85    }
86
87    /* init renderbuffer fields */
88    strb->Base.Width  = width;
89    strb->Base.Height = height;
90    strb->Base.Format = st_pipe_format_to_mesa_format(format);
91    strb->Base._BaseFormat = _mesa_base_fbo_format(ctx, internalFormat);
92    strb->Base.DataType = st_format_datatype(format);
93
94    strb->defined = GL_FALSE;  /* undefined contents now */
95
96    if (strb->software) {
97       size_t size;
98       
99       free(strb->data);
100
101       assert(strb->format != PIPE_FORMAT_NONE);
102       
103       strb->stride = util_format_get_stride(strb->format, width);
104       size = util_format_get_2d_size(strb->format, strb->stride, height);
105       
106       strb->data = malloc(size);
107       
108       return strb->data != NULL;
109    }
110    else {
111       struct pipe_resource template;
112     
113       /* Free the old surface and texture
114        */
115       pipe_surface_reference( &strb->surface, NULL );
116       pipe_resource_reference( &strb->texture, NULL );
117       pipe_sampler_view_reference(&strb->sampler_view, NULL);
118
119       /* Setup new texture template.
120        */
121       memset(&template, 0, sizeof(template));
122       template.target = st->internal_target;
123       template.format = format;
124       template.width0 = width;
125       template.height0 = height;
126       template.depth0 = 1;
127       template.array_size = 1;
128       template.last_level = 0;
129       template.nr_samples = rb->NumSamples;
130       if (util_format_is_depth_or_stencil(format)) {
131          template.bind = PIPE_BIND_DEPTH_STENCIL;
132       }
133       else {
134          template.bind = (PIPE_BIND_DISPLAY_TARGET |
135                           PIPE_BIND_RENDER_TARGET);
136       }
137
138       strb->texture = screen->resource_create(screen, &template);
139
140       if (!strb->texture) 
141          return FALSE;
142
143       memset(&surf_tmpl, 0, sizeof(surf_tmpl));
144       u_surface_default_template(&surf_tmpl, strb->texture, template.bind);
145       strb->surface = pipe->create_surface(pipe,
146                                            strb->texture,
147                                            &surf_tmpl);
148       if (strb->surface) {
149          assert(strb->surface->texture);
150          assert(strb->surface->format);
151          assert(strb->surface->width == width);
152          assert(strb->surface->height == height);
153       }
154
155       return strb->surface != NULL;
156    }
157 }
158
159
160 /**
161  * gl_renderbuffer::Delete()
162  */
163 static void
164 st_renderbuffer_delete(struct gl_renderbuffer *rb)
165 {
166    struct st_renderbuffer *strb = st_renderbuffer(rb);
167    ASSERT(strb);
168    pipe_surface_reference(&strb->surface, NULL);
169    pipe_resource_reference(&strb->texture, NULL);
170    pipe_sampler_view_reference(&strb->sampler_view, NULL);
171    free(strb->data);
172    free(strb);
173 }
174
175
176 /**
177  * gl_renderbuffer::GetPointer()
178  */
179 static void *
180 null_get_pointer(struct gl_context * ctx, struct gl_renderbuffer *rb,
181                  GLint x, GLint y)
182 {
183    /* By returning NULL we force all software rendering to go through
184     * the span routines.
185     */
186 #if 0
187    assert(0);  /* Should never get called with softpipe */
188 #endif
189    return NULL;
190 }
191
192
193 /**
194  * Called via ctx->Driver.NewFramebuffer()
195  */
196 static struct gl_framebuffer *
197 st_new_framebuffer(struct gl_context *ctx, GLuint name)
198 {
199    /* XXX not sure we need to subclass gl_framebuffer for pipe */
200    return _mesa_new_framebuffer(ctx, name);
201 }
202
203
204 /**
205  * Called via ctx->Driver.NewRenderbuffer()
206  */
207 static struct gl_renderbuffer *
208 st_new_renderbuffer(struct gl_context *ctx, GLuint name)
209 {
210    struct st_renderbuffer *strb = ST_CALLOC_STRUCT(st_renderbuffer);
211    if (strb) {
212       _mesa_init_renderbuffer(&strb->Base, name);
213       strb->Base.Delete = st_renderbuffer_delete;
214       strb->Base.AllocStorage = st_renderbuffer_alloc_storage;
215       strb->Base.GetPointer = null_get_pointer;
216       strb->format = PIPE_FORMAT_NONE;
217       return &strb->Base;
218    }
219    return NULL;
220 }
221
222
223 /**
224  * Allocate a renderbuffer for a an on-screen window (not a user-created
225  * renderbuffer).  The window system code determines the format.
226  */
227 struct gl_renderbuffer *
228 st_new_renderbuffer_fb(enum pipe_format format, int samples, boolean sw)
229 {
230    struct st_renderbuffer *strb;
231
232    strb = ST_CALLOC_STRUCT(st_renderbuffer);
233    if (!strb) {
234       _mesa_error(NULL, GL_OUT_OF_MEMORY, "creating renderbuffer");
235       return NULL;
236    }
237
238    _mesa_init_renderbuffer(&strb->Base, 0);
239    strb->Base.ClassID = 0x4242; /* just a unique value */
240    strb->Base.NumSamples = samples;
241    strb->Base.Format = st_pipe_format_to_mesa_format(format);
242    strb->Base._BaseFormat = _mesa_get_format_base_format(strb->Base.Format);
243    strb->Base.DataType = st_format_datatype(format);
244    strb->format = format;
245    strb->software = sw;
246    
247    switch (format) {
248    case PIPE_FORMAT_R8G8B8A8_UNORM:
249    case PIPE_FORMAT_B8G8R8A8_UNORM:
250    case PIPE_FORMAT_A8R8G8B8_UNORM:
251    case PIPE_FORMAT_R8G8B8X8_UNORM:
252    case PIPE_FORMAT_B8G8R8X8_UNORM:
253    case PIPE_FORMAT_X8R8G8B8_UNORM:
254    case PIPE_FORMAT_B5G5R5A1_UNORM:
255    case PIPE_FORMAT_B4G4R4A4_UNORM:
256    case PIPE_FORMAT_B5G6R5_UNORM:
257       strb->Base.InternalFormat = GL_RGBA;
258       break;
259    case PIPE_FORMAT_Z16_UNORM:
260       strb->Base.InternalFormat = GL_DEPTH_COMPONENT16;
261       break;
262    case PIPE_FORMAT_Z32_UNORM:
263       strb->Base.InternalFormat = GL_DEPTH_COMPONENT32;
264       break;
265    case PIPE_FORMAT_Z24_UNORM_S8_USCALED:
266    case PIPE_FORMAT_S8_USCALED_Z24_UNORM:
267    case PIPE_FORMAT_Z24X8_UNORM:
268    case PIPE_FORMAT_X8Z24_UNORM:
269       strb->Base.InternalFormat = GL_DEPTH24_STENCIL8_EXT;
270       break;
271    case PIPE_FORMAT_S8_USCALED:
272       strb->Base.InternalFormat = GL_STENCIL_INDEX8_EXT;
273       break;
274    case PIPE_FORMAT_R16G16B16A16_SNORM:
275       strb->Base.InternalFormat = GL_RGBA16;
276       break;
277    case PIPE_FORMAT_R8_UNORM:
278       strb->Base.InternalFormat = GL_R8;
279       break;
280    case PIPE_FORMAT_R8G8_UNORM:
281       strb->Base.InternalFormat = GL_RG8;
282       break;
283    case PIPE_FORMAT_R16_UNORM:
284       strb->Base.InternalFormat = GL_R16;
285       break;
286    case PIPE_FORMAT_R16G16_UNORM:
287       strb->Base.InternalFormat = GL_RG16;
288       break;
289    default:
290       _mesa_problem(NULL,
291                     "Unexpected format in st_new_renderbuffer_fb");
292       free(strb);
293       return NULL;
294    }
295
296    /* st-specific methods */
297    strb->Base.Delete = st_renderbuffer_delete;
298    strb->Base.AllocStorage = st_renderbuffer_alloc_storage;
299    strb->Base.GetPointer = null_get_pointer;
300
301    /* surface is allocated in st_renderbuffer_alloc_storage() */
302    strb->surface = NULL;
303
304    return &strb->Base;
305 }
306
307
308
309
310 /**
311  * Called via ctx->Driver.BindFramebufferEXT().
312  */
313 static void
314 st_bind_framebuffer(struct gl_context *ctx, GLenum target,
315                     struct gl_framebuffer *fb, struct gl_framebuffer *fbread)
316 {
317
318 }
319
320 /**
321  * Called by ctx->Driver.FramebufferRenderbuffer
322  */
323 static void
324 st_framebuffer_renderbuffer(struct gl_context *ctx, 
325                             struct gl_framebuffer *fb,
326                             GLenum attachment,
327                             struct gl_renderbuffer *rb)
328 {
329    /* XXX no need for derivation? */
330    _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb);
331 }
332
333
334 /**
335  * Called by ctx->Driver.RenderTexture
336  */
337 static void
338 st_render_texture(struct gl_context *ctx,
339                   struct gl_framebuffer *fb,
340                   struct gl_renderbuffer_attachment *att)
341 {
342    struct st_context *st = st_context(ctx);
343    struct pipe_context *pipe = st->pipe;
344    struct st_renderbuffer *strb;
345    struct gl_renderbuffer *rb;
346    struct pipe_resource *pt = st_get_texobj_resource(att->Texture);
347    struct st_texture_object *stObj;
348    const struct gl_texture_image *texImage;
349    struct pipe_surface surf_tmpl;
350
351    /* When would this fail?  Perhaps assert? */
352    if (!pt) 
353       return;
354
355    /* get pointer to texture image we're rendeing to */
356    texImage = att->Texture->Image[att->CubeMapFace][att->TextureLevel];
357
358    /* create new renderbuffer which wraps the texture image */
359    rb = st_new_renderbuffer(ctx, 0);
360    if (!rb) {
361       _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture()");
362       return;
363    }
364
365    _mesa_reference_renderbuffer(&att->Renderbuffer, rb);
366    assert(rb->RefCount == 1);
367    rb->AllocStorage = NULL; /* should not get called */
368    strb = st_renderbuffer(rb);
369
370    assert(strb->Base.RefCount > 0);
371
372    /* get the texture for the texture object */
373    stObj = st_texture_object(att->Texture);
374
375    /* point renderbuffer at texobject */
376    strb->rtt = stObj;
377    strb->rtt_level = att->TextureLevel;
378    strb->rtt_face = att->CubeMapFace;
379    strb->rtt_slice = att->Zoffset;
380
381    rb->Width = texImage->Width2;
382    rb->Height = texImage->Height2;
383    rb->_BaseFormat = texImage->_BaseFormat;
384    /*printf("***** render to texture level %d: %d x %d\n", att->TextureLevel, rb->Width, rb->Height);*/
385
386    /*printf("***** pipe texture %d x %d\n", pt->width0, pt->height0);*/
387
388    pipe_resource_reference( &strb->texture, pt );
389
390    pipe_surface_reference(&strb->surface, NULL);
391
392    pipe_sampler_view_reference(&strb->sampler_view,
393                                st_get_texture_sampler_view(stObj, pipe));
394
395    assert(strb->rtt_level <= strb->texture->last_level);
396
397    /* new surface for rendering into the texture */
398    memset(&surf_tmpl, 0, sizeof(surf_tmpl));
399    surf_tmpl.format = ctx->Color.sRGBEnabled ? strb->texture->format : util_format_linear(strb->texture->format);
400    surf_tmpl.usage = PIPE_BIND_RENDER_TARGET;
401    surf_tmpl.u.tex.level = strb->rtt_level;
402    surf_tmpl.u.tex.first_layer = strb->rtt_face + strb->rtt_slice;
403    surf_tmpl.u.tex.last_layer = strb->rtt_face + strb->rtt_slice;
404    strb->surface = pipe->create_surface(pipe,
405                                         strb->texture,
406                                         &surf_tmpl);
407
408    strb->format = pt->format;
409
410    strb->Base.Format = st_pipe_format_to_mesa_format(pt->format);
411    strb->Base.DataType = st_format_datatype(pt->format);
412
413    /*
414    printf("RENDER TO TEXTURE obj=%p pt=%p surf=%p  %d x %d\n",
415           att->Texture, pt, strb->surface, rb->Width, rb->Height);
416    */
417
418    /* Invalidate buffer state so that the pipe's framebuffer state
419     * gets updated.
420     * That's where the new renderbuffer (which we just created) gets
421     * passed to the pipe as a (color/depth) render target.
422     */
423    st_invalidate_state(ctx, _NEW_BUFFERS);
424 }
425
426
427 /**
428  * Called via ctx->Driver.FinishRenderTexture.
429  */
430 static void
431 st_finish_render_texture(struct gl_context *ctx,
432                          struct gl_renderbuffer_attachment *att)
433 {
434    struct st_renderbuffer *strb = st_renderbuffer(att->Renderbuffer);
435
436    if (!strb)
437       return;
438
439    strb->rtt = NULL;
440
441    /*
442    printf("FINISH RENDER TO TEXTURE surf=%p\n", strb->surface);
443    */
444
445    /* restore previous framebuffer state */
446    st_invalidate_state(ctx, _NEW_BUFFERS);
447 }
448
449
450 /**
451  * Validate a renderbuffer attachment for a particular set of bindings.
452  */
453 static GLboolean
454 st_validate_attachment(struct gl_context *ctx,
455                        struct pipe_screen *screen,
456                        const struct gl_renderbuffer_attachment *att,
457                        unsigned bindings)
458 {
459    const struct st_texture_object *stObj = st_texture_object(att->Texture);
460    enum pipe_format format;
461    gl_format texFormat;
462
463    /* Only validate texture attachments for now, since
464     * st_renderbuffer_alloc_storage makes sure that
465     * the format is supported.
466     */
467    if (att->Type != GL_TEXTURE)
468       return GL_TRUE;
469
470    if (!stObj)
471       return GL_FALSE;
472
473    format = stObj->pt->format;
474    texFormat =
475       stObj->base.Image[att->CubeMapFace][att->TextureLevel]->TexFormat;
476
477    /* If the encoding is sRGB and sRGB rendering cannot be enabled,
478     * check for linear format support instead.
479     * Later when we create a surface, we change the format to a linear one. */
480    if (!ctx->Const.sRGBCapable &&
481        _mesa_get_format_color_encoding(texFormat) == GL_SRGB) {
482       const gl_format linearFormat = _mesa_get_srgb_format_linear(texFormat);
483       format = st_mesa_format_to_pipe_format(linearFormat);
484    }
485
486    return screen->is_format_supported(screen, format,
487                                       PIPE_TEXTURE_2D,
488                                       stObj->pt->nr_samples, bindings);
489 }
490
491
492 /**
493  * Check if two renderbuffer attachments name a combined depth/stencil
494  * renderbuffer.
495  */
496 GLboolean
497 st_is_depth_stencil_combined(const struct gl_renderbuffer_attachment *depth,
498                              const struct gl_renderbuffer_attachment *stencil)
499 {
500    assert(depth && stencil);
501
502    if (depth->Type == stencil->Type) {
503       if (depth->Type == GL_RENDERBUFFER_EXT &&
504           depth->Renderbuffer == stencil->Renderbuffer)
505          return GL_TRUE;
506
507       if (depth->Type == GL_TEXTURE &&
508           depth->Texture == stencil->Texture)
509          return GL_TRUE;
510    }
511
512    return GL_FALSE;
513 }
514  
515
516 /**
517  * Check that the framebuffer configuration is valid in terms of what
518  * the driver can support.
519  *
520  * For Gallium we only supports combined Z+stencil, not separate buffers.
521  */
522 static void
523 st_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
524 {
525    struct st_context *st = st_context(ctx);
526    struct pipe_screen *screen = st->pipe->screen;
527    const struct gl_renderbuffer_attachment *depth =
528          &fb->Attachment[BUFFER_DEPTH];
529    const struct gl_renderbuffer_attachment *stencil =
530          &fb->Attachment[BUFFER_STENCIL];
531    GLuint i;
532    enum pipe_format first_format = PIPE_FORMAT_NONE;
533    boolean mixed_formats =
534          screen->get_param(screen, PIPE_CAP_MIXED_COLORBUFFER_FORMATS) != 0;
535
536    if (depth->Type && stencil->Type && depth->Type != stencil->Type) {
537       fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
538       return;
539    }
540    if (depth->Type == GL_RENDERBUFFER_EXT &&
541        stencil->Type == GL_RENDERBUFFER_EXT &&
542        depth->Renderbuffer != stencil->Renderbuffer) {
543       fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
544       return;
545    }
546    if (depth->Type == GL_TEXTURE &&
547        stencil->Type == GL_TEXTURE &&
548        depth->Texture != stencil->Texture) {
549       fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
550       return;
551    }
552
553    if (!st_validate_attachment(ctx,
554                                screen,
555                                depth,
556                                PIPE_BIND_DEPTH_STENCIL)) {
557       fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
558       return;
559    }
560    if (!st_validate_attachment(ctx,
561                                screen,
562                                stencil,
563                                PIPE_BIND_DEPTH_STENCIL)) {
564       fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
565       return;
566    }
567    for (i = 0; i < ctx->Const.MaxColorAttachments; i++) {
568       struct gl_renderbuffer_attachment *att =
569             &fb->Attachment[BUFFER_COLOR0 + i];
570       enum pipe_format format;
571
572       if (!st_validate_attachment(ctx,
573                                   screen,
574                                   att,
575                                   PIPE_BIND_RENDER_TARGET)) {
576          fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
577          return;
578       }
579
580       if (!mixed_formats) {
581          /* Disallow mixed formats. */
582          if (att->Type != GL_NONE) {
583             format = st_renderbuffer(att->Renderbuffer)->surface->format;
584          } else {
585             continue;
586          }
587
588          if (first_format == PIPE_FORMAT_NONE) {
589             first_format = format;
590          } else if (format != first_format) {
591             fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
592             return;
593          }
594       }
595    }
596 }
597
598
599 /**
600  * Called via glDrawBuffer.
601  */
602 static void
603 st_DrawBuffers(struct gl_context *ctx, GLsizei count, const GLenum *buffers)
604 {
605    struct st_context *st = st_context(ctx);
606    struct gl_framebuffer *fb = ctx->DrawBuffer;
607    GLuint i;
608
609    (void) count;
610    (void) buffers;
611
612    /* add the renderbuffers on demand */
613    for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
614       gl_buffer_index idx = fb->_ColorDrawBufferIndexes[i];
615       st_manager_add_color_renderbuffer(st, fb, idx);
616    }
617 }
618
619
620 /**
621  * Called via glReadBuffer.
622  */
623 static void
624 st_ReadBuffer(struct gl_context *ctx, GLenum buffer)
625 {
626    struct st_context *st = st_context(ctx);
627    struct gl_framebuffer *fb = ctx->ReadBuffer;
628
629    (void) buffer;
630
631    /* add the renderbuffer on demand */
632    st_manager_add_color_renderbuffer(st, fb, fb->_ColorReadBufferIndex);
633 }
634
635
636 void st_init_fbo_functions(struct dd_function_table *functions)
637 {
638 #if FEATURE_EXT_framebuffer_object
639    functions->NewFramebuffer = st_new_framebuffer;
640    functions->NewRenderbuffer = st_new_renderbuffer;
641    functions->BindFramebuffer = st_bind_framebuffer;
642    functions->FramebufferRenderbuffer = st_framebuffer_renderbuffer;
643    functions->RenderTexture = st_render_texture;
644    functions->FinishRenderTexture = st_finish_render_texture;
645    functions->ValidateFramebuffer = st_validate_framebuffer;
646 #endif
647    /* no longer needed by core Mesa, drivers handle resizes...
648    functions->ResizeBuffers = st_resize_buffers;
649    */
650
651    functions->DrawBuffers = st_DrawBuffers;
652    functions->ReadBuffer = st_ReadBuffer;
653 }
654
655 /* XXX unused ? */
656 struct pipe_sampler_view *
657 st_get_renderbuffer_sampler_view(struct st_renderbuffer *rb,
658                                  struct pipe_context *pipe)
659 {
660    if (!rb->sampler_view) {
661       rb->sampler_view = st_create_texture_sampler_view(pipe, rb->texture);
662    }
663
664    return rb->sampler_view;
665 }