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