/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 |