Implement support for GL_ARB_draw_buffers with GL_MAX_DRAW_BUFFERS > 1.
authorBrian <brian@nostromo.localnet.net>
Sun, 11 Mar 2007 23:00:39 +0000 (17:00 -0600)
committerBrian <brian@nostromo.localnet.net>
Sun, 11 Mar 2007 23:00:39 +0000 (17:00 -0600)
GL_MAX_DRAW_BUFFERS is currently 4.
Added gl_FragData[] output for fragment programs.
In _swrast_write_rgba_span() loop over the color outputs/renderbuffers.

src/mesa/main/config.h
src/mesa/main/mtypes.h
src/mesa/shader/slang/slang_codegen.c
src/mesa/swrast/s_context.c
src/mesa/swrast/s_context.h
src/mesa/swrast/s_fragprog.c
src/mesa/swrast/s_span.c

index 00df084fc881a935952cd1f34b4339e10d403f16..8ea2d2c615ad10c24d7ff1059055ca21fa3f391a 100644 (file)
 
 /** For GL_ARB_draw_buffers */
 /*@{*/
-#define MAX_DRAW_BUFFERS 1
+#define MAX_DRAW_BUFFERS 4
 /*@}*/
 
 
index b08e77ea880c2df42465b147aba812d2be6d3615..25a5a3cc3606322d1a70b5197f5d1b19d9fb54e5 100644 (file)
@@ -306,7 +306,8 @@ enum
    FRAG_RESULT_COLR = 0,
    FRAG_RESULT_COLH = 1,
    FRAG_RESULT_DEPR = 2,
-   FRAG_RESULT_MAX = 3
+   FRAG_RESULT_DATA0 = 3,
+   FRAG_RESULT_MAX = (FRAG_RESULT_DATA0 + MAX_DRAW_BUFFERS)
 };
 
 
index 640b87a34d30af29a97a946a3ea5aaef8a9925ac..88a4b2d6578aed7e90e012dbdcff5886f1375e44 100644 (file)
@@ -284,6 +284,7 @@ _slang_output_index(const char *name, GLenum target)
    static const struct output_info fragOutputs[] = {
       { "gl_FragColor", FRAG_RESULT_COLR },
       { "gl_FragDepth", FRAG_RESULT_DEPR },
+      { "gl_FragData", FRAG_RESULT_DATA0 },
       { NULL, 0 }
    };
    GLuint i;
index 8864c217a5e64df2b58bc700d1c596710556f55e..00702b43013121d2583b513dbf47227bc5985401 100644 (file)
@@ -548,6 +548,44 @@ _swrast_update_fragment_attribs(GLcontext *ctx)
 }
 
 
+/**
+ * Update the swrast->_ColorOutputsMask which indicates which color
+ * renderbuffers (aka rendertargets) are being written to by the current
+ * fragment program.
+ * We also take glDrawBuffers() into account to skip outputs that are
+ * set to GL_NONE.
+ */
+static void
+_swrast_update_color_outputs(GLcontext *ctx)
+{
+   SWcontext *swrast = SWRAST_CONTEXT(ctx);
+   const struct gl_framebuffer *fb = ctx->DrawBuffer;
+
+   swrast->_ColorOutputsMask = 0;
+   swrast->_NumColorOutputs = 0;
+
+   if (ctx->FragmentProgram._Current) {
+      const GLbitfield outputsWritten
+         = ctx->FragmentProgram._Current->Base.OutputsWritten;
+      GLuint output;
+      for (output = 0; output < ctx->Const.MaxDrawBuffers; output++) {
+         if ((outputsWritten & (1 << (FRAG_RESULT_DATA0 + output)))
+             && (fb->_NumColorDrawBuffers[output] > 0)) {
+            swrast->_ColorOutputsMask |= (1 << output);
+            swrast->_NumColorOutputs = output + 1;
+         }
+      }
+   }
+   if (swrast->_ColorOutputsMask == 0x0) {
+      /* no fragment program, or frag prog didn't write to gl_FragData[] */
+      if (fb->_NumColorDrawBuffers[0] > 0) {
+         swrast->_ColorOutputsMask = 0x1;
+         swrast->_NumColorOutputs = 1;
+      }
+   }
+}
+
+
 void
 _swrast_validate_derived( GLcontext *ctx )
 {
@@ -594,6 +632,9 @@ _swrast_validate_derived( GLcontext *ctx )
                               _NEW_TEXTURE))
          _swrast_update_fragment_attribs(ctx);
 
+      if (swrast->NewState & (_NEW_PROGRAM | _NEW_BUFFERS))
+         _swrast_update_color_outputs(ctx);
+
       swrast->NewState = 0;
       swrast->StateChanges = 0;
       swrast->InvalidateState = _swrast_invalidate_state;
index a3f61cd5e54c448fe2c4492af7da3614cc0e99c4..3a9a48922ef08e92b378d7ee3dcf562d4d407fba 100644 (file)
@@ -133,6 +133,10 @@ typedef struct
    GLboolean _FogEnabled;
    GLenum _FogMode;  /* either GL_FOG_MODE or fragment program's fog mode */
 
+   /** Multiple render targets */
+   GLbitfield _ColorOutputsMask;
+   GLuint _NumColorOutputs;
+
    /** Fragment attributes to compute during rasterization.
     * Mask of FRAG_BIT_* flags.
     */
index dbfc1b8c0cc00d8f35604a258d4b67e7c2c14857..7260759306ef5fb9f073e788b03f3c6161809946 100644 (file)
@@ -139,7 +139,9 @@ init_machine(GLcontext *ctx, struct gl_program_machine *machine,
 static void
 run_program(GLcontext *ctx, SWspan *span, GLuint start, GLuint end)
 {
+   SWcontext *swrast = SWRAST_CONTEXT(ctx);
    const struct gl_fragment_program *program = ctx->FragmentProgram._Current;
+   const GLbitfield outputsWritten = program->Base.OutputsWritten;
    struct gl_program_machine machine;
    GLuint i;
 
@@ -148,12 +150,28 @@ run_program(GLcontext *ctx, SWspan *span, GLuint start, GLuint end)
          init_machine(ctx, &machine, program, span, i);
 
          if (_mesa_execute_program(ctx, &program->Base, &machine)) {
+
             /* Store result color */
-            COPY_4V(span->array->attribs[FRAG_ATTRIB_COL0][i],
-                    machine.Outputs[FRAG_RESULT_COLR]);
+            if (outputsWritten & (1 << FRAG_RESULT_COLR)) {
+               COPY_4V(span->array->attribs[FRAG_ATTRIB_COL0][i],
+                       machine.Outputs[FRAG_RESULT_COLR]);
+            }
+            else {
+               /* Multiple drawbuffers / render targets
+                * Note that colors beyond 0 and 1 will overwrite other
+                * attributes, such as FOGC, TEX0, TEX1, etc.  That's OK.
+                */
+               GLuint output;
+               for (output = 0; output < swrast->_NumColorOutputs; output++) {
+                  if (outputsWritten & (1 << (FRAG_RESULT_DATA0 + output))) {
+                     COPY_4V(span->array->attribs[FRAG_ATTRIB_COL0+output][i],
+                             machine.Outputs[FRAG_RESULT_DATA0 + output]);
+                  }
+               }
+            }
 
             /* Store result depth/z */
-            if (program->Base.OutputsWritten & (1 << FRAG_RESULT_DEPR)) {
+            if (outputsWritten & (1 << FRAG_RESULT_DEPR)) {
                const GLfloat depth = machine.Outputs[FRAG_RESULT_DEPR][2];
                if (depth <= 0.0)
                   span->array->z[i] = 0;
index a2044d0042ea6b2c4ca4b1aba3fb6e1bc5be9462..f9f0a1f813df27113da81db52b425e3374bc57a6 100644 (file)
@@ -1215,24 +1215,31 @@ clamp_colors(SWspan *span)
 
 /**
  * Convert the span's color arrays to the given type.
+ * The only way 'output' can be greater than one is when we have a fragment
+ * program that writes to gl_FragData[1] or higher.
+ * \param output  which fragment program color output is being processed
  */
 static INLINE void
-convert_color_type(SWspan *span, GLenum newType)
+convert_color_type(SWspan *span, GLenum newType, GLuint output)
 {
    GLvoid *src, *dst;
-   if (span->array->ChanType == GL_UNSIGNED_BYTE) {
-      src = span->array->color.sz1.rgba;
+
+   if (output > 0 || span->array->ChanType == GL_FLOAT) {
+      src = span->array->attribs[FRAG_ATTRIB_COL0 + output];
+      span->array->ChanType = GL_FLOAT;
    }
    else if (span->array->ChanType == GL_UNSIGNED_BYTE) {
-      src = span->array->color.sz2.rgba;
+      src = span->array->color.sz1.rgba;
    }
    else {
-      src = span->array->attribs[FRAG_ATTRIB_COL0];
+      ASSERT(span->array->ChanType == GL_UNSIGNED_SHORT);
+      src = span->array->color.sz2.rgba;
    }
+
    if (newType == GL_UNSIGNED_BYTE) {
       dst = span->array->color.sz1.rgba;
    }
-   else if (newType == GL_UNSIGNED_BYTE) {
+   else if (newType == GL_UNSIGNED_SHORT) {
       dst = span->array->color.sz2.rgba;
    }
    else {
@@ -1329,6 +1336,8 @@ _swrast_write_rgba_span( GLcontext *ctx, SWspan *span)
    const GLboolean shader = (ctx->FragmentProgram._Current
                              || ctx->ATIFragmentShader._Enabled);
    const GLboolean shaderOrTexture = shader || ctx->Texture._EnabledUnits;
+   struct gl_framebuffer *fb = ctx->DrawBuffer;
+   GLuint output;
    GLboolean deferredTexture;
 
    /*
@@ -1393,10 +1402,10 @@ _swrast_write_rgba_span( GLcontext *ctx, SWspan *span)
       GLuint i;
       for (i = 0; i < span->end; i++) {
          if (span->array->mask[i]) {
-            assert(span->array->x[i] >= ctx->DrawBuffer->_Xmin);
-            assert(span->array->x[i] < ctx->DrawBuffer->_Xmax);
-            assert(span->array->y[i] >= ctx->DrawBuffer->_Ymin);
-            assert(span->array->y[i] < ctx->DrawBuffer->_Ymax);
+            assert(span->array->x[i] >= fb->_Xmin);
+            assert(span->array->x[i] < fb->_Xmax);
+            assert(span->array->y[i] >= fb->_Ymin);
+            assert(span->array->y[i] < fb->_Ymax);
          }
       }
    }
@@ -1428,13 +1437,13 @@ _swrast_write_rgba_span( GLcontext *ctx, SWspan *span)
       if (span->interpMask & SPAN_Z)
          _swrast_span_interpolate_z(ctx, span);
 
-      if (ctx->Stencil.Enabled && ctx->DrawBuffer->Visual.stencilBits > 0) {
+      if (ctx->Stencil.Enabled && fb->Visual.stencilBits > 0) {
          /* Combined Z/stencil tests */
          if (!_swrast_stencil_and_ztest_span(ctx, span)) {
             goto end;
          }
       }
-      else if (ctx->DrawBuffer->Visual.depthBits > 0) {
+      else if (fb->Visual.depthBits > 0) {
          /* Just regular depth testing */
          ASSERT(ctx->Depth.Test);
          ASSERT(span->arrayMask & SPAN_Z);
@@ -1514,64 +1523,67 @@ _swrast_write_rgba_span( GLcontext *ctx, SWspan *span)
    /*
     * Write to renderbuffers
     */
-   {
-      struct gl_framebuffer *fb = ctx->DrawBuffer;
-      const GLuint output = 0; /* only frag progs can write to other outputs */
-      const GLuint numDrawBuffers = fb->_NumColorDrawBuffers[output];
-      GLchan rgbaSave[MAX_WIDTH][4];
-      GLuint buf;
-
-      if (numDrawBuffers > 0) {
-         if (fb->_ColorDrawBuffers[output][0]->DataType
-             != span->array->ChanType) {
-            convert_color_type(span,
-                               fb->_ColorDrawBuffers[output][0]->DataType);
-         }
-      }
-
-      if (numDrawBuffers > 1) {
-         /* save colors for second, third renderbuffer writes */
-         _mesa_memcpy(rgbaSave, span->array->rgba,
-                      4 * span->end * sizeof(GLchan));
-      }
-
-      for (buf = 0; buf < numDrawBuffers; buf++) {
-         struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[output][buf];
-         ASSERT(rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB);
-
-         if (ctx->Color._LogicOpEnabled) {
-            _swrast_logicop_rgba_span(ctx, rb, span);
-         }
-         else if (ctx->Color.BlendEnabled) {
-            _swrast_blend_span(ctx, rb, span);
-         }
-
-         if (colorMask != 0xffffffff) {
-            _swrast_mask_rgba_span(ctx, rb, span);
-         }
-
-         if (span->arrayMask & SPAN_XY) {
-            /* array of pixel coords */
-            ASSERT(rb->PutValues);
-            rb->PutValues(ctx, rb, span->end,
-                          span->array->x, span->array->y,
-                          span->array->rgba, span->array->mask);
-         }
-         else {
-            /* horizontal run of pixels */
-            ASSERT(rb->PutRow);
-            rb->PutRow(ctx, rb, span->end, span->x, span->y, span->array->rgba,
-                       span->writeAll ? NULL: span->array->mask);
-         }
-
-         if (buf + 1 < numDrawBuffers) {
-            /* restore original span values */
-            _mesa_memcpy(span->array->rgba, rgbaSave,
-                         4 * span->end * sizeof(GLchan));
-         }
-      } /* for buf */
-
-   }
+   /* Loop over color outputs (GL_ARB_draw_buffers) written by frag prog */
+   for (output = 0; output < swrast->_NumColorOutputs; output++) {
+      if (swrast->_ColorOutputsMask & (1 << output)) {
+        const GLuint numDrawBuffers = fb->_NumColorDrawBuffers[output];
+        GLchan rgbaSave[MAX_WIDTH][4];
+        GLuint buf;
+
+        ASSERT(numDrawBuffers > 0);
+
+        if (fb->_ColorDrawBuffers[output][0]->DataType
+            != span->array->ChanType || output > 0) {
+           convert_color_type(span,
+                              fb->_ColorDrawBuffers[output][0]->DataType,
+                              output);
+        }
+
+        if (numDrawBuffers > 1) {
+           /* save colors for second, third renderbuffer writes */
+           _mesa_memcpy(rgbaSave, span->array->rgba,
+                        4 * span->end * sizeof(GLchan));
+        }
+
+        /* Loop over renderbuffers (i.e. GL_FRONT_AND_BACK) */
+        for (buf = 0; buf < numDrawBuffers; buf++) {
+           struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[output][buf];
+           ASSERT(rb->_BaseFormat == GL_RGBA || rb->_BaseFormat == GL_RGB);
+
+           if (ctx->Color._LogicOpEnabled) {
+              _swrast_logicop_rgba_span(ctx, rb, span);
+           }
+           else if (ctx->Color.BlendEnabled) {
+              _swrast_blend_span(ctx, rb, span);
+           }
+
+           if (colorMask != 0xffffffff) {
+              _swrast_mask_rgba_span(ctx, rb, span);
+           }
+
+           if (span->arrayMask & SPAN_XY) {
+              /* array of pixel coords */
+              ASSERT(rb->PutValues);
+              rb->PutValues(ctx, rb, span->end,
+                            span->array->x, span->array->y,
+                            span->array->rgba, span->array->mask);
+           }
+           else {
+              /* horizontal run of pixels */
+              ASSERT(rb->PutRow);
+              rb->PutRow(ctx, rb, span->end, span->x, span->y,
+                         span->array->rgba,
+                         span->writeAll ? NULL: span->array->mask);
+           }
+
+           if (buf + 1 < numDrawBuffers) {
+              /* restore original span values */
+              _mesa_memcpy(span->array->rgba, rgbaSave,
+                           4 * span->end * sizeof(GLchan));
+           }
+        } /* for buf */
+      } /* if output is written to */
+   } /* for output */
 
 end:
    /* restore these values before returning */