void
draw_set_so_state(struct draw_context *draw,
- struct pipe_stream_output_state *state)
+ struct pipe_stream_output_info *state)
{
memcpy(&draw->so.state,
state,
- sizeof(struct pipe_stream_output_state));
+ sizeof(struct pipe_stream_output_info));
}
void
unsigned num_buffers);
void
draw_set_so_state(struct draw_context *draw,
- struct pipe_stream_output_state *state);
+ struct pipe_stream_output_info *state);
/***********************************************************************
/** Stream output (vertex feedback) state */
struct {
- struct pipe_stream_output_state state;
+ struct pipe_stream_output_info state;
void *buffers[PIPE_MAX_SO_BUFFERS];
uint num_buffers;
} so;
unsigned input_vertex_stride = so->input_vertex_stride;
struct draw_context *draw = so->draw;
const float (*input_ptr)[4];
- const struct pipe_stream_output_state *state =
+ const struct pipe_stream_output_info *state =
&draw->so.state;
float **buffer = 0;
input = (const float (*)[4])(
(const char *)input_ptr + (indices[i] * input_vertex_stride));
for (slot = 0; slot < state->num_outputs; ++slot) {
- unsigned idx = state->register_index[slot];
- unsigned writemask = state->register_mask[slot];
+ unsigned idx = state->output[slot].register_index;
+ unsigned writemask = state->output[slot].register_mask;
unsigned written_compos = 0;
unsigned compo;
- buffer = (float**)&so->buffers[state->output_buffer[slot]];
+ buffer = (float**)&so->buffers[state->output[slot].output_buffer];
/*debug_printf("\tSlot = %d, vs_slot = %d, idx = %d:\n",
slot, vs_slot, idx);*/
}
emit->single_buffer = TRUE;
for (i = 0; i < draw->so.state.num_outputs; ++i) {
- if (draw->so.state.output_buffer[i] != 0)
+ if (draw->so.state.output[i].output_buffer != 0)
emit->single_buffer = FALSE;
}
}
state.tokens = tokens;
+ memset(&state.stream_output, 0, sizeof(state.stream_output));
if (isvs)
return pipe->create_vs_state(pipe, &state);
state.tokens = ureg_finalize(ureg);
if(!state.tokens)
return NULL;
+ memset(&state.stream_output, 0, sizeof(state.stream_output));
if (ureg->processor == TGSI_PROCESSOR_VERTEX)
return pipe->create_vs_state( pipe, &state );
util_dump_shader_state(FILE *stream, const struct pipe_shader_state *state)
{
char str[8192];
+ unsigned i;
if(!state) {
util_dump_null(stream);
util_dump_string(stream, str);
util_dump_member_end(stream);
+ util_dump_member_begin(stream, "stream_output");
+ util_dump_struct_begin(stream, "pipe_stream_output_info");
+ util_dump_member(stream, uint, &state->stream_output, num_outputs);
+ util_dump_member(stream, uint, &state->stream_output, stride);
+ util_dump_array_begin(stream);
+ for(i = 0; i < state->stream_output.num_outputs; ++i) {
+ util_dump_elem_begin(stream);
+ util_dump_struct_begin(stream, ""); /* anonymous */
+ util_dump_member(stream, uint, &state->stream_output.output[i], register_index);
+ util_dump_member(stream, uint, &state->stream_output.output[i], register_mask);
+ util_dump_member(stream, uint, &state->stream_output.output[i], output_buffer);
+ util_dump_struct_end(stream);
+ util_dump_elem_end(stream);
+ }
+ util_dump_array_end(stream);
+ util_dump_struct_end(stream);
+ util_dump_member_end(stream);
+
util_dump_struct_end(stream);
}
* ``set_index_buffer``
-* ``set_stream_output_buffers``
-
Non-CSO State
^^^^^^^^^^^^^
* ``surface_destroy`` destroys a surface and releases its reference to the
associated resource.
+Stream output targets
+^^^^^^^^^^^^^^^^^^^^^
+
+Stream output, also known as transform feedback, allows writing the primitives
+produced by the vertex pipeline to buffers. This is done after the geometry
+shader or vertex shader if no geometry shader is present.
+
+The stream output targets are views into buffer resources which can be bound
+as stream outputs and specify a memory range where it's valid to write
+primitives. The pipe driver must implement memory protection such that any
+primitives written outside of the specified memory range are discarded.
+
+Two stream output targets can use the same resource at the same time, but
+with a disjoint memory range.
+
+Additionally, the stream output target internally maintains the offset
+into the buffer which is incremented everytime something is written to it.
+The internal offset is equal to how much data has already been written.
+It can be stored in device memory and the CPU actually doesn't have to query
+it.
+
+The stream output target can be used in a draw command to provide
+the vertex count. The vertex count is derived from the internal offset
+discussed above.
+
+* ``create_stream_output_target`` create a new target.
+
+* ``stream_output_target_destroy`` destroys a target. Users of this should
+ use pipe_so_target_reference instead.
+
+* ``set_stream_output_targets`` binds stream output targets. The parameter
+ append_bitmask is a bitmask, where the i-th bit specifies whether new
+ primitives should be appended to the i-th buffer (writing starts at
+ the internal offset), or whether writing should start at the beginning
+ (the internal offset is effectively set to 0).
+
+NOTE: The currently-bound vertex or geometry shader must be compiled with
+the properly-filled-in structure pipe_stream_output_info describing which
+outputs should be written to buffers and how. The structure is part of
+pipe_shader_state.
+
Clearing
^^^^^^^^
for a driver to batch multiple blits with the same source and
destination.
-
-Stream Output
-^^^^^^^^^^^^^
-
-Stream output, also known as transform feedback allows writing the results of the
-vertex pipeline (after the geometry shader or vertex shader if no geometry shader
-is present) to be written to a buffer created with a ``PIPE_BIND_STREAM_OUTPUT``
-flag.
-
-First a stream output state needs to be created with the
-``create_stream_output_state`` call. It specific the details of what's being written,
-to which buffer and with what kind of a writemask.
-
-Then target buffers needs to be set with the call to ``set_stream_output_buffers``
-which sets the buffers and the offsets from the start of those buffer to where
-the data will be written to.
-
-
Transfers
^^^^^^^^^
from color blend equations, in :ref:`Blend` state.
* ``PIPE_CAP_SM3``: Whether the vertex shader and fragment shader support equivalent
opcodes to the Shader Model 3 specification. XXX oh god this is horrible
+* ``PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS``: The maximum number of stream buffers.
+* ``PIPE_CAP_PRIMITIVE_RESTART``: Whether primitive restart is supported.
* ``PIPE_CAP_MAX_COMBINED_SAMPLERS``: The total number of samplers accessible from
the vertex and fragment shader, inclusive.
* ``PIPE_CAP_INDEP_BLEND_ENABLE``: Whether per-rendertarget blend enabling and channel
* ``PIPE_BIND_CONSTANT_BUFFER``: A buffer of shader constants.
* ``PIPE_BIND_TRANSFER_WRITE``: A transfer object which will be written to.
* ``PIPE_BIND_TRANSFER_READ``: A transfer object which will be read from.
+* ``PIPE_BIND_STREAM_OUTPUT``: A stream output buffer.
* ``PIPE_BIND_CUSTOM``:
* ``PIPE_BIND_SCANOUT``: A front color buffer or scanout buffer.
* ``PIPE_BIND_SHARED``: A sharable buffer that can be given to another
};
struct lp_so_state {
- struct pipe_stream_output_state base;
+ struct pipe_stream_output_info base;
};
static void *
llvmpipe_create_stream_output_state(struct pipe_context *pipe,
- const struct pipe_stream_output_state *templ)
+ const struct pipe_stream_output_info *templ)
{
struct lp_so_state *so;
so = (struct lp_so_state *) CALLOC_STRUCT(lp_so_state);
case PIPE_CAP_TIMER_QUERY:
case PIPE_CAP_OCCLUSION_QUERY:
return 1;
- case PIPE_CAP_STREAM_OUTPUT:
+ case PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS:
return 0;
case PIPE_CAP_BLEND_EQUATION_SEPARATE:
case PIPE_CAP_INDEP_BLEND_ENABLE:
case PIPE_CAP_TIMER_QUERY:
case PIPE_CAP_OCCLUSION_QUERY:
return 1;
- case PIPE_CAP_STREAM_OUTPUT:
+ case PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS:
return 0;
case PIPE_CAP_BLEND_EQUATION_SEPARATE:
case PIPE_CAP_INDEP_BLEND_ENABLE:
static void *
nvc0_tfb_state_create(struct pipe_context *pipe,
- const struct pipe_stream_output_state *pso)
+ const struct pipe_stream_output_info *pso)
{
struct nvc0_transform_feedback_state *so;
int n = 0;
for (b = 0; b < 4; ++b) {
for (i = 0; i < pso->num_outputs; ++i) {
- if (pso->output_buffer[i] != b)
+ if (pso->output[i].output_buffer != b)
continue;
for (c = 0; c < 4; ++c) {
- if (!(pso->register_mask[i] & (1 << c)))
+ if (!(pso->output[i].register_mask & (1 << c)))
continue;
so->varying_count[b]++;
- so->varying_index[n++] = (pso->register_index[i] << 2) | c;
+ so->varying_index[n++] = (pso->output[i].register_index << 2) | c;
}
}
so->stride[b] = so->varying_count[b] * 4;
case PIPE_CAP_SCALED_RESOLVE:
case PIPE_CAP_MIN_TEXEL_OFFSET:
case PIPE_CAP_MAX_TEXEL_OFFSET:
- case PIPE_CAP_STREAM_OUTPUT:
+ case PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS:
return 0;
/* SWTCL-only features. */
return family >= CHIP_CEDAR ? 1 : 0;
/* Unsupported features. */
- case PIPE_CAP_STREAM_OUTPUT:
+ case PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS:
+ case PIPE_CAP_MAX_STREAM_OUTPUT_SEPARATE_ATTRIBS:
+ case PIPE_CAP_MAX_STREAM_OUTPUT_SEPARATE_COMPONENTS:
+ case PIPE_CAP_MAX_STREAM_OUTPUT_INTERLEAVED_COMPONENTS:
+ case PIPE_CAP_STREAM_OUTPUT_PAUSE_RESUME:
case PIPE_CAP_TGSI_INSTANCEID:
case PIPE_CAP_TGSI_FS_COORD_ORIGIN_LOWER_LEFT:
case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER:
case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_HALF_INTEGER:
case PIPE_CAP_TGSI_FS_COORD_PIXEL_CENTER_INTEGER:
return 1;
- case PIPE_CAP_STREAM_OUTPUT:
+ case PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS:
return 0;
case PIPE_CAP_PRIMITIVE_RESTART:
return 1;
};
struct sp_so_state {
- struct pipe_stream_output_state base;
+ struct pipe_stream_output_info base;
};
static void *
softpipe_create_stream_output_state(struct pipe_context *pipe,
- const struct pipe_stream_output_state *templ)
+ const struct pipe_stream_output_info *templ)
{
struct sp_so_state *so;
so = (struct sp_so_state *) CALLOC_STRUCT(sp_so_state);
if (so) {
so->base.num_outputs = templ->num_outputs;
so->base.stride = templ->stride;
- memcpy(so->base.output_buffer,
- templ->output_buffer,
- sizeof(int) * templ->num_outputs);
- memcpy(so->base.register_index,
- templ->register_index,
- sizeof(int) * templ->num_outputs);
- memcpy(so->base.register_mask,
- templ->register_mask,
- sizeof(ubyte) * templ->num_outputs);
+ memcpy(so->base.output, templ->output,
+ templ->num_outputs * sizeof(templ->output[0]));
}
return so;
}
void trace_dump_shader_state(const struct pipe_shader_state *state)
{
static char str[8192];
+ unsigned i;
if (!trace_dumping_enabled_locked())
return;
trace_dump_string(str);
trace_dump_member_end();
+ trace_dump_member_begin("stream_output");
+ trace_dump_struct_begin("pipe_stream_output_info");
+ trace_dump_member(uint, &state->stream_output, num_outputs);
+ trace_dump_member(uint, &state->stream_output, stride);
+ trace_dump_array_begin();
+ for(i = 0; i < state->stream_output.num_outputs; ++i) {
+ trace_dump_elem_begin();
+ trace_dump_struct_begin(""); /* anonymous */
+ trace_dump_member(uint, &state->stream_output.output[i], register_index);
+ trace_dump_member(uint, &state->stream_output.output[i], register_mask);
+ trace_dump_member(uint, &state->stream_output.output[i], output_buffer);
+ trace_dump_struct_end();
+ trace_dump_elem_end();
+ }
+ trace_dump_array_end();
+ trace_dump_struct_end();
+ trace_dump_member_end();
+
trace_dump_struct_end();
}
trace_dump_member(uint, state, min_index);
trace_dump_member(uint, state, max_index);
+ trace_dump_member(ptr, state, count_from_stream_output);
+
trace_dump_struct_end();
}
struct pipe_scissor_state;
struct pipe_shader_state;
struct pipe_stencil_ref;
-struct pipe_stream_output_state;
+struct pipe_stream_output_target;
struct pipe_surface;
struct pipe_vertex_buffer;
struct pipe_vertex_element;
/*@{*/
void (*draw_vbo)( struct pipe_context *pipe,
const struct pipe_draw_info *info );
-
- /**
- * Draw the stream output buffer at index 0
- */
- void (*draw_stream_output)( struct pipe_context *pipe, unsigned mode );
/*@}*/
/**
void (*bind_vertex_elements_state)(struct pipe_context *, void *);
void (*delete_vertex_elements_state)(struct pipe_context *, void *);
- void * (*create_stream_output_state)(struct pipe_context *,
- const struct pipe_stream_output_state *);
- void (*bind_stream_output_state)(struct pipe_context *, void *);
- void (*delete_stream_output_state)(struct pipe_context*, void*);
-
/*@}*/
/**
void (*set_index_buffer)( struct pipe_context *pipe,
const struct pipe_index_buffer * );
- void (*set_stream_output_buffers)(struct pipe_context *,
- struct pipe_resource **buffers,
- int *offsets, /*array of offsets
- from the start of each
- of the buffers */
- int num_buffers);
+ /*@}*/
+
+ /**
+ * Stream output functions.
+ */
+ /*@{*/
+
+ struct pipe_stream_output_target *(*create_stream_output_target)(
+ struct pipe_context *,
+ struct pipe_resource *,
+ unsigned buffer_offset,
+ unsigned buffer_size);
+
+ void (*stream_output_target_destroy)(struct pipe_context *,
+ struct pipe_stream_output_target *);
+
+ void (*set_stream_output_targets)(struct pipe_context *,
+ unsigned num_targets,
+ struct pipe_stream_output_target **targets,
+ unsigned append_bitmask);
/*@}*/
PIPE_CAP_TEXTURE_MIRROR_CLAMP = 25,
PIPE_CAP_BLEND_EQUATION_SEPARATE = 28,
PIPE_CAP_SM3 = 29, /*< Shader Model, supported */
- PIPE_CAP_STREAM_OUTPUT = 30,
+ PIPE_CAP_MAX_STREAM_OUTPUT_BUFFERS = 30,
PIPE_CAP_PRIMITIVE_RESTART = 31,
/** Maximum texture image units accessible from vertex and fragment shaders
* combined */
PIPE_CAP_MAX_TEXEL_OFFSET = 51,
PIPE_CAP_CONDITIONAL_RENDER = 52,
PIPE_CAP_TEXTURE_BARRIER = 53,
- PIPE_CAP_TGSI_CAN_COMPACT_VARYINGS = 54, /* temporary */
- PIPE_CAP_TGSI_CAN_COMPACT_CONSTANTS = 55 /* temporary */
+ PIPE_CAP_MAX_STREAM_OUTPUT_SEPARATE_ATTRIBS = 54,
+ PIPE_CAP_MAX_STREAM_OUTPUT_SEPARATE_COMPONENTS = 55,
+ PIPE_CAP_MAX_STREAM_OUTPUT_INTERLEAVED_COMPONENTS = 56,
+ PIPE_CAP_STREAM_OUTPUT_PAUSE_RESUME = 57,
+ PIPE_CAP_TGSI_CAN_COMPACT_VARYINGS = 58, /* temporary */
+ PIPE_CAP_TGSI_CAN_COMPACT_CONSTANTS = 59 /* temporary */
};
/**
*/
unsigned gl_rasterization_rules:1;
+ /**
+ * When true, rasterization is disabled and no pixels are written.
+ * This only makes sense with the Stream Out functionality.
+ */
+ unsigned rasterizer_discard:1;
+
unsigned line_stipple_factor:8; /**< [1..256] actually */
unsigned line_stipple_pattern:16;
};
+/**
+ * Stream output for vertex transform feedback.
+ */
+struct pipe_stream_output_info
+{
+ unsigned num_outputs;
+ /** stride for an entire vertex, only used if all output_buffers are 0 */
+ unsigned stride;
+ /**
+ * Array of stream outputs, in the order they are to be written in.
+ * Selected components are tightly packed into the output buffer.
+ */
+ struct {
+ unsigned register_index:8; /**< 0 to PIPE_MAX_SHADER_OUTPUTS */
+ unsigned register_mask:4; /**< TGSI_WRITEMASK_x */
+ unsigned output_buffer:4; /**< 0 to PIPE_MAX_SO_BUFFERS */
+ } output[PIPE_MAX_SHADER_OUTPUTS];
+};
+
+
struct pipe_shader_state
{
const struct tgsi_token *tokens;
+ struct pipe_stream_output_info stream_output;
};
/**
- * Stream output for vertex transform feedback.
- */
-struct pipe_stream_output_state
-{
- /** number of the output buffer to insert each element into */
- int output_buffer[PIPE_MAX_SHADER_OUTPUTS];
- /** which register to grab each output from */
- int register_index[PIPE_MAX_SHADER_OUTPUTS];
- /** TGSI_WRITEMASK signifying which components to output */
- ubyte register_mask[PIPE_MAX_SHADER_OUTPUTS];
- /** number of outputs */
- int num_outputs;
- /** stride for an entire vertex, only used if all output_buffers are 0 */
- unsigned stride;
-};
-
-
-/**
* Transfer object. For data transfer to/from a resource.
*/
struct pipe_transfer
/**
+ * A stream output target. The structure specifies the range vertices can
+ * be written to.
+ *
+ * In addition to that, the structure should internally maintain the offset
+ * into the buffer, which should be incremented everytime something is written
+ * (appended) to it. The internal offset is buffer_offset + how many bytes
+ * have been written. The internal offset can be stored on the device
+ * and the CPU actually doesn't have to query it.
+ *
+ * Use PIPE_QUERY_SO_STATISTICS to know how many primitives have
+ * actually been written.
+ */
+struct pipe_stream_output_target
+{
+ struct pipe_reference reference;
+ struct pipe_resource *buffer; /**< buffer into which this is a target view */
+ struct pipe_context *context; /**< context this view belongs to */
+
+ unsigned buffer_offset; /**< offset where data should be written, in bytes */
+ unsigned buffer_size; /**< how much data is allowed to be written */
+};
+
+
+/**
* Information to describe a vertex attribute (position, color, etc)
*/
struct pipe_vertex_element
*/
boolean primitive_restart;
unsigned restart_index;
+
+ /**
+ * Stream output target. If not NULL, it's used to provide the 'count'
+ * parameter based on the number vertices captured by the stream output
+ * stage. (or generally, based on the number of bytes captured)
+ *
+ * Only 'mode', 'start_instance', and 'instance_count' are taken into
+ * account, all the other variables from pipe_draw_info are ignored.
+ *
+ * 'start' is implicitly 0 and 'count' is set as discussed above.
+ * The draw command is non-indexed.
+ *
+ * Note that this only provides the count. The vertex buffers must
+ * be set via set_vertex_buffers manually.
+ */
+ struct pipe_stream_output_target *count_from_stream_output;
};
type == PIPE_SHADER_FRAGMENT);
state.tokens = tokens;
+ memset(&state.stream_output, 0, sizeof(state.stream_output));
shader->type = type;
shader->tokens = tokens;