Subversion Repositories Kolibri OS

Compare Revisions

Regard whitespace Rev 5563 → Rev 5564

/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/NOTES
0,0 → 1,55
INTRODUCTION
 
Mesa's native software rasterizer. This module provides the fallback
paths for rasterization operations and states that aren't accelerated
in hardware drivers, and as the full rasterization engine in software
drivers.
 
The swrast module 'stands alone', relying only on interfaces to core
mesa and it's own driver interface. It knows nothing about the tnl or
other modules, allowing it to be used for fallback paths in future tnl
schemes without modification.
 
As well as providing triangle/line/point rasterization functionality,
the module provides implementations of the pixel operations
(ReadPixels, etc), and texture operations (CopyTexSubImage) which may
be plugged in to the core Mesa driver interface where accelerated
versions of these operations are unavailable.
 
 
STATE
 
To create and destroy the module:
 
GLboolean _swrast_CreateContext( struct gl_context *ctx );
void _swrast_DestroyContext( struct gl_context *ctx );
This module tracks state changes internally and maintains derived
values based on the current state. For this to work, the driver
ensure the following funciton is called whenever the state changes and
the swsetup module is 'awake':
 
void _swrast_InvalidateState( struct gl_context *ctx, GLuint new_state );
 
There is no explicit call to put the swrast module to sleep.
 
 
CUSTOMIZATION
 
void (*choose_point)( struct gl_context * );
void (*choose_line)( struct gl_context * );
void (*choose_triangle)( struct gl_context * );
 
Drivers may add additional triangle/line/point functions to swrast by
overriding these functions. It is necessary for the driver to be very
careful that it doesn't return an inappropriate function, eg a
rasterization function in feedback mode. See the X11 driver for
examples.
 
DRIVER INTERFACE
 
The swrast device driver provides swrast primarily with span- and
pixel- level interfaces to a framebuffer, with a few additional hooks
for locking and setting the read buffer.
 
See the definition of struct swrast_device_driver in swrast.h.
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_aaline.c
0,0 → 1,494
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#include "c99_math.h"
#include "main/glheader.h"
#include "main/imports.h"
#include "main/macros.h"
#include "main/mtypes.h"
#include "main/teximage.h"
#include "swrast/s_aaline.h"
#include "swrast/s_context.h"
#include "swrast/s_span.h"
#include "swrast/swrast.h"
 
 
#define SUB_PIXEL 4
 
 
/*
* Info about the AA line we're rendering
*/
struct LineInfo
{
GLfloat x0, y0; /* start */
GLfloat x1, y1; /* end */
GLfloat dx, dy; /* direction vector */
GLfloat len; /* length */
GLfloat halfWidth; /* half of line width */
GLfloat xAdj, yAdj; /* X and Y adjustment for quad corners around line */
/* for coverage computation */
GLfloat qx0, qy0; /* quad vertices */
GLfloat qx1, qy1;
GLfloat qx2, qy2;
GLfloat qx3, qy3;
GLfloat ex0, ey0; /* quad edge vectors */
GLfloat ex1, ey1;
GLfloat ex2, ey2;
GLfloat ex3, ey3;
 
/* DO_Z */
GLfloat zPlane[4];
/* DO_RGBA - always enabled */
GLfloat rPlane[4], gPlane[4], bPlane[4], aPlane[4];
/* DO_ATTRIBS */
GLfloat wPlane[4];
GLfloat attrPlane[VARYING_SLOT_MAX][4][4];
GLfloat lambda[VARYING_SLOT_MAX];
GLfloat texWidth[VARYING_SLOT_MAX];
GLfloat texHeight[VARYING_SLOT_MAX];
 
SWspan span;
};
 
 
 
/*
* Compute the equation of a plane used to interpolate line fragment data
* such as color, Z, texture coords, etc.
* Input: (x0, y0) and (x1,y1) are the endpoints of the line.
* z0, and z1 are the end point values to interpolate.
* Output: plane - the plane equation.
*
* Note: we don't really have enough parameters to specify a plane.
* We take the endpoints of the line and compute a plane such that
* the cross product of the line vector and the plane normal is
* parallel to the projection plane.
*/
static void
compute_plane(GLfloat x0, GLfloat y0, GLfloat x1, GLfloat y1,
GLfloat z0, GLfloat z1, GLfloat plane[4])
{
#if 0
/* original */
const GLfloat px = x1 - x0;
const GLfloat py = y1 - y0;
const GLfloat pz = z1 - z0;
const GLfloat qx = -py;
const GLfloat qy = px;
const GLfloat qz = 0;
const GLfloat a = py * qz - pz * qy;
const GLfloat b = pz * qx - px * qz;
const GLfloat c = px * qy - py * qx;
const GLfloat d = -(a * x0 + b * y0 + c * z0);
plane[0] = a;
plane[1] = b;
plane[2] = c;
plane[3] = d;
#else
/* simplified */
const GLfloat px = x1 - x0;
const GLfloat py = y1 - y0;
const GLfloat pz = z0 - z1;
const GLfloat a = pz * px;
const GLfloat b = pz * py;
const GLfloat c = px * px + py * py;
const GLfloat d = -(a * x0 + b * y0 + c * z0);
if (a == 0.0 && b == 0.0 && c == 0.0 && d == 0.0) {
plane[0] = 0.0;
plane[1] = 0.0;
plane[2] = 1.0;
plane[3] = 0.0;
}
else {
plane[0] = a;
plane[1] = b;
plane[2] = c;
plane[3] = d;
}
#endif
}
 
 
static inline void
constant_plane(GLfloat value, GLfloat plane[4])
{
plane[0] = 0.0;
plane[1] = 0.0;
plane[2] = -1.0;
plane[3] = value;
}
 
 
static inline GLfloat
solve_plane(GLfloat x, GLfloat y, const GLfloat plane[4])
{
const GLfloat z = (plane[3] + plane[0] * x + plane[1] * y) / -plane[2];
return z;
}
 
#define SOLVE_PLANE(X, Y, PLANE) \
((PLANE[3] + PLANE[0] * (X) + PLANE[1] * (Y)) / -PLANE[2])
 
 
/*
* Return 1 / solve_plane().
*/
static inline GLfloat
solve_plane_recip(GLfloat x, GLfloat y, const GLfloat plane[4])
{
const GLfloat denom = plane[3] + plane[0] * x + plane[1] * y;
if (denom == 0.0)
return 0.0;
else
return -plane[2] / denom;
}
 
 
/*
* Solve plane and return clamped GLchan value.
*/
static inline GLchan
solve_plane_chan(GLfloat x, GLfloat y, const GLfloat plane[4])
{
const GLfloat z = (plane[3] + plane[0] * x + plane[1] * y) / -plane[2];
#if CHAN_TYPE == GL_FLOAT
return CLAMP(z, 0.0F, CHAN_MAXF);
#else
if (z < 0)
return 0;
else if (z > CHAN_MAX)
return CHAN_MAX;
return (GLchan) IROUND_POS(z);
#endif
}
 
 
/*
* Compute mipmap level of detail.
*/
static inline GLfloat
compute_lambda(const GLfloat sPlane[4], const GLfloat tPlane[4],
GLfloat invQ, GLfloat width, GLfloat height)
{
GLfloat dudx = sPlane[0] / sPlane[2] * invQ * width;
GLfloat dudy = sPlane[1] / sPlane[2] * invQ * width;
GLfloat dvdx = tPlane[0] / tPlane[2] * invQ * height;
GLfloat dvdy = tPlane[1] / tPlane[2] * invQ * height;
GLfloat r1 = dudx * dudx + dudy * dudy;
GLfloat r2 = dvdx * dvdx + dvdy * dvdy;
GLfloat rho2 = r1 + r2;
/* return log base 2 of rho */
if (rho2 == 0.0F)
return 0.0;
else
return logf(rho2) * 1.442695f * 0.5f;/* 1.442695 = 1/log(2) */
}
 
 
 
 
/*
* Fill in the samples[] array with the (x,y) subpixel positions of
* xSamples * ySamples sample positions.
* Note that the four corner samples are put into the first four
* positions of the array. This allows us to optimize for the common
* case of all samples being inside the polygon.
*/
static void
make_sample_table(GLint xSamples, GLint ySamples, GLfloat samples[][2])
{
const GLfloat dx = 1.0F / (GLfloat) xSamples;
const GLfloat dy = 1.0F / (GLfloat) ySamples;
GLint x, y;
GLint i;
 
i = 4;
for (x = 0; x < xSamples; x++) {
for (y = 0; y < ySamples; y++) {
GLint j;
if (x == 0 && y == 0) {
/* lower left */
j = 0;
}
else if (x == xSamples - 1 && y == 0) {
/* lower right */
j = 1;
}
else if (x == 0 && y == ySamples - 1) {
/* upper left */
j = 2;
}
else if (x == xSamples - 1 && y == ySamples - 1) {
/* upper right */
j = 3;
}
else {
j = i++;
}
samples[j][0] = x * dx + 0.5F * dx;
samples[j][1] = y * dy + 0.5F * dy;
}
}
}
 
 
 
/*
* Compute how much of the given pixel's area is inside the rectangle
* defined by vertices v0, v1, v2, v3.
* Vertices MUST be specified in counter-clockwise order.
* Return: coverage in [0, 1].
*/
static GLfloat
compute_coveragef(const struct LineInfo *info,
GLint winx, GLint winy)
{
static GLfloat samples[SUB_PIXEL * SUB_PIXEL][2];
static GLboolean haveSamples = GL_FALSE;
const GLfloat x = (GLfloat) winx;
const GLfloat y = (GLfloat) winy;
GLint stop = 4, i;
GLfloat insideCount = SUB_PIXEL * SUB_PIXEL;
 
if (!haveSamples) {
make_sample_table(SUB_PIXEL, SUB_PIXEL, samples);
haveSamples = GL_TRUE;
}
 
#if 0 /*DEBUG*/
{
const GLfloat area = dx0 * dy1 - dx1 * dy0;
assert(area >= 0.0);
}
#endif
 
for (i = 0; i < stop; i++) {
const GLfloat sx = x + samples[i][0];
const GLfloat sy = y + samples[i][1];
const GLfloat fx0 = sx - info->qx0;
const GLfloat fy0 = sy - info->qy0;
const GLfloat fx1 = sx - info->qx1;
const GLfloat fy1 = sy - info->qy1;
const GLfloat fx2 = sx - info->qx2;
const GLfloat fy2 = sy - info->qy2;
const GLfloat fx3 = sx - info->qx3;
const GLfloat fy3 = sy - info->qy3;
/* cross product determines if sample is inside or outside each edge */
GLfloat cross0 = (info->ex0 * fy0 - info->ey0 * fx0);
GLfloat cross1 = (info->ex1 * fy1 - info->ey1 * fx1);
GLfloat cross2 = (info->ex2 * fy2 - info->ey2 * fx2);
GLfloat cross3 = (info->ex3 * fy3 - info->ey3 * fx3);
/* Check if the sample is exactly on an edge. If so, let cross be a
* positive or negative value depending on the direction of the edge.
*/
if (cross0 == 0.0F)
cross0 = info->ex0 + info->ey0;
if (cross1 == 0.0F)
cross1 = info->ex1 + info->ey1;
if (cross2 == 0.0F)
cross2 = info->ex2 + info->ey2;
if (cross3 == 0.0F)
cross3 = info->ex3 + info->ey3;
if (cross0 < 0.0F || cross1 < 0.0F || cross2 < 0.0F || cross3 < 0.0F) {
/* point is outside quadrilateral */
insideCount -= 1.0F;
stop = SUB_PIXEL * SUB_PIXEL;
}
}
if (stop == 4)
return 1.0F;
else
return insideCount * (1.0F / (SUB_PIXEL * SUB_PIXEL));
}
 
 
typedef void (*plot_func)(struct gl_context *ctx, struct LineInfo *line,
int ix, int iy);
 
 
/*
* Draw an AA line segment (called many times per line when stippling)
*/
static void
segment(struct gl_context *ctx,
struct LineInfo *line,
plot_func plot,
GLfloat t0, GLfloat t1)
{
const GLfloat absDx = (line->dx < 0.0F) ? -line->dx : line->dx;
const GLfloat absDy = (line->dy < 0.0F) ? -line->dy : line->dy;
/* compute the actual segment's endpoints */
const GLfloat x0 = line->x0 + t0 * line->dx;
const GLfloat y0 = line->y0 + t0 * line->dy;
const GLfloat x1 = line->x0 + t1 * line->dx;
const GLfloat y1 = line->y0 + t1 * line->dy;
 
/* compute vertices of the line-aligned quadrilateral */
line->qx0 = x0 - line->yAdj;
line->qy0 = y0 + line->xAdj;
line->qx1 = x0 + line->yAdj;
line->qy1 = y0 - line->xAdj;
line->qx2 = x1 + line->yAdj;
line->qy2 = y1 - line->xAdj;
line->qx3 = x1 - line->yAdj;
line->qy3 = y1 + line->xAdj;
/* compute the quad's edge vectors (for coverage calc) */
line->ex0 = line->qx1 - line->qx0;
line->ey0 = line->qy1 - line->qy0;
line->ex1 = line->qx2 - line->qx1;
line->ey1 = line->qy2 - line->qy1;
line->ex2 = line->qx3 - line->qx2;
line->ey2 = line->qy3 - line->qy2;
line->ex3 = line->qx0 - line->qx3;
line->ey3 = line->qy0 - line->qy3;
 
if (absDx > absDy) {
/* X-major line */
GLfloat dydx = line->dy / line->dx;
GLfloat xLeft, xRight, yBot, yTop;
GLint ix, ixRight;
if (x0 < x1) {
xLeft = x0 - line->halfWidth;
xRight = x1 + line->halfWidth;
if (line->dy >= 0.0) {
yBot = y0 - 3.0F * line->halfWidth;
yTop = y0 + line->halfWidth;
}
else {
yBot = y0 - line->halfWidth;
yTop = y0 + 3.0F * line->halfWidth;
}
}
else {
xLeft = x1 - line->halfWidth;
xRight = x0 + line->halfWidth;
if (line->dy <= 0.0) {
yBot = y1 - 3.0F * line->halfWidth;
yTop = y1 + line->halfWidth;
}
else {
yBot = y1 - line->halfWidth;
yTop = y1 + 3.0F * line->halfWidth;
}
}
 
/* scan along the line, left-to-right */
ixRight = (GLint) (xRight + 1.0F);
 
/*printf("avg span height: %g\n", yTop - yBot);*/
for (ix = (GLint) xLeft; ix < ixRight; ix++) {
const GLint iyBot = (GLint) yBot;
const GLint iyTop = (GLint) (yTop + 1.0F);
GLint iy;
/* scan across the line, bottom-to-top */
for (iy = iyBot; iy < iyTop; iy++) {
(*plot)(ctx, line, ix, iy);
}
yBot += dydx;
yTop += dydx;
}
}
else {
/* Y-major line */
GLfloat dxdy = line->dx / line->dy;
GLfloat yBot, yTop, xLeft, xRight;
GLint iy, iyTop;
if (y0 < y1) {
yBot = y0 - line->halfWidth;
yTop = y1 + line->halfWidth;
if (line->dx >= 0.0) {
xLeft = x0 - 3.0F * line->halfWidth;
xRight = x0 + line->halfWidth;
}
else {
xLeft = x0 - line->halfWidth;
xRight = x0 + 3.0F * line->halfWidth;
}
}
else {
yBot = y1 - line->halfWidth;
yTop = y0 + line->halfWidth;
if (line->dx <= 0.0) {
xLeft = x1 - 3.0F * line->halfWidth;
xRight = x1 + line->halfWidth;
}
else {
xLeft = x1 - line->halfWidth;
xRight = x1 + 3.0F * line->halfWidth;
}
}
 
/* scan along the line, bottom-to-top */
iyTop = (GLint) (yTop + 1.0F);
 
/*printf("avg span width: %g\n", xRight - xLeft);*/
for (iy = (GLint) yBot; iy < iyTop; iy++) {
const GLint ixLeft = (GLint) xLeft;
const GLint ixRight = (GLint) (xRight + 1.0F);
GLint ix;
/* scan across the line, left-to-right */
for (ix = ixLeft; ix < ixRight; ix++) {
(*plot)(ctx, line, ix, iy);
}
xLeft += dxdy;
xRight += dxdy;
}
}
}
 
 
#define NAME(x) aa_rgba_##x
#define DO_Z
#include "s_aalinetemp.h"
 
 
#define NAME(x) aa_general_rgba_##x
#define DO_Z
#define DO_ATTRIBS
#include "s_aalinetemp.h"
 
 
 
void
_swrast_choose_aa_line_function(struct gl_context *ctx)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
 
assert(ctx->Line.SmoothFlag);
 
if (ctx->Texture._EnabledCoordUnits != 0
|| _swrast_use_fragment_program(ctx)
|| (ctx->Light.Enabled &&
ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)
|| ctx->Fog.ColorSumEnabled
|| swrast->_FogEnabled) {
swrast->Line = aa_general_rgba_line;
}
else {
swrast->Line = aa_rgba_line;
}
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_aaline.h
0,0 → 1,38
 
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_AALINE_H
#define S_AALINE_H
 
 
struct gl_context;
 
 
extern void
_swrast_choose_aa_line_function(struct gl_context *ctx);
 
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_aalinetemp.h
0,0 → 1,243
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
/*
* Antialiased line template.
*/
 
 
/*
* Function to render each fragment in the AA line.
* \param ix - integer fragment window X coordiante
* \param iy - integer fragment window Y coordiante
*/
static void
NAME(plot)(struct gl_context *ctx, struct LineInfo *line, int ix, int iy)
{
const SWcontext *swrast = SWRAST_CONTEXT(ctx);
const GLfloat fx = (GLfloat) ix;
const GLfloat fy = (GLfloat) iy;
const GLfloat coverage = compute_coveragef(line, ix, iy);
const GLuint i = line->span.end;
 
(void) swrast;
 
if (coverage == 0.0)
return;
 
line->span.end++;
line->span.array->coverage[i] = coverage;
line->span.array->x[i] = ix;
line->span.array->y[i] = iy;
 
/*
* Compute Z, color, texture coords, fog for the fragment by
* solving the plane equations at (ix,iy).
*/
#ifdef DO_Z
line->span.array->z[i] = (GLuint) solve_plane(fx, fy, line->zPlane);
#endif
line->span.array->rgba[i][RCOMP] = solve_plane_chan(fx, fy, line->rPlane);
line->span.array->rgba[i][GCOMP] = solve_plane_chan(fx, fy, line->gPlane);
line->span.array->rgba[i][BCOMP] = solve_plane_chan(fx, fy, line->bPlane);
line->span.array->rgba[i][ACOMP] = solve_plane_chan(fx, fy, line->aPlane);
#if defined(DO_ATTRIBS)
ATTRIB_LOOP_BEGIN
GLfloat (*attribArray)[4] = line->span.array->attribs[attr];
if (attr >= VARYING_SLOT_TEX0 && attr < VARYING_SLOT_VAR0
&& !_swrast_use_fragment_program(ctx)) {
/* texcoord w/ divide by Q */
const GLuint unit = attr - VARYING_SLOT_TEX0;
const GLfloat invQ = solve_plane_recip(fx, fy, line->attrPlane[attr][3]);
GLuint c;
for (c = 0; c < 3; c++) {
attribArray[i][c] = solve_plane(fx, fy, line->attrPlane[attr][c]) * invQ;
}
line->span.array->lambda[unit][i]
= compute_lambda(line->attrPlane[attr][0],
line->attrPlane[attr][1], invQ,
line->texWidth[attr], line->texHeight[attr]);
}
else {
/* non-texture attrib */
const GLfloat invW = solve_plane_recip(fx, fy, line->wPlane);
GLuint c;
for (c = 0; c < 4; c++) {
attribArray[i][c] = solve_plane(fx, fy, line->attrPlane[attr][c]) * invW;
}
}
ATTRIB_LOOP_END
#endif
 
if (line->span.end == SWRAST_MAX_WIDTH) {
_swrast_write_rgba_span(ctx, &(line->span));
line->span.end = 0; /* reset counter */
}
}
 
 
 
/*
* Line setup
*/
static void
NAME(line)(struct gl_context *ctx, const SWvertex *v0, const SWvertex *v1)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
GLfloat tStart, tEnd; /* segment start, end along line length */
GLboolean inSegment;
GLint iLen, i;
 
/* Init the LineInfo struct */
struct LineInfo line;
line.x0 = v0->attrib[VARYING_SLOT_POS][0];
line.y0 = v0->attrib[VARYING_SLOT_POS][1];
line.x1 = v1->attrib[VARYING_SLOT_POS][0];
line.y1 = v1->attrib[VARYING_SLOT_POS][1];
line.dx = line.x1 - line.x0;
line.dy = line.y1 - line.y0;
line.len = sqrtf(line.dx * line.dx + line.dy * line.dy);
line.halfWidth = 0.5F * CLAMP(ctx->Line.Width,
ctx->Const.MinLineWidthAA,
ctx->Const.MaxLineWidthAA);
 
if (line.len == 0.0 || IS_INF_OR_NAN(line.len))
return;
 
INIT_SPAN(line.span, GL_LINE);
line.span.arrayMask = SPAN_XY | SPAN_COVERAGE;
line.span.facing = swrast->PointLineFacing;
line.xAdj = line.dx / line.len * line.halfWidth;
line.yAdj = line.dy / line.len * line.halfWidth;
 
#ifdef DO_Z
line.span.arrayMask |= SPAN_Z;
compute_plane(line.x0, line.y0, line.x1, line.y1,
v0->attrib[VARYING_SLOT_POS][2], v1->attrib[VARYING_SLOT_POS][2], line.zPlane);
#endif
line.span.arrayMask |= SPAN_RGBA;
if (ctx->Light.ShadeModel == GL_SMOOTH) {
compute_plane(line.x0, line.y0, line.x1, line.y1,
v0->color[RCOMP], v1->color[RCOMP], line.rPlane);
compute_plane(line.x0, line.y0, line.x1, line.y1,
v0->color[GCOMP], v1->color[GCOMP], line.gPlane);
compute_plane(line.x0, line.y0, line.x1, line.y1,
v0->color[BCOMP], v1->color[BCOMP], line.bPlane);
compute_plane(line.x0, line.y0, line.x1, line.y1,
v0->color[ACOMP], v1->color[ACOMP], line.aPlane);
}
else {
constant_plane(v1->color[RCOMP], line.rPlane);
constant_plane(v1->color[GCOMP], line.gPlane);
constant_plane(v1->color[BCOMP], line.bPlane);
constant_plane(v1->color[ACOMP], line.aPlane);
}
#if defined(DO_ATTRIBS)
{
const GLfloat invW0 = v0->attrib[VARYING_SLOT_POS][3];
const GLfloat invW1 = v1->attrib[VARYING_SLOT_POS][3];
line.span.arrayMask |= SPAN_LAMBDA;
compute_plane(line.x0, line.y0, line.x1, line.y1, invW0, invW1, line.wPlane);
ATTRIB_LOOP_BEGIN
GLuint c;
if (swrast->_InterpMode[attr] == GL_FLAT) {
for (c = 0; c < 4; c++) {
constant_plane(v1->attrib[attr][c], line.attrPlane[attr][c]);
}
}
else {
for (c = 0; c < 4; c++) {
const GLfloat a0 = v0->attrib[attr][c] * invW0;
const GLfloat a1 = v1->attrib[attr][c] * invW1;
compute_plane(line.x0, line.y0, line.x1, line.y1, a0, a1,
line.attrPlane[attr][c]);
}
}
line.span.arrayAttribs |= BITFIELD64_BIT(attr);
if (attr >= VARYING_SLOT_TEX0 && attr < VARYING_SLOT_VAR0) {
const GLuint u = attr - VARYING_SLOT_TEX0;
const struct gl_texture_object *obj = ctx->Texture.Unit[u]._Current;
const struct gl_texture_image *texImage =
_mesa_base_tex_image(obj);
line.texWidth[attr] = (GLfloat) texImage->Width;
line.texHeight[attr] = (GLfloat) texImage->Height;
}
ATTRIB_LOOP_END
}
#endif
 
tStart = tEnd = 0.0;
inSegment = GL_FALSE;
iLen = (GLint) line.len;
 
if (ctx->Line.StippleFlag) {
for (i = 0; i < iLen; i++) {
const GLuint bit = (swrast->StippleCounter / ctx->Line.StippleFactor) & 0xf;
if ((1 << bit) & ctx->Line.StipplePattern) {
/* stipple bit is on */
const GLfloat t = (GLfloat) i / (GLfloat) line.len;
if (!inSegment) {
/* start new segment */
inSegment = GL_TRUE;
tStart = t;
}
else {
/* still in the segment, extend it */
tEnd = t;
}
}
else {
/* stipple bit is off */
if (inSegment && (tEnd > tStart)) {
/* draw the segment */
segment(ctx, &line, NAME(plot), tStart, tEnd);
inSegment = GL_FALSE;
}
else {
/* still between segments, do nothing */
}
}
swrast->StippleCounter++;
}
 
if (inSegment) {
/* draw the final segment of the line */
segment(ctx, &line, NAME(plot), tStart, 1.0F);
}
}
else {
/* non-stippled */
segment(ctx, &line, NAME(plot), 0.0, 1.0);
}
 
_swrast_write_rgba_span(ctx, &(line.span));
}
 
 
 
 
#undef DO_Z
#undef DO_ATTRIBS
#undef NAME
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_aatriangle.c
0,0 → 1,297
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
/*
* Antialiased Triangle rasterizers
*/
 
 
#include "main/glheader.h"
#include "main/context.h"
#include "main/macros.h"
#include "main/imports.h"
#include "main/state.h"
#include "s_aatriangle.h"
#include "s_context.h"
#include "s_span.h"
 
 
/*
* Compute coefficients of a plane using the X,Y coords of the v0, v1, v2
* vertices and the given Z values.
* A point (x,y,z) lies on plane iff a*x+b*y+c*z+d = 0.
*/
static inline void
compute_plane(const GLfloat v0[], const GLfloat v1[], const GLfloat v2[],
GLfloat z0, GLfloat z1, GLfloat z2, GLfloat plane[4])
{
const GLfloat px = v1[0] - v0[0];
const GLfloat py = v1[1] - v0[1];
const GLfloat pz = z1 - z0;
 
const GLfloat qx = v2[0] - v0[0];
const GLfloat qy = v2[1] - v0[1];
const GLfloat qz = z2 - z0;
 
/* Crossproduct "(a,b,c):= dv1 x dv2" is orthogonal to plane. */
const GLfloat a = py * qz - pz * qy;
const GLfloat b = pz * qx - px * qz;
const GLfloat c = px * qy - py * qx;
/* Point on the plane = "r*(a,b,c) + w", with fixed "r" depending
on the distance of plane from origin and arbitrary "w" parallel
to the plane. */
/* The scalar product "(r*(a,b,c)+w)*(a,b,c)" is "r*(a^2+b^2+c^2)",
which is equal to "-d" below. */
const GLfloat d = -(a * v0[0] + b * v0[1] + c * z0);
 
plane[0] = a;
plane[1] = b;
plane[2] = c;
plane[3] = d;
}
 
 
/*
* Compute coefficients of a plane with a constant Z value.
*/
static inline void
constant_plane(GLfloat value, GLfloat plane[4])
{
plane[0] = 0.0;
plane[1] = 0.0;
plane[2] = -1.0;
plane[3] = value;
}
 
#define CONSTANT_PLANE(VALUE, PLANE) \
do { \
PLANE[0] = 0.0F; \
PLANE[1] = 0.0F; \
PLANE[2] = -1.0F; \
PLANE[3] = VALUE; \
} while (0)
 
 
 
/*
* Solve plane equation for Z at (X,Y).
*/
static inline GLfloat
solve_plane(GLfloat x, GLfloat y, const GLfloat plane[4])
{
assert(plane[2] != 0.0F);
return (plane[3] + plane[0] * x + plane[1] * y) / -plane[2];
}
 
 
#define SOLVE_PLANE(X, Y, PLANE) \
((PLANE[3] + PLANE[0] * (X) + PLANE[1] * (Y)) / -PLANE[2])
 
 
/*
* Solve plane and return clamped GLchan value.
*/
static inline GLchan
solve_plane_chan(GLfloat x, GLfloat y, const GLfloat plane[4])
{
const GLfloat z = (plane[3] + plane[0] * x + plane[1] * y) / -plane[2];
#if CHAN_TYPE == GL_FLOAT
return CLAMP(z, 0.0F, CHAN_MAXF);
#else
if (z < 0)
return 0;
else if (z > CHAN_MAX)
return CHAN_MAX;
return (GLchan) IROUND_POS(z);
#endif
}
 
 
static inline GLfloat
plane_dx(const GLfloat plane[4])
{
return -plane[0] / plane[2];
}
 
static inline GLfloat
plane_dy(const GLfloat plane[4])
{
return -plane[1] / plane[2];
}
 
 
 
/*
* Compute how much (area) of the given pixel is inside the triangle.
* Vertices MUST be specified in counter-clockwise order.
* Return: coverage in [0, 1].
*/
static GLfloat
compute_coveragef(const GLfloat v0[3], const GLfloat v1[3],
const GLfloat v2[3], GLint winx, GLint winy)
{
/* Given a position [0,3]x[0,3] return the sub-pixel sample position.
* Contributed by Ray Tice.
*
* Jitter sample positions -
* - average should be .5 in x & y for each column
* - each of the 16 rows and columns should be used once
* - the rectangle formed by the first four points
* should contain the other points
* - the distrubition should be fairly even in any given direction
*
* The pattern drawn below isn't optimal, but it's better than a regular
* grid. In the drawing, the center of each subpixel is surrounded by
* four dots. The "x" marks the jittered position relative to the
* subpixel center.
*/
#define POS(a, b) (0.5+a*4+b)/16
static const GLfloat samples[16][2] = {
/* start with the four corners */
{ POS(0, 2), POS(0, 0) },
{ POS(3, 3), POS(0, 2) },
{ POS(0, 0), POS(3, 1) },
{ POS(3, 1), POS(3, 3) },
/* continue with interior samples */
{ POS(1, 1), POS(0, 1) },
{ POS(2, 0), POS(0, 3) },
{ POS(0, 3), POS(1, 3) },
{ POS(1, 2), POS(1, 0) },
{ POS(2, 3), POS(1, 2) },
{ POS(3, 2), POS(1, 1) },
{ POS(0, 1), POS(2, 2) },
{ POS(1, 0), POS(2, 1) },
{ POS(2, 1), POS(2, 3) },
{ POS(3, 0), POS(2, 0) },
{ POS(1, 3), POS(3, 0) },
{ POS(2, 2), POS(3, 2) }
};
 
const GLfloat x = (GLfloat) winx;
const GLfloat y = (GLfloat) winy;
const GLfloat dx0 = v1[0] - v0[0];
const GLfloat dy0 = v1[1] - v0[1];
const GLfloat dx1 = v2[0] - v1[0];
const GLfloat dy1 = v2[1] - v1[1];
const GLfloat dx2 = v0[0] - v2[0];
const GLfloat dy2 = v0[1] - v2[1];
GLint stop = 4, i;
GLfloat insideCount = 16.0F;
 
assert(dx0 * dy1 - dx1 * dy0 >= 0.0); /* area >= 0.0 */
 
for (i = 0; i < stop; i++) {
const GLfloat sx = x + samples[i][0];
const GLfloat sy = y + samples[i][1];
/* cross product determines if sample is inside or outside each edge */
GLfloat cross = (dx0 * (sy - v0[1]) - dy0 * (sx - v0[0]));
/* Check if the sample is exactly on an edge. If so, let cross be a
* positive or negative value depending on the direction of the edge.
*/
if (cross == 0.0F)
cross = dx0 + dy0;
if (cross < 0.0F) {
/* sample point is outside first edge */
insideCount -= 1.0F;
stop = 16;
}
else {
/* sample point is inside first edge */
cross = (dx1 * (sy - v1[1]) - dy1 * (sx - v1[0]));
if (cross == 0.0F)
cross = dx1 + dy1;
if (cross < 0.0F) {
/* sample point is outside second edge */
insideCount -= 1.0F;
stop = 16;
}
else {
/* sample point is inside first and second edges */
cross = (dx2 * (sy - v2[1]) - dy2 * (sx - v2[0]));
if (cross == 0.0F)
cross = dx2 + dy2;
if (cross < 0.0F) {
/* sample point is outside third edge */
insideCount -= 1.0F;
stop = 16;
}
}
}
}
if (stop == 4)
return 1.0F;
else
return insideCount * (1.0F / 16.0F);
}
 
 
 
static void
rgba_aa_tri(struct gl_context *ctx,
const SWvertex *v0,
const SWvertex *v1,
const SWvertex *v2)
{
#define DO_Z
#include "s_aatritemp.h"
}
 
 
static void
general_aa_tri(struct gl_context *ctx,
const SWvertex *v0,
const SWvertex *v1,
const SWvertex *v2)
{
#define DO_Z
#define DO_ATTRIBS
#include "s_aatritemp.h"
}
 
 
 
/*
* Examine GL state and set swrast->Triangle to an
* appropriate antialiased triangle rasterizer function.
*/
void
_swrast_set_aa_triangle_function(struct gl_context *ctx)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
 
assert(ctx->Polygon.SmoothFlag);
 
if (ctx->Texture._EnabledCoordUnits != 0
|| _swrast_use_fragment_program(ctx)
|| swrast->_FogEnabled
|| _mesa_need_secondary_color(ctx)) {
SWRAST_CONTEXT(ctx)->Triangle = general_aa_tri;
}
else {
SWRAST_CONTEXT(ctx)->Triangle = rgba_aa_tri;
}
 
assert(SWRAST_CONTEXT(ctx)->Triangle);
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_aatriangle.h
0,0 → 1,38
 
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_AATRIANGLE_H
#define S_AATRIANGLE_H
 
 
struct gl_context;
 
 
extern void
_swrast_set_aa_triangle_function(struct gl_context *ctx);
 
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_aatritemp.h
0,0 → 1,343
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
/*
* Antialiased Triangle Rasterizer Template
*
* This file is #include'd to generate custom AA triangle rasterizers.
* NOTE: this code hasn't been optimized yet. That'll come after it
* works correctly.
*
* The following macros may be defined to indicate what auxillary information
* must be copmuted across the triangle:
* DO_Z - if defined, compute Z values
* DO_ATTRIBS - if defined, compute texcoords, varying, etc.
*/
 
/*void triangle( struct gl_context *ctx, GLuint v0, GLuint v1, GLuint v2, GLuint pv )*/
{
const SWcontext *swrast = SWRAST_CONTEXT(ctx);
const GLfloat *p0 = v0->attrib[VARYING_SLOT_POS];
const GLfloat *p1 = v1->attrib[VARYING_SLOT_POS];
const GLfloat *p2 = v2->attrib[VARYING_SLOT_POS];
const SWvertex *vMin, *vMid, *vMax;
GLint iyMin, iyMax;
GLfloat yMin, yMax;
GLboolean ltor;
GLfloat majDx, majDy; /* major (i.e. long) edge dx and dy */
SWspan span;
#ifdef DO_Z
GLfloat zPlane[4];
#endif
GLfloat rPlane[4], gPlane[4], bPlane[4], aPlane[4];
#if defined(DO_ATTRIBS)
GLfloat attrPlane[VARYING_SLOT_MAX][4][4];
GLfloat wPlane[4]; /* win[3] */
#endif
GLfloat bf = SWRAST_CONTEXT(ctx)->_BackfaceCullSign;
(void) swrast;
 
INIT_SPAN(span, GL_POLYGON);
span.arrayMask = SPAN_COVERAGE;
 
/* determine bottom to top order of vertices */
{
GLfloat y0 = v0->attrib[VARYING_SLOT_POS][1];
GLfloat y1 = v1->attrib[VARYING_SLOT_POS][1];
GLfloat y2 = v2->attrib[VARYING_SLOT_POS][1];
if (y0 <= y1) {
if (y1 <= y2) {
vMin = v0; vMid = v1; vMax = v2; /* y0<=y1<=y2 */
}
else if (y2 <= y0) {
vMin = v2; vMid = v0; vMax = v1; /* y2<=y0<=y1 */
}
else {
vMin = v0; vMid = v2; vMax = v1; bf = -bf; /* y0<=y2<=y1 */
}
}
else {
if (y0 <= y2) {
vMin = v1; vMid = v0; vMax = v2; bf = -bf; /* y1<=y0<=y2 */
}
else if (y2 <= y1) {
vMin = v2; vMid = v1; vMax = v0; bf = -bf; /* y2<=y1<=y0 */
}
else {
vMin = v1; vMid = v2; vMax = v0; /* y1<=y2<=y0 */
}
}
}
 
majDx = vMax->attrib[VARYING_SLOT_POS][0] - vMin->attrib[VARYING_SLOT_POS][0];
majDy = vMax->attrib[VARYING_SLOT_POS][1] - vMin->attrib[VARYING_SLOT_POS][1];
 
/* front/back-face determination and cullling */
{
const GLfloat botDx = vMid->attrib[VARYING_SLOT_POS][0] - vMin->attrib[VARYING_SLOT_POS][0];
const GLfloat botDy = vMid->attrib[VARYING_SLOT_POS][1] - vMin->attrib[VARYING_SLOT_POS][1];
const GLfloat area = majDx * botDy - botDx * majDy;
/* Do backface culling */
if (area * bf < 0 || area == 0 || IS_INF_OR_NAN(area))
return;
ltor = (GLboolean) (area < 0.0F);
 
span.facing = area * swrast->_BackfaceSign > 0.0F;
}
 
/* Plane equation setup:
* We evaluate plane equations at window (x,y) coordinates in order
* to compute color, Z, fog, texcoords, etc. This isn't terribly
* efficient but it's easy and reliable.
*/
#ifdef DO_Z
compute_plane(p0, p1, p2, p0[2], p1[2], p2[2], zPlane);
span.arrayMask |= SPAN_Z;
#endif
if (ctx->Light.ShadeModel == GL_SMOOTH) {
compute_plane(p0, p1, p2, v0->color[RCOMP], v1->color[RCOMP], v2->color[RCOMP], rPlane);
compute_plane(p0, p1, p2, v0->color[GCOMP], v1->color[GCOMP], v2->color[GCOMP], gPlane);
compute_plane(p0, p1, p2, v0->color[BCOMP], v1->color[BCOMP], v2->color[BCOMP], bPlane);
compute_plane(p0, p1, p2, v0->color[ACOMP], v1->color[ACOMP], v2->color[ACOMP], aPlane);
}
else {
constant_plane(v2->color[RCOMP], rPlane);
constant_plane(v2->color[GCOMP], gPlane);
constant_plane(v2->color[BCOMP], bPlane);
constant_plane(v2->color[ACOMP], aPlane);
}
span.arrayMask |= SPAN_RGBA;
#if defined(DO_ATTRIBS)
{
const GLfloat invW0 = v0->attrib[VARYING_SLOT_POS][3];
const GLfloat invW1 = v1->attrib[VARYING_SLOT_POS][3];
const GLfloat invW2 = v2->attrib[VARYING_SLOT_POS][3];
compute_plane(p0, p1, p2, invW0, invW1, invW2, wPlane);
span.attrStepX[VARYING_SLOT_POS][3] = plane_dx(wPlane);
span.attrStepY[VARYING_SLOT_POS][3] = plane_dy(wPlane);
ATTRIB_LOOP_BEGIN
GLuint c;
if (swrast->_InterpMode[attr] == GL_FLAT) {
for (c = 0; c < 4; c++) {
constant_plane(v2->attrib[attr][c] * invW2, attrPlane[attr][c]);
}
}
else {
for (c = 0; c < 4; c++) {
const GLfloat a0 = v0->attrib[attr][c] * invW0;
const GLfloat a1 = v1->attrib[attr][c] * invW1;
const GLfloat a2 = v2->attrib[attr][c] * invW2;
compute_plane(p0, p1, p2, a0, a1, a2, attrPlane[attr][c]);
}
}
for (c = 0; c < 4; c++) {
span.attrStepX[attr][c] = plane_dx(attrPlane[attr][c]);
span.attrStepY[attr][c] = plane_dy(attrPlane[attr][c]);
}
ATTRIB_LOOP_END
}
#endif
 
/* Begin bottom-to-top scan over the triangle.
* The long edge will either be on the left or right side of the
* triangle. We always scan from the long edge toward the shorter
* edges, stopping when we find that coverage = 0. If the long edge
* is on the left we scan left-to-right. Else, we scan right-to-left.
*/
yMin = vMin->attrib[VARYING_SLOT_POS][1];
yMax = vMax->attrib[VARYING_SLOT_POS][1];
iyMin = (GLint) yMin;
iyMax = (GLint) yMax + 1;
 
if (ltor) {
/* scan left to right */
const GLfloat *pMin = vMin->attrib[VARYING_SLOT_POS];
const GLfloat *pMid = vMid->attrib[VARYING_SLOT_POS];
const GLfloat *pMax = vMax->attrib[VARYING_SLOT_POS];
const GLfloat dxdy = majDx / majDy;
const GLfloat xAdj = dxdy < 0.0F ? -dxdy : 0.0F;
GLint iy;
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic) private(iy) firstprivate(span)
#endif
for (iy = iyMin; iy < iyMax; iy++) {
GLfloat x = pMin[0] - (yMin - iy) * dxdy;
GLint ix, startX = (GLint) (x - xAdj);
GLuint count;
GLfloat coverage = 0.0F;
 
#ifdef _OPENMP
/* each thread needs to use a different (global) SpanArrays variable */
span.array = SWRAST_CONTEXT(ctx)->SpanArrays + omp_get_thread_num();
#endif
/* skip over fragments with zero coverage */
while (startX < SWRAST_MAX_WIDTH) {
coverage = compute_coveragef(pMin, pMid, pMax, startX, iy);
if (coverage > 0.0F)
break;
startX++;
}
 
/* enter interior of triangle */
ix = startX;
 
#if defined(DO_ATTRIBS)
/* compute attributes at left-most fragment */
span.attrStart[VARYING_SLOT_POS][3] = solve_plane(ix + 0.5F, iy + 0.5F, wPlane);
ATTRIB_LOOP_BEGIN
GLuint c;
for (c = 0; c < 4; c++) {
span.attrStart[attr][c] = solve_plane(ix + 0.5F, iy + 0.5F, attrPlane[attr][c]);
}
ATTRIB_LOOP_END
#endif
 
count = 0;
while (coverage > 0.0F) {
/* (cx,cy) = center of fragment */
const GLfloat cx = ix + 0.5F, cy = iy + 0.5F;
SWspanarrays *array = span.array;
array->coverage[count] = coverage;
#ifdef DO_Z
array->z[count] = (GLuint) solve_plane(cx, cy, zPlane);
#endif
array->rgba[count][RCOMP] = solve_plane_chan(cx, cy, rPlane);
array->rgba[count][GCOMP] = solve_plane_chan(cx, cy, gPlane);
array->rgba[count][BCOMP] = solve_plane_chan(cx, cy, bPlane);
array->rgba[count][ACOMP] = solve_plane_chan(cx, cy, aPlane);
ix++;
count++;
coverage = compute_coveragef(pMin, pMid, pMax, ix, iy);
}
if (ix > startX) {
span.x = startX;
span.y = iy;
span.end = (GLuint) ix - (GLuint) startX;
_swrast_write_rgba_span(ctx, &span);
}
}
}
else {
/* scan right to left */
const GLfloat *pMin = vMin->attrib[VARYING_SLOT_POS];
const GLfloat *pMid = vMid->attrib[VARYING_SLOT_POS];
const GLfloat *pMax = vMax->attrib[VARYING_SLOT_POS];
const GLfloat dxdy = majDx / majDy;
const GLfloat xAdj = dxdy > 0 ? dxdy : 0.0F;
GLint iy;
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic) private(iy) firstprivate(span)
#endif
for (iy = iyMin; iy < iyMax; iy++) {
GLfloat x = pMin[0] - (yMin - iy) * dxdy;
GLint ix, left, startX = (GLint) (x + xAdj);
GLuint count, n;
GLfloat coverage = 0.0F;
#ifdef _OPENMP
/* each thread needs to use a different (global) SpanArrays variable */
span.array = SWRAST_CONTEXT(ctx)->SpanArrays + omp_get_thread_num();
#endif
/* make sure we're not past the window edge */
if (startX >= ctx->DrawBuffer->_Xmax) {
startX = ctx->DrawBuffer->_Xmax - 1;
}
 
/* skip fragments with zero coverage */
while (startX > 0) {
coverage = compute_coveragef(pMin, pMax, pMid, startX, iy);
if (coverage > 0.0F)
break;
startX--;
}
/* enter interior of triangle */
ix = startX;
count = 0;
while (coverage > 0.0F) {
/* (cx,cy) = center of fragment */
const GLfloat cx = ix + 0.5F, cy = iy + 0.5F;
SWspanarrays *array = span.array;
assert(ix >= 0);
array->coverage[ix] = coverage;
#ifdef DO_Z
array->z[ix] = (GLuint) solve_plane(cx, cy, zPlane);
#endif
array->rgba[ix][RCOMP] = solve_plane_chan(cx, cy, rPlane);
array->rgba[ix][GCOMP] = solve_plane_chan(cx, cy, gPlane);
array->rgba[ix][BCOMP] = solve_plane_chan(cx, cy, bPlane);
array->rgba[ix][ACOMP] = solve_plane_chan(cx, cy, aPlane);
ix--;
count++;
coverage = compute_coveragef(pMin, pMax, pMid, ix, iy);
}
#if defined(DO_ATTRIBS)
/* compute attributes at left-most fragment */
span.attrStart[VARYING_SLOT_POS][3] = solve_plane(ix + 1.5F, iy + 0.5F, wPlane);
ATTRIB_LOOP_BEGIN
GLuint c;
for (c = 0; c < 4; c++) {
span.attrStart[attr][c] = solve_plane(ix + 1.5F, iy + 0.5F, attrPlane[attr][c]);
}
ATTRIB_LOOP_END
#endif
 
if (startX > ix) {
n = (GLuint) startX - (GLuint) ix;
 
left = ix + 1;
 
/* shift all values to the left */
/* XXX this is temporary */
{
SWspanarrays *array = span.array;
GLint j;
for (j = 0; j < (GLint) n; j++) {
array->coverage[j] = array->coverage[j + left];
COPY_CHAN4(array->rgba[j], array->rgba[j + left]);
#ifdef DO_Z
array->z[j] = array->z[j + left];
#endif
}
}
 
span.x = left;
span.y = iy;
span.end = n;
_swrast_write_rgba_span(ctx, &span);
}
}
}
}
 
 
#undef DO_Z
#undef DO_ATTRIBS
#undef DO_OCCLUSION_TEST
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_alpha.c
0,0 → 1,159
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
/**
* \file swrast/s_alpha.c
* \brief Functions to apply alpha test.
*/
 
#include "main/glheader.h"
#include "main/context.h"
#include "main/macros.h"
 
#include "s_alpha.h"
#include "s_context.h"
 
 
#define ALPHA_TEST(ALPHA, LOOP_CODE) \
do { \
switch (ctx->Color.AlphaFunc) { \
case GL_LESS: \
for (i = 0; i < n; i++) { \
mask[i] &= (ALPHA < ref); \
LOOP_CODE; \
} \
break; \
case GL_LEQUAL: \
for (i = 0; i < n; i++) { \
mask[i] &= (ALPHA <= ref); \
LOOP_CODE; \
} \
break; \
case GL_GEQUAL: \
for (i = 0; i < n; i++) { \
mask[i] &= (ALPHA >= ref); \
LOOP_CODE; \
} \
break; \
case GL_GREATER: \
for (i = 0; i < n; i++) { \
mask[i] &= (ALPHA > ref); \
LOOP_CODE; \
} \
break; \
case GL_NOTEQUAL: \
for (i = 0; i < n; i++) { \
mask[i] &= (ALPHA != ref); \
LOOP_CODE; \
} \
break; \
case GL_EQUAL: \
for (i = 0; i < n; i++) { \
mask[i] &= (ALPHA == ref); \
LOOP_CODE; \
} \
break; \
default: \
_mesa_problem(ctx, "Invalid alpha test in _swrast_alpha_test" ); \
return 0; \
} \
} while (0)
 
 
 
/**
* Perform the alpha test for an array of pixels.
* For pixels that fail the test, mask[i] will be set to 0.
* \return 0 if all pixels in the span failed the alpha test,
* 1 if one or more pixels passed the alpha test.
*/
GLint
_swrast_alpha_test(const struct gl_context *ctx, SWspan *span)
{
const GLuint n = span->end;
GLubyte *mask = span->array->mask;
GLuint i;
 
if (ctx->Color.AlphaFunc == GL_ALWAYS) {
/* do nothing */
return 1;
}
else if (ctx->Color.AlphaFunc == GL_NEVER) {
/* All pixels failed - caller should check for this return value and
* act accordingly.
*/
span->writeAll = GL_FALSE;
return 0;
}
 
if (span->arrayMask & SPAN_RGBA) {
/* Use array's alpha values */
if (span->array->ChanType == GL_UNSIGNED_BYTE) {
GLubyte (*rgba)[4] = span->array->rgba8;
GLubyte ref;
CLAMPED_FLOAT_TO_UBYTE(ref, ctx->Color.AlphaRef);
ALPHA_TEST(rgba[i][ACOMP], ;);
}
else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
GLushort (*rgba)[4] = span->array->rgba16;
GLushort ref;
CLAMPED_FLOAT_TO_USHORT(ref, ctx->Color.AlphaRef);
ALPHA_TEST(rgba[i][ACOMP], ;);
}
else {
GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0];
const GLfloat ref = ctx->Color.AlphaRef;
ALPHA_TEST(rgba[i][ACOMP], ;);
}
}
else {
/* Interpolate alpha values */
assert(span->interpMask & SPAN_RGBA);
if (span->array->ChanType == GL_UNSIGNED_BYTE) {
const GLfixed alphaStep = span->alphaStep;
GLfixed alpha = span->alpha;
GLubyte ref;
CLAMPED_FLOAT_TO_UBYTE(ref, ctx->Color.AlphaRef);
ALPHA_TEST(FixedToInt(alpha), alpha += alphaStep);
}
else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
const GLfixed alphaStep = span->alphaStep;
GLfixed alpha = span->alpha;
GLushort ref;
CLAMPED_FLOAT_TO_USHORT(ref, ctx->Color.AlphaRef);
ALPHA_TEST(FixedToInt(alpha), alpha += alphaStep);
}
else {
const GLfloat alphaStep = FixedToFloat(span->alphaStep);
GLfloat alpha = FixedToFloat(span->alpha);
const GLfloat ref = ctx->Color.AlphaRef;
ALPHA_TEST(alpha, alpha += alphaStep);
}
}
 
span->writeAll = GL_FALSE;
 
/* XXX examine mask[] values? */
return 1;
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_alpha.h
0,0 → 1,39
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_ALPHA_H
#define S_ALPHA_H
 
 
#include "main/glheader.h"
#include "s_span.h"
 
struct gl_context;
 
extern GLint
_swrast_alpha_test( const struct gl_context *ctx, SWspan *span );
 
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_atifragshader.c
0,0 → 1,590
/*
* Copyright (C) 2004 David Airlie All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* DAVID AIRLIE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
 
#include "main/glheader.h"
#include "main/macros.h"
#include "main/atifragshader.h"
#include "main/samplerobj.h"
#include "swrast/s_atifragshader.h"
#include "swrast/s_context.h"
 
 
/**
* State for executing ATI fragment shader.
*/
struct atifs_machine
{
GLfloat Registers[6][4]; /** six temporary registers */
GLfloat PrevPassRegisters[6][4];
GLfloat Inputs[2][4]; /** Primary, secondary input colors */
};
 
 
 
/**
* Fetch a texel.
*/
static void
fetch_texel(struct gl_context * ctx, const GLfloat texcoord[4], GLfloat lambda,
GLuint unit, GLfloat color[4])
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
 
/* XXX use a float-valued TextureSample routine here!!! */
swrast->TextureSample[unit](ctx, _mesa_get_samplerobj(ctx, unit),
ctx->Texture.Unit[unit]._Current,
1, (const GLfloat(*)[4]) texcoord,
&lambda, (GLfloat (*)[4]) color);
}
 
static void
apply_swizzle(GLfloat values[4], GLuint swizzle)
{
GLfloat s, t, r, q;
 
s = values[0];
t = values[1];
r = values[2];
q = values[3];
 
switch (swizzle) {
case GL_SWIZZLE_STR_ATI:
values[0] = s;
values[1] = t;
values[2] = r;
break;
case GL_SWIZZLE_STQ_ATI:
values[0] = s;
values[1] = t;
values[2] = q;
break;
case GL_SWIZZLE_STR_DR_ATI:
values[0] = s / r;
values[1] = t / r;
values[2] = 1 / r;
break;
case GL_SWIZZLE_STQ_DQ_ATI:
/* make sure q is not 0 to avoid problems later with infinite values (texture lookup)? */
if (q == 0.0F)
q = 0.000000001F;
values[0] = s / q;
values[1] = t / q;
values[2] = 1.0F / q;
break;
}
values[3] = 0.0;
}
 
static void
apply_src_rep(GLint optype, GLuint rep, GLfloat * val)
{
GLint i;
GLint start, end;
if (!rep)
return;
 
start = optype ? 3 : 0;
end = 4;
 
for (i = start; i < end; i++) {
switch (rep) {
case GL_RED:
val[i] = val[0];
break;
case GL_GREEN:
val[i] = val[1];
break;
case GL_BLUE:
val[i] = val[2];
break;
case GL_ALPHA:
val[i] = val[3];
break;
}
}
}
 
static void
apply_src_mod(GLint optype, GLuint mod, GLfloat * val)
{
GLint i;
GLint start, end;
 
if (!mod)
return;
 
start = optype ? 3 : 0;
end = 4;
 
for (i = start; i < end; i++) {
if (mod & GL_COMP_BIT_ATI)
val[i] = 1 - val[i];
 
if (mod & GL_BIAS_BIT_ATI)
val[i] = val[i] - 0.5F;
 
if (mod & GL_2X_BIT_ATI)
val[i] = 2 * val[i];
 
if (mod & GL_NEGATE_BIT_ATI)
val[i] = -val[i];
}
}
 
static void
apply_dst_mod(GLuint optype, GLuint mod, GLfloat * val)
{
GLint i;
GLint has_sat = mod & GL_SATURATE_BIT_ATI;
GLint start, end;
 
mod &= ~GL_SATURATE_BIT_ATI;
 
start = optype ? 3 : 0;
end = optype ? 4 : 3;
 
for (i = start; i < end; i++) {
switch (mod) {
case GL_2X_BIT_ATI:
val[i] = 2 * val[i];
break;
case GL_4X_BIT_ATI:
val[i] = 4 * val[i];
break;
case GL_8X_BIT_ATI:
val[i] = 8 * val[i];
break;
case GL_HALF_BIT_ATI:
val[i] = val[i] * 0.5F;
break;
case GL_QUARTER_BIT_ATI:
val[i] = val[i] * 0.25F;
break;
case GL_EIGHTH_BIT_ATI:
val[i] = val[i] * 0.125F;
break;
}
 
if (has_sat) {
if (val[i] < 0.0F)
val[i] = 0.0F;
else if (val[i] > 1.0F)
val[i] = 1.0F;
}
else {
if (val[i] < -8.0F)
val[i] = -8.0F;
else if (val[i] > 8.0F)
val[i] = 8.0F;
}
}
}
 
 
static void
write_dst_addr(GLuint optype, GLuint mod, GLuint mask, GLfloat * src,
GLfloat * dst)
{
GLint i;
apply_dst_mod(optype, mod, src);
 
if (optype == ATI_FRAGMENT_SHADER_COLOR_OP) {
if (mask) {
if (mask & GL_RED_BIT_ATI)
dst[0] = src[0];
 
if (mask & GL_GREEN_BIT_ATI)
dst[1] = src[1];
 
if (mask & GL_BLUE_BIT_ATI)
dst[2] = src[2];
}
else {
for (i = 0; i < 3; i++)
dst[i] = src[i];
}
}
else
dst[3] = src[3];
}
 
static void
finish_pass(struct atifs_machine *machine)
{
GLint i;
 
for (i = 0; i < 6; i++) {
COPY_4V(machine->PrevPassRegisters[i], machine->Registers[i]);
}
}
 
 
static void
handle_pass_op(struct atifs_machine *machine, struct atifs_setupinst *texinst,
const SWspan *span, GLuint column, GLuint idx)
{
GLuint swizzle = texinst->swizzle;
GLuint pass_tex = texinst->src;
 
if (pass_tex >= GL_TEXTURE0_ARB && pass_tex <= GL_TEXTURE7_ARB) {
pass_tex -= GL_TEXTURE0_ARB;
COPY_4V(machine->Registers[idx],
span->array->attribs[VARYING_SLOT_TEX0 + pass_tex][column]);
}
else if (pass_tex >= GL_REG_0_ATI && pass_tex <= GL_REG_5_ATI) {
pass_tex -= GL_REG_0_ATI;
COPY_4V(machine->Registers[idx], machine->PrevPassRegisters[pass_tex]);
}
apply_swizzle(machine->Registers[idx], swizzle);
 
}
 
static void
handle_sample_op(struct gl_context * ctx, struct atifs_machine *machine,
struct atifs_setupinst *texinst, const SWspan *span,
GLuint column, GLuint idx)
{
/* sample from unit idx using texinst->src as coords */
GLuint swizzle = texinst->swizzle;
GLuint coord_source = texinst->src;
GLfloat tex_coords[4] = { 0 };
 
if (coord_source >= GL_TEXTURE0_ARB && coord_source <= GL_TEXTURE7_ARB) {
coord_source -= GL_TEXTURE0_ARB;
COPY_4V(tex_coords,
span->array->attribs[VARYING_SLOT_TEX0 + coord_source][column]);
}
else if (coord_source >= GL_REG_0_ATI && coord_source <= GL_REG_5_ATI) {
coord_source -= GL_REG_0_ATI;
COPY_4V(tex_coords, machine->PrevPassRegisters[coord_source]);
}
apply_swizzle(tex_coords, swizzle);
fetch_texel(ctx, tex_coords, 0.0F, idx, machine->Registers[idx]);
}
 
#define SETUP_SRC_REG(optype, i, x) \
do { \
COPY_4V(src[optype][i], x); \
} while (0)
 
 
 
/**
* Execute the given fragment shader.
* NOTE: we do everything in single-precision floating point
* \param ctx - rendering context
* \param shader - the shader to execute
* \param machine - virtual machine state
* \param span - the SWspan we're operating on
* \param column - which pixel [i] we're operating on in the span
*/
static void
execute_shader(struct gl_context *ctx, const struct ati_fragment_shader *shader,
struct atifs_machine *machine, const SWspan *span,
GLuint column)
{
GLuint pc;
struct atifs_instruction *inst;
struct atifs_setupinst *texinst;
GLint optype;
GLuint i;
GLint j, pass;
GLint dstreg;
GLfloat src[2][3][4];
GLfloat zeros[4] = { 0.0, 0.0, 0.0, 0.0 };
GLfloat ones[4] = { 1.0, 1.0, 1.0, 1.0 };
GLfloat dst[2][4], *dstp;
 
for (pass = 0; pass < shader->NumPasses; pass++) {
if (pass > 0)
finish_pass(machine);
for (j = 0; j < MAX_NUM_FRAGMENT_REGISTERS_ATI; j++) {
texinst = &shader->SetupInst[pass][j];
if (texinst->Opcode == ATI_FRAGMENT_SHADER_PASS_OP)
handle_pass_op(machine, texinst, span, column, j);
else if (texinst->Opcode == ATI_FRAGMENT_SHADER_SAMPLE_OP)
handle_sample_op(ctx, machine, texinst, span, column, j);
}
 
for (pc = 0; pc < shader->numArithInstr[pass]; pc++) {
inst = &shader->Instructions[pass][pc];
 
/* setup the source registers for color and alpha ops */
for (optype = 0; optype < 2; optype++) {
for (i = 0; i < inst->ArgCount[optype]; i++) {
GLint index = inst->SrcReg[optype][i].Index;
 
if (index >= GL_REG_0_ATI && index <= GL_REG_5_ATI)
SETUP_SRC_REG(optype, i,
machine->Registers[index - GL_REG_0_ATI]);
else if (index >= GL_CON_0_ATI && index <= GL_CON_7_ATI) {
if (shader->LocalConstDef & (1 << (index - GL_CON_0_ATI))) {
SETUP_SRC_REG(optype, i,
shader->Constants[index - GL_CON_0_ATI]);
} else {
SETUP_SRC_REG(optype, i,
ctx->ATIFragmentShader.GlobalConstants[index - GL_CON_0_ATI]);
}
}
else if (index == GL_ONE)
SETUP_SRC_REG(optype, i, ones);
else if (index == GL_ZERO)
SETUP_SRC_REG(optype, i, zeros);
else if (index == GL_PRIMARY_COLOR_EXT)
SETUP_SRC_REG(optype, i,
machine->Inputs[ATI_FS_INPUT_PRIMARY]);
else if (index == GL_SECONDARY_INTERPOLATOR_ATI)
SETUP_SRC_REG(optype, i,
machine->Inputs[ATI_FS_INPUT_SECONDARY]);
 
apply_src_rep(optype, inst->SrcReg[optype][i].argRep,
src[optype][i]);
apply_src_mod(optype, inst->SrcReg[optype][i].argMod,
src[optype][i]);
}
}
 
/* Execute the operations - color then alpha */
for (optype = 0; optype < 2; optype++) {
if (inst->Opcode[optype]) {
switch (inst->Opcode[optype]) {
case GL_ADD_ATI:
if (!optype)
for (i = 0; i < 3; i++) {
dst[optype][i] =
src[optype][0][i] + src[optype][1][i];
}
else
dst[optype][3] = src[optype][0][3] + src[optype][1][3];
break;
case GL_SUB_ATI:
if (!optype)
for (i = 0; i < 3; i++) {
dst[optype][i] =
src[optype][0][i] - src[optype][1][i];
}
else
dst[optype][3] = src[optype][0][3] - src[optype][1][3];
break;
case GL_MUL_ATI:
if (!optype)
for (i = 0; i < 3; i++) {
dst[optype][i] =
src[optype][0][i] * src[optype][1][i];
}
else
dst[optype][3] = src[optype][0][3] * src[optype][1][3];
break;
case GL_MAD_ATI:
if (!optype)
for (i = 0; i < 3; i++) {
dst[optype][i] =
src[optype][0][i] * src[optype][1][i] +
src[optype][2][i];
}
else
dst[optype][3] =
src[optype][0][3] * src[optype][1][3] +
src[optype][2][3];
break;
case GL_LERP_ATI:
if (!optype)
for (i = 0; i < 3; i++) {
dst[optype][i] =
src[optype][0][i] * src[optype][1][i] + (1 -
src
[optype]
[0][i]) *
src[optype][2][i];
}
else
dst[optype][3] =
src[optype][0][3] * src[optype][1][3] + (1 -
src[optype]
[0][3]) *
src[optype][2][3];
break;
 
case GL_MOV_ATI:
if (!optype)
for (i = 0; i < 3; i++) {
dst[optype][i] = src[optype][0][i];
}
else
dst[optype][3] = src[optype][0][3];
break;
case GL_CND_ATI:
if (!optype) {
for (i = 0; i < 3; i++) {
dst[optype][i] =
(src[optype][2][i] >
0.5) ? src[optype][0][i] : src[optype][1][i];
}
}
else {
dst[optype][3] =
(src[optype][2][3] >
0.5) ? src[optype][0][3] : src[optype][1][3];
}
break;
 
case GL_CND0_ATI:
if (!optype)
for (i = 0; i < 3; i++) {
dst[optype][i] =
(src[optype][2][i] >=
0) ? src[optype][0][i] : src[optype][1][i];
}
else {
dst[optype][3] =
(src[optype][2][3] >=
0) ? src[optype][0][3] : src[optype][1][3];
}
break;
case GL_DOT2_ADD_ATI:
{
GLfloat result;
 
/* DOT 2 always uses the source from the color op */
/* could save recalculation of dot products for alpha inst */
result = src[0][0][0] * src[0][1][0] +
src[0][0][1] * src[0][1][1] + src[0][2][2];
if (!optype) {
for (i = 0; i < 3; i++) {
dst[optype][i] = result;
}
}
else
dst[optype][3] = result;
}
break;
case GL_DOT3_ATI:
{
GLfloat result;
 
/* DOT 3 always uses the source from the color op */
result = src[0][0][0] * src[0][1][0] +
src[0][0][1] * src[0][1][1] +
src[0][0][2] * src[0][1][2];
 
if (!optype) {
for (i = 0; i < 3; i++) {
dst[optype][i] = result;
}
}
else
dst[optype][3] = result;
}
break;
case GL_DOT4_ATI:
{
GLfloat result;
 
/* DOT 4 always uses the source from the color op */
result = src[0][0][0] * src[0][1][0] +
src[0][0][1] * src[0][1][1] +
src[0][0][2] * src[0][1][2] +
src[0][0][3] * src[0][1][3];
if (!optype) {
for (i = 0; i < 3; i++) {
dst[optype][i] = result;
}
}
else
dst[optype][3] = result;
}
break;
 
}
}
}
 
/* write out the destination registers */
for (optype = 0; optype < 2; optype++) {
if (inst->Opcode[optype]) {
dstreg = inst->DstReg[optype].Index;
dstp = machine->Registers[dstreg - GL_REG_0_ATI];
 
if ((optype == 0) || ((inst->Opcode[1] != GL_DOT2_ADD_ATI) &&
(inst->Opcode[1] != GL_DOT3_ATI) && (inst->Opcode[1] != GL_DOT4_ATI)))
write_dst_addr(optype, inst->DstReg[optype].dstMod,
inst->DstReg[optype].dstMask, dst[optype],
dstp);
else
write_dst_addr(1, inst->DstReg[0].dstMod, 0, dst[1], dstp);
}
}
}
}
}
 
 
/**
* Init fragment shader virtual machine state.
*/
static void
init_machine(struct gl_context * ctx, struct atifs_machine *machine,
const struct ati_fragment_shader *shader,
const SWspan *span, GLuint col)
{
GLfloat (*inputs)[4] = machine->Inputs;
GLint i, j;
 
for (i = 0; i < 6; i++) {
for (j = 0; j < 4; j++)
machine->Registers[i][j] = 0.0;
}
 
COPY_4V(inputs[ATI_FS_INPUT_PRIMARY], span->array->attribs[VARYING_SLOT_COL0][col]);
COPY_4V(inputs[ATI_FS_INPUT_SECONDARY], span->array->attribs[VARYING_SLOT_COL1][col]);
}
 
 
 
/**
* Execute the current ATI shader program, operating on the given span.
*/
void
_swrast_exec_fragment_shader(struct gl_context * ctx, SWspan *span)
{
const struct ati_fragment_shader *shader = ctx->ATIFragmentShader.Current;
struct atifs_machine machine;
GLuint i;
 
/* incoming colors should be floats */
assert(span->array->ChanType == GL_FLOAT);
 
for (i = 0; i < span->end; i++) {
if (span->array->mask[i]) {
init_machine(ctx, &machine, shader, span, i);
 
execute_shader(ctx, shader, &machine, span, i);
 
/* store result color */
{
const GLfloat *colOut = machine.Registers[0];
/*fprintf(stderr,"outputs %f %f %f %f\n",
colOut[0], colOut[1], colOut[2], colOut[3]); */
COPY_4V(span->array->attribs[VARYING_SLOT_COL0][i], colOut);
}
}
}
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_atifragshader.h
0,0 → 1,37
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2003 David Airlie All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* DAVID AIRLIE BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
* AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_ATIFRAGSHADER_H
#define S_ATIFRAGSHADER_H
 
 
#include "s_span.h"
 
struct gl_context;
 
extern void
_swrast_exec_fragment_shader( struct gl_context *ctx, SWspan *span );
 
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_bitmap.c
0,0 → 1,223
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
/**
* \file swrast/s_bitmap.c
* \brief glBitmap rendering.
* \author Brian Paul
*/
 
#include "main/glheader.h"
#include "main/bufferobj.h"
#include "main/condrender.h"
#include "main/image.h"
#include "main/macros.h"
#include "main/pbo.h"
 
#include "s_context.h"
#include "s_span.h"
 
 
 
/**
* Render a bitmap.
* Called via ctx->Driver.Bitmap()
* All parameter error checking will have been done before this is called.
*/
void
_swrast_Bitmap( struct gl_context *ctx, GLint px, GLint py,
GLsizei width, GLsizei height,
const struct gl_pixelstore_attrib *unpack,
const GLubyte *bitmap )
{
GLint row, col;
GLuint count = 0;
SWspan span;
 
assert(ctx->RenderMode == GL_RENDER);
 
if (!_mesa_check_conditional_render(ctx))
return; /* don't draw */
 
bitmap = (const GLubyte *) _mesa_map_pbo_source(ctx, unpack, bitmap);
if (!bitmap)
return;
 
swrast_render_start(ctx);
 
if (SWRAST_CONTEXT(ctx)->NewState)
_swrast_validate_derived( ctx );
 
INIT_SPAN(span, GL_BITMAP);
span.end = width;
span.arrayMask = SPAN_XY;
_swrast_span_default_attribs(ctx, &span);
 
for (row = 0; row < height; row++) {
const GLubyte *src = (const GLubyte *) _mesa_image_address2d(unpack,
bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0);
 
if (unpack->LsbFirst) {
/* Lsb first */
GLubyte mask = 1U << (unpack->SkipPixels & 0x7);
for (col = 0; col < width; col++) {
if (*src & mask) {
span.array->x[count] = px + col;
span.array->y[count] = py + row;
count++;
}
if (mask == 128U) {
src++;
mask = 1U;
}
else {
mask = mask << 1;
}
}
 
/* get ready for next row */
if (mask != 1)
src++;
}
else {
/* Msb first */
GLubyte mask = 128U >> (unpack->SkipPixels & 0x7);
for (col = 0; col < width; col++) {
if (*src & mask) {
span.array->x[count] = px + col;
span.array->y[count] = py + row;
count++;
}
if (mask == 1U) {
src++;
mask = 128U;
}
else {
mask = mask >> 1;
}
}
 
/* get ready for next row */
if (mask != 128)
src++;
}
 
if (count + width >= SWRAST_MAX_WIDTH || row + 1 == height) {
/* flush the span */
span.end = count;
_swrast_write_rgba_span(ctx, &span);
span.end = 0;
count = 0;
}
}
 
swrast_render_finish(ctx);
 
_mesa_unmap_pbo_source(ctx, unpack);
}
 
 
#if 0
/*
* XXX this is another way to implement Bitmap. Use horizontal runs of
* fragments, initializing the mask array to indicate which fragments to
* draw or skip.
*/
void
_swrast_Bitmap( struct gl_context *ctx, GLint px, GLint py,
GLsizei width, GLsizei height,
const struct gl_pixelstore_attrib *unpack,
const GLubyte *bitmap )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
GLint row, col;
SWspan span;
 
assert(ctx->RenderMode == GL_RENDER);
assert(bitmap);
 
swrast_render_start(ctx);
 
if (SWRAST_CONTEXT(ctx)->NewState)
_swrast_validate_derived( ctx );
 
INIT_SPAN(span, GL_BITMAP);
span.end = width;
span.arrayMask = SPAN_MASK;
_swrast_span_default_attribs(ctx, &span);
 
/*span.arrayMask |= SPAN_MASK;*/ /* we'll init span.mask[] */
span.x = px;
span.y = py;
/*span.end = width;*/
 
for (row=0; row<height; row++, span.y++) {
const GLubyte *src = (const GLubyte *) _mesa_image_address2d(unpack,
bitmap, width, height, GL_COLOR_INDEX, GL_BITMAP, row, 0);
 
if (unpack->LsbFirst) {
/* Lsb first */
GLubyte mask = 1U << (unpack->SkipPixels & 0x7);
for (col=0; col<width; col++) {
span.array->mask[col] = (*src & mask) ? GL_TRUE : GL_FALSE;
if (mask == 128U) {
src++;
mask = 1U;
}
else {
mask = mask << 1;
}
}
 
_swrast_write_rgba_span(ctx, &span);
 
/* get ready for next row */
if (mask != 1)
src++;
}
else {
/* Msb first */
GLubyte mask = 128U >> (unpack->SkipPixels & 0x7);
for (col=0; col<width; col++) {
span.array->mask[col] = (*src & mask) ? GL_TRUE : GL_FALSE;
if (mask == 1U) {
src++;
mask = 128U;
}
else {
mask = mask >> 1;
}
}
 
_swrast_write_rgba_span(ctx, &span);
 
/* get ready for next row */
if (mask != 128)
src++;
}
}
 
swrast_render_finish(ctx);
}
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_blend.c
0,0 → 1,1006
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
/**
* \file swrast/s_blend.c
* \brief software blending.
* \author Brian Paul
*
* Only a few blend modes have been optimized (min, max, transparency, add)
* more optimized cases can easily be added if needed.
* Celestia uses glBlendFunc(GL_SRC_ALPHA, GL_ONE), for example.
*/
 
 
 
#include "main/glheader.h"
#include "main/context.h"
#include "main/colormac.h"
#include "main/macros.h"
 
#include "s_blend.h"
#include "s_context.h"
#include "s_span.h"
 
 
#if defined(USE_MMX_ASM)
#include "x86/mmx.h"
#include "x86/common_x86_asm.h"
#endif
 
 
/**
* Integer divide by 255
* Declare "int divtemp" before using.
* This satisfies Glean and should be reasonably fast.
* Contributed by Nathan Hand.
*/
#define DIV255(X) (divtemp = (X), ((divtemp << 8) + divtemp + 256) >> 16)
 
 
 
/**
* Special case for glBlendFunc(GL_ZERO, GL_ONE).
* No-op means the framebuffer values remain unchanged.
* Any chanType ok.
*/
static void
blend_noop(struct gl_context *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
GLint bytes;
 
assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
assert(ctx->Color.Blend[0].SrcRGB == GL_ZERO);
assert(ctx->Color.Blend[0].DstRGB == GL_ONE);
(void) ctx;
 
/* just memcpy */
if (chanType == GL_UNSIGNED_BYTE)
bytes = 4 * n * sizeof(GLubyte);
else if (chanType == GL_UNSIGNED_SHORT)
bytes = 4 * n * sizeof(GLushort);
else
bytes = 4 * n * sizeof(GLfloat);
 
memcpy(src, dst, bytes);
}
 
 
/**
* Special case for glBlendFunc(GL_ONE, GL_ZERO)
* Any chanType ok.
*/
static void
blend_replace(struct gl_context *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
assert(ctx->Color.Blend[0].SrcRGB == GL_ONE);
assert(ctx->Color.Blend[0].DstRGB == GL_ZERO);
(void) ctx;
(void) n;
(void) mask;
(void) src;
(void) dst;
}
 
 
/**
* Common transparency blending mode:
* glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA).
*/
static void
blend_transparency_ubyte(struct gl_context *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
GLuint i;
 
assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
assert(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
assert(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
assert(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
assert(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
assert(chanType == GL_UNSIGNED_BYTE);
 
(void) ctx;
 
for (i = 0; i < n; i++) {
if (mask[i]) {
const GLint t = rgba[i][ACOMP]; /* t is in [0, 255] */
if (t == 0) {
/* 0% alpha */
COPY_4UBV(rgba[i], dest[i]);
}
else if (t != 255) {
GLint divtemp;
const GLint r = DIV255((rgba[i][RCOMP] - dest[i][RCOMP]) * t) + dest[i][RCOMP];
const GLint g = DIV255((rgba[i][GCOMP] - dest[i][GCOMP]) * t) + dest[i][GCOMP];
const GLint b = DIV255((rgba[i][BCOMP] - dest[i][BCOMP]) * t) + dest[i][BCOMP];
const GLint a = DIV255((rgba[i][ACOMP] - dest[i][ACOMP]) * t) + dest[i][ACOMP];
assert(r <= 255);
assert(g <= 255);
assert(b <= 255);
assert(a <= 255);
rgba[i][RCOMP] = (GLubyte) r;
rgba[i][GCOMP] = (GLubyte) g;
rgba[i][BCOMP] = (GLubyte) b;
rgba[i][ACOMP] = (GLubyte) a;
}
}
}
}
 
 
static void
blend_transparency_ushort(struct gl_context *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
GLushort (*rgba)[4] = (GLushort (*)[4]) src;
const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
GLuint i;
 
assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
assert(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
assert(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
assert(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
assert(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
assert(chanType == GL_UNSIGNED_SHORT);
 
(void) ctx;
 
for (i = 0; i < n; i++) {
if (mask[i]) {
const GLint t = rgba[i][ACOMP];
if (t == 0) {
/* 0% alpha */
COPY_4V(rgba[i], dest[i]);
}
else if (t != 65535) {
const GLfloat tt = (GLfloat) t / 65535.0F;
GLushort r = (GLushort) ((rgba[i][RCOMP] - dest[i][RCOMP]) * tt + dest[i][RCOMP]);
GLushort g = (GLushort) ((rgba[i][GCOMP] - dest[i][GCOMP]) * tt + dest[i][GCOMP]);
GLushort b = (GLushort) ((rgba[i][BCOMP] - dest[i][BCOMP]) * tt + dest[i][BCOMP]);
GLushort a = (GLushort) ((rgba[i][ACOMP] - dest[i][ACOMP]) * tt + dest[i][ACOMP]);
ASSIGN_4V(rgba[i], r, g, b, a);
}
}
}
}
 
 
static void
blend_transparency_float(struct gl_context *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
GLuint i;
 
assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
assert(ctx->Color.Blend[0].SrcRGB == GL_SRC_ALPHA);
assert(ctx->Color.Blend[0].SrcA == GL_SRC_ALPHA);
assert(ctx->Color.Blend[0].DstRGB == GL_ONE_MINUS_SRC_ALPHA);
assert(ctx->Color.Blend[0].DstA == GL_ONE_MINUS_SRC_ALPHA);
assert(chanType == GL_FLOAT);
 
(void) ctx;
 
for (i = 0; i < n; i++) {
if (mask[i]) {
const GLfloat t = rgba[i][ACOMP]; /* t in [0, 1] */
if (t == 0.0F) {
/* 0% alpha */
COPY_4V(rgba[i], dest[i]);
}
else if (t != 1.0F) {
GLfloat r = (rgba[i][RCOMP] - dest[i][RCOMP]) * t + dest[i][RCOMP];
GLfloat g = (rgba[i][GCOMP] - dest[i][GCOMP]) * t + dest[i][GCOMP];
GLfloat b = (rgba[i][BCOMP] - dest[i][BCOMP]) * t + dest[i][BCOMP];
GLfloat a = (rgba[i][ACOMP] - dest[i][ACOMP]) * t + dest[i][ACOMP];
ASSIGN_4V(rgba[i], r, g, b, a);
}
}
}
}
 
 
 
/**
* Add src and dest: glBlendFunc(GL_ONE, GL_ONE).
* Any chanType ok.
*/
static void
blend_add(struct gl_context *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
GLuint i;
 
assert(ctx->Color.Blend[0].EquationRGB == GL_FUNC_ADD);
assert(ctx->Color.Blend[0].EquationA == GL_FUNC_ADD);
assert(ctx->Color.Blend[0].SrcRGB == GL_ONE);
assert(ctx->Color.Blend[0].DstRGB == GL_ONE);
(void) ctx;
 
if (chanType == GL_UNSIGNED_BYTE) {
GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
for (i=0;i<n;i++) {
if (mask[i]) {
GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
rgba[i][RCOMP] = (GLubyte) MIN2( r, 255 );
rgba[i][GCOMP] = (GLubyte) MIN2( g, 255 );
rgba[i][BCOMP] = (GLubyte) MIN2( b, 255 );
rgba[i][ACOMP] = (GLubyte) MIN2( a, 255 );
}
}
}
else if (chanType == GL_UNSIGNED_SHORT) {
GLushort (*rgba)[4] = (GLushort (*)[4]) src;
const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
for (i=0;i<n;i++) {
if (mask[i]) {
GLint r = rgba[i][RCOMP] + dest[i][RCOMP];
GLint g = rgba[i][GCOMP] + dest[i][GCOMP];
GLint b = rgba[i][BCOMP] + dest[i][BCOMP];
GLint a = rgba[i][ACOMP] + dest[i][ACOMP];
rgba[i][RCOMP] = (GLshort) MIN2( r, 255 );
rgba[i][GCOMP] = (GLshort) MIN2( g, 255 );
rgba[i][BCOMP] = (GLshort) MIN2( b, 255 );
rgba[i][ACOMP] = (GLshort) MIN2( a, 255 );
}
}
}
else {
GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
assert(chanType == GL_FLOAT);
for (i=0;i<n;i++) {
if (mask[i]) {
/* don't RGB clamp to max */
rgba[i][RCOMP] += dest[i][RCOMP];
rgba[i][GCOMP] += dest[i][GCOMP];
rgba[i][BCOMP] += dest[i][BCOMP];
rgba[i][ACOMP] += dest[i][ACOMP];
}
}
}
}
 
 
 
/**
* Blend min function.
* Any chanType ok.
*/
static void
blend_min(struct gl_context *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
GLuint i;
assert(ctx->Color.Blend[0].EquationRGB == GL_MIN);
assert(ctx->Color.Blend[0].EquationA == GL_MIN);
(void) ctx;
 
if (chanType == GL_UNSIGNED_BYTE) {
GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
for (i=0;i<n;i++) {
if (mask[i]) {
rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
}
}
}
else if (chanType == GL_UNSIGNED_SHORT) {
GLushort (*rgba)[4] = (GLushort (*)[4]) src;
const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
for (i=0;i<n;i++) {
if (mask[i]) {
rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
}
}
}
else {
GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
assert(chanType == GL_FLOAT);
for (i=0;i<n;i++) {
if (mask[i]) {
rgba[i][RCOMP] = MIN2( rgba[i][RCOMP], dest[i][RCOMP] );
rgba[i][GCOMP] = MIN2( rgba[i][GCOMP], dest[i][GCOMP] );
rgba[i][BCOMP] = MIN2( rgba[i][BCOMP], dest[i][BCOMP] );
rgba[i][ACOMP] = MIN2( rgba[i][ACOMP], dest[i][ACOMP] );
}
}
}
}
 
 
/**
* Blend max function.
* Any chanType ok.
*/
static void
blend_max(struct gl_context *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
GLuint i;
assert(ctx->Color.Blend[0].EquationRGB == GL_MAX);
assert(ctx->Color.Blend[0].EquationA == GL_MAX);
(void) ctx;
 
if (chanType == GL_UNSIGNED_BYTE) {
GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
for (i=0;i<n;i++) {
if (mask[i]) {
rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
}
}
}
else if (chanType == GL_UNSIGNED_SHORT) {
GLushort (*rgba)[4] = (GLushort (*)[4]) src;
const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
for (i=0;i<n;i++) {
if (mask[i]) {
rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
}
}
}
else {
GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
assert(chanType == GL_FLOAT);
for (i=0;i<n;i++) {
if (mask[i]) {
rgba[i][RCOMP] = MAX2( rgba[i][RCOMP], dest[i][RCOMP] );
rgba[i][GCOMP] = MAX2( rgba[i][GCOMP], dest[i][GCOMP] );
rgba[i][BCOMP] = MAX2( rgba[i][BCOMP], dest[i][BCOMP] );
rgba[i][ACOMP] = MAX2( rgba[i][ACOMP], dest[i][ACOMP] );
}
}
}
}
 
 
 
/**
* Modulate: result = src * dest
* Any chanType ok.
*/
static void
blend_modulate(struct gl_context *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst, GLenum chanType)
{
GLuint i;
(void) ctx;
 
if (chanType == GL_UNSIGNED_BYTE) {
GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
for (i=0;i<n;i++) {
if (mask[i]) {
GLint divtemp;
rgba[i][RCOMP] = DIV255(rgba[i][RCOMP] * dest[i][RCOMP]);
rgba[i][GCOMP] = DIV255(rgba[i][GCOMP] * dest[i][GCOMP]);
rgba[i][BCOMP] = DIV255(rgba[i][BCOMP] * dest[i][BCOMP]);
rgba[i][ACOMP] = DIV255(rgba[i][ACOMP] * dest[i][ACOMP]);
}
}
}
else if (chanType == GL_UNSIGNED_SHORT) {
GLushort (*rgba)[4] = (GLushort (*)[4]) src;
const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
for (i=0;i<n;i++) {
if (mask[i]) {
rgba[i][RCOMP] = (rgba[i][RCOMP] * dest[i][RCOMP] + 65535) >> 16;
rgba[i][GCOMP] = (rgba[i][GCOMP] * dest[i][GCOMP] + 65535) >> 16;
rgba[i][BCOMP] = (rgba[i][BCOMP] * dest[i][BCOMP] + 65535) >> 16;
rgba[i][ACOMP] = (rgba[i][ACOMP] * dest[i][ACOMP] + 65535) >> 16;
}
}
}
else {
GLfloat (*rgba)[4] = (GLfloat (*)[4]) src;
const GLfloat (*dest)[4] = (const GLfloat (*)[4]) dst;
assert(chanType == GL_FLOAT);
for (i=0;i<n;i++) {
if (mask[i]) {
rgba[i][RCOMP] = rgba[i][RCOMP] * dest[i][RCOMP];
rgba[i][GCOMP] = rgba[i][GCOMP] * dest[i][GCOMP];
rgba[i][BCOMP] = rgba[i][BCOMP] * dest[i][BCOMP];
rgba[i][ACOMP] = rgba[i][ACOMP] * dest[i][ACOMP];
}
}
}
}
 
 
/**
* Do any blending operation, using floating point.
* \param n number of pixels
* \param mask fragment writemask array
* \param rgba array of incoming (and modified) pixels
* \param dest array of pixels from the dest color buffer
*/
static void
blend_general_float(struct gl_context *ctx, GLuint n, const GLubyte mask[],
GLfloat rgba[][4], GLfloat dest[][4],
GLenum chanType)
{
GLuint i;
 
for (i = 0; i < n; i++) {
if (mask[i]) {
/* Incoming/source Color */
const GLfloat Rs = rgba[i][RCOMP];
const GLfloat Gs = rgba[i][GCOMP];
const GLfloat Bs = rgba[i][BCOMP];
const GLfloat As = rgba[i][ACOMP];
 
/* Frame buffer/dest color */
const GLfloat Rd = dest[i][RCOMP];
const GLfloat Gd = dest[i][GCOMP];
const GLfloat Bd = dest[i][BCOMP];
const GLfloat Ad = dest[i][ACOMP];
 
GLfloat sR, sG, sB, sA; /* Source factor */
GLfloat dR, dG, dB, dA; /* Dest factor */
GLfloat r, g, b, a; /* result color */
 
/* XXX for the case of constant blend terms we could init
* the sX and dX variables just once before the loop.
*/
 
/* Source RGB factor */
switch (ctx->Color.Blend[0].SrcRGB) {
case GL_ZERO:
sR = sG = sB = 0.0F;
break;
case GL_ONE:
sR = sG = sB = 1.0F;
break;
case GL_DST_COLOR:
sR = Rd;
sG = Gd;
sB = Bd;
break;
case GL_ONE_MINUS_DST_COLOR:
sR = 1.0F - Rd;
sG = 1.0F - Gd;
sB = 1.0F - Bd;
break;
case GL_SRC_ALPHA:
sR = sG = sB = As;
break;
case GL_ONE_MINUS_SRC_ALPHA:
sR = sG = sB = 1.0F - As;
break;
case GL_DST_ALPHA:
sR = sG = sB = Ad;
break;
case GL_ONE_MINUS_DST_ALPHA:
sR = sG = sB = 1.0F - Ad;
break;
case GL_SRC_ALPHA_SATURATE:
if (As < 1.0F - Ad) {
sR = sG = sB = As;
}
else {
sR = sG = sB = 1.0F - Ad;
}
break;
case GL_CONSTANT_COLOR:
sR = ctx->Color.BlendColor[0];
sG = ctx->Color.BlendColor[1];
sB = ctx->Color.BlendColor[2];
break;
case GL_ONE_MINUS_CONSTANT_COLOR:
sR = 1.0F - ctx->Color.BlendColor[0];
sG = 1.0F - ctx->Color.BlendColor[1];
sB = 1.0F - ctx->Color.BlendColor[2];
break;
case GL_CONSTANT_ALPHA:
sR = sG = sB = ctx->Color.BlendColor[3];
break;
case GL_ONE_MINUS_CONSTANT_ALPHA:
sR = sG = sB = 1.0F - ctx->Color.BlendColor[3];
break;
case GL_SRC_COLOR:
sR = Rs;
sG = Gs;
sB = Bs;
break;
case GL_ONE_MINUS_SRC_COLOR:
sR = 1.0F - Rs;
sG = 1.0F - Gs;
sB = 1.0F - Bs;
break;
default:
/* this should never happen */
_mesa_problem(ctx, "Bad blend source RGB factor in blend_general_float");
return;
}
 
/* Source Alpha factor */
switch (ctx->Color.Blend[0].SrcA) {
case GL_ZERO:
sA = 0.0F;
break;
case GL_ONE:
sA = 1.0F;
break;
case GL_DST_COLOR:
sA = Ad;
break;
case GL_ONE_MINUS_DST_COLOR:
sA = 1.0F - Ad;
break;
case GL_SRC_ALPHA:
sA = As;
break;
case GL_ONE_MINUS_SRC_ALPHA:
sA = 1.0F - As;
break;
case GL_DST_ALPHA:
sA = Ad;
break;
case GL_ONE_MINUS_DST_ALPHA:
sA = 1.0F - Ad;
break;
case GL_SRC_ALPHA_SATURATE:
sA = 1.0;
break;
case GL_CONSTANT_COLOR:
sA = ctx->Color.BlendColor[3];
break;
case GL_ONE_MINUS_CONSTANT_COLOR:
sA = 1.0F - ctx->Color.BlendColor[3];
break;
case GL_CONSTANT_ALPHA:
sA = ctx->Color.BlendColor[3];
break;
case GL_ONE_MINUS_CONSTANT_ALPHA:
sA = 1.0F - ctx->Color.BlendColor[3];
break;
case GL_SRC_COLOR:
sA = As;
break;
case GL_ONE_MINUS_SRC_COLOR:
sA = 1.0F - As;
break;
default:
/* this should never happen */
sA = 0.0F;
_mesa_problem(ctx, "Bad blend source A factor in blend_general_float");
return;
}
 
/* Dest RGB factor */
switch (ctx->Color.Blend[0].DstRGB) {
case GL_ZERO:
dR = dG = dB = 0.0F;
break;
case GL_ONE:
dR = dG = dB = 1.0F;
break;
case GL_SRC_COLOR:
dR = Rs;
dG = Gs;
dB = Bs;
break;
case GL_ONE_MINUS_SRC_COLOR:
dR = 1.0F - Rs;
dG = 1.0F - Gs;
dB = 1.0F - Bs;
break;
case GL_SRC_ALPHA:
dR = dG = dB = As;
break;
case GL_ONE_MINUS_SRC_ALPHA:
dR = dG = dB = 1.0F - As;
break;
case GL_DST_ALPHA:
dR = dG = dB = Ad;
break;
case GL_ONE_MINUS_DST_ALPHA:
dR = dG = dB = 1.0F - Ad;
break;
case GL_CONSTANT_COLOR:
dR = ctx->Color.BlendColor[0];
dG = ctx->Color.BlendColor[1];
dB = ctx->Color.BlendColor[2];
break;
case GL_ONE_MINUS_CONSTANT_COLOR:
dR = 1.0F - ctx->Color.BlendColor[0];
dG = 1.0F - ctx->Color.BlendColor[1];
dB = 1.0F - ctx->Color.BlendColor[2];
break;
case GL_CONSTANT_ALPHA:
dR = dG = dB = ctx->Color.BlendColor[3];
break;
case GL_ONE_MINUS_CONSTANT_ALPHA:
dR = dG = dB = 1.0F - ctx->Color.BlendColor[3];
break;
case GL_DST_COLOR:
dR = Rd;
dG = Gd;
dB = Bd;
break;
case GL_ONE_MINUS_DST_COLOR:
dR = 1.0F - Rd;
dG = 1.0F - Gd;
dB = 1.0F - Bd;
break;
default:
/* this should never happen */
dR = dG = dB = 0.0F;
_mesa_problem(ctx, "Bad blend dest RGB factor in blend_general_float");
return;
}
 
/* Dest Alpha factor */
switch (ctx->Color.Blend[0].DstA) {
case GL_ZERO:
dA = 0.0F;
break;
case GL_ONE:
dA = 1.0F;
break;
case GL_SRC_COLOR:
dA = As;
break;
case GL_ONE_MINUS_SRC_COLOR:
dA = 1.0F - As;
break;
case GL_SRC_ALPHA:
dA = As;
break;
case GL_ONE_MINUS_SRC_ALPHA:
dA = 1.0F - As;
break;
case GL_DST_ALPHA:
dA = Ad;
break;
case GL_ONE_MINUS_DST_ALPHA:
dA = 1.0F - Ad;
break;
case GL_CONSTANT_COLOR:
dA = ctx->Color.BlendColor[3];
break;
case GL_ONE_MINUS_CONSTANT_COLOR:
dA = 1.0F - ctx->Color.BlendColor[3];
break;
case GL_CONSTANT_ALPHA:
dA = ctx->Color.BlendColor[3];
break;
case GL_ONE_MINUS_CONSTANT_ALPHA:
dA = 1.0F - ctx->Color.BlendColor[3];
break;
case GL_DST_COLOR:
dA = Ad;
break;
case GL_ONE_MINUS_DST_COLOR:
dA = 1.0F - Ad;
break;
default:
/* this should never happen */
dA = 0.0F;
_mesa_problem(ctx, "Bad blend dest A factor in blend_general_float");
return;
}
 
/* compute the blended RGB */
switch (ctx->Color.Blend[0].EquationRGB) {
case GL_FUNC_ADD:
r = Rs * sR + Rd * dR;
g = Gs * sG + Gd * dG;
b = Bs * sB + Bd * dB;
a = As * sA + Ad * dA;
break;
case GL_FUNC_SUBTRACT:
r = Rs * sR - Rd * dR;
g = Gs * sG - Gd * dG;
b = Bs * sB - Bd * dB;
a = As * sA - Ad * dA;
break;
case GL_FUNC_REVERSE_SUBTRACT:
r = Rd * dR - Rs * sR;
g = Gd * dG - Gs * sG;
b = Bd * dB - Bs * sB;
a = Ad * dA - As * sA;
break;
case GL_MIN:
r = MIN2( Rd, Rs );
g = MIN2( Gd, Gs );
b = MIN2( Bd, Bs );
break;
case GL_MAX:
r = MAX2( Rd, Rs );
g = MAX2( Gd, Gs );
b = MAX2( Bd, Bs );
break;
default:
/* should never get here */
r = g = b = 0.0F; /* silence uninitialized var warning */
_mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
return;
}
 
/* compute the blended alpha */
switch (ctx->Color.Blend[0].EquationA) {
case GL_FUNC_ADD:
a = As * sA + Ad * dA;
break;
case GL_FUNC_SUBTRACT:
a = As * sA - Ad * dA;
break;
case GL_FUNC_REVERSE_SUBTRACT:
a = Ad * dA - As * sA;
break;
case GL_MIN:
a = MIN2( Ad, As );
break;
case GL_MAX:
a = MAX2( Ad, As );
break;
default:
/* should never get here */
a = 0.0F; /* silence uninitialized var warning */
_mesa_problem(ctx, "unexpected BlendEquation in blend_general()");
return;
}
 
/* final clamping */
#if 0
rgba[i][RCOMP] = MAX2( r, 0.0F );
rgba[i][GCOMP] = MAX2( g, 0.0F );
rgba[i][BCOMP] = MAX2( b, 0.0F );
rgba[i][ACOMP] = CLAMP( a, 0.0F, 1.0F );
#else
ASSIGN_4V(rgba[i], r, g, b, a);
#endif
}
}
}
 
 
/**
* Do any blending operation, any chanType.
*/
static void
blend_general(struct gl_context *ctx, GLuint n, const GLubyte mask[],
void *src, const void *dst, GLenum chanType)
{
GLfloat (*rgbaF)[4], (*destF)[4];
 
rgbaF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat));
destF = (GLfloat (*)[4]) malloc(4 * n * sizeof(GLfloat));
if (!rgbaF || !destF) {
free(rgbaF);
free(destF);
_mesa_error(ctx, GL_OUT_OF_MEMORY, "blending");
return;
}
 
if (chanType == GL_UNSIGNED_BYTE) {
GLubyte (*rgba)[4] = (GLubyte (*)[4]) src;
const GLubyte (*dest)[4] = (const GLubyte (*)[4]) dst;
GLuint i;
/* convert ubytes to floats */
for (i = 0; i < n; i++) {
if (mask[i]) {
rgbaF[i][RCOMP] = UBYTE_TO_FLOAT(rgba[i][RCOMP]);
rgbaF[i][GCOMP] = UBYTE_TO_FLOAT(rgba[i][GCOMP]);
rgbaF[i][BCOMP] = UBYTE_TO_FLOAT(rgba[i][BCOMP]);
rgbaF[i][ACOMP] = UBYTE_TO_FLOAT(rgba[i][ACOMP]);
destF[i][RCOMP] = UBYTE_TO_FLOAT(dest[i][RCOMP]);
destF[i][GCOMP] = UBYTE_TO_FLOAT(dest[i][GCOMP]);
destF[i][BCOMP] = UBYTE_TO_FLOAT(dest[i][BCOMP]);
destF[i][ACOMP] = UBYTE_TO_FLOAT(dest[i][ACOMP]);
}
}
/* do blend */
blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
/* convert back to ubytes */
for (i = 0; i < n; i++) {
if (mask[i])
_mesa_unclamped_float_rgba_to_ubyte(rgba[i], rgbaF[i]);
}
}
else if (chanType == GL_UNSIGNED_SHORT) {
GLushort (*rgba)[4] = (GLushort (*)[4]) src;
const GLushort (*dest)[4] = (const GLushort (*)[4]) dst;
GLuint i;
/* convert ushorts to floats */
for (i = 0; i < n; i++) {
if (mask[i]) {
rgbaF[i][RCOMP] = USHORT_TO_FLOAT(rgba[i][RCOMP]);
rgbaF[i][GCOMP] = USHORT_TO_FLOAT(rgba[i][GCOMP]);
rgbaF[i][BCOMP] = USHORT_TO_FLOAT(rgba[i][BCOMP]);
rgbaF[i][ACOMP] = USHORT_TO_FLOAT(rgba[i][ACOMP]);
destF[i][RCOMP] = USHORT_TO_FLOAT(dest[i][RCOMP]);
destF[i][GCOMP] = USHORT_TO_FLOAT(dest[i][GCOMP]);
destF[i][BCOMP] = USHORT_TO_FLOAT(dest[i][BCOMP]);
destF[i][ACOMP] = USHORT_TO_FLOAT(dest[i][ACOMP]);
}
}
/* do blend */
blend_general_float(ctx, n, mask, rgbaF, destF, chanType);
/* convert back to ushorts */
for (i = 0; i < n; i++) {
if (mask[i]) {
UNCLAMPED_FLOAT_TO_USHORT(rgba[i][RCOMP], rgbaF[i][RCOMP]);
UNCLAMPED_FLOAT_TO_USHORT(rgba[i][GCOMP], rgbaF[i][GCOMP]);
UNCLAMPED_FLOAT_TO_USHORT(rgba[i][BCOMP], rgbaF[i][BCOMP]);
UNCLAMPED_FLOAT_TO_USHORT(rgba[i][ACOMP], rgbaF[i][ACOMP]);
}
}
}
else {
blend_general_float(ctx, n, mask, (GLfloat (*)[4]) src,
(GLfloat (*)[4]) dst, chanType);
}
 
free(rgbaF);
free(destF);
}
 
 
 
/**
* Analyze current blending parameters to pick fastest blending function.
* Result: the ctx->Color.BlendFunc pointer is updated.
*/
void
_swrast_choose_blend_func(struct gl_context *ctx, GLenum chanType)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
const GLenum eq = ctx->Color.Blend[0].EquationRGB;
const GLenum srcRGB = ctx->Color.Blend[0].SrcRGB;
const GLenum dstRGB = ctx->Color.Blend[0].DstRGB;
const GLenum srcA = ctx->Color.Blend[0].SrcA;
const GLenum dstA = ctx->Color.Blend[0].DstA;
 
if (ctx->Color.Blend[0].EquationRGB != ctx->Color.Blend[0].EquationA) {
swrast->BlendFunc = blend_general;
}
else if (eq == GL_MIN) {
/* Note: GL_MIN ignores the blending weight factors */
#if defined(USE_MMX_ASM)
if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
swrast->BlendFunc = _mesa_mmx_blend_min;
}
else
#endif
swrast->BlendFunc = blend_min;
}
else if (eq == GL_MAX) {
/* Note: GL_MAX ignores the blending weight factors */
#if defined(USE_MMX_ASM)
if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
swrast->BlendFunc = _mesa_mmx_blend_max;
}
else
#endif
swrast->BlendFunc = blend_max;
}
else if (srcRGB != srcA || dstRGB != dstA) {
swrast->BlendFunc = blend_general;
}
else if (eq == GL_FUNC_ADD && srcRGB == GL_SRC_ALPHA
&& dstRGB == GL_ONE_MINUS_SRC_ALPHA) {
#if defined(USE_MMX_ASM)
if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
swrast->BlendFunc = _mesa_mmx_blend_transparency;
}
else
#endif
{
if (chanType == GL_UNSIGNED_BYTE)
swrast->BlendFunc = blend_transparency_ubyte;
else if (chanType == GL_UNSIGNED_SHORT)
swrast->BlendFunc = blend_transparency_ushort;
else
swrast->BlendFunc = blend_transparency_float;
}
}
else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ONE) {
#if defined(USE_MMX_ASM)
if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
swrast->BlendFunc = _mesa_mmx_blend_add;
}
else
#endif
swrast->BlendFunc = blend_add;
}
else if (((eq == GL_FUNC_ADD || eq == GL_FUNC_REVERSE_SUBTRACT)
&& (srcRGB == GL_ZERO && dstRGB == GL_SRC_COLOR))
||
((eq == GL_FUNC_ADD || eq == GL_FUNC_SUBTRACT)
&& (srcRGB == GL_DST_COLOR && dstRGB == GL_ZERO))) {
#if defined(USE_MMX_ASM)
if (cpu_has_mmx && chanType == GL_UNSIGNED_BYTE) {
swrast->BlendFunc = _mesa_mmx_blend_modulate;
}
else
#endif
swrast->BlendFunc = blend_modulate;
}
else if (eq == GL_FUNC_ADD && srcRGB == GL_ZERO && dstRGB == GL_ONE) {
swrast->BlendFunc = blend_noop;
}
else if (eq == GL_FUNC_ADD && srcRGB == GL_ONE && dstRGB == GL_ZERO) {
swrast->BlendFunc = blend_replace;
}
else {
swrast->BlendFunc = blend_general;
}
}
 
 
 
/**
* Apply the blending operator to a span of pixels.
* We can handle horizontal runs of pixels (spans) or arrays of x/y
* pixel coordinates.
*/
void
_swrast_blend_span(struct gl_context *ctx, struct gl_renderbuffer *rb, SWspan *span)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
void *rbPixels;
 
assert(span->end <= SWRAST_MAX_WIDTH);
assert(span->arrayMask & SPAN_RGBA);
assert(!ctx->Color.ColorLogicOpEnabled);
 
rbPixels = _swrast_get_dest_rgba(ctx, rb, span);
 
swrast->BlendFunc(ctx, span->end, span->array->mask,
span->array->rgba, rbPixels, span->array->ChanType);
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_blend.h
0,0 → 1,45
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_BLEND_H
#define S_BLEND_H
 
 
#include "main/glheader.h"
#include "s_span.h"
 
struct gl_context;
struct gl_renderbuffer;
 
 
extern void
_swrast_blend_span(struct gl_context *ctx, struct gl_renderbuffer *rb, SWspan *span);
 
 
extern void
_swrast_choose_blend_func(struct gl_context *ctx, GLenum chanType);
 
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_blit.c
0,0 → 1,811
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#include "main/glheader.h"
#include "main/condrender.h"
#include "main/image.h"
#include "main/macros.h"
#include "main/format_unpack.h"
#include "main/format_pack.h"
#include "main/condrender.h"
#include "s_context.h"
 
 
#define ABS(X) ((X) < 0 ? -(X) : (X))
 
 
/**
* Generate a row resampler function for GL_NEAREST mode.
*/
#define RESAMPLE(NAME, PIXELTYPE, SIZE) \
static void \
NAME(GLint srcWidth, GLint dstWidth, \
const GLvoid *srcBuffer, GLvoid *dstBuffer, \
GLboolean flip) \
{ \
const PIXELTYPE *src = (const PIXELTYPE *) srcBuffer;\
PIXELTYPE *dst = (PIXELTYPE *) dstBuffer; \
GLint dstCol; \
\
if (flip) { \
for (dstCol = 0; dstCol < dstWidth; dstCol++) { \
GLint srcCol = (dstCol * srcWidth) / dstWidth; \
assert(srcCol >= 0); \
assert(srcCol < srcWidth); \
srcCol = srcWidth - 1 - srcCol; /* flip */ \
if (SIZE == 1) { \
dst[dstCol] = src[srcCol]; \
} \
else if (SIZE == 2) { \
dst[dstCol*2+0] = src[srcCol*2+0]; \
dst[dstCol*2+1] = src[srcCol*2+1]; \
} \
else if (SIZE == 4) { \
dst[dstCol*4+0] = src[srcCol*4+0]; \
dst[dstCol*4+1] = src[srcCol*4+1]; \
dst[dstCol*4+2] = src[srcCol*4+2]; \
dst[dstCol*4+3] = src[srcCol*4+3]; \
} \
} \
} \
else { \
for (dstCol = 0; dstCol < dstWidth; dstCol++) { \
GLint srcCol = (dstCol * srcWidth) / dstWidth; \
assert(srcCol >= 0); \
assert(srcCol < srcWidth); \
if (SIZE == 1) { \
dst[dstCol] = src[srcCol]; \
} \
else if (SIZE == 2) { \
dst[dstCol*2+0] = src[srcCol*2+0]; \
dst[dstCol*2+1] = src[srcCol*2+1]; \
} \
else if (SIZE == 4) { \
dst[dstCol*4+0] = src[srcCol*4+0]; \
dst[dstCol*4+1] = src[srcCol*4+1]; \
dst[dstCol*4+2] = src[srcCol*4+2]; \
dst[dstCol*4+3] = src[srcCol*4+3]; \
} \
} \
} \
}
 
/**
* Resamplers for 1, 2, 4, 8 and 16-byte pixels.
*/
RESAMPLE(resample_row_1, GLubyte, 1)
RESAMPLE(resample_row_2, GLushort, 1)
RESAMPLE(resample_row_4, GLuint, 1)
RESAMPLE(resample_row_8, GLuint, 2)
RESAMPLE(resample_row_16, GLuint, 4)
 
 
/**
* Blit color, depth or stencil with GL_NEAREST filtering.
*/
static void
blit_nearest(struct gl_context *ctx,
struct gl_framebuffer *readFb,
struct gl_framebuffer *drawFb,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield buffer)
{
struct gl_renderbuffer *readRb, *drawRb = NULL;
struct gl_renderbuffer_attachment *readAtt = NULL, *drawAtt = NULL;
GLuint numDrawBuffers = 0;
GLuint i;
 
const GLint srcWidth = ABS(srcX1 - srcX0);
const GLint dstWidth = ABS(dstX1 - dstX0);
const GLint srcHeight = ABS(srcY1 - srcY0);
const GLint dstHeight = ABS(dstY1 - dstY0);
 
const GLint srcXpos = MIN2(srcX0, srcX1);
const GLint srcYpos = MIN2(srcY0, srcY1);
const GLint dstXpos = MIN2(dstX0, dstX1);
const GLint dstYpos = MIN2(dstY0, dstY1);
 
const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
enum mode {
DIRECT,
UNPACK_RGBA_FLOAT,
UNPACK_Z_FLOAT,
UNPACK_Z_INT,
UNPACK_S,
} mode = DIRECT;
GLubyte *srcMap, *dstMap;
GLint srcRowStride, dstRowStride;
GLint dstRow;
 
GLint pixelSize = 0;
GLvoid *srcBuffer, *dstBuffer;
GLint prevY = -1;
 
typedef void (*resample_func)(GLint srcWidth, GLint dstWidth,
const GLvoid *srcBuffer, GLvoid *dstBuffer,
GLboolean flip);
resample_func resampleRow;
 
switch (buffer) {
case GL_COLOR_BUFFER_BIT:
readAtt = &readFb->Attachment[readFb->_ColorReadBufferIndex];
readRb = readFb->_ColorReadBuffer;
numDrawBuffers = drawFb->_NumColorDrawBuffers;
break;
case GL_DEPTH_BUFFER_BIT:
readAtt = &readFb->Attachment[BUFFER_DEPTH];
drawAtt = &drawFb->Attachment[BUFFER_DEPTH];
readRb = readAtt->Renderbuffer;
drawRb = drawAtt->Renderbuffer;
numDrawBuffers = 1;
 
/* Note that for depth/stencil, the formats of src/dst must match. By
* using the core helpers for pack/unpack, we avoid needing to handle
* masking for things like DEPTH copies of Z24S8.
*/
if (readRb->Format == MESA_FORMAT_Z_FLOAT32 ||
readRb->Format == MESA_FORMAT_Z32_FLOAT_S8X24_UINT) {
mode = UNPACK_Z_FLOAT;
} else {
mode = UNPACK_Z_INT;
}
pixelSize = 4;
break;
case GL_STENCIL_BUFFER_BIT:
readAtt = &readFb->Attachment[BUFFER_STENCIL];
drawAtt = &drawFb->Attachment[BUFFER_STENCIL];
readRb = readAtt->Renderbuffer;
drawRb = drawAtt->Renderbuffer;
numDrawBuffers = 1;
mode = UNPACK_S;
pixelSize = 1;
break;
default:
_mesa_problem(ctx, "unexpected buffer in blit_nearest()");
return;
}
 
/* allocate the src/dst row buffers */
srcBuffer = malloc(MAX_PIXEL_BYTES * srcWidth);
dstBuffer = malloc(MAX_PIXEL_BYTES * dstWidth);
if (!srcBuffer || !dstBuffer)
goto fail_no_memory;
 
/* Blit to all the draw buffers */
for (i = 0; i < numDrawBuffers; i++) {
if (buffer == GL_COLOR_BUFFER_BIT) {
int idx = drawFb->_ColorDrawBufferIndexes[i];
if (idx == -1)
continue;
drawAtt = &drawFb->Attachment[idx];
drawRb = drawAtt->Renderbuffer;
 
if (!drawRb)
continue;
 
if (readRb->Format == drawRb->Format) {
mode = DIRECT;
pixelSize = _mesa_get_format_bytes(readRb->Format);
} else {
mode = UNPACK_RGBA_FLOAT;
pixelSize = 16;
}
}
 
/* choose row resampler */
switch (pixelSize) {
case 1:
resampleRow = resample_row_1;
break;
case 2:
resampleRow = resample_row_2;
break;
case 4:
resampleRow = resample_row_4;
break;
case 8:
resampleRow = resample_row_8;
break;
case 16:
resampleRow = resample_row_16;
break;
default:
_mesa_problem(ctx, "unexpected pixel size (%d) in blit_nearest",
pixelSize);
goto fail;
}
 
if ((readRb == drawRb) ||
(readAtt->Texture && drawAtt->Texture &&
(readAtt->Texture == drawAtt->Texture))) {
/* map whole buffer for read/write */
/* XXX we could be clever and just map the union region of the
* source and dest rects.
*/
GLubyte *map;
GLint rowStride;
GLint formatSize = _mesa_get_format_bytes(readRb->Format);
 
ctx->Driver.MapRenderbuffer(ctx, readRb, 0, 0,
readRb->Width, readRb->Height,
GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
&map, &rowStride);
if (!map) {
goto fail_no_memory;
}
 
srcMap = map + srcYpos * rowStride + srcXpos * formatSize;
dstMap = map + dstYpos * rowStride + dstXpos * formatSize;
 
/* this handles overlapping copies */
if (srcY0 < dstY0) {
/* copy in reverse (top->down) order */
srcMap += rowStride * (readRb->Height - 1);
dstMap += rowStride * (readRb->Height - 1);
srcRowStride = -rowStride;
dstRowStride = -rowStride;
}
else {
/* copy in normal (bottom->up) order */
srcRowStride = rowStride;
dstRowStride = rowStride;
}
}
else {
/* different src/dst buffers */
ctx->Driver.MapRenderbuffer(ctx, readRb,
srcXpos, srcYpos,
srcWidth, srcHeight,
GL_MAP_READ_BIT, &srcMap, &srcRowStride);
if (!srcMap) {
goto fail_no_memory;
}
ctx->Driver.MapRenderbuffer(ctx, drawRb,
dstXpos, dstYpos,
dstWidth, dstHeight,
GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
if (!dstMap) {
ctx->Driver.UnmapRenderbuffer(ctx, readRb);
goto fail_no_memory;
}
}
 
for (dstRow = 0; dstRow < dstHeight; dstRow++) {
GLfloat srcRowF = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F;
GLint srcRow = IROUND(srcRowF);
GLubyte *dstRowStart = dstMap + dstRowStride * dstRow;
 
assert(srcRow >= 0);
assert(srcRow < srcHeight);
 
if (invertY) {
srcRow = srcHeight - 1 - srcRow;
}
 
/* get pixel row from source and resample to match dest width */
if (prevY != srcRow) {
GLubyte *srcRowStart = srcMap + srcRowStride * srcRow;
 
switch (mode) {
case DIRECT:
memcpy(srcBuffer, srcRowStart, pixelSize * srcWidth);
break;
case UNPACK_RGBA_FLOAT:
_mesa_unpack_rgba_row(readRb->Format, srcWidth, srcRowStart,
srcBuffer);
break;
case UNPACK_Z_FLOAT:
_mesa_unpack_float_z_row(readRb->Format, srcWidth, srcRowStart,
srcBuffer);
break;
case UNPACK_Z_INT:
_mesa_unpack_uint_z_row(readRb->Format, srcWidth, srcRowStart,
srcBuffer);
break;
case UNPACK_S:
_mesa_unpack_ubyte_stencil_row(readRb->Format, srcWidth,
srcRowStart, srcBuffer);
break;
}
 
(*resampleRow)(srcWidth, dstWidth, srcBuffer, dstBuffer, invertX);
prevY = srcRow;
}
 
/* store pixel row in destination */
switch (mode) {
case DIRECT:
memcpy(dstRowStart, dstBuffer, pixelSize * dstWidth);
break;
case UNPACK_RGBA_FLOAT:
_mesa_pack_float_rgba_row(drawRb->Format, dstWidth, dstBuffer,
dstRowStart);
break;
case UNPACK_Z_FLOAT:
_mesa_pack_float_z_row(drawRb->Format, dstWidth, dstBuffer,
dstRowStart);
break;
case UNPACK_Z_INT:
_mesa_pack_uint_z_row(drawRb->Format, dstWidth, dstBuffer,
dstRowStart);
break;
case UNPACK_S:
_mesa_pack_ubyte_stencil_row(drawRb->Format, dstWidth, dstBuffer,
dstRowStart);
break;
}
}
 
ctx->Driver.UnmapRenderbuffer(ctx, readRb);
if (drawRb != readRb) {
ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
}
}
 
fail:
free(srcBuffer);
free(dstBuffer);
return;
 
fail_no_memory:
free(srcBuffer);
free(dstBuffer);
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFrameBuffer");
}
 
 
 
#define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )
 
static inline GLfloat
lerp_2d(GLfloat a, GLfloat b,
GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11)
{
const GLfloat temp0 = LERP(a, v00, v10);
const GLfloat temp1 = LERP(a, v01, v11);
return LERP(b, temp0, temp1);
}
 
 
/**
* Bilinear interpolation of two source rows.
* GLubyte pixels.
*/
static void
resample_linear_row_ub(GLint srcWidth, GLint dstWidth,
const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
{
const GLubyte (*srcColor0)[4] = (const GLubyte (*)[4]) srcBuffer0;
const GLubyte (*srcColor1)[4] = (const GLubyte (*)[4]) srcBuffer1;
GLubyte (*dstColor)[4] = (GLubyte (*)[4]) dstBuffer;
GLint dstCol;
 
for (dstCol = 0; dstCol < dstWidth; dstCol++) {
const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F;
GLint srcCol0 = MAX2(0, IFLOOR(srcCol));
GLint srcCol1 = srcCol0 + 1;
GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
GLfloat red, green, blue, alpha;
 
assert(srcCol0 < srcWidth);
assert(srcCol1 <= srcWidth);
 
if (srcCol1 == srcWidth) {
/* last column fudge */
srcCol1--;
colWeight = 0.0;
}
 
if (flip) {
srcCol0 = srcWidth - 1 - srcCol0;
srcCol1 = srcWidth - 1 - srcCol1;
}
 
red = lerp_2d(colWeight, rowWeight,
srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
green = lerp_2d(colWeight, rowWeight,
srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
blue = lerp_2d(colWeight, rowWeight,
srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
alpha = lerp_2d(colWeight, rowWeight,
srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
dstColor[dstCol][RCOMP] = IFLOOR(red);
dstColor[dstCol][GCOMP] = IFLOOR(green);
dstColor[dstCol][BCOMP] = IFLOOR(blue);
dstColor[dstCol][ACOMP] = IFLOOR(alpha);
}
}
 
 
/**
* Bilinear interpolation of two source rows. floating point pixels.
*/
static void
resample_linear_row_float(GLint srcWidth, GLint dstWidth,
const GLvoid *srcBuffer0, const GLvoid *srcBuffer1,
GLvoid *dstBuffer, GLboolean flip, GLfloat rowWeight)
{
const GLfloat (*srcColor0)[4] = (const GLfloat (*)[4]) srcBuffer0;
const GLfloat (*srcColor1)[4] = (const GLfloat (*)[4]) srcBuffer1;
GLfloat (*dstColor)[4] = (GLfloat (*)[4]) dstBuffer;
GLint dstCol;
 
for (dstCol = 0; dstCol < dstWidth; dstCol++) {
const GLfloat srcCol = (dstCol + 0.5F) / dstWidth * srcWidth - 0.5F;
GLint srcCol0 = MAX2(0, IFLOOR(srcCol));
GLint srcCol1 = srcCol0 + 1;
GLfloat colWeight = srcCol - srcCol0; /* fractional part of srcCol */
GLfloat red, green, blue, alpha;
 
assert(srcCol0 < srcWidth);
assert(srcCol1 <= srcWidth);
 
if (srcCol1 == srcWidth) {
/* last column fudge */
srcCol1--;
colWeight = 0.0;
}
 
if (flip) {
srcCol0 = srcWidth - 1 - srcCol0;
srcCol1 = srcWidth - 1 - srcCol1;
}
 
red = lerp_2d(colWeight, rowWeight,
srcColor0[srcCol0][RCOMP], srcColor0[srcCol1][RCOMP],
srcColor1[srcCol0][RCOMP], srcColor1[srcCol1][RCOMP]);
green = lerp_2d(colWeight, rowWeight,
srcColor0[srcCol0][GCOMP], srcColor0[srcCol1][GCOMP],
srcColor1[srcCol0][GCOMP], srcColor1[srcCol1][GCOMP]);
blue = lerp_2d(colWeight, rowWeight,
srcColor0[srcCol0][BCOMP], srcColor0[srcCol1][BCOMP],
srcColor1[srcCol0][BCOMP], srcColor1[srcCol1][BCOMP]);
alpha = lerp_2d(colWeight, rowWeight,
srcColor0[srcCol0][ACOMP], srcColor0[srcCol1][ACOMP],
srcColor1[srcCol0][ACOMP], srcColor1[srcCol1][ACOMP]);
dstColor[dstCol][RCOMP] = red;
dstColor[dstCol][GCOMP] = green;
dstColor[dstCol][BCOMP] = blue;
dstColor[dstCol][ACOMP] = alpha;
}
}
 
 
 
/**
* Bilinear filtered blit (color only, non-integer values).
*/
static void
blit_linear(struct gl_context *ctx,
struct gl_framebuffer *readFb,
struct gl_framebuffer *drawFb,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1)
{
struct gl_renderbuffer *readRb = readFb->_ColorReadBuffer;
struct gl_renderbuffer_attachment *readAtt =
&readFb->Attachment[readFb->_ColorReadBufferIndex];
 
const GLint srcWidth = ABS(srcX1 - srcX0);
const GLint dstWidth = ABS(dstX1 - dstX0);
const GLint srcHeight = ABS(srcY1 - srcY0);
const GLint dstHeight = ABS(dstY1 - dstY0);
 
const GLint srcXpos = MIN2(srcX0, srcX1);
const GLint srcYpos = MIN2(srcY0, srcY1);
const GLint dstXpos = MIN2(dstX0, dstX1);
const GLint dstYpos = MIN2(dstY0, dstY1);
 
const GLboolean invertX = (srcX1 < srcX0) ^ (dstX1 < dstX0);
const GLboolean invertY = (srcY1 < srcY0) ^ (dstY1 < dstY0);
 
GLint dstRow;
 
GLint pixelSize;
GLvoid *srcBuffer0, *srcBuffer1;
GLint srcBufferY0 = -1, srcBufferY1 = -1;
GLvoid *dstBuffer;
 
mesa_format readFormat = _mesa_get_srgb_format_linear(readRb->Format);
GLuint bpp = _mesa_get_format_bytes(readFormat);
 
GLenum pixelType;
 
GLubyte *srcMap, *dstMap;
GLint srcRowStride, dstRowStride;
GLuint i;
 
 
/* Determine datatype for resampling */
if (_mesa_get_format_max_bits(readFormat) == 8 &&
_mesa_get_format_datatype(readFormat) == GL_UNSIGNED_NORMALIZED) {
pixelType = GL_UNSIGNED_BYTE;
pixelSize = 4 * sizeof(GLubyte);
}
else {
pixelType = GL_FLOAT;
pixelSize = 4 * sizeof(GLfloat);
}
 
/* Allocate the src/dst row buffers.
* Keep two adjacent src rows around for bilinear sampling.
*/
srcBuffer0 = malloc(pixelSize * srcWidth);
srcBuffer1 = malloc(pixelSize * srcWidth);
dstBuffer = malloc(pixelSize * dstWidth);
if (!srcBuffer0 || !srcBuffer1 || !dstBuffer) {
goto fail_no_memory;
}
 
for (i = 0; i < drawFb->_NumColorDrawBuffers; i++) {
GLint idx = drawFb->_ColorDrawBufferIndexes[i];
struct gl_renderbuffer_attachment *drawAtt;
struct gl_renderbuffer *drawRb;
mesa_format drawFormat;
 
if (idx == -1)
continue;
 
drawAtt = &drawFb->Attachment[idx];
drawRb = drawAtt->Renderbuffer;
if (!drawRb)
continue;
 
drawFormat = _mesa_get_srgb_format_linear(drawRb->Format);
 
/*
* Map src / dst renderbuffers
*/
if ((readRb == drawRb) ||
(readAtt->Texture && drawAtt->Texture &&
(readAtt->Texture == drawAtt->Texture))) {
/* map whole buffer for read/write */
ctx->Driver.MapRenderbuffer(ctx, readRb,
0, 0, readRb->Width, readRb->Height,
GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
&srcMap, &srcRowStride);
if (!srcMap) {
goto fail_no_memory;
}
 
dstMap = srcMap;
dstRowStride = srcRowStride;
}
else {
/* different src/dst buffers */
/* XXX with a bit of work we could just map the regions to be
* read/written instead of the whole buffers.
*/
ctx->Driver.MapRenderbuffer(ctx, readRb,
0, 0, readRb->Width, readRb->Height,
GL_MAP_READ_BIT, &srcMap, &srcRowStride);
if (!srcMap) {
goto fail_no_memory;
}
ctx->Driver.MapRenderbuffer(ctx, drawRb,
0, 0, drawRb->Width, drawRb->Height,
GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
if (!dstMap) {
ctx->Driver.UnmapRenderbuffer(ctx, readRb);
goto fail_no_memory;
}
}
 
for (dstRow = 0; dstRow < dstHeight; dstRow++) {
const GLint dstY = dstYpos + dstRow;
GLfloat srcRow = (dstRow + 0.5F) / dstHeight * srcHeight - 0.5F;
GLint srcRow0 = MAX2(0, IFLOOR(srcRow));
GLint srcRow1 = srcRow0 + 1;
GLfloat rowWeight = srcRow - srcRow0; /* fractional part of srcRow */
 
if (srcRow1 == srcHeight) {
/* last row fudge */
srcRow1 = srcRow0;
rowWeight = 0.0;
}
 
if (invertY) {
srcRow0 = srcHeight - 1 - srcRow0;
srcRow1 = srcHeight - 1 - srcRow1;
}
 
srcY0 = srcYpos + srcRow0;
srcY1 = srcYpos + srcRow1;
 
/* get the two source rows */
if (srcY0 == srcBufferY0 && srcY1 == srcBufferY1) {
/* use same source row buffers again */
}
else if (srcY0 == srcBufferY1) {
/* move buffer1 into buffer0 by swapping pointers */
GLvoid *tmp = srcBuffer0;
srcBuffer0 = srcBuffer1;
srcBuffer1 = tmp;
/* get y1 row */
{
GLubyte *src = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
if (pixelType == GL_UNSIGNED_BYTE) {
_mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
src, srcBuffer1);
}
else {
_mesa_unpack_rgba_row(readFormat, srcWidth,
src, srcBuffer1);
}
}
srcBufferY0 = srcY0;
srcBufferY1 = srcY1;
}
else {
/* get both new rows */
{
GLubyte *src0 = srcMap + srcY0 * srcRowStride + srcXpos * bpp;
GLubyte *src1 = srcMap + srcY1 * srcRowStride + srcXpos * bpp;
if (pixelType == GL_UNSIGNED_BYTE) {
_mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
src0, srcBuffer0);
_mesa_unpack_ubyte_rgba_row(readFormat, srcWidth,
src1, srcBuffer1);
}
else {
_mesa_unpack_rgba_row(readFormat, srcWidth, src0, srcBuffer0);
_mesa_unpack_rgba_row(readFormat, srcWidth, src1, srcBuffer1);
}
}
srcBufferY0 = srcY0;
srcBufferY1 = srcY1;
}
 
if (pixelType == GL_UNSIGNED_BYTE) {
resample_linear_row_ub(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
dstBuffer, invertX, rowWeight);
}
else {
resample_linear_row_float(srcWidth, dstWidth, srcBuffer0, srcBuffer1,
dstBuffer, invertX, rowWeight);
}
 
/* store pixel row in destination */
{
GLubyte *dst = dstMap + dstY * dstRowStride + dstXpos * bpp;
if (pixelType == GL_UNSIGNED_BYTE) {
_mesa_pack_ubyte_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
}
else {
_mesa_pack_float_rgba_row(drawFormat, dstWidth, dstBuffer, dst);
}
}
}
 
ctx->Driver.UnmapRenderbuffer(ctx, readRb);
if (drawRb != readRb) {
ctx->Driver.UnmapRenderbuffer(ctx, drawRb);
}
}
 
free(srcBuffer0);
free(srcBuffer1);
free(dstBuffer);
return;
 
fail_no_memory:
free(srcBuffer0);
free(srcBuffer1);
free(dstBuffer);
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glBlitFramebuffer");
}
 
 
 
/**
* Software fallback for glBlitFramebufferEXT().
*/
void
_swrast_BlitFramebuffer(struct gl_context *ctx,
struct gl_framebuffer *readFb,
struct gl_framebuffer *drawFb,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter)
{
static const GLbitfield buffers[3] = {
GL_COLOR_BUFFER_BIT,
GL_DEPTH_BUFFER_BIT,
GL_STENCIL_BUFFER_BIT
};
static const GLenum buffer_enums[3] = {
GL_COLOR,
GL_DEPTH,
GL_STENCIL,
};
GLint i;
 
/* Page 679 of OpenGL 4.4 spec says:
* "Added BlitFramebuffer to commands affected by conditional rendering in
* section 10.10 (Bug 9562)."
*/
if (!_mesa_check_conditional_render(ctx))
return; /* Do not blit */
 
if (!_mesa_clip_blit(ctx, readFb, drawFb, &srcX0, &srcY0, &srcX1, &srcY1,
&dstX0, &dstY0, &dstX1, &dstY1)) {
return;
}
 
if (SWRAST_CONTEXT(ctx)->NewState)
_swrast_validate_derived(ctx);
 
/* First, try covering whatever buffers possible using the fast 1:1 copy
* path.
*/
if (srcX1 - srcX0 == dstX1 - dstX0 &&
srcY1 - srcY0 == dstY1 - dstY0 &&
srcX0 < srcX1 &&
srcY0 < srcY1 &&
dstX0 < dstX1 &&
dstY0 < dstY1) {
for (i = 0; i < 3; i++) {
if (mask & buffers[i]) {
if (swrast_fast_copy_pixels(ctx,
readFb, drawFb,
srcX0, srcY0,
srcX1 - srcX0, srcY1 - srcY0,
dstX0, dstY0,
buffer_enums[i])) {
mask &= ~buffers[i];
}
}
}
 
if (!mask)
return;
}
 
if (filter == GL_NEAREST) {
for (i = 0; i < 3; i++) {
if (mask & buffers[i]) {
blit_nearest(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1, buffers[i]);
}
}
}
else {
assert(filter == GL_LINEAR);
if (mask & GL_COLOR_BUFFER_BIT) { /* depth/stencil not allowed */
blit_linear(ctx, readFb, drawFb, srcX0, srcY0, srcX1, srcY1,
dstX0, dstY0, dstX1, dstY1);
}
}
 
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_chan.h
0,0 → 1,128
/*
* Mesa 3-D graphics library
*
* Copyright (C) 2011 VMware, Inc. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
/**
* Types, macros, etc for the GLchan datatype.
* The swrast module is kind of hard-coded for 8bpp color channels but
* may be recompiled to use 16- or 32-bit color channels. But that
* feature is seldom used and is likely broken in various ways.
*/
 
#ifndef U_CHAN_H
#define U_CHAN_H
 
 
#include "main/config.h"
 
 
/**
* Default bits per color channel: 8, 16 or 32
*/
#ifndef CHAN_BITS
#define CHAN_BITS 8
#endif
 
 
/**
* Color channel data type.
*/
#if CHAN_BITS == 8
typedef GLubyte GLchan;
#define CHAN_MAX 255
#define CHAN_MAXF 255.0F
#define CHAN_TYPE GL_UNSIGNED_BYTE
#elif CHAN_BITS == 16
typedef GLushort GLchan;
#define CHAN_MAX 65535
#define CHAN_MAXF 65535.0F
#define CHAN_TYPE GL_UNSIGNED_SHORT
#elif CHAN_BITS == 32
typedef GLfloat GLchan;
#define CHAN_MAX 1.0
#define CHAN_MAXF 1.0F
#define CHAN_TYPE GL_FLOAT
#else
#error "illegal number of color channel bits"
#endif
 
 
#if CHAN_BITS == 8
 
#define CHAN_TO_UBYTE(c) (c)
#define CHAN_TO_USHORT(c) (((c) << 8) | (c))
#define CHAN_TO_SHORT(c) (((c) << 7) | ((c) >> 1))
#define CHAN_TO_FLOAT(c) UBYTE_TO_FLOAT(c)
 
#define CLAMPED_FLOAT_TO_CHAN(c, f) CLAMPED_FLOAT_TO_UBYTE(c, f)
#define UNCLAMPED_FLOAT_TO_CHAN(c, f) UNCLAMPED_FLOAT_TO_UBYTE(c, f)
 
#define COPY_CHAN4(DST, SRC) COPY_4UBV(DST, SRC)
 
#elif CHAN_BITS == 16
 
#define CHAN_TO_UBYTE(c) ((c) >> 8)
#define CHAN_TO_USHORT(c) (c)
#define CHAN_TO_SHORT(c) ((c) >> 1)
#define CHAN_TO_FLOAT(c) ((GLfloat) ((c) * (1.0 / CHAN_MAXF)))
 
#define CLAMPED_FLOAT_TO_CHAN(c, f) CLAMPED_FLOAT_TO_USHORT(c, f)
#define UNCLAMPED_FLOAT_TO_CHAN(c, f) UNCLAMPED_FLOAT_TO_USHORT(c, f)
 
#define COPY_CHAN4(DST, SRC) COPY_4V(DST, SRC)
 
#elif CHAN_BITS == 32
 
#define CHAN_TO_UBYTE(c) FLOAT_TO_UBYTE(c)
#define CHAN_TO_USHORT(c) ((GLushort) (CLAMP((c), 0.0f, 1.0f) * 65535.0))
#define CHAN_TO_SHORT(c) ((GLshort) (CLAMP((c), 0.0f, 1.0f) * 32767.0))
#define CHAN_TO_FLOAT(c) (c)
 
#define CLAMPED_FLOAT_TO_CHAN(c, f) c = (f)
#define UNCLAMPED_FLOAT_TO_CHAN(c, f) c = (f)
 
#define COPY_CHAN4(DST, SRC) COPY_4V(DST, SRC)
 
#else
 
#error unexpected CHAN_BITS size
 
#endif
 
 
/**
* Convert 4 floats to GLchan values.
* \param dst pointer to destination GLchan[4] array.
* \param f pointer to source GLfloat[4] array.
*/
#define UNCLAMPED_FLOAT_TO_RGBA_CHAN(dst, f) \
do { \
UNCLAMPED_FLOAT_TO_CHAN((dst)[0], (f)[0]); \
UNCLAMPED_FLOAT_TO_CHAN((dst)[1], (f)[1]); \
UNCLAMPED_FLOAT_TO_CHAN((dst)[2], (f)[2]); \
UNCLAMPED_FLOAT_TO_CHAN((dst)[3], (f)[3]); \
} while (0)
 
 
 
#endif /* U_CHAN_H */
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_clear.c
0,0 → 1,257
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
#include "main/glheader.h"
#include "main/accum.h"
#include "main/condrender.h"
#include "main/format_pack.h"
#include "main/macros.h"
#include "main/imports.h"
#include "main/mtypes.h"
 
#include "s_context.h"
#include "s_depth.h"
#include "s_stencil.h"
 
 
 
/**
* Clear an rgba color buffer with masking if needed.
*/
static void
clear_rgba_buffer(struct gl_context *ctx, struct gl_renderbuffer *rb,
const GLubyte colorMask[4])
{
const GLint x = ctx->DrawBuffer->_Xmin;
const GLint y = ctx->DrawBuffer->_Ymin;
const GLint height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
const GLint width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
const GLuint pixelSize = _mesa_get_format_bytes(rb->Format);
const GLboolean doMasking = (colorMask[0] == 0 ||
colorMask[1] == 0 ||
colorMask[2] == 0 ||
colorMask[3] == 0);
const GLfloat (*clearColor)[4] =
(const GLfloat (*)[4]) ctx->Color.ClearColor.f;
GLbitfield mapMode = GL_MAP_WRITE_BIT;
GLubyte *map;
GLint rowStride;
GLint i, j;
 
if (doMasking) {
/* we'll need to read buffer values too */
mapMode |= GL_MAP_READ_BIT;
}
 
/* map dest buffer */
ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
mapMode, &map, &rowStride);
if (!map) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(color)");
return;
}
 
/* for 1, 2, 4-byte clearing */
#define SIMPLE_TYPE_CLEAR(TYPE) \
do { \
TYPE pixel, pixelMask; \
_mesa_pack_float_rgba_row(rb->Format, 1, clearColor, &pixel); \
if (doMasking) { \
_mesa_pack_colormask(rb->Format, colorMask, &pixelMask); \
pixel &= pixelMask; \
pixelMask = ~pixelMask; \
} \
for (i = 0; i < height; i++) { \
TYPE *row = (TYPE *) map; \
if (doMasking) { \
for (j = 0; j < width; j++) { \
row[j] = (row[j] & pixelMask) | pixel; \
} \
} \
else { \
for (j = 0; j < width; j++) { \
row[j] = pixel; \
} \
} \
map += rowStride; \
} \
} while (0)
 
 
/* for 3, 6, 8, 12, 16-byte clearing */
#define MULTI_WORD_CLEAR(TYPE, N) \
do { \
TYPE pixel[N], pixelMask[N]; \
GLuint k; \
_mesa_pack_float_rgba_row(rb->Format, 1, clearColor, pixel); \
if (doMasking) { \
_mesa_pack_colormask(rb->Format, colorMask, pixelMask); \
for (k = 0; k < N; k++) { \
pixel[k] &= pixelMask[k]; \
pixelMask[k] = ~pixelMask[k]; \
} \
} \
for (i = 0; i < height; i++) { \
TYPE *row = (TYPE *) map; \
if (doMasking) { \
for (j = 0; j < width; j++) { \
for (k = 0; k < N; k++) { \
row[j * N + k] = \
(row[j * N + k] & pixelMask[k]) | pixel[k]; \
} \
} \
} \
else { \
for (j = 0; j < width; j++) { \
for (k = 0; k < N; k++) { \
row[j * N + k] = pixel[k]; \
} \
} \
} \
map += rowStride; \
} \
} while(0)
 
switch (pixelSize) {
case 1:
SIMPLE_TYPE_CLEAR(GLubyte);
break;
case 2:
SIMPLE_TYPE_CLEAR(GLushort);
break;
case 3:
MULTI_WORD_CLEAR(GLubyte, 3);
break;
case 4:
SIMPLE_TYPE_CLEAR(GLuint);
break;
case 6:
MULTI_WORD_CLEAR(GLushort, 3);
break;
case 8:
MULTI_WORD_CLEAR(GLuint, 2);
break;
case 12:
MULTI_WORD_CLEAR(GLuint, 3);
break;
case 16:
MULTI_WORD_CLEAR(GLuint, 4);
break;
default:
_mesa_problem(ctx, "bad pixel size in clear_rgba_buffer()");
}
 
/* unmap buffer */
ctx->Driver.UnmapRenderbuffer(ctx, rb);
}
 
 
/**
* Clear the front/back/left/right/aux color buffers.
* This function is usually only called if the device driver can't
* clear its own color buffers for some reason (such as with masking).
*/
static void
clear_color_buffers(struct gl_context *ctx)
{
GLuint buf;
 
for (buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) {
struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[buf];
 
/* If this is an ES2 context or GL_ARB_ES2_compatibility is supported,
* the framebuffer can be complete with some attachments be missing. In
* this case the _ColorDrawBuffers pointer will be NULL.
*/
if (rb == NULL)
continue;
 
clear_rgba_buffer(ctx, rb, ctx->Color.ColorMask[buf]);
}
}
 
 
/**
* Called via the device driver's ctx->Driver.Clear() function if the
* device driver can't clear one or more of the buffers itself.
* \param buffers bitfield of BUFFER_BIT_* values indicating which
* renderbuffers are to be cleared.
* \param all if GL_TRUE, clear whole buffer, else clear specified region.
*/
void
_swrast_Clear(struct gl_context *ctx, GLbitfield buffers)
{
const GLbitfield BUFFER_DS = BUFFER_BIT_DEPTH | BUFFER_BIT_STENCIL;
 
#ifdef DEBUG_FOO
{
const GLbitfield legalBits =
BUFFER_BIT_FRONT_LEFT |
BUFFER_BIT_FRONT_RIGHT |
BUFFER_BIT_BACK_LEFT |
BUFFER_BIT_BACK_RIGHT |
BUFFER_BIT_DEPTH |
BUFFER_BIT_STENCIL |
BUFFER_BIT_ACCUM |
BUFFER_BIT_AUX0;
assert((buffers & (~legalBits)) == 0);
}
#endif
 
if (!_mesa_check_conditional_render(ctx))
return; /* don't clear */
 
if (SWRAST_CONTEXT(ctx)->NewState)
_swrast_validate_derived(ctx);
 
if ((buffers & BUFFER_BITS_COLOR)
&& (ctx->DrawBuffer->_NumColorDrawBuffers > 0)) {
clear_color_buffers(ctx);
}
 
if (buffers & BUFFER_BIT_ACCUM) {
_mesa_clear_accum_buffer(ctx);
}
 
if (buffers & BUFFER_DS) {
struct gl_renderbuffer *depthRb =
ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
struct gl_renderbuffer *stencilRb =
ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
 
if ((buffers & BUFFER_DS) == BUFFER_DS && depthRb == stencilRb) {
/* clear depth and stencil together */
_swrast_clear_depth_stencil_buffer(ctx);
}
else {
/* clear depth, stencil separately */
if (buffers & BUFFER_BIT_DEPTH) {
_swrast_clear_depth_buffer(ctx);
}
if (buffers & BUFFER_BIT_STENCIL) {
_swrast_clear_stencil_buffer(ctx);
}
}
}
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_context.c
0,0 → 1,950
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
* Authors:
* Keith Whitwell <keithw@vmware.com> Brian Paul
*/
 
#include "main/imports.h"
#include "main/bufferobj.h"
#include "main/mtypes.h"
#include "main/samplerobj.h"
#include "main/teximage.h"
#include "program/prog_parameter.h"
#include "program/prog_statevars.h"
#include "swrast.h"
#include "s_blend.h"
#include "s_context.h"
#include "s_lines.h"
#include "s_points.h"
#include "s_span.h"
#include "s_texfetch.h"
#include "s_triangle.h"
#include "s_texfilter.h"
 
 
/**
* Recompute the value of swrast->_RasterMask, etc. according to
* the current context. The _RasterMask field can be easily tested by
* drivers to determine certain basic GL state (does the primitive need
* stenciling, logic-op, fog, etc?).
*/
static void
_swrast_update_rasterflags( struct gl_context *ctx )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
GLbitfield rasterMask = 0;
GLuint i;
 
if (ctx->Color.AlphaEnabled) rasterMask |= ALPHATEST_BIT;
if (ctx->Color.BlendEnabled) rasterMask |= BLEND_BIT;
if (ctx->Depth.Test) rasterMask |= DEPTH_BIT;
if (swrast->_FogEnabled) rasterMask |= FOG_BIT;
if (ctx->Scissor.EnableFlags) rasterMask |= CLIP_BIT;
if (ctx->Stencil._Enabled) rasterMask |= STENCIL_BIT;
for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) {
if (!ctx->Color.ColorMask[i][0] ||
!ctx->Color.ColorMask[i][1] ||
!ctx->Color.ColorMask[i][2] ||
!ctx->Color.ColorMask[i][3]) {
rasterMask |= MASKING_BIT;
break;
}
}
if (ctx->Color.ColorLogicOpEnabled) rasterMask |= LOGIC_OP_BIT;
if (ctx->Texture._MaxEnabledTexImageUnit >= 0) rasterMask |= TEXTURE_BIT;
if ( ctx->ViewportArray[0].X < 0
|| ctx->ViewportArray[0].X + ctx->ViewportArray[0].Width > (GLfloat) ctx->DrawBuffer->Width
|| ctx->ViewportArray[0].Y < 0
|| ctx->ViewportArray[0].Y + ctx->ViewportArray[0].Height > (GLfloat) ctx->DrawBuffer->Height) {
rasterMask |= CLIP_BIT;
}
 
if (ctx->Query.CurrentOcclusionObject)
rasterMask |= OCCLUSION_BIT;
 
 
/* If we're not drawing to exactly one color buffer set the
* MULTI_DRAW_BIT flag. Also set it if we're drawing to no
* buffers or the RGBA or CI mask disables all writes.
*/
if (ctx->DrawBuffer->_NumColorDrawBuffers != 1) {
/* more than one color buffer designated for writing (or zero buffers) */
rasterMask |= MULTI_DRAW_BIT;
}
 
for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) {
if (ctx->Color.ColorMask[i][0] +
ctx->Color.ColorMask[i][1] +
ctx->Color.ColorMask[i][2] +
ctx->Color.ColorMask[i][3] == 0) {
rasterMask |= MULTI_DRAW_BIT; /* all RGBA channels disabled */
break;
}
}
 
 
if (_swrast_use_fragment_program(ctx)) {
rasterMask |= FRAGPROG_BIT;
}
 
if (ctx->ATIFragmentShader._Enabled) {
rasterMask |= ATIFRAGSHADER_BIT;
}
 
#if CHAN_TYPE == GL_FLOAT
if (ctx->Color.ClampFragmentColor == GL_TRUE) {
rasterMask |= CLAMPING_BIT;
}
#endif
 
SWRAST_CONTEXT(ctx)->_RasterMask = rasterMask;
}
 
 
/**
* Examine polygon cull state to compute the _BackfaceCullSign field.
* _BackfaceCullSign will be 0 if no culling, -1 if culling back-faces,
* and 1 if culling front-faces. The Polygon FrontFace state also
* factors in.
*/
static void
_swrast_update_polygon( struct gl_context *ctx )
{
GLfloat backface_sign;
 
if (ctx->Polygon.CullFlag) {
switch (ctx->Polygon.CullFaceMode) {
case GL_BACK:
backface_sign = -1.0F;
break;
case GL_FRONT:
backface_sign = 1.0F;
break;
case GL_FRONT_AND_BACK:
/* fallthrough */
default:
backface_sign = 0.0F;
}
}
else {
backface_sign = 0.0F;
}
 
SWRAST_CONTEXT(ctx)->_BackfaceCullSign = backface_sign;
 
/* This is for front/back-face determination, but not for culling */
SWRAST_CONTEXT(ctx)->_BackfaceSign
= (ctx->Polygon.FrontFace == GL_CW) ? -1.0F : 1.0F;
}
 
 
 
/**
* Update the _PreferPixelFog field to indicate if we need to compute
* fog blend factors (from the fog coords) per-fragment.
*/
static void
_swrast_update_fog_hint( struct gl_context *ctx )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
swrast->_PreferPixelFog = (!swrast->AllowVertexFog ||
_swrast_use_fragment_program(ctx) ||
(ctx->Hint.Fog == GL_NICEST &&
swrast->AllowPixelFog));
}
 
 
 
/**
* Update the swrast->_TextureCombinePrimary flag.
*/
static void
_swrast_update_texture_env( struct gl_context *ctx )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
GLuint i;
 
swrast->_TextureCombinePrimary = GL_FALSE;
 
for (i = 0; i < ctx->Const.MaxTextureUnits; i++) {
const struct gl_tex_env_combine_state *combine =
ctx->Texture.Unit[i]._CurrentCombine;
GLuint term;
for (term = 0; term < combine->_NumArgsRGB; term++) {
if (combine->SourceRGB[term] == GL_PRIMARY_COLOR) {
swrast->_TextureCombinePrimary = GL_TRUE;
return;
}
if (combine->SourceA[term] == GL_PRIMARY_COLOR) {
swrast->_TextureCombinePrimary = GL_TRUE;
return;
}
}
}
}
 
 
/**
* Determine if we can defer texturing/shading until after Z/stencil
* testing. This potentially allows us to skip texturing/shading for
* lots of fragments.
*/
static void
_swrast_update_deferred_texture(struct gl_context *ctx)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
if (ctx->Color.AlphaEnabled) {
/* alpha test depends on post-texture/shader colors */
swrast->_DeferredTexture = GL_FALSE;
}
else {
GLboolean use_fprog = _swrast_use_fragment_program(ctx);
const struct gl_fragment_program *fprog
= ctx->FragmentProgram._Current;
if (use_fprog && (fprog->Base.OutputsWritten & (1 << FRAG_RESULT_DEPTH))) {
/* Z comes from fragment program/shader */
swrast->_DeferredTexture = GL_FALSE;
}
else if (use_fprog && fprog->UsesKill) {
swrast->_DeferredTexture = GL_FALSE;
}
else if (ctx->Query.CurrentOcclusionObject) {
/* occlusion query depends on shader discard/kill results */
swrast->_DeferredTexture = GL_FALSE;
}
else {
swrast->_DeferredTexture = GL_TRUE;
}
}
}
 
 
/**
* Update swrast->_FogColor and swrast->_FogEnable values.
*/
static void
_swrast_update_fog_state( struct gl_context *ctx )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
const struct gl_fragment_program *fp = ctx->FragmentProgram._Current;
 
assert(fp == NULL || fp->Base.Target == GL_FRAGMENT_PROGRAM_ARB);
(void) fp; /* silence unused var warning */
 
/* determine if fog is needed, and if so, which fog mode */
swrast->_FogEnabled = (!_swrast_use_fragment_program(ctx) &&
ctx->Fog.Enabled);
}
 
 
/**
* Update state for running fragment programs. Basically, load the
* program parameters with current state values.
*/
static void
_swrast_update_fragment_program(struct gl_context *ctx, GLbitfield newState)
{
if (!_swrast_use_fragment_program(ctx))
return;
 
_mesa_load_state_parameters(ctx,
ctx->FragmentProgram._Current->Base.Parameters);
}
 
 
/**
* See if we can do early diffuse+specular (primary+secondary) color
* add per vertex instead of per-fragment.
*/
static void
_swrast_update_specular_vertex_add(struct gl_context *ctx)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
GLboolean separateSpecular = ctx->Fog.ColorSumEnabled ||
(ctx->Light.Enabled &&
ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR);
 
swrast->SpecularVertexAdd = (separateSpecular
&& ctx->Texture._MaxEnabledTexImageUnit == -1
&& !_swrast_use_fragment_program(ctx)
&& !ctx->ATIFragmentShader._Enabled);
}
 
 
#define _SWRAST_NEW_DERIVED (_SWRAST_NEW_RASTERMASK | \
_NEW_PROGRAM_CONSTANTS | \
_NEW_TEXTURE | \
_NEW_HINT | \
_NEW_POLYGON )
 
/* State referenced by _swrast_choose_triangle, _swrast_choose_line.
*/
#define _SWRAST_NEW_TRIANGLE (_SWRAST_NEW_DERIVED | \
_NEW_RENDERMODE| \
_NEW_POLYGON| \
_NEW_DEPTH| \
_NEW_STENCIL| \
_NEW_COLOR| \
_NEW_TEXTURE| \
_SWRAST_NEW_RASTERMASK| \
_NEW_LIGHT| \
_NEW_FOG | \
_MESA_NEW_SEPARATE_SPECULAR)
 
#define _SWRAST_NEW_LINE (_SWRAST_NEW_DERIVED | \
_NEW_RENDERMODE| \
_NEW_LINE| \
_NEW_TEXTURE| \
_NEW_LIGHT| \
_NEW_FOG| \
_NEW_DEPTH | \
_MESA_NEW_SEPARATE_SPECULAR)
 
#define _SWRAST_NEW_POINT (_SWRAST_NEW_DERIVED | \
_NEW_RENDERMODE | \
_NEW_POINT | \
_NEW_TEXTURE | \
_NEW_LIGHT | \
_NEW_FOG | \
_MESA_NEW_SEPARATE_SPECULAR)
 
#define _SWRAST_NEW_TEXTURE_SAMPLE_FUNC _NEW_TEXTURE
 
#define _SWRAST_NEW_TEXTURE_ENV_MODE _NEW_TEXTURE
 
#define _SWRAST_NEW_BLEND_FUNC _NEW_COLOR
 
 
 
/**
* Stub for swrast->Triangle to select a true triangle function
* after a state change.
*/
static void
_swrast_validate_triangle( struct gl_context *ctx,
const SWvertex *v0,
const SWvertex *v1,
const SWvertex *v2 )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
 
_swrast_validate_derived( ctx );
swrast->choose_triangle( ctx );
assert(swrast->Triangle);
 
if (swrast->SpecularVertexAdd) {
/* separate specular color, but no texture */
swrast->SpecTriangle = swrast->Triangle;
swrast->Triangle = _swrast_add_spec_terms_triangle;
}
 
swrast->Triangle( ctx, v0, v1, v2 );
}
 
/**
* Called via swrast->Line. Examine current GL state and choose a software
* line routine. Then call it.
*/
static void
_swrast_validate_line( struct gl_context *ctx, const SWvertex *v0, const SWvertex *v1 )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
 
_swrast_validate_derived( ctx );
swrast->choose_line( ctx );
assert(swrast->Line);
 
if (swrast->SpecularVertexAdd) {
swrast->SpecLine = swrast->Line;
swrast->Line = _swrast_add_spec_terms_line;
}
 
swrast->Line( ctx, v0, v1 );
}
 
/**
* Called via swrast->Point. Examine current GL state and choose a software
* point routine. Then call it.
*/
static void
_swrast_validate_point( struct gl_context *ctx, const SWvertex *v0 )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
 
_swrast_validate_derived( ctx );
swrast->choose_point( ctx );
 
if (swrast->SpecularVertexAdd) {
swrast->SpecPoint = swrast->Point;
swrast->Point = _swrast_add_spec_terms_point;
}
 
swrast->Point( ctx, v0 );
}
 
 
/**
* Called via swrast->BlendFunc. Examine GL state to choose a blending
* function, then call it.
*/
static void
_swrast_validate_blend_func(struct gl_context *ctx, GLuint n, const GLubyte mask[],
GLvoid *src, const GLvoid *dst,
GLenum chanType )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
 
_swrast_validate_derived( ctx ); /* why is this needed? */
_swrast_choose_blend_func( ctx, chanType );
 
swrast->BlendFunc( ctx, n, mask, src, dst, chanType );
}
 
static void
_swrast_sleep( struct gl_context *ctx, GLbitfield new_state )
{
(void) ctx; (void) new_state;
}
 
 
static void
_swrast_invalidate_state( struct gl_context *ctx, GLbitfield new_state )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
GLuint i;
 
swrast->NewState |= new_state;
 
/* After 10 statechanges without any swrast functions being called,
* put the module to sleep.
*/
if (++swrast->StateChanges > 10) {
swrast->InvalidateState = _swrast_sleep;
swrast->NewState = ~0;
new_state = ~0;
}
 
if (new_state & swrast->InvalidateTriangleMask)
swrast->Triangle = _swrast_validate_triangle;
 
if (new_state & swrast->InvalidateLineMask)
swrast->Line = _swrast_validate_line;
 
if (new_state & swrast->InvalidatePointMask)
swrast->Point = _swrast_validate_point;
 
if (new_state & _SWRAST_NEW_BLEND_FUNC)
swrast->BlendFunc = _swrast_validate_blend_func;
 
if (new_state & _SWRAST_NEW_TEXTURE_SAMPLE_FUNC)
for (i = 0 ; i < ARRAY_SIZE(swrast->TextureSample); i++)
swrast->TextureSample[i] = NULL;
}
 
 
void
_swrast_update_texture_samplers(struct gl_context *ctx)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
GLuint u;
 
if (!swrast)
return; /* pipe hack */
 
for (u = 0; u < ARRAY_SIZE(swrast->TextureSample); u++) {
struct gl_texture_object *tObj = ctx->Texture.Unit[u]._Current;
/* Note: If tObj is NULL, the sample function will be a simple
* function that just returns opaque black (0,0,0,1).
*/
_mesa_update_fetch_functions(ctx, u);
swrast->TextureSample[u] =
_swrast_choose_texture_sample_func(ctx, tObj,
_mesa_get_samplerobj(ctx, u));
}
}
 
 
/**
* Update swrast->_ActiveAttribs, swrast->_NumActiveAttribs,
* swrast->_ActiveAtttribMask.
*/
static void
_swrast_update_active_attribs(struct gl_context *ctx)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
GLbitfield64 attribsMask;
 
/*
* Compute _ActiveAttribsMask = which fragment attributes are needed.
*/
if (_swrast_use_fragment_program(ctx)) {
/* fragment program/shader */
attribsMask = ctx->FragmentProgram._Current->Base.InputsRead;
attribsMask &= ~VARYING_BIT_POS; /* WPOS is always handled specially */
}
else if (ctx->ATIFragmentShader._Enabled) {
attribsMask = ~0; /* XXX fix me */
}
else {
/* fixed function */
attribsMask = 0x0;
 
#if CHAN_TYPE == GL_FLOAT
attribsMask |= VARYING_BIT_COL0;
#endif
 
if (ctx->Fog.ColorSumEnabled ||
(ctx->Light.Enabled &&
ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) {
attribsMask |= VARYING_BIT_COL1;
}
 
if (swrast->_FogEnabled)
attribsMask |= VARYING_BIT_FOGC;
 
attribsMask |= (ctx->Texture._EnabledCoordUnits << VARYING_SLOT_TEX0);
}
 
swrast->_ActiveAttribMask = attribsMask;
 
/* Update _ActiveAttribs[] list */
{
GLuint i, num = 0;
for (i = 0; i < VARYING_SLOT_MAX; i++) {
if (attribsMask & BITFIELD64_BIT(i)) {
swrast->_ActiveAttribs[num++] = i;
/* how should this attribute be interpolated? */
if (i == VARYING_SLOT_COL0 || i == VARYING_SLOT_COL1)
swrast->_InterpMode[i] = ctx->Light.ShadeModel;
else
swrast->_InterpMode[i] = GL_SMOOTH;
}
}
swrast->_NumActiveAttribs = num;
}
}
 
 
void
_swrast_validate_derived( struct gl_context *ctx )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
 
if (swrast->NewState) {
if (swrast->NewState & _NEW_POLYGON)
_swrast_update_polygon( ctx );
 
if (swrast->NewState & (_NEW_HINT | _NEW_PROGRAM))
_swrast_update_fog_hint( ctx );
 
if (swrast->NewState & _SWRAST_NEW_TEXTURE_ENV_MODE)
_swrast_update_texture_env( ctx );
 
if (swrast->NewState & (_NEW_FOG | _NEW_PROGRAM))
_swrast_update_fog_state( ctx );
 
if (swrast->NewState & (_NEW_PROGRAM_CONSTANTS | _NEW_PROGRAM))
_swrast_update_fragment_program( ctx, swrast->NewState );
 
if (swrast->NewState & (_NEW_TEXTURE | _NEW_PROGRAM)) {
_swrast_update_texture_samplers( ctx );
}
 
if (swrast->NewState & (_NEW_COLOR | _NEW_PROGRAM))
_swrast_update_deferred_texture(ctx);
 
if (swrast->NewState & _SWRAST_NEW_RASTERMASK)
_swrast_update_rasterflags( ctx );
 
if (swrast->NewState & (_NEW_DEPTH |
_NEW_FOG |
_NEW_LIGHT |
_NEW_PROGRAM |
_NEW_TEXTURE))
_swrast_update_active_attribs(ctx);
 
if (swrast->NewState & (_NEW_FOG |
_NEW_PROGRAM |
_NEW_LIGHT |
_NEW_TEXTURE))
_swrast_update_specular_vertex_add(ctx);
 
swrast->NewState = 0;
swrast->StateChanges = 0;
swrast->InvalidateState = _swrast_invalidate_state;
}
}
 
#define SWRAST_DEBUG 0
 
/* Public entrypoints: See also s_bitmap.c, etc.
*/
void
_swrast_Quad( struct gl_context *ctx,
const SWvertex *v0, const SWvertex *v1,
const SWvertex *v2, const SWvertex *v3 )
{
if (SWRAST_DEBUG) {
_mesa_debug(ctx, "_swrast_Quad\n");
_swrast_print_vertex( ctx, v0 );
_swrast_print_vertex( ctx, v1 );
_swrast_print_vertex( ctx, v2 );
_swrast_print_vertex( ctx, v3 );
}
SWRAST_CONTEXT(ctx)->Triangle( ctx, v0, v1, v3 );
SWRAST_CONTEXT(ctx)->Triangle( ctx, v1, v2, v3 );
}
 
void
_swrast_Triangle( struct gl_context *ctx, const SWvertex *v0,
const SWvertex *v1, const SWvertex *v2 )
{
if (SWRAST_DEBUG) {
_mesa_debug(ctx, "_swrast_Triangle\n");
_swrast_print_vertex( ctx, v0 );
_swrast_print_vertex( ctx, v1 );
_swrast_print_vertex( ctx, v2 );
}
SWRAST_CONTEXT(ctx)->Triangle( ctx, v0, v1, v2 );
}
 
void
_swrast_Line( struct gl_context *ctx, const SWvertex *v0, const SWvertex *v1 )
{
if (SWRAST_DEBUG) {
_mesa_debug(ctx, "_swrast_Line\n");
_swrast_print_vertex( ctx, v0 );
_swrast_print_vertex( ctx, v1 );
}
SWRAST_CONTEXT(ctx)->Line( ctx, v0, v1 );
}
 
void
_swrast_Point( struct gl_context *ctx, const SWvertex *v0 )
{
if (SWRAST_DEBUG) {
_mesa_debug(ctx, "_swrast_Point\n");
_swrast_print_vertex( ctx, v0 );
}
SWRAST_CONTEXT(ctx)->Point( ctx, v0 );
}
 
void
_swrast_InvalidateState( struct gl_context *ctx, GLbitfield new_state )
{
if (SWRAST_DEBUG) {
_mesa_debug(ctx, "_swrast_InvalidateState\n");
}
SWRAST_CONTEXT(ctx)->InvalidateState( ctx, new_state );
}
 
void
_swrast_ResetLineStipple( struct gl_context *ctx )
{
if (SWRAST_DEBUG) {
_mesa_debug(ctx, "_swrast_ResetLineStipple\n");
}
SWRAST_CONTEXT(ctx)->StippleCounter = 0;
}
 
void
_swrast_SetFacing(struct gl_context *ctx, GLuint facing)
{
SWRAST_CONTEXT(ctx)->PointLineFacing = facing;
}
 
void
_swrast_allow_vertex_fog( struct gl_context *ctx, GLboolean value )
{
if (SWRAST_DEBUG) {
_mesa_debug(ctx, "_swrast_allow_vertex_fog %d\n", value);
}
SWRAST_CONTEXT(ctx)->InvalidateState( ctx, _NEW_HINT );
SWRAST_CONTEXT(ctx)->AllowVertexFog = value;
}
 
void
_swrast_allow_pixel_fog( struct gl_context *ctx, GLboolean value )
{
if (SWRAST_DEBUG) {
_mesa_debug(ctx, "_swrast_allow_pixel_fog %d\n", value);
}
SWRAST_CONTEXT(ctx)->InvalidateState( ctx, _NEW_HINT );
SWRAST_CONTEXT(ctx)->AllowPixelFog = value;
}
 
 
/**
* Initialize native program limits by copying the logical limits.
* See comments in init_program_limits() in context.c
*/
static void
init_program_native_limits(struct gl_program_constants *prog)
{
prog->MaxNativeInstructions = prog->MaxInstructions;
prog->MaxNativeAluInstructions = prog->MaxAluInstructions;
prog->MaxNativeTexInstructions = prog->MaxTexInstructions;
prog->MaxNativeTexIndirections = prog->MaxTexIndirections;
prog->MaxNativeAttribs = prog->MaxAttribs;
prog->MaxNativeTemps = prog->MaxTemps;
prog->MaxNativeAddressRegs = prog->MaxAddressRegs;
prog->MaxNativeParameters = prog->MaxParameters;
}
 
 
GLboolean
_swrast_CreateContext( struct gl_context *ctx )
{
GLuint i;
SWcontext *swrast = calloc(1, sizeof(SWcontext));
#ifdef _OPENMP
const GLuint maxThreads = omp_get_max_threads();
#else
const GLuint maxThreads = 1;
#endif
 
assert(ctx->Const.MaxViewportWidth <= SWRAST_MAX_WIDTH);
assert(ctx->Const.MaxViewportHeight <= SWRAST_MAX_WIDTH);
 
assert(ctx->Const.MaxRenderbufferSize <= SWRAST_MAX_WIDTH);
 
/* make sure largest texture image is <= SWRAST_MAX_WIDTH in size */
assert((1 << (ctx->Const.MaxTextureLevels - 1)) <= SWRAST_MAX_WIDTH);
assert((1 << (ctx->Const.MaxCubeTextureLevels - 1)) <= SWRAST_MAX_WIDTH);
assert((1 << (ctx->Const.Max3DTextureLevels - 1)) <= SWRAST_MAX_WIDTH);
 
assert(PROG_MAX_WIDTH == SWRAST_MAX_WIDTH);
 
if (SWRAST_DEBUG) {
_mesa_debug(ctx, "_swrast_CreateContext\n");
}
 
if (!swrast)
return GL_FALSE;
 
swrast->NewState = ~0;
 
swrast->choose_point = _swrast_choose_point;
swrast->choose_line = _swrast_choose_line;
swrast->choose_triangle = _swrast_choose_triangle;
 
swrast->InvalidatePointMask = _SWRAST_NEW_POINT;
swrast->InvalidateLineMask = _SWRAST_NEW_LINE;
swrast->InvalidateTriangleMask = _SWRAST_NEW_TRIANGLE;
 
swrast->Point = _swrast_validate_point;
swrast->Line = _swrast_validate_line;
swrast->Triangle = _swrast_validate_triangle;
swrast->InvalidateState = _swrast_sleep;
swrast->BlendFunc = _swrast_validate_blend_func;
 
swrast->AllowVertexFog = GL_TRUE;
swrast->AllowPixelFog = GL_TRUE;
 
swrast->Driver.SpanRenderStart = _swrast_span_render_start;
swrast->Driver.SpanRenderFinish = _swrast_span_render_finish;
 
for (i = 0; i < ARRAY_SIZE(swrast->TextureSample); i++)
swrast->TextureSample[i] = NULL;
 
/* SpanArrays is global and shared by all SWspan instances. However, when
* using multiple threads, it is necessary to have one SpanArrays instance
* per thread.
*/
swrast->SpanArrays = malloc(maxThreads * sizeof(SWspanarrays));
if (!swrast->SpanArrays) {
free(swrast);
return GL_FALSE;
}
for(i = 0; i < maxThreads; i++) {
swrast->SpanArrays[i].ChanType = CHAN_TYPE;
#if CHAN_TYPE == GL_UNSIGNED_BYTE
swrast->SpanArrays[i].rgba = swrast->SpanArrays[i].rgba8;
#elif CHAN_TYPE == GL_UNSIGNED_SHORT
swrast->SpanArrays[i].rgba = swrast->SpanArrays[i].rgba16;
#else
swrast->SpanArrays[i].rgba = swrast->SpanArrays[i].attribs[VARYING_SLOT_COL0];
#endif
}
 
/* init point span buffer */
swrast->PointSpan.primitive = GL_POINT;
swrast->PointSpan.end = 0;
swrast->PointSpan.facing = 0;
swrast->PointSpan.array = swrast->SpanArrays;
 
init_program_native_limits(&ctx->Const.Program[MESA_SHADER_VERTEX]);
init_program_native_limits(&ctx->Const.Program[MESA_SHADER_GEOMETRY]);
init_program_native_limits(&ctx->Const.Program[MESA_SHADER_FRAGMENT]);
 
ctx->swrast_context = swrast;
 
swrast->stencil_temp.buf1 = malloc(SWRAST_MAX_WIDTH * sizeof(GLubyte));
swrast->stencil_temp.buf2 = malloc(SWRAST_MAX_WIDTH * sizeof(GLubyte));
swrast->stencil_temp.buf3 = malloc(SWRAST_MAX_WIDTH * sizeof(GLubyte));
swrast->stencil_temp.buf4 = malloc(SWRAST_MAX_WIDTH * sizeof(GLubyte));
 
if (!swrast->stencil_temp.buf1 ||
!swrast->stencil_temp.buf2 ||
!swrast->stencil_temp.buf3 ||
!swrast->stencil_temp.buf4) {
_swrast_DestroyContext(ctx);
return GL_FALSE;
}
 
return GL_TRUE;
}
 
void
_swrast_DestroyContext( struct gl_context *ctx )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
 
if (SWRAST_DEBUG) {
_mesa_debug(ctx, "_swrast_DestroyContext\n");
}
 
free( swrast->SpanArrays );
free( swrast->ZoomedArrays );
free( swrast->TexelBuffer );
 
free(swrast->stencil_temp.buf1);
free(swrast->stencil_temp.buf2);
free(swrast->stencil_temp.buf3);
free(swrast->stencil_temp.buf4);
 
free( swrast );
 
ctx->swrast_context = 0;
}
 
 
struct swrast_device_driver *
_swrast_GetDeviceDriverReference( struct gl_context *ctx )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
return &swrast->Driver;
}
 
void
_swrast_flush( struct gl_context *ctx )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
/* flush any pending fragments from rendering points */
if (swrast->PointSpan.end > 0) {
_swrast_write_rgba_span(ctx, &(swrast->PointSpan));
swrast->PointSpan.end = 0;
}
}
 
void
_swrast_render_primitive( struct gl_context *ctx, GLenum prim )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
if (swrast->Primitive == GL_POINTS && prim != GL_POINTS) {
_swrast_flush(ctx);
}
swrast->Primitive = prim;
}
 
 
/** called via swrast->Driver.SpanRenderStart() */
void
_swrast_span_render_start(struct gl_context *ctx)
{
_swrast_map_textures(ctx);
_swrast_map_renderbuffers(ctx);
}
 
 
/** called via swrast->Driver.SpanRenderFinish() */
void
_swrast_span_render_finish(struct gl_context *ctx)
{
_swrast_unmap_textures(ctx);
_swrast_unmap_renderbuffers(ctx);
}
 
 
void
_swrast_render_start( struct gl_context *ctx )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
if (swrast->Driver.SpanRenderStart)
swrast->Driver.SpanRenderStart( ctx );
swrast->PointSpan.end = 0;
}
void
_swrast_render_finish( struct gl_context *ctx )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
 
_swrast_flush(ctx);
 
if (swrast->Driver.SpanRenderFinish)
swrast->Driver.SpanRenderFinish( ctx );
}
 
 
#define SWRAST_DEBUG_VERTICES 0
 
void
_swrast_print_vertex( struct gl_context *ctx, const SWvertex *v )
{
GLuint i;
 
if (SWRAST_DEBUG_VERTICES) {
_mesa_debug(ctx, "win %f %f %f %f\n",
v->attrib[VARYING_SLOT_POS][0],
v->attrib[VARYING_SLOT_POS][1],
v->attrib[VARYING_SLOT_POS][2],
v->attrib[VARYING_SLOT_POS][3]);
 
for (i = 0 ; i < ctx->Const.MaxTextureCoordUnits ; i++)
if (ctx->Texture.Unit[i]._Current)
_mesa_debug(ctx, "texcoord[%d] %f %f %f %f\n", i,
v->attrib[VARYING_SLOT_TEX0 + i][0],
v->attrib[VARYING_SLOT_TEX0 + i][1],
v->attrib[VARYING_SLOT_TEX0 + i][2],
v->attrib[VARYING_SLOT_TEX0 + i][3]);
 
#if CHAN_TYPE == GL_FLOAT
_mesa_debug(ctx, "color %f %f %f %f\n",
v->color[0], v->color[1], v->color[2], v->color[3]);
#else
_mesa_debug(ctx, "color %d %d %d %d\n",
v->color[0], v->color[1], v->color[2], v->color[3]);
#endif
_mesa_debug(ctx, "spec %g %g %g %g\n",
v->attrib[VARYING_SLOT_COL1][0],
v->attrib[VARYING_SLOT_COL1][1],
v->attrib[VARYING_SLOT_COL1][2],
v->attrib[VARYING_SLOT_COL1][3]);
_mesa_debug(ctx, "fog %f\n", v->attrib[VARYING_SLOT_FOGC][0]);
_mesa_debug(ctx, "index %f\n", v->attrib[VARYING_SLOT_CI][0]);
_mesa_debug(ctx, "pointsize %f\n", v->pointSize);
_mesa_debug(ctx, "\n");
}
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_context.h
0,0 → 1,499
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
/**
* \file swrast/s_context.h
* \brief Software rasterization context and private types.
* \author Keith Whitwell <keithw@vmware.com>
*/
 
/**
* \mainpage swrast module
*
* This module, software rasterization, contains the software fallback
* routines for drawing points, lines, triangles, bitmaps and images.
* All rendering boils down to writing spans (arrays) of pixels with
* particular colors. The span-writing routines must be implemented
* by the device driver.
*/
 
 
#ifndef S_CONTEXT_H
#define S_CONTEXT_H
 
#include "main/compiler.h"
#include "main/mtypes.h"
#include "main/texcompress.h"
#include "program/prog_execute.h"
#include "swrast.h"
#include "s_fragprog.h"
#include "s_span.h"
 
 
typedef void (*texture_sample_func)(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoords[][4],
const GLfloat lambda[], GLfloat rgba[][4]);
 
typedef void (*blend_func)(struct gl_context *ctx, GLuint n,
const GLubyte mask[],
GLvoid *src, const GLvoid *dst,
GLenum chanType);
 
typedef void (*swrast_point_func)( struct gl_context *ctx, const SWvertex *);
 
typedef void (*swrast_line_func)( struct gl_context *ctx,
const SWvertex *, const SWvertex *);
 
typedef void (*swrast_tri_func)( struct gl_context *ctx, const SWvertex *,
const SWvertex *, const SWvertex *);
 
 
typedef void (*validate_texture_image_func)(struct gl_context *ctx,
struct gl_texture_object *texObj,
GLuint face, GLuint level);
 
 
/**
* \defgroup Bitmasks
* Bitmasks to indicate which rasterization options are enabled
* (RasterMask)
*/
/*@{*/
#define ALPHATEST_BIT 0x001 /**< Alpha-test pixels */
#define BLEND_BIT 0x002 /**< Blend pixels */
#define DEPTH_BIT 0x004 /**< Depth-test pixels */
#define FOG_BIT 0x008 /**< Fog pixels */
#define LOGIC_OP_BIT 0x010 /**< Apply logic op in software */
#define CLIP_BIT 0x020 /**< Scissor or window clip pixels */
#define STENCIL_BIT 0x040 /**< Stencil pixels */
#define MASKING_BIT 0x080 /**< Do glColorMask or glIndexMask */
#define MULTI_DRAW_BIT 0x400 /**< Write to more than one color- */
/**< buffer or no buffers. */
#define OCCLUSION_BIT 0x800 /**< GL_HP_occlusion_test enabled */
#define TEXTURE_BIT 0x1000 /**< Texturing really enabled */
#define FRAGPROG_BIT 0x2000 /**< Fragment program enabled */
#define ATIFRAGSHADER_BIT 0x4000 /**< ATI Fragment shader enabled */
#define CLAMPING_BIT 0x8000 /**< Clamp colors to [0,1] */
/*@}*/
 
#define _SWRAST_NEW_RASTERMASK (_NEW_BUFFERS| \
_NEW_SCISSOR| \
_NEW_COLOR| \
_NEW_DEPTH| \
_NEW_FOG| \
_NEW_PROGRAM| \
_NEW_STENCIL| \
_NEW_TEXTURE| \
_NEW_VIEWPORT| \
_NEW_DEPTH)
 
 
struct swrast_texture_image;
 
 
/**
* Fetch a texel from texture image at given position.
*/
typedef void (*FetchTexelFunc)(const struct swrast_texture_image *texImage,
GLint col, GLint row, GLint img,
GLfloat *texelOut);
 
 
/**
* Subclass of gl_texture_image.
* We need extra fields/info to keep tracking of mapped texture buffers,
* strides and Fetch functions.
*/
struct swrast_texture_image
{
struct gl_texture_image Base;
 
GLboolean _IsPowerOfTwo; /**< Are all dimensions powers of two? */
 
/** used for mipmap LOD computation */
GLfloat WidthScale, HeightScale, DepthScale;
 
/**
* Byte stride between rows in ImageSlices.
*
* For compressed textures, this is the byte stride between one row of
* blocks and the next row of blocks.
*
* Only valid while one of the ImageSlices is mapped, and must be the same
* between all slices.
*/
GLint RowStride;
/**
* When a texture image is mapped for swrast, this array contains pointers
* to the beginning of each slice.
*
* For swrast-allocated textures, these pointers will always stay
* initialized to point within Buffer.
*/
void **ImageSlices;
 
/** Malloc'd texture memory */
GLubyte *Buffer;
 
FetchTexelFunc FetchTexel;
 
/** For fetching texels from compressed textures */
compressed_fetch_func FetchCompressedTexel;
};
 
 
/** cast wrapper */
static inline struct swrast_texture_image *
swrast_texture_image(struct gl_texture_image *img)
{
return (struct swrast_texture_image *) img;
}
 
/** cast wrapper */
static inline const struct swrast_texture_image *
swrast_texture_image_const(const struct gl_texture_image *img)
{
return (const struct swrast_texture_image *) img;
}
 
 
/**
* Subclass of gl_renderbuffer with extra fields needed for software
* rendering.
*/
struct swrast_renderbuffer
{
struct gl_renderbuffer Base;
 
GLubyte *Buffer; /**< The malloc'd memory for buffer */
 
/** These fields are only valid while buffer is mapped for rendering */
GLubyte *Map;
GLint RowStride; /**< in bytes */
 
/** For span rendering */
GLenum ColorType;
};
 
 
/** cast wrapper */
static inline struct swrast_renderbuffer *
swrast_renderbuffer(struct gl_renderbuffer *img)
{
return (struct swrast_renderbuffer *) img;
}
 
 
 
/**
* \struct SWcontext
* \brief Per-context state that's private to the software rasterizer module.
*/
typedef struct
{
/** Driver interface:
*/
struct swrast_device_driver Driver;
 
/** Configuration mechanisms to make software rasterizer match
* characteristics of the hardware rasterizer (if present):
*/
GLboolean AllowVertexFog;
GLboolean AllowPixelFog;
 
/** Derived values, invalidated on statechanges, updated from
* _swrast_validate_derived():
*/
GLbitfield _RasterMask;
GLfloat _BackfaceSign; /** +1 or -1 */
GLfloat _BackfaceCullSign; /** +1, 0, or -1 */
GLboolean _PreferPixelFog; /* Compute fog blend factor per fragment? */
GLboolean _TextureCombinePrimary;
GLboolean _FogEnabled;
GLboolean _DeferredTexture;
 
/** List/array of the fragment attributes to interpolate */
GLuint _ActiveAttribs[VARYING_SLOT_MAX];
/** Same info, but as a bitmask of VARYING_BIT_x bits */
GLbitfield64 _ActiveAttribMask;
/** Number of fragment attributes to interpolate */
GLuint _NumActiveAttribs;
/** Indicates how each attrib is to be interpolated (lines/tris) */
GLenum _InterpMode[VARYING_SLOT_MAX]; /* GL_FLAT or GL_SMOOTH (for now) */
 
/* Working values:
*/
GLuint StippleCounter; /**< Line stipple counter */
GLuint PointLineFacing;
GLbitfield NewState;
GLuint StateChanges;
GLenum Primitive; /* current primitive being drawn (ala glBegin) */
GLboolean SpecularVertexAdd; /**< Add specular/secondary color per vertex */
 
void (*InvalidateState)( struct gl_context *ctx, GLbitfield new_state );
 
/**
* When the NewState mask intersects these masks, we invalidate the
* Point/Line/Triangle function pointers below.
*/
/*@{*/
GLbitfield InvalidatePointMask;
GLbitfield InvalidateLineMask;
GLbitfield InvalidateTriangleMask;
/*@}*/
 
/**
* Device drivers plug in functions for these callbacks.
* Will be called when the GL state change mask intersects the above masks.
*/
/*@{*/
void (*choose_point)( struct gl_context * );
void (*choose_line)( struct gl_context * );
void (*choose_triangle)( struct gl_context * );
/*@}*/
 
/**
* Current point, line and triangle drawing functions.
*/
/*@{*/
swrast_point_func Point;
swrast_line_func Line;
swrast_tri_func Triangle;
/*@}*/
 
/**
* Placeholders for when separate specular (or secondary color) is
* enabled but texturing is not.
*/
/*@{*/
swrast_point_func SpecPoint;
swrast_line_func SpecLine;
swrast_tri_func SpecTriangle;
/*@}*/
 
/**
* Typically, we'll allocate a sw_span structure as a local variable
* and set its 'array' pointer to point to this object. The reason is
* this object is big and causes problems when allocated on the stack
* on some systems.
*/
SWspanarrays *SpanArrays;
SWspanarrays *ZoomedArrays; /**< For pixel zooming */
 
/**
* Used to buffer N GL_POINTS, instead of rendering one by one.
*/
SWspan PointSpan;
 
/** Internal hooks, kept up to date by the same mechanism as above.
*/
blend_func BlendFunc;
texture_sample_func TextureSample[MAX_COMBINED_TEXTURE_IMAGE_UNITS];
 
/** Buffer for saving the sampled texture colors.
* Needed for GL_ARB_texture_env_crossbar implementation.
*/
GLfloat *TexelBuffer;
 
validate_texture_image_func ValidateTextureImage;
 
/** State used during execution of fragment programs */
struct gl_program_machine FragProgMachine;
 
/** Temporary arrays for stencil operations. To avoid large stack
* allocations.
*/
struct {
GLubyte *buf1, *buf2, *buf3, *buf4;
} stencil_temp;
 
} SWcontext;
 
 
extern void
_swrast_validate_derived( struct gl_context *ctx );
 
extern void
_swrast_update_texture_samplers(struct gl_context *ctx);
 
 
/** Return SWcontext for the given struct gl_context */
static inline SWcontext *
SWRAST_CONTEXT(struct gl_context *ctx)
{
return (SWcontext *) ctx->swrast_context;
}
 
/** const version of above */
static inline const SWcontext *
CONST_SWRAST_CONTEXT(const struct gl_context *ctx)
{
return (const SWcontext *) ctx->swrast_context;
}
 
 
/**
* Called prior to framebuffer reading/writing.
* For drivers that rely on swrast for fallback rendering, this is the
* driver's opportunity to map renderbuffers and textures.
*/
static inline void
swrast_render_start(struct gl_context *ctx)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
if (swrast->Driver.SpanRenderStart)
swrast->Driver.SpanRenderStart(ctx);
}
 
 
/** Called after framebuffer reading/writing */
static inline void
swrast_render_finish(struct gl_context *ctx)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
if (swrast->Driver.SpanRenderFinish)
swrast->Driver.SpanRenderFinish(ctx);
}
 
 
extern void
_swrast_span_render_start(struct gl_context *ctx);
 
extern void
_swrast_span_render_finish(struct gl_context *ctx);
 
extern void
_swrast_map_textures(struct gl_context *ctx);
 
extern void
_swrast_unmap_textures(struct gl_context *ctx);
 
extern unsigned int
_swrast_teximage_slice_height(struct gl_texture_image *texImage);
 
extern void
_swrast_map_texture(struct gl_context *ctx, struct gl_texture_object *texObj);
 
extern void
_swrast_unmap_texture(struct gl_context *ctx, struct gl_texture_object *texObj);
 
 
extern void
_swrast_map_renderbuffers(struct gl_context *ctx);
 
extern void
_swrast_unmap_renderbuffers(struct gl_context *ctx);
 
 
/**
* Size of an RGBA pixel, in bytes, for given datatype.
*/
#define RGBA_PIXEL_SIZE(TYPE) \
((TYPE == GL_UNSIGNED_BYTE) ? 4 * sizeof(GLubyte) : \
((TYPE == GL_UNSIGNED_SHORT) ? 4 * sizeof(GLushort) \
: 4 * sizeof(GLfloat)))
 
 
 
/*
* Fixed point arithmetic macros
*/
#ifndef FIXED_FRAC_BITS
#define FIXED_FRAC_BITS 11
#endif
 
#define FIXED_SHIFT FIXED_FRAC_BITS
#define FIXED_ONE (1 << FIXED_SHIFT)
#define FIXED_HALF (1 << (FIXED_SHIFT-1))
#define FIXED_FRAC_MASK (FIXED_ONE - 1)
#define FIXED_INT_MASK (~FIXED_FRAC_MASK)
#define FIXED_EPSILON 1
#define FIXED_SCALE ((float) FIXED_ONE)
#define FIXED_DBL_SCALE ((double) FIXED_ONE)
#define FloatToFixed(X) (IROUND((X) * FIXED_SCALE))
#define FixedToDouble(X) ((X) * (1.0 / FIXED_DBL_SCALE))
#define IntToFixed(I) ((I) << FIXED_SHIFT)
#define FixedToInt(X) ((X) >> FIXED_SHIFT)
#define FixedToUns(X) (((unsigned int)(X)) >> FIXED_SHIFT)
#define FixedCeil(X) (((X) + FIXED_ONE - FIXED_EPSILON) & FIXED_INT_MASK)
#define FixedFloor(X) ((X) & FIXED_INT_MASK)
#define FixedToFloat(X) ((X) * (1.0F / FIXED_SCALE))
#define PosFloatToFixed(X) FloatToFixed(X)
#define SignedFloatToFixed(X) FloatToFixed(X)
 
 
 
/*
* XXX these macros are just bandages for now in order to make
* CHAN_BITS==32 compile cleanly.
* These should probably go elsewhere at some point.
*/
#if CHAN_TYPE == GL_FLOAT
#define ChanToFixed(X) (X)
#define FixedToChan(X) (X)
#else
#define ChanToFixed(X) IntToFixed(X)
#define FixedToChan(X) FixedToInt(X)
#endif
 
 
/**
* For looping over fragment attributes in the pointe, line
* triangle rasterizers.
*/
#define ATTRIB_LOOP_BEGIN \
{ \
GLuint a; \
for (a = 0; a < swrast->_NumActiveAttribs; a++) { \
const GLuint attr = swrast->_ActiveAttribs[a];
 
#define ATTRIB_LOOP_END } }
 
 
/**
* Return the address of a pixel value in a mapped renderbuffer.
*/
static inline GLubyte *
_swrast_pixel_address(struct gl_renderbuffer *rb, GLint x, GLint y)
{
struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
const GLint bpp = _mesa_get_format_bytes(rb->Format);
const GLint rowStride = srb->RowStride;
assert(x >= 0);
assert(y >= 0);
/* NOTE: using <= only because of s_tritemp.h which gets a pixel
* address but doesn't necessarily access it.
*/
assert(x <= (GLint) rb->Width);
assert(y <= (GLint) rb->Height);
assert(srb->Map);
return (GLubyte *) srb->Map + y * rowStride + x * bpp;
}
 
 
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_copypix.c
0,0 → 1,675
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#include "main/glheader.h"
#include "main/context.h"
#include "main/condrender.h"
#include "main/macros.h"
#include "main/pixeltransfer.h"
#include "main/imports.h"
 
#include "s_context.h"
#include "s_depth.h"
#include "s_span.h"
#include "s_stencil.h"
#include "s_zoom.h"
 
 
 
/**
* Determine if there's overlap in an image copy.
* This test also compensates for the fact that copies are done from
* bottom to top and overlaps can sometimes be handled correctly
* without making a temporary image copy.
* \return GL_TRUE if the regions overlap, GL_FALSE otherwise.
*/
static GLboolean
regions_overlap(GLint srcx, GLint srcy,
GLint dstx, GLint dsty,
GLint width, GLint height,
GLfloat zoomX, GLfloat zoomY)
{
if (zoomX == 1.0 && zoomY == 1.0) {
/* no zoom */
if (srcx >= dstx + width || (srcx + width <= dstx)) {
return GL_FALSE;
}
else if (srcy < dsty) { /* this is OK */
return GL_FALSE;
}
else if (srcy > dsty + height) {
return GL_FALSE;
}
else {
return GL_TRUE;
}
}
else {
/* add one pixel of slop when zooming, just to be safe */
if (srcx > (dstx + ((zoomX > 0.0F) ? (width * zoomX + 1.0F) : 0.0F))) {
/* src is completely right of dest */
return GL_FALSE;
}
else if (srcx + width + 1.0F < dstx + ((zoomX > 0.0F) ? 0.0F : (width * zoomX))) {
/* src is completely left of dest */
return GL_FALSE;
}
else if ((srcy < dsty) && (srcy + height < dsty + (height * zoomY))) {
/* src is completely below dest */
return GL_FALSE;
}
else if ((srcy > dsty) && (srcy + height > dsty + (height * zoomY))) {
/* src is completely above dest */
return GL_FALSE;
}
else {
return GL_TRUE;
}
}
}
 
 
/**
* RGBA copypixels
*/
static void
copy_rgba_pixels(struct gl_context *ctx, GLint srcx, GLint srcy,
GLint width, GLint height, GLint destx, GLint desty)
{
GLfloat *tmpImage, *p;
GLint sy, dy, stepy, row;
const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
GLint overlapping;
GLuint transferOps = ctx->_ImageTransferState;
SWspan span;
 
if (!ctx->ReadBuffer->_ColorReadBuffer) {
/* no readbuffer - OK */
return;
}
 
if (ctx->DrawBuffer == ctx->ReadBuffer) {
overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
}
else {
overlapping = GL_FALSE;
}
 
/* Determine if copy should be done bottom-to-top or top-to-bottom */
if (!overlapping && srcy < desty) {
/* top-down max-to-min */
sy = srcy + height - 1;
dy = desty + height - 1;
stepy = -1;
}
else {
/* bottom-up min-to-max */
sy = srcy;
dy = desty;
stepy = 1;
}
 
INIT_SPAN(span, GL_BITMAP);
_swrast_span_default_attribs(ctx, &span);
span.arrayMask = SPAN_RGBA;
span.arrayAttribs = VARYING_BIT_COL0; /* we'll fill in COL0 attrib values */
 
if (overlapping) {
tmpImage = malloc(width * height * sizeof(GLfloat) * 4);
if (!tmpImage) {
_mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
return;
}
/* read the source image as RGBA/float */
p = tmpImage;
for (row = 0; row < height; row++) {
_swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
width, srcx, sy + row, p );
p += width * 4;
}
p = tmpImage;
}
else {
tmpImage = NULL; /* silence compiler warnings */
p = NULL;
}
 
assert(width < SWRAST_MAX_WIDTH);
 
for (row = 0; row < height; row++, sy += stepy, dy += stepy) {
GLvoid *rgba = span.array->attribs[VARYING_SLOT_COL0];
 
/* Get row/span of source pixels */
if (overlapping) {
/* get from buffered image */
memcpy(rgba, p, width * sizeof(GLfloat) * 4);
p += width * 4;
}
else {
/* get from framebuffer */
_swrast_read_rgba_span( ctx, ctx->ReadBuffer->_ColorReadBuffer,
width, srcx, sy, rgba );
}
 
if (transferOps) {
_mesa_apply_rgba_transfer_ops(ctx, transferOps, width,
(GLfloat (*)[4]) rgba);
}
 
/* Write color span */
span.x = destx;
span.y = dy;
span.end = width;
span.array->ChanType = GL_FLOAT;
if (zoom) {
_swrast_write_zoomed_rgba_span(ctx, destx, desty, &span, rgba);
}
else {
_swrast_write_rgba_span(ctx, &span);
}
}
 
span.array->ChanType = CHAN_TYPE; /* restore */
 
if (overlapping)
free(tmpImage);
}
 
 
/**
* Convert floating point Z values to integer Z values with pixel transfer's
* Z scale and bias.
*/
static void
scale_and_bias_z(struct gl_context *ctx, GLuint width,
const GLfloat depth[], GLuint z[])
{
const GLuint depthMax = ctx->DrawBuffer->_DepthMax;
GLuint i;
 
if (depthMax <= 0xffffff &&
ctx->Pixel.DepthScale == 1.0 &&
ctx->Pixel.DepthBias == 0.0) {
/* no scale or bias and no clamping and no worry of overflow */
const GLfloat depthMaxF = ctx->DrawBuffer->_DepthMaxF;
for (i = 0; i < width; i++) {
z[i] = (GLuint) (depth[i] * depthMaxF);
}
}
else {
/* need to be careful with overflow */
const GLdouble depthMaxF = ctx->DrawBuffer->_DepthMaxF;
for (i = 0; i < width; i++) {
GLdouble d = depth[i] * ctx->Pixel.DepthScale + ctx->Pixel.DepthBias;
d = CLAMP(d, 0.0, 1.0) * depthMaxF;
if (d >= depthMaxF)
z[i] = depthMax;
else
z[i] = (GLuint) d;
}
}
}
 
 
 
/*
* TODO: Optimize!!!!
*/
static void
copy_depth_pixels( struct gl_context *ctx, GLint srcx, GLint srcy,
GLint width, GLint height,
GLint destx, GLint desty )
{
struct gl_framebuffer *fb = ctx->ReadBuffer;
struct gl_renderbuffer *readRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
GLfloat *p, *tmpImage, *depth;
GLint sy, dy, stepy;
GLint j;
const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
GLint overlapping;
SWspan span;
 
if (!readRb) {
/* no readbuffer - OK */
return;
}
 
INIT_SPAN(span, GL_BITMAP);
_swrast_span_default_attribs(ctx, &span);
span.arrayMask = SPAN_Z;
 
if (ctx->DrawBuffer == ctx->ReadBuffer) {
overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
}
else {
overlapping = GL_FALSE;
}
 
/* Determine if copy should be bottom-to-top or top-to-bottom */
if (!overlapping && srcy < desty) {
/* top-down max-to-min */
sy = srcy + height - 1;
dy = desty + height - 1;
stepy = -1;
}
else {
/* bottom-up min-to-max */
sy = srcy;
dy = desty;
stepy = 1;
}
 
if (overlapping) {
GLint ssy = sy;
tmpImage = malloc(width * height * sizeof(GLfloat));
if (!tmpImage) {
_mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
return;
}
p = tmpImage;
for (j = 0; j < height; j++, ssy += stepy) {
_swrast_read_depth_span_float(ctx, readRb, width, srcx, ssy, p);
p += width;
}
p = tmpImage;
}
else {
tmpImage = NULL; /* silence compiler warning */
p = NULL;
}
 
depth = malloc(width * sizeof(GLfloat));
if (!depth) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels()");
goto end;
}
 
for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
/* get depth values */
if (overlapping) {
memcpy(depth, p, width * sizeof(GLfloat));
p += width;
}
else {
_swrast_read_depth_span_float(ctx, readRb, width, srcx, sy, depth);
}
 
/* apply scale and bias */
scale_and_bias_z(ctx, width, depth, span.array->z);
 
/* write depth values */
span.x = destx;
span.y = dy;
span.end = width;
if (zoom)
_swrast_write_zoomed_depth_span(ctx, destx, desty, &span);
else
_swrast_write_rgba_span(ctx, &span);
}
 
free(depth);
 
end:
if (overlapping)
free(tmpImage);
}
 
 
 
static void
copy_stencil_pixels( struct gl_context *ctx, GLint srcx, GLint srcy,
GLint width, GLint height,
GLint destx, GLint desty )
{
struct gl_framebuffer *fb = ctx->ReadBuffer;
struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
GLint sy, dy, stepy;
GLint j;
GLubyte *p, *tmpImage, *stencil;
const GLboolean zoom = ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F;
GLint overlapping;
 
if (!rb) {
/* no readbuffer - OK */
return;
}
 
if (ctx->DrawBuffer == ctx->ReadBuffer) {
overlapping = regions_overlap(srcx, srcy, destx, desty, width, height,
ctx->Pixel.ZoomX, ctx->Pixel.ZoomY);
}
else {
overlapping = GL_FALSE;
}
 
/* Determine if copy should be bottom-to-top or top-to-bottom */
if (!overlapping && srcy < desty) {
/* top-down max-to-min */
sy = srcy + height - 1;
dy = desty + height - 1;
stepy = -1;
}
else {
/* bottom-up min-to-max */
sy = srcy;
dy = desty;
stepy = 1;
}
 
if (overlapping) {
GLint ssy = sy;
tmpImage = malloc(width * height * sizeof(GLubyte));
if (!tmpImage) {
_mesa_error( ctx, GL_OUT_OF_MEMORY, "glCopyPixels" );
return;
}
p = tmpImage;
for (j = 0; j < height; j++, ssy += stepy) {
_swrast_read_stencil_span( ctx, rb, width, srcx, ssy, p );
p += width;
}
p = tmpImage;
}
else {
tmpImage = NULL; /* silence compiler warning */
p = NULL;
}
 
stencil = malloc(width * sizeof(GLubyte));
if (!stencil) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels()");
goto end;
}
 
for (j = 0; j < height; j++, sy += stepy, dy += stepy) {
/* Get stencil values */
if (overlapping) {
memcpy(stencil, p, width * sizeof(GLubyte));
p += width;
}
else {
_swrast_read_stencil_span( ctx, rb, width, srcx, sy, stencil );
}
 
_mesa_apply_stencil_transfer_ops(ctx, width, stencil);
 
/* Write stencil values */
if (zoom) {
_swrast_write_zoomed_stencil_span(ctx, destx, desty, width,
destx, dy, stencil);
}
else {
_swrast_write_stencil_span( ctx, width, destx, dy, stencil );
}
}
 
free(stencil);
 
end:
if (overlapping)
free(tmpImage);
}
 
 
/**
* Try to do a fast 1:1 blit with memcpy.
* \return GL_TRUE if successful, GL_FALSE otherwise.
*/
GLboolean
swrast_fast_copy_pixels(struct gl_context *ctx,
struct gl_framebuffer *srcFb,
struct gl_framebuffer *dstFb,
GLint srcX, GLint srcY, GLsizei width, GLsizei height,
GLint dstX, GLint dstY, GLenum type)
{
struct gl_renderbuffer *srcRb, *dstRb;
GLint row;
GLuint pixelBytes, widthInBytes;
GLubyte *srcMap, *dstMap;
GLint srcRowStride, dstRowStride;
 
if (type == GL_COLOR) {
if (dstFb->_NumColorDrawBuffers != 1)
return GL_FALSE;
srcRb = srcFb->_ColorReadBuffer;
dstRb = dstFb->_ColorDrawBuffers[0];
}
else if (type == GL_STENCIL) {
srcRb = srcFb->Attachment[BUFFER_STENCIL].Renderbuffer;
dstRb = dstFb->Attachment[BUFFER_STENCIL].Renderbuffer;
}
else if (type == GL_DEPTH) {
srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer;
dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer;
}
else {
assert(type == GL_DEPTH_STENCIL_EXT);
/* XXX correct? */
srcRb = srcFb->Attachment[BUFFER_DEPTH].Renderbuffer;
dstRb = dstFb->Attachment[BUFFER_DEPTH].Renderbuffer;
}
 
/* src and dst renderbuffers must be same format */
if (!srcRb || !dstRb || srcRb->Format != dstRb->Format) {
return GL_FALSE;
}
 
if (type == GL_STENCIL || type == GL_DEPTH_COMPONENT) {
/* can't handle packed depth+stencil here */
if (_mesa_is_format_packed_depth_stencil(srcRb->Format) ||
_mesa_is_format_packed_depth_stencil(dstRb->Format))
return GL_FALSE;
}
else if (type == GL_DEPTH_STENCIL) {
/* can't handle separate depth/stencil buffers */
if (srcRb != srcFb->Attachment[BUFFER_STENCIL].Renderbuffer ||
dstRb != dstFb->Attachment[BUFFER_STENCIL].Renderbuffer)
return GL_FALSE;
}
 
/* clipping not supported */
if (srcX < 0 || srcX + width > (GLint) srcFb->Width ||
srcY < 0 || srcY + height > (GLint) srcFb->Height ||
dstX < dstFb->_Xmin || dstX + width > dstFb->_Xmax ||
dstY < dstFb->_Ymin || dstY + height > dstFb->_Ymax) {
return GL_FALSE;
}
 
pixelBytes = _mesa_get_format_bytes(srcRb->Format);
widthInBytes = width * pixelBytes;
 
if (srcRb == dstRb) {
/* map whole buffer for read/write */
/* XXX we could be clever and just map the union region of the
* source and dest rects.
*/
GLubyte *map;
GLint rowStride;
 
ctx->Driver.MapRenderbuffer(ctx, srcRb, 0, 0,
srcRb->Width, srcRb->Height,
GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
&map, &rowStride);
if (!map) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
return GL_TRUE; /* don't retry with slow path */
}
 
srcMap = map + srcY * rowStride + srcX * pixelBytes;
dstMap = map + dstY * rowStride + dstX * pixelBytes;
 
/* this handles overlapping copies */
if (srcY < dstY) {
/* copy in reverse (top->down) order */
srcMap += rowStride * (height - 1);
dstMap += rowStride * (height - 1);
srcRowStride = -rowStride;
dstRowStride = -rowStride;
}
else {
/* copy in normal (bottom->up) order */
srcRowStride = rowStride;
dstRowStride = rowStride;
}
}
else {
/* different src/dst buffers */
ctx->Driver.MapRenderbuffer(ctx, srcRb, srcX, srcY,
width, height,
GL_MAP_READ_BIT, &srcMap, &srcRowStride);
if (!srcMap) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
return GL_TRUE; /* don't retry with slow path */
}
ctx->Driver.MapRenderbuffer(ctx, dstRb, dstX, dstY,
width, height,
GL_MAP_WRITE_BIT, &dstMap, &dstRowStride);
if (!dstMap) {
ctx->Driver.UnmapRenderbuffer(ctx, srcRb);
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glCopyPixels");
return GL_TRUE; /* don't retry with slow path */
}
}
 
for (row = 0; row < height; row++) {
/* memmove() in case of overlap */
memmove(dstMap, srcMap, widthInBytes);
dstMap += dstRowStride;
srcMap += srcRowStride;
}
 
ctx->Driver.UnmapRenderbuffer(ctx, srcRb);
if (dstRb != srcRb) {
ctx->Driver.UnmapRenderbuffer(ctx, dstRb);
}
 
return GL_TRUE;
}
 
 
/**
* Find/map the renderbuffer that we'll be reading from.
* The swrast_render_start() function only maps the drawing buffers,
* not the read buffer.
*/
static struct gl_renderbuffer *
map_readbuffer(struct gl_context *ctx, GLenum type)
{
struct gl_framebuffer *fb = ctx->ReadBuffer;
struct gl_renderbuffer *rb;
struct swrast_renderbuffer *srb;
 
switch (type) {
case GL_COLOR:
rb = fb->Attachment[fb->_ColorReadBufferIndex].Renderbuffer;
break;
case GL_DEPTH:
case GL_DEPTH_STENCIL:
rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
break;
case GL_STENCIL:
rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
break;
default:
return NULL;
}
 
srb = swrast_renderbuffer(rb);
 
if (!srb || srb->Map) {
/* no buffer, or buffer is mapped already, we're done */
return NULL;
}
 
ctx->Driver.MapRenderbuffer(ctx, rb,
0, 0, rb->Width, rb->Height,
GL_MAP_READ_BIT,
&srb->Map, &srb->RowStride);
 
return rb;
}
 
 
/**
* Do software-based glCopyPixels.
* By time we get here, all parameters will have been error-checked.
*/
void
_swrast_CopyPixels(struct gl_context *ctx,
GLint srcx, GLint srcy, GLsizei width, GLsizei height,
GLint destx, GLint desty, GLenum type)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
struct gl_renderbuffer *rb;
if (!_mesa_check_conditional_render(ctx))
return; /* don't copy */
 
if (swrast->NewState)
_swrast_validate_derived( ctx );
 
if (!(SWRAST_CONTEXT(ctx)->_RasterMask != 0x0 ||
ctx->Pixel.ZoomX != 1.0F ||
ctx->Pixel.ZoomY != 1.0F ||
ctx->_ImageTransferState) &&
swrast_fast_copy_pixels(ctx, ctx->ReadBuffer, ctx->DrawBuffer,
srcx, srcy, width, height, destx, desty,
type)) {
/* all done */
return;
}
 
swrast_render_start(ctx);
rb = map_readbuffer(ctx, type);
 
switch (type) {
case GL_COLOR:
copy_rgba_pixels( ctx, srcx, srcy, width, height, destx, desty );
break;
case GL_DEPTH:
copy_depth_pixels( ctx, srcx, srcy, width, height, destx, desty );
break;
case GL_STENCIL:
copy_stencil_pixels( ctx, srcx, srcy, width, height, destx, desty );
break;
case GL_DEPTH_STENCIL_EXT:
/* Copy buffers separately (if the fast copy path wasn't taken) */
copy_depth_pixels(ctx, srcx, srcy, width, height, destx, desty);
copy_stencil_pixels(ctx, srcx, srcy, width, height, destx, desty);
break;
default:
_mesa_problem(ctx, "unexpected type in _swrast_CopyPixels");
}
 
swrast_render_finish(ctx);
 
if (rb) {
struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
ctx->Driver.UnmapRenderbuffer(ctx, rb);
srb->Map = NULL;
}
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_depth.c
0,0 → 1,762
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#include "main/glheader.h"
#include "main/context.h"
#include "main/formats.h"
#include "main/format_unpack.h"
#include "main/format_pack.h"
#include "main/macros.h"
#include "main/imports.h"
 
#include "s_context.h"
#include "s_depth.h"
#include "s_span.h"
 
 
 
#define Z_TEST(COMPARE) \
do { \
GLuint i; \
for (i = 0; i < n; i++) { \
if (mask[i]) { \
if (COMPARE) { \
/* pass */ \
if (write) { \
zbuffer[i] = zfrag[i]; \
} \
passed++; \
} \
else { \
/* fail */ \
mask[i] = 0; \
} \
} \
} \
} while (0)
 
 
/**
* Do depth test for an array of 16-bit Z values.
* @param zbuffer array of Z buffer values (16-bit)
* @param zfrag array of fragment Z values (use 16-bit in 32-bit uint)
* @param mask which fragments are alive, killed afterward
* @return number of fragments which pass the test.
*/
static GLuint
depth_test_span16( struct gl_context *ctx, GLuint n,
GLushort zbuffer[], const GLuint zfrag[], GLubyte mask[] )
{
const GLboolean write = ctx->Depth.Mask;
GLuint passed = 0;
 
/* switch cases ordered from most frequent to less frequent */
switch (ctx->Depth.Func) {
case GL_LESS:
Z_TEST(zfrag[i] < zbuffer[i]);
break;
case GL_LEQUAL:
Z_TEST(zfrag[i] <= zbuffer[i]);
break;
case GL_GEQUAL:
Z_TEST(zfrag[i] >= zbuffer[i]);
break;
case GL_GREATER:
Z_TEST(zfrag[i] > zbuffer[i]);
break;
case GL_NOTEQUAL:
Z_TEST(zfrag[i] != zbuffer[i]);
break;
case GL_EQUAL:
Z_TEST(zfrag[i] == zbuffer[i]);
break;
case GL_ALWAYS:
Z_TEST(1);
break;
case GL_NEVER:
memset(mask, 0, n * sizeof(GLubyte));
break;
default:
_mesa_problem(ctx, "Bad depth func in depth_test_span16");
}
 
return passed;
}
 
 
/**
* Do depth test for an array of 32-bit Z values.
* @param zbuffer array of Z buffer values (32-bit)
* @param zfrag array of fragment Z values (use 32-bits in 32-bit uint)
* @param mask which fragments are alive, killed afterward
* @return number of fragments which pass the test.
*/
static GLuint
depth_test_span32( struct gl_context *ctx, GLuint n,
GLuint zbuffer[], const GLuint zfrag[], GLubyte mask[])
{
const GLboolean write = ctx->Depth.Mask;
GLuint passed = 0;
 
/* switch cases ordered from most frequent to less frequent */
switch (ctx->Depth.Func) {
case GL_LESS:
Z_TEST(zfrag[i] < zbuffer[i]);
break;
case GL_LEQUAL:
Z_TEST(zfrag[i] <= zbuffer[i]);
break;
case GL_GEQUAL:
Z_TEST(zfrag[i] >= zbuffer[i]);
break;
case GL_GREATER:
Z_TEST(zfrag[i] > zbuffer[i]);
break;
case GL_NOTEQUAL:
Z_TEST(zfrag[i] != zbuffer[i]);
break;
case GL_EQUAL:
Z_TEST(zfrag[i] == zbuffer[i]);
break;
case GL_ALWAYS:
Z_TEST(1);
break;
case GL_NEVER:
memset(mask, 0, n * sizeof(GLubyte));
break;
default:
_mesa_problem(ctx, "Bad depth func in depth_test_span32");
}
 
return passed;
}
 
 
/**
* Clamp fragment Z values to the depth near/far range (glDepthRange()).
* This is used when GL_ARB_depth_clamp/GL_DEPTH_CLAMP is turned on.
* In that case, vertexes are not clipped against the near/far planes
* so rasterization will produce fragment Z values outside the usual
* [0,1] range.
*/
void
_swrast_depth_clamp_span( struct gl_context *ctx, SWspan *span )
{
struct gl_framebuffer *fb = ctx->DrawBuffer;
const GLuint count = span->end;
GLint *zValues = (GLint *) span->array->z; /* sign change */
GLint min, max;
GLfloat min_f, max_f;
GLuint i;
 
if (ctx->ViewportArray[0].Near < ctx->ViewportArray[0].Far) {
min_f = ctx->ViewportArray[0].Near;
max_f = ctx->ViewportArray[0].Far;
} else {
min_f = ctx->ViewportArray[0].Far;
max_f = ctx->ViewportArray[0].Near;
}
 
/* Convert floating point values in [0,1] to device Z coordinates in
* [0, DepthMax].
* ex: If the Z buffer has 24 bits, DepthMax = 0xffffff.
*
* XXX this all falls apart if we have 31 or more bits of Z because
* the triangle rasterization code produces unsigned Z values. Negative
* vertex Z values come out as large fragment Z uints.
*/
min = (GLint) (min_f * fb->_DepthMaxF);
max = (GLint) (max_f * fb->_DepthMaxF);
if (max < 0)
max = 0x7fffffff; /* catch over flow for 30-bit z */
 
/* Note that we do the comparisons here using signed integers.
*/
for (i = 0; i < count; i++) {
if (zValues[i] < min)
zValues[i] = min;
if (zValues[i] > max)
zValues[i] = max;
}
}
 
 
/**
* Get array of 32-bit z values from the depth buffer. With clipping.
* Note: the returned values are always in the range [0, 2^32-1].
*/
static void
get_z32_values(struct gl_context *ctx, struct gl_renderbuffer *rb,
GLuint count, const GLint x[], const GLint y[],
GLuint zbuffer[])
{
struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
const GLint w = rb->Width, h = rb->Height;
const GLubyte *map = _swrast_pixel_address(rb, 0, 0);
GLuint i;
 
if (rb->Format == MESA_FORMAT_Z_UNORM32) {
const GLint rowStride = srb->RowStride;
for (i = 0; i < count; i++) {
if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) {
zbuffer[i] = *((GLuint *) (map + y[i] * rowStride + x[i] * 4));
}
}
}
else {
const GLint bpp = _mesa_get_format_bytes(rb->Format);
const GLint rowStride = srb->RowStride;
for (i = 0; i < count; i++) {
if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) {
const GLubyte *src = map + y[i] * rowStride+ x[i] * bpp;
_mesa_unpack_uint_z_row(rb->Format, 1, src, &zbuffer[i]);
}
}
}
}
 
 
/**
* Put an array of 32-bit z values into the depth buffer.
* Note: the z values are always in the range [0, 2^32-1].
*/
static void
put_z32_values(struct gl_context *ctx, struct gl_renderbuffer *rb,
GLuint count, const GLint x[], const GLint y[],
const GLuint zvalues[], const GLubyte mask[])
{
struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
const GLint w = rb->Width, h = rb->Height;
GLubyte *map = _swrast_pixel_address(rb, 0, 0);
GLuint i;
 
if (rb->Format == MESA_FORMAT_Z_UNORM32) {
const GLint rowStride = srb->RowStride;
for (i = 0; i < count; i++) {
if (mask[i] && x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) {
GLuint *dst = (GLuint *) (map + y[i] * rowStride + x[i] * 4);
*dst = zvalues[i];
}
}
}
else {
gl_pack_uint_z_func packZ = _mesa_get_pack_uint_z_func(rb->Format);
const GLint bpp = _mesa_get_format_bytes(rb->Format);
const GLint rowStride = srb->RowStride;
for (i = 0; i < count; i++) {
if (mask[i] && x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) {
void *dst = map + y[i] * rowStride + x[i] * bpp;
packZ(zvalues + i, dst);
}
}
}
}
 
 
/**
* Apply depth (Z) buffer testing to the span.
* \return approx number of pixels that passed (only zero is reliable)
*/
GLuint
_swrast_depth_test_span(struct gl_context *ctx, SWspan *span)
{
struct gl_framebuffer *fb = ctx->DrawBuffer;
struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
const GLint bpp = _mesa_get_format_bytes(rb->Format);
void *zStart;
const GLuint count = span->end;
const GLuint *fragZ = span->array->z;
GLubyte *mask = span->array->mask;
void *zBufferVals;
GLuint *zBufferTemp = NULL;
GLuint passed;
GLuint zBits = _mesa_get_format_bits(rb->Format, GL_DEPTH_BITS);
GLboolean ztest16 = GL_FALSE;
 
if (span->arrayMask & SPAN_XY)
zStart = NULL;
else
zStart = _swrast_pixel_address(rb, span->x, span->y);
 
if (rb->Format == MESA_FORMAT_Z_UNORM16 && !(span->arrayMask & SPAN_XY)) {
/* directly read/write row of 16-bit Z values */
zBufferVals = zStart;
ztest16 = GL_TRUE;
}
else if (rb->Format == MESA_FORMAT_Z_UNORM32 && !(span->arrayMask & SPAN_XY)) {
/* directly read/write row of 32-bit Z values */
zBufferVals = zStart;
}
else {
if (_mesa_get_format_datatype(rb->Format) != GL_UNSIGNED_NORMALIZED) {
_mesa_problem(ctx, "Incorrectly writing swrast's integer depth "
"values to %s depth buffer",
_mesa_get_format_name(rb->Format));
}
 
/* copy Z buffer values into temp buffer (32-bit Z values) */
zBufferTemp = malloc(count * sizeof(GLuint));
if (!zBufferTemp)
return 0;
 
if (span->arrayMask & SPAN_XY) {
get_z32_values(ctx, rb, count,
span->array->x, span->array->y, zBufferTemp);
}
else {
_mesa_unpack_uint_z_row(rb->Format, count, zStart, zBufferTemp);
}
 
if (zBits == 24) {
GLuint i;
/* Convert depth buffer values from 32 to 24 bits to match the
* fragment Z values generated by rasterization.
*/
for (i = 0; i < count; i++) {
zBufferTemp[i] >>= 8;
}
}
else if (zBits == 16) {
GLuint i;
/* Convert depth buffer values from 32 to 16 bits */
for (i = 0; i < count; i++) {
zBufferTemp[i] >>= 16;
}
}
else {
assert(zBits == 32);
}
 
zBufferVals = zBufferTemp;
}
 
/* do the depth test either with 16 or 32-bit values */
if (ztest16)
passed = depth_test_span16(ctx, count, zBufferVals, fragZ, mask);
else
passed = depth_test_span32(ctx, count, zBufferVals, fragZ, mask);
 
if (zBufferTemp) {
/* need to write temp Z values back into the buffer */
 
/* Convert depth buffer values back to 32-bit values. The least
* significant bits don't matter since they'll get dropped when
* they're packed back into the depth buffer.
*/
if (zBits == 24) {
GLuint i;
for (i = 0; i < count; i++) {
zBufferTemp[i] = (zBufferTemp[i] << 8);
}
}
else if (zBits == 16) {
GLuint i;
for (i = 0; i < count; i++) {
zBufferTemp[i] = zBufferTemp[i] << 16;
}
}
 
if (span->arrayMask & SPAN_XY) {
/* random locations */
put_z32_values(ctx, rb, count, span->array->x, span->array->y,
zBufferTemp, mask);
}
else {
/* horizontal row */
gl_pack_uint_z_func packZ = _mesa_get_pack_uint_z_func(rb->Format);
GLubyte *dst = zStart;
GLuint i;
for (i = 0; i < count; i++) {
if (mask[i]) {
packZ(&zBufferTemp[i], dst);
}
dst += bpp;
}
}
 
free(zBufferTemp);
}
 
if (passed < count) {
span->writeAll = GL_FALSE;
}
return passed;
}
 
 
/**
* GL_EXT_depth_bounds_test extension.
* Discard fragments depending on whether the corresponding Z-buffer
* values are outside the depth bounds test range.
* Note: we test the Z buffer values, not the fragment Z values!
* \return GL_TRUE if any fragments pass, GL_FALSE if no fragments pass
*/
GLboolean
_swrast_depth_bounds_test( struct gl_context *ctx, SWspan *span )
{
struct gl_framebuffer *fb = ctx->DrawBuffer;
struct gl_renderbuffer *rb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
GLubyte *zStart;
GLuint zMin = (GLuint) (ctx->Depth.BoundsMin * fb->_DepthMaxF + 0.5F);
GLuint zMax = (GLuint) (ctx->Depth.BoundsMax * fb->_DepthMaxF + 0.5F);
GLubyte *mask = span->array->mask;
const GLuint count = span->end;
GLuint i;
GLboolean anyPass = GL_FALSE;
GLuint *zBufferTemp;
const GLuint *zBufferVals;
 
zBufferTemp = malloc(count * sizeof(GLuint));
if (!zBufferTemp) {
/* don't generate a stream of OUT_OF_MEMORY errors here */
return GL_FALSE;
}
 
if (span->arrayMask & SPAN_XY)
zStart = NULL;
else
zStart = _swrast_pixel_address(rb, span->x, span->y);
 
if (rb->Format == MESA_FORMAT_Z_UNORM32 && !(span->arrayMask & SPAN_XY)) {
/* directly access 32-bit values in the depth buffer */
zBufferVals = (const GLuint *) zStart;
}
else {
/* unpack Z values into a temporary array */
if (span->arrayMask & SPAN_XY) {
get_z32_values(ctx, rb, count, span->array->x, span->array->y,
zBufferTemp);
}
else {
_mesa_unpack_uint_z_row(rb->Format, count, zStart, zBufferTemp);
}
zBufferVals = zBufferTemp;
}
 
/* Now do the tests */
for (i = 0; i < count; i++) {
if (mask[i]) {
if (zBufferVals[i] < zMin || zBufferVals[i] > zMax)
mask[i] = GL_FALSE;
else
anyPass = GL_TRUE;
}
}
 
free(zBufferTemp);
 
return anyPass;
}
 
 
 
/**********************************************************************/
/***** Read Depth Buffer *****/
/**********************************************************************/
 
 
/**
* Read a span of depth values from the given depth renderbuffer, returning
* the values as GLfloats.
* This function does clipping to prevent reading outside the depth buffer's
* bounds.
*/
void
_swrast_read_depth_span_float(struct gl_context *ctx,
struct gl_renderbuffer *rb,
GLint n, GLint x, GLint y, GLfloat depth[])
{
if (!rb) {
/* really only doing this to prevent FP exceptions later */
memset(depth, 0, n * sizeof(GLfloat));
return;
}
 
if (y < 0 || y >= (GLint) rb->Height ||
x + n <= 0 || x >= (GLint) rb->Width) {
/* span is completely outside framebuffer */
memset(depth, 0, n * sizeof(GLfloat));
return;
}
 
if (x < 0) {
GLint dx = -x;
GLint i;
for (i = 0; i < dx; i++)
depth[i] = 0.0;
x = 0;
n -= dx;
depth += dx;
}
if (x + n > (GLint) rb->Width) {
GLint dx = x + n - (GLint) rb->Width;
GLint i;
for (i = 0; i < dx; i++)
depth[n - i - 1] = 0.0;
n -= dx;
}
if (n <= 0) {
return;
}
 
_mesa_unpack_float_z_row(rb->Format, n, _swrast_pixel_address(rb, x, y),
depth);
}
 
 
/**
* Clear the given z/depth renderbuffer. If the buffer is a combined
* depth+stencil buffer, only the Z bits will be touched.
*/
void
_swrast_clear_depth_buffer(struct gl_context *ctx)
{
struct gl_renderbuffer *rb =
ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
GLint x, y, width, height;
GLubyte *map;
GLint rowStride, i, j;
GLbitfield mapMode;
 
if (!rb || !ctx->Depth.Mask) {
/* no depth buffer, or writing to it is disabled */
return;
}
 
/* compute region to clear */
x = ctx->DrawBuffer->_Xmin;
y = ctx->DrawBuffer->_Ymin;
width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
 
mapMode = GL_MAP_WRITE_BIT;
if (rb->Format == MESA_FORMAT_Z24_UNORM_S8_UINT ||
rb->Format == MESA_FORMAT_Z24_UNORM_X8_UINT ||
rb->Format == MESA_FORMAT_S8_UINT_Z24_UNORM ||
rb->Format == MESA_FORMAT_X8_UINT_Z24_UNORM) {
mapMode |= GL_MAP_READ_BIT;
}
 
ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
mapMode, &map, &rowStride);
if (!map) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(depth)");
return;
}
 
switch (rb->Format) {
case MESA_FORMAT_Z_UNORM16:
{
GLfloat clear = (GLfloat) ctx->Depth.Clear;
GLushort clearVal = 0;
_mesa_pack_float_z_row(rb->Format, 1, &clear, &clearVal);
if (clearVal == 0xffff && width * 2 == rowStride) {
/* common case */
memset(map, 0xff, width * height * 2);
}
else {
for (i = 0; i < height; i++) {
GLushort *row = (GLushort *) map;
for (j = 0; j < width; j++) {
row[j] = clearVal;
}
map += rowStride;
}
}
}
break;
case MESA_FORMAT_Z_UNORM32:
case MESA_FORMAT_Z_FLOAT32:
{
GLfloat clear = (GLfloat) ctx->Depth.Clear;
GLuint clearVal = 0;
_mesa_pack_float_z_row(rb->Format, 1, &clear, &clearVal);
for (i = 0; i < height; i++) {
GLuint *row = (GLuint *) map;
for (j = 0; j < width; j++) {
row[j] = clearVal;
}
map += rowStride;
}
}
break;
case MESA_FORMAT_Z24_UNORM_S8_UINT:
case MESA_FORMAT_Z24_UNORM_X8_UINT:
case MESA_FORMAT_S8_UINT_Z24_UNORM:
case MESA_FORMAT_X8_UINT_Z24_UNORM:
{
GLfloat clear = (GLfloat) ctx->Depth.Clear;
GLuint clearVal = 0;
GLuint mask;
 
if (rb->Format == MESA_FORMAT_Z24_UNORM_S8_UINT ||
rb->Format == MESA_FORMAT_Z24_UNORM_X8_UINT)
mask = 0xff000000;
else
mask = 0xff;
 
_mesa_pack_float_z_row(rb->Format, 1, &clear, &clearVal);
for (i = 0; i < height; i++) {
GLuint *row = (GLuint *) map;
for (j = 0; j < width; j++) {
row[j] = (row[j] & mask) | clearVal;
}
map += rowStride;
}
 
}
break;
case MESA_FORMAT_Z32_FLOAT_S8X24_UINT:
/* XXX untested */
{
GLfloat clearVal = (GLfloat) ctx->Depth.Clear;
for (i = 0; i < height; i++) {
GLfloat *row = (GLfloat *) map;
for (j = 0; j < width; j++) {
row[j * 2] = clearVal;
}
map += rowStride;
}
}
break;
default:
_mesa_problem(ctx, "Unexpected depth buffer format %s"
" in _swrast_clear_depth_buffer()",
_mesa_get_format_name(rb->Format));
}
 
ctx->Driver.UnmapRenderbuffer(ctx, rb);
}
 
 
 
 
/**
* Clear both depth and stencil values in a combined depth+stencil buffer.
*/
void
_swrast_clear_depth_stencil_buffer(struct gl_context *ctx)
{
const GLubyte stencilBits = ctx->DrawBuffer->Visual.stencilBits;
const GLuint writeMask = ctx->Stencil.WriteMask[0];
const GLuint stencilMax = (1 << stencilBits) - 1;
struct gl_renderbuffer *rb =
ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
GLint x, y, width, height;
GLbitfield mapMode;
GLubyte *map;
GLint rowStride, i, j;
 
/* check that we really have a combined depth+stencil buffer */
assert(rb == ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer);
 
/* compute region to clear */
x = ctx->DrawBuffer->_Xmin;
y = ctx->DrawBuffer->_Ymin;
width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
 
mapMode = GL_MAP_WRITE_BIT;
if ((writeMask & stencilMax) != stencilMax) {
/* need to mask stencil values */
mapMode |= GL_MAP_READ_BIT;
}
 
ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
mapMode, &map, &rowStride);
if (!map) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(depth+stencil)");
return;
}
 
switch (rb->Format) {
case MESA_FORMAT_Z24_UNORM_S8_UINT:
case MESA_FORMAT_S8_UINT_Z24_UNORM:
{
GLfloat zClear = (GLfloat) ctx->Depth.Clear;
GLuint clear = 0, mask;
 
_mesa_pack_float_z_row(rb->Format, 1, &zClear, &clear);
 
if (rb->Format == MESA_FORMAT_Z24_UNORM_S8_UINT) {
mask = ((~writeMask) & 0xff) << 24;
clear |= (ctx->Stencil.Clear & writeMask & 0xff) << 24;
}
else {
mask = ((~writeMask) & 0xff);
clear |= (ctx->Stencil.Clear & writeMask & 0xff);
}
 
for (i = 0; i < height; i++) {
GLuint *row = (GLuint *) map;
if (mask != 0x0) {
for (j = 0; j < width; j++) {
row[j] = (row[j] & mask) | clear;
}
}
else {
for (j = 0; j < width; j++) {
row[j] = clear;
}
}
map += rowStride;
}
}
break;
case MESA_FORMAT_Z32_FLOAT_S8X24_UINT:
/* XXX untested */
{
const GLfloat zClear = (GLfloat) ctx->Depth.Clear;
const GLuint sClear = ctx->Stencil.Clear & writeMask;
const GLuint sMask = (~writeMask) & 0xff;
for (i = 0; i < height; i++) {
GLfloat *zRow = (GLfloat *) map;
GLuint *sRow = (GLuint *) map;
for (j = 0; j < width; j++) {
zRow[j * 2 + 0] = zClear;
}
if (sMask != 0) {
for (j = 0; j < width; j++) {
sRow[j * 2 + 1] = (sRow[j * 2 + 1] & sMask) | sClear;
}
}
else {
for (j = 0; j < width; j++) {
sRow[j * 2 + 1] = sClear;
}
}
map += rowStride;
}
}
break;
default:
_mesa_problem(ctx, "Unexpected depth buffer format %s"
" in _swrast_clear_depth_buffer()",
_mesa_get_format_name(rb->Format));
}
 
ctx->Driver.UnmapRenderbuffer(ctx, rb);
 
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_depth.h
0,0 → 1,58
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_DEPTH_H
#define S_DEPTH_H
 
 
#include "main/glheader.h"
#include "s_span.h"
 
struct gl_context;
struct gl_renderbuffer;
 
 
extern GLuint
_swrast_depth_test_span( struct gl_context *ctx, SWspan *span);
 
extern void
_swrast_depth_clamp_span( struct gl_context *ctx, SWspan *span );
 
extern GLboolean
_swrast_depth_bounds_test( struct gl_context *ctx, SWspan *span );
 
 
extern void
_swrast_read_depth_span_float( struct gl_context *ctx, struct gl_renderbuffer *rb,
GLint n, GLint x, GLint y, GLfloat depth[] );
 
extern void
_swrast_clear_depth_buffer(struct gl_context *ctx);
 
extern void
_swrast_clear_depth_stencil_buffer(struct gl_context *ctx);
 
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_drawpix.c
0,0 → 1,758
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#include "main/glheader.h"
#include "main/bufferobj.h"
#include "main/colormac.h"
#include "main/condrender.h"
#include "main/context.h"
#include "main/format_pack.h"
#include "main/format_utils.h"
#include "main/glformats.h"
#include "main/image.h"
#include "main/imports.h"
#include "main/macros.h"
#include "main/pack.h"
#include "main/pbo.h"
#include "main/pixeltransfer.h"
#include "main/state.h"
 
#include "s_context.h"
#include "s_span.h"
#include "s_stencil.h"
#include "s_zoom.h"
 
 
/**
* Handle a common case of drawing GL_RGB/GL_UNSIGNED_BYTE into a
* MESA_FORMAT_XRGB888 or MESA_FORMAT_ARGB888 renderbuffer.
*/
static void
fast_draw_rgb_ubyte_pixels(struct gl_context *ctx,
struct gl_renderbuffer *rb,
GLint x, GLint y,
GLsizei width, GLsizei height,
const struct gl_pixelstore_attrib *unpack,
const GLvoid *pixels)
{
const GLubyte *src = (const GLubyte *)
_mesa_image_address2d(unpack, pixels, width,
height, GL_RGB, GL_UNSIGNED_BYTE, 0, 0);
const GLint srcRowStride = _mesa_image_row_stride(unpack, width,
GL_RGB, GL_UNSIGNED_BYTE);
GLint i, j;
GLubyte *dst;
GLint dstRowStride;
 
ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
GL_MAP_WRITE_BIT, &dst, &dstRowStride);
 
if (!dst) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
return;
}
 
if (ctx->Pixel.ZoomY == -1.0f) {
dst = dst + (height - 1) * dstRowStride;
dstRowStride = -dstRowStride;
}
 
for (i = 0; i < height; i++) {
GLuint *dst4 = (GLuint *) dst;
for (j = 0; j < width; j++) {
dst4[j] = PACK_COLOR_8888(0xff, src[j*3+0], src[j*3+1], src[j*3+2]);
}
dst += dstRowStride;
src += srcRowStride;
}
 
ctx->Driver.UnmapRenderbuffer(ctx, rb);
}
 
 
/**
* Handle a common case of drawing GL_RGBA/GL_UNSIGNED_BYTE into a
* MESA_FORMAT_ARGB888 or MESA_FORMAT_xRGB888 renderbuffer.
*/
static void
fast_draw_rgba_ubyte_pixels(struct gl_context *ctx,
struct gl_renderbuffer *rb,
GLint x, GLint y,
GLsizei width, GLsizei height,
const struct gl_pixelstore_attrib *unpack,
const GLvoid *pixels)
{
const GLubyte *src = (const GLubyte *)
_mesa_image_address2d(unpack, pixels, width,
height, GL_RGBA, GL_UNSIGNED_BYTE, 0, 0);
const GLint srcRowStride =
_mesa_image_row_stride(unpack, width, GL_RGBA, GL_UNSIGNED_BYTE);
GLint i, j;
GLubyte *dst;
GLint dstRowStride;
 
ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
GL_MAP_WRITE_BIT, &dst, &dstRowStride);
 
if (!dst) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
return;
}
 
if (ctx->Pixel.ZoomY == -1.0f) {
dst = dst + (height - 1) * dstRowStride;
dstRowStride = -dstRowStride;
}
 
for (i = 0; i < height; i++) {
GLuint *dst4 = (GLuint *) dst;
for (j = 0; j < width; j++) {
dst4[j] = PACK_COLOR_8888(src[j*4+3], src[j*4+0],
src[j*4+1], src[j*4+2]);
}
dst += dstRowStride;
src += srcRowStride;
}
 
ctx->Driver.UnmapRenderbuffer(ctx, rb);
}
 
 
/**
* Handle a common case of drawing a format/type combination that
* exactly matches the renderbuffer format.
*/
static void
fast_draw_generic_pixels(struct gl_context *ctx,
struct gl_renderbuffer *rb,
GLint x, GLint y,
GLsizei width, GLsizei height,
GLenum format, GLenum type,
const struct gl_pixelstore_attrib *unpack,
const GLvoid *pixels)
{
const GLubyte *src = (const GLubyte *)
_mesa_image_address2d(unpack, pixels, width,
height, format, type, 0, 0);
const GLint srcRowStride =
_mesa_image_row_stride(unpack, width, format, type);
const GLint rowLength = width * _mesa_get_format_bytes(rb->Format);
GLint i;
GLubyte *dst;
GLint dstRowStride;
 
ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
GL_MAP_WRITE_BIT, &dst, &dstRowStride);
 
if (!dst) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
return;
}
 
if (ctx->Pixel.ZoomY == -1.0f) {
dst = dst + (height - 1) * dstRowStride;
dstRowStride = -dstRowStride;
}
 
for (i = 0; i < height; i++) {
memcpy(dst, src, rowLength);
dst += dstRowStride;
src += srcRowStride;
}
 
ctx->Driver.UnmapRenderbuffer(ctx, rb);
}
 
 
/**
* Try to do a fast and simple RGB(a) glDrawPixels.
* Return: GL_TRUE if success, GL_FALSE if slow path must be used instead
*/
static GLboolean
fast_draw_rgba_pixels(struct gl_context *ctx, GLint x, GLint y,
GLsizei width, GLsizei height,
GLenum format, GLenum type,
const struct gl_pixelstore_attrib *userUnpack,
const GLvoid *pixels)
{
struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0];
SWcontext *swrast = SWRAST_CONTEXT(ctx);
struct gl_pixelstore_attrib unpack;
 
if (!rb)
return GL_TRUE; /* no-op */
 
if (ctx->DrawBuffer->_NumColorDrawBuffers > 1 ||
(swrast->_RasterMask & ~CLIP_BIT) ||
ctx->Texture._EnabledCoordUnits ||
userUnpack->SwapBytes ||
ctx->Pixel.ZoomX != 1.0f ||
fabsf(ctx->Pixel.ZoomY) != 1.0f ||
ctx->_ImageTransferState) {
/* can't handle any of those conditions */
return GL_FALSE;
}
 
unpack = *userUnpack;
 
/* clipping */
if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height, &unpack)) {
/* image was completely clipped: no-op, all done */
return GL_TRUE;
}
 
if (format == GL_RGB &&
type == GL_UNSIGNED_BYTE &&
(rb->Format == MESA_FORMAT_B8G8R8X8_UNORM ||
rb->Format == MESA_FORMAT_B8G8R8A8_UNORM)) {
fast_draw_rgb_ubyte_pixels(ctx, rb, x, y, width, height,
&unpack, pixels);
return GL_TRUE;
}
 
if (format == GL_RGBA &&
type == GL_UNSIGNED_BYTE &&
(rb->Format == MESA_FORMAT_B8G8R8X8_UNORM ||
rb->Format == MESA_FORMAT_B8G8R8A8_UNORM)) {
fast_draw_rgba_ubyte_pixels(ctx, rb, x, y, width, height,
&unpack, pixels);
return GL_TRUE;
}
 
if (_mesa_format_matches_format_and_type(rb->Format, format, type,
ctx->Unpack.SwapBytes)) {
fast_draw_generic_pixels(ctx, rb, x, y, width, height,
format, type, &unpack, pixels);
return GL_TRUE;
}
 
/* can't handle this pixel format and/or data type */
return GL_FALSE;
}
 
 
 
/*
* Draw stencil image.
*/
static void
draw_stencil_pixels( struct gl_context *ctx, GLint x, GLint y,
GLsizei width, GLsizei height,
GLenum type,
const struct gl_pixelstore_attrib *unpack,
const GLvoid *pixels )
{
const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
const GLenum destType = GL_UNSIGNED_BYTE;
GLint row;
GLubyte *values;
 
values = malloc(width * sizeof(GLubyte));
if (!values) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
return;
}
 
for (row = 0; row < height; row++) {
const GLvoid *source = _mesa_image_address2d(unpack, pixels,
width, height,
GL_STENCIL_INDEX, type,
row, 0);
_mesa_unpack_stencil_span(ctx, width, destType, values,
type, source, unpack,
ctx->_ImageTransferState);
if (zoom) {
_swrast_write_zoomed_stencil_span(ctx, x, y, width,
x, y, values);
}
else {
_swrast_write_stencil_span(ctx, width, x, y, values);
}
 
y++;
}
 
free(values);
}
 
 
/*
* Draw depth image.
*/
static void
draw_depth_pixels( struct gl_context *ctx, GLint x, GLint y,
GLsizei width, GLsizei height,
GLenum type,
const struct gl_pixelstore_attrib *unpack,
const GLvoid *pixels )
{
const GLboolean scaleOrBias
= ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
SWspan span;
 
INIT_SPAN(span, GL_BITMAP);
span.arrayMask = SPAN_Z;
_swrast_span_default_attribs(ctx, &span);
 
if (type == GL_UNSIGNED_SHORT
&& ctx->DrawBuffer->Visual.depthBits == 16
&& !scaleOrBias
&& !zoom
&& width <= SWRAST_MAX_WIDTH
&& !unpack->SwapBytes) {
/* Special case: directly write 16-bit depth values */
GLint row;
for (row = 0; row < height; row++) {
const GLushort *zSrc = (const GLushort *)
_mesa_image_address2d(unpack, pixels, width, height,
GL_DEPTH_COMPONENT, type, row, 0);
GLint i;
for (i = 0; i < width; i++)
span.array->z[i] = zSrc[i];
span.x = x;
span.y = y + row;
span.end = width;
_swrast_write_rgba_span(ctx, &span);
}
}
else if (type == GL_UNSIGNED_INT
&& !scaleOrBias
&& !zoom
&& width <= SWRAST_MAX_WIDTH
&& !unpack->SwapBytes) {
/* Special case: shift 32-bit values down to Visual.depthBits */
const GLint shift = 32 - ctx->DrawBuffer->Visual.depthBits;
GLint row;
for (row = 0; row < height; row++) {
const GLuint *zSrc = (const GLuint *)
_mesa_image_address2d(unpack, pixels, width, height,
GL_DEPTH_COMPONENT, type, row, 0);
if (shift == 0) {
memcpy(span.array->z, zSrc, width * sizeof(GLuint));
}
else {
GLint col;
for (col = 0; col < width; col++)
span.array->z[col] = zSrc[col] >> shift;
}
span.x = x;
span.y = y + row;
span.end = width;
_swrast_write_rgba_span(ctx, &span);
}
}
else {
/* General case */
const GLuint depthMax = ctx->DrawBuffer->_DepthMax;
GLint skipPixels = 0;
 
/* in case width > SWRAST_MAX_WIDTH do the copy in chunks */
while (skipPixels < width) {
const GLint spanWidth = MIN2(width - skipPixels, SWRAST_MAX_WIDTH);
GLint row;
assert(span.end <= SWRAST_MAX_WIDTH);
for (row = 0; row < height; row++) {
const GLvoid *zSrc = _mesa_image_address2d(unpack,
pixels, width, height,
GL_DEPTH_COMPONENT, type,
row, skipPixels);
 
/* Set these for each row since the _swrast_write_* function may
* change them while clipping.
*/
span.x = x + skipPixels;
span.y = y + row;
span.end = spanWidth;
 
_mesa_unpack_depth_span(ctx, spanWidth,
GL_UNSIGNED_INT, span.array->z, depthMax,
type, zSrc, unpack);
if (zoom) {
_swrast_write_zoomed_depth_span(ctx, x, y, &span);
}
else {
_swrast_write_rgba_span(ctx, &span);
}
}
skipPixels += spanWidth;
}
}
}
 
 
 
/**
* Draw RGBA image.
*/
static void
draw_rgba_pixels( struct gl_context *ctx, GLint x, GLint y,
GLsizei width, GLsizei height,
GLenum format, GLenum type,
const struct gl_pixelstore_attrib *unpack,
const GLvoid *pixels )
{
const GLint imgX = x, imgY = y;
const GLboolean zoom = ctx->Pixel.ZoomX!=1.0 || ctx->Pixel.ZoomY!=1.0;
GLbitfield transferOps = ctx->_ImageTransferState;
SWspan span;
 
/* Try an optimized glDrawPixels first */
if (fast_draw_rgba_pixels(ctx, x, y, width, height, format, type,
unpack, pixels)) {
return;
}
 
swrast_render_start(ctx);
 
INIT_SPAN(span, GL_BITMAP);
_swrast_span_default_attribs(ctx, &span);
span.arrayMask = SPAN_RGBA;
span.arrayAttribs = VARYING_BIT_COL0; /* we're fill in COL0 attrib values */
 
if (ctx->DrawBuffer->_NumColorDrawBuffers > 0) {
GLenum datatype = _mesa_get_format_datatype(
ctx->DrawBuffer->_ColorDrawBuffers[0]->Format);
if (datatype != GL_FLOAT &&
ctx->Color.ClampFragmentColor != GL_FALSE) {
/* need to clamp colors before applying fragment ops */
transferOps |= IMAGE_CLAMP_BIT;
}
}
 
/*
* General solution
*/
{
const GLbitfield interpMask = span.interpMask;
const GLbitfield arrayMask = span.arrayMask;
GLint skipPixels = 0;
/* use span array for temp color storage */
GLfloat *rgba = (GLfloat *) span.array->attribs[VARYING_SLOT_COL0];
void *tempImage = NULL;
 
/* We have to deal with GL_COLOR_INDEX manually because
* _mesa_format_convert does not handle this format. So what we do here is
* convert it to RGBA ubyte first and then convert from that to dst as
* usual.
*/
if (format == GL_COLOR_INDEX) {
/* This will handle byte swapping and transferops if needed */
tempImage =
_mesa_unpack_color_index_to_rgba_ubyte(ctx, 2,
pixels, format, type,
width, height, 1,
unpack,
transferOps);
if (!tempImage) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
return;
}
 
transferOps = 0;
pixels = tempImage;
format = GL_RGBA;
type = GL_UNSIGNED_BYTE;
} else if (unpack->SwapBytes) {
/* We have to handle byte-swapping scenarios before calling
* _mesa_format_convert
*/
GLint swapSize = _mesa_sizeof_packed_type(type);
if (swapSize == 2 || swapSize == 4) {
int components = _mesa_components_in_format(format);
int elementCount = width * height * components;
tempImage = malloc(elementCount * swapSize);
if (!tempImage) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
return;
}
if (swapSize == 2)
_mesa_swap2_copy(tempImage, (GLushort *) pixels, elementCount);
else
_mesa_swap4_copy(tempImage, (GLuint *) pixels, elementCount);
pixels = tempImage;
}
}
 
const GLint srcStride
= _mesa_image_row_stride(unpack, width, format, type);
 
/* if the span is wider than SWRAST_MAX_WIDTH we have to do it in chunks */
while (skipPixels < width) {
const GLint spanWidth = MIN2(width - skipPixels, SWRAST_MAX_WIDTH);
const GLubyte *source
= (const GLubyte *) _mesa_image_address2d(unpack, pixels,
width, height, format,
type, 0, skipPixels);
GLint row;
 
/* get image row as float/RGBA */
uint32_t srcMesaFormat = _mesa_format_from_format_and_type(format, type);
for (row = 0; row < height; row++) {
int dstRowStride = 4 * width * sizeof(float);
_mesa_format_convert(rgba, RGBA32_FLOAT, dstRowStride,
(void*)source, srcMesaFormat, srcStride,
spanWidth, 1, NULL);
if (transferOps)
_mesa_apply_rgba_transfer_ops(ctx, transferOps, spanWidth, (GLfloat (*)[4])rgba);
/* Set these for each row since the _swrast_write_* functions
* may change them while clipping/rendering.
*/
span.array->ChanType = GL_FLOAT;
span.x = x + skipPixels;
span.y = y + row;
span.end = spanWidth;
span.arrayMask = arrayMask;
span.interpMask = interpMask;
if (zoom) {
_swrast_write_zoomed_rgba_span(ctx, imgX, imgY, &span, rgba);
}
else {
_swrast_write_rgba_span(ctx, &span);
}
 
source += srcStride;
} /* for row */
 
skipPixels += spanWidth;
} /* while skipPixels < width */
 
/* XXX this is ugly/temporary, to undo above change */
span.array->ChanType = CHAN_TYPE;
 
free(tempImage);
}
 
swrast_render_finish(ctx);
}
 
 
/**
* Draw depth+stencil values into a MESA_FORAMT_Z24_S8 or MESA_FORMAT_Z24_UNORM_S8_UINT
* renderbuffer. No masking, zooming, scaling, etc.
*/
static void
fast_draw_depth_stencil(struct gl_context *ctx, GLint x, GLint y,
GLsizei width, GLsizei height,
const struct gl_pixelstore_attrib *unpack,
const GLvoid *pixels)
{
const GLenum format = GL_DEPTH_STENCIL_EXT;
const GLenum type = GL_UNSIGNED_INT_24_8;
struct gl_renderbuffer *rb =
ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
GLubyte *src, *dst;
GLint srcRowStride, dstRowStride;
GLint i;
 
src = _mesa_image_address2d(unpack, pixels, width, height,
format, type, 0, 0);
srcRowStride = _mesa_image_row_stride(unpack, width, format, type);
 
dst = _swrast_pixel_address(rb, x, y);
dstRowStride = srb->RowStride;
 
for (i = 0; i < height; i++) {
_mesa_pack_uint_24_8_depth_stencil_row(rb->Format, width,
(const GLuint *) src, dst);
dst += dstRowStride;
src += srcRowStride;
}
}
 
 
 
/**
* This is a bit different from drawing GL_DEPTH_COMPONENT pixels.
* The only per-pixel operations that apply are depth scale/bias,
* stencil offset/shift, GL_DEPTH_WRITEMASK and GL_STENCIL_WRITEMASK,
* and pixel zoom.
* Also, only the depth buffer and stencil buffers are touched, not the
* color buffer(s).
*/
static void
draw_depth_stencil_pixels(struct gl_context *ctx, GLint x, GLint y,
GLsizei width, GLsizei height, GLenum type,
const struct gl_pixelstore_attrib *unpack,
const GLvoid *pixels)
{
const GLint imgX = x, imgY = y;
const GLboolean scaleOrBias
= ctx->Pixel.DepthScale != 1.0 || ctx->Pixel.DepthBias != 0.0;
const GLuint stencilMask = ctx->Stencil.WriteMask[0];
const GLenum stencilType = GL_UNSIGNED_BYTE;
const GLboolean zoom = ctx->Pixel.ZoomX != 1.0 || ctx->Pixel.ZoomY != 1.0;
struct gl_renderbuffer *depthRb, *stencilRb;
struct gl_pixelstore_attrib clippedUnpack = *unpack;
 
if (!zoom) {
if (!_mesa_clip_drawpixels(ctx, &x, &y, &width, &height,
&clippedUnpack)) {
/* totally clipped */
return;
}
}
depthRb = ctx->ReadBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
stencilRb = ctx->ReadBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
assert(depthRb);
assert(stencilRb);
 
if (depthRb == stencilRb &&
(depthRb->Format == MESA_FORMAT_S8_UINT_Z24_UNORM ||
depthRb->Format == MESA_FORMAT_Z24_UNORM_S8_UINT) &&
type == GL_UNSIGNED_INT_24_8 &&
!scaleOrBias &&
!zoom &&
ctx->Depth.Mask &&
(stencilMask & 0xff) == 0xff) {
fast_draw_depth_stencil(ctx, x, y, width, height,
&clippedUnpack, pixels);
}
else {
/* sub-optimal cases:
* Separate depth/stencil buffers, or pixel transfer ops required.
*/
/* XXX need to handle very wide images (skippixels) */
GLuint *zValues; /* 32-bit Z values */
GLint i;
 
zValues = malloc(width * sizeof(GLuint));
if (!zValues) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glDrawPixels");
return;
}
 
for (i = 0; i < height; i++) {
const GLuint *depthStencilSrc = (const GLuint *)
_mesa_image_address2d(&clippedUnpack, pixels, width, height,
GL_DEPTH_STENCIL_EXT, type, i, 0);
 
if (ctx->Depth.Mask) {
_mesa_unpack_depth_span(ctx, width,
GL_UNSIGNED_INT, /* dest type */
zValues, /* dest addr */
0xffffffff, /* depth max */
type, /* src type */
depthStencilSrc, /* src addr */
&clippedUnpack);
if (zoom) {
_swrast_write_zoomed_z_span(ctx, imgX, imgY, width, x,
y + i, zValues);
}
else {
GLubyte *dst = _swrast_pixel_address(depthRb, x, y + i);
_mesa_pack_uint_z_row(depthRb->Format, width, zValues, dst);
}
}
 
if (stencilMask != 0x0) {
GLubyte *stencilValues = (GLubyte *) zValues; /* re-use buffer */
/* get stencil values, with shift/offset/mapping */
_mesa_unpack_stencil_span(ctx, width, stencilType, stencilValues,
type, depthStencilSrc, &clippedUnpack,
ctx->_ImageTransferState);
if (zoom)
_swrast_write_zoomed_stencil_span(ctx, imgX, imgY, width,
x, y + i, stencilValues);
else
_swrast_write_stencil_span(ctx, width, x, y + i, stencilValues);
}
}
 
free(zValues);
}
}
 
 
/**
* Execute software-based glDrawPixels.
* By time we get here, all error checking will have been done.
*/
void
_swrast_DrawPixels( struct gl_context *ctx,
GLint x, GLint y,
GLsizei width, GLsizei height,
GLenum format, GLenum type,
const struct gl_pixelstore_attrib *unpack,
const GLvoid *pixels )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
GLboolean save_vp_override = ctx->VertexProgram._Overriden;
 
if (!_mesa_check_conditional_render(ctx))
return; /* don't draw */
 
/* We are creating fragments directly, without going through vertex
* programs.
*
* This override flag tells the fragment processing code that its input
* comes from a non-standard source, and it may therefore not rely on
* optimizations that assume e.g. constant color if there is no color
* vertex array.
*/
_mesa_set_vp_override(ctx, GL_TRUE);
 
if (ctx->NewState)
_mesa_update_state(ctx);
 
if (swrast->NewState)
_swrast_validate_derived( ctx );
 
pixels = _mesa_map_pbo_source(ctx, unpack, pixels);
if (!pixels) {
_mesa_set_vp_override(ctx, save_vp_override);
return;
}
 
/*
* By time we get here, all error checking should have been done.
*/
switch (format) {
case GL_STENCIL_INDEX:
swrast_render_start(ctx);
draw_stencil_pixels( ctx, x, y, width, height, type, unpack, pixels );
swrast_render_finish(ctx);
break;
case GL_DEPTH_COMPONENT:
swrast_render_start(ctx);
draw_depth_pixels( ctx, x, y, width, height, type, unpack, pixels );
swrast_render_finish(ctx);
break;
case GL_DEPTH_STENCIL_EXT:
swrast_render_start(ctx);
draw_depth_stencil_pixels(ctx, x, y, width, height, type, unpack, pixels);
swrast_render_finish(ctx);
break;
default:
/* all other formats should be color formats */
draw_rgba_pixels(ctx, x, y, width, height, format, type, unpack, pixels);
}
 
_mesa_set_vp_override(ctx, save_vp_override);
 
_mesa_unmap_pbo_source(ctx, unpack);
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_feedback.c
0,0 → 1,137
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
#include "main/glheader.h"
#include "main/feedback.h"
#include "main/macros.h"
 
#include "s_context.h"
#include "s_feedback.h"
#include "s_triangle.h"
 
 
 
static void
feedback_vertex(struct gl_context * ctx, const SWvertex * v, const SWvertex * pv)
{
GLfloat win[4];
const GLfloat *vtc = v->attrib[VARYING_SLOT_TEX0];
const GLfloat *color = v->attrib[VARYING_SLOT_COL0];
 
win[0] = v->attrib[VARYING_SLOT_POS][0];
win[1] = v->attrib[VARYING_SLOT_POS][1];
win[2] = v->attrib[VARYING_SLOT_POS][2] / ctx->DrawBuffer->_DepthMaxF;
win[3] = 1.0F / v->attrib[VARYING_SLOT_POS][3];
 
_mesa_feedback_vertex(ctx, win, color, vtc);
}
 
 
/*
* Put triangle in feedback buffer.
*/
void
_swrast_feedback_triangle(struct gl_context *ctx, const SWvertex *v0,
const SWvertex *v1, const SWvertex *v2)
{
if (!_swrast_culltriangle(ctx, v0, v1, v2)) {
_mesa_feedback_token(ctx, (GLfloat) (GLint) GL_POLYGON_TOKEN);
_mesa_feedback_token(ctx, (GLfloat) 3); /* three vertices */
 
if (ctx->Light.ShadeModel == GL_SMOOTH) {
feedback_vertex(ctx, v0, v0);
feedback_vertex(ctx, v1, v1);
feedback_vertex(ctx, v2, v2);
}
else {
feedback_vertex(ctx, v0, v2);
feedback_vertex(ctx, v1, v2);
feedback_vertex(ctx, v2, v2);
}
}
}
 
 
void
_swrast_feedback_line(struct gl_context *ctx, const SWvertex *v0,
const SWvertex *v1)
{
GLenum token = GL_LINE_TOKEN;
SWcontext *swrast = SWRAST_CONTEXT(ctx);
 
if (swrast->StippleCounter == 0)
token = GL_LINE_RESET_TOKEN;
 
_mesa_feedback_token(ctx, (GLfloat) (GLint) token);
 
if (ctx->Light.ShadeModel == GL_SMOOTH) {
feedback_vertex(ctx, v0, v0);
feedback_vertex(ctx, v1, v1);
}
else {
feedback_vertex(ctx, v0, v1);
feedback_vertex(ctx, v1, v1);
}
 
swrast->StippleCounter++;
}
 
 
void
_swrast_feedback_point(struct gl_context *ctx, const SWvertex *v)
{
_mesa_feedback_token(ctx, (GLfloat) (GLint) GL_POINT_TOKEN);
feedback_vertex(ctx, v, v);
}
 
 
void
_swrast_select_triangle(struct gl_context *ctx, const SWvertex *v0,
const SWvertex *v1, const SWvertex *v2)
{
if (!_swrast_culltriangle(ctx, v0, v1, v2)) {
const GLfloat zs = 1.0F / ctx->DrawBuffer->_DepthMaxF;
 
_mesa_update_hitflag( ctx, v0->attrib[VARYING_SLOT_POS][2] * zs );
_mesa_update_hitflag( ctx, v1->attrib[VARYING_SLOT_POS][2] * zs );
_mesa_update_hitflag( ctx, v2->attrib[VARYING_SLOT_POS][2] * zs );
}
}
 
 
void
_swrast_select_line(struct gl_context *ctx, const SWvertex *v0, const SWvertex *v1)
{
const GLfloat zs = 1.0F / ctx->DrawBuffer->_DepthMaxF;
_mesa_update_hitflag( ctx, v0->attrib[VARYING_SLOT_POS][2] * zs );
_mesa_update_hitflag( ctx, v1->attrib[VARYING_SLOT_POS][2] * zs );
}
 
 
void
_swrast_select_point(struct gl_context *ctx, const SWvertex *v)
{
const GLfloat zs = 1.0F / ctx->DrawBuffer->_DepthMaxF;
_mesa_update_hitflag( ctx, v->attrib[VARYING_SLOT_POS][2] * zs );
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_feedback.h
0,0 → 1,50
 
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_FEEDBACK_H
#define S_FEEDBACK_H
 
 
#include "swrast.h"
 
 
extern void _swrast_feedback_point( struct gl_context *ctx, const SWvertex *v );
 
extern void _swrast_feedback_line( struct gl_context *ctx,
const SWvertex *v1, const SWvertex *v2 );
 
extern void _swrast_feedback_triangle( struct gl_context *ctx, const SWvertex *v0,
const SWvertex *v1, const SWvertex *v2 );
 
extern void _swrast_select_point( struct gl_context *ctx, const SWvertex *v );
 
extern void _swrast_select_line( struct gl_context *ctx,
const SWvertex *v1, const SWvertex *v2 );
 
extern void _swrast_select_triangle( struct gl_context *ctx, const SWvertex *v0,
const SWvertex *v1, const SWvertex *v2 );
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_fog.c
0,0 → 1,244
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#include "c99_math.h"
#include "main/glheader.h"
#include "main/macros.h"
 
#include "s_context.h"
#include "s_fog.h"
 
 
/**
* Used to convert current raster distance to a fog factor in [0,1].
*/
GLfloat
_swrast_z_to_fogfactor(struct gl_context *ctx, GLfloat z)
{
GLfloat d, f;
 
switch (ctx->Fog.Mode) {
case GL_LINEAR:
if (ctx->Fog.Start == ctx->Fog.End)
d = 1.0F;
else
d = 1.0F / (ctx->Fog.End - ctx->Fog.Start);
f = (ctx->Fog.End - z) * d;
return CLAMP(f, 0.0F, 1.0F);
case GL_EXP:
d = ctx->Fog.Density;
f = expf(-d * z);
f = CLAMP(f, 0.0F, 1.0F);
return f;
case GL_EXP2:
d = ctx->Fog.Density;
f = expf(-(d * d * z * z));
f = CLAMP(f, 0.0F, 1.0F);
return f;
default:
_mesa_problem(ctx, "Bad fog mode in _swrast_z_to_fogfactor");
return 0.0;
}
}
 
 
#define LINEAR_FOG(f, coord) f = (fogEnd - coord) * fogScale
 
#define EXP_FOG(f, coord) f = expf(density * coord)
 
#define EXP2_FOG(f, coord) \
do { \
GLfloat tmp = negDensitySquared * coord * coord; \
if (tmp < FLT_MIN_10_EXP) \
tmp = FLT_MIN_10_EXP; \
f = expf(tmp); \
} while(0)
 
 
#define BLEND_FOG(f, coord) f = coord
 
 
 
/**
* Template code for computing fog blend factor and applying it to colors.
* \param TYPE either GLubyte, GLushort or GLfloat.
* \param COMPUTE_F code to compute the fog blend factor, f.
*/
#define FOG_LOOP(TYPE, FOG_FUNC) \
if (span->arrayAttribs & VARYING_BIT_FOGC) { \
GLuint i; \
for (i = 0; i < span->end; i++) { \
const GLfloat fogCoord = span->array->attribs[VARYING_SLOT_FOGC][i][0]; \
const GLfloat c = fabsf(fogCoord); \
GLfloat f, oneMinusF; \
FOG_FUNC(f, c); \
f = CLAMP(f, 0.0F, 1.0F); \
oneMinusF = 1.0F - f; \
rgba[i][RCOMP] = (TYPE) (f * rgba[i][RCOMP] + oneMinusF * rFog); \
rgba[i][GCOMP] = (TYPE) (f * rgba[i][GCOMP] + oneMinusF * gFog); \
rgba[i][BCOMP] = (TYPE) (f * rgba[i][BCOMP] + oneMinusF * bFog); \
} \
} \
else { \
const GLfloat fogStep = span->attrStepX[VARYING_SLOT_FOGC][0]; \
GLfloat fogCoord = span->attrStart[VARYING_SLOT_FOGC][0]; \
const GLfloat wStep = span->attrStepX[VARYING_SLOT_POS][3]; \
GLfloat w = span->attrStart[VARYING_SLOT_POS][3]; \
GLuint i; \
for (i = 0; i < span->end; i++) { \
const GLfloat c = fabsf(fogCoord) / w; \
GLfloat f, oneMinusF; \
FOG_FUNC(f, c); \
f = CLAMP(f, 0.0F, 1.0F); \
oneMinusF = 1.0F - f; \
rgba[i][RCOMP] = (TYPE) (f * rgba[i][RCOMP] + oneMinusF * rFog); \
rgba[i][GCOMP] = (TYPE) (f * rgba[i][GCOMP] + oneMinusF * gFog); \
rgba[i][BCOMP] = (TYPE) (f * rgba[i][BCOMP] + oneMinusF * bFog); \
fogCoord += fogStep; \
w += wStep; \
} \
}
 
/**
* Apply fog to a span of RGBA pixels.
* The fog value are either in the span->array->fog array or interpolated from
* the fog/fogStep values.
* They fog values are either fog coordinates (Z) or fog blend factors.
* _PreferPixelFog should be in sync with that state!
*/
void
_swrast_fog_rgba_span( const struct gl_context *ctx, SWspan *span )
{
const SWcontext *swrast = CONST_SWRAST_CONTEXT(ctx);
GLfloat rFog, gFog, bFog;
 
assert(swrast->_FogEnabled);
assert(span->arrayMask & SPAN_RGBA);
 
/* compute (scaled) fog color */
if (span->array->ChanType == GL_UNSIGNED_BYTE) {
rFog = ctx->Fog.Color[RCOMP] * 255.0F;
gFog = ctx->Fog.Color[GCOMP] * 255.0F;
bFog = ctx->Fog.Color[BCOMP] * 255.0F;
}
else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
rFog = ctx->Fog.Color[RCOMP] * 65535.0F;
gFog = ctx->Fog.Color[GCOMP] * 65535.0F;
bFog = ctx->Fog.Color[BCOMP] * 65535.0F;
}
else {
rFog = ctx->Fog.Color[RCOMP];
gFog = ctx->Fog.Color[GCOMP];
bFog = ctx->Fog.Color[BCOMP];
}
 
if (swrast->_PreferPixelFog) {
/* The span's fog values are fog coordinates, now compute blend factors
* and blend the fragment colors with the fog color.
*/
switch (ctx->Fog.Mode) {
case GL_LINEAR:
{
const GLfloat fogEnd = ctx->Fog.End;
const GLfloat fogScale = (ctx->Fog.Start == ctx->Fog.End)
? 1.0F : 1.0F / (ctx->Fog.End - ctx->Fog.Start);
if (span->array->ChanType == GL_UNSIGNED_BYTE) {
GLubyte (*rgba)[4] = span->array->rgba8;
FOG_LOOP(GLubyte, LINEAR_FOG);
}
else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
GLushort (*rgba)[4] = span->array->rgba16;
FOG_LOOP(GLushort, LINEAR_FOG);
}
else {
GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0];
assert(span->array->ChanType == GL_FLOAT);
FOG_LOOP(GLfloat, LINEAR_FOG);
}
}
break;
 
case GL_EXP:
{
const GLfloat density = -ctx->Fog.Density;
if (span->array->ChanType == GL_UNSIGNED_BYTE) {
GLubyte (*rgba)[4] = span->array->rgba8;
FOG_LOOP(GLubyte, EXP_FOG);
}
else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
GLushort (*rgba)[4] = span->array->rgba16;
FOG_LOOP(GLushort, EXP_FOG);
}
else {
GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0];
assert(span->array->ChanType == GL_FLOAT);
FOG_LOOP(GLfloat, EXP_FOG);
}
}
break;
 
case GL_EXP2:
{
const GLfloat negDensitySquared = -ctx->Fog.Density * ctx->Fog.Density;
if (span->array->ChanType == GL_UNSIGNED_BYTE) {
GLubyte (*rgba)[4] = span->array->rgba8;
FOG_LOOP(GLubyte, EXP2_FOG);
}
else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
GLushort (*rgba)[4] = span->array->rgba16;
FOG_LOOP(GLushort, EXP2_FOG);
}
else {
GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0];
assert(span->array->ChanType == GL_FLOAT);
FOG_LOOP(GLfloat, EXP2_FOG);
}
}
break;
 
default:
_mesa_problem(ctx, "Bad fog mode in _swrast_fog_rgba_span");
return;
}
}
else {
/* The span's fog start/step/array values are blend factors in [0,1].
* They were previously computed per-vertex.
*/
if (span->array->ChanType == GL_UNSIGNED_BYTE) {
GLubyte (*rgba)[4] = span->array->rgba8;
FOG_LOOP(GLubyte, BLEND_FOG);
}
else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
GLushort (*rgba)[4] = span->array->rgba16;
FOG_LOOP(GLushort, BLEND_FOG);
}
else {
GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0];
assert(span->array->ChanType == GL_FLOAT);
FOG_LOOP(GLfloat, BLEND_FOG);
}
}
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_fog.h
0,0 → 1,42
 
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2002 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_FOG_H
#define S_FOG_H
 
 
#include "main/glheader.h"
#include "s_span.h"
 
struct gl_context;
 
extern GLfloat
_swrast_z_to_fogfactor(struct gl_context *ctx, GLfloat z);
 
extern void
_swrast_fog_rgba_span( const struct gl_context *ctx, SWspan *span );
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_fragprog.c
0,0 → 1,291
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
#include "main/glheader.h"
#include "main/macros.h"
#include "main/samplerobj.h"
#include "main/teximage.h"
#include "program/prog_instruction.h"
 
#include "s_context.h"
#include "s_fragprog.h"
#include "s_span.h"
 
/**
* \brief Should swrast use a fragment program?
*
* \return true if the current fragment program exists and is not the fixed
* function fragment program
*/
GLboolean
_swrast_use_fragment_program(struct gl_context *ctx)
{
struct gl_fragment_program *fp = ctx->FragmentProgram._Current;
return fp && !(fp == ctx->FragmentProgram._TexEnvProgram
&& fp->Base.NumInstructions == 0);
}
 
/**
* Apply texture object's swizzle (X/Y/Z/W/0/1) to incoming 'texel'
* and return results in 'colorOut'.
*/
static inline void
swizzle_texel(const GLfloat texel[4], GLfloat colorOut[4], GLuint swizzle)
{
if (swizzle == SWIZZLE_NOOP) {
COPY_4V(colorOut, texel);
}
else {
GLfloat vector[6];
vector[SWIZZLE_X] = texel[0];
vector[SWIZZLE_Y] = texel[1];
vector[SWIZZLE_Z] = texel[2];
vector[SWIZZLE_W] = texel[3];
vector[SWIZZLE_ZERO] = 0.0F;
vector[SWIZZLE_ONE] = 1.0F;
colorOut[0] = vector[GET_SWZ(swizzle, 0)];
colorOut[1] = vector[GET_SWZ(swizzle, 1)];
colorOut[2] = vector[GET_SWZ(swizzle, 2)];
colorOut[3] = vector[GET_SWZ(swizzle, 3)];
}
}
 
 
/**
* Fetch a texel with given lod.
* Called via machine->FetchTexelLod()
*/
static void
fetch_texel_lod( struct gl_context *ctx, const GLfloat texcoord[4], GLfloat lambda,
GLuint unit, GLfloat color[4] )
{
const struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
 
if (texObj) {
SWcontext *swrast = SWRAST_CONTEXT(ctx);
GLfloat rgba[4];
const struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, unit);
 
lambda = CLAMP(lambda, samp->MinLod, samp->MaxLod);
 
swrast->TextureSample[unit](ctx, samp, ctx->Texture.Unit[unit]._Current,
1, (const GLfloat (*)[4]) texcoord,
&lambda, &rgba);
swizzle_texel(rgba, color, texObj->_Swizzle);
}
else {
ASSIGN_4V(color, 0.0F, 0.0F, 0.0F, 1.0F);
}
}
 
 
/**
* Fetch a texel with the given partial derivatives to compute a level
* of detail in the mipmap.
* Called via machine->FetchTexelDeriv()
* \param lodBias the lod bias which may be specified by a TXB instruction,
* otherwise zero.
*/
static void
fetch_texel_deriv( struct gl_context *ctx, const GLfloat texcoord[4],
const GLfloat texdx[4], const GLfloat texdy[4],
GLfloat lodBias, GLuint unit, GLfloat color[4] )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
const struct gl_texture_object *texObj = texUnit->_Current;
 
if (texObj) {
const struct gl_texture_image *texImg = _mesa_base_tex_image(texObj);
const struct swrast_texture_image *swImg =
swrast_texture_image_const(texImg);
const struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, unit);
const GLfloat texW = (GLfloat) swImg->WidthScale;
const GLfloat texH = (GLfloat) swImg->HeightScale;
GLfloat lambda;
GLfloat rgba[4];
 
lambda = _swrast_compute_lambda(texdx[0], texdy[0], /* ds/dx, ds/dy */
texdx[1], texdy[1], /* dt/dx, dt/dy */
texdx[3], texdy[3], /* dq/dx, dq/dy */
texW, texH,
texcoord[0], texcoord[1], texcoord[3],
1.0F / texcoord[3]);
 
lambda += lodBias + texUnit->LodBias + samp->LodBias;
 
lambda = CLAMP(lambda, samp->MinLod, samp->MaxLod);
 
swrast->TextureSample[unit](ctx, samp, ctx->Texture.Unit[unit]._Current,
1, (const GLfloat (*)[4]) texcoord,
&lambda, &rgba);
swizzle_texel(rgba, color, texObj->_Swizzle);
}
else {
ASSIGN_4V(color, 0.0F, 0.0F, 0.0F, 1.0F);
}
}
 
 
/**
* Initialize the virtual fragment program machine state prior to running
* fragment program on a fragment. This involves initializing the input
* registers, condition codes, etc.
* \param machine the virtual machine state to init
* \param program the fragment program we're about to run
* \param span the span of pixels we'll operate on
* \param col which element (column) of the span we'll operate on
*/
static void
init_machine(struct gl_context *ctx, struct gl_program_machine *machine,
const struct gl_fragment_program *program,
const SWspan *span, GLuint col)
{
GLfloat *wpos = span->array->attribs[VARYING_SLOT_POS][col];
 
/* ARB_fragment_coord_conventions */
if (program->OriginUpperLeft)
wpos[1] = ctx->DrawBuffer->Height - 1 - wpos[1];
if (!program->PixelCenterInteger) {
wpos[0] += 0.5F;
wpos[1] += 0.5F;
}
 
/* Setup pointer to input attributes */
machine->Attribs = span->array->attribs;
 
machine->DerivX = (GLfloat (*)[4]) span->attrStepX;
machine->DerivY = (GLfloat (*)[4]) span->attrStepY;
machine->NumDeriv = VARYING_SLOT_MAX;
 
machine->Samplers = program->Base.SamplerUnits;
 
/* if running a GLSL program (not ARB_fragment_program) */
if (ctx->_Shader->CurrentProgram[MESA_SHADER_FRAGMENT]) {
/* Store front/back facing value */
machine->Attribs[VARYING_SLOT_FACE][col][0] = 1.0F - span->facing;
}
 
machine->CurElement = col;
 
/* init condition codes */
machine->CondCodes[0] = COND_EQ;
machine->CondCodes[1] = COND_EQ;
machine->CondCodes[2] = COND_EQ;
machine->CondCodes[3] = COND_EQ;
 
/* init call stack */
machine->StackDepth = 0;
 
machine->FetchTexelLod = fetch_texel_lod;
machine->FetchTexelDeriv = fetch_texel_deriv;
}
 
 
/**
* Run fragment program on the pixels in span from 'start' to 'end' - 1.
*/
static void
run_program(struct gl_context *ctx, SWspan *span, GLuint start, GLuint end)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
const struct gl_fragment_program *program = ctx->FragmentProgram._Current;
const GLbitfield64 outputsWritten = program->Base.OutputsWritten;
struct gl_program_machine *machine = &swrast->FragProgMachine;
GLuint i;
 
for (i = start; i < end; i++) {
if (span->array->mask[i]) {
init_machine(ctx, machine, program, span, i);
 
if (_mesa_execute_program(ctx, &program->Base, machine)) {
 
/* Store result color */
if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) {
COPY_4V(span->array->attribs[VARYING_SLOT_COL0][i],
machine->Outputs[FRAG_RESULT_COLOR]);
}
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 buf;
for (buf = 0; buf < ctx->DrawBuffer->_NumColorDrawBuffers; buf++) {
if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DATA0 + buf)) {
COPY_4V(span->array->attribs[VARYING_SLOT_COL0 + buf][i],
machine->Outputs[FRAG_RESULT_DATA0 + buf]);
}
}
}
 
/* Store result depth/z */
if (outputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) {
const GLfloat depth = machine->Outputs[FRAG_RESULT_DEPTH][2];
if (depth <= 0.0)
span->array->z[i] = 0;
else if (depth >= 1.0)
span->array->z[i] = ctx->DrawBuffer->_DepthMax;
else
span->array->z[i] =
(GLuint) (depth * ctx->DrawBuffer->_DepthMaxF + 0.5F);
}
}
else {
/* killed fragment */
span->array->mask[i] = GL_FALSE;
span->writeAll = GL_FALSE;
}
}
}
}
 
 
/**
* Execute the current fragment program for all the fragments
* in the given span.
*/
void
_swrast_exec_fragment_program( struct gl_context *ctx, SWspan *span )
{
const struct gl_fragment_program *program = ctx->FragmentProgram._Current;
 
/* incoming colors should be floats */
if (program->Base.InputsRead & VARYING_BIT_COL0) {
assert(span->array->ChanType == GL_FLOAT);
}
 
run_program(ctx, span, 0, span->end);
 
if (program->Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_COLOR)) {
span->interpMask &= ~SPAN_RGBA;
span->arrayMask |= SPAN_RGBA;
}
 
if (program->Base.OutputsWritten & BITFIELD64_BIT(FRAG_RESULT_DEPTH)) {
span->interpMask &= ~SPAN_Z;
span->arrayMask |= SPAN_Z;
}
}
 
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_fragprog.h
0,0 → 1,42
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_FRAGPROG_H
#define S_FRAGPROG_H
 
 
#include "s_span.h"
 
struct gl_context;
 
GLboolean
_swrast_use_fragment_program(struct gl_context *ctx);
 
extern void
_swrast_exec_fragment_program(struct gl_context *ctx, SWspan *span);
 
 
#endif /* S_FRAGPROG_H */
 
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_lines.c
0,0 → 1,267
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#include "main/glheader.h"
#include "main/context.h"
#include "main/macros.h"
#include "s_aaline.h"
#include "s_context.h"
#include "s_feedback.h"
#include "s_lines.h"
#include "s_span.h"
 
 
/*
* Init the mask[] array to implement a line stipple.
*/
static void
compute_stipple_mask( struct gl_context *ctx, GLuint len, GLubyte mask[] )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
GLuint i;
 
for (i = 0; i < len; i++) {
GLuint bit = (swrast->StippleCounter / ctx->Line.StippleFactor) & 0xf;
if ((1 << bit) & ctx->Line.StipplePattern) {
mask[i] = GL_TRUE;
}
else {
mask[i] = GL_FALSE;
}
swrast->StippleCounter++;
}
}
 
 
/*
* To draw a wide line we can simply redraw the span N times, side by side.
*/
static void
draw_wide_line( struct gl_context *ctx, SWspan *span, GLboolean xMajor )
{
const GLint width = (GLint) CLAMP(ctx->Line.Width,
ctx->Const.MinLineWidth,
ctx->Const.MaxLineWidth);
GLint start;
 
assert(span->end < SWRAST_MAX_WIDTH);
 
if (width & 1)
start = width / 2;
else
start = width / 2 - 1;
 
if (xMajor) {
GLint *y = span->array->y;
GLuint i;
GLint w;
for (w = 0; w < width; w++) {
if (w == 0) {
for (i = 0; i < span->end; i++)
y[i] -= start;
}
else {
for (i = 0; i < span->end; i++)
y[i]++;
}
_swrast_write_rgba_span(ctx, span);
}
}
else {
GLint *x = span->array->x;
GLuint i;
GLint w;
for (w = 0; w < width; w++) {
if (w == 0) {
for (i = 0; i < span->end; i++)
x[i] -= start;
}
else {
for (i = 0; i < span->end; i++)
x[i]++;
}
_swrast_write_rgba_span(ctx, span);
}
}
}
 
 
 
/**********************************************************************/
/***** Rasterization *****/
/**********************************************************************/
 
/* Simple RGBA index line (no stipple, width=1, no Z, no fog, no tex)*/
#define NAME simple_no_z_rgba_line
#define INTERP_RGBA
#define RENDER_SPAN(span) _swrast_write_rgba_span(ctx, &span);
#include "s_linetemp.h"
 
 
/* Z, fog, wide, stipple RGBA line */
#define NAME rgba_line
#define INTERP_RGBA
#define INTERP_Z
#define RENDER_SPAN(span) \
if (ctx->Line.StippleFlag) { \
span.arrayMask |= SPAN_MASK; \
compute_stipple_mask(ctx, span.end, span.array->mask); \
} \
if (ctx->Line.Width > 1.0) { \
draw_wide_line(ctx, &span, (GLboolean)(dx > dy)); \
} \
else { \
_swrast_write_rgba_span(ctx, &span); \
}
#include "s_linetemp.h"
 
 
/* General-purpose line (any/all features). */
#define NAME general_line
#define INTERP_RGBA
#define INTERP_Z
#define INTERP_ATTRIBS
#define RENDER_SPAN(span) \
if (ctx->Line.StippleFlag) { \
span.arrayMask |= SPAN_MASK; \
compute_stipple_mask(ctx, span.end, span.array->mask); \
} \
if (ctx->Line.Width > 1.0) { \
draw_wide_line(ctx, &span, (GLboolean)(dx > dy)); \
} \
else { \
_swrast_write_rgba_span(ctx, &span); \
}
#include "s_linetemp.h"
 
 
 
void
_swrast_add_spec_terms_line(struct gl_context *ctx,
const SWvertex *v0, const SWvertex *v1)
{
SWvertex *ncv0 = (SWvertex *)v0;
SWvertex *ncv1 = (SWvertex *)v1;
GLfloat rSum, gSum, bSum;
GLchan cSave[2][4];
 
/* save original colors */
COPY_CHAN4(cSave[0], ncv0->color);
COPY_CHAN4(cSave[1], ncv1->color);
/* sum v0 */
rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[VARYING_SLOT_COL1][0];
gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[VARYING_SLOT_COL1][1];
bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[VARYING_SLOT_COL1][2];
UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum);
UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum);
UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum);
/* sum v1 */
rSum = CHAN_TO_FLOAT(ncv1->color[0]) + ncv1->attrib[VARYING_SLOT_COL1][0];
gSum = CHAN_TO_FLOAT(ncv1->color[1]) + ncv1->attrib[VARYING_SLOT_COL1][1];
bSum = CHAN_TO_FLOAT(ncv1->color[2]) + ncv1->attrib[VARYING_SLOT_COL1][2];
UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[0], rSum);
UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[1], gSum);
UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[2], bSum);
/* draw */
SWRAST_CONTEXT(ctx)->SpecLine( ctx, ncv0, ncv1 );
/* restore original colors */
COPY_CHAN4(ncv0->color, cSave[0]);
COPY_CHAN4(ncv1->color, cSave[1]);
}
 
 
 
#ifdef DEBUG
 
/* record the current line function name */
static const char *lineFuncName = NULL;
 
#define USE(lineFunc) \
do { \
lineFuncName = #lineFunc; \
/*printf("%s\n", lineFuncName);*/ \
swrast->Line = lineFunc; \
} while (0)
 
#else
 
#define USE(lineFunc) swrast->Line = lineFunc
 
#endif
 
 
 
/**
* Determine which line drawing function to use given the current
* rendering context.
*
* Please update the summary flag _SWRAST_NEW_LINE if you add or remove
* tests to this code.
*/
void
_swrast_choose_line( struct gl_context *ctx )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
GLboolean specular = (ctx->Fog.ColorSumEnabled ||
(ctx->Light.Enabled &&
ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR));
 
if (ctx->RenderMode == GL_RENDER) {
if (ctx->Line.SmoothFlag) {
/* antialiased lines */
_swrast_choose_aa_line_function(ctx);
assert(swrast->Line);
}
else if (ctx->Texture._EnabledCoordUnits
|| _swrast_use_fragment_program(ctx)
|| swrast->_FogEnabled
|| specular) {
USE(general_line);
}
else if (ctx->Depth.Test
|| ctx->Line.Width != 1.0
|| ctx->Line.StippleFlag) {
/* no texture, but Z, fog, width>1, stipple, etc. */
#if CHAN_BITS == 32
USE(general_line);
#else
USE(rgba_line);
#endif
}
else {
assert(!ctx->Depth.Test);
assert(ctx->Line.Width == 1.0);
/* simple lines */
USE(simple_no_z_rgba_line);
}
}
else if (ctx->RenderMode == GL_FEEDBACK) {
USE(_swrast_feedback_line);
}
else {
assert(ctx->RenderMode == GL_SELECT);
USE(_swrast_select_line);
}
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_lines.h
0,0 → 1,41
 
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_LINES_H
#define S_LINES_H
 
#include "swrast.h"
 
void
_swrast_choose_line( struct gl_context *ctx );
 
void
_swrast_add_spec_terms_line( struct gl_context *ctx,
const SWvertex *v0,
const SWvertex *v1 );
 
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_linetemp.h
0,0 → 1,402
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
/*
* Line Rasterizer Template
*
* This file is #include'd to generate custom line rasterizers.
*
* The following macros may be defined to indicate what auxillary information
* must be interplated along the line:
* INTERP_Z - if defined, interpolate Z values
* INTERP_ATTRIBS - if defined, interpolate attribs (texcoords, varying, etc)
*
* When one can directly address pixels in the color buffer the following
* macros can be defined and used to directly compute pixel addresses during
* rasterization (see pixelPtr):
* PIXEL_TYPE - the datatype of a pixel (GLubyte, GLushort, GLuint)
* BYTES_PER_ROW - number of bytes per row in the color buffer
* PIXEL_ADDRESS(X,Y) - returns the address of pixel at (X,Y) where
* Y==0 at bottom of screen and increases upward.
*
* Similarly, for direct depth buffer access, this type is used for depth
* buffer addressing:
* DEPTH_TYPE - either GLushort or GLuint
*
* Optionally, one may provide one-time setup code
* SETUP_CODE - code which is to be executed once per line
*
* To actually "plot" each pixel the PLOT macro must be defined...
* PLOT(X,Y) - code to plot a pixel. Example:
* if (Z < *zPtr) {
* *zPtr = Z;
* color = pack_rgb( FixedToInt(r0), FixedToInt(g0),
* FixedToInt(b0) );
* put_pixel( X, Y, color );
* }
*
* This code was designed for the origin to be in the lower-left corner.
*
*/
 
 
static void
NAME( struct gl_context *ctx, const SWvertex *vert0, const SWvertex *vert1 )
{
const SWcontext *swrast = SWRAST_CONTEXT(ctx);
SWspan span;
GLuint interpFlags = 0;
GLint x0 = (GLint) vert0->attrib[VARYING_SLOT_POS][0];
GLint x1 = (GLint) vert1->attrib[VARYING_SLOT_POS][0];
GLint y0 = (GLint) vert0->attrib[VARYING_SLOT_POS][1];
GLint y1 = (GLint) vert1->attrib[VARYING_SLOT_POS][1];
GLint dx, dy;
GLint numPixels;
GLint xstep, ystep;
#if defined(DEPTH_TYPE)
const GLint depthBits = ctx->DrawBuffer->Visual.depthBits;
const GLint fixedToDepthShift = depthBits <= 16 ? FIXED_SHIFT : 0;
struct gl_renderbuffer *zrb = ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
#define FixedToDepth(F) ((F) >> fixedToDepthShift)
GLint zPtrXstep, zPtrYstep;
DEPTH_TYPE *zPtr;
#elif defined(INTERP_Z)
const GLint depthBits = ctx->DrawBuffer->Visual.depthBits;
#endif
#ifdef PIXEL_ADDRESS
PIXEL_TYPE *pixelPtr;
GLint pixelXstep, pixelYstep;
#endif
 
#ifdef SETUP_CODE
SETUP_CODE
#endif
 
(void) swrast;
 
/* Cull primitives with malformed coordinates.
*/
{
GLfloat tmp = vert0->attrib[VARYING_SLOT_POS][0] + vert0->attrib[VARYING_SLOT_POS][1]
+ vert1->attrib[VARYING_SLOT_POS][0] + vert1->attrib[VARYING_SLOT_POS][1];
if (IS_INF_OR_NAN(tmp))
return;
}
 
/*
printf("%s():\n", __func__);
printf(" (%f, %f, %f) -> (%f, %f, %f)\n",
vert0->attrib[VARYING_SLOT_POS][0],
vert0->attrib[VARYING_SLOT_POS][1],
vert0->attrib[VARYING_SLOT_POS][2],
vert1->attrib[VARYING_SLOT_POS][0],
vert1->attrib[VARYING_SLOT_POS][1],
vert1->attrib[VARYING_SLOT_POS][2]);
printf(" (%d, %d, %d) -> (%d, %d, %d)\n",
vert0->color[0], vert0->color[1], vert0->color[2],
vert1->color[0], vert1->color[1], vert1->color[2]);
printf(" (%d, %d, %d) -> (%d, %d, %d)\n",
vert0->specular[0], vert0->specular[1], vert0->specular[2],
vert1->specular[0], vert1->specular[1], vert1->specular[2]);
*/
 
/*
* Despite being clipped to the view volume, the line's window coordinates
* may just lie outside the window bounds. That is, if the legal window
* coordinates are [0,W-1][0,H-1], it's possible for x==W and/or y==H.
* This quick and dirty code nudges the endpoints inside the window if
* necessary.
*/
#ifdef CLIP_HACK
{
GLint w = ctx->DrawBuffer->Width;
GLint h = ctx->DrawBuffer->Height;
if ((x0==w) | (x1==w)) {
if ((x0==w) & (x1==w))
return;
x0 -= x0==w;
x1 -= x1==w;
}
if ((y0==h) | (y1==h)) {
if ((y0==h) & (y1==h))
return;
y0 -= y0==h;
y1 -= y1==h;
}
}
#endif
 
dx = x1 - x0;
dy = y1 - y0;
if (dx == 0 && dy == 0)
return;
 
/*
printf("%s %d,%d %g %g %g %g %g %g %g %g\n", __func__, dx, dy,
vert0->attrib[VARYING_SLOT_COL1][0],
vert0->attrib[VARYING_SLOT_COL1][1],
vert0->attrib[VARYING_SLOT_COL1][2],
vert0->attrib[VARYING_SLOT_COL1][3],
vert1->attrib[VARYING_SLOT_COL1][0],
vert1->attrib[VARYING_SLOT_COL1][1],
vert1->attrib[VARYING_SLOT_COL1][2],
vert1->attrib[VARYING_SLOT_COL1][3]);
*/
 
#ifdef DEPTH_TYPE
zPtr = (DEPTH_TYPE *) _swrast_pixel_address(zrb, x0, y0);
#endif
#ifdef PIXEL_ADDRESS
pixelPtr = (PIXEL_TYPE *) PIXEL_ADDRESS(x0,y0);
#endif
 
if (dx<0) {
dx = -dx; /* make positive */
xstep = -1;
#ifdef DEPTH_TYPE
zPtrXstep = -((GLint)sizeof(DEPTH_TYPE));
#endif
#ifdef PIXEL_ADDRESS
pixelXstep = -((GLint)sizeof(PIXEL_TYPE));
#endif
}
else {
xstep = 1;
#ifdef DEPTH_TYPE
zPtrXstep = ((GLint)sizeof(DEPTH_TYPE));
#endif
#ifdef PIXEL_ADDRESS
pixelXstep = ((GLint)sizeof(PIXEL_TYPE));
#endif
}
 
if (dy<0) {
dy = -dy; /* make positive */
ystep = -1;
#ifdef DEPTH_TYPE
zPtrYstep = -((GLint) (ctx->DrawBuffer->Width * sizeof(DEPTH_TYPE)));
#endif
#ifdef PIXEL_ADDRESS
pixelYstep = BYTES_PER_ROW;
#endif
}
else {
ystep = 1;
#ifdef DEPTH_TYPE
zPtrYstep = (GLint) (ctx->DrawBuffer->Width * sizeof(DEPTH_TYPE));
#endif
#ifdef PIXEL_ADDRESS
pixelYstep = -(BYTES_PER_ROW);
#endif
}
 
assert(dx >= 0);
assert(dy >= 0);
 
numPixels = MAX2(dx, dy);
 
/*
* Span setup: compute start and step values for all interpolated values.
*/
interpFlags |= SPAN_RGBA;
if (ctx->Light.ShadeModel == GL_SMOOTH) {
span.red = ChanToFixed(vert0->color[0]);
span.green = ChanToFixed(vert0->color[1]);
span.blue = ChanToFixed(vert0->color[2]);
span.alpha = ChanToFixed(vert0->color[3]);
span.redStep = (ChanToFixed(vert1->color[0]) - span.red ) / numPixels;
span.greenStep = (ChanToFixed(vert1->color[1]) - span.green) / numPixels;
span.blueStep = (ChanToFixed(vert1->color[2]) - span.blue ) / numPixels;
span.alphaStep = (ChanToFixed(vert1->color[3]) - span.alpha) / numPixels;
}
else {
span.red = ChanToFixed(vert1->color[0]);
span.green = ChanToFixed(vert1->color[1]);
span.blue = ChanToFixed(vert1->color[2]);
span.alpha = ChanToFixed(vert1->color[3]);
span.redStep = 0;
span.greenStep = 0;
span.blueStep = 0;
span.alphaStep = 0;
}
#if defined(INTERP_Z) || defined(DEPTH_TYPE)
interpFlags |= SPAN_Z;
{
if (depthBits <= 16) {
span.z = FloatToFixed(vert0->attrib[VARYING_SLOT_POS][2]) + FIXED_HALF;
span.zStep = FloatToFixed( vert1->attrib[VARYING_SLOT_POS][2]
- vert0->attrib[VARYING_SLOT_POS][2]) / numPixels;
}
else {
/* don't use fixed point */
span.z = (GLuint) vert0->attrib[VARYING_SLOT_POS][2];
span.zStep = (GLint) (( vert1->attrib[VARYING_SLOT_POS][2]
- vert0->attrib[VARYING_SLOT_POS][2]) / numPixels);
}
}
#endif
#if defined(INTERP_ATTRIBS)
{
const GLfloat invLen = 1.0F / numPixels;
const GLfloat invw0 = vert0->attrib[VARYING_SLOT_POS][3];
const GLfloat invw1 = vert1->attrib[VARYING_SLOT_POS][3];
 
span.attrStart[VARYING_SLOT_POS][3] = invw0;
span.attrStepX[VARYING_SLOT_POS][3] = (invw1 - invw0) * invLen;
span.attrStepY[VARYING_SLOT_POS][3] = 0.0;
 
ATTRIB_LOOP_BEGIN
if (swrast->_InterpMode[attr] == GL_FLAT) {
COPY_4V(span.attrStart[attr], vert1->attrib[attr]);
ASSIGN_4V(span.attrStepX[attr], 0.0, 0.0, 0.0, 0.0);
}
else {
GLuint c;
for (c = 0; c < 4; c++) {
float da;
span.attrStart[attr][c] = invw0 * vert0->attrib[attr][c];
da = (invw1 * vert1->attrib[attr][c]) - span.attrStart[attr][c];
span.attrStepX[attr][c] = da * invLen;
}
}
ASSIGN_4V(span.attrStepY[attr], 0.0, 0.0, 0.0, 0.0);
ATTRIB_LOOP_END
}
#endif
 
INIT_SPAN(span, GL_LINE);
span.end = numPixels;
span.interpMask = interpFlags;
span.arrayMask = SPAN_XY;
 
span.facing = swrast->PointLineFacing;
 
 
/*
* Draw
*/
 
if (dx > dy) {
/*** X-major line ***/
GLint i;
GLint errorInc = dy+dy;
GLint error = errorInc-dx;
GLint errorDec = error-dx;
 
for (i = 0; i < dx; i++) {
#ifdef DEPTH_TYPE
GLuint Z = FixedToDepth(span.z);
#endif
#ifdef PLOT
PLOT( x0, y0 );
#else
span.array->x[i] = x0;
span.array->y[i] = y0;
#endif
x0 += xstep;
#ifdef DEPTH_TYPE
zPtr = (DEPTH_TYPE *) ((GLubyte*) zPtr + zPtrXstep);
span.z += span.zStep;
#endif
#ifdef PIXEL_ADDRESS
pixelPtr = (PIXEL_TYPE*) ((GLubyte*) pixelPtr + pixelXstep);
#endif
if (error < 0) {
error += errorInc;
}
else {
error += errorDec;
y0 += ystep;
#ifdef DEPTH_TYPE
zPtr = (DEPTH_TYPE *) ((GLubyte*) zPtr + zPtrYstep);
#endif
#ifdef PIXEL_ADDRESS
pixelPtr = (PIXEL_TYPE*) ((GLubyte*) pixelPtr + pixelYstep);
#endif
}
}
}
else {
/*** Y-major line ***/
GLint i;
GLint errorInc = dx+dx;
GLint error = errorInc-dy;
GLint errorDec = error-dy;
 
for (i=0;i<dy;i++) {
#ifdef DEPTH_TYPE
GLuint Z = FixedToDepth(span.z);
#endif
#ifdef PLOT
PLOT( x0, y0 );
#else
span.array->x[i] = x0;
span.array->y[i] = y0;
#endif
y0 += ystep;
#ifdef DEPTH_TYPE
zPtr = (DEPTH_TYPE *) ((GLubyte*) zPtr + zPtrYstep);
span.z += span.zStep;
#endif
#ifdef PIXEL_ADDRESS
pixelPtr = (PIXEL_TYPE*) ((GLubyte*) pixelPtr + pixelYstep);
#endif
if (error<0) {
error += errorInc;
}
else {
error += errorDec;
x0 += xstep;
#ifdef DEPTH_TYPE
zPtr = (DEPTH_TYPE *) ((GLubyte*) zPtr + zPtrXstep);
#endif
#ifdef PIXEL_ADDRESS
pixelPtr = (PIXEL_TYPE*) ((GLubyte*) pixelPtr + pixelXstep);
#endif
}
}
}
 
#ifdef RENDER_SPAN
RENDER_SPAN( span );
#endif
 
(void)span;
 
}
 
 
#undef NAME
#undef INTERP_Z
#undef INTERP_ATTRIBS
#undef PIXEL_ADDRESS
#undef PIXEL_TYPE
#undef DEPTH_TYPE
#undef BYTES_PER_ROW
#undef SETUP_CODE
#undef PLOT
#undef CLIP_HACK
#undef FixedToDepth
#undef RENDER_SPAN
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_logic.c
0,0 → 1,218
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#include "main/glheader.h"
#include "main/context.h"
#include "main/imports.h"
#include "main/macros.h"
 
#include "s_context.h"
#include "s_logic.h"
#include "s_span.h"
 
 
/**
* We do all logic ops on 4-byte GLuints.
* Depending on bytes per pixel, the mask array elements correspond to
* 1, 2 or 4 GLuints.
*/
#define LOGIC_OP_LOOP(MODE, MASKSTRIDE) \
do { \
GLuint i; \
switch (MODE) { \
case GL_CLEAR: \
for (i = 0; i < n; i++) { \
if (mask[i / MASKSTRIDE]) { \
src[i] = 0; \
} \
} \
break; \
case GL_SET: \
for (i = 0; i < n; i++) { \
if (mask[i / MASKSTRIDE]) { \
src[i] = ~0; \
} \
} \
break; \
case GL_COPY: \
/* do nothing */ \
break; \
case GL_COPY_INVERTED: \
for (i = 0; i < n; i++) { \
if (mask[i / MASKSTRIDE]) { \
src[i] = ~src[i]; \
} \
} \
break; \
case GL_NOOP: \
for (i = 0; i < n; i++) { \
if (mask[i / MASKSTRIDE]) { \
src[i] = dest[i]; \
} \
} \
break; \
case GL_INVERT: \
for (i = 0; i < n; i++) { \
if (mask[i / MASKSTRIDE]) { \
src[i] = ~dest[i]; \
} \
} \
break; \
case GL_AND: \
for (i = 0; i < n; i++) { \
if (mask[i / MASKSTRIDE]) { \
src[i] &= dest[i]; \
} \
} \
break; \
case GL_NAND: \
for (i = 0; i < n; i++) { \
if (mask[i / MASKSTRIDE]) { \
src[i] = ~(src[i] & dest[i]); \
} \
} \
break; \
case GL_OR: \
for (i = 0; i < n; i++) { \
if (mask[i / MASKSTRIDE]) { \
src[i] |= dest[i]; \
} \
} \
break; \
case GL_NOR: \
for (i = 0; i < n; i++) { \
if (mask[i / MASKSTRIDE]) { \
src[i] = ~(src[i] | dest[i]); \
} \
} \
break; \
case GL_XOR: \
for (i = 0; i < n; i++) { \
if (mask[i / MASKSTRIDE]) { \
src[i] ^= dest[i]; \
} \
} \
break; \
case GL_EQUIV: \
for (i = 0; i < n; i++) { \
if (mask[i / MASKSTRIDE]) { \
src[i] = ~(src[i] ^ dest[i]); \
} \
} \
break; \
case GL_AND_REVERSE: \
for (i = 0; i < n; i++) { \
if (mask[i / MASKSTRIDE]) { \
src[i] = src[i] & ~dest[i]; \
} \
} \
break; \
case GL_AND_INVERTED: \
for (i = 0; i < n; i++) { \
if (mask[i / MASKSTRIDE]) { \
src[i] = ~src[i] & dest[i]; \
} \
} \
break; \
case GL_OR_REVERSE: \
for (i = 0; i < n; i++) { \
if (mask[i / MASKSTRIDE]) { \
src[i] = src[i] | ~dest[i]; \
} \
} \
break; \
case GL_OR_INVERTED: \
for (i = 0; i < n; i++) { \
if (mask[i / MASKSTRIDE]) { \
src[i] = ~src[i] | dest[i]; \
} \
} \
break; \
default: \
_mesa_problem(ctx, "bad logicop mode");\
} \
} while (0)
 
 
 
static inline void
logicop_uint1(struct gl_context *ctx, GLuint n, GLuint src[], const GLuint dest[],
const GLubyte mask[])
{
LOGIC_OP_LOOP(ctx->Color.LogicOp, 1);
}
 
 
static inline void
logicop_uint2(struct gl_context *ctx, GLuint n, GLuint src[], const GLuint dest[],
const GLubyte mask[])
{
LOGIC_OP_LOOP(ctx->Color.LogicOp, 2);
}
 
 
static inline void
logicop_uint4(struct gl_context *ctx, GLuint n, GLuint src[], const GLuint dest[],
const GLubyte mask[])
{
LOGIC_OP_LOOP(ctx->Color.LogicOp, 4);
}
 
 
 
/**
* Apply the current logic operator to a span of RGBA pixels.
* We can handle horizontal runs of pixels (spans) or arrays of x/y
* pixel coordinates.
*/
void
_swrast_logicop_rgba_span(struct gl_context *ctx, struct gl_renderbuffer *rb,
SWspan *span)
{
void *rbPixels;
 
assert(span->end < SWRAST_MAX_WIDTH);
assert(span->arrayMask & SPAN_RGBA);
 
rbPixels = _swrast_get_dest_rgba(ctx, rb, span);
 
if (span->array->ChanType == GL_UNSIGNED_BYTE) {
/* treat 4*GLubyte as GLuint */
logicop_uint1(ctx, span->end,
(GLuint *) span->array->rgba8,
(const GLuint *) rbPixels, span->array->mask);
}
else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
/* treat 2*GLushort as GLuint */
logicop_uint2(ctx, 2 * span->end,
(GLuint *) span->array->rgba16,
(const GLuint *) rbPixels, span->array->mask);
}
else {
logicop_uint4(ctx, 4 * span->end,
(GLuint *) span->array->attribs[VARYING_SLOT_COL0],
(const GLuint *) rbPixels, span->array->mask);
}
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_logic.h
0,0 → 1,40
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_LOGIC_H
#define S_LOGIC_H
 
 
#include "s_span.h"
 
struct gl_context;
struct gl_renderbuffer;
 
extern void
_swrast_logicop_rgba_span(struct gl_context *ctx, struct gl_renderbuffer *rb,
SWspan *span);
 
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_masking.c
0,0 → 1,102
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
/*
* Implement the effect of glColorMask and glIndexMask in software.
*/
 
 
#include "main/glheader.h"
#include "main/macros.h"
 
#include "s_context.h"
#include "s_masking.h"
#include "s_span.h"
 
 
/**
* Apply the color mask to a span of rgba values.
*/
void
_swrast_mask_rgba_span(struct gl_context *ctx, struct gl_renderbuffer *rb,
SWspan *span, GLuint buf)
{
const GLuint n = span->end;
void *rbPixels;
 
assert(n < SWRAST_MAX_WIDTH);
assert(span->arrayMask & SPAN_RGBA);
 
rbPixels = _swrast_get_dest_rgba(ctx, rb, span);
 
/*
* Do component masking.
* Note that we're not using span->array->mask[] here. We could...
*/
if (span->array->ChanType == GL_UNSIGNED_BYTE) {
/* treat 4xGLubyte as 1xGLuint */
const GLuint srcMask = *((GLuint *) ctx->Color.ColorMask[buf]);
const GLuint dstMask = ~srcMask;
const GLuint *dst = (const GLuint *) rbPixels;
GLuint *src = (GLuint *) span->array->rgba8;
GLuint i;
for (i = 0; i < n; i++) {
src[i] = (src[i] & srcMask) | (dst[i] & dstMask);
}
}
else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
/* 2-byte components */
/* XXX try to use 64-bit arithmetic someday */
const GLushort rMask = ctx->Color.ColorMask[buf][RCOMP] ? 0xffff : 0x0;
const GLushort gMask = ctx->Color.ColorMask[buf][GCOMP] ? 0xffff : 0x0;
const GLushort bMask = ctx->Color.ColorMask[buf][BCOMP] ? 0xffff : 0x0;
const GLushort aMask = ctx->Color.ColorMask[buf][ACOMP] ? 0xffff : 0x0;
const GLushort (*dst)[4] = (const GLushort (*)[4]) rbPixels;
GLushort (*src)[4] = span->array->rgba16;
GLuint i;
for (i = 0; i < n; i++) {
src[i][RCOMP] = (src[i][RCOMP] & rMask) | (dst[i][RCOMP] & ~rMask);
src[i][GCOMP] = (src[i][GCOMP] & gMask) | (dst[i][GCOMP] & ~gMask);
src[i][BCOMP] = (src[i][BCOMP] & bMask) | (dst[i][BCOMP] & ~bMask);
src[i][ACOMP] = (src[i][ACOMP] & aMask) | (dst[i][ACOMP] & ~aMask);
}
}
else {
/* 4-byte components */
const GLuint rMask = ctx->Color.ColorMask[buf][RCOMP] ? ~0x0 : 0x0;
const GLuint gMask = ctx->Color.ColorMask[buf][GCOMP] ? ~0x0 : 0x0;
const GLuint bMask = ctx->Color.ColorMask[buf][BCOMP] ? ~0x0 : 0x0;
const GLuint aMask = ctx->Color.ColorMask[buf][ACOMP] ? ~0x0 : 0x0;
const GLuint (*dst)[4] = (const GLuint (*)[4]) rbPixels;
GLuint (*src)[4] = (GLuint (*)[4]) span->array->attribs[VARYING_SLOT_COL0];
GLuint i;
for (i = 0; i < n; i++) {
src[i][RCOMP] = (src[i][RCOMP] & rMask) | (dst[i][RCOMP] & ~rMask);
src[i][GCOMP] = (src[i][GCOMP] & gMask) | (dst[i][GCOMP] & ~gMask);
src[i][BCOMP] = (src[i][BCOMP] & bMask) | (dst[i][BCOMP] & ~bMask);
src[i][ACOMP] = (src[i][ACOMP] & aMask) | (dst[i][ACOMP] & ~aMask);
}
}
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_masking.h
0,0 → 1,41
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_MASKING_H
#define S_MASKING_H
 
 
#include "main/glheader.h"
#include "s_span.h"
 
struct gl_context;
struct gl_renderbuffer;
 
 
extern void
_swrast_mask_rgba_span(struct gl_context *ctx, struct gl_renderbuffer *rb,
SWspan *span, GLuint buf);
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_points.c
0,0 → 1,571
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#include "main/glheader.h"
#include "main/macros.h"
#include "s_context.h"
#include "s_feedback.h"
#include "s_points.h"
#include "s_span.h"
 
 
/**
* Used to cull points with invalid coords
*/
#define CULL_INVALID(V) \
do { \
float tmp = (V)->attrib[VARYING_SLOT_POS][0] \
+ (V)->attrib[VARYING_SLOT_POS][1]; \
if (IS_INF_OR_NAN(tmp)) \
return; \
} while(0)
 
 
 
/**
* Get/compute the point size.
* The size may come from a vertex shader, or computed with attentuation
* or just the glPointSize value.
* Must also clamp to user-defined range and implmentation limits.
*/
static inline GLfloat
get_size(const struct gl_context *ctx, const SWvertex *vert, GLboolean smoothed)
{
GLfloat size;
 
if (ctx->Point._Attenuated || ctx->VertexProgram.PointSizeEnabled) {
/* use vertex's point size */
size = vert->pointSize;
}
else {
/* use constant point size */
size = ctx->Point.Size;
}
/* always clamp to user-specified limits */
size = CLAMP(size, ctx->Point.MinSize, ctx->Point.MaxSize);
/* clamp to implementation limits */
if (smoothed)
size = CLAMP(size, ctx->Const.MinPointSizeAA, ctx->Const.MaxPointSizeAA);
else
size = CLAMP(size, ctx->Const.MinPointSize, ctx->Const.MaxPointSize);
 
return size;
}
 
 
/**
* Draw a point sprite
*/
static void
sprite_point(struct gl_context *ctx, const SWvertex *vert)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
SWspan span;
GLfloat size;
GLuint tCoords[MAX_TEXTURE_COORD_UNITS + 1];
GLuint numTcoords = 0;
GLfloat t0, dtdy;
 
CULL_INVALID(vert);
 
/* z coord */
if (ctx->DrawBuffer->Visual.depthBits <= 16)
span.z = FloatToFixed(vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
else
span.z = (GLuint) (vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
span.zStep = 0;
 
size = get_size(ctx, vert, GL_FALSE);
 
/* span init */
INIT_SPAN(span, GL_POINT);
span.interpMask = SPAN_Z | SPAN_RGBA;
 
span.facing = swrast->PointLineFacing;
 
span.red = ChanToFixed(vert->color[0]);
span.green = ChanToFixed(vert->color[1]);
span.blue = ChanToFixed(vert->color[2]);
span.alpha = ChanToFixed(vert->color[3]);
span.redStep = 0;
span.greenStep = 0;
span.blueStep = 0;
span.alphaStep = 0;
 
/* need these for fragment programs */
span.attrStart[VARYING_SLOT_POS][3] = 1.0F;
span.attrStepX[VARYING_SLOT_POS][3] = 0.0F;
span.attrStepY[VARYING_SLOT_POS][3] = 0.0F;
 
{
GLfloat s, r, dsdx;
 
/* texcoord / pointcoord interpolants */
s = 0.0F;
dsdx = 1.0F / size;
if (ctx->Point.SpriteOrigin == GL_LOWER_LEFT) {
dtdy = 1.0F / size;
t0 = 0.5F * dtdy;
}
else {
/* GL_UPPER_LEFT */
dtdy = -1.0F / size;
t0 = 1.0F + 0.5F * dtdy;
}
 
ATTRIB_LOOP_BEGIN
if (attr >= VARYING_SLOT_TEX0 && attr <= VARYING_SLOT_TEX7) {
/* a texcoord attribute */
const GLuint u = attr - VARYING_SLOT_TEX0;
assert(u < ARRAY_SIZE(ctx->Point.CoordReplace));
if (ctx->Point.CoordReplace[u]) {
tCoords[numTcoords++] = attr;
 
if (ctx->Point.SpriteRMode == GL_ZERO)
r = 0.0F;
else if (ctx->Point.SpriteRMode == GL_S)
r = vert->attrib[attr][0];
else /* GL_R */
r = vert->attrib[attr][2];
 
span.attrStart[attr][0] = s;
span.attrStart[attr][1] = 0.0; /* overwritten below */
span.attrStart[attr][2] = r;
span.attrStart[attr][3] = 1.0;
 
span.attrStepX[attr][0] = dsdx;
span.attrStepX[attr][1] = 0.0;
span.attrStepX[attr][2] = 0.0;
span.attrStepX[attr][3] = 0.0;
 
span.attrStepY[attr][0] = 0.0;
span.attrStepY[attr][1] = dtdy;
span.attrStepY[attr][2] = 0.0;
span.attrStepY[attr][3] = 0.0;
 
continue;
}
}
else if (attr == VARYING_SLOT_PNTC) {
/* GLSL gl_PointCoord.xy (.zw undefined) */
span.attrStart[VARYING_SLOT_PNTC][0] = 0.0;
span.attrStart[VARYING_SLOT_PNTC][1] = 0.0; /* t0 set below */
span.attrStepX[VARYING_SLOT_PNTC][0] = dsdx;
span.attrStepX[VARYING_SLOT_PNTC][1] = 0.0;
span.attrStepY[VARYING_SLOT_PNTC][0] = 0.0;
span.attrStepY[VARYING_SLOT_PNTC][1] = dtdy;
tCoords[numTcoords++] = VARYING_SLOT_PNTC;
continue;
}
/* use vertex's texcoord/attrib */
COPY_4V(span.attrStart[attr], vert->attrib[attr]);
ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
ATTRIB_LOOP_END;
}
 
/* compute pos, bounds and render */
{
const GLfloat x = vert->attrib[VARYING_SLOT_POS][0];
const GLfloat y = vert->attrib[VARYING_SLOT_POS][1];
GLint iSize = (GLint) (size + 0.5F);
GLint xmin, xmax, ymin, ymax, iy;
GLint iRadius;
GLfloat tcoord = t0;
 
iSize = MAX2(1, iSize);
iRadius = iSize / 2;
 
if (iSize & 1) {
/* odd size */
xmin = (GLint) (x - iRadius);
xmax = (GLint) (x + iRadius);
ymin = (GLint) (y - iRadius);
ymax = (GLint) (y + iRadius);
}
else {
/* even size */
/* 0.501 factor allows conformance to pass */
xmin = (GLint) (x + 0.501) - iRadius;
xmax = xmin + iSize - 1;
ymin = (GLint) (y + 0.501) - iRadius;
ymax = ymin + iSize - 1;
}
 
/* render spans */
for (iy = ymin; iy <= ymax; iy++) {
GLuint i;
/* setup texcoord T for this row */
for (i = 0; i < numTcoords; i++) {
span.attrStart[tCoords[i]][1] = tcoord;
}
 
/* these might get changed by span clipping */
span.x = xmin;
span.y = iy;
span.end = xmax - xmin + 1;
 
_swrast_write_rgba_span(ctx, &span);
 
tcoord += dtdy;
}
}
}
 
 
/**
* Draw smooth/antialiased point. RGB or CI mode.
*/
static void
smooth_point(struct gl_context *ctx, const SWvertex *vert)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
SWspan span;
GLfloat size, alphaAtten;
 
CULL_INVALID(vert);
 
/* z coord */
if (ctx->DrawBuffer->Visual.depthBits <= 16)
span.z = FloatToFixed(vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
else
span.z = (GLuint) (vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
span.zStep = 0;
 
size = get_size(ctx, vert, GL_TRUE);
 
/* alpha attenuation / fade factor */
if (ctx->Multisample._Enabled) {
if (vert->pointSize >= ctx->Point.Threshold) {
alphaAtten = 1.0F;
}
else {
GLfloat dsize = vert->pointSize / ctx->Point.Threshold;
alphaAtten = dsize * dsize;
}
}
else {
alphaAtten = 1.0;
}
(void) alphaAtten; /* not used */
 
/* span init */
INIT_SPAN(span, GL_POINT);
span.interpMask = SPAN_Z | SPAN_RGBA;
span.arrayMask = SPAN_COVERAGE | SPAN_MASK;
 
span.facing = swrast->PointLineFacing;
 
span.red = ChanToFixed(vert->color[0]);
span.green = ChanToFixed(vert->color[1]);
span.blue = ChanToFixed(vert->color[2]);
span.alpha = ChanToFixed(vert->color[3]);
span.redStep = 0;
span.greenStep = 0;
span.blueStep = 0;
span.alphaStep = 0;
 
/* need these for fragment programs */
span.attrStart[VARYING_SLOT_POS][3] = 1.0F;
span.attrStepX[VARYING_SLOT_POS][3] = 0.0F;
span.attrStepY[VARYING_SLOT_POS][3] = 0.0F;
 
ATTRIB_LOOP_BEGIN
COPY_4V(span.attrStart[attr], vert->attrib[attr]);
ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
ATTRIB_LOOP_END
 
/* compute pos, bounds and render */
{
const GLfloat x = vert->attrib[VARYING_SLOT_POS][0];
const GLfloat y = vert->attrib[VARYING_SLOT_POS][1];
const GLfloat radius = 0.5F * size;
const GLfloat rmin = radius - 0.7071F; /* 0.7071 = sqrt(2)/2 */
const GLfloat rmax = radius + 0.7071F;
const GLfloat rmin2 = MAX2(0.0F, rmin * rmin);
const GLfloat rmax2 = rmax * rmax;
const GLfloat cscale = 1.0F / (rmax2 - rmin2);
const GLint xmin = (GLint) (x - radius);
const GLint xmax = (GLint) (x + radius);
const GLint ymin = (GLint) (y - radius);
const GLint ymax = (GLint) (y + radius);
GLint ix, iy;
 
for (iy = ymin; iy <= ymax; iy++) {
 
/* these might get changed by span clipping */
span.x = xmin;
span.y = iy;
span.end = xmax - xmin + 1;
 
/* compute coverage for each pixel in span */
for (ix = xmin; ix <= xmax; ix++) {
const GLfloat dx = ix - x + 0.5F;
const GLfloat dy = iy - y + 0.5F;
const GLfloat dist2 = dx * dx + dy * dy;
GLfloat coverage;
 
if (dist2 < rmax2) {
if (dist2 >= rmin2) {
/* compute partial coverage */
coverage = 1.0F - (dist2 - rmin2) * cscale;
}
else {
/* full coverage */
coverage = 1.0F;
}
span.array->mask[ix - xmin] = 1;
}
else {
/* zero coverage - fragment outside the radius */
coverage = 0.0;
span.array->mask[ix - xmin] = 0;
}
span.array->coverage[ix - xmin] = coverage;
}
 
/* render span */
_swrast_write_rgba_span(ctx, &span);
 
}
}
}
 
 
/**
* Draw large (size >= 1) non-AA point. RGB or CI mode.
*/
static void
large_point(struct gl_context *ctx, const SWvertex *vert)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
SWspan span;
GLfloat size;
 
CULL_INVALID(vert);
 
/* z coord */
if (ctx->DrawBuffer->Visual.depthBits <= 16)
span.z = FloatToFixed(vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
else
span.z = (GLuint) (vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
span.zStep = 0;
 
size = get_size(ctx, vert, GL_FALSE);
 
/* span init */
INIT_SPAN(span, GL_POINT);
span.arrayMask = SPAN_XY;
span.facing = swrast->PointLineFacing;
 
span.interpMask = SPAN_Z | SPAN_RGBA;
span.red = ChanToFixed(vert->color[0]);
span.green = ChanToFixed(vert->color[1]);
span.blue = ChanToFixed(vert->color[2]);
span.alpha = ChanToFixed(vert->color[3]);
span.redStep = 0;
span.greenStep = 0;
span.blueStep = 0;
span.alphaStep = 0;
 
/* need these for fragment programs */
span.attrStart[VARYING_SLOT_POS][3] = 1.0F;
span.attrStepX[VARYING_SLOT_POS][3] = 0.0F;
span.attrStepY[VARYING_SLOT_POS][3] = 0.0F;
 
ATTRIB_LOOP_BEGIN
COPY_4V(span.attrStart[attr], vert->attrib[attr]);
ASSIGN_4V(span.attrStepX[attr], 0, 0, 0, 0);
ASSIGN_4V(span.attrStepY[attr], 0, 0, 0, 0);
ATTRIB_LOOP_END
 
/* compute pos, bounds and render */
{
const GLfloat x = vert->attrib[VARYING_SLOT_POS][0];
const GLfloat y = vert->attrib[VARYING_SLOT_POS][1];
GLint iSize = (GLint) (size + 0.5F);
GLint xmin, xmax, ymin, ymax, ix, iy;
GLint iRadius;
 
iSize = MAX2(1, iSize);
iRadius = iSize / 2;
 
if (iSize & 1) {
/* odd size */
xmin = (GLint) (x - iRadius);
xmax = (GLint) (x + iRadius);
ymin = (GLint) (y - iRadius);
ymax = (GLint) (y + iRadius);
}
else {
/* even size */
/* 0.501 factor allows conformance to pass */
xmin = (GLint) (x + 0.501) - iRadius;
xmax = xmin + iSize - 1;
ymin = (GLint) (y + 0.501) - iRadius;
ymax = ymin + iSize - 1;
}
 
/* generate fragments */
span.end = 0;
for (iy = ymin; iy <= ymax; iy++) {
for (ix = xmin; ix <= xmax; ix++) {
span.array->x[span.end] = ix;
span.array->y[span.end] = iy;
span.end++;
}
}
assert(span.end <= SWRAST_MAX_WIDTH);
_swrast_write_rgba_span(ctx, &span);
}
}
 
 
/**
* Draw size=1, single-pixel point
*/
static void
pixel_point(struct gl_context *ctx, const SWvertex *vert)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
/*
* Note that unlike the other functions, we put single-pixel points
* into a special span array in order to render as many points as
* possible with a single _swrast_write_rgba_span() call.
*/
SWspan *span = &(swrast->PointSpan);
GLuint count;
 
CULL_INVALID(vert);
 
/* Span init */
span->interpMask = 0;
span->arrayMask = SPAN_XY | SPAN_Z;
span->arrayMask |= SPAN_RGBA;
/*span->arrayMask |= SPAN_LAMBDA;*/
span->arrayAttribs = swrast->_ActiveAttribMask; /* we'll produce these vals */
 
/* need these for fragment programs */
span->attrStart[VARYING_SLOT_POS][3] = 1.0F;
span->attrStepX[VARYING_SLOT_POS][3] = 0.0F;
span->attrStepY[VARYING_SLOT_POS][3] = 0.0F;
 
/* check if we need to flush */
if (span->end >= SWRAST_MAX_WIDTH ||
(swrast->_RasterMask & (BLEND_BIT | LOGIC_OP_BIT | MASKING_BIT)) ||
span->facing != swrast->PointLineFacing) {
if (span->end > 0) {
_swrast_write_rgba_span(ctx, span);
span->end = 0;
}
}
 
count = span->end;
 
span->facing = swrast->PointLineFacing;
 
/* fragment attributes */
span->array->rgba[count][RCOMP] = vert->color[0];
span->array->rgba[count][GCOMP] = vert->color[1];
span->array->rgba[count][BCOMP] = vert->color[2];
span->array->rgba[count][ACOMP] = vert->color[3];
 
ATTRIB_LOOP_BEGIN
COPY_4V(span->array->attribs[attr][count], vert->attrib[attr]);
ATTRIB_LOOP_END
 
/* fragment position */
span->array->x[count] = (GLint) vert->attrib[VARYING_SLOT_POS][0];
span->array->y[count] = (GLint) vert->attrib[VARYING_SLOT_POS][1];
span->array->z[count] = (GLint) (vert->attrib[VARYING_SLOT_POS][2] + 0.5F);
 
span->end = count + 1;
assert(span->end <= SWRAST_MAX_WIDTH);
}
 
 
/**
* Add specular color to primary color, draw point, restore original
* primary color.
*/
void
_swrast_add_spec_terms_point(struct gl_context *ctx, const SWvertex *v0)
{
SWvertex *ncv0 = (SWvertex *) v0; /* cast away const */
GLfloat rSum, gSum, bSum;
GLchan cSave[4];
 
/* save */
COPY_CHAN4(cSave, ncv0->color);
/* sum */
rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[VARYING_SLOT_COL1][0];
gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[VARYING_SLOT_COL1][1];
bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[VARYING_SLOT_COL1][2];
UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum);
UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum);
UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum);
/* draw */
SWRAST_CONTEXT(ctx)->SpecPoint(ctx, ncv0);
/* restore */
COPY_CHAN4(ncv0->color, cSave);
}
 
 
/**
* Examine current state to determine which point drawing function to use.
*/
void
_swrast_choose_point(struct gl_context *ctx)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
const GLfloat size = CLAMP(ctx->Point.Size,
ctx->Point.MinSize,
ctx->Point.MaxSize);
 
if (ctx->RenderMode == GL_RENDER) {
if (ctx->Point.PointSprite) {
swrast->Point = sprite_point;
}
else if (ctx->Point.SmoothFlag) {
swrast->Point = smooth_point;
}
else if (size > 1.0 ||
ctx->Point._Attenuated ||
ctx->VertexProgram.PointSizeEnabled) {
swrast->Point = large_point;
}
else {
swrast->Point = pixel_point;
}
}
else if (ctx->RenderMode == GL_FEEDBACK) {
swrast->Point = _swrast_feedback_point;
}
else {
/* GL_SELECT mode */
swrast->Point = _swrast_select_point;
}
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_points.h
0,0 → 1,39
 
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_POINTS_H
#define S_POINTS_H
 
#include "swrast.h"
 
extern void
_swrast_choose_point( struct gl_context *ctx );
 
extern void
_swrast_add_spec_terms_point( struct gl_context *ctx,
const SWvertex *v0 );
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_renderbuffer.c
0,0 → 1,697
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
/**
* Functions for allocating/managing software-based renderbuffers.
* Also, routines for reading/writing software-based renderbuffer data as
* ubytes, ushorts, uints, etc.
*/
 
 
#include "main/glheader.h"
#include "main/imports.h"
#include "main/context.h"
#include "main/fbobject.h"
#include "main/formats.h"
#include "main/mtypes.h"
#include "main/renderbuffer.h"
#include "swrast/s_context.h"
#include "swrast/s_renderbuffer.h"
 
 
/**
* This is a software fallback for the gl_renderbuffer->AllocStorage
* function.
* Device drivers will typically override this function for the buffers
* which it manages (typically color buffers, Z and stencil).
* Other buffers (like software accumulation and aux buffers) which the driver
* doesn't manage can be handled with this function.
*
* This one multi-purpose function can allocate stencil, depth, accum, color
* or color-index buffers!
*/
static GLboolean
soft_renderbuffer_storage(struct gl_context *ctx, struct gl_renderbuffer *rb,
GLenum internalFormat,
GLuint width, GLuint height)
{
struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
GLuint bpp;
 
switch (internalFormat) {
case GL_RGB:
case GL_R3_G3_B2:
case GL_RGB4:
case GL_RGB5:
case GL_RGB8:
case GL_RGB10:
case GL_RGB12:
case GL_RGB16:
rb->Format = MESA_FORMAT_BGR_UNORM8;
break;
case GL_RGBA:
case GL_RGBA2:
case GL_RGBA4:
case GL_RGB5_A1:
case GL_RGBA8:
#if 1
case GL_RGB10_A2:
case GL_RGBA12:
#endif
if (_mesa_little_endian())
rb->Format = MESA_FORMAT_R8G8B8A8_UNORM;
else
rb->Format = MESA_FORMAT_A8B8G8R8_UNORM;
break;
case GL_RGBA16:
case GL_RGBA16_SNORM:
/* for accum buffer */
rb->Format = MESA_FORMAT_RGBA_SNORM16;
break;
case GL_STENCIL_INDEX:
case GL_STENCIL_INDEX1_EXT:
case GL_STENCIL_INDEX4_EXT:
case GL_STENCIL_INDEX8_EXT:
case GL_STENCIL_INDEX16_EXT:
rb->Format = MESA_FORMAT_S_UINT8;
break;
case GL_DEPTH_COMPONENT:
case GL_DEPTH_COMPONENT16:
rb->Format = MESA_FORMAT_Z_UNORM16;
break;
case GL_DEPTH_COMPONENT24:
rb->Format = MESA_FORMAT_Z24_UNORM_X8_UINT;
break;
case GL_DEPTH_COMPONENT32:
rb->Format = MESA_FORMAT_Z_UNORM32;
break;
case GL_DEPTH_STENCIL_EXT:
case GL_DEPTH24_STENCIL8_EXT:
rb->Format = MESA_FORMAT_S8_UINT_Z24_UNORM;
break;
default:
/* unsupported format */
return GL_FALSE;
}
 
bpp = _mesa_get_format_bytes(rb->Format);
 
/* free old buffer storage */
free(srb->Buffer);
srb->Buffer = NULL;
 
srb->RowStride = width * bpp;
 
if (width > 0 && height > 0) {
/* allocate new buffer storage */
srb->Buffer = malloc(srb->RowStride * height);
 
if (srb->Buffer == NULL) {
rb->Width = 0;
rb->Height = 0;
_mesa_error(ctx, GL_OUT_OF_MEMORY,
"software renderbuffer allocation (%d x %d x %d)",
width, height, bpp);
return GL_FALSE;
}
}
 
rb->Width = width;
rb->Height = height;
rb->_BaseFormat = _mesa_base_fbo_format(ctx, internalFormat);
 
if (rb->Name == 0 &&
internalFormat == GL_RGBA16_SNORM &&
rb->_BaseFormat == 0) {
/* NOTE: This is a special case just for accumulation buffers.
* This is a very limited use case- there's no snorm texturing or
* rendering going on.
*/
rb->_BaseFormat = GL_RGBA;
}
else {
/* the internalFormat should have been error checked long ago */
assert(rb->_BaseFormat);
}
 
return GL_TRUE;
}
 
 
/**
* Called via gl_renderbuffer::Delete()
*/
static void
soft_renderbuffer_delete(struct gl_context *ctx, struct gl_renderbuffer *rb)
{
struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
 
free(srb->Buffer);
srb->Buffer = NULL;
_mesa_delete_renderbuffer(ctx, rb);
}
 
 
void
_swrast_map_soft_renderbuffer(struct gl_context *ctx,
struct gl_renderbuffer *rb,
GLuint x, GLuint y, GLuint w, GLuint h,
GLbitfield mode,
GLubyte **out_map,
GLint *out_stride)
{
struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
GLubyte *map = srb->Buffer;
int cpp = _mesa_get_format_bytes(rb->Format);
int stride = rb->Width * cpp;
 
if (!map) {
*out_map = NULL;
*out_stride = 0;
}
 
map += y * stride;
map += x * cpp;
 
*out_map = map;
*out_stride = stride;
}
 
 
void
_swrast_unmap_soft_renderbuffer(struct gl_context *ctx,
struct gl_renderbuffer *rb)
{
}
 
 
 
/**
* Allocate a software-based renderbuffer. This is called via the
* ctx->Driver.NewRenderbuffer() function when the user creates a new
* renderbuffer.
* This would not be used for hardware-based renderbuffers.
*/
struct gl_renderbuffer *
_swrast_new_soft_renderbuffer(struct gl_context *ctx, GLuint name)
{
struct swrast_renderbuffer *srb = CALLOC_STRUCT(swrast_renderbuffer);
if (srb) {
_mesa_init_renderbuffer(&srb->Base, name);
srb->Base.AllocStorage = soft_renderbuffer_storage;
srb->Base.Delete = soft_renderbuffer_delete;
}
return &srb->Base;
}
 
 
/**
* Add software-based color renderbuffers to the given framebuffer.
* This is a helper routine for device drivers when creating a
* window system framebuffer (not a user-created render/framebuffer).
* Once this function is called, you can basically forget about this
* renderbuffer; core Mesa will handle all the buffer management and
* rendering!
*/
static GLboolean
add_color_renderbuffers(struct gl_context *ctx, struct gl_framebuffer *fb,
GLuint rgbBits, GLuint alphaBits,
GLboolean frontLeft, GLboolean backLeft,
GLboolean frontRight, GLboolean backRight)
{
gl_buffer_index b;
 
if (rgbBits > 16 || alphaBits > 16) {
_mesa_problem(ctx,
"Unsupported bit depth in add_color_renderbuffers");
return GL_FALSE;
}
 
assert(MAX_COLOR_ATTACHMENTS >= 4);
 
for (b = BUFFER_FRONT_LEFT; b <= BUFFER_BACK_RIGHT; b++) {
struct gl_renderbuffer *rb;
 
if (b == BUFFER_FRONT_LEFT && !frontLeft)
continue;
else if (b == BUFFER_BACK_LEFT && !backLeft)
continue;
else if (b == BUFFER_FRONT_RIGHT && !frontRight)
continue;
else if (b == BUFFER_BACK_RIGHT && !backRight)
continue;
 
assert(fb->Attachment[b].Renderbuffer == NULL);
 
rb = ctx->Driver.NewRenderbuffer(ctx, 0);
if (!rb) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating color buffer");
return GL_FALSE;
}
 
rb->InternalFormat = GL_RGBA;
 
rb->AllocStorage = soft_renderbuffer_storage;
_mesa_add_renderbuffer(fb, b, rb);
}
 
return GL_TRUE;
}
 
 
/**
* Add a software-based depth renderbuffer to the given framebuffer.
* This is a helper routine for device drivers when creating a
* window system framebuffer (not a user-created render/framebuffer).
* Once this function is called, you can basically forget about this
* renderbuffer; core Mesa will handle all the buffer management and
* rendering!
*/
static GLboolean
add_depth_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
GLuint depthBits)
{
struct gl_renderbuffer *rb;
 
if (depthBits > 32) {
_mesa_problem(ctx,
"Unsupported depthBits in add_depth_renderbuffer");
return GL_FALSE;
}
 
assert(fb->Attachment[BUFFER_DEPTH].Renderbuffer == NULL);
 
rb = _swrast_new_soft_renderbuffer(ctx, 0);
if (!rb) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating depth buffer");
return GL_FALSE;
}
 
if (depthBits <= 16) {
rb->InternalFormat = GL_DEPTH_COMPONENT16;
}
else if (depthBits <= 24) {
rb->InternalFormat = GL_DEPTH_COMPONENT24;
}
else {
rb->InternalFormat = GL_DEPTH_COMPONENT32;
}
 
rb->AllocStorage = soft_renderbuffer_storage;
_mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb);
 
return GL_TRUE;
}
 
 
/**
* Add a software-based stencil renderbuffer to the given framebuffer.
* This is a helper routine for device drivers when creating a
* window system framebuffer (not a user-created render/framebuffer).
* Once this function is called, you can basically forget about this
* renderbuffer; core Mesa will handle all the buffer management and
* rendering!
*/
static GLboolean
add_stencil_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
GLuint stencilBits)
{
struct gl_renderbuffer *rb;
 
if (stencilBits > 16) {
_mesa_problem(ctx,
"Unsupported stencilBits in add_stencil_renderbuffer");
return GL_FALSE;
}
 
assert(fb->Attachment[BUFFER_STENCIL].Renderbuffer == NULL);
 
rb = _swrast_new_soft_renderbuffer(ctx, 0);
if (!rb) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating stencil buffer");
return GL_FALSE;
}
 
assert(stencilBits <= 8);
rb->InternalFormat = GL_STENCIL_INDEX8;
 
rb->AllocStorage = soft_renderbuffer_storage;
_mesa_add_renderbuffer(fb, BUFFER_STENCIL, rb);
 
return GL_TRUE;
}
 
 
static GLboolean
add_depth_stencil_renderbuffer(struct gl_context *ctx,
struct gl_framebuffer *fb)
{
struct gl_renderbuffer *rb;
 
assert(fb->Attachment[BUFFER_DEPTH].Renderbuffer == NULL);
assert(fb->Attachment[BUFFER_STENCIL].Renderbuffer == NULL);
 
rb = _swrast_new_soft_renderbuffer(ctx, 0);
if (!rb) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating depth+stencil buffer");
return GL_FALSE;
}
 
rb->InternalFormat = GL_DEPTH_STENCIL;
 
rb->AllocStorage = soft_renderbuffer_storage;
_mesa_add_renderbuffer(fb, BUFFER_DEPTH, rb);
_mesa_add_renderbuffer(fb, BUFFER_STENCIL, rb);
 
return GL_TRUE;
}
 
 
/**
* Add a software-based accumulation renderbuffer to the given framebuffer.
* This is a helper routine for device drivers when creating a
* window system framebuffer (not a user-created render/framebuffer).
* Once this function is called, you can basically forget about this
* renderbuffer; core Mesa will handle all the buffer management and
* rendering!
*/
static GLboolean
add_accum_renderbuffer(struct gl_context *ctx, struct gl_framebuffer *fb,
GLuint redBits, GLuint greenBits,
GLuint blueBits, GLuint alphaBits)
{
struct gl_renderbuffer *rb;
 
if (redBits > 16 || greenBits > 16 || blueBits > 16 || alphaBits > 16) {
_mesa_problem(ctx,
"Unsupported accumBits in add_accum_renderbuffer");
return GL_FALSE;
}
 
assert(fb->Attachment[BUFFER_ACCUM].Renderbuffer == NULL);
 
rb = _swrast_new_soft_renderbuffer(ctx, 0);
if (!rb) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating accum buffer");
return GL_FALSE;
}
 
rb->InternalFormat = GL_RGBA16_SNORM;
rb->AllocStorage = soft_renderbuffer_storage;
_mesa_add_renderbuffer(fb, BUFFER_ACCUM, rb);
 
return GL_TRUE;
}
 
 
 
/**
* Add a software-based aux renderbuffer to the given framebuffer.
* This is a helper routine for device drivers when creating a
* window system framebuffer (not a user-created render/framebuffer).
* Once this function is called, you can basically forget about this
* renderbuffer; core Mesa will handle all the buffer management and
* rendering!
*
* NOTE: color-index aux buffers not supported.
*/
static GLboolean
add_aux_renderbuffers(struct gl_context *ctx, struct gl_framebuffer *fb,
GLuint colorBits, GLuint numBuffers)
{
GLuint i;
 
if (colorBits > 16) {
_mesa_problem(ctx,
"Unsupported colorBits in add_aux_renderbuffers");
return GL_FALSE;
}
 
assert(numBuffers <= MAX_AUX_BUFFERS);
 
for (i = 0; i < numBuffers; i++) {
struct gl_renderbuffer *rb = _swrast_new_soft_renderbuffer(ctx, 0);
 
assert(fb->Attachment[BUFFER_AUX0 + i].Renderbuffer == NULL);
 
if (!rb) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "Allocating aux buffer");
return GL_FALSE;
}
 
assert (colorBits <= 8);
rb->InternalFormat = GL_RGBA;
 
rb->AllocStorage = soft_renderbuffer_storage;
_mesa_add_renderbuffer(fb, BUFFER_AUX0 + i, rb);
}
return GL_TRUE;
}
 
 
/**
* Create/attach software-based renderbuffers to the given framebuffer.
* This is a helper routine for device drivers. Drivers can just as well
* call the individual _mesa_add_*_renderbuffer() routines directly.
*/
void
_swrast_add_soft_renderbuffers(struct gl_framebuffer *fb,
GLboolean color,
GLboolean depth,
GLboolean stencil,
GLboolean accum,
GLboolean alpha,
GLboolean aux)
{
GLboolean frontLeft = GL_TRUE;
GLboolean backLeft = fb->Visual.doubleBufferMode;
GLboolean frontRight = fb->Visual.stereoMode;
GLboolean backRight = fb->Visual.stereoMode && fb->Visual.doubleBufferMode;
 
if (color) {
assert(fb->Visual.redBits == fb->Visual.greenBits);
assert(fb->Visual.redBits == fb->Visual.blueBits);
add_color_renderbuffers(NULL, fb,
fb->Visual.redBits,
fb->Visual.alphaBits,
frontLeft, backLeft,
frontRight, backRight);
}
 
#if 0
/* This is pretty much for debugging purposes only since there's a perf
* hit for using combined depth/stencil in swrast.
*/
if (depth && fb->Visual.depthBits == 24 &&
stencil && fb->Visual.stencilBits == 8) {
/* use combined depth/stencil buffer */
add_depth_stencil_renderbuffer(NULL, fb);
}
else
#else
(void) add_depth_stencil_renderbuffer;
#endif
{
if (depth) {
assert(fb->Visual.depthBits > 0);
add_depth_renderbuffer(NULL, fb, fb->Visual.depthBits);
}
 
if (stencil) {
assert(fb->Visual.stencilBits > 0);
add_stencil_renderbuffer(NULL, fb, fb->Visual.stencilBits);
}
}
 
if (accum) {
assert(fb->Visual.accumRedBits > 0);
assert(fb->Visual.accumGreenBits > 0);
assert(fb->Visual.accumBlueBits > 0);
add_accum_renderbuffer(NULL, fb,
fb->Visual.accumRedBits,
fb->Visual.accumGreenBits,
fb->Visual.accumBlueBits,
fb->Visual.accumAlphaBits);
}
 
if (aux) {
assert(fb->Visual.numAuxBuffers > 0);
add_aux_renderbuffers(NULL, fb, fb->Visual.redBits,
fb->Visual.numAuxBuffers);
}
 
#if 0
if (multisample) {
/* maybe someday */
}
#endif
}
 
 
 
static void
map_attachment(struct gl_context *ctx,
struct gl_framebuffer *fb,
gl_buffer_index buffer)
{
struct gl_texture_object *texObj = fb->Attachment[buffer].Texture;
struct gl_renderbuffer *rb = fb->Attachment[buffer].Renderbuffer;
struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
 
if (texObj) {
/* map texture image (render to texture) */
const GLuint level = fb->Attachment[buffer].TextureLevel;
const GLuint face = fb->Attachment[buffer].CubeMapFace;
const GLuint slice = fb->Attachment[buffer].Zoffset;
struct gl_texture_image *texImage = texObj->Image[face][level];
if (texImage) {
ctx->Driver.MapTextureImage(ctx, texImage, slice,
0, 0, texImage->Width, texImage->Height,
GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
&srb->Map, &srb->RowStride);
}
}
else if (rb) {
/* Map ordinary renderbuffer */
ctx->Driver.MapRenderbuffer(ctx, rb,
0, 0, rb->Width, rb->Height,
GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
&srb->Map, &srb->RowStride);
}
 
assert(srb->Map);
}
 
static void
unmap_attachment(struct gl_context *ctx,
struct gl_framebuffer *fb,
gl_buffer_index buffer)
{
struct gl_texture_object *texObj = fb->Attachment[buffer].Texture;
struct gl_renderbuffer *rb = fb->Attachment[buffer].Renderbuffer;
struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
 
if (texObj) {
/* unmap texture image (render to texture) */
const GLuint level = fb->Attachment[buffer].TextureLevel;
const GLuint face = fb->Attachment[buffer].CubeMapFace;
const GLuint slice = fb->Attachment[buffer].Zoffset;
struct gl_texture_image *texImage = texObj->Image[face][level];
if (texImage) {
ctx->Driver.UnmapTextureImage(ctx, texImage, slice);
}
}
else if (rb) {
/* unmap ordinary renderbuffer */
ctx->Driver.UnmapRenderbuffer(ctx, rb);
}
 
srb->Map = NULL;
}
 
 
/**
* Determine what type to use (ubyte vs. float) for span colors for the
* given renderbuffer.
* See also _swrast_write_rgba_span().
*/
static void
find_renderbuffer_colortype(struct gl_renderbuffer *rb)
{
struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
GLuint rbMaxBits = _mesa_get_format_max_bits(rb->Format);
GLenum rbDatatype = _mesa_get_format_datatype(rb->Format);
 
if (rbDatatype == GL_UNSIGNED_NORMALIZED && rbMaxBits <= 8) {
/* the buffer's values fit in GLubyte values */
srb->ColorType = GL_UNSIGNED_BYTE;
}
else {
/* use floats otherwise */
srb->ColorType = GL_FLOAT;
}
}
 
 
/**
* Map the renderbuffers we'll use for tri/line/point rendering.
*/
void
_swrast_map_renderbuffers(struct gl_context *ctx)
{
struct gl_framebuffer *fb = ctx->DrawBuffer;
struct gl_renderbuffer *depthRb, *stencilRb;
GLuint buf;
 
depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
if (depthRb) {
/* map depth buffer */
map_attachment(ctx, fb, BUFFER_DEPTH);
}
 
stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
if (stencilRb && stencilRb != depthRb) {
/* map stencil buffer */
map_attachment(ctx, fb, BUFFER_STENCIL);
}
 
for (buf = 0; buf < fb->_NumColorDrawBuffers; buf++) {
if (fb->_ColorDrawBufferIndexes[buf] >= 0) {
map_attachment(ctx, fb, fb->_ColorDrawBufferIndexes[buf]);
find_renderbuffer_colortype(fb->_ColorDrawBuffers[buf]);
}
}
}
/**
* Unmap renderbuffers after rendering.
*/
void
_swrast_unmap_renderbuffers(struct gl_context *ctx)
{
struct gl_framebuffer *fb = ctx->DrawBuffer;
struct gl_renderbuffer *depthRb, *stencilRb;
GLuint buf;
 
depthRb = fb->Attachment[BUFFER_DEPTH].Renderbuffer;
if (depthRb) {
/* map depth buffer */
unmap_attachment(ctx, fb, BUFFER_DEPTH);
}
 
stencilRb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
if (stencilRb && stencilRb != depthRb) {
/* map stencil buffer */
unmap_attachment(ctx, fb, BUFFER_STENCIL);
}
 
for (buf = 0; buf < fb->_NumColorDrawBuffers; buf++) {
if (fb->_ColorDrawBufferIndexes[buf] >= 0) {
unmap_attachment(ctx, fb, fb->_ColorDrawBufferIndexes[buf]);
}
}
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_renderbuffer.h
0,0 → 1,66
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_RENDERBUFFER_H
#define S_RENDERBUFFER_H
 
#include "main/glheader.h"
 
 
struct gl_context;
struct gl_framebuffer;
struct gl_renderbuffer;
 
 
extern struct gl_renderbuffer *
_swrast_new_soft_renderbuffer(struct gl_context *ctx, GLuint name);
 
extern void
_swrast_map_soft_renderbuffer(struct gl_context *ctx,
struct gl_renderbuffer *rb,
GLuint x, GLuint y, GLuint w, GLuint h,
GLbitfield mode,
GLubyte **out_map,
GLint *out_stride);
 
extern void
_swrast_unmap_soft_renderbuffer(struct gl_context *ctx,
struct gl_renderbuffer *rb);
 
extern void
_swrast_set_renderbuffer_accessors(struct gl_renderbuffer *rb);
 
 
extern void
_swrast_add_soft_renderbuffers(struct gl_framebuffer *fb,
GLboolean color,
GLboolean depth,
GLboolean stencil,
GLboolean accum,
GLboolean alpha,
GLboolean aux);
 
 
#endif /* S_RENDERBUFFER_H */
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_span.c
0,0 → 1,1595
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
* Copyright (C) 2009 VMware, Inc. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
/**
* \file swrast/s_span.c
* \brief Span processing functions used by all rasterization functions.
* This is where all the per-fragment tests are performed
* \author Brian Paul
*/
 
#include "c99_math.h"
#include "main/glheader.h"
#include "main/format_pack.h"
#include "main/format_unpack.h"
#include "main/macros.h"
#include "main/imports.h"
#include "main/image.h"
#include "main/samplerobj.h"
#include "main/teximage.h"
 
#include "s_atifragshader.h"
#include "s_alpha.h"
#include "s_blend.h"
#include "s_context.h"
#include "s_depth.h"
#include "s_fog.h"
#include "s_logic.h"
#include "s_masking.h"
#include "s_fragprog.h"
#include "s_span.h"
#include "s_stencil.h"
#include "s_texcombine.h"
 
#include <stdbool.h>
 
/**
* Set default fragment attributes for the span using the
* current raster values. Used prior to glDraw/CopyPixels
* and glBitmap.
*/
void
_swrast_span_default_attribs(struct gl_context *ctx, SWspan *span)
{
GLchan r, g, b, a;
/* Z*/
{
const GLfloat depthMax = ctx->DrawBuffer->_DepthMaxF;
if (ctx->DrawBuffer->Visual.depthBits <= 16)
span->z = FloatToFixed(ctx->Current.RasterPos[2] * depthMax + 0.5F);
else {
GLfloat tmpf = ctx->Current.RasterPos[2] * depthMax;
tmpf = MIN2(tmpf, depthMax);
span->z = (GLint)tmpf;
}
span->zStep = 0;
span->interpMask |= SPAN_Z;
}
 
/* W (for perspective correction) */
span->attrStart[VARYING_SLOT_POS][3] = 1.0;
span->attrStepX[VARYING_SLOT_POS][3] = 0.0;
span->attrStepY[VARYING_SLOT_POS][3] = 0.0;
 
/* primary color, or color index */
UNCLAMPED_FLOAT_TO_CHAN(r, ctx->Current.RasterColor[0]);
UNCLAMPED_FLOAT_TO_CHAN(g, ctx->Current.RasterColor[1]);
UNCLAMPED_FLOAT_TO_CHAN(b, ctx->Current.RasterColor[2]);
UNCLAMPED_FLOAT_TO_CHAN(a, ctx->Current.RasterColor[3]);
#if CHAN_TYPE == GL_FLOAT
span->red = r;
span->green = g;
span->blue = b;
span->alpha = a;
#else
span->red = IntToFixed(r);
span->green = IntToFixed(g);
span->blue = IntToFixed(b);
span->alpha = IntToFixed(a);
#endif
span->redStep = 0;
span->greenStep = 0;
span->blueStep = 0;
span->alphaStep = 0;
span->interpMask |= SPAN_RGBA;
 
COPY_4V(span->attrStart[VARYING_SLOT_COL0], ctx->Current.RasterColor);
ASSIGN_4V(span->attrStepX[VARYING_SLOT_COL0], 0.0, 0.0, 0.0, 0.0);
ASSIGN_4V(span->attrStepY[VARYING_SLOT_COL0], 0.0, 0.0, 0.0, 0.0);
 
/* Secondary color */
if (ctx->Light.Enabled || ctx->Fog.ColorSumEnabled)
{
COPY_4V(span->attrStart[VARYING_SLOT_COL1], ctx->Current.RasterSecondaryColor);
ASSIGN_4V(span->attrStepX[VARYING_SLOT_COL1], 0.0, 0.0, 0.0, 0.0);
ASSIGN_4V(span->attrStepY[VARYING_SLOT_COL1], 0.0, 0.0, 0.0, 0.0);
}
 
/* fog */
{
const SWcontext *swrast = SWRAST_CONTEXT(ctx);
GLfloat fogVal; /* a coord or a blend factor */
if (swrast->_PreferPixelFog) {
/* fog blend factors will be computed from fog coordinates per pixel */
fogVal = ctx->Current.RasterDistance;
}
else {
/* fog blend factor should be computed from fogcoord now */
fogVal = _swrast_z_to_fogfactor(ctx, ctx->Current.RasterDistance);
}
span->attrStart[VARYING_SLOT_FOGC][0] = fogVal;
span->attrStepX[VARYING_SLOT_FOGC][0] = 0.0;
span->attrStepY[VARYING_SLOT_FOGC][0] = 0.0;
}
 
/* texcoords */
{
GLuint i;
for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
const GLuint attr = VARYING_SLOT_TEX0 + i;
const GLfloat *tc = ctx->Current.RasterTexCoords[i];
if (_swrast_use_fragment_program(ctx) ||
ctx->ATIFragmentShader._Enabled) {
COPY_4V(span->attrStart[attr], tc);
}
else if (tc[3] > 0.0F) {
/* use (s/q, t/q, r/q, 1) */
span->attrStart[attr][0] = tc[0] / tc[3];
span->attrStart[attr][1] = tc[1] / tc[3];
span->attrStart[attr][2] = tc[2] / tc[3];
span->attrStart[attr][3] = 1.0;
}
else {
ASSIGN_4V(span->attrStart[attr], 0.0F, 0.0F, 0.0F, 1.0F);
}
ASSIGN_4V(span->attrStepX[attr], 0.0F, 0.0F, 0.0F, 0.0F);
ASSIGN_4V(span->attrStepY[attr], 0.0F, 0.0F, 0.0F, 0.0F);
}
}
}
 
 
/**
* Interpolate the active attributes (and'd with attrMask) to
* fill in span->array->attribs[].
* Perspective correction will be done. The point/line/triangle function
* should have computed attrStart/Step values for VARYING_SLOT_POS[3]!
*/
static inline void
interpolate_active_attribs(struct gl_context *ctx, SWspan *span,
GLbitfield64 attrMask)
{
const SWcontext *swrast = SWRAST_CONTEXT(ctx);
 
/*
* Don't overwrite existing array values, such as colors that may have
* been produced by glDraw/CopyPixels.
*/
attrMask &= ~span->arrayAttribs;
 
ATTRIB_LOOP_BEGIN
if (attrMask & BITFIELD64_BIT(attr)) {
const GLfloat dwdx = span->attrStepX[VARYING_SLOT_POS][3];
GLfloat w = span->attrStart[VARYING_SLOT_POS][3];
const GLfloat dv0dx = span->attrStepX[attr][0];
const GLfloat dv1dx = span->attrStepX[attr][1];
const GLfloat dv2dx = span->attrStepX[attr][2];
const GLfloat dv3dx = span->attrStepX[attr][3];
GLfloat v0 = span->attrStart[attr][0] + span->leftClip * dv0dx;
GLfloat v1 = span->attrStart[attr][1] + span->leftClip * dv1dx;
GLfloat v2 = span->attrStart[attr][2] + span->leftClip * dv2dx;
GLfloat v3 = span->attrStart[attr][3] + span->leftClip * dv3dx;
GLuint k;
for (k = 0; k < span->end; k++) {
const GLfloat invW = 1.0f / w;
span->array->attribs[attr][k][0] = v0 * invW;
span->array->attribs[attr][k][1] = v1 * invW;
span->array->attribs[attr][k][2] = v2 * invW;
span->array->attribs[attr][k][3] = v3 * invW;
v0 += dv0dx;
v1 += dv1dx;
v2 += dv2dx;
v3 += dv3dx;
w += dwdx;
}
assert((span->arrayAttribs & BITFIELD64_BIT(attr)) == 0);
span->arrayAttribs |= BITFIELD64_BIT(attr);
}
ATTRIB_LOOP_END
}
 
 
/**
* Interpolate primary colors to fill in the span->array->rgba8 (or rgb16)
* color array.
*/
static inline void
interpolate_int_colors(struct gl_context *ctx, SWspan *span)
{
#if CHAN_BITS != 32
const GLuint n = span->end;
GLuint i;
 
assert(!(span->arrayMask & SPAN_RGBA));
#endif
 
switch (span->array->ChanType) {
#if CHAN_BITS != 32
case GL_UNSIGNED_BYTE:
{
GLubyte (*rgba)[4] = span->array->rgba8;
if (span->interpMask & SPAN_FLAT) {
GLubyte color[4];
color[RCOMP] = FixedToInt(span->red);
color[GCOMP] = FixedToInt(span->green);
color[BCOMP] = FixedToInt(span->blue);
color[ACOMP] = FixedToInt(span->alpha);
for (i = 0; i < n; i++) {
COPY_4UBV(rgba[i], color);
}
}
else {
GLfixed r = span->red;
GLfixed g = span->green;
GLfixed b = span->blue;
GLfixed a = span->alpha;
GLint dr = span->redStep;
GLint dg = span->greenStep;
GLint db = span->blueStep;
GLint da = span->alphaStep;
for (i = 0; i < n; i++) {
rgba[i][RCOMP] = FixedToChan(r);
rgba[i][GCOMP] = FixedToChan(g);
rgba[i][BCOMP] = FixedToChan(b);
rgba[i][ACOMP] = FixedToChan(a);
r += dr;
g += dg;
b += db;
a += da;
}
}
}
break;
case GL_UNSIGNED_SHORT:
{
GLushort (*rgba)[4] = span->array->rgba16;
if (span->interpMask & SPAN_FLAT) {
GLushort color[4];
color[RCOMP] = FixedToInt(span->red);
color[GCOMP] = FixedToInt(span->green);
color[BCOMP] = FixedToInt(span->blue);
color[ACOMP] = FixedToInt(span->alpha);
for (i = 0; i < n; i++) {
COPY_4V(rgba[i], color);
}
}
else {
GLushort (*rgba)[4] = span->array->rgba16;
GLfixed r, g, b, a;
GLint dr, dg, db, da;
r = span->red;
g = span->green;
b = span->blue;
a = span->alpha;
dr = span->redStep;
dg = span->greenStep;
db = span->blueStep;
da = span->alphaStep;
for (i = 0; i < n; i++) {
rgba[i][RCOMP] = FixedToChan(r);
rgba[i][GCOMP] = FixedToChan(g);
rgba[i][BCOMP] = FixedToChan(b);
rgba[i][ACOMP] = FixedToChan(a);
r += dr;
g += dg;
b += db;
a += da;
}
}
}
break;
#endif
case GL_FLOAT:
interpolate_active_attribs(ctx, span, VARYING_BIT_COL0);
break;
default:
_mesa_problem(ctx, "bad datatype 0x%x in interpolate_int_colors",
span->array->ChanType);
}
span->arrayMask |= SPAN_RGBA;
}
 
 
/**
* Populate the VARYING_SLOT_COL0 array.
*/
static inline void
interpolate_float_colors(SWspan *span)
{
GLfloat (*col0)[4] = span->array->attribs[VARYING_SLOT_COL0];
const GLuint n = span->end;
GLuint i;
 
assert(!(span->arrayAttribs & VARYING_BIT_COL0));
 
if (span->arrayMask & SPAN_RGBA) {
/* convert array of int colors */
for (i = 0; i < n; i++) {
col0[i][0] = UBYTE_TO_FLOAT(span->array->rgba8[i][0]);
col0[i][1] = UBYTE_TO_FLOAT(span->array->rgba8[i][1]);
col0[i][2] = UBYTE_TO_FLOAT(span->array->rgba8[i][2]);
col0[i][3] = UBYTE_TO_FLOAT(span->array->rgba8[i][3]);
}
}
else {
/* interpolate red/green/blue/alpha to get float colors */
assert(span->interpMask & SPAN_RGBA);
if (span->interpMask & SPAN_FLAT) {
GLfloat r = FixedToFloat(span->red);
GLfloat g = FixedToFloat(span->green);
GLfloat b = FixedToFloat(span->blue);
GLfloat a = FixedToFloat(span->alpha);
for (i = 0; i < n; i++) {
ASSIGN_4V(col0[i], r, g, b, a);
}
}
else {
GLfloat r = FixedToFloat(span->red);
GLfloat g = FixedToFloat(span->green);
GLfloat b = FixedToFloat(span->blue);
GLfloat a = FixedToFloat(span->alpha);
GLfloat dr = FixedToFloat(span->redStep);
GLfloat dg = FixedToFloat(span->greenStep);
GLfloat db = FixedToFloat(span->blueStep);
GLfloat da = FixedToFloat(span->alphaStep);
for (i = 0; i < n; i++) {
col0[i][0] = r;
col0[i][1] = g;
col0[i][2] = b;
col0[i][3] = a;
r += dr;
g += dg;
b += db;
a += da;
}
}
}
 
span->arrayAttribs |= VARYING_BIT_COL0;
span->array->ChanType = GL_FLOAT;
}
 
 
 
/**
* Fill in the span.zArray array from the span->z, zStep values.
*/
void
_swrast_span_interpolate_z( const struct gl_context *ctx, SWspan *span )
{
const GLuint n = span->end;
GLuint i;
 
assert(!(span->arrayMask & SPAN_Z));
 
if (ctx->DrawBuffer->Visual.depthBits <= 16) {
GLfixed zval = span->z;
GLuint *z = span->array->z;
for (i = 0; i < n; i++) {
z[i] = FixedToInt(zval);
zval += span->zStep;
}
}
else {
/* Deep Z buffer, no fixed->int shift */
GLuint zval = span->z;
GLuint *z = span->array->z;
for (i = 0; i < n; i++) {
z[i] = zval;
zval += span->zStep;
}
}
span->interpMask &= ~SPAN_Z;
span->arrayMask |= SPAN_Z;
}
 
 
/**
* Compute mipmap LOD from partial derivatives.
* This the ideal solution, as given in the OpenGL spec.
*/
GLfloat
_swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
{
GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ);
GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ);
GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ);
GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ);
GLfloat x = sqrtf(dudx * dudx + dvdx * dvdx);
GLfloat y = sqrtf(dudy * dudy + dvdy * dvdy);
GLfloat rho = MAX2(x, y);
GLfloat lambda = LOG2(rho);
return lambda;
}
 
 
/**
* Compute mipmap LOD from partial derivatives.
* This is a faster approximation than above function.
*/
#if 0
GLfloat
_swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
GLfloat s, GLfloat t, GLfloat q, GLfloat invQ)
{
GLfloat dsdx2 = (s + dsdx) / (q + dqdx) - s * invQ;
GLfloat dtdx2 = (t + dtdx) / (q + dqdx) - t * invQ;
GLfloat dsdy2 = (s + dsdy) / (q + dqdy) - s * invQ;
GLfloat dtdy2 = (t + dtdy) / (q + dqdy) - t * invQ;
GLfloat maxU, maxV, rho, lambda;
dsdx2 = fabsf(dsdx2);
dsdy2 = fabsf(dsdy2);
dtdx2 = fabsf(dtdx2);
dtdy2 = fabsf(dtdy2);
maxU = MAX2(dsdx2, dsdy2) * texW;
maxV = MAX2(dtdx2, dtdy2) * texH;
rho = MAX2(maxU, maxV);
lambda = LOG2(rho);
return lambda;
}
#endif
 
 
/**
* Fill in the span.array->attrib[VARYING_SLOT_TEXn] arrays from the
* using the attrStart/Step values.
*
* This function only used during fixed-function fragment processing.
*
* Note: in the places where we divide by Q (or mult by invQ) we're
* really doing two things: perspective correction and texcoord
* projection. Remember, for texcoord (s,t,r,q) we need to index
* texels with (s/q, t/q, r/q).
*/
static void
interpolate_texcoords(struct gl_context *ctx, SWspan *span)
{
const GLuint maxUnit
= (ctx->Texture._EnabledCoordUnits > 1) ? ctx->Const.MaxTextureUnits : 1;
GLuint u;
 
/* XXX CoordUnits vs. ImageUnits */
for (u = 0; u < maxUnit; u++) {
if (ctx->Texture._EnabledCoordUnits & (1 << u)) {
const GLuint attr = VARYING_SLOT_TEX0 + u;
const struct gl_texture_object *obj = ctx->Texture.Unit[u]._Current;
GLfloat texW, texH;
GLboolean needLambda;
GLfloat (*texcoord)[4] = span->array->attribs[attr];
GLfloat *lambda = span->array->lambda[u];
const GLfloat dsdx = span->attrStepX[attr][0];
const GLfloat dsdy = span->attrStepY[attr][0];
const GLfloat dtdx = span->attrStepX[attr][1];
const GLfloat dtdy = span->attrStepY[attr][1];
const GLfloat drdx = span->attrStepX[attr][2];
const GLfloat dqdx = span->attrStepX[attr][3];
const GLfloat dqdy = span->attrStepY[attr][3];
GLfloat s = span->attrStart[attr][0] + span->leftClip * dsdx;
GLfloat t = span->attrStart[attr][1] + span->leftClip * dtdx;
GLfloat r = span->attrStart[attr][2] + span->leftClip * drdx;
GLfloat q = span->attrStart[attr][3] + span->leftClip * dqdx;
 
if (obj) {
const struct gl_texture_image *img = _mesa_base_tex_image(obj);
const struct swrast_texture_image *swImg =
swrast_texture_image_const(img);
const struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, u);
 
needLambda = (samp->MinFilter != samp->MagFilter)
|| _swrast_use_fragment_program(ctx);
/* LOD is calculated directly in the ansiotropic filter, we can
* skip the normal lambda function as the result is ignored.
*/
if (samp->MaxAnisotropy > 1.0 &&
samp->MinFilter == GL_LINEAR_MIPMAP_LINEAR) {
needLambda = GL_FALSE;
}
texW = swImg->WidthScale;
texH = swImg->HeightScale;
}
else {
/* using a fragment program */
texW = 1.0;
texH = 1.0;
needLambda = GL_FALSE;
}
 
if (needLambda) {
GLuint i;
if (_swrast_use_fragment_program(ctx)
|| ctx->ATIFragmentShader._Enabled) {
/* do perspective correction but don't divide s, t, r by q */
const GLfloat dwdx = span->attrStepX[VARYING_SLOT_POS][3];
GLfloat w = span->attrStart[VARYING_SLOT_POS][3] + span->leftClip * dwdx;
for (i = 0; i < span->end; i++) {
const GLfloat invW = 1.0F / w;
texcoord[i][0] = s * invW;
texcoord[i][1] = t * invW;
texcoord[i][2] = r * invW;
texcoord[i][3] = q * invW;
lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
dqdx, dqdy, texW, texH,
s, t, q, invW);
s += dsdx;
t += dtdx;
r += drdx;
q += dqdx;
w += dwdx;
}
}
else {
for (i = 0; i < span->end; i++) {
const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
texcoord[i][0] = s * invQ;
texcoord[i][1] = t * invQ;
texcoord[i][2] = r * invQ;
texcoord[i][3] = q;
lambda[i] = _swrast_compute_lambda(dsdx, dsdy, dtdx, dtdy,
dqdx, dqdy, texW, texH,
s, t, q, invQ);
s += dsdx;
t += dtdx;
r += drdx;
q += dqdx;
}
}
span->arrayMask |= SPAN_LAMBDA;
}
else {
GLuint i;
if (_swrast_use_fragment_program(ctx) ||
ctx->ATIFragmentShader._Enabled) {
/* do perspective correction but don't divide s, t, r by q */
const GLfloat dwdx = span->attrStepX[VARYING_SLOT_POS][3];
GLfloat w = span->attrStart[VARYING_SLOT_POS][3] + span->leftClip * dwdx;
for (i = 0; i < span->end; i++) {
const GLfloat invW = 1.0F / w;
texcoord[i][0] = s * invW;
texcoord[i][1] = t * invW;
texcoord[i][2] = r * invW;
texcoord[i][3] = q * invW;
lambda[i] = 0.0;
s += dsdx;
t += dtdx;
r += drdx;
q += dqdx;
w += dwdx;
}
}
else if (dqdx == 0.0F) {
/* Ortho projection or polygon's parallel to window X axis */
const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
for (i = 0; i < span->end; i++) {
texcoord[i][0] = s * invQ;
texcoord[i][1] = t * invQ;
texcoord[i][2] = r * invQ;
texcoord[i][3] = q;
lambda[i] = 0.0;
s += dsdx;
t += dtdx;
r += drdx;
}
}
else {
for (i = 0; i < span->end; i++) {
const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
texcoord[i][0] = s * invQ;
texcoord[i][1] = t * invQ;
texcoord[i][2] = r * invQ;
texcoord[i][3] = q;
lambda[i] = 0.0;
s += dsdx;
t += dtdx;
r += drdx;
q += dqdx;
}
}
} /* lambda */
} /* if */
} /* for */
}
 
 
/**
* Fill in the arrays->attribs[VARYING_SLOT_POS] array.
*/
static inline void
interpolate_wpos(struct gl_context *ctx, SWspan *span)
{
GLfloat (*wpos)[4] = span->array->attribs[VARYING_SLOT_POS];
GLuint i;
const GLfloat zScale = 1.0F / ctx->DrawBuffer->_DepthMaxF;
GLfloat w, dw;
 
if (span->arrayMask & SPAN_XY) {
for (i = 0; i < span->end; i++) {
wpos[i][0] = (GLfloat) span->array->x[i];
wpos[i][1] = (GLfloat) span->array->y[i];
}
}
else {
for (i = 0; i < span->end; i++) {
wpos[i][0] = (GLfloat) span->x + i;
wpos[i][1] = (GLfloat) span->y;
}
}
 
dw = span->attrStepX[VARYING_SLOT_POS][3];
w = span->attrStart[VARYING_SLOT_POS][3] + span->leftClip * dw;
for (i = 0; i < span->end; i++) {
wpos[i][2] = (GLfloat) span->array->z[i] * zScale;
wpos[i][3] = w;
w += dw;
}
}
 
 
/**
* Apply the current polygon stipple pattern to a span of pixels.
*/
static inline void
stipple_polygon_span(struct gl_context *ctx, SWspan *span)
{
GLubyte *mask = span->array->mask;
 
assert(ctx->Polygon.StippleFlag);
 
if (span->arrayMask & SPAN_XY) {
/* arrays of x/y pixel coords */
GLuint i;
for (i = 0; i < span->end; i++) {
const GLint col = span->array->x[i] % 32;
const GLint row = span->array->y[i] % 32;
const GLuint stipple = ctx->PolygonStipple[row];
if (((1 << col) & stipple) == 0) {
mask[i] = 0;
}
}
}
else {
/* horizontal span of pixels */
const GLuint highBit = 1 << 31;
const GLuint stipple = ctx->PolygonStipple[span->y % 32];
GLuint i, m = highBit >> (GLuint) (span->x % 32);
for (i = 0; i < span->end; i++) {
if ((m & stipple) == 0) {
mask[i] = 0;
}
m = m >> 1;
if (m == 0) {
m = highBit;
}
}
}
span->writeAll = GL_FALSE;
}
 
 
/**
* Clip a pixel span to the current buffer/window boundaries:
* DrawBuffer->_Xmin, _Xmax, _Ymin, _Ymax. This will accomplish
* window clipping and scissoring.
* Return: GL_TRUE some pixels still visible
* GL_FALSE nothing visible
*/
static inline GLuint
clip_span( struct gl_context *ctx, SWspan *span )
{
const GLint xmin = ctx->DrawBuffer->_Xmin;
const GLint xmax = ctx->DrawBuffer->_Xmax;
const GLint ymin = ctx->DrawBuffer->_Ymin;
const GLint ymax = ctx->DrawBuffer->_Ymax;
 
span->leftClip = 0;
 
if (span->arrayMask & SPAN_XY) {
/* arrays of x/y pixel coords */
const GLint *x = span->array->x;
const GLint *y = span->array->y;
const GLint n = span->end;
GLubyte *mask = span->array->mask;
GLint i;
GLuint passed = 0;
if (span->arrayMask & SPAN_MASK) {
/* note: using & intead of && to reduce branches */
for (i = 0; i < n; i++) {
mask[i] &= (x[i] >= xmin) & (x[i] < xmax)
& (y[i] >= ymin) & (y[i] < ymax);
passed += mask[i];
}
}
else {
/* note: using & intead of && to reduce branches */
for (i = 0; i < n; i++) {
mask[i] = (x[i] >= xmin) & (x[i] < xmax)
& (y[i] >= ymin) & (y[i] < ymax);
passed += mask[i];
}
}
return passed > 0;
}
else {
/* horizontal span of pixels */
const GLint x = span->x;
const GLint y = span->y;
GLint n = span->end;
 
/* Trivial rejection tests */
if (y < ymin || y >= ymax || x + n <= xmin || x >= xmax) {
span->end = 0;
return GL_FALSE; /* all pixels clipped */
}
 
/* Clip to right */
if (x + n > xmax) {
assert(x < xmax);
n = span->end = xmax - x;
}
 
/* Clip to the left */
if (x < xmin) {
const GLint leftClip = xmin - x;
GLuint i;
 
assert(leftClip > 0);
assert(x + n > xmin);
 
/* Clip 'leftClip' pixels from the left side.
* The span->leftClip field will be applied when we interpolate
* fragment attributes.
* For arrays of values, shift them left.
*/
for (i = 0; i < VARYING_SLOT_MAX; i++) {
if (span->interpMask & (1 << i)) {
GLuint j;
for (j = 0; j < 4; j++) {
span->attrStart[i][j] += leftClip * span->attrStepX[i][j];
}
}
}
 
span->red += leftClip * span->redStep;
span->green += leftClip * span->greenStep;
span->blue += leftClip * span->blueStep;
span->alpha += leftClip * span->alphaStep;
span->index += leftClip * span->indexStep;
span->z += leftClip * span->zStep;
span->intTex[0] += leftClip * span->intTexStep[0];
span->intTex[1] += leftClip * span->intTexStep[1];
 
#define SHIFT_ARRAY(ARRAY, SHIFT, LEN) \
memmove(ARRAY, ARRAY + (SHIFT), (LEN) * sizeof(ARRAY[0]))
 
for (i = 0; i < VARYING_SLOT_MAX; i++) {
if (span->arrayAttribs & BITFIELD64_BIT(i)) {
/* shift array elements left by 'leftClip' */
SHIFT_ARRAY(span->array->attribs[i], leftClip, n - leftClip);
}
}
 
SHIFT_ARRAY(span->array->mask, leftClip, n - leftClip);
SHIFT_ARRAY(span->array->rgba8, leftClip, n - leftClip);
SHIFT_ARRAY(span->array->rgba16, leftClip, n - leftClip);
SHIFT_ARRAY(span->array->x, leftClip, n - leftClip);
SHIFT_ARRAY(span->array->y, leftClip, n - leftClip);
SHIFT_ARRAY(span->array->z, leftClip, n - leftClip);
SHIFT_ARRAY(span->array->index, leftClip, n - leftClip);
for (i = 0; i < MAX_TEXTURE_COORD_UNITS; i++) {
SHIFT_ARRAY(span->array->lambda[i], leftClip, n - leftClip);
}
SHIFT_ARRAY(span->array->coverage, leftClip, n - leftClip);
 
#undef SHIFT_ARRAY
 
span->leftClip = leftClip;
span->x = xmin;
span->end -= leftClip;
span->writeAll = GL_FALSE;
}
 
assert(span->x >= xmin);
assert(span->x + span->end <= xmax);
assert(span->y >= ymin);
assert(span->y < ymax);
 
return GL_TRUE; /* some pixels visible */
}
}
 
 
/**
* Add specular colors to primary colors.
* Only called during fixed-function operation.
* Result is float color array (VARYING_SLOT_COL0).
*/
static inline void
add_specular(struct gl_context *ctx, SWspan *span)
{
const SWcontext *swrast = SWRAST_CONTEXT(ctx);
const GLubyte *mask = span->array->mask;
GLfloat (*col0)[4] = span->array->attribs[VARYING_SLOT_COL0];
GLfloat (*col1)[4] = span->array->attribs[VARYING_SLOT_COL1];
GLuint i;
 
assert(!_swrast_use_fragment_program(ctx));
assert(span->arrayMask & SPAN_RGBA);
assert(swrast->_ActiveAttribMask & VARYING_BIT_COL1);
(void) swrast; /* silence warning */
 
if (span->array->ChanType == GL_FLOAT) {
if ((span->arrayAttribs & VARYING_BIT_COL0) == 0) {
interpolate_active_attribs(ctx, span, VARYING_BIT_COL0);
}
}
else {
/* need float colors */
if ((span->arrayAttribs & VARYING_BIT_COL0) == 0) {
interpolate_float_colors(span);
}
}
 
if ((span->arrayAttribs & VARYING_BIT_COL1) == 0) {
/* XXX could avoid this and interpolate COL1 in the loop below */
interpolate_active_attribs(ctx, span, VARYING_BIT_COL1);
}
 
assert(span->arrayAttribs & VARYING_BIT_COL0);
assert(span->arrayAttribs & VARYING_BIT_COL1);
 
for (i = 0; i < span->end; i++) {
if (mask[i]) {
col0[i][0] += col1[i][0];
col0[i][1] += col1[i][1];
col0[i][2] += col1[i][2];
}
}
 
span->array->ChanType = GL_FLOAT;
}
 
 
/**
* Apply antialiasing coverage value to alpha values.
*/
static inline void
apply_aa_coverage(SWspan *span)
{
const GLfloat *coverage = span->array->coverage;
GLuint i;
if (span->array->ChanType == GL_UNSIGNED_BYTE) {
GLubyte (*rgba)[4] = span->array->rgba8;
for (i = 0; i < span->end; i++) {
const GLfloat a = rgba[i][ACOMP] * coverage[i];
rgba[i][ACOMP] = (GLubyte) CLAMP(a, 0.0, 255.0);
assert(coverage[i] >= 0.0);
assert(coverage[i] <= 1.0);
}
}
else if (span->array->ChanType == GL_UNSIGNED_SHORT) {
GLushort (*rgba)[4] = span->array->rgba16;
for (i = 0; i < span->end; i++) {
const GLfloat a = rgba[i][ACOMP] * coverage[i];
rgba[i][ACOMP] = (GLushort) CLAMP(a, 0.0, 65535.0);
}
}
else {
GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0];
for (i = 0; i < span->end; i++) {
rgba[i][ACOMP] = rgba[i][ACOMP] * coverage[i];
/* clamp later */
}
}
}
 
 
/**
* Clamp span's float colors to [0,1]
*/
static inline void
clamp_colors(SWspan *span)
{
GLfloat (*rgba)[4] = span->array->attribs[VARYING_SLOT_COL0];
GLuint i;
assert(span->array->ChanType == GL_FLOAT);
for (i = 0; i < span->end; i++) {
rgba[i][RCOMP] = CLAMP(rgba[i][RCOMP], 0.0F, 1.0F);
rgba[i][GCOMP] = CLAMP(rgba[i][GCOMP], 0.0F, 1.0F);
rgba[i][BCOMP] = CLAMP(rgba[i][BCOMP], 0.0F, 1.0F);
rgba[i][ACOMP] = CLAMP(rgba[i][ACOMP], 0.0F, 1.0F);
}
}
 
 
/**
* Convert the span's color arrays to the given type.
* The only way 'output' can be greater than zero 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 srcType, GLenum newType, GLuint output)
{
GLvoid *src, *dst;
 
if (output > 0 || srcType == GL_FLOAT) {
src = span->array->attribs[VARYING_SLOT_COL0 + output];
span->array->ChanType = GL_FLOAT;
}
else if (srcType == GL_UNSIGNED_BYTE) {
src = span->array->rgba8;
}
else {
assert(srcType == GL_UNSIGNED_SHORT);
src = span->array->rgba16;
}
 
if (newType == GL_UNSIGNED_BYTE) {
dst = span->array->rgba8;
}
else if (newType == GL_UNSIGNED_SHORT) {
dst = span->array->rgba16;
}
else {
dst = span->array->attribs[VARYING_SLOT_COL0];
}
 
_mesa_convert_colors(span->array->ChanType, src,
newType, dst,
span->end, span->array->mask);
 
span->array->ChanType = newType;
span->array->rgba = dst;
}
 
 
 
/**
* Apply fragment shader, fragment program or normal texturing to span.
*/
static inline void
shade_texture_span(struct gl_context *ctx, SWspan *span)
{
if (_swrast_use_fragment_program(ctx) ||
ctx->ATIFragmentShader._Enabled) {
/* programmable shading */
if (span->primitive == GL_BITMAP && span->array->ChanType != GL_FLOAT) {
convert_color_type(span, span->array->ChanType, GL_FLOAT, 0);
}
else {
span->array->rgba = (void *) span->array->attribs[VARYING_SLOT_COL0];
}
 
if (span->primitive != GL_POINT ||
(span->interpMask & SPAN_RGBA) ||
ctx->Point.PointSprite) {
/* for single-pixel points, we populated the arrays already */
interpolate_active_attribs(ctx, span, ~0);
}
span->array->ChanType = GL_FLOAT;
 
if (!(span->arrayMask & SPAN_Z))
_swrast_span_interpolate_z (ctx, span);
 
#if 0
if (inputsRead & VARYING_BIT_POS)
#else
/* XXX always interpolate wpos so that DDX/DDY work */
#endif
interpolate_wpos(ctx, span);
 
/* Run fragment program/shader now */
if (_swrast_use_fragment_program(ctx)) {
_swrast_exec_fragment_program(ctx, span);
}
else {
assert(ctx->ATIFragmentShader._Enabled);
_swrast_exec_fragment_shader(ctx, span);
}
}
else if (ctx->Texture._EnabledCoordUnits) {
/* conventional texturing */
 
#if CHAN_BITS == 32
if ((span->arrayAttribs & VARYING_BIT_COL0) == 0) {
interpolate_int_colors(ctx, span);
}
#else
if (!(span->arrayMask & SPAN_RGBA))
interpolate_int_colors(ctx, span);
#endif
if ((span->arrayAttribs & VARYING_BITS_TEX_ANY) == 0x0)
interpolate_texcoords(ctx, span);
 
_swrast_texture_span(ctx, span);
}
}
 
 
/** Put colors at x/y locations into a renderbuffer */
static void
put_values(struct gl_context *ctx, struct gl_renderbuffer *rb,
GLenum datatype,
GLuint count, const GLint x[], const GLint y[],
const void *values, const GLubyte *mask)
{
gl_pack_ubyte_rgba_func pack_ubyte = NULL;
gl_pack_float_rgba_func pack_float = NULL;
GLuint i;
 
if (datatype == GL_UNSIGNED_BYTE)
pack_ubyte = _mesa_get_pack_ubyte_rgba_function(rb->Format);
else
pack_float = _mesa_get_pack_float_rgba_function(rb->Format);
 
for (i = 0; i < count; i++) {
if (mask[i]) {
GLubyte *dst = _swrast_pixel_address(rb, x[i], y[i]);
 
if (datatype == GL_UNSIGNED_BYTE) {
pack_ubyte((const GLubyte *) values + 4 * i, dst);
}
else {
assert(datatype == GL_FLOAT);
pack_float((const GLfloat *) values + 4 * i, dst);
}
}
}
}
 
 
/** Put row of colors into renderbuffer */
void
_swrast_put_row(struct gl_context *ctx, struct gl_renderbuffer *rb,
GLenum datatype,
GLuint count, GLint x, GLint y,
const void *values, const GLubyte *mask)
{
GLubyte *dst = _swrast_pixel_address(rb, x, y);
 
if (!mask) {
if (datatype == GL_UNSIGNED_BYTE) {
_mesa_pack_ubyte_rgba_row(rb->Format, count,
(const GLubyte (*)[4]) values, dst);
}
else {
assert(datatype == GL_FLOAT);
_mesa_pack_float_rgba_row(rb->Format, count,
(const GLfloat (*)[4]) values, dst);
}
}
else {
const GLuint bpp = _mesa_get_format_bytes(rb->Format);
GLuint i, runLen, runStart;
/* We can't pass a 'mask' array to the _mesa_pack_rgba_row() functions
* so look for runs where mask=1...
*/
runLen = runStart = 0;
for (i = 0; i < count; i++) {
if (mask[i]) {
if (runLen == 0)
runStart = i;
runLen++;
}
 
if (!mask[i] || i == count - 1) {
/* might be the end of a run of pixels */
if (runLen > 0) {
if (datatype == GL_UNSIGNED_BYTE) {
_mesa_pack_ubyte_rgba_row(rb->Format, runLen,
(const GLubyte (*)[4]) values + runStart,
dst + runStart * bpp);
}
else {
assert(datatype == GL_FLOAT);
_mesa_pack_float_rgba_row(rb->Format, runLen,
(const GLfloat (*)[4]) values + runStart,
dst + runStart * bpp);
}
runLen = 0;
}
}
}
}
}
 
 
 
/**
* Apply all the per-fragment operations to a span.
* This now includes texturing (_swrast_write_texture_span() is history).
* This function may modify any of the array values in the span.
* span->interpMask and span->arrayMask may be changed but will be restored
* to their original values before returning.
*/
void
_swrast_write_rgba_span( struct gl_context *ctx, SWspan *span)
{
const SWcontext *swrast = SWRAST_CONTEXT(ctx);
const GLuint *colorMask = (GLuint *) ctx->Color.ColorMask;
const GLbitfield origInterpMask = span->interpMask;
const GLbitfield origArrayMask = span->arrayMask;
const GLbitfield64 origArrayAttribs = span->arrayAttribs;
const GLenum origChanType = span->array->ChanType;
void * const origRgba = span->array->rgba;
const GLboolean shader = (_swrast_use_fragment_program(ctx)
|| ctx->ATIFragmentShader._Enabled);
const GLboolean shaderOrTexture = shader || ctx->Texture._EnabledCoordUnits;
struct gl_framebuffer *fb = ctx->DrawBuffer;
 
/*
printf("%s() interp 0x%x array 0x%x\n", __func__,
span->interpMask, span->arrayMask);
*/
 
assert(span->primitive == GL_POINT ||
span->primitive == GL_LINE ||
span->primitive == GL_POLYGON ||
span->primitive == GL_BITMAP);
 
/* Fragment write masks */
if (span->arrayMask & SPAN_MASK) {
/* mask was initialized by caller, probably glBitmap */
span->writeAll = GL_FALSE;
}
else {
memset(span->array->mask, 1, span->end);
span->writeAll = GL_TRUE;
}
 
/* Clip to window/scissor box */
if (!clip_span(ctx, span)) {
return;
}
 
assert(span->end <= SWRAST_MAX_WIDTH);
 
/* Depth bounds test */
if (ctx->Depth.BoundsTest && fb->Visual.depthBits > 0) {
if (!_swrast_depth_bounds_test(ctx, span)) {
return;
}
}
 
#ifdef DEBUG
/* Make sure all fragments are within window bounds */
if (span->arrayMask & SPAN_XY) {
/* array of pixel locations */
GLuint i;
for (i = 0; i < span->end; i++) {
if (span->array->mask[i]) {
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);
}
}
}
#endif
 
/* Polygon Stippling */
if (ctx->Polygon.StippleFlag && span->primitive == GL_POLYGON) {
stipple_polygon_span(ctx, span);
}
 
/* This is the normal place to compute the fragment color/Z
* from texturing or shading.
*/
if (shaderOrTexture && !swrast->_DeferredTexture) {
shade_texture_span(ctx, span);
}
 
/* Do the alpha test */
if (ctx->Color.AlphaEnabled) {
if (!_swrast_alpha_test(ctx, span)) {
/* all fragments failed test */
goto end;
}
}
 
/* Stencil and Z testing */
if (ctx->Stencil._Enabled || ctx->Depth.Test) {
if (!(span->arrayMask & SPAN_Z))
_swrast_span_interpolate_z(ctx, span);
 
if (ctx->Transform.DepthClamp)
_swrast_depth_clamp_span(ctx, span);
 
if (ctx->Stencil._Enabled) {
/* Combined Z/stencil tests */
if (!_swrast_stencil_and_ztest_span(ctx, span)) {
/* all fragments failed test */
goto end;
}
}
else if (fb->Visual.depthBits > 0) {
/* Just regular depth testing */
assert(ctx->Depth.Test);
assert(span->arrayMask & SPAN_Z);
if (!_swrast_depth_test_span(ctx, span)) {
/* all fragments failed test */
goto end;
}
}
}
 
if (ctx->Query.CurrentOcclusionObject) {
/* update count of 'passed' fragments */
struct gl_query_object *q = ctx->Query.CurrentOcclusionObject;
GLuint i;
for (i = 0; i < span->end; i++)
q->Result += span->array->mask[i];
}
 
/* We had to wait until now to check for glColorMask(0,0,0,0) because of
* the occlusion test.
*/
if (fb->_NumColorDrawBuffers == 1 && colorMask[0] == 0x0) {
/* no colors to write */
goto end;
}
 
/* If we were able to defer fragment color computation to now, there's
* a good chance that many fragments will have already been killed by
* Z/stencil testing.
*/
if (shaderOrTexture && swrast->_DeferredTexture) {
shade_texture_span(ctx, span);
}
 
#if CHAN_BITS == 32
if ((span->arrayAttribs & VARYING_BIT_COL0) == 0) {
interpolate_active_attribs(ctx, span, VARYING_BIT_COL0);
}
#else
if ((span->arrayMask & SPAN_RGBA) == 0) {
interpolate_int_colors(ctx, span);
}
#endif
 
assert(span->arrayMask & SPAN_RGBA);
 
if (span->primitive == GL_BITMAP || !swrast->SpecularVertexAdd) {
/* Add primary and specular (diffuse + specular) colors */
if (!shader) {
if (ctx->Fog.ColorSumEnabled ||
(ctx->Light.Enabled &&
ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) {
add_specular(ctx, span);
}
}
}
 
/* Fog */
if (swrast->_FogEnabled) {
_swrast_fog_rgba_span(ctx, span);
}
 
/* Antialias coverage application */
if (span->arrayMask & SPAN_COVERAGE) {
apply_aa_coverage(span);
}
 
/* Clamp color/alpha values over the range [0.0, 1.0] before storage */
if (ctx->Color.ClampFragmentColor == GL_TRUE &&
span->array->ChanType == GL_FLOAT) {
clamp_colors(span);
}
 
/*
* Write to renderbuffers.
* Depending on glDrawBuffer() state and the which color outputs are
* written by the fragment shader, we may either replicate one color to
* all renderbuffers or write a different color to each renderbuffer.
* multiFragOutputs=TRUE for the later case.
*/
{
const GLuint numBuffers = fb->_NumColorDrawBuffers;
const struct gl_fragment_program *fp = ctx->FragmentProgram._Current;
const GLboolean multiFragOutputs =
_swrast_use_fragment_program(ctx)
&& fp->Base.OutputsWritten >= (1 << FRAG_RESULT_DATA0);
/* Save srcColorType because convert_color_type() can change it */
const GLenum srcColorType = span->array->ChanType;
GLuint buf;
 
for (buf = 0; buf < numBuffers; buf++) {
struct gl_renderbuffer *rb = fb->_ColorDrawBuffers[buf];
 
/* color[fragOutput] will be written to buffer[buf] */
 
if (rb) {
/* re-use one of the attribute array buffers for rgbaSave */
GLchan (*rgbaSave)[4] = (GLchan (*)[4]) span->array->attribs[0];
struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
const GLenum dstColorType = srb->ColorType;
 
assert(dstColorType == GL_UNSIGNED_BYTE ||
dstColorType == GL_FLOAT);
 
/* set span->array->rgba to colors for renderbuffer's datatype */
if (srcColorType != dstColorType) {
convert_color_type(span, srcColorType, dstColorType,
multiFragOutputs ? buf : 0);
}
else {
if (srcColorType == GL_UNSIGNED_BYTE) {
span->array->rgba = span->array->rgba8;
}
else {
span->array->rgba = (void *)
span->array->attribs[VARYING_SLOT_COL0];
}
}
 
if (!multiFragOutputs && numBuffers > 1) {
/* save colors for second, third renderbuffer writes */
memcpy(rgbaSave, span->array->rgba,
4 * span->end * sizeof(GLchan));
}
 
assert(rb->_BaseFormat == GL_RGBA ||
rb->_BaseFormat == GL_RGB ||
rb->_BaseFormat == GL_RED ||
rb->_BaseFormat == GL_RG ||
rb->_BaseFormat == GL_ALPHA);
 
if (ctx->Color.ColorLogicOpEnabled) {
_swrast_logicop_rgba_span(ctx, rb, span);
}
else if ((ctx->Color.BlendEnabled >> buf) & 1) {
_swrast_blend_span(ctx, rb, span);
}
 
if (colorMask[buf] != 0xffffffff) {
_swrast_mask_rgba_span(ctx, rb, span, buf);
}
 
if (span->arrayMask & SPAN_XY) {
/* array of pixel coords */
put_values(ctx, rb,
span->array->ChanType, span->end,
span->array->x, span->array->y,
span->array->rgba, span->array->mask);
}
else {
/* horizontal run of pixels */
_swrast_put_row(ctx, rb,
span->array->ChanType,
span->end, span->x, span->y,
span->array->rgba,
span->writeAll ? NULL: span->array->mask);
}
 
if (!multiFragOutputs && numBuffers > 1) {
/* restore original span values */
memcpy(span->array->rgba, rgbaSave,
4 * span->end * sizeof(GLchan));
}
 
} /* if rb */
} /* for buf */
}
 
end:
/* restore these values before returning */
span->interpMask = origInterpMask;
span->arrayMask = origArrayMask;
span->arrayAttribs = origArrayAttribs;
span->array->ChanType = origChanType;
span->array->rgba = origRgba;
}
 
 
/**
* Read float RGBA pixels from a renderbuffer. Clipping will be done to
* prevent reading ouside the buffer's boundaries.
* \param rgba the returned colors
*/
void
_swrast_read_rgba_span( struct gl_context *ctx, struct gl_renderbuffer *rb,
GLuint n, GLint x, GLint y,
GLvoid *rgba)
{
struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
GLenum dstType = GL_FLOAT;
const GLint bufWidth = (GLint) rb->Width;
const GLint bufHeight = (GLint) rb->Height;
 
if (y < 0 || y >= bufHeight || x + (GLint) n < 0 || x >= bufWidth) {
/* completely above, below, or right */
/* XXX maybe leave rgba values undefined? */
memset(rgba, 0, 4 * n * sizeof(GLchan));
}
else {
GLint skip, length;
GLubyte *src;
 
if (x < 0) {
/* left edge clipping */
skip = -x;
length = (GLint) n - skip;
if (length < 0) {
/* completely left of window */
return;
}
if (length > bufWidth) {
length = bufWidth;
}
}
else if ((GLint) (x + n) > bufWidth) {
/* right edge clipping */
skip = 0;
length = bufWidth - x;
if (length < 0) {
/* completely to right of window */
return;
}
}
else {
/* no clipping */
skip = 0;
length = (GLint) n;
}
 
assert(rb);
assert(rb->_BaseFormat == GL_RGBA ||
rb->_BaseFormat == GL_RGB ||
rb->_BaseFormat == GL_RG ||
rb->_BaseFormat == GL_RED ||
rb->_BaseFormat == GL_LUMINANCE ||
rb->_BaseFormat == GL_INTENSITY ||
rb->_BaseFormat == GL_LUMINANCE_ALPHA ||
rb->_BaseFormat == GL_ALPHA);
 
assert(srb->Map);
(void) srb; /* silence unused var warning */
 
src = _swrast_pixel_address(rb, x + skip, y);
 
if (dstType == GL_UNSIGNED_BYTE) {
_mesa_unpack_ubyte_rgba_row(rb->Format, length, src,
(GLubyte (*)[4]) rgba + skip);
}
else if (dstType == GL_FLOAT) {
_mesa_unpack_rgba_row(rb->Format, length, src,
(GLfloat (*)[4]) rgba + skip);
}
else {
_mesa_problem(ctx, "unexpected type in _swrast_read_rgba_span()");
}
}
}
 
 
/**
* Get colors at x/y positions with clipping.
* \param type type of values to return
*/
static void
get_values(struct gl_context *ctx, struct gl_renderbuffer *rb,
GLuint count, const GLint x[], const GLint y[],
void *values, GLenum type)
{
GLuint i;
 
for (i = 0; i < count; i++) {
if (x[i] >= 0 && y[i] >= 0 &&
x[i] < (GLint) rb->Width && y[i] < (GLint) rb->Height) {
/* inside */
const GLubyte *src = _swrast_pixel_address(rb, x[i], y[i]);
 
if (type == GL_UNSIGNED_BYTE) {
_mesa_unpack_ubyte_rgba_row(rb->Format, 1, src,
(GLubyte (*)[4]) values + i);
}
else if (type == GL_FLOAT) {
_mesa_unpack_rgba_row(rb->Format, 1, src,
(GLfloat (*)[4]) values + i);
}
else {
_mesa_problem(ctx, "unexpected type in get_values()");
}
}
}
}
 
 
/**
* Get row of colors with clipping.
* \param type type of values to return
*/
static void
get_row(struct gl_context *ctx, struct gl_renderbuffer *rb,
GLuint count, GLint x, GLint y,
GLvoid *values, GLenum type)
{
GLint skip = 0;
GLubyte *src;
 
if (y < 0 || y >= (GLint) rb->Height)
return; /* above or below */
 
if (x + (GLint) count <= 0 || x >= (GLint) rb->Width)
return; /* entirely left or right */
 
if (x + count > rb->Width) {
/* right clip */
GLint clip = x + count - rb->Width;
count -= clip;
}
 
if (x < 0) {
/* left clip */
skip = -x;
x = 0;
count -= skip;
}
 
src = _swrast_pixel_address(rb, x, y);
 
if (type == GL_UNSIGNED_BYTE) {
_mesa_unpack_ubyte_rgba_row(rb->Format, count, src,
(GLubyte (*)[4]) values + skip);
}
else if (type == GL_FLOAT) {
_mesa_unpack_rgba_row(rb->Format, count, src,
(GLfloat (*)[4]) values + skip);
}
else {
_mesa_problem(ctx, "unexpected type in get_row()");
}
}
 
 
/**
* Get RGBA pixels from the given renderbuffer.
* Used by blending, logicop and masking functions.
* \return pointer to the colors we read.
*/
void *
_swrast_get_dest_rgba(struct gl_context *ctx, struct gl_renderbuffer *rb,
SWspan *span)
{
void *rbPixels;
 
/* Point rbPixels to a temporary space */
rbPixels = span->array->attribs[VARYING_SLOT_MAX - 1];
 
/* Get destination values from renderbuffer */
if (span->arrayMask & SPAN_XY) {
get_values(ctx, rb, span->end, span->array->x, span->array->y,
rbPixels, span->array->ChanType);
}
else {
get_row(ctx, rb, span->end, span->x, span->y,
rbPixels, span->array->ChanType);
}
 
return rbPixels;
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_span.h
0,0 → 1,217
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
* Copyright (C) 2009 VMware, Inc. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_SPAN_H
#define S_SPAN_H
 
 
#include "main/config.h"
#include "main/glheader.h"
#include "main/mtypes.h"
#include "swrast/s_chan.h"
#include "swrast/swrast.h"
 
 
struct gl_context;
struct gl_renderbuffer;
 
 
/**
* \defgroup SpanFlags
* Special bitflags to describe span data.
*
* In general, the point/line/triangle functions interpolate/emit the
* attributes specified by swrast->_ActiveAttribs (i.e. FRAT_BIT_* values).
* Some things don't fit into that, though, so we have these flags.
*/
/*@{*/
#define SPAN_RGBA 0x01 /**< interpMask and arrayMask */
#define SPAN_Z 0x02 /**< interpMask and arrayMask */
#define SPAN_FLAT 0x04 /**< interpMask: flat shading? */
#define SPAN_XY 0x08 /**< array.x[], y[] valid? */
#define SPAN_MASK 0x10 /**< was array.mask[] filled in by caller? */
#define SPAN_LAMBDA 0x20 /**< array.lambda[] valid? */
#define SPAN_COVERAGE 0x40 /**< array.coverage[] valid? */
/*@}*/
 
 
/**
* \sw_span_arrays
* \brief Arrays of fragment values.
*
* These will either be computed from the span x/xStep values or
* filled in by glDraw/CopyPixels, etc.
* These arrays are separated out of sw_span to conserve memory.
*/
typedef struct sw_span_arrays
{
/** Per-fragment attributes (indexed by VARYING_SLOT_* tokens) */
/* XXX someday look at transposing first two indexes for better memory
* access pattern.
*/
GLfloat attribs[VARYING_SLOT_MAX][SWRAST_MAX_WIDTH][4];
 
/** This mask indicates which fragments are alive or culled */
GLubyte mask[SWRAST_MAX_WIDTH];
 
GLenum ChanType; /**< Color channel type, GL_UNSIGNED_BYTE, GL_FLOAT */
 
/** Attribute arrays that don't fit into attribs[] array above */
/*@{*/
GLubyte rgba8[SWRAST_MAX_WIDTH][4];
GLushort rgba16[SWRAST_MAX_WIDTH][4];
GLchan (*rgba)[4]; /** either == rgba8 or rgba16 */
GLint x[SWRAST_MAX_WIDTH]; /**< fragment X coords */
GLint y[SWRAST_MAX_WIDTH]; /**< fragment Y coords */
GLuint z[SWRAST_MAX_WIDTH]; /**< fragment Z coords */
GLuint index[SWRAST_MAX_WIDTH]; /**< Color indexes */
GLfloat lambda[MAX_TEXTURE_COORD_UNITS][SWRAST_MAX_WIDTH]; /**< Texture LOD */
GLfloat coverage[SWRAST_MAX_WIDTH]; /**< Fragment coverage for AA/smoothing */
/*@}*/
} SWspanarrays;
 
 
/**
* The SWspan structure describes the colors, Z, fogcoord, texcoords,
* etc for either a horizontal run or an array of independent pixels.
* We can either specify a base/step to indicate interpolated values, or
* fill in explicit arrays of values. The interpMask and arrayMask bitfields
* indicate which attributes are active interpolants or arrays, respectively.
*
* It would be interesting to experiment with multiprocessor rasterization
* with this structure. The triangle rasterizer could simply emit a
* stream of these structures which would be consumed by one or more
* span-processing threads which could run in parallel.
*/
typedef struct sw_span
{
/** Coord of first fragment in horizontal span/run */
GLint x, y;
 
/** Number of fragments in the span */
GLuint end;
 
/** for clipping left edge of spans */
GLuint leftClip;
 
/** This flag indicates that mask[] array is effectively filled with ones */
GLboolean writeAll;
 
/** either GL_POLYGON, GL_LINE, GL_POLYGON, GL_BITMAP */
GLenum primitive;
 
/** 0 = front-facing span, 1 = back-facing span (for two-sided stencil) */
GLuint facing;
 
/**
* This bitmask (of \link SpanFlags SPAN_* flags\endlink) indicates
* which of the attrStart/StepX/StepY variables are relevant.
*/
GLbitfield interpMask;
 
/** Fragment attribute interpolants */
GLfloat attrStart[VARYING_SLOT_MAX][4]; /**< initial value */
GLfloat attrStepX[VARYING_SLOT_MAX][4]; /**< dvalue/dx */
GLfloat attrStepY[VARYING_SLOT_MAX][4]; /**< dvalue/dy */
 
/* XXX the rest of these will go away eventually... */
 
/* For horizontal spans, step is the partial derivative wrt X.
* For lines, step is the delta from one fragment to the next.
*/
GLfixed red, redStep;
GLfixed green, greenStep;
GLfixed blue, blueStep;
GLfixed alpha, alphaStep;
GLfixed index, indexStep;
GLfixed z, zStep; /**< XXX z should probably be GLuint */
GLfixed intTex[2], intTexStep[2]; /**< (s,t) for unit[0] only */
 
/**
* This bitmask (of \link SpanFlags SPAN_* flags\endlink) indicates
* which of the fragment arrays in the span_arrays struct are relevant.
*/
GLbitfield arrayMask;
 
/** Mask of VARYING_BIT_x bits */
GLbitfield64 arrayAttribs;
 
/**
* We store the arrays of fragment values in a separate struct so
* that we can allocate sw_span structs on the stack without using
* a lot of memory. The span_arrays struct is about 1.4MB while the
* sw_span struct is only about 512 bytes.
*/
SWspanarrays *array;
} SWspan;
 
 
 
#define INIT_SPAN(S, PRIMITIVE) \
do { \
(S).primitive = (PRIMITIVE); \
(S).interpMask = 0x0; \
(S).arrayMask = 0x0; \
(S).arrayAttribs = 0x0; \
(S).end = 0; \
(S).leftClip = 0; \
(S).facing = 0; \
(S).array = SWRAST_CONTEXT(ctx)->SpanArrays; \
} while (0)
 
 
 
extern void
_swrast_span_default_attribs(struct gl_context *ctx, SWspan *span);
 
extern void
_swrast_span_interpolate_z( const struct gl_context *ctx, SWspan *span );
 
extern GLfloat
_swrast_compute_lambda(GLfloat dsdx, GLfloat dsdy, GLfloat dtdx, GLfloat dtdy,
GLfloat dqdx, GLfloat dqdy, GLfloat texW, GLfloat texH,
GLfloat s, GLfloat t, GLfloat q, GLfloat invQ);
 
 
extern void
_swrast_write_rgba_span( struct gl_context *ctx, SWspan *span);
 
 
extern void
_swrast_read_rgba_span(struct gl_context *ctx, struct gl_renderbuffer *rb,
GLuint n, GLint x, GLint y, GLvoid *rgba);
 
extern void
_swrast_put_row(struct gl_context *ctx, struct gl_renderbuffer *rb,
GLenum datatype,
GLuint count, GLint x, GLint y,
const void *values, const GLubyte *mask);
 
extern void *
_swrast_get_dest_rgba(struct gl_context *ctx, struct gl_renderbuffer *rb,
SWspan *span);
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_stencil.c
0,0 → 1,650
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#include "main/glheader.h"
#include "main/context.h"
#include "main/imports.h"
#include "main/format_pack.h"
#include "main/format_unpack.h"
#include "main/core.h"
#include "main/stencil.h"
 
#include "s_context.h"
#include "s_depth.h"
#include "s_stencil.h"
#include "s_span.h"
 
 
 
/* Stencil Logic:
 
IF stencil test fails THEN
Apply fail-op to stencil value
Don't write the pixel (RGBA,Z)
ELSE
IF doing depth test && depth test fails THEN
Apply zfail-op to stencil value
Write RGBA and Z to appropriate buffers
ELSE
Apply zpass-op to stencil value
ENDIF
 
*/
 
 
 
/**
* Compute/return the offset of the stencil value in a pixel.
* For example, if the format is Z24+S8, the position of the stencil bits
* within the 4-byte pixel will be either 0 or 3.
*/
static GLint
get_stencil_offset(mesa_format format)
{
const GLubyte one = 1;
GLubyte pixel[MAX_PIXEL_BYTES];
GLint bpp = _mesa_get_format_bytes(format);
GLint i;
 
assert(_mesa_get_format_bits(format, GL_STENCIL_BITS) == 8);
memset(pixel, 0, sizeof(pixel));
_mesa_pack_ubyte_stencil_row(format, 1, &one, pixel);
 
for (i = 0; i < bpp; i++) {
if (pixel[i])
return i;
}
 
_mesa_problem(NULL, "get_stencil_offset() failed\n");
return 0;
}
 
 
/** Clamp the stencil value to [0, 255] */
static inline GLubyte
clamp(GLint val)
{
if (val < 0)
return 0;
else if (val > 255)
return 255;
else
return val;
}
 
 
#define STENCIL_OP(NEW_VAL) \
if (invmask == 0) { \
for (i = j = 0; i < n; i++, j += stride) { \
if (mask[i]) { \
GLubyte s = stencil[j]; \
(void) s; \
stencil[j] = (GLubyte) (NEW_VAL); \
} \
} \
} \
else { \
for (i = j = 0; i < n; i++, j += stride) { \
if (mask[i]) { \
GLubyte s = stencil[j]; \
stencil[j] = (GLubyte) ((invmask & s) | (wrtmask & (NEW_VAL))); \
} \
} \
}
 
 
/**
* Apply the given stencil operator to the array of stencil values.
* Don't touch stencil[i] if mask[i] is zero.
* @param n number of stencil values
* @param oper the stencil buffer operator
* @param face 0 or 1 for front or back face operation
* @param stencil array of stencil values (in/out)
* @param mask array [n] of flag: 1=apply operator, 0=don't apply operator
* @param stride stride between stencil values
*/
static void
apply_stencil_op(const struct gl_context *ctx, GLenum oper, GLuint face,
GLuint n, GLubyte stencil[], const GLubyte mask[],
GLint stride)
{
const GLubyte ref = _mesa_get_stencil_ref(ctx, face);
const GLubyte wrtmask = ctx->Stencil.WriteMask[face];
const GLubyte invmask = (GLubyte) (~wrtmask);
GLuint i, j;
 
switch (oper) {
case GL_KEEP:
/* do nothing */
break;
case GL_ZERO:
/* replace stencil buf values with zero */
STENCIL_OP(0);
break;
case GL_REPLACE:
/* replace stencil buf values with ref value */
STENCIL_OP(ref);
break;
case GL_INCR:
/* increment stencil buf values, with clamping */
STENCIL_OP(clamp(s + 1));
break;
case GL_DECR:
/* increment stencil buf values, with clamping */
STENCIL_OP(clamp(s - 1));
break;
case GL_INCR_WRAP_EXT:
/* increment stencil buf values, without clamping */
STENCIL_OP(s + 1);
break;
case GL_DECR_WRAP_EXT:
/* increment stencil buf values, without clamping */
STENCIL_OP(s - 1);
break;
case GL_INVERT:
/* replace stencil buf values with inverted value */
STENCIL_OP(~s);
break;
default:
_mesa_problem(ctx, "Bad stencil op in apply_stencil_op");
}
}
 
 
 
#define STENCIL_TEST(FUNC) \
for (i = j = 0; i < n; i++, j += stride) { \
if (mask[i]) { \
s = (GLubyte) (stencil[j] & valueMask); \
if (FUNC) { \
/* stencil pass */ \
fail[i] = 0; \
} \
else { \
/* stencil fail */ \
fail[i] = 1; \
mask[i] = 0; \
} \
} \
else { \
fail[i] = 0; \
} \
}
 
 
 
/**
* Apply stencil test to an array of stencil values (before depth buffering).
* For the values that fail, we'll apply the GL_STENCIL_FAIL operator to
* the stencil values.
*
* @param face 0 or 1 for front or back-face polygons
* @param n number of pixels in the array
* @param stencil array of [n] stencil values (in/out)
* @param mask array [n] of flag: 0=skip the pixel, 1=stencil the pixel,
* values are set to zero where the stencil test fails.
* @param stride stride between stencil values
* @return GL_FALSE = all pixels failed, GL_TRUE = zero or more pixels passed.
*/
static GLboolean
do_stencil_test(struct gl_context *ctx, GLuint face, GLuint n,
GLubyte stencil[], GLubyte mask[], GLint stride)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
GLubyte *fail = swrast->stencil_temp.buf2;
GLboolean allfail = GL_FALSE;
GLuint i, j;
const GLuint valueMask = ctx->Stencil.ValueMask[face];
const GLubyte ref = (GLubyte) (_mesa_get_stencil_ref(ctx, face) & valueMask);
GLubyte s;
 
/*
* Perform stencil test. The results of this operation are stored
* in the fail[] array:
* IF fail[i] is non-zero THEN
* the stencil fail operator is to be applied
* ELSE
* the stencil fail operator is not to be applied
* ENDIF
*/
switch (ctx->Stencil.Function[face]) {
case GL_NEVER:
STENCIL_TEST(0);
allfail = GL_TRUE;
break;
case GL_LESS:
STENCIL_TEST(ref < s);
break;
case GL_LEQUAL:
STENCIL_TEST(ref <= s);
break;
case GL_GREATER:
STENCIL_TEST(ref > s);
break;
case GL_GEQUAL:
STENCIL_TEST(ref >= s);
break;
case GL_EQUAL:
STENCIL_TEST(ref == s);
break;
case GL_NOTEQUAL:
STENCIL_TEST(ref != s);
break;
case GL_ALWAYS:
STENCIL_TEST(1);
break;
default:
_mesa_problem(ctx, "Bad stencil func in gl_stencil_span");
return 0;
}
 
if (ctx->Stencil.FailFunc[face] != GL_KEEP) {
apply_stencil_op(ctx, ctx->Stencil.FailFunc[face], face, n, stencil,
fail, stride);
}
 
return !allfail;
}
 
 
/**
* Compute the zpass/zfail masks by comparing the pre- and post-depth test
* masks.
*/
static inline void
compute_pass_fail_masks(GLuint n, const GLubyte origMask[],
const GLubyte newMask[],
GLubyte passMask[], GLubyte failMask[])
{
GLuint i;
for (i = 0; i < n; i++) {
assert(newMask[i] == 0 || newMask[i] == 1);
passMask[i] = origMask[i] & newMask[i];
failMask[i] = origMask[i] & (newMask[i] ^ 1);
}
}
 
 
/**
* Get 8-bit stencil values from random locations in the stencil buffer.
*/
static void
get_s8_values(struct gl_context *ctx, struct gl_renderbuffer *rb,
GLuint count, const GLint x[], const GLint y[],
GLubyte stencil[])
{
struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
const GLint w = rb->Width, h = rb->Height;
const GLubyte *map = _swrast_pixel_address(rb, 0, 0);
GLuint i;
 
if (rb->Format == MESA_FORMAT_S_UINT8) {
const GLint rowStride = srb->RowStride;
for (i = 0; i < count; i++) {
if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) {
stencil[i] = *(map + y[i] * rowStride + x[i]);
}
}
}
else {
const GLint bpp = _mesa_get_format_bytes(rb->Format);
const GLint rowStride = srb->RowStride;
for (i = 0; i < count; i++) {
if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) {
const GLubyte *src = map + y[i] * rowStride + x[i] * bpp;
_mesa_unpack_ubyte_stencil_row(rb->Format, 1, src, &stencil[i]);
}
}
}
}
 
 
/**
* Put 8-bit stencil values at random locations into the stencil buffer.
*/
static void
put_s8_values(struct gl_context *ctx, struct gl_renderbuffer *rb,
GLuint count, const GLint x[], const GLint y[],
const GLubyte stencil[])
{
const GLint w = rb->Width, h = rb->Height;
gl_pack_ubyte_stencil_func pack_stencil =
_mesa_get_pack_ubyte_stencil_func(rb->Format);
GLuint i;
 
for (i = 0; i < count; i++) {
if (x[i] >= 0 && y[i] >= 0 && x[i] < w && y[i] < h) {
GLubyte *dst = _swrast_pixel_address(rb, x[i], y[i]);
pack_stencil(&stencil[i], dst);
}
}
}
 
 
/**
* /return GL_TRUE = one or more fragments passed,
* GL_FALSE = all fragments failed.
*/
GLboolean
_swrast_stencil_and_ztest_span(struct gl_context *ctx, SWspan *span)
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
struct gl_framebuffer *fb = ctx->DrawBuffer;
struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
const GLint stencilOffset = get_stencil_offset(rb->Format);
const GLint stencilStride = _mesa_get_format_bytes(rb->Format);
const GLuint face = (span->facing == 0) ? 0 : ctx->Stencil._BackFace;
const GLuint count = span->end;
GLubyte *mask = span->array->mask;
GLubyte *stencilTemp = swrast->stencil_temp.buf1;
GLubyte *stencilBuf;
 
if (span->arrayMask & SPAN_XY) {
/* read stencil values from random locations */
get_s8_values(ctx, rb, count, span->array->x, span->array->y,
stencilTemp);
stencilBuf = stencilTemp;
}
else {
/* Processing a horizontal run of pixels. Since stencil is always
* 8 bits for all MESA_FORMATs, we just need to use the right offset
* and stride to access them.
*/
stencilBuf = _swrast_pixel_address(rb, span->x, span->y) + stencilOffset;
}
 
/*
* Apply the stencil test to the fragments.
* failMask[i] is 1 if the stencil test failed.
*/
if (!do_stencil_test(ctx, face, count, stencilBuf, mask, stencilStride)) {
/* all fragments failed the stencil test, we're done. */
span->writeAll = GL_FALSE;
if (span->arrayMask & SPAN_XY) {
/* need to write the updated stencil values back to the buffer */
put_s8_values(ctx, rb, count, span->array->x, span->array->y,
stencilTemp);
}
return GL_FALSE;
}
 
/*
* Some fragments passed the stencil test, apply depth test to them
* and apply Zpass and Zfail stencil ops.
*/
if (ctx->Depth.Test == GL_FALSE ||
ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer == NULL) {
/*
* No depth buffer, just apply zpass stencil function to active pixels.
*/
apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face, count,
stencilBuf, mask, stencilStride);
}
else {
/*
* Perform depth buffering, then apply zpass or zfail stencil function.
*/
SWcontext *swrast = SWRAST_CONTEXT(ctx);
GLubyte *passMask = swrast->stencil_temp.buf2;
GLubyte *failMask = swrast->stencil_temp.buf3;
GLubyte *origMask = swrast->stencil_temp.buf4;
 
/* save the current mask bits */
memcpy(origMask, mask, count * sizeof(GLubyte));
 
/* apply the depth test */
_swrast_depth_test_span(ctx, span);
 
compute_pass_fail_masks(count, origMask, mask, passMask, failMask);
 
/* apply the pass and fail operations */
if (ctx->Stencil.ZFailFunc[face] != GL_KEEP) {
apply_stencil_op(ctx, ctx->Stencil.ZFailFunc[face], face,
count, stencilBuf, failMask, stencilStride);
}
if (ctx->Stencil.ZPassFunc[face] != GL_KEEP) {
apply_stencil_op(ctx, ctx->Stencil.ZPassFunc[face], face,
count, stencilBuf, passMask, stencilStride);
}
}
 
/* Write updated stencil values back into hardware stencil buffer */
if (span->arrayMask & SPAN_XY) {
put_s8_values(ctx, rb, count, span->array->x, span->array->y,
stencilBuf);
}
span->writeAll = GL_FALSE;
return GL_TRUE; /* one or more fragments passed both tests */
}
 
 
 
 
/**
* Return a span of stencil values from the stencil buffer.
* Used for glRead/CopyPixels
* Input: n - how many pixels
* x,y - location of first pixel
* Output: stencil - the array of stencil values
*/
void
_swrast_read_stencil_span(struct gl_context *ctx, struct gl_renderbuffer *rb,
GLint n, GLint x, GLint y, GLubyte stencil[])
{
GLubyte *src;
 
if (y < 0 || y >= (GLint) rb->Height ||
x + n <= 0 || x >= (GLint) rb->Width) {
/* span is completely outside framebuffer */
return; /* undefined values OK */
}
 
if (x < 0) {
GLint dx = -x;
x = 0;
n -= dx;
stencil += dx;
}
if (x + n > (GLint) rb->Width) {
GLint dx = x + n - rb->Width;
n -= dx;
}
if (n <= 0) {
return;
}
 
src = _swrast_pixel_address(rb, x, y);
_mesa_unpack_ubyte_stencil_row(rb->Format, n, src, stencil);
}
 
 
 
/**
* Write a span of stencil values to the stencil buffer. This function
* applies the stencil write mask when needed.
* Used for glDraw/CopyPixels
* Input: n - how many pixels
* x, y - location of first pixel
* stencil - the array of stencil values
*/
void
_swrast_write_stencil_span(struct gl_context *ctx, GLint n, GLint x, GLint y,
const GLubyte stencil[] )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
struct gl_framebuffer *fb = ctx->DrawBuffer;
struct gl_renderbuffer *rb = fb->Attachment[BUFFER_STENCIL].Renderbuffer;
const GLuint stencilMax = (1 << fb->Visual.stencilBits) - 1;
const GLuint stencilMask = ctx->Stencil.WriteMask[0];
GLubyte *stencilBuf;
 
if (y < 0 || y >= (GLint) rb->Height ||
x + n <= 0 || x >= (GLint) rb->Width) {
/* span is completely outside framebuffer */
return; /* undefined values OK */
}
if (x < 0) {
GLint dx = -x;
x = 0;
n -= dx;
stencil += dx;
}
if (x + n > (GLint) rb->Width) {
GLint dx = x + n - rb->Width;
n -= dx;
}
if (n <= 0) {
return;
}
 
stencilBuf = _swrast_pixel_address(rb, x, y);
 
if ((stencilMask & stencilMax) != stencilMax) {
/* need to apply writemask */
GLubyte *destVals = swrast->stencil_temp.buf1;
GLubyte *newVals = swrast->stencil_temp.buf2;
GLint i;
 
_mesa_unpack_ubyte_stencil_row(rb->Format, n, stencilBuf, destVals);
for (i = 0; i < n; i++) {
newVals[i]
= (stencil[i] & stencilMask) | (destVals[i] & ~stencilMask);
}
_mesa_pack_ubyte_stencil_row(rb->Format, n, newVals, stencilBuf);
}
else {
_mesa_pack_ubyte_stencil_row(rb->Format, n, stencil, stencilBuf);
}
}
 
 
 
/**
* Clear the stencil buffer. If the buffer is a combined
* depth+stencil buffer, only the stencil bits will be touched.
*/
void
_swrast_clear_stencil_buffer(struct gl_context *ctx)
{
struct gl_renderbuffer *rb =
ctx->DrawBuffer->Attachment[BUFFER_STENCIL].Renderbuffer;
const GLubyte stencilBits = ctx->DrawBuffer->Visual.stencilBits;
const GLuint writeMask = ctx->Stencil.WriteMask[0];
const GLuint stencilMax = (1 << stencilBits) - 1;
GLint x, y, width, height;
GLubyte *map;
GLint rowStride, i, j;
GLbitfield mapMode;
 
if (!rb || writeMask == 0)
return;
 
/* compute region to clear */
x = ctx->DrawBuffer->_Xmin;
y = ctx->DrawBuffer->_Ymin;
width = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin;
height = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin;
 
mapMode = GL_MAP_WRITE_BIT;
if ((writeMask & stencilMax) != stencilMax) {
/* need to mask stencil values */
mapMode |= GL_MAP_READ_BIT;
}
else if (_mesa_get_format_bits(rb->Format, GL_DEPTH_BITS) > 0) {
/* combined depth+stencil, need to mask Z values */
mapMode |= GL_MAP_READ_BIT;
}
 
ctx->Driver.MapRenderbuffer(ctx, rb, x, y, width, height,
mapMode, &map, &rowStride);
if (!map) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "glClear(stencil)");
return;
}
 
switch (rb->Format) {
case MESA_FORMAT_S_UINT8:
{
GLubyte clear = ctx->Stencil.Clear & writeMask & 0xff;
GLubyte mask = (~writeMask) & 0xff;
if (mask != 0) {
/* masked clear */
for (i = 0; i < height; i++) {
GLubyte *row = map;
for (j = 0; j < width; j++) {
row[j] = (row[j] & mask) | clear;
}
map += rowStride;
}
}
else if (rowStride == width) {
/* clear whole buffer */
memset(map, clear, width * height);
}
else {
/* clear scissored */
for (i = 0; i < height; i++) {
memset(map, clear, width);
map += rowStride;
}
}
}
break;
case MESA_FORMAT_Z24_UNORM_S8_UINT:
{
GLuint clear = (ctx->Stencil.Clear & writeMask & 0xff) << 24;
GLuint mask = (((~writeMask) & 0xff) << 24) | 0xffffff;
for (i = 0; i < height; i++) {
GLuint *row = (GLuint *) map;
for (j = 0; j < width; j++) {
row[j] = (row[j] & mask) | clear;
}
map += rowStride;
}
}
break;
case MESA_FORMAT_S8_UINT_Z24_UNORM:
{
GLuint clear = ctx->Stencil.Clear & writeMask & 0xff;
GLuint mask = 0xffffff00 | ((~writeMask) & 0xff);
for (i = 0; i < height; i++) {
GLuint *row = (GLuint *) map;
for (j = 0; j < width; j++) {
row[j] = (row[j] & mask) | clear;
}
map += rowStride;
}
}
break;
default:
_mesa_problem(ctx, "Unexpected stencil buffer format %s"
" in _swrast_clear_stencil_buffer()",
_mesa_get_format_name(rb->Format));
}
 
ctx->Driver.UnmapRenderbuffer(ctx, rb);
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_stencil.h
0,0 → 1,53
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_STENCIL_H
#define S_STENCIL_H
 
 
#include "main/mtypes.h"
#include "s_span.h"
 
 
 
extern GLboolean
_swrast_stencil_and_ztest_span(struct gl_context *ctx, SWspan *span);
 
 
extern void
_swrast_read_stencil_span(struct gl_context *ctx, struct gl_renderbuffer *rb,
GLint n, GLint x, GLint y, GLubyte stencil[]);
 
 
extern void
_swrast_write_stencil_span( struct gl_context *ctx, GLint n, GLint x, GLint y,
const GLubyte stencil[] );
 
 
extern void
_swrast_clear_stencil_buffer(struct gl_context *ctx);
 
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_texcombine.c
0,0 → 1,720
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
* Copyright (C) 2009 VMware, Inc. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#include "main/glheader.h"
#include "main/context.h"
#include "main/imports.h"
#include "main/macros.h"
#include "main/pixeltransfer.h"
#include "main/samplerobj.h"
#include "program/prog_instruction.h"
 
#include "s_context.h"
#include "s_texcombine.h"
 
 
/**
* Pointer to array of float[4]
* This type makes the code below more concise and avoids a lot of casting.
*/
typedef float (*float4_array)[4];
 
 
/**
* Return array of texels for given unit.
*/
static inline float4_array
get_texel_array(SWcontext *swrast, GLuint unit)
{
#ifdef _OPENMP
return (float4_array) (swrast->TexelBuffer + unit * SWRAST_MAX_WIDTH * 4 * omp_get_num_threads() + (SWRAST_MAX_WIDTH * 4 * omp_get_thread_num()));
#else
return (float4_array) (swrast->TexelBuffer + unit * SWRAST_MAX_WIDTH * 4);
#endif
}
 
 
 
/**
* Do texture application for:
* GL_EXT_texture_env_combine
* GL_ARB_texture_env_combine
* GL_EXT_texture_env_dot3
* GL_ARB_texture_env_dot3
* GL_ATI_texture_env_combine3
* GL_NV_texture_env_combine4
* conventional GL texture env modes
*
* \param ctx rendering context
* \param unit the texture combiner unit
* \param primary_rgba incoming fragment color array
* \param texelBuffer pointer to texel colors for all texture units
*
* \param span two fields are used in this function:
* span->end: number of fragments to process
* span->array->rgba: incoming/result fragment colors
*/
static void
texture_combine( struct gl_context *ctx, GLuint unit,
const float4_array primary_rgba,
const GLfloat *texelBuffer,
SWspan *span )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
const struct gl_texture_unit *textureUnit = &(ctx->Texture.Unit[unit]);
const struct gl_tex_env_combine_state *combine = textureUnit->_CurrentCombine;
float4_array argRGB[MAX_COMBINER_TERMS];
float4_array argA[MAX_COMBINER_TERMS];
const GLfloat scaleRGB = (GLfloat) (1 << combine->ScaleShiftRGB);
const GLfloat scaleA = (GLfloat) (1 << combine->ScaleShiftA);
const GLuint numArgsRGB = combine->_NumArgsRGB;
const GLuint numArgsA = combine->_NumArgsA;
float4_array ccolor[4], rgba;
GLuint i, term;
GLuint n = span->end;
GLchan (*rgbaChan)[4] = span->array->rgba;
 
/* alloc temp pixel buffers */
rgba = malloc(4 * n * sizeof(GLfloat));
if (!rgba) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_combine");
return;
}
 
for (i = 0; i < numArgsRGB || i < numArgsA; i++) {
ccolor[i] = malloc(4 * n * sizeof(GLfloat));
if (!ccolor[i]) {
while (i) {
free(ccolor[i]);
i--;
}
_mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_combine");
free(rgba);
return;
}
}
 
for (i = 0; i < n; i++) {
rgba[i][RCOMP] = CHAN_TO_FLOAT(rgbaChan[i][RCOMP]);
rgba[i][GCOMP] = CHAN_TO_FLOAT(rgbaChan[i][GCOMP]);
rgba[i][BCOMP] = CHAN_TO_FLOAT(rgbaChan[i][BCOMP]);
rgba[i][ACOMP] = CHAN_TO_FLOAT(rgbaChan[i][ACOMP]);
}
 
/*
printf("modeRGB 0x%x modeA 0x%x srcRGB1 0x%x srcA1 0x%x srcRGB2 0x%x srcA2 0x%x\n",
combine->ModeRGB,
combine->ModeA,
combine->SourceRGB[0],
combine->SourceA[0],
combine->SourceRGB[1],
combine->SourceA[1]);
*/
 
/*
* Do operand setup for up to 4 operands. Loop over the terms.
*/
for (term = 0; term < numArgsRGB; term++) {
const GLenum srcRGB = combine->SourceRGB[term];
const GLenum operandRGB = combine->OperandRGB[term];
 
switch (srcRGB) {
case GL_TEXTURE:
argRGB[term] = get_texel_array(swrast, unit);
break;
case GL_PRIMARY_COLOR:
argRGB[term] = primary_rgba;
break;
case GL_PREVIOUS:
argRGB[term] = rgba;
break;
case GL_CONSTANT:
{
float4_array c = ccolor[term];
GLfloat red = textureUnit->EnvColor[0];
GLfloat green = textureUnit->EnvColor[1];
GLfloat blue = textureUnit->EnvColor[2];
GLfloat alpha = textureUnit->EnvColor[3];
for (i = 0; i < n; i++) {
ASSIGN_4V(c[i], red, green, blue, alpha);
}
argRGB[term] = ccolor[term];
}
break;
/* GL_ATI_texture_env_combine3 allows GL_ZERO & GL_ONE as sources.
*/
case GL_ZERO:
{
float4_array c = ccolor[term];
for (i = 0; i < n; i++) {
ASSIGN_4V(c[i], 0.0F, 0.0F, 0.0F, 0.0F);
}
argRGB[term] = ccolor[term];
}
break;
case GL_ONE:
{
float4_array c = ccolor[term];
for (i = 0; i < n; i++) {
ASSIGN_4V(c[i], 1.0F, 1.0F, 1.0F, 1.0F);
}
argRGB[term] = ccolor[term];
}
break;
default:
/* ARB_texture_env_crossbar source */
{
const GLuint srcUnit = srcRGB - GL_TEXTURE0;
assert(srcUnit < ctx->Const.MaxTextureUnits);
if (!ctx->Texture.Unit[srcUnit]._Current)
goto end;
argRGB[term] = get_texel_array(swrast, srcUnit);
}
}
 
if (operandRGB != GL_SRC_COLOR) {
float4_array src = argRGB[term];
float4_array dst = ccolor[term];
 
/* point to new arg[term] storage */
argRGB[term] = ccolor[term];
 
switch (operandRGB) {
case GL_ONE_MINUS_SRC_COLOR:
for (i = 0; i < n; i++) {
dst[i][RCOMP] = 1.0F - src[i][RCOMP];
dst[i][GCOMP] = 1.0F - src[i][GCOMP];
dst[i][BCOMP] = 1.0F - src[i][BCOMP];
}
break;
case GL_SRC_ALPHA:
for (i = 0; i < n; i++) {
dst[i][RCOMP] =
dst[i][GCOMP] =
dst[i][BCOMP] = src[i][ACOMP];
}
break;
case GL_ONE_MINUS_SRC_ALPHA:
for (i = 0; i < n; i++) {
dst[i][RCOMP] =
dst[i][GCOMP] =
dst[i][BCOMP] = 1.0F - src[i][ACOMP];
}
break;
default:
_mesa_problem(ctx, "Bad operandRGB");
}
}
}
 
/*
* Set up the argA[term] pointers
*/
for (term = 0; term < numArgsA; term++) {
const GLenum srcA = combine->SourceA[term];
const GLenum operandA = combine->OperandA[term];
 
switch (srcA) {
case GL_TEXTURE:
argA[term] = get_texel_array(swrast, unit);
break;
case GL_PRIMARY_COLOR:
argA[term] = primary_rgba;
break;
case GL_PREVIOUS:
argA[term] = rgba;
break;
case GL_CONSTANT:
{
float4_array c = ccolor[term];
GLfloat alpha = textureUnit->EnvColor[3];
for (i = 0; i < n; i++)
c[i][ACOMP] = alpha;
argA[term] = ccolor[term];
}
break;
/* GL_ATI_texture_env_combine3 allows GL_ZERO & GL_ONE as sources.
*/
case GL_ZERO:
{
float4_array c = ccolor[term];
for (i = 0; i < n; i++)
c[i][ACOMP] = 0.0F;
argA[term] = ccolor[term];
}
break;
case GL_ONE:
{
float4_array c = ccolor[term];
for (i = 0; i < n; i++)
c[i][ACOMP] = 1.0F;
argA[term] = ccolor[term];
}
break;
default:
/* ARB_texture_env_crossbar source */
{
const GLuint srcUnit = srcA - GL_TEXTURE0;
assert(srcUnit < ctx->Const.MaxTextureUnits);
if (!ctx->Texture.Unit[srcUnit]._Current)
goto end;
argA[term] = get_texel_array(swrast, srcUnit);
}
}
 
if (operandA == GL_ONE_MINUS_SRC_ALPHA) {
float4_array src = argA[term];
float4_array dst = ccolor[term];
argA[term] = ccolor[term];
for (i = 0; i < n; i++) {
dst[i][ACOMP] = 1.0F - src[i][ACOMP];
}
}
}
 
/* RGB channel combine */
{
float4_array arg0 = argRGB[0];
float4_array arg1 = argRGB[1];
float4_array arg2 = argRGB[2];
float4_array arg3 = argRGB[3];
 
switch (combine->ModeRGB) {
case GL_REPLACE:
for (i = 0; i < n; i++) {
rgba[i][RCOMP] = arg0[i][RCOMP] * scaleRGB;
rgba[i][GCOMP] = arg0[i][GCOMP] * scaleRGB;
rgba[i][BCOMP] = arg0[i][BCOMP] * scaleRGB;
}
break;
case GL_MODULATE:
for (i = 0; i < n; i++) {
rgba[i][RCOMP] = arg0[i][RCOMP] * arg1[i][RCOMP] * scaleRGB;
rgba[i][GCOMP] = arg0[i][GCOMP] * arg1[i][GCOMP] * scaleRGB;
rgba[i][BCOMP] = arg0[i][BCOMP] * arg1[i][BCOMP] * scaleRGB;
}
break;
case GL_ADD:
if (textureUnit->EnvMode == GL_COMBINE4_NV) {
/* (a * b) + (c * d) */
for (i = 0; i < n; i++) {
rgba[i][RCOMP] = (arg0[i][RCOMP] * arg1[i][RCOMP] +
arg2[i][RCOMP] * arg3[i][RCOMP]) * scaleRGB;
rgba[i][GCOMP] = (arg0[i][GCOMP] * arg1[i][GCOMP] +
arg2[i][GCOMP] * arg3[i][GCOMP]) * scaleRGB;
rgba[i][BCOMP] = (arg0[i][BCOMP] * arg1[i][BCOMP] +
arg2[i][BCOMP] * arg3[i][BCOMP]) * scaleRGB;
}
}
else {
/* 2-term addition */
for (i = 0; i < n; i++) {
rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP]) * scaleRGB;
rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP]) * scaleRGB;
rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP]) * scaleRGB;
}
}
break;
case GL_ADD_SIGNED:
if (textureUnit->EnvMode == GL_COMBINE4_NV) {
/* (a * b) + (c * d) - 0.5 */
for (i = 0; i < n; i++) {
rgba[i][RCOMP] = (arg0[i][RCOMP] * arg1[i][RCOMP] +
arg2[i][RCOMP] * arg3[i][RCOMP] - 0.5F) * scaleRGB;
rgba[i][GCOMP] = (arg0[i][GCOMP] * arg1[i][GCOMP] +
arg2[i][GCOMP] * arg3[i][GCOMP] - 0.5F) * scaleRGB;
rgba[i][BCOMP] = (arg0[i][BCOMP] * arg1[i][BCOMP] +
arg2[i][BCOMP] * arg3[i][BCOMP] - 0.5F) * scaleRGB;
}
}
else {
for (i = 0; i < n; i++) {
rgba[i][RCOMP] = (arg0[i][RCOMP] + arg1[i][RCOMP] - 0.5F) * scaleRGB;
rgba[i][GCOMP] = (arg0[i][GCOMP] + arg1[i][GCOMP] - 0.5F) * scaleRGB;
rgba[i][BCOMP] = (arg0[i][BCOMP] + arg1[i][BCOMP] - 0.5F) * scaleRGB;
}
}
break;
case GL_INTERPOLATE:
for (i = 0; i < n; i++) {
rgba[i][RCOMP] = (arg0[i][RCOMP] * arg2[i][RCOMP] +
arg1[i][RCOMP] * (1.0F - arg2[i][RCOMP])) * scaleRGB;
rgba[i][GCOMP] = (arg0[i][GCOMP] * arg2[i][GCOMP] +
arg1[i][GCOMP] * (1.0F - arg2[i][GCOMP])) * scaleRGB;
rgba[i][BCOMP] = (arg0[i][BCOMP] * arg2[i][BCOMP] +
arg1[i][BCOMP] * (1.0F - arg2[i][BCOMP])) * scaleRGB;
}
break;
case GL_SUBTRACT:
for (i = 0; i < n; i++) {
rgba[i][RCOMP] = (arg0[i][RCOMP] - arg1[i][RCOMP]) * scaleRGB;
rgba[i][GCOMP] = (arg0[i][GCOMP] - arg1[i][GCOMP]) * scaleRGB;
rgba[i][BCOMP] = (arg0[i][BCOMP] - arg1[i][BCOMP]) * scaleRGB;
}
break;
case GL_DOT3_RGB_EXT:
case GL_DOT3_RGBA_EXT:
/* Do not scale the result by 1 2 or 4 */
for (i = 0; i < n; i++) {
GLfloat dot = ((arg0[i][RCOMP] - 0.5F) * (arg1[i][RCOMP] - 0.5F) +
(arg0[i][GCOMP] - 0.5F) * (arg1[i][GCOMP] - 0.5F) +
(arg0[i][BCOMP] - 0.5F) * (arg1[i][BCOMP] - 0.5F))
* 4.0F;
dot = CLAMP(dot, 0.0F, 1.0F);
rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = dot;
}
break;
case GL_DOT3_RGB:
case GL_DOT3_RGBA:
/* DO scale the result by 1 2 or 4 */
for (i = 0; i < n; i++) {
GLfloat dot = ((arg0[i][RCOMP] - 0.5F) * (arg1[i][RCOMP] - 0.5F) +
(arg0[i][GCOMP] - 0.5F) * (arg1[i][GCOMP] - 0.5F) +
(arg0[i][BCOMP] - 0.5F) * (arg1[i][BCOMP] - 0.5F))
* 4.0F * scaleRGB;
dot = CLAMP(dot, 0.0F, 1.0F);
rgba[i][RCOMP] = rgba[i][GCOMP] = rgba[i][BCOMP] = dot;
}
break;
case GL_MODULATE_ADD_ATI:
for (i = 0; i < n; i++) {
rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) +
arg1[i][RCOMP]) * scaleRGB;
rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) +
arg1[i][GCOMP]) * scaleRGB;
rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) +
arg1[i][BCOMP]) * scaleRGB;
}
break;
case GL_MODULATE_SIGNED_ADD_ATI:
for (i = 0; i < n; i++) {
rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) +
arg1[i][RCOMP] - 0.5F) * scaleRGB;
rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) +
arg1[i][GCOMP] - 0.5F) * scaleRGB;
rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) +
arg1[i][BCOMP] - 0.5F) * scaleRGB;
}
break;
case GL_MODULATE_SUBTRACT_ATI:
for (i = 0; i < n; i++) {
rgba[i][RCOMP] = ((arg0[i][RCOMP] * arg2[i][RCOMP]) -
arg1[i][RCOMP]) * scaleRGB;
rgba[i][GCOMP] = ((arg0[i][GCOMP] * arg2[i][GCOMP]) -
arg1[i][GCOMP]) * scaleRGB;
rgba[i][BCOMP] = ((arg0[i][BCOMP] * arg2[i][BCOMP]) -
arg1[i][BCOMP]) * scaleRGB;
}
break;
default:
_mesa_problem(ctx, "invalid combine mode");
}
}
 
/* Alpha channel combine */
{
float4_array arg0 = argA[0];
float4_array arg1 = argA[1];
float4_array arg2 = argA[2];
float4_array arg3 = argA[3];
 
switch (combine->ModeA) {
case GL_REPLACE:
for (i = 0; i < n; i++) {
rgba[i][ACOMP] = arg0[i][ACOMP] * scaleA;
}
break;
case GL_MODULATE:
for (i = 0; i < n; i++) {
rgba[i][ACOMP] = arg0[i][ACOMP] * arg1[i][ACOMP] * scaleA;
}
break;
case GL_ADD:
if (textureUnit->EnvMode == GL_COMBINE4_NV) {
/* (a * b) + (c * d) */
for (i = 0; i < n; i++) {
rgba[i][ACOMP] = (arg0[i][ACOMP] * arg1[i][ACOMP] +
arg2[i][ACOMP] * arg3[i][ACOMP]) * scaleA;
}
}
else {
/* two-term add */
for (i = 0; i < n; i++) {
rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP]) * scaleA;
}
}
break;
case GL_ADD_SIGNED:
if (textureUnit->EnvMode == GL_COMBINE4_NV) {
/* (a * b) + (c * d) - 0.5 */
for (i = 0; i < n; i++) {
rgba[i][ACOMP] = (arg0[i][ACOMP] * arg1[i][ACOMP] +
arg2[i][ACOMP] * arg3[i][ACOMP] -
0.5F) * scaleA;
}
}
else {
/* a + b - 0.5 */
for (i = 0; i < n; i++) {
rgba[i][ACOMP] = (arg0[i][ACOMP] + arg1[i][ACOMP] - 0.5F) * scaleA;
}
}
break;
case GL_INTERPOLATE:
for (i = 0; i < n; i++) {
rgba[i][ACOMP] = (arg0[i][ACOMP] * arg2[i][ACOMP] +
arg1[i][ACOMP] * (1.0F - arg2[i][ACOMP]))
* scaleA;
}
break;
case GL_SUBTRACT:
for (i = 0; i < n; i++) {
rgba[i][ACOMP] = (arg0[i][ACOMP] - arg1[i][ACOMP]) * scaleA;
}
break;
case GL_MODULATE_ADD_ATI:
for (i = 0; i < n; i++) {
rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP])
+ arg1[i][ACOMP]) * scaleA;
}
break;
case GL_MODULATE_SIGNED_ADD_ATI:
for (i = 0; i < n; i++) {
rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP]) +
arg1[i][ACOMP] - 0.5F) * scaleA;
}
break;
case GL_MODULATE_SUBTRACT_ATI:
for (i = 0; i < n; i++) {
rgba[i][ACOMP] = ((arg0[i][ACOMP] * arg2[i][ACOMP])
- arg1[i][ACOMP]) * scaleA;
}
break;
default:
_mesa_problem(ctx, "invalid combine mode");
}
}
 
/* Fix the alpha component for GL_DOT3_RGBA_EXT/ARB combining.
* This is kind of a kludge. It would have been better if the spec
* were written such that the GL_COMBINE_ALPHA value could be set to
* GL_DOT3.
*/
if (combine->ModeRGB == GL_DOT3_RGBA_EXT ||
combine->ModeRGB == GL_DOT3_RGBA) {
for (i = 0; i < n; i++) {
rgba[i][ACOMP] = rgba[i][RCOMP];
}
}
 
for (i = 0; i < n; i++) {
UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][RCOMP], rgba[i][RCOMP]);
UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][GCOMP], rgba[i][GCOMP]);
UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][BCOMP], rgba[i][BCOMP]);
UNCLAMPED_FLOAT_TO_CHAN(rgbaChan[i][ACOMP], rgba[i][ACOMP]);
}
/* The span->array->rgba values are of CHAN type so set
* span->array->ChanType field accordingly.
*/
span->array->ChanType = CHAN_TYPE;
 
end:
for (i = 0; i < numArgsRGB || i < numArgsA; i++) {
free(ccolor[i]);
}
free(rgba);
}
 
 
/**
* Apply X/Y/Z/W/0/1 swizzle to an array of colors/texels.
* See GL_EXT_texture_swizzle.
*/
static void
swizzle_texels(GLuint swizzle, GLuint count, float4_array texels)
{
const GLuint swzR = GET_SWZ(swizzle, 0);
const GLuint swzG = GET_SWZ(swizzle, 1);
const GLuint swzB = GET_SWZ(swizzle, 2);
const GLuint swzA = GET_SWZ(swizzle, 3);
GLfloat vector[6];
GLuint i;
 
vector[SWIZZLE_ZERO] = 0;
vector[SWIZZLE_ONE] = 1.0F;
 
for (i = 0; i < count; i++) {
vector[SWIZZLE_X] = texels[i][0];
vector[SWIZZLE_Y] = texels[i][1];
vector[SWIZZLE_Z] = texels[i][2];
vector[SWIZZLE_W] = texels[i][3];
texels[i][RCOMP] = vector[swzR];
texels[i][GCOMP] = vector[swzG];
texels[i][BCOMP] = vector[swzB];
texels[i][ACOMP] = vector[swzA];
}
}
 
 
/**
* Apply texture mapping to a span of fragments.
*/
void
_swrast_texture_span( struct gl_context *ctx, SWspan *span )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
float4_array primary_rgba;
GLuint unit;
 
if (!swrast->TexelBuffer) {
#ifdef _OPENMP
const GLint maxThreads = omp_get_max_threads();
 
/* TexelBuffer memory allocation needs to be done in a critical section
* as this code runs in a parallel loop.
* When entering the section, first check if TexelBuffer has been
* initialized already by another thread while this thread was waiting.
*/
#pragma omp critical
if (!swrast->TexelBuffer) {
#else
const GLint maxThreads = 1;
#endif
 
/* TexelBuffer is also global and normally shared by all SWspan
* instances; when running with multiple threads, create one per
* thread.
*/
swrast->TexelBuffer =
malloc(ctx->Const.Program[MESA_SHADER_FRAGMENT].MaxTextureImageUnits * maxThreads *
SWRAST_MAX_WIDTH * 4 * sizeof(GLfloat));
#ifdef _OPENMP
} /* critical section */
#endif
 
if (!swrast->TexelBuffer) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_combine");
return;
}
}
 
primary_rgba = malloc(span->end * 4 * sizeof(GLfloat));
 
if (!primary_rgba) {
_mesa_error(ctx, GL_OUT_OF_MEMORY, "texture_span");
return;
}
 
assert(span->end <= SWRAST_MAX_WIDTH);
 
/*
* Save copy of the incoming fragment colors (the GL_PRIMARY_COLOR)
*/
if (swrast->_TextureCombinePrimary) {
GLuint i;
for (i = 0; i < span->end; i++) {
primary_rgba[i][RCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][RCOMP]);
primary_rgba[i][GCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][GCOMP]);
primary_rgba[i][BCOMP] = CHAN_TO_FLOAT(span->array->rgba[i][BCOMP]);
primary_rgba[i][ACOMP] = CHAN_TO_FLOAT(span->array->rgba[i][ACOMP]);
}
}
 
/*
* Must do all texture sampling before combining in order to
* accommodate GL_ARB_texture_env_crossbar.
*/
for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit];
if (texUnit->_Current) {
const GLfloat (*texcoords)[4] = (const GLfloat (*)[4])
span->array->attribs[VARYING_SLOT_TEX0 + unit];
const struct gl_texture_object *curObj = texUnit->_Current;
const struct gl_sampler_object *samp = _mesa_get_samplerobj(ctx, unit);
GLfloat *lambda = span->array->lambda[unit];
float4_array texels = get_texel_array(swrast, unit);
 
/* adjust texture lod (lambda) */
if (span->arrayMask & SPAN_LAMBDA) {
if (texUnit->LodBias + samp->LodBias != 0.0F) {
/* apply LOD bias, but don't clamp yet */
const GLfloat bias = CLAMP(texUnit->LodBias + samp->LodBias,
-ctx->Const.MaxTextureLodBias,
ctx->Const.MaxTextureLodBias);
GLuint i;
for (i = 0; i < span->end; i++) {
lambda[i] += bias;
}
}
 
if (samp->MinLod != -1000.0 ||
samp->MaxLod != 1000.0) {
/* apply LOD clamping to lambda */
const GLfloat min = samp->MinLod;
const GLfloat max = samp->MaxLod;
GLuint i;
for (i = 0; i < span->end; i++) {
GLfloat l = lambda[i];
lambda[i] = CLAMP(l, min, max);
}
}
}
else if (samp->MaxAnisotropy > 1.0 &&
samp->MinFilter == GL_LINEAR_MIPMAP_LINEAR) {
/* sample_lambda_2d_aniso is beeing used as texture_sample_func,
* it requires the current SWspan *span as an additional parameter.
* In order to keep the same function signature, the unused lambda
* parameter will be modified to actually contain the SWspan pointer.
* This is a Hack. To make it right, the texture_sample_func
* signature and all implementing functions need to be modified.
*/
/* "hide" SWspan struct; cast to (GLfloat *) to suppress warning */
lambda = (GLfloat *)span;
}
 
/* Sample the texture (span->end = number of fragments) */
swrast->TextureSample[unit]( ctx, samp,
ctx->Texture.Unit[unit]._Current,
span->end, texcoords, lambda, texels );
 
/* GL_EXT_texture_swizzle */
if (curObj->_Swizzle != SWIZZLE_NOOP) {
swizzle_texels(curObj->_Swizzle, span->end, texels);
}
}
}
 
/*
* OK, now apply the texture (aka texture combine/blend).
* We modify the span->color.rgba values.
*/
for (unit = 0; unit < ctx->Const.MaxTextureUnits; unit++) {
if (ctx->Texture.Unit[unit]._Current)
texture_combine(ctx, unit, primary_rgba, swrast->TexelBuffer, span);
}
 
free(primary_rgba);
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_texcombine.h
0,0 → 1,37
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_TEXCOMBINE_H
#define S_TEXCOMBINE_H
 
 
#include "s_span.h"
 
struct gl_context;
 
extern void
_swrast_texture_span( struct gl_context *ctx, SWspan *span );
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_texfetch.c
0,0 → 1,627
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
* Copyright (c) 2009 VMware, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
/**
* \file s_texfetch.c
*
* Texel fetch/store functions
*
* \author Gareth Hughes
*/
 
 
#include "main/macros.h"
#include "main/texcompress.h"
#include "main/texcompress_fxt1.h"
#include "main/texcompress_s3tc.h"
#include "main/texcompress_rgtc.h"
#include "main/texcompress_etc.h"
#include "main/teximage.h"
#include "main/samplerobj.h"
#include "s_context.h"
#include "s_texfetch.h"
#include "../../gallium/auxiliary/util/u_format_rgb9e5.h"
#include "../../gallium/auxiliary/util/u_format_r11g11b10f.h"
#include "util/format_srgb.h"
 
 
/* Texel fetch routines for all supported formats
*/
#define DIM 1
#include "s_texfetch_tmp.h"
 
#define DIM 2
#include "s_texfetch_tmp.h"
 
#define DIM 3
#include "s_texfetch_tmp.h"
 
 
/**
* All compressed texture texel fetching is done though this function.
* Basically just call a core-Mesa texel fetch function.
*/
static void
fetch_compressed(const struct swrast_texture_image *swImage,
GLint i, GLint j, GLint k, GLfloat *texel)
{
/* The FetchCompressedTexel function takes an integer pixel rowstride,
* while the image's rowstride is bytes per row of blocks.
*/
GLuint bw, bh;
GLuint texelBytes = _mesa_get_format_bytes(swImage->Base.TexFormat);
_mesa_get_format_block_size(swImage->Base.TexFormat, &bw, &bh);
assert(swImage->RowStride * bw % texelBytes == 0);
 
swImage->FetchCompressedTexel(swImage->ImageSlices[k],
swImage->RowStride * bw / texelBytes,
i, j, texel);
}
 
 
 
/**
* Null texel fetch function.
*
* Have to have this so the FetchTexel function pointer is never NULL.
*/
static void fetch_null_texelf( const struct swrast_texture_image *texImage,
GLint i, GLint j, GLint k, GLfloat *texel )
{
(void) texImage; (void) i; (void) j; (void) k;
texel[RCOMP] = 0.0;
texel[GCOMP] = 0.0;
texel[BCOMP] = 0.0;
texel[ACOMP] = 0.0;
_mesa_warning(NULL, "fetch_null_texelf() called!");
}
 
 
#define FETCH_FUNCS(NAME) \
{ \
MESA_FORMAT_ ## NAME, \
fetch_texel_1d_ ## NAME, \
fetch_texel_2d_ ## NAME, \
fetch_texel_3d_ ## NAME, \
}
 
#define FETCH_NULL(NAME) \
{ \
MESA_FORMAT_ ## NAME, \
NULL, \
NULL, \
NULL \
}
 
/**
* Table to map MESA_FORMAT_ to texel fetch/store funcs.
*/
static struct {
mesa_format Name;
FetchTexelFunc Fetch1D;
FetchTexelFunc Fetch2D;
FetchTexelFunc Fetch3D;
}
texfetch_funcs[] =
{
{
MESA_FORMAT_NONE,
fetch_null_texelf,
fetch_null_texelf,
fetch_null_texelf
},
 
/* Packed unorm formats */
FETCH_FUNCS(A8B8G8R8_UNORM),
FETCH_FUNCS(X8B8G8R8_UNORM),
FETCH_FUNCS(R8G8B8A8_UNORM),
FETCH_FUNCS(R8G8B8X8_UNORM),
FETCH_FUNCS(B8G8R8A8_UNORM),
FETCH_FUNCS(B8G8R8X8_UNORM),
FETCH_FUNCS(A8R8G8B8_UNORM),
FETCH_FUNCS(X8R8G8B8_UNORM),
FETCH_FUNCS(L16A16_UNORM),
FETCH_FUNCS(A16L16_UNORM),
FETCH_FUNCS(B5G6R5_UNORM),
FETCH_FUNCS(R5G6B5_UNORM),
FETCH_FUNCS(B4G4R4A4_UNORM),
FETCH_NULL(B4G4R4X4_UNORM),
FETCH_FUNCS(A4R4G4B4_UNORM),
FETCH_FUNCS(A1B5G5R5_UNORM),
FETCH_FUNCS(B5G5R5A1_UNORM),
FETCH_NULL(B5G5R5X1_UNORM),
FETCH_FUNCS(A1R5G5B5_UNORM),
FETCH_FUNCS(L8A8_UNORM),
FETCH_FUNCS(A8L8_UNORM),
FETCH_FUNCS(R8G8_UNORM),
FETCH_FUNCS(G8R8_UNORM),
FETCH_FUNCS(L4A4_UNORM),
FETCH_FUNCS(B2G3R3_UNORM),
FETCH_FUNCS(R16G16_UNORM),
FETCH_FUNCS(G16R16_UNORM),
FETCH_FUNCS(B10G10R10A2_UNORM),
FETCH_NULL(B10G10R10X2_UNORM),
FETCH_FUNCS(R10G10B10A2_UNORM),
FETCH_NULL(R10G10B10X2_UNORM),
 
FETCH_FUNCS(S8_UINT_Z24_UNORM),
{
MESA_FORMAT_X8_UINT_Z24_UNORM,
fetch_texel_1d_S8_UINT_Z24_UNORM,
fetch_texel_2d_S8_UINT_Z24_UNORM,
fetch_texel_3d_S8_UINT_Z24_UNORM
},
FETCH_FUNCS(Z24_UNORM_S8_UINT),
{
MESA_FORMAT_Z24_UNORM_X8_UINT,
fetch_texel_1d_Z24_UNORM_S8_UINT,
fetch_texel_2d_Z24_UNORM_S8_UINT,
fetch_texel_3d_Z24_UNORM_S8_UINT
},
FETCH_NULL(R3G3B2_UNORM),
FETCH_NULL(A4B4G4R4_UNORM),
FETCH_NULL(R4G4B4A4_UNORM),
FETCH_NULL(R5G5B5A1_UNORM),
FETCH_NULL(A2B10G10R10_UNORM),
FETCH_NULL(A2R10G10B10_UNORM),
 
FETCH_FUNCS(YCBCR),
FETCH_FUNCS(YCBCR_REV),
 
/* Array unorm formats */
FETCH_FUNCS(A_UNORM8),
FETCH_FUNCS(A_UNORM16),
FETCH_FUNCS(L_UNORM8),
FETCH_FUNCS(L_UNORM16),
FETCH_FUNCS(I_UNORM8),
FETCH_FUNCS(I_UNORM16),
FETCH_FUNCS(R_UNORM8),
FETCH_FUNCS(R_UNORM16),
FETCH_FUNCS(BGR_UNORM8),
FETCH_FUNCS(RGB_UNORM8),
FETCH_FUNCS(RGBA_UNORM16),
FETCH_FUNCS(RGBX_UNORM16),
FETCH_FUNCS(Z_UNORM16),
FETCH_FUNCS(Z_UNORM32),
FETCH_NULL(S_UINT8),
 
/* Packed signed/normalized formats */
FETCH_FUNCS(A8B8G8R8_SNORM),
FETCH_FUNCS(X8B8G8R8_SNORM),
FETCH_FUNCS(R8G8B8A8_SNORM),
FETCH_NULL(R8G8B8X8_SNORM),
FETCH_FUNCS(R16G16_SNORM),
FETCH_NULL(G16R16_SNORM),
FETCH_FUNCS(R8G8_SNORM),
FETCH_NULL(G8R8_SNORM),
FETCH_FUNCS(L8A8_SNORM),
FETCH_FUNCS(A8L8_SNORM),
 
/* Array signed/normalized formats */
FETCH_FUNCS(A_SNORM8),
FETCH_FUNCS(A_SNORM16),
FETCH_FUNCS(L_SNORM8),
FETCH_FUNCS(L_SNORM16),
FETCH_FUNCS(I_SNORM8),
FETCH_FUNCS(I_SNORM16),
FETCH_FUNCS(R_SNORM8),
FETCH_FUNCS(R_SNORM16),
FETCH_FUNCS(LA_SNORM16),
FETCH_FUNCS(RGB_SNORM16),
FETCH_FUNCS(RGBA_SNORM16),
FETCH_NULL(RGBX_SNORM16),
 
/* Packed sRGB formats */
FETCH_FUNCS(A8B8G8R8_SRGB),
FETCH_FUNCS(B8G8R8A8_SRGB),
FETCH_FUNCS(A8R8G8B8_SRGB),
FETCH_NULL(B8G8R8X8_SRGB),
FETCH_NULL(X8R8G8B8_SRGB),
FETCH_FUNCS(R8G8B8A8_SRGB),
FETCH_FUNCS(R8G8B8X8_SRGB),
FETCH_FUNCS(X8B8G8R8_SRGB),
FETCH_FUNCS(L8A8_SRGB),
FETCH_FUNCS(A8L8_SRGB),
 
/* Array sRGB formats */
FETCH_FUNCS(L_SRGB8),
FETCH_FUNCS(BGR_SRGB8),
 
/* Packed float formats */
FETCH_FUNCS(R9G9B9E5_FLOAT),
FETCH_FUNCS(R11G11B10_FLOAT),
FETCH_FUNCS(Z32_FLOAT_S8X24_UINT),
 
/* Array float formats */
FETCH_FUNCS(A_FLOAT16),
FETCH_FUNCS(A_FLOAT32),
FETCH_FUNCS(L_FLOAT16),
FETCH_FUNCS(L_FLOAT32),
FETCH_FUNCS(LA_FLOAT16),
FETCH_FUNCS(LA_FLOAT32),
FETCH_FUNCS(I_FLOAT16),
FETCH_FUNCS(I_FLOAT32),
FETCH_FUNCS(R_FLOAT16),
FETCH_FUNCS(R_FLOAT32),
FETCH_FUNCS(RG_FLOAT16),
FETCH_FUNCS(RG_FLOAT32),
FETCH_FUNCS(RGB_FLOAT16),
FETCH_FUNCS(RGB_FLOAT32),
FETCH_FUNCS(RGBA_FLOAT16),
FETCH_FUNCS(RGBA_FLOAT32),
FETCH_FUNCS(RGBX_FLOAT16),
FETCH_FUNCS(RGBX_FLOAT32),
{
MESA_FORMAT_Z_FLOAT32,
fetch_texel_1d_R_FLOAT32, /* Reuse the R32F functions. */
fetch_texel_2d_R_FLOAT32,
fetch_texel_3d_R_FLOAT32
},
 
/* Packed signed/unsigned non-normalized integer formats */
FETCH_NULL(B10G10R10A2_UINT),
FETCH_NULL(R10G10B10A2_UINT),
FETCH_NULL(A2B10G10R10_UINT),
FETCH_NULL(A2R10G10B10_UINT),
 
/* Array signed/unsigned non-normalized integer formats */
FETCH_NULL(A_UINT8),
FETCH_NULL(A_UINT16),
FETCH_NULL(A_UINT32),
FETCH_NULL(A_SINT8),
FETCH_NULL(A_SINT16),
FETCH_NULL(A_SINT32),
FETCH_NULL(I_UINT8),
FETCH_NULL(I_UINT16),
FETCH_NULL(I_UINT32),
FETCH_NULL(I_SINT8),
FETCH_NULL(I_SINT16),
FETCH_NULL(I_SINT32),
FETCH_NULL(L_UINT8),
FETCH_NULL(L_UINT16),
FETCH_NULL(L_UINT32),
FETCH_NULL(L_SINT8),
FETCH_NULL(L_SINT16),
FETCH_NULL(L_SINT32),
FETCH_NULL(LA_UINT8),
FETCH_NULL(LA_UINT16),
FETCH_NULL(LA_UINT32),
FETCH_NULL(LA_SINT8),
FETCH_NULL(LA_SINT16),
FETCH_NULL(LA_SINT32),
FETCH_NULL(R_UINT8),
FETCH_NULL(R_UINT16),
FETCH_NULL(R_UINT32),
FETCH_NULL(R_SINT8),
FETCH_NULL(R_SINT16),
FETCH_NULL(R_SINT32),
FETCH_NULL(RG_UINT8),
FETCH_NULL(RG_UINT16),
FETCH_NULL(RG_UINT32),
FETCH_NULL(RG_SINT8),
FETCH_NULL(RG_SINT16),
FETCH_NULL(RG_SINT32),
FETCH_NULL(RGB_UINT8),
FETCH_NULL(RGB_UINT16),
FETCH_NULL(RGB_UINT32),
FETCH_NULL(RGB_SINT8),
FETCH_NULL(RGB_SINT16),
FETCH_NULL(RGB_SINT32),
FETCH_FUNCS(RGBA_UINT8),
FETCH_FUNCS(RGBA_UINT16),
FETCH_FUNCS(RGBA_UINT32),
FETCH_FUNCS(RGBA_SINT8),
FETCH_FUNCS(RGBA_SINT16),
FETCH_FUNCS(RGBA_SINT32),
FETCH_NULL(RGBX_UINT8),
FETCH_NULL(RGBX_UINT16),
FETCH_NULL(RGBX_UINT32),
FETCH_NULL(RGBX_SINT8),
FETCH_NULL(RGBX_SINT16),
FETCH_NULL(RGBX_SINT32),
 
/* DXT compressed formats */
{
MESA_FORMAT_RGB_DXT1,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_RGBA_DXT1,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_RGBA_DXT3,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_RGBA_DXT5,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
 
/* DXT sRGB compressed formats */
{
MESA_FORMAT_SRGB_DXT1,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_SRGBA_DXT1,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_SRGBA_DXT3,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_SRGBA_DXT5,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
 
/* FXT1 compressed formats */
{
MESA_FORMAT_RGB_FXT1,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_RGBA_FXT1,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
 
/* RGTC compressed formats */
{
MESA_FORMAT_R_RGTC1_UNORM,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_R_RGTC1_SNORM,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_RG_RGTC2_UNORM,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_RG_RGTC2_SNORM,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
 
/* LATC1/2 compressed formats */
{
MESA_FORMAT_L_LATC1_UNORM,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_L_LATC1_SNORM,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_LA_LATC2_UNORM,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_LA_LATC2_SNORM,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
 
/* ETC1/2 compressed formats */
{
MESA_FORMAT_ETC1_RGB8,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_ETC2_RGB8,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_ETC2_SRGB8,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_ETC2_RGBA8_EAC,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_ETC2_SRGB8_ALPHA8_EAC,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_ETC2_R11_EAC,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_ETC2_RG11_EAC,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_ETC2_SIGNED_R11_EAC,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_ETC2_SIGNED_RG11_EAC,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_ETC2_RGB8_PUNCHTHROUGH_ALPHA1,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_ETC2_SRGB8_PUNCHTHROUGH_ALPHA1,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_BPTC_RGBA_UNORM,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_BPTC_SRGB_ALPHA_UNORM,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_BPTC_RGB_SIGNED_FLOAT,
fetch_compressed,
fetch_compressed,
fetch_compressed
},
{
MESA_FORMAT_BPTC_RGB_UNSIGNED_FLOAT,
fetch_compressed,
fetch_compressed,
fetch_compressed
}
};
 
 
/**
* Initialize the texture image's FetchTexel methods.
*/
static void
set_fetch_functions(const struct gl_sampler_object *samp,
struct swrast_texture_image *texImage, GLuint dims)
{
mesa_format format = texImage->Base.TexFormat;
 
#ifdef DEBUG
/* check that the table entries are sorted by format name */
mesa_format fmt;
for (fmt = 0; fmt < MESA_FORMAT_COUNT; fmt++) {
assert(texfetch_funcs[fmt].Name == fmt);
}
#endif
 
STATIC_ASSERT(ARRAY_SIZE(texfetch_funcs) == MESA_FORMAT_COUNT);
 
if (samp->sRGBDecode == GL_SKIP_DECODE_EXT &&
_mesa_get_format_color_encoding(format) == GL_SRGB) {
format = _mesa_get_srgb_format_linear(format);
}
 
assert(format < MESA_FORMAT_COUNT);
 
switch (dims) {
case 1:
texImage->FetchTexel = texfetch_funcs[format].Fetch1D;
break;
case 2:
texImage->FetchTexel = texfetch_funcs[format].Fetch2D;
break;
case 3:
texImage->FetchTexel = texfetch_funcs[format].Fetch3D;
break;
default:
assert(!"Bad dims in set_fetch_functions()");
}
 
texImage->FetchCompressedTexel = _mesa_get_compressed_fetch_func(format);
 
assert(texImage->FetchTexel);
}
 
void
_mesa_update_fetch_functions(struct gl_context *ctx, GLuint unit)
{
struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
struct gl_sampler_object *samp;
GLuint face, i;
GLuint dims;
 
if (!texObj)
return;
 
samp = _mesa_get_samplerobj(ctx, unit);
 
dims = _mesa_get_texture_dimensions(texObj->Target);
 
for (face = 0; face < 6; face++) {
for (i = 0; i < MAX_TEXTURE_LEVELS; i++) {
if (texObj->Image[face][i]) {
set_fetch_functions(samp,
swrast_texture_image(texObj->Image[face][i]),
dims);
}
}
}
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_texfetch.h
0,0 → 1,35
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
* Copyright (c) 2009 VMware, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_TEXFETCH_H
#define S_TEXFETCH_H
 
#include "swrast/s_context.h"
 
void
_mesa_update_fetch_functions(struct gl_context *ctx, GLuint unit);
 
#endif /* S_TEXFETCH_H */
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_texfetch_tmp.h
0,0 → 1,196
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
* Copyright (c) 2008-2009 VMware, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
/**
* \file texfetch_tmp.h
* Texel fetch functions template.
*
* This template file is used by texfetch.c to generate texel fetch functions
* for 1-D, 2-D and 3-D texture images.
*
* It should be expanded by defining \p DIM as the number texture dimensions
* (1, 2 or 3). According to the value of \p DIM a series of macros is defined
* for the texel lookup in the gl_texture_image::Data.
*
* \author Gareth Hughes
* \author Brian Paul
*/
 
#include <format_unpack.h>
 
#if DIM == 1
 
#define TEXEL_ADDR( type, image, i, j, k, size ) \
((void) (j), (void) (k), ((type *)(image)->ImageSlices[0] + (i) * (size)))
 
#define FETCH(x) fetch_texel_1d_##x
 
#elif DIM == 2
 
#define TEXEL_ADDR( type, image, i, j, k, size ) \
((void) (k), \
((type *)((GLubyte *) (image)->ImageSlices[0] + (image)->RowStride * (j)) + \
(i) * (size)))
 
#define FETCH(x) fetch_texel_2d_##x
 
#elif DIM == 3
 
#define TEXEL_ADDR( type, image, i, j, k, size ) \
((type *)((GLubyte *) (image)->ImageSlices[k] + \
(image)->RowStride * (j)) + (i) * (size))
 
#define FETCH(x) fetch_texel_3d_##x
 
#else
#error illegal number of texture dimensions
#endif
 
#define FETCH_Z(x, type, size) \
static void \
FETCH(x) (const struct swrast_texture_image *texImage, \
GLint i, GLint j, GLint k, GLfloat *texel) \
{ \
const type *src = TEXEL_ADDR(type, texImage, i, j, k, size); \
_mesa_unpack_float_z_row(MESA_FORMAT_##x, 1, src, texel); \
}
 
#define FETCH_RGBA(x, type, size) \
static void \
FETCH(x) (const struct swrast_texture_image *texImage, \
GLint i, GLint j, GLint k, GLfloat *texel) \
{ \
const type *src = TEXEL_ADDR(type, texImage, i, j, k, size); \
_mesa_unpack_rgba_row(MESA_FORMAT_##x, 1, src, (GLvoid *)texel); \
}
 
FETCH_Z(Z_UNORM32, GLuint, 1)
FETCH_Z(Z_UNORM16, GLushort, 1)
FETCH_Z(S8_UINT_Z24_UNORM, GLuint, 1) /* only return Z, not stencil data */
FETCH_Z(Z24_UNORM_S8_UINT, GLuint, 1) /* only return Z, not stencil data */
FETCH_Z(Z32_FLOAT_S8X24_UINT, GLfloat, 2)
 
FETCH_RGBA(RGBA_FLOAT32, GLfloat, 4)
FETCH_RGBA(RGBA_FLOAT16, GLhalfARB, 4)
FETCH_RGBA(RGB_FLOAT32, GLfloat, 3)
FETCH_RGBA(RGB_FLOAT16, GLhalfARB, 3)
FETCH_RGBA(A_FLOAT32, GLfloat, 1)
FETCH_RGBA(A_FLOAT16, GLhalfARB, 1)
FETCH_RGBA(L_FLOAT32, GLfloat, 1)
FETCH_RGBA(L_FLOAT16, GLhalfARB, 1)
FETCH_RGBA(LA_FLOAT32, GLfloat, 2)
FETCH_RGBA(LA_FLOAT16, GLhalfARB, 2)
FETCH_RGBA(I_FLOAT32, GLfloat, 1)
FETCH_RGBA(I_FLOAT16, GLhalfARB, 1)
FETCH_RGBA(R_FLOAT32, GLfloat, 1)
FETCH_RGBA(R_FLOAT16, GLhalfARB, 1)
FETCH_RGBA(RG_FLOAT32, GLfloat, 2)
FETCH_RGBA(RG_FLOAT16, GLhalfARB, 2)
FETCH_RGBA(A8B8G8R8_UNORM, GLuint, 1)
FETCH_RGBA(R8G8B8A8_UNORM, GLuint, 1)
FETCH_RGBA(B8G8R8A8_UNORM, GLuint, 1)
FETCH_RGBA(A8R8G8B8_UNORM, GLuint, 1)
FETCH_RGBA(X8B8G8R8_UNORM, GLuint, 1)
FETCH_RGBA(R8G8B8X8_UNORM, GLuint, 1)
FETCH_RGBA(B8G8R8X8_UNORM, GLuint, 1)
FETCH_RGBA(X8R8G8B8_UNORM, GLuint, 1)
FETCH_RGBA(BGR_UNORM8, GLubyte, 3)
FETCH_RGBA(RGB_UNORM8, GLubyte, 3)
FETCH_RGBA(B5G6R5_UNORM, GLushort, 1)
FETCH_RGBA(R5G6B5_UNORM, GLushort, 1)
FETCH_RGBA(B4G4R4A4_UNORM, GLushort, 1)
FETCH_RGBA(A4R4G4B4_UNORM, GLushort, 1)
FETCH_RGBA(A1B5G5R5_UNORM, GLushort, 1)
FETCH_RGBA(B5G5R5A1_UNORM, GLushort, 1)
FETCH_RGBA(A1R5G5B5_UNORM, GLushort, 1)
FETCH_RGBA(B10G10R10A2_UNORM, GLuint, 1)
FETCH_RGBA(R10G10B10A2_UNORM, GLuint, 1)
FETCH_RGBA(R8G8_UNORM, GLushort, 1)
FETCH_RGBA(G8R8_UNORM, GLushort, 1)
FETCH_RGBA(L4A4_UNORM, GLubyte, 1)
FETCH_RGBA(L8A8_UNORM, GLushort, 1)
FETCH_RGBA(R_UNORM8, GLubyte, 1)
FETCH_RGBA(R_UNORM16, GLushort, 1)
FETCH_RGBA(A8L8_UNORM, GLushort, 1)
FETCH_RGBA(R16G16_UNORM, GLuint, 1)
FETCH_RGBA(G16R16_UNORM, GLuint, 1)
FETCH_RGBA(L16A16_UNORM, GLuint, 1)
FETCH_RGBA(A16L16_UNORM, GLuint, 1)
FETCH_RGBA(B2G3R3_UNORM, GLubyte, 1)
FETCH_RGBA(A_UNORM8, GLubyte, 1)
FETCH_RGBA(A_UNORM16, GLushort, 1)
FETCH_RGBA(L_UNORM8, GLubyte, 1)
FETCH_RGBA(L_UNORM16, GLushort, 1)
FETCH_RGBA(I_UNORM8, GLubyte, 1)
FETCH_RGBA(I_UNORM16, GLushort, 1)
FETCH_RGBA(BGR_SRGB8, GLubyte, 3)
FETCH_RGBA(A8B8G8R8_SRGB, GLuint, 1)
FETCH_RGBA(B8G8R8A8_SRGB, GLuint, 1)
FETCH_RGBA(A8R8G8B8_SRGB, GLuint, 1)
FETCH_RGBA(R8G8B8A8_SRGB, GLuint, 1)
FETCH_RGBA(R8G8B8X8_SRGB, GLuint, 1)
FETCH_RGBA(X8B8G8R8_SRGB, GLuint, 1)
FETCH_RGBA(L_SRGB8, GLubyte, 1)
FETCH_RGBA(L8A8_SRGB, GLushort, 1)
FETCH_RGBA(A8L8_SRGB, GLushort, 2)
FETCH_RGBA(RGBA_SINT8, GLbyte, 4)
FETCH_RGBA(RGBA_SINT16, GLshort, 4)
FETCH_RGBA(RGBA_SINT32, GLint, 4)
FETCH_RGBA(RGBA_UINT8, GLubyte, 4)
FETCH_RGBA(RGBA_UINT16, GLushort, 4)
FETCH_RGBA(RGBA_UINT32, GLuint, 4)
FETCH_RGBA(R_SNORM8, GLbyte, 1)
FETCH_RGBA(A_SNORM8, GLbyte, 1)
FETCH_RGBA(L_SNORM8, GLbyte, 1)
FETCH_RGBA(I_SNORM8, GLbyte, 1)
FETCH_RGBA(R8G8_SNORM, GLshort, 1)
FETCH_RGBA(L8A8_SNORM, GLshort, 1)
FETCH_RGBA(A8L8_SNORM, GLshort, 1)
FETCH_RGBA(X8B8G8R8_SNORM, GLint, 1)
FETCH_RGBA(A8B8G8R8_SNORM, GLint, 1)
FETCH_RGBA(R8G8B8A8_SNORM, GLint, 1)
FETCH_RGBA(R_SNORM16, GLshort, 1)
FETCH_RGBA(A_SNORM16, GLshort, 1)
FETCH_RGBA(L_SNORM16, GLshort, 1)
FETCH_RGBA(I_SNORM16, GLshort, 1)
FETCH_RGBA(R16G16_SNORM, GLshort, 2)
FETCH_RGBA(LA_SNORM16, GLshort, 2)
FETCH_RGBA(RGB_SNORM16, GLshort, 3)
FETCH_RGBA(RGBA_SNORM16, GLshort, 4)
FETCH_RGBA(RGBA_UNORM16, GLushort, 4)
FETCH_RGBA(RGBX_UNORM16, GLushort, 4)
FETCH_RGBA(RGBX_FLOAT16, GLhalfARB, 4)
FETCH_RGBA(RGBX_FLOAT32, GLfloat, 4)
FETCH_RGBA(YCBCR, GLushort, 1) /* Fetch texel from 1D, 2D or 3D ycbcr texture, returning RGBA. */
FETCH_RGBA(YCBCR_REV, GLushort, 1) /* Fetch texel from 1D, 2D or 3D ycbcr texture, returning RGBA. */
FETCH_RGBA(R9G9B9E5_FLOAT, GLuint, 1)
FETCH_RGBA(R11G11B10_FLOAT, GLuint, 1)
 
#undef TEXEL_ADDR
#undef DIM
#undef FETCH
#undef FETCH_Z
#undef FETCH_RGBA
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_texfilter.c
0,0 → 1,3843
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#include "c99_math.h"
#include "main/glheader.h"
#include "main/context.h"
#include "main/imports.h"
#include "main/macros.h"
#include "main/samplerobj.h"
#include "main/teximage.h"
#include "main/texobj.h"
 
#include "s_context.h"
#include "s_texfilter.h"
 
 
/*
* Note, the FRAC macro has to work perfectly. Otherwise you'll sometimes
* see 1-pixel bands of improperly weighted linear-filtered textures.
* The tests/texwrap.c demo is a good test.
* Also note, FRAC(x) doesn't truly return the fractional part of x for x < 0.
* Instead, if x < 0 then FRAC(x) = 1 - true_frac(x).
*/
#define FRAC(f) ((f) - IFLOOR(f))
 
 
 
/**
* Linear interpolation macro
*/
#define LERP(T, A, B) ( (A) + (T) * ((B) - (A)) )
 
 
/**
* Do 2D/biliner interpolation of float values.
* v00, v10, v01 and v11 are typically four texture samples in a square/box.
* a and b are the horizontal and vertical interpolants.
* It's important that this function is inlined when compiled with
* optimization! If we find that's not true on some systems, convert
* to a macro.
*/
static inline GLfloat
lerp_2d(GLfloat a, GLfloat b,
GLfloat v00, GLfloat v10, GLfloat v01, GLfloat v11)
{
const GLfloat temp0 = LERP(a, v00, v10);
const GLfloat temp1 = LERP(a, v01, v11);
return LERP(b, temp0, temp1);
}
 
 
/**
* Do 3D/trilinear interpolation of float values.
* \sa lerp_2d
*/
static GLfloat
lerp_3d(GLfloat a, GLfloat b, GLfloat c,
GLfloat v000, GLfloat v100, GLfloat v010, GLfloat v110,
GLfloat v001, GLfloat v101, GLfloat v011, GLfloat v111)
{
const GLfloat temp00 = LERP(a, v000, v100);
const GLfloat temp10 = LERP(a, v010, v110);
const GLfloat temp01 = LERP(a, v001, v101);
const GLfloat temp11 = LERP(a, v011, v111);
const GLfloat temp0 = LERP(b, temp00, temp10);
const GLfloat temp1 = LERP(b, temp01, temp11);
return LERP(c, temp0, temp1);
}
 
 
/**
* Do linear interpolation of colors.
*/
static void
lerp_rgba(GLfloat result[4], GLfloat t, const GLfloat a[4], const GLfloat b[4])
{
result[0] = LERP(t, a[0], b[0]);
result[1] = LERP(t, a[1], b[1]);
result[2] = LERP(t, a[2], b[2]);
result[3] = LERP(t, a[3], b[3]);
}
 
 
/**
* Do bilinear interpolation of colors.
*/
static void
lerp_rgba_2d(GLfloat result[4], GLfloat a, GLfloat b,
const GLfloat t00[4], const GLfloat t10[4],
const GLfloat t01[4], const GLfloat t11[4])
{
result[0] = lerp_2d(a, b, t00[0], t10[0], t01[0], t11[0]);
result[1] = lerp_2d(a, b, t00[1], t10[1], t01[1], t11[1]);
result[2] = lerp_2d(a, b, t00[2], t10[2], t01[2], t11[2]);
result[3] = lerp_2d(a, b, t00[3], t10[3], t01[3], t11[3]);
}
 
 
/**
* Do trilinear interpolation of colors.
*/
static void
lerp_rgba_3d(GLfloat result[4], GLfloat a, GLfloat b, GLfloat c,
const GLfloat t000[4], const GLfloat t100[4],
const GLfloat t010[4], const GLfloat t110[4],
const GLfloat t001[4], const GLfloat t101[4],
const GLfloat t011[4], const GLfloat t111[4])
{
GLuint k;
/* compiler should unroll these short loops */
for (k = 0; k < 4; k++) {
result[k] = lerp_3d(a, b, c, t000[k], t100[k], t010[k], t110[k],
t001[k], t101[k], t011[k], t111[k]);
}
}
 
 
/**
* Used for GL_REPEAT wrap mode. Using A % B doesn't produce the
* right results for A<0. Casting to A to be unsigned only works if B
* is a power of two. Adding a bias to A (which is a multiple of B)
* avoids the problems with A < 0 (for reasonable A) without using a
* conditional.
*/
#define REMAINDER(A, B) (((A) + (B) * 1024) % (B))
 
 
/**
* Used to compute texel locations for linear sampling.
* Input:
* wrapMode = GL_REPEAT, GL_CLAMP, GL_CLAMP_TO_EDGE, GL_CLAMP_TO_BORDER
* s = texcoord in [0,1]
* size = width (or height or depth) of texture
* Output:
* i0, i1 = returns two nearest texel indexes
* weight = returns blend factor between texels
*/
static void
linear_texel_locations(GLenum wrapMode,
const struct gl_texture_image *img,
GLint size, GLfloat s,
GLint *i0, GLint *i1, GLfloat *weight)
{
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
GLfloat u;
switch (wrapMode) {
case GL_REPEAT:
u = s * size - 0.5F;
if (swImg->_IsPowerOfTwo) {
*i0 = IFLOOR(u) & (size - 1);
*i1 = (*i0 + 1) & (size - 1);
}
else {
*i0 = REMAINDER(IFLOOR(u), size);
*i1 = REMAINDER(*i0 + 1, size);
}
break;
case GL_CLAMP_TO_EDGE:
if (s <= 0.0F)
u = 0.0F;
else if (s >= 1.0F)
u = (GLfloat) size;
else
u = s * size;
u -= 0.5F;
*i0 = IFLOOR(u);
*i1 = *i0 + 1;
if (*i0 < 0)
*i0 = 0;
if (*i1 >= (GLint) size)
*i1 = size - 1;
break;
case GL_CLAMP_TO_BORDER:
{
const GLfloat min = -1.0F / (2.0F * size);
const GLfloat max = 1.0F - min;
if (s <= min)
u = min * size;
else if (s >= max)
u = max * size;
else
u = s * size;
u -= 0.5F;
*i0 = IFLOOR(u);
*i1 = *i0 + 1;
}
break;
case GL_MIRRORED_REPEAT:
{
const GLint flr = IFLOOR(s);
if (flr & 1)
u = 1.0F - (s - (GLfloat) flr);
else
u = s - (GLfloat) flr;
u = (u * size) - 0.5F;
*i0 = IFLOOR(u);
*i1 = *i0 + 1;
if (*i0 < 0)
*i0 = 0;
if (*i1 >= (GLint) size)
*i1 = size - 1;
}
break;
case GL_MIRROR_CLAMP_EXT:
u = fabsf(s);
if (u >= 1.0F)
u = (GLfloat) size;
else
u *= size;
u -= 0.5F;
*i0 = IFLOOR(u);
*i1 = *i0 + 1;
break;
case GL_MIRROR_CLAMP_TO_EDGE_EXT:
u = fabsf(s);
if (u >= 1.0F)
u = (GLfloat) size;
else
u *= size;
u -= 0.5F;
*i0 = IFLOOR(u);
*i1 = *i0 + 1;
if (*i0 < 0)
*i0 = 0;
if (*i1 >= (GLint) size)
*i1 = size - 1;
break;
case GL_MIRROR_CLAMP_TO_BORDER_EXT:
{
const GLfloat min = -1.0F / (2.0F * size);
const GLfloat max = 1.0F - min;
u = fabsf(s);
if (u <= min)
u = min * size;
else if (u >= max)
u = max * size;
else
u *= size;
u -= 0.5F;
*i0 = IFLOOR(u);
*i1 = *i0 + 1;
}
break;
case GL_CLAMP:
if (s <= 0.0F)
u = 0.0F;
else if (s >= 1.0F)
u = (GLfloat) size;
else
u = s * size;
u -= 0.5F;
*i0 = IFLOOR(u);
*i1 = *i0 + 1;
break;
default:
_mesa_problem(NULL, "Bad wrap mode");
*i0 = *i1 = 0;
u = 0.0F;
break;
}
*weight = FRAC(u);
}
 
 
/**
* Used to compute texel location for nearest sampling.
*/
static GLint
nearest_texel_location(GLenum wrapMode,
const struct gl_texture_image *img,
GLint size, GLfloat s)
{
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
GLint i;
 
switch (wrapMode) {
case GL_REPEAT:
/* s limited to [0,1) */
/* i limited to [0,size-1] */
i = IFLOOR(s * size);
if (swImg->_IsPowerOfTwo)
i &= (size - 1);
else
i = REMAINDER(i, size);
return i;
case GL_CLAMP_TO_EDGE:
{
/* s limited to [min,max] */
/* i limited to [0, size-1] */
const GLfloat min = 1.0F / (2.0F * size);
const GLfloat max = 1.0F - min;
if (s < min)
i = 0;
else if (s > max)
i = size - 1;
else
i = IFLOOR(s * size);
}
return i;
case GL_CLAMP_TO_BORDER:
{
/* s limited to [min,max] */
/* i limited to [-1, size] */
const GLfloat min = -1.0F / (2.0F * size);
const GLfloat max = 1.0F - min;
if (s <= min)
i = -1;
else if (s >= max)
i = size;
else
i = IFLOOR(s * size);
}
return i;
case GL_MIRRORED_REPEAT:
{
const GLfloat min = 1.0F / (2.0F * size);
const GLfloat max = 1.0F - min;
const GLint flr = IFLOOR(s);
GLfloat u;
if (flr & 1)
u = 1.0F - (s - (GLfloat) flr);
else
u = s - (GLfloat) flr;
if (u < min)
i = 0;
else if (u > max)
i = size - 1;
else
i = IFLOOR(u * size);
}
return i;
case GL_MIRROR_CLAMP_EXT:
{
/* s limited to [0,1] */
/* i limited to [0,size-1] */
const GLfloat u = fabsf(s);
if (u <= 0.0F)
i = 0;
else if (u >= 1.0F)
i = size - 1;
else
i = IFLOOR(u * size);
}
return i;
case GL_MIRROR_CLAMP_TO_EDGE_EXT:
{
/* s limited to [min,max] */
/* i limited to [0, size-1] */
const GLfloat min = 1.0F / (2.0F * size);
const GLfloat max = 1.0F - min;
const GLfloat u = fabsf(s);
if (u < min)
i = 0;
else if (u > max)
i = size - 1;
else
i = IFLOOR(u * size);
}
return i;
case GL_MIRROR_CLAMP_TO_BORDER_EXT:
{
/* s limited to [min,max] */
/* i limited to [0, size-1] */
const GLfloat min = -1.0F / (2.0F * size);
const GLfloat max = 1.0F - min;
const GLfloat u = fabsf(s);
if (u < min)
i = -1;
else if (u > max)
i = size;
else
i = IFLOOR(u * size);
}
return i;
case GL_CLAMP:
/* s limited to [0,1] */
/* i limited to [0,size-1] */
if (s <= 0.0F)
i = 0;
else if (s >= 1.0F)
i = size - 1;
else
i = IFLOOR(s * size);
return i;
default:
_mesa_problem(NULL, "Bad wrap mode");
return 0;
}
}
 
 
/* Power of two image sizes only */
static void
linear_repeat_texel_location(GLuint size, GLfloat s,
GLint *i0, GLint *i1, GLfloat *weight)
{
GLfloat u = s * size - 0.5F;
*i0 = IFLOOR(u) & (size - 1);
*i1 = (*i0 + 1) & (size - 1);
*weight = FRAC(u);
}
 
 
/**
* Do clamp/wrap for a texture rectangle coord, GL_NEAREST filter mode.
*/
static GLint
clamp_rect_coord_nearest(GLenum wrapMode, GLfloat coord, GLint max)
{
switch (wrapMode) {
case GL_CLAMP:
return IFLOOR( CLAMP(coord, 0.0F, max - 1) );
case GL_CLAMP_TO_EDGE:
return IFLOOR( CLAMP(coord, 0.5F, max - 0.5F) );
case GL_CLAMP_TO_BORDER:
return IFLOOR( CLAMP(coord, -0.5F, max + 0.5F) );
default:
_mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_nearest");
return 0;
}
}
 
 
/**
* As above, but GL_LINEAR filtering.
*/
static void
clamp_rect_coord_linear(GLenum wrapMode, GLfloat coord, GLint max,
GLint *i0out, GLint *i1out, GLfloat *weight)
{
GLfloat fcol;
GLint i0, i1;
switch (wrapMode) {
case GL_CLAMP:
/* Not exactly what the spec says, but it matches NVIDIA output */
fcol = CLAMP(coord - 0.5F, 0.0F, max - 1);
i0 = IFLOOR(fcol);
i1 = i0 + 1;
break;
case GL_CLAMP_TO_EDGE:
fcol = CLAMP(coord, 0.5F, max - 0.5F);
fcol -= 0.5F;
i0 = IFLOOR(fcol);
i1 = i0 + 1;
if (i1 > max - 1)
i1 = max - 1;
break;
case GL_CLAMP_TO_BORDER:
fcol = CLAMP(coord, -0.5F, max + 0.5F);
fcol -= 0.5F;
i0 = IFLOOR(fcol);
i1 = i0 + 1;
break;
default:
_mesa_problem(NULL, "bad wrapMode in clamp_rect_coord_linear");
i0 = i1 = 0;
fcol = 0.0F;
break;
}
*i0out = i0;
*i1out = i1;
*weight = FRAC(fcol);
}
 
 
/**
* Compute slice/image to use for 1D or 2D array texture.
*/
static GLint
tex_array_slice(GLfloat coord, GLsizei size)
{
GLint slice = IFLOOR(coord + 0.5f);
slice = CLAMP(slice, 0, size - 1);
return slice;
}
 
 
/**
* Compute nearest integer texcoords for given texobj and coordinate.
* NOTE: only used for depth texture sampling.
*/
static void
nearest_texcoord(const struct gl_sampler_object *samp,
const struct gl_texture_object *texObj,
GLuint level,
const GLfloat texcoord[4],
GLint *i, GLint *j, GLint *k)
{
const struct gl_texture_image *img = texObj->Image[0][level];
const GLint width = img->Width;
const GLint height = img->Height;
const GLint depth = img->Depth;
 
switch (texObj->Target) {
case GL_TEXTURE_RECTANGLE_ARB:
*i = clamp_rect_coord_nearest(samp->WrapS, texcoord[0], width);
*j = clamp_rect_coord_nearest(samp->WrapT, texcoord[1], height);
*k = 0;
break;
case GL_TEXTURE_1D:
*i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
*j = 0;
*k = 0;
break;
case GL_TEXTURE_2D:
*i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
*j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
*k = 0;
break;
case GL_TEXTURE_1D_ARRAY_EXT:
*i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
*j = tex_array_slice(texcoord[1], height);
*k = 0;
break;
case GL_TEXTURE_2D_ARRAY_EXT:
*i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
*j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
*k = tex_array_slice(texcoord[2], depth);
break;
default:
*i = *j = *k = 0;
break;
}
}
 
 
/**
* Compute linear integer texcoords for given texobj and coordinate.
* NOTE: only used for depth texture sampling.
*/
static void
linear_texcoord(const struct gl_sampler_object *samp,
const struct gl_texture_object *texObj,
GLuint level,
const GLfloat texcoord[4],
GLint *i0, GLint *i1, GLint *j0, GLint *j1, GLint *slice,
GLfloat *wi, GLfloat *wj)
{
const struct gl_texture_image *img = texObj->Image[0][level];
const GLint width = img->Width;
const GLint height = img->Height;
const GLint depth = img->Depth;
 
switch (texObj->Target) {
case GL_TEXTURE_RECTANGLE_ARB:
clamp_rect_coord_linear(samp->WrapS, texcoord[0],
width, i0, i1, wi);
clamp_rect_coord_linear(samp->WrapT, texcoord[1],
height, j0, j1, wj);
*slice = 0;
break;
 
case GL_TEXTURE_1D:
case GL_TEXTURE_2D:
linear_texel_locations(samp->WrapS, img, width,
texcoord[0], i0, i1, wi);
linear_texel_locations(samp->WrapT, img, height,
texcoord[1], j0, j1, wj);
*slice = 0;
break;
 
case GL_TEXTURE_1D_ARRAY_EXT:
linear_texel_locations(samp->WrapS, img, width,
texcoord[0], i0, i1, wi);
*j0 = tex_array_slice(texcoord[1], height);
*j1 = *j0;
*slice = 0;
break;
 
case GL_TEXTURE_2D_ARRAY_EXT:
linear_texel_locations(samp->WrapS, img, width,
texcoord[0], i0, i1, wi);
linear_texel_locations(samp->WrapT, img, height,
texcoord[1], j0, j1, wj);
*slice = tex_array_slice(texcoord[2], depth);
break;
 
default:
*slice = 0;
break;
}
}
 
 
 
/**
* For linear interpolation between mipmap levels N and N+1, this function
* computes N.
*/
static GLint
linear_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda)
{
if (lambda < 0.0F)
return tObj->BaseLevel;
else if (lambda > tObj->_MaxLambda)
return (GLint) (tObj->BaseLevel + tObj->_MaxLambda);
else
return (GLint) (tObj->BaseLevel + lambda);
}
 
 
/**
* Compute the nearest mipmap level to take texels from.
*/
static GLint
nearest_mipmap_level(const struct gl_texture_object *tObj, GLfloat lambda)
{
GLfloat l;
GLint level;
if (lambda <= 0.5F)
l = 0.0F;
else if (lambda > tObj->_MaxLambda + 0.4999F)
l = tObj->_MaxLambda + 0.4999F;
else
l = lambda;
level = (GLint) (tObj->BaseLevel + l + 0.5F);
if (level > tObj->_MaxLevel)
level = tObj->_MaxLevel;
return level;
}
 
 
 
/*
* Bitflags for texture border color sampling.
*/
#define I0BIT 1
#define I1BIT 2
#define J0BIT 4
#define J1BIT 8
#define K0BIT 16
#define K1BIT 32
 
 
 
/**
* The lambda[] array values are always monotonic. Either the whole span
* will be minified, magnified, or split between the two. This function
* determines the subranges in [0, n-1] that are to be minified or magnified.
*/
static void
compute_min_mag_ranges(const struct gl_sampler_object *samp,
GLuint n, const GLfloat lambda[],
GLuint *minStart, GLuint *minEnd,
GLuint *magStart, GLuint *magEnd)
{
GLfloat minMagThresh;
 
/* we shouldn't be here if minfilter == magfilter */
assert(samp->MinFilter != samp->MagFilter);
 
/* This bit comes from the OpenGL spec: */
if (samp->MagFilter == GL_LINEAR
&& (samp->MinFilter == GL_NEAREST_MIPMAP_NEAREST ||
samp->MinFilter == GL_NEAREST_MIPMAP_LINEAR)) {
minMagThresh = 0.5F;
}
else {
minMagThresh = 0.0F;
}
 
#if 0
/* DEBUG CODE: Verify that lambda[] is monotonic.
* We can't really use this because the inaccuracy in the LOG2 function
* causes this test to fail, yet the resulting texturing is correct.
*/
if (n > 1) {
GLuint i;
printf("lambda delta = %g\n", lambda[0] - lambda[n-1]);
if (lambda[0] >= lambda[n-1]) { /* decreasing */
for (i = 0; i < n - 1; i++) {
assert((GLint) (lambda[i] * 10) >= (GLint) (lambda[i+1] * 10));
}
}
else { /* increasing */
for (i = 0; i < n - 1; i++) {
assert((GLint) (lambda[i] * 10) <= (GLint) (lambda[i+1] * 10));
}
}
}
#endif /* DEBUG */
 
if (lambda[0] <= minMagThresh && (n <= 1 || lambda[n-1] <= minMagThresh)) {
/* magnification for whole span */
*magStart = 0;
*magEnd = n;
*minStart = *minEnd = 0;
}
else if (lambda[0] > minMagThresh && (n <=1 || lambda[n-1] > minMagThresh)) {
/* minification for whole span */
*minStart = 0;
*minEnd = n;
*magStart = *magEnd = 0;
}
else {
/* a mix of minification and magnification */
GLuint i;
if (lambda[0] > minMagThresh) {
/* start with minification */
for (i = 1; i < n; i++) {
if (lambda[i] <= minMagThresh)
break;
}
*minStart = 0;
*minEnd = i;
*magStart = i;
*magEnd = n;
}
else {
/* start with magnification */
for (i = 1; i < n; i++) {
if (lambda[i] > minMagThresh)
break;
}
*magStart = 0;
*magEnd = i;
*minStart = i;
*minEnd = n;
}
}
 
#if 0
/* Verify the min/mag Start/End values
* We don't use this either (see above)
*/
{
GLint i;
for (i = 0; i < n; i++) {
if (lambda[i] > minMagThresh) {
/* minification */
assert(i >= *minStart);
assert(i < *minEnd);
}
else {
/* magnification */
assert(i >= *magStart);
assert(i < *magEnd);
}
}
}
#endif
}
 
 
/**
* When we sample the border color, it must be interpreted according to
* the base texture format. Ex: if the texture base format it GL_ALPHA,
* we return (0,0,0,BorderAlpha).
*/
static void
get_border_color(const struct gl_sampler_object *samp,
const struct gl_texture_image *img,
GLfloat rgba[4])
{
switch (img->_BaseFormat) {
case GL_RGB:
rgba[0] = samp->BorderColor.f[0];
rgba[1] = samp->BorderColor.f[1];
rgba[2] = samp->BorderColor.f[2];
rgba[3] = 1.0F;
break;
case GL_ALPHA:
rgba[0] = rgba[1] = rgba[2] = 0.0;
rgba[3] = samp->BorderColor.f[3];
break;
case GL_LUMINANCE:
rgba[0] = rgba[1] = rgba[2] = samp->BorderColor.f[0];
rgba[3] = 1.0;
break;
case GL_LUMINANCE_ALPHA:
rgba[0] = rgba[1] = rgba[2] = samp->BorderColor.f[0];
rgba[3] = samp->BorderColor.f[3];
break;
case GL_INTENSITY:
rgba[0] = rgba[1] = rgba[2] = rgba[3] = samp->BorderColor.f[0];
break;
default:
COPY_4V(rgba, samp->BorderColor.f);
break;
}
}
 
 
/**
* Put z into texel according to GL_DEPTH_MODE.
*/
static void
apply_depth_mode(GLenum depthMode, GLfloat z, GLfloat texel[4])
{
switch (depthMode) {
case GL_LUMINANCE:
ASSIGN_4V(texel, z, z, z, 1.0F);
break;
case GL_INTENSITY:
ASSIGN_4V(texel, z, z, z, z);
break;
case GL_ALPHA:
ASSIGN_4V(texel, 0.0F, 0.0F, 0.0F, z);
break;
case GL_RED:
ASSIGN_4V(texel, z, 0.0F, 0.0F, 1.0F);
break;
default:
_mesa_problem(NULL, "Bad depth texture mode");
}
}
 
 
/**
* Is the given texture a depth (or depth/stencil) texture?
*/
static GLboolean
is_depth_texture(const struct gl_texture_object *tObj)
{
GLenum format = _mesa_texture_base_format(tObj);
return format == GL_DEPTH_COMPONENT || format == GL_DEPTH_STENCIL_EXT;
}
 
 
/**********************************************************************/
/* 1-D Texture Sampling Functions */
/**********************************************************************/
 
/**
* Return the texture sample for coordinate (s) using GL_NEAREST filter.
*/
static void
sample_1d_nearest(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_image *img,
const GLfloat texcoord[4], GLfloat rgba[4])
{
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
const GLint width = img->Width2; /* without border, power of two */
GLint i;
i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
/* skip over the border, if any */
i += img->Border;
if (i < 0 || i >= (GLint) img->Width) {
/* Need this test for GL_CLAMP_TO_BORDER mode */
get_border_color(samp, img, rgba);
}
else {
swImg->FetchTexel(swImg, i, 0, 0, rgba);
}
}
 
 
/**
* Return the texture sample for coordinate (s) using GL_LINEAR filter.
*/
static void
sample_1d_linear(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_image *img,
const GLfloat texcoord[4], GLfloat rgba[4])
{
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
const GLint width = img->Width2;
GLint i0, i1;
GLbitfield useBorderColor = 0x0;
GLfloat a;
GLfloat t0[4], t1[4]; /* texels */
 
linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
 
if (img->Border) {
i0 += img->Border;
i1 += img->Border;
}
else {
if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
}
 
/* fetch texel colors */
if (useBorderColor & I0BIT) {
get_border_color(samp, img, t0);
}
else {
swImg->FetchTexel(swImg, i0, 0, 0, t0);
}
if (useBorderColor & I1BIT) {
get_border_color(samp, img, t1);
}
else {
swImg->FetchTexel(swImg, i1, 0, 0, t1);
}
 
lerp_rgba(rgba, a, t0, t1);
}
 
 
static void
sample_1d_nearest_mipmap_nearest(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level = nearest_mipmap_level(tObj, lambda[i]);
sample_1d_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
}
}
 
 
static void
sample_1d_linear_mipmap_nearest(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level = nearest_mipmap_level(tObj, lambda[i]);
sample_1d_linear(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
}
}
 
 
static void
sample_1d_nearest_mipmap_linear(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level = linear_mipmap_level(tObj, lambda[i]);
if (level >= tObj->_MaxLevel) {
sample_1d_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
texcoord[i], rgba[i]);
}
else {
GLfloat t0[4], t1[4];
const GLfloat f = FRAC(lambda[i]);
sample_1d_nearest(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
sample_1d_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
lerp_rgba(rgba[i], f, t0, t1);
}
}
}
 
 
static void
sample_1d_linear_mipmap_linear(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level = linear_mipmap_level(tObj, lambda[i]);
if (level >= tObj->_MaxLevel) {
sample_1d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
texcoord[i], rgba[i]);
}
else {
GLfloat t0[4], t1[4];
const GLfloat f = FRAC(lambda[i]);
sample_1d_linear(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
sample_1d_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
lerp_rgba(rgba[i], f, t0, t1);
}
}
}
 
 
/** Sample 1D texture, nearest filtering for both min/magnification */
static void
sample_nearest_1d( struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4], const GLfloat lambda[],
GLfloat rgba[][4] )
{
GLuint i;
const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
(void) lambda;
for (i = 0; i < n; i++) {
sample_1d_nearest(ctx, samp, image, texcoords[i], rgba[i]);
}
}
 
 
/** Sample 1D texture, linear filtering for both min/magnification */
static void
sample_linear_1d( struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4], const GLfloat lambda[],
GLfloat rgba[][4] )
{
GLuint i;
const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
(void) lambda;
for (i = 0; i < n; i++) {
sample_1d_linear(ctx, samp, image, texcoords[i], rgba[i]);
}
}
 
 
/** Sample 1D texture, using lambda to choose between min/magnification */
static void
sample_lambda_1d( struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4],
const GLfloat lambda[], GLfloat rgba[][4] )
{
GLuint minStart, minEnd; /* texels with minification */
GLuint magStart, magEnd; /* texels with magnification */
GLuint i;
 
assert(lambda != NULL);
compute_min_mag_ranges(samp, n, lambda,
&minStart, &minEnd, &magStart, &magEnd);
 
if (minStart < minEnd) {
/* do the minified texels */
const GLuint m = minEnd - minStart;
switch (samp->MinFilter) {
case GL_NEAREST:
for (i = minStart; i < minEnd; i++)
sample_1d_nearest(ctx, samp, _mesa_base_tex_image(tObj),
texcoords[i], rgba[i]);
break;
case GL_LINEAR:
for (i = minStart; i < minEnd; i++)
sample_1d_linear(ctx, samp, _mesa_base_tex_image(tObj),
texcoords[i], rgba[i]);
break;
case GL_NEAREST_MIPMAP_NEAREST:
sample_1d_nearest_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
case GL_LINEAR_MIPMAP_NEAREST:
sample_1d_linear_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
case GL_NEAREST_MIPMAP_LINEAR:
sample_1d_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
case GL_LINEAR_MIPMAP_LINEAR:
sample_1d_linear_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
default:
_mesa_problem(ctx, "Bad min filter in sample_1d_texture");
return;
}
}
 
if (magStart < magEnd) {
/* do the magnified texels */
switch (samp->MagFilter) {
case GL_NEAREST:
for (i = magStart; i < magEnd; i++)
sample_1d_nearest(ctx, samp, _mesa_base_tex_image(tObj),
texcoords[i], rgba[i]);
break;
case GL_LINEAR:
for (i = magStart; i < magEnd; i++)
sample_1d_linear(ctx, samp, _mesa_base_tex_image(tObj),
texcoords[i], rgba[i]);
break;
default:
_mesa_problem(ctx, "Bad mag filter in sample_1d_texture");
return;
}
}
}
 
 
/**********************************************************************/
/* 2-D Texture Sampling Functions */
/**********************************************************************/
 
 
/**
* Return the texture sample for coordinate (s,t) using GL_NEAREST filter.
*/
static void
sample_2d_nearest(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_image *img,
const GLfloat texcoord[4],
GLfloat rgba[])
{
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
const GLint width = img->Width2; /* without border, power of two */
const GLint height = img->Height2; /* without border, power of two */
GLint i, j;
(void) ctx;
 
i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
 
/* skip over the border, if any */
i += img->Border;
j += img->Border;
 
if (i < 0 || i >= (GLint) img->Width || j < 0 || j >= (GLint) img->Height) {
/* Need this test for GL_CLAMP_TO_BORDER mode */
get_border_color(samp, img, rgba);
}
else {
swImg->FetchTexel(swImg, i, j, 0, rgba);
}
}
 
 
/**
* Return the texture sample for coordinate (s,t) using GL_LINEAR filter.
* New sampling code contributed by Lynn Quam <quam@ai.sri.com>.
*/
static void
sample_2d_linear(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_image *img,
const GLfloat texcoord[4],
GLfloat rgba[])
{
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
const GLint width = img->Width2;
const GLint height = img->Height2;
GLint i0, j0, i1, j1;
GLbitfield useBorderColor = 0x0;
GLfloat a, b;
GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */
 
linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
linear_texel_locations(samp->WrapT, img, height, texcoord[1], &j0, &j1, &b);
 
if (img->Border) {
i0 += img->Border;
i1 += img->Border;
j0 += img->Border;
j1 += img->Border;
}
else {
if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
}
 
/* fetch four texel colors */
if (useBorderColor & (I0BIT | J0BIT)) {
get_border_color(samp, img, t00);
}
else {
swImg->FetchTexel(swImg, i0, j0, 0, t00);
}
if (useBorderColor & (I1BIT | J0BIT)) {
get_border_color(samp, img, t10);
}
else {
swImg->FetchTexel(swImg, i1, j0, 0, t10);
}
if (useBorderColor & (I0BIT | J1BIT)) {
get_border_color(samp, img, t01);
}
else {
swImg->FetchTexel(swImg, i0, j1, 0, t01);
}
if (useBorderColor & (I1BIT | J1BIT)) {
get_border_color(samp, img, t11);
}
else {
swImg->FetchTexel(swImg, i1, j1, 0, t11);
}
 
lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11);
}
 
 
/**
* As above, but we know WRAP_S == REPEAT and WRAP_T == REPEAT.
* We don't have to worry about the texture border.
*/
static void
sample_2d_linear_repeat(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_image *img,
const GLfloat texcoord[4],
GLfloat rgba[])
{
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
const GLint width = img->Width2;
const GLint height = img->Height2;
GLint i0, j0, i1, j1;
GLfloat wi, wj;
GLfloat t00[4], t10[4], t01[4], t11[4]; /* sampled texel colors */
 
(void) ctx;
 
assert(samp->WrapS == GL_REPEAT);
assert(samp->WrapT == GL_REPEAT);
assert(img->Border == 0);
assert(swImg->_IsPowerOfTwo);
 
linear_repeat_texel_location(width, texcoord[0], &i0, &i1, &wi);
linear_repeat_texel_location(height, texcoord[1], &j0, &j1, &wj);
 
swImg->FetchTexel(swImg, i0, j0, 0, t00);
swImg->FetchTexel(swImg, i1, j0, 0, t10);
swImg->FetchTexel(swImg, i0, j1, 0, t01);
swImg->FetchTexel(swImg, i1, j1, 0, t11);
 
lerp_rgba_2d(rgba, wi, wj, t00, t10, t01, t11);
}
 
 
static void
sample_2d_nearest_mipmap_nearest(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
for (i = 0; i < n; i++) {
GLint level = nearest_mipmap_level(tObj, lambda[i]);
sample_2d_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
}
}
 
 
static void
sample_2d_linear_mipmap_nearest(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level = nearest_mipmap_level(tObj, lambda[i]);
sample_2d_linear(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
}
}
 
 
static void
sample_2d_nearest_mipmap_linear(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level = linear_mipmap_level(tObj, lambda[i]);
if (level >= tObj->_MaxLevel) {
sample_2d_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
texcoord[i], rgba[i]);
}
else {
GLfloat t0[4], t1[4]; /* texels */
const GLfloat f = FRAC(lambda[i]);
sample_2d_nearest(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
sample_2d_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
lerp_rgba(rgba[i], f, t0, t1);
}
}
}
 
 
static void
sample_2d_linear_mipmap_linear( struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4] )
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level = linear_mipmap_level(tObj, lambda[i]);
if (level >= tObj->_MaxLevel) {
sample_2d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
texcoord[i], rgba[i]);
}
else {
GLfloat t0[4], t1[4]; /* texels */
const GLfloat f = FRAC(lambda[i]);
sample_2d_linear(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
sample_2d_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
lerp_rgba(rgba[i], f, t0, t1);
}
}
}
 
 
static void
sample_2d_linear_mipmap_linear_repeat(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
assert(samp->WrapS == GL_REPEAT);
assert(samp->WrapT == GL_REPEAT);
for (i = 0; i < n; i++) {
GLint level = linear_mipmap_level(tObj, lambda[i]);
if (level >= tObj->_MaxLevel) {
sample_2d_linear_repeat(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
texcoord[i], rgba[i]);
}
else {
GLfloat t0[4], t1[4]; /* texels */
const GLfloat f = FRAC(lambda[i]);
sample_2d_linear_repeat(ctx, samp, tObj->Image[0][level ],
texcoord[i], t0);
sample_2d_linear_repeat(ctx, samp, tObj->Image[0][level+1],
texcoord[i], t1);
lerp_rgba(rgba[i], f, t0, t1);
}
}
}
 
 
/** Sample 2D texture, nearest filtering for both min/magnification */
static void
sample_nearest_2d(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
(void) lambda;
for (i = 0; i < n; i++) {
sample_2d_nearest(ctx, samp, image, texcoords[i], rgba[i]);
}
}
 
 
/** Sample 2D texture, linear filtering for both min/magnification */
static void
sample_linear_2d(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
const struct swrast_texture_image *swImg = swrast_texture_image_const(image);
(void) lambda;
if (samp->WrapS == GL_REPEAT &&
samp->WrapT == GL_REPEAT &&
swImg->_IsPowerOfTwo &&
image->Border == 0) {
for (i = 0; i < n; i++) {
sample_2d_linear_repeat(ctx, samp, image, texcoords[i], rgba[i]);
}
}
else {
for (i = 0; i < n; i++) {
sample_2d_linear(ctx, samp, image, texcoords[i], rgba[i]);
}
}
}
 
 
/**
* Optimized 2-D texture sampling:
* S and T wrap mode == GL_REPEAT
* GL_NEAREST min/mag filter
* No border,
* RowStride == Width,
* Format = GL_RGB
*/
static void
opt_sample_rgb_2d(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoords[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
const struct gl_texture_image *img = _mesa_base_tex_image(tObj);
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
const GLfloat width = (GLfloat) img->Width;
const GLfloat height = (GLfloat) img->Height;
const GLint colMask = img->Width - 1;
const GLint rowMask = img->Height - 1;
const GLint shift = img->WidthLog2;
GLuint k;
(void) ctx;
(void) lambda;
assert(samp->WrapS==GL_REPEAT);
assert(samp->WrapT==GL_REPEAT);
assert(img->Border==0);
assert(img->TexFormat == MESA_FORMAT_BGR_UNORM8);
assert(swImg->_IsPowerOfTwo);
(void) swImg;
 
for (k=0; k<n; k++) {
GLint i = IFLOOR(texcoords[k][0] * width) & colMask;
GLint j = IFLOOR(texcoords[k][1] * height) & rowMask;
GLint pos = (j << shift) | i;
GLubyte *texel = (GLubyte *) swImg->ImageSlices[0] + 3 * pos;
rgba[k][RCOMP] = UBYTE_TO_FLOAT(texel[2]);
rgba[k][GCOMP] = UBYTE_TO_FLOAT(texel[1]);
rgba[k][BCOMP] = UBYTE_TO_FLOAT(texel[0]);
rgba[k][ACOMP] = 1.0F;
}
}
 
 
/**
* Optimized 2-D texture sampling:
* S and T wrap mode == GL_REPEAT
* GL_NEAREST min/mag filter
* No border
* RowStride == Width,
* Format = GL_RGBA
*/
static void
opt_sample_rgba_2d(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoords[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
const struct gl_texture_image *img = _mesa_base_tex_image(tObj);
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
const GLfloat width = (GLfloat) img->Width;
const GLfloat height = (GLfloat) img->Height;
const GLint colMask = img->Width - 1;
const GLint rowMask = img->Height - 1;
const GLint shift = img->WidthLog2;
GLuint i;
(void) ctx;
(void) lambda;
assert(samp->WrapS==GL_REPEAT);
assert(samp->WrapT==GL_REPEAT);
assert(img->Border==0);
assert(img->TexFormat == MESA_FORMAT_A8B8G8R8_UNORM);
assert(swImg->_IsPowerOfTwo);
(void) swImg;
 
for (i = 0; i < n; i++) {
const GLint col = IFLOOR(texcoords[i][0] * width) & colMask;
const GLint row = IFLOOR(texcoords[i][1] * height) & rowMask;
const GLint pos = (row << shift) | col;
const GLuint texel = *((GLuint *) swImg->ImageSlices[0] + pos);
rgba[i][RCOMP] = UBYTE_TO_FLOAT( (texel >> 24) );
rgba[i][GCOMP] = UBYTE_TO_FLOAT( (texel >> 16) & 0xff );
rgba[i][BCOMP] = UBYTE_TO_FLOAT( (texel >> 8) & 0xff );
rgba[i][ACOMP] = UBYTE_TO_FLOAT( (texel ) & 0xff );
}
}
 
 
/** Sample 2D texture, using lambda to choose between min/magnification */
static void
sample_lambda_2d(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoords[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
const struct gl_texture_image *tImg = _mesa_base_tex_image(tObj);
const struct swrast_texture_image *swImg = swrast_texture_image_const(tImg);
GLuint minStart, minEnd; /* texels with minification */
GLuint magStart, magEnd; /* texels with magnification */
 
const GLboolean repeatNoBorderPOT = (samp->WrapS == GL_REPEAT)
&& (samp->WrapT == GL_REPEAT)
&& (tImg->Border == 0)
&& (_mesa_format_row_stride(tImg->TexFormat, tImg->Width) ==
swImg->RowStride)
&& swImg->_IsPowerOfTwo;
 
assert(lambda != NULL);
compute_min_mag_ranges(samp, n, lambda,
&minStart, &minEnd, &magStart, &magEnd);
 
if (minStart < minEnd) {
/* do the minified texels */
const GLuint m = minEnd - minStart;
switch (samp->MinFilter) {
case GL_NEAREST:
if (repeatNoBorderPOT) {
switch (tImg->TexFormat) {
case MESA_FORMAT_BGR_UNORM8:
opt_sample_rgb_2d(ctx, samp, tObj, m, texcoords + minStart,
NULL, rgba + minStart);
break;
case MESA_FORMAT_A8B8G8R8_UNORM:
opt_sample_rgba_2d(ctx, samp, tObj, m, texcoords + minStart,
NULL, rgba + minStart);
break;
default:
sample_nearest_2d(ctx, samp, tObj, m, texcoords + minStart,
NULL, rgba + minStart );
}
}
else {
sample_nearest_2d(ctx, samp, tObj, m, texcoords + minStart,
NULL, rgba + minStart);
}
break;
case GL_LINEAR:
sample_linear_2d(ctx, samp, tObj, m, texcoords + minStart,
NULL, rgba + minStart);
break;
case GL_NEAREST_MIPMAP_NEAREST:
sample_2d_nearest_mipmap_nearest(ctx, samp, tObj, m,
texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
case GL_LINEAR_MIPMAP_NEAREST:
sample_2d_linear_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
case GL_NEAREST_MIPMAP_LINEAR:
sample_2d_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
case GL_LINEAR_MIPMAP_LINEAR:
if (repeatNoBorderPOT)
sample_2d_linear_mipmap_linear_repeat(ctx, samp, tObj, m,
texcoords + minStart, lambda + minStart, rgba + minStart);
else
sample_2d_linear_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
default:
_mesa_problem(ctx, "Bad min filter in sample_2d_texture");
return;
}
}
 
if (magStart < magEnd) {
/* do the magnified texels */
const GLuint m = magEnd - magStart;
 
switch (samp->MagFilter) {
case GL_NEAREST:
if (repeatNoBorderPOT) {
switch (tImg->TexFormat) {
case MESA_FORMAT_BGR_UNORM8:
opt_sample_rgb_2d(ctx, samp, tObj, m, texcoords + magStart,
NULL, rgba + magStart);
break;
case MESA_FORMAT_A8B8G8R8_UNORM:
opt_sample_rgba_2d(ctx, samp, tObj, m, texcoords + magStart,
NULL, rgba + magStart);
break;
default:
sample_nearest_2d(ctx, samp, tObj, m, texcoords + magStart,
NULL, rgba + magStart );
}
}
else {
sample_nearest_2d(ctx, samp, tObj, m, texcoords + magStart,
NULL, rgba + magStart);
}
break;
case GL_LINEAR:
sample_linear_2d(ctx, samp, tObj, m, texcoords + magStart,
NULL, rgba + magStart);
break;
default:
_mesa_problem(ctx, "Bad mag filter in sample_lambda_2d");
break;
}
}
}
 
 
/* For anisotropic filtering */
#define WEIGHT_LUT_SIZE 1024
 
static GLfloat *weightLut = NULL;
 
/**
* Creates the look-up table used to speed-up EWA sampling
*/
static void
create_filter_table(void)
{
GLuint i;
if (!weightLut) {
weightLut = malloc(WEIGHT_LUT_SIZE * sizeof(GLfloat));
 
for (i = 0; i < WEIGHT_LUT_SIZE; ++i) {
GLfloat alpha = 2;
GLfloat r2 = (GLfloat) i / (GLfloat) (WEIGHT_LUT_SIZE - 1);
GLfloat weight = (GLfloat) exp(-alpha * r2);
weightLut[i] = weight;
}
}
}
 
 
/**
* Elliptical weighted average (EWA) filter for producing high quality
* anisotropic filtered results.
* Based on the Higher Quality Elliptical Weighted Avarage Filter
* published by Paul S. Heckbert in his Master's Thesis
* "Fundamentals of Texture Mapping and Image Warping" (1989)
*/
static void
sample_2d_ewa(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
const GLfloat texcoord[4],
const GLfloat dudx, const GLfloat dvdx,
const GLfloat dudy, const GLfloat dvdy, const GLint lod,
GLfloat rgba[])
{
GLint level = lod > 0 ? lod : 0;
GLfloat scaling = 1.0f / (1 << level);
const struct gl_texture_image *img = tObj->Image[0][level];
const struct gl_texture_image *mostDetailedImage =
_mesa_base_tex_image(tObj);
const struct swrast_texture_image *swImg =
swrast_texture_image_const(mostDetailedImage);
GLfloat tex_u = -0.5f + texcoord[0] * swImg->WidthScale * scaling;
GLfloat tex_v = -0.5f + texcoord[1] * swImg->HeightScale * scaling;
 
GLfloat ux = dudx * scaling;
GLfloat vx = dvdx * scaling;
GLfloat uy = dudy * scaling;
GLfloat vy = dvdy * scaling;
 
/* compute ellipse coefficients to bound the region:
* A*x*x + B*x*y + C*y*y = F.
*/
GLfloat A = vx*vx+vy*vy+1;
GLfloat B = -2*(ux*vx+uy*vy);
GLfloat C = ux*ux+uy*uy+1;
GLfloat F = A*C-B*B/4.0f;
 
/* check if it is an ellipse */
/* assert(F > 0.0); */
 
/* Compute the ellipse's (u,v) bounding box in texture space */
GLfloat d = -B*B+4.0f*C*A;
GLfloat box_u = 2.0f / d * sqrtf(d*C*F); /* box_u -> half of bbox with */
GLfloat box_v = 2.0f / d * sqrtf(A*d*F); /* box_v -> half of bbox height */
 
GLint u0 = (GLint) floorf(tex_u - box_u);
GLint u1 = (GLint) ceilf (tex_u + box_u);
GLint v0 = (GLint) floorf(tex_v - box_v);
GLint v1 = (GLint) ceilf (tex_v + box_v);
 
GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F};
GLfloat newCoord[2];
GLfloat den = 0.0F;
GLfloat ddq;
GLfloat U = u0 - tex_u;
GLint v;
 
/* Scale ellipse formula to directly index the Filter Lookup Table.
* i.e. scale so that F = WEIGHT_LUT_SIZE-1
*/
GLfloat formScale = (GLfloat) (WEIGHT_LUT_SIZE - 1) / F;
A *= formScale;
B *= formScale;
C *= formScale;
/* F *= formScale; */ /* no need to scale F as we don't use it below here */
 
/* Heckbert MS thesis, p. 59; scan over the bounding box of the ellipse
* and incrementally update the value of Ax^2+Bxy*Cy^2; when this
* value, q, is less than F, we're inside the ellipse
*/
ddq = 2 * A;
for (v = v0; v <= v1; ++v) {
GLfloat V = v - tex_v;
GLfloat dq = A * (2 * U + 1) + B * V;
GLfloat q = (C * V + B * U) * V + A * U * U;
 
GLint u;
for (u = u0; u <= u1; ++u) {
/* Note that the ellipse has been pre-scaled so F = WEIGHT_LUT_SIZE - 1 */
if (q < WEIGHT_LUT_SIZE) {
/* as a LUT is used, q must never be negative;
* should not happen, though
*/
const GLint qClamped = q >= 0.0F ? (GLint) q : 0;
GLfloat weight = weightLut[qClamped];
 
newCoord[0] = u / ((GLfloat) img->Width2);
newCoord[1] = v / ((GLfloat) img->Height2);
 
sample_2d_nearest(ctx, samp, img, newCoord, rgba);
num[0] += weight * rgba[0];
num[1] += weight * rgba[1];
num[2] += weight * rgba[2];
num[3] += weight * rgba[3];
 
den += weight;
}
q += dq;
dq += ddq;
}
}
 
if (den <= 0.0F) {
/* Reaching this place would mean
* that no pixels intersected the ellipse.
* This should never happen because
* the filter we use always
* intersects at least one pixel.
*/
 
/*rgba[0]=0;
rgba[1]=0;
rgba[2]=0;
rgba[3]=0;*/
/* not enough pixels in resampling, resort to direct interpolation */
sample_2d_linear(ctx, samp, img, texcoord, rgba);
return;
}
 
rgba[0] = num[0] / den;
rgba[1] = num[1] / den;
rgba[2] = num[2] / den;
rgba[3] = num[3] / den;
}
 
 
/**
* Anisotropic filtering using footprint assembly as outlined in the
* EXT_texture_filter_anisotropic spec:
* http://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt
* Faster than EWA but has less quality (more aliasing effects)
*/
static void
sample_2d_footprint(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
const GLfloat texcoord[4],
const GLfloat dudx, const GLfloat dvdx,
const GLfloat dudy, const GLfloat dvdy, const GLint lod,
GLfloat rgba[])
{
GLint level = lod > 0 ? lod : 0;
GLfloat scaling = 1.0F / (1 << level);
const struct gl_texture_image *img = tObj->Image[0][level];
 
GLfloat ux = dudx * scaling;
GLfloat vx = dvdx * scaling;
GLfloat uy = dudy * scaling;
GLfloat vy = dvdy * scaling;
 
GLfloat Px2 = ux * ux + vx * vx; /* squared length of dx */
GLfloat Py2 = uy * uy + vy * vy; /* squared length of dy */
 
GLint numSamples;
GLfloat ds;
GLfloat dt;
 
GLfloat num[4] = {0.0F, 0.0F, 0.0F, 0.0F};
GLfloat newCoord[2];
GLint s;
 
/* Calculate the per anisotropic sample offsets in s,t space. */
if (Px2 > Py2) {
numSamples = (GLint) ceilf(sqrtf(Px2));
ds = ux / ((GLfloat) img->Width2);
dt = vx / ((GLfloat) img->Height2);
}
else {
numSamples = (GLint) ceilf(sqrtf(Py2));
ds = uy / ((GLfloat) img->Width2);
dt = vy / ((GLfloat) img->Height2);
}
 
for (s = 0; s<numSamples; s++) {
newCoord[0] = texcoord[0] + ds * ((GLfloat)(s+1) / (numSamples+1) -0.5f);
newCoord[1] = texcoord[1] + dt * ((GLfloat)(s+1) / (numSamples+1) -0.5f);
 
sample_2d_linear(ctx, samp, img, newCoord, rgba);
num[0] += rgba[0];
num[1] += rgba[1];
num[2] += rgba[2];
num[3] += rgba[3];
}
 
rgba[0] = num[0] / numSamples;
rgba[1] = num[1] / numSamples;
rgba[2] = num[2] / numSamples;
rgba[3] = num[3] / numSamples;
}
 
 
/**
* Returns the index of the specified texture object in the
* gl_context texture unit array.
*/
static GLuint
texture_unit_index(const struct gl_context *ctx,
const struct gl_texture_object *tObj)
{
const GLuint maxUnit
= (ctx->Texture._EnabledCoordUnits > 1) ? ctx->Const.MaxTextureUnits : 1;
GLuint u;
 
/* XXX CoordUnits vs. ImageUnits */
for (u = 0; u < maxUnit; u++) {
if (ctx->Texture.Unit[u]._Current == tObj)
break; /* found */
}
if (u >= maxUnit)
u = 0; /* not found, use 1st one; should never happen */
return u;
}
 
 
/**
* Sample 2D texture using an anisotropic filter.
* NOTE: the const GLfloat lambda_iso[] parameter does *NOT* contain
* the lambda float array but a "hidden" SWspan struct which is required
* by this function but is not available in the texture_sample_func signature.
* See _swrast_texture_span( struct gl_context *ctx, SWspan *span ) on how
* this function is called.
*/
static void
sample_lambda_2d_aniso(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoords[][4],
const GLfloat lambda_iso[], GLfloat rgba[][4])
{
const struct gl_texture_image *tImg = _mesa_base_tex_image(tObj);
const struct swrast_texture_image *swImg = swrast_texture_image_const(tImg);
const GLfloat maxEccentricity =
samp->MaxAnisotropy * samp->MaxAnisotropy;
/* re-calculate the lambda values so that they are usable with anisotropic
* filtering
*/
SWspan *span = (SWspan *)lambda_iso; /* access the "hidden" SWspan struct */
 
/* based on interpolate_texcoords(struct gl_context *ctx, SWspan *span)
* in swrast/s_span.c
*/
/* find the texture unit index by looking up the current texture object
* from the context list of available texture objects.
*/
const GLuint u = texture_unit_index(ctx, tObj);
const GLuint attr = VARYING_SLOT_TEX0 + u;
GLfloat texW, texH;
 
const GLfloat dsdx = span->attrStepX[attr][0];
const GLfloat dsdy = span->attrStepY[attr][0];
const GLfloat dtdx = span->attrStepX[attr][1];
const GLfloat dtdy = span->attrStepY[attr][1];
const GLfloat dqdx = span->attrStepX[attr][3];
const GLfloat dqdy = span->attrStepY[attr][3];
GLfloat s = span->attrStart[attr][0] + span->leftClip * dsdx;
GLfloat t = span->attrStart[attr][1] + span->leftClip * dtdx;
GLfloat q = span->attrStart[attr][3] + span->leftClip * dqdx;
 
/* from swrast/s_texcombine.c _swrast_texture_span */
const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[u];
const GLboolean adjustLOD =
(texUnit->LodBias + samp->LodBias != 0.0F)
|| (samp->MinLod != -1000.0 || samp->MaxLod != 1000.0);
 
GLuint i;
/* on first access create the lookup table containing the filter weights. */
if (!weightLut) {
create_filter_table();
}
 
texW = swImg->WidthScale;
texH = swImg->HeightScale;
 
for (i = 0; i < n; i++) {
const GLfloat invQ = (q == 0.0F) ? 1.0F : (1.0F / q);
GLfloat dudx = texW * ((s + dsdx) / (q + dqdx) - s * invQ);
GLfloat dvdx = texH * ((t + dtdx) / (q + dqdx) - t * invQ);
GLfloat dudy = texW * ((s + dsdy) / (q + dqdy) - s * invQ);
GLfloat dvdy = texH * ((t + dtdy) / (q + dqdy) - t * invQ);
/* note: instead of working with Px and Py, we will use the
* squared length instead, to avoid sqrt.
*/
GLfloat Px2 = dudx * dudx + dvdx * dvdx;
GLfloat Py2 = dudy * dudy + dvdy * dvdy;
 
GLfloat Pmax2;
GLfloat Pmin2;
GLfloat e;
GLfloat lod;
 
s += dsdx;
t += dtdx;
q += dqdx;
if (Px2 < Py2) {
Pmax2 = Py2;
Pmin2 = Px2;
}
else {
Pmax2 = Px2;
Pmin2 = Py2;
}
/* if the eccentricity of the ellipse is too big, scale up the shorter
* of the two vectors to limit the maximum amount of work per pixel
*/
e = Pmax2 / Pmin2;
if (e > maxEccentricity) {
/* GLfloat s=e / maxEccentricity;
minor[0] *= s;
minor[1] *= s;
Pmin2 *= s; */
Pmin2 = Pmax2 / maxEccentricity;
}
/* note: we need to have Pmin=sqrt(Pmin2) here, but we can avoid
* this since 0.5*log(x) = log(sqrt(x))
*/
lod = 0.5f * LOG2(Pmin2);
if (adjustLOD) {
/* from swrast/s_texcombine.c _swrast_texture_span */
if (texUnit->LodBias + samp->LodBias != 0.0F) {
/* apply LOD bias, but don't clamp yet */
const GLfloat bias =
CLAMP(texUnit->LodBias + samp->LodBias,
-ctx->Const.MaxTextureLodBias,
ctx->Const.MaxTextureLodBias);
lod += bias;
 
if (samp->MinLod != -1000.0 ||
samp->MaxLod != 1000.0) {
/* apply LOD clamping to lambda */
lod = CLAMP(lod, samp->MinLod, samp->MaxLod);
}
}
}
/* If the ellipse covers the whole image, we can
* simply return the average of the whole image.
*/
if (lod >= tObj->_MaxLevel) {
sample_2d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
texcoords[i], rgba[i]);
}
else {
/* don't bother interpolating between multiple LODs; it doesn't
* seem to be worth the extra running time.
*/
sample_2d_ewa(ctx, samp, tObj, texcoords[i],
dudx, dvdx, dudy, dvdy, (GLint) floorf(lod), rgba[i]);
 
/* unused: */
(void) sample_2d_footprint;
/*
sample_2d_footprint(ctx, tObj, texcoords[i],
dudx, dvdx, dudy, dvdy, floor(lod), rgba[i]);
*/
}
}
}
 
 
 
/**********************************************************************/
/* 3-D Texture Sampling Functions */
/**********************************************************************/
 
/**
* Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
*/
static void
sample_3d_nearest(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_image *img,
const GLfloat texcoord[4],
GLfloat rgba[4])
{
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
const GLint width = img->Width2; /* without border, power of two */
const GLint height = img->Height2; /* without border, power of two */
const GLint depth = img->Depth2; /* without border, power of two */
GLint i, j, k;
(void) ctx;
 
i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
k = nearest_texel_location(samp->WrapR, img, depth, texcoord[2]);
 
if (i < 0 || i >= (GLint) img->Width ||
j < 0 || j >= (GLint) img->Height ||
k < 0 || k >= (GLint) img->Depth) {
/* Need this test for GL_CLAMP_TO_BORDER mode */
get_border_color(samp, img, rgba);
}
else {
swImg->FetchTexel(swImg, i, j, k, rgba);
}
}
 
 
/**
* Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
*/
static void
sample_3d_linear(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_image *img,
const GLfloat texcoord[4],
GLfloat rgba[4])
{
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
const GLint width = img->Width2;
const GLint height = img->Height2;
const GLint depth = img->Depth2;
GLint i0, j0, k0, i1, j1, k1;
GLbitfield useBorderColor = 0x0;
GLfloat a, b, c;
GLfloat t000[4], t010[4], t001[4], t011[4];
GLfloat t100[4], t110[4], t101[4], t111[4];
 
linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
linear_texel_locations(samp->WrapT, img, height, texcoord[1], &j0, &j1, &b);
linear_texel_locations(samp->WrapR, img, depth, texcoord[2], &k0, &k1, &c);
 
if (img->Border) {
i0 += img->Border;
i1 += img->Border;
j0 += img->Border;
j1 += img->Border;
k0 += img->Border;
k1 += img->Border;
}
else {
/* check if sampling texture border color */
if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
if (k0 < 0 || k0 >= depth) useBorderColor |= K0BIT;
if (k1 < 0 || k1 >= depth) useBorderColor |= K1BIT;
}
 
/* Fetch texels */
if (useBorderColor & (I0BIT | J0BIT | K0BIT)) {
get_border_color(samp, img, t000);
}
else {
swImg->FetchTexel(swImg, i0, j0, k0, t000);
}
if (useBorderColor & (I1BIT | J0BIT | K0BIT)) {
get_border_color(samp, img, t100);
}
else {
swImg->FetchTexel(swImg, i1, j0, k0, t100);
}
if (useBorderColor & (I0BIT | J1BIT | K0BIT)) {
get_border_color(samp, img, t010);
}
else {
swImg->FetchTexel(swImg, i0, j1, k0, t010);
}
if (useBorderColor & (I1BIT | J1BIT | K0BIT)) {
get_border_color(samp, img, t110);
}
else {
swImg->FetchTexel(swImg, i1, j1, k0, t110);
}
 
if (useBorderColor & (I0BIT | J0BIT | K1BIT)) {
get_border_color(samp, img, t001);
}
else {
swImg->FetchTexel(swImg, i0, j0, k1, t001);
}
if (useBorderColor & (I1BIT | J0BIT | K1BIT)) {
get_border_color(samp, img, t101);
}
else {
swImg->FetchTexel(swImg, i1, j0, k1, t101);
}
if (useBorderColor & (I0BIT | J1BIT | K1BIT)) {
get_border_color(samp, img, t011);
}
else {
swImg->FetchTexel(swImg, i0, j1, k1, t011);
}
if (useBorderColor & (I1BIT | J1BIT | K1BIT)) {
get_border_color(samp, img, t111);
}
else {
swImg->FetchTexel(swImg, i1, j1, k1, t111);
}
 
/* trilinear interpolation of samples */
lerp_rgba_3d(rgba, a, b, c, t000, t100, t010, t110, t001, t101, t011, t111);
}
 
 
static void
sample_3d_nearest_mipmap_nearest(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4] )
{
GLuint i;
for (i = 0; i < n; i++) {
GLint level = nearest_mipmap_level(tObj, lambda[i]);
sample_3d_nearest(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
}
}
 
 
static void
sample_3d_linear_mipmap_nearest(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level = nearest_mipmap_level(tObj, lambda[i]);
sample_3d_linear(ctx, samp, tObj->Image[0][level], texcoord[i], rgba[i]);
}
}
 
 
static void
sample_3d_nearest_mipmap_linear(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level = linear_mipmap_level(tObj, lambda[i]);
if (level >= tObj->_MaxLevel) {
sample_3d_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
texcoord[i], rgba[i]);
}
else {
GLfloat t0[4], t1[4]; /* texels */
const GLfloat f = FRAC(lambda[i]);
sample_3d_nearest(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
sample_3d_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
lerp_rgba(rgba[i], f, t0, t1);
}
}
}
 
 
static void
sample_3d_linear_mipmap_linear(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level = linear_mipmap_level(tObj, lambda[i]);
if (level >= tObj->_MaxLevel) {
sample_3d_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
texcoord[i], rgba[i]);
}
else {
GLfloat t0[4], t1[4]; /* texels */
const GLfloat f = FRAC(lambda[i]);
sample_3d_linear(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
sample_3d_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
lerp_rgba(rgba[i], f, t0, t1);
}
}
}
 
 
/** Sample 3D texture, nearest filtering for both min/magnification */
static void
sample_nearest_3d(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4], const GLfloat lambda[],
GLfloat rgba[][4])
{
GLuint i;
const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
(void) lambda;
for (i = 0; i < n; i++) {
sample_3d_nearest(ctx, samp, image, texcoords[i], rgba[i]);
}
}
 
 
/** Sample 3D texture, linear filtering for both min/magnification */
static void
sample_linear_3d(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
(void) lambda;
for (i = 0; i < n; i++) {
sample_3d_linear(ctx, samp, image, texcoords[i], rgba[i]);
}
}
 
 
/** Sample 3D texture, using lambda to choose between min/magnification */
static void
sample_lambda_3d(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4], const GLfloat lambda[],
GLfloat rgba[][4])
{
GLuint minStart, minEnd; /* texels with minification */
GLuint magStart, magEnd; /* texels with magnification */
GLuint i;
 
assert(lambda != NULL);
compute_min_mag_ranges(samp, n, lambda,
&minStart, &minEnd, &magStart, &magEnd);
 
if (minStart < minEnd) {
/* do the minified texels */
GLuint m = minEnd - minStart;
switch (samp->MinFilter) {
case GL_NEAREST:
for (i = minStart; i < minEnd; i++)
sample_3d_nearest(ctx, samp, _mesa_base_tex_image(tObj),
texcoords[i], rgba[i]);
break;
case GL_LINEAR:
for (i = minStart; i < minEnd; i++)
sample_3d_linear(ctx, samp, _mesa_base_tex_image(tObj),
texcoords[i], rgba[i]);
break;
case GL_NEAREST_MIPMAP_NEAREST:
sample_3d_nearest_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
case GL_LINEAR_MIPMAP_NEAREST:
sample_3d_linear_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
case GL_NEAREST_MIPMAP_LINEAR:
sample_3d_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
case GL_LINEAR_MIPMAP_LINEAR:
sample_3d_linear_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
default:
_mesa_problem(ctx, "Bad min filter in sample_3d_texture");
return;
}
}
 
if (magStart < magEnd) {
/* do the magnified texels */
switch (samp->MagFilter) {
case GL_NEAREST:
for (i = magStart; i < magEnd; i++)
sample_3d_nearest(ctx, samp, _mesa_base_tex_image(tObj),
texcoords[i], rgba[i]);
break;
case GL_LINEAR:
for (i = magStart; i < magEnd; i++)
sample_3d_linear(ctx, samp, _mesa_base_tex_image(tObj),
texcoords[i], rgba[i]);
break;
default:
_mesa_problem(ctx, "Bad mag filter in sample_3d_texture");
return;
}
}
}
 
 
/**********************************************************************/
/* Texture Cube Map Sampling Functions */
/**********************************************************************/
 
/**
* Choose one of six sides of a texture cube map given the texture
* coord (rx,ry,rz). Return pointer to corresponding array of texture
* images.
*/
static const struct gl_texture_image **
choose_cube_face(const struct gl_texture_object *texObj,
const GLfloat texcoord[4], GLfloat newCoord[4])
{
/*
major axis
direction target sc tc ma
---------- ------------------------------- --- --- ---
+rx TEXTURE_CUBE_MAP_POSITIVE_X_EXT -rz -ry rx
-rx TEXTURE_CUBE_MAP_NEGATIVE_X_EXT +rz -ry rx
+ry TEXTURE_CUBE_MAP_POSITIVE_Y_EXT +rx +rz ry
-ry TEXTURE_CUBE_MAP_NEGATIVE_Y_EXT +rx -rz ry
+rz TEXTURE_CUBE_MAP_POSITIVE_Z_EXT +rx -ry rz
-rz TEXTURE_CUBE_MAP_NEGATIVE_Z_EXT -rx -ry rz
*/
const GLfloat rx = texcoord[0];
const GLfloat ry = texcoord[1];
const GLfloat rz = texcoord[2];
const GLfloat arx = fabsf(rx), ary = fabsf(ry), arz = fabsf(rz);
GLuint face;
GLfloat sc, tc, ma;
 
if (arx >= ary && arx >= arz) {
if (rx >= 0.0F) {
face = FACE_POS_X;
sc = -rz;
tc = -ry;
ma = arx;
}
else {
face = FACE_NEG_X;
sc = rz;
tc = -ry;
ma = arx;
}
}
else if (ary >= arx && ary >= arz) {
if (ry >= 0.0F) {
face = FACE_POS_Y;
sc = rx;
tc = rz;
ma = ary;
}
else {
face = FACE_NEG_Y;
sc = rx;
tc = -rz;
ma = ary;
}
}
else {
if (rz > 0.0F) {
face = FACE_POS_Z;
sc = rx;
tc = -ry;
ma = arz;
}
else {
face = FACE_NEG_Z;
sc = -rx;
tc = -ry;
ma = arz;
}
}
 
{
const float ima = 1.0F / ma;
newCoord[0] = ( sc * ima + 1.0F ) * 0.5F;
newCoord[1] = ( tc * ima + 1.0F ) * 0.5F;
}
 
return (const struct gl_texture_image **) texObj->Image[face];
}
 
 
static void
sample_nearest_cube(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4], const GLfloat lambda[],
GLfloat rgba[][4])
{
GLuint i;
(void) lambda;
for (i = 0; i < n; i++) {
const struct gl_texture_image **images;
GLfloat newCoord[4];
images = choose_cube_face(tObj, texcoords[i], newCoord);
sample_2d_nearest(ctx, samp, images[tObj->BaseLevel],
newCoord, rgba[i]);
}
if (is_depth_texture(tObj)) {
for (i = 0; i < n; i++) {
apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
}
}
}
 
 
static void
sample_linear_cube(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
(void) lambda;
for (i = 0; i < n; i++) {
const struct gl_texture_image **images;
GLfloat newCoord[4];
images = choose_cube_face(tObj, texcoords[i], newCoord);
sample_2d_linear(ctx, samp, images[tObj->BaseLevel],
newCoord, rgba[i]);
}
if (is_depth_texture(tObj)) {
for (i = 0; i < n; i++) {
apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
}
}
}
 
 
static void
sample_cube_nearest_mipmap_nearest(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
const struct gl_texture_image **images;
GLfloat newCoord[4];
GLint level;
images = choose_cube_face(tObj, texcoord[i], newCoord);
 
/* XXX we actually need to recompute lambda here based on the newCoords.
* But we would need the texcoords of adjacent fragments to compute that
* properly, and we don't have those here.
* For now, do an approximation: subtracting 1 from the chosen mipmap
* level seems to work in some test cases.
* The same adjustment is done in the next few functions.
*/
level = nearest_mipmap_level(tObj, lambda[i]);
level = MAX2(level - 1, 0);
 
sample_2d_nearest(ctx, samp, images[level], newCoord, rgba[i]);
}
if (is_depth_texture(tObj)) {
for (i = 0; i < n; i++) {
apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
}
}
}
 
 
static void
sample_cube_linear_mipmap_nearest(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
const struct gl_texture_image **images;
GLfloat newCoord[4];
GLint level = nearest_mipmap_level(tObj, lambda[i]);
level = MAX2(level - 1, 0); /* see comment above */
images = choose_cube_face(tObj, texcoord[i], newCoord);
sample_2d_linear(ctx, samp, images[level], newCoord, rgba[i]);
}
if (is_depth_texture(tObj)) {
for (i = 0; i < n; i++) {
apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
}
}
}
 
 
static void
sample_cube_nearest_mipmap_linear(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
const struct gl_texture_image **images;
GLfloat newCoord[4];
GLint level = linear_mipmap_level(tObj, lambda[i]);
level = MAX2(level - 1, 0); /* see comment above */
images = choose_cube_face(tObj, texcoord[i], newCoord);
if (level >= tObj->_MaxLevel) {
sample_2d_nearest(ctx, samp, images[tObj->_MaxLevel],
newCoord, rgba[i]);
}
else {
GLfloat t0[4], t1[4]; /* texels */
const GLfloat f = FRAC(lambda[i]);
sample_2d_nearest(ctx, samp, images[level ], newCoord, t0);
sample_2d_nearest(ctx, samp, images[level+1], newCoord, t1);
lerp_rgba(rgba[i], f, t0, t1);
}
}
if (is_depth_texture(tObj)) {
for (i = 0; i < n; i++) {
apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
}
}
}
 
 
static void
sample_cube_linear_mipmap_linear(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
const struct gl_texture_image **images;
GLfloat newCoord[4];
GLint level = linear_mipmap_level(tObj, lambda[i]);
level = MAX2(level - 1, 0); /* see comment above */
images = choose_cube_face(tObj, texcoord[i], newCoord);
if (level >= tObj->_MaxLevel) {
sample_2d_linear(ctx, samp, images[tObj->_MaxLevel],
newCoord, rgba[i]);
}
else {
GLfloat t0[4], t1[4];
const GLfloat f = FRAC(lambda[i]);
sample_2d_linear(ctx, samp, images[level ], newCoord, t0);
sample_2d_linear(ctx, samp, images[level+1], newCoord, t1);
lerp_rgba(rgba[i], f, t0, t1);
}
}
if (is_depth_texture(tObj)) {
for (i = 0; i < n; i++) {
apply_depth_mode(tObj->DepthMode, rgba[i][0], rgba[i]);
}
}
}
 
 
/** Sample cube texture, using lambda to choose between min/magnification */
static void
sample_lambda_cube(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4], const GLfloat lambda[],
GLfloat rgba[][4])
{
GLuint minStart, minEnd; /* texels with minification */
GLuint magStart, magEnd; /* texels with magnification */
 
assert(lambda != NULL);
compute_min_mag_ranges(samp, n, lambda,
&minStart, &minEnd, &magStart, &magEnd);
 
if (minStart < minEnd) {
/* do the minified texels */
const GLuint m = minEnd - minStart;
switch (samp->MinFilter) {
case GL_NEAREST:
sample_nearest_cube(ctx, samp, tObj, m, texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
case GL_LINEAR:
sample_linear_cube(ctx, samp, tObj, m, texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
case GL_NEAREST_MIPMAP_NEAREST:
sample_cube_nearest_mipmap_nearest(ctx, samp, tObj, m,
texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
case GL_LINEAR_MIPMAP_NEAREST:
sample_cube_linear_mipmap_nearest(ctx, samp, tObj, m,
texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
case GL_NEAREST_MIPMAP_LINEAR:
sample_cube_nearest_mipmap_linear(ctx, samp, tObj, m,
texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
case GL_LINEAR_MIPMAP_LINEAR:
sample_cube_linear_mipmap_linear(ctx, samp, tObj, m,
texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
default:
_mesa_problem(ctx, "Bad min filter in sample_lambda_cube");
break;
}
}
 
if (magStart < magEnd) {
/* do the magnified texels */
const GLuint m = magEnd - magStart;
switch (samp->MagFilter) {
case GL_NEAREST:
sample_nearest_cube(ctx, samp, tObj, m, texcoords + magStart,
lambda + magStart, rgba + magStart);
break;
case GL_LINEAR:
sample_linear_cube(ctx, samp, tObj, m, texcoords + magStart,
lambda + magStart, rgba + magStart);
break;
default:
_mesa_problem(ctx, "Bad mag filter in sample_lambda_cube");
break;
}
}
}
 
 
/**********************************************************************/
/* Texture Rectangle Sampling Functions */
/**********************************************************************/
 
 
static void
sample_nearest_rect(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4], const GLfloat lambda[],
GLfloat rgba[][4])
{
const struct gl_texture_image *img = tObj->Image[0][0];
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
const GLint width = img->Width;
const GLint height = img->Height;
GLuint i;
 
(void) ctx;
(void) lambda;
 
assert(samp->WrapS == GL_CLAMP ||
samp->WrapS == GL_CLAMP_TO_EDGE ||
samp->WrapS == GL_CLAMP_TO_BORDER);
assert(samp->WrapT == GL_CLAMP ||
samp->WrapT == GL_CLAMP_TO_EDGE ||
samp->WrapT == GL_CLAMP_TO_BORDER);
 
for (i = 0; i < n; i++) {
GLint row, col;
col = clamp_rect_coord_nearest(samp->WrapS, texcoords[i][0], width);
row = clamp_rect_coord_nearest(samp->WrapT, texcoords[i][1], height);
if (col < 0 || col >= width || row < 0 || row >= height)
get_border_color(samp, img, rgba[i]);
else
swImg->FetchTexel(swImg, col, row, 0, rgba[i]);
}
}
 
 
static void
sample_linear_rect(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
const struct gl_texture_image *img = tObj->Image[0][0];
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
const GLint width = img->Width;
const GLint height = img->Height;
GLuint i;
 
(void) ctx;
(void) lambda;
 
assert(samp->WrapS == GL_CLAMP ||
samp->WrapS == GL_CLAMP_TO_EDGE ||
samp->WrapS == GL_CLAMP_TO_BORDER);
assert(samp->WrapT == GL_CLAMP ||
samp->WrapT == GL_CLAMP_TO_EDGE ||
samp->WrapT == GL_CLAMP_TO_BORDER);
 
for (i = 0; i < n; i++) {
GLint i0, j0, i1, j1;
GLfloat t00[4], t01[4], t10[4], t11[4];
GLfloat a, b;
GLbitfield useBorderColor = 0x0;
 
clamp_rect_coord_linear(samp->WrapS, texcoords[i][0], width,
&i0, &i1, &a);
clamp_rect_coord_linear(samp->WrapT, texcoords[i][1], height,
&j0, &j1, &b);
 
/* compute integer rows/columns */
if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
 
/* get four texel samples */
if (useBorderColor & (I0BIT | J0BIT))
get_border_color(samp, img, t00);
else
swImg->FetchTexel(swImg, i0, j0, 0, t00);
 
if (useBorderColor & (I1BIT | J0BIT))
get_border_color(samp, img, t10);
else
swImg->FetchTexel(swImg, i1, j0, 0, t10);
 
if (useBorderColor & (I0BIT | J1BIT))
get_border_color(samp, img, t01);
else
swImg->FetchTexel(swImg, i0, j1, 0, t01);
 
if (useBorderColor & (I1BIT | J1BIT))
get_border_color(samp, img, t11);
else
swImg->FetchTexel(swImg, i1, j1, 0, t11);
 
lerp_rgba_2d(rgba[i], a, b, t00, t10, t01, t11);
}
}
 
 
/** Sample Rect texture, using lambda to choose between min/magnification */
static void
sample_lambda_rect(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4], const GLfloat lambda[],
GLfloat rgba[][4])
{
GLuint minStart, minEnd, magStart, magEnd;
 
/* We only need lambda to decide between minification and magnification.
* There is no mipmapping with rectangular textures.
*/
compute_min_mag_ranges(samp, n, lambda,
&minStart, &minEnd, &magStart, &magEnd);
 
if (minStart < minEnd) {
if (samp->MinFilter == GL_NEAREST) {
sample_nearest_rect(ctx, samp, tObj, minEnd - minStart,
texcoords + minStart, NULL, rgba + minStart);
}
else {
sample_linear_rect(ctx, samp, tObj, minEnd - minStart,
texcoords + minStart, NULL, rgba + minStart);
}
}
if (magStart < magEnd) {
if (samp->MagFilter == GL_NEAREST) {
sample_nearest_rect(ctx, samp, tObj, magEnd - magStart,
texcoords + magStart, NULL, rgba + magStart);
}
else {
sample_linear_rect(ctx, samp, tObj, magEnd - magStart,
texcoords + magStart, NULL, rgba + magStart);
}
}
}
 
 
/**********************************************************************/
/* 2D Texture Array Sampling Functions */
/**********************************************************************/
 
/**
* Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
*/
static void
sample_2d_array_nearest(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_image *img,
const GLfloat texcoord[4],
GLfloat rgba[4])
{
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
const GLint width = img->Width2; /* without border, power of two */
const GLint height = img->Height2; /* without border, power of two */
const GLint depth = img->Depth;
GLint i, j;
GLint array;
(void) ctx;
 
i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
j = nearest_texel_location(samp->WrapT, img, height, texcoord[1]);
array = tex_array_slice(texcoord[2], depth);
 
if (i < 0 || i >= (GLint) img->Width ||
j < 0 || j >= (GLint) img->Height ||
array < 0 || array >= (GLint) img->Depth) {
/* Need this test for GL_CLAMP_TO_BORDER mode */
get_border_color(samp, img, rgba);
}
else {
swImg->FetchTexel(swImg, i, j, array, rgba);
}
}
 
 
/**
* Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
*/
static void
sample_2d_array_linear(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_image *img,
const GLfloat texcoord[4],
GLfloat rgba[4])
{
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
const GLint width = img->Width2;
const GLint height = img->Height2;
const GLint depth = img->Depth;
GLint i0, j0, i1, j1;
GLint array;
GLbitfield useBorderColor = 0x0;
GLfloat a, b;
GLfloat t00[4], t01[4], t10[4], t11[4];
 
linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
linear_texel_locations(samp->WrapT, img, height, texcoord[1], &j0, &j1, &b);
array = tex_array_slice(texcoord[2], depth);
 
if (array < 0 || array >= depth) {
COPY_4V(rgba, samp->BorderColor.f);
}
else {
if (img->Border) {
i0 += img->Border;
i1 += img->Border;
j0 += img->Border;
j1 += img->Border;
}
else {
/* check if sampling texture border color */
if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
if (j0 < 0 || j0 >= height) useBorderColor |= J0BIT;
if (j1 < 0 || j1 >= height) useBorderColor |= J1BIT;
}
 
/* Fetch texels */
if (useBorderColor & (I0BIT | J0BIT)) {
get_border_color(samp, img, t00);
}
else {
swImg->FetchTexel(swImg, i0, j0, array, t00);
}
if (useBorderColor & (I1BIT | J0BIT)) {
get_border_color(samp, img, t10);
}
else {
swImg->FetchTexel(swImg, i1, j0, array, t10);
}
if (useBorderColor & (I0BIT | J1BIT)) {
get_border_color(samp, img, t01);
}
else {
swImg->FetchTexel(swImg, i0, j1, array, t01);
}
if (useBorderColor & (I1BIT | J1BIT)) {
get_border_color(samp, img, t11);
}
else {
swImg->FetchTexel(swImg, i1, j1, array, t11);
}
/* trilinear interpolation of samples */
lerp_rgba_2d(rgba, a, b, t00, t10, t01, t11);
}
}
 
 
static void
sample_2d_array_nearest_mipmap_nearest(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
for (i = 0; i < n; i++) {
GLint level = nearest_mipmap_level(tObj, lambda[i]);
sample_2d_array_nearest(ctx, samp, tObj->Image[0][level], texcoord[i],
rgba[i]);
}
}
 
 
static void
sample_2d_array_linear_mipmap_nearest(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level = nearest_mipmap_level(tObj, lambda[i]);
sample_2d_array_linear(ctx, samp, tObj->Image[0][level],
texcoord[i], rgba[i]);
}
}
 
 
static void
sample_2d_array_nearest_mipmap_linear(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level = linear_mipmap_level(tObj, lambda[i]);
if (level >= tObj->_MaxLevel) {
sample_2d_array_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
texcoord[i], rgba[i]);
}
else {
GLfloat t0[4], t1[4]; /* texels */
const GLfloat f = FRAC(lambda[i]);
sample_2d_array_nearest(ctx, samp, tObj->Image[0][level ],
texcoord[i], t0);
sample_2d_array_nearest(ctx, samp, tObj->Image[0][level+1],
texcoord[i], t1);
lerp_rgba(rgba[i], f, t0, t1);
}
}
}
 
 
static void
sample_2d_array_linear_mipmap_linear(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level = linear_mipmap_level(tObj, lambda[i]);
if (level >= tObj->_MaxLevel) {
sample_2d_array_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
texcoord[i], rgba[i]);
}
else {
GLfloat t0[4], t1[4]; /* texels */
const GLfloat f = FRAC(lambda[i]);
sample_2d_array_linear(ctx, samp, tObj->Image[0][level ],
texcoord[i], t0);
sample_2d_array_linear(ctx, samp, tObj->Image[0][level+1],
texcoord[i], t1);
lerp_rgba(rgba[i], f, t0, t1);
}
}
}
 
 
/** Sample 2D Array texture, nearest filtering for both min/magnification */
static void
sample_nearest_2d_array(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4], const GLfloat lambda[],
GLfloat rgba[][4])
{
GLuint i;
const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
(void) lambda;
for (i = 0; i < n; i++) {
sample_2d_array_nearest(ctx, samp, image, texcoords[i], rgba[i]);
}
}
 
 
 
/** Sample 2D Array texture, linear filtering for both min/magnification */
static void
sample_linear_2d_array(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
(void) lambda;
for (i = 0; i < n; i++) {
sample_2d_array_linear(ctx, samp, image, texcoords[i], rgba[i]);
}
}
 
 
/** Sample 2D Array texture, using lambda to choose between min/magnification */
static void
sample_lambda_2d_array(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4], const GLfloat lambda[],
GLfloat rgba[][4])
{
GLuint minStart, minEnd; /* texels with minification */
GLuint magStart, magEnd; /* texels with magnification */
GLuint i;
 
assert(lambda != NULL);
compute_min_mag_ranges(samp, n, lambda,
&minStart, &minEnd, &magStart, &magEnd);
 
if (minStart < minEnd) {
/* do the minified texels */
GLuint m = minEnd - minStart;
switch (samp->MinFilter) {
case GL_NEAREST:
for (i = minStart; i < minEnd; i++)
sample_2d_array_nearest(ctx, samp, _mesa_base_tex_image(tObj),
texcoords[i], rgba[i]);
break;
case GL_LINEAR:
for (i = minStart; i < minEnd; i++)
sample_2d_array_linear(ctx, samp, _mesa_base_tex_image(tObj),
texcoords[i], rgba[i]);
break;
case GL_NEAREST_MIPMAP_NEAREST:
sample_2d_array_nearest_mipmap_nearest(ctx, samp, tObj, m,
texcoords + minStart,
lambda + minStart,
rgba + minStart);
break;
case GL_LINEAR_MIPMAP_NEAREST:
sample_2d_array_linear_mipmap_nearest(ctx, samp, tObj, m,
texcoords + minStart,
lambda + minStart,
rgba + minStart);
break;
case GL_NEAREST_MIPMAP_LINEAR:
sample_2d_array_nearest_mipmap_linear(ctx, samp, tObj, m,
texcoords + minStart,
lambda + minStart,
rgba + minStart);
break;
case GL_LINEAR_MIPMAP_LINEAR:
sample_2d_array_linear_mipmap_linear(ctx, samp, tObj, m,
texcoords + minStart,
lambda + minStart,
rgba + minStart);
break;
default:
_mesa_problem(ctx, "Bad min filter in sample_2d_array_texture");
return;
}
}
 
if (magStart < magEnd) {
/* do the magnified texels */
switch (samp->MagFilter) {
case GL_NEAREST:
for (i = magStart; i < magEnd; i++)
sample_2d_array_nearest(ctx, samp, _mesa_base_tex_image(tObj),
texcoords[i], rgba[i]);
break;
case GL_LINEAR:
for (i = magStart; i < magEnd; i++)
sample_2d_array_linear(ctx, samp, _mesa_base_tex_image(tObj),
texcoords[i], rgba[i]);
break;
default:
_mesa_problem(ctx, "Bad mag filter in sample_2d_array_texture");
return;
}
}
}
 
 
 
 
/**********************************************************************/
/* 1D Texture Array Sampling Functions */
/**********************************************************************/
 
/**
* Return the texture sample for coordinate (s,t,r) using GL_NEAREST filter.
*/
static void
sample_1d_array_nearest(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_image *img,
const GLfloat texcoord[4],
GLfloat rgba[4])
{
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
const GLint width = img->Width2; /* without border, power of two */
const GLint height = img->Height;
GLint i;
GLint array;
(void) ctx;
 
i = nearest_texel_location(samp->WrapS, img, width, texcoord[0]);
array = tex_array_slice(texcoord[1], height);
 
if (i < 0 || i >= (GLint) img->Width ||
array < 0 || array >= (GLint) img->Height) {
/* Need this test for GL_CLAMP_TO_BORDER mode */
get_border_color(samp, img, rgba);
}
else {
swImg->FetchTexel(swImg, i, array, 0, rgba);
}
}
 
 
/**
* Return the texture sample for coordinate (s,t,r) using GL_LINEAR filter.
*/
static void
sample_1d_array_linear(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_image *img,
const GLfloat texcoord[4],
GLfloat rgba[4])
{
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
const GLint width = img->Width2;
const GLint height = img->Height;
GLint i0, i1;
GLint array;
GLbitfield useBorderColor = 0x0;
GLfloat a;
GLfloat t0[4], t1[4];
 
linear_texel_locations(samp->WrapS, img, width, texcoord[0], &i0, &i1, &a);
array = tex_array_slice(texcoord[1], height);
 
if (img->Border) {
i0 += img->Border;
i1 += img->Border;
}
else {
/* check if sampling texture border color */
if (i0 < 0 || i0 >= width) useBorderColor |= I0BIT;
if (i1 < 0 || i1 >= width) useBorderColor |= I1BIT;
}
 
if (array < 0 || array >= height) useBorderColor |= K0BIT;
 
/* Fetch texels */
if (useBorderColor & (I0BIT | K0BIT)) {
get_border_color(samp, img, t0);
}
else {
swImg->FetchTexel(swImg, i0, array, 0, t0);
}
if (useBorderColor & (I1BIT | K0BIT)) {
get_border_color(samp, img, t1);
}
else {
swImg->FetchTexel(swImg, i1, array, 0, t1);
}
 
/* bilinear interpolation of samples */
lerp_rgba(rgba, a, t0, t1);
}
 
 
static void
sample_1d_array_nearest_mipmap_nearest(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
for (i = 0; i < n; i++) {
GLint level = nearest_mipmap_level(tObj, lambda[i]);
sample_1d_array_nearest(ctx, samp, tObj->Image[0][level], texcoord[i],
rgba[i]);
}
}
 
 
static void
sample_1d_array_linear_mipmap_nearest(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level = nearest_mipmap_level(tObj, lambda[i]);
sample_1d_array_linear(ctx, samp, tObj->Image[0][level],
texcoord[i], rgba[i]);
}
}
 
 
static void
sample_1d_array_nearest_mipmap_linear(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level = linear_mipmap_level(tObj, lambda[i]);
if (level >= tObj->_MaxLevel) {
sample_1d_array_nearest(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
texcoord[i], rgba[i]);
}
else {
GLfloat t0[4], t1[4]; /* texels */
const GLfloat f = FRAC(lambda[i]);
sample_1d_array_nearest(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
sample_1d_array_nearest(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
lerp_rgba(rgba[i], f, t0, t1);
}
}
}
 
 
static void
sample_1d_array_linear_mipmap_linear(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj,
GLuint n, const GLfloat texcoord[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
assert(lambda != NULL);
for (i = 0; i < n; i++) {
GLint level = linear_mipmap_level(tObj, lambda[i]);
if (level >= tObj->_MaxLevel) {
sample_1d_array_linear(ctx, samp, tObj->Image[0][tObj->_MaxLevel],
texcoord[i], rgba[i]);
}
else {
GLfloat t0[4], t1[4]; /* texels */
const GLfloat f = FRAC(lambda[i]);
sample_1d_array_linear(ctx, samp, tObj->Image[0][level ], texcoord[i], t0);
sample_1d_array_linear(ctx, samp, tObj->Image[0][level+1], texcoord[i], t1);
lerp_rgba(rgba[i], f, t0, t1);
}
}
}
 
 
/** Sample 1D Array texture, nearest filtering for both min/magnification */
static void
sample_nearest_1d_array(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4], const GLfloat lambda[],
GLfloat rgba[][4])
{
GLuint i;
const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
(void) lambda;
for (i = 0; i < n; i++) {
sample_1d_array_nearest(ctx, samp, image, texcoords[i], rgba[i]);
}
}
 
 
/** Sample 1D Array texture, linear filtering for both min/magnification */
static void
sample_linear_1d_array(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4],
const GLfloat lambda[], GLfloat rgba[][4])
{
GLuint i;
const struct gl_texture_image *image = _mesa_base_tex_image(tObj);
(void) lambda;
for (i = 0; i < n; i++) {
sample_1d_array_linear(ctx, samp, image, texcoords[i], rgba[i]);
}
}
 
 
/** Sample 1D Array texture, using lambda to choose between min/magnification */
static void
sample_lambda_1d_array(struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4], const GLfloat lambda[],
GLfloat rgba[][4])
{
GLuint minStart, minEnd; /* texels with minification */
GLuint magStart, magEnd; /* texels with magnification */
GLuint i;
 
assert(lambda != NULL);
compute_min_mag_ranges(samp, n, lambda,
&minStart, &minEnd, &magStart, &magEnd);
 
if (minStart < minEnd) {
/* do the minified texels */
GLuint m = minEnd - minStart;
switch (samp->MinFilter) {
case GL_NEAREST:
for (i = minStart; i < minEnd; i++)
sample_1d_array_nearest(ctx, samp, _mesa_base_tex_image(tObj),
texcoords[i], rgba[i]);
break;
case GL_LINEAR:
for (i = minStart; i < minEnd; i++)
sample_1d_array_linear(ctx, samp, _mesa_base_tex_image(tObj),
texcoords[i], rgba[i]);
break;
case GL_NEAREST_MIPMAP_NEAREST:
sample_1d_array_nearest_mipmap_nearest(ctx, samp, tObj, m, texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
case GL_LINEAR_MIPMAP_NEAREST:
sample_1d_array_linear_mipmap_nearest(ctx, samp, tObj, m,
texcoords + minStart,
lambda + minStart,
rgba + minStart);
break;
case GL_NEAREST_MIPMAP_LINEAR:
sample_1d_array_nearest_mipmap_linear(ctx, samp, tObj, m, texcoords + minStart,
lambda + minStart, rgba + minStart);
break;
case GL_LINEAR_MIPMAP_LINEAR:
sample_1d_array_linear_mipmap_linear(ctx, samp, tObj, m,
texcoords + minStart,
lambda + minStart,
rgba + minStart);
break;
default:
_mesa_problem(ctx, "Bad min filter in sample_1d_array_texture");
return;
}
}
 
if (magStart < magEnd) {
/* do the magnified texels */
switch (samp->MagFilter) {
case GL_NEAREST:
for (i = magStart; i < magEnd; i++)
sample_1d_array_nearest(ctx, samp, _mesa_base_tex_image(tObj),
texcoords[i], rgba[i]);
break;
case GL_LINEAR:
for (i = magStart; i < magEnd; i++)
sample_1d_array_linear(ctx, samp, _mesa_base_tex_image(tObj),
texcoords[i], rgba[i]);
break;
default:
_mesa_problem(ctx, "Bad mag filter in sample_1d_array_texture");
return;
}
}
}
 
 
/**
* Compare texcoord against depth sample. Return 1.0 or 0.0 value.
*/
static GLfloat
shadow_compare(GLenum function, GLfloat coord, GLfloat depthSample)
{
switch (function) {
case GL_LEQUAL:
return (coord <= depthSample) ? 1.0F : 0.0F;
case GL_GEQUAL:
return (coord >= depthSample) ? 1.0F : 0.0F;
case GL_LESS:
return (coord < depthSample) ? 1.0F : 0.0F;
case GL_GREATER:
return (coord > depthSample) ? 1.0F : 0.0F;
case GL_EQUAL:
return (coord == depthSample) ? 1.0F : 0.0F;
case GL_NOTEQUAL:
return (coord != depthSample) ? 1.0F : 0.0F;
case GL_ALWAYS:
return 1.0F;
case GL_NEVER:
return 0.0F;
case GL_NONE:
return depthSample;
default:
_mesa_problem(NULL, "Bad compare func in shadow_compare");
return 0.0F;
}
}
 
 
/**
* Compare texcoord against four depth samples.
*/
static GLfloat
shadow_compare4(GLenum function, GLfloat coord,
GLfloat depth00, GLfloat depth01,
GLfloat depth10, GLfloat depth11,
GLfloat wi, GLfloat wj)
{
const GLfloat d = 0.25F;
GLfloat luminance = 1.0F;
 
switch (function) {
case GL_LEQUAL:
if (coord > depth00) luminance -= d;
if (coord > depth01) luminance -= d;
if (coord > depth10) luminance -= d;
if (coord > depth11) luminance -= d;
return luminance;
case GL_GEQUAL:
if (coord < depth00) luminance -= d;
if (coord < depth01) luminance -= d;
if (coord < depth10) luminance -= d;
if (coord < depth11) luminance -= d;
return luminance;
case GL_LESS:
if (coord >= depth00) luminance -= d;
if (coord >= depth01) luminance -= d;
if (coord >= depth10) luminance -= d;
if (coord >= depth11) luminance -= d;
return luminance;
case GL_GREATER:
if (coord <= depth00) luminance -= d;
if (coord <= depth01) luminance -= d;
if (coord <= depth10) luminance -= d;
if (coord <= depth11) luminance -= d;
return luminance;
case GL_EQUAL:
if (coord != depth00) luminance -= d;
if (coord != depth01) luminance -= d;
if (coord != depth10) luminance -= d;
if (coord != depth11) luminance -= d;
return luminance;
case GL_NOTEQUAL:
if (coord == depth00) luminance -= d;
if (coord == depth01) luminance -= d;
if (coord == depth10) luminance -= d;
if (coord == depth11) luminance -= d;
return luminance;
case GL_ALWAYS:
return 1.0F;
case GL_NEVER:
return 0.0F;
case GL_NONE:
/* ordinary bilinear filtering */
return lerp_2d(wi, wj, depth00, depth10, depth01, depth11);
default:
_mesa_problem(NULL, "Bad compare func in sample_compare4");
return 0.0F;
}
}
 
 
/**
* Choose the mipmap level to use when sampling from a depth texture.
*/
static int
choose_depth_texture_level(const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLfloat lambda)
{
GLint level;
 
if (samp->MinFilter == GL_NEAREST || samp->MinFilter == GL_LINEAR) {
/* no mipmapping - use base level */
level = tObj->BaseLevel;
}
else {
/* choose mipmap level */
lambda = CLAMP(lambda, samp->MinLod, samp->MaxLod);
level = (GLint) lambda;
level = CLAMP(level, tObj->BaseLevel, tObj->_MaxLevel);
}
 
return level;
}
 
 
/**
* Sample a shadow/depth texture. This function is incomplete. It doesn't
* check for minification vs. magnification, etc.
*/
static void
sample_depth_texture( struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4], const GLfloat lambda[],
GLfloat texel[][4] )
{
const GLint level = choose_depth_texture_level(samp, tObj, lambda[0]);
const struct gl_texture_image *img = tObj->Image[0][level];
const struct swrast_texture_image *swImg = swrast_texture_image_const(img);
const GLint width = img->Width;
const GLint height = img->Height;
const GLint depth = img->Depth;
const GLuint compare_coord = (tObj->Target == GL_TEXTURE_2D_ARRAY_EXT)
? 3 : 2;
GLenum function;
GLfloat result;
 
assert(img->_BaseFormat == GL_DEPTH_COMPONENT ||
img->_BaseFormat == GL_DEPTH_STENCIL_EXT);
 
assert(tObj->Target == GL_TEXTURE_1D ||
tObj->Target == GL_TEXTURE_2D ||
tObj->Target == GL_TEXTURE_RECTANGLE_NV ||
tObj->Target == GL_TEXTURE_1D_ARRAY_EXT ||
tObj->Target == GL_TEXTURE_2D_ARRAY_EXT ||
tObj->Target == GL_TEXTURE_CUBE_MAP);
 
/* XXXX if samp->MinFilter != samp->MagFilter, we're ignoring lambda */
 
function = (samp->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB) ?
samp->CompareFunc : GL_NONE;
 
if (samp->MagFilter == GL_NEAREST) {
GLuint i;
for (i = 0; i < n; i++) {
GLfloat depthSample, depthRef;
GLint col, row, slice;
 
nearest_texcoord(samp, tObj, level, texcoords[i], &col, &row, &slice);
 
if (col >= 0 && row >= 0 && col < width && row < height &&
slice >= 0 && slice < depth) {
swImg->FetchTexel(swImg, col, row, slice, &depthSample);
}
else {
depthSample = samp->BorderColor.f[0];
}
 
depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F);
 
result = shadow_compare(function, depthRef, depthSample);
 
apply_depth_mode(tObj->DepthMode, result, texel[i]);
}
}
else {
GLuint i;
assert(samp->MagFilter == GL_LINEAR);
for (i = 0; i < n; i++) {
GLfloat depth00, depth01, depth10, depth11, depthRef;
GLint i0, i1, j0, j1;
GLint slice;
GLfloat wi, wj;
GLuint useBorderTexel;
 
linear_texcoord(samp, tObj, level, texcoords[i], &i0, &i1, &j0, &j1, &slice,
&wi, &wj);
 
useBorderTexel = 0;
if (img->Border) {
i0 += img->Border;
i1 += img->Border;
if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) {
j0 += img->Border;
j1 += img->Border;
}
}
else {
if (i0 < 0 || i0 >= (GLint) width) useBorderTexel |= I0BIT;
if (i1 < 0 || i1 >= (GLint) width) useBorderTexel |= I1BIT;
if (j0 < 0 || j0 >= (GLint) height) useBorderTexel |= J0BIT;
if (j1 < 0 || j1 >= (GLint) height) useBorderTexel |= J1BIT;
}
 
if (slice < 0 || slice >= (GLint) depth) {
depth00 = samp->BorderColor.f[0];
depth01 = samp->BorderColor.f[0];
depth10 = samp->BorderColor.f[0];
depth11 = samp->BorderColor.f[0];
}
else {
/* get four depth samples from the texture */
if (useBorderTexel & (I0BIT | J0BIT)) {
depth00 = samp->BorderColor.f[0];
}
else {
swImg->FetchTexel(swImg, i0, j0, slice, &depth00);
}
if (useBorderTexel & (I1BIT | J0BIT)) {
depth10 = samp->BorderColor.f[0];
}
else {
swImg->FetchTexel(swImg, i1, j0, slice, &depth10);
}
 
if (tObj->Target != GL_TEXTURE_1D_ARRAY_EXT) {
if (useBorderTexel & (I0BIT | J1BIT)) {
depth01 = samp->BorderColor.f[0];
}
else {
swImg->FetchTexel(swImg, i0, j1, slice, &depth01);
}
if (useBorderTexel & (I1BIT | J1BIT)) {
depth11 = samp->BorderColor.f[0];
}
else {
swImg->FetchTexel(swImg, i1, j1, slice, &depth11);
}
}
else {
depth01 = depth00;
depth11 = depth10;
}
}
 
depthRef = CLAMP(texcoords[i][compare_coord], 0.0F, 1.0F);
 
result = shadow_compare4(function, depthRef,
depth00, depth01, depth10, depth11,
wi, wj);
 
apply_depth_mode(tObj->DepthMode, result, texel[i]);
} /* for */
} /* if filter */
}
 
 
/**
* We use this function when a texture object is in an "incomplete" state.
* When a fragment program attempts to sample an incomplete texture we
* return black (see issue 23 in GL_ARB_fragment_program spec).
* Note: fragment programs don't observe the texture enable/disable flags.
*/
static void
null_sample_func( struct gl_context *ctx,
const struct gl_sampler_object *samp,
const struct gl_texture_object *tObj, GLuint n,
const GLfloat texcoords[][4], const GLfloat lambda[],
GLfloat rgba[][4])
{
GLuint i;
(void) ctx;
(void) tObj;
(void) texcoords;
(void) lambda;
(void) samp;
for (i = 0; i < n; i++) {
rgba[i][RCOMP] = 0;
rgba[i][GCOMP] = 0;
rgba[i][BCOMP] = 0;
rgba[i][ACOMP] = 1.0;
}
}
 
 
/**
* Choose the texture sampling function for the given texture object.
*/
texture_sample_func
_swrast_choose_texture_sample_func( struct gl_context *ctx,
const struct gl_texture_object *t,
const struct gl_sampler_object *sampler)
{
if (!t || !_mesa_is_texture_complete(t, sampler)) {
return &null_sample_func;
}
else {
const GLboolean needLambda =
(GLboolean) (sampler->MinFilter != sampler->MagFilter);
 
switch (t->Target) {
case GL_TEXTURE_1D:
if (is_depth_texture(t)) {
return &sample_depth_texture;
}
else if (needLambda) {
return &sample_lambda_1d;
}
else if (sampler->MinFilter == GL_LINEAR) {
return &sample_linear_1d;
}
else {
assert(sampler->MinFilter == GL_NEAREST);
return &sample_nearest_1d;
}
case GL_TEXTURE_2D:
if (is_depth_texture(t)) {
return &sample_depth_texture;
}
else if (needLambda) {
/* Anisotropic filtering extension. Activated only if mipmaps are used */
if (sampler->MaxAnisotropy > 1.0 &&
sampler->MinFilter == GL_LINEAR_MIPMAP_LINEAR) {
return &sample_lambda_2d_aniso;
}
return &sample_lambda_2d;
}
else if (sampler->MinFilter == GL_LINEAR) {
return &sample_linear_2d;
}
else {
/* check for a few optimized cases */
const struct gl_texture_image *img = _mesa_base_tex_image(t);
const struct swrast_texture_image *swImg =
swrast_texture_image_const(img);
texture_sample_func func;
 
assert(sampler->MinFilter == GL_NEAREST);
func = &sample_nearest_2d;
if (sampler->WrapS == GL_REPEAT &&
sampler->WrapT == GL_REPEAT &&
swImg->_IsPowerOfTwo &&
img->Border == 0) {
if (img->TexFormat == MESA_FORMAT_BGR_UNORM8)
func = &opt_sample_rgb_2d;
else if (img->TexFormat == MESA_FORMAT_A8B8G8R8_UNORM)
func = &opt_sample_rgba_2d;
}
 
return func;
}
case GL_TEXTURE_3D:
if (needLambda) {
return &sample_lambda_3d;
}
else if (sampler->MinFilter == GL_LINEAR) {
return &sample_linear_3d;
}
else {
assert(sampler->MinFilter == GL_NEAREST);
return &sample_nearest_3d;
}
case GL_TEXTURE_CUBE_MAP:
if (needLambda) {
return &sample_lambda_cube;
}
else if (sampler->MinFilter == GL_LINEAR) {
return &sample_linear_cube;
}
else {
assert(sampler->MinFilter == GL_NEAREST);
return &sample_nearest_cube;
}
case GL_TEXTURE_RECTANGLE_NV:
if (is_depth_texture(t)) {
return &sample_depth_texture;
}
else if (needLambda) {
return &sample_lambda_rect;
}
else if (sampler->MinFilter == GL_LINEAR) {
return &sample_linear_rect;
}
else {
assert(sampler->MinFilter == GL_NEAREST);
return &sample_nearest_rect;
}
case GL_TEXTURE_1D_ARRAY_EXT:
if (is_depth_texture(t)) {
return &sample_depth_texture;
}
else if (needLambda) {
return &sample_lambda_1d_array;
}
else if (sampler->MinFilter == GL_LINEAR) {
return &sample_linear_1d_array;
}
else {
assert(sampler->MinFilter == GL_NEAREST);
return &sample_nearest_1d_array;
}
case GL_TEXTURE_2D_ARRAY_EXT:
if (is_depth_texture(t)) {
return &sample_depth_texture;
}
else if (needLambda) {
return &sample_lambda_2d_array;
}
else if (sampler->MinFilter == GL_LINEAR) {
return &sample_linear_2d_array;
}
else {
assert(sampler->MinFilter == GL_NEAREST);
return &sample_nearest_2d_array;
}
default:
_mesa_problem(ctx,
"invalid target in _swrast_choose_texture_sample_func");
return &null_sample_func;
}
}
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_texfilter.h
0,0 → 1,42
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_TEXFILTER_H
#define S_TEXFILTER_H
 
 
#include "s_context.h"
 
struct gl_context;
struct gl_texture_object;
 
 
extern texture_sample_func
_swrast_choose_texture_sample_func( struct gl_context *ctx,
const struct gl_texture_object *tObj,
const struct gl_sampler_object *sampler);
 
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_texrender.c
0,0 → 1,102
 
#include "main/context.h"
#include "main/fbobject.h"
#include "main/macros.h"
#include "main/teximage.h"
#include "main/renderbuffer.h"
#include "swrast/swrast.h"
#include "swrast/s_context.h"
#include "swrast/s_texfetch.h"
 
 
/*
* Render-to-texture code for GL_EXT_framebuffer_object
*/
 
 
static void
delete_texture_wrapper(struct gl_context *ctx, struct gl_renderbuffer *rb)
{
assert(rb->RefCount == 0);
free(rb);
}
 
/**
* Update the renderbuffer wrapper for rendering to a texture.
* For example, update the width, height of the RB based on the texture size,
* update the internal format info, etc.
*/
static void
update_wrapper(struct gl_context *ctx, struct gl_renderbuffer_attachment *att)
{
struct gl_renderbuffer *rb = att->Renderbuffer;
struct swrast_renderbuffer *srb = swrast_renderbuffer(rb);
struct swrast_texture_image *swImage;
mesa_format format;
GLuint zOffset;
 
(void) ctx;
 
swImage = swrast_texture_image(rb->TexImage);
assert(swImage);
 
format = swImage->Base.TexFormat;
 
if (att->Texture->Target == GL_TEXTURE_1D_ARRAY_EXT) {
zOffset = 0;
}
else {
zOffset = att->Zoffset;
}
 
/* Want to store linear values, not sRGB */
rb->Format = _mesa_get_srgb_format_linear(format);
 
srb->Buffer = swImage->ImageSlices[zOffset];
}
 
 
 
/**
* Called when rendering to a texture image begins, or when changing
* the dest mipmap level, cube face, etc.
* This is a fallback routine for software render-to-texture.
*
* Called via the glRenderbufferTexture1D/2D/3D() functions
* and elsewhere (such as glTexImage2D).
*
* The image we're rendering into is
* att->Texture->Image[att->CubeMapFace][att->TextureLevel];
* It'll never be NULL.
*
* \param fb the framebuffer object the texture is being bound to
* \param att the fb attachment point of the texture
*
* \sa _mesa_FramebufferRenderbuffer_sw
*/
void
_swrast_render_texture(struct gl_context *ctx,
struct gl_framebuffer *fb,
struct gl_renderbuffer_attachment *att)
{
struct gl_renderbuffer *rb = att->Renderbuffer;
(void) fb;
 
/* plug in our texture_renderbuffer-specific functions */
rb->Delete = delete_texture_wrapper;
 
update_wrapper(ctx, att);
}
 
 
void
_swrast_finish_render_texture(struct gl_context *ctx,
struct gl_renderbuffer *rb)
{
/* do nothing */
/* The renderbuffer texture wrapper will get deleted by the
* normal mechanism for deleting renderbuffers.
*/
(void) ctx;
(void) rb;
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_texture.c
0,0 → 1,386
/*
* Mesa 3-D graphics library
*
* Copyright (C) 2011 VMware, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
/**
* Functions for mapping/unmapping texture images.
*/
 
 
#include "main/context.h"
#include "main/fbobject.h"
#include "main/teximage.h"
#include "main/texobj.h"
#include "swrast/swrast.h"
#include "swrast/s_context.h"
 
 
/**
* Allocate a new swrast_texture_image (a subclass of gl_texture_image).
* Called via ctx->Driver.NewTextureImage().
*/
struct gl_texture_image *
_swrast_new_texture_image( struct gl_context *ctx )
{
(void) ctx;
return (struct gl_texture_image *) CALLOC_STRUCT(swrast_texture_image);
}
 
 
/**
* Free a swrast_texture_image (a subclass of gl_texture_image).
* Called via ctx->Driver.DeleteTextureImage().
*/
void
_swrast_delete_texture_image(struct gl_context *ctx,
struct gl_texture_image *texImage)
{
/* Nothing special for the subclass yet */
_mesa_delete_texture_image(ctx, texImage);
}
 
static unsigned int
texture_slices(struct gl_texture_image *texImage)
{
if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY)
return texImage->Height;
else
return texImage->Depth;
}
 
unsigned int
_swrast_teximage_slice_height(struct gl_texture_image *texImage)
{
/* For 1D array textures, the slices are all 1 pixel high, and Height is
* the number of slices.
*/
if (texImage->TexObject->Target == GL_TEXTURE_1D_ARRAY)
return 1;
else
return texImage->Height;
}
 
/**
* Called via ctx->Driver.AllocTextureImageBuffer()
*/
GLboolean
_swrast_alloc_texture_image_buffer(struct gl_context *ctx,
struct gl_texture_image *texImage)
{
struct swrast_texture_image *swImg = swrast_texture_image(texImage);
GLuint bytesPerSlice;
GLuint slices = texture_slices(texImage);
GLuint i;
 
if (!_swrast_init_texture_image(texImage))
return GL_FALSE;
 
bytesPerSlice = _mesa_format_image_size(texImage->TexFormat, texImage->Width,
_swrast_teximage_slice_height(texImage), 1);
 
assert(!swImg->Buffer);
swImg->Buffer = _mesa_align_malloc(bytesPerSlice * slices, 512);
if (!swImg->Buffer)
return GL_FALSE;
 
/* RowStride and ImageSlices[] describe how to address texels in 'Data' */
swImg->RowStride = _mesa_format_row_stride(texImage->TexFormat,
texImage->Width);
 
for (i = 0; i < slices; i++) {
swImg->ImageSlices[i] = swImg->Buffer + bytesPerSlice * i;
}
 
return GL_TRUE;
}
 
 
/**
* Code that overrides ctx->Driver.AllocTextureImageBuffer may use this to
* initialize the fields of swrast_texture_image without allocating the image
* buffer or initializing RowStride or the contents of ImageSlices.
*
* Returns GL_TRUE on success, GL_FALSE on memory allocation failure.
*/
GLboolean
_swrast_init_texture_image(struct gl_texture_image *texImage)
{
struct swrast_texture_image *swImg = swrast_texture_image(texImage);
 
if ((texImage->Width == 1 || _mesa_is_pow_two(texImage->Width2)) &&
(texImage->Height == 1 || _mesa_is_pow_two(texImage->Height2)) &&
(texImage->Depth == 1 || _mesa_is_pow_two(texImage->Depth2)))
swImg->_IsPowerOfTwo = GL_TRUE;
else
swImg->_IsPowerOfTwo = GL_FALSE;
 
/* Compute Width/Height/DepthScale for mipmap lod computation */
if (texImage->TexObject->Target == GL_TEXTURE_RECTANGLE_NV) {
/* scale = 1.0 since texture coords directly map to texels */
swImg->WidthScale = 1.0;
swImg->HeightScale = 1.0;
swImg->DepthScale = 1.0;
}
else {
swImg->WidthScale = (GLfloat) texImage->Width;
swImg->HeightScale = (GLfloat) texImage->Height;
swImg->DepthScale = (GLfloat) texImage->Depth;
}
 
assert(!swImg->ImageSlices);
swImg->ImageSlices = calloc(texture_slices(texImage), sizeof(void *));
if (!swImg->ImageSlices)
return GL_FALSE;
 
return GL_TRUE;
}
 
 
/**
* Called via ctx->Driver.FreeTextureImageBuffer()
*/
void
_swrast_free_texture_image_buffer(struct gl_context *ctx,
struct gl_texture_image *texImage)
{
struct swrast_texture_image *swImage = swrast_texture_image(texImage);
 
_mesa_align_free(swImage->Buffer);
swImage->Buffer = NULL;
 
free(swImage->ImageSlices);
swImage->ImageSlices = NULL;
}
 
 
/**
* Error checking for debugging only.
*/
static void
check_map_teximage(const struct gl_texture_image *texImage,
GLuint slice, GLuint x, GLuint y, GLuint w, GLuint h)
{
 
if (texImage->TexObject->Target == GL_TEXTURE_1D)
assert(y == 0 && h == 1);
 
assert(x < texImage->Width || texImage->Width == 0);
assert(y < texImage->Height || texImage->Height == 0);
assert(x + w <= texImage->Width);
assert(y + h <= texImage->Height);
}
 
/**
* Map a 2D slice of a texture image into user space.
* (x,y,w,h) defines a region of interest (ROI). Reading/writing texels
* outside of the ROI is undefined.
*
* \param texImage the texture image
* \param slice the 3D image slice or array texture slice
* \param x, y, w, h region of interest
* \param mode bitmask of GL_MAP_READ_BIT, GL_MAP_WRITE_BIT
* \param mapOut returns start of mapping of region of interest
* \param rowStrideOut returns row stride (in bytes)
*/
void
_swrast_map_teximage(struct gl_context *ctx,
struct gl_texture_image *texImage,
GLuint slice,
GLuint x, GLuint y, GLuint w, GLuint h,
GLbitfield mode,
GLubyte **mapOut,
GLint *rowStrideOut)
{
struct swrast_texture_image *swImage = swrast_texture_image(texImage);
GLubyte *map;
GLint stride, texelSize;
GLuint bw, bh;
 
check_map_teximage(texImage, slice, x, y, w, h);
 
if (!swImage->Buffer) {
/* Either glTexImage was called with a NULL <pixels> argument or
* we ran out of memory when allocating texture memory,
*/
*mapOut = NULL;
*rowStrideOut = 0;
return;
}
 
texelSize = _mesa_get_format_bytes(texImage->TexFormat);
stride = _mesa_format_row_stride(texImage->TexFormat, texImage->Width);
_mesa_get_format_block_size(texImage->TexFormat, &bw, &bh);
 
assert(x % bw == 0);
assert(y % bh == 0);
 
/* This function can only be used with a swrast-allocated buffer, in which
* case ImageSlices is populated with pointers into Buffer.
*/
assert(swImage->Buffer);
assert(swImage->Buffer == swImage->ImageSlices[0]);
 
assert(slice < texture_slices(texImage));
map = swImage->ImageSlices[slice];
 
/* apply x/y offset to map address */
map += stride * (y / bh) + texelSize * (x / bw);
 
*mapOut = map;
*rowStrideOut = stride;
}
 
void
_swrast_unmap_teximage(struct gl_context *ctx,
struct gl_texture_image *texImage,
GLuint slice)
{
/* nop */
}
 
 
void
_swrast_map_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
{
const GLuint faces = _mesa_num_tex_faces(texObj->Target);
GLuint face, level;
 
for (face = 0; face < faces; face++) {
for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
struct gl_texture_image *texImage = texObj->Image[face][level];
struct swrast_texture_image *swImage = swrast_texture_image(texImage);
unsigned int i, slices;
 
if (!texImage)
continue;
 
/* In the case of a swrast-allocated texture buffer, the ImageSlices
* and RowStride are always available.
*/
if (swImage->Buffer) {
assert(swImage->ImageSlices[0] == swImage->Buffer);
continue;
}
 
if (!swImage->ImageSlices) {
swImage->ImageSlices =
calloc(texture_slices(texImage), sizeof(void *));
if (!swImage->ImageSlices)
continue;
}
 
slices = texture_slices(texImage);
 
for (i = 0; i < slices; i++) {
GLubyte *map;
GLint rowStride;
 
if (swImage->ImageSlices[i])
continue;
 
ctx->Driver.MapTextureImage(ctx, texImage, i,
0, 0,
texImage->Width, texImage->Height,
GL_MAP_READ_BIT | GL_MAP_WRITE_BIT,
&map, &rowStride);
 
swImage->ImageSlices[i] = map;
/* A swrast-using driver has to return the same rowstride for
* every slice of the same texture, since we don't track them
* separately.
*/
if (i == 0)
swImage->RowStride = rowStride;
else
assert(swImage->RowStride == rowStride);
}
}
}
}
 
 
void
_swrast_unmap_texture(struct gl_context *ctx, struct gl_texture_object *texObj)
{
const GLuint faces = _mesa_num_tex_faces(texObj->Target);
GLuint face, level;
 
for (face = 0; face < faces; face++) {
for (level = texObj->BaseLevel; level < MAX_TEXTURE_LEVELS; level++) {
struct gl_texture_image *texImage = texObj->Image[face][level];
struct swrast_texture_image *swImage = swrast_texture_image(texImage);
unsigned int i, slices;
 
if (!texImage)
continue;
 
if (swImage->Buffer)
return;
 
if (!swImage->ImageSlices)
continue;
 
slices = texture_slices(texImage);
 
for (i = 0; i < slices; i++) {
if (swImage->ImageSlices[i]) {
ctx->Driver.UnmapTextureImage(ctx, texImage, i);
swImage->ImageSlices[i] = NULL;
}
}
}
}
}
 
 
/**
* Map all textures for reading prior to software rendering.
*/
void
_swrast_map_textures(struct gl_context *ctx)
{
int unit;
 
for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) {
struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
 
if (texObj)
_swrast_map_texture(ctx, texObj);
}
}
 
 
/**
* Unmap all textures for reading prior to software rendering.
*/
void
_swrast_unmap_textures(struct gl_context *ctx)
{
int unit;
for (unit = 0; unit <= ctx->Texture._MaxEnabledTexImageUnit; unit++) {
struct gl_texture_object *texObj = ctx->Texture.Unit[unit]._Current;
 
if (texObj)
_swrast_unmap_texture(ctx, texObj);
}
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_triangle.c
0,0 → 1,1163
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
/*
* When the device driver doesn't implement triangle rasterization it
* can hook in _swrast_Triangle, which eventually calls one of these
* functions to draw triangles.
*/
 
#include "main/glheader.h"
#include "main/context.h"
#include "main/imports.h"
#include "main/macros.h"
#include "main/mtypes.h"
#include "main/state.h"
#include "main/samplerobj.h"
#include "main/teximage.h"
#include "program/prog_instruction.h"
 
#include "s_aatriangle.h"
#include "s_context.h"
#include "s_feedback.h"
#include "s_span.h"
#include "s_triangle.h"
 
 
/**
* Test if a triangle should be culled. Used for feedback and selection mode.
* \return GL_TRUE if the triangle is to be culled, GL_FALSE otherwise.
*/
GLboolean
_swrast_culltriangle( struct gl_context *ctx,
const SWvertex *v0,
const SWvertex *v1,
const SWvertex *v2 )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
GLfloat ex = v1->attrib[VARYING_SLOT_POS][0] - v0->attrib[VARYING_SLOT_POS][0];
GLfloat ey = v1->attrib[VARYING_SLOT_POS][1] - v0->attrib[VARYING_SLOT_POS][1];
GLfloat fx = v2->attrib[VARYING_SLOT_POS][0] - v0->attrib[VARYING_SLOT_POS][0];
GLfloat fy = v2->attrib[VARYING_SLOT_POS][1] - v0->attrib[VARYING_SLOT_POS][1];
GLfloat c = ex*fy-ey*fx;
 
if (c * swrast->_BackfaceSign * swrast->_BackfaceCullSign <= 0.0F)
return GL_FALSE;
 
return GL_TRUE;
}
 
 
 
/*
* Render a flat-shaded RGBA triangle.
*/
#define NAME flat_rgba_triangle
#define INTERP_Z 1
#define SETUP_CODE \
assert(ctx->Texture._EnabledCoordUnits == 0);\
assert(ctx->Light.ShadeModel==GL_FLAT); \
span.interpMask |= SPAN_RGBA; \
span.red = ChanToFixed(v2->color[0]); \
span.green = ChanToFixed(v2->color[1]); \
span.blue = ChanToFixed(v2->color[2]); \
span.alpha = ChanToFixed(v2->color[3]); \
span.redStep = 0; \
span.greenStep = 0; \
span.blueStep = 0; \
span.alphaStep = 0;
#define RENDER_SPAN( span ) _swrast_write_rgba_span(ctx, &span);
#include "s_tritemp.h"
 
 
 
/*
* Render a smooth-shaded RGBA triangle.
*/
#define NAME smooth_rgba_triangle
#define INTERP_Z 1
#define INTERP_RGB 1
#define INTERP_ALPHA 1
#define SETUP_CODE \
{ \
/* texturing must be off */ \
assert(ctx->Texture._EnabledCoordUnits == 0); \
assert(ctx->Light.ShadeModel==GL_SMOOTH); \
}
#define RENDER_SPAN( span ) _swrast_write_rgba_span(ctx, &span);
#include "s_tritemp.h"
 
 
 
/*
* Render an RGB, GL_DECAL, textured triangle.
* Interpolate S,T only w/out mipmapping or perspective correction.
*
* No fog. No depth testing.
*/
#define NAME simple_textured_triangle
#define INTERP_INT_TEX 1
#define S_SCALE twidth
#define T_SCALE theight
 
#define SETUP_CODE \
struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; \
const struct gl_texture_object *obj = \
ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; \
const struct gl_texture_image *texImg = \
_mesa_base_tex_image(obj); \
const struct swrast_texture_image *swImg = \
swrast_texture_image_const(texImg); \
const GLfloat twidth = (GLfloat) texImg->Width; \
const GLfloat theight = (GLfloat) texImg->Height; \
const GLint twidth_log2 = texImg->WidthLog2; \
const GLubyte *texture = (const GLubyte *) swImg->ImageSlices[0]; \
const GLint smask = texImg->Width - 1; \
const GLint tmask = texImg->Height - 1; \
assert(texImg->TexFormat == MESA_FORMAT_BGR_UNORM8); \
if (!rb || !texture) { \
return; \
}
 
#define RENDER_SPAN( span ) \
GLuint i; \
GLubyte (*rgba)[4] = swrast->SpanArrays->rgba8; \
span.intTex[0] -= FIXED_HALF; /* off-by-one error? */ \
span.intTex[1] -= FIXED_HALF; \
for (i = 0; i < span.end; i++) { \
GLint s = FixedToInt(span.intTex[0]) & smask; \
GLint t = FixedToInt(span.intTex[1]) & tmask; \
GLint pos = (t << twidth_log2) + s; \
pos = pos + pos + pos; /* multiply by 3 */ \
rgba[i][RCOMP] = texture[pos+2]; \
rgba[i][GCOMP] = texture[pos+1]; \
rgba[i][BCOMP] = texture[pos+0]; \
rgba[i][ACOMP] = 0xff; \
span.intTex[0] += span.intTexStep[0]; \
span.intTex[1] += span.intTexStep[1]; \
} \
_swrast_put_row(ctx, rb, GL_UNSIGNED_BYTE, span.end, \
span.x, span.y, rgba, NULL);
 
#include "s_tritemp.h"
 
 
 
/*
* Render an RGB, GL_DECAL, textured triangle.
* Interpolate S,T, GL_LESS depth test, w/out mipmapping or
* perspective correction.
* Depth buffer bits must be <= sizeof(DEFAULT_SOFTWARE_DEPTH_TYPE)
*
* No fog.
*/
#define NAME simple_z_textured_triangle
#define INTERP_Z 1
#define DEPTH_TYPE DEFAULT_SOFTWARE_DEPTH_TYPE
#define INTERP_INT_TEX 1
#define S_SCALE twidth
#define T_SCALE theight
 
#define SETUP_CODE \
struct gl_renderbuffer *rb = ctx->DrawBuffer->_ColorDrawBuffers[0]; \
const struct gl_texture_object *obj = \
ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; \
const struct gl_texture_image *texImg = \
_mesa_base_tex_image(obj); \
const struct swrast_texture_image *swImg = \
swrast_texture_image_const(texImg); \
const GLfloat twidth = (GLfloat) texImg->Width; \
const GLfloat theight = (GLfloat) texImg->Height; \
const GLint twidth_log2 = texImg->WidthLog2; \
const GLubyte *texture = (const GLubyte *) swImg->ImageSlices[0]; \
const GLint smask = texImg->Width - 1; \
const GLint tmask = texImg->Height - 1; \
assert(texImg->TexFormat == MESA_FORMAT_BGR_UNORM8); \
if (!rb || !texture) { \
return; \
}
 
#define RENDER_SPAN( span ) \
GLuint i; \
GLubyte (*rgba)[4] = swrast->SpanArrays->rgba8; \
GLubyte *mask = swrast->SpanArrays->mask; \
span.intTex[0] -= FIXED_HALF; /* off-by-one error? */ \
span.intTex[1] -= FIXED_HALF; \
for (i = 0; i < span.end; i++) { \
const GLuint z = FixedToDepth(span.z); \
if (z < zRow[i]) { \
GLint s = FixedToInt(span.intTex[0]) & smask; \
GLint t = FixedToInt(span.intTex[1]) & tmask; \
GLint pos = (t << twidth_log2) + s; \
pos = pos + pos + pos; /* multiply by 3 */ \
rgba[i][RCOMP] = texture[pos+2]; \
rgba[i][GCOMP] = texture[pos+1]; \
rgba[i][BCOMP] = texture[pos+0]; \
rgba[i][ACOMP] = 0xff; \
zRow[i] = z; \
mask[i] = 1; \
} \
else { \
mask[i] = 0; \
} \
span.intTex[0] += span.intTexStep[0]; \
span.intTex[1] += span.intTexStep[1]; \
span.z += span.zStep; \
} \
_swrast_put_row(ctx, rb, GL_UNSIGNED_BYTE, \
span.end, span.x, span.y, rgba, mask);
 
#include "s_tritemp.h"
 
 
#if CHAN_TYPE != GL_FLOAT
 
struct affine_info
{
GLenum filter;
GLenum format;
GLenum envmode;
GLint smask, tmask;
GLint twidth_log2;
const GLchan *texture;
GLfixed er, eg, eb, ea;
GLint tbytesline, tsize;
};
 
 
static inline GLint
ilerp(GLint t, GLint a, GLint b)
{
return a + ((t * (b - a)) >> FIXED_SHIFT);
}
 
static inline GLint
ilerp_2d(GLint ia, GLint ib, GLint v00, GLint v10, GLint v01, GLint v11)
{
const GLint temp0 = ilerp(ia, v00, v10);
const GLint temp1 = ilerp(ia, v01, v11);
return ilerp(ib, temp0, temp1);
}
 
 
/* This function can handle GL_NEAREST or GL_LINEAR sampling of 2D RGB or RGBA
* textures with GL_REPLACE, GL_MODULATE, GL_BLEND, GL_DECAL or GL_ADD
* texture env modes.
*/
static inline void
affine_span(struct gl_context *ctx, SWspan *span,
struct affine_info *info)
{
GLchan sample[4]; /* the filtered texture sample */
const GLuint texEnableSave = ctx->Texture._EnabledCoordUnits;
 
/* Instead of defining a function for each mode, a test is done
* between the outer and inner loops. This is to reduce code size
* and complexity. Observe that an optimizing compiler kills
* unused variables (for instance tf,sf,ti,si in case of GL_NEAREST).
*/
 
#define NEAREST_RGB \
sample[RCOMP] = tex00[2]; \
sample[GCOMP] = tex00[1]; \
sample[BCOMP] = tex00[0]; \
sample[ACOMP] = CHAN_MAX;
 
#define LINEAR_RGB \
sample[RCOMP] = ilerp_2d(sf, tf, tex00[2], tex01[2], tex10[2], tex11[2]);\
sample[GCOMP] = ilerp_2d(sf, tf, tex00[1], tex01[1], tex10[1], tex11[1]);\
sample[BCOMP] = ilerp_2d(sf, tf, tex00[0], tex01[0], tex10[0], tex11[0]);\
sample[ACOMP] = CHAN_MAX;
 
#define NEAREST_RGBA \
sample[RCOMP] = tex00[3]; \
sample[GCOMP] = tex00[2]; \
sample[BCOMP] = tex00[1]; \
sample[ACOMP] = tex00[0];
 
#define LINEAR_RGBA \
sample[RCOMP] = ilerp_2d(sf, tf, tex00[3], tex01[3], tex10[3], tex11[3]);\
sample[GCOMP] = ilerp_2d(sf, tf, tex00[2], tex01[2], tex10[2], tex11[2]);\
sample[BCOMP] = ilerp_2d(sf, tf, tex00[1], tex01[1], tex10[1], tex11[1]);\
sample[ACOMP] = ilerp_2d(sf, tf, tex00[0], tex01[0], tex10[0], tex11[0])
 
#define MODULATE \
dest[RCOMP] = span->red * (sample[RCOMP] + 1u) >> (FIXED_SHIFT + 8); \
dest[GCOMP] = span->green * (sample[GCOMP] + 1u) >> (FIXED_SHIFT + 8); \
dest[BCOMP] = span->blue * (sample[BCOMP] + 1u) >> (FIXED_SHIFT + 8); \
dest[ACOMP] = span->alpha * (sample[ACOMP] + 1u) >> (FIXED_SHIFT + 8)
 
#define DECAL \
dest[RCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->red + \
((sample[ACOMP] + 1) * sample[RCOMP] << FIXED_SHIFT)) \
>> (FIXED_SHIFT + 8); \
dest[GCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->green + \
((sample[ACOMP] + 1) * sample[GCOMP] << FIXED_SHIFT)) \
>> (FIXED_SHIFT + 8); \
dest[BCOMP] = ((CHAN_MAX - sample[ACOMP]) * span->blue + \
((sample[ACOMP] + 1) * sample[BCOMP] << FIXED_SHIFT)) \
>> (FIXED_SHIFT + 8); \
dest[ACOMP] = FixedToInt(span->alpha)
 
#define BLEND \
dest[RCOMP] = ((CHAN_MAX - sample[RCOMP]) * span->red \
+ (sample[RCOMP] + 1) * info->er) >> (FIXED_SHIFT + 8); \
dest[GCOMP] = ((CHAN_MAX - sample[GCOMP]) * span->green \
+ (sample[GCOMP] + 1) * info->eg) >> (FIXED_SHIFT + 8); \
dest[BCOMP] = ((CHAN_MAX - sample[BCOMP]) * span->blue \
+ (sample[BCOMP] + 1) * info->eb) >> (FIXED_SHIFT + 8); \
dest[ACOMP] = span->alpha * (sample[ACOMP] + 1) >> (FIXED_SHIFT + 8)
 
#define REPLACE COPY_CHAN4(dest, sample)
 
#define ADD \
{ \
GLint rSum = FixedToInt(span->red) + (GLint) sample[RCOMP]; \
GLint gSum = FixedToInt(span->green) + (GLint) sample[GCOMP]; \
GLint bSum = FixedToInt(span->blue) + (GLint) sample[BCOMP]; \
dest[RCOMP] = MIN2(rSum, CHAN_MAX); \
dest[GCOMP] = MIN2(gSum, CHAN_MAX); \
dest[BCOMP] = MIN2(bSum, CHAN_MAX); \
dest[ACOMP] = span->alpha * (sample[ACOMP] + 1) >> (FIXED_SHIFT + 8); \
}
 
/* shortcuts */
 
#define NEAREST_RGB_REPLACE \
NEAREST_RGB; \
dest[0] = sample[0]; \
dest[1] = sample[1]; \
dest[2] = sample[2]; \
dest[3] = FixedToInt(span->alpha);
 
#define NEAREST_RGBA_REPLACE \
dest[RCOMP] = tex00[3]; \
dest[GCOMP] = tex00[2]; \
dest[BCOMP] = tex00[1]; \
dest[ACOMP] = tex00[0]
 
#define SPAN_NEAREST(DO_TEX, COMPS) \
for (i = 0; i < span->end; i++) { \
/* Isn't it necessary to use FixedFloor below?? */ \
GLint s = FixedToInt(span->intTex[0]) & info->smask; \
GLint t = FixedToInt(span->intTex[1]) & info->tmask; \
GLint pos = (t << info->twidth_log2) + s; \
const GLchan *tex00 = info->texture + COMPS * pos; \
DO_TEX; \
span->red += span->redStep; \
span->green += span->greenStep; \
span->blue += span->blueStep; \
span->alpha += span->alphaStep; \
span->intTex[0] += span->intTexStep[0]; \
span->intTex[1] += span->intTexStep[1]; \
dest += 4; \
}
 
#define SPAN_LINEAR(DO_TEX, COMPS) \
for (i = 0; i < span->end; i++) { \
/* Isn't it necessary to use FixedFloor below?? */ \
const GLint s = FixedToInt(span->intTex[0]) & info->smask; \
const GLint t = FixedToInt(span->intTex[1]) & info->tmask; \
const GLfixed sf = span->intTex[0] & FIXED_FRAC_MASK; \
const GLfixed tf = span->intTex[1] & FIXED_FRAC_MASK; \
const GLint pos = (t << info->twidth_log2) + s; \
const GLchan *tex00 = info->texture + COMPS * pos; \
const GLchan *tex10 = tex00 + info->tbytesline; \
const GLchan *tex01 = tex00 + COMPS; \
const GLchan *tex11 = tex10 + COMPS; \
if (t == info->tmask) { \
tex10 -= info->tsize; \
tex11 -= info->tsize; \
} \
if (s == info->smask) { \
tex01 -= info->tbytesline; \
tex11 -= info->tbytesline; \
} \
DO_TEX; \
span->red += span->redStep; \
span->green += span->greenStep; \
span->blue += span->blueStep; \
span->alpha += span->alphaStep; \
span->intTex[0] += span->intTexStep[0]; \
span->intTex[1] += span->intTexStep[1]; \
dest += 4; \
}
 
 
GLuint i;
GLchan *dest = span->array->rgba[0];
 
/* Disable tex units so they're not re-applied in swrast_write_rgba_span */
ctx->Texture._EnabledCoordUnits = 0x0;
 
span->intTex[0] -= FIXED_HALF;
span->intTex[1] -= FIXED_HALF;
switch (info->filter) {
case GL_NEAREST:
switch (info->format) {
case MESA_FORMAT_BGR_UNORM8:
switch (info->envmode) {
case GL_MODULATE:
SPAN_NEAREST(NEAREST_RGB;MODULATE,3);
break;
case GL_DECAL:
case GL_REPLACE:
SPAN_NEAREST(NEAREST_RGB_REPLACE,3);
break;
case GL_BLEND:
SPAN_NEAREST(NEAREST_RGB;BLEND,3);
break;
case GL_ADD:
SPAN_NEAREST(NEAREST_RGB;ADD,3);
break;
default:
_mesa_problem(ctx, "bad tex env mode in SPAN_LINEAR");
return;
}
break;
case MESA_FORMAT_A8B8G8R8_UNORM:
switch(info->envmode) {
case GL_MODULATE:
SPAN_NEAREST(NEAREST_RGBA;MODULATE,4);
break;
case GL_DECAL:
SPAN_NEAREST(NEAREST_RGBA;DECAL,4);
break;
case GL_BLEND:
SPAN_NEAREST(NEAREST_RGBA;BLEND,4);
break;
case GL_ADD:
SPAN_NEAREST(NEAREST_RGBA;ADD,4);
break;
case GL_REPLACE:
SPAN_NEAREST(NEAREST_RGBA_REPLACE,4);
break;
default:
_mesa_problem(ctx, "bad tex env mode (2) in SPAN_LINEAR");
return;
}
break;
}
break;
 
case GL_LINEAR:
span->intTex[0] -= FIXED_HALF;
span->intTex[1] -= FIXED_HALF;
switch (info->format) {
case MESA_FORMAT_BGR_UNORM8:
switch (info->envmode) {
case GL_MODULATE:
SPAN_LINEAR(LINEAR_RGB;MODULATE,3);
break;
case GL_DECAL:
case GL_REPLACE:
SPAN_LINEAR(LINEAR_RGB;REPLACE,3);
break;
case GL_BLEND:
SPAN_LINEAR(LINEAR_RGB;BLEND,3);
break;
case GL_ADD:
SPAN_LINEAR(LINEAR_RGB;ADD,3);
break;
default:
_mesa_problem(ctx, "bad tex env mode (3) in SPAN_LINEAR");
return;
}
break;
case MESA_FORMAT_A8B8G8R8_UNORM:
switch (info->envmode) {
case GL_MODULATE:
SPAN_LINEAR(LINEAR_RGBA;MODULATE,4);
break;
case GL_DECAL:
SPAN_LINEAR(LINEAR_RGBA;DECAL,4);
break;
case GL_BLEND:
SPAN_LINEAR(LINEAR_RGBA;BLEND,4);
break;
case GL_ADD:
SPAN_LINEAR(LINEAR_RGBA;ADD,4);
break;
case GL_REPLACE:
SPAN_LINEAR(LINEAR_RGBA;REPLACE,4);
break;
default:
_mesa_problem(ctx, "bad tex env mode (4) in SPAN_LINEAR");
return;
}
break;
}
break;
}
span->interpMask &= ~SPAN_RGBA;
assert(span->arrayMask & SPAN_RGBA);
 
_swrast_write_rgba_span(ctx, span);
 
/* re-enable texture units */
ctx->Texture._EnabledCoordUnits = texEnableSave;
 
#undef SPAN_NEAREST
#undef SPAN_LINEAR
}
 
 
 
/*
* Render an RGB/RGBA textured triangle without perspective correction.
*/
#define NAME affine_textured_triangle
#define INTERP_Z 1
#define INTERP_RGB 1
#define INTERP_ALPHA 1
#define INTERP_INT_TEX 1
#define S_SCALE twidth
#define T_SCALE theight
 
#define SETUP_CODE \
struct affine_info info; \
struct gl_texture_unit *unit = ctx->Texture.Unit+0; \
const struct gl_texture_object *obj = \
ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; \
const struct gl_texture_image *texImg = \
_mesa_base_tex_image(obj); \
const struct swrast_texture_image *swImg = \
swrast_texture_image_const(texImg); \
const GLfloat twidth = (GLfloat) texImg->Width; \
const GLfloat theight = (GLfloat) texImg->Height; \
info.texture = (const GLchan *) swImg->ImageSlices[0]; \
info.twidth_log2 = texImg->WidthLog2; \
info.smask = texImg->Width - 1; \
info.tmask = texImg->Height - 1; \
info.format = texImg->TexFormat; \
info.filter = obj->Sampler.MinFilter; \
info.envmode = unit->EnvMode; \
info.er = 0; \
info.eg = 0; \
info.eb = 0; \
span.arrayMask |= SPAN_RGBA; \
\
if (info.envmode == GL_BLEND) { \
/* potential off-by-one error here? (1.0f -> 2048 -> 0) */ \
info.er = FloatToFixed(unit->EnvColor[RCOMP] * CHAN_MAXF); \
info.eg = FloatToFixed(unit->EnvColor[GCOMP] * CHAN_MAXF); \
info.eb = FloatToFixed(unit->EnvColor[BCOMP] * CHAN_MAXF); \
info.ea = FloatToFixed(unit->EnvColor[ACOMP] * CHAN_MAXF); \
} \
if (!info.texture) { \
/* this shouldn't happen */ \
return; \
} \
\
switch (info.format) { \
case MESA_FORMAT_BGR_UNORM8: \
info.tbytesline = texImg->Width * 3; \
break; \
case MESA_FORMAT_A8B8G8R8_UNORM: \
info.tbytesline = texImg->Width * 4; \
break; \
default: \
_mesa_problem(NULL, "Bad texture format in affine_texture_triangle");\
return; \
} \
info.tsize = texImg->Height * info.tbytesline;
 
#define RENDER_SPAN( span ) affine_span(ctx, &span, &info);
 
#include "s_tritemp.h"
 
 
 
struct persp_info
{
GLenum filter;
GLenum format;
GLenum envmode;
GLint smask, tmask;
GLint twidth_log2;
const GLchan *texture;
GLfixed er, eg, eb, ea; /* texture env color */
GLint tbytesline, tsize;
};
 
 
static inline void
fast_persp_span(struct gl_context *ctx, SWspan *span,
struct persp_info *info)
{
GLchan sample[4]; /* the filtered texture sample */
 
/* Instead of defining a function for each mode, a test is done
* between the outer and inner loops. This is to reduce code size
* and complexity. Observe that an optimizing compiler kills
* unused variables (for instance tf,sf,ti,si in case of GL_NEAREST).
*/
#define SPAN_NEAREST(DO_TEX,COMP) \
for (i = 0; i < span->end; i++) { \
GLdouble invQ = tex_coord[2] ? \
(1.0 / tex_coord[2]) : 1.0; \
GLfloat s_tmp = (GLfloat) (tex_coord[0] * invQ); \
GLfloat t_tmp = (GLfloat) (tex_coord[1] * invQ); \
GLint s = IFLOOR(s_tmp) & info->smask; \
GLint t = IFLOOR(t_tmp) & info->tmask; \
GLint pos = (t << info->twidth_log2) + s; \
const GLchan *tex00 = info->texture + COMP * pos; \
DO_TEX; \
span->red += span->redStep; \
span->green += span->greenStep; \
span->blue += span->blueStep; \
span->alpha += span->alphaStep; \
tex_coord[0] += tex_step[0]; \
tex_coord[1] += tex_step[1]; \
tex_coord[2] += tex_step[2]; \
dest += 4; \
}
 
#define SPAN_LINEAR(DO_TEX,COMP) \
for (i = 0; i < span->end; i++) { \
GLdouble invQ = tex_coord[2] ? \
(1.0 / tex_coord[2]) : 1.0; \
const GLfloat s_tmp = (GLfloat) (tex_coord[0] * invQ); \
const GLfloat t_tmp = (GLfloat) (tex_coord[1] * invQ); \
const GLfixed s_fix = FloatToFixed(s_tmp) - FIXED_HALF; \
const GLfixed t_fix = FloatToFixed(t_tmp) - FIXED_HALF; \
const GLint s = FixedToInt(FixedFloor(s_fix)) & info->smask; \
const GLint t = FixedToInt(FixedFloor(t_fix)) & info->tmask; \
const GLfixed sf = s_fix & FIXED_FRAC_MASK; \
const GLfixed tf = t_fix & FIXED_FRAC_MASK; \
const GLint pos = (t << info->twidth_log2) + s; \
const GLchan *tex00 = info->texture + COMP * pos; \
const GLchan *tex10 = tex00 + info->tbytesline; \
const GLchan *tex01 = tex00 + COMP; \
const GLchan *tex11 = tex10 + COMP; \
if (t == info->tmask) { \
tex10 -= info->tsize; \
tex11 -= info->tsize; \
} \
if (s == info->smask) { \
tex01 -= info->tbytesline; \
tex11 -= info->tbytesline; \
} \
DO_TEX; \
span->red += span->redStep; \
span->green += span->greenStep; \
span->blue += span->blueStep; \
span->alpha += span->alphaStep; \
tex_coord[0] += tex_step[0]; \
tex_coord[1] += tex_step[1]; \
tex_coord[2] += tex_step[2]; \
dest += 4; \
}
 
GLuint i;
GLfloat tex_coord[3], tex_step[3];
GLchan *dest = span->array->rgba[0];
 
const GLuint texEnableSave = ctx->Texture._EnabledCoordUnits;
ctx->Texture._EnabledCoordUnits = 0;
 
tex_coord[0] = span->attrStart[VARYING_SLOT_TEX0][0] * (info->smask + 1);
tex_step[0] = span->attrStepX[VARYING_SLOT_TEX0][0] * (info->smask + 1);
tex_coord[1] = span->attrStart[VARYING_SLOT_TEX0][1] * (info->tmask + 1);
tex_step[1] = span->attrStepX[VARYING_SLOT_TEX0][1] * (info->tmask + 1);
/* span->attrStart[VARYING_SLOT_TEX0][2] only if 3D-texturing, here only 2D */
tex_coord[2] = span->attrStart[VARYING_SLOT_TEX0][3];
tex_step[2] = span->attrStepX[VARYING_SLOT_TEX0][3];
 
switch (info->filter) {
case GL_NEAREST:
switch (info->format) {
case MESA_FORMAT_BGR_UNORM8:
switch (info->envmode) {
case GL_MODULATE:
SPAN_NEAREST(NEAREST_RGB;MODULATE,3);
break;
case GL_DECAL:
case GL_REPLACE:
SPAN_NEAREST(NEAREST_RGB_REPLACE,3);
break;
case GL_BLEND:
SPAN_NEAREST(NEAREST_RGB;BLEND,3);
break;
case GL_ADD:
SPAN_NEAREST(NEAREST_RGB;ADD,3);
break;
default:
_mesa_problem(ctx, "bad tex env mode (5) in SPAN_LINEAR");
return;
}
break;
case MESA_FORMAT_A8B8G8R8_UNORM:
switch(info->envmode) {
case GL_MODULATE:
SPAN_NEAREST(NEAREST_RGBA;MODULATE,4);
break;
case GL_DECAL:
SPAN_NEAREST(NEAREST_RGBA;DECAL,4);
break;
case GL_BLEND:
SPAN_NEAREST(NEAREST_RGBA;BLEND,4);
break;
case GL_ADD:
SPAN_NEAREST(NEAREST_RGBA;ADD,4);
break;
case GL_REPLACE:
SPAN_NEAREST(NEAREST_RGBA_REPLACE,4);
break;
default:
_mesa_problem(ctx, "bad tex env mode (6) in SPAN_LINEAR");
return;
}
break;
}
break;
 
case GL_LINEAR:
switch (info->format) {
case MESA_FORMAT_BGR_UNORM8:
switch (info->envmode) {
case GL_MODULATE:
SPAN_LINEAR(LINEAR_RGB;MODULATE,3);
break;
case GL_DECAL:
case GL_REPLACE:
SPAN_LINEAR(LINEAR_RGB;REPLACE,3);
break;
case GL_BLEND:
SPAN_LINEAR(LINEAR_RGB;BLEND,3);
break;
case GL_ADD:
SPAN_LINEAR(LINEAR_RGB;ADD,3);
break;
default:
_mesa_problem(ctx, "bad tex env mode (7) in SPAN_LINEAR");
return;
}
break;
case MESA_FORMAT_A8B8G8R8_UNORM:
switch (info->envmode) {
case GL_MODULATE:
SPAN_LINEAR(LINEAR_RGBA;MODULATE,4);
break;
case GL_DECAL:
SPAN_LINEAR(LINEAR_RGBA;DECAL,4);
break;
case GL_BLEND:
SPAN_LINEAR(LINEAR_RGBA;BLEND,4);
break;
case GL_ADD:
SPAN_LINEAR(LINEAR_RGBA;ADD,4);
break;
case GL_REPLACE:
SPAN_LINEAR(LINEAR_RGBA;REPLACE,4);
break;
default:
_mesa_problem(ctx, "bad tex env mode (8) in SPAN_LINEAR");
return;
}
break;
}
break;
}
assert(span->arrayMask & SPAN_RGBA);
_swrast_write_rgba_span(ctx, span);
 
#undef SPAN_NEAREST
#undef SPAN_LINEAR
 
/* restore state */
ctx->Texture._EnabledCoordUnits = texEnableSave;
}
 
 
/*
* Render an perspective corrected RGB/RGBA textured triangle.
* The Q (aka V in Mesa) coordinate must be zero such that the divide
* by interpolated Q/W comes out right.
*
*/
#define NAME persp_textured_triangle
#define INTERP_Z 1
#define INTERP_RGB 1
#define INTERP_ALPHA 1
#define INTERP_ATTRIBS 1
 
#define SETUP_CODE \
struct persp_info info; \
const struct gl_texture_unit *unit = ctx->Texture.Unit+0; \
const struct gl_texture_object *obj = \
ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX]; \
const struct gl_texture_image *texImg = \
_mesa_base_tex_image(obj); \
const struct swrast_texture_image *swImg = \
swrast_texture_image_const(texImg); \
info.texture = (const GLchan *) swImg->ImageSlices[0]; \
info.twidth_log2 = texImg->WidthLog2; \
info.smask = texImg->Width - 1; \
info.tmask = texImg->Height - 1; \
info.format = texImg->TexFormat; \
info.filter = obj->Sampler.MinFilter; \
info.envmode = unit->EnvMode; \
info.er = 0; \
info.eg = 0; \
info.eb = 0; \
\
if (info.envmode == GL_BLEND) { \
/* potential off-by-one error here? (1.0f -> 2048 -> 0) */ \
info.er = FloatToFixed(unit->EnvColor[RCOMP] * CHAN_MAXF); \
info.eg = FloatToFixed(unit->EnvColor[GCOMP] * CHAN_MAXF); \
info.eb = FloatToFixed(unit->EnvColor[BCOMP] * CHAN_MAXF); \
info.ea = FloatToFixed(unit->EnvColor[ACOMP] * CHAN_MAXF); \
} \
if (!info.texture) { \
/* this shouldn't happen */ \
return; \
} \
\
switch (info.format) { \
case MESA_FORMAT_BGR_UNORM8: \
info.tbytesline = texImg->Width * 3; \
break; \
case MESA_FORMAT_A8B8G8R8_UNORM: \
info.tbytesline = texImg->Width * 4; \
break; \
default: \
_mesa_problem(NULL, "Bad texture format in persp_textured_triangle");\
return; \
} \
info.tsize = texImg->Height * info.tbytesline;
 
#define RENDER_SPAN( span ) \
span.interpMask &= ~SPAN_RGBA; \
span.arrayMask |= SPAN_RGBA; \
fast_persp_span(ctx, &span, &info);
 
#include "s_tritemp.h"
 
#endif /*CHAN_TYPE != GL_FLOAT*/
 
 
 
/*
* Render an RGBA triangle with arbitrary attributes.
*/
#define NAME general_triangle
#define INTERP_Z 1
#define INTERP_RGB 1
#define INTERP_ALPHA 1
#define INTERP_ATTRIBS 1
#define RENDER_SPAN( span ) _swrast_write_rgba_span(ctx, &span);
#include "s_tritemp.h"
 
 
 
 
/*
* Special tri function for occlusion testing
*/
#define NAME occlusion_zless_16_triangle
#define INTERP_Z 1
#define SETUP_CODE \
struct gl_renderbuffer *rb = \
ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer; \
struct gl_query_object *q = ctx->Query.CurrentOcclusionObject; \
assert(ctx->Depth.Test); \
assert(!ctx->Depth.Mask); \
assert(ctx->Depth.Func == GL_LESS); \
assert(rb->Format == MESA_FORMAT_Z_UNORM16); \
if (!q) { \
return; \
}
#define RENDER_SPAN( span ) \
{ \
GLuint i; \
const GLushort *zRow = (const GLushort *) \
_swrast_pixel_address(rb, span.x, span.y); \
for (i = 0; i < span.end; i++) { \
GLuint z = FixedToDepth(span.z); \
if (z < zRow[i]) { \
q->Result++; \
} \
span.z += span.zStep; \
} \
}
#include "s_tritemp.h"
 
 
 
static void
nodraw_triangle( struct gl_context *ctx,
const SWvertex *v0,
const SWvertex *v1,
const SWvertex *v2 )
{
(void) (ctx && v0 && v1 && v2);
}
 
 
/*
* This is used when separate specular color is enabled, but not
* texturing. We add the specular color to the primary color,
* draw the triangle, then restore the original primary color.
* Inefficient, but seldom needed.
*/
void
_swrast_add_spec_terms_triangle(struct gl_context *ctx, const SWvertex *v0,
const SWvertex *v1, const SWvertex *v2)
{
SWvertex *ncv0 = (SWvertex *)v0; /* drop const qualifier */
SWvertex *ncv1 = (SWvertex *)v1;
SWvertex *ncv2 = (SWvertex *)v2;
GLfloat rSum, gSum, bSum;
GLchan cSave[3][4];
 
/* save original colors */
COPY_CHAN4( cSave[0], ncv0->color );
COPY_CHAN4( cSave[1], ncv1->color );
COPY_CHAN4( cSave[2], ncv2->color );
/* sum v0 */
rSum = CHAN_TO_FLOAT(ncv0->color[0]) + ncv0->attrib[VARYING_SLOT_COL1][0];
gSum = CHAN_TO_FLOAT(ncv0->color[1]) + ncv0->attrib[VARYING_SLOT_COL1][1];
bSum = CHAN_TO_FLOAT(ncv0->color[2]) + ncv0->attrib[VARYING_SLOT_COL1][2];
UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[0], rSum);
UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[1], gSum);
UNCLAMPED_FLOAT_TO_CHAN(ncv0->color[2], bSum);
/* sum v1 */
rSum = CHAN_TO_FLOAT(ncv1->color[0]) + ncv1->attrib[VARYING_SLOT_COL1][0];
gSum = CHAN_TO_FLOAT(ncv1->color[1]) + ncv1->attrib[VARYING_SLOT_COL1][1];
bSum = CHAN_TO_FLOAT(ncv1->color[2]) + ncv1->attrib[VARYING_SLOT_COL1][2];
UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[0], rSum);
UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[1], gSum);
UNCLAMPED_FLOAT_TO_CHAN(ncv1->color[2], bSum);
/* sum v2 */
rSum = CHAN_TO_FLOAT(ncv2->color[0]) + ncv2->attrib[VARYING_SLOT_COL1][0];
gSum = CHAN_TO_FLOAT(ncv2->color[1]) + ncv2->attrib[VARYING_SLOT_COL1][1];
bSum = CHAN_TO_FLOAT(ncv2->color[2]) + ncv2->attrib[VARYING_SLOT_COL1][2];
UNCLAMPED_FLOAT_TO_CHAN(ncv2->color[0], rSum);
UNCLAMPED_FLOAT_TO_CHAN(ncv2->color[1], gSum);
UNCLAMPED_FLOAT_TO_CHAN(ncv2->color[2], bSum);
/* draw */
SWRAST_CONTEXT(ctx)->SpecTriangle( ctx, ncv0, ncv1, ncv2 );
/* restore original colors */
COPY_CHAN4( ncv0->color, cSave[0] );
COPY_CHAN4( ncv1->color, cSave[1] );
COPY_CHAN4( ncv2->color, cSave[2] );
}
 
 
 
#ifdef DEBUG
 
/* record the current triangle function name */
const char *_mesa_triFuncName = NULL;
 
#define USE(triFunc) \
do { \
_mesa_triFuncName = #triFunc; \
/*printf("%s\n", _mesa_triFuncName);*/ \
swrast->Triangle = triFunc; \
} while (0)
 
#else
 
#define USE(triFunc) swrast->Triangle = triFunc;
 
#endif
 
 
 
 
/*
* Determine which triangle rendering function to use given the current
* rendering context.
*
* Please update the summary flag _SWRAST_NEW_TRIANGLE if you add or
* remove tests to this code.
*/
void
_swrast_choose_triangle( struct gl_context *ctx )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
 
if (ctx->Polygon.CullFlag &&
ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK) {
USE(nodraw_triangle);
return;
}
 
if (ctx->RenderMode==GL_RENDER) {
struct gl_renderbuffer *depthRb =
ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
 
if (ctx->Polygon.SmoothFlag) {
_swrast_set_aa_triangle_function(ctx);
assert(swrast->Triangle);
return;
}
 
/* special case for occlusion testing */
if (ctx->Query.CurrentOcclusionObject &&
ctx->Depth.Test &&
ctx->Depth.Mask == GL_FALSE &&
ctx->Depth.Func == GL_LESS &&
!ctx->Stencil._Enabled &&
depthRb &&
depthRb->Format == MESA_FORMAT_Z_UNORM16) {
if (ctx->Color.ColorMask[0][0] == 0 &&
ctx->Color.ColorMask[0][1] == 0 &&
ctx->Color.ColorMask[0][2] == 0 &&
ctx->Color.ColorMask[0][3] == 0) {
USE(occlusion_zless_16_triangle);
return;
}
}
 
/*
* XXX should examine swrast->_ActiveAttribMask to determine what
* needs to be interpolated.
*/
if (ctx->Texture._EnabledCoordUnits ||
_swrast_use_fragment_program(ctx) ||
ctx->ATIFragmentShader._Enabled ||
_mesa_need_secondary_color(ctx) ||
swrast->_FogEnabled) {
/* Ugh, we do a _lot_ of tests to pick the best textured tri func */
const struct gl_texture_object *texObj2D;
const struct gl_sampler_object *samp;
const struct gl_texture_image *texImg;
const struct swrast_texture_image *swImg;
GLenum minFilter, magFilter, envMode;
mesa_format format;
texObj2D = ctx->Texture.Unit[0].CurrentTex[TEXTURE_2D_INDEX];
if (ctx->Texture.Unit[0].Sampler)
samp = ctx->Texture.Unit[0].Sampler;
else if (texObj2D)
samp = &texObj2D->Sampler;
else
samp = NULL;
 
texImg = texObj2D ? _mesa_base_tex_image(texObj2D) : NULL;
swImg = swrast_texture_image_const(texImg);
 
format = texImg ? texImg->TexFormat : MESA_FORMAT_NONE;
minFilter = texObj2D ? samp->MinFilter : GL_NONE;
magFilter = texObj2D ? samp->MagFilter : GL_NONE;
envMode = ctx->Texture.Unit[0].EnvMode;
 
/* First see if we can use an optimized 2-D texture function */
if (ctx->Texture._EnabledCoordUnits == 0x1
&& !_swrast_use_fragment_program(ctx)
&& !ctx->ATIFragmentShader._Enabled
&& ctx->Texture._MaxEnabledTexImageUnit == 0
&& ctx->Texture.Unit[0]._Current->Target == GL_TEXTURE_2D
&& samp->WrapS == GL_REPEAT
&& samp->WrapT == GL_REPEAT
&& texObj2D->_Swizzle == SWIZZLE_NOOP
&& swImg->_IsPowerOfTwo
&& texImg->Border == 0
&& (_mesa_format_row_stride(format, texImg->Width) ==
swImg->RowStride)
&& (format == MESA_FORMAT_BGR_UNORM8 || format == MESA_FORMAT_A8B8G8R8_UNORM)
&& minFilter == magFilter
&& ctx->Light.Model.ColorControl == GL_SINGLE_COLOR
&& !swrast->_FogEnabled
&& ctx->Texture.Unit[0].EnvMode != GL_COMBINE_EXT
&& ctx->Texture.Unit[0].EnvMode != GL_COMBINE4_NV) {
if (ctx->Hint.PerspectiveCorrection==GL_FASTEST) {
if (minFilter == GL_NEAREST
&& format == MESA_FORMAT_BGR_UNORM8
&& (envMode == GL_REPLACE || envMode == GL_DECAL)
&& ((swrast->_RasterMask == (DEPTH_BIT | TEXTURE_BIT)
&& ctx->Depth.Func == GL_LESS
&& ctx->Depth.Mask == GL_TRUE)
|| swrast->_RasterMask == TEXTURE_BIT)
&& ctx->Polygon.StippleFlag == GL_FALSE
&& ctx->DrawBuffer->Visual.depthBits <= 16) {
if (swrast->_RasterMask == (DEPTH_BIT | TEXTURE_BIT)) {
USE(simple_z_textured_triangle);
}
else {
USE(simple_textured_triangle);
}
}
else {
#if CHAN_BITS != 8
USE(general_triangle);
#else
if (format == MESA_FORMAT_A8B8G8R8_UNORM && !_mesa_little_endian()) {
/* We only handle RGBA8888 correctly on little endian
* in the optimized code above.
*/
USE(general_triangle);
}
else {
USE(affine_textured_triangle);
}
#endif
}
}
else {
#if CHAN_BITS != 8
USE(general_triangle);
#else
USE(persp_textured_triangle);
#endif
}
}
else {
/* general case textured triangles */
USE(general_triangle);
}
}
else {
assert(!swrast->_FogEnabled);
assert(!_mesa_need_secondary_color(ctx));
if (ctx->Light.ShadeModel==GL_SMOOTH) {
/* smooth shaded, no texturing, stippled or some raster ops */
#if CHAN_BITS != 8
USE(general_triangle);
#else
USE(smooth_rgba_triangle);
#endif
}
else {
/* flat shaded, no texturing, stippled or some raster ops */
#if CHAN_BITS != 8
USE(general_triangle);
#else
USE(flat_rgba_triangle);
#endif
}
}
}
else if (ctx->RenderMode==GL_FEEDBACK) {
USE(_swrast_feedback_triangle);
}
else {
/* GL_SELECT mode */
USE(_swrast_select_triangle);
}
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_triangle.h
0,0 → 1,50
 
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2003 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
 
#ifndef S_TRIANGLES_H
#define S_TRIANGLES_H
 
 
#include "swrast.h"
 
 
extern GLboolean
_swrast_culltriangle( struct gl_context *ctx,
const SWvertex *v0,
const SWvertex *v1,
const SWvertex *v2);
 
extern void
_swrast_choose_triangle( struct gl_context *ctx );
 
extern void
_swrast_add_spec_terms_triangle( struct gl_context *ctx,
const SWvertex *v0,
const SWvertex *v1,
const SWvertex *v2 );
 
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_tritemp.h
0,0 → 1,934
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2007 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
/*
* Triangle Rasterizer Template
*
* This file is #include'd to generate custom triangle rasterizers.
*
* The following macros may be defined to indicate what auxillary information
* must be interpolated across the triangle:
* INTERP_Z - if defined, interpolate integer Z values
* INTERP_RGB - if defined, interpolate integer RGB values
* INTERP_ALPHA - if defined, interpolate integer Alpha values
* INTERP_INT_TEX - if defined, interpolate integer ST texcoords
* (fast, simple 2-D texture mapping, without
* perspective correction)
* INTERP_ATTRIBS - if defined, interpolate arbitrary attribs (texcoords,
* varying vars, etc) This also causes W to be
* computed for perspective correction).
*
* When one can directly address pixels in the color buffer the following
* macros can be defined and used to compute pixel addresses during
* rasterization (see pRow):
* PIXEL_TYPE - the datatype of a pixel (GLubyte, GLushort, GLuint)
* BYTES_PER_ROW - number of bytes per row in the color buffer
* PIXEL_ADDRESS(X,Y) - returns the address of pixel at (X,Y) where
* Y==0 at bottom of screen and increases upward.
*
* Similarly, for direct depth buffer access, this type is used for depth
* buffer addressing (see zRow):
* DEPTH_TYPE - either GLushort or GLuint
*
* Optionally, one may provide one-time setup code per triangle:
* SETUP_CODE - code which is to be executed once per triangle
*
* The following macro MUST be defined:
* RENDER_SPAN(span) - code to write a span of pixels.
*
* This code was designed for the origin to be in the lower-left corner.
*
* Inspired by triangle rasterizer code written by Allen Akin. Thanks Allen!
*
*
* Some notes on rasterization accuracy:
*
* This code uses fixed point arithmetic (the GLfixed type) to iterate
* over the triangle edges and interpolate ancillary data (such as Z,
* color, secondary color, etc). The number of fractional bits in
* GLfixed and the value of SUB_PIXEL_BITS has a direct bearing on the
* accuracy of rasterization.
*
* If SUB_PIXEL_BITS=4 then we'll snap the vertices to the nearest
* 1/16 of a pixel. If we're walking up a long, nearly vertical edge
* (dx=1/16, dy=1024) we'll need 4 + 10 = 14 fractional bits in
* GLfixed to walk the edge without error. If the maximum viewport
* height is 4K pixels, then we'll need 4 + 12 = 16 fractional bits.
*
* Historically, Mesa has used 11 fractional bits in GLfixed, snaps
* vertices to 1/16 pixel and allowed a maximum viewport height of 2K
* pixels. 11 fractional bits is actually insufficient for accurately
* rasterizing some triangles. More recently, the maximum viewport
* height was increased to 4K pixels. Thus, Mesa should be using 16
* fractional bits in GLfixed. Unfortunately, there may be some issues
* with setting FIXED_FRAC_BITS=16, such as multiplication overflow.
* This will have to be examined in some detail...
*
* For now, if you find rasterization errors, particularly with tall,
* sliver triangles, try increasing FIXED_FRAC_BITS and/or decreasing
* SUB_PIXEL_BITS.
*/
 
 
#ifndef MAX_GLUINT
#define MAX_GLUINT 0xffffffffu
#endif
 
 
/*
* Some code we unfortunately need to prevent negative interpolated colors.
*/
#ifndef CLAMP_INTERPOLANT
#define CLAMP_INTERPOLANT(CHANNEL, CHANNELSTEP, LEN) \
do { \
GLfixed endVal = span.CHANNEL + (LEN) * span.CHANNELSTEP; \
if (endVal < 0) { \
span.CHANNEL -= endVal; \
} \
if (span.CHANNEL < 0) { \
span.CHANNEL = 0; \
} \
} while (0)
#endif
 
 
static void NAME(struct gl_context *ctx, const SWvertex *v0,
const SWvertex *v1,
const SWvertex *v2 )
{
typedef struct {
const SWvertex *v0, *v1; /* Y(v0) < Y(v1) */
GLfloat dx; /* X(v1) - X(v0) */
GLfloat dy; /* Y(v1) - Y(v0) */
GLfloat dxdy; /* dx/dy */
GLfixed fdxdy; /* dx/dy in fixed-point */
GLfloat adjy; /* adjust from v[0]->fy to fsy, scaled */
GLfixed fsx; /* first sample point x coord */
GLfixed fsy;
GLfixed fx0; /* fixed pt X of lower endpoint */
GLint lines; /* number of lines to be sampled on this edge */
} EdgeT;
 
const SWcontext *swrast = SWRAST_CONTEXT(ctx);
#ifdef INTERP_Z
const GLint depthBits = ctx->DrawBuffer->Visual.depthBits;
const GLint fixedToDepthShift = depthBits <= 16 ? FIXED_SHIFT : 0;
const GLfloat maxDepth = ctx->DrawBuffer->_DepthMaxF;
#define FixedToDepth(F) ((F) >> fixedToDepthShift)
#endif
EdgeT eMaj, eTop, eBot;
GLfloat oneOverArea;
const SWvertex *vMin, *vMid, *vMax; /* Y(vMin)<=Y(vMid)<=Y(vMax) */
GLfloat bf = SWRAST_CONTEXT(ctx)->_BackfaceSign;
const GLint snapMask = ~((FIXED_ONE / (1 << SUB_PIXEL_BITS)) - 1); /* for x/y coord snapping */
GLfixed vMin_fx, vMin_fy, vMid_fx, vMid_fy, vMax_fx, vMax_fy;
 
SWspan span;
 
(void) swrast;
 
INIT_SPAN(span, GL_POLYGON);
span.y = 0; /* silence warnings */
 
#ifdef INTERP_Z
(void) fixedToDepthShift;
#endif
 
/*
printf("%s()\n", __func__);
printf(" %g, %g, %g\n",
v0->attrib[VARYING_SLOT_POS][0],
v0->attrib[VARYING_SLOT_POS][1],
v0->attrib[VARYING_SLOT_POS][2]);
printf(" %g, %g, %g\n",
v1->attrib[VARYING_SLOT_POS][0],
v1->attrib[VARYING_SLOT_POS][1],
v1->attrib[VARYING_SLOT_POS][2]);
printf(" %g, %g, %g\n",
v2->attrib[VARYING_SLOT_POS][0],
v2->attrib[VARYING_SLOT_POS][1],
v2->attrib[VARYING_SLOT_POS][2]);
*/
 
/* Compute fixed point x,y coords w/ half-pixel offsets and snapping.
* And find the order of the 3 vertices along the Y axis.
*/
{
const GLfixed fy0 = FloatToFixed(v0->attrib[VARYING_SLOT_POS][1] - 0.5F) & snapMask;
const GLfixed fy1 = FloatToFixed(v1->attrib[VARYING_SLOT_POS][1] - 0.5F) & snapMask;
const GLfixed fy2 = FloatToFixed(v2->attrib[VARYING_SLOT_POS][1] - 0.5F) & snapMask;
if (fy0 <= fy1) {
if (fy1 <= fy2) {
/* y0 <= y1 <= y2 */
vMin = v0; vMid = v1; vMax = v2;
vMin_fy = fy0; vMid_fy = fy1; vMax_fy = fy2;
}
else if (fy2 <= fy0) {
/* y2 <= y0 <= y1 */
vMin = v2; vMid = v0; vMax = v1;
vMin_fy = fy2; vMid_fy = fy0; vMax_fy = fy1;
}
else {
/* y0 <= y2 <= y1 */
vMin = v0; vMid = v2; vMax = v1;
vMin_fy = fy0; vMid_fy = fy2; vMax_fy = fy1;
bf = -bf;
}
}
else {
if (fy0 <= fy2) {
/* y1 <= y0 <= y2 */
vMin = v1; vMid = v0; vMax = v2;
vMin_fy = fy1; vMid_fy = fy0; vMax_fy = fy2;
bf = -bf;
}
else if (fy2 <= fy1) {
/* y2 <= y1 <= y0 */
vMin = v2; vMid = v1; vMax = v0;
vMin_fy = fy2; vMid_fy = fy1; vMax_fy = fy0;
bf = -bf;
}
else {
/* y1 <= y2 <= y0 */
vMin = v1; vMid = v2; vMax = v0;
vMin_fy = fy1; vMid_fy = fy2; vMax_fy = fy0;
}
}
 
/* fixed point X coords */
vMin_fx = FloatToFixed(vMin->attrib[VARYING_SLOT_POS][0] + 0.5F) & snapMask;
vMid_fx = FloatToFixed(vMid->attrib[VARYING_SLOT_POS][0] + 0.5F) & snapMask;
vMax_fx = FloatToFixed(vMax->attrib[VARYING_SLOT_POS][0] + 0.5F) & snapMask;
}
 
/* vertex/edge relationship */
eMaj.v0 = vMin; eMaj.v1 = vMax; /*TODO: .v1's not needed */
eTop.v0 = vMid; eTop.v1 = vMax;
eBot.v0 = vMin; eBot.v1 = vMid;
 
/* compute deltas for each edge: vertex[upper] - vertex[lower] */
eMaj.dx = FixedToFloat(vMax_fx - vMin_fx);
eMaj.dy = FixedToFloat(vMax_fy - vMin_fy);
eTop.dx = FixedToFloat(vMax_fx - vMid_fx);
eTop.dy = FixedToFloat(vMax_fy - vMid_fy);
eBot.dx = FixedToFloat(vMid_fx - vMin_fx);
eBot.dy = FixedToFloat(vMid_fy - vMin_fy);
 
/* compute area, oneOverArea and perform backface culling */
{
const GLfloat area = eMaj.dx * eBot.dy - eBot.dx * eMaj.dy;
 
if (IS_INF_OR_NAN(area) || area == 0.0F)
return;
 
if (area * bf * swrast->_BackfaceCullSign < 0.0)
return;
 
oneOverArea = 1.0F / area;
 
/* 0 = front, 1 = back */
span.facing = oneOverArea * bf > 0.0F;
}
 
/* Edge setup. For a triangle strip these could be reused... */
{
eMaj.fsy = FixedCeil(vMin_fy);
eMaj.lines = FixedToInt(FixedCeil(vMax_fy - eMaj.fsy));
if (eMaj.lines > 0) {
eMaj.dxdy = eMaj.dx / eMaj.dy;
eMaj.fdxdy = SignedFloatToFixed(eMaj.dxdy);
eMaj.adjy = (GLfloat) (eMaj.fsy - vMin_fy); /* SCALED! */
eMaj.fx0 = vMin_fx;
eMaj.fsx = eMaj.fx0 + (GLfixed) (eMaj.adjy * eMaj.dxdy);
}
else {
return; /*CULLED*/
}
 
eTop.fsy = FixedCeil(vMid_fy);
eTop.lines = FixedToInt(FixedCeil(vMax_fy - eTop.fsy));
if (eTop.lines > 0) {
eTop.dxdy = eTop.dx / eTop.dy;
eTop.fdxdy = SignedFloatToFixed(eTop.dxdy);
eTop.adjy = (GLfloat) (eTop.fsy - vMid_fy); /* SCALED! */
eTop.fx0 = vMid_fx;
eTop.fsx = eTop.fx0 + (GLfixed) (eTop.adjy * eTop.dxdy);
}
 
eBot.fsy = FixedCeil(vMin_fy);
eBot.lines = FixedToInt(FixedCeil(vMid_fy - eBot.fsy));
if (eBot.lines > 0) {
eBot.dxdy = eBot.dx / eBot.dy;
eBot.fdxdy = SignedFloatToFixed(eBot.dxdy);
eBot.adjy = (GLfloat) (eBot.fsy - vMin_fy); /* SCALED! */
eBot.fx0 = vMin_fx;
eBot.fsx = eBot.fx0 + (GLfixed) (eBot.adjy * eBot.dxdy);
}
}
 
/*
* Conceptually, we view a triangle as two subtriangles
* separated by a perfectly horizontal line. The edge that is
* intersected by this line is one with maximal absolute dy; we
* call it a ``major'' edge. The other two edges are the
* ``top'' edge (for the upper subtriangle) and the ``bottom''
* edge (for the lower subtriangle). If either of these two
* edges is horizontal or very close to horizontal, the
* corresponding subtriangle might cover zero sample points;
* we take care to handle such cases, for performance as well
* as correctness.
*
* By stepping rasterization parameters along the major edge,
* we can avoid recomputing them at the discontinuity where
* the top and bottom edges meet. However, this forces us to
* be able to scan both left-to-right and right-to-left.
* Also, we must determine whether the major edge is at the
* left or right side of the triangle. We do this by
* computing the magnitude of the cross-product of the major
* and top edges. Since this magnitude depends on the sine of
* the angle between the two edges, its sign tells us whether
* we turn to the left or to the right when travelling along
* the major edge to the top edge, and from this we infer
* whether the major edge is on the left or the right.
*
* Serendipitously, this cross-product magnitude is also a
* value we need to compute the iteration parameter
* derivatives for the triangle, and it can be used to perform
* backface culling because its sign tells us whether the
* triangle is clockwise or counterclockwise. In this code we
* refer to it as ``area'' because it's also proportional to
* the pixel area of the triangle.
*/
 
{
GLint scan_from_left_to_right; /* true if scanning left-to-right */
 
/*
* Execute user-supplied setup code
*/
#ifdef SETUP_CODE
SETUP_CODE
#endif
 
scan_from_left_to_right = (oneOverArea < 0.0F);
 
 
/* compute d?/dx and d?/dy derivatives */
#ifdef INTERP_Z
span.interpMask |= SPAN_Z;
{
GLfloat eMaj_dz = vMax->attrib[VARYING_SLOT_POS][2] - vMin->attrib[VARYING_SLOT_POS][2];
GLfloat eBot_dz = vMid->attrib[VARYING_SLOT_POS][2] - vMin->attrib[VARYING_SLOT_POS][2];
span.attrStepX[VARYING_SLOT_POS][2] = oneOverArea * (eMaj_dz * eBot.dy - eMaj.dy * eBot_dz);
if (span.attrStepX[VARYING_SLOT_POS][2] > maxDepth ||
span.attrStepX[VARYING_SLOT_POS][2] < -maxDepth) {
/* probably a sliver triangle */
span.attrStepX[VARYING_SLOT_POS][2] = 0.0;
span.attrStepY[VARYING_SLOT_POS][2] = 0.0;
}
else {
span.attrStepY[VARYING_SLOT_POS][2] = oneOverArea * (eMaj.dx * eBot_dz - eMaj_dz * eBot.dx);
}
if (depthBits <= 16)
span.zStep = SignedFloatToFixed(span.attrStepX[VARYING_SLOT_POS][2]);
else
span.zStep = (GLint) span.attrStepX[VARYING_SLOT_POS][2];
}
#endif
#ifdef INTERP_RGB
span.interpMask |= SPAN_RGBA;
if (ctx->Light.ShadeModel == GL_SMOOTH) {
GLfloat eMaj_dr = (GLfloat) (vMax->color[RCOMP] - vMin->color[RCOMP]);
GLfloat eBot_dr = (GLfloat) (vMid->color[RCOMP] - vMin->color[RCOMP]);
GLfloat eMaj_dg = (GLfloat) (vMax->color[GCOMP] - vMin->color[GCOMP]);
GLfloat eBot_dg = (GLfloat) (vMid->color[GCOMP] - vMin->color[GCOMP]);
GLfloat eMaj_db = (GLfloat) (vMax->color[BCOMP] - vMin->color[BCOMP]);
GLfloat eBot_db = (GLfloat) (vMid->color[BCOMP] - vMin->color[BCOMP]);
# ifdef INTERP_ALPHA
GLfloat eMaj_da = (GLfloat) (vMax->color[ACOMP] - vMin->color[ACOMP]);
GLfloat eBot_da = (GLfloat) (vMid->color[ACOMP] - vMin->color[ACOMP]);
# endif
span.attrStepX[VARYING_SLOT_COL0][0] = oneOverArea * (eMaj_dr * eBot.dy - eMaj.dy * eBot_dr);
span.attrStepY[VARYING_SLOT_COL0][0] = oneOverArea * (eMaj.dx * eBot_dr - eMaj_dr * eBot.dx);
span.attrStepX[VARYING_SLOT_COL0][1] = oneOverArea * (eMaj_dg * eBot.dy - eMaj.dy * eBot_dg);
span.attrStepY[VARYING_SLOT_COL0][1] = oneOverArea * (eMaj.dx * eBot_dg - eMaj_dg * eBot.dx);
span.attrStepX[VARYING_SLOT_COL0][2] = oneOverArea * (eMaj_db * eBot.dy - eMaj.dy * eBot_db);
span.attrStepY[VARYING_SLOT_COL0][2] = oneOverArea * (eMaj.dx * eBot_db - eMaj_db * eBot.dx);
span.redStep = SignedFloatToFixed(span.attrStepX[VARYING_SLOT_COL0][0]);
span.greenStep = SignedFloatToFixed(span.attrStepX[VARYING_SLOT_COL0][1]);
span.blueStep = SignedFloatToFixed(span.attrStepX[VARYING_SLOT_COL0][2]);
# ifdef INTERP_ALPHA
span.attrStepX[VARYING_SLOT_COL0][3] = oneOverArea * (eMaj_da * eBot.dy - eMaj.dy * eBot_da);
span.attrStepY[VARYING_SLOT_COL0][3] = oneOverArea * (eMaj.dx * eBot_da - eMaj_da * eBot.dx);
span.alphaStep = SignedFloatToFixed(span.attrStepX[VARYING_SLOT_COL0][3]);
# endif /* INTERP_ALPHA */
}
else {
assert(ctx->Light.ShadeModel == GL_FLAT);
span.interpMask |= SPAN_FLAT;
span.attrStepX[VARYING_SLOT_COL0][0] = span.attrStepY[VARYING_SLOT_COL0][0] = 0.0F;
span.attrStepX[VARYING_SLOT_COL0][1] = span.attrStepY[VARYING_SLOT_COL0][1] = 0.0F;
span.attrStepX[VARYING_SLOT_COL0][2] = span.attrStepY[VARYING_SLOT_COL0][2] = 0.0F;
span.redStep = 0;
span.greenStep = 0;
span.blueStep = 0;
# ifdef INTERP_ALPHA
span.attrStepX[VARYING_SLOT_COL0][3] = span.attrStepY[VARYING_SLOT_COL0][3] = 0.0F;
span.alphaStep = 0;
# endif
}
#endif /* INTERP_RGB */
#ifdef INTERP_INT_TEX
{
GLfloat eMaj_ds = (vMax->attrib[VARYING_SLOT_TEX0][0] - vMin->attrib[VARYING_SLOT_TEX0][0]) * S_SCALE;
GLfloat eBot_ds = (vMid->attrib[VARYING_SLOT_TEX0][0] - vMin->attrib[VARYING_SLOT_TEX0][0]) * S_SCALE;
GLfloat eMaj_dt = (vMax->attrib[VARYING_SLOT_TEX0][1] - vMin->attrib[VARYING_SLOT_TEX0][1]) * T_SCALE;
GLfloat eBot_dt = (vMid->attrib[VARYING_SLOT_TEX0][1] - vMin->attrib[VARYING_SLOT_TEX0][1]) * T_SCALE;
span.attrStepX[VARYING_SLOT_TEX0][0] = oneOverArea * (eMaj_ds * eBot.dy - eMaj.dy * eBot_ds);
span.attrStepY[VARYING_SLOT_TEX0][0] = oneOverArea * (eMaj.dx * eBot_ds - eMaj_ds * eBot.dx);
span.attrStepX[VARYING_SLOT_TEX0][1] = oneOverArea * (eMaj_dt * eBot.dy - eMaj.dy * eBot_dt);
span.attrStepY[VARYING_SLOT_TEX0][1] = oneOverArea * (eMaj.dx * eBot_dt - eMaj_dt * eBot.dx);
span.intTexStep[0] = SignedFloatToFixed(span.attrStepX[VARYING_SLOT_TEX0][0]);
span.intTexStep[1] = SignedFloatToFixed(span.attrStepX[VARYING_SLOT_TEX0][1]);
}
#endif
#ifdef INTERP_ATTRIBS
{
/* attrib[VARYING_SLOT_POS][3] is 1/W */
const GLfloat wMax = vMax->attrib[VARYING_SLOT_POS][3];
const GLfloat wMin = vMin->attrib[VARYING_SLOT_POS][3];
const GLfloat wMid = vMid->attrib[VARYING_SLOT_POS][3];
{
const GLfloat eMaj_dw = wMax - wMin;
const GLfloat eBot_dw = wMid - wMin;
span.attrStepX[VARYING_SLOT_POS][3] = oneOverArea * (eMaj_dw * eBot.dy - eMaj.dy * eBot_dw);
span.attrStepY[VARYING_SLOT_POS][3] = oneOverArea * (eMaj.dx * eBot_dw - eMaj_dw * eBot.dx);
}
ATTRIB_LOOP_BEGIN
if (swrast->_InterpMode[attr] == GL_FLAT) {
ASSIGN_4V(span.attrStepX[attr], 0.0, 0.0, 0.0, 0.0);
ASSIGN_4V(span.attrStepY[attr], 0.0, 0.0, 0.0, 0.0);
}
else {
GLuint c;
for (c = 0; c < 4; c++) {
GLfloat eMaj_da = vMax->attrib[attr][c] * wMax - vMin->attrib[attr][c] * wMin;
GLfloat eBot_da = vMid->attrib[attr][c] * wMid - vMin->attrib[attr][c] * wMin;
span.attrStepX[attr][c] = oneOverArea * (eMaj_da * eBot.dy - eMaj.dy * eBot_da);
span.attrStepY[attr][c] = oneOverArea * (eMaj.dx * eBot_da - eMaj_da * eBot.dx);
}
}
ATTRIB_LOOP_END
}
#endif
 
/*
* We always sample at pixel centers. However, we avoid
* explicit half-pixel offsets in this code by incorporating
* the proper offset in each of x and y during the
* transformation to window coordinates.
*
* We also apply the usual rasterization rules to prevent
* cracks and overlaps. A pixel is considered inside a
* subtriangle if it meets all of four conditions: it is on or
* to the right of the left edge, strictly to the left of the
* right edge, on or below the top edge, and strictly above
* the bottom edge. (Some edges may be degenerate.)
*
* The following discussion assumes left-to-right scanning
* (that is, the major edge is on the left); the right-to-left
* case is a straightforward variation.
*
* We start by finding the half-integral y coordinate that is
* at or below the top of the triangle. This gives us the
* first scan line that could possibly contain pixels that are
* inside the triangle.
*
* Next we creep down the major edge until we reach that y,
* and compute the corresponding x coordinate on the edge.
* Then we find the half-integral x that lies on or just
* inside the edge. This is the first pixel that might lie in
* the interior of the triangle. (We won't know for sure
* until we check the other edges.)
*
* As we rasterize the triangle, we'll step down the major
* edge. For each step in y, we'll move an integer number
* of steps in x. There are two possible x step sizes, which
* we'll call the ``inner'' step (guaranteed to land on the
* edge or inside it) and the ``outer'' step (guaranteed to
* land on the edge or outside it). The inner and outer steps
* differ by one. During rasterization we maintain an error
* term that indicates our distance from the true edge, and
* select either the inner step or the outer step, whichever
* gets us to the first pixel that falls inside the triangle.
*
* All parameters (z, red, etc.) as well as the buffer
* addresses for color and z have inner and outer step values,
* so that we can increment them appropriately. This method
* eliminates the need to adjust parameters by creeping a
* sub-pixel amount into the triangle at each scanline.
*/
 
{
GLint subTriangle;
GLfixed fxLeftEdge = 0, fxRightEdge = 0;
GLfixed fdxLeftEdge = 0, fdxRightEdge = 0;
GLfixed fError = 0, fdError = 0;
#ifdef PIXEL_ADDRESS
PIXEL_TYPE *pRow = NULL;
GLint dPRowOuter = 0, dPRowInner; /* offset in bytes */
#endif
#ifdef INTERP_Z
# ifdef DEPTH_TYPE
struct gl_renderbuffer *zrb
= ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
DEPTH_TYPE *zRow = NULL;
GLint dZRowOuter = 0, dZRowInner; /* offset in bytes */
# endif
GLuint zLeft = 0;
GLfixed fdzOuter = 0, fdzInner;
#endif
#ifdef INTERP_RGB
GLint rLeft = 0, fdrOuter = 0, fdrInner;
GLint gLeft = 0, fdgOuter = 0, fdgInner;
GLint bLeft = 0, fdbOuter = 0, fdbInner;
#endif
#ifdef INTERP_ALPHA
GLint aLeft = 0, fdaOuter = 0, fdaInner;
#endif
#ifdef INTERP_INT_TEX
GLfixed sLeft=0, dsOuter=0, dsInner;
GLfixed tLeft=0, dtOuter=0, dtInner;
#endif
#ifdef INTERP_ATTRIBS
GLfloat wLeft = 0, dwOuter = 0, dwInner;
GLfloat attrLeft[VARYING_SLOT_MAX][4];
GLfloat daOuter[VARYING_SLOT_MAX][4], daInner[VARYING_SLOT_MAX][4];
#endif
 
for (subTriangle=0; subTriangle<=1; subTriangle++) {
EdgeT *eLeft, *eRight;
int setupLeft, setupRight;
int lines;
 
if (subTriangle==0) {
/* bottom half */
if (scan_from_left_to_right) {
eLeft = &eMaj;
eRight = &eBot;
lines = eRight->lines;
setupLeft = 1;
setupRight = 1;
}
else {
eLeft = &eBot;
eRight = &eMaj;
lines = eLeft->lines;
setupLeft = 1;
setupRight = 1;
}
}
else {
/* top half */
if (scan_from_left_to_right) {
eLeft = &eMaj;
eRight = &eTop;
lines = eRight->lines;
setupLeft = 0;
setupRight = 1;
}
else {
eLeft = &eTop;
eRight = &eMaj;
lines = eLeft->lines;
setupLeft = 1;
setupRight = 0;
}
if (lines == 0)
return;
}
 
if (setupLeft && eLeft->lines > 0) {
const SWvertex *vLower = eLeft->v0;
const GLfixed fsy = eLeft->fsy;
const GLfixed fsx = eLeft->fsx; /* no fractional part */
const GLfixed fx = FixedCeil(fsx); /* no fractional part */
const GLfixed adjx = (GLfixed) (fx - eLeft->fx0); /* SCALED! */
const GLfixed adjy = (GLfixed) eLeft->adjy; /* SCALED! */
GLint idxOuter;
GLfloat dxOuter;
GLfixed fdxOuter;
 
fError = fx - fsx - FIXED_ONE;
fxLeftEdge = fsx - FIXED_EPSILON;
fdxLeftEdge = eLeft->fdxdy;
fdxOuter = FixedFloor(fdxLeftEdge - FIXED_EPSILON);
fdError = fdxOuter - fdxLeftEdge + FIXED_ONE;
idxOuter = FixedToInt(fdxOuter);
dxOuter = (GLfloat) idxOuter;
span.y = FixedToInt(fsy);
 
/* silence warnings on some compilers */
(void) dxOuter;
(void) adjx;
(void) adjy;
(void) vLower;
 
#ifdef PIXEL_ADDRESS
{
pRow = (PIXEL_TYPE *) PIXEL_ADDRESS(FixedToInt(fxLeftEdge), span.y);
dPRowOuter = -((int)BYTES_PER_ROW) + idxOuter * sizeof(PIXEL_TYPE);
/* negative because Y=0 at bottom and increases upward */
}
#endif
/*
* Now we need the set of parameter (z, color, etc.) values at
* the point (fx, fsy). This gives us properly-sampled parameter
* values that we can step from pixel to pixel. Furthermore,
* although we might have intermediate results that overflow
* the normal parameter range when we step temporarily outside
* the triangle, we shouldn't overflow or underflow for any
* pixel that's actually inside the triangle.
*/
 
#ifdef INTERP_Z
{
GLfloat z0 = vLower->attrib[VARYING_SLOT_POS][2];
if (depthBits <= 16) {
/* interpolate fixed-pt values */
GLfloat tmp = (z0 * FIXED_SCALE
+ span.attrStepX[VARYING_SLOT_POS][2] * adjx
+ span.attrStepY[VARYING_SLOT_POS][2] * adjy) + FIXED_HALF;
if (tmp < MAX_GLUINT / 2)
zLeft = (GLfixed) tmp;
else
zLeft = MAX_GLUINT / 2;
fdzOuter = SignedFloatToFixed(span.attrStepY[VARYING_SLOT_POS][2] +
dxOuter * span.attrStepX[VARYING_SLOT_POS][2]);
}
else {
/* interpolate depth values w/out scaling */
zLeft = (GLuint) (z0 + span.attrStepX[VARYING_SLOT_POS][2] * FixedToFloat(adjx)
+ span.attrStepY[VARYING_SLOT_POS][2] * FixedToFloat(adjy));
fdzOuter = (GLint) (span.attrStepY[VARYING_SLOT_POS][2] +
dxOuter * span.attrStepX[VARYING_SLOT_POS][2]);
}
# ifdef DEPTH_TYPE
zRow = (DEPTH_TYPE *)
_swrast_pixel_address(zrb, FixedToInt(fxLeftEdge), span.y);
dZRowOuter = (ctx->DrawBuffer->Width + idxOuter) * sizeof(DEPTH_TYPE);
# endif
}
#endif
#ifdef INTERP_RGB
if (ctx->Light.ShadeModel == GL_SMOOTH) {
rLeft = (GLint)(ChanToFixed(vLower->color[RCOMP])
+ span.attrStepX[VARYING_SLOT_COL0][0] * adjx
+ span.attrStepY[VARYING_SLOT_COL0][0] * adjy) + FIXED_HALF;
gLeft = (GLint)(ChanToFixed(vLower->color[GCOMP])
+ span.attrStepX[VARYING_SLOT_COL0][1] * adjx
+ span.attrStepY[VARYING_SLOT_COL0][1] * adjy) + FIXED_HALF;
bLeft = (GLint)(ChanToFixed(vLower->color[BCOMP])
+ span.attrStepX[VARYING_SLOT_COL0][2] * adjx
+ span.attrStepY[VARYING_SLOT_COL0][2] * adjy) + FIXED_HALF;
fdrOuter = SignedFloatToFixed(span.attrStepY[VARYING_SLOT_COL0][0]
+ dxOuter * span.attrStepX[VARYING_SLOT_COL0][0]);
fdgOuter = SignedFloatToFixed(span.attrStepY[VARYING_SLOT_COL0][1]
+ dxOuter * span.attrStepX[VARYING_SLOT_COL0][1]);
fdbOuter = SignedFloatToFixed(span.attrStepY[VARYING_SLOT_COL0][2]
+ dxOuter * span.attrStepX[VARYING_SLOT_COL0][2]);
# ifdef INTERP_ALPHA
aLeft = (GLint)(ChanToFixed(vLower->color[ACOMP])
+ span.attrStepX[VARYING_SLOT_COL0][3] * adjx
+ span.attrStepY[VARYING_SLOT_COL0][3] * adjy) + FIXED_HALF;
fdaOuter = SignedFloatToFixed(span.attrStepY[VARYING_SLOT_COL0][3]
+ dxOuter * span.attrStepX[VARYING_SLOT_COL0][3]);
# endif
}
else {
assert(ctx->Light.ShadeModel == GL_FLAT);
rLeft = ChanToFixed(v2->color[RCOMP]);
gLeft = ChanToFixed(v2->color[GCOMP]);
bLeft = ChanToFixed(v2->color[BCOMP]);
fdrOuter = fdgOuter = fdbOuter = 0;
# ifdef INTERP_ALPHA
aLeft = ChanToFixed(v2->color[ACOMP]);
fdaOuter = 0;
# endif
}
#endif /* INTERP_RGB */
 
 
#ifdef INTERP_INT_TEX
{
GLfloat s0, t0;
s0 = vLower->attrib[VARYING_SLOT_TEX0][0] * S_SCALE;
sLeft = (GLfixed)(s0 * FIXED_SCALE + span.attrStepX[VARYING_SLOT_TEX0][0] * adjx
+ span.attrStepY[VARYING_SLOT_TEX0][0] * adjy) + FIXED_HALF;
dsOuter = SignedFloatToFixed(span.attrStepY[VARYING_SLOT_TEX0][0]
+ dxOuter * span.attrStepX[VARYING_SLOT_TEX0][0]);
 
t0 = vLower->attrib[VARYING_SLOT_TEX0][1] * T_SCALE;
tLeft = (GLfixed)(t0 * FIXED_SCALE + span.attrStepX[VARYING_SLOT_TEX0][1] * adjx
+ span.attrStepY[VARYING_SLOT_TEX0][1] * adjy) + FIXED_HALF;
dtOuter = SignedFloatToFixed(span.attrStepY[VARYING_SLOT_TEX0][1]
+ dxOuter * span.attrStepX[VARYING_SLOT_TEX0][1]);
}
#endif
#ifdef INTERP_ATTRIBS
{
const GLuint attr = VARYING_SLOT_POS;
wLeft = vLower->attrib[VARYING_SLOT_POS][3]
+ (span.attrStepX[attr][3] * adjx
+ span.attrStepY[attr][3] * adjy) * (1.0F/FIXED_SCALE);
dwOuter = span.attrStepY[attr][3] + dxOuter * span.attrStepX[attr][3];
}
ATTRIB_LOOP_BEGIN
const GLfloat invW = vLower->attrib[VARYING_SLOT_POS][3];
if (swrast->_InterpMode[attr] == GL_FLAT) {
GLuint c;
for (c = 0; c < 4; c++) {
attrLeft[attr][c] = v2->attrib[attr][c] * invW;
daOuter[attr][c] = 0.0;
}
}
else {
GLuint c;
for (c = 0; c < 4; c++) {
const GLfloat a = vLower->attrib[attr][c] * invW;
attrLeft[attr][c] = a + ( span.attrStepX[attr][c] * adjx
+ span.attrStepY[attr][c] * adjy) * (1.0F/FIXED_SCALE);
daOuter[attr][c] = span.attrStepY[attr][c] + dxOuter * span.attrStepX[attr][c];
}
}
ATTRIB_LOOP_END
#endif
} /*if setupLeft*/
 
 
if (setupRight && eRight->lines>0) {
fxRightEdge = eRight->fsx - FIXED_EPSILON;
fdxRightEdge = eRight->fdxdy;
}
 
if (lines==0) {
continue;
}
 
 
/* Rasterize setup */
#ifdef PIXEL_ADDRESS
dPRowInner = dPRowOuter + sizeof(PIXEL_TYPE);
#endif
#ifdef INTERP_Z
# ifdef DEPTH_TYPE
dZRowInner = dZRowOuter + sizeof(DEPTH_TYPE);
# endif
fdzInner = fdzOuter + span.zStep;
#endif
#ifdef INTERP_RGB
fdrInner = fdrOuter + span.redStep;
fdgInner = fdgOuter + span.greenStep;
fdbInner = fdbOuter + span.blueStep;
#endif
#ifdef INTERP_ALPHA
fdaInner = fdaOuter + span.alphaStep;
#endif
#ifdef INTERP_INT_TEX
dsInner = dsOuter + span.intTexStep[0];
dtInner = dtOuter + span.intTexStep[1];
#endif
#ifdef INTERP_ATTRIBS
dwInner = dwOuter + span.attrStepX[VARYING_SLOT_POS][3];
ATTRIB_LOOP_BEGIN
GLuint c;
for (c = 0; c < 4; c++) {
daInner[attr][c] = daOuter[attr][c] + span.attrStepX[attr][c];
}
ATTRIB_LOOP_END
#endif
 
while (lines > 0) {
/* initialize the span interpolants to the leftmost value */
/* ff = fixed-pt fragment */
const GLint right = FixedToInt(fxRightEdge);
span.x = FixedToInt(fxLeftEdge);
if (right <= span.x)
span.end = 0;
else
span.end = right - span.x;
 
#ifdef INTERP_Z
span.z = zLeft;
#endif
#ifdef INTERP_RGB
span.red = rLeft;
span.green = gLeft;
span.blue = bLeft;
#endif
#ifdef INTERP_ALPHA
span.alpha = aLeft;
#endif
#ifdef INTERP_INT_TEX
span.intTex[0] = sLeft;
span.intTex[1] = tLeft;
#endif
 
#ifdef INTERP_ATTRIBS
span.attrStart[VARYING_SLOT_POS][3] = wLeft;
ATTRIB_LOOP_BEGIN
GLuint c;
for (c = 0; c < 4; c++) {
span.attrStart[attr][c] = attrLeft[attr][c];
}
ATTRIB_LOOP_END
#endif
 
/* This is where we actually generate fragments */
/* XXX the test for span.y > 0 _shouldn't_ be needed but
* it fixes a problem on 64-bit Opterons (bug 4842).
*/
if (span.end > 0 && span.y >= 0) {
const GLint len = span.end - 1;
(void) len;
#ifdef INTERP_RGB
CLAMP_INTERPOLANT(red, redStep, len);
CLAMP_INTERPOLANT(green, greenStep, len);
CLAMP_INTERPOLANT(blue, blueStep, len);
#endif
#ifdef INTERP_ALPHA
CLAMP_INTERPOLANT(alpha, alphaStep, len);
#endif
{
RENDER_SPAN( span );
}
}
 
/*
* Advance to the next scan line. Compute the
* new edge coordinates, and adjust the
* pixel-center x coordinate so that it stays
* on or inside the major edge.
*/
span.y++;
lines--;
 
fxLeftEdge += fdxLeftEdge;
fxRightEdge += fdxRightEdge;
 
fError += fdError;
if (fError >= 0) {
fError -= FIXED_ONE;
 
#ifdef PIXEL_ADDRESS
pRow = (PIXEL_TYPE *) ((GLubyte *) pRow + dPRowOuter);
#endif
#ifdef INTERP_Z
# ifdef DEPTH_TYPE
zRow = (DEPTH_TYPE *) ((GLubyte *) zRow + dZRowOuter);
# endif
zLeft += fdzOuter;
#endif
#ifdef INTERP_RGB
rLeft += fdrOuter;
gLeft += fdgOuter;
bLeft += fdbOuter;
#endif
#ifdef INTERP_ALPHA
aLeft += fdaOuter;
#endif
#ifdef INTERP_INT_TEX
sLeft += dsOuter;
tLeft += dtOuter;
#endif
#ifdef INTERP_ATTRIBS
wLeft += dwOuter;
ATTRIB_LOOP_BEGIN
GLuint c;
for (c = 0; c < 4; c++) {
attrLeft[attr][c] += daOuter[attr][c];
}
ATTRIB_LOOP_END
#endif
}
else {
#ifdef PIXEL_ADDRESS
pRow = (PIXEL_TYPE *) ((GLubyte *) pRow + dPRowInner);
#endif
#ifdef INTERP_Z
# ifdef DEPTH_TYPE
zRow = (DEPTH_TYPE *) ((GLubyte *) zRow + dZRowInner);
# endif
zLeft += fdzInner;
#endif
#ifdef INTERP_RGB
rLeft += fdrInner;
gLeft += fdgInner;
bLeft += fdbInner;
#endif
#ifdef INTERP_ALPHA
aLeft += fdaInner;
#endif
#ifdef INTERP_INT_TEX
sLeft += dsInner;
tLeft += dtInner;
#endif
#ifdef INTERP_ATTRIBS
wLeft += dwInner;
ATTRIB_LOOP_BEGIN
GLuint c;
for (c = 0; c < 4; c++) {
attrLeft[attr][c] += daInner[attr][c];
}
ATTRIB_LOOP_END
#endif
}
} /*while lines>0*/
 
} /* for subTriangle */
 
}
}
}
 
#undef SETUP_CODE
#undef RENDER_SPAN
 
#undef PIXEL_TYPE
#undef BYTES_PER_ROW
#undef PIXEL_ADDRESS
#undef DEPTH_TYPE
 
#undef INTERP_Z
#undef INTERP_RGB
#undef INTERP_ALPHA
#undef INTERP_INT_TEX
#undef INTERP_ATTRIBS
 
#undef S_SCALE
#undef T_SCALE
 
#undef FixedToDepth
 
#undef NAME
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_zoom.c
0,0 → 1,441
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2008 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
#include "main/glheader.h"
#include "main/macros.h"
#include "main/imports.h"
#include "main/format_pack.h"
 
#include "s_context.h"
#include "s_span.h"
#include "s_stencil.h"
#include "s_zoom.h"
 
 
/**
* Compute the bounds of the region resulting from zooming a pixel span.
* The resulting region will be entirely inside the window/scissor bounds
* so no additional clipping is needed.
* \param imageX, imageY position of the mage being drawn (gl WindowPos)
* \param spanX, spanY position of span being drawing
* \param width number of pixels in span
* \param x0, x1 returned X bounds of zoomed region [x0, x1)
* \param y0, y1 returned Y bounds of zoomed region [y0, y1)
* \return GL_TRUE if any zoomed pixels visible, GL_FALSE if totally clipped
*/
static GLboolean
compute_zoomed_bounds(struct gl_context *ctx, GLint imageX, GLint imageY,
GLint spanX, GLint spanY, GLint width,
GLint *x0, GLint *x1, GLint *y0, GLint *y1)
{
const struct gl_framebuffer *fb = ctx->DrawBuffer;
GLint c0, c1, r0, r1;
 
assert(spanX >= imageX);
assert(spanY >= imageY);
 
/*
* Compute destination columns: [c0, c1)
*/
c0 = imageX + (GLint) ((spanX - imageX) * ctx->Pixel.ZoomX);
c1 = imageX + (GLint) ((spanX + width - imageX) * ctx->Pixel.ZoomX);
if (c1 < c0) {
/* swap */
GLint tmp = c1;
c1 = c0;
c0 = tmp;
}
c0 = CLAMP(c0, fb->_Xmin, fb->_Xmax);
c1 = CLAMP(c1, fb->_Xmin, fb->_Xmax);
if (c0 == c1) {
return GL_FALSE; /* no width */
}
 
/*
* Compute destination rows: [r0, r1)
*/
r0 = imageY + (GLint) ((spanY - imageY) * ctx->Pixel.ZoomY);
r1 = imageY + (GLint) ((spanY + 1 - imageY) * ctx->Pixel.ZoomY);
if (r1 < r0) {
/* swap */
GLint tmp = r1;
r1 = r0;
r0 = tmp;
}
r0 = CLAMP(r0, fb->_Ymin, fb->_Ymax);
r1 = CLAMP(r1, fb->_Ymin, fb->_Ymax);
if (r0 == r1) {
return GL_FALSE; /* no height */
}
 
*x0 = c0;
*x1 = c1;
*y0 = r0;
*y1 = r1;
 
return GL_TRUE;
}
 
 
/**
* Convert a zoomed x image coordinate back to an unzoomed x coord.
* 'zx' is screen position of a pixel in the zoomed image, who's left edge
* is at 'imageX'.
* return corresponding x coord in the original, unzoomed image.
* This can use this for unzooming X or Y values.
*/
static inline GLint
unzoom_x(GLfloat zoomX, GLint imageX, GLint zx)
{
/*
zx = imageX + (x - imageX) * zoomX;
zx - imageX = (x - imageX) * zoomX;
(zx - imageX) / zoomX = x - imageX;
*/
GLint x;
if (zoomX < 0.0)
zx++;
x = imageX + (GLint) ((zx - imageX) / zoomX);
return x;
}
 
 
 
/**
* Helper function called from _swrast_write_zoomed_rgba/rgb/
* index/depth_span().
*/
static void
zoom_span( struct gl_context *ctx, GLint imgX, GLint imgY, const SWspan *span,
const GLvoid *src, GLenum format )
{
SWcontext *swrast = SWRAST_CONTEXT(ctx);
SWspan zoomed;
GLint x0, x1, y0, y1;
GLint zoomedWidth;
 
if (!compute_zoomed_bounds(ctx, imgX, imgY, span->x, span->y, span->end,
&x0, &x1, &y0, &y1)) {
return; /* totally clipped */
}
 
if (!swrast->ZoomedArrays) {
/* allocate on demand */
swrast->ZoomedArrays = (SWspanarrays *) calloc(1, sizeof(SWspanarrays));
if (!swrast->ZoomedArrays)
return;
}
 
zoomedWidth = x1 - x0;
assert(zoomedWidth > 0);
assert(zoomedWidth <= SWRAST_MAX_WIDTH);
 
/* no pixel arrays! must be horizontal spans. */
assert((span->arrayMask & SPAN_XY) == 0);
assert(span->primitive == GL_BITMAP);
 
INIT_SPAN(zoomed, GL_BITMAP);
zoomed.x = x0;
zoomed.end = zoomedWidth;
zoomed.array = swrast->ZoomedArrays;
zoomed.array->ChanType = span->array->ChanType;
if (zoomed.array->ChanType == GL_UNSIGNED_BYTE)
zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba8;
else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT)
zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->rgba16;
else
zoomed.array->rgba = (GLchan (*)[4]) zoomed.array->attribs[VARYING_SLOT_COL0];
 
COPY_4V(zoomed.attrStart[VARYING_SLOT_POS], span->attrStart[VARYING_SLOT_POS]);
COPY_4V(zoomed.attrStepX[VARYING_SLOT_POS], span->attrStepX[VARYING_SLOT_POS]);
COPY_4V(zoomed.attrStepY[VARYING_SLOT_POS], span->attrStepY[VARYING_SLOT_POS]);
 
zoomed.attrStart[VARYING_SLOT_FOGC][0] = span->attrStart[VARYING_SLOT_FOGC][0];
zoomed.attrStepX[VARYING_SLOT_FOGC][0] = span->attrStepX[VARYING_SLOT_FOGC][0];
zoomed.attrStepY[VARYING_SLOT_FOGC][0] = span->attrStepY[VARYING_SLOT_FOGC][0];
 
if (format == GL_RGBA || format == GL_RGB) {
/* copy Z info */
zoomed.z = span->z;
zoomed.zStep = span->zStep;
/* we'll generate an array of colorss */
zoomed.interpMask = span->interpMask & ~SPAN_RGBA;
zoomed.arrayMask |= SPAN_RGBA;
zoomed.arrayAttribs |= VARYING_BIT_COL0; /* we'll produce these values */
assert(span->arrayMask & SPAN_RGBA);
}
else if (format == GL_DEPTH_COMPONENT) {
/* Copy color info */
zoomed.red = span->red;
zoomed.green = span->green;
zoomed.blue = span->blue;
zoomed.alpha = span->alpha;
zoomed.redStep = span->redStep;
zoomed.greenStep = span->greenStep;
zoomed.blueStep = span->blueStep;
zoomed.alphaStep = span->alphaStep;
/* we'll generate an array of depth values */
zoomed.interpMask = span->interpMask & ~SPAN_Z;
zoomed.arrayMask |= SPAN_Z;
assert(span->arrayMask & SPAN_Z);
}
else {
_mesa_problem(ctx, "Bad format in zoom_span");
return;
}
 
/* zoom the span horizontally */
if (format == GL_RGBA) {
if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
const GLubyte (*rgba)[4] = (const GLubyte (*)[4]) src;
GLint i;
for (i = 0; i < zoomedWidth; i++) {
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
assert(j >= 0);
assert(j < (GLint) span->end);
COPY_4UBV(zoomed.array->rgba8[i], rgba[j]);
}
}
else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
const GLushort (*rgba)[4] = (const GLushort (*)[4]) src;
GLint i;
for (i = 0; i < zoomedWidth; i++) {
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
assert(j >= 0);
assert(j < (GLint) span->end);
COPY_4V(zoomed.array->rgba16[i], rgba[j]);
}
}
else {
const GLfloat (*rgba)[4] = (const GLfloat (*)[4]) src;
GLint i;
for (i = 0; i < zoomedWidth; i++) {
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
assert(j >= 0);
assert(j < (GLint) span->end);
COPY_4V(zoomed.array->attribs[VARYING_SLOT_COL0][i], rgba[j]);
}
}
}
else if (format == GL_RGB) {
if (zoomed.array->ChanType == GL_UNSIGNED_BYTE) {
const GLubyte (*rgb)[3] = (const GLubyte (*)[3]) src;
GLint i;
for (i = 0; i < zoomedWidth; i++) {
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
assert(j >= 0);
assert(j < (GLint) span->end);
zoomed.array->rgba8[i][0] = rgb[j][0];
zoomed.array->rgba8[i][1] = rgb[j][1];
zoomed.array->rgba8[i][2] = rgb[j][2];
zoomed.array->rgba8[i][3] = 0xff;
}
}
else if (zoomed.array->ChanType == GL_UNSIGNED_SHORT) {
const GLushort (*rgb)[3] = (const GLushort (*)[3]) src;
GLint i;
for (i = 0; i < zoomedWidth; i++) {
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
assert(j >= 0);
assert(j < (GLint) span->end);
zoomed.array->rgba16[i][0] = rgb[j][0];
zoomed.array->rgba16[i][1] = rgb[j][1];
zoomed.array->rgba16[i][2] = rgb[j][2];
zoomed.array->rgba16[i][3] = 0xffff;
}
}
else {
const GLfloat (*rgb)[3] = (const GLfloat (*)[3]) src;
GLint i;
for (i = 0; i < zoomedWidth; i++) {
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
assert(j >= 0);
assert(j < (GLint) span->end);
zoomed.array->attribs[VARYING_SLOT_COL0][i][0] = rgb[j][0];
zoomed.array->attribs[VARYING_SLOT_COL0][i][1] = rgb[j][1];
zoomed.array->attribs[VARYING_SLOT_COL0][i][2] = rgb[j][2];
zoomed.array->attribs[VARYING_SLOT_COL0][i][3] = 1.0F;
}
}
}
else if (format == GL_DEPTH_COMPONENT) {
const GLuint *zValues = (const GLuint *) src;
GLint i;
for (i = 0; i < zoomedWidth; i++) {
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - span->x;
assert(j >= 0);
assert(j < (GLint) span->end);
zoomed.array->z[i] = zValues[j];
}
/* Now, fall into the RGB path below */
format = GL_RGBA;
}
 
/* write the span in rows [r0, r1) */
if (format == GL_RGBA || format == GL_RGB) {
/* Writing the span may modify the colors, so make a backup now if we're
* going to call _swrast_write_zoomed_span() more than once.
* Also, clipping may change the span end value, so store it as well.
*/
const GLint end = zoomed.end; /* save */
void *rgbaSave;
const GLint pixelSize =
(zoomed.array->ChanType == GL_UNSIGNED_BYTE) ? 4 * sizeof(GLubyte) :
((zoomed.array->ChanType == GL_UNSIGNED_SHORT) ? 4 * sizeof(GLushort)
: 4 * sizeof(GLfloat));
 
rgbaSave = malloc(zoomed.end * pixelSize);
if (!rgbaSave) {
return;
}
 
if (y1 - y0 > 1) {
memcpy(rgbaSave, zoomed.array->rgba, zoomed.end * pixelSize);
}
for (zoomed.y = y0; zoomed.y < y1; zoomed.y++) {
_swrast_write_rgba_span(ctx, &zoomed);
zoomed.end = end; /* restore */
if (y1 - y0 > 1) {
/* restore the colors */
memcpy(zoomed.array->rgba, rgbaSave, zoomed.end * pixelSize);
}
}
 
free(rgbaSave);
}
}
 
 
void
_swrast_write_zoomed_rgba_span(struct gl_context *ctx, GLint imgX, GLint imgY,
const SWspan *span, const GLvoid *rgba)
{
zoom_span(ctx, imgX, imgY, span, rgba, GL_RGBA);
}
 
 
void
_swrast_write_zoomed_rgb_span(struct gl_context *ctx, GLint imgX, GLint imgY,
const SWspan *span, const GLvoid *rgb)
{
zoom_span(ctx, imgX, imgY, span, rgb, GL_RGB);
}
 
 
void
_swrast_write_zoomed_depth_span(struct gl_context *ctx, GLint imgX, GLint imgY,
const SWspan *span)
{
zoom_span(ctx, imgX, imgY, span,
(const GLvoid *) span->array->z, GL_DEPTH_COMPONENT);
}
 
 
/**
* Zoom/write stencil values.
* No per-fragment operations are applied.
*/
void
_swrast_write_zoomed_stencil_span(struct gl_context *ctx, GLint imgX, GLint imgY,
GLint width, GLint spanX, GLint spanY,
const GLubyte stencil[])
{
GLubyte *zoomedVals;
GLint x0, x1, y0, y1, y;
GLint i, zoomedWidth;
 
if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
&x0, &x1, &y0, &y1)) {
return; /* totally clipped */
}
 
zoomedWidth = x1 - x0;
assert(zoomedWidth > 0);
assert(zoomedWidth <= SWRAST_MAX_WIDTH);
 
zoomedVals = malloc(zoomedWidth * sizeof(GLubyte));
if (!zoomedVals)
return;
 
/* zoom the span horizontally */
for (i = 0; i < zoomedWidth; i++) {
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
assert(j >= 0);
assert(j < width);
zoomedVals[i] = stencil[j];
}
 
/* write the zoomed spans */
for (y = y0; y < y1; y++) {
_swrast_write_stencil_span(ctx, zoomedWidth, x0, y, zoomedVals);
}
 
free(zoomedVals);
}
 
 
/**
* Zoom/write 32-bit Z values.
* No per-fragment operations are applied.
*/
void
_swrast_write_zoomed_z_span(struct gl_context *ctx, GLint imgX, GLint imgY,
GLint width, GLint spanX, GLint spanY,
const GLuint *zVals)
{
struct gl_renderbuffer *rb =
ctx->DrawBuffer->Attachment[BUFFER_DEPTH].Renderbuffer;
GLuint *zoomedVals;
GLint x0, x1, y0, y1, y;
GLint i, zoomedWidth;
 
if (!compute_zoomed_bounds(ctx, imgX, imgY, spanX, spanY, width,
&x0, &x1, &y0, &y1)) {
return; /* totally clipped */
}
 
zoomedWidth = x1 - x0;
assert(zoomedWidth > 0);
assert(zoomedWidth <= SWRAST_MAX_WIDTH);
 
zoomedVals = malloc(zoomedWidth * sizeof(GLuint));
if (!zoomedVals)
return;
 
/* zoom the span horizontally */
for (i = 0; i < zoomedWidth; i++) {
GLint j = unzoom_x(ctx->Pixel.ZoomX, imgX, x0 + i) - spanX;
assert(j >= 0);
assert(j < width);
zoomedVals[i] = zVals[j];
}
 
/* write the zoomed spans */
for (y = y0; y < y1; y++) {
GLubyte *dst = _swrast_pixel_address(rb, x0, y);
_mesa_pack_uint_z_row(rb->Format, zoomedWidth, zoomedVals, dst);
}
 
free(zoomedVals);
}
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/s_zoom.h
0,0 → 1,56
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2005 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
 
#ifndef S_ZOOM_H
#define S_ZOOM_H
 
#include "main/mtypes.h"
#include "s_span.h"
 
 
extern void
_swrast_write_zoomed_rgba_span(struct gl_context *ctx, GLint imgX, GLint imgY,
const SWspan *span, const GLvoid *rgba);
 
extern void
_swrast_write_zoomed_rgb_span(struct gl_context *ctx, GLint imgX, GLint imgY,
const SWspan *span, const GLvoid *rgb);
 
extern void
_swrast_write_zoomed_depth_span(struct gl_context *ctx, GLint imgX, GLint imgY,
const SWspan *span);
 
 
extern void
_swrast_write_zoomed_stencil_span(struct gl_context *ctx, GLint imgX, GLint imgY,
GLint width, GLint spanX, GLint spanY,
const GLubyte stencil[]);
 
extern void
_swrast_write_zoomed_z_span(struct gl_context *ctx, GLint imgX, GLint imgY,
GLint width, GLint spanX, GLint spanY,
const GLuint *zVals);
 
 
#endif
/contrib/sdk/sources/Mesa/mesa-10.6.0/src/mesa/swrast/swrast.h
0,0 → 1,301
/*
* Mesa 3-D graphics library
*
* Copyright (C) 1999-2006 Brian Paul All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*
*/
 
/**
* \file swrast/swrast.h
* \brief Public interface to the software rasterization functions.
* \author Keith Whitwell <keithw@vmware.com>
*/
 
#ifndef SWRAST_H
#define SWRAST_H
 
#include "main/mtypes.h"
#include "swrast/s_chan.h"
 
 
/**
* If non-zero use GLdouble for walking triangle edges, for better accuracy.
*/
#define TRIANGLE_WALK_DOUBLE 0
 
 
/**
* Bits per depth buffer value (max is 32).
*/
#ifndef DEFAULT_SOFTWARE_DEPTH_BITS
#define DEFAULT_SOFTWARE_DEPTH_BITS 16
#endif
/** Depth buffer data type */
#if DEFAULT_SOFTWARE_DEPTH_BITS <= 16
#define DEFAULT_SOFTWARE_DEPTH_TYPE GLushort
#else
#define DEFAULT_SOFTWARE_DEPTH_TYPE GLuint
#endif
 
 
/**
* Max image/surface/texture size.
*/
#define SWRAST_MAX_WIDTH 16384
#define SWRAST_MAX_HEIGHT 16384
 
 
/**
* \struct SWvertex
* \brief Data-structure to handle vertices in the software rasterizer.
*
* The software rasterizer now uses this format for vertices. Thus a
* 'RasterSetup' stage or other translation is required between the
* tnl module and the swrast rasterization functions. This serves to
* isolate the swrast module from the internals of the tnl module, and
* improve its usefulness as a fallback mechanism for hardware
* drivers.
*
* wpos = attr[VARYING_SLOT_POS] and MUST BE THE FIRST values in the
* vertex because of the tnl clipping code.
 
* wpos[0] and [1] are the screen-coords of SWvertex.
* wpos[2] is the z-buffer coord (if 16-bit Z buffer, in range [0,65535]).
* wpos[3] is 1/w where w is the clip-space W coord. This is the value
* that clip{XYZ} were multiplied by to get ndc{XYZ}.
*
* Full software drivers:
* - Register the rastersetup and triangle functions from
* utils/software_helper.
* - On statechange, update the rasterization pointers in that module.
*
* Rasterization hardware drivers:
* - Keep native rastersetup.
* - Implement native twoside,offset and unfilled triangle setup.
* - Implement a translator from native vertices to swrast vertices.
* - On partial fallback (mix of accelerated and unaccelerated
* prims), call a pass-through function which translates native
* vertices to SWvertices and calls the appropriate swrast function.
* - On total fallback (vertex format insufficient for state or all
* primitives unaccelerated), hook in swrast_setup instead.
*/
typedef struct {
GLfloat attrib[VARYING_SLOT_MAX][4];
GLchan color[4]; /** integer color */
GLfloat pointSize;
} SWvertex;
 
 
#define VARYING_SLOT_CI VARYING_SLOT_COL0
 
 
struct swrast_device_driver;
 
 
/* These are the public-access functions exported from swrast.
*/
 
extern GLboolean
_swrast_CreateContext( struct gl_context *ctx );
 
extern void
_swrast_DestroyContext( struct gl_context *ctx );
 
/* Get a (non-const) reference to the device driver struct for swrast.
*/
extern struct swrast_device_driver *
_swrast_GetDeviceDriverReference( struct gl_context *ctx );
 
extern void
_swrast_Bitmap( struct gl_context *ctx,
GLint px, GLint py,
GLsizei width, GLsizei height,
const struct gl_pixelstore_attrib *unpack,
const GLubyte *bitmap );
 
extern void
_swrast_CopyPixels(struct gl_context *ctx,
GLint srcx, GLint srcy,
GLint destx, GLint desty,
GLsizei width, GLsizei height,
GLenum type);
 
extern GLboolean
swrast_fast_copy_pixels(struct gl_context *ctx,
struct gl_framebuffer *srcFb,
struct gl_framebuffer *dstFb,
GLint srcX, GLint srcY, GLsizei width, GLsizei height,
GLint dstX, GLint dstY, GLenum type);
 
extern void
_swrast_DrawPixels( struct gl_context *ctx,
GLint x, GLint y,
GLsizei width, GLsizei height,
GLenum format, GLenum type,
const struct gl_pixelstore_attrib *unpack,
const GLvoid *pixels );
 
extern void
_swrast_BlitFramebuffer(struct gl_context *ctx,
struct gl_framebuffer *readFb,
struct gl_framebuffer *drawFb,
GLint srcX0, GLint srcY0, GLint srcX1, GLint srcY1,
GLint dstX0, GLint dstY0, GLint dstX1, GLint dstY1,
GLbitfield mask, GLenum filter);
 
extern void
_swrast_Clear(struct gl_context *ctx, GLbitfield buffers);
 
 
 
/* Reset the stipple counter
*/
extern void
_swrast_ResetLineStipple( struct gl_context *ctx );
 
/**
* Indicates front/back facing for subsequent points/lines when drawing
* unfilled polygons. Needed for two-side stencil.
*/
extern void
_swrast_SetFacing(struct gl_context *ctx, GLuint facing);
 
/* These will always render the correct point/line/triangle for the
* current state.
*
* For flatshaded primitives, the provoking vertex is the final one.
*/
extern void
_swrast_Point( struct gl_context *ctx, const SWvertex *v );
 
extern void
_swrast_Line( struct gl_context *ctx, const SWvertex *v0, const SWvertex *v1 );
 
extern void
_swrast_Triangle( struct gl_context *ctx, const SWvertex *v0,
const SWvertex *v1, const SWvertex *v2 );
 
extern void
_swrast_Quad( struct gl_context *ctx,
const SWvertex *v0, const SWvertex *v1,
const SWvertex *v2, const SWvertex *v3);
 
extern void
_swrast_flush( struct gl_context *ctx );
 
extern void
_swrast_render_primitive( struct gl_context *ctx, GLenum mode );
 
extern void
_swrast_render_start( struct gl_context *ctx );
 
extern void
_swrast_render_finish( struct gl_context *ctx );
 
extern struct gl_texture_image *
_swrast_new_texture_image( struct gl_context *ctx );
 
extern void
_swrast_delete_texture_image(struct gl_context *ctx,
struct gl_texture_image *texImage);
 
extern GLboolean
_swrast_alloc_texture_image_buffer(struct gl_context *ctx,
struct gl_texture_image *texImage);
 
extern GLboolean
_swrast_init_texture_image(struct gl_texture_image *texImage);
 
extern void
_swrast_free_texture_image_buffer(struct gl_context *ctx,
struct gl_texture_image *texImage);
 
extern void
_swrast_map_teximage(struct gl_context *ctx,
struct gl_texture_image *texImage,
GLuint slice,
GLuint x, GLuint y, GLuint w, GLuint h,
GLbitfield mode,
GLubyte **mapOut,
GLint *rowStrideOut);
 
extern void
_swrast_unmap_teximage(struct gl_context *ctx,
struct gl_texture_image *texImage,
GLuint slice);
 
/* Tell the software rasterizer about core state changes.
*/
extern void
_swrast_InvalidateState( struct gl_context *ctx, GLbitfield new_state );
 
/* Configure software rasterizer to match hardware rasterizer characteristics:
*/
extern void
_swrast_allow_vertex_fog( struct gl_context *ctx, GLboolean value );
 
extern void
_swrast_allow_pixel_fog( struct gl_context *ctx, GLboolean value );
 
/* Debug:
*/
extern void
_swrast_print_vertex( struct gl_context *ctx, const SWvertex *v );
 
 
 
extern void
_swrast_eject_texture_images(struct gl_context *ctx);
 
 
extern void
_swrast_render_texture(struct gl_context *ctx,
struct gl_framebuffer *fb,
struct gl_renderbuffer_attachment *att);
 
extern void
_swrast_finish_render_texture(struct gl_context *ctx,
struct gl_renderbuffer *rb);
 
 
/**
* The driver interface for the software rasterizer.
* XXX this may go away.
* We may move these functions to ctx->Driver.RenderStart, RenderEnd.
*/
struct swrast_device_driver {
/*
* These are called before and after accessing renderbuffers during
* software rasterization.
*
* These are a suitable place for grabbing/releasing hardware locks.
*
* NOTE: The swrast triangle/line/point routines *DO NOT* call
* these functions. Locking in that case must be organized by the
* driver by other mechanisms.
*/
void (*SpanRenderStart)(struct gl_context *ctx);
void (*SpanRenderFinish)(struct gl_context *ctx);
};
 
 
 
#endif