Merge branch 'mesa_7_5_branch'
[mesa.git] / src / mesa / state_tracker / st_cb_rasterpos.c
index 13580e400bd8806d1428626ddaac388e20d7ba0f..3bcccd0df46dc16da818a28e55f2317e04d2cbf2 100644 (file)
  * 
  **************************************************************************/
 
- /*
-  * 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/macros.h"
+#include "main/feedback.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 "draw/draw_context.h"
+#include "draw/draw_pipe.h"
 #include "shader/prog_instruction.h"
-#include "vf/vf.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_flush( struct draw_stage *stage, unsigned flags )
 {
-   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_reset_stipple_counter( 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_tri( struct draw_stage *stage, struct prim_header *prim )
 {
-   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;
-   }
+   /* should never get here */
+   assert(0);
 }
 
+static void
+rastpos_line( 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_destroy(struct draw_stage *stage)
 {
-   if (v[2] > v[3] || v[2] < -v[3] ) {
-      return 0;
-   }
-   else {
-      return 1;
-   }
+   _mesa_free(stage);
 }
 
 
 /**
- * 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 != ~0U)
+      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 *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;
+   struct rastpos_stage *rs = rastpos_stage(stage);
+   GLcontext *ctx = rs->ctx;
+   struct st_context *st = ctx->st;
+   const GLfloat height = (GLfloat) 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];
+   if (st_fb_orientation(ctx->DrawBuffer) == Y_0_TOP)
+      ctx->Current.RasterPos[1] = height - pos[1]; /* invert Y */
+   else
+      ctx->Current.RasterPos[1] = pos[1];
+   ctx->Current.RasterPos[2] = pos[2];
+   ctx->Current.RasterPos[3] = pos[3];
+
+   /* update other raster attribs */
+   update_attrib(ctx, outputMapping, prim->v[0],
+                 ctx->Current.RasterColor,
+                 VERT_RESULT_COL0, VERT_ATTRIB_COLOR0);
+
+   update_attrib(ctx, outputMapping, prim->v[0],
+                 ctx->Current.RasterSecondaryColor,
+                 VERT_RESULT_COL1, VERT_ATTRIB_COLOR1);
+
+   for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) {
+      update_attrib(ctx, outputMapping, prim->v[0],
+                    ctx->Current.RasterTexCoords[i],
+                    VERT_RESULT_TEX0 + i, VERT_ATTRIB_TEX0 + i);
    }
 
-   /* clip to user clipping planes */
-   if (ctx->Transform.ClipPlanesEnabled && !userclip_point(ctx, clipPos)) {
-      ctx->Current.RasterPosValid = GL_FALSE;
-      return;
+   if (ctx->RenderMode == GL_SELECT) {
+      _mesa_update_hitflag( ctx, ctx->Current.RasterPos[2] );
    }
+}
 
 
-   /*
-    * 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 (ctx->Fog.FogCoordinateSource == GL_FOG_COORDINATE_EXT)
-      ctx->Current.RasterDistance = ctx->Current.Attrib[VERT_ATTRIB_FOG][0];
-   else {
-#if 0
-      /* XXX we don't have an eye coord! */
-      ctx->Current.RasterDistance =
-         SQRTF( eye[0]*eye[0] + eye[1]*eye[1] + eye[2]*eye[2] );
-#endif
+/**
+ * Create rasterpos "drawing" stage.
+ */
+static struct rastpos_stage *
+new_draw_rastpos_stage(GLcontext *ctx, struct draw_context *draw)
+{
+   struct rastpos_stage *rs = ST_CALLOC_STRUCT(rastpos_stage);
+   GLuint i;
+
+   rs->stage.draw = draw;
+   rs->stage.next = NULL;
+   rs->stage.point = rastpos_point;
+   rs->stage.line = rastpos_line;
+   rs->stage.tri = rastpos_tri;
+   rs->stage.flush = rastpos_flush;
+   rs->stage.destroy = rastpos_destroy;
+   rs->stage.reset_stipple_counter = rastpos_reset_stipple_counter;
+   rs->stage.destroy = rastpos_destroy;
+   rs->ctx = ctx;
+
+   for (i = 0; i < Elements(rs->array); i++) {
+      rs->array[i].Size = 4;
+      rs->array[i].Type = GL_FLOAT;
+      rs->array[i].Format = GL_RGBA;
+      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];
    }
 
-   /* 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);
-   }
+   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;
 
-   ctx->Current.RasterPosValid = GL_TRUE;
+   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);
-      /* 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 */
-      if (pipe->set_feedback_buffer)
-         pipe->set_feedback_buffer(pipe, 0, &fb_buf);
+   else {
+      /* create rastpos draw stage */
+      rs = new_draw_rastpos_stage(ctx, draw);
+      st->rastpos_stage = &rs->stage;
    }
 
+   /* plug our rastpos stage into the draw module */
+   draw_set_rasterize_stage(st->draw, st->rastpos_stage);
 
-   /* 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, *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];
-      }
-
-      if (outputMapping[VERT_RESULT_COL1] != ~0) {
-         color1 = buf;
-         buf += 4;
-      }
-      else {
-         color1 = ctx->Current.Attrib[VERT_ATTRIB_COLOR1];
-      }
-
-      if (outputMapping[VERT_RESULT_TEX0] != ~0) {
-         tex0 = buf;
-         buf += 4;
-      }
-      else {
-         tex0 = ctx->Current.Attrib[VERT_ATTRIB_TEX0];
-      }
-
-      update_rasterpos(ctx, pos, color0, color1, tex0);
-   }
+   /* make sure everything's up to date */
+   st_validate_state(ctx->st);
+
+   /* 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;