summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrian <brian@nostromo.localnet.net>2007-03-11 17:00:39 -0600
committerBrian <brian@nostromo.localnet.net>2007-03-11 17:00:39 -0600
commit1c09bcfdda4083636a3ac27d804a34ef87875ce7 (patch)
tree9d97cdcff44f9a789e0bec8c15609d61c3db2d17
parentd23dd812ad597ddbe82be5f95708ece9ad63a2fa (diff)
Implement support for GL_ARB_draw_buffers with GL_MAX_DRAW_BUFFERS > 1.
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.
-rw-r--r--src/mesa/main/config.h2
-rw-r--r--src/mesa/main/mtypes.h3
-rw-r--r--src/mesa/shader/slang/slang_codegen.c1
-rw-r--r--src/mesa/swrast/s_context.c41
-rw-r--r--src/mesa/swrast/s_context.h4
-rw-r--r--src/mesa/swrast/s_fragprog.c24
-rw-r--r--src/mesa/swrast/s_span.c152
7 files changed, 152 insertions, 75 deletions
diff --git a/src/mesa/main/config.h b/src/mesa/main/config.h
index 00df084fc8..8ea2d2c615 100644
--- a/src/mesa/main/config.h
+++ b/src/mesa/main/config.h
@@ -216,7 +216,7 @@
/** For GL_ARB_draw_buffers */
/*@{*/
-#define MAX_DRAW_BUFFERS 1
+#define MAX_DRAW_BUFFERS 4
/*@}*/
diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
index b08e77ea88..25a5a3cc36 100644
--- a/src/mesa/main/mtypes.h
+++ b/src/mesa/main/mtypes.h
@@ -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)
};
diff --git a/src/mesa/shader/slang/slang_codegen.c b/src/mesa/shader/slang/slang_codegen.c
index 640b87a34d..88a4b2d657 100644
--- a/src/mesa/shader/slang/slang_codegen.c
+++ b/src/mesa/shader/slang/slang_codegen.c
@@ -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;
diff --git a/src/mesa/swrast/s_context.c b/src/mesa/swrast/s_context.c
index 8864c217a5..00702b4301 100644
--- a/src/mesa/swrast/s_context.c
+++ b/src/mesa/swrast/s_context.c
@@ -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;
diff --git a/src/mesa/swrast/s_context.h b/src/mesa/swrast/s_context.h
index a3f61cd5e5..3a9a48922e 100644
--- a/src/mesa/swrast/s_context.h
+++ b/src/mesa/swrast/s_context.h
@@ -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.
*/
diff --git a/src/mesa/swrast/s_fragprog.c b/src/mesa/swrast/s_fragprog.c
index dbfc1b8c0c..7260759306 100644
--- a/src/mesa/swrast/s_fragprog.c
+++ b/src/mesa/swrast/s_fragprog.c
@@ -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;
diff --git a/src/mesa/swrast/s_span.c b/src/mesa/swrast/s_span.c
index a2044d0042..f9f0a1f813 100644
--- a/src/mesa/swrast/s_span.c
+++ b/src/mesa/swrast/s_span.c
@@ -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 */