*
**************************************************************************/
- /*
- * Authors:
- * Brian Paul
- */
+/**
+ * glRasterPos implementation. Basically render a GL_POINT with our
+ * private draw module. Plug in a special "rasterpos" stage at the end
+ * of the 'draw' pipeline to capture the results and update the current
+ * raster pos attributes.
+ *
+ * Authors:
+ * Brian Paul
+ */
+
#include "main/imports.h"
-#include "main/feedback.h"
#include "main/macros.h"
#include "st_context.h"
#include "st_atom.h"
-#include "st_cache.h"
#include "st_draw.h"
-#include "st_program.h"
#include "st_cb_rasterpos.h"
#include "st_draw.h"
-#include "st_format.h"
-#include "pipe/p_context.h"
-#include "pipe/p_defines.h"
-#include "pipe/p_winsys.h"
+#include "pipe/draw/draw_context.h"
+#include "pipe/draw/draw_private.h"
#include "shader/prog_instruction.h"
+#include "vbo/vbo.h"
-static void
-setup_vertex_attribs(GLcontext *ctx)
+/**
+ * Our special drawing pipeline stage (replaces rasterization).
+ */
+struct rastpos_stage
{
- struct pipe_context *pipe = ctx->st->pipe;
- const struct cso_vertex_shader *vs = ctx->st->state.vs;
- const struct st_vertex_program *stvp = ctx->st->vp;
- uint slot;
-
- /* all attributes come from the default attribute buffer */
- {
- struct pipe_vertex_buffer vbuffer;
- vbuffer.buffer = ctx->st->default_attrib_buffer;
- vbuffer.buffer_offset = 0;
- vbuffer.pitch = 0; /* must be zero! */
- vbuffer.max_index = 1;
- pipe->set_vertex_buffer(pipe, 0, &vbuffer);
- }
+ struct draw_stage stage; /**< Base class */
+ GLcontext *ctx; /**< Rendering context */
- for (slot = 0; slot < vs->state.num_inputs; slot++) {
- struct pipe_vertex_element velement;
- const GLuint attr = stvp->index_to_input[slot];
+ /* vertex attrib info we can setup once and re-use */
+ struct gl_client_array array[VERT_ATTRIB_MAX];
+ const struct gl_client_array *arrays[VERT_ATTRIB_MAX];
+ struct _mesa_prim prim;
+};
- velement.src_offset = attr * 4 * sizeof(GLfloat);
- velement.vertex_buffer_index = 0;
- velement.dst_offset = 0;
- velement.src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
- pipe->set_vertex_element(pipe, slot, &velement);
- }
-}
+static INLINE struct rastpos_stage *
+rastpos_stage( struct draw_stage *stage )
+{
+ return (struct rastpos_stage *) stage;
+}
static void
-setup_feedback(GLcontext *ctx)
+rastpos_begin( struct draw_stage *stage )
{
- struct pipe_context *pipe = ctx->st->pipe;
- const struct pipe_shader_state *vs = &ctx->st->state.vs->state;
- struct pipe_feedback_state feedback;
- uint i;
-
- memset(&feedback, 0, sizeof(feedback));
- feedback.enabled = 1;
- feedback.interleaved = 1;
- feedback.discard = 1;
- feedback.num_attribs = 0;
-
- /* feedback all results from vertex shader */
- for (i = 0; i < vs->num_outputs; i++) {
- feedback.attrib[feedback.num_attribs] = i;
- feedback.size[feedback.num_attribs] = 4;
- feedback.num_attribs++;
- }
-
- if (pipe->set_feedback_state)
- pipe->set_feedback_state(pipe, &feedback);
+ /* no-op */
}
+static void
+rastpos_end( struct draw_stage *stage )
+{
+ /* no-op */
+}
-
-
-
-/**
- * Clip a point against the view volume.
- *
- * \param v vertex vector describing the point to clip.
- *
- * \return zero if outside view volume, or one if inside.
- */
-static GLuint
-viewclip_point( const GLfloat v[] )
+static void
+rastpos_reset_stipple_counter( struct draw_stage *stage )
{
- if ( v[0] > v[3] || v[0] < -v[3]
- || v[1] > v[3] || v[1] < -v[3]
- || v[2] > v[3] || v[2] < -v[3] ) {
- return 0;
- }
- else {
- return 1;
- }
+ /* no-op */
}
+static void
+rastpos_tri( struct draw_stage *stage, struct prim_header *prim )
+{
+ /* should never get here */
+ assert(0);
+}
-/**
- * Clip a point against the far/near Z clipping planes.
- *
- * \param v vertex vector describing the point to clip.
- *
- * \return zero if outside view volume, or one if inside.
- */
-static GLuint
-viewclip_point_z( const GLfloat v[] )
+static void
+rastpos_line( struct draw_stage *stage, struct prim_header *prim )
{
- if (v[2] > v[3] || v[2] < -v[3] ) {
- return 0;
- }
- else {
- return 1;
- }
+ /* should never get here */
+ assert(0);
}
/**
- * Clip a point against the user clipping planes.
- *
- * \param ctx GL context.
- * \param v vertex vector describing the point to clip.
- *
- * \return zero if the point was clipped, or one otherwise.
+ * Update a raster pos attribute from the vertex result if it's present,
+ * else copy the current attrib.
*/
-static GLuint
-userclip_point( GLcontext *ctx, const GLfloat v[] )
+static void
+update_attrib(GLcontext *ctx, const GLuint *outputMapping,
+ const struct vertex_header *vert,
+ GLfloat *dest,
+ GLuint result, GLuint defaultAttrib)
{
- GLuint p;
-
- for (p = 0; p < ctx->Const.MaxClipPlanes; p++) {
- if (ctx->Transform.ClipPlanesEnabled & (1 << p)) {
- GLfloat dot = v[0] * ctx->Transform._ClipUserPlane[p][0]
- + v[1] * ctx->Transform._ClipUserPlane[p][1]
- + v[2] * ctx->Transform._ClipUserPlane[p][2]
- + v[3] * ctx->Transform._ClipUserPlane[p][3];
- if (dot < 0.0F) {
- return 0;
- }
- }
- }
-
- return 1;
+ const GLfloat *src;
+ const GLuint k = outputMapping[result];
+ if (k != ~0)
+ src = vert->data[k];
+ else
+ src = ctx->Current.Attrib[defaultAttrib];
+ COPY_4V(dest, src);
}
/**
- * Update the current raster position.
- * Do clip testing, etc. here.
+ * Normally, this function would render a GL_POINT.
*/
static void
-update_rasterpos(GLcontext *ctx,
- const float clipPos[4],
- const float color0[4],
- const float color1[4],
- const float *fog,
- const float *tex)
+rastpos_point(struct draw_stage *stage, struct prim_header *prim)
{
- uint i;
- float d, ndc[3];
-
- /* clip to view volume */
- if (ctx->Transform.RasterPositionUnclipped) {
- /* GL_IBM_rasterpos_clip: only clip against Z */
- if (viewclip_point_z(clipPos) == 0) {
- ctx->Current.RasterPosValid = GL_FALSE;
- return;
- }
- }
- else if (viewclip_point(clipPos) == 0) {
- /* Normal OpenGL behaviour */
- ctx->Current.RasterPosValid = GL_FALSE;
- return;
- }
-
- /* clip to user clipping planes */
- if (ctx->Transform.ClipPlanesEnabled && !userclip_point(ctx, clipPos)) {
- ctx->Current.RasterPosValid = GL_FALSE;
- return;
- }
+ struct rastpos_stage *rs = rastpos_stage(stage);
+ GLcontext *ctx = rs->ctx;
+ struct st_context *st = ctx->st;
+ const GLfloat height = ctx->DrawBuffer->Height;
+ const GLuint *outputMapping = st->vertex_result_to_slot;
+ const GLfloat *pos;
+ GLuint i;
+
+ /* if we get here, we didn't get clipped */
+ ctx->Current.RasterPosValid = GL_TRUE;
+ /* update raster pos */
+ pos = prim->v[0]->data[0];
+ ctx->Current.RasterPos[0] = pos[0];
+ ctx->Current.RasterPos[1] = height - 1 - pos[1];
+ ctx->Current.RasterPos[2] = pos[2];
+ ctx->Current.RasterPos[3] = pos[3];
- /*
- * update current raster position
- */
- /* ndc = clip / W */
- d = (clipPos[3] == 0.0F) ? 1.0F : 1.0F / clipPos[3];
- ndc[0] = clipPos[0] * d;
- ndc[1] = clipPos[1] * d;
- ndc[2] = clipPos[2] * d;
- /* wincoord = viewport_mapping(ndc) */
- ctx->Current.RasterPos[0] = (ndc[0] * ctx->Viewport._WindowMap.m[MAT_SX]
- + ctx->Viewport._WindowMap.m[MAT_TX]);
- ctx->Current.RasterPos[1] = (ndc[1] * ctx->Viewport._WindowMap.m[MAT_SY]
- + ctx->Viewport._WindowMap.m[MAT_TY]);
- ctx->Current.RasterPos[2] = (ndc[2] * ctx->Viewport._WindowMap.m[MAT_SZ]
- + ctx->Viewport._WindowMap.m[MAT_TZ])
- / ctx->DrawBuffer->_DepthMaxF;
- ctx->Current.RasterPos[3] = clipPos[3];
-
- /* compute raster distance */
-#if 0
- if (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT)
- ctx->Current.RasterDistance = ctx->Current.Attrib[VERT_ATTRIB_FOG][0];
- else {
- /* XXX we don't have an eye coord! */
- ctx->Current.RasterDistance =
- SQRTF( eye[0]*eye[0] + eye[1]*eye[1] + eye[2]*eye[2] );
- }
-#else
- ctx->Current.RasterDistance = fog[0];
-#endif
-
- /* colors and texcoords */
- COPY_4FV(ctx->Current.RasterColor, color0);
- COPY_4FV(ctx->Current.RasterSecondaryColor, color1);
- for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
- COPY_4FV(ctx->Current.RasterTexCoords + i, tex + i *4);
- }
+ /* update other raster attribs */
+ update_attrib(ctx, outputMapping, prim->v[0],
+ ctx->Current.RasterColor,
+ VERT_RESULT_COL0, VERT_ATTRIB_COLOR0);
- ctx->Current.RasterPosValid = GL_TRUE;
+ update_attrib(ctx, outputMapping, prim->v[0],
+ ctx->Current.RasterSecondaryColor,
+ VERT_RESULT_COL1, VERT_ATTRIB_COLOR1);
- if (ctx->RenderMode == GL_SELECT) {
- _mesa_update_hitflag( ctx, ctx->Current.RasterPos[2] );
+ for (i = 0; i < MAX_TEXTURE_UNITS; i++) {
+ update_attrib(ctx, outputMapping, prim->v[0],
+ ctx->Current.RasterTexCoords[i],
+ VERT_RESULT_TEX0 + i, VERT_ATTRIB_TEX0 + i);
}
}
+/**
+ * Create rasterpos "drawing" stage.
+ */
+static struct rastpos_stage *
+new_draw_rastpos_stage(GLcontext *ctx, struct draw_context *draw)
+{
+ struct rastpos_stage *rs = CALLOC_STRUCT(rastpos_stage);
+
+ rs->stage.draw = draw;
+ rs->stage.next = NULL;
+ rs->stage.begin = rastpos_begin;
+ rs->stage.point = rastpos_point;
+ rs->stage.line = rastpos_line;
+ rs->stage.tri = rastpos_tri;
+ rs->stage.end = rastpos_end;
+ rs->stage.reset_stipple_counter = rastpos_reset_stipple_counter;
+ rs->ctx = ctx;
+
+ return rs;
+}
+
static void
st_RasterPos(GLcontext *ctx, const GLfloat v[4])
{
- const struct st_context *st = ctx->st;
- struct pipe_context *pipe = st->pipe;
- float *buf_map;
- struct pipe_feedback_buffer fb_buf;
+ struct st_context *st = ctx->st;
+ struct draw_context *draw = st->draw;
+ struct rastpos_stage *rs;
- st_validate_state(ctx->st);
-
- /* setup vertex buffers */
- setup_vertex_attribs(ctx);
-
- /*
- * Load the default attribute buffer with current attribs.
- */
- {
- struct pipe_buffer_handle *buf = st->default_attrib_buffer;
- const unsigned size = sizeof(ctx->Current.Attrib);
- const void *data = ctx->Current.Attrib;
- /* colors, texcoords, etc */
- pipe->winsys->buffer_data(pipe->winsys, buf,
- size, data,
- PIPE_BUFFER_USAGE_VERTEX);
- /* position */
- pipe->winsys->buffer_subdata(pipe->winsys, buf,
- 0, /* offset */
- 4 * sizeof(float), /* size */
- v); /* data */
+ if (st->rastpos_stage) {
+ /* get rastpos stage info */
+ rs = rastpos_stage(st->rastpos_stage);
}
-
-
- /* setup feedback state */
- setup_feedback(ctx);
-
- /* setup vertex feedback buffer */
- {
- fb_buf.size = 8 * 4 * sizeof(float);
- fb_buf.buffer = pipe->winsys->buffer_create(pipe->winsys, 0);
- fb_buf.start_offset = 0;
- pipe->winsys->buffer_data(pipe->winsys, fb_buf.buffer,
- fb_buf.size,
- NULL, /* data */
- PIPE_BUFFER_USAGE_VERTEX);
- if (pipe->set_feedback_buffer)
- pipe->set_feedback_buffer(pipe, 0, &fb_buf);
- }
-
-
- /* draw a point */
- pipe->draw_arrays(pipe, GL_POINTS, 0, 1);
-
- /* get feedback */
- buf_map = (float *) pipe->winsys->buffer_map(pipe->winsys, fb_buf.buffer,
- PIPE_BUFFER_FLAG_READ);
-
- /* extract values and update rasterpos state */
- {
- const GLuint *outputMapping = st->vertex_result_to_slot;
- const float *pos, *color0, *color1, *fog, *tex0;
- float *buf = buf_map;
-
- assert(outputMapping[VERT_RESULT_HPOS] != ~0);
- pos = buf;
- buf += 4;
-
- if (outputMapping[VERT_RESULT_COL0] != ~0) {
- color0 = buf;
- buf += 4;
- }
- else {
- color0 = ctx->Current.Attrib[VERT_ATTRIB_COLOR0];
+ else {
+ /* create rastpos draw stage */
+ GLuint i;
+
+ rs = new_draw_rastpos_stage(ctx, draw);
+ st->rastpos_stage = &rs->stage;
+
+ /* one-time init */
+ for (i = 0; i < VERT_ATTRIB_MAX; i++) {
+ rs->array[i].Size = 4;
+ rs->array[i].Type = GL_FLOAT;
+ rs->array[i].Stride = 0;
+ rs->array[i].StrideB = 0;
+ rs->array[i].Ptr = (GLubyte *) ctx->Current.Attrib[i];
+ rs->array[i].Enabled = GL_TRUE;
+ rs->array[i].Normalized = GL_TRUE;
+ rs->array[i].BufferObj = NULL;
+ rs->arrays[i] = &rs->array[i];
}
- if (outputMapping[VERT_RESULT_COL1] != ~0) {
- color1 = buf;
- buf += 4;
- }
- else {
- color1 = ctx->Current.Attrib[VERT_ATTRIB_COLOR1];
- }
+ rs->prim.mode = GL_POINTS;
+ rs->prim.indexed = 0;
+ rs->prim.begin = 1;
+ rs->prim.end = 1;
+ rs->prim.weak = 0;
+ rs->prim.start = 0;
+ rs->prim.count = 1;
+ }
- if (outputMapping[VERT_RESULT_FOGC] != ~0) {
- fog = buf;
- buf += 4;
- }
- else {
- fog = ctx->Current.Attrib[VERT_ATTRIB_FOG];
- }
+ /* plug our rastpos stage into the draw module */
+ draw_set_rasterize_stage(st->draw, st->rastpos_stage);
- if (outputMapping[VERT_RESULT_TEX0] != ~0) {
- tex0 = buf;
- buf += 4;
- }
- else {
- tex0 = ctx->Current.Attrib[VERT_ATTRIB_TEX0];
- }
+ /* make sure everything's up to date */
+ st_validate_state(ctx->st);
- update_rasterpos(ctx, pos, color0, color1, fog, tex0);
- }
+ /* This will get set only if rastpos_point(), above, gets called */
+ ctx->Current.RasterPosValid = GL_FALSE;
- /* free vertex feedback buffer */
- pipe->winsys->buffer_unmap(pipe->winsys, fb_buf.buffer);
- pipe->winsys->buffer_reference(pipe->winsys, &fb_buf.buffer, NULL);
+ /* All vertex attribs but position were previously initialized above.
+ * Just plug in position pointer now.
+ */
+ rs->array[0].Ptr = (GLubyte *) v;
- /* restore pipe state */
- if (pipe->set_feedback_state)
- pipe->set_feedback_state(pipe, &st->state.feedback);
+ /* draw the point */
+ st_feedback_draw_vbo(ctx, rs->arrays, &rs->prim, 1, NULL, 0, 1);
}
+
void st_init_rasterpos_functions(struct dd_function_table *functions)
{
functions->RasterPos = st_RasterPos;