st/mesa: bind NULL colorbuffers as specified by glDrawBuffers
authorMarek Olšák <marek.olsak@amd.com>
Wed, 8 Jan 2014 00:09:15 +0000 (01:09 +0100)
committerMarek Olšák <marek.olsak@amd.com>
Mon, 13 Jan 2014 14:48:07 +0000 (15:48 +0100)
An example why it is required:

    Let's say there's a fragment shader writing to gl_FragData[0..1].
    The user calls: glDrawBuffers(2, {GL_NONE, GL_COLOR_ATTACHMENT0});

    That means gl_FragData[0] is unused and gl_FragData[1] is written
    to GL_COLOR_ATTACHMENT0.

st/mesa was skipping the GL_NONE draw buffer, therefore gl_FragData[0]
was written to GL_COLOR_ATTACHMENT0, which was wrong.

This commit fixes it, but drivers must also be fixed not to crash when
binding NULL colorbuffers. There is also a new set of piglit tests for this.

The MSAA state also had to be fixed not to crash when reading fb->cbufs[0].

Reviewed-by: Brian Paul <brianp@vmware.com>
src/gallium/auxiliary/util/u_framebuffer.c
src/gallium/auxiliary/util/u_framebuffer.h
src/mesa/state_tracker/st_atom_framebuffer.c
src/mesa/state_tracker/st_atom_msaa.c
src/mesa/state_tracker/st_cb_clear.c
src/mesa/state_tracker/st_cb_fbo.c

index 683967237e91df9563a3b20c953a893fceb60caf..377b802b62a74d5d0af184d79e294cdd5b6c839b 100644 (file)
@@ -171,3 +171,24 @@ util_framebuffer_get_num_layers(const struct pipe_framebuffer_state *fb)
        }
        return num_layers;
 }
+
+
+/**
+ * Return the number of MSAA samples.
+ */
+unsigned
+util_framebuffer_get_num_samples(const struct pipe_framebuffer_state *fb)
+{
+   unsigned i;
+
+   for (i = 0; i < fb->nr_cbufs; i++) {
+      if (fb->cbufs[i]) {
+         return MAX2(1, fb->cbufs[i]->texture->nr_samples);
+      }
+   }
+   if (fb->zsbuf) {
+      return MAX2(1, fb->zsbuf->texture->nr_samples);
+   }
+
+   return 1;
+}
index 0e6c98363a86376a7f137d90030481cc39df6afd..c73942c9c142b8c14656512f8fa8186b8202c080 100644 (file)
@@ -60,6 +60,10 @@ extern unsigned
 util_framebuffer_get_num_layers(const struct pipe_framebuffer_state *fb);
 
 
+extern unsigned
+util_framebuffer_get_num_samples(const struct pipe_framebuffer_state *fb);
+
+
 #ifdef __cplusplus
 }
 #endif
index 51f079cdad560b024a91227b4d887c8949b030b9..a77fe54ae12013499603ececfd82bd4be99a43bf 100644 (file)
@@ -65,12 +65,14 @@ update_framebuffer_state( struct st_context *st )
    /* Examine Mesa's ctx->DrawBuffer->_ColorDrawBuffers state
     * to determine which surfaces to draw to
     */
-   framebuffer->nr_cbufs = 0;
+   framebuffer->nr_cbufs = fb->_NumColorDrawBuffers;
+
    for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
+      pipe_surface_reference(&framebuffer->cbufs[i], NULL);
+
       strb = st_renderbuffer(fb->_ColorDrawBuffers[i]);
 
       if (strb) {
-         /*printf("--------- framebuffer surface rtt %p\n", strb->rtt);*/
          if (strb->is_rtt ||
              (strb->texture && util_format_is_srgb(strb->texture->format))) {
             /* rendering to a GL texture, may have to update surface */
@@ -78,13 +80,12 @@ update_framebuffer_state( struct st_context *st )
          }
 
          if (strb->surface) {
-            pipe_surface_reference(&framebuffer->cbufs[framebuffer->nr_cbufs],
-                                   strb->surface);
-            framebuffer->nr_cbufs++;
+            pipe_surface_reference(&framebuffer->cbufs[i], strb->surface);
          }
          strb->defined = GL_TRUE; /* we'll be drawing something */
       }
    }
+
    for (i = framebuffer->nr_cbufs; i < PIPE_MAX_COLOR_BUFS; i++) {
       pipe_surface_reference(&framebuffer->cbufs[i], NULL);
    }
@@ -113,7 +114,8 @@ update_framebuffer_state( struct st_context *st )
 #ifdef DEBUG
    /* Make sure the resource binding flags were set properly */
    for (i = 0; i < framebuffer->nr_cbufs; i++) {
-      assert(framebuffer->cbufs[i]->texture->bind & PIPE_BIND_RENDER_TARGET);
+      assert(!framebuffer->cbufs[i] ||
+             framebuffer->cbufs[i]->texture->bind & PIPE_BIND_RENDER_TARGET);
    }
    if (framebuffer->zsbuf) {
       assert(framebuffer->zsbuf->texture->bind & PIPE_BIND_DEPTH_STENCIL);
index fb760460c5738bfdca3f888fa638d57f9e5d8b05..2f3a42e0248f62334c3d67b9283c5d47766e222e 100644 (file)
@@ -31,6 +31,7 @@
 #include "st_atom.h"
 
 #include "cso_cache/cso_context.h"
+#include "util/u_framebuffer.h"
 
 
 /* Second state atom for user clip planes:
 static void update_sample_mask( struct st_context *st )
 {
    unsigned sample_mask = 0xffffffff;
-   unsigned sample_count = 1;
    struct pipe_framebuffer_state *framebuffer = &st->state.framebuffer;
-
    /* dependency here on bound surface (or rather, sample count) is worrying */
-   if (framebuffer->zsbuf)
-      sample_count = framebuffer->zsbuf->texture->nr_samples;
-   else if (framebuffer->cbufs[0])
-      sample_count = framebuffer->cbufs[0]->texture->nr_samples;
+   unsigned sample_count = util_framebuffer_get_num_samples(framebuffer);
 
    if (st->ctx->Multisample.Enabled && sample_count > 1) {
    /* unlike in gallium/d3d10 the mask is only active if msaa is enabled */
index a84c9075f5e882521ecf4cd0c629f89296d06ab8..87dccee1f4995f1c7abc0672b406e4ad67cfd802 100644 (file)
@@ -446,7 +446,7 @@ st_Clear(struct gl_context *ctx, GLbitfield mask)
       for (i = 0; i < ctx->DrawBuffer->_NumColorDrawBuffers; i++) {
          GLuint b = ctx->DrawBuffer->_ColorDrawBufferIndexes[i];
 
-         if (mask & (1 << b)) {
+         if (b >= 0 && mask & (1 << b)) {
             struct gl_renderbuffer *rb
                = ctx->DrawBuffer->Attachment[b].Renderbuffer;
             struct st_renderbuffer *strb = st_renderbuffer(rb);
index 70baa9965decf8fcffd8226485199cbbcc8400cf..daa94df92b8662c977ba12fd2ba57a55f1e65cc3 100644 (file)
@@ -680,7 +680,10 @@ st_DrawBuffers(struct gl_context *ctx, GLsizei count, const GLenum *buffers)
    /* add the renderbuffers on demand */
    for (i = 0; i < fb->_NumColorDrawBuffers; i++) {
       gl_buffer_index idx = fb->_ColorDrawBufferIndexes[i];
-      st_manager_add_color_renderbuffer(st, fb, idx);
+
+      if (idx >= 0) {
+         st_manager_add_color_renderbuffer(st, fb, idx);
+      }
    }
 }