1 /**************************************************************************
3 * Copyright 2007 Tungsten Graphics, Inc., Cedar Park, Texas.
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
35 #include "main/context.h"
36 #include "main/macros.h"
38 #include "pipe/p_defines.h"
39 #include "pipe/p_context.h"
40 #include "pipe/p_winsys.h"
43 #include "sp_context.h"
46 #include "pipe/draw/draw_private.h"
47 #include "pipe/draw/draw_context.h"
48 #include "pipe/draw/draw_prim.h"
50 #include "pipe/tgsi/core/tgsi_exec.h"
51 #include "pipe/tgsi/core/tgsi_build.h"
52 #include "pipe/tgsi/core/tgsi_util.h"
56 #define ALIGN16_DECL(TYPE, NAME, SIZE) TYPE NAME[SIZE] __attribute__(( aligned( 16 ) ))
57 #define ALIGN16_ASSIGN(P) P
59 #define ALIGN16_DECL(TYPE, NAME, SIZE) TYPE NAME[SIZE + 1]
60 #define ALIGN16_ASSIGN(P) align16(P)
65 static INLINE
unsigned
66 compute_clipmask(float cx
, float cy
, float cz
, float cw
)
69 #if defined(macintosh) || defined(__powerpc__)
70 /* on powerpc cliptest is 17% faster in this way. */
71 mask
= (((cw
< cx
) << CLIP_RIGHT_SHIFT
));
72 mask
|= (((cw
< -cx
) << CLIP_LEFT_SHIFT
));
73 mask
|= (((cw
< cy
) << CLIP_TOP_SHIFT
));
74 mask
|= (((cw
< -cy
) << CLIP_BOTTOM_SHIFT
));
75 mask
|= (((cw
< cz
) << CLIP_FAR_SHIFT
));
76 mask
|= (((cw
< -cz
) << CLIP_NEAR_SHIFT
));
77 #else /* !defined(macintosh)) */
79 if (-cx
+ cw
< 0) mask
|= CLIP_RIGHT_BIT
;
80 if ( cx
+ cw
< 0) mask
|= CLIP_LEFT_BIT
;
81 if (-cy
+ cw
< 0) mask
|= CLIP_TOP_BIT
;
82 if ( cy
+ cw
< 0) mask
|= CLIP_BOTTOM_BIT
;
83 if (-cz
+ cw
< 0) mask
|= CLIP_FAR_BIT
;
84 if ( cz
+ cw
< 0) mask
|= CLIP_NEAR_BIT
;
85 #endif /* defined(macintosh) */
92 * Transform vertices with the current vertex program/shader
93 * Up to four vertices can be shaded at a time.
94 * \param vbuffer the input vertex data
95 * \param elts indexes of four input vertices
96 * \param count number of vertices to shade [1..4]
97 * \param vOut array of pointers to four output vertices
100 run_vertex_program(struct draw_context
*draw
,
101 const void *vbuffer
, unsigned elts
[4], unsigned count
,
102 struct vertex_header
*vOut
[])
104 struct softpipe_context
*sp
= softpipe_context(draw
->pipe
);
105 struct tgsi_exec_machine machine
;
108 ALIGN16_DECL(struct tgsi_exec_vector
, inputs
, PIPE_ATTRIB_MAX
);
109 ALIGN16_DECL(struct tgsi_exec_vector
, outputs
, PIPE_ATTRIB_MAX
);
110 const float *scale
= draw
->viewport
.scale
;
111 const float *trans
= draw
->viewport
.translate
;
116 memset( &machine
, 0, sizeof( machine
) );
119 /* init machine state */
120 tgsi_exec_machine_init(
126 /* Consts does not require 16 byte alignment. */
127 machine
.Consts
= sp
->vs
.constants
->constant
;
129 machine
.Inputs
= ALIGN16_ASSIGN(inputs
);
130 machine
.Outputs
= ALIGN16_ASSIGN(outputs
);
132 /* load machine inputs */
133 for (j
= 0; j
< count
; j
++) {
135 for (attr
= 0; attr
< 16; attr
++) {
136 if (sp
->vs
.inputs_read
& (1 << attr
)) {
138 = (const float *) ((const ubyte
*) vbuffer
139 + draw
->vertex_buffer
[attr
].buffer_offset
140 + draw
->vertex_element
[attr
].src_offset
141 + elts
[j
] * draw
->vertex_buffer
[attr
].pitch
);
143 machine
.Inputs
[attr
].xyzw
[0].f
[j
] = p
[0]; /*X*/
144 machine
.Inputs
[attr
].xyzw
[1].f
[j
] = p
[1]; /*Y*/
145 machine
.Inputs
[attr
].xyzw
[2].f
[j
] = p
[2]; /*Z*/
146 machine
.Inputs
[attr
].xyzw
[3].f
[j
] = 1.0; /*W*/
149 printf("Input vertex %d: %f %f %f\n",
150 j
, p
[0], p
[1], p
[2]);
159 for (i
= 0; i
< 4; i
++) {
160 printf(" %d: %f %f %f %f\n", i
,
161 machine
.Consts
[i
][0],
162 machine
.Consts
[i
][1],
163 machine
.Consts
[i
][2],
164 machine
.Consts
[i
][3]);
169 tgsi_exec_machine_run( &machine
);
172 printf("VS result: %f %f %f %f\n",
173 outputs
[0].xyzw
[0].f
[0],
174 outputs
[0].xyzw
[1].f
[0],
175 outputs
[0].xyzw
[2].f
[0],
176 outputs
[0].xyzw
[3].f
[0]);
179 /* store machine results */
180 assert(sp
->vs
.outputs_written
& (1 << VERT_RESULT_HPOS
));
181 for (j
= 0; j
< count
; j
++) {
185 /* Handle attr[0] (position) specially: */
186 x
= vOut
[j
]->clip
[0] = outputs
[0].xyzw
[0].f
[j
];
187 y
= vOut
[j
]->clip
[1] = outputs
[0].xyzw
[1].f
[j
];
188 z
= vOut
[j
]->clip
[2] = outputs
[0].xyzw
[2].f
[j
];
189 w
= vOut
[j
]->clip
[3] = outputs
[0].xyzw
[3].f
[j
];
191 vOut
[j
]->clipmask
= compute_clipmask(x
, y
, z
, w
);
192 vOut
[j
]->edgeflag
= 1;
200 /* Viewport mapping */
201 vOut
[j
]->data
[0][0] = x
* scale
[0] + trans
[0];
202 vOut
[j
]->data
[0][1] = y
* scale
[1] + trans
[1];
203 vOut
[j
]->data
[0][2] = z
* scale
[2] + trans
[2];
204 vOut
[j
]->data
[0][3] = w
;
206 printf("wincoord: %f %f %f\n",
209 vOut
[j
]->data
[0][2]);
212 /* remaining attributes: */
213 /* pack into sequential post-transform attrib slots */
215 for (attr
= 1; attr
< VERT_RESULT_MAX
; attr
++) {
216 if (sp
->vs
.outputs_written
& (1 << attr
)) {
217 assert(slot
< draw
->nr_attrs
- 2);
218 vOut
[j
]->data
[slot
][0] = outputs
[attr
].xyzw
[0].f
[j
];
219 vOut
[j
]->data
[slot
][1] = outputs
[attr
].xyzw
[1].f
[j
];
220 vOut
[j
]->data
[slot
][2] = outputs
[attr
].xyzw
[2].f
[j
];
221 vOut
[j
]->data
[slot
][3] = outputs
[attr
].xyzw
[3].f
[j
];
230 &machine
.Outputs
[1].xyzw
[0].f
[0],
231 sizeof( quad
->outputs
.color
) );
237 * Stand-in for actual vertex program execution
238 * XXX this will probably live in a new file, like "sp_vs.c"
239 * \param draw the drawing context
240 * \param vbuffer the mapped vertex buffer pointer
241 * \param elem which element of the vertex buffer to use as input
242 * \param vOut the output vertex
246 run_vertex_program(struct draw_context
*draw
,
247 const void *vbuffer
, unsigned elem
,
248 struct vertex_header
*vOut
)
250 const float *vIn
, *cIn
;
251 const float *scale
= draw
->viewport
.scale
;
252 const float *trans
= draw
->viewport
.translate
;
253 const void *mapped
= vbuffer
;
255 /* XXX temporary hack: */
256 GET_CURRENT_CONTEXT(ctx
);
257 const float *m
= ctx
->_ModelProjectMatrix
.m
;
259 vIn
= (const float *) ((const ubyte
*) mapped
260 + draw
->vertex_buffer
[0].buffer_offset
261 + draw
->vertex_element
[0].src_offset
262 + elem
* draw
->vertex_buffer
[0].pitch
);
264 cIn
= (const float *) ((const ubyte
*) mapped
265 + draw
->vertex_buffer
[3].buffer_offset
266 + draw
->vertex_element
[3].src_offset
267 + elem
* draw
->vertex_buffer
[3].pitch
);
275 vOut
->clipmask
= 0x0;
278 vOut
->clip
[0] = m
[0] * x
+ m
[4] * y
+ m
[ 8] * z
+ m
[12] * w
;
279 vOut
->clip
[1] = m
[1] * x
+ m
[5] * y
+ m
[ 9] * z
+ m
[13] * w
;
280 vOut
->clip
[2] = m
[2] * x
+ m
[6] * y
+ m
[10] * z
+ m
[14] * w
;
281 vOut
->clip
[3] = m
[3] * x
+ m
[7] * y
+ m
[11] * z
+ m
[15] * w
;
284 x
= vOut
->clip
[0] / vOut
->clip
[3];
285 y
= vOut
->clip
[1] / vOut
->clip
[3];
286 z
= vOut
->clip
[2] / vOut
->clip
[3];
287 w
= 1.0 / vOut
->clip
[3];
290 vOut
->data
[0][0] = scale
[0] * x
+ trans
[0];
291 vOut
->data
[0][1] = scale
[1] * y
+ trans
[1];
292 vOut
->data
[0][2] = scale
[2] * z
+ trans
[2];
293 vOut
->data
[0][3] = w
;
296 vOut
->data
[1][0] = cIn
[0];
297 vOut
->data
[1][1] = cIn
[1];
298 vOut
->data
[1][2] = cIn
[2];
299 vOut
->data
[1][3] = 1.0;
306 * Called by the draw module when the vertx cache needs to be flushed.
307 * This involves running the vertex shader.
309 static void vs_flush( struct draw_context
*draw
)
313 /* We're not really running a vertex shader yet, so flushing the vs
314 * queue is just a matter of building the vertices and returning.
316 /* Actually, I'm cheating even more and pre-building them still
317 * with the mesa/vf module. So it's very easy...
320 for (i
= 0; i
< draw
->vs
.queue_nr
; i
++) {
322 for (i
= 0; i
< draw
->vs
.queue_nr
; i
+=4) {
324 /* Would do the following steps here:
326 * 1) Loop over vertex element descriptors, fetch data from each
327 * to build the pre-tnl vertex. This might require a new struct
328 * to represent the pre-tnl vertex.
330 * 2) Bundle groups of upto 4 pre-tnl vertices together and pass
333 * 3) Do any necessary unswizzling, make sure vertex headers are
334 * correctly populated, store resulting post-transformed
335 * vertices in vcache.
337 * In this version, just do the last step:
340 const unsigned elt
= draw
->vs
.queue
[i
].elt
;
341 struct vertex_header
*dest
= draw
->vs
.queue
[i
].dest
;
343 run_vertex_program(draw
, draw
->mapped_vbuffer
, elt
, dest
);
345 struct vertex_header
*dests
[4];
349 for (j
= 0; j
< 4; j
++) {
350 elts
[j
] = draw
->vs
.queue
[i
+ j
].elt
;
351 dests
[j
] = draw
->vs
.queue
[i
+ j
].dest
;
354 n
= MIN2(4, draw
->vs
.queue_nr
- i
);
358 run_vertex_program(draw
, draw
->mapped_vbuffer
, elts
, n
, dests
);
361 draw
->vs
.queue_nr
= 0;
367 softpipe_draw_arrays(struct pipe_context
*pipe
, unsigned mode
,
368 unsigned start
, unsigned count
)
370 struct softpipe_context
*sp
= softpipe_context(pipe
);
371 struct draw_context
*draw
= sp
->draw
;
372 struct pipe_buffer_handle
*buf
;
374 softpipe_map_surfaces(sp
);
379 buf
= sp
->vertex_buffer
[0].buffer
;
381 = pipe
->winsys
->buffer_map(pipe
->winsys
, buf
, PIPE_BUFFER_FLAG_READ
);
384 /* tell drawing pipeline we're beginning drawing */
385 draw
->pipeline
.first
->begin( draw
->pipeline
.first
);
387 draw
->vs_flush
= vs_flush
;
388 draw
->pipe
= pipe
; /* XXX pass pipe to draw_create() */
390 draw_invalidate_vcache( draw
);
392 draw_set_element_buffer(draw
, 0, NULL
); /* no index/element buffer */
393 draw_set_prim( draw
, mode
);
395 /* XXX draw_prim_info() and TRIM here */
396 draw_prim(draw
, start
, count
);
398 /* draw any left-over buffered prims */
401 /* tell drawing pipeline we're done drawing */
402 draw
->pipeline
.first
->end( draw
->pipeline
.first
);
405 * unmap vertex buffer
407 pipe
->winsys
->buffer_unmap(pipe
->winsys
, buf
);
409 softpipe_unmap_surfaces(sp
);
414 #define EMIT_ATTR( VF_ATTR, STYLE, SIZE ) \
416 if (draw->nr_attrs >= 2) \
417 draw->vf_attr_to_slot[VF_ATTR] = draw->nr_attrs - 2; \
418 draw->attrs[draw->nr_attrs].attrib = VF_ATTR; \
419 draw->attrs[draw->nr_attrs].format = STYLE; \
421 draw->vertex_size += SIZE; \
426 * XXX very similar to same func in draw_vb.c (which will go away)
429 draw_set_vertex_attributes2( struct draw_context
*draw
,
430 const unsigned *slot_to_vf_attr
,
435 memset(draw
->vf_attr_to_slot
, 0, sizeof(draw
->vf_attr_to_slot
));
437 draw
->vertex_size
= 0;
440 * First three attribs are always the same: header, clip pos, winpos
442 EMIT_ATTR(VF_ATTRIB_VERTEX_HEADER
, EMIT_1F
, 1);
443 EMIT_ATTR(VF_ATTRIB_CLIP_POS
, EMIT_4F
, 4);
445 assert(slot_to_vf_attr
[0] == VF_ATTRIB_POS
);
446 EMIT_ATTR(slot_to_vf_attr
[0], EMIT_4F_VIEWPORT
, 4);
449 * Remaining attribs (color, texcoords, etc)
451 for (i
= 1; i
< nr_attrs
; i
++)
452 EMIT_ATTR(slot_to_vf_attr
[i
], EMIT_4F
, 4);
454 draw
->vertex_size
*= 4; /* floats to bytes */