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 #if 0 /* looks like the Z offset issue got fixed */
283 rmesa
->hw
.vte
.cmd
[1] = R300_VPORT_X_SCALE_ENA
284 | R300_VPORT_X_OFFSET_ENA
285 | R300_VPORT_Y_SCALE_ENA
286 | R300_VPORT_Y_OFFSET_ENA
289 R300_STATECHANGE(rmesa
, vte
);
291 r300EmitState(rmesa
);
293 /* Magic register - note it is right after 20b0 */
295 if(rmesa
->state
.texture
.tc_count
>0){
299 assign_pipeline(rmesa
, &SINGLE_TEXTURE_PIPELINE
);
301 assign_pipeline(rmesa
, &FLAT_COLOR_PIPELINE
);
304 rmesa
->state
.vertex_shader
.matrix
[0].length
=16;
305 memcpy(rmesa
->state
.vertex_shader
.matrix
[0].body
.f
, ctx
->_ModelProjectMatrix
.m
, 16*4);
307 rmesa
->state
.vertex_shader
.unknown2
.length
=4;
308 rmesa
->state
.vertex_shader
.unknown2
.body
.f
[0]=0.0;
309 rmesa
->state
.vertex_shader
.unknown2
.body
.f
[1]=0.0;
310 rmesa
->state
.vertex_shader
.unknown2
.body
.f
[2]=1.0;
311 rmesa
->state
.vertex_shader
.unknown2
.body
.f
[3]=0.0;
314 r300EmitVertexShader(rmesa
);
315 r300EmitPixelShader(rmesa
);
318 reg_start(R300_RB3D_COLORMASK
, 0);
321 /* ----------------------------------- */
323 /* We need LOAD_VBPNTR to setup AOS_ATTR fields.. the offsets are irrelevant */
324 r300EmitLOAD_VBPNTR(rmesa
, 0);
326 for(i
=0; i
< VB
->PrimitiveCount
; i
++){
327 GLuint prim
= VB
->Primitive
[i
].mode
;
328 GLuint start
= VB
->Primitive
[i
].start
;
329 GLuint length
= VB
->Primitive
[i
].count
;
330 r300_render_immediate_primitive(rmesa
, ctx
, start
, start
+ length
, prim
);
333 /* This sequence is required after any 3d drawing packet
334 I suspect it work arounds a bug (or deficiency) in hardware */
336 reg_start(R300_RB3D_DSTCACHE_CTLSTAT
,0);
346 /* vertex buffer implementation */
348 /* We use the start part of GART texture buffer for vertices */
351 static void upload_vertex_buffer(r300ContextPtr rmesa
,
352 GLcontext
*ctx
, AOS_DATA
*array
, int *n_arrays
)
354 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
355 struct vertex_buffer
*VB
= &tnl
->vb
;
358 radeonScreenPtr rsp
=rmesa
->radeon
.radeonScreen
;
359 /* Not the most efficient implementation, but, for now, I just want something that
361 /* to do - make single memcpy per column (is it possible ?) */
362 /* to do - use dirty flags to avoid redundant copies */
363 #define UPLOAD_VECTOR(v, r, f)\
365 /* Is the data dirty ? */ \
366 if (v->flags & ((1<<v->size)-1)) { \
367 fprintf(stderr, "size=%d vs stride=%d\n", v->size, v->stride); \
368 if(v->size*4==v->stride){\
370 memcpy(rsp->gartTextures.map+offset, v->data, v->stride*VB->Count); \
372 for(i=0;i<VB->Count;i++){ \
373 /* copy one vertex at a time*/ \
374 memcpy(rsp->gartTextures.map+offset+i*v->size*4, VEC_ELT(v, GLfloat, i), v->size*4); \
377 /* v->flags &= ~((1<<v->size)-1);*/ \
379 array[idx].element_size=v->size; \
380 array[idx].stride=v->size; \
381 array[idx].format=(f); \
382 array[idx].ncomponents=v->size; \
383 array[idx].offset=rsp->gartTextures.handle+offset; \
385 offset+=v->size*4*VB->Count; \
389 UPLOAD_VECTOR(VB
->ObjPtr
, REG_COORDS
, AOS_FORMAT_FLOAT
);
390 UPLOAD_VECTOR(VB
->ColorPtr
[0], REG_COLOR0
, AOS_FORMAT_FLOAT_COLOR
);
393 if(idx
>=R300_MAX_AOS_ARRAYS
){
394 fprintf(stderr
, "Aieee ! Maximum AOS arrays count exceeded.. \n");
399 static void r300_render_vb_flat_primitive(r300ContextPtr rmesa
,
405 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
406 struct vertex_buffer
*VB
= &tnl
->vb
;
408 int k
, type
, n_arrays
;
411 if(end
<=start
)return; /* do we need to watch for this ? */
413 type
=r300_get_primitive_type(rmesa
, ctx
, start
, end
, prim
);
416 fire_AOS(PASS_PREFIX end
-start
, type
);
419 static GLboolean
r300_run_vb_flat_render(GLcontext
*ctx
,
420 struct tnl_pipeline_stage
*stage
)
422 r300ContextPtr rmesa
= R300_CONTEXT(ctx
);
423 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
424 struct vertex_buffer
*VB
= &tnl
->vb
;
426 AOS_DATA vb_arrays
[R300_MAX_AOS_ARRAYS
];
427 AOS_DATA vb_arrays2
[R300_MAX_AOS_ARRAYS
];
430 if (RADEON_DEBUG
== DEBUG_PRIMS
)
431 fprintf(stderr
, "%s\n", __FUNCTION__
);
433 /* setup array of structures data */
435 upload_vertex_buffer(rmesa
, ctx
, vb_arrays
, &n_arrays
);
436 fprintf(stderr
, "Using %d AOS arrays\n", n_arrays
);
438 reg_start(R300_RB3D_DSTCACHE_CTLSTAT
,0);
444 r300_setup_routing(rmesa
, ctx
, GL_FALSE
);
446 r300EmitState(rmesa
);
448 FLAT_COLOR_PIPELINE
.vertex_shader
.matrix
[0].length
=16;
449 memcpy(FLAT_COLOR_PIPELINE
.vertex_shader
.matrix
[0].body
.f
, ctx
->_ModelProjectMatrix
.m
, 16*4);
451 FLAT_COLOR_PIPELINE
.vertex_shader
.unknown2
.length
=4;
452 FLAT_COLOR_PIPELINE
.vertex_shader
.unknown2
.body
.f
[0]=0.0;
453 FLAT_COLOR_PIPELINE
.vertex_shader
.unknown2
.body
.f
[1]=0.0;
454 FLAT_COLOR_PIPELINE
.vertex_shader
.unknown2
.body
.f
[2]=1.0;
455 FLAT_COLOR_PIPELINE
.vertex_shader
.unknown2
.body
.f
[3]=0.0;
457 program_pipeline(PASS_PREFIX
&FLAT_COLOR_PIPELINE
);
459 set_quad0(PASS_PREFIX
1.0,1.0,1.0,1.0);
460 set_init21(PASS_PREFIX
0.0,1.0);
462 for(i
=0; i
< VB
->PrimitiveCount
; i
++){
463 GLuint prim
= VB
->Primitive
[i
].mode
;
464 GLuint start
= VB
->Primitive
[i
].start
;
465 GLuint length
= VB
->Primitive
[i
].count
;
468 memcpy(vb_arrays2
, vb_arrays
, sizeof(AOS_DATA
)*n_arrays
);
469 for(j
=0;j
<n_arrays
;j
++){
470 vb_arrays2
[j
].offset
+=vb_arrays2
[j
].stride
*start
*4;
473 setup_AOS(PASS_PREFIX vb_arrays2
, n_arrays
);
475 r300_render_vb_flat_primitive(rmesa
, ctx
, start
, start
+ length
, prim
);
478 /* This sequence is required after any 3d drawing packet
479 I suspect it work arounds a bug (or deficiency) in hardware */
481 reg_start(R300_RB3D_DSTCACHE_CTLSTAT
,0);
487 end_3d(PASS_PREFIX_VOID
);
489 /* Flush state - we are done drawing.. */
491 fprintf(stderr
, "\n");
497 * Called by the pipeline manager to render a batch of primitives.
498 * We can return true to pass on to the next stage (i.e. software
499 * rasterization) or false to indicate that the pipeline has finished
500 * after we render something.
502 static GLboolean
r300_run_render(GLcontext
*ctx
,
503 struct tnl_pipeline_stage
*stage
)
505 r300ContextPtr rmesa
= R300_CONTEXT(ctx
);
506 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
507 struct vertex_buffer
*VB
= &tnl
->vb
;
510 if (RADEON_DEBUG
== DEBUG_PRIMS
)
511 fprintf(stderr
, "%s\n", __FUNCTION__
);
516 return r300_run_immediate_render(ctx
, stage
);
522 mgaContextPtr mmesa
= MGA_CONTEXT(ctx
);
523 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
524 struct vertex_buffer
*VB
= &tnl
->vb
;
527 /* Don't handle clipping or indexed vertices or vertex manipulations.
529 if (mmesa
->RenderIndex
!= 0 ||
530 !mga_validate_render( ctx
, VB
)) {
534 tnl
->Driver
.Render
.Start( ctx
);
535 mmesa
->SetupNewInputs
= ~0;
537 for (i
= 0 ; i
< VB
->PrimitiveCount
; i
++)
539 GLuint prim
= VB
->Primitive
[i
].mode
;
540 GLuint start
= VB
->Primitive
[i
].start
;
541 GLuint length
= VB
->Primitive
[i
].count
;
546 mga_render_tab_verts
[prim
& PRIM_MODE_MASK
]( ctx
, start
, start
+ length
,
550 tnl
->Driver
.Render
.Finish( ctx
);
552 return GL_FALSE
; /* finished the pipe */
558 * Called by the pipeline manager once before rendering.
559 * We check the GL state here to
560 * a) decide whether we can do the current state in hardware and
561 * b) update hardware registers
563 #define FALLBACK_IF(expr) \
566 if (RADEON_DEBUG & DEBUG_FALLBACKS) \
567 fprintf(stderr, "%s: fallback:%s\n", \
568 __FUNCTION__, #expr); \
569 stage->active = GL_FALSE; \
574 static void r300_check_render(GLcontext
*ctx
, struct tnl_pipeline_stage
*stage
)
576 r300ContextPtr r300
= R300_CONTEXT(ctx
);
579 if (RADEON_DEBUG
& DEBUG_STATE
)
580 fprintf(stderr
, "%s\n", __FUNCTION__
);
582 /* We only support rendering in hardware for now */
583 if (ctx
->RenderMode
!= GL_RENDER
) {
584 stage
->active
= GL_FALSE
;
588 // I failed to figure out how dither works in hardware,
589 // let's just ignore it for now
590 //FALLBACK_IF(ctx->Color.DitherFlag);
592 /* I'm almost certain I forgot something here */
593 #if 0 /* This should work now.. */
594 FALLBACK_IF(ctx
->Color
.AlphaEnabled
); // GL_ALPHA_TEST
596 //FALLBACK_IF(ctx->Color.BlendEnabled); // GL_BLEND
597 FALLBACK_IF(ctx
->Fog
.Enabled
); // GL_FOG
598 FALLBACK_IF(ctx
->Line
.SmoothFlag
); // GL_LINE_SMOOTH
599 FALLBACK_IF(ctx
->Line
.StippleFlag
); // GL_LINE_STIPPLE
600 FALLBACK_IF(ctx
->Point
.SmoothFlag
); // GL_POINT_SMOOTH
601 if (ctx
->Extensions
.NV_point_sprite
|| ctx
->Extensions
.ARB_point_sprite
)
602 FALLBACK_IF(ctx
->Point
.PointSprite
); // GL_POINT_SPRITE_NV
603 FALLBACK_IF(ctx
->Polygon
.OffsetPoint
); // GL_POLYGON_OFFSET_POINT
604 FALLBACK_IF(ctx
->Polygon
.OffsetLine
); // GL_POLYGON_OFFSET_LINE
605 FALLBACK_IF(ctx
->Polygon
.OffsetFill
); // GL_POLYGON_OFFSET_FILL
606 FALLBACK_IF(ctx
->Polygon
.SmoothFlag
); // GL_POLYGON_SMOOTH
607 FALLBACK_IF(ctx
->Polygon
.StippleFlag
); // GL_POLYGON_STIPPLE
608 FALLBACK_IF(ctx
->Stencil
.Enabled
); // GL_STENCIL_TEST
609 FALLBACK_IF(ctx
->Multisample
.Enabled
); // GL_MULTISAMPLE_ARB
611 /* One step at a time - let one texture pass.. */
612 for (i
= 1; i
< ctx
->Const
.MaxTextureUnits
; i
++)
613 FALLBACK_IF(ctx
->Texture
.Unit
[i
].Enabled
);
616 /* let r300_run_render do its job */
618 stage
->active
= GL_FALSE
;
623 static void dtr(struct tnl_pipeline_stage
*stage
)
628 const struct tnl_pipeline_stage _r300_render_stage
= {
630 _NEW_ALL
, /* re-check (always re-check for now) */
631 0, /* re-run (always runs) */
632 GL_TRUE
, /* active */
633 0, 0, /* inputs (set in check_render), outputs */
634 0, 0, /* changed_inputs, private */
635 dtr
, /* destructor */
636 r300_check_render
, /* check */
637 r300_run_render
/* run */