/**************************************************************************
*
- * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * Copyright 2007 VMware, Inc.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* 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 NON-INFRINGEMENT.
- * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
+ * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS 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.
/**
* \brief Primitive rasterization/rendering (points, lines, triangles)
*
- * \author Keith Whitwell <keith@tungstengraphics.com>
+ * \author Keith Whitwell <keithw@vmware.com>
* \author Brian Paul
*/
#include "sp_setup.h"
#include "sp_state.h"
#include "draw/draw_context.h"
-#include "draw/draw_vertex.h"
#include "pipe/p_shader_tokens.h"
#include "util/u_math.h"
#include "util/u_memory.h"
#define DEBUG_VERTS 0
#define DEBUG_FRAGS 0
+
/**
* Triangle edge info
*/
};
+/**
+ * Max number of quads (2x2 pixel blocks) to process per batch.
+ * This can't be arbitrarily increased since we depend on some 32-bit
+ * bitmasks (two bits per quad).
+ */
#define MAX_QUADS 16
/**
- * Triangle setup info (derived from draw_stage).
+ * Triangle setup info.
* Also used for line drawing (taking some liberties).
*/
struct setup_context {
int facing;
float pixel_offset;
+ unsigned max_layer;
struct quad_header quad[MAX_QUADS];
struct quad_header *quad_ptrs[MAX_QUADS];
uint numFragsWritten; /**< per primitive */
#endif
- unsigned winding; /* which winding to cull */
+ unsigned cull_face; /* which faces cull */
unsigned nr_vertex_attrs;
};
-/**
- * Do triangle cull test using tri determinant (sign indicates orientation)
- * \return true if triangle is to be culled.
- */
-static INLINE boolean
-cull_tri(const struct setup_context *setup, float det)
-{
- if (det != 0) {
- /* if (det < 0 then Z points toward camera and triangle is
- * counter-clockwise winding.
- */
- unsigned winding = (det < 0) ? PIPE_WINDING_CCW : PIPE_WINDING_CW;
-
- if ((winding & setup->winding) == 0)
- return FALSE;
- }
-
- /* Culled:
- */
- return TRUE;
-}
/**
* Clip setup->quad against the scissor/surface bounds.
*/
-static INLINE void
-quad_clip( struct setup_context *setup, struct quad_header *quad )
+static inline void
+quad_clip(struct setup_context *setup, struct quad_header *quad)
{
- const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect;
+ unsigned viewport_index = quad[0].input.viewport_index;
+ const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect[viewport_index];
const int minx = (int) cliprect->minx;
const int maxx = (int) cliprect->maxx;
const int miny = (int) cliprect->miny;
/**
* Emit a quad (pass to next stage) with clipping.
*/
-static INLINE void
-clip_emit_quad( struct setup_context *setup, struct quad_header *quad )
+static inline void
+clip_emit_quad(struct setup_context *setup, struct quad_header *quad)
{
- quad_clip( setup, quad );
+ quad_clip(setup, quad);
if (quad->inout.mask) {
struct softpipe_context *sp = setup->softpipe;
+#if DEBUG_FRAGS
+ setup->numFragsEmitted += util_bitcount(quad->inout.mask);
+#endif
+
sp->quad.first->run( sp->quad.first, &quad, 1 );
}
}
* Given an X or Y coordinate, return the block/quad coordinate that it
* belongs to.
*/
-static INLINE int block( int x )
+static inline int
+block(int x)
{
return x & ~(2-1);
}
-static INLINE int block_x( int x )
+
+static inline int
+block_x(int x)
{
return x & ~(16-1);
}
/**
* Render a horizontal span of quads
*/
-static void flush_spans( struct setup_context *setup )
+static void
+flush_spans(struct setup_context *setup)
{
- const int step = 16;
+ const int step = MAX_QUADS;
const int xleft0 = setup->span.left[0];
const int xleft1 = setup->span.left[1];
const int xright0 = setup->span.right[0];
const int xright1 = setup->span.right[1];
struct quad_stage *pipe = setup->softpipe->quad.first;
-
- int minleft = block_x(MIN2(xleft0, xleft1));
- int maxright = MAX2(xright0, xright1);
+ const int minleft = block_x(MIN2(xleft0, xleft1));
+ const int maxright = MAX2(xright0, xright1);
int x;
+ /* process quads in horizontal chunks of 16 */
for (x = minleft; x < maxright; x += step) {
unsigned skip_left0 = CLAMP(xleft0 - x, 0, step);
unsigned skip_left1 = CLAMP(xleft1 - x, 0, step);
setup->quad[q].inout.mask = quadmask;
setup->quad_ptrs[q] = &setup->quad[q];
q++;
+#if DEBUG_FRAGS
+ setup->numFragsEmitted += util_bitcount(quadmask);
+#endif
}
mask0 >>= 2;
mask1 >>= 2;
#if DEBUG_VERTS
-static void print_vertex(const struct setup_context *setup,
- const float (*v)[4])
+static void
+print_vertex(const struct setup_context *setup,
+ const float (*v)[4])
{
int i;
debug_printf(" Vertex: (%p)\n", (void *) v);
}
#endif
+
/**
* Sort the vertices from top to bottom order, setting up the triangle
* edge fields (ebot, emaj, etop).
* \return FALSE if coords are inf/nan (cull the tri), TRUE otherwise
*/
-static boolean setup_sort_vertices( struct setup_context *setup,
- float det,
- const float (*v0)[4],
- const float (*v1)[4],
- const float (*v2)[4] )
+static boolean
+setup_sort_vertices(struct setup_context *setup,
+ float det,
+ const float (*v0)[4],
+ const float (*v1)[4],
+ const float (*v2)[4])
{
- setup->vprovoke = v2;
+ if (setup->softpipe->rasterizer->flatshade_first)
+ setup->vprovoke = v0;
+ else
+ setup->vprovoke = v2;
/* determine bottom to top order of vertices */
{
/* We need to know if this is a front or back-facing triangle for:
* - the GLSL gl_FrontFacing fragment attribute (bool)
* - two-sided stencil test
+ * 0 = front-facing, 1 = back-facing
*/
setup->facing =
- ((det > 0.0) ^
- (setup->softpipe->rasterizer->front_winding == PIPE_WINDING_CW));
+ ((det < 0.0) ^
+ (setup->softpipe->rasterizer->front_ccw));
+
+ {
+ unsigned face = setup->facing == 0 ? PIPE_FACE_FRONT : PIPE_FACE_BACK;
+
+ if (face & setup->cull_face)
+ return FALSE;
+ }
+
/* Prepare pixel offset for rasterisation:
* - pixel center (0.5, 0.5) for GL, or
* - assume (0.0, 0.0) for other APIs.
*/
- if (setup->softpipe->rasterizer->gl_rasterization_rules) {
+ if (setup->softpipe->rasterizer->half_pixel_center) {
setup->pixel_offset = 0.5f;
} else {
setup->pixel_offset = 0.0f;
}
+/* Apply cylindrical wrapping to v0, v1, v2 coordinates, if enabled.
+ * Input coordinates must be in [0, 1] range, otherwise results are undefined.
+ * Some combinations of coordinates produce invalid results,
+ * but this behaviour is acceptable.
+ */
+static void
+tri_apply_cylindrical_wrap(float v0,
+ float v1,
+ float v2,
+ uint cylindrical_wrap,
+ float output[3])
+{
+ if (cylindrical_wrap) {
+ float delta;
+
+ delta = v1 - v0;
+ if (delta > 0.5f) {
+ v0 += 1.0f;
+ }
+ else if (delta < -0.5f) {
+ v1 += 1.0f;
+ }
+
+ delta = v2 - v1;
+ if (delta > 0.5f) {
+ v1 += 1.0f;
+ }
+ else if (delta < -0.5f) {
+ v2 += 1.0f;
+ }
+
+ delta = v0 - v2;
+ if (delta > 0.5f) {
+ v2 += 1.0f;
+ }
+ else if (delta < -0.5f) {
+ v0 += 1.0f;
+ }
+ }
+
+ output[0] = v0;
+ output[1] = v1;
+ output[2] = v2;
+}
+
+
/**
* Compute a0 for a constant-valued coefficient (GL_FLAT shading).
* The value value comes from vertex[slot][i].
* \param slot which attribute slot
* \param i which component of the slot (0..3)
*/
-static void const_coeff( struct setup_context *setup,
- struct tgsi_interp_coef *coef,
- uint vertSlot, uint i)
+static void
+const_coeff(struct setup_context *setup,
+ struct tgsi_interp_coef *coef,
+ uint vertSlot, uint i)
{
assert(i <= 3);
/**
* Compute a0, dadx and dady for a linearly interpolated coefficient,
* for a triangle.
+ * v[0], v[1] and v[2] are vmin, vmid and vmax, respectively.
*/
-static void tri_linear_coeff( struct setup_context *setup,
- struct tgsi_interp_coef *coef,
- uint vertSlot, uint i)
+static void
+tri_linear_coeff(struct setup_context *setup,
+ struct tgsi_interp_coef *coef,
+ uint i,
+ const float v[3])
{
- float botda = setup->vmid[vertSlot][i] - setup->vmin[vertSlot][i];
- float majda = setup->vmax[vertSlot][i] - setup->vmin[vertSlot][i];
+ float botda = v[1] - v[0];
+ float majda = v[2] - v[0];
float a = setup->ebot.dy * majda - botda * setup->emaj.dy;
float b = setup->emaj.dx * botda - majda * setup->ebot.dx;
float dadx = a * setup->oneoverarea;
* to define a0 as the sample at a pixel center somewhere near vmin
* instead - i'll switch to this later.
*/
- coef->a0[i] = (setup->vmin[vertSlot][i] -
+ coef->a0[i] = (v[0] -
(dadx * (setup->vmin[0][0] - setup->pixel_offset) +
dady * (setup->vmin[0][1] - setup->pixel_offset)));
-
- /*
- debug_printf("attr[%d].%c: %f dx:%f dy:%f\n",
- slot, "xyzw"[i],
- setup->coef[slot].a0[i],
- setup->coef[slot].dadx[i],
- setup->coef[slot].dady[i]);
- */
}
* the plane coefficients (a0, dadx, dady).
* Later, when we compute the value at a particular fragment position we'll
* divide the interpolated value by the interpolated W at that fragment.
+ * v[0], v[1] and v[2] are vmin, vmid and vmax, respectively.
*/
-static void tri_persp_coeff( struct setup_context *setup,
- struct tgsi_interp_coef *coef,
- uint vertSlot, uint i)
+static void
+tri_persp_coeff(struct setup_context *setup,
+ struct tgsi_interp_coef *coef,
+ uint i,
+ const float v[3])
{
/* premultiply by 1/w (v[0][3] is always W):
*/
- float mina = setup->vmin[vertSlot][i] * setup->vmin[0][3];
- float mida = setup->vmid[vertSlot][i] * setup->vmid[0][3];
- float maxa = setup->vmax[vertSlot][i] * setup->vmax[0][3];
+ float mina = v[0] * setup->vmin[0][3];
+ float mida = v[1] * setup->vmid[0][3];
+ float maxa = v[2] * setup->vmax[0][3];
float botda = mida - mina;
float majda = maxa - mina;
float a = setup->ebot.dy * majda - botda * setup->emaj.dy;
float dadx = a * setup->oneoverarea;
float dady = b * setup->oneoverarea;
- /*
- debug_printf("tri persp %d,%d: %f %f %f\n", vertSlot, i,
- setup->vmin[vertSlot][i],
- setup->vmid[vertSlot][i],
- setup->vmax[vertSlot][i]
- );
- */
assert(i <= 3);
coef->dadx[i] = dadx;
/**
* Special coefficient setup for gl_FragCoord.
- * X and Y are trivial, though Y has to be inverted for OpenGL.
+ * X and Y are trivial, though Y may have to be inverted for OpenGL.
* Z and W are copied from posCoef which should have already been computed.
* We could do a bit less work if we'd examine gl_FragCoord's swizzle mask.
*/
static void
setup_fragcoord_coeff(struct setup_context *setup, uint slot)
{
+ const struct tgsi_shader_info *fsInfo = &setup->softpipe->fs_variant->info;
+ boolean origin_lower_left =
+ fsInfo->properties[TGSI_PROPERTY_FS_COORD_ORIGIN];
+ boolean pixel_center_integer =
+ fsInfo->properties[TGSI_PROPERTY_FS_COORD_PIXEL_CENTER];
+
/*X*/
- setup->coef[slot].a0[0] = 0;
- setup->coef[slot].dadx[0] = 1.0;
- setup->coef[slot].dady[0] = 0.0;
+ setup->coef[slot].a0[0] = pixel_center_integer ? 0.0f : 0.5f;
+ setup->coef[slot].dadx[0] = 1.0f;
+ setup->coef[slot].dady[0] = 0.0f;
/*Y*/
- setup->coef[slot].a0[1] = 0.0;
- setup->coef[slot].dadx[1] = 0.0;
- setup->coef[slot].dady[1] = 1.0;
+ setup->coef[slot].a0[1] =
+ (origin_lower_left ? setup->softpipe->framebuffer.height-1 : 0)
+ + (pixel_center_integer ? 0.0f : 0.5f);
+ setup->coef[slot].dadx[1] = 0.0f;
+ setup->coef[slot].dady[1] = origin_lower_left ? -1.0f : 1.0f;
/*Z*/
setup->coef[slot].a0[2] = setup->posCoef.a0[2];
setup->coef[slot].dadx[2] = setup->posCoef.dadx[2];
* Compute the setup->coef[] array dadx, dady, a0 values.
* Must be called after setup->vmin,vmid,vmax,vprovoke are initialized.
*/
-static void setup_tri_coefficients( struct setup_context *setup )
+static void
+setup_tri_coefficients(struct setup_context *setup)
{
struct softpipe_context *softpipe = setup->softpipe;
- const struct sp_fragment_shader *spfs = softpipe->fs;
- const struct vertex_info *vinfo = softpipe_get_vertex_info(softpipe);
+ const struct tgsi_shader_info *fsInfo = &setup->softpipe->fs_variant->info;
+ const struct sp_setup_info *sinfo = &softpipe->setup_info;
uint fragSlot;
+ float v[3];
+
+ assert(sinfo->valid);
/* z and w are done by linear interpolation:
*/
- tri_linear_coeff(setup, &setup->posCoef, 0, 2);
- tri_linear_coeff(setup, &setup->posCoef, 0, 3);
+ v[0] = setup->vmin[0][2];
+ v[1] = setup->vmid[0][2];
+ v[2] = setup->vmax[0][2];
+ tri_linear_coeff(setup, &setup->posCoef, 2, v);
+
+ v[0] = setup->vmin[0][3];
+ v[1] = setup->vmid[0][3];
+ v[2] = setup->vmax[0][3];
+ tri_linear_coeff(setup, &setup->posCoef, 3, v);
/* setup interpolation for all the remaining attributes:
*/
- for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) {
- const uint vertSlot = vinfo->attrib[fragSlot].src_index;
+ for (fragSlot = 0; fragSlot < fsInfo->num_inputs; fragSlot++) {
+ const uint vertSlot = sinfo->attrib[fragSlot].src_index;
uint j;
- switch (vinfo->attrib[fragSlot].interp_mode) {
- case INTERP_CONSTANT:
- for (j = 0; j < NUM_CHANNELS; j++)
+ switch (sinfo->attrib[fragSlot].interp) {
+ case SP_INTERP_CONSTANT:
+ for (j = 0; j < TGSI_NUM_CHANNELS; j++) {
const_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
+ }
break;
- case INTERP_LINEAR:
- for (j = 0; j < NUM_CHANNELS; j++)
- tri_linear_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
+ case SP_INTERP_LINEAR:
+ for (j = 0; j < TGSI_NUM_CHANNELS; j++) {
+ tri_apply_cylindrical_wrap(setup->vmin[vertSlot][j],
+ setup->vmid[vertSlot][j],
+ setup->vmax[vertSlot][j],
+ fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j),
+ v);
+ tri_linear_coeff(setup, &setup->coef[fragSlot], j, v);
+ }
break;
- case INTERP_PERSPECTIVE:
- for (j = 0; j < NUM_CHANNELS; j++)
- tri_persp_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
+ case SP_INTERP_PERSPECTIVE:
+ for (j = 0; j < TGSI_NUM_CHANNELS; j++) {
+ tri_apply_cylindrical_wrap(setup->vmin[vertSlot][j],
+ setup->vmid[vertSlot][j],
+ setup->vmax[vertSlot][j],
+ fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j),
+ v);
+ tri_persp_coeff(setup, &setup->coef[fragSlot], j, v);
+ }
break;
- case INTERP_POS:
+ case SP_INTERP_POS:
setup_fragcoord_coeff(setup, fragSlot);
break;
default:
assert(0);
}
- if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
- setup->coef[fragSlot].a0[0] = 1.0f - setup->facing;
+ if (fsInfo->input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
+ /* convert 0 to 1.0 and 1 to -1.0 */
+ setup->coef[fragSlot].a0[0] = setup->facing * -2.0f + 1.0f;
setup->coef[fragSlot].dadx[0] = 0.0;
setup->coef[fragSlot].dady[0] = 0.0;
}
+
+ if (0) {
+ for (j = 0; j < TGSI_NUM_CHANNELS; j++) {
+ debug_printf("attr[%d].%c: a0:%f dx:%f dy:%f\n",
+ fragSlot, "xyzw"[j],
+ setup->coef[fragSlot].a0[j],
+ setup->coef[fragSlot].dadx[j],
+ setup->coef[fragSlot].dady[j]);
+ }
+ }
}
}
-
-static void setup_tri_edges( struct setup_context *setup )
+static void
+setup_tri_edges(struct setup_context *setup)
{
float vmin_x = setup->vmin[0][0] + setup->pixel_offset;
float vmid_x = setup->vmid[0][0] + setup->pixel_offset;
setup->emaj.sy = ceilf(vmin_y);
setup->emaj.lines = (int) ceilf(vmax_y - setup->emaj.sy);
- setup->emaj.dxdy = setup->emaj.dx / setup->emaj.dy;
+ setup->emaj.dxdy = setup->emaj.dy ? setup->emaj.dx / setup->emaj.dy : .0f;
setup->emaj.sx = vmin_x + (setup->emaj.sy - vmin_y) * setup->emaj.dxdy;
setup->etop.sy = ceilf(vmid_y);
setup->etop.lines = (int) ceilf(vmax_y - setup->etop.sy);
- setup->etop.dxdy = setup->etop.dx / setup->etop.dy;
+ setup->etop.dxdy = setup->etop.dy ? setup->etop.dx / setup->etop.dy : .0f;
setup->etop.sx = vmid_x + (setup->etop.sy - vmid_y) * setup->etop.dxdy;
setup->ebot.sy = ceilf(vmin_y);
setup->ebot.lines = (int) ceilf(vmid_y - setup->ebot.sy);
- setup->ebot.dxdy = setup->ebot.dx / setup->ebot.dy;
+ setup->ebot.dxdy = setup->ebot.dy ? setup->ebot.dx / setup->ebot.dy : .0f;
setup->ebot.sx = vmin_x + (setup->ebot.sy - vmin_y) * setup->ebot.dxdy;
}
* Render the upper or lower half of a triangle.
* Scissoring/cliprect is applied here too.
*/
-static void subtriangle( struct setup_context *setup,
- struct edge *eleft,
- struct edge *eright,
- unsigned lines )
+static void
+subtriangle(struct setup_context *setup,
+ struct edge *eleft,
+ struct edge *eright,
+ int lines,
+ unsigned viewport_index)
{
- const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect;
+ const struct pipe_scissor_state *cliprect = &setup->softpipe->cliprect[viewport_index];
const int minx = (int) cliprect->minx;
const int maxx = (int) cliprect->maxx;
const int miny = (int) cliprect->miny;
int sy = (int)eleft->sy;
assert((int)eleft->sy == (int) eright->sy);
+ assert(lines >= 0);
/* clip top/bottom */
start_y = sy;
* calculate it here.
*/
static float
-calc_det( const float (*v0)[4],
- const float (*v1)[4],
- const float (*v2)[4] )
+calc_det(const float (*v0)[4],
+ const float (*v1)[4],
+ const float (*v2)[4])
{
/* edge vectors e = v0 - v2, f = v1 - v2 */
const float ex = v0[0][0] - v2[0][0];
/**
* Do setup for triangle rasterization, then render the triangle.
*/
-void sp_setup_tri( struct setup_context *setup,
- const float (*v0)[4],
- const float (*v1)[4],
- const float (*v2)[4] )
+void
+sp_setup_tri(struct setup_context *setup,
+ const float (*v0)[4],
+ const float (*v1)[4],
+ const float (*v2)[4])
{
float det;
-
+ uint layer = 0;
+ unsigned viewport_index = 0;
#if DEBUG_VERTS
debug_printf("Setup triangle:\n");
print_vertex(setup, v0);
print_vertex(setup, v2);
#endif
- if (setup->softpipe->no_rast)
+ if (setup->softpipe->no_rast || setup->softpipe->rasterizer->rasterizer_discard)
return;
det = calc_det(v0, v1, v2);
setup->numFragsWritten = 0;
#endif
- if (cull_tri( setup, det ))
- return;
-
if (!setup_sort_vertices( setup, det, v0, v1, v2 ))
return;
+
setup_tri_coefficients( setup );
setup_tri_edges( setup );
setup->span.right[0] = 0;
setup->span.right[1] = 0;
/* setup->span.z_mode = tri_z_mode( setup->ctx ); */
+ if (setup->softpipe->layer_slot > 0) {
+ layer = *(unsigned *)setup->vprovoke[setup->softpipe->layer_slot];
+ layer = MIN2(layer, setup->max_layer);
+ }
+ setup->quad[0].input.layer = layer;
+
+ if (setup->softpipe->viewport_index_slot > 0) {
+ unsigned *udata = (unsigned*)v0[setup->softpipe->viewport_index_slot];
+ viewport_index = sp_clamp_viewport_idx(*udata);
+ }
+ setup->quad[0].input.viewport_index = viewport_index;
/* init_constant_attribs( setup ); */
if (setup->oneoverarea < 0.0) {
/* emaj on left:
*/
- subtriangle( setup, &setup->emaj, &setup->ebot, setup->ebot.lines );
- subtriangle( setup, &setup->emaj, &setup->etop, setup->etop.lines );
+ subtriangle(setup, &setup->emaj, &setup->ebot, setup->ebot.lines, viewport_index);
+ subtriangle(setup, &setup->emaj, &setup->etop, setup->etop.lines, viewport_index);
}
else {
/* emaj on right:
*/
- subtriangle( setup, &setup->ebot, &setup->emaj, setup->ebot.lines );
- subtriangle( setup, &setup->etop, &setup->emaj, setup->etop.lines );
+ subtriangle(setup, &setup->ebot, &setup->emaj, setup->ebot.lines, viewport_index);
+ subtriangle(setup, &setup->etop, &setup->emaj, setup->etop.lines, viewport_index);
}
flush_spans( setup );
+ if (setup->softpipe->active_statistics_queries) {
+ setup->softpipe->pipeline_statistics.c_primitives++;
+ }
+
#if DEBUG_FRAGS
printf("Tri: %u frags emitted, %u written\n",
setup->numFragsEmitted,
}
+/* Apply cylindrical wrapping to v0, v1 coordinates, if enabled.
+ * Input coordinates must be in [0, 1] range, otherwise results are undefined.
+ */
+static void
+line_apply_cylindrical_wrap(float v0,
+ float v1,
+ uint cylindrical_wrap,
+ float output[2])
+{
+ if (cylindrical_wrap) {
+ float delta;
+
+ delta = v1 - v0;
+ if (delta > 0.5f) {
+ v0 += 1.0f;
+ }
+ else if (delta < -0.5f) {
+ v1 += 1.0f;
+ }
+ }
+
+ output[0] = v0;
+ output[1] = v1;
+}
+
/**
* Compute a0, dadx and dady for a linearly interpolated coefficient,
* for a line.
+ * v[0] and v[1] are vmin and vmax, respectively.
*/
static void
line_linear_coeff(const struct setup_context *setup,
struct tgsi_interp_coef *coef,
- uint vertSlot, uint i)
+ uint i,
+ const float v[2])
{
- const float da = setup->vmax[vertSlot][i] - setup->vmin[vertSlot][i];
+ const float da = v[1] - v[0];
const float dadx = da * setup->emaj.dx * setup->oneoverarea;
const float dady = da * setup->emaj.dy * setup->oneoverarea;
coef->dadx[i] = dadx;
coef->dady[i] = dady;
- coef->a0[i] = (setup->vmin[vertSlot][i] -
+ coef->a0[i] = (v[0] -
(dadx * (setup->vmin[0][0] - setup->pixel_offset) +
dady * (setup->vmin[0][1] - setup->pixel_offset)));
}
/**
* Compute a0, dadx and dady for a perspective-corrected interpolant,
* for a line.
+ * v[0] and v[1] are vmin and vmax, respectively.
*/
static void
line_persp_coeff(const struct setup_context *setup,
struct tgsi_interp_coef *coef,
- uint vertSlot, uint i)
+ uint i,
+ const float v[2])
{
- /* XXX double-check/verify this arithmetic */
- const float a0 = setup->vmin[vertSlot][i] * setup->vmin[0][3];
- const float a1 = setup->vmax[vertSlot][i] * setup->vmax[0][3];
+ const float a0 = v[0] * setup->vmin[0][3];
+ const float a1 = v[1] * setup->vmax[0][3];
const float da = a1 - a0;
const float dadx = da * setup->emaj.dx * setup->oneoverarea;
const float dady = da * setup->emaj.dy * setup->oneoverarea;
coef->dadx[i] = dadx;
coef->dady[i] = dady;
- coef->a0[i] = (setup->vmin[vertSlot][i] -
+ coef->a0[i] = (a0 -
(dadx * (setup->vmin[0][0] - setup->pixel_offset) +
dady * (setup->vmin[0][1] - setup->pixel_offset)));
}
* Compute the setup->coef[] array dadx, dady, a0 values.
* Must be called after setup->vmin,vmax are initialized.
*/
-static INLINE boolean
+static boolean
setup_line_coefficients(struct setup_context *setup,
const float (*v0)[4],
const float (*v1)[4])
{
struct softpipe_context *softpipe = setup->softpipe;
- const struct sp_fragment_shader *spfs = softpipe->fs;
- const struct vertex_info *vinfo = softpipe_get_vertex_info(softpipe);
+ const struct tgsi_shader_info *fsInfo = &setup->softpipe->fs_variant->info;
+ const struct sp_setup_info *sinfo = &softpipe->setup_info;
uint fragSlot;
float area;
+ float v[2];
+
+ assert(sinfo->valid);
/* use setup->vmin, vmax to point to vertices */
if (softpipe->rasterizer->flatshade_first)
/* z and w are done by linear interpolation:
*/
- line_linear_coeff(setup, &setup->posCoef, 0, 2);
- line_linear_coeff(setup, &setup->posCoef, 0, 3);
+ v[0] = setup->vmin[0][2];
+ v[1] = setup->vmax[0][2];
+ line_linear_coeff(setup, &setup->posCoef, 2, v);
+
+ v[0] = setup->vmin[0][3];
+ v[1] = setup->vmax[0][3];
+ line_linear_coeff(setup, &setup->posCoef, 3, v);
/* setup interpolation for all the remaining attributes:
*/
- for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) {
- const uint vertSlot = vinfo->attrib[fragSlot].src_index;
+ for (fragSlot = 0; fragSlot < fsInfo->num_inputs; fragSlot++) {
+ const uint vertSlot = sinfo->attrib[fragSlot].src_index;
uint j;
- switch (vinfo->attrib[fragSlot].interp_mode) {
- case INTERP_CONSTANT:
- for (j = 0; j < NUM_CHANNELS; j++)
+ switch (sinfo->attrib[fragSlot].interp) {
+ case SP_INTERP_CONSTANT:
+ for (j = 0; j < TGSI_NUM_CHANNELS; j++)
const_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
break;
- case INTERP_LINEAR:
- for (j = 0; j < NUM_CHANNELS; j++)
- line_linear_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
+ case SP_INTERP_LINEAR:
+ for (j = 0; j < TGSI_NUM_CHANNELS; j++) {
+ line_apply_cylindrical_wrap(setup->vmin[vertSlot][j],
+ setup->vmax[vertSlot][j],
+ fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j),
+ v);
+ line_linear_coeff(setup, &setup->coef[fragSlot], j, v);
+ }
break;
- case INTERP_PERSPECTIVE:
- for (j = 0; j < NUM_CHANNELS; j++)
- line_persp_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
+ case SP_INTERP_PERSPECTIVE:
+ for (j = 0; j < TGSI_NUM_CHANNELS; j++) {
+ line_apply_cylindrical_wrap(setup->vmin[vertSlot][j],
+ setup->vmax[vertSlot][j],
+ fsInfo->input_cylindrical_wrap[fragSlot] & (1 << j),
+ v);
+ line_persp_coeff(setup, &setup->coef[fragSlot], j, v);
+ }
break;
- case INTERP_POS:
+ case SP_INTERP_POS:
setup_fragcoord_coeff(setup, fragSlot);
break;
default:
assert(0);
}
- if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
- setup->coef[fragSlot].a0[0] = 1.0f - setup->facing;
+ if (fsInfo->input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
+ /* convert 0 to 1.0 and 1 to -1.0 */
+ setup->coef[fragSlot].a0[0] = setup->facing * -2.0f + 1.0f;
setup->coef[fragSlot].dadx[0] = 0.0;
setup->coef[fragSlot].dady[0] = 0.0;
}
/**
* Plot a pixel in a line segment.
*/
-static INLINE void
+static inline void
plot(struct setup_context *setup, int x, int y)
{
const int iy = y & 1;
/* flush prev quad, start new quad */
if (setup->quad[0].input.x0 != -1)
- clip_emit_quad( setup, &setup->quad[0] );
+ clip_emit_quad(setup, &setup->quad[0]);
setup->quad[0].input.x0 = quadX;
setup->quad[0].input.y0 = quadY;
*/
void
sp_setup_line(struct setup_context *setup,
- const float (*v0)[4],
- const float (*v1)[4])
+ const float (*v0)[4],
+ const float (*v1)[4])
{
int x0 = (int) v0[0][0];
int x1 = (int) v1[0][0];
int dx = x1 - x0;
int dy = y1 - y0;
int xstep, ystep;
+ uint layer = 0;
+ unsigned viewport_index = 0;
#if DEBUG_VERTS
debug_printf("Setup line:\n");
print_vertex(setup, v1);
#endif
- if (setup->softpipe->no_rast)
+ if (setup->softpipe->no_rast || setup->softpipe->rasterizer->rasterizer_discard)
return;
if (dx == 0 && dy == 0)
setup->quad[0].input.x0 = setup->quad[0].input.y0 = -1;
setup->quad[0].inout.mask = 0x0;
+ if (setup->softpipe->layer_slot > 0) {
+ layer = *(unsigned *)setup->vprovoke[setup->softpipe->layer_slot];
+ layer = MIN2(layer, setup->max_layer);
+ }
+ setup->quad[0].input.layer = layer;
+
+ if (setup->softpipe->viewport_index_slot > 0) {
+ unsigned *udata = (unsigned*)setup->vprovoke[setup->softpipe->viewport_index_slot];
+ viewport_index = sp_clamp_viewport_idx(*udata);
+ }
+ setup->quad[0].input.viewport_index = viewport_index;
/* XXX temporary: set coverage to 1.0 so the line appears
* if AA mode happens to be enabled.
/* draw final quad */
if (setup->quad[0].inout.mask) {
- clip_emit_quad( setup, &setup->quad[0] );
+ clip_emit_quad(setup, &setup->quad[0]);
}
}
* XXX could optimize a lot for 1-pixel points.
*/
void
-sp_setup_point( struct setup_context *setup,
- const float (*v0)[4] )
+sp_setup_point(struct setup_context *setup,
+ const float (*v0)[4])
{
struct softpipe_context *softpipe = setup->softpipe;
- const struct sp_fragment_shader *spfs = softpipe->fs;
+ const struct tgsi_shader_info *fsInfo = &setup->softpipe->fs_variant->info;
const int sizeAttr = setup->softpipe->psize_slot;
const float size
= sizeAttr > 0 ? v0[sizeAttr][0]
const boolean round = (boolean) setup->softpipe->rasterizer->point_smooth;
const float x = v0[0][0]; /* Note: data[0] is always position */
const float y = v0[0][1];
- const struct vertex_info *vinfo = softpipe_get_vertex_info(softpipe);
+ const struct sp_setup_info *sinfo = &softpipe->setup_info;
uint fragSlot;
-
+ uint layer = 0;
+ unsigned viewport_index = 0;
#if DEBUG_VERTS
debug_printf("Setup point:\n");
print_vertex(setup, v0);
#endif
- if (softpipe->no_rast)
+ assert(sinfo->valid);
+
+ if (setup->softpipe->no_rast || setup->softpipe->rasterizer->rasterizer_discard)
return;
assert(setup->softpipe->reduced_prim == PIPE_PRIM_POINTS);
+ if (setup->softpipe->layer_slot > 0) {
+ layer = *(unsigned *)v0[setup->softpipe->layer_slot];
+ layer = MIN2(layer, setup->max_layer);
+ }
+ setup->quad[0].input.layer = layer;
+
+ if (setup->softpipe->viewport_index_slot > 0) {
+ unsigned *udata = (unsigned*)v0[setup->softpipe->viewport_index_slot];
+ viewport_index = sp_clamp_viewport_idx(*udata);
+ }
+ setup->quad[0].input.viewport_index = viewport_index;
+
/* For points, all interpolants are constant-valued.
* However, for point sprites, we'll need to setup texcoords appropriately.
* XXX: which coefficients are the texcoords???
const_coeff(setup, &setup->posCoef, 0, 2);
const_coeff(setup, &setup->posCoef, 0, 3);
- for (fragSlot = 0; fragSlot < spfs->info.num_inputs; fragSlot++) {
- const uint vertSlot = vinfo->attrib[fragSlot].src_index;
+ for (fragSlot = 0; fragSlot < fsInfo->num_inputs; fragSlot++) {
+ const uint vertSlot = sinfo->attrib[fragSlot].src_index;
uint j;
- switch (vinfo->attrib[fragSlot].interp_mode) {
- case INTERP_CONSTANT:
+ switch (sinfo->attrib[fragSlot].interp) {
+ case SP_INTERP_CONSTANT:
/* fall-through */
- case INTERP_LINEAR:
- for (j = 0; j < NUM_CHANNELS; j++)
+ case SP_INTERP_LINEAR:
+ for (j = 0; j < TGSI_NUM_CHANNELS; j++)
const_coeff(setup, &setup->coef[fragSlot], vertSlot, j);
break;
- case INTERP_PERSPECTIVE:
- for (j = 0; j < NUM_CHANNELS; j++)
+ case SP_INTERP_PERSPECTIVE:
+ for (j = 0; j < TGSI_NUM_CHANNELS; j++)
point_persp_coeff(setup, setup->vprovoke,
&setup->coef[fragSlot], vertSlot, j);
break;
- case INTERP_POS:
+ case SP_INTERP_POS:
setup_fragcoord_coeff(setup, fragSlot);
break;
default:
assert(0);
}
- if (spfs->info.input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
- setup->coef[fragSlot].a0[0] = 1.0f - setup->facing;
+ if (fsInfo->input_semantic_name[fragSlot] == TGSI_SEMANTIC_FACE) {
+ /* convert 0 to 1.0 and 1 to -1.0 */
+ setup->coef[fragSlot].a0[0] = setup->facing * -2.0f + 1.0f;
setup->coef[fragSlot].dadx[0] = 0.0;
setup->coef[fragSlot].dady[0] = 0.0;
}
setup->quad[0].input.x0 = (int) x - ix;
setup->quad[0].input.y0 = (int) y - iy;
setup->quad[0].inout.mask = (1 << ix) << (2 * iy);
- clip_emit_quad( setup, &setup->quad[0] );
+ clip_emit_quad(setup, &setup->quad[0]);
}
else {
if (round) {
if (setup->quad[0].inout.mask) {
setup->quad[0].input.x0 = ix;
setup->quad[0].input.y0 = iy;
- clip_emit_quad( setup, &setup->quad[0] );
+ clip_emit_quad(setup, &setup->quad[0]);
}
}
}
setup->quad[0].inout.mask = mask;
setup->quad[0].input.x0 = ix;
setup->quad[0].input.y0 = iy;
- clip_emit_quad( setup, &setup->quad[0] );
+ clip_emit_quad(setup, &setup->quad[0]);
}
}
}
}
}
-void sp_setup_prepare( struct setup_context *setup )
+
+/**
+ * Called by vbuf code just before we start buffering primitives.
+ */
+void
+sp_setup_prepare(struct setup_context *setup)
{
struct softpipe_context *sp = setup->softpipe;
-
+ int i;
+ unsigned max_layer = ~0;
if (sp->dirty) {
- softpipe_update_derived(sp);
+ softpipe_update_derived(sp, sp->reduced_api_prim);
}
/* Note: nr_attrs is only used for debugging (vertex printing) */
setup->nr_vertex_attrs = draw_num_shader_outputs(sp->draw);
+ /*
+ * Determine how many layers the fb has (used for clamping layer value).
+ * OpenGL (but not d3d10) permits different amount of layers per rt, however
+ * results are undefined if layer exceeds the amount of layers of ANY
+ * attachment hence don't need separate per cbuf and zsbuf max.
+ */
+ for (i = 0; i < setup->softpipe->framebuffer.nr_cbufs; i++) {
+ struct pipe_surface *cbuf = setup->softpipe->framebuffer.cbufs[i];
+ if (cbuf) {
+ max_layer = MIN2(max_layer,
+ cbuf->u.tex.last_layer - cbuf->u.tex.first_layer);
+
+ }
+ }
+
+ setup->max_layer = max_layer;
+
sp->quad.first->begin( sp->quad.first );
if (sp->reduced_api_prim == PIPE_PRIM_TRIANGLES &&
- sp->rasterizer->fill_cw == PIPE_POLYGON_MODE_FILL &&
- sp->rasterizer->fill_ccw == PIPE_POLYGON_MODE_FILL) {
+ sp->rasterizer->fill_front == PIPE_POLYGON_MODE_FILL &&
+ sp->rasterizer->fill_back == PIPE_POLYGON_MODE_FILL) {
/* we'll do culling */
- setup->winding = sp->rasterizer->cull_mode;
+ setup->cull_face = sp->rasterizer->cull_face;
}
else {
/* 'draw' will do culling */
- setup->winding = PIPE_WINDING_NONE;
+ setup->cull_face = PIPE_FACE_NONE;
}
}
-
-void sp_setup_destroy_context( struct setup_context *setup )
+void
+sp_setup_destroy_context(struct setup_context *setup)
{
FREE( setup );
}
/**
* Create a new primitive setup/render stage.
*/
-struct setup_context *sp_setup_create_context( struct softpipe_context *softpipe )
+struct setup_context *
+sp_setup_create_context(struct softpipe_context *softpipe)
{
struct setup_context *setup = CALLOC_STRUCT(setup_context);
unsigned i;
return setup;
}
-