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 **************************************************************************/
31 * \brief R300 Render (Vertex Buffer Implementation)
33 * The immediate implementation has been removed from CVS in favor of the vertex
34 * buffer implementation.
36 * The render functions are called by the pipeline manager to render a batch of
37 * primitives. They return TRUE to pass on to the next stage (i.e. software
38 * rasterization) or FALSE to indicate that the pipeline has finished after
39 * rendering something.
41 * When falling back to software TCL still attempt to use hardware
44 * I am not sure that the cache related registers are setup correctly, but
45 * obviously this does work... Further investigation is needed.
47 * \author Nicolai Haehnle <prefect_@gmx.net>
49 * \todo Add immediate implementation back? Perhaps this is useful if there are
53 #include "r300_render.h"
55 #include "main/glheader.h"
56 #include "main/imports.h"
57 #include "main/enums.h"
58 #include "main/macros.h"
59 #include "main/context.h"
61 #include "main/simple_list.h"
62 #include "main/api_arrayelt.h"
63 #include "swrast/swrast.h"
64 #include "swrast_setup/swrast_setup.h"
66 #include "vbo/vbo_split.h"
67 #include "r300_context.h"
68 #include "r300_state.h"
70 #include "r300_emit.h"
71 #include "r300_swtcl.h"
74 * \brief Convert a OpenGL primitive type into a R300 primitive type.
76 int r300PrimitiveType(r300ContextPtr rmesa
, int prim
)
78 switch (prim
& PRIM_MODE_MASK
) {
80 return R300_VAP_VF_CNTL__PRIM_POINTS
;
83 return R300_VAP_VF_CNTL__PRIM_LINES
;
86 return R300_VAP_VF_CNTL__PRIM_LINE_STRIP
;
89 return R300_VAP_VF_CNTL__PRIM_LINE_LOOP
;
92 return R300_VAP_VF_CNTL__PRIM_TRIANGLES
;
94 case GL_TRIANGLE_STRIP
:
95 return R300_VAP_VF_CNTL__PRIM_TRIANGLE_STRIP
;
98 return R300_VAP_VF_CNTL__PRIM_TRIANGLE_FAN
;
101 return R300_VAP_VF_CNTL__PRIM_QUADS
;
104 return R300_VAP_VF_CNTL__PRIM_QUAD_STRIP
;
107 return R300_VAP_VF_CNTL__PRIM_POLYGON
;
116 int r300NumVerts(r300ContextPtr rmesa
, int num_verts
, int prim
)
120 switch (prim
& PRIM_MODE_MASK
) {
125 verts_off
= num_verts
% 2;
129 verts_off
= num_verts
;
133 verts_off
= num_verts
;
136 verts_off
= num_verts
% 3;
138 case GL_TRIANGLE_STRIP
:
140 verts_off
= num_verts
;
142 case GL_TRIANGLE_FAN
:
144 verts_off
= num_verts
;
147 verts_off
= num_verts
% 4;
151 verts_off
= num_verts
;
153 verts_off
= num_verts
% 2;
157 verts_off
= num_verts
;
165 return num_verts
- verts_off
;
168 static void r300FireEB(r300ContextPtr rmesa
, int vertex_count
, int type
, int offset
)
170 BATCH_LOCALS(&rmesa
->radeon
);
173 /* offset is in indices */
175 OUT_BATCH_PACKET3(R300_PACKET3_3D_DRAW_INDX_2
, 0);
176 if (rmesa
->ind_buf
.is_32bit
) {
177 /* convert to bytes */
180 OUT_BATCH(R300_VAP_VF_CNTL__PRIM_WALK_INDICES
|
181 (vertex_count
<< 16) | type
|
182 R300_VAP_VF_CNTL__INDEX_SIZE_32bit
);
184 /* convert to bytes */
186 size
= (vertex_count
+ 1) >> 1;
187 OUT_BATCH(R300_VAP_VF_CNTL__PRIM_WALK_INDICES
|
188 (vertex_count
<< 16) | type
);
191 if (!rmesa
->radeon
.radeonScreen
->kernel_mm
) {
192 OUT_BATCH_PACKET3(R300_PACKET3_INDX_BUFFER
, 2);
193 OUT_BATCH(R300_INDX_BUFFER_ONE_REG_WR
| (0 << R300_INDX_BUFFER_SKIP_SHIFT
) |
194 (R300_VAP_PORT_IDX0
>> 2));
195 OUT_BATCH_RELOC(0, rmesa
->ind_buf
.bo
, rmesa
->ind_buf
.bo_offset
+ offset
, RADEON_GEM_DOMAIN_GTT
, 0, 0);
198 OUT_BATCH_PACKET3(R300_PACKET3_INDX_BUFFER
, 2);
199 OUT_BATCH(R300_INDX_BUFFER_ONE_REG_WR
| (0 << R300_INDX_BUFFER_SKIP_SHIFT
) |
200 (R300_VAP_PORT_IDX0
>> 2));
201 OUT_BATCH(rmesa
->ind_buf
.bo_offset
+ offset
);
203 radeon_cs_write_reloc(rmesa
->radeon
.cmdbuf
.cs
,
204 rmesa
->ind_buf
.bo
, RADEON_GEM_DOMAIN_GTT
, 0, 0);
209 static void r300EmitAOS(r300ContextPtr rmesa
, GLuint nr
, GLuint offset
)
211 BATCH_LOCALS(&rmesa
->radeon
);
213 int sz
= 1 + (nr
>> 1) * 3 + (nr
& 1) * 2;
216 if (RADEON_DEBUG
& RADEON_VERTS
)
217 fprintf(stderr
, "%s: nr=%d, ofs=0x%08x\n", __FUNCTION__
, nr
,
220 if (!rmesa
->radeon
.radeonScreen
->kernel_mm
) {
221 BEGIN_BATCH(sz
+2+(nr
* 2));
222 OUT_BATCH_PACKET3(R300_PACKET3_3D_LOAD_VBPNTR
, sz
- 1);
225 for (i
= 0; i
+ 1 < nr
; i
+= 2) {
226 OUT_BATCH((rmesa
->radeon
.tcl
.aos
[i
].components
<< 0) |
227 (rmesa
->radeon
.tcl
.aos
[i
].stride
<< 8) |
228 (rmesa
->radeon
.tcl
.aos
[i
+ 1].components
<< 16) |
229 (rmesa
->radeon
.tcl
.aos
[i
+ 1].stride
<< 24));
231 voffset
= rmesa
->radeon
.tcl
.aos
[i
+ 0].offset
+
232 offset
* 4 * rmesa
->radeon
.tcl
.aos
[i
+ 0].stride
;
233 OUT_BATCH_RELOC(voffset
,
234 rmesa
->radeon
.tcl
.aos
[i
].bo
,
236 RADEON_GEM_DOMAIN_GTT
,
238 voffset
= rmesa
->radeon
.tcl
.aos
[i
+ 1].offset
+
239 offset
* 4 * rmesa
->radeon
.tcl
.aos
[i
+ 1].stride
;
240 OUT_BATCH_RELOC(voffset
,
241 rmesa
->radeon
.tcl
.aos
[i
+1].bo
,
243 RADEON_GEM_DOMAIN_GTT
,
248 OUT_BATCH((rmesa
->radeon
.tcl
.aos
[nr
- 1].components
<< 0) |
249 (rmesa
->radeon
.tcl
.aos
[nr
- 1].stride
<< 8));
250 voffset
= rmesa
->radeon
.tcl
.aos
[nr
- 1].offset
+
251 offset
* 4 * rmesa
->radeon
.tcl
.aos
[nr
- 1].stride
;
252 OUT_BATCH_RELOC(voffset
,
253 rmesa
->radeon
.tcl
.aos
[nr
- 1].bo
,
255 RADEON_GEM_DOMAIN_GTT
,
261 BEGIN_BATCH(sz
+2+(nr
* 2));
262 OUT_BATCH_PACKET3(R300_PACKET3_3D_LOAD_VBPNTR
, sz
- 1);
265 for (i
= 0; i
+ 1 < nr
; i
+= 2) {
266 OUT_BATCH((rmesa
->radeon
.tcl
.aos
[i
].components
<< 0) |
267 (rmesa
->radeon
.tcl
.aos
[i
].stride
<< 8) |
268 (rmesa
->radeon
.tcl
.aos
[i
+ 1].components
<< 16) |
269 (rmesa
->radeon
.tcl
.aos
[i
+ 1].stride
<< 24));
271 voffset
= rmesa
->radeon
.tcl
.aos
[i
+ 0].offset
+
272 offset
* 4 * rmesa
->radeon
.tcl
.aos
[i
+ 0].stride
;
274 voffset
= rmesa
->radeon
.tcl
.aos
[i
+ 1].offset
+
275 offset
* 4 * rmesa
->radeon
.tcl
.aos
[i
+ 1].stride
;
280 OUT_BATCH((rmesa
->radeon
.tcl
.aos
[nr
- 1].components
<< 0) |
281 (rmesa
->radeon
.tcl
.aos
[nr
- 1].stride
<< 8));
282 voffset
= rmesa
->radeon
.tcl
.aos
[nr
- 1].offset
+
283 offset
* 4 * rmesa
->radeon
.tcl
.aos
[nr
- 1].stride
;
286 for (i
= 0; i
+ 1 < nr
; i
+= 2) {
287 voffset
= rmesa
->radeon
.tcl
.aos
[i
+ 0].offset
+
288 offset
* 4 * rmesa
->radeon
.tcl
.aos
[i
+ 0].stride
;
289 radeon_cs_write_reloc(rmesa
->radeon
.cmdbuf
.cs
,
290 rmesa
->radeon
.tcl
.aos
[i
+0].bo
,
291 RADEON_GEM_DOMAIN_GTT
,
293 voffset
= rmesa
->radeon
.tcl
.aos
[i
+ 1].offset
+
294 offset
* 4 * rmesa
->radeon
.tcl
.aos
[i
+ 1].stride
;
295 radeon_cs_write_reloc(rmesa
->radeon
.cmdbuf
.cs
,
296 rmesa
->radeon
.tcl
.aos
[i
+1].bo
,
297 RADEON_GEM_DOMAIN_GTT
,
301 voffset
= rmesa
->radeon
.tcl
.aos
[nr
- 1].offset
+
302 offset
* 4 * rmesa
->radeon
.tcl
.aos
[nr
- 1].stride
;
303 radeon_cs_write_reloc(rmesa
->radeon
.cmdbuf
.cs
,
304 rmesa
->radeon
.tcl
.aos
[nr
-1].bo
,
305 RADEON_GEM_DOMAIN_GTT
,
313 static void r300FireAOS(r300ContextPtr rmesa
, int vertex_count
, int type
)
315 BATCH_LOCALS(&rmesa
->radeon
);
317 r300_emit_scissor(rmesa
->radeon
.glCtx
);
319 OUT_BATCH_PACKET3(R300_PACKET3_3D_DRAW_VBUF_2
, 0);
320 OUT_BATCH(R300_VAP_VF_CNTL__PRIM_WALK_VERTEX_LIST
| (vertex_count
<< 16) | type
);
324 void r300RunRenderPrimitive(GLcontext
* ctx
, int start
, int end
, int prim
)
326 r300ContextPtr rmesa
= R300_CONTEXT(ctx
);
327 BATCH_LOCALS(&rmesa
->radeon
);
330 type
= r300PrimitiveType(rmesa
, prim
);
331 num_verts
= r300NumVerts(rmesa
, end
- start
, prim
);
333 if (type
< 0 || num_verts
<= 0)
336 if (rmesa
->ind_buf
.bo
) {
337 GLuint first
, incr
, offset
= 0;
339 if (!split_prim_inplace(prim
& PRIM_MODE_MASK
, &first
, &incr
) &&
341 WARN_ONCE("Fixme: can't handle spliting prim %d\n", prim
);
346 r300EmitAOS(rmesa
, rmesa
->radeon
.tcl
.aos_count
, 0);
347 if (rmesa
->radeon
.radeonScreen
->kernel_mm
) {
348 BEGIN_BATCH_NO_AUTOSTATE(2);
349 OUT_BATCH_REGSEQ(R300_VAP_VF_MAX_VTX_INDX
, 1);
350 OUT_BATCH(rmesa
->radeon
.tcl
.aos
[0].count
);
354 r300_emit_scissor(rmesa
->radeon
.glCtx
);
355 while (num_verts
> 0) {
359 nr
= MIN2(num_verts
, 65535);
360 nr
-= (nr
- first
) % incr
;
362 /* get alignment for IB correct */
363 if (nr
!= num_verts
) {
365 align
= nr
* (rmesa
->ind_buf
.is_32bit
? 4 : 2);
370 WARN_ONCE("did the impossible happen? we never aligned nr to dword\n");
375 r300FireEB(rmesa
, nr
, type
, offset
);
382 GLuint first
, incr
, offset
= 0;
384 if (!split_prim_inplace(prim
& PRIM_MODE_MASK
, &first
, &incr
) &&
386 WARN_ONCE("Fixme: can't handle spliting prim %d\n", prim
);
390 if (rmesa
->radeon
.radeonScreen
->kernel_mm
) {
391 BEGIN_BATCH_NO_AUTOSTATE(2);
392 OUT_BATCH_REGSEQ(R300_VAP_VF_MAX_VTX_INDX
, 1);
393 OUT_BATCH(rmesa
->radeon
.tcl
.aos
[0].count
);
397 r300_emit_scissor(rmesa
->radeon
.glCtx
);
398 while (num_verts
> 0) {
400 nr
= MIN2(num_verts
, 65535);
401 nr
-= (nr
- first
) % incr
;
402 r300EmitAOS(rmesa
, rmesa
->radeon
.tcl
.aos_count
, start
+ offset
);
403 r300FireAOS(rmesa
, nr
, type
);
411 static const char *getFallbackString(uint32_t bit
)
414 case R300_FALLBACK_VERTEX_PROGRAM
:
415 return "vertex program";
416 case R300_FALLBACK_LINE_SMOOTH
:
417 return "smooth lines";
418 case R300_FALLBACK_POINT_SMOOTH
:
419 return "smooth points";
420 case R300_FALLBACK_POLYGON_SMOOTH
:
421 return "smooth polygons";
422 case R300_FALLBACK_LINE_STIPPLE
:
423 return "line stipple";
424 case R300_FALLBACK_POLYGON_STIPPLE
:
425 return "polygon stipple";
426 case R300_FALLBACK_STENCIL_TWOSIDE
:
427 return "two-sided stencil";
428 case R300_FALLBACK_RENDER_MODE
:
429 return "render mode != GL_RENDER";
430 case R300_FALLBACK_FRAGMENT_PROGRAM
:
431 return "fragment program";
432 case R300_FALLBACK_AOS_LIMIT
:
434 case R300_FALLBACK_INVALID_BUFFERS
:
435 return "invalid buffers";
441 void r300SwitchFallback(GLcontext
*ctx
, uint32_t bit
, GLboolean mode
)
443 TNLcontext
*tnl
= TNL_CONTEXT(ctx
);
444 r300ContextPtr rmesa
= R300_CONTEXT(ctx
);
445 uint32_t old_fallback
= rmesa
->fallback
;
446 static uint32_t fallback_warn
= 0;
449 if ((fallback_warn
& bit
) == 0) {
450 if (RADEON_DEBUG
& RADEON_FALLBACKS
)
451 fprintf(stderr
, "WARNING! Falling back to software for %s\n", getFallbackString(bit
));
452 fallback_warn
|= bit
;
454 rmesa
->fallback
|= bit
;
456 /* update only if we change from no tcl fallbacks to some tcl fallbacks */
457 if (rmesa
->options
.hw_tcl_enabled
) {
458 if (((old_fallback
& R300_TCL_FALLBACK_MASK
) == 0) &&
459 ((bit
& R300_TCL_FALLBACK_MASK
) > 0)) {
460 R300_STATECHANGE(rmesa
, vap_cntl_status
);
461 rmesa
->hw
.vap_cntl_status
.cmd
[1] |= R300_VAP_TCL_BYPASS
;
465 /* update only if we change from no raster fallbacks to some raster fallbacks */
466 if (((old_fallback
& R300_RASTER_FALLBACK_MASK
) == 0) &&
467 ((bit
& R300_RASTER_FALLBACK_MASK
) > 0)) {
469 radeon_firevertices(&rmesa
->radeon
);
470 rmesa
->radeon
.swtcl
.RenderIndex
= ~0;
471 _swsetup_Wakeup( ctx
);
474 rmesa
->fallback
&= ~bit
;
476 /* update only if we have disabled all tcl fallbacks */
477 if (rmesa
->options
.hw_tcl_enabled
) {
478 if ((old_fallback
& R300_TCL_FALLBACK_MASK
) == bit
) {
479 R300_STATECHANGE(rmesa
, vap_cntl_status
);
480 rmesa
->hw
.vap_cntl_status
.cmd
[1] &= ~R300_VAP_TCL_BYPASS
;
484 /* update only if we have disabled all raster fallbacks */
485 if ((old_fallback
& R300_RASTER_FALLBACK_MASK
) == bit
) {
486 _swrast_flush( ctx
);
488 tnl
->Driver
.Render
.Start
= r300RenderStart
;
489 tnl
->Driver
.Render
.Finish
= r300RenderFinish
;
490 tnl
->Driver
.Render
.PrimitiveNotify
= r300RenderPrimitive
;
491 tnl
->Driver
.Render
.ResetLineStipple
= r300ResetLineStipple
;
492 tnl
->Driver
.Render
.BuildVertices
= _tnl_build_vertices
;
493 tnl
->Driver
.Render
.CopyPV
= _tnl_copy_pv
;
494 tnl
->Driver
.Render
.Interp
= _tnl_interp
;
496 _tnl_invalidate_vertex_state( ctx
, ~0 );
497 _tnl_invalidate_vertices( ctx
, ~0 );