17117f1b4Smrg/*
27117f1b4Smrg * Mesa 3-D graphics library
37117f1b4Smrg *
47117f1b4Smrg * Copyright (C) 1999-2007  Brian Paul   All Rights Reserved.
57117f1b4Smrg *
67117f1b4Smrg * Permission is hereby granted, free of charge, to any person obtaining a
77117f1b4Smrg * copy of this software and associated documentation files (the "Software"),
87117f1b4Smrg * to deal in the Software without restriction, including without limitation
97117f1b4Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
107117f1b4Smrg * and/or sell copies of the Software, and to permit persons to whom the
117117f1b4Smrg * Software is furnished to do so, subject to the following conditions:
127117f1b4Smrg *
137117f1b4Smrg * The above copyright notice and this permission notice shall be included
147117f1b4Smrg * in all copies or substantial portions of the Software.
157117f1b4Smrg *
167117f1b4Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
177117f1b4Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
187117f1b4Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19af69d88dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20af69d88dSmrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21af69d88dSmrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22af69d88dSmrg * OTHER DEALINGS IN THE SOFTWARE.
237117f1b4Smrg */
247117f1b4Smrg
25c1f859d4Smrg#include "main/glheader.h"
2601e04c3fSmrg#include "main/macros.h"
27af69d88dSmrg#include "main/samplerobj.h"
2801e04c3fSmrg#include "main/teximage.h"
293464ebd5Sriastradh#include "program/prog_instruction.h"
307117f1b4Smrg
313464ebd5Sriastradh#include "s_context.h"
327117f1b4Smrg#include "s_fragprog.h"
337117f1b4Smrg#include "s_span.h"
347117f1b4Smrg
35af69d88dSmrg/**
36af69d88dSmrg * \brief Should swrast use a fragment program?
37af69d88dSmrg *
38af69d88dSmrg * \return true if the current fragment program exists and is not the fixed
39af69d88dSmrg *         function fragment program
40af69d88dSmrg */
41af69d88dSmrgGLboolean
42af69d88dSmrg_swrast_use_fragment_program(struct gl_context *ctx)
43af69d88dSmrg{
4401e04c3fSmrg   struct gl_program *fp = ctx->FragmentProgram._Current;
45af69d88dSmrg   return fp && !(fp == ctx->FragmentProgram._TexEnvProgram
4601e04c3fSmrg                  && fp->arb.NumInstructions == 0);
47af69d88dSmrg}
487117f1b4Smrg
494a49301eSmrg/**
504a49301eSmrg * Apply texture object's swizzle (X/Y/Z/W/0/1) to incoming 'texel'
514a49301eSmrg * and return results in 'colorOut'.
524a49301eSmrg */
53af69d88dSmrgstatic inline void
544a49301eSmrgswizzle_texel(const GLfloat texel[4], GLfloat colorOut[4], GLuint swizzle)
554a49301eSmrg{
564a49301eSmrg   if (swizzle == SWIZZLE_NOOP) {
574a49301eSmrg      COPY_4V(colorOut, texel);
584a49301eSmrg   }
594a49301eSmrg   else {
604a49301eSmrg      GLfloat vector[6];
614a49301eSmrg      vector[SWIZZLE_X] = texel[0];
624a49301eSmrg      vector[SWIZZLE_Y] = texel[1];
634a49301eSmrg      vector[SWIZZLE_Z] = texel[2];
644a49301eSmrg      vector[SWIZZLE_W] = texel[3];
654a49301eSmrg      vector[SWIZZLE_ZERO] = 0.0F;
664a49301eSmrg      vector[SWIZZLE_ONE] = 1.0F;
674a49301eSmrg      colorOut[0] = vector[GET_SWZ(swizzle, 0)];
684a49301eSmrg      colorOut[1] = vector[GET_SWZ(swizzle, 1)];
694a49301eSmrg      colorOut[2] = vector[GET_SWZ(swizzle, 2)];
704a49301eSmrg      colorOut[3] = vector[GET_SWZ(swizzle, 3)];
714a49301eSmrg   }
724a49301eSmrg}
734a49301eSmrg
744a49301eSmrg
757117f1b4Smrg/**
76c1f859d4Smrg * Fetch a texel with given lod.
77c1f859d4Smrg * Called via machine->FetchTexelLod()
787117f1b4Smrg */
797117f1b4Smrgstatic void
803464ebd5Sriastradhfetch_texel_lod( struct gl_context *ctx, const GLfloat texcoord[4], GLfloat lambda,
81c1f859d4Smrg                 GLuint unit, GLfloat color[4] )
827117f1b4Smrg{
837117f1b4Smrg   const struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
847117f1b4Smrg
85c1f859d4Smrg   if (texObj) {
86c1f859d4Smrg      SWcontext *swrast = SWRAST_CONTEXT(ctx);
874a49301eSmrg      GLfloat rgba[4];
88af69d88dSmrg      const struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, unit);
89c1f859d4Smrg
907ec681f3Smrg      lambda = CLAMP(lambda, samp->Attrib.MinLod, samp->Attrib.MaxLod);
917117f1b4Smrg
92af69d88dSmrg      swrast->TextureSample[unit](ctx, samp, ctx->Texture.Unit[unit]._Current,
93af69d88dSmrg                                  1, (const GLfloat (*)[4]) texcoord,
94c1f859d4Smrg                                  &lambda, &rgba);
957ec681f3Smrg      swizzle_texel(rgba, color, texObj->Attrib._Swizzle);
96c1f859d4Smrg   }
97c1f859d4Smrg   else {
984a49301eSmrg      ASSIGN_4V(color, 0.0F, 0.0F, 0.0F, 1.0F);
99c1f859d4Smrg   }
1007117f1b4Smrg}
1017117f1b4Smrg
1027117f1b4Smrg
1037117f1b4Smrg/**
1047117f1b4Smrg * Fetch a texel with the given partial derivatives to compute a level
1057117f1b4Smrg * of detail in the mipmap.
106c1f859d4Smrg * Called via machine->FetchTexelDeriv()
1074a49301eSmrg * \param lodBias  the lod bias which may be specified by a TXB instruction,
1084a49301eSmrg *                 otherwise zero.
1097117f1b4Smrg */
1107117f1b4Smrgstatic void
1113464ebd5Sriastradhfetch_texel_deriv( struct gl_context *ctx, const GLfloat texcoord[4],
1127117f1b4Smrg                   const GLfloat texdx[4], const GLfloat texdy[4],
1137117f1b4Smrg                   GLfloat lodBias, GLuint unit, GLfloat color[4] )
1147117f1b4Smrg{
1157117f1b4Smrg   SWcontext *swrast = SWRAST_CONTEXT(ctx);
1164a49301eSmrg   const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
1174a49301eSmrg   const struct gl_texture_object *texObj = texUnit->_Current;
118c1f859d4Smrg
119c1f859d4Smrg   if (texObj) {
12001e04c3fSmrg      const struct gl_texture_image *texImg = _mesa_base_tex_image(texObj);
121af69d88dSmrg      const struct swrast_texture_image *swImg =
122af69d88dSmrg         swrast_texture_image_const(texImg);
123af69d88dSmrg      const struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, unit);
124af69d88dSmrg      const GLfloat texW = (GLfloat) swImg->WidthScale;
125af69d88dSmrg      const GLfloat texH = (GLfloat) swImg->HeightScale;
126c1f859d4Smrg      GLfloat lambda;
1274a49301eSmrg      GLfloat rgba[4];
128c1f859d4Smrg
129c1f859d4Smrg      lambda = _swrast_compute_lambda(texdx[0], texdy[0], /* ds/dx, ds/dy */
130c1f859d4Smrg                                      texdx[1], texdy[1], /* dt/dx, dt/dy */
1314a49301eSmrg                                      texdx[3], texdy[3], /* dq/dx, dq/dy */
132c1f859d4Smrg                                      texW, texH,
133c1f859d4Smrg                                      texcoord[0], texcoord[1], texcoord[3],
1344a49301eSmrg                                      1.0F / texcoord[3]);
1354a49301eSmrg
1367ec681f3Smrg      lambda += lodBias + texUnit->LodBias + samp->Attrib.LodBias;
137c1f859d4Smrg
1387ec681f3Smrg      lambda = CLAMP(lambda, samp->Attrib.MinLod, samp->Attrib.MaxLod);
139c1f859d4Smrg
140af69d88dSmrg      swrast->TextureSample[unit](ctx, samp, ctx->Texture.Unit[unit]._Current,
141af69d88dSmrg                                  1, (const GLfloat (*)[4]) texcoord,
142c1f859d4Smrg                                  &lambda, &rgba);
1437ec681f3Smrg      swizzle_texel(rgba, color, texObj->Attrib._Swizzle);
144c1f859d4Smrg   }
145c1f859d4Smrg   else {
1464a49301eSmrg      ASSIGN_4V(color, 0.0F, 0.0F, 0.0F, 1.0F);
147c1f859d4Smrg   }
1487117f1b4Smrg}
1497117f1b4Smrg
1507117f1b4Smrg
1517117f1b4Smrg/**
1527117f1b4Smrg * Initialize the virtual fragment program machine state prior to running
1537117f1b4Smrg * fragment program on a fragment.  This involves initializing the input
1547117f1b4Smrg * registers, condition codes, etc.
1557117f1b4Smrg * \param machine  the virtual machine state to init
1567117f1b4Smrg * \param program  the fragment program we're about to run
1577117f1b4Smrg * \param span  the span of pixels we'll operate on
1587117f1b4Smrg * \param col  which element (column) of the span we'll operate on
1597117f1b4Smrg */
1607117f1b4Smrgstatic void
1613464ebd5Sriastradhinit_machine(struct gl_context *ctx, struct gl_program_machine *machine,
16201e04c3fSmrg             const struct gl_program *program, const SWspan *span, GLuint col)
1637117f1b4Smrg{
164af69d88dSmrg   GLfloat *wpos = span->array->attribs[VARYING_SLOT_POS][col];
165cdc920a0Smrg
166cdc920a0Smrg   /* ARB_fragment_coord_conventions */
167b9abf16eSmaya   if (program->info.fs.origin_upper_left)
168cdc920a0Smrg      wpos[1] = ctx->DrawBuffer->Height - 1 - wpos[1];
169b9abf16eSmaya   if (!program->info.fs.pixel_center_integer) {
170cdc920a0Smrg      wpos[0] += 0.5F;
171cdc920a0Smrg      wpos[1] += 0.5F;
1727117f1b4Smrg   }
1737117f1b4Smrg
1747117f1b4Smrg   /* Setup pointer to input attributes */
1757117f1b4Smrg   machine->Attribs = span->array->attribs;
1767117f1b4Smrg
1777117f1b4Smrg   machine->DerivX = (GLfloat (*)[4]) span->attrStepX;
1787117f1b4Smrg   machine->DerivY = (GLfloat (*)[4]) span->attrStepY;
179af69d88dSmrg   machine->NumDeriv = VARYING_SLOT_MAX;
1807117f1b4Smrg
18101e04c3fSmrg   machine->Samplers = program->SamplerUnits;
182c1f859d4Smrg
183c1f859d4Smrg   /* if running a GLSL program (not ARB_fragment_program) */
184af69d88dSmrg   if (ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT]) {
1854a49301eSmrg      /* Store front/back facing value */
186af69d88dSmrg      machine->Attribs[VARYING_SLOT_FACE][col][0] = 1.0F - span->facing;
1877117f1b4Smrg   }
1887117f1b4Smrg
1897117f1b4Smrg   machine->CurElement = col;
1907117f1b4Smrg
1917117f1b4Smrg   /* init call stack */
1927117f1b4Smrg   machine->StackDepth = 0;
1937117f1b4Smrg
194c1f859d4Smrg   machine->FetchTexelLod = fetch_texel_lod;
1957117f1b4Smrg   machine->FetchTexelDeriv = fetch_texel_deriv;
1967117f1b4Smrg}
1977117f1b4Smrg
1987117f1b4Smrg
1997117f1b4Smrg/**
2007117f1b4Smrg * Run fragment program on the pixels in span from 'start' to 'end' - 1.
2017117f1b4Smrg */
2027117f1b4Smrgstatic void
2033464ebd5Sriastradhrun_program(struct gl_context *ctx, SWspan *span, GLuint start, GLuint end)
2047117f1b4Smrg{
2057117f1b4Smrg   SWcontext *swrast = SWRAST_CONTEXT(ctx);
20601e04c3fSmrg   const struct gl_program *program = ctx->FragmentProgram._Current;
20701e04c3fSmrg   const GLbitfield64 outputsWritten = program->info.outputs_written;
2087117f1b4Smrg   struct gl_program_machine *machine = &swrast->FragProgMachine;
2097117f1b4Smrg   GLuint i;
2107117f1b4Smrg
2117117f1b4Smrg   for (i = start; i < end; i++) {
2127117f1b4Smrg      if (span->array->mask[i]) {
2137117f1b4Smrg         init_machine(ctx, machine, program, span, i);
2147117f1b4Smrg
21501e04c3fSmrg         if (_mesa_execute_program(ctx, program, machine)) {
2167117f1b4Smrg
2177117f1b4Smrg            /* Store result color */
2184a49301eSmrg	    if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) {
219af69d88dSmrg               COPY_4V(span->array->attribs[VARYING_SLOT_COL0][i],
2204a49301eSmrg                       machine->Outputs[FRAG_RESULT_COLOR]);
2217117f1b4Smrg            }
2227117f1b4Smrg            else {
2237117f1b4Smrg               /* Multiple drawbuffers / render targets
2247117f1b4Smrg                * Note that colors beyond 0 and 1 will overwrite other
2257117f1b4Smrg                * attributes, such as FOGC, TEX0, TEX1, etc.  That's OK.
2267117f1b4Smrg                */
227c1f859d4Smrg               GLuint buf;
228c1f859d4Smrg               for (buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) {
2294a49301eSmrg                  if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DATA0 + buf)) {
230af69d88dSmrg                     COPY_4V(span->array->attribs[VARYING_SLOT_COL0 + buf][i],
231c1f859d4Smrg                             machine->Outputs[FRAG_RESULT_DATA0 + buf]);
2327117f1b4Smrg                  }
2337117f1b4Smrg               }
2347117f1b4Smrg            }
2357117f1b4Smrg
2367117f1b4Smrg            /* Store result depth/z */
2374a49301eSmrg            if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) {
2384a49301eSmrg               const GLfloat depth = machine->Outputs[FRAG_RESULT_DEPTH][2];
23901e04c3fSmrg               if (depth <= 0.0F)
2407117f1b4Smrg                  span->array->z[i] = 0;
24101e04c3fSmrg               else if (depth >= 1.0F)
2427117f1b4Smrg                  span->array->z[i] = ctx->DrawBuffer->_DepthMax;
2437117f1b4Smrg               else
244af69d88dSmrg                  span->array->z[i] =
245af69d88dSmrg                     (GLuint) (depth * ctx->DrawBuffer->_DepthMaxF + 0.5F);
2467117f1b4Smrg            }
2477117f1b4Smrg         }
2487117f1b4Smrg         else {
2497117f1b4Smrg            /* killed fragment */
2507117f1b4Smrg            span->array->mask[i] = GL_FALSE;
2517117f1b4Smrg            span->writeAll = GL_FALSE;
2527117f1b4Smrg         }
2537117f1b4Smrg      }
2547117f1b4Smrg   }
2557117f1b4Smrg}
2567117f1b4Smrg
2577117f1b4Smrg
2587117f1b4Smrg/**
2597117f1b4Smrg * Execute the current fragment program for all the fragments
2607117f1b4Smrg * in the given span.
2617117f1b4Smrg */
2627117f1b4Smrgvoid
2633464ebd5Sriastradh_swrast_exec_fragment_program( struct gl_context *ctx, SWspan *span )
2647117f1b4Smrg{
26501e04c3fSmrg   const struct gl_program *program = ctx->FragmentProgram._Current;
2667117f1b4Smrg
2677117f1b4Smrg   /* incoming colors should be floats */
26801e04c3fSmrg   if (program->info.inputs_read & VARYING_BIT_COL0) {
26901e04c3fSmrg      assert(span->array->ChanType == GL_FLOAT);
2707117f1b4Smrg   }
2717117f1b4Smrg
2727117f1b4Smrg   run_program(ctx, span, 0, span->end);
2737117f1b4Smrg
27401e04c3fSmrg   if (program->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_COLOR)) {
2757117f1b4Smrg      span->interpMask &= ~SPAN_RGBA;
2767117f1b4Smrg      span->arrayMask |= SPAN_RGBA;
2777117f1b4Smrg   }
2787117f1b4Smrg
27901e04c3fSmrg   if (program->info.outputs_written & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) {
2807117f1b4Smrg      span->interpMask &= ~SPAN_Z;
2817117f1b4Smrg      span->arrayMask |= SPAN_Z;
2827117f1b4Smrg   }
2837117f1b4Smrg}
2847117f1b4Smrg
285