Savage DRM version 2.2.0. Otherwise the render stage is disabled.
NULL
};
-extern const struct tnl_pipeline_stage _savage_texnorm_stage;
-extern const struct tnl_pipeline_stage _savage_render_stage;
+extern struct tnl_pipeline_stage _savage_texnorm_stage;
+extern struct tnl_pipeline_stage _savage_render_stage;
static const struct tnl_pipeline_stage *savage_pipeline[] = {
imesa->vtxBuf = &imesa->clientVtxBuf;
+ imesa->firstElt = -1;
+
/* Uninitialized vertex format. Force setting the vertex state in
* savageRenderStart.
*/
/* Install the customized pipeline:
*/
-#if 1
_tnl_destroy_pipeline( ctx );
_tnl_install_pipeline( ctx, savage_pipeline );
-#endif
+ /* DRM versions before 2.1.3 would only render triangle lists. ELTS
+ * support was added in 2.2.0. */
+ if (sPriv->drmMinor < 2) {
+ _savage_render_stage.active = GL_FALSE;
+ fprintf (stderr,
+ "*** Disabling fast path because your DRM version is buggy "
+ "or doesn't\n*** support ELTS. You need at least Savage DRM "
+ "version 2.2.\n");
+ }
+
/* Configure swrast to match hardware characteristics:
*/
savageTextureObjectPtr next_t, t;
savageFlushVertices(imesa);
+ savageReleaseIndexedVerts(imesa);
savageFlushCmdBuf(imesa, GL_TRUE); /* release DMA buffer */
/* update for multi-tex*/
drm_savage_cmd_header_t *write; /* append stuff here */
};
+struct savage_elt_t {
+ GLuint n; /* number of elts currently allocated */
+ drm_savage_cmd_header_t *cmd; /* the indexed drawing command */
+};
+
struct savage_context_t {
GLint refcount;
/* Command buffer */
struct savage_cmdbuf_t cmdBuf;
+ /* Elt book-keeping */
+ struct savage_elt_t elts;
+ GLint firstElt;
+
/* Vertex buffers */
struct savage_vtxbuf_t dmaVtxBuf, clientVtxBuf;
struct savage_vtxbuf_t *vtxBuf;
drm_savage_cmd_header_t *start;
int ret;
+ /* complete indexed drawing commands */
+ savageFlushElts(imesa);
+
/* If we lost the context we must restore the initial state (at
* the start of the command buffer). */
if (imesa->lostContext) {
}
if (discard) {
+ assert (!savageHaveIndexedVerts(imesa));
imesa->dmaVtxBuf.total = 0;
imesa->dmaVtxBuf.used = 0;
imesa->dmaVtxBuf.flushed = 0;
}
- imesa->clientVtxBuf.used = 0;
- imesa->clientVtxBuf.flushed = 0;
-
+ if (!savageHaveIndexedVerts(imesa)) {
+ imesa->clientVtxBuf.used = 0;
+ imesa->clientVtxBuf.flushed = 0;
+ }
imesa->cmdBuf.write = imesa->cmdBuf.base;
/* Save the current state at the start of the command buffer. That
extern void savageGetDMABuffer( savageContextPtr imesa );
+static __inline
+void savageReleaseIndexedVerts( savageContextPtr imesa )
+{
+ imesa->firstElt = -1;
+}
+
+static __inline
+GLboolean savageHaveIndexedVerts( savageContextPtr imesa )
+{
+ return (imesa->firstElt != -1);
+}
+
static __inline
u_int32_t *savageAllocVtxBuf( savageContextPtr imesa, GLuint words )
{
if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
fprintf (stderr, "... flushing DMA buffer in %s\n",
__FUNCTION__);
- savageFlushVertices( imesa );
+ savageReleaseIndexedVerts(imesa);
+ savageFlushVertices(imesa);
LOCK_HARDWARE(imesa);
savageFlushCmdBufLocked(imesa, GL_TRUE); /* discard DMA buffer */
savageGetDMABuffer(imesa);
if (SAVAGE_DEBUG & DEBUG_VERBOSE_MSG)
fprintf (stderr, "... flushing client vertex buffer in %s\n",
__FUNCTION__);
- savageFlushVertices( imesa );
+ savageReleaseIndexedVerts(imesa);
+ savageFlushVertices(imesa);
LOCK_HARDWARE(imesa);
savageFlushCmdBufLocked(imesa, GL_FALSE); /* free clientVtxBuf */
UNLOCK_HARDWARE(imesa);
return head;
}
+static __inline
+u_int32_t *savageAllocIndexedVerts( savageContextPtr imesa, GLuint n )
+{
+ u_int32_t *ret;
+ savageFlushVertices(imesa);
+ ret = savageAllocVtxBuf(imesa, n*imesa->HwVertexSize);
+ imesa->firstElt = imesa->vtxBuf->flushed / imesa->HwVertexSize;
+ imesa->vtxBuf->flushed = imesa->vtxBuf->used;
+ return ret;
+}
+
+/* Flush Elts:
+ * - Complete the drawing command with the correct number of indices.
+ * - Actually allocate entries for the indices in the command buffer.
+ * (This allocation must succeed without wrapping the cmd buffer!)
+ */
+static __inline
+void savageFlushElts( savageContextPtr imesa )
+{
+ if (imesa->elts.cmd) {
+ GLuint qwords = (imesa->elts.n + 3) >> 2;
+ assert(imesa->cmdBuf.write - imesa->cmdBuf.base + qwords
+ <= imesa->cmdBuf.size);
+ imesa->cmdBuf.write += qwords;
+
+ imesa->elts.cmd->idx.count = imesa->elts.n;
+ imesa->elts.cmd = NULL;
+ }
+}
+
+/* Allocate a command buffer entry with <bytes> bytes of arguments:
+ * - implies savageFlushElts
+ */
static __inline
drm_savage_cmd_header_t *savageAllocCmdBuf( savageContextPtr imesa, GLuint bytes )
{
drm_savage_cmd_header_t *ret;
GLuint qwords = ((bytes + 7) >> 3) + 1; /* round up */
assert (qwords < imesa->cmdBuf.size);
- if (imesa->cmdBuf.write - imesa->cmdBuf.base + qwords > imesa->cmdBuf.size) {
+
+ savageFlushElts(imesa);
+
+ if (imesa->cmdBuf.write - imesa->cmdBuf.base + qwords > imesa->cmdBuf.size)
savageFlushCmdBuf(imesa, GL_FALSE);
- }
+
ret = (drm_savage_cmd_header_t *)imesa->cmdBuf.write;
imesa->cmdBuf.write += qwords;
return ret;
}
+/* Allocate Elts:
+ * - if it doesn't fit, flush the cmd buffer first
+ * - allocates the drawing command on the cmd buffer if there is no
+ * incomplete indexed drawing command yet
+ * - increments the number of elts. Final allocation is done in savageFlushElts
+ */
+static __inline
+u_int16_t *savageAllocElts( savageContextPtr imesa, GLuint n )
+{
+ u_int16_t *ret;
+ GLuint qwords;
+ assert (savageHaveIndexedVerts(imesa));
+
+ if (imesa->elts.cmd)
+ qwords = (imesa->elts.n + n + 3) >> 2;
+ else
+ qwords = ((n + 3) >> 2) + 1;
+ if (imesa->cmdBuf.write - imesa->cmdBuf.base + qwords > imesa->cmdBuf.size)
+ savageFlushCmdBuf(imesa, GL_FALSE); /* implies savageFlushElts */
+
+ if (!imesa->elts.cmd) {
+ savageFlushVertices(imesa);
+ imesa->elts.cmd = savageAllocCmdBuf(imesa, 0);
+ imesa->elts.cmd->idx.cmd = (imesa->vtxBuf == &imesa->dmaVtxBuf) ?
+ SAVAGE_CMD_DMA_IDX : SAVAGE_CMD_VB_IDX;
+ imesa->elts.cmd->idx.prim = imesa->HwPrim;
+ imesa->elts.cmd->idx.skip = imesa->skip;
+ imesa->elts.n = 0;
+ }
+
+ ret = (u_int16_t *)(imesa->elts.cmd+1) + imesa->elts.n;
+ imesa->elts.n += n;
+ return ret;
+}
+
#endif
#define HAVE_QUADS 0
#define HAVE_QUAD_STRIPS 0
-#define HAVE_ELTS 0 /* for now */
+#define HAVE_ELTS 1
#define LOCAL_VARS savageContextPtr imesa = SAVAGE_CONTEXT(ctx)
#define INIT( prim ) do { \
case GL_TRIANGLE_FAN: imesa->HwPrim = SAVAGE_PRIM_TRIFAN; break; \
} \
} while (0)
-#define FLUSH() savageFlushVertices(imesa)
+#define FLUSH() savageFlushElts(imesa), savageFlushVertices(imesa)
+
#define GET_CURRENT_VB_MAX_VERTS() \
((imesa->bufferSize/4 - imesa->vtxBuf->used) / imesa->HwVertexSize)
#define GET_SUBSEQUENT_VB_MAX_VERTS() \
#define EMIT_VERTS( ctx, j, nr, buf ) \
_tnl_emit_vertices_to_buffer(ctx, j, (j)+(nr), buf )
+#define ELTS_VARS( buf ) GLushort *dest = buf, firstElt = imesa->firstElt
+#define ELT_INIT( prim ) INIT(prim)
+
+/* (size - used - 1 qword for drawing command) * 4 elts per qword */
+#define GET_CURRENT_VB_MAX_ELTS() \
+ ((imesa->cmdBuf.size - (imesa->cmdBuf.write - imesa->cmdBuf.base) - 1)*4)
+/* (size - space for initial state - 1 qword for drawing command) * 4 elts
+ * imesa is not defined in validate_render :( */
+#define GET_SUBSEQUENT_VB_MAX_ELTS() \
+ ((SAVAGE_CONTEXT(ctx)->cmdBuf.size - \
+ (SAVAGE_CONTEXT(ctx)->cmdBuf.start - \
+ SAVAGE_CONTEXT(ctx)->cmdBuf.base) - 1)*4)
+
+#define ALLOC_ELTS(nr) savageAllocElts(imesa, nr)
+#define EMIT_ELT(offset, x) do { \
+ (dest)[offset] = (GLushort) ((x)+firstElt); \
+} while (0)
+#define EMIT_TWO_ELTS(offset, x, y) do { \
+ *(GLuint *)(dest + offset) = (((y)+firstElt) << 16) | \
+ ((x)+firstElt); \
+} while (0)
+
+#define INCR_ELTS( nr ) dest += nr
+#define ELTPTR dest
+#define RELEASE_ELT_VERTS() \
+ savageReleaseIndexedVerts(imesa)
+
+#define EMIT_INDEXED_VERTS( ctx, start, count ) do { \
+ GLuint *buf = savageAllocIndexedVerts(imesa, count-start); \
+ EMIT_VERTS(ctx, start, count-start, buf); \
+} while (0)
+
#define TAG(x) savage_##x
#include "tnl_dd/t_dd_dmatmp.h"
savageContextPtr imesa = SAVAGE_CONTEXT(ctx);
TNLcontext *tnl = TNL_CONTEXT(ctx);
struct vertex_buffer *VB = &tnl->vb;
- tnl_render_func *tab;
+ tnl_render_func *tab, *tab_elts;
GLboolean valid;
GLuint i;
+ if (savageHaveIndexedVerts(imesa) && (!VB->Elts || stage->changed_inputs))
+ savageReleaseIndexedVerts(imesa);
+
if (imesa->savageScreen->chipset < S3_SAVAGE4 &&
(ctx->_TriangleCaps & DD_FLATSHADE)) {
tab = savage_flat_render_tab_verts_s3d;
+ tab_elts = savage_flat_render_tab_elts_s3d;
valid = savage_flat_validate_render_s3d( ctx, VB );
} else {
tab = savage_render_tab_verts;
+ tab_elts = savage_render_tab_elts;
valid = savage_validate_render( ctx, VB );
}
- /* Don't handle clipping or indexed vertices or vertex manipulations.
+ /* Don't handle clipping or vertex manipulations.
*/
if (imesa->RenderIndex != 0 || !valid) {
return GL_TRUE;
tnl->Driver.Render.Start( ctx );
/* Check RenderIndex again. The ptexHack is detected late in RenderStart.
- * Also check for fallbacks detected late.
+ * Also check for ptex fallbacks detected late.
*/
if (imesa->RenderIndex != 0 || imesa->Fallback != 0) {
return GL_TRUE;
/* setup for hardware culling */
imesa->raster_primitive = GL_TRIANGLES;
imesa->new_state |= SAVAGE_NEW_CULL;
+
+ /* update and emit state */
savageDDUpdateHwState(ctx);
+ savageEmitChangedState(imesa);
+
+ if (VB->Elts) {
+ tab = tab_elts;
+ if (!savageHaveIndexedVerts(imesa)) {
+ if (VB->Count > GET_SUBSEQUENT_VB_MAX_VERTS())
+ return GL_TRUE;
+ EMIT_INDEXED_VERTS(ctx, 0, VB->Count);
+ }
+ }
for (i = 0 ; i < VB->PrimitiveCount ; i++)
{
static void savage_check_render( GLcontext *ctx,
struct tnl_pipeline_stage *stage )
{
- __DRIscreenPrivate *driScrnPriv =
- SAVAGE_CONTEXT(ctx)->savageScreen->driScrnPriv;
stage->inputs = TNL_CONTEXT(ctx)->render_inputs;
- /* This hack will go away when we depend on 2.2.x for ELTS. */
- if (driScrnPriv->drmMinor <= 1 && driScrnPriv->drmPatch < 3) {
- static GLboolean firstTime = GL_TRUE;
- stage->active = GL_FALSE;
- if (firstTime) {
- fprintf (stderr,
- "*** Disabling fast path because your DRM version is buggy.\n"
- "*** You need at least Savage DRM version 2.1.3.\n");
- firstTime = GL_FALSE;
- }
- }
}
static void dtr( struct tnl_pipeline_stage *stage )
(void)stage;
}
-const struct tnl_pipeline_stage _savage_render_stage =
+struct tnl_pipeline_stage _savage_render_stage =
{
"savage render",
(_DD_NEW_SEPARATE_SPECULAR |
}
}
-const struct tnl_pipeline_stage _savage_texnorm_stage =
+struct tnl_pipeline_stage _savage_texnorm_stage =
{
"savage texture coordinate normalization stage", /* name */
_NEW_TEXTURE, /* check_state */