OSDN Git Service

i965/vec4: Fix confusion between SWIZZLE and BRW_SWIZZLE macros.
[android-x86/external-mesa.git] / src / mesa / state_tracker / st_cb_fbo.c
1 /**************************************************************************
2  * 
3  * Copyright 2007 VMware, Inc.
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 VMWARE 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/glformats.h"
41 #include "main/macros.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_cb_texture.h"
51 #include "st_format.h"
52 #include "st_texture.h"
53 #include "st_manager.h"
54
55 #include "util/u_format.h"
56 #include "util/u_inlines.h"
57 #include "util/u_surface.h"
58
59
60 static GLboolean
61 st_renderbuffer_alloc_sw_storage(struct gl_context * ctx,
62                                  struct gl_renderbuffer *rb,
63                                  GLenum internalFormat,
64                                  GLuint width, GLuint height)
65 {
66    struct st_context *st = st_context(ctx);
67    struct st_renderbuffer *strb = st_renderbuffer(rb);
68    enum pipe_format format;
69    size_t size;
70
71    free(strb->data);
72    strb->data = NULL;
73
74    if (internalFormat == GL_RGBA16_SNORM) {
75       /* Special case for software accum buffers.  Otherwise, if the
76        * call to st_choose_renderbuffer_format() fails (because the
77        * driver doesn't support signed 16-bit/channel colors) we'd
78        * just return without allocating the software accum buffer.
79        */
80       format = PIPE_FORMAT_R16G16B16A16_SNORM;
81    }
82    else {
83       format = st_choose_renderbuffer_format(st, internalFormat, 0);
84
85       /* Not setting gl_renderbuffer::Format here will cause
86        * FRAMEBUFFER_UNSUPPORTED and ValidateFramebuffer will not be called.
87        */
88       if (format == PIPE_FORMAT_NONE) {
89          return GL_TRUE;
90       }
91    }
92
93    strb->Base.Format = st_pipe_format_to_mesa_format(format);
94
95    size = _mesa_format_image_size(strb->Base.Format, width, height, 1);
96    strb->data = malloc(size);
97    return strb->data != NULL;
98 }
99
100
101 /**
102  * gl_renderbuffer::AllocStorage()
103  * This is called to allocate the original drawing surface, and
104  * during window resize.
105  */
106 static GLboolean
107 st_renderbuffer_alloc_storage(struct gl_context * ctx,
108                               struct gl_renderbuffer *rb,
109                               GLenum internalFormat,
110                               GLuint width, GLuint height)
111 {
112    struct st_context *st = st_context(ctx);
113    struct pipe_context *pipe = st->pipe;
114    struct pipe_screen *screen = st->pipe->screen;
115    struct st_renderbuffer *strb = st_renderbuffer(rb);
116    enum pipe_format format = PIPE_FORMAT_NONE;
117    struct pipe_surface surf_tmpl;
118    struct pipe_resource templ;
119
120    /* init renderbuffer fields */
121    strb->Base.Width  = width;
122    strb->Base.Height = height;
123    strb->Base._BaseFormat = _mesa_base_fbo_format(ctx, internalFormat);
124    strb->defined = GL_FALSE;  /* undefined contents now */
125
126    if (strb->software) {
127       return st_renderbuffer_alloc_sw_storage(ctx, rb, internalFormat,
128                                               width, height);
129    }
130
131    /* Free the old surface and texture
132     */
133    pipe_surface_reference( &strb->surface, NULL );
134    pipe_resource_reference( &strb->texture, NULL );
135
136    /* If an sRGB framebuffer is unsupported, sRGB formats behave like linear
137     * formats.
138     */
139    if (!ctx->Extensions.EXT_framebuffer_sRGB) {
140       internalFormat = _mesa_get_linear_internalformat(internalFormat);
141    }
142
143    /* Handle multisample renderbuffers first.
144     *
145     * From ARB_framebuffer_object:
146     *   If <samples> is zero, then RENDERBUFFER_SAMPLES is set to zero.
147     *   Otherwise <samples> represents a request for a desired minimum
148     *   number of samples. Since different implementations may support
149     *   different sample counts for multisampled rendering, the actual
150     *   number of samples allocated for the renderbuffer image is
151     *   implementation dependent.  However, the resulting value for
152     *   RENDERBUFFER_SAMPLES is guaranteed to be greater than or equal
153     *   to <samples> and no more than the next larger sample count supported
154     *   by the implementation.
155     *
156     * So let's find the supported number of samples closest to NumSamples.
157     * (NumSamples == 1) is treated the same as (NumSamples == 0).
158     */
159    if (rb->NumSamples > 1) {
160       unsigned i;
161
162       for (i = rb->NumSamples; i <= ctx->Const.MaxSamples; i++) {
163          format = st_choose_renderbuffer_format(st, internalFormat, i);
164
165          if (format != PIPE_FORMAT_NONE) {
166             rb->NumSamples = i;
167             break;
168          }
169       }
170    } else {
171       format = st_choose_renderbuffer_format(st, internalFormat, 0);
172    }
173
174    /* Not setting gl_renderbuffer::Format here will cause
175     * FRAMEBUFFER_UNSUPPORTED and ValidateFramebuffer will not be called.
176     */
177    if (format == PIPE_FORMAT_NONE) {
178       return GL_TRUE;
179    }
180
181    strb->Base.Format = st_pipe_format_to_mesa_format(format);
182
183    if (width == 0 || height == 0) {
184       /* if size is zero, nothing to allocate */
185       return GL_TRUE;
186    }
187
188    /* Setup new texture template.
189     */
190    memset(&templ, 0, sizeof(templ));
191    templ.target = st->internal_target;
192    templ.format = format;
193    templ.width0 = width;
194    templ.height0 = height;
195    templ.depth0 = 1;
196    templ.array_size = 1;
197    templ.nr_samples = rb->NumSamples;
198    if (util_format_is_depth_or_stencil(format)) {
199       templ.bind = PIPE_BIND_DEPTH_STENCIL;
200    }
201    else if (strb->Base.Name != 0) {
202       /* this is a user-created renderbuffer */
203       templ.bind = PIPE_BIND_RENDER_TARGET;
204    }
205    else {
206       /* this is a window-system buffer */
207       templ.bind = (PIPE_BIND_DISPLAY_TARGET |
208                     PIPE_BIND_RENDER_TARGET);
209    }
210
211    strb->texture = screen->resource_create(screen, &templ);
212
213    if (!strb->texture)
214       return FALSE;
215
216    u_surface_default_template(&surf_tmpl, strb->texture);
217    strb->surface = pipe->create_surface(pipe,
218                                         strb->texture,
219                                         &surf_tmpl);
220    if (strb->surface) {
221       assert(strb->surface->texture);
222       assert(strb->surface->format);
223       assert(strb->surface->width == width);
224       assert(strb->surface->height == height);
225    }
226
227    return strb->surface != NULL;
228 }
229
230
231 /**
232  * gl_renderbuffer::Delete()
233  */
234 static void
235 st_renderbuffer_delete(struct gl_context *ctx, struct gl_renderbuffer *rb)
236 {
237    struct st_renderbuffer *strb = st_renderbuffer(rb);
238    if (ctx) {
239       struct st_context *st = st_context(ctx);
240       pipe_surface_release(st->pipe, &strb->surface);
241    }
242    pipe_resource_reference(&strb->texture, NULL);
243    free(strb->data);
244    _mesa_delete_renderbuffer(ctx, rb);
245 }
246
247
248 /**
249  * Called via ctx->Driver.NewFramebuffer()
250  */
251 static struct gl_framebuffer *
252 st_new_framebuffer(struct gl_context *ctx, GLuint name)
253 {
254    /* XXX not sure we need to subclass gl_framebuffer for pipe */
255    return _mesa_new_framebuffer(ctx, name);
256 }
257
258
259 /**
260  * Called via ctx->Driver.NewRenderbuffer()
261  */
262 static struct gl_renderbuffer *
263 st_new_renderbuffer(struct gl_context *ctx, GLuint name)
264 {
265    struct st_renderbuffer *strb = ST_CALLOC_STRUCT(st_renderbuffer);
266    if (strb) {
267       assert(name != 0);
268       _mesa_init_renderbuffer(&strb->Base, name);
269       strb->Base.Delete = st_renderbuffer_delete;
270       strb->Base.AllocStorage = st_renderbuffer_alloc_storage;
271       return &strb->Base;
272    }
273    return NULL;
274 }
275
276
277 /**
278  * Allocate a renderbuffer for a an on-screen window (not a user-created
279  * renderbuffer).  The window system code determines the format.
280  */
281 struct gl_renderbuffer *
282 st_new_renderbuffer_fb(enum pipe_format format, int samples, boolean sw)
283 {
284    struct st_renderbuffer *strb;
285
286    strb = ST_CALLOC_STRUCT(st_renderbuffer);
287    if (!strb) {
288       _mesa_error(NULL, GL_OUT_OF_MEMORY, "creating renderbuffer");
289       return NULL;
290    }
291
292    _mesa_init_renderbuffer(&strb->Base, 0);
293    strb->Base.ClassID = 0x4242; /* just a unique value */
294    strb->Base.NumSamples = samples;
295    strb->Base.Format = st_pipe_format_to_mesa_format(format);
296    strb->Base._BaseFormat = _mesa_get_format_base_format(strb->Base.Format);
297    strb->software = sw;
298    
299    switch (format) {
300    case PIPE_FORMAT_R8G8B8A8_UNORM:
301    case PIPE_FORMAT_B8G8R8A8_UNORM:
302    case PIPE_FORMAT_A8R8G8B8_UNORM:
303       strb->Base.InternalFormat = GL_RGBA8;
304       break;
305    case PIPE_FORMAT_R8G8B8X8_UNORM:
306    case PIPE_FORMAT_B8G8R8X8_UNORM:
307    case PIPE_FORMAT_X8R8G8B8_UNORM:
308       strb->Base.InternalFormat = GL_RGB8;
309       break;
310    case PIPE_FORMAT_B5G5R5A1_UNORM:
311       strb->Base.InternalFormat = GL_RGB5_A1;
312       break;
313    case PIPE_FORMAT_B4G4R4A4_UNORM:
314       strb->Base.InternalFormat = GL_RGBA4;
315       break;
316    case PIPE_FORMAT_B5G6R5_UNORM:
317       strb->Base.InternalFormat = GL_RGB565;
318       break;
319    case PIPE_FORMAT_Z16_UNORM:
320       strb->Base.InternalFormat = GL_DEPTH_COMPONENT16;
321       break;
322    case PIPE_FORMAT_Z32_UNORM:
323       strb->Base.InternalFormat = GL_DEPTH_COMPONENT32;
324       break;
325    case PIPE_FORMAT_Z24_UNORM_S8_UINT:
326    case PIPE_FORMAT_S8_UINT_Z24_UNORM:
327       strb->Base.InternalFormat = GL_DEPTH24_STENCIL8_EXT;
328       break;
329    case PIPE_FORMAT_Z24X8_UNORM:
330    case PIPE_FORMAT_X8Z24_UNORM:
331       strb->Base.InternalFormat = GL_DEPTH_COMPONENT24;
332       break;
333    case PIPE_FORMAT_S8_UINT:
334       strb->Base.InternalFormat = GL_STENCIL_INDEX8_EXT;
335       break;
336    case PIPE_FORMAT_R16G16B16A16_SNORM:
337       /* accum buffer */
338       strb->Base.InternalFormat = GL_RGBA16_SNORM;
339       break;
340    case PIPE_FORMAT_R16G16B16A16_UNORM:
341       strb->Base.InternalFormat = GL_RGBA16;
342       break;
343    case PIPE_FORMAT_R8_UNORM:
344       strb->Base.InternalFormat = GL_R8;
345       break;
346    case PIPE_FORMAT_R8G8_UNORM:
347       strb->Base.InternalFormat = GL_RG8;
348       break;
349    case PIPE_FORMAT_R16_UNORM:
350       strb->Base.InternalFormat = GL_R16;
351       break;
352    case PIPE_FORMAT_R16G16_UNORM:
353       strb->Base.InternalFormat = GL_RG16;
354       break;
355    case PIPE_FORMAT_R32G32B32A32_FLOAT:
356       strb->Base.InternalFormat = GL_RGBA32F;
357       break;
358    case PIPE_FORMAT_R16G16B16A16_FLOAT:
359       strb->Base.InternalFormat = GL_RGBA16F;
360       break;
361    default:
362       _mesa_problem(NULL,
363                     "Unexpected format %s in st_new_renderbuffer_fb",
364                     util_format_name(format));
365       free(strb);
366       return NULL;
367    }
368
369    /* st-specific methods */
370    strb->Base.Delete = st_renderbuffer_delete;
371    strb->Base.AllocStorage = st_renderbuffer_alloc_storage;
372
373    /* surface is allocated in st_renderbuffer_alloc_storage() */
374    strb->surface = NULL;
375
376    return &strb->Base;
377 }
378
379
380 /**
381  * Called via ctx->Driver.BindFramebufferEXT().
382  */
383 static void
384 st_bind_framebuffer(struct gl_context *ctx, GLenum target,
385                     struct gl_framebuffer *fb, struct gl_framebuffer *fbread)
386 {
387    /* no-op */
388 }
389
390
391 /**
392  * Create or update the pipe_surface of a FBO renderbuffer.
393  * This is usually called after st_finalize_texture.
394  */
395 void
396 st_update_renderbuffer_surface(struct st_context *st,
397                                struct st_renderbuffer *strb)
398 {
399    struct pipe_context *pipe = st->pipe;
400    struct pipe_resource *resource = strb->texture;
401    int rtt_width = strb->Base.Width;
402    int rtt_height = strb->Base.Height;
403    int rtt_depth = strb->Base.Depth;
404    enum pipe_format format = st->ctx->Color.sRGBEnabled ? resource->format :
405          util_format_linear(resource->format);
406    unsigned first_layer, last_layer, level;
407
408    if (resource->target == PIPE_TEXTURE_1D_ARRAY) {
409       rtt_depth = rtt_height;
410       rtt_height = 1;
411    }
412
413    /* find matching mipmap level size */
414    for (level = 0; level <= resource->last_level; level++) {
415       if (u_minify(resource->width0, level) == rtt_width &&
416           u_minify(resource->height0, level) == rtt_height &&
417           (resource->target != PIPE_TEXTURE_3D ||
418            u_minify(resource->depth0, level) == rtt_depth)) {
419          break;
420       }
421    }
422    assert(level <= resource->last_level);
423
424    /* determine the layer bounds */
425    if (strb->rtt_layered) {
426       first_layer = 0;
427       last_layer = util_max_layer(strb->texture, level);
428    }
429    else {
430       first_layer =
431       last_layer = strb->rtt_face + strb->rtt_slice;
432    }
433
434    if (!strb->surface ||
435        strb->surface->texture->nr_samples != strb->Base.NumSamples ||
436        strb->surface->format != format ||
437        strb->surface->texture != resource ||
438        strb->surface->width != rtt_width ||
439        strb->surface->height != rtt_height ||
440        strb->surface->u.tex.level != level ||
441        strb->surface->u.tex.first_layer != first_layer ||
442        strb->surface->u.tex.last_layer != last_layer) {
443       /* create a new pipe_surface */
444       struct pipe_surface surf_tmpl;
445       memset(&surf_tmpl, 0, sizeof(surf_tmpl));
446       surf_tmpl.format = format;
447       surf_tmpl.u.tex.level = level;
448       surf_tmpl.u.tex.first_layer = first_layer;
449       surf_tmpl.u.tex.last_layer = last_layer;
450
451       pipe_surface_reference(&strb->surface, NULL);
452
453       strb->surface = pipe->create_surface(pipe, resource, &surf_tmpl);
454    }
455 }
456
457 /**
458  * Called by ctx->Driver.RenderTexture
459  */
460 static void
461 st_render_texture(struct gl_context *ctx,
462                   struct gl_framebuffer *fb,
463                   struct gl_renderbuffer_attachment *att)
464 {
465    struct st_context *st = st_context(ctx);
466    struct pipe_context *pipe = st->pipe;
467    struct gl_renderbuffer *rb = att->Renderbuffer;
468    struct st_renderbuffer *strb = st_renderbuffer(rb);
469    struct pipe_resource *pt;
470
471    if (!st_finalize_texture(ctx, pipe, att->Texture))
472       return;
473
474    pt = st_get_texobj_resource(att->Texture);
475    assert(pt);
476
477    /* point renderbuffer at texobject */
478    strb->is_rtt = TRUE;
479    strb->rtt_face = att->CubeMapFace;
480    strb->rtt_slice = att->Zoffset;
481    strb->rtt_layered = att->Layered;
482    pipe_resource_reference(&strb->texture, pt);
483
484    pipe_surface_release(pipe, &strb->surface);
485
486    st_update_renderbuffer_surface(st, strb);
487
488    strb->Base.Format = st_pipe_format_to_mesa_format(pt->format);
489
490    /* Invalidate buffer state so that the pipe's framebuffer state
491     * gets updated.
492     * That's where the new renderbuffer (which we just created) gets
493     * passed to the pipe as a (color/depth) render target.
494     */
495    st_invalidate_state(ctx, _NEW_BUFFERS);
496
497
498    /* Need to trigger a call to update_framebuffer() since we just
499     * attached a new renderbuffer.
500     */
501    ctx->NewState |= _NEW_BUFFERS;
502 }
503
504
505 /**
506  * Called via ctx->Driver.FinishRenderTexture.
507  */
508 static void
509 st_finish_render_texture(struct gl_context *ctx, struct gl_renderbuffer *rb)
510 {
511    struct st_renderbuffer *strb = st_renderbuffer(rb);
512
513    if (!strb)
514       return;
515
516    strb->is_rtt = FALSE;
517
518    /* restore previous framebuffer state */
519    st_invalidate_state(ctx, _NEW_BUFFERS);
520 }
521
522
523 /** Debug helper */
524 static void
525 st_fbo_invalid(const char *reason)
526 {
527    if (MESA_DEBUG_FLAGS & DEBUG_INCOMPLETE_FBO) {
528       _mesa_debug(NULL, "Invalid FBO: %s\n", reason);
529    }
530 }
531
532
533 /**
534  * Validate a renderbuffer attachment for a particular set of bindings.
535  */
536 static GLboolean
537 st_validate_attachment(struct gl_context *ctx,
538                        struct pipe_screen *screen,
539                        const struct gl_renderbuffer_attachment *att,
540                        unsigned bindings)
541 {
542    const struct st_texture_object *stObj = st_texture_object(att->Texture);
543    enum pipe_format format;
544    mesa_format texFormat;
545    GLboolean valid;
546
547    /* Sanity check: we must be binding the surface as a (color) render target
548     * or depth/stencil target.
549     */
550    assert(bindings == PIPE_BIND_RENDER_TARGET ||
551           bindings == PIPE_BIND_DEPTH_STENCIL);
552
553    /* Only validate texture attachments for now, since
554     * st_renderbuffer_alloc_storage makes sure that
555     * the format is supported.
556     */
557    if (att->Type != GL_TEXTURE)
558       return GL_TRUE;
559
560    if (!stObj || !stObj->pt)
561       return GL_FALSE;
562
563    format = stObj->pt->format;
564    texFormat = att->Renderbuffer->TexImage->TexFormat;
565
566    /* If the encoding is sRGB and sRGB rendering cannot be enabled,
567     * check for linear format support instead.
568     * Later when we create a surface, we change the format to a linear one. */
569    if (!ctx->Extensions.EXT_framebuffer_sRGB &&
570        _mesa_get_format_color_encoding(texFormat) == GL_SRGB) {
571       const mesa_format linearFormat = _mesa_get_srgb_format_linear(texFormat);
572       format = st_mesa_format_to_pipe_format(linearFormat);
573    }
574
575    valid = screen->is_format_supported(screen, format,
576                                       PIPE_TEXTURE_2D,
577                                       stObj->pt->nr_samples, bindings);
578    if (!valid) {
579       st_fbo_invalid("Invalid format");
580    }
581
582    return valid;
583 }
584  
585
586 /**
587  * Check that the framebuffer configuration is valid in terms of what
588  * the driver can support.
589  *
590  * For Gallium we only supports combined Z+stencil, not separate buffers.
591  */
592 static void
593 st_validate_framebuffer(struct gl_context *ctx, struct gl_framebuffer *fb)
594 {
595    struct st_context *st = st_context(ctx);
596    struct pipe_screen *screen = st->pipe->screen;
597    const struct gl_renderbuffer_attachment *depth =
598          &fb->Attachment[BUFFER_DEPTH];
599    const struct gl_renderbuffer_attachment *stencil =
600          &fb->Attachment[BUFFER_STENCIL];
601    GLuint i;
602    enum pipe_format first_format = PIPE_FORMAT_NONE;
603    boolean mixed_formats =
604          screen->get_param(screen, PIPE_CAP_MIXED_COLORBUFFER_FORMATS) != 0;
605
606    if (depth->Type && stencil->Type && depth->Type != stencil->Type) {
607       st_fbo_invalid("Different Depth/Stencil buffer formats");
608       fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
609       return;
610    }
611    if (depth->Type == GL_RENDERBUFFER_EXT &&
612        stencil->Type == GL_RENDERBUFFER_EXT &&
613        depth->Renderbuffer != stencil->Renderbuffer) {
614       st_fbo_invalid("Separate Depth/Stencil buffers");
615       fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
616       return;
617    }
618    if (depth->Type == GL_TEXTURE &&
619        stencil->Type == GL_TEXTURE &&
620        depth->Texture != stencil->Texture) {
621       fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
622       st_fbo_invalid("Different Depth/Stencil textures");
623       return;
624    }
625
626    if (!st_validate_attachment(ctx,
627                                screen,
628                                depth,
629                                PIPE_BIND_DEPTH_STENCIL)) {
630       fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
631       return;
632    }
633    if (!st_validate_attachment(ctx,
634                                screen,
635                                stencil,
636                                PIPE_BIND_DEPTH_STENCIL)) {
637       fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
638       return;
639    }
640    for (i = 0; i < ctx->Const.MaxColorAttachments; i++) {
641       struct gl_renderbuffer_attachment *att =
642             &fb->Attachment[BUFFER_COLOR0 + i];
643       enum pipe_format format;
644
645       if (!st_validate_attachment(ctx,
646                                   screen,
647                                   att,
648                                   PIPE_BIND_RENDER_TARGET)) {
649          fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
650          return;
651       }
652
653       if (!mixed_formats) {
654          /* Disallow mixed formats. */
655          if (att->Type != GL_NONE) {
656             format = st_renderbuffer(att->Renderbuffer)->surface->format;
657          } else {
658             continue;
659          }
660
661          if (first_format == PIPE_FORMAT_NONE) {
662             first_format = format;
663          } else if (format != first_format) {
664             fb->_Status = GL_FRAMEBUFFER_UNSUPPORTED_EXT;
665             st_fbo_invalid("Mixed color formats");
666             return;
667          }
668       }
669    }
670 }
671
672
673 /**
674  * Called via glDrawBuffer.
675  */
676 static void
677 st_DrawBuffers(struct gl_context *ctx, GLsizei count, const GLenum *buffers)
678 {
679    struct st_context *st = st_context(ctx);
680    struct gl_framebuffer *fb = ctx->DrawBuffer;
681    GLuint i;
682
683    (void) count;
684    (void) buffers;
685
686    /* add the renderbuffers on demand */
687    for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
688       gl_buffer_index idx = fb->_ColorDrawBufferIndexes[i];
689
690       if (idx >= 0) {
691          st_manager_add_color_renderbuffer(st, fb, idx);
692       }
693    }
694 }
695
696
697 /**
698  * Called via glReadBuffer.
699  */
700 static void
701 st_ReadBuffer(struct gl_context *ctx, GLenum buffer)
702 {
703    struct st_context *st = st_context(ctx);
704    struct gl_framebuffer *fb = ctx->ReadBuffer;
705
706    (void) buffer;
707
708    /* add the renderbuffer on demand */
709    if (fb->_ColorReadBufferIndex >= 0)
710       st_manager_add_color_renderbuffer(st, fb, fb->_ColorReadBufferIndex);
711 }
712
713
714
715 /**
716  * Called via ctx->Driver.MapRenderbuffer.
717  */
718 static void
719 st_MapRenderbuffer(struct gl_context *ctx,
720                    struct gl_renderbuffer *rb,
721                    GLuint x, GLuint y, GLuint w, GLuint h,
722                    GLbitfield mode,
723                    GLubyte **mapOut, GLint *rowStrideOut)
724 {
725    struct st_context *st = st_context(ctx);
726    struct st_renderbuffer *strb = st_renderbuffer(rb);
727    struct pipe_context *pipe = st->pipe;
728    const GLboolean invert = rb->Name == 0;
729    unsigned usage;
730    GLuint y2;
731    GLubyte *map;
732
733    if (strb->software) {
734       /* software-allocated renderbuffer (probably an accum buffer) */
735       if (strb->data) {
736          GLint bpp = _mesa_get_format_bytes(strb->Base.Format);
737          GLint stride = _mesa_format_row_stride(strb->Base.Format,
738                                                 strb->Base.Width);
739          *mapOut = (GLubyte *) strb->data + y * stride + x * bpp;
740          *rowStrideOut = stride;
741       }
742       else {
743          *mapOut = NULL;
744          *rowStrideOut = 0;
745       }
746       return;
747    }
748
749    usage = 0x0;
750    if (mode & GL_MAP_READ_BIT)
751       usage |= PIPE_TRANSFER_READ;
752    if (mode & GL_MAP_WRITE_BIT)
753       usage |= PIPE_TRANSFER_WRITE;
754    if (mode & GL_MAP_INVALIDATE_RANGE_BIT)
755       usage |= PIPE_TRANSFER_DISCARD_RANGE;
756
757    /* Note: y=0=bottom of buffer while y2=0=top of buffer.
758     * 'invert' will be true for window-system buffers and false for
759     * user-allocated renderbuffers and textures.
760     */
761    if (invert)
762       y2 = strb->Base.Height - y - h;
763    else
764       y2 = y;
765
766     map = pipe_transfer_map(pipe,
767                             strb->texture,
768                             strb->surface->u.tex.level,
769                             strb->surface->u.tex.first_layer,
770                             usage, x, y2, w, h, &strb->transfer);
771    if (map) {
772       if (invert) {
773          *rowStrideOut = -(int) strb->transfer->stride;
774          map += (h - 1) * strb->transfer->stride;
775       }
776       else {
777          *rowStrideOut = strb->transfer->stride;
778       }
779       *mapOut = map;
780    }
781    else {
782       *mapOut = NULL;
783       *rowStrideOut = 0;
784    }
785 }
786
787
788 /**
789  * Called via ctx->Driver.UnmapRenderbuffer.
790  */
791 static void
792 st_UnmapRenderbuffer(struct gl_context *ctx,
793                      struct gl_renderbuffer *rb)
794 {
795    struct st_context *st = st_context(ctx);
796    struct st_renderbuffer *strb = st_renderbuffer(rb);
797    struct pipe_context *pipe = st->pipe;
798
799    if (strb->software) {
800       /* software-allocated renderbuffer (probably an accum buffer) */
801       return;
802    }
803
804    pipe_transfer_unmap(pipe, strb->transfer);
805    strb->transfer = NULL;
806 }
807
808
809
810 void st_init_fbo_functions(struct dd_function_table *functions)
811 {
812    functions->NewFramebuffer = st_new_framebuffer;
813    functions->NewRenderbuffer = st_new_renderbuffer;
814    functions->BindFramebuffer = st_bind_framebuffer;
815    functions->FramebufferRenderbuffer = _mesa_framebuffer_renderbuffer;
816    functions->RenderTexture = st_render_texture;
817    functions->FinishRenderTexture = st_finish_render_texture;
818    functions->ValidateFramebuffer = st_validate_framebuffer;
819
820    functions->DrawBuffers = st_DrawBuffers;
821    functions->ReadBuffer = st_ReadBuffer;
822
823    functions->MapRenderbuffer = st_MapRenderbuffer;
824    functions->UnmapRenderbuffer = st_UnmapRenderbuffer;
825 }
826
827