1 /**************************************************************************
3 Copyright (C) 2004 Nicolai Haehnle.
7 Permission is hereby granted, free of charge, to any person obtaining a
8 copy of this software and associated documentation files (the "Software"),
9 to deal in the Software without restriction, including without limitation
10 on the rights to use, copy, modify, merge, publish, distribute, sub
11 license, and/or sell copies of the Software, and to permit persons to whom
12 the Software is furnished to do so, subject to the following conditions:
14 The above copyright notice and this permission notice (including the next
15 paragraph) shall be included in all copies or substantial portions of the
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
21 ATI, VA LINUX SYSTEMS AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
22 DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
23 OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
24 USE OR OTHER DEALINGS IN THE SOFTWARE.
26 **************************************************************************/
30 * Nicolai Haehnle <prefect_@gmx.net>
40 #include "simple_list.h"
42 #include "api_arrayelt.h"
43 #include "swrast/swrast.h"
44 #include "swrast_setup/swrast_setup.h"
45 #include "array_cache/acache.h"
48 #include "radeon_reg.h"
49 #include "radeon_macros.h"
50 #include "radeon_ioctl.h"
51 #include "radeon_state.h"
52 #include "r300_context.h"
53 #include "r300_ioctl.h"
54 #include "r300_state.h"
56 #include "r300_program.h"
62 /**********************************************************************
63 * Hardware rasterization
65 * When we fell back to software TCL, we still try to use the
66 * rasterization hardware for rendering.
67 **********************************************************************/
69 static int r300_get_primitive_type(r300ContextPtr rmesa
,
75 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
76 struct vertex_buffer
*VB
= &tnl
->vb
;
78 int type
=-1, min_vertices
=0;
81 if(end
<=start
)return -1; /* do we need to watch for this ? */
83 switch (prim
& PRIM_MODE_MASK
) {
86 type
=R300_VAP_VF_CNTL__PRIM_POINTS
;
91 type
=R300_VAP_VF_CNTL__PRIM_LINES
;
96 type
=R300_VAP_VF_CNTL__PRIM_LINE_STRIP
;
106 type
=R300_VAP_VF_CNTL__PRIM_TRIANGLES
;
109 case GL_TRIANGLE_STRIP
:
111 type
=R300_VAP_VF_CNTL__PRIM_TRIANGLE_STRIP
;
114 case GL_TRIANGLE_FAN
:
116 type
=R300_VAP_VF_CNTL__PRIM_TRIANGLE_FAN
;
121 type
=R300_VAP_VF_CNTL__PRIM_QUADS
;
126 type
=R300_VAP_VF_CNTL__PRIM_QUAD_STRIP
;
130 fprintf(stderr
, "Cannot handle primitive %02x ", prim
& PRIM_MODE_MASK
);
135 fprintf(stderr
, "[%d-%d]%s ", start
, end
, name
);
137 if(start
+min_vertices
>=end
){
138 fprintf(stderr
, "Not enough vertices\n");
144 /* This function compiles GL context into state registers that
145 describe data routing inside of R300 pipeline.
147 In particular, it programs input_route, output_vtx_fmt, texture
148 unit configuration and gb_output_vtx_fmt
150 This function encompasses setup_AOS() from r300_lib.c
156 /* Immediate implementation - vertex data is sent via command stream */
158 static GLfloat default_vector
[4]={0.0, 0.0, 0.0, 1.0};
160 #define output_vector(v, i) \
163 for(_i=0;_i<v->size;_i++){ \
164 efloat(VEC_ELT(v, GLfloat, i)[_i]); \
166 for(_i=v->size;_i<4;_i++){ \
167 efloat(default_vector[_i]); \
171 /* Immediate implementation - vertex data is sent via command stream */
173 static void r300_render_immediate_primitive(r300ContextPtr rmesa
,
179 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
180 struct vertex_buffer
*VB
= &tnl
->vb
;
185 type
=r300_get_primitive_type(rmesa
, ctx
, start
, end
, prim
);
188 fprintf(stderr
,"ObjPtr: size=%d stride=%d\n",
189 VB
->ObjPtr
->size
, VB
->ObjPtr
->stride
);
190 fprintf(stderr
,"ColorPtr[0]: size=%d stride=%d\n",
191 VB
->ColorPtr
[0]->size
, VB
->ColorPtr
[0]->stride
);
192 fprintf(stderr
,"TexCoordPtr[0]: size=%d stride=%d\n",
193 VB
->TexCoordPtr
[0]->size
, VB
->TexCoordPtr
[0]->stride
);
199 start_immediate_packet(end
-start
, type
, 8+4*rmesa
->state
.texture
.tc_count
);
201 for(i
=start
;i
<end
;i
++){
203 fprintf(stderr
, "* (%f %f %f %f) (%f %f %f %f)\n",
204 VEC_ELT(VB
->ObjPtr
, GLfloat
, i
)[0],
205 VEC_ELT(VB
->ObjPtr
, GLfloat
, i
)[1],
206 VEC_ELT(VB
->ObjPtr
, GLfloat
, i
)[2],
207 VEC_ELT(VB
->ObjPtr
, GLfloat
, i
)[3],
209 VEC_ELT(VB
->ColorPtr
[0], GLfloat
, i
)[0],
210 VEC_ELT(VB
->ColorPtr
[0], GLfloat
, i
)[1],
211 VEC_ELT(VB
->ColorPtr
[0], GLfloat
, i
)[2],
212 VEC_ELT(VB
->ColorPtr
[0], GLfloat
, i
)[3]
218 output_vector(VB
->ObjPtr
, i
);
220 /* color components */
221 output_vector(VB
->ColorPtr
[0], i
);
223 /* texture coordinates */
224 for(k
=0;k
< ctx
->Const
.MaxTextureUnits
;k
++)
225 if(ctx
->Texture
.Unit
[k
].Enabled
)
226 output_vector(VB
->TexCoordPtr
[k
], i
);
232 static void assign_pipeline(r300ContextPtr rmesa
, R300_PIPELINE
*p
)
234 /* Watch out ! This is buggy .. but will do for now */
236 /* At least one sanity check is in order */
237 if(sizeof(rmesa
->state
.vertex_shader
) != sizeof(p
->vertex_shader
)){
238 fprintf(stderr
, "Aieee ! vertex_shader sizes don't match.\n");
241 if(sizeof(rmesa
->state
.pixel_shader
) != sizeof(p
->pixel_shader
)){
242 fprintf(stderr
, "Aieee ! vertex_shader sizes don't match.\n");
246 memcpy(&rmesa
->state
.vertex_shader
, &(p
->vertex_shader
), sizeof(rmesa
->state
.vertex_shader
));
247 memcpy(&rmesa
->state
.pixel_shader
, &(p
->pixel_shader
), sizeof(rmesa
->state
.pixel_shader
));
251 static GLboolean
r300_run_immediate_render(GLcontext
*ctx
,
252 struct tnl_pipeline_stage
*stage
)
254 r300ContextPtr rmesa
= R300_CONTEXT(ctx
);
255 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
256 struct vertex_buffer
*VB
= &tnl
->vb
;
258 /* Only do 2d textures */
259 struct gl_texture_object
*to
=ctx
->Texture
.Unit
[0].Current2D
;
260 r300TexObjPtr t
=to
->DriverData
;
264 /* Update texture state - needs to be done only when actually changed..
265 All the time for now.. */
266 /* Flush state - make sure command buffer is nice and large */
270 if (RADEON_DEBUG
== DEBUG_PRIMS
)
271 fprintf(stderr
, "%s\n", __FUNCTION__
);
274 /* needed before starting 3d operation .. */
275 reg_start(R300_RB3D_DSTCACHE_CTLSTAT
,0);
282 rmesa
->hw
.vte
.cmd
[1] = R300_VPORT_X_SCALE_ENA
283 | R300_VPORT_X_OFFSET_ENA
284 | R300_VPORT_Y_SCALE_ENA
285 | R300_VPORT_Y_OFFSET_ENA
287 R300_STATECHANGE(rmesa
, vte
);
289 r300EmitState(rmesa
);
291 /* Magic register - note it is right after 20b0 */
293 if(rmesa
->state
.texture
.tc_count
>0){
297 assign_pipeline(rmesa
, &SINGLE_TEXTURE_PIPELINE
);
299 assign_pipeline(rmesa
, &FLAT_COLOR_PIPELINE
);
302 rmesa
->state
.vertex_shader
.matrix
[0].length
=16;
303 memcpy(rmesa
->state
.vertex_shader
.matrix
[0].body
.f
, ctx
->_ModelProjectMatrix
.m
, 16*4);
305 rmesa
->state
.vertex_shader
.unknown2
.length
=4;
306 rmesa
->state
.vertex_shader
.unknown2
.body
.f
[0]=0.0;
307 rmesa
->state
.vertex_shader
.unknown2
.body
.f
[1]=0.0;
308 rmesa
->state
.vertex_shader
.unknown2
.body
.f
[2]=1.0;
309 rmesa
->state
.vertex_shader
.unknown2
.body
.f
[3]=0.0;
312 r300EmitVertexShader(rmesa
);
313 r300EmitPixelShader(rmesa
);
315 /* We need LOAD_VBPNTR to setup AOS_ATTR fields.. the offsets are irrelevant */
316 r300EmitLOAD_VBPNTR(rmesa
, 0);
318 for(i
=0; i
< VB
->PrimitiveCount
; i
++){
319 GLuint prim
= VB
->Primitive
[i
].mode
;
320 GLuint start
= VB
->Primitive
[i
].start
;
321 GLuint length
= VB
->Primitive
[i
].count
;
322 r300_render_immediate_primitive(rmesa
, ctx
, start
, start
+ length
, prim
);
325 /* This sequence is required after any 3d drawing packet
326 I suspect it work arounds a bug (or deficiency) in hardware */
328 reg_start(R300_RB3D_DSTCACHE_CTLSTAT
,0);
338 /* vertex buffer implementation */
340 /* We use the start part of GART texture buffer for vertices */
343 static void upload_vertex_buffer(r300ContextPtr rmesa
,
344 GLcontext
*ctx
, AOS_DATA
*array
, int *n_arrays
)
346 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
347 struct vertex_buffer
*VB
= &tnl
->vb
;
350 radeonScreenPtr rsp
=rmesa
->radeon
.radeonScreen
;
351 /* Not the most efficient implementation, but, for now, I just want something that
353 /* to do - make single memcpy per column (is it possible ?) */
354 /* to do - use dirty flags to avoid redundant copies */
355 #define UPLOAD_VECTOR(v, r, f)\
357 /* Is the data dirty ? */ \
358 if (v->flags & ((1<<v->size)-1)) { \
359 fprintf(stderr, "size=%d vs stride=%d\n", v->size, v->stride); \
360 if(v->size*4==v->stride){\
362 memcpy(rsp->gartTextures.map+offset, v->data, v->stride*VB->Count); \
364 for(i=0;i<VB->Count;i++){ \
365 /* copy one vertex at a time*/ \
366 memcpy(rsp->gartTextures.map+offset+i*v->size*4, VEC_ELT(v, GLfloat, i), v->size*4); \
369 /* v->flags &= ~((1<<v->size)-1);*/ \
371 array[idx].element_size=v->size; \
372 array[idx].stride=v->size; \
373 array[idx].format=(f); \
374 array[idx].ncomponents=v->size; \
375 array[idx].offset=rsp->gartTextures.handle+offset; \
377 offset+=v->size*4*VB->Count; \
381 UPLOAD_VECTOR(VB
->ObjPtr
, REG_COORDS
, AOS_FORMAT_FLOAT
);
382 UPLOAD_VECTOR(VB
->ColorPtr
[0], REG_COLOR0
, AOS_FORMAT_FLOAT_COLOR
);
385 if(idx
>=R300_MAX_AOS_ARRAYS
){
386 fprintf(stderr
, "Aieee ! Maximum AOS arrays count exceeded.. \n");
391 static void r300_render_vb_flat_primitive(r300ContextPtr rmesa
,
397 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
398 struct vertex_buffer
*VB
= &tnl
->vb
;
400 int k
, type
, n_arrays
;
403 if(end
<=start
)return; /* do we need to watch for this ? */
405 type
=r300_get_primitive_type(rmesa
, ctx
, start
, end
, prim
);
408 fire_AOS(PASS_PREFIX end
-start
, type
);
411 static GLboolean
r300_run_vb_flat_render(GLcontext
*ctx
,
412 struct tnl_pipeline_stage
*stage
)
414 r300ContextPtr rmesa
= R300_CONTEXT(ctx
);
415 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
416 struct vertex_buffer
*VB
= &tnl
->vb
;
418 AOS_DATA vb_arrays
[R300_MAX_AOS_ARRAYS
];
419 AOS_DATA vb_arrays2
[R300_MAX_AOS_ARRAYS
];
422 if (RADEON_DEBUG
== DEBUG_PRIMS
)
423 fprintf(stderr
, "%s\n", __FUNCTION__
);
425 /* setup array of structures data */
427 upload_vertex_buffer(rmesa
, ctx
, vb_arrays
, &n_arrays
);
428 fprintf(stderr
, "Using %d AOS arrays\n", n_arrays
);
430 reg_start(R300_RB3D_DSTCACHE_CTLSTAT
,0);
436 r300_setup_routing(rmesa
, ctx
, GL_FALSE
);
438 r300EmitState(rmesa
);
440 FLAT_COLOR_PIPELINE
.vertex_shader
.matrix
[0].length
=16;
441 memcpy(FLAT_COLOR_PIPELINE
.vertex_shader
.matrix
[0].body
.f
, ctx
->_ModelProjectMatrix
.m
, 16*4);
443 FLAT_COLOR_PIPELINE
.vertex_shader
.unknown2
.length
=4;
444 FLAT_COLOR_PIPELINE
.vertex_shader
.unknown2
.body
.f
[0]=0.0;
445 FLAT_COLOR_PIPELINE
.vertex_shader
.unknown2
.body
.f
[1]=0.0;
446 FLAT_COLOR_PIPELINE
.vertex_shader
.unknown2
.body
.f
[2]=1.0;
447 FLAT_COLOR_PIPELINE
.vertex_shader
.unknown2
.body
.f
[3]=0.0;
449 program_pipeline(PASS_PREFIX
&FLAT_COLOR_PIPELINE
);
451 set_quad0(PASS_PREFIX
1.0,1.0,1.0,1.0);
452 set_init21(PASS_PREFIX
0.0,1.0);
454 for(i
=0; i
< VB
->PrimitiveCount
; i
++){
455 GLuint prim
= VB
->Primitive
[i
].mode
;
456 GLuint start
= VB
->Primitive
[i
].start
;
457 GLuint length
= VB
->Primitive
[i
].count
;
460 memcpy(vb_arrays2
, vb_arrays
, sizeof(AOS_DATA
)*n_arrays
);
461 for(j
=0;j
<n_arrays
;j
++){
462 vb_arrays2
[j
].offset
+=vb_arrays2
[j
].stride
*start
*4;
465 setup_AOS(PASS_PREFIX vb_arrays2
, n_arrays
);
467 r300_render_vb_flat_primitive(rmesa
, ctx
, start
, start
+ length
, prim
);
470 /* This sequence is required after any 3d drawing packet
471 I suspect it work arounds a bug (or deficiency) in hardware */
473 reg_start(R300_RB3D_DSTCACHE_CTLSTAT
,0);
479 end_3d(PASS_PREFIX_VOID
);
481 /* Flush state - we are done drawing.. */
483 fprintf(stderr
, "\n");
489 * Called by the pipeline manager to render a batch of primitives.
490 * We can return true to pass on to the next stage (i.e. software
491 * rasterization) or false to indicate that the pipeline has finished
492 * after we render something.
494 static GLboolean
r300_run_render(GLcontext
*ctx
,
495 struct tnl_pipeline_stage
*stage
)
497 r300ContextPtr rmesa
= R300_CONTEXT(ctx
);
498 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
499 struct vertex_buffer
*VB
= &tnl
->vb
;
502 if (RADEON_DEBUG
== DEBUG_PRIMS
)
503 fprintf(stderr
, "%s\n", __FUNCTION__
);
508 return r300_run_immediate_render(ctx
, stage
);
514 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
515 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
516 struct vertex_buffer
*VB
= &tnl
->vb
;
519 /* Don't handle clipping or indexed vertices or vertex manipulations.
521 if (mmesa
->RenderIndex
!= 0 ||
522 !mga_validate_render( ctx
, VB
)) {
526 tnl
->Driver
.Render
.Start( ctx
);
527 mmesa
->SetupNewInputs
= ~0;
529 for (i
= 0 ; i
< VB
->PrimitiveCount
; i
++)
531 GLuint prim
= VB
->Primitive
[i
].mode
;
532 GLuint start
= VB
->Primitive
[i
].start
;
533 GLuint length
= VB
->Primitive
[i
].count
;
538 mga_render_tab_verts
[prim
& PRIM_MODE_MASK
]( ctx
, start
, start
+ length
,
542 tnl
->Driver
.Render
.Finish( ctx
);
544 return GL_FALSE
; /* finished the pipe */
550 * Called by the pipeline manager once before rendering.
551 * We check the GL state here to
552 * a) decide whether we can do the current state in hardware and
553 * b) update hardware registers
555 #define FALLBACK_IF(expr) \
558 if (RADEON_DEBUG & DEBUG_FALLBACKS) \
559 fprintf(stderr, "%s: fallback:%s\n", \
560 __FUNCTION__, #expr); \
561 stage->active = GL_FALSE; \
566 static void r300_check_render(GLcontext
*ctx
, struct tnl_pipeline_stage
*stage
)
568 r300ContextPtr r300
= R300_CONTEXT(ctx
);
571 if (RADEON_DEBUG
& DEBUG_STATE
)
572 fprintf(stderr
, "%s\n", __FUNCTION__
);
574 /* We only support rendering in hardware for now */
575 if (ctx
->RenderMode
!= GL_RENDER
) {
576 stage
->active
= GL_FALSE
;
580 // I failed to figure out how dither works in hardware,
581 // let's just ignore it for now
582 //FALLBACK_IF(ctx->Color.DitherFlag);
584 /* I'm almost certain I forgot something here */
585 #if 0 /* This should work now.. */
586 FALLBACK_IF(ctx
->Color
.AlphaEnabled
); // GL_ALPHA_TEST
588 FALLBACK_IF(ctx
->Color
.BlendEnabled
); // GL_BLEND
589 FALLBACK_IF(ctx
->Fog
.Enabled
); // GL_FOG
590 FALLBACK_IF(ctx
->Line
.SmoothFlag
); // GL_LINE_SMOOTH
591 FALLBACK_IF(ctx
->Line
.StippleFlag
); // GL_LINE_STIPPLE
592 FALLBACK_IF(ctx
->Point
.SmoothFlag
); // GL_POINT_SMOOTH
593 if (ctx
->Extensions
.NV_point_sprite
|| ctx
->Extensions
.ARB_point_sprite
)
594 FALLBACK_IF(ctx
->Point
.PointSprite
); // GL_POINT_SPRITE_NV
595 FALLBACK_IF(ctx
->Polygon
.OffsetPoint
); // GL_POLYGON_OFFSET_POINT
596 FALLBACK_IF(ctx
->Polygon
.OffsetLine
); // GL_POLYGON_OFFSET_LINE
597 FALLBACK_IF(ctx
->Polygon
.OffsetFill
); // GL_POLYGON_OFFSET_FILL
598 FALLBACK_IF(ctx
->Polygon
.SmoothFlag
); // GL_POLYGON_SMOOTH
599 FALLBACK_IF(ctx
->Polygon
.StippleFlag
); // GL_POLYGON_STIPPLE
600 FALLBACK_IF(ctx
->Stencil
.Enabled
); // GL_STENCIL_TEST
601 FALLBACK_IF(ctx
->Multisample
.Enabled
); // GL_MULTISAMPLE_ARB
603 /* One step at a time - let one texture pass.. */
604 for (i
= 1; i
< ctx
->Const
.MaxTextureUnits
; i
++)
605 FALLBACK_IF(ctx
->Texture
.Unit
[i
].Enabled
);
608 /* let r300_run_render do its job */
610 stage
->active
= GL_FALSE
;
615 static void dtr(struct tnl_pipeline_stage
*stage
)
620 const struct tnl_pipeline_stage _r300_render_stage
= {
622 _NEW_ALL
, /* re-check (always re-check for now) */
623 0, /* re-run (always runs) */
624 GL_TRUE
, /* active */
625 0, 0, /* inputs (set in check_render), outputs */
626 0, 0, /* changed_inputs, private */
627 dtr
, /* destructor */
628 r300_check_render
, /* check */
629 r300_run_render
/* run */