draw/draw_pipe_vbuf.c \
draw/draw_pipe_wide_line.c \
draw/draw_pipe_wide_point.c \
+ draw/draw_prim_assembler.c \
draw/draw_pt.c \
draw/draw_pt_emit.c \
draw/draw_pt_fetch.c \
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2013 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * 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 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.
+ *
+ **************************************************************************/
+
+#include "draw_prim_assembler.h"
+
+#include "util/u_debug.h"
+#include "util/u_memory.h"
+#include "util/u_prim.h"
+
+#include "pipe/p_defines.h"
+
+struct draw_assembler
+{
+ struct draw_context *draw;
+
+ struct draw_prim_info *output_prims;
+ struct draw_vertex_info *output_verts;
+
+ const struct draw_prim_info *input_prims;
+ const struct draw_vertex_info *input_verts;
+};
+
+boolean
+draw_prim_assembler_is_required(const struct draw_context *draw,
+ const struct draw_prim_info *prim_info,
+ const struct draw_vertex_info *vert_info)
+{
+ switch (prim_info->prim) {
+ case PIPE_PRIM_LINES_ADJACENCY:
+ case PIPE_PRIM_LINE_STRIP_ADJACENCY:
+ case PIPE_PRIM_TRIANGLES_ADJACENCY:
+ case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+/*
+ * Copy the vertex header along with its data from the current
+ * vertex buffer into a buffer holding vertices arranged
+ * into decomposed primitives (i.e. buffer without the
+ * adjacency vertices)
+ */
+static void
+copy_verts(struct draw_assembler *asmblr,
+ unsigned *indices, unsigned num_indices)
+{
+ unsigned i;
+
+ char *output = (char*)asmblr->output_verts->verts;
+ const char *input = (const char*)asmblr->input_verts->verts;
+
+ for (i = 0; i < num_indices; ++i) {
+ unsigned idx = indices[i];
+ unsigned output_offset =
+ asmblr->output_verts->count * asmblr->output_verts->stride;
+ unsigned input_offset = asmblr->input_verts->stride * idx;
+ memcpy(output + output_offset, input + input_offset,
+ asmblr->input_verts->vertex_size);
+ asmblr->output_verts->count += 1;
+ }
+}
+
+static void
+prim_point(struct draw_assembler *asmblr,
+ unsigned idx)
+{
+ unsigned indices[1];
+
+ indices[0] = idx;
+
+ copy_verts(asmblr, indices, 1);
+}
+
+static void
+prim_line(struct draw_assembler *asmblr,
+ unsigned i0, unsigned i1)
+{
+ unsigned indices[2];
+
+ indices[0] = i0;
+ indices[1] = i1;
+
+ copy_verts(asmblr, indices, 2);
+}
+
+static void
+prim_line_adj(struct draw_assembler *asmblr,
+ unsigned i0, unsigned i1, unsigned i2, unsigned i3)
+{
+ unsigned indices[2];
+
+ indices[0] = i1;
+ indices[1] = i2;
+
+ copy_verts(asmblr, indices, 2);
+}
+
+static void
+prim_tri(struct draw_assembler *asmblr,
+ unsigned i0, unsigned i1, unsigned i2)
+{
+ unsigned indices[3];
+
+ indices[0] = i0;
+ indices[1] = i1;
+ indices[2] = i2;
+
+ copy_verts(asmblr, indices, 3);
+}
+
+static void
+prim_tri_adj(struct draw_assembler *asmblr,
+ unsigned i0, unsigned i1, unsigned i2,
+ unsigned i3, unsigned i4, unsigned i5)
+{
+ unsigned indices[3];
+
+ indices[0] = i0;
+ indices[1] = i2;
+ indices[2] = i4;
+
+ copy_verts(asmblr, indices, 3);
+}
+
+
+
+#define FUNC assembler_run_linear
+#define GET_ELT(idx) (start + (idx))
+#include "draw_prim_assembler_tmp.h"
+
+#define FUNC assembler_run_elts
+#define LOCAL_VARS const ushort *elts = input_prims->elts;
+#define GET_ELT(idx) (elts[start + (idx)])
+#include "draw_prim_assembler_tmp.h"
+
+
+
+/*
+ * Primitive assembler breaks up adjacency primitives and assembles
+ * the base primitives they represent, e.g. vertices forming
+ * PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY
+ * become vertices forming PIPE_PRIM_TRIANGLES
+ * This is needed because specification says that the adjacency
+ * primitives are only visible in the geometry shader so we need
+ * to get rid of them so that the rest of the pipeline can
+ * process the inputs.
+ */
+void
+draw_prim_assembler_run(struct draw_context *draw,
+ const struct draw_prim_info *input_prims,
+ const struct draw_vertex_info *input_verts,
+ struct draw_prim_info *output_prims,
+ struct draw_vertex_info *output_verts)
+{
+ struct draw_assembler asmblr;
+ unsigned start, i;
+ unsigned assembled_prim = u_assembled_primitive(input_prims->prim);
+ unsigned max_primitives = u_decomposed_prims_for_vertices(
+ input_prims->prim, input_prims->count);
+ unsigned max_verts = u_vertices_per_prim(assembled_prim) * max_primitives;
+
+ asmblr.draw = draw;
+ asmblr.output_prims = output_prims;
+ asmblr.output_verts = output_verts;
+ asmblr.input_prims = input_prims;
+ asmblr.input_verts = input_verts;
+
+ output_prims->linear = TRUE;
+ output_prims->elts = NULL;
+ output_prims->start = 0;
+ output_prims->prim = u_assembled_primitive(input_prims->prim);
+ output_prims->flags = 0x0;
+ output_prims->primitive_lengths = MALLOC(sizeof(unsigned));
+ output_prims->primitive_lengths[0] = 0;
+ output_prims->primitive_count = 1;
+
+ output_verts->vertex_size = input_verts->vertex_size;
+ output_verts->stride = input_verts->stride;
+ output_verts->verts = (struct vertex_header*)MALLOC(
+ input_verts->vertex_size * max_verts);
+ output_verts->count = 0;
+
+
+ for (start = i = 0; i < input_prims->primitive_count;
+ start += input_prims->primitive_lengths[i], i++)
+ {
+ unsigned count = input_prims->primitive_lengths[i];
+ if (input_prims->linear) {
+ assembler_run_linear(&asmblr, input_prims, input_verts,
+ start, count);
+ } else {
+ assembler_run_elts(&asmblr, input_prims, input_verts,
+ start, count);
+ }
+ }
+
+ output_prims->primitive_lengths[0] = output_verts->count;
+ output_prims->count = output_verts->count;
+}
--- /dev/null
+/**************************************************************************
+ *
+ * Copyright 2013 VMware, Inc.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sub license, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial portions
+ * of the Software.
+ *
+ * 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 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.
+ *
+ **************************************************************************/
+
+/*
+ * Input assembler needs to be able to decompose adjacency primitives
+ * into something that can be understood by the rest of the pipeline.
+ * The specs say that the adjacency primitives are *only* visible
+ * in the geometry shader, for everything else they need to be
+ * decomposed. Which in most of the cases is not an issue, because the
+ * geometry shader always decomposes them for us, but without geometry
+ * shader we were passing unchanged adjacency primitives to the
+ * rest of the pipeline and causing crashes everywhere.
+ * If geometry shader is missing and the input primitive is one of
+ * the adjacency primitives we use the code from this file to
+ * decompose them into something that the rest of the pipeline can
+ * understand.
+ *
+ */
+
+#ifndef DRAW_PRIM_ASSEMBLER_H
+#define DRAW_PRIM_ASSEMBLER_H
+
+#include "draw/draw_private.h"
+
+boolean
+draw_prim_assembler_is_required(const struct draw_context *draw,
+ const struct draw_prim_info *prim_info,
+ const struct draw_vertex_info *vert_info);
+
+void
+draw_prim_assembler_run(struct draw_context *draw,
+ const struct draw_prim_info *in_prim_info,
+ const struct draw_vertex_info *in_vert_info,
+ struct draw_prim_info *out_prim_info,
+ struct draw_vertex_info *out_vert_info);
+
+
+#endif
--- /dev/null
+#define FUNC_VARS \
+ struct draw_assembler *asmblr, \
+ const struct draw_prim_info *input_prims, \
+ const struct draw_vertex_info *input_verts, \
+ unsigned start, \
+ unsigned count
+
+#define FUNC_ENTER \
+ /* declare more local vars */ \
+ const unsigned prim = input_prims->prim; \
+ const unsigned prim_flags = input_prims->flags; \
+ const boolean quads_flatshade_last = FALSE; \
+ const boolean last_vertex_last = !asmblr->draw->rasterizer->flatshade_first; \
+ switch (prim) { \
+ case PIPE_PRIM_QUADS: \
+ case PIPE_PRIM_QUAD_STRIP: \
+ case PIPE_PRIM_POLYGON: \
+ debug_assert(!"unexpected primitive type in prim assembler"); \
+ return; \
+ default: \
+ break; \
+ } \
+
+
+#define POINT(i0) prim_point(asmblr, i0)
+#define LINE(flags, i0, i1) prim_line(asmblr, i0, i1)
+#define TRIANGLE(flags, i0, i1, i2) prim_tri(asmblr, i0, i1, i2)
+#define LINE_ADJ(flags, i0, i1, i2, i3) prim_line_adj(asmblr, i0, i1, i2, i3)
+#define TRIANGLE_ADJ(flags,i0,i1,i2,i3,i4,i5) prim_tri_adj(asmblr,i0,i1,i2,i3,i4,i5)
+
+#include "draw_decompose_tmp.h"
#include "draw/draw_context.h"
#include "draw/draw_vbuf.h"
#include "draw/draw_vertex.h"
+#include "draw/draw_prim_assembler.h"
#include "draw/draw_pt.h"
#include "draw/draw_vs.h"
#include "draw/draw_gs.h"
unsigned i;
unsigned instance_id_index = ~0;
- unsigned gs_out_prim = (gs ? gs->output_primitive : prim);
+ const unsigned gs_out_prim = (gs ? gs->output_primitive :
+ u_assembled_primitive(prim));
/* Add one to num_outputs because the pipeline occasionally tags on
* an additional texcoord, eg for AA lines.
static void fetch_pipeline_generic( struct draw_pt_middle_end *middle,
const struct draw_fetch_info *fetch_info,
- const struct draw_prim_info *prim_info )
+ const struct draw_prim_info *in_prim_info )
{
struct fetch_pipeline_middle_end *fpme = (struct fetch_pipeline_middle_end *)middle;
struct draw_context *draw = fpme->draw;
struct draw_vertex_info vs_vert_info;
struct draw_vertex_info gs_vert_info;
struct draw_vertex_info *vert_info;
+ struct draw_prim_info ia_prim_info;
+ struct draw_vertex_info ia_vert_info;
+ const struct draw_prim_info *prim_info = in_prim_info;
+ boolean free_prim_info = FALSE;
unsigned opt = fpme->opt;
fetched_vert_info.count = fetch_info->count;
FREE(vert_info->verts);
vert_info = &gs_vert_info;
prim_info = &gs_prim_info;
+ } else {
+ if (draw_prim_assembler_is_required(draw, prim_info, vert_info)) {
+ draw_prim_assembler_run(draw, prim_info, vert_info,
+ &ia_prim_info, &ia_vert_info);
+
+ if (ia_vert_info.count) {
+ FREE(vert_info->verts);
+ vert_info = &ia_vert_info;
+ prim_info = &ia_prim_info;
+ free_prim_info = TRUE;
+ }
+ }
}
}
}
FREE(vert_info->verts);
+ if (free_prim_info) {
+ FREE(prim_info->primitive_lengths);
+ }
}
static void fetch_pipeline_run( struct draw_pt_middle_end *middle,
#include "draw/draw_vbuf.h"
#include "draw/draw_vertex.h"
#include "draw/draw_pt.h"
+#include "draw/draw_prim_assembler.h"
#include "draw/draw_vs.h"
#include "draw/draw_llvm.h"
#include "gallivm/lp_bld_init.h"
struct draw_context *draw = fpme->draw;
struct draw_vertex_shader *vs = draw->vs.vertex_shader;
struct draw_geometry_shader *gs = draw->gs.geometry_shader;
- const unsigned out_prim = gs ? gs->output_primitive : in_prim;
+ const unsigned out_prim = gs ? gs->output_primitive :
+ u_assembled_primitive(in_prim);
/* Add one to num_outputs because the pipeline occasionally tags on
* an additional texcoord, eg for AA lines.
static void
llvm_pipeline_generic( struct draw_pt_middle_end *middle,
const struct draw_fetch_info *fetch_info,
- const struct draw_prim_info *prim_info )
+ const struct draw_prim_info *in_prim_info )
{
struct llvm_middle_end *fpme = (struct llvm_middle_end *)middle;
struct draw_context *draw = fpme->draw;
struct draw_vertex_info llvm_vert_info;
struct draw_vertex_info gs_vert_info;
struct draw_vertex_info *vert_info;
+ struct draw_prim_info ia_prim_info;
+ struct draw_vertex_info ia_vert_info;
+ const struct draw_prim_info *prim_info = in_prim_info;
+ boolean free_prim_info = FALSE;
unsigned opt = fpme->opt;
unsigned clipped = 0;
FREE(vert_info->verts);
vert_info = &gs_vert_info;
prim_info = &gs_prim_info;
+ } else {
+ if (draw_prim_assembler_is_required(draw, prim_info, vert_info)) {
+ draw_prim_assembler_run(draw, prim_info, vert_info,
+ &ia_prim_info, &ia_vert_info);
+
+ if (ia_vert_info.count) {
+ FREE(vert_info->verts);
+ vert_info = &ia_vert_info;
+ prim_info = &ia_prim_info;
+ free_prim_info = TRUE;
+ }
+ }
}
/* stream output needs to be done before clipping */
}
}
FREE(vert_info->verts);
+ if (free_prim_info) {
+ FREE(prim_info->primitive_lengths);
+ }
}
}
}
+static INLINE unsigned
+u_assembled_primitive(unsigned prim)
+{
+ switch (prim) {
+ case PIPE_PRIM_LINES_ADJACENCY:
+ return PIPE_PRIM_LINES;
+ case PIPE_PRIM_LINE_STRIP_ADJACENCY:
+ return PIPE_PRIM_LINES;
+ case PIPE_PRIM_TRIANGLES_ADJACENCY:
+ return PIPE_PRIM_TRIANGLES;
+ case PIPE_PRIM_TRIANGLE_STRIP_ADJACENCY:
+ return PIPE_PRIM_TRIANGLES;
+ default:
+ return prim;
+ }
+
+ return prim;
+}
+
+
+
const char *u_prim_name( unsigned pipe_prim );
#endif