/**************************************************************************
*
* Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
* All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sub license, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial portions
* of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
* IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
**************************************************************************/
/*
* Render unclipped vertex buffers by emitting vertices directly to
* dma buffers. Use strip/fan hardware acceleration where possible.
*
*/
#include "main/glheader.h"
#include "main/context.h"
#include "main/macros.h"
#include "main/imports.h"
#include "main/mtypes.h"
#include "main/enums.h"
#include "math/m_xform.h"
#include "tnl/t_context.h"
#include "tnl/t_vertex.h"
#include "tnl/t_pipeline.h"
#include "intel_screen.h"
#include "intel_context.h"
#include "intel_tris.h"
#include "intel_batchbuffer.h"
#include "intel_reg.h"
/*
* Render unclipped vertex buffers by emitting vertices directly to
* dma buffers. Use strip/fan hardware primitives where possible.
* Try to simulate missing primitives with indexed vertices.
*/
#define HAVE_POINTS 0 /* Has it, but can't use because subpixel has to
* be adjusted for points on the INTEL/I845G
*/
#define HAVE_LINES 1
#define HAVE_LINE_STRIPS 1
#define HAVE_TRIANGLES 1
#define HAVE_TRI_STRIPS 1
#define HAVE_TRI_STRIP_1 0 /* has it, template can't use it yet */
#define HAVE_TRI_FANS 1
#define HAVE_POLYGONS 1
#define HAVE_QUADS 0
#define HAVE_QUAD_STRIPS 0
#define HAVE_ELTS 0
static uint32_t hw_prim[GL_POLYGON + 1] = {
0,
PRIM3D_LINELIST,
PRIM3D_LINESTRIP,
PRIM3D_LINESTRIP,
PRIM3D_TRILIST,
PRIM3D_TRISTRIP,
PRIM3D_TRIFAN,
0,
0,
PRIM3D_POLY
};
static const GLenum reduced_prim[GL_POLYGON + 1] = {
GL_POINTS,
GL_LINES,
GL_LINES,
GL_LINES,
GL_TRIANGLES,
GL_TRIANGLES,
GL_TRIANGLES,
GL_TRIANGLES,
GL_TRIANGLES,
GL_TRIANGLES
};
static const int scale_prim[GL_POLYGON + 1] = {
0, /* fallback case */
1,
2,
2,
1,
3,
3,
0, /* fallback case */
0, /* fallback case */
3
};
static void
intelDmaPrimitive(struct intel_context *intel, GLenum prim)
{
if (0)
fprintf(stderr, "%s %s\n", __FUNCTION__, _mesa_lookup_enum_by_nr(prim));
INTEL_FIREVERTICES(intel);
intel->vtbl.reduced_primitive_state(intel, reduced_prim[prim]);
intel_set_prim(intel, hw_prim[prim]);
}
#define INTEL_NO_VBO_STATE_RESERVED 1500
static INLINE GLuint intel_get_vb_max(struct intel_context *intel)
{
GLuint ret;
if (intel->intelScreen->no_vbo) {
ret = intel->batch.bo->size - INTEL_NO_VBO_STATE_RESERVED;
} else
ret = INTEL_VB_SIZE;
ret /= (intel->vertex_size * 4);
return ret;
}
static INLINE GLuint intel_get_current_max(struct intel_context *intel)
{
GLuint ret;
if (intel->intelScreen->no_vbo) {
ret = intel_batchbuffer_space(intel);
ret = ret <= INTEL_NO_VBO_STATE_RESERVED ? 0 : ret - INTEL_NO_VBO_STATE_RESERVED;
} else
ret = (INTEL_VB_SIZE - intel->prim.current_offset);
return ret / (intel->vertex_size * 4);
}
#define LOCAL_VARS struct intel_context *intel = intel_context(ctx)
#define INIT( prim ) \
do { \
intelDmaPrimitive( intel, prim ); \
} while (0)
#define FLUSH() INTEL_FIREVERTICES(intel)
#define GET_SUBSEQUENT_VB_MAX_VERTS() intel_get_vb_max(intel)
#define GET_CURRENT_VB_MAX_VERTS() intel_get_current_max(intel)
#define ALLOC_VERTS(nr) intel_get_prim_space(intel, nr)
#define EMIT_VERTS( ctx, j, nr, buf ) \
_tnl_emit_vertices_to_buffer(ctx, j, (j)+(nr), buf )
#define TAG(x) intel_##x
#include "tnl_dd/t_dd_dmatmp.h"
/**********************************************************************/
/* Render pipeline stage */
/**********************************************************************/
/* Heuristic to choose between the two render paths:
*/
static bool
choose_render(struct intel_context *intel, struct vertex_buffer *VB)
{
int vertsz = intel->vertex_size;
int cost_render = 0;
int cost_fallback = 0;
int nr_prims = 0;
int nr_rprims = 0;
int nr_rverts = 0;
int rprim = intel->reduced_primitive;
int i = 0;
for (i = 0; i < VB->PrimitiveCount; i++) {
GLuint prim = VB->Primitive[i].mode;
GLuint length = VB->Primitive[i].count;
if (!length)
continue;
nr_prims++;
nr_rverts += length * scale_prim[prim & PRIM_MODE_MASK];
if (reduced_prim[prim & PRIM_MODE_MASK] != rprim) {
nr_rprims++;
rprim = reduced_prim[prim & PRIM_MODE_MASK];
}
}
/* One point for each generated primitive:
*/
cost_render = nr_prims;
cost_fallback = nr_rprims;
/* One point for every 1024 dwords (4k) of dma:
*/
cost_render += (vertsz * i) / 1024;
cost_fallback += (vertsz * nr_rverts) / 1024;
if (0)
fprintf(stderr, "cost render: %d fallback: %d\n",
cost_render, cost_fallback);
if (cost_render > cost_fallback)
return false;
return true;
}
static GLboolean
intel_run_render(struct gl_context * ctx, struct tnl_pipeline_stage *stage)
{
struct intel_context *intel = intel_context(ctx);
TNLcontext *tnl = TNL_CONTEXT(ctx);
struct vertex_buffer *VB = &tnl->vb;
GLuint i;
intel->vtbl.render_prevalidate( intel );
/* Don't handle clipping or indexed vertices.
*/
if (intel->RenderIndex != 0 ||
!intel_validate_render(ctx, VB) || !choose_render(intel, VB)) {
return true;
}
tnl->clipspace.new_inputs |= VERT_BIT_POS;
tnl->Driver.Render.Start(ctx);
for (i = 0; i < VB->PrimitiveCount; i++) {
GLuint prim = _tnl_translate_prim(&VB->Primitive[i]);
GLuint start = VB->Primitive[i].start;
GLuint length = VB->Primitive[i].count;
if (!length)
continue;
intel_render_tab_verts[prim & PRIM_MODE_MASK] (ctx, start,
start + length, prim);
}
tnl->Driver.Render.Finish(ctx);
INTEL_FIREVERTICES(intel);
return false; /* finished the pipe */
}
static const struct tnl_pipeline_stage _intel_render_stage = {
"intel render",
NULL,
NULL,
NULL,
NULL,
intel_run_render /* run */
};
const struct tnl_pipeline_stage *intel_pipeline[] = {
&_tnl_vertex_transform_stage,
&_tnl_normal_transform_stage,
&_tnl_lighting_stage,
&_tnl_fog_coordinate_stage,
&_tnl_texgen_stage,
&_tnl_texture_transform_stage,
&_tnl_point_attenuation_stage,
&_tnl_vertex_program_stage,
#if 1
&_intel_render_stage, /* ADD: unclipped rastersetup-to-dma */
#endif
&_tnl_render_stage,
0,
};