[Mesa-dev] [PATCH 1/4] gallium: introduce explicit frequency declaration for vertex elements

Luca Barbieri luca at luca-barbieri.com
Mon Aug 16 04:30:05 PDT 2010


Currently constant elements are specified only with a stride 0, while
per-instanced are implicitly indentified by a non-zero instance_divisor.

However, drivers often need to know whether an element is constant
or not when setting up the vertex element CSO instead of when setting
the buffers.

So, we add a new "frequency" member, which is the equivalent of
InputSlotClass in D3D11_INPUT_ELEMENT_DESC, to specify constant elements.

Note that the approach of setting instance_divisor to 0xffffffff doesn't
work in practice, because in Direct3D instance numbers are unsigned
32-bit integers, and are explicitly allowed to wrap around.

This change is compatible with two exceptions:
1. Users who do not zero-initialize pipe_vertex_element must set frequency
   to 0 (or PIPE_ELEMENT_FREQUENCY_PER_VERTEX, which has value 0)
2. Users who set a non-zero instance_divisor must set frequency to
   PIPE_ELEMENT_FREQUENCY_PER_INSTANCE

Drivers don't need any changes, but can often benefit from the additional
information.

Note that it is still allowed to make any type of element constant at
vertex buffer bind time, by setting stride = 0, but drivers are not
supposed to optimize for this case, which may thus be slower (due to
needless computation of the index and repeated fetching of the same value).

Constant elements are a Gallium-only feature not present in Direct3D 11,
mainly intended to support OpenGL.

Note that we could extend instance_divisor to act as a divisor for
per-vertex data too, or introduce the ability to have "instances of
instances", and up in an unlimited hierarchy.

However, no API or hardware appears to support these features, and hence
we refrain from adding them to Gallium.
---
 src/gallium/docs/d3d11ddi.txt                    |    2 +-
 src/gallium/docs/source/context.rst              |   23 ++++++++++++++++++---
 src/gallium/docs/source/cso/velems.rst           |   11 +++++++--
 src/gallium/drivers/r300/r300_render_translate.c |    1 +
 src/gallium/include/pipe/p_defines.h             |    7 ++++++
 src/gallium/include/pipe/p_state.h               |   14 +++++++++---
 src/gallium/state_trackers/python/p_context.i    |    1 +
 src/gallium/tests/graw/tri-instanced.c           |    1 +
 src/mesa/state_tracker/st_cb_drawtex.c           |    1 +
 src/mesa/state_tracker/st_draw_feedback.c        |    1 +
 10 files changed, 50 insertions(+), 12 deletions(-)

diff --git a/src/gallium/docs/d3d11ddi.txt b/src/gallium/docs/d3d11ddi.txt
index f8155c8..b1e315f 100644
--- a/src/gallium/docs/d3d11ddi.txt
+++ b/src/gallium/docs/d3d11ddi.txt
@@ -171,7 +171,7 @@ CreateRenderTargetView -> get_tex_surface
 
 CreateElementLayout -> create_vertex_elements_state
 	! D3D11 allows sparse vertex elements (via InputRegister); in Gallium they must be specified sequentially
-	! D3D11 has an extra flag (InputSlotClass) that is the same as instance_divisor == 0
+	+ Gallium supports specifying that elements are constant in the element layout
 
 CreateGeometryShader -> create_gs_state
 CreateGeometryShaderWithStreamOutput -> create_gs_state + create_stream_output_state
diff --git a/src/gallium/docs/source/context.rst b/src/gallium/docs/source/context.rst
index f241411..101e12c 100644
--- a/src/gallium/docs/source/context.rst
+++ b/src/gallium/docs/source/context.rst
@@ -154,18 +154,33 @@ If there is an index buffer bound, and ``indexed`` field is true, all vertex
 indices will be looked up in the index buffer.  ``min_index``, ``max_index``,
 and ``index_bias`` apply after index lookup.
 
-If a given vertex element has ``instance_divisor`` set to 0, it is said
-it contains per-vertex data and effective vertex attribute address needs
-to be recalculated for every index.
+If a given vertex element has ``frequency`` set to
+PIPE_ELEMENT_FREQUENCY_PER_VERTEX,
+it is said it contains per-vertex data and effective vertex attribute address
+needs to be recalculated for every index.
 
   attribAddr = ``stride`` * index + ``src_offset``
 
-If a given vertex element has ``instance_divisor`` set to non-zero,
+If a given vertex element has ``frequency`` set to
+PIPE_ELEMENT_FREQUENCY_PER_INSTANCE,
 it is said it contains per-instance data and effective vertex attribute
 address needs to recalculated for every ``instance_divisor``-th instance.
 
   attribAddr = ``stride`` * instanceID / ``instance_divisor`` + ``src_offset``
 
+If a given vertex element has ``frequency`` set to
+PIPE_ELEMENT_FREQUENCY_CONSTANT,
+it is said it contains constant data and effective vertex attribute
+address is constant.
+
+  attribAddr = ``src_offset``
+
+Note that both per-vertex and per-instance data can be effectively
+constant if ``stride` is specified as 0, or the instance divisor is greater than
+the highest instance number used, but this is discouraged unless
+necessary, as it will tend to result in lower performance than explicitly
+setting ``frequency`` to PIPE_ELEMENT_FREQUENCY_CONSTANT.
+
 In the above formulas, ``src_offset`` is taken from the given vertex element
 and ``stride`` is taken from a vertex buffer associated with the given
 vertex element.
diff --git a/src/gallium/docs/source/cso/velems.rst b/src/gallium/docs/source/cso/velems.rst
index 978ad4a..52acb0a 100644
--- a/src/gallium/docs/source/cso/velems.rst
+++ b/src/gallium/docs/source/cso/velems.rst
@@ -48,10 +48,15 @@ Members
 src_offset
     The byte offset of the attribute in the buffer given by
     vertex_buffer_index for the first vertex.
+frequency
+    Frequency of the attribute (per-vertex, per-instance or constant).
+    Note that any data may actually be constant if stride = 0, but
+    this may have lower performance */ 
 instance_divisor
-    The instance data rate divisor, used for instancing.
-    0 means this is per-vertex data, n means per-instance data used for
-    n consecutive instances (n > 0).
+    Instance data rate divisor.
+    Must be 0 for per-vertex and constant data.
+    For per-instance data, this must be the nonzero number of consecutive
+    instances using the same data.
 vertex_buffer_index
     The vertex buffer this attribute lives in. Several attributes may
     live in the same vertex buffer.
diff --git a/src/gallium/drivers/r300/r300_render_translate.c b/src/gallium/drivers/r300/r300_render_translate.c
index 0ea11e5..4f511ef 100644
--- a/src/gallium/drivers/r300/r300_render_translate.c
+++ b/src/gallium/drivers/r300/r300_render_translate.c
@@ -157,6 +157,7 @@ void r300_begin_vertex_translate(struct r300_context *r300)
         for (i = 0; i < ve->count; i++) {
             if (vb_translated[ve->velem[i].vertex_buffer_index]) {
                 te = &key.element[tr_elem_index[i]];
+                new_velems[i].frequency = ve->velem[i].frequency;
                 new_velems[i].instance_divisor = ve->velem[i].instance_divisor;
                 new_velems[i].src_format = te->output_format;
                 new_velems[i].src_offset = te->output_offset;
diff --git a/src/gallium/include/pipe/p_defines.h b/src/gallium/include/pipe/p_defines.h
index 00aa207..bfdec3d 100644
--- a/src/gallium/include/pipe/p_defines.h
+++ b/src/gallium/include/pipe/p_defines.h
@@ -518,6 +518,13 @@ struct pipe_query_data_timestamp_disjoint
    boolean  disjoint;
 };
 
+enum pipe_element_frequency
+{
+	PIPE_ELEMENT_FREQUENCY_PER_VERTEX,
+	PIPE_ELEMENT_FREQUENCY_PER_INSTANCE,
+	PIPE_ELEMENT_FREQUENCY_CONSTANT
+};
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/src/gallium/include/pipe/p_state.h b/src/gallium/include/pipe/p_state.h
index 0f1a44c..5b7387b 100644
--- a/src/gallium/include/pipe/p_state.h
+++ b/src/gallium/include/pipe/p_state.h
@@ -397,13 +397,12 @@ struct pipe_transfer
  */
 struct pipe_vertex_buffer
 {
-   unsigned stride;    /**< stride to same attrib in next vertex, in bytes */
+   unsigned stride;    /**< stride to same attrib in next vertex, in bytes (can always be 0, and must be 0 for PIPE_ELEMENT_FREQUENCY_CONSTANT) */
    unsigned max_index;   /**< number of vertices in this buffer */
    unsigned buffer_offset;  /**< offset to start of data in buffer, in bytes */
    struct pipe_resource *buffer;  /**< the actual buffer */
 };
 
-
 /**
  * Information to describe a vertex attribute (position, color, etc)
  */
@@ -412,8 +411,15 @@ struct pipe_vertex_element
    /** Offset of this attribute, in bytes, from the start of the vertex */
    unsigned src_offset;
 
-   /** Instance data rate divisor. 0 means this is per-vertex data,
-    *  n means per-instance data used for n consecutive instances (n > 0).
+   /** Frequency of the attribute (per-vertex, per-instance or constant).
+    * Note that any data may actually be constant if stride = 0, but
+    * this may have lower performance */
+   enum pipe_element_frequency frequency;
+
+   /** Instance data rate divisor.
+    * Must be 0 for per-vertex and constant data.
+    * For per-instance data, this must be the nonzero number of consecutive
+    * instances using the same data.
     */
    unsigned instance_divisor;
 
diff --git a/src/gallium/state_trackers/python/p_context.i b/src/gallium/state_trackers/python/p_context.i
index 40c4603..cd0c235 100644
--- a/src/gallium/state_trackers/python/p_context.i
+++ b/src/gallium/state_trackers/python/p_context.i
@@ -364,6 +364,7 @@ struct st_context {
       /* tell pipe about the vertex attributes */
       for (i = 0; i < num_attribs; i++) {
          velements[i].src_offset = i * 4 * sizeof(float);
+         velements[i].frequency = PIPE_ELEMENT_FREQUENCY_PER_VERTEX;
          velements[i].instance_divisor = 0;
          velements[i].vertex_buffer_index = 0;
          velements[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
diff --git a/src/gallium/tests/graw/tri-instanced.c b/src/gallium/tests/graw/tri-instanced.c
index 8859f74..db5647e 100644
--- a/src/gallium/tests/graw/tri-instanced.c
+++ b/src/gallium/tests/graw/tri-instanced.c
@@ -124,6 +124,7 @@ static void set_vertices( void )
    ve[2].src_offset = 0;
    ve[2].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
    ve[2].vertex_buffer_index = 1;
+   ve[2].frequency = PIPE_ELEMENT_FREQUENCY_PER_INSTANCE;
    ve[2].instance_divisor = 1;
 
    handle = ctx->create_vertex_elements_state(ctx, 3, ve);
diff --git a/src/mesa/state_tracker/st_cb_drawtex.c b/src/mesa/state_tracker/st_cb_drawtex.c
index c99a8d7..b004123 100644
--- a/src/mesa/state_tracker/st_cb_drawtex.c
+++ b/src/mesa/state_tracker/st_cb_drawtex.c
@@ -238,6 +238,7 @@ st_DrawTex(GLcontext *ctx, GLfloat x, GLfloat y, GLfloat z,
 
    for (i = 0; i < numAttribs; i++) {
       velements[i].src_offset = i * 4 * sizeof(float);
+      velements[i].frequency = PIPE_ELEMENT_FREQUENCY_PER_VERTEX;
       velements[i].instance_divisor = 0;
       velements[i].vertex_buffer_index = 0;
       velements[i].src_format = PIPE_FORMAT_R32G32B32A32_FLOAT;
diff --git a/src/mesa/state_tracker/st_draw_feedback.c b/src/mesa/state_tracker/st_draw_feedback.c
index 5cf2666..564732e 100644
--- a/src/mesa/state_tracker/st_draw_feedback.c
+++ b/src/mesa/state_tracker/st_draw_feedback.c
@@ -180,6 +180,7 @@ st_feedback_draw_vbo(GLcontext *ctx,
       /* common-case setup */
       vbuffers[attr].stride = arrays[mesaAttr]->StrideB; /* in bytes */
       vbuffers[attr].max_index = max_index;
+      velements[attr].frequency = PIPE_ELEMENT_FREQUENCY_PER_VERTEX;
       velements[attr].instance_divisor = 0;
       velements[attr].vertex_buffer_index = attr;
       velements[attr].src_format = 
-- 
1.7.0.4



More information about the mesa-dev mailing list