From 41b58954e1742493452b91d9ecdb761db5de3bed Mon Sep 17 00:00:00 2001 From: Keith Whitwell Date: Thu, 10 Jun 2004 12:48:07 +0000 Subject: [PATCH] New driver for i915 as well as older i830/i845/i865 chipsets. --- src/mesa/drivers/dri/i915/Makefile | 58 ++ src/mesa/drivers/dri/i915/i830_context.c | 143 +++ src/mesa/drivers/dri/i915/i830_context.h | 197 ++++ src/mesa/drivers/dri/i915/i830_metaops.c | 699 ++++++++++++++ src/mesa/drivers/dri/i915/i830_reg.h | 665 +++++++++++++ src/mesa/drivers/dri/i915/i830_state.c | 1183 ++++++++++++++++++++++++ src/mesa/drivers/dri/i915/i830_tex.c | 325 +++++++ src/mesa/drivers/dri/i915/i830_texblend.c | 1058 +++++++++++++++++++++ src/mesa/drivers/dri/i915/i830_texstate.c | 333 +++++++ src/mesa/drivers/dri/i915/i830_vtbl.c | 426 +++++++++ src/mesa/drivers/dri/i915/i915_context.c | 211 +++++ src/mesa/drivers/dri/i915/i915_context.h | 330 +++++++ src/mesa/drivers/dri/i915/i915_debug.c | 272 ++++++ src/mesa/drivers/dri/i915/i915_fragprog.c | 1033 +++++++++++++++++++++ src/mesa/drivers/dri/i915/i915_metaops.c | 494 ++++++++++ src/mesa/drivers/dri/i915/i915_program.c | 446 +++++++++ src/mesa/drivers/dri/i915/i915_program.h | 143 +++ src/mesa/drivers/dri/i915/i915_reg.h | 859 +++++++++++++++++ src/mesa/drivers/dri/i915/i915_state.c | 1073 +++++++++++++++++++++ src/mesa/drivers/dri/i915/i915_tex.c | 155 ++++ src/mesa/drivers/dri/i915/i915_texprog.c | 635 +++++++++++++ src/mesa/drivers/dri/i915/i915_texstate.c | 625 +++++++++++++ src/mesa/drivers/dri/i915/i915_vtbl.c | 332 +++++++ src/mesa/drivers/dri/i915/intel_batchbuffer.c | 668 +++++++++++++ src/mesa/drivers/dri/i915/intel_batchbuffer.h | 103 +++ src/mesa/drivers/dri/i915/intel_context.c | 666 +++++++++++++ src/mesa/drivers/dri/i915/intel_context.h | 431 +++++++++ src/mesa/drivers/dri/i915/intel_ioctl.c | 585 ++++++++++++ src/mesa/drivers/dri/i915/intel_ioctl.h | 46 + src/mesa/drivers/dri/i915/intel_pixel.c | 469 ++++++++++ src/mesa/drivers/dri/i915/intel_reg.h | 64 ++ src/mesa/drivers/dri/i915/intel_render.c | 239 +++++ src/mesa/drivers/dri/i915/intel_screen.c | 543 +++++++++++ src/mesa/drivers/dri/i915/intel_screen.h | 76 ++ src/mesa/drivers/dri/i915/intel_span.c | 323 +++++++ src/mesa/drivers/dri/i915/intel_span.h | 16 + src/mesa/drivers/dri/i915/intel_state.c | 135 +++ src/mesa/drivers/dri/i915/intel_tex.c | 665 +++++++++++++ src/mesa/drivers/dri/i915/intel_tex.h | 22 + src/mesa/drivers/dri/i915/intel_tris.c | 900 ++++++++++++++++++ src/mesa/drivers/dri/i915/intel_tris.h | 26 + src/mesa/drivers/dri/i915/server/i830_common.h | 169 ++++ src/mesa/drivers/dri/i915/server/i830_dri.h | 70 ++ 43 files changed, 17911 insertions(+) create mode 100644 src/mesa/drivers/dri/i915/Makefile create mode 100644 src/mesa/drivers/dri/i915/i830_context.c create mode 100644 src/mesa/drivers/dri/i915/i830_context.h create mode 100644 src/mesa/drivers/dri/i915/i830_metaops.c create mode 100644 src/mesa/drivers/dri/i915/i830_reg.h create mode 100644 src/mesa/drivers/dri/i915/i830_state.c create mode 100644 src/mesa/drivers/dri/i915/i830_tex.c create mode 100644 src/mesa/drivers/dri/i915/i830_texblend.c create mode 100644 src/mesa/drivers/dri/i915/i830_texstate.c create mode 100644 src/mesa/drivers/dri/i915/i830_vtbl.c create mode 100644 src/mesa/drivers/dri/i915/i915_context.c create mode 100644 src/mesa/drivers/dri/i915/i915_context.h create mode 100644 src/mesa/drivers/dri/i915/i915_debug.c create mode 100644 src/mesa/drivers/dri/i915/i915_fragprog.c create mode 100644 src/mesa/drivers/dri/i915/i915_metaops.c create mode 100644 src/mesa/drivers/dri/i915/i915_program.c create mode 100644 src/mesa/drivers/dri/i915/i915_program.h create mode 100644 src/mesa/drivers/dri/i915/i915_reg.h create mode 100644 src/mesa/drivers/dri/i915/i915_state.c create mode 100644 src/mesa/drivers/dri/i915/i915_tex.c create mode 100644 src/mesa/drivers/dri/i915/i915_texprog.c create mode 100644 src/mesa/drivers/dri/i915/i915_texstate.c create mode 100644 src/mesa/drivers/dri/i915/i915_vtbl.c create mode 100644 src/mesa/drivers/dri/i915/intel_batchbuffer.c create mode 100644 src/mesa/drivers/dri/i915/intel_batchbuffer.h create mode 100644 src/mesa/drivers/dri/i915/intel_context.c create mode 100644 src/mesa/drivers/dri/i915/intel_context.h create mode 100644 src/mesa/drivers/dri/i915/intel_ioctl.c create mode 100644 src/mesa/drivers/dri/i915/intel_ioctl.h create mode 100644 src/mesa/drivers/dri/i915/intel_pixel.c create mode 100644 src/mesa/drivers/dri/i915/intel_reg.h create mode 100644 src/mesa/drivers/dri/i915/intel_render.c create mode 100644 src/mesa/drivers/dri/i915/intel_screen.c create mode 100644 src/mesa/drivers/dri/i915/intel_screen.h create mode 100644 src/mesa/drivers/dri/i915/intel_span.c create mode 100644 src/mesa/drivers/dri/i915/intel_span.h create mode 100644 src/mesa/drivers/dri/i915/intel_state.c create mode 100644 src/mesa/drivers/dri/i915/intel_tex.c create mode 100644 src/mesa/drivers/dri/i915/intel_tex.h create mode 100644 src/mesa/drivers/dri/i915/intel_tris.c create mode 100644 src/mesa/drivers/dri/i915/intel_tris.h create mode 100644 src/mesa/drivers/dri/i915/server/i830_common.h create mode 100644 src/mesa/drivers/dri/i915/server/i830_dri.h diff --git a/src/mesa/drivers/dri/i915/Makefile b/src/mesa/drivers/dri/i915/Makefile new file mode 100644 index 0000000..acf78d7 --- /dev/null +++ b/src/mesa/drivers/dri/i915/Makefile @@ -0,0 +1,58 @@ + +TOP = ../../../../.. +include $(TOP)/configs/current + +LIBNAME = i915_dri.so + + +COMMON_SOURCES = \ + ../../common/driverfuncs.c \ + ../common/mm.c \ + ../common/utils.c \ + ../common/texmem.c \ + ../common/vblank.c \ + ../common/xmlconfig.c \ + ../common/dri_util.c \ + ../common/glcontextmodes.c + +DRIVER_SOURCES = \ + i915_context.c \ + i915_debug.c \ + i915_fragprog.c \ + i915_metaops.c \ + i915_program.c \ + i915_state.c \ + i915_tex.c \ + i915_texprog.c \ + i915_texstate.c \ + i915_vtbl.c \ + i830_context.c \ + i830_metaops.c \ + i830_state.c \ + i830_texblend.c \ + i830_tex.c \ + i830_texstate.c \ + i830_vtbl.c \ + intel_batchbuffer.c \ + intel_context.c \ + intel_ioctl.c \ + intel_pixel.c \ + intel_render.c \ + intel_screen.c \ + intel_span.c \ + intel_state.c \ + intel_tex.c \ + intel_tris.c + +C_SOURCES = \ + $(COMMON_SOURCES) \ + $(MINIGLX_SOURCES) \ + $(DRIVER_SOURCES) + +ASM_SOURCES = + + + +include ../Makefile.template + +symlinks: diff --git a/src/mesa/drivers/dri/i915/i830_context.c b/src/mesa/drivers/dri/i915/i830_context.c new file mode 100644 index 0000000..4acec31 --- /dev/null +++ b/src/mesa/drivers/dri/i915/i830_context.c @@ -0,0 +1,143 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "i830_context.h" +#include "imports.h" +#include "texmem.h" +#include "intel_tex.h" +#include "tnl/tnl.h" +#include "tnl/t_vertex.h" +#include "tnl/t_context.h" + + +/*************************************** + * Mesa's Driver Functions + ***************************************/ + +/* This is the extension list explicitly enabled by the client and + * excludes functionality available in Mesa and also excludes legacy + * extensions. It is recognized that in an open source driver, those + * extensions will probably be re-enabled. + */ +static const GLubyte *i830GetString( GLcontext *ctx, GLenum name ) +{ + if (name == GL_EXTENSIONS) + return + "GL_ARB_multitexture " + "GL_ARB_texture_border_clamp " + "GL_ARB_texture_compression " + "GL_ARB_texture_env_add " + "GL_ARB_texture_env_combine " + "GL_ARB_texture_env_dot3 " + "GL_ARB_texture_mirrored_repeat " + "GL_ARB_transpose_matrix " + "GL_ARB_vertex_buffer_object " + "GL_ARB_vertex_program " + "GL_ARB_window_pos " + "GL_EXT_abgr " + "GL_EXT_bgra " + "GL_EXT_blend_color " + "GL_EXT_blend_func_separate " + "GL_EXT_blend_minmax " + "GL_EXT_blend_subtract " + "GL_EXT_clip_volume_hint " + "GL_EXT_compiled_vertex_array " + "GL_EXT_draw_range_elements " + "GL_EXT_fog_coord " + "GL_EXT_multi_draw_arrays " + "GL_EXT_packed_pixels " + "GL_EXT_rescale_normal " + "GL_EXT_secondary_color " + "GL_EXT_separate_specular_color " + "GL_EXT_stencil_wrap " + "GL_EXT_texture_env_add " + "GL_EXT_texture_env_combine " + "GL_EXT_texture_filter_anisotropic " + "GL_IBM_texture_mirrored_repeat " + "GL_MESA_ycbcr_texture " + "GL_MESA_window_pos " + "GL_NV_texgen_reflection " + "GL_SGIS_generate_mipmap "; + + return intelGetString( ctx, name ); +} + + +static void i830InitDriverFunctions( struct dd_function_table *functions ) +{ + intelInitDriverFunctions( functions ); + i830InitStateFuncs( functions ); + i830InitTextureFuncs( functions ); + functions->GetString = i830GetString; +} + + +GLboolean i830CreateContext( const __GLcontextModes *mesaVis, + __DRIcontextPrivate *driContextPriv, + void *sharedContextPrivate) +{ + struct dd_function_table functions; + i830ContextPtr i830 = (i830ContextPtr) CALLOC_STRUCT(i830_context); + intelContextPtr intel = &i830->intel; + GLcontext *ctx = &intel->ctx; + if (!i830) return GL_FALSE; + + i830InitVtbl( i830 ); + i830InitDriverFunctions( &functions ); + + if (!intelInitContext( intel, mesaVis, driContextPriv, + sharedContextPrivate, &functions )) { + FREE(i830); + return GL_FALSE; + } + + intel->ctx.Const.MaxTextureUnits = I830_TEX_UNITS; + intel->ctx.Const.MaxTextureImageUnits = I830_TEX_UNITS; + intel->ctx.Const.MaxTextureCoordUnits = I830_TEX_UNITS; + + intel->nr_heaps = 1; + intel->texture_heaps[0] = + driCreateTextureHeap( 0, intel, + intel->intelScreen->textureSize, + 12, + I830_NR_TEX_REGIONS, + intel->sarea->texList, + & intel->sarea->texAge, + & intel->swapped, + sizeof( struct i830_texture_object ), + (destroy_texture_object_t *)intelDestroyTexObj ); + + /* FIXME: driCalculateMaxTextureLevels assumes that mipmaps are tightly + * FIXME: packed, but they're not in Intel graphics hardware. + */ + intel->ctx.Const.MaxTextureUnits = 1; + driCalculateMaxTextureLevels( intel->texture_heaps, + intel->nr_heaps, + &intel->ctx.Const, + 4, + 11, /* max 2D texture size is 2048x2048 */ + 8, /* max 3D texture size is 256^3 */ + 0, /* max CUBE. not supported */ + 0, /* max RECT. supported, but not enabled */ + 12, + GL_FALSE ); + intel->ctx.Const.MaxTextureUnits = I830_TEX_UNITS; + + _tnl_init_vertices( ctx, ctx->Const.MaxArrayLockSize + 12, + 18 * sizeof(GLfloat) ); + + intel->verts = TNL_CONTEXT(ctx)->clipspace.vertex_buf; + + i830InitState( i830 ); + + + _tnl_allow_vertex_fog( ctx, 1 ); + _tnl_allow_pixel_fog( ctx, 0 ); + + return GL_TRUE; +} + diff --git a/src/mesa/drivers/dri/i915/i830_context.h b/src/mesa/drivers/dri/i915/i830_context.h new file mode 100644 index 0000000..27948f0 --- /dev/null +++ b/src/mesa/drivers/dri/i915/i830_context.h @@ -0,0 +1,197 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#ifndef I830CONTEXT_INC +#define I830CONTEXT_INC + +#include "intel_context.h" + +#define I830_FALLBACK_TEXTURE 0x1000 +#define I830_FALLBACK_COLORMASK 0x2000 +#define I830_FALLBACK_STENCIL 0x4000 +#define I830_FALLBACK_STIPPLE 0x8000 +#define I830_FALLBACK_LOGICOP 0x10000 + +#define I830_UPLOAD_CTX 0x1 +#define I830_UPLOAD_BUFFERS 0x2 +#define I830_UPLOAD_STIPPLE 0x4 +#define I830_UPLOAD_TEX(i) (0x10<<(i)) +#define I830_UPLOAD_TEXBLEND(i) (0x100<<(i)) +#define I830_UPLOAD_TEX_ALL (0x0f0) +#define I830_UPLOAD_TEXBLEND_ALL (0xf00) + +/* State structure offsets - these will probably disappear. + */ +#define I830_DESTREG_CBUFADDR0 0 +#define I830_DESTREG_CBUFADDR1 1 +#define I830_DESTREG_CBUFADDR2 2 +#define I830_DESTREG_DBUFADDR0 3 +#define I830_DESTREG_DBUFADDR1 4 +#define I830_DESTREG_DBUFADDR2 5 +#define I830_DESTREG_DV0 6 +#define I830_DESTREG_DV1 7 +#define I830_DESTREG_SENABLE 8 +#define I830_DESTREG_SR0 9 +#define I830_DESTREG_SR1 10 +#define I830_DESTREG_SR2 11 +#define I830_DEST_SETUP_SIZE 12 + +#define I830_CTXREG_STATE1 0 +#define I830_CTXREG_STATE2 1 +#define I830_CTXREG_STATE3 2 +#define I830_CTXREG_STATE4 3 +#define I830_CTXREG_STATE5 4 +#define I830_CTXREG_IALPHAB 5 +#define I830_CTXREG_STENCILTST 6 +#define I830_CTXREG_ENABLES_1 7 +#define I830_CTXREG_ENABLES_2 8 +#define I830_CTXREG_AA 9 +#define I830_CTXREG_FOGCOLOR 10 +#define I830_CTXREG_BLENDCOLOR0 11 +#define I830_CTXREG_BLENDCOLOR1 12 +#define I830_CTXREG_VF 13 +#define I830_CTXREG_VF2 14 +#define I830_CTXREG_MCSB0 15 +#define I830_CTXREG_MCSB1 16 +#define I830_CTX_SETUP_SIZE 17 + +#define I830_STPREG_ST0 0 +#define I830_STPREG_ST1 1 +#define I830_STP_SETUP_SIZE 2 + +#define I830_TEXREG_TM0LI 0 /* load immediate 2 texture map n */ +#define I830_TEXREG_TM0S0 1 +#define I830_TEXREG_TM0S1 2 +#define I830_TEXREG_TM0S2 3 +#define I830_TEXREG_TM0S3 4 +#define I830_TEXREG_TM0S4 5 +#define I830_TEXREG_MCS 6 /* _3DSTATE_MAP_COORD_SETS */ +#define I830_TEX_SETUP_SIZE 7 + +#define I830_TEXBLEND_SIZE 12 /* (4 args + op) * 2 + COLOR_FACTOR */ + +struct i830_texture_object +{ + struct intel_texture_object intel; + GLuint Setup[I830_TEX_SETUP_SIZE]; +}; + +#define I830_TEX_UNITS 4 + +struct i830_hw_state { + GLuint Ctx[I830_CTX_SETUP_SIZE]; + GLuint Buffer[I830_DEST_SETUP_SIZE]; + GLuint Stipple[I830_STP_SETUP_SIZE]; + GLuint Tex[I830_TEX_UNITS][I830_TEX_SETUP_SIZE]; + GLuint TexBlend[I830_TEX_UNITS][I830_TEXBLEND_SIZE]; + GLuint TexBlendWordsUsed[I830_TEX_UNITS]; + GLuint emitted; /* I810_UPLOAD_* */ + GLuint active; +}; + +struct i830_context +{ + struct intel_context intel; + + GLuint last_index; + + struct i830_hw_state meta, initial, state, *current; +}; + +typedef struct i830_context *i830ContextPtr; +typedef struct i830_texture_object *i830TextureObjectPtr; + +#define I830_CONTEXT(ctx) ((i830ContextPtr)(ctx)) + + + +#define I830_STATECHANGE(i830, flag) \ +do { \ + INTEL_FIREVERTICES( &i830->intel ); \ + i830->state.emitted &= ~flag; \ +} while (0) + +#define I830_ACTIVESTATE(i830, flag, mode) \ +do { \ + INTEL_FIREVERTICES( &i830->intel ); \ + if (mode) \ + i830->state.active |= flag; \ + else \ + i830->state.active &= ~flag; \ +} while (0) + +/* i830_vtbl.c + */ +extern void +i830InitVtbl( i830ContextPtr i830 ); + +/* i830_context.c + */ +extern GLboolean +i830CreateContext( const __GLcontextModes *mesaVis, + __DRIcontextPrivate *driContextPriv, + void *sharedContextPrivate); + +/* i830_tex.c, i830_texstate.c + */ +extern void +i830UpdateTextureState( intelContextPtr intel ); + +extern void +i830InitTextureFuncs( struct dd_function_table *functions ); + +extern intelTextureObjectPtr +i830AllocTexObj( struct gl_texture_object *tObj ); + +/* i830_texblend.c + */ +extern GLuint +i830SetBlend_GL1_2(i830ContextPtr i830, int unit, + GLenum envMode, GLenum format, + GLuint texel_op, + GLuint *state, + const GLfloat *envcolor ); + +extern void +i830EmitTextureBlend( i830ContextPtr i830 ); + + +/* i830_state.c + */ +extern void +i830InitStateFuncs( struct dd_function_table *functions ); + +extern void +i830EmitState( i830ContextPtr i830 ); + +extern void +i830InitState( i830ContextPtr i830 ); + +/* i830_metaops.c + */ +extern GLboolean +i830TryTextureReadPixels( GLcontext *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + GLvoid *pixels ); + +extern GLboolean +i830TryTextureDrawPixels( GLcontext *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels ); + +extern void +i830ClearWithTris( intelContextPtr intel, GLbitfield mask, + GLboolean all, GLint cx, GLint cy, GLint cw, GLint ch); + + + +#endif + diff --git a/src/mesa/drivers/dri/i915/i830_metaops.c b/src/mesa/drivers/dri/i915/i830_metaops.c new file mode 100644 index 0000000..fb2ee12 --- /dev/null +++ b/src/mesa/drivers/dri/i915/i830_metaops.c @@ -0,0 +1,699 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "glheader.h" +#include "enums.h" +#include "mtypes.h" +#include "macros.h" +#include "utils.h" + +#include "intel_screen.h" +#include "intel_batchbuffer.h" +#include "intel_ioctl.h" + +#include "i830_context.h" +#include "i830_reg.h" + +/* A large amount of state doesn't need to be uploaded. + */ +#define ACTIVE (I830_UPLOAD_TEXBLEND(0) | \ + I830_UPLOAD_STIPPLE | \ + I830_UPLOAD_CTX | \ + I830_UPLOAD_BUFFERS | \ + I830_UPLOAD_TEX(0)) + + +#define SET_STATE( i830, STATE ) \ +do { \ + i830->current->emitted &= ~ACTIVE; \ + i830->current = &i830->STATE; \ + i830->current->emitted &= ~ACTIVE; \ +} while (0) + +/* Operations where the 3D engine is decoupled temporarily from the + * current GL state and used for other purposes than simply rendering + * incoming triangles. + */ +static void set_initial_state( i830ContextPtr i830 ) +{ + memcpy(&i830->meta, &i830->initial, sizeof(i830->meta) ); + i830->meta.active = ACTIVE; + i830->meta.emitted = 0; +} + + +static void set_no_depth_stencil_write( i830ContextPtr i830 ) +{ + /* ctx->Driver.Enable( ctx, GL_STENCIL_TEST, GL_FALSE ) + */ + i830->meta.Ctx[I830_CTXREG_ENABLES_1] &= ~ENABLE_STENCIL_TEST; + i830->meta.Ctx[I830_CTXREG_ENABLES_2] &= ~ENABLE_STENCIL_WRITE; + i830->meta.Ctx[I830_CTXREG_ENABLES_1] |= DISABLE_STENCIL_TEST; + i830->meta.Ctx[I830_CTXREG_ENABLES_2] |= DISABLE_STENCIL_WRITE; + + + /* ctx->Driver.Enable( ctx, GL_DEPTH_TEST, GL_FALSE ) + */ + i830->meta.Ctx[I830_CTXREG_ENABLES_1] &= ~ENABLE_DIS_DEPTH_TEST_MASK; + i830->meta.Ctx[I830_CTXREG_ENABLES_2] &= ~ENABLE_DIS_DEPTH_WRITE_MASK; + i830->meta.Ctx[I830_CTXREG_ENABLES_1] |= DISABLE_DEPTH_TEST; + i830->meta.Ctx[I830_CTXREG_ENABLES_2] |= DISABLE_DEPTH_WRITE; + + i830->meta.emitted &= ~I830_UPLOAD_CTX; +} + +/* Set stencil unit to replace always with the reference value. + */ +static void set_stencil_replace( i830ContextPtr i830, + GLuint s_mask, + GLuint s_clear) +{ + /* ctx->Driver.Enable( ctx, GL_STENCIL_TEST, GL_TRUE ) + */ + i830->meta.Ctx[I830_CTXREG_ENABLES_1] |= ENABLE_STENCIL_TEST; + i830->meta.Ctx[I830_CTXREG_ENABLES_2] |= ENABLE_STENCIL_WRITE; + + + /* ctx->Driver.Enable( ctx, GL_DEPTH_TEST, GL_FALSE ) + */ + i830->meta.Ctx[I830_CTXREG_ENABLES_1] &= ~ENABLE_DIS_DEPTH_TEST_MASK; + i830->meta.Ctx[I830_CTXREG_ENABLES_2] &= ~ENABLE_DIS_DEPTH_WRITE_MASK; + i830->meta.Ctx[I830_CTXREG_ENABLES_1] |= DISABLE_DEPTH_TEST; + i830->meta.Ctx[I830_CTXREG_ENABLES_2] |= DISABLE_DEPTH_WRITE; + + /* ctx->Driver.StencilMask( ctx, s_mask ) + */ + i830->meta.Ctx[I830_CTXREG_STATE4] &= ~MODE4_ENABLE_STENCIL_WRITE_MASK; + i830->meta.Ctx[I830_CTXREG_STATE4] |= (ENABLE_STENCIL_WRITE_MASK | + STENCIL_WRITE_MASK((s_mask&0xff))); + + /* ctx->Driver.StencilOp( ctx, GL_REPLACE, GL_REPLACE, GL_REPLACE ) + */ + i830->meta.Ctx[I830_CTXREG_STENCILTST] &= ~(STENCIL_OPS_MASK); + i830->meta.Ctx[I830_CTXREG_STENCILTST] |= + (ENABLE_STENCIL_PARMS | + STENCIL_FAIL_OP(STENCILOP_REPLACE) | + STENCIL_PASS_DEPTH_FAIL_OP(STENCILOP_REPLACE) | + STENCIL_PASS_DEPTH_PASS_OP(STENCILOP_REPLACE)); + + /* ctx->Driver.StencilFunc( ctx, GL_ALWAYS, s_clear, ~0 ) + */ + i830->meta.Ctx[I830_CTXREG_STATE4] &= ~MODE4_ENABLE_STENCIL_TEST_MASK; + i830->meta.Ctx[I830_CTXREG_STATE4] |= (ENABLE_STENCIL_TEST_MASK | + STENCIL_TEST_MASK(0xff)); + + i830->meta.Ctx[I830_CTXREG_STENCILTST] &= ~(STENCIL_REF_VALUE_MASK | + ENABLE_STENCIL_TEST_FUNC_MASK); + i830->meta.Ctx[I830_CTXREG_STENCILTST] |= + (ENABLE_STENCIL_REF_VALUE | + ENABLE_STENCIL_TEST_FUNC | + STENCIL_REF_VALUE((s_clear&0xff)) | + STENCIL_TEST_FUNC(COMPAREFUNC_ALWAYS)); + + + + i830->meta.emitted &= ~I830_UPLOAD_CTX; +} + + +static void set_color_mask( i830ContextPtr i830, GLboolean state ) +{ + const GLuint mask = ((1 << WRITEMASK_RED_SHIFT) | + (1 << WRITEMASK_GREEN_SHIFT) | + (1 << WRITEMASK_BLUE_SHIFT) | + (1 << WRITEMASK_ALPHA_SHIFT)); + + if (state) { + i830->meta.Ctx[I830_CTXREG_ENABLES_2] &= ~mask; + i830->meta.Ctx[I830_CTXREG_ENABLES_2] |= + (i830->state.Ctx[I830_CTXREG_ENABLES_2] & mask); + } + else + i830->meta.Ctx[I830_CTXREG_ENABLES_2] |= mask; + + i830->meta.emitted &= ~I830_UPLOAD_CTX; +} + +/* Installs a one-stage passthrough texture blend pipeline. Is there + * more that can be done to turn off texturing? + */ +static void set_no_texture( i830ContextPtr i830 ) +{ + i830->meta.TexBlendWordsUsed[0] = + i830SetBlend_GL1_2( i830, 0, GL_NONE, 0, + TEXBLENDARG_TEXEL0, + i830->meta.TexBlend[0], 0 ); + i830->meta.TexBlend[0][0] |= TEXOP_LAST_STAGE; + i830->meta.emitted &= ~I830_UPLOAD_TEXBLEND(0); +} + +/* Set up a single element blend stage for 'replace' texturing with no + * funny ops. + */ +static void enable_texture_blend_replace( i830ContextPtr i830, + GLenum format ) +{ + i830->meta.TexBlendWordsUsed[0] = + i830SetBlend_GL1_2( i830, 0, GL_REPLACE, format, + TEXBLENDARG_TEXEL0, + i830->meta.TexBlend[0], 0 ); + i830->meta.TexBlend[0][0] |= TEXOP_LAST_STAGE; + i830->meta.emitted &= ~I830_UPLOAD_TEXBLEND(0); + +/* fprintf(stderr, "%s: TexBlendWordsUsed[0]: %d\n", */ +/* __FUNCTION__, i830->meta.TexBlendWordsUsed[0]); */ +} + + + +/* Set up an arbitary piece of memory as a rectangular texture + * (including the front or back buffer). + */ +static void set_tex_rect_source( i830ContextPtr i830, + GLuint offset, + GLuint width, + GLuint height, + GLuint pitch, + GLuint textureFormat ) +{ + GLint numLevels = 1; + GLuint *setup = i830->meta.Tex[0]; + + pitch *= i830->intel.intelScreen->cpp; + +/* fprintf(stderr, "%s: offset: %x w: %d h: %d pitch %d format %x\n", */ +/* __FUNCTION__, offset, width, height, pitch, textureFormat ); */ + + setup[I830_TEXREG_TM0LI] = (_3DSTATE_LOAD_STATE_IMMEDIATE_2 | + (LOAD_TEXTURE_MAP0 << 0) | 4); + setup[I830_TEXREG_TM0S0] = (TM0S0_USE_FENCE | offset); + setup[I830_TEXREG_TM0S1] = (((height - 1) << TM0S1_HEIGHT_SHIFT) | + ((width - 1) << TM0S1_WIDTH_SHIFT) | + textureFormat); + setup[I830_TEXREG_TM0S2] = ((((pitch / 4) - 1) << TM0S2_PITCH_SHIFT)); + setup[I830_TEXREG_TM0S3] &= ~TM0S3_MAX_MIP_MASK; + setup[I830_TEXREG_TM0S3] &= ~TM0S3_MIN_MIP_MASK; + setup[I830_TEXREG_TM0S3] |= ((numLevels - 1)*4) << TM0S3_MIN_MIP_SHIFT; + + setup[I830_TEXREG_MCS] = (_3DSTATE_MAP_COORD_SET_CMD | + MAP_UNIT(0) | + ENABLE_TEXCOORD_PARAMS | + TEXCOORDS_ARE_IN_TEXELUNITS | + TEXCOORDTYPE_CARTESIAN | + ENABLE_ADDR_V_CNTL | + TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_WRAP) | + ENABLE_ADDR_U_CNTL | + TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_WRAP)); + + i830->meta.emitted &= ~I830_UPLOAD_TEX(0); +} + + +/* Select between front and back draw buffers. + */ +static void set_draw_offset( i830ContextPtr i830, + GLuint offset ) +{ + i830->meta.Buffer[I830_DESTREG_CBUFADDR2] = offset; + i830->meta.emitted &= ~I830_UPLOAD_BUFFERS; +} + +/* Setup an arbitary draw format, useful for targeting + * texture or agp memory. + */ +static void set_draw_format( i830ContextPtr i830, + GLuint format, + GLuint depth_format) +{ + i830->meta.Buffer[I830_DESTREG_DV1] = (DSTORG_HORT_BIAS(0x8) | /* .5 */ + DSTORG_VERT_BIAS(0x8) | /* .5 */ + format | + DEPTH_IS_Z | + depth_format); +} + + +static void set_vertex_format( i830ContextPtr i830 ) +{ + i830->meta.Ctx[I830_CTXREG_VF] = (_3DSTATE_VFT0_CMD | + VFT0_TEX_COUNT(1) | + VFT0_DIFFUSE | + VFT0_SPEC | + VFT0_XYZW); + i830->meta.Ctx[I830_CTXREG_VF2] = (_3DSTATE_VFT1_CMD | + VFT1_TEX0_FMT(TEXCOORDFMT_2D) | + VFT1_TEX1_FMT(TEXCOORDFMT_2D) | + VFT1_TEX2_FMT(TEXCOORDFMT_2D) | + VFT1_TEX3_FMT(TEXCOORDFMT_2D)); + i830->meta.emitted &= ~I830_UPLOAD_CTX; +} + + +static void draw_quad(i830ContextPtr i830, + GLfloat x0, GLfloat x1, + GLfloat y0, GLfloat y1, + GLubyte red, GLubyte green, + GLubyte blue, GLubyte alpha, + GLfloat s0, GLfloat s1, + GLfloat t0, GLfloat t1 ) +{ + GLuint vertex_size = 8; + GLuint *vb = intelEmitInlinePrimitiveLocked( &i830->intel, + PRIM3D_TRIFAN, + 4*vertex_size, + vertex_size ); + intelVertex tmp; + int i; + + +/* fprintf(stderr, "%s: %f,%f-%f,%f 0x%x%x%x%x %f,%f-%f,%f\n", */ +/* __FUNCTION__, */ +/* x0,y0,x1,y1,red,green,blue,alpha,s0,t0,s1,t1); */ + + + /* initial vertex, left bottom */ + tmp.v.x = x0; + tmp.v.y = y0; + tmp.v.z = 1.0; + tmp.v.w = 1.0; + tmp.v.color.red = red; + tmp.v.color.green = green; + tmp.v.color.blue = blue; + tmp.v.color.alpha = alpha; + tmp.v.specular.red = 0; + tmp.v.specular.green = 0; + tmp.v.specular.blue = 0; + tmp.v.specular.alpha = 0; + tmp.v.u0 = s0; + tmp.v.v0 = t0; + for (i = 0 ; i < 8 ; i++) + vb[i] = tmp.ui[i]; + + /* right bottom */ + vb += 8; + tmp.v.x = x1; + tmp.v.u0 = s1; + for (i = 0 ; i < 8 ; i++) + vb[i] = tmp.ui[i]; + + /* right top */ + vb += 8; + tmp.v.y = y1; + tmp.v.v0 = t1; + for (i = 0 ; i < 8 ; i++) + vb[i] = tmp.ui[i]; + + /* left top */ + vb += 8; + tmp.v.x = x0; + tmp.v.u0 = s0; + for (i = 0 ; i < 8 ; i++) + vb[i] = tmp.ui[i]; + +/* fprintf(stderr, "%s: DV1: %x\n", */ +/* __FUNCTION__, i830->meta.Buffer[I830_DESTREG_DV1]); */ +} + +void +i830ClearWithTris(intelContextPtr intel, GLbitfield mask, + GLboolean all, + GLint cx, GLint cy, GLint cw, GLint ch) +{ + i830ContextPtr i830 = I830_CONTEXT( intel ); + __DRIdrawablePrivate *dPriv = intel->driDrawable; + intelScreenPrivate *screen = intel->intelScreen; + int x0, y0, x1, y1; + + + SET_STATE( i830, meta ); + set_initial_state( i830 ); + set_no_texture( i830 ); + set_vertex_format( i830 ); + + LOCK_HARDWARE(intel); + + if(!all) { + x0 = cx; + y0 = cy; + x1 = x0 + cw; + y1 = y0 + ch; + } else { + x0 = 0; + y0 = 0; + x1 = x0 + dPriv->w; + y1 = y0 + dPriv->h; + } + + /* Don't do any clipping to screen - these are window coordinates. + * The active cliprects will be applied as for any other geometry. + */ + + if(mask & DD_FRONT_LEFT_BIT) { + set_no_depth_stencil_write( i830 ); + set_color_mask( i830, GL_TRUE ); + set_draw_offset( i830, screen->frontOffset ); + draw_quad(i830, x0, x1, y0, y1, + intel->clear_red, intel->clear_green, + intel->clear_blue, intel->clear_alpha, + 0, 0, 0, 0); + } + + if(mask & DD_BACK_LEFT_BIT) { + set_no_depth_stencil_write( i830 ); + set_color_mask( i830, GL_TRUE ); + set_draw_offset( i830, screen->backOffset ); + + draw_quad(i830, x0, x1, y0, y1, + intel->clear_red, intel->clear_green, + intel->clear_blue, intel->clear_alpha, + 0, 0, 0, 0); + } + + if(mask & DD_STENCIL_BIT) { + set_stencil_replace( i830, + intel->ctx.Stencil.WriteMask[0], + intel->ctx.Stencil.Clear); + + set_color_mask( i830, GL_FALSE ); + set_draw_offset( i830, screen->frontOffset ); + draw_quad( i830, x0, x1, y0, y1, 0, 0, 0, 0, 0, 0, 0, 0 ); + } + + UNLOCK_HARDWARE(intel); + + SET_STATE( i830, state ); +} + + + + +GLboolean +i830TryTextureReadPixels( GLcontext *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + GLvoid *pixels ) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + intelContextPtr intel = INTEL_CONTEXT(ctx); + intelScreenPrivate *screen = i830->intel.intelScreen; + GLint pitch = pack->RowLength ? pack->RowLength : width; + __DRIdrawablePrivate *dPriv = i830->intel.driDrawable; + int textureFormat; + GLenum glTextureFormat; + int src_offset = i830->meta.Buffer[I830_DESTREG_CBUFADDR2]; + int destOffset = intelAgpOffsetFromVirtual( &i830->intel, pixels); + int destFormat, depthFormat, destPitch; + drm_clip_rect_t tmp; + + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s\n", __FUNCTION__); + + + if ( ctx->_ImageTransferState || + pack->SwapBytes || + pack->LsbFirst || + !pack->Invert) { + fprintf(stderr, "%s: check_color failed\n", __FUNCTION__); + return GL_FALSE; + } + + switch (screen->fbFormat) { + case DV_PF_565: + textureFormat = MAPSURF_16BIT | MT_16BIT_RGB565; + glTextureFormat = GL_RGB; + break; + case DV_PF_555: + textureFormat = MAPSURF_16BIT | MT_16BIT_ARGB1555; + glTextureFormat = GL_RGBA; + break; + case DV_PF_8888: + textureFormat = MAPSURF_32BIT | MT_32BIT_ARGB8888; + glTextureFormat = GL_RGBA; + break; + default: + fprintf(stderr, "%s: textureFormat failed %x\n", __FUNCTION__, + screen->fbFormat); + return GL_FALSE; + } + + + switch (type) { + case GL_UNSIGNED_SHORT_5_6_5: + if (format != GL_RGB) return GL_FALSE; + destFormat = COLR_BUF_RGB565; + depthFormat = DEPTH_FRMT_16_FIXED; + destPitch = pitch * 2; + break; + case GL_UNSIGNED_INT_8_8_8_8_REV: + if (format != GL_BGRA) return GL_FALSE; + destFormat = COLR_BUF_ARGB8888; + depthFormat = DEPTH_FRMT_24_FIXED_8_OTHER; + destPitch = pitch * 4; + break; + default: + fprintf(stderr, "%s: destFormat failed %s\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(type)); + return GL_FALSE; + } + + destFormat |= (0x02<<24); + +/* fprintf(stderr, "type: %s destFormat: %x\n", */ +/* _mesa_lookup_enum_by_nr(type), */ +/* destFormat); */ + + intelFlush( ctx ); + + SET_STATE( i830, meta ); + set_initial_state( i830 ); + set_no_depth_stencil_write( i830 ); + + LOCK_HARDWARE( intel ); + { + intelWaitForIdle( intel ); /* required by GL */ + + if (!driClipRectToFramebuffer(ctx->ReadBuffer, &x, &y, &width, &height)) { + UNLOCK_HARDWARE( intel ); + SET_STATE(i830, state); + fprintf(stderr, "%s: cliprect failed\n", __FUNCTION__); + return GL_TRUE; + } + +#if 0 + /* FIXME -- Just emit the correct state + */ + if (i830SetParam(i830->driFd, I830_SETPARAM_CBUFFER_PITCH, + destPitch) != 0) { + UNLOCK_HARDWARE( intel ); + SET_STATE(i830, state); + fprintf(stderr, "%s: setparam failed\n", __FUNCTION__); + return GL_FALSE; + } +#endif + + + y = dPriv->h - y - height; + x += dPriv->x; + y += dPriv->y; + + + /* Set the frontbuffer up as a large rectangular texture. + */ + set_tex_rect_source( i830, + src_offset, + screen->width, + screen->height, + screen->frontPitch, + textureFormat ); + + + enable_texture_blend_replace( i830, glTextureFormat ); + + + /* Set the 3d engine to draw into the agp memory + */ + + set_draw_offset( i830, destOffset ); + set_draw_format( i830, destFormat, depthFormat ); + + + /* Draw a single quad, no cliprects: + */ + i830->intel.numClipRects = 1; + i830->intel.pClipRects = &tmp; + i830->intel.pClipRects[0].x1 = 0; + i830->intel.pClipRects[0].y1 = 0; + i830->intel.pClipRects[0].x2 = width; + i830->intel.pClipRects[0].y2 = height; + + draw_quad( i830, + 0, width, 0, height, + 0, 255, 0, 0, + x, x+width, y, y+height ); + + intelWindowMoved( intel ); + } + UNLOCK_HARDWARE( intel ); + intelFinish( ctx ); /* required by GL */ + + SET_STATE( i830, state ); + return GL_TRUE; +} + + +GLboolean +i830TryTextureDrawPixels( GLcontext *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + i830ContextPtr i830 = I830_CONTEXT(ctx); + GLint pitch = unpack->RowLength ? unpack->RowLength : width; + __DRIdrawablePrivate *dPriv = intel->driDrawable; + int textureFormat; + GLenum glTextureFormat; + int dst_offset = i830->meta.Buffer[I830_DESTREG_CBUFADDR2]; + int src_offset = intelAgpOffsetFromVirtual( intel, pixels ); + + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s\n", __FUNCTION__); + + /* Todo -- upload images that aren't in agp space, then texture + * from them. + */ + + if ( !intelIsAgpMemory( intel, pixels, pitch*height ) ) { + fprintf(stderr, "%s: intelIsAgpMemory failed\n", __FUNCTION__); + return GL_FALSE; + } + + /* Todo -- don't want to clobber all the drawing state like we do + * for readpixels -- most of this state can be handled just fine. + */ + if ( ctx->_ImageTransferState || + unpack->SwapBytes || + unpack->LsbFirst || + ctx->Color.AlphaEnabled || + ctx->Depth.Test || + ctx->Fog.Enabled || + ctx->Scissor.Enabled || + ctx->Stencil.Enabled || + !ctx->Color.ColorMask[0] || + !ctx->Color.ColorMask[1] || + !ctx->Color.ColorMask[2] || + !ctx->Color.ColorMask[3] || + ctx->Color.ColorLogicOpEnabled || + ctx->Texture._EnabledUnits || + ctx->Depth.OcclusionTest) { + fprintf(stderr, "%s: other tests failed\n", __FUNCTION__); + return GL_FALSE; + } + + /* Todo -- remove these restrictions: + */ + if (ctx->Pixel.ZoomX != 1.0F || + ctx->Pixel.ZoomY != -1.0F) + return GL_FALSE; + + + + switch (type) { + case GL_UNSIGNED_SHORT_1_5_5_5_REV: + if (format != GL_BGRA) return GL_FALSE; + textureFormat = MAPSURF_16BIT | MT_16BIT_ARGB1555; + glTextureFormat = GL_RGBA; + break; + case GL_UNSIGNED_SHORT_5_6_5: + if (format != GL_RGB) return GL_FALSE; + textureFormat = MAPSURF_16BIT | MT_16BIT_RGB565; + glTextureFormat = GL_RGB; + break; + case GL_UNSIGNED_SHORT_8_8_MESA: + if (format != GL_YCBCR_MESA) return GL_FALSE; + textureFormat = (MAPSURF_422 | MT_422_YCRCB_SWAPY +/* | TM0S1_COLORSPACE_CONVERSION */ + ); + glTextureFormat = GL_YCBCR_MESA; + break; + case GL_UNSIGNED_SHORT_8_8_REV_MESA: + if (format != GL_YCBCR_MESA) return GL_FALSE; + textureFormat = (MAPSURF_422 | MT_422_YCRCB_NORMAL +/* | TM0S1_COLORSPACE_CONVERSION */ + ); + glTextureFormat = GL_YCBCR_MESA; + break; + case GL_UNSIGNED_INT_8_8_8_8_REV: + if (format != GL_BGRA) return GL_FALSE; + textureFormat = MAPSURF_32BIT | MT_32BIT_ARGB8888; + glTextureFormat = GL_RGBA; + break; + default: + fprintf(stderr, "%s: destFormat failed\n", __FUNCTION__); + return GL_FALSE; + } + + intelFlush( ctx ); + + SET_STATE( i830, meta ); + + LOCK_HARDWARE( intel ); + { + intelWaitForIdle( intel ); /* required by GL */ + + y -= height; /* cope with pixel zoom */ + + if (!driClipRectToFramebuffer(ctx->ReadBuffer, &x, &y, &width, &height)) { + UNLOCK_HARDWARE( intel ); + SET_STATE(i830, state); + fprintf(stderr, "%s: cliprect failed\n", __FUNCTION__); + return GL_TRUE; + } + + + y = dPriv->h - y - height; + + set_initial_state( i830 ); + + /* Set the pixel image up as a rectangular texture. + */ + set_tex_rect_source( i830, + src_offset, + width, + height, + pitch, /* XXXX!!!! -- /2 sometimes */ + textureFormat ); + + + enable_texture_blend_replace( i830, glTextureFormat ); + + + /* Draw to the current draw buffer: + */ + set_draw_offset( i830, dst_offset ); + + /* Draw a quad, use regular cliprects + */ +/* fprintf(stderr, "x: %d y: %d width %d height %d\n", x, y, width, height); */ + + draw_quad( i830, + x, x+width, y, y+height, + 0, 255, 0, 0, + 0, width, 0, height ); + + intelWindowMoved( intel ); + } + UNLOCK_HARDWARE( intel ); + intelFinish( ctx ); /* required by GL */ + + SET_STATE(i830, state); + + return GL_TRUE; +} + diff --git a/src/mesa/drivers/dri/i915/i830_reg.h b/src/mesa/drivers/dri/i915/i830_reg.h new file mode 100644 index 0000000..176c869 --- /dev/null +++ b/src/mesa/drivers/dri/i915/i830_reg.h @@ -0,0 +1,665 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + + +#ifndef _I830_REG_H_ +#define _I830_REG_H_ + + +#include "intel_reg.h" + +#define I830_SET_FIELD( var, mask, value ) (var &= ~(mask), var |= value) + +#define _3DSTATE_AA_CMD (CMD_3D | (0x06<<24)) +#define AA_LINE_ECAAR_WIDTH_ENABLE (1<<16) +#define AA_LINE_ECAAR_WIDTH_0_5 0 +#define AA_LINE_ECAAR_WIDTH_1_0 (1<<14) +#define AA_LINE_ECAAR_WIDTH_2_0 (2<<14) +#define AA_LINE_ECAAR_WIDTH_4_0 (3<<14) +#define AA_LINE_REGION_WIDTH_ENABLE (1<<8) +#define AA_LINE_REGION_WIDTH_0_5 0 +#define AA_LINE_REGION_WIDTH_1_0 (1<<6) +#define AA_LINE_REGION_WIDTH_2_0 (2<<6) +#define AA_LINE_REGION_WIDTH_4_0 (3<<6) +#define AA_LINE_ENABLE ((1<<1) | 1) +#define AA_LINE_DISABLE (1<<1) + +#define _3DSTATE_BUF_INFO_CMD (CMD_3D | (0x1d<<24) | (0x8e<<16) | 1) +/* Dword 1 */ +#define BUF_3D_ID_COLOR_BACK (0x3<<24) +#define BUF_3D_ID_DEPTH (0x7<<24) +#define BUF_3D_USE_FENCE (1<<23) +#define BUF_3D_TILED_SURFACE (1<<22) +#define BUF_3D_TILE_WALK_X 0 +#define BUF_3D_TILE_WALK_Y (1<<21) +#define BUF_3D_PITCH(x) (((x)/4)<<2) +/* Dword 2 */ +#define BUF_3D_ADDR(x) ((x) & ~0x3) + + +#define _3DSTATE_COLOR_FACTOR_CMD (CMD_3D | (0x1d<<24) | (0x1<<16)) + +#define _3DSTATE_COLOR_FACTOR_N_CMD(stage) (CMD_3D | (0x1d<<24) | \ + ((0x90+(stage))<<16)) + +#define _3DSTATE_CONST_BLEND_COLOR_CMD (CMD_3D | (0x1d<<24) | (0x88<<16)) + +#define _3DSTATE_DFLT_DIFFUSE_CMD (CMD_3D | (0x1d<<24) | (0x99<<16)) + +#define _3DSTATE_DFLT_SPEC_CMD (CMD_3D | (0x1d<<24) | (0x9a<<16)) + +#define _3DSTATE_DFLT_Z_CMD (CMD_3D | (0x1d<<24) | (0x98<<16)) + + +#define _3DSTATE_DST_BUF_VARS_CMD (CMD_3D | (0x1d<<24) | (0x85<<16)) +/* Dword 1 */ +#define DSTORG_HORT_BIAS(x) ((x)<<20) +#define DSTORG_VERT_BIAS(x) ((x)<<16) +#define COLOR_4_2_2_CHNL_WRT_ALL 0 +#define COLOR_4_2_2_CHNL_WRT_Y (1<<12) +#define COLOR_4_2_2_CHNL_WRT_CR (2<<12) +#define COLOR_4_2_2_CHNL_WRT_CB (3<<12) +#define COLOR_4_2_2_CHNL_WRT_CRCB (4<<12) +#define COLR_BUF_8BIT 0 +#define COLR_BUF_RGB555 (1<<8) +#define COLR_BUF_RGB565 (2<<8) +#define COLR_BUF_ARGB8888 (3<<8) +#define DEPTH_IS_Z 0 +#define DEPTH_IS_W (1<<6) +#define DEPTH_FRMT_16_FIXED 0 +#define DEPTH_FRMT_16_FLOAT (1<<2) +#define DEPTH_FRMT_24_FIXED_8_OTHER (2<<2) +#define DEPTH_FRMT_24_FLOAT_8_OTHER (3<<2) +#define VERT_LINE_STRIDE_1 (1<<1) +#define VERT_LINE_STRIDE_0 0 +#define VERT_LINE_STRIDE_OFS_1 1 +#define VERT_LINE_STRIDE_OFS_0 0 + + +#define _3DSTATE_DRAW_RECT_CMD (CMD_3D|(0x1d<<24)|(0x80<<16)|3) +/* Dword 1 */ +#define DRAW_RECT_DIS_DEPTH_OFS (1<<30) +#define DRAW_DITHER_OFS_X(x) ((x)<<26) +#define DRAW_DITHER_OFS_Y(x) ((x)<<24) +/* Dword 2 */ +#define DRAW_YMIN(x) ((x)<<16) +#define DRAW_XMIN(x) (x) +/* Dword 3 */ +#define DRAW_YMAX(x) ((x)<<16) +#define DRAW_XMAX(x) (x) +/* Dword 4 */ +#define DRAW_YORG(x) ((x)<<16) +#define DRAW_XORG(x) (x) + + +#define _3DSTATE_ENABLES_1_CMD (CMD_3D|(0x3<<24)) +#define ENABLE_LOGIC_OP_MASK ((1<<23)|(1<<22)) +#define ENABLE_LOGIC_OP ((1<<23)|(1<<22)) +#define DISABLE_LOGIC_OP (1<<23) +#define ENABLE_STENCIL_TEST ((1<<21)|(1<<20)) +#define DISABLE_STENCIL_TEST (1<<21) +#define ENABLE_DEPTH_BIAS ((1<<11)|(1<<10)) +#define DISABLE_DEPTH_BIAS (1<<11) +#define ENABLE_SPEC_ADD_MASK ((1<<9)|(1<<8)) +#define ENABLE_SPEC_ADD ((1<<9)|(1<<8)) +#define DISABLE_SPEC_ADD (1<<9) +#define ENABLE_DIS_FOG_MASK ((1<<7)|(1<<6)) +#define ENABLE_FOG ((1<<7)|(1<<6)) +#define DISABLE_FOG (1<<7) +#define ENABLE_DIS_ALPHA_TEST_MASK ((1<<5)|(1<<4)) +#define ENABLE_ALPHA_TEST ((1<<5)|(1<<4)) +#define DISABLE_ALPHA_TEST (1<<5) +#define ENABLE_DIS_CBLEND_MASK ((1<<3)|(1<<2)) +#define ENABLE_COLOR_BLEND ((1<<3)|(1<<2)) +#define DISABLE_COLOR_BLEND (1<<3) +#define ENABLE_DIS_DEPTH_TEST_MASK ((1<<1)|1) +#define ENABLE_DEPTH_TEST ((1<<1)|1) +#define DISABLE_DEPTH_TEST (1<<1) + +/* _3DSTATE_ENABLES_2, p138 */ +#define _3DSTATE_ENABLES_2_CMD (CMD_3D|(0x4<<24)) +#define ENABLE_STENCIL_WRITE ((1<<21)|(1<<20)) +#define DISABLE_STENCIL_WRITE (1<<21) +#define ENABLE_TEX_CACHE ((1<<17)|(1<<16)) +#define DISABLE_TEX_CACHE (1<<17) +#define ENABLE_DITHER ((1<<9)|(1<<8)) +#define DISABLE_DITHER (1<<9) +#define ENABLE_COLOR_MASK (1<<10) +#define WRITEMASK_ALPHA (1<<7) +#define WRITEMASK_ALPHA_SHIFT 7 +#define WRITEMASK_RED (1<<6) +#define WRITEMASK_RED_SHIFT 6 +#define WRITEMASK_GREEN (1<<5) +#define WRITEMASK_GREEN_SHIFT 5 +#define WRITEMASK_BLUE (1<<4) +#define WRITEMASK_BLUE_SHIFT 4 +#define WRITEMASK_MASK ((1<<4)|(1<<5)|(1<<6)|(1<<7)) +#define ENABLE_COLOR_WRITE ((1<<3)|(1<<2)) +#define DISABLE_COLOR_WRITE (1<<3) +#define ENABLE_DIS_DEPTH_WRITE_MASK 0x3 +#define ENABLE_DEPTH_WRITE ((1<<1)|1) +#define DISABLE_DEPTH_WRITE (1<<1) + +/* _3DSTATE_FOG_COLOR, p139 */ +#define _3DSTATE_FOG_COLOR_CMD (CMD_3D|(0x15<<24)) +#define FOG_COLOR_RED(x) ((x)<<16) +#define FOG_COLOR_GREEN(x) ((x)<<8) +#define FOG_COLOR_BLUE(x) (x) + +/* _3DSTATE_FOG_MODE, p140 */ +#define _3DSTATE_FOG_MODE_CMD (CMD_3D|(0x1d<<24)|(0x89<<16)|2) +/* Dword 1 */ +#define FOGFUNC_ENABLE (1<<31) +#define FOGFUNC_VERTEX 0 +#define FOGFUNC_PIXEL_EXP (1<<28) +#define FOGFUNC_PIXEL_EXP2 (2<<28) +#define FOGFUNC_PIXEL_LINEAR (3<<28) +#define FOGSRC_INDEX_Z (1<<27) +#define FOGSRC_INDEX_W ((1<<27)|(1<<25)) +#define FOG_LINEAR_CONST (1<<24) +#define FOG_CONST_1(x) ((x)<<4) +#define ENABLE_FOG_DENSITY (1<<23) +/* Dword 2 */ +#define FOG_CONST_2(x) (x) +/* Dword 3 */ +#define FOG_DENSITY(x) (x) + +/* _3DSTATE_INDEPENDENT_ALPHA_BLEND, p142 */ +#define _3DSTATE_INDPT_ALPHA_BLEND_CMD (CMD_3D|(0x0b<<24)) +#define ENABLE_INDPT_ALPHA_BLEND ((1<<23)|(1<<22)) +#define DISABLE_INDPT_ALPHA_BLEND (1<<23) +#define ALPHA_BLENDFUNC_MASK 0x3f0000 +#define ENABLE_ALPHA_BLENDFUNC (1<<21) +#define ABLENDFUNC_ADD 0 +#define ABLENDFUNC_SUB (1<<16) +#define ABLENDFUNC_RVSE_SUB (2<<16) +#define ABLENDFUNC_MIN (3<<16) +#define ABLENDFUNC_MAX (4<<16) +#define SRC_DST_ABLEND_MASK 0xfff +#define ENABLE_SRC_ABLEND_FACTOR (1<<11) +#define SRC_ABLEND_FACT(x) ((x)<<6) +#define ENABLE_DST_ABLEND_FACTOR (1<<5) +#define DST_ABLEND_FACT(x) (x) + +#define BLENDFACT_ZERO 0x01 +#define BLENDFACT_ONE 0x02 +#define BLENDFACT_SRC_COLR 0x03 +#define BLENDFACT_INV_SRC_COLR 0x04 +#define BLENDFACT_SRC_ALPHA 0x05 +#define BLENDFACT_INV_SRC_ALPHA 0x06 +#define BLENDFACT_DST_ALPHA 0x07 +#define BLENDFACT_INV_DST_ALPHA 0x08 +#define BLENDFACT_DST_COLR 0x09 +#define BLENDFACT_INV_DST_COLR 0x0a +#define BLENDFACT_SRC_ALPHA_SATURATE 0x0b +#define BLENDFACT_CONST_COLOR 0x0c +#define BLENDFACT_INV_CONST_COLOR 0x0d +#define BLENDFACT_CONST_ALPHA 0x0e +#define BLENDFACT_INV_CONST_ALPHA 0x0f + +/* _3DSTATE_MAP_BLEND_ARG, p152 */ +#define _3DSTATE_MAP_BLEND_ARG_CMD(stage) (CMD_3D|(0x0e<<24)|((stage)<<20)) + +#define TEXPIPE_COLOR 0 +#define TEXPIPE_ALPHA (1<<18) +#define TEXPIPE_KILL (2<<18) +#define TEXBLEND_ARG0 0 +#define TEXBLEND_ARG1 (1<<15) +#define TEXBLEND_ARG2 (2<<15) +#define TEXBLEND_ARG3 (3<<15) +#define TEXBLENDARG_MODIFY_PARMS (1<<6) +#define TEXBLENDARG_REPLICATE_ALPHA (1<<5) +#define TEXBLENDARG_INV_ARG (1<<4) +#define TEXBLENDARG_ONE 0 +#define TEXBLENDARG_FACTOR 0x01 +#define TEXBLENDARG_ACCUM 0x02 +#define TEXBLENDARG_DIFFUSE 0x03 +#define TEXBLENDARG_SPEC 0x04 +#define TEXBLENDARG_CURRENT 0x05 +#define TEXBLENDARG_TEXEL0 0x06 +#define TEXBLENDARG_TEXEL1 0x07 +#define TEXBLENDARG_TEXEL2 0x08 +#define TEXBLENDARG_TEXEL3 0x09 +#define TEXBLENDARG_FACTOR_N 0x0e + +/* _3DSTATE_MAP_BLEND_OP, p155 */ +#define _3DSTATE_MAP_BLEND_OP_CMD(stage) (CMD_3D|(0x0d<<24)|((stage)<<20)) +#if 0 +# define TEXPIPE_COLOR 0 +# define TEXPIPE_ALPHA (1<<18) +# define TEXPIPE_KILL (2<<18) +#endif +#define ENABLE_TEXOUTPUT_WRT_SEL (1<<17) +#define TEXOP_OUTPUT_CURRENT 0 +#define TEXOP_OUTPUT_ACCUM (1<<15) +#define ENABLE_TEX_CNTRL_STAGE ((1<<12)|(1<<11)) +#define DISABLE_TEX_CNTRL_STAGE (1<<12) +#define TEXOP_SCALE_SHIFT 9 +#define TEXOP_SCALE_1X (0 << TEXOP_SCALE_SHIFT) +#define TEXOP_SCALE_2X (1 << TEXOP_SCALE_SHIFT) +#define TEXOP_SCALE_4X (2 << TEXOP_SCALE_SHIFT) +#define TEXOP_MODIFY_PARMS (1<<8) +#define TEXOP_LAST_STAGE (1<<7) +#define TEXBLENDOP_KILLPIXEL 0x02 +#define TEXBLENDOP_ARG1 0x01 +#define TEXBLENDOP_ARG2 0x02 +#define TEXBLENDOP_MODULATE 0x03 +#define TEXBLENDOP_ADD 0x06 +#define TEXBLENDOP_ADDSIGNED 0x07 +#define TEXBLENDOP_BLEND 0x08 +#define TEXBLENDOP_BLEND_AND_ADD 0x09 +#define TEXBLENDOP_SUBTRACT 0x0a +#define TEXBLENDOP_DOT3 0x0b +#define TEXBLENDOP_DOT4 0x0c +#define TEXBLENDOP_MODULATE_AND_ADD 0x0d +#define TEXBLENDOP_MODULATE_2X_AND_ADD 0x0e +#define TEXBLENDOP_MODULATE_4X_AND_ADD 0x0f + +/* _3DSTATE_MAP_BUMP_TABLE, p160 TODO */ +/* _3DSTATE_MAP_COLOR_CHROMA_KEY, p161 TODO */ + +#define _3DSTATE_MAP_COORD_TRANSFORM ((3<<29)|(0x1d<<24)|(0x8c<<16)) +#define DISABLE_TEX_TRANSFORM (1<<28) +#define TEXTURE_SET(x) (x<<29) + +#define _3DSTATE_VERTEX_TRANSFORM ((3<<29)|(0x1d<<24)|(0x8b<<16)) +#define DISABLE_VIEWPORT_TRANSFORM (1<<31) +#define DISABLE_PERSPECTIVE_DIVIDE (1<<29) + + +/* _3DSTATE_MAP_COORD_SET_BINDINGS, p162 */ +#define _3DSTATE_MAP_COORD_SETBIND_CMD (CMD_3D|(0x1d<<24)|(0x02<<16)) +#define TEXBIND_MASK3 ((1<<15)|(1<<14)|(1<<13)|(1<<12)) +#define TEXBIND_MASK2 ((1<<11)|(1<<10)|(1<<9)|(1<<8)) +#define TEXBIND_MASK1 ((1<<7)|(1<<6)|(1<<5)|(1<<4)) +#define TEXBIND_MASK0 ((1<<3)|(1<<2)|(1<<1)|1) + +#define TEXBIND_SET3(x) ((x)<<12) +#define TEXBIND_SET2(x) ((x)<<8) +#define TEXBIND_SET1(x) ((x)<<4) +#define TEXBIND_SET0(x) (x) + +#define TEXCOORDSRC_KEEP 0 +#define TEXCOORDSRC_DEFAULT 0x01 +#define TEXCOORDSRC_VTXSET_0 0x08 +#define TEXCOORDSRC_VTXSET_1 0x09 +#define TEXCOORDSRC_VTXSET_2 0x0a +#define TEXCOORDSRC_VTXSET_3 0x0b +#define TEXCOORDSRC_VTXSET_4 0x0c +#define TEXCOORDSRC_VTXSET_5 0x0d +#define TEXCOORDSRC_VTXSET_6 0x0e +#define TEXCOORDSRC_VTXSET_7 0x0f + +#define MAP_UNIT(unit) ((unit)<<16) +#define MAP_UNIT_MASK (0x7<<16) + +/* _3DSTATE_MAP_COORD_SETS, p164 */ +#define _3DSTATE_MAP_COORD_SET_CMD (CMD_3D|(0x1c<<24)|(0x01<<19)) +#define ENABLE_TEXCOORD_PARAMS (1<<15) +#define TEXCOORDS_ARE_NORMAL (1<<14) +#define TEXCOORDS_ARE_IN_TEXELUNITS 0 +#define TEXCOORDTYPE_CARTESIAN 0 +#define TEXCOORDTYPE_HOMOGENEOUS (1<<11) +#define TEXCOORDTYPE_VECTOR (2<<11) +#define TEXCOORDTYPE_MASK (0x7<<11) +#define ENABLE_ADDR_V_CNTL (1<<7) +#define ENABLE_ADDR_U_CNTL (1<<3) +#define TEXCOORD_ADDR_V_MODE(x) ((x)<<4) +#define TEXCOORD_ADDR_U_MODE(x) (x) +#define TEXCOORDMODE_WRAP 0 +#define TEXCOORDMODE_MIRROR 1 +#define TEXCOORDMODE_CLAMP 2 +#define TEXCOORDMODE_WRAP_SHORTEST 3 +#define TEXCOORDMODE_CLAMP_BORDER 4 +#define TEXCOORD_ADDR_V_MASK 0x70 +#define TEXCOORD_ADDR_U_MASK 0x7 + +/* _3DSTATE_MAP_CUBE, p168 TODO */ +#define _3DSTATE_MAP_CUBE (CMD_3D|(0x1c<<24)|(0x0a<<19)) +#define CUBE_NEGX_ENABLE (1<<5) +#define CUBE_POSX_ENABLE (1<<4) +#define CUBE_NEGY_ENABLE (1<<3) +#define CUBE_POSY_ENABLE (1<<2) +#define CUBE_NEGZ_ENABLE (1<<1) +#define CUBE_POSZ_ENABLE (1<<0) + + +/* _3DSTATE_MODES_1, p190 */ +#define _3DSTATE_MODES_1_CMD (CMD_3D|(0x08<<24)) +#define BLENDFUNC_MASK 0x3f0000 +#define ENABLE_COLR_BLND_FUNC (1<<21) +#define BLENDFUNC_ADD 0 +#define BLENDFUNC_SUB (1<<16) +#define BLENDFUNC_RVRSE_SUB (2<<16) +#define BLENDFUNC_MIN (3<<16) +#define BLENDFUNC_MAX (4<<16) +#define SRC_DST_BLND_MASK 0xfff +#define ENABLE_SRC_BLND_FACTOR (1<<11) +#define ENABLE_DST_BLND_FACTOR (1<<5) +#define SRC_BLND_FACT(x) ((x)<<6) +#define DST_BLND_FACT(x) (x) + +/* Use the blendfact defines for BLND_FACTOR macros */ +#if 0 +#define BLENDFACT_ZERO 0x01 +#define BLENDFACT_ONE 0x02 +#define BLENDFACT_SRC_COLR 0x03 +#define BLENDFACT_INV_SRC_COLR 0x04 +#define BLENDFACT_SRC_ALPHA 0x05 +#define BLENDFACT_INV_SRC_ALPHA 0x06 +#define BLENDFACT_DST_ALPHA 0x07 +#define BLENDFACT_INV_DST_ALPHA 0x08 +#define BLENDFACT_CONST_ALPHA 0x0e +#define BLENDFACT_INV_CONST_ALPHA 0x0f +#endif + +/* _3DSTATE_MODES_2, p192 */ +#define _3DSTATE_MODES_2_CMD (CMD_3D|(0x0f<<24)) +#define ENABLE_GLOBAL_DEPTH_BIAS (1<<22) +#define GLOBAL_DEPTH_BIAS(x) ((x)<<14) +#define ENABLE_ALPHA_TEST_FUNC (1<<13) +#define ENABLE_ALPHA_REF_VALUE (1<<8) +#define ALPHA_TEST_FUNC(x) ((x)<<9) +#define ALPHA_REF_VALUE(x) (x) + +#define ALPHA_TEST_REF_MASK 0x3fff +#define COMPAREFUNC_ALWAYS 0 +#define COMPAREFUNC_NEVER 0x1 +#define COMPAREFUNC_LESS 0x2 +#define COMPAREFUNC_EQUAL 0x3 +#define COMPAREFUNC_LEQUAL 0x4 +#define COMPAREFUNC_GREATER 0x5 +#define COMPAREFUNC_NOTEQUAL 0x6 +#define COMPAREFUNC_GEQUAL 0x7 + +/* _3DSTATE_MODES_3, p193 */ +#define _3DSTATE_MODES_3_CMD (CMD_3D|(0x02<<24)) +#define DEPTH_TEST_FUNC_MASK 0x1f0000 +#define ENABLE_DEPTH_TEST_FUNC (1<<20) +/* Uses COMPAREFUNC */ +#define DEPTH_TEST_FUNC(x) ((x)<<16) +#define ENABLE_ALPHA_SHADE_MODE (1<<11) +#define ENABLE_FOG_SHADE_MODE (1<<9) +#define ENABLE_SPEC_SHADE_MODE (1<<7) +#define ENABLE_COLOR_SHADE_MODE (1<<5) +#define ALPHA_SHADE_MODE(x) ((x)<<10) +#define FOG_SHADE_MODE(x) ((x)<<8) +#define SPEC_SHADE_MODE(x) ((x)<<6) +#define COLOR_SHADE_MODE(x) ((x)<<4) +#define CULLMODE_MASK 0xf +#define ENABLE_CULL_MODE (1<<3) +#define CULLMODE_BOTH 0 +#define CULLMODE_NONE 1 +#define CULLMODE_CW 2 +#define CULLMODE_CCW 3 + +#define SHADE_MODE_LINEAR 0 +#define SHADE_MODE_FLAT 0x1 + +/* _3DSTATE_MODES_4, p195 */ +#define _3DSTATE_MODES_4_CMD (CMD_3D|(0x16<<24)) +#define ENABLE_LOGIC_OP_FUNC (1<<23) +#define LOGIC_OP_FUNC(x) ((x)<<18) +#define LOGICOP_MASK ((1<<18)|(1<<19)|(1<<20)|(1<<21)) +#define LOGICOP_CLEAR 0 +#define LOGICOP_NOR 0x1 +#define LOGICOP_AND_INV 0x2 +#define LOGICOP_COPY_INV 0x3 +#define LOGICOP_AND_RVRSE 0x4 +#define LOGICOP_INV 0x5 +#define LOGICOP_XOR 0x6 +#define LOGICOP_NAND 0x7 +#define LOGICOP_AND 0x8 +#define LOGICOP_EQUIV 0x9 +#define LOGICOP_NOOP 0xa +#define LOGICOP_OR_INV 0xb +#define LOGICOP_COPY 0xc +#define LOGICOP_OR_RVRSE 0xd +#define LOGICOP_OR 0xe +#define LOGICOP_SET 0xf +#define MODE4_ENABLE_STENCIL_TEST_MASK ((1<<17)|(0xff00)) +#define ENABLE_STENCIL_TEST_MASK (1<<17) +#define STENCIL_TEST_MASK(x) ((x)<<8) +#define MODE4_ENABLE_STENCIL_WRITE_MASK ((1<<16)|(0x00ff)) +#define ENABLE_STENCIL_WRITE_MASK (1<<16) +#define STENCIL_WRITE_MASK(x) (x) + +/* _3DSTATE_MODES_5, p196 */ +#define _3DSTATE_MODES_5_CMD (CMD_3D|(0x0c<<24)) +#define ENABLE_SPRITE_POINT_TEX (1<<23) +#define SPRITE_POINT_TEX_ON (1<<22) +#define SPRITE_POINT_TEX_OFF 0 +#define FLUSH_RENDER_CACHE (1<<18) +#define FLUSH_TEXTURE_CACHE (1<<16) +#define FIXED_LINE_WIDTH_MASK 0xfc00 +#define ENABLE_FIXED_LINE_WIDTH (1<<15) +#define FIXED_LINE_WIDTH(x) ((x)<<10) +#define FIXED_POINT_WIDTH_MASK 0x3ff +#define ENABLE_FIXED_POINT_WIDTH (1<<9) +#define FIXED_POINT_WIDTH(x) (x) + +/* _3DSTATE_RASTERIZATION_RULES, p198 */ +#define _3DSTATE_RASTER_RULES_CMD (CMD_3D|(0x07<<24)) +#define ENABLE_POINT_RASTER_RULE (1<<15) +#define OGL_POINT_RASTER_RULE (1<<13) +#define ENABLE_LINE_STRIP_PROVOKE_VRTX (1<<8) +#define ENABLE_TRI_FAN_PROVOKE_VRTX (1<<5) +#define ENABLE_TRI_STRIP_PROVOKE_VRTX (1<<2) +#define LINE_STRIP_PROVOKE_VRTX(x) ((x)<<6) +#define TRI_FAN_PROVOKE_VRTX(x) ((x)<<3) +#define TRI_STRIP_PROVOKE_VRTX(x) (x) + +/* _3DSTATE_SCISSOR_ENABLE, p200 */ +#define _3DSTATE_SCISSOR_ENABLE_CMD (CMD_3D|(0x1c<<24)|(0x10<<19)) +#define ENABLE_SCISSOR_RECT ((1<<1) | 1) +#define DISABLE_SCISSOR_RECT (1<<1) + +/* _3DSTATE_SCISSOR_RECTANGLE_0, p201 */ +#define _3DSTATE_SCISSOR_RECT_0_CMD (CMD_3D|(0x1d<<24)|(0x81<<16)|1) +/* Dword 1 */ +#define SCISSOR_RECT_0_YMIN(x) ((x)<<16) +#define SCISSOR_RECT_0_XMIN(x) (x) +/* Dword 2 */ +#define SCISSOR_RECT_0_YMAX(x) ((x)<<16) +#define SCISSOR_RECT_0_XMAX(x) (x) + +/* _3DSTATE_STENCIL_TEST, p202 */ +#define _3DSTATE_STENCIL_TEST_CMD (CMD_3D|(0x09<<24)) +#define ENABLE_STENCIL_PARMS (1<<23) +#define STENCIL_OPS_MASK (0xffc000) +#define STENCIL_FAIL_OP(x) ((x)<<20) +#define STENCIL_PASS_DEPTH_FAIL_OP(x) ((x)<<17) +#define STENCIL_PASS_DEPTH_PASS_OP(x) ((x)<<14) + +#define STENCILOP_KEEP 0 +#define STENCILOP_ZERO 0x1 +#define STENCILOP_REPLACE 0x2 +#define STENCILOP_INCRSAT 0x3 +#define STENCILOP_DECRSAT 0x4 +#define STENCILOP_INCR 0x5 +#define STENCILOP_DECR 0x6 +#define STENCILOP_INVERT 0x7 + +#define ENABLE_STENCIL_TEST_FUNC_MASK ((1<<13)|(1<<12)|(1<<11)|(1<<10)|(1<<9)) +#define ENABLE_STENCIL_TEST_FUNC (1<<13) +/* Uses COMPAREFUNC */ +#define STENCIL_TEST_FUNC(x) ((x)<<9) +#define STENCIL_REF_VALUE_MASK ((1<<8)|0xff) +#define ENABLE_STENCIL_REF_VALUE (1<<8) +#define STENCIL_REF_VALUE(x) (x) + +/* _3DSTATE_VERTEX_FORMAT, p204 */ +#define _3DSTATE_VFT0_CMD (CMD_3D|(0x05<<24)) +#define VFT0_POINT_WIDTH (1<<12) +#define VFT0_TEX_COUNT_MASK (7<<8) +#define VFT0_TEX_COUNT_SHIFT 8 +#define VFT0_TEX_COUNT(x) ((x)<<8) +#define VFT0_SPEC (1<<7) +#define VFT0_DIFFUSE (1<<6) +#define VFT0_DEPTH_OFFSET (1<<5) +#define VFT0_XYZ (1<<1) +#define VFT0_XYZW (2<<1) +#define VFT0_XY (3<<1) +#define VFT0_XYW (4<<1) +#define VFT0_XYZW_MASK (7<<1) + +/* _3DSTATE_VERTEX_FORMAT_2, p206 */ +#define _3DSTATE_VFT1_CMD (CMD_3D|(0x0a<<24)) +#define VFT1_TEX7_FMT(x) ((x)<<14) +#define VFT1_TEX6_FMT(x) ((x)<<12) +#define VFT1_TEX5_FMT(x) ((x)<<10) +#define VFT1_TEX4_FMT(x) ((x)<<8) +#define VFT1_TEX3_FMT(x) ((x)<<6) +#define VFT1_TEX2_FMT(x) ((x)<<4) +#define VFT1_TEX1_FMT(x) ((x)<<2) +#define VFT1_TEX0_FMT(x) (x) +#define VFT1_TEX0_MASK 3 +#define VFT1_TEX1_SHIFT 2 +#define TEXCOORDFMT_2D 0 +#define TEXCOORDFMT_3D 1 +#define TEXCOORDFMT_4D 2 +#define TEXCOORDFMT_1D 3 + +/*New stuff picked up along the way */ + +#define MLC_LOD_BIAS_MASK ((1<<7)-1) + + +/* _3DSTATE_VERTEX_TRANSFORM, p207 */ +#define _3DSTATE_VERTEX_TRANS_CMD (CMD_3D|(0x1d<<24)|(0x8b<<16)|0) +#define _3DSTATE_VERTEX_TRANS_MTX_CMD (CMD_3D|(0x1d<<24)|(0x8b<<16)|6) +/* Dword 1 */ +#define ENABLE_VIEWPORT_TRANSFORM ((1<<31)|(1<<30)) +#define DISABLE_VIEWPORT_TRANSFORM (1<<31) +#define ENABLE_PERSP_DIVIDE ((1<<29)|(1<<28)) +#define DISABLE_PERSP_DIVIDE (1<<29) +#define VRTX_TRANS_LOAD_MATRICES 0x7421 +#define VRTX_TRANS_NO_LOAD_MATRICES 0x0000 +/* Dword 2 -> 7 are matrix elements */ + +/* _3DSTATE_W_STATE, p209 */ +#define _3DSTATE_W_STATE_CMD (CMD_3D|(0x1d<<24)|(0x8d<<16)|1) +/* Dword 1 */ +#define MAGIC_W_STATE_DWORD1 0x00000008 +/* Dword 2 */ +#define WFAR_VALUE(x) (x) + + +/* Stipple command, carried over from the i810, apparently: + */ +#define _3DSTATE_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16)) +#define ST1_ENABLE (1<<16) +#define ST1_MASK (0xffff) + + + +#define _3DSTATE_LOAD_STATE_IMMEDIATE_2 ((0x3<<29)|(0x1d<<24)|(0x03<<16)) +#define LOAD_TEXTURE_MAP0 (1<<11) +#define LOAD_GLOBAL_COLOR_FACTOR (1<<6) + +#define TM0S0_ADDRESS_MASK 0xfffffffc +#define TM0S0_USE_FENCE (1<<1) + +#define TM0S1_HEIGHT_SHIFT 21 +#define TM0S1_WIDTH_SHIFT 10 +#define TM0S1_PALETTE_SELECT (1<<9) +#define TM0S1_MAPSURF_FORMAT_MASK (0x7 << 6) +#define TM0S1_MAPSURF_FORMAT_SHIFT 6 +#define MAPSURF_8BIT_INDEXED (0<<6) +#define MAPSURF_8BIT (1<<6) +#define MAPSURF_16BIT (2<<6) +#define MAPSURF_32BIT (3<<6) +#define MAPSURF_411 (4<<6) +#define MAPSURF_422 (5<<6) +#define MAPSURF_COMPRESSED (6<<6) +#define MAPSURF_4BIT_INDEXED (7<<6) +#define TM0S1_MT_FORMAT_MASK (0x7 << 3) +#define TM0S1_MT_FORMAT_SHIFT 3 +#define MT_4BIT_IDX_ARGB8888 (7<<3) /* SURFACE_4BIT_INDEXED */ +#define MT_8BIT_IDX_RGB565 (0<<3) /* SURFACE_8BIT_INDEXED */ +#define MT_8BIT_IDX_ARGB1555 (1<<3) +#define MT_8BIT_IDX_ARGB4444 (2<<3) +#define MT_8BIT_IDX_AY88 (3<<3) +#define MT_8BIT_IDX_ABGR8888 (4<<3) +#define MT_8BIT_IDX_BUMP_88DVDU (5<<3) +#define MT_8BIT_IDX_BUMP_655LDVDU (6<<3) +#define MT_8BIT_IDX_ARGB8888 (7<<3) +#define MT_8BIT_I8 (0<<3) /* SURFACE_8BIT */ +#define MT_8BIT_L8 (1<<3) +#define MT_16BIT_RGB565 (0<<3) /* SURFACE_16BIT */ +#define MT_16BIT_ARGB1555 (1<<3) +#define MT_16BIT_ARGB4444 (2<<3) +#define MT_16BIT_AY88 (3<<3) +#define MT_16BIT_DIB_ARGB1555_8888 (4<<3) +#define MT_16BIT_BUMP_88DVDU (5<<3) +#define MT_16BIT_BUMP_655LDVDU (6<<3) +#define MT_16BIT_DIB_RGB565_8888 (7<<3) +#define MT_32BIT_ARGB8888 (0<<3) /* SURFACE_32BIT */ +#define MT_32BIT_ABGR8888 (1<<3) +#define MT_32BIT_BUMP_XLDVDU_8888 (6<<3) +#define MT_32BIT_DIB_8888 (7<<3) +#define MT_411_YUV411 (0<<3) /* SURFACE_411 */ +#define MT_422_YCRCB_SWAPY (0<<3) /* SURFACE_422 */ +#define MT_422_YCRCB_NORMAL (1<<3) +#define MT_422_YCRCB_SWAPUV (2<<3) +#define MT_422_YCRCB_SWAPUVY (3<<3) +#define MT_COMPRESS_DXT1 (0<<3) /* SURFACE_COMPRESSED */ +#define MT_COMPRESS_DXT2_3 (1<<3) +#define MT_COMPRESS_DXT4_5 (2<<3) +#define MT_COMPRESS_FXT1 (3<<3) +#define TM0S1_COLORSPACE_CONVERSION (1 << 2) +#define TM0S1_TILED_SURFACE (1 << 1) +#define TM0S1_TILE_WALK (1 << 0) + +#define TM0S2_PITCH_SHIFT 21 +#define TM0S2_CUBE_FACE_ENA_SHIFT 15 +#define TM0S2_MAP_FORMAT (1<<14) +#define TM0S2_VERTICAL_LINE_STRIDE (1<<13) +#define TM0S2_VERITCAL_LINE_STRIDE_OFF (1<<12) +#define TM0S2_OUTPUT_CHAN_SHIFT 10 +#define TM0S2_OUTPUT_CHAN_MASK (3<<10) + +#define TM0S3_MIP_FILTER_MASK (0x3<<30) +#define TM0S3_MIP_FILTER_SHIFT 30 +#define MIPFILTER_NONE 0 +#define MIPFILTER_NEAREST 1 +#define MIPFILTER_LINEAR 3 +#define TM0S3_MAG_FILTER_MASK (0x3<<28) +#define TM0S3_MAG_FILTER_SHIFT 28 +#define TM0S3_MIN_FILTER_MASK (0x3<<26) +#define TM0S3_MIN_FILTER_SHIFT 26 +#define FILTER_NEAREST 0 +#define FILTER_LINEAR 1 +#define FILTER_ANISOTROPIC 2 + +#define TM0S3_LOD_BIAS_SHIFT 17 +#define TM0S3_LOD_BIAS_MASK (0x1ff<<17) +#define TM0S3_MAX_MIP_SHIFT 9 +#define TM0S3_MAX_MIP_MASK (0xff<<9) +#define TM0S3_MIN_MIP_SHIFT 3 +#define TM0S3_MIN_MIP_MASK (0x3f<<3) +#define TM0S3_KILL_PIXEL (1<<2) +#define TM0S3_KEYED_FILTER (1<<1) +#define TM0S3_CHROMA_KEY (1<<0) + + +/* _3DSTATE_MAP_TEXEL_STREAM, p188 */ +#define _3DSTATE_MAP_TEX_STREAM_CMD (CMD_3D|(0x1c<<24)|(0x05<<19)) +#define DISABLE_TEX_STREAM_BUMP (1<<12) +#define ENABLE_TEX_STREAM_BUMP ((1<<12)|(1<<11)) +#define TEX_MODIFY_UNIT_0 0 +#define TEX_MODIFY_UNIT_1 (1<<8) +#define ENABLE_TEX_STREAM_COORD_SET (1<<7) +#define TEX_STREAM_COORD_SET(x) ((x)<<4) +#define ENABLE_TEX_STREAM_MAP_IDX (1<<3) +#define TEX_STREAM_MAP_IDX(x) (x) + + +#define MI_FLUSH ((0<<29)|(4<<23)) +#define FLUSH_MAP_CACHE (1<<0) + +#endif diff --git a/src/mesa/drivers/dri/i915/i830_state.c b/src/mesa/drivers/dri/i915/i830_state.c new file mode 100644 index 0000000..4649a75 --- /dev/null +++ b/src/mesa/drivers/dri/i915/i830_state.c @@ -0,0 +1,1183 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + + +#include "glheader.h" +#include "context.h" +#include "macros.h" +#include "enums.h" +#include "dd.h" + +#include "texmem.h" + +#include "intel_screen.h" +#include "intel_batchbuffer.h" + +#include "i830_context.h" +#include "i830_reg.h" + +static void i830StencilFunc(GLcontext *ctx, GLenum func, GLint ref, + GLuint mask) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + int test = 0; + + mask = mask & 0xff; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s : func: %s, ref : 0x%x, mask: 0x%x\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(func), ref, mask); + + switch(func) { + case GL_NEVER: + test = COMPAREFUNC_NEVER; + break; + case GL_LESS: + test = COMPAREFUNC_LESS; + break; + case GL_LEQUAL: + test = COMPAREFUNC_LEQUAL; + break; + case GL_GREATER: + test = COMPAREFUNC_GREATER; + break; + case GL_GEQUAL: + test = COMPAREFUNC_GEQUAL; + break; + case GL_NOTEQUAL: + test = COMPAREFUNC_NOTEQUAL; + break; + case GL_EQUAL: + test = COMPAREFUNC_EQUAL; + break; + case GL_ALWAYS: + test = COMPAREFUNC_ALWAYS; + break; + default: + return; + } + + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_STATE4] &= ~MODE4_ENABLE_STENCIL_TEST_MASK; + i830->state.Ctx[I830_CTXREG_STATE4] |= (ENABLE_STENCIL_TEST_MASK | + STENCIL_TEST_MASK(mask)); + i830->state.Ctx[I830_CTXREG_STENCILTST] &= ~(STENCIL_REF_VALUE_MASK | + ENABLE_STENCIL_TEST_FUNC_MASK); + i830->state.Ctx[I830_CTXREG_STENCILTST] |= (ENABLE_STENCIL_REF_VALUE | + ENABLE_STENCIL_TEST_FUNC | + STENCIL_REF_VALUE(ref) | + STENCIL_TEST_FUNC(test)); +} + +static void i830StencilMask(GLcontext *ctx, GLuint mask) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s : mask 0x%x\n", __FUNCTION__, mask); + + mask = mask & 0xff; + + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_STATE4] &= ~MODE4_ENABLE_STENCIL_WRITE_MASK; + i830->state.Ctx[I830_CTXREG_STATE4] |= (ENABLE_STENCIL_WRITE_MASK | + STENCIL_WRITE_MASK(mask)); +} + +static void i830StencilOp(GLcontext *ctx, GLenum fail, GLenum zfail, + GLenum zpass) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + int fop, dfop, dpop; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s: fail : %s, zfail: %s, zpass : %s\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(fail), + _mesa_lookup_enum_by_nr(zfail), + _mesa_lookup_enum_by_nr(zpass)); + + fop = 0; dfop = 0; dpop = 0; + + switch(fail) { + case GL_KEEP: + fop = STENCILOP_KEEP; + break; + case GL_ZERO: + fop = STENCILOP_ZERO; + break; + case GL_REPLACE: + fop = STENCILOP_REPLACE; + break; + case GL_INCR: + fop = STENCILOP_INCRSAT; + break; + case GL_DECR: + fop = STENCILOP_DECRSAT; + break; + case GL_INCR_WRAP: + fop = STENCILOP_INCR; + break; + case GL_DECR_WRAP: + fop = STENCILOP_DECR; + break; + case GL_INVERT: + fop = STENCILOP_INVERT; + break; + default: + break; + } + switch(zfail) { + case GL_KEEP: + dfop = STENCILOP_KEEP; + break; + case GL_ZERO: + dfop = STENCILOP_ZERO; + break; + case GL_REPLACE: + dfop = STENCILOP_REPLACE; + break; + case GL_INCR: + dfop = STENCILOP_INCRSAT; + break; + case GL_DECR: + dfop = STENCILOP_DECRSAT; + break; + case GL_INCR_WRAP: + dfop = STENCILOP_INCR; + break; + case GL_DECR_WRAP: + dfop = STENCILOP_DECR; + break; + case GL_INVERT: + dfop = STENCILOP_INVERT; + break; + default: + break; + } + switch(zpass) { + case GL_KEEP: + dpop = STENCILOP_KEEP; + break; + case GL_ZERO: + dpop = STENCILOP_ZERO; + break; + case GL_REPLACE: + dpop = STENCILOP_REPLACE; + break; + case GL_INCR: + dpop = STENCILOP_INCRSAT; + break; + case GL_DECR: + dpop = STENCILOP_DECRSAT; + break; + case GL_INCR_WRAP: + dpop = STENCILOP_INCR; + break; + case GL_DECR_WRAP: + dpop = STENCILOP_DECR; + break; + case GL_INVERT: + dpop = STENCILOP_INVERT; + break; + default: + break; + } + + + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_STENCILTST] &= ~(STENCIL_OPS_MASK); + i830->state.Ctx[I830_CTXREG_STENCILTST] |= (ENABLE_STENCIL_PARMS | + STENCIL_FAIL_OP(fop) | + STENCIL_PASS_DEPTH_FAIL_OP(dfop) | + STENCIL_PASS_DEPTH_PASS_OP(dpop)); +} + +static void i830AlphaFunc(GLcontext *ctx, GLenum func, GLfloat ref) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + int test = 0; + GLubyte refByte; + GLuint refInt; + + UNCLAMPED_FLOAT_TO_UBYTE(refByte, ref); + refInt = (GLuint)refByte; + + switch(func) { + case GL_NEVER: + test = COMPAREFUNC_NEVER; + break; + case GL_LESS: + test = COMPAREFUNC_LESS; + break; + case GL_LEQUAL: + test = COMPAREFUNC_LEQUAL; + break; + case GL_GREATER: + test = COMPAREFUNC_GREATER; + break; + case GL_GEQUAL: + test = COMPAREFUNC_GEQUAL; + break; + case GL_NOTEQUAL: + test = COMPAREFUNC_NOTEQUAL; + break; + case GL_EQUAL: + test = COMPAREFUNC_EQUAL; + break; + case GL_ALWAYS: + test = COMPAREFUNC_ALWAYS; + break; + default: + return; + } + + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_STATE2] &= ~ALPHA_TEST_REF_MASK; + i830->state.Ctx[I830_CTXREG_STATE2] |= (ENABLE_ALPHA_TEST_FUNC | + ENABLE_ALPHA_REF_VALUE | + ALPHA_TEST_FUNC(test) | + ALPHA_REF_VALUE(refInt)); +} + +/* This function makes sure that the proper enables are + * set for LogicOp, Independant Alpha Blend, and Blending. + * It needs to be called from numerous places where we + * could change the LogicOp or Independant Alpha Blend without subsequent + * calls to glEnable. + */ +static void i830EvalLogicOpBlendState(GLcontext *ctx) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + + if (ctx->Color._LogicOpEnabled) { + i830->state.Ctx[I830_CTXREG_ENABLES_1] &= ~(ENABLE_COLOR_BLEND | + ENABLE_LOGIC_OP_MASK); + i830->state.Ctx[I830_CTXREG_ENABLES_1] |= (DISABLE_COLOR_BLEND | + ENABLE_LOGIC_OP); + } else if (ctx->Color.BlendEnabled) { + i830->state.Ctx[I830_CTXREG_ENABLES_1] &= ~(ENABLE_COLOR_BLEND | + ENABLE_LOGIC_OP_MASK); + i830->state.Ctx[I830_CTXREG_ENABLES_1] |= (ENABLE_COLOR_BLEND | + DISABLE_LOGIC_OP); + } else { + i830->state.Ctx[I830_CTXREG_ENABLES_1] &= ~(ENABLE_COLOR_BLEND | + ENABLE_LOGIC_OP_MASK); + i830->state.Ctx[I830_CTXREG_ENABLES_1] |= (DISABLE_COLOR_BLEND | + DISABLE_LOGIC_OP); + } +} + +static void i830BlendColor(GLcontext *ctx, const GLfloat color[4]) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + GLubyte r, g, b, a; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + UNCLAMPED_FLOAT_TO_UBYTE(r, color[RCOMP]); + UNCLAMPED_FLOAT_TO_UBYTE(g, color[GCOMP]); + UNCLAMPED_FLOAT_TO_UBYTE(b, color[BCOMP]); + UNCLAMPED_FLOAT_TO_UBYTE(a, color[ACOMP]); + + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_BLENDCOLOR1] = (a<<24) | (r<<16) | (g<<8) | b; +} + +static void i830BlendEquationSeparate(GLcontext *ctx, GLenum modeRGB, + GLenum modeA) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + int func = ENABLE_ALPHA_BLENDFUNC; + + assert( modeRGB == modeA ); + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s %s\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(modeRGB)); + + /* This will catch a logicop blend equation */ + i830EvalLogicOpBlendState(ctx); + + switch(modeRGB) { + case GL_FUNC_ADD: + func |= BLENDFUNC_ADD; + break; + case GL_MIN: + func |= BLENDFUNC_MIN; + break; + case GL_MAX: + func |= BLENDFUNC_MAX; + break; + case GL_FUNC_SUBTRACT: + func |= BLENDFUNC_SUB; + break; + case GL_FUNC_REVERSE_SUBTRACT: + func |= BLENDFUNC_RVRSE_SUB; + break; + case GL_LOGIC_OP: + default: return; + } + + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_STATE1] &= ~BLENDFUNC_MASK; + i830->state.Ctx[I830_CTXREG_STATE1] |= func; +} + + + +static int translate_blend_factor( GLenum factor ) +{ + switch(factor) { + case GL_ZERO: + return BLENDFACT_ZERO; + case GL_SRC_ALPHA: + return BLENDFACT_SRC_ALPHA; + case GL_ONE: + return BLENDFACT_ONE; + case GL_SRC_COLOR: + return BLENDFACT_SRC_COLR; + case GL_ONE_MINUS_SRC_COLOR: + return BLENDFACT_INV_SRC_COLR; + case GL_DST_COLOR: + return BLENDFACT_DST_COLR; + case GL_ONE_MINUS_DST_COLOR: + return BLENDFACT_INV_DST_COLR; + case GL_ONE_MINUS_SRC_ALPHA: + return BLENDFACT_INV_SRC_ALPHA; + case GL_DST_ALPHA: + return BLENDFACT_DST_ALPHA; + case GL_ONE_MINUS_DST_ALPHA: + return BLENDFACT_INV_DST_ALPHA; + case GL_SRC_ALPHA_SATURATE: + return BLENDFACT_SRC_ALPHA_SATURATE; + case GL_CONSTANT_COLOR: + return BLENDFACT_CONST_COLOR; + case GL_ONE_MINUS_CONSTANT_COLOR: + return BLENDFACT_INV_CONST_COLOR; + case GL_CONSTANT_ALPHA: + return BLENDFACT_CONST_ALPHA; + case GL_ONE_MINUS_CONSTANT_ALPHA: + return BLENDFACT_INV_CONST_ALPHA; + default: + return BLENDFACT_ZERO; + } +} + +static void i830BlendFuncSeparate(GLcontext *ctx, GLenum sfactorRGB, + GLenum dfactorRGB, GLenum sfactorA, + GLenum dfactorA ) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + int iab = i830->state.Ctx[I830_CTXREG_IALPHAB]; + int s1 = i830->state.Ctx[I830_CTXREG_STATE1]; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + + iab &= ~(SRC_DST_ABLEND_MASK|ENABLE_INDPT_ALPHA_BLEND); + s1 &= ~SRC_DST_BLND_MASK; + + iab |= (ENABLE_SRC_ABLEND_FACTOR|ENABLE_DST_ABLEND_FACTOR); + s1 |= (ENABLE_SRC_BLND_FACTOR|ENABLE_DST_BLND_FACTOR); + + if (ctx->Color.BlendEquationRGB == GL_MIN || + ctx->Color.BlendEquationRGB == GL_MAX) { + sfactorA = sfactorRGB = dfactorA = dfactorRGB = GL_ONE; + } + + iab |= SRC_ABLEND_FACT(translate_blend_factor(sfactorA)); + iab |= DST_ABLEND_FACT(translate_blend_factor(dfactorA)); + s1 |= SRC_BLND_FACT(translate_blend_factor(sfactorRGB)); + s1 |= DST_BLND_FACT(translate_blend_factor(dfactorRGB)); + + if (sfactorA != sfactorRGB || dfactorA != dfactorRGB) + iab |= ENABLE_INDPT_ALPHA_BLEND; + else + iab |= DISABLE_INDPT_ALPHA_BLEND; + + if (iab != i830->state.Ctx[I830_CTXREG_IALPHAB] || + s1 != i830->state.Ctx[I830_CTXREG_STATE1]) { + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_IALPHAB] = iab; + i830->state.Ctx[I830_CTXREG_STATE1] = s1; + } +} + + + +static void i830DepthFunc(GLcontext *ctx, GLenum func) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + int test = 0; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + switch(func) { + case GL_NEVER: + test = COMPAREFUNC_NEVER; + break; + case GL_LESS: + test = COMPAREFUNC_LESS; + break; + case GL_LEQUAL: + test = COMPAREFUNC_LEQUAL; + break; + case GL_GREATER: + test = COMPAREFUNC_GREATER; + break; + case GL_GEQUAL: + test = COMPAREFUNC_GEQUAL; + break; + case GL_NOTEQUAL: + test = COMPAREFUNC_NOTEQUAL; + break; + case GL_EQUAL: + test = COMPAREFUNC_EQUAL; + break; + case GL_ALWAYS: + test = COMPAREFUNC_ALWAYS; + break; + default: return; + } + + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_STATE3] &= ~DEPTH_TEST_FUNC_MASK; + i830->state.Ctx[I830_CTXREG_STATE3] |= (ENABLE_DEPTH_TEST_FUNC | + DEPTH_TEST_FUNC(test)); +} + +static void i830DepthMask(GLcontext *ctx, GLboolean flag) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s flag (%d)\n", __FUNCTION__, flag); + + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + + i830->state.Ctx[I830_CTXREG_ENABLES_2] &= ~ENABLE_DIS_DEPTH_WRITE_MASK; + + if (flag && ctx->Depth.Test) + i830->state.Ctx[I830_CTXREG_ENABLES_2] |= ENABLE_DEPTH_WRITE; + else + i830->state.Ctx[I830_CTXREG_ENABLES_2] |= DISABLE_DEPTH_WRITE; +} + +/* ============================================================= + * Polygon stipple + * + * The i830 supports a 4x4 stipple natively, GL wants 32x32. + * Fortunately stipple is usually a repeating pattern. + */ +static void i830PolygonStipple( GLcontext *ctx, const GLubyte *mask ) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + const GLubyte *m = mask; + GLubyte p[4]; + int i,j,k; + int active = (ctx->Polygon.StippleFlag && + i830->intel.reduced_primitive == GL_TRIANGLES); + GLuint newMask; + + if (active) { + I830_STATECHANGE(i830, I830_UPLOAD_STIPPLE); + i830->state.Stipple[I830_STPREG_ST1] &= ~ST1_ENABLE; + } + + p[0] = mask[12] & 0xf; p[0] |= p[0] << 4; + p[1] = mask[8] & 0xf; p[1] |= p[1] << 4; + p[2] = mask[4] & 0xf; p[2] |= p[2] << 4; + p[3] = mask[0] & 0xf; p[3] |= p[3] << 4; + + for (k = 0 ; k < 8 ; k++) + for (j = 3 ; j >= 0; j--) + for (i = 0 ; i < 4 ; i++, m++) + if (*m != p[j]) { + i830->intel.hw_stipple = 0; + return; + } + + newMask = (((p[0] & 0xf) << 0) | + ((p[1] & 0xf) << 4) | + ((p[2] & 0xf) << 8) | + ((p[3] & 0xf) << 12)); + + + if (newMask == 0xffff || newMask == 0x0) { + /* this is needed to make conform pass */ + i830->intel.hw_stipple = 0; + return; + } + + i830->state.Stipple[I830_STPREG_ST1] &= ~0xffff; + i830->state.Stipple[I830_STPREG_ST1] |= newMask; + i830->intel.hw_stipple = 1; + + if (active) + i830->state.Stipple[I830_STPREG_ST1] |= ST1_ENABLE; +} + + +/* ============================================================= + * Hardware clipping + */ +static void i830Scissor(GLcontext *ctx, GLint x, GLint y, + GLsizei w, GLsizei h) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + intelScreenPrivate *screen = i830->intel.intelScreen; + int x1, y1, x2, y2; + + if (!i830->intel.driDrawable) + return; + + x1 = x; + y1 = i830->intel.driDrawable->h - (y + h); + x2 = x + w - 1; + y2 = y1 + h - 1; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "[%s] x(%d) y(%d) w(%d) h(%d)\n", __FUNCTION__, + x, y, w, h); + + if (x1 < 0) x1 = 0; + if (y1 < 0) y1 = 0; + if (x2 < 0) x2 = 0; + if (y2 < 0) y2 = 0; + + if (x2 >= screen->width) x2 = screen->width-1; + if (y2 >= screen->height) y2 = screen->height-1; + if (x1 >= screen->width) x1 = screen->width-1; + if (y1 >= screen->height) y1 = screen->height-1; + + + I830_STATECHANGE(i830, I830_UPLOAD_BUFFERS); + i830->state.Buffer[I830_DESTREG_SR1] = (y1 << 16) | (x1 & 0xffff); + i830->state.Buffer[I830_DESTREG_SR2] = (y2 << 16) | (x2 & 0xffff); +} + +static void i830LogicOp(GLcontext *ctx, GLenum opcode) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + int tmp = 0; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + /* FIXME: This should be a look-up table, like the r200 driver. */ + switch(opcode) { + case GL_CLEAR: + tmp = LOGICOP_CLEAR; + break; + case GL_AND: + tmp = LOGICOP_AND; + break; + case GL_AND_REVERSE: + tmp = LOGICOP_AND_RVRSE; + break; + case GL_COPY: + tmp = LOGICOP_COPY; + break; + case GL_COPY_INVERTED: + tmp = LOGICOP_COPY_INV; + break; + case GL_AND_INVERTED: + tmp = LOGICOP_AND_INV; + break; + case GL_NOOP: + tmp = LOGICOP_NOOP; + break; + case GL_XOR: + tmp = LOGICOP_XOR; + break; + case GL_OR: + tmp = LOGICOP_OR; + break; + case GL_OR_INVERTED: + tmp = LOGICOP_OR_INV; + break; + case GL_NOR: + tmp = LOGICOP_NOR; + break; + case GL_EQUIV: + tmp = LOGICOP_EQUIV; + break; + case GL_INVERT: + tmp = LOGICOP_INV; + break; + case GL_OR_REVERSE: + tmp = LOGICOP_OR_RVRSE; + break; + case GL_NAND: + tmp = LOGICOP_NAND; + break; + case GL_SET: + tmp = LOGICOP_SET; + break; + default: + return; + } + + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_STATE4] &= ~LOGICOP_MASK; + i830->state.Ctx[I830_CTXREG_STATE4] |= LOGIC_OP_FUNC(tmp); +} + + + +static void i830CullFaceFrontFace(GLcontext *ctx, GLenum unused) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + GLuint mode; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + if (!ctx->Polygon.CullFlag) { + mode = CULLMODE_NONE; + } + else if (ctx->Polygon.CullFaceMode != GL_FRONT_AND_BACK) { + mode = CULLMODE_CW; + + if (ctx->Polygon.CullFaceMode == GL_FRONT) + mode ^= (CULLMODE_CW ^ CULLMODE_CCW); + if (ctx->Polygon.FrontFace != GL_CCW) + mode ^= (CULLMODE_CW ^ CULLMODE_CCW); + } + else { + mode = CULLMODE_BOTH; + } + + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_STATE3] &= ~CULLMODE_MASK; + i830->state.Ctx[I830_CTXREG_STATE3] |= ENABLE_CULL_MODE | mode; +} + +static void i830LineWidth( GLcontext *ctx, GLfloat widthf ) +{ + i830ContextPtr i830 = I830_CONTEXT( ctx ); + int width; + int state5; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + width = (int)(widthf * 2); + CLAMP_SELF(width, 1, 15); + + state5 = i830->state.Ctx[I830_CTXREG_STATE5] & ~FIXED_LINE_WIDTH_MASK; + state5 |= (ENABLE_FIXED_LINE_WIDTH | FIXED_LINE_WIDTH(width)); + + if (state5 != i830->state.Ctx[I830_CTXREG_STATE5]) { + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_STATE5] = state5; + } +} + +static void i830PointSize(GLcontext *ctx, GLfloat size) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + GLint point_size = (int)size; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + CLAMP_SELF(point_size, 1, 256); + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_STATE5] &= ~FIXED_POINT_WIDTH_MASK; + i830->state.Ctx[I830_CTXREG_STATE5] |= (ENABLE_FIXED_POINT_WIDTH | + FIXED_POINT_WIDTH(point_size)); +} + + +/* ============================================================= + * Color masks + */ + +static void i830ColorMask(GLcontext *ctx, + GLboolean r, GLboolean g, + GLboolean b, GLboolean a) +{ + i830ContextPtr i830 = I830_CONTEXT( ctx ); + GLuint tmp = 0; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s r(%d) g(%d) b(%d) a(%d)\n", __FUNCTION__, r, g, b, a); + + tmp = ((i830->state.Ctx[I830_CTXREG_ENABLES_2] & ~WRITEMASK_MASK) | + ENABLE_COLOR_MASK | + ENABLE_COLOR_WRITE | + ((!r) << WRITEMASK_RED_SHIFT) | + ((!g) << WRITEMASK_GREEN_SHIFT) | + ((!b) << WRITEMASK_BLUE_SHIFT) | + ((!a) << WRITEMASK_ALPHA_SHIFT)); + + if (tmp != i830->state.Ctx[I830_CTXREG_ENABLES_2]) { + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_ENABLES_2] = tmp; + } +} + +static void update_specular( GLcontext *ctx ) +{ + i830ContextPtr i830 = I830_CONTEXT( ctx ); + + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_ENABLES_1] &= ~ENABLE_SPEC_ADD_MASK; + + if (NEED_SECONDARY_COLOR(ctx)) + i830->state.Ctx[I830_CTXREG_ENABLES_1] |= ENABLE_SPEC_ADD; + else + i830->state.Ctx[I830_CTXREG_ENABLES_1] |= DISABLE_SPEC_ADD; +} + +static void i830LightModelfv(GLcontext *ctx, GLenum pname, + const GLfloat *param) +{ + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + if (pname == GL_LIGHT_MODEL_COLOR_CONTROL) { + update_specular( ctx ); + } +} + +/* In Mesa 3.5 we can reliably do native flatshading. + */ +static void i830ShadeModel(GLcontext *ctx, GLenum mode) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + + +#define SHADE_MODE_MASK ((1<<10)|(1<<8)|(1<<6)|(1<<4)) + + i830->state.Ctx[I830_CTXREG_STATE3] &= ~SHADE_MODE_MASK; + + if (mode == GL_FLAT) { + i830->state.Ctx[I830_CTXREG_STATE3] |= (ALPHA_SHADE_MODE(SHADE_MODE_FLAT) | + FOG_SHADE_MODE(SHADE_MODE_FLAT) | + SPEC_SHADE_MODE(SHADE_MODE_FLAT) | + COLOR_SHADE_MODE(SHADE_MODE_FLAT)); + } else { + i830->state.Ctx[I830_CTXREG_STATE3] |= (ALPHA_SHADE_MODE(SHADE_MODE_LINEAR) | + FOG_SHADE_MODE(SHADE_MODE_LINEAR) | + SPEC_SHADE_MODE(SHADE_MODE_LINEAR) | + COLOR_SHADE_MODE(SHADE_MODE_LINEAR)); + } +} + +/* ============================================================= + * Fog + */ +static void i830Fogfv(GLcontext *ctx, GLenum pname, const GLfloat *param) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + if (pname == GL_FOG_COLOR) { + GLuint color = (((GLubyte)(ctx->Fog.Color[0]*255.0F) << 16) | + ((GLubyte)(ctx->Fog.Color[1]*255.0F) << 8) | + ((GLubyte)(ctx->Fog.Color[2]*255.0F) << 0)); + + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_FOGCOLOR] = (_3DSTATE_FOG_COLOR_CMD | color); + } +} + +/* ============================================================= + */ + +static void i830Enable(GLcontext *ctx, GLenum cap, GLboolean state) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + + switch(cap) { + case GL_LIGHTING: + case GL_COLOR_SUM: + update_specular( ctx ); + break; + + case GL_ALPHA_TEST: + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_ENABLES_1] &= ~ENABLE_DIS_ALPHA_TEST_MASK; + if (state) + i830->state.Ctx[I830_CTXREG_ENABLES_1] |= ENABLE_ALPHA_TEST; + else + i830->state.Ctx[I830_CTXREG_ENABLES_1] |= DISABLE_ALPHA_TEST; + + break; + + case GL_BLEND: + i830EvalLogicOpBlendState(ctx); + break; + + case GL_COLOR_LOGIC_OP: + i830EvalLogicOpBlendState(ctx); + + /* Logicop doesn't seem to work at 16bpp: + */ + if (i830->intel.intelScreen->cpp == 2) + FALLBACK( &i830->intel, I830_FALLBACK_LOGICOP, state ); + break; + + case GL_DITHER: + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_ENABLES_2] &= ~ENABLE_DITHER; + + if (state) + i830->state.Ctx[I830_CTXREG_ENABLES_2] |= ENABLE_DITHER; + else + i830->state.Ctx[I830_CTXREG_ENABLES_2] |= DISABLE_DITHER; + break; + + case GL_DEPTH_TEST: + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_ENABLES_1] &= ~ENABLE_DIS_DEPTH_TEST_MASK; + + if (state) + i830->state.Ctx[I830_CTXREG_ENABLES_1] |= ENABLE_DEPTH_TEST; + else + i830->state.Ctx[I830_CTXREG_ENABLES_1] |= DISABLE_DEPTH_TEST; + + /* Also turn off depth writes when GL_DEPTH_TEST is disabled: + */ + i830DepthMask( ctx, ctx->Depth.Mask ); + break; + + case GL_SCISSOR_TEST: + I830_STATECHANGE(i830, I830_UPLOAD_BUFFERS); + + if (state) + i830->state.Buffer[I830_DESTREG_SENABLE] = + (_3DSTATE_SCISSOR_ENABLE_CMD | + ENABLE_SCISSOR_RECT); + else + i830->state.Buffer[I830_DESTREG_SENABLE] = + (_3DSTATE_SCISSOR_ENABLE_CMD | + DISABLE_SCISSOR_RECT); + + break; + + case GL_LINE_SMOOTH: + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + + i830->state.Ctx[I830_CTXREG_AA] &= ~AA_LINE_ENABLE; + if (state) + i830->state.Ctx[I830_CTXREG_AA] |= AA_LINE_ENABLE; + else + i830->state.Ctx[I830_CTXREG_AA] |= AA_LINE_DISABLE; + break; + + case GL_FOG: + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + i830->state.Ctx[I830_CTXREG_ENABLES_1] &= ~ENABLE_DIS_FOG_MASK; + if (state) + i830->state.Ctx[I830_CTXREG_ENABLES_1] |= ENABLE_FOG; + else + i830->state.Ctx[I830_CTXREG_ENABLES_1] |= DISABLE_FOG; + break; + + case GL_CULL_FACE: + i830CullFaceFrontFace(ctx, 0); + break; + + case GL_TEXTURE_2D: + break; + + case GL_STENCIL_TEST: + if (i830->intel.hw_stencil) { + I830_STATECHANGE(i830, I830_UPLOAD_CTX); + + if (state) { + i830->state.Ctx[I830_CTXREG_ENABLES_1] |= ENABLE_STENCIL_TEST; + i830->state.Ctx[I830_CTXREG_ENABLES_2] |= ENABLE_STENCIL_WRITE; + } else { + i830->state.Ctx[I830_CTXREG_ENABLES_1] &= ~ENABLE_STENCIL_TEST; + i830->state.Ctx[I830_CTXREG_ENABLES_2] &= ~ENABLE_STENCIL_WRITE; + i830->state.Ctx[I830_CTXREG_ENABLES_1] |= DISABLE_STENCIL_TEST; + i830->state.Ctx[I830_CTXREG_ENABLES_2] |= DISABLE_STENCIL_WRITE; + } + } else { + FALLBACK( &i830->intel, I830_FALLBACK_STENCIL, state ); + } + break; + + case GL_POLYGON_STIPPLE: + /* The stipple command worked on my 855GM box, but not my 845G. + * I'll do more testing later to find out exactly which hardware + * supports it. Disabled for now. + */ + if (i830->intel.hw_stipple && + i830->intel.reduced_primitive == GL_TRIANGLES) + { + I830_STATECHANGE(i830, I830_UPLOAD_STIPPLE); + i830->state.Stipple[I830_STPREG_ST1] &= ~ST1_ENABLE; + if (state) + i830->state.Stipple[I830_STPREG_ST1] |= ST1_ENABLE; + } + break; + + default: + ; + } +} + + +static void i830_init_packets( i830ContextPtr i830 ) +{ + intelScreenPrivate *screen = i830->intel.intelScreen; + + /* Zero all state */ + memset(&i830->state, 0, sizeof(i830->state)); + + /* Set default blend state */ + i830->state.TexBlend[0][0] = (_3DSTATE_MAP_BLEND_OP_CMD(0) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXOP_LAST_STAGE | + TEXBLENDOP_ARG1); + i830->state.TexBlend[0][1] = (_3DSTATE_MAP_BLEND_OP_CMD(0) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + i830->state.TexBlend[0][2] = (_3DSTATE_MAP_BLEND_ARG_CMD(0) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_DIFFUSE); + i830->state.TexBlend[0][3] = (_3DSTATE_MAP_BLEND_ARG_CMD(0) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_DIFFUSE); + + i830->state.TexBlendWordsUsed[0] = 4; + + + i830->state.Ctx[I830_CTXREG_VF] = 0; + i830->state.Ctx[I830_CTXREG_VF2] = 0; + + i830->state.Ctx[I830_CTXREG_AA] = (_3DSTATE_AA_CMD | + AA_LINE_ECAAR_WIDTH_ENABLE | + AA_LINE_ECAAR_WIDTH_1_0 | + AA_LINE_REGION_WIDTH_ENABLE | + AA_LINE_REGION_WIDTH_1_0 | + AA_LINE_DISABLE); + + i830->state.Ctx[I830_CTXREG_ENABLES_1] = (_3DSTATE_ENABLES_1_CMD | + DISABLE_LOGIC_OP | + DISABLE_STENCIL_TEST | + DISABLE_DEPTH_BIAS | + DISABLE_SPEC_ADD | + DISABLE_FOG | + DISABLE_ALPHA_TEST | + DISABLE_COLOR_BLEND | + DISABLE_DEPTH_TEST); + + if (i830->intel.hw_stencil) { + i830->state.Ctx[I830_CTXREG_ENABLES_2] = (_3DSTATE_ENABLES_2_CMD | + ENABLE_STENCIL_WRITE | + ENABLE_TEX_CACHE | + ENABLE_DITHER | + ENABLE_COLOR_MASK | + /* set no color comps disabled */ + ENABLE_COLOR_WRITE | + ENABLE_DEPTH_WRITE); + } else { + i830->state.Ctx[I830_CTXREG_ENABLES_2] = (_3DSTATE_ENABLES_2_CMD | + DISABLE_STENCIL_WRITE | + ENABLE_TEX_CACHE | + ENABLE_DITHER | + ENABLE_COLOR_MASK | + /* set no color comps disabled */ + ENABLE_COLOR_WRITE | + ENABLE_DEPTH_WRITE); + } + + i830->state.Ctx[I830_CTXREG_STATE1] = (_3DSTATE_MODES_1_CMD | + ENABLE_COLR_BLND_FUNC | + BLENDFUNC_ADD | + ENABLE_SRC_BLND_FACTOR | + SRC_BLND_FACT(BLENDFACT_ONE) | + ENABLE_DST_BLND_FACTOR | + DST_BLND_FACT(BLENDFACT_ZERO) ); + + i830->state.Ctx[I830_CTXREG_STATE2] = (_3DSTATE_MODES_2_CMD | + ENABLE_GLOBAL_DEPTH_BIAS | + GLOBAL_DEPTH_BIAS(0) | + ENABLE_ALPHA_TEST_FUNC | + ALPHA_TEST_FUNC(COMPAREFUNC_ALWAYS) | + ALPHA_REF_VALUE(0) ); + + i830->state.Ctx[I830_CTXREG_STATE3] = (_3DSTATE_MODES_3_CMD | + ENABLE_DEPTH_TEST_FUNC | + DEPTH_TEST_FUNC(COMPAREFUNC_LESS) | + ENABLE_ALPHA_SHADE_MODE | + ALPHA_SHADE_MODE(SHADE_MODE_LINEAR) | + ENABLE_FOG_SHADE_MODE | + FOG_SHADE_MODE(SHADE_MODE_LINEAR) | + ENABLE_SPEC_SHADE_MODE | + SPEC_SHADE_MODE(SHADE_MODE_LINEAR) | + ENABLE_COLOR_SHADE_MODE | + COLOR_SHADE_MODE(SHADE_MODE_LINEAR) | + ENABLE_CULL_MODE | + CULLMODE_NONE); + + i830->state.Ctx[I830_CTXREG_STATE4] = (_3DSTATE_MODES_4_CMD | + ENABLE_LOGIC_OP_FUNC | + LOGIC_OP_FUNC(LOGICOP_COPY) | + ENABLE_STENCIL_TEST_MASK | + STENCIL_TEST_MASK(0xff) | + ENABLE_STENCIL_WRITE_MASK | + STENCIL_WRITE_MASK(0xff)); + + i830->state.Ctx[I830_CTXREG_STENCILTST] = (_3DSTATE_STENCIL_TEST_CMD | + ENABLE_STENCIL_PARMS | + STENCIL_FAIL_OP(STENCILOP_KEEP) | + STENCIL_PASS_DEPTH_FAIL_OP(STENCILOP_KEEP) | + STENCIL_PASS_DEPTH_PASS_OP(STENCILOP_KEEP) | + ENABLE_STENCIL_TEST_FUNC | + STENCIL_TEST_FUNC(COMPAREFUNC_ALWAYS) | + ENABLE_STENCIL_REF_VALUE | + STENCIL_REF_VALUE(0) ); + + i830->state.Ctx[I830_CTXREG_STATE5] = (_3DSTATE_MODES_5_CMD | + FLUSH_TEXTURE_CACHE | + ENABLE_SPRITE_POINT_TEX | + SPRITE_POINT_TEX_OFF | + ENABLE_FIXED_LINE_WIDTH | + FIXED_LINE_WIDTH(0x2) | /* 1.0 */ + ENABLE_FIXED_POINT_WIDTH | + FIXED_POINT_WIDTH(1) ); + + i830->state.Ctx[I830_CTXREG_IALPHAB] = (_3DSTATE_INDPT_ALPHA_BLEND_CMD | + DISABLE_INDPT_ALPHA_BLEND | + ENABLE_ALPHA_BLENDFUNC | + ABLENDFUNC_ADD); + + i830->state.Ctx[I830_CTXREG_FOGCOLOR] = (_3DSTATE_FOG_COLOR_CMD | + FOG_COLOR_RED(0) | + FOG_COLOR_GREEN(0) | + FOG_COLOR_BLUE(0)); + + i830->state.Ctx[I830_CTXREG_BLENDCOLOR0] = _3DSTATE_CONST_BLEND_COLOR_CMD; + i830->state.Ctx[I830_CTXREG_BLENDCOLOR1] = 0; + + i830->state.Ctx[I830_CTXREG_MCSB0] = _3DSTATE_MAP_COORD_SETBIND_CMD; + i830->state.Ctx[I830_CTXREG_MCSB1] = (TEXBIND_SET3(TEXCOORDSRC_VTXSET_3) | + TEXBIND_SET2(TEXCOORDSRC_VTXSET_2) | + TEXBIND_SET1(TEXCOORDSRC_VTXSET_1) | + TEXBIND_SET0(TEXCOORDSRC_VTXSET_0)); + + + i830->state.Stipple[I830_STPREG_ST0] = _3DSTATE_STIPPLE; + + i830->state.Buffer[I830_DESTREG_CBUFADDR0] = _3DSTATE_BUF_INFO_CMD; + i830->state.Buffer[I830_DESTREG_CBUFADDR1] = + (BUF_3D_ID_COLOR_BACK | + BUF_3D_PITCH(screen->frontPitch * screen->cpp) | + BUF_3D_USE_FENCE); + + + i830->state.Buffer[I830_DESTREG_DBUFADDR0] = _3DSTATE_BUF_INFO_CMD; + i830->state.Buffer[I830_DESTREG_DBUFADDR1] = + (BUF_3D_ID_DEPTH | + BUF_3D_PITCH(screen->depthPitch * screen->cpp) | + BUF_3D_USE_FENCE); + i830->state.Buffer[I830_DESTREG_DBUFADDR2] = screen->depthOffset; + + + i830->state.Buffer[I830_DESTREG_DV0] = _3DSTATE_DST_BUF_VARS_CMD; + + switch (screen->fbFormat) { + case DV_PF_555: + case DV_PF_565: + i830->state.Buffer[I830_DESTREG_DV1] = (DSTORG_HORT_BIAS(0x8) | /* .5 */ + DSTORG_VERT_BIAS(0x8) | /* .5 */ + screen->fbFormat | + DEPTH_IS_Z | + DEPTH_FRMT_16_FIXED); + break; + case DV_PF_8888: + i830->state.Buffer[I830_DESTREG_DV1] = (DSTORG_HORT_BIAS(0x8) | /* .5 */ + DSTORG_VERT_BIAS(0x8) | /* .5 */ + screen->fbFormat | + DEPTH_IS_Z | + DEPTH_FRMT_24_FIXED_8_OTHER); + break; + } + + i830->state.Buffer[I830_DESTREG_SENABLE] = (_3DSTATE_SCISSOR_ENABLE_CMD | + DISABLE_SCISSOR_RECT); + i830->state.Buffer[I830_DESTREG_SR0] = _3DSTATE_SCISSOR_RECT_0_CMD; + i830->state.Buffer[I830_DESTREG_SR1] = 0; + i830->state.Buffer[I830_DESTREG_SR2] = 0; +} + + +void i830InitStateFuncs( struct dd_function_table *functions ) +{ + functions->AlphaFunc = i830AlphaFunc; + functions->BlendColor = i830BlendColor; + functions->BlendEquationSeparate = i830BlendEquationSeparate; + functions->BlendFuncSeparate = i830BlendFuncSeparate; + functions->ColorMask = i830ColorMask; + functions->CullFace = i830CullFaceFrontFace; + functions->DepthFunc = i830DepthFunc; + functions->DepthMask = i830DepthMask; + functions->Enable = i830Enable; + functions->Fogfv = i830Fogfv; + functions->FrontFace = i830CullFaceFrontFace; + functions->LightModelfv = i830LightModelfv; + functions->LineWidth = i830LineWidth; + functions->LogicOpcode = i830LogicOp; + functions->PointSize = i830PointSize; + functions->PolygonStipple = i830PolygonStipple; + functions->Scissor = i830Scissor; + functions->ShadeModel = i830ShadeModel; + functions->StencilFunc = i830StencilFunc; + functions->StencilMask = i830StencilMask; + functions->StencilOp = i830StencilOp; +} + +void i830InitState( i830ContextPtr i830 ) +{ + GLcontext *ctx = &i830->intel.ctx; + + i830_init_packets( i830 ); + + intelInitState( ctx ); + + memcpy( &i830->initial, &i830->state, sizeof(i830->state) ); + + i830->current = &i830->state; + i830->state.emitted = 0; + i830->state.active = (I830_UPLOAD_TEXBLEND(0) | + I830_UPLOAD_STIPPLE | + I830_UPLOAD_CTX | + I830_UPLOAD_BUFFERS); +} + + + + + diff --git a/src/mesa/drivers/dri/i915/i830_tex.c b/src/mesa/drivers/dri/i915/i830_tex.c new file mode 100644 index 0000000..34baf28 --- /dev/null +++ b/src/mesa/drivers/dri/i915/i830_tex.c @@ -0,0 +1,325 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "glheader.h" +#include "mtypes.h" +#include "imports.h" +#include "simple_list.h" +#include "enums.h" +#include "image.h" +#include "texstore.h" +#include "texformat.h" +#include "texmem.h" +#include "swrast/swrast.h" + +#include "mm.h" + +#include "intel_ioctl.h" + +#include "i830_context.h" +#include "i830_reg.h" + + + + +/** + * Set the texture wrap modes. + * + * The i830M (and related graphics cores) do not support GL_CLAMP. The Intel + * drivers for "other operating systems" implement GL_CLAMP as + * GL_CLAMP_TO_EDGE, so the same is done here. + * + * \param t Texture object whose wrap modes are to be set + * \param swrap Wrap mode for the \a s texture coordinate + * \param twrap Wrap mode for the \a t texture coordinate + */ +static void i830SetTexWrapping(i830TextureObjectPtr tex, + GLenum swrap, + GLenum twrap) +{ + tex->Setup[I830_TEXREG_MCS] &= ~(TEXCOORD_ADDR_U_MASK|TEXCOORD_ADDR_V_MASK); + + switch( swrap ) { + case GL_REPEAT: + tex->Setup[I830_TEXREG_MCS] |= TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_WRAP); + break; + case GL_CLAMP: + case GL_CLAMP_TO_EDGE: + tex->Setup[I830_TEXREG_MCS] |= TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_CLAMP); + break; + case GL_CLAMP_TO_BORDER: + tex->Setup[I830_TEXREG_MCS] |= + TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_CLAMP_BORDER); + break; + case GL_MIRRORED_REPEAT: + tex->Setup[I830_TEXREG_MCS] |= + TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_MIRROR); + break; + default: + break; + } + + switch( twrap ) { + case GL_REPEAT: + tex->Setup[I830_TEXREG_MCS] |= TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_WRAP); + break; + case GL_CLAMP: + case GL_CLAMP_TO_EDGE: + tex->Setup[I830_TEXREG_MCS] |= TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_CLAMP); + break; + case GL_CLAMP_TO_BORDER: + tex->Setup[I830_TEXREG_MCS] |= + TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_CLAMP_BORDER); + break; + case GL_MIRRORED_REPEAT: + tex->Setup[I830_TEXREG_MCS] |= + TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_MIRROR); + break; + default: + break; + } +} + + +/** + * Set the texture magnification and minification modes. + * + * \param t Texture whose filter modes are to be set + * \param minf Texture minification mode + * \param magf Texture magnification mode + * \param bias LOD bias for this texture unit. + */ + +static void i830SetTexFilter( i830TextureObjectPtr t, GLenum minf, GLenum magf, + GLfloat maxanisotropy ) +{ + int minFilt = 0, mipFilt = 0, magFilt = 0; + + if(INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + if ( maxanisotropy > 1.0 ) { + minFilt = FILTER_ANISOTROPIC; + magFilt = FILTER_ANISOTROPIC; + } + else { + switch (minf) { + case GL_NEAREST: + minFilt = FILTER_NEAREST; + mipFilt = MIPFILTER_NONE; + break; + case GL_LINEAR: + minFilt = FILTER_LINEAR; + mipFilt = MIPFILTER_NONE; + break; + case GL_NEAREST_MIPMAP_NEAREST: + minFilt = FILTER_NEAREST; + mipFilt = MIPFILTER_NEAREST; + break; + case GL_LINEAR_MIPMAP_NEAREST: + minFilt = FILTER_LINEAR; + mipFilt = MIPFILTER_NEAREST; + break; + case GL_NEAREST_MIPMAP_LINEAR: + minFilt = FILTER_NEAREST; + mipFilt = MIPFILTER_LINEAR; + break; + case GL_LINEAR_MIPMAP_LINEAR: + minFilt = FILTER_LINEAR; + mipFilt = MIPFILTER_LINEAR; + break; + default: + break; + } + + switch (magf) { + case GL_NEAREST: + magFilt = FILTER_NEAREST; + break; + case GL_LINEAR: + magFilt = FILTER_LINEAR; + break; + default: + break; + } + } + + t->Setup[I830_TEXREG_TM0S3] &= ~TM0S3_MIN_FILTER_MASK; + t->Setup[I830_TEXREG_TM0S3] &= ~TM0S3_MIP_FILTER_MASK; + t->Setup[I830_TEXREG_TM0S3] &= ~TM0S3_MAG_FILTER_MASK; + t->Setup[I830_TEXREG_TM0S3] |= ((minFilt << TM0S3_MIN_FILTER_SHIFT) | + (mipFilt << TM0S3_MIP_FILTER_SHIFT) | + (magFilt << TM0S3_MAG_FILTER_SHIFT)); +} + +static void i830SetTexBorderColor(i830TextureObjectPtr t, GLubyte color[4]) +{ + if(INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + t->Setup[I830_TEXREG_TM0S4] = + INTEL_PACKCOLOR8888(color[0],color[1],color[2],color[3]); +} + + +/** + * Allocate space for and load the mesa images into the texture memory block. + * This will happen before drawing with a new texture, or drawing with a + * texture after it was swapped out or teximaged again. + */ + +intelTextureObjectPtr i830AllocTexObj( struct gl_texture_object *texObj ) +{ + i830TextureObjectPtr t = CALLOC_STRUCT( i830_texture_object ); + if ( !t ) + return NULL; + + texObj->DriverData = t; + t->intel.base.tObj = texObj; + t->intel.dirty = I830_UPLOAD_TEX_ALL; + make_empty_list( &t->intel.base ); + + t->Setup[I830_TEXREG_TM0LI] = 0; /* not used */ + t->Setup[I830_TEXREG_TM0S0] = 0; + t->Setup[I830_TEXREG_TM0S1] = 0; + t->Setup[I830_TEXREG_TM0S2] = 0; + t->Setup[I830_TEXREG_TM0S3] = 0; + t->Setup[I830_TEXREG_MCS] = (_3DSTATE_MAP_COORD_SET_CMD | + MAP_UNIT(0) | + ENABLE_TEXCOORD_PARAMS | + TEXCOORDS_ARE_NORMAL | + TEXCOORDTYPE_CARTESIAN | + ENABLE_ADDR_V_CNTL | + TEXCOORD_ADDR_V_MODE(TEXCOORDMODE_WRAP) | + ENABLE_ADDR_U_CNTL | + TEXCOORD_ADDR_U_MODE(TEXCOORDMODE_WRAP)); + + + i830SetTexWrapping( t, texObj->WrapS, texObj->WrapT ); + i830SetTexFilter( t, texObj->MinFilter, texObj->MagFilter, + texObj->MaxAnisotropy ); + i830SetTexBorderColor( t, texObj->_BorderChan ); + + return &t->intel; +} + + +static void i830TexParameter( GLcontext *ctx, GLenum target, + struct gl_texture_object *tObj, + GLenum pname, const GLfloat *params ) +{ + i830TextureObjectPtr t = (i830TextureObjectPtr) tObj->DriverData; + if (!t) + return; + + switch (pname) { + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_MAG_FILTER: + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + i830SetTexFilter( t, tObj->MinFilter, tObj->MagFilter, + tObj->MaxAnisotropy); + break; + + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + i830SetTexWrapping( t, tObj->WrapS, tObj->WrapT ); + break; + + case GL_TEXTURE_BORDER_COLOR: + i830SetTexBorderColor( t, tObj->_BorderChan ); + break; + + case GL_TEXTURE_BASE_LEVEL: + case GL_TEXTURE_MAX_LEVEL: + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + /* The i830 and its successors can do a lot of this without + * reloading the textures. A project for someone? + */ + intelFlush( ctx ); + driSwapOutTextureObject( (driTextureObject *) t ); + break; + + default: + return; + } + + t->intel.dirty = I830_UPLOAD_TEX_ALL; +} + + +static void i830TexEnv( GLcontext *ctx, GLenum target, + GLenum pname, const GLfloat *param ) +{ + i830ContextPtr i830 = I830_CONTEXT( ctx ); + GLuint unit = ctx->Texture.CurrentUnit; + + switch (pname) { + case GL_TEXTURE_ENV_COLOR: +#if 0 + { + GLubyte r, g, b, a; + GLuint col; + + UNCLAMPED_FLOAT_TO_UBYTE(r, param[RCOMP]); + UNCLAMPED_FLOAT_TO_UBYTE(g, param[GCOMP]); + UNCLAMPED_FLOAT_TO_UBYTE(b, param[BCOMP]); + UNCLAMPED_FLOAT_TO_UBYTE(a, param[ACOMP]); + + col = ((a << 24) | (r << 16) | (g << 8) | b); + + if (col != i830->state.TexEnv[unit][I830_TEXENVREG_COL1]) { + I830_STATECHANGE(i830, I830_UPLOAD_TEXENV); + i830->state.TexEnv[unit][I830_TEXENVREG_COL1] = col; + } + + break; + } +#endif + case GL_TEXTURE_ENV_MODE: + case GL_COMBINE_RGB: + case GL_COMBINE_ALPHA: + case GL_SOURCE0_RGB: + case GL_SOURCE1_RGB: + case GL_SOURCE2_RGB: + case GL_SOURCE0_ALPHA: + case GL_SOURCE1_ALPHA: + case GL_SOURCE2_ALPHA: + case GL_OPERAND0_RGB: + case GL_OPERAND1_RGB: + case GL_OPERAND2_RGB: + case GL_OPERAND0_ALPHA: + case GL_OPERAND1_ALPHA: + case GL_OPERAND2_ALPHA: + case GL_RGB_SCALE: + case GL_ALPHA_SCALE: + break; + + case GL_TEXTURE_LOD_BIAS: { + int b = (int) ((*param) * 16.0); + if (b > 63) b = 63; + if (b < -64) b = -64; + I830_STATECHANGE(i830, I830_UPLOAD_TEX(unit)); + i830->state.Tex[unit][I830_TEXREG_TM0S3] &= ~TM0S3_LOD_BIAS_MASK; + i830->state.Tex[unit][I830_TEXREG_TM0S3] |= + ((b << TM0S3_LOD_BIAS_SHIFT) & TM0S3_LOD_BIAS_MASK); + break; + } + + default: + break; + } +} + + + + +void i830InitTextureFuncs( struct dd_function_table *functions ) +{ + functions->TexEnv = i830TexEnv; + functions->TexParameter = i830TexParameter; +} diff --git a/src/mesa/drivers/dri/i915/i830_texblend.c b/src/mesa/drivers/dri/i915/i830_texblend.c new file mode 100644 index 0000000..e30b2df --- /dev/null +++ b/src/mesa/drivers/dri/i915/i830_texblend.c @@ -0,0 +1,1058 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "glheader.h" +#include "macros.h" +#include "mtypes.h" +#include "simple_list.h" +#include "enums.h" +#include "texformat.h" +#include "texstore.h" + +#include "mm.h" + +#include "intel_screen.h" +#include "intel_ioctl.h" +#include "intel_tex.h" + +#include "i830_context.h" +#include "i830_reg.h" + + +/* ================================================================ + * Texture combine functions + */ +static GLuint pass_through( GLuint *state, GLuint blendUnit ) +{ + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + + return 4; +} + +static GLuint emit_factor( GLuint blendUnit, GLuint *state, GLuint count, + const GLfloat *factor ) +{ + GLubyte r, g, b, a; + GLuint col; + + if (0) + fprintf(stderr, "emit constant %d: %.2f %.2f %.2f %.2f\n", + blendUnit, factor[0], factor[1], factor[2], factor[3]); + + UNCLAMPED_FLOAT_TO_UBYTE(r, factor[0]); + UNCLAMPED_FLOAT_TO_UBYTE(g, factor[1]); + UNCLAMPED_FLOAT_TO_UBYTE(b, factor[2]); + UNCLAMPED_FLOAT_TO_UBYTE(a, factor[3]); + + col = ((a << 24) | (r << 16) | (g << 8) | b); + + state[count++] = _3DSTATE_COLOR_FACTOR_N_CMD(blendUnit); + state[count++] = col; + + return count; +} + + +static __inline__ GLuint GetTexelOp(GLint unit) +{ + switch(unit) { + case 0: return TEXBLENDARG_TEXEL0; + case 1: return TEXBLENDARG_TEXEL1; + case 2: return TEXBLENDARG_TEXEL2; + case 3: return TEXBLENDARG_TEXEL3; + default: return TEXBLENDARG_TEXEL0; + } +} + + +GLuint i830SetBlend_GL1_2(i830ContextPtr i830, int blendUnit, + GLenum envMode, GLenum format, GLuint texel_op, + GLuint *state, const GLfloat *factor) +{ + if(INTEL_DEBUG&DEBUG_TEXTURE) + fprintf(stderr, "%s %s %s texel_op(0x%x)\n", + __FUNCTION__, + _mesa_lookup_enum_by_nr(format), + _mesa_lookup_enum_by_nr(envMode), + texel_op); + + switch(envMode) { + case GL_REPLACE: + switch(format) { + case GL_ALPHA: + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + return 4; + + case GL_LUMINANCE: + case GL_RGB: + case GL_YCBCR_MESA: + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + return 4; + + case GL_INTENSITY: + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + return 4; + + default: + /* Always set to passthru if something is funny */ + return pass_through( state, blendUnit ); + } + + case GL_MODULATE: + switch(format) { + case GL_ALPHA: + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_MODULATE); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[4] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + return 5; + + case GL_LUMINANCE: + case GL_RGB: + case GL_YCBCR_MESA: + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_MODULATE); + state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + state[4] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + return 5; + + case GL_INTENSITY: + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_MODULATE); + state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_MODULATE); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + state[4] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[5] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + return 6; + + default: + /* Always set to passthru if something is funny */ + return pass_through( state, blendUnit ); + } + + case GL_DECAL: + switch(format) { + case GL_RGB: + case GL_YCBCR_MESA: + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + return 4; + + case GL_RGBA: + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_BLEND); + state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG0 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_REPLICATE_ALPHA | + texel_op); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[4] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + state[5] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + return 6; + default: + /* Always set to passthru if something is funny */ + return pass_through( state, blendUnit ); + } + + case GL_BLEND: + switch(format) { + case GL_ALPHA: + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_MODULATE); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[4] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + return 5; + + case GL_LUMINANCE: + case GL_RGB: + case GL_YCBCR_MESA: + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_BLEND); + state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG0 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_FACTOR_N); + state[4] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + state[5] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + return emit_factor( blendUnit, state, 6, factor ); + + case GL_INTENSITY: + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_BLEND); + state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_BLEND); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG0 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_FACTOR_N); + state[4] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + state[5] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG0 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[6] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_FACTOR_N); + state[7] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + return emit_factor( blendUnit, state, 8, factor ); + + + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_BLEND); + state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_MODULATE); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG0 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_FACTOR_N); + state[4] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + state[5] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[6] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + return emit_factor( blendUnit, state, 7, factor ); + + default: + /* Always set to passthru if something is funny */ + return pass_through( state, blendUnit ); + } + + case GL_ADD: + switch(format) { + case GL_ALPHA: + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_MODULATE); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[4] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + return 5; + + case GL_LUMINANCE: + case GL_RGB: + case GL_YCBCR_MESA: + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ADD); + state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ARG1); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + state[4] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + return 5; + + case GL_INTENSITY: + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ADD); + state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ADD); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + state[4] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[5] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + return 6; + + case GL_LUMINANCE_ALPHA: + case GL_RGBA: + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_ADD); + state[1] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_SCALE_1X | + TEXOP_MODIFY_PARMS | + TEXBLENDOP_MODULATE); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + state[4] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + texel_op); + state[5] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + TEXBLENDARG_CURRENT); + return 6; + + default: + /* Always set to passthru if something is funny */ + return pass_through( state, blendUnit ); + } + + default: + /* Always set to passthru if something is funny */ + return pass_through( state, blendUnit ); + } +} + +static GLuint i830SetTexEnvCombine(i830ContextPtr i830, + const struct gl_texture_unit *texUnit, + GLint blendUnit, + GLuint texel_op, + GLuint *state, + const GLfloat *factor ) +{ + GLuint blendop; + GLuint ablendop; + GLuint args_RGB[3]; + GLuint args_A[3]; + GLuint rgb_shift; + GLuint alpha_shift; + GLboolean need_factor = 0; + int i; + + if(INTEL_DEBUG&DEBUG_TEXTURE) + fprintf(stderr, "%s\n", __FUNCTION__); + + + /* The EXT version of the DOT3 extension does not support the + * scale factor, but the ARB version (and the version in OpenGL + * 1.3) does. + */ + switch (texUnit->Combine.ModeRGB) { + case GL_DOT3_RGB_EXT: + alpha_shift = texUnit->Combine.ScaleShiftA; + rgb_shift = 0; + break; + + case GL_DOT3_RGBA_EXT: + alpha_shift = 0; + rgb_shift = 0; + break; + + default: + rgb_shift = texUnit->Combine.ScaleShiftRGB; + alpha_shift = texUnit->Combine.ScaleShiftA; + break; + } + + + switch(texUnit->Combine.ModeRGB) { + case GL_REPLACE: + blendop = TEXBLENDOP_ARG1; + break; + case GL_MODULATE: + blendop = TEXBLENDOP_MODULATE; + break; + case GL_ADD: + blendop = TEXBLENDOP_ADD; + break; + case GL_ADD_SIGNED: + blendop = TEXBLENDOP_ADDSIGNED; + break; + case GL_INTERPOLATE: + blendop = TEXBLENDOP_BLEND; + break; + case GL_SUBTRACT: + blendop = TEXBLENDOP_SUBTRACT; + break; + case GL_DOT3_RGB_EXT: + case GL_DOT3_RGB: + blendop = TEXBLENDOP_DOT3; + break; + case GL_DOT3_RGBA_EXT: + case GL_DOT3_RGBA: + blendop = TEXBLENDOP_DOT3; + break; + default: + return pass_through( state, blendUnit ); + } + + blendop |= (rgb_shift << TEXOP_SCALE_SHIFT); + + + /* Handle RGB args */ + for(i = 0; i < 3; i++) { + switch(texUnit->Combine.SourceRGB[i]) { + case GL_TEXTURE: + args_RGB[i] = texel_op; + break; + case GL_CONSTANT: + args_RGB[i] = TEXBLENDARG_FACTOR_N; + need_factor = 1; + break; + case GL_PRIMARY_COLOR: + args_RGB[i] = TEXBLENDARG_DIFFUSE; + break; + case GL_PREVIOUS: + args_RGB[i] = TEXBLENDARG_CURRENT; + break; + default: + return pass_through( state, blendUnit ); + } + + switch(texUnit->Combine.OperandRGB[i]) { + case GL_SRC_COLOR: + args_RGB[i] |= 0; + break; + case GL_ONE_MINUS_SRC_COLOR: + args_RGB[i] |= TEXBLENDARG_INV_ARG; + break; + case GL_SRC_ALPHA: + args_RGB[i] |= TEXBLENDARG_REPLICATE_ALPHA; + break; + case GL_ONE_MINUS_SRC_ALPHA: + args_RGB[i] |= (TEXBLENDARG_REPLICATE_ALPHA | + TEXBLENDARG_INV_ARG); + break; + default: + return pass_through( state, blendUnit ); + } + } + + + /* Need to knobble the alpha calculations of TEXBLENDOP_DOT4 to + * match the spec. Can't use DOT3 as it won't propogate values + * into alpha as required: + * + * Note - the global factor is set up with alpha == .5, so + * the alpha part of the DOT4 calculation should be zero. + */ + if ( texUnit->Combine.ModeRGB == GL_DOT3_RGBA_EXT || + texUnit->Combine.ModeRGB == GL_DOT3_RGBA ) { + ablendop = TEXBLENDOP_DOT4; + args_A[0] = TEXBLENDARG_FACTOR; /* the global factor */ + args_A[1] = TEXBLENDARG_FACTOR; + args_A[2] = TEXBLENDARG_FACTOR; + } + else { + switch(texUnit->Combine.ModeA) { + case GL_REPLACE: + ablendop = TEXBLENDOP_ARG1; + break; + case GL_MODULATE: + ablendop = TEXBLENDOP_MODULATE; + break; + case GL_ADD: + ablendop = TEXBLENDOP_ADD; + break; + case GL_ADD_SIGNED: + ablendop = TEXBLENDOP_ADDSIGNED; + break; + case GL_INTERPOLATE: + ablendop = TEXBLENDOP_BLEND; + break; + case GL_SUBTRACT: + ablendop = TEXBLENDOP_SUBTRACT; + break; + default: + return pass_through( state, blendUnit ); + } + + + ablendop |= (alpha_shift << TEXOP_SCALE_SHIFT); + + /* Handle A args */ + for(i = 0; i < 3; i++) { + switch(texUnit->Combine.SourceA[i]) { + case GL_TEXTURE: + args_A[i] = texel_op; + break; + case GL_CONSTANT: + args_A[i] = TEXBLENDARG_FACTOR_N; + need_factor = 1; + break; + case GL_PRIMARY_COLOR: + args_A[i] = TEXBLENDARG_DIFFUSE; + break; + case GL_PREVIOUS: + args_A[i] = TEXBLENDARG_CURRENT; + break; + default: + return pass_through( state, blendUnit ); + } + + switch(texUnit->Combine.OperandA[i]) { + case GL_SRC_ALPHA: + args_A[i] |= 0; + break; + case GL_ONE_MINUS_SRC_ALPHA: + args_A[i] |= TEXBLENDARG_INV_ARG; + break; + default: + return pass_through( state, blendUnit ); + } + } + } + + + + /* Native Arg1 == Arg0 in GL_EXT_texture_env_combine spec */ + /* Native Arg2 == Arg1 in GL_EXT_texture_env_combine spec */ + /* Native Arg0 == Arg2 in GL_EXT_texture_env_combine spec */ + + /* When we render we need to figure out which is the last really enabled + * tex unit, and put last stage on it + */ + + + /* Build color pipeline */ + + state[0] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_COLOR | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + DISABLE_TEX_CNTRL_STAGE | + TEXOP_MODIFY_PARMS | + blendop); + state[1] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + args_RGB[0]); + state[2] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + args_RGB[1]); + state[3] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_COLOR | + TEXBLEND_ARG0 | + TEXBLENDARG_MODIFY_PARMS | + args_RGB[2]); + + /* Build Alpha pipeline */ + state[4] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | + TEXPIPE_ALPHA | + ENABLE_TEXOUTPUT_WRT_SEL | + TEXOP_OUTPUT_CURRENT | + TEXOP_MODIFY_PARMS | + ablendop); + state[5] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG1 | + TEXBLENDARG_MODIFY_PARMS | + args_A[0]); + state[6] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG2 | + TEXBLENDARG_MODIFY_PARMS | + args_A[1]); + state[7] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | + TEXPIPE_ALPHA | + TEXBLEND_ARG0 | + TEXBLENDARG_MODIFY_PARMS | + args_A[2]); + + + if (need_factor) + return emit_factor( blendUnit, state, 8, factor ); + else + return 8; +} + + +static void emit_texblend( i830ContextPtr i830, GLuint unit, GLuint blendUnit, + GLboolean last_stage ) +{ + struct gl_texture_unit *texUnit = &i830->intel.ctx.Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + i830TextureObjectPtr t = (i830TextureObjectPtr)tObj->DriverData; + GLuint tmp[I830_TEXBLEND_SIZE], tmp_sz; + + + if (0) fprintf(stderr, "%s unit %d\n", __FUNCTION__, unit); + + /* Update i830->state.TexBlend + */ + if (texUnit->EnvMode == GL_COMBINE) { + tmp_sz = i830SetTexEnvCombine(i830, texUnit, blendUnit, + GetTexelOp(unit), tmp, + texUnit->EnvColor ); + } + else { + tmp_sz = i830SetBlend_GL1_2(i830, blendUnit, texUnit->EnvMode, + t->intel.image[0][0].internalFormat, + GetTexelOp(unit), tmp, + texUnit->EnvColor ); + } + + if (last_stage) + tmp[0] |= TEXOP_LAST_STAGE; + + if (tmp_sz != i830->state.TexBlendWordsUsed[blendUnit] || + memcmp( tmp, i830->state.TexBlend[blendUnit], tmp_sz * sizeof(GLuint))) { + + I830_STATECHANGE( i830, I830_UPLOAD_TEXBLEND(blendUnit) ); + memcpy( i830->state.TexBlend[blendUnit], tmp, tmp_sz * sizeof(GLuint)); + i830->state.TexBlendWordsUsed[blendUnit] = tmp_sz; + } + + I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND(blendUnit), GL_TRUE); +} + +static void emit_passthrough( i830ContextPtr i830 ) +{ + GLuint tmp[I830_TEXBLEND_SIZE], tmp_sz; + GLuint unit = 0; + + tmp_sz = pass_through( tmp, unit ); + tmp[0] |= TEXOP_LAST_STAGE; + + if (tmp_sz != i830->state.TexBlendWordsUsed[unit] || + memcmp( tmp, i830->state.TexBlend[unit], tmp_sz * sizeof(GLuint))) { + + I830_STATECHANGE( i830, I830_UPLOAD_TEXBLEND(unit) ); + memcpy( i830->state.TexBlend[unit], tmp, tmp_sz * sizeof(GLuint)); + i830->state.TexBlendWordsUsed[unit] = tmp_sz; + } + + I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND(unit), GL_TRUE); +} + +void i830EmitTextureBlend( i830ContextPtr i830 ) +{ + GLcontext *ctx = &i830->intel.ctx; + GLuint unit, last_stage = 0, blendunit = 0; + + I830_ACTIVESTATE(i830, I830_UPLOAD_TEXBLEND_ALL, GL_FALSE); + + if (ctx->Texture._EnabledUnits) { + for (unit = 0 ; unit < ctx->Const.MaxTextureUnits ; unit++) + if (ctx->Texture.Unit[unit]._ReallyEnabled) + last_stage = unit; + + for (unit = 0 ; unit < ctx->Const.MaxTextureUnits ; unit++) + if (ctx->Texture.Unit[unit]._ReallyEnabled) + emit_texblend( i830, unit, blendunit++, last_stage == unit ); + } + else { + emit_passthrough( i830 ); + } +} + diff --git a/src/mesa/drivers/dri/i915/i830_texstate.c b/src/mesa/drivers/dri/i915/i830_texstate.c new file mode 100644 index 0000000..acf5cc9 --- /dev/null +++ b/src/mesa/drivers/dri/i915/i830_texstate.c @@ -0,0 +1,333 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "glheader.h" +#include "macros.h" +#include "mtypes.h" +#include "simple_list.h" +#include "enums.h" +#include "texformat.h" +#include "texstore.h" + +#include "mm.h" + +#include "intel_screen.h" +#include "intel_ioctl.h" +#include "intel_tex.h" + +#include "i830_context.h" +#include "i830_reg.h" + + +#define I830_TEX_UNIT_ENABLED(unit) (1<DriverData; + const struct gl_texture_image *baseImage = tObj->Image[0][tObj->BaseLevel]; + GLint firstLevel, lastLevel, numLevels; + + switch( baseImage->TexFormat->MesaFormat ) { + case MESA_FORMAT_L8: + t->intel.texelBytes = 1; + textureFormat = MAPSURF_8BIT | MT_8BIT_L8; + break; + + case MESA_FORMAT_I8: + t->intel.texelBytes = 1; + textureFormat = MAPSURF_8BIT | MT_8BIT_I8; + break; + + case MESA_FORMAT_A8: + t->intel.texelBytes = 1; + textureFormat = MAPSURF_8BIT | MT_8BIT_I8; /* Kludge -- check with conform, glean */ + break; + + case MESA_FORMAT_AL88: + t->intel.texelBytes = 2; + textureFormat = MAPSURF_16BIT | MT_16BIT_AY88; + break; + + case MESA_FORMAT_RGB565: + t->intel.texelBytes = 2; + textureFormat = MAPSURF_16BIT | MT_16BIT_RGB565; + break; + + case MESA_FORMAT_ARGB1555: + t->intel.texelBytes = 2; + textureFormat = MAPSURF_16BIT | MT_16BIT_ARGB1555; + break; + + case MESA_FORMAT_ARGB4444: + t->intel.texelBytes = 2; + textureFormat = MAPSURF_16BIT | MT_16BIT_ARGB4444; + break; + + case MESA_FORMAT_ARGB8888: + t->intel.texelBytes = 4; + textureFormat = MAPSURF_32BIT | MT_32BIT_ARGB8888; + break; + + case MESA_FORMAT_YCBCR_REV: + t->intel.texelBytes = 2; + textureFormat = (MAPSURF_422 | MT_422_YCRCB_NORMAL | + TM0S1_COLORSPACE_CONVERSION); + break; + + case MESA_FORMAT_YCBCR: + t->intel.texelBytes = 2; + textureFormat = (MAPSURF_422 | MT_422_YCRCB_SWAPY | /* ??? */ + TM0S1_COLORSPACE_CONVERSION); + break; + + default: + fprintf(stderr, "%s: bad image format\n", __FUNCTION__); + abort(); + } + + /* Compute which mipmap levels we really want to send to the hardware. + * This depends on the base image size, GL_TEXTURE_MIN_LOD, + * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL. + * Yes, this looks overly complicated, but it's all needed. + */ + driCalculateTextureFirstLastLevel( (driTextureObject *) t ); + + + /* Figure out the amount of memory required to hold all the mipmap + * levels. Choose the smallest pitch to accomodate the largest + * mipmap: + */ + firstLevel = t->intel.base.firstLevel; + lastLevel = t->intel.base.lastLevel; + numLevels = lastLevel - firstLevel + 1; + + /* Pitch would be subject to additional rules if texture memory were + * tiled. Currently it isn't. + */ + if (0) { + pitch = 128; + while (pitch < tObj->Image[0][firstLevel]->Width * t->intel.texelBytes) + pitch *= 2; + } + else { + pitch = tObj->Image[0][firstLevel]->Width * t->intel.texelBytes; + pitch = (pitch + 3) & ~3; + } + + + /* All images must be loaded at this pitch. Count the number of + * lines required: + */ + for ( total_height = i = 0 ; i < numLevels ; i++ ) { + t->intel.image[0][i].image = tObj->Image[0][firstLevel + i]; + if (!t->intel.image[0][i].image) + break; + + t->intel.image[0][i].offset = total_height * pitch; + t->intel.image[0][i].internalFormat = baseImage->Format; + total_height += MAX2(2, t->intel.image[0][i].image->Height); + } + + t->intel.Pitch = pitch; + t->intel.base.totalSize = total_height*pitch; + t->intel.max_level = i-1; + t->Setup[I830_TEXREG_TM0S1] = + (((tObj->Image[0][firstLevel]->Height - 1) << TM0S1_HEIGHT_SHIFT) | + ((tObj->Image[0][firstLevel]->Width - 1) << TM0S1_WIDTH_SHIFT) | + textureFormat); + t->Setup[I830_TEXREG_TM0S2] = + (((pitch / 4) - 1) << TM0S2_PITCH_SHIFT); + t->Setup[I830_TEXREG_TM0S3] &= ~TM0S3_MAX_MIP_MASK; + t->Setup[I830_TEXREG_TM0S3] &= ~TM0S3_MIN_MIP_MASK; + t->Setup[I830_TEXREG_TM0S3] |= ((numLevels - 1)*4) << TM0S3_MIN_MIP_SHIFT; + t->intel.dirty = I830_UPLOAD_TEX_ALL; + + return intelUploadTexImages( &i830->intel, &t->intel, 0 ); +} + + +static void i830_import_tex_unit( i830ContextPtr i830, + i830TextureObjectPtr t, + GLuint unit ) +{ + if(INTEL_DEBUG&DEBUG_TEXTURE) + fprintf(stderr, "%s unit(%d)\n", __FUNCTION__, unit); + + if (i830->intel.CurrentTexObj[unit]) + i830->intel.CurrentTexObj[unit]->base.bound &= ~(1U << unit); + + i830->intel.CurrentTexObj[unit] = (intelTextureObjectPtr)t; + t->intel.base.bound |= (1 << unit); + + I830_STATECHANGE( i830, I830_UPLOAD_TEX(unit) ); + + i830->state.Tex[unit][I830_TEXREG_TM0LI] = (_3DSTATE_LOAD_STATE_IMMEDIATE_2 | + (LOAD_TEXTURE_MAP0 << unit) | 4); + i830->state.Tex[unit][I830_TEXREG_TM0S0] = (TM0S0_USE_FENCE | + t->intel.TextureOffset); + + i830->state.Tex[unit][I830_TEXREG_TM0S1] = t->Setup[I830_TEXREG_TM0S1]; + i830->state.Tex[unit][I830_TEXREG_TM0S2] = t->Setup[I830_TEXREG_TM0S2]; + + i830->state.Tex[unit][I830_TEXREG_TM0S3] &= TM0S3_LOD_BIAS_MASK; + i830->state.Tex[unit][I830_TEXREG_TM0S3] |= (t->Setup[I830_TEXREG_TM0S3] & + ~TM0S3_LOD_BIAS_MASK); + + i830->state.Tex[unit][I830_TEXREG_TM0S4] = t->Setup[I830_TEXREG_TM0S4]; + i830->state.Tex[unit][I830_TEXREG_MCS] = (t->Setup[I830_TEXREG_MCS] & + ~MAP_UNIT_MASK); + i830->state.Tex[unit][I830_TEXREG_MCS] |= MAP_UNIT(unit); + + t->intel.dirty &= ~I830_UPLOAD_TEX(unit); +} + + + +static GLboolean enable_tex_common( GLcontext *ctx, GLuint unit ) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + i830TextureObjectPtr t = (i830TextureObjectPtr)tObj->DriverData; + + if (0) fprintf(stderr, "%s\n", __FUNCTION__); + + /* Fallback if there's a texture border */ + if ( tObj->Image[0][tObj->BaseLevel]->Border > 0 ) { + fprintf(stderr, "Texture border\n"); + return GL_FALSE; + } + + /* Upload teximages (not pipelined) + */ + if (t->intel.base.dirty_images[0]) { + if (!i830SetTexImages( i830, tObj )) { + return GL_FALSE; + } + } + + /* Update state if this is a different texture object to last + * time. + */ + if (i830->intel.CurrentTexObj[unit] != &t->intel || + (t->intel.dirty & I830_UPLOAD_TEX(unit))) { + i830_import_tex_unit( i830, t, unit); + } + + I830_ACTIVESTATE(i830, I830_UPLOAD_TEX(unit), GL_TRUE); + + return GL_TRUE; +} + +static GLboolean enable_tex_rect( GLcontext *ctx, GLuint unit ) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + GLuint mcs = i830->state.Tex[unit][I830_TEXREG_MCS]; + + mcs &= ~TEXCOORDS_ARE_NORMAL; + mcs |= TEXCOORDS_ARE_IN_TEXELUNITS; + + if (mcs != i830->state.Tex[unit][I830_TEXREG_MCS]) { + I830_STATECHANGE(i830, I830_UPLOAD_TEX(unit)); + i830->state.Tex[unit][I830_TEXREG_MCS] = mcs; + } + + return GL_TRUE; +} + + +static GLboolean enable_tex_2d( GLcontext *ctx, GLuint unit ) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + GLuint mcs = i830->state.Tex[unit][I830_TEXREG_MCS]; + + mcs &= ~TEXCOORDS_ARE_IN_TEXELUNITS; + mcs |= TEXCOORDS_ARE_NORMAL; + + if (mcs != i830->state.Tex[unit][I830_TEXREG_MCS]) { + I830_STATECHANGE(i830, I830_UPLOAD_TEX(unit)); + i830->state.Tex[unit][I830_TEXREG_MCS] = mcs; + } + + return GL_TRUE; +} + + +static GLboolean disable_tex( GLcontext *ctx, GLuint unit ) +{ + i830ContextPtr i830 = I830_CONTEXT(ctx); + + /* This is happening too often. I need to conditionally send diffuse + * state to the card. Perhaps a diffuse dirty flag of some kind. + * Will need to change this logic if more than 2 texture units are + * used. We need to only do this up to the last unit enabled, or unit + * one if nothing is enabled. + */ + + if ( i830->intel.CurrentTexObj[unit] != NULL ) { + /* The old texture is no longer bound to this texture unit. + * Mark it as such. + */ + + i830->intel.CurrentTexObj[unit]->base.bound &= ~(1U << 0); + i830->intel.CurrentTexObj[unit] = NULL; + } + + return GL_TRUE; +} + +static GLboolean i830UpdateTexUnit( GLcontext *ctx, GLuint unit ) +{ + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + + if (texUnit->_ReallyEnabled && + INTEL_CONTEXT(ctx)->intelScreen->textureSize < 2048 * 1024) + return GL_FALSE; + + if (texUnit->_ReallyEnabled == TEXTURE_1D_BIT || + texUnit->_ReallyEnabled == TEXTURE_2D_BIT) { + return (enable_tex_common( ctx, unit ) && + enable_tex_2d( ctx, unit )); + } + else if (texUnit->_ReallyEnabled == TEXTURE_RECT_BIT) { + return (enable_tex_common( ctx, unit ) && + enable_tex_rect( ctx, unit )); + } + else if (texUnit->_ReallyEnabled) { + return GL_FALSE; + } + else { + return disable_tex( ctx, unit ); + } +} + + +void i830UpdateTextureState( intelContextPtr intel ) +{ + i830ContextPtr i830 = I830_CONTEXT(intel); + GLcontext *ctx = &intel->ctx; + GLboolean ok; + + if (0) fprintf(stderr, "%s\n", __FUNCTION__); + + I830_ACTIVESTATE(i830, I830_UPLOAD_TEX_ALL, GL_FALSE); + + ok = (i830UpdateTexUnit( ctx, 0 ) && + i830UpdateTexUnit( ctx, 1 ) && + i830UpdateTexUnit( ctx, 2 ) && + i830UpdateTexUnit( ctx, 3 )); + + FALLBACK( intel, I830_FALLBACK_TEXTURE, !ok ); + + if (ok) + i830EmitTextureBlend( i830 ); +} + + + diff --git a/src/mesa/drivers/dri/i915/i830_vtbl.c b/src/mesa/drivers/dri/i915/i830_vtbl.c new file mode 100644 index 0000000..5fb436f --- /dev/null +++ b/src/mesa/drivers/dri/i915/i830_vtbl.c @@ -0,0 +1,426 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + + +#include "i830_context.h" +#include "i830_reg.h" + +#include "intel_batchbuffer.h" + +#include "tnl/t_context.h" +#include "tnl/t_vertex.h" + +static GLboolean i830_check_vertex_size( intelContextPtr intel, + GLuint expected ); + +#define SZ_TO_HW(sz) ((sz-2)&0x3) +#define EMIT_SZ(sz) (EMIT_1F + (sz) - 1) +#define EMIT_ATTR( ATTR, STYLE, V0 ) \ +do { \ + intel->vertex_attrs[intel->vertex_attr_count].attrib = (ATTR); \ + intel->vertex_attrs[intel->vertex_attr_count].format = (STYLE); \ + intel->vertex_attr_count++; \ + v0 |= V0; \ +} while (0) + +#define EMIT_PAD( N ) \ +do { \ + intel->vertex_attrs[intel->vertex_attr_count].attrib = 0; \ + intel->vertex_attrs[intel->vertex_attr_count].format = EMIT_PAD; \ + intel->vertex_attrs[intel->vertex_attr_count].offset = (N); \ + intel->vertex_attr_count++; \ +} while (0) + + +#define VRTX_TEX_SET_FMT(n, x) ((x)<<((n)*2)) +#define TEXBIND_SET(n, x) ((x)<<((n)*4)) + +static void i830_render_start( intelContextPtr intel ) +{ + GLcontext *ctx = &intel->ctx; + i830ContextPtr i830 = I830_CONTEXT(intel); + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_buffer *VB = &tnl->vb; + GLuint index = tnl->render_inputs; + GLuint v0 = _3DSTATE_VFT0_CMD; + GLuint v2 = _3DSTATE_VFT1_CMD; + GLuint mcsb1 = 0; + + /* Important: + */ + VB->AttribPtr[VERT_ATTRIB_POS] = VB->NdcPtr; + intel->vertex_attr_count = 0; + + /* EMIT_ATTR's must be in order as they tell t_vertex.c how to + * build up a hardware vertex. + */ + if (index & _TNL_BITS_TEX_ANY) { + EMIT_ATTR( _TNL_ATTRIB_POS, EMIT_4F_VIEWPORT, VFT0_XYZW ); + intel->coloroffset = 4; + } + else { + EMIT_ATTR( _TNL_ATTRIB_POS, EMIT_3F_VIEWPORT, VFT0_XYZ ); + intel->coloroffset = 3; + } + + EMIT_ATTR( _TNL_ATTRIB_COLOR0, EMIT_4UB_4F_RGBA, VFT0_DIFFUSE ); + + intel->specoffset = 0; + if (index & (_TNL_BIT_COLOR1|_TNL_BIT_FOG)) { + if (index & _TNL_BIT_COLOR1) { + intel->specoffset = intel->coloroffset + 1; + EMIT_ATTR( _TNL_ATTRIB_COLOR1, EMIT_3UB_3F_RGB, VFT0_SPEC ); + } + else + EMIT_PAD( 3 ); + + if (index & _TNL_BIT_FOG) + EMIT_ATTR( _TNL_ATTRIB_FOG, EMIT_1UB_1F, VFT0_SPEC ); + else + EMIT_PAD( 1 ); + } + + if (index & _TNL_BITS_TEX_ANY) { + int i, count = 0; + + for (i = 0; i < I830_TEX_UNITS; i++) { + if (index & _TNL_BIT_TEX(i)) { + GLuint sz = VB->TexCoordPtr[i]->size; + GLuint emit; + GLuint mcs = (i830->state.Tex[i][I830_TEXREG_MCS] & + ~TEXCOORDTYPE_MASK); + + switch (sz) { + case 1: + case 2: + case 3: /* XXX: fix for CUBE/VOLUME textures */ + emit = EMIT_2F; + sz = 2; + mcs |= TEXCOORDTYPE_CARTESIAN; + break; + case 4: + emit = EMIT_3F_XYW; + sz = 3; + mcs |= TEXCOORDTYPE_HOMOGENEOUS; + break; + default: + continue; + }; + + + EMIT_ATTR( _TNL_ATTRIB_TEX0+i, emit, 0 ); + v2 |= VRTX_TEX_SET_FMT(count, SZ_TO_HW(sz)); + mcsb1 |= (count+8)<<(i*4); + + if (mcs != i830->state.Tex[i][I830_TEXREG_MCS]) { + I830_STATECHANGE(i830, I830_UPLOAD_TEX(i)); + i830->state.Tex[i][I830_TEXREG_MCS] = mcs; + } + + count++; + } + } + + v0 |= VFT0_TEX_COUNT(count); + } + + /* Only need to change the vertex emit code if there has been a + * statechange to a new hardware vertex format: + */ + if (v0 != i830->state.Ctx[I830_CTXREG_VF] || + v2 != i830->state.Ctx[I830_CTXREG_VF2] || + mcsb1 != i830->state.Ctx[I830_CTXREG_MCSB1] || + index != i830->last_index) { + + I830_STATECHANGE( i830, I830_UPLOAD_CTX ); + + /* Must do this *after* statechange, so as not to affect + * buffered vertices reliant on the old state: + */ + intel->vertex_size = + _tnl_install_attrs( ctx, + intel->vertex_attrs, + intel->vertex_attr_count, + intel->ViewportMatrix.m, 0 ); + + intel->vertex_size >>= 2; + + i830->state.Ctx[I830_CTXREG_VF] = v0; + i830->state.Ctx[I830_CTXREG_VF2] = v2; + i830->state.Ctx[I830_CTXREG_MCSB1] = mcsb1; + i830->last_index = index; + + assert(i830_check_vertex_size( intel, intel->vertex_size )); + } +} + +static void i830_reduced_primitive_state( intelContextPtr intel, + GLenum rprim ) +{ + i830ContextPtr i830 = I830_CONTEXT(intel); + GLuint st1 = i830->state.Stipple[I830_STPREG_ST1]; + + st1 &= ~ST1_ENABLE; + + switch (rprim) { + case GL_TRIANGLES: + if (intel->ctx.Polygon.StippleFlag && + intel->hw_stipple) + st1 |= ST1_ENABLE; + break; + case GL_LINES: + case GL_POINTS: + default: + break; + } + + i830->intel.reduced_primitive = rprim; + + if (st1 != i830->state.Stipple[I830_STPREG_ST1]) { + I830_STATECHANGE(i830, I830_UPLOAD_STIPPLE); + i830->state.Stipple[I830_STPREG_ST1] = st1; + } +} + +/* Pull apart the vertex format registers and figure out how large a + * vertex is supposed to be. + */ +static GLboolean i830_check_vertex_size( intelContextPtr intel, + GLuint expected ) +{ + i830ContextPtr i830 = I830_CONTEXT(intel); + int vft0 = i830->current->Ctx[I830_CTXREG_VF]; + int vft1 = i830->current->Ctx[I830_CTXREG_VF2]; + int nrtex = (vft0 & VFT0_TEX_COUNT_MASK) >> VFT0_TEX_COUNT_SHIFT; + int i, sz = 0; + + switch (vft0 & VFT0_XYZW_MASK) { + case VFT0_XY: sz = 2; break; + case VFT0_XYZ: sz = 3; break; + case VFT0_XYW: sz = 3; break; + case VFT0_XYZW: sz = 4; break; + default: + fprintf(stderr, "no xyzw specified\n"); + return 0; + } + + if (vft0 & VFT0_SPEC) sz++; + if (vft0 & VFT0_DIFFUSE) sz++; + if (vft0 & VFT0_DEPTH_OFFSET) sz++; + if (vft0 & VFT0_POINT_WIDTH) sz++; + + for (i = 0 ; i < nrtex ; i++) { + switch (vft1 & VFT1_TEX0_MASK) { + case TEXCOORDFMT_2D: sz += 2; break; + case TEXCOORDFMT_3D: sz += 3; break; + case TEXCOORDFMT_4D: sz += 4; break; + case TEXCOORDFMT_1D: sz += 1; break; + } + vft1 >>= VFT1_TEX1_SHIFT; + } + + if (sz != expected) + fprintf(stderr, "vertex size mismatch %d/%d\n", sz, expected); + + return sz == expected; +} + +static void i830_emit_invarient_state( intelContextPtr intel ) +{ + BATCH_LOCALS; + + BEGIN_BATCH( 200 ); + + OUT_BATCH(_3DSTATE_MAP_CUBE | MAP_UNIT(0)); + OUT_BATCH(_3DSTATE_MAP_CUBE | MAP_UNIT(1)); + OUT_BATCH(_3DSTATE_MAP_CUBE | MAP_UNIT(2)); + OUT_BATCH(_3DSTATE_MAP_CUBE | MAP_UNIT(3)); + + OUT_BATCH(_3DSTATE_DFLT_DIFFUSE_CMD); + OUT_BATCH(0); + + OUT_BATCH(_3DSTATE_DFLT_SPEC_CMD); + OUT_BATCH(0); + + OUT_BATCH(_3DSTATE_DFLT_Z_CMD); + OUT_BATCH(0); + + OUT_BATCH(_3DSTATE_FOG_MODE_CMD); + OUT_BATCH(FOGFUNC_ENABLE | + FOG_LINEAR_CONST | + FOGSRC_INDEX_Z | + ENABLE_FOG_DENSITY); + OUT_BATCH(0); + OUT_BATCH(0); + + + OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD | + MAP_UNIT(0) | + DISABLE_TEX_STREAM_BUMP | + ENABLE_TEX_STREAM_COORD_SET | + TEX_STREAM_COORD_SET(0) | + ENABLE_TEX_STREAM_MAP_IDX | TEX_STREAM_MAP_IDX(0)); + OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD | + MAP_UNIT(1) | + DISABLE_TEX_STREAM_BUMP | + ENABLE_TEX_STREAM_COORD_SET | + TEX_STREAM_COORD_SET(1) | + ENABLE_TEX_STREAM_MAP_IDX | TEX_STREAM_MAP_IDX(1)); + OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD | + MAP_UNIT(2) | + DISABLE_TEX_STREAM_BUMP | + ENABLE_TEX_STREAM_COORD_SET | + TEX_STREAM_COORD_SET(2) | + ENABLE_TEX_STREAM_MAP_IDX | TEX_STREAM_MAP_IDX(2)); + OUT_BATCH(_3DSTATE_MAP_TEX_STREAM_CMD | + MAP_UNIT(3) | + DISABLE_TEX_STREAM_BUMP | + ENABLE_TEX_STREAM_COORD_SET | + TEX_STREAM_COORD_SET(3) | + ENABLE_TEX_STREAM_MAP_IDX | TEX_STREAM_MAP_IDX(3)); + + OUT_BATCH(_3DSTATE_MAP_COORD_TRANSFORM); + OUT_BATCH(DISABLE_TEX_TRANSFORM | TEXTURE_SET(0)); + OUT_BATCH(_3DSTATE_MAP_COORD_TRANSFORM); + OUT_BATCH(DISABLE_TEX_TRANSFORM | TEXTURE_SET(1)); + OUT_BATCH(_3DSTATE_MAP_COORD_TRANSFORM); + OUT_BATCH(DISABLE_TEX_TRANSFORM | TEXTURE_SET(2)); + OUT_BATCH(_3DSTATE_MAP_COORD_TRANSFORM); + OUT_BATCH(DISABLE_TEX_TRANSFORM | TEXTURE_SET(3)); + + OUT_BATCH(_3DSTATE_RASTER_RULES_CMD | + ENABLE_POINT_RASTER_RULE | + OGL_POINT_RASTER_RULE | + ENABLE_LINE_STRIP_PROVOKE_VRTX | + ENABLE_TRI_FAN_PROVOKE_VRTX | + ENABLE_TRI_STRIP_PROVOKE_VRTX | + LINE_STRIP_PROVOKE_VRTX(1) | + TRI_FAN_PROVOKE_VRTX(2) | + TRI_STRIP_PROVOKE_VRTX(2)); + + OUT_BATCH(_3DSTATE_SCISSOR_ENABLE_CMD | + DISABLE_SCISSOR_RECT); + + OUT_BATCH(_3DSTATE_SCISSOR_RECT_0_CMD); + OUT_BATCH(0); + OUT_BATCH(0); + + OUT_BATCH(_3DSTATE_VERTEX_TRANSFORM); + OUT_BATCH(DISABLE_VIEWPORT_TRANSFORM | DISABLE_PERSPECTIVE_DIVIDE); + + OUT_BATCH(_3DSTATE_W_STATE_CMD); + OUT_BATCH(MAGIC_W_STATE_DWORD1); + OUT_BATCH(0x3f800000 /* 1.0 in IEEE float */ ); + + + OUT_BATCH(_3DSTATE_COLOR_FACTOR_CMD); + OUT_BATCH(0x80808080); /* .5 required in alpha for GL_DOT3_RGBA_EXT */ + + ADVANCE_BATCH(); +} + + +#define emit( intel, state, size ) \ +do { \ + int k; \ + BEGIN_BATCH( size / sizeof(GLuint)); \ + for (k = 0 ; k < size / sizeof(GLuint) ; k++) \ + OUT_BATCH(state[k]); \ + ADVANCE_BATCH(); \ +} while (0); + + +/* Push the state into the sarea and/or texture memory. + */ +static void i830_emit_state( intelContextPtr intel ) +{ + i830ContextPtr i830 = I830_CONTEXT(intel); + struct i830_hw_state *state = i830->current; + BATCH_LOCALS; + int i; + GLuint dirty = state->active & ~state->emitted; + + if (dirty & I830_UPLOAD_CTX) { + if (VERBOSE) fprintf(stderr, "I830_UPLOAD_CTX:\n"); + emit( i830, state->Ctx, sizeof(state->Ctx) ); + } + + if (dirty & I830_UPLOAD_BUFFERS) { + if (VERBOSE) fprintf(stderr, "I830_UPLOAD_BUFFERS:\n"); + emit( i830, state->Buffer, sizeof(state->Buffer) ); + } + + if (dirty & I830_UPLOAD_STIPPLE) { + if (VERBOSE) fprintf(stderr, "I830_UPLOAD_STIPPLE:\n"); + emit( i830, state->Stipple, sizeof(state->Stipple) ); + } + + for (i = 0; i < I830_TEX_UNITS; i++) { + if ((dirty & I830_UPLOAD_TEX(i))) { + if (VERBOSE) fprintf(stderr, "I830_UPLOAD_TEX(%d):\n", i); + emit( i830, state->Tex[i], sizeof(state->Tex[i])); + } + + if (dirty & I830_UPLOAD_TEXBLEND(i)) { + if (VERBOSE) fprintf(stderr, "I830_UPLOAD_TEXBLEND(%d):\n", i); + emit( i830, state->TexBlend[i], + state->TexBlendWordsUsed[i] * 4 ); + } + } + + state->emitted |= dirty; +} + +static void i830_destroy_context( intelContextPtr intel ) +{ + _tnl_free_vertices(&intel->ctx); +} + +static void i830_set_draw_offset( intelContextPtr intel, int offset ) +{ + i830ContextPtr i830 = I830_CONTEXT(intel); + I830_STATECHANGE( i830, I830_UPLOAD_BUFFERS ); + i830->state.Buffer[I830_DESTREG_CBUFADDR2] = offset; +} + +/* This isn't really handled at the moment. + */ +static void i830_lost_hardware( intelContextPtr intel ) +{ + I830_CONTEXT(intel)->state.emitted = 0; +} + + + +static void i830_emit_flush( intelContextPtr intel ) +{ + BATCH_LOCALS; + + BEGIN_BATCH(2); + OUT_BATCH( MI_FLUSH | FLUSH_MAP_CACHE ); + OUT_BATCH( 0 ); + ADVANCE_BATCH(); +} + + + + +void i830InitVtbl( i830ContextPtr i830 ) +{ + i830->intel.vtbl.alloc_tex_obj = i830AllocTexObj; + i830->intel.vtbl.check_vertex_size = i830_check_vertex_size; + i830->intel.vtbl.clear_with_tris = i830ClearWithTris; + i830->intel.vtbl.destroy = i830_destroy_context; + i830->intel.vtbl.emit_invarient_state = i830_emit_invarient_state; + i830->intel.vtbl.emit_state = i830_emit_state; + i830->intel.vtbl.lost_hardware = i830_lost_hardware; + i830->intel.vtbl.reduced_primitive_state = i830_reduced_primitive_state; + i830->intel.vtbl.set_draw_offset = i830_set_draw_offset; + i830->intel.vtbl.update_texture_state = i830UpdateTextureState; + i830->intel.vtbl.emit_flush = i830_emit_flush; + i830->intel.vtbl.render_start = i830_render_start; +} diff --git a/src/mesa/drivers/dri/i915/i915_context.c b/src/mesa/drivers/dri/i915/i915_context.c new file mode 100644 index 0000000..f2cdcfc --- /dev/null +++ b/src/mesa/drivers/dri/i915/i915_context.c @@ -0,0 +1,211 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "i915_context.h" +#include "imports.h" +#include "intel_tex.h" +#include "intel_tris.h" +#include "tnl/t_context.h" +#include "tnl/t_pipeline.h" +#include "tnl/t_vertex.h" + +#include "swrast/swrast.h" +#include "swrast_setup/swrast_setup.h" +#include "tnl/tnl.h" +#include "array_cache/acache.h" + +#include "utils.h" +#include "i915_reg.h" + +/*************************************** + * Mesa's Driver Functions + ***************************************/ + + +static const char * const card_extensions[] = +{ + "GL_ARB_fragment_program", + "GL_ARB_texture_cube_map", + "GL_EXT_blend_equation_separate", + "GL_ATI_blend_equation_separate", + "GL_ARB_point_parameters", + NULL +}; + +/* Override intel default. + */ +static void i915InvalidateState( GLcontext *ctx, GLuint new_state ) +{ + _swrast_InvalidateState( ctx, new_state ); + _swsetup_InvalidateState( ctx, new_state ); + _ac_InvalidateState( ctx, new_state ); + _tnl_InvalidateState( ctx, new_state ); + _tnl_invalidate_vertex_state( ctx, new_state ); + INTEL_CONTEXT(ctx)->NewGLState |= new_state; + + /* Todo: gather state values under which tracked parameters become + * invalidated, add callbacks for things like + * ProgramLocalParameters, etc. + */ + { + struct i915_fragment_program *p = + (struct i915_fragment_program *)ctx->FragmentProgram.Current; + if (p->nr_params) + p->params_uptodate = 0; + } + +} + +/* This is the extension list explicitly enabled by the client and + * excludes functionality available in Mesa and also excludes legacy + * extensions. It is recognized that in an open source driver, those + * extensions will probably be re-enabled. + */ +static const GLubyte *i915GetString( GLcontext *ctx, GLenum name ) +{ + if (name == GL_EXTENSIONS) + return + "GL_ARB_fragment_program " + "GL_ARB_multitexture " + "GL_ARB_point_parameters " + "GL_ARB_texture_border_clamp " + "GL_ARB_texture_compression " + "GL_ARB_texture_cube_map " + "GL_ARB_texture_env_add " + "GL_ARB_texture_env_combine " + "GL_ARB_texture_env_dot3 " + "GL_ARB_texture_mirrored_repeat " + "GL_ARB_transpose_matrix " + "GL_ARB_vertex_buffer_object " + "GL_ARB_vertex_program " + "GL_ARB_window_pos " + "GL_EXT_abgr " + "GL_EXT_bgra " + "GL_EXT_blend_color " + "GL_EXT_blend_func_separate " + "GL_EXT_blend_minmax " + "GL_EXT_blend_subtract " + "GL_EXT_clip_volume_hint " + "GL_EXT_compiled_vertex_array " + "GL_EXT_draw_range_elements " + "GL_EXT_fog_coord " + "GL_EXT_multi_draw_arrays " + "GL_EXT_packed_pixels " + "GL_EXT_rescale_normal " + "GL_EXT_secondary_color " + "GL_EXT_separate_specular_color " + "GL_EXT_stencil_wrap " + "GL_EXT_texture3D " + "GL_EXT_texture_env_add " + "GL_EXT_texture_env_combine " + "GL_EXT_texture_filter_anisotropic " + "GL_IBM_texture_mirrored_repeat " + "GL_MESA_ycbcr_texture " + "GL_MESA_window_pos " + "GL_NV_texgen_reflection " + "GL_SGIS_generate_mipmap"; + + return intelGetString( ctx, name ); +} + + +static void i915InitDriverFunctions( struct dd_function_table *functions ) +{ + intelInitDriverFunctions( functions ); + i915InitStateFunctions( functions ); + i915InitTextureFuncs( functions ); + i915InitFragProgFuncs( functions ); + functions->UpdateState = i915InvalidateState; + functions->GetString = i915GetString; +} + + + +GLboolean i915CreateContext( const __GLcontextModes *mesaVis, + __DRIcontextPrivate *driContextPriv, + void *sharedContextPrivate) +{ + struct dd_function_table functions; + i915ContextPtr i915 = (i915ContextPtr) CALLOC_STRUCT(i915_context); + intelContextPtr intel = &i915->intel; + GLcontext *ctx = &intel->ctx; + + if (!i915) return GL_FALSE; + + i915InitVtbl( i915 ); + + i915InitDriverFunctions( &functions ); + + if (!intelInitContext( intel, mesaVis, driContextPriv, + sharedContextPrivate, &functions )) { + FREE(i915); + return GL_FALSE; + } + + ctx->Const.MaxTextureUnits = I915_TEX_UNITS; + ctx->Const.MaxTextureImageUnits = I915_TEX_UNITS; + ctx->Const.MaxTextureCoordUnits = I915_TEX_UNITS; + + intel->nr_heaps = 1; + intel->texture_heaps[0] = + driCreateTextureHeap( 0, intel, + intel->intelScreen->textureSize, + 12, + I830_NR_TEX_REGIONS, + intel->sarea->texList, + & intel->sarea->texAge, + & intel->swapped, + sizeof( struct i915_texture_object ), + (destroy_texture_object_t *)intelDestroyTexObj ); + + /* FIXME: driCalculateMaxTextureLevels assumes that mipmaps are tightly + * FIXME: packed, but they're not in Intel graphics hardware. + */ + ctx->Const.MaxTextureUnits = 1; + driCalculateMaxTextureLevels( intel->texture_heaps, + intel->nr_heaps, + &intel->ctx.Const, + 4, + 11, /* max 2D texture size is 2048x2048 */ + 8, /* 3D texture */ + 11, /* cube texture. */ + 0, /* max RECT. supported, but not enabled */ + 12, + GL_FALSE ); + ctx->Const.MaxTextureUnits = I915_TEX_UNITS; + + /* GL_ARB_fragment_program limits - don't think Mesa actually + * validates programs against these, and in any case one ARB + * instruction can translate to more than one HW instruction, so + * we'll still have to check and fallback each time. + */ + + ctx->Const.MaxFragmentProgramTemps = I915_MAX_TEMPORARY; + ctx->Const.MaxFragmentProgramAttribs = 11; /* 8 tex, 2 color, fog */ + ctx->Const.MaxFragmentProgramLocalParams = I915_MAX_CONSTANT; + ctx->Const.MaxFragmentProgramEnvParams = I915_MAX_CONSTANT; + ctx->Const.MaxFragmentProgramAluInstructions = I915_MAX_ALU_INSN; + ctx->Const.MaxFragmentProgramTexInstructions = I915_MAX_TEX_INSN; + ctx->Const.MaxFragmentProgramInstructions = (I915_MAX_ALU_INSN + + I915_MAX_TEX_INSN); + ctx->Const.MaxFragmentProgramTexIndirections = I915_MAX_TEX_INDIRECT; + ctx->Const.MaxFragmentProgramAddressRegs = 0; /* I don't think we have one */ + + + driInitExtensions( ctx, card_extensions, GL_FALSE ); + + + _tnl_init_vertices( ctx, ctx->Const.MaxArrayLockSize + 12, + 36 * sizeof(GLfloat) ); + + intel->verts = TNL_CONTEXT(ctx)->clipspace.vertex_buf; + + i915InitState( i915 ); + + return GL_TRUE; +} + diff --git a/src/mesa/drivers/dri/i915/i915_context.h b/src/mesa/drivers/dri/i915/i915_context.h new file mode 100644 index 0000000..05863fa --- /dev/null +++ b/src/mesa/drivers/dri/i915/i915_context.h @@ -0,0 +1,330 @@ + /************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#ifndef I915CONTEXT_INC +#define I915CONTEXT_INC + +#include "intel_context.h" + +#define I915_FALLBACK_TEXTURE 0x1000 +#define I915_FALLBACK_COLORMASK 0x2000 +#define I915_FALLBACK_STENCIL 0x4000 +#define I915_FALLBACK_STIPPLE 0x8000 +#define I915_FALLBACK_PROGRAM 0x10000 +#define I915_FALLBACK_LOGICOP 0x20000 + +#define I915_UPLOAD_CTX 0x1 +#define I915_UPLOAD_BUFFERS 0x2 +#define I915_UPLOAD_STIPPLE 0x4 +#define I915_UPLOAD_PROGRAM 0x8 +#define I915_UPLOAD_CONSTANTS 0x10 +#define I915_UPLOAD_FOG 0x20 +#define I915_UPLOAD_TEX(i) (0x00010000<<(i)) +#define I915_UPLOAD_TEX_ALL (0x00ff0000) +#define I915_UPLOAD_TEX_0_SHIFT 16 + + +/* State structure offsets - these will probably disappear. + */ +#define I915_DESTREG_CBUFADDR0 0 +#define I915_DESTREG_CBUFADDR1 1 +#define I915_DESTREG_CBUFADDR2 2 +#define I915_DESTREG_DBUFADDR0 3 +#define I915_DESTREG_DBUFADDR1 4 +#define I915_DESTREG_DBUFADDR2 5 +#define I915_DESTREG_DV0 6 +#define I915_DESTREG_DV1 7 +#define I915_DESTREG_SENABLE 8 +#define I915_DESTREG_SR0 9 +#define I915_DESTREG_SR1 10 +#define I915_DESTREG_SR2 11 +#define I915_DEST_SETUP_SIZE 12 + +#define I915_CTXREG_STATE4 0 +#define I915_CTXREG_LI 1 +#define I915_CTXREG_LIS2 2 +#define I915_CTXREG_LIS4 3 +#define I915_CTXREG_LIS5 4 +#define I915_CTXREG_LIS6 5 +#define I915_CTXREG_IAB 6 +#define I915_CTXREG_BLENDCOLOR0 7 +#define I915_CTXREG_BLENDCOLOR1 8 +#define I915_CTX_SETUP_SIZE 9 + +#define I915_FOGREG_COLOR 0 +#define I915_FOGREG_MODE0 1 +#define I915_FOGREG_MODE1 2 +#define I915_FOGREG_MODE2 3 +#define I915_FOGREG_MODE3 4 +#define I915_FOG_SETUP_SIZE 5 + +#define I915_STPREG_ST0 0 +#define I915_STPREG_ST1 1 +#define I915_STP_SETUP_SIZE 2 + +#define I915_TEXREG_MS2 0 +#define I915_TEXREG_MS3 1 +#define I915_TEXREG_MS4 2 +#define I915_TEXREG_SS2 3 +#define I915_TEXREG_SS3 4 +#define I915_TEXREG_SS4 5 +#define I915_TEX_SETUP_SIZE 6 + +#define I915_MAX_CONSTANT 32 +#define I915_CONSTANT_SIZE (2+(4*I915_MAX_CONSTANT)) + + +#define I915_PROGRAM_SIZE 192 + + +/* Hardware version of a parsed fragment program. "Derived" from the + * mesa fragment_program struct. + */ +struct i915_fragment_program { + struct fragment_program FragProg; + + GLboolean translated; + GLboolean params_uptodate; + GLboolean on_hardware; + GLboolean error; /* If program is malformed for any reason. */ + + GLuint nr_tex_indirect; + GLuint nr_tex_insn; + GLuint nr_alu_insn; + GLuint nr_decl_insn; + + + + + /* TODO: split between the stored representation of a program and + * the state used to build that representation. + */ + GLcontext *ctx; + + GLuint declarations[I915_PROGRAM_SIZE]; + GLuint program[I915_PROGRAM_SIZE]; + + GLfloat constant[I915_MAX_CONSTANT][4]; + GLuint constant_flags[I915_MAX_CONSTANT]; + GLuint nr_constants; + + GLuint *csr; /* Cursor, points into program. + */ + + GLuint *decl; /* Cursor, points into declarations. + */ + + GLuint decl_s; /* flags for which s regs need to be decl'd */ + GLuint decl_t; /* flags for which t regs need to be decl'd */ + + GLuint temp_flag; /* Tracks temporary regs which are in + * use. + */ + + GLuint utemp_flag; /* Tracks TYPE_U temporary regs which are in + * use. + */ + + + + /* Helpers for i915_fragprog.c: + */ + GLuint wpos_tex; + GLboolean depth_written; + + struct { + GLuint reg; /* Hardware constant idx */ + const GLfloat *values; /* Pointer to tracked values */ + } param[I915_MAX_CONSTANT]; + GLuint nr_params; + + + + + /* Helpers for i915_texprog.c: + */ + GLuint src_texture; /* Reg containing sampled texture color, + * else UREG_BAD. + */ + + GLuint src_previous; /* Reg containing color from previous + * stage. May need to be decl'd. + */ + + GLuint last_tex_stage; /* Number of last enabled texture unit */ + + struct vertex_buffer *VB; +}; + + + + + + +struct i915_texture_object +{ + struct intel_texture_object intel; + GLenum lastTarget; + GLboolean refs_border_color; + GLuint Setup[I915_TEX_SETUP_SIZE]; +}; + +#define I915_TEX_UNITS 8 + + +struct i915_hw_state { + GLuint Ctx[I915_CTX_SETUP_SIZE]; + GLuint Buffer[I915_DEST_SETUP_SIZE]; + GLuint Stipple[I915_STP_SETUP_SIZE]; + GLuint Fog[I915_FOG_SETUP_SIZE]; + GLuint Tex[I915_TEX_UNITS][I915_TEX_SETUP_SIZE]; + GLuint Constant[I915_CONSTANT_SIZE]; + GLuint ConstantSize; + GLuint Program[I915_PROGRAM_SIZE]; + GLuint ProgramSize; + GLuint active; /* I915_UPLOAD_* */ + GLuint emitted; /* I915_UPLOAD_* */ +}; + +#define I915_FOG_PIXEL 2 +#define I915_FOG_VERTEX 1 +#define I915_FOG_NONE 0 + +struct i915_context +{ + struct intel_context intel; + + GLuint last_ReallyEnabled; + GLuint vertex_fog; + + struct i915_fragment_program tex_program; + struct i915_fragment_program *current_program; + + struct i915_hw_state meta, initial, state, *current; +}; + + +typedef struct i915_context *i915ContextPtr; +typedef struct i915_texture_object *i915TextureObjectPtr; + +#define I915_CONTEXT(ctx) ((i915ContextPtr)(ctx)) + + + +#define I915_STATECHANGE(i915, flag) \ +do { \ + if (0) fprintf(stderr, "I915_STATECHANGE %x in %s\n", flag, __FUNCTION__); \ + INTEL_FIREVERTICES( &(i915)->intel ); \ + (i915)->state.emitted &= ~(flag); \ +} while (0) + +#define I915_ACTIVESTATE(i915, flag, mode) \ +do { \ + if (0) fprintf(stderr, "I915_ACTIVESTATE %x %d in %s\n", \ + flag, mode, __FUNCTION__); \ + INTEL_FIREVERTICES( &(i915)->intel ); \ + if (mode) \ + (i915)->state.active |= (flag); \ + else \ + (i915)->state.active &= ~(flag); \ +} while (0) + + +/*====================================================================== + * i915_vtbl.c + */ +extern void i915InitVtbl( i915ContextPtr i915 ); + + + +#define SZ_TO_HW(sz) ((sz-2)&0x3) +#define EMIT_SZ(sz) (EMIT_1F + (sz) - 1) +#define EMIT_ATTR( ATTR, STYLE, S4, SZ ) \ +do { \ + intel->vertex_attrs[intel->vertex_attr_count].attrib = (ATTR); \ + intel->vertex_attrs[intel->vertex_attr_count].format = (STYLE); \ + s4 |= S4; \ + intel->vertex_attr_count++; \ + offset += (SZ); \ +} while (0) + +#define EMIT_PAD( N ) \ +do { \ + intel->vertex_attrs[intel->vertex_attr_count].attrib = 0; \ + intel->vertex_attrs[intel->vertex_attr_count].format = EMIT_PAD; \ + intel->vertex_attrs[intel->vertex_attr_count].offset = (N); \ + intel->vertex_attr_count++; \ + offset += (N); \ +} while (0) + + + +/*====================================================================== + * i915_context.c + */ +extern GLboolean i915CreateContext( const __GLcontextModes *mesaVis, + __DRIcontextPrivate *driContextPriv, + void *sharedContextPrivate); + + +/*====================================================================== + * i915_texprog.c + */ +extern void i915ValidateTextureProgram( i915ContextPtr i915 ); + + +/*====================================================================== + * i915_debug.c + */ +extern void i915_disassemble_program( const GLuint *program, GLuint sz ); +extern void i915_print_ureg( const char *msg, GLuint ureg ); + + +/*====================================================================== + * i915_state.c + */ +extern void i915InitStateFunctions( struct dd_function_table *functions ); +extern void i915InitState( i915ContextPtr i915 ); + + +/*====================================================================== + * i915_tex.c + */ +extern void i915UpdateTextureState( intelContextPtr intel ); +extern void i915InitTextureFuncs( struct dd_function_table *functions ); +extern intelTextureObjectPtr i915AllocTexObj( struct gl_texture_object *texObj ); + +/*====================================================================== + * i915_metaops.c + */ +extern GLboolean +i915TryTextureReadPixels( GLcontext *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + GLvoid *pixels ); + +extern GLboolean +i915TryTextureDrawPixels( GLcontext *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels ); + +extern void +i915ClearWithTris( intelContextPtr intel, GLbitfield mask, + GLboolean all, GLint cx, GLint cy, GLint cw, GLint ch); + + +/*====================================================================== + * i915_fragprog.c + */ +extern void i915ValidateFragmentProgram( i915ContextPtr i915 ); +extern void i915InitFragProgFuncs( struct dd_function_table *functions ); + +#endif + diff --git a/src/mesa/drivers/dri/i915/i915_debug.c b/src/mesa/drivers/dri/i915/i915_debug.c new file mode 100644 index 0000000..c67e0d4 --- /dev/null +++ b/src/mesa/drivers/dri/i915/i915_debug.c @@ -0,0 +1,272 @@ +#include "i915_reg.h" +#include "i915_context.h" +#include + + +static const char *opcodes[0x20] = { + "NOP", + "ADD", + "MOV", + "MUL", + "MAD", + "DP2ADD", + "DP3", + "DP4", + "FRC", + "RCP", + "RSQ", + "EXP", + "LOG", + "CMP", + "MIN", + "MAX", + "FLR", + "MOD", + "TRC", + "SGE", + "SLT", + "TEXLD", + "TEXLDP", + "TEXLDB", + "TEXKILL", + "DCL", + "0x1a", + "0x1b", + "0x1c", + "0x1d", + "0x1e", + "0x1f", +}; + + +static const int args[0x20] = { + 0, /* 0 nop */ + 2, /* 1 add */ + 1, /* 2 mov */ + 2, /* 3 m ul */ + 3, /* 4 mad */ + 3, /* 5 dp2add */ + 2, /* 6 dp3 */ + 2, /* 7 dp4 */ + 1, /* 8 frc */ + 1, /* 9 rcp */ + 1, /* a rsq */ + 1, /* b exp */ + 1, /* c log */ + 3, /* d cmp */ + 2, /* e min */ + 2, /* f max */ + 1, /* 10 flr */ + 1, /* 11 mod */ + 1, /* 12 trc */ + 2, /* 13 sge */ + 2, /* 14 slt */ + 1, + 1, + 1, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +}; + + +static const char *regname[0x8] = { + "R", + "T", + "CONST", + "S", + "OC", + "OD", + "U", + "UNKNOWN", +}; + +static void print_reg_type_nr( GLuint type, GLuint nr ) +{ + switch (type) { + case REG_TYPE_T: + switch (nr) { + case T_DIFFUSE: fprintf(stderr, "T_DIFFUSE"); return; + case T_SPECULAR: fprintf(stderr, "T_SPECULAR"); return; + case T_FOG_W: fprintf(stderr, "T_FOG_W"); return; + default: fprintf(stderr, "T_TEX%d", nr); return; + } + case REG_TYPE_OC: + if (nr == 0) { + fprintf(stderr, "oC"); + return; + } + break; + case REG_TYPE_OD: + if (nr == 0) { + fprintf(stderr, "oD"); + return; + } + break; + default: + break; + } + + fprintf(stderr, "%s[%d]", regname[type], nr); +} + +#define REG_SWIZZLE_MASK 0x7777 +#define REG_NEGATE_MASK 0x8888 + +#define REG_SWIZZLE_XYZW ((SRC_X << A2_SRC2_CHANNEL_X_SHIFT) | \ + (SRC_Y << A2_SRC2_CHANNEL_Y_SHIFT) | \ + (SRC_Z << A2_SRC2_CHANNEL_Z_SHIFT) | \ + (SRC_W << A2_SRC2_CHANNEL_W_SHIFT)) + + +static void print_reg_neg_swizzle( GLuint reg ) +{ + int i; + + if ((reg & REG_SWIZZLE_MASK) == REG_SWIZZLE_XYZW && + (reg & REG_NEGATE_MASK) == 0) + return; + + fprintf(stderr, "."); + + for (i = 3 ; i >= 0; i--) { + if (reg & (1<<((i*4)+3))) + fprintf(stderr, "-"); + + switch ((reg>>(i*4)) & 0x7) { + case 0: fprintf(stderr, "x"); break; + case 1: fprintf(stderr, "y"); break; + case 2: fprintf(stderr, "z"); break; + case 3: fprintf(stderr, "w"); break; + case 4: fprintf(stderr, "0"); break; + case 5: fprintf(stderr, "1"); break; + default: fprintf(stderr, "?"); break; + } + } +} + + +static void print_src_reg( GLuint dword ) +{ + GLuint nr = (dword >> A2_SRC2_NR_SHIFT) & REG_NR_MASK; + GLuint type = (dword >> A2_SRC2_TYPE_SHIFT) & REG_TYPE_MASK; + print_reg_type_nr( type, nr ); + print_reg_neg_swizzle( dword ); +} + +void i915_print_ureg( const char *msg, GLuint ureg ) +{ + fprintf(stderr, "%s: ", msg); + print_src_reg( ureg >> 8 ); + fprintf(stderr, "\n"); +} + +static void print_dest_reg( GLuint dword ) +{ + GLuint nr = (dword >> A0_DEST_NR_SHIFT) & REG_NR_MASK; + GLuint type = (dword >> A0_DEST_TYPE_SHIFT) & REG_TYPE_MASK; + print_reg_type_nr( type, nr ); + if ((dword & A0_DEST_CHANNEL_ALL) == A0_DEST_CHANNEL_ALL) + return; + fprintf(stderr, "."); + if (dword & A0_DEST_CHANNEL_X) fprintf(stderr, "x"); + if (dword & A0_DEST_CHANNEL_Y) fprintf(stderr, "y"); + if (dword & A0_DEST_CHANNEL_Z) fprintf(stderr, "z"); + if (dword & A0_DEST_CHANNEL_W) fprintf(stderr, "w"); +} + + +#define GET_SRC0_REG(r0, r1) ((r0<<14)|(r1>>A1_SRC0_CHANNEL_W_SHIFT)) +#define GET_SRC1_REG(r0, r1) ((r0<<8)|(r1>>A2_SRC1_CHANNEL_W_SHIFT)) +#define GET_SRC2_REG(r) (r) + + +static void print_arith_op( GLuint opcode, const GLuint *program ) +{ + if (opcode != A0_NOP) { + print_dest_reg(program[0]); + if (program[0] & A0_DEST_SATURATE) + fprintf(stderr, " = SATURATE "); + else + fprintf(stderr, " = "); + } + + fprintf(stderr, "%s ", opcodes[opcode]); + + print_src_reg(GET_SRC0_REG(program[0], program[1])); + if (args[opcode] == 1) { + fprintf(stderr, "\n"); + return; + } + + fprintf(stderr, ", "); + print_src_reg(GET_SRC1_REG(program[1], program[2])); + if (args[opcode] == 2) { + fprintf(stderr, "\n"); + return; + } + + fprintf(stderr, ", "); + print_src_reg(GET_SRC2_REG(program[2])); + fprintf(stderr, "\n"); + return; +} + + +static void print_tex_op( GLuint opcode, const GLuint *program ) +{ + print_dest_reg(program[0] | A0_DEST_CHANNEL_ALL); + fprintf(stderr, " = "); + + fprintf(stderr, "%s ", opcodes[opcode]); + + fprintf(stderr, "S[%d],", + program[0] & T0_SAMPLER_NR_MASK); + + print_reg_type_nr( (program[1]>>T1_ADDRESS_REG_TYPE_SHIFT) & REG_TYPE_MASK, + (program[1]>>T1_ADDRESS_REG_NR_SHIFT) & REG_NR_MASK ); + fprintf(stderr, "\n"); +} + +static void print_dcl_op( GLuint opcode, const GLuint *program ) +{ + fprintf(stderr, "%s ", opcodes[opcode]); + print_dest_reg(program[0] | A0_DEST_CHANNEL_ALL); + fprintf(stderr, "\n"); +} + + +void i915_disassemble_program( const GLuint *program, GLuint sz ) +{ + GLuint size = program[0] & 0x1ff; + GLint i; + + fprintf(stderr, "BEGIN\n"); + + if (size+2 != sz) { + fprintf(stderr, "%s: program size mismatch %d/%d\n", __FUNCTION__, + size+2, sz); + exit(1); + } + + program ++; + for (i = 1 ; i < sz ; i+=3, program+=3) { + GLuint opcode = program[0] & (0x1f<<24); + + if (opcode >= A0_NOP && opcode <= A0_SLT) + print_arith_op(opcode >> 24, program); + else if (opcode >= T0_TEXLD && opcode <= T0_TEXKILL) + print_tex_op(opcode >> 24, program); + else if (opcode == D0_DCL) + print_dcl_op(opcode >> 24, program); + else + fprintf(stderr, "Unknown opcode 0x%x\n", opcode); + } + + fprintf(stderr, "END\n\n"); +} diff --git a/src/mesa/drivers/dri/i915/i915_fragprog.c b/src/mesa/drivers/dri/i915/i915_fragprog.c new file mode 100644 index 0000000..f9c80cb --- /dev/null +++ b/src/mesa/drivers/dri/i915/i915_fragprog.c @@ -0,0 +1,1033 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "glheader.h" +#include "macros.h" +#include "enums.h" + +#include "tnl/t_context.h" +#include "intel_batchbuffer.h" + +#include "i915_reg.h" +#include "i915_context.h" +#include "i915_program.h" + +#include "nvfragprog.h" +#include "program.h" +#include "arbfragparse.h" + + + + +#define PI 3.141592 + + +/* 1, -1/3!, 1/5!, -1/7! */ +static const GLfloat sin_constants[4] = { 1.0, + -1.0/(3*2*1), + 1.0/(5*4*3*2*1), + -1.0/(7*6*5*4*3*2*1) }; + +/* 1, -1/2!, 1/4!, -1/6! */ +static const GLfloat cos_constants[4] = { 1.0, + -1.0/(2*1), + 1.0/(4*3*2*1), + -1.0/(6*5*4*3*2*1) }; + +/** + * Retrieve a ureg for the given source register. Will emit + * constants, apply swizzling and negation as needed. + */ +static GLuint src_vector( struct i915_fragment_program *p, + const struct fp_src_register *source, + const struct fragment_program *program ) +{ + GLuint src; + + switch (source->File) { + + /* Registers: + */ + case PROGRAM_TEMPORARY: + if (source->Index >= I915_MAX_TEMPORARY) { + i915_program_error( p, "Exceeded max temporary reg" ); + return 0; + } + src = UREG( REG_TYPE_R, source->Index ); + break; + case PROGRAM_INPUT: + switch (source->Index) { + case FRAG_ATTRIB_WPOS: + src = i915_emit_decl( p, REG_TYPE_T, p->wpos_tex, D0_CHANNEL_ALL ); + break; + case FRAG_ATTRIB_COL0: + src = i915_emit_decl( p, REG_TYPE_T, T_DIFFUSE, D0_CHANNEL_ALL ); + break; + case FRAG_ATTRIB_COL1: + src = i915_emit_decl( p, REG_TYPE_T, T_SPECULAR, D0_CHANNEL_XYZ ); + src = swizzle( src, X, Y, Z, ONE ); + break; + case FRAG_ATTRIB_FOGC: + src = i915_emit_decl( p, REG_TYPE_T, T_FOG_W, D0_CHANNEL_W ); + src = swizzle( src, W, W, W, W ); + break; + case FRAG_ATTRIB_TEX0: + case FRAG_ATTRIB_TEX1: + case FRAG_ATTRIB_TEX2: + case FRAG_ATTRIB_TEX3: + case FRAG_ATTRIB_TEX4: + case FRAG_ATTRIB_TEX5: + case FRAG_ATTRIB_TEX6: + case FRAG_ATTRIB_TEX7: + src = i915_emit_decl( p, REG_TYPE_T, + T_TEX0 + (source->Index - FRAG_ATTRIB_TEX0), + D0_CHANNEL_ALL ); + break; + + default: + i915_program_error( p, "Bad source->Index" ); + return 0; + } + break; + + /* Various paramters and env values. All emitted to + * hardware as program constants. + */ + case PROGRAM_LOCAL_PARAM: + src = i915_emit_param4fv( + p, program->Base.LocalParams[source->Index]); + break; + + case PROGRAM_ENV_PARAM: + src = i915_emit_param4fv( + p, p->ctx->FragmentProgram.Parameters[source->Index]); + break; + + case PROGRAM_STATE_VAR: + case PROGRAM_NAMED_PARAM: + src = i915_emit_param4fv( + p, program->Parameters->Parameters[source->Index].Values ); + break; + + default: + i915_program_error( p, "Bad source->File" ); + return 0; + } + + src = swizzle(src, + source->Swizzle[0], + source->Swizzle[1], + source->Swizzle[2], + source->Swizzle[3]); + + if (source->NegateBase) + src = negate( src, 1,1,1,1 ); + + return src; +} + + +static GLuint get_result_vector( struct i915_fragment_program *p, + const struct fp_instruction *inst ) +{ + switch (inst->DstReg.File) { + case PROGRAM_OUTPUT: + switch (inst->DstReg.Index) { + case 0: + return UREG(REG_TYPE_OC, 0); + case 1: + p->depth_written = 1; + return UREG(REG_TYPE_OD, 0); + default: + i915_program_error( p, "Bad inst->DstReg.Index" ); + return 0; + } + case PROGRAM_TEMPORARY: + return UREG(REG_TYPE_R, inst->DstReg.Index); + default: + i915_program_error( p, "Bad inst->DstReg.File" ); + return 0; + } +} + +static GLuint get_result_flags( const struct fp_instruction *inst ) +{ + GLuint flags = 0; + + if (inst->Saturate) flags |= A0_DEST_SATURATE; + if (inst->DstReg.WriteMask[0]) flags |= A0_DEST_CHANNEL_X; + if (inst->DstReg.WriteMask[1]) flags |= A0_DEST_CHANNEL_Y; + if (inst->DstReg.WriteMask[2]) flags |= A0_DEST_CHANNEL_Z; + if (inst->DstReg.WriteMask[3]) flags |= A0_DEST_CHANNEL_W; + + return flags; +} + +static GLuint translate_tex_src_bit( struct i915_fragment_program *p, + GLubyte bit ) +{ + switch (bit) { + case TEXTURE_1D_BIT: return D0_SAMPLE_TYPE_2D; + case TEXTURE_2D_BIT: return D0_SAMPLE_TYPE_2D; + case TEXTURE_RECT_BIT: return D0_SAMPLE_TYPE_2D; + case TEXTURE_3D_BIT: return D0_SAMPLE_TYPE_VOLUME; + case TEXTURE_CUBE_BIT: return D0_SAMPLE_TYPE_CUBE; + default: i915_program_error(p, "TexSrcBit"); return 0; + } +} + +#define EMIT_TEX( OP ) \ +do { \ + GLuint dim = translate_tex_src_bit( p, inst->TexSrcBit ); \ + GLuint sampler = i915_emit_decl(p, REG_TYPE_S, \ + inst->TexSrcUnit, dim); \ + GLuint coord = src_vector( p, &inst->SrcReg[0], program); \ + /* Texel lookup */ \ + \ + i915_emit_texld( p, \ + get_result_vector( p, inst ), \ + get_result_flags( inst ), \ + sampler, \ + coord, \ + OP); \ +} while (0) + +#define EMIT_ARITH( OP, N ) \ +do { \ + i915_emit_arith( p, \ + OP, \ + get_result_vector( p, inst ), \ + get_result_flags( inst ), 0, \ + (N<1)?0:src_vector( p, &inst->SrcReg[0], program), \ + (N<2)?0:src_vector( p, &inst->SrcReg[1], program), \ + (N<3)?0:src_vector( p, &inst->SrcReg[2], program)); \ +} while (0) + +#define EMIT_1ARG_ARITH( OP ) EMIT_ARITH( OP, 1 ) +#define EMIT_2ARG_ARITH( OP ) EMIT_ARITH( OP, 2 ) +#define EMIT_3ARG_ARITH( OP ) EMIT_ARITH( OP, 3 ) + + +/* Possible concerns: + * + * SIN, COS -- could use another taylor step? + * LIT -- results seem a little different to sw mesa + * LOG -- different to mesa on negative numbers, but this is conformant. + * + * Parse failures -- Mesa doesn't currently give a good indication + * internally whether a particular program string parsed or not. This + * can lead to confusion -- hopefully we cope with it ok now. + * + */ +static void upload_program( struct i915_fragment_program *p ) +{ + const struct fragment_program *program = p->ctx->FragmentProgram.Current; + const struct fp_instruction *inst = program->Instructions; + +/* _mesa_debug_fp_inst(program->Base.NumInstructions, inst); */ + + /* Is this a parse-failed program? Ensure a valid program is + * loaded, as the flagging of an error isn't sufficient to stop + * this being uploaded to hardware. + */ + if (inst[0].Opcode == FP_OPCODE_END) { + GLuint tmp = i915_get_utemp( p ); + i915_emit_arith( p, + A0_MOV, + UREG(REG_TYPE_OC, 0), + A0_DEST_CHANNEL_ALL, 0, + swizzle(tmp,ONE,ZERO,ONE,ONE), 0, 0); + return; + } + + while (1) { + GLuint src0, src1, src2, flags; + GLuint tmp = 0; + + switch (inst->Opcode) { + case FP_OPCODE_ABS: + src0 = src_vector( p, &inst->SrcReg[0], program); + i915_emit_arith( p, + A0_MAX, + get_result_vector( p, inst ), + get_result_flags( inst ), 0, + src0, negate(src0, 1,1,1,1), 0); + break; + + case FP_OPCODE_ADD: + EMIT_2ARG_ARITH( A0_ADD ); + break; + + case FP_OPCODE_CMP: + src0 = src_vector( p, &inst->SrcReg[0], program); + src1 = src_vector( p, &inst->SrcReg[1], program); + src2 = src_vector( p, &inst->SrcReg[2], program); + i915_emit_arith( p, + A0_CMP, + get_result_vector( p, inst ), + get_result_flags( inst ), 0, + src0, src2, src1); /* NOTE: order of src2, src1 */ + break; + + case FP_OPCODE_COS: + src0 = src_vector( p, &inst->SrcReg[0], program); + tmp = i915_get_utemp( p ); + + i915_emit_arith( p, + A0_MUL, + tmp, A0_DEST_CHANNEL_X, 0, + src0, + i915_emit_const1f(p, 1.0/(PI * 2)), + 0); + + i915_emit_arith( p, + A0_MOD, + tmp, A0_DEST_CHANNEL_X, 0, + tmp, + 0, 0 ); + + /* By choosing different taylor constants, could get rid of this mul: + */ + i915_emit_arith( p, + A0_MUL, + tmp, A0_DEST_CHANNEL_X, 0, + tmp, + i915_emit_const1f(p, (PI * 2)), + 0); + + /* + * t0.xy = MUL x.xx11, x.x1111 ; x^2, x, 1, 1 + * t0 = MUL t0.xyxy t0.xx11 ; x^4, x^3, x^2, 1 + * t0 = MUL t0.xxz1 t0.z111 ; x^6 x^4 x^2 1 + * result = DP4 t0, cos_constants + */ + i915_emit_arith( p, + A0_MUL, + tmp, A0_DEST_CHANNEL_XY, 0, + swizzle(tmp, X,X,ONE,ONE), + swizzle(tmp, X,ONE,ONE,ONE), 0); + + i915_emit_arith( p, + A0_MUL, + tmp, A0_DEST_CHANNEL_XYZ, 0, + swizzle(tmp, X,Y,X,ONE), + swizzle(tmp, X,X,ONE,ONE), 0); + + i915_emit_arith( p, + A0_MUL, + tmp, A0_DEST_CHANNEL_XYZ, 0, + swizzle(tmp, X,X,Z,ONE), + swizzle(tmp, Z,ONE,ONE,ONE), 0); + + i915_emit_arith( p, + A0_DP4, + get_result_vector( p, inst ), + get_result_flags( inst ), 0, + swizzle(tmp, ONE,Z,Y,X), + i915_emit_const4fv( p, cos_constants ), 0); + + break; + + case FP_OPCODE_DP3: + EMIT_2ARG_ARITH( A0_DP3 ); + break; + + case FP_OPCODE_DP4: + EMIT_2ARG_ARITH( A0_DP4 ); + break; + + case FP_OPCODE_DPH: + src0 = src_vector( p, &inst->SrcReg[0], program); + src1 = src_vector( p, &inst->SrcReg[1], program); + + i915_emit_arith( p, + A0_DP4, + get_result_vector( p, inst ), + get_result_flags( inst ), 0, + swizzle(src0, X,Y,Z,ONE), src1, 0); + break; + + case FP_OPCODE_DST: + src0 = src_vector( p, &inst->SrcReg[0], program); + src1 = src_vector( p, &inst->SrcReg[1], program); + + /* result[0] = 1 * 1; + * result[1] = a[1] * b[1]; + * result[2] = a[2] * 1; + * result[3] = 1 * b[3]; + */ + i915_emit_arith( p, + A0_MUL, + get_result_vector( p, inst ), + get_result_flags( inst ), 0, + swizzle(src0, ONE, Y, Z, ONE), + swizzle(src1, ONE, Y, ONE, W ), + 0); + break; + + case FP_OPCODE_EX2: + src0 = src_vector( p, &inst->SrcReg[0], program); + + i915_emit_arith( p, + A0_EXP, + get_result_vector( p, inst ), + get_result_flags( inst ), 0, + swizzle(src0,X,X,X,X), 0, 0); + break; + + case FP_OPCODE_FLR: + EMIT_1ARG_ARITH( A0_FLR ); + break; + + case FP_OPCODE_FRC: + EMIT_1ARG_ARITH( A0_FRC ); + break; + + case FP_OPCODE_KIL: + src0 = src_vector( p, &inst->SrcReg[0], program); + tmp = i915_get_utemp( p ); + + i915_emit_texld( p, + tmp, A0_DEST_CHANNEL_ALL, /* use a dummy dest reg */ + 0, + src0, + T0_TEXKILL ); + break; + + case FP_OPCODE_LG2: + src0 = src_vector( p, &inst->SrcReg[0], program); + + i915_emit_arith( p, + A0_LOG, + get_result_vector( p, inst ), + get_result_flags( inst ), 0, + swizzle(src0,X,X,X,X), 0, 0); + break; + + case FP_OPCODE_LIT: + src0 = src_vector( p, &inst->SrcReg[0], program); + tmp = i915_get_utemp( p ); + + /* tmp = max( a.xyzw, a.00zw ) + * XXX: Clamp tmp.w to -128..128 + * tmp.y = log(tmp.y) + * tmp.y = tmp.w * tmp.y + * tmp.y = exp(tmp.y) + * result = cmp (a.11-x1, a.1x01, a.1xy1 ) + */ + i915_emit_arith( p, A0_MAX, tmp, A0_DEST_CHANNEL_ALL, 0, + src0, swizzle(src0, ZERO, ZERO, Z, W), 0 ); + + i915_emit_arith( p, A0_LOG, tmp, A0_DEST_CHANNEL_Y, 0, + swizzle(tmp, Y, Y, Y, Y), 0, 0 ); + + i915_emit_arith( p, A0_MUL, tmp, A0_DEST_CHANNEL_Y, 0, + swizzle(tmp, ZERO, Y, ZERO, ZERO), + swizzle(tmp, ZERO, W, ZERO, ZERO), 0 ); + + i915_emit_arith( p, A0_EXP, tmp, A0_DEST_CHANNEL_Y, 0, + swizzle(tmp, Y, Y, Y, Y), 0, 0 ); + + i915_emit_arith( p, A0_CMP, + get_result_vector( p, inst ), + get_result_flags( inst ), 0, + negate(swizzle(tmp, ONE, ONE, X, ONE),0,0,1,0), + swizzle(tmp, ONE, X, ZERO, ONE), + swizzle(tmp, ONE, X, Y, ONE)); + + break; + + case FP_OPCODE_LRP: + src0 = src_vector( p, &inst->SrcReg[0], program); + src1 = src_vector( p, &inst->SrcReg[1], program); + src2 = src_vector( p, &inst->SrcReg[2], program); + flags = get_result_flags( inst ); + tmp = i915_get_utemp( p ); + + /* b*a + c*(1-a) + * + * b*a + c - ca + * + * tmp = b*a + c, + * result = (-c)*a + tmp + */ + i915_emit_arith( p, A0_MAD, tmp, + flags & A0_DEST_CHANNEL_ALL, 0, + src1, src0, src2 ); + + i915_emit_arith( p, A0_MAD, + get_result_vector( p, inst ), + flags, 0, + negate(src2, 1,1,1,1), src0, tmp ); + break; + + case FP_OPCODE_MAD: + EMIT_3ARG_ARITH( A0_MAD ); + break; + + case FP_OPCODE_MAX: + EMIT_2ARG_ARITH( A0_MAX ); + break; + + case FP_OPCODE_MIN: + src0 = src_vector( p, &inst->SrcReg[0], program); + src1 = src_vector( p, &inst->SrcReg[1], program); + tmp = i915_get_utemp( p ); + flags = get_result_flags( inst ); + + i915_emit_arith( p, + A0_MAX, + tmp, flags & A0_DEST_CHANNEL_ALL, 0, + negate(src0,1,1,1,1), + negate(src1,1,1,1,1), 0); + + i915_emit_arith( p, + A0_MOV, + get_result_vector( p, inst ), + flags, 0, + negate(tmp, 1,1,1,1), 0, 0); + break; + + case FP_OPCODE_MOV: + EMIT_1ARG_ARITH( A0_MOV ); + break; + + case FP_OPCODE_MUL: + EMIT_2ARG_ARITH( A0_MUL ); + break; + + case FP_OPCODE_POW: + src0 = src_vector( p, &inst->SrcReg[0], program); + src1 = src_vector( p, &inst->SrcReg[1], program); + tmp = i915_get_utemp( p ); + flags = get_result_flags( inst ); + + /* XXX: masking on intermediate values, here and elsewhere. + */ + i915_emit_arith( p, + A0_LOG, + tmp, A0_DEST_CHANNEL_X, 0, + swizzle(src0,X,X,X,X), 0, 0); + + i915_emit_arith( p, + A0_MUL, + tmp, A0_DEST_CHANNEL_X, 0, + tmp, src1, 0); + + + i915_emit_arith( p, + A0_EXP, + get_result_vector( p, inst ), + flags, 0, + swizzle(tmp,X,X,X,X), 0, 0); + + break; + + case FP_OPCODE_RCP: + src0 = src_vector( p, &inst->SrcReg[0], program); + + i915_emit_arith( p, + A0_RCP, + get_result_vector( p, inst ), + get_result_flags( inst ), 0, + swizzle(src0,X,X,X,X), 0, 0); + break; + + case FP_OPCODE_RSQ: + + src0 = src_vector( p, &inst->SrcReg[0], program); + + i915_emit_arith( p, + A0_RSQ, + get_result_vector( p, inst ), + get_result_flags( inst ), 0, + swizzle(src0,X,X,X,X), 0, 0); + break; + + case FP_OPCODE_SCS: + src0 = src_vector( p, &inst->SrcReg[0], program); + tmp = i915_get_utemp( p ); + + /* + * t0.xy = MUL x.xx11, x.x1111 ; x^2, x, 1, 1 + * t0 = MUL t0.xyxy t0.xx11 ; x^4, x^3, x^2, x + * t1 = MUL t0.xyyw t0.yz11 ; x^7 x^5 x^3 x + * scs.x = DP4 t1, sin_constants + * t1 = MUL t0.xxz1 t0.z111 ; x^6 x^4 x^2 1 + * scs.y = DP4 t1, cos_constants + */ + i915_emit_arith( p, + A0_MUL, + tmp, A0_DEST_CHANNEL_XY, 0, + swizzle(src0, X,X,ONE,ONE), + swizzle(src0, X,ONE,ONE,ONE), 0); + + i915_emit_arith( p, + A0_MUL, + tmp, A0_DEST_CHANNEL_ALL, 0, + swizzle(tmp, X,Y,X,Y), + swizzle(tmp, X,X,ONE,ONE), 0); + + if (inst->DstReg.WriteMask[1]) { + GLuint tmp1; + + if (inst->DstReg.WriteMask[0]) + tmp1 = i915_get_utemp( p ); + else + tmp1 = tmp; + + i915_emit_arith( p, + A0_MUL, + tmp1, A0_DEST_CHANNEL_ALL, 0, + swizzle(tmp, X,Y,Y,W), + swizzle(tmp, X,Z,ONE,ONE), 0); + + i915_emit_arith( p, + A0_DP4, + get_result_vector( p, inst ), + A0_DEST_CHANNEL_Y, 0, + swizzle(tmp1, W,Z,Y,X), + i915_emit_const4fv( p, sin_constants ), 0); + } + + if (inst->DstReg.WriteMask[0]) { + i915_emit_arith( p, + A0_MUL, + tmp, A0_DEST_CHANNEL_XYZ, 0, + swizzle(tmp, X,X,Z,ONE), + swizzle(tmp, Z,ONE,ONE,ONE), 0); + + i915_emit_arith( p, + A0_DP4, + get_result_vector( p, inst ), + A0_DEST_CHANNEL_X, 0, + swizzle(tmp, ONE,Z,Y,X), + i915_emit_const4fv( p, cos_constants ), 0); + } + break; + + case FP_OPCODE_SGE: + EMIT_2ARG_ARITH( A0_SGE ); + break; + + case FP_OPCODE_SIN: + src0 = src_vector( p, &inst->SrcReg[0], program); + tmp = i915_get_utemp( p ); + + i915_emit_arith( p, + A0_MUL, + tmp, A0_DEST_CHANNEL_X, 0, + src0, + i915_emit_const1f(p, 1.0/(PI * 2)), + 0); + + i915_emit_arith( p, + A0_MOD, + tmp, A0_DEST_CHANNEL_X, 0, + tmp, + 0, 0 ); + + /* By choosing different taylor constants, could get rid of this mul: + */ + i915_emit_arith( p, + A0_MUL, + tmp, A0_DEST_CHANNEL_X, 0, + tmp, + i915_emit_const1f(p, (PI * 2)), + 0); + + /* + * t0.xy = MUL x.xx11, x.x1111 ; x^2, x, 1, 1 + * t0 = MUL t0.xyxy t0.xx11 ; x^4, x^3, x^2, x + * t1 = MUL t0.xyyw t0.yz11 ; x^7 x^5 x^3 x + * result = DP4 t1.wzyx, sin_constants + */ + i915_emit_arith( p, + A0_MUL, + tmp, A0_DEST_CHANNEL_XY, 0, + swizzle(tmp, X,X,ONE,ONE), + swizzle(tmp, X,ONE,ONE,ONE), 0); + + i915_emit_arith( p, + A0_MUL, + tmp, A0_DEST_CHANNEL_ALL, 0, + swizzle(tmp, X,Y,X,Y), + swizzle(tmp, X,X,ONE,ONE), 0); + + i915_emit_arith( p, + A0_MUL, + tmp, A0_DEST_CHANNEL_ALL, 0, + swizzle(tmp, X,Y,Y,W), + swizzle(tmp, X,Z,ONE,ONE), 0); + + i915_emit_arith( p, + A0_DP4, + get_result_vector( p, inst ), + get_result_flags( inst ), 0, + swizzle(tmp, W, Z, Y, X ), + i915_emit_const4fv( p, sin_constants ), 0); + break; + + case FP_OPCODE_SLT: + EMIT_2ARG_ARITH( A0_SLT ); + break; + + case FP_OPCODE_SUB: + src0 = src_vector( p, &inst->SrcReg[0], program); + src1 = src_vector( p, &inst->SrcReg[1], program); + + i915_emit_arith( p, + A0_ADD, + get_result_vector( p, inst ), + get_result_flags( inst ), 0, + src0, negate(src1, 1,1,1,1), 0); + break; + + case FP_OPCODE_SWZ: + EMIT_1ARG_ARITH( A0_MOV ); /* extended swizzle handled natively */ + break; + + case FP_OPCODE_TEX: + EMIT_TEX( T0_TEXLD ); + break; + + case FP_OPCODE_TXB: + EMIT_TEX( T0_TEXLDB ); + break; + + case FP_OPCODE_TXP: + EMIT_TEX( T0_TEXLDP ); + break; + + case FP_OPCODE_XPD: + /* Cross product: + * result.x = src0.y * src1.z - src0.z * src1.y; + * result.y = src0.z * src1.x - src0.x * src1.z; + * result.z = src0.x * src1.y - src0.y * src1.x; + * result.w = undef; + */ + src0 = src_vector( p, &inst->SrcReg[0], program); + src1 = src_vector( p, &inst->SrcReg[1], program); + tmp = i915_get_utemp( p ); + + i915_emit_arith( p, + A0_MUL, + tmp, A0_DEST_CHANNEL_ALL, 0, + swizzle(src0,Z,X,Y,ONE), + swizzle(src1,Y,Z,X,ONE), 0); + + i915_emit_arith( p, + A0_MAD, + get_result_vector( p, inst ), + get_result_flags( inst ), 0, + swizzle(src0,Y,Z,X,ONE), + swizzle(src1,Z,X,Y,ONE), + negate(tmp,1,1,1,0)); + break; + + case FP_OPCODE_END: + return; + + default: + i915_program_error( p, "bad opcode" ); + return; + } + + inst++; + i915_release_utemps( p ); + } +} + +/* Rather than trying to intercept and jiggle depth writes during + * emit, just move the value into its correct position at the end of + * the program: + */ +static void fixup_depth_write( struct i915_fragment_program *p ) +{ + if (p->depth_written) { + GLuint depth = UREG(REG_TYPE_OD, 0); + + i915_emit_arith( p, + A0_MOV, + depth, A0_DEST_CHANNEL_W, 0, + swizzle(depth,X,Y,Z,Z), + 0, 0); + } +} + + +#define FRAG_BIT_TEX(n) (FRAG_BIT_TEX0 << (n)) + + +static void check_wpos( struct i915_fragment_program *p ) +{ + GLuint inputs = p->FragProg.InputsRead; + GLint i; + + p->wpos_tex = 0; + + for (i = 0; i < p->ctx->Const.MaxTextureCoordUnits; i++) { + if (inputs & FRAG_BIT_TEX(i)) + continue; + else if (inputs & FRAG_BIT_WPOS) { + p->wpos_tex = i; + inputs &= ~FRAG_BIT_WPOS; + } + } + + if (inputs & FRAG_BIT_WPOS) { + i915_program_error(p, "No free texcoord for wpos value"); + } +} + + +static void translate_program( struct i915_fragment_program *p ) +{ + i915ContextPtr i915 = I915_CONTEXT(p->ctx); + + i915_init_program( i915, p ); + check_wpos( p ); + upload_program( p ); + fixup_depth_write( p ); + i915_fini_program( p ); + + p->translated = 1; +} + + +static void track_params( struct i915_fragment_program *p ) +{ + GLint i; + + if (p->nr_params) + _mesa_load_state_parameters(p->ctx, p->FragProg.Parameters); + + for (i = 0; i < p->nr_params; i++) { + GLint reg = p->param[i].reg; + COPY_4V( p->constant[reg], p->param[i].values ); + } + + p->params_uptodate = 1; + p->on_hardware = 0; /* overkill */ +} + + +static void i915BindProgram( GLcontext *ctx, + GLenum target, + struct program *prog ) +{ + if (target == GL_FRAGMENT_PROGRAM_ARB) { + i915ContextPtr i915 = I915_CONTEXT(ctx); + struct i915_fragment_program *p = (struct i915_fragment_program *)prog; + + if (i915->current_program == p) + return; + + if (i915->current_program) { + i915->current_program->on_hardware = 0; + i915->current_program->params_uptodate = 0; + } + + i915->current_program = p; + + assert(p->on_hardware == 0); + assert(p->params_uptodate == 0); + + /* Hack: make sure fog is correctly enabled according to this + * fragment program's fog options. + */ + ctx->Driver.Enable( ctx, GL_FRAGMENT_PROGRAM_ARB, + ctx->FragmentProgram.Enabled ); + } +} + +static struct program *i915NewProgram( GLcontext *ctx, + GLenum target, + GLuint id ) +{ + switch (target) { + case GL_VERTEX_PROGRAM_ARB: + return _mesa_init_vertex_program( ctx, CALLOC_STRUCT(vertex_program), + target, id ); + + case GL_FRAGMENT_PROGRAM_ARB: { + struct i915_fragment_program *prog = CALLOC_STRUCT(i915_fragment_program); + if (prog) { + i915_init_program( I915_CONTEXT(ctx), prog ); + + return _mesa_init_fragment_program( ctx, &prog->FragProg, + target, id ); + } + else + return NULL; + } + + case GL_FRAGMENT_PROGRAM_NV: + default: + _mesa_problem(ctx, "bad target in _mesa_new_program"); + return NULL; + } +} + +static void i915DeleteProgram( GLcontext *ctx, + struct program *prog ) +{ + if (prog->Target == GL_FRAGMENT_PROGRAM_ARB) { + i915ContextPtr i915 = I915_CONTEXT(ctx); + struct i915_fragment_program *p = (struct i915_fragment_program *)prog; + + if (i915->current_program == p) + i915->current_program = 0; + } + + _mesa_delete_program( ctx, prog ); +} + + +static GLboolean i915IsProgramNative( GLcontext *ctx, + GLenum target, + struct program *prog ) +{ + if (target == GL_FRAGMENT_PROGRAM_ARB) { + struct i915_fragment_program *p = (struct i915_fragment_program *)prog; + + if (!p->translated) + translate_program( p ); + + return !p->error; + } + else + return GL_TRUE; +} + +static void i915ProgramStringNotify( GLcontext *ctx, + GLenum target, + struct program *prog ) +{ + if (target == GL_FRAGMENT_PROGRAM_ARB) { + struct i915_fragment_program *p = (struct i915_fragment_program *)prog; + p->translated = 0; + + /* Hack: make sure fog is correctly enabled according to this + * fragment program's fog options. + */ + ctx->Driver.Enable( ctx, GL_FRAGMENT_PROGRAM_ARB, + ctx->FragmentProgram.Enabled ); + } +} + + +void i915ValidateFragmentProgram( i915ContextPtr i915 ) +{ + GLcontext *ctx = &i915->intel.ctx; + intelContextPtr intel = INTEL_CONTEXT(ctx); + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_buffer *VB = &tnl->vb; + + struct i915_fragment_program *p = + (struct i915_fragment_program *)ctx->FragmentProgram.Current; + + GLuint inputsRead = p->FragProg.InputsRead; + GLuint s4 = i915->state.Ctx[I915_CTXREG_LIS4] & ~S4_VFMT_MASK; + GLuint s2 = S2_TEXCOORD_NONE; + int i, offset = 0; + + /* Important: + */ + VB->AttribPtr[VERT_ATTRIB_POS] = VB->NdcPtr; + + if (!p->translated) + translate_program( p ); + + intel->vertex_attr_count = 0; + intel->wpos_offset = 0; + intel->wpos_size = 0; + intel->coloroffset = 0; + intel->specoffset = 0; + + if (inputsRead & FRAG_BITS_TEX_ANY) { + EMIT_ATTR( _TNL_ATTRIB_POS, EMIT_4F_VIEWPORT, S4_VFMT_XYZW, 16 ); + } + else { + EMIT_ATTR( _TNL_ATTRIB_POS, EMIT_3F_VIEWPORT, S4_VFMT_XYZ, 12 ); + } + + if (inputsRead & FRAG_BIT_COL0) { + intel->coloroffset = offset / 4; + EMIT_ATTR( _TNL_ATTRIB_COLOR0, EMIT_4UB_4F_RGBA, S4_VFMT_COLOR, 4 ); + } + + if (inputsRead & FRAG_BIT_COL1) { + intel->specoffset = offset / 4; + EMIT_ATTR( _TNL_ATTRIB_COLOR1, EMIT_3UB_3F_RGB, S4_VFMT_SPEC_FOG, 3 ); + EMIT_PAD( 1 ); + } + + if (inputsRead & FRAG_BIT_FOGC) { + EMIT_ATTR( _TNL_ATTRIB_FOG, EMIT_1F, S4_VFMT_FOG_PARAM, 4 ); + } + + for (i = 0; i < p->ctx->Const.MaxTextureCoordUnits; i++) { + if (inputsRead & FRAG_BIT_TEX(i)) { + int sz = VB->TexCoordPtr[i]->size; + + s2 &= ~S2_TEXCOORD_FMT(i, S2_TEXCOORD_FMT0_MASK); + s2 |= S2_TEXCOORD_FMT(i, SZ_TO_HW(sz)); + + EMIT_ATTR( _TNL_ATTRIB_TEX0+i, EMIT_SZ(sz), 0, sz * 4 ); + } + else if (i == p->wpos_tex) { + + /* If WPOS is required, duplicate the XYZ position data in an + * unused texture coordinate: + */ + s2 &= ~S2_TEXCOORD_FMT(i, S2_TEXCOORD_FMT0_MASK); + s2 |= S2_TEXCOORD_FMT(i, SZ_TO_HW(3)); + + intel->wpos_offset = offset; + intel->wpos_size = 3 * sizeof(GLuint); + + EMIT_PAD( intel->wpos_size ); + } + } + + if (s2 != i915->state.Ctx[I915_CTXREG_LIS2] || + s4 != i915->state.Ctx[I915_CTXREG_LIS4]) { + + I915_STATECHANGE( i915, I915_UPLOAD_CTX ); + + /* Must do this *after* statechange, so as not to affect + * buffered vertices reliant on the old state: + */ + intel->vertex_size = _tnl_install_attrs( &intel->ctx, + intel->vertex_attrs, + intel->vertex_attr_count, + intel->ViewportMatrix.m, 0 ); + + intel->vertex_size >>= 2; + + i915->state.Ctx[I915_CTXREG_LIS2] = s2; + i915->state.Ctx[I915_CTXREG_LIS4] = s4; + + assert(intel->vtbl.check_vertex_size( intel, intel->vertex_size )); + } + + if (!p->params_uptodate) + track_params( p ); + + if (!p->on_hardware) + i915_upload_program( i915, p ); +} + +void i915InitFragProgFuncs( struct dd_function_table *functions ) +{ + functions->BindProgram = i915BindProgram; + functions->NewProgram = i915NewProgram; + functions->DeleteProgram = i915DeleteProgram; + functions->IsProgramNative = i915IsProgramNative; + functions->ProgramStringNotify = i915ProgramStringNotify; +} diff --git a/src/mesa/drivers/dri/i915/i915_metaops.c b/src/mesa/drivers/dri/i915/i915_metaops.c new file mode 100644 index 0000000..4c620cb --- /dev/null +++ b/src/mesa/drivers/dri/i915/i915_metaops.c @@ -0,0 +1,494 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "glheader.h" +#include "enums.h" +#include "mtypes.h" +#include "macros.h" +#include "utils.h" + +#include "intel_screen.h" +#include "intel_batchbuffer.h" +#include "intel_ioctl.h" + +#include "i915_context.h" +#include "i915_reg.h" + +/* A large amount of state doesn't need to be uploaded. + */ +#define ACTIVE (I915_UPLOAD_PROGRAM | \ + I915_UPLOAD_STIPPLE | \ + I915_UPLOAD_CTX | \ + I915_UPLOAD_BUFFERS | \ + I915_UPLOAD_TEX(0)) + +#define SET_STATE( i915, STATE ) \ +do { \ + i915->current->emitted &= ~ACTIVE; \ + i915->current = &i915->STATE; \ + i915->current->emitted &= ~ACTIVE; \ +} while (0) + +/* Operations where the 3D engine is decoupled temporarily from the + * current GL state and used for other purposes than simply rendering + * incoming triangles. + */ +static void set_initial_state( i915ContextPtr i915 ) +{ + memcpy(&i915->meta, &i915->initial, sizeof(i915->meta) ); + i915->meta.active = ACTIVE; + i915->meta.emitted = 0; +} + + +static void set_no_depth_stencil_write( i915ContextPtr i915 ) +{ + /* ctx->Driver.Enable( ctx, GL_STENCIL_TEST, GL_FALSE ) + */ + i915->meta.Ctx[I915_CTXREG_LIS5] &= ~(S5_STENCIL_TEST_ENABLE | + S5_STENCIL_WRITE_ENABLE); + + /* ctx->Driver.Enable( ctx, GL_DEPTH_TEST, GL_FALSE ) + */ + i915->meta.Ctx[I915_CTXREG_LIS6] &= ~(S6_DEPTH_TEST_ENABLE | + S6_DEPTH_WRITE_ENABLE); + + i915->meta.emitted &= ~I915_UPLOAD_CTX; +} + +/* Set stencil unit to replace always with the reference value. + */ +static void set_stencil_replace( i915ContextPtr i915, + GLuint s_mask, + GLuint s_clear) +{ + GLuint op = STENCILOP_REPLACE; + GLuint func = COMPAREFUNC_ALWAYS; + + /* ctx->Driver.Enable( ctx, GL_STENCIL_TEST, GL_TRUE ) + */ + i915->meta.Ctx[I915_CTXREG_LIS5] |= (S5_STENCIL_TEST_ENABLE | + S5_STENCIL_WRITE_ENABLE); + + + /* ctx->Driver.Enable( ctx, GL_DEPTH_TEST, GL_FALSE ) + */ + i915->meta.Ctx[I915_CTXREG_LIS6] &= ~(S6_DEPTH_TEST_ENABLE | + S6_DEPTH_WRITE_ENABLE); + + + /* ctx->Driver.StencilMask( ctx, s_mask ) + */ + i915->meta.Ctx[I915_CTXREG_STATE4] &= ~MODE4_ENABLE_STENCIL_WRITE_MASK; + + i915->meta.Ctx[I915_CTXREG_STATE4] |= (ENABLE_STENCIL_WRITE_MASK | + STENCIL_WRITE_MASK(s_mask)); + + + /* ctx->Driver.StencilOp( ctx, GL_REPLACE, GL_REPLACE, GL_REPLACE ) + */ + i915->meta.Ctx[I915_CTXREG_LIS5] &= ~(S5_STENCIL_FAIL_MASK | + S5_STENCIL_PASS_Z_FAIL_MASK | + S5_STENCIL_PASS_Z_PASS_MASK); + + i915->meta.Ctx[I915_CTXREG_LIS5] |= ((op << S5_STENCIL_FAIL_SHIFT) | + (op << S5_STENCIL_PASS_Z_FAIL_SHIFT) | + (op << S5_STENCIL_PASS_Z_PASS_SHIFT)); + + + /* ctx->Driver.StencilFunc( ctx, GL_ALWAYS, s_ref, ~0 ) + */ + i915->meta.Ctx[I915_CTXREG_STATE4] &= ~MODE4_ENABLE_STENCIL_TEST_MASK; + i915->meta.Ctx[I915_CTXREG_STATE4] |= (ENABLE_STENCIL_TEST_MASK | + STENCIL_TEST_MASK(0xff)); + + i915->meta.Ctx[I915_CTXREG_LIS5] &= ~(S5_STENCIL_REF_MASK | + S5_STENCIL_TEST_FUNC_MASK); + + i915->meta.Ctx[I915_CTXREG_LIS5] |= ((s_clear << S5_STENCIL_REF_SHIFT) | + (func << S5_STENCIL_TEST_FUNC_SHIFT)); + + + i915->meta.emitted &= ~I915_UPLOAD_CTX; +} + + +static void set_color_mask( i915ContextPtr i915, GLboolean state ) +{ + const GLuint mask = (S5_WRITEDISABLE_RED | + S5_WRITEDISABLE_GREEN | + S5_WRITEDISABLE_BLUE | + S5_WRITEDISABLE_ALPHA); + + /* Copy colormask state from "regular" hw context. + */ + if (state) { + i915->meta.Ctx[I915_CTXREG_LIS5] &= ~mask; + i915->meta.Ctx[I915_CTXREG_LIS5] |= + (i915->state.Ctx[I915_CTXREG_LIS5] & mask); + } + else + i915->meta.Ctx[I915_CTXREG_LIS5] |= mask; + + i915->meta.emitted &= ~I915_UPLOAD_CTX; +} + + + + +#define REG( type, nr ) (((type)<<5)|(nr)) + +#define REG_R(x) REG(REG_TYPE_R, x) +#define REG_T(x) REG(REG_TYPE_T, x) +#define REG_CONST(x) REG(REG_TYPE_CONST, x) +#define REG_S(x) REG(REG_TYPE_S, x) +#define REG_OC REG(REG_TYPE_OC, 0) +#define REG_OD REG(REG_TYPE_OD, 0) +#define REG_U(x) REG(REG_TYPE_U, x) + +#define REG_T_DIFFUSE REG(REG_TYPE_T, T_DIFFUSE) +#define REG_T_SPECULAR REG(REG_TYPE_T, T_SPECULAR) +#define REG_T_FOG_W REG(REG_TYPE_T, T_FOG_W) +#define REG_T_TEX(x) REG(REG_TYPE_T, x) + + +#define A0_DEST_REG( reg ) ( (reg) << A0_DEST_NR_SHIFT ) +#define A0_SRC0_REG( reg ) ( (reg) << A0_SRC0_NR_SHIFT ) +#define A1_SRC1_REG( reg ) ( (reg) << A1_SRC1_NR_SHIFT ) +#define A1_SRC2_REG( reg ) ( (reg) << A1_SRC2_NR_SHIFT ) +#define A2_SRC2_REG( reg ) ( (reg) << A2_SRC2_NR_SHIFT ) +#define D0_DECL_REG( reg ) ( (reg) << D0_NR_SHIFT ) +#define T0_DEST_REG( reg ) ( (reg) << T0_DEST_NR_SHIFT ) + +#define T0_SAMPLER( unit ) ((unit)<meta.Program, prog, sizeof(prog) ); + i915->meta.ProgramSize = sizeof(prog) / sizeof(*prog); + i915->meta.Program[0] |= i915->meta.ProgramSize - 2; + i915->meta.emitted &= ~I915_UPLOAD_PROGRAM; +} + + +static void enable_texture_blend_replace( i915ContextPtr i915 ) +{ + static const GLuint prog[] = { + _3DSTATE_PIXEL_SHADER_PROGRAM, + + /* Declare the sampler: + */ + (D0_DCL | + D0_DECL_REG( REG_S(0) ) | + D0_SAMPLE_TYPE_2D | + D0_CHANNEL_NONE), + D1_MBZ, + D2_MBZ, + + /* Declare the interpolated texture coordinate: + */ + (D0_DCL | + D0_DECL_REG( REG_T_TEX(0) ) | + D0_CHANNEL_ALL), + D1_MBZ, + D2_MBZ, + + /* output-color = texld(sample0, texcoord0) + */ + (T0_TEXLD | + T0_DEST_REG( REG_OC ) | + T0_SAMPLER( 0 )), + T1_ADDRESS_REG(REG_TYPE_T, 0), + T2_MBZ + }; + + memcpy( i915->meta.Program, prog, sizeof(prog) ); + i915->meta.ProgramSize = sizeof(prog) / sizeof(*prog); + i915->meta.Program[0] |= i915->meta.ProgramSize - 2; + i915->meta.emitted &= ~I915_UPLOAD_PROGRAM; +} + + + + + +/* Set up an arbitary piece of memory as a rectangular texture + * (including the front or back buffer). + */ +static void set_tex_rect_source( i915ContextPtr i915, + GLuint offset, + GLuint width, + GLuint height, + GLuint pitch, + GLuint textureFormat ) +{ + GLuint unit = 0; + GLint numLevels = 1; + GLuint *state = i915->meta.Tex[0]; + + pitch *= i915->intel.intelScreen->cpp; + +/* fprintf(stderr, "%s: offset: %x w: %d h: %d pitch %d format %x\n", */ +/* __FUNCTION__, offset, width, height, pitch, textureFormat ); */ + + state[I915_TEXREG_MS2] = offset; + state[I915_TEXREG_MS3] = (((height - 1) << MS3_HEIGHT_SHIFT) | + ((width - 1) << MS3_WIDTH_SHIFT) | + textureFormat | + MS3_USE_FENCE_REGS); + + state[I915_TEXREG_MS4] = ((((pitch / 4) - 1) << MS4_PITCH_SHIFT) | + MS4_CUBE_FACE_ENA_MASK | + ((((numLevels-1) * 4)) << MS4_MAX_LOD_SHIFT)); + + state[I915_TEXREG_SS2] = ((FILTER_NEAREST << SS2_MIN_FILTER_SHIFT) | + (MIPFILTER_NONE << SS2_MIP_FILTER_SHIFT) | + (FILTER_NEAREST << SS2_MAG_FILTER_SHIFT)); + state[I915_TEXREG_SS3] = ((TEXCOORDMODE_WRAP << SS3_TCX_ADDR_MODE_SHIFT) | + (TEXCOORDMODE_WRAP << SS3_TCY_ADDR_MODE_SHIFT) | + (TEXCOORDMODE_WRAP << SS3_TCZ_ADDR_MODE_SHIFT) | + (unit<meta.emitted &= ~I915_UPLOAD_TEX(0); +} + + +/* Select between front and back draw buffers. + */ +static void set_draw_offset( i915ContextPtr i915, + GLuint offset ) +{ + i915->meta.Buffer[I915_DESTREG_CBUFADDR2] = offset; + i915->meta.emitted &= ~I915_UPLOAD_BUFFERS; +} + +/* Setup an arbitary draw format, useful for targeting texture or agp + * memory. + */ +static void set_draw_format( i915ContextPtr i915, + GLuint format, + GLuint depth_format) +{ + i915->meta.Buffer[I915_DESTREG_DV1] = (DSTORG_HORT_BIAS(0x8) | /* .5 */ + DSTORG_VERT_BIAS(0x8) | /* .5 */ + format | + LOD_PRECLAMP_OGL | + TEX_DEFAULT_COLOR_OGL | + depth_format); + + i915->meta.emitted &= ~I915_UPLOAD_BUFFERS; +/* fprintf(stderr, "%s: DV1: %x\n", */ +/* __FUNCTION__, i915->meta.Buffer[I915_DESTREG_DV1]); */ +} + +static void set_vertex_format( i915ContextPtr i915 ) +{ + i915->meta.Ctx[I915_CTXREG_LIS2] = + (S2_TEXCOORD_FMT(0, TEXCOORDFMT_2D) | + S2_TEXCOORD_FMT(1, TEXCOORDFMT_NOT_PRESENT) | + S2_TEXCOORD_FMT(2, TEXCOORDFMT_NOT_PRESENT) | + S2_TEXCOORD_FMT(3, TEXCOORDFMT_NOT_PRESENT) | + S2_TEXCOORD_FMT(4, TEXCOORDFMT_NOT_PRESENT) | + S2_TEXCOORD_FMT(5, TEXCOORDFMT_NOT_PRESENT) | + S2_TEXCOORD_FMT(6, TEXCOORDFMT_NOT_PRESENT) | + S2_TEXCOORD_FMT(7, TEXCOORDFMT_NOT_PRESENT)); + + i915->meta.Ctx[I915_CTXREG_LIS4] &= ~S4_VFMT_MASK; + + i915->meta.Ctx[I915_CTXREG_LIS4] |= + (S4_VFMT_COLOR | + S4_VFMT_SPEC_FOG | + S4_VFMT_XYZW); + + i915->meta.emitted &= ~I915_UPLOAD_CTX; + +} + + +static void draw_quad(i915ContextPtr i915, + GLfloat x0, GLfloat x1, + GLfloat y0, GLfloat y1, + GLubyte red, GLubyte green, + GLubyte blue, GLubyte alpha, + GLfloat s0, GLfloat s1, + GLfloat t0, GLfloat t1 ) +{ + GLuint vertex_size = 8; + GLuint *vb = intelEmitInlinePrimitiveLocked( &i915->intel, + PRIM3D_TRIFAN, + 4 * vertex_size, + vertex_size ); + intelVertex tmp; + int i; + + if (0) + fprintf(stderr, "%s: %f,%f-%f,%f 0x%x%x%x%x %f,%f-%f,%f\n", + __FUNCTION__, + x0,y0,x1,y1,red,green,blue,alpha,s0,t0,s1,t1); + + + /* initial vertex, left bottom */ + tmp.v.x = x0; + tmp.v.y = y0; + tmp.v.z = 1.0; + tmp.v.w = 1.0; + tmp.v.color.red = red; + tmp.v.color.green = green; + tmp.v.color.blue = blue; + tmp.v.color.alpha = alpha; + tmp.v.specular.red = 0; + tmp.v.specular.green = 0; + tmp.v.specular.blue = 0; + tmp.v.specular.alpha = 0; + tmp.v.u0 = s0; + tmp.v.v0 = t0; + + for (i = 0 ; i < vertex_size ; i++) + vb[i] = tmp.ui[i]; + + /* right bottom */ + vb += vertex_size; + tmp.v.x = x1; + tmp.v.u0 = s1; + for (i = 0 ; i < vertex_size ; i++) + vb[i] = tmp.ui[i]; + + /* right top */ + vb += vertex_size; + tmp.v.y = y1; + tmp.v.v0 = t1; + for (i = 0 ; i < vertex_size ; i++) + vb[i] = tmp.ui[i]; + + /* left top */ + vb += vertex_size; + tmp.v.x = x0; + tmp.v.u0 = s0; + for (i = 0 ; i < vertex_size ; i++) + vb[i] = tmp.ui[i]; +} + +void +i915ClearWithTris(intelContextPtr intel, GLbitfield mask, + GLboolean all, + GLint cx, GLint cy, GLint cw, GLint ch) +{ + i915ContextPtr i915 = I915_CONTEXT( intel ); + __DRIdrawablePrivate *dPriv = intel->driDrawable; + intelScreenPrivate *screen = intel->intelScreen; + int x0, y0, x1, y1; + + SET_STATE( i915, meta ); + set_initial_state( i915 ); + set_no_texture( i915 ); + set_vertex_format( i915 ); + + LOCK_HARDWARE(intel); + + if(!all) { + x0 = cx; + y0 = cy; + x1 = x0 + cw; + y1 = y0 + ch; + } else { + x0 = 0; + y0 = 0; + x1 = x0 + dPriv->w; + y1 = y0 + dPriv->h; + } + + /* Don't do any clipping to screen - these are window coordinates. + * The active cliprects will be applied as for any other geometry. + */ + + if (mask & DD_FRONT_LEFT_BIT) { + set_no_depth_stencil_write( i915 ); + set_color_mask( i915, GL_TRUE ); + set_draw_offset( i915, screen->frontOffset ); + + draw_quad(i915, x0, x1, y0, y1, + intel->clear_red, intel->clear_green, + intel->clear_blue, intel->clear_alpha, + 0, 0, 0, 0); + } + + if(mask & DD_BACK_LEFT_BIT) { + set_no_depth_stencil_write( i915 ); + set_color_mask( i915, GL_TRUE ); + set_draw_offset( i915, screen->backOffset ); + + draw_quad(i915, x0, x1, y0, y1, + intel->clear_red, intel->clear_green, + intel->clear_blue, intel->clear_alpha, + 0, 0, 0, 0); + } + + if(mask & DD_STENCIL_BIT) { + set_stencil_replace( i915, + intel->ctx.Stencil.WriteMask[0], + intel->ctx.Stencil.Clear); + + set_color_mask( i915, GL_FALSE ); + set_draw_offset( i915, screen->frontOffset ); /* could be either? */ + + draw_quad( i915, x0, x1, y0, y1, 0, 0, 0, 0, 0, 0, 0, 0 ); + } + + UNLOCK_HARDWARE(intel); + + SET_STATE( i915, state ); +} + + diff --git a/src/mesa/drivers/dri/i915/i915_program.c b/src/mesa/drivers/dri/i915/i915_program.c new file mode 100644 index 0000000..03baa16 --- /dev/null +++ b/src/mesa/drivers/dri/i915/i915_program.c @@ -0,0 +1,446 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include + +#include "glheader.h" +#include "macros.h" +#include "enums.h" + +#include "tnl/t_context.h" +#include "intel_batchbuffer.h" + +#include "i915_reg.h" +#include "i915_context.h" +#include "i915_program.h" + + +#define A0_DEST( reg ) (((reg)&UREG_TYPE_NR_MASK)>>UREG_A0_DEST_SHIFT_LEFT) +#define D0_DEST( reg ) (((reg)&UREG_TYPE_NR_MASK)>>UREG_A0_DEST_SHIFT_LEFT) +#define T0_DEST( reg ) (((reg)&UREG_TYPE_NR_MASK)>>UREG_A0_DEST_SHIFT_LEFT) +#define A0_SRC0( reg ) (((reg)&UREG_MASK)>>UREG_A0_SRC0_SHIFT_LEFT) +#define A1_SRC0( reg ) (((reg)&UREG_MASK)<>UREG_A1_SRC1_SHIFT_LEFT) +#define A2_SRC1( reg ) (((reg)&UREG_MASK)<>UREG_A2_SRC2_SHIFT_LEFT) + +/* These are special, and don't have swizzle/negate bits. + */ +#define T0_SAMPLER( reg ) (GET_UREG_NR(reg)<temp_flag ); + if (!bit) { + fprintf(stderr, "%s: out of temporaries\n", __FILE__); + exit(1); + } + + p->temp_flag |= 1<<(bit-1); + return UREG(REG_TYPE_R, (bit-1)); +} + + +GLuint i915_get_utemp( struct i915_fragment_program *p ) +{ + int bit = ffs( ~p->utemp_flag ); + if (!bit) { + fprintf(stderr, "%s: out of temporaries\n", __FILE__); + exit(1); + } + + p->utemp_flag |= 1<<(bit-1); + return UREG(REG_TYPE_U, (bit-1)); +} + +void i915_release_utemps( struct i915_fragment_program *p ) +{ + p->utemp_flag = ~0x7; +} + + +GLuint i915_emit_decl( struct i915_fragment_program *p, + GLuint type, GLuint nr, GLuint d0_flags ) +{ + GLuint reg = UREG(type, nr); + + if (type == REG_TYPE_T) { + if (p->decl_t & (1<decl_t |= (1<decl_s & (1<decl_s |= (1<decl++) = (D0_DCL | D0_DEST( reg ) | d0_flags); + *(p->decl++) = D1_MBZ; + *(p->decl++) = D2_MBZ; + + p->nr_decl_insn++; + return reg; +} + +GLuint i915_emit_arith( struct i915_fragment_program *p, + GLuint op, + GLuint dest, + GLuint mask, + GLuint saturate, + GLuint src0, + GLuint src1, + GLuint src2 ) +{ + GLuint c[3]; + GLuint nr_const = 0; + + assert(GET_UREG_TYPE(dest) != REG_TYPE_CONST); + assert(dest = UREG(GET_UREG_TYPE(dest), GET_UREG_NR(dest))); + + if (GET_UREG_TYPE(src0) == REG_TYPE_CONST) c[nr_const++] = 0; + if (GET_UREG_TYPE(src1) == REG_TYPE_CONST) c[nr_const++] = 1; + if (GET_UREG_TYPE(src2) == REG_TYPE_CONST) c[nr_const++] = 2; + + /* Recursively call this function to MOV additional const values + * into temporary registers. Use utemp registers for this - + * currently shouldn't be possible to run out, but keep an eye on + * this. + */ + if (nr_const > 1) { + GLuint s[3], first, i, old_utemp_flag; + + s[0] = src0; + s[1] = src1; + s[2] = src2; + old_utemp_flag = p->utemp_flag; + + first = GET_UREG_NR(s[c[0]]); + for (i = 1 ; i < nr_const ; i++) { + if (GET_UREG_NR(s[c[i]]) != first) { + GLuint tmp = i915_get_utemp(p); + + i915_emit_arith( p, A0_MOV, tmp, A0_DEST_CHANNEL_ALL, 0, + s[c[i]], 0, 0 ); + s[c[i]] = tmp; + } + } + + src0 = s[0]; + src1 = s[1]; + src2 = s[2]; + p->utemp_flag = old_utemp_flag; /* restore */ + } + + *(p->csr++) = (op | + A0_DEST( dest ) | + mask | + saturate | + A0_SRC0( src0 )); + *(p->csr++) = (A1_SRC0( src0 ) | + A1_SRC1( src1 )); + *(p->csr++) = (A2_SRC1( src1 ) | + A2_SRC2( src2 )); + + p->nr_alu_insn++; + return dest; +} + +GLuint i915_emit_texld( struct i915_fragment_program *p, + GLuint dest, + GLuint destmask, + GLuint sampler, + GLuint coord, + GLuint op ) +{ + assert(GET_UREG_TYPE(dest) != REG_TYPE_CONST); + assert(dest = UREG(GET_UREG_TYPE(dest), GET_UREG_NR(dest))); + + if (GET_UREG_TYPE(coord) != REG_TYPE_T) { + p->nr_tex_indirect++; + } + + *(p->csr++) = (op | + T0_DEST( dest ) | + destmask | + T0_SAMPLER( sampler )); + + *(p->csr++) = T1_ADDRESS_REG( coord ); + *(p->csr++) = T2_MBZ; + + p->nr_tex_insn++; + return dest; +} + + +GLuint i915_emit_const1f( struct i915_fragment_program *p, GLfloat c0 ) +{ + GLint reg, idx; + + if (c0 == 0.0) return swizzle(UREG(REG_TYPE_R, 0), ZERO, ZERO, ZERO, ZERO); + if (c0 == 1.0) return swizzle(UREG(REG_TYPE_R, 0), ONE, ONE, ONE, ONE ); + + for (reg = 0; reg < I915_MAX_CONSTANT; reg++) { + if (p->constant_flags[reg] == I915_CONSTFLAG_PARAM) + continue; + for (idx = 0; idx < 4; idx++) { + if (!(p->constant_flags[reg] & (1<constant[reg][idx] == c0) { + p->constant[reg][idx] = c0; + p->constant_flags[reg] |= 1< p->nr_constants) p->nr_constants = reg+1; + return swizzle(UREG(REG_TYPE_CONST, reg),idx,ZERO,ZERO,ONE); + } + } + } + + fprintf(stderr, "%s: out of constants\n", __FUNCTION__); + p->error = 1; + return 0; +} + +GLuint i915_emit_const2f( struct i915_fragment_program *p, + GLfloat c0, GLfloat c1 ) +{ + GLint reg, idx; + + if (c0 == 0.0) return swizzle(i915_emit_const1f(p, c1), ZERO, X, Z, W); + if (c0 == 1.0) return swizzle(i915_emit_const1f(p, c1), ONE, X, Z, W); + + if (c1 == 0.0) return swizzle(i915_emit_const1f(p, c0), X, ZERO, Z, W); + if (c1 == 1.0) return swizzle(i915_emit_const1f(p, c0), X, ONE, Z, W); + + for (reg = 0; reg < I915_MAX_CONSTANT; reg++) { + if (p->constant_flags[reg] == 0xf || + p->constant_flags[reg] == I915_CONSTFLAG_PARAM) + continue; + for (idx = 0; idx < 3; idx++) { + if (!(p->constant_flags[reg] & (3<constant[reg][idx] = c0; + p->constant[reg][idx+1] = c1; + p->constant_flags[reg] |= 3< p->nr_constants) p->nr_constants = reg+1; + return swizzle(UREG(REG_TYPE_CONST, reg),idx,idx+1,ZERO,ONE); + } + } + } + + fprintf(stderr, "%s: out of constants\n", __FUNCTION__); + p->error = 1; + return 0; +} + + + +GLuint i915_emit_const4f( struct i915_fragment_program *p, + GLfloat c0, GLfloat c1, GLfloat c2, GLfloat c3 ) +{ + GLint reg; + + for (reg = 0; reg < I915_MAX_CONSTANT; reg++) { + if (p->constant_flags[reg] == 0xf && + p->constant[reg][0] == c0 && + p->constant[reg][1] == c1 && + p->constant[reg][2] == c2 && + p->constant[reg][3] == c3) { + return UREG(REG_TYPE_CONST, reg); + } + else if (p->constant_flags[reg] == 0) { + p->constant[reg][0] = c0; + p->constant[reg][1] = c1; + p->constant[reg][2] = c2; + p->constant[reg][3] = c3; + p->constant_flags[reg] = 0xf; + if (reg+1 > p->nr_constants) p->nr_constants = reg+1; + return UREG(REG_TYPE_CONST, reg); + } + } + + fprintf(stderr, "%s: out of constants\n", __FUNCTION__); + p->error = 1; + return 0; +} + + +GLuint i915_emit_const4fv( struct i915_fragment_program *p, const GLfloat *c ) +{ + return i915_emit_const4f( p, c[0], c[1], c[2], c[3] ); +} + + +GLuint i915_emit_param4fv( struct i915_fragment_program *p, + const GLfloat *values ) +{ + GLint reg, i; + + for (i = 0; i < p->nr_params; i++) { + if (p->param[i].values == values) + return UREG(REG_TYPE_CONST, p->param[i].reg); + } + + + for (reg = 0; reg < I915_MAX_CONSTANT; reg++) { + if (p->constant_flags[reg] == 0) { + p->constant_flags[reg] = I915_CONSTFLAG_PARAM; + i = p->nr_params++; + + p->param[i].values = values; + p->param[i].reg = reg; + p->params_uptodate = 0; + + if (reg+1 > p->nr_constants) p->nr_constants = reg+1; + return UREG(REG_TYPE_CONST, reg); + } + } + + fprintf(stderr, "%s: out of constants\n", __FUNCTION__); + p->error = 1; + return 0; +} + + + + +void i915_program_error( struct i915_fragment_program *p, const GLubyte *msg ) +{ + fprintf(stderr, "%s\n", msg); + p->error = 1; +} + +void i915_init_program( i915ContextPtr i915, struct i915_fragment_program *p ) +{ + GLcontext *ctx = &i915->intel.ctx; + TNLcontext *tnl = TNL_CONTEXT( ctx ); + + p->translated = 0; + p->params_uptodate = 0; + p->on_hardware = 0; + p->error = 0; + + p->nr_tex_indirect = 1; /* correct? */ + p->nr_tex_insn = 0; + p->nr_alu_insn = 0; + p->nr_decl_insn = 0; + + p->ctx = ctx; + memset( p->constant_flags, 0, sizeof(p->constant_flags) ); + + p->nr_constants = 0; + p->csr = p->program; + p->decl = p->declarations; + p->decl_s = 0; + p->decl_t = 0; + p->temp_flag = 0xffff000; + p->utemp_flag = ~0x7; + p->wpos_tex = 0; + p->depth_written = 0; + p->nr_params = 0; + + p->src_texture = UREG_BAD; + p->src_previous = UREG(REG_TYPE_T, T_DIFFUSE); + p->last_tex_stage = 0; + p->VB = &tnl->vb; + + *(p->decl++) = _3DSTATE_PIXEL_SHADER_PROGRAM; +} + + +void i915_fini_program( struct i915_fragment_program *p ) +{ + GLuint program_size = p->csr - p->program; + GLuint decl_size = p->decl - p->declarations; + + if (p->nr_tex_indirect > I915_MAX_TEX_INDIRECT) + i915_program_error(p, "Exceeded max nr indirect texture lookups"); + + if (p->nr_tex_insn > I915_MAX_TEX_INSN) + i915_program_error(p, "Exceeded max TEX instructions"); + + if (p->nr_alu_insn > I915_MAX_ALU_INSN) + i915_program_error(p, "Exceeded max ALU instructions"); + + if (p->nr_decl_insn > I915_MAX_DECL_INSN) + i915_program_error(p, "Exceeded max DECL instructions"); + + p->declarations[0] |= program_size + decl_size - 2; +} + +void i915_upload_program( i915ContextPtr i915, struct i915_fragment_program *p ) +{ + GLuint program_size = p->csr - p->program; + GLuint decl_size = p->decl - p->declarations; + + FALLBACK( &i915->intel, I915_FALLBACK_PROGRAM, p->error ); + + /* Could just go straight to the batchbuffer from here: + */ + if (i915->state.ProgramSize != (program_size + decl_size) || + memcmp(i915->state.Program + decl_size, p->program, + program_size*sizeof(int)) != 0) { + I915_STATECHANGE( i915, I915_UPLOAD_PROGRAM ); + memcpy(i915->state.Program, p->declarations, decl_size*sizeof(int)); + memcpy(i915->state.Program + decl_size, p->program, + program_size*sizeof(int)); + i915->state.ProgramSize = decl_size + program_size; + } + + /* Always seemed to get a failure if I used memcmp() to + * shortcircuit this state upload. Needs further investigation? + */ + if (p->nr_constants) { + GLuint nr = p->nr_constants; + + I915_ACTIVESTATE( i915, I915_UPLOAD_CONSTANTS, 1 ); + I915_STATECHANGE( i915, I915_UPLOAD_CONSTANTS ); + + i915->state.Constant[0] = _3DSTATE_PIXEL_SHADER_CONSTANTS | ((nr) * 4); + i915->state.Constant[1] = (1<<(nr-1)) | ((1<<(nr-1))-1); + + memcpy(&i915->state.Constant[2], p->constant, 4*sizeof(int)*(nr)); + i915->state.ConstantSize = 2 + (nr) * 4; + + if (0) { + GLuint i; + for (i = 0; i < nr; i++) { + fprintf(stderr, "const[%d]: %f %f %f %f\n", i, + p->constant[i][0], + p->constant[i][1], + p->constant[i][2], + p->constant[i][3]); + } + } + } + else { + I915_ACTIVESTATE( i915, I915_UPLOAD_CONSTANTS, 0 ); + } + + p->on_hardware = 1; +} diff --git a/src/mesa/drivers/dri/i915/i915_program.h b/src/mesa/drivers/dri/i915/i915_program.h new file mode 100644 index 0000000..7ed2e84 --- /dev/null +++ b/src/mesa/drivers/dri/i915/i915_program.h @@ -0,0 +1,143 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + + +#ifndef I915_PROGRAM_H +#define I915_PROGRAM_H + +#include "i915_context.h" +#include "i915_reg.h" + + + +/* Having zero and one in here makes the definition of swizzle a lot + * easier. + */ +#define UREG_TYPE_SHIFT 29 +#define UREG_NR_SHIFT 24 +#define UREG_CHANNEL_X_NEGATE_SHIFT 23 +#define UREG_CHANNEL_X_SHIFT 20 +#define UREG_CHANNEL_Y_NEGATE_SHIFT 19 +#define UREG_CHANNEL_Y_SHIFT 16 +#define UREG_CHANNEL_Z_NEGATE_SHIFT 15 +#define UREG_CHANNEL_Z_SHIFT 12 +#define UREG_CHANNEL_W_NEGATE_SHIFT 11 +#define UREG_CHANNEL_W_SHIFT 8 +#define UREG_CHANNEL_ZERO_NEGATE_MBZ 5 +#define UREG_CHANNEL_ZERO_SHIFT 4 +#define UREG_CHANNEL_ONE_NEGATE_MBZ 1 +#define UREG_CHANNEL_ONE_SHIFT 0 + +#define UREG_BAD 0xffffffff /* not a valid ureg */ + +#define X SRC_X +#define Y SRC_Y +#define Z SRC_Z +#define W SRC_W +#define ZERO SRC_ZERO +#define ONE SRC_ONE + +/* Construct a ureg: + */ +#define UREG( type, nr ) (((type)<< UREG_TYPE_SHIFT) | \ + ((nr) << UREG_NR_SHIFT) | \ + (X << UREG_CHANNEL_X_SHIFT) | \ + (Y << UREG_CHANNEL_Y_SHIFT) | \ + (Z << UREG_CHANNEL_Z_SHIFT) | \ + (W << UREG_CHANNEL_W_SHIFT) | \ + (ZERO << UREG_CHANNEL_ZERO_SHIFT) | \ + (ONE << UREG_CHANNEL_ONE_SHIFT)) + +#define GET_CHANNEL_SRC( reg, channel ) ((reg<<(channel*4)) & (0xf<<20)) +#define CHANNEL_SRC( src, channel ) (src>>(channel*4)) + +#define GET_UREG_TYPE(reg) (((reg)>>UREG_TYPE_SHIFT)®_TYPE_MASK) +#define GET_UREG_NR(reg) (((reg)>>UREG_NR_SHIFT)®_NR_MASK) + + + +#define UREG_XYZW_CHANNEL_MASK 0x00ffff00 + +/* One neat thing about the UREG representation: + */ +static __inline int swizzle( int reg, int x, int y, int z, int w ) +{ + return ((reg & ~UREG_XYZW_CHANNEL_MASK) | + CHANNEL_SRC( GET_CHANNEL_SRC( reg, x ), 0 ) | + CHANNEL_SRC( GET_CHANNEL_SRC( reg, y ), 1 ) | + CHANNEL_SRC( GET_CHANNEL_SRC( reg, z ), 2 ) | + CHANNEL_SRC( GET_CHANNEL_SRC( reg, w ), 3 )); +} + +/* Another neat thing about the UREG representation: + */ +static __inline int negate( int reg, int x, int y, int z, int w ) +{ + return reg ^ (((x&1)<= 0.0) ? src1 : src2 */ +#define A0_MIN (0xe<<24) /* dst = (src0 < src1) ? src0 : src1 */ +#define A0_MAX (0xf<<24) /* dst = (src0 >= src1) ? src0 : src1 */ +#define A0_FLR (0x10<<24) /* dst = floor(src0) */ +#define A0_MOD (0x11<<24) /* dst = src0 fmod 1.0 */ +#define A0_TRC (0x12<<24) /* dst = int(src0) */ +#define A0_SGE (0x13<<24) /* dst = src0 >= src1 ? 1.0 : 0.0 */ +#define A0_SLT (0x14<<24) /* dst = src0 < src1 ? 1.0 : 0.0 */ +#define A0_DEST_SATURATE (1<<22) +#define A0_DEST_TYPE_SHIFT 19 +/* Allow: R, OC, OD, U */ +#define A0_DEST_NR_SHIFT 14 +/* Allow R: 0..15, OC,OD: 0..0, U: 0..2 */ +#define A0_DEST_CHANNEL_X (1<<10) +#define A0_DEST_CHANNEL_Y (2<<10) +#define A0_DEST_CHANNEL_Z (4<<10) +#define A0_DEST_CHANNEL_W (8<<10) +#define A0_DEST_CHANNEL_ALL (0xf<<10) +#define A0_DEST_CHANNEL_SHIFT 10 +#define A0_SRC0_TYPE_SHIFT 7 +#define A0_SRC0_NR_SHIFT 2 + +#define A0_DEST_CHANNEL_XY (A0_DEST_CHANNEL_X|A0_DEST_CHANNEL_Y) +#define A0_DEST_CHANNEL_XYZ (A0_DEST_CHANNEL_XY|A0_DEST_CHANNEL_Z) + + +#define SRC_X 0 +#define SRC_Y 1 +#define SRC_Z 2 +#define SRC_W 3 +#define SRC_ZERO 4 +#define SRC_ONE 5 + +#define A1_SRC0_CHANNEL_X_NEGATE (1<<31) +#define A1_SRC0_CHANNEL_X_SHIFT 28 +#define A1_SRC0_CHANNEL_Y_NEGATE (1<<27) +#define A1_SRC0_CHANNEL_Y_SHIFT 24 +#define A1_SRC0_CHANNEL_Z_NEGATE (1<<23) +#define A1_SRC0_CHANNEL_Z_SHIFT 20 +#define A1_SRC0_CHANNEL_W_NEGATE (1<<19) +#define A1_SRC0_CHANNEL_W_SHIFT 16 +#define A1_SRC1_TYPE_SHIFT 13 +#define A1_SRC1_NR_SHIFT 8 +#define A1_SRC1_CHANNEL_X_NEGATE (1<<7) +#define A1_SRC1_CHANNEL_X_SHIFT 4 +#define A1_SRC1_CHANNEL_Y_NEGATE (1<<3) +#define A1_SRC1_CHANNEL_Y_SHIFT 0 + +#define A2_SRC1_CHANNEL_Z_NEGATE (1<<31) +#define A2_SRC1_CHANNEL_Z_SHIFT 28 +#define A2_SRC1_CHANNEL_W_NEGATE (1<<27) +#define A2_SRC1_CHANNEL_W_SHIFT 24 +#define A2_SRC2_TYPE_SHIFT 21 +#define A2_SRC2_NR_SHIFT 16 +#define A2_SRC2_CHANNEL_X_NEGATE (1<<15) +#define A2_SRC2_CHANNEL_X_SHIFT 12 +#define A2_SRC2_CHANNEL_Y_NEGATE (1<<11) +#define A2_SRC2_CHANNEL_Y_SHIFT 8 +#define A2_SRC2_CHANNEL_Z_NEGATE (1<<7) +#define A2_SRC2_CHANNEL_Z_SHIFT 4 +#define A2_SRC2_CHANNEL_W_NEGATE (1<<3) +#define A2_SRC2_CHANNEL_W_SHIFT 0 + + + +/* Texture instructions */ +#define T0_TEXLD (0x15<<24) /* Sample texture using predeclared + * sampler and address, and output + * filtered texel data to destination + * register */ +#define T0_TEXLDP (0x16<<24) /* Same as texld but performs a + * perspective divide of the texture + * coordinate .xyz values by .w before + * sampling. */ +#define T0_TEXLDB (0x17<<24) /* Same as texld but biases the + * computed LOD by w. Only S4.6 two's + * comp is used. This implies that a + * float to fixed conversion is + * done. */ +#define T0_TEXKILL (0x18<<24) /* Does not perform a sampling + * operation. Simply kills the pixel + * if any channel of the address + * register is < 0.0. */ +#define T0_DEST_TYPE_SHIFT 19 +/* Allow: R, OC, OD, U */ +/* Note: U (unpreserved) regs do not retain their values between + * phases (cannot be used for feedback) + * + * Note: oC and OD registers can only be used as the destination of a + * texture instruction once per phase (this is an implementation + * restriction). + */ +#define T0_DEST_NR_SHIFT 14 +/* Allow R: 0..15, OC,OD: 0..0, U: 0..2 */ +#define T0_SAMPLER_NR_SHIFT 0 /* This field ignored for TEXKILL */ +#define T0_SAMPLER_NR_MASK (0xf<<0) + +#define T1_ADDRESS_REG_TYPE_SHIFT 24 /* Reg to use as texture coord */ +/* Allow R, T, OC, OD -- R, OC, OD are 'dependent' reads, new program phase */ +#define T1_ADDRESS_REG_NR_SHIFT 17 +#define T2_MBZ 0 + +/* Declaration instructions */ +#define D0_DCL (0x19<<24) /* Declare a t (interpolated attrib) + * register or an s (sampler) + * register. */ +#define D0_SAMPLE_TYPE_SHIFT 22 +#define D0_SAMPLE_TYPE_2D (0x0<<22) +#define D0_SAMPLE_TYPE_CUBE (0x1<<22) +#define D0_SAMPLE_TYPE_VOLUME (0x2<<22) +#define D0_SAMPLE_TYPE_MASK (0x3<<22) + +#define D0_TYPE_SHIFT 19 +/* Allow: T, S */ +#define D0_NR_SHIFT 14 +/* Allow T: 0..10, S: 0..15 */ +#define D0_CHANNEL_X (1<<10) +#define D0_CHANNEL_Y (2<<10) +#define D0_CHANNEL_Z (4<<10) +#define D0_CHANNEL_W (8<<10) +#define D0_CHANNEL_ALL (0xf<<10) +#define D0_CHANNEL_NONE (0<<10) + +#define D0_CHANNEL_XY (D0_CHANNEL_X|D0_CHANNEL_Y) +#define D0_CHANNEL_XYZ (D0_CHANNEL_XY|D0_CHANNEL_Z) + +/* I915 Errata: Do not allow (xz), (xw), (xzw) combinations for diffuse + * or specular declarations. + * + * For T dcls, only allow: (x), (xy), (xyz), (w), (xyzw) + * + * Must be zero for S (sampler) dcls + */ +#define D1_MBZ 0 +#define D2_MBZ 0 + + + +/* p207 */ +#define _3DSTATE_MAP_STATE (CMD_3D|(0x1d<<24)|(0x0<<16)) + +#define MS1_MAPMASK_SHIFT 0 +#define MS1_MAPMASK_MASK (0x8fff<<0) + +#define MS2_UNTRUSTED_SURFACE (1<<31) +#define MS2_ADDRESS_MASK 0xfffffffc +#define MS2_VERTICAL_LINE_STRIDE (1<<1) +#define MS2_VERTICAL_OFFSET (1<<1) + +#define MS3_HEIGHT_SHIFT 21 +#define MS3_WIDTH_SHIFT 10 +#define MS3_PALETTE_SELECT (1<<9) +#define MS3_MAPSURF_FORMAT_SHIFT 7 +#define MS3_MAPSURF_FORMAT_MASK (0x7<<7) +#define MAPSURF_8BIT (1<<7) +#define MAPSURF_16BIT (2<<7) +#define MAPSURF_32BIT (3<<7) +#define MAPSURF_422 (5<<7) +#define MAPSURF_COMPRESSED (6<<7) +#define MAPSURF_4BIT_INDEXED (7<<7) +#define MS3_MT_FORMAT_MASK (0x7 << 3) +#define MS3_MT_FORMAT_SHIFT 3 +#define MT_4BIT_IDX_ARGB8888 (7<<3) /* SURFACE_4BIT_INDEXED */ +#define MT_8BIT_I8 (0<<3) /* SURFACE_8BIT */ +#define MT_8BIT_L8 (1<<3) +#define MT_8BIT_A8 (4<<3) +#define MT_8BIT_MONO8 (5<<3) +#define MT_16BIT_RGB565 (0<<3) /* SURFACE_16BIT */ +#define MT_16BIT_ARGB1555 (1<<3) +#define MT_16BIT_ARGB4444 (2<<3) +#define MT_16BIT_AY88 (3<<3) +#define MT_16BIT_88DVDU (5<<3) +#define MT_16BIT_BUMP_655LDVDU (6<<3) +#define MT_16BIT_I16 (7<<3) +#define MT_16BIT_L16 (8<<3) +#define MT_16BIT_A16 (9<<3) +#define MT_32BIT_ARGB8888 (0<<3) /* SURFACE_32BIT */ +#define MT_32BIT_ABGR8888 (1<<3) +#define MT_32BIT_XRGB8888 (2<<3) +#define MT_32BIT_XBGR8888 (3<<3) +#define MT_32BIT_QWVU8888 (4<<3) +#define MT_32BIT_AXVU8888 (5<<3) +#define MT_32BIT_LXVU8888 (6<<3) +#define MT_32BIT_XLVU8888 (7<<3) +#define MT_32BIT_ARGB2101010 (8<<3) +#define MT_32BIT_ABGR2101010 (9<<3) +#define MT_422_YCRCB_SWAPY (0<<3) /* SURFACE_422 */ +#define MT_422_YCRCB_NORMAL (1<<3) +#define MT_422_YCRCB_SWAPUV (2<<3) +#define MT_422_YCRCB_SWAPUVY (3<<3) +#define MT_COMPRESS_DXT1 (0<<3) /* SURFACE_COMPRESSED */ +#define MT_COMPRESS_DXT2_3 (1<<3) +#define MT_COMPRESS_DXT4_5 (2<<3) +#define MT_COMPRESS_FXT1 (3<<3) +#define MT_COMPRESS_DXT1_RGB (4<<3) +#define MS3_USE_FENCE_REGS (1<<2) +#define MS3_TILED_SURFACE (1<<1) +#define MS3_TILE_WALK (1<<0) + +#define MS4_PITCH_SHIFT 21 +#define MS4_CUBE_FACE_ENA_NEGX (1<<20) +#define MS4_CUBE_FACE_ENA_POSX (1<<19) +#define MS4_CUBE_FACE_ENA_NEGY (1<<18) +#define MS4_CUBE_FACE_ENA_POSY (1<<17) +#define MS4_CUBE_FACE_ENA_NEGZ (1<<16) +#define MS4_CUBE_FACE_ENA_POSZ (1<<15) +#define MS4_CUBE_FACE_ENA_MASK (0x3f<<15) +#define MS4_MAX_LOD_SHIFT 9 +#define MS4_MAX_LOD_MASK (0x3f<<9) +#define MS4_VOLUME_DEPTH_SHIFT 0 +#define MS4_VOLUME_DEPTH_MASK (0xff<<0) + +/* p244 */ +#define _3DSTATE_SAMPLER_STATE (CMD_3D|(0x1d<<24)|(0x1<<16)) + +#define SS1_MAPMASK_SHIFT 0 +#define SS1_MAPMASK_MASK (0x8fff<<0) + +#define SS2_REVERSE_GAMMA_ENABLE (1<<31) +#define SS2_PACKED_TO_PLANAR_ENABLE (1<<30) +#define SS2_COLORSPACE_CONVERSION (1<<29) +#define SS2_CHROMAKEY_SHIFT 27 +#define SS2_BASE_MIP_LEVEL_SHIFT 22 +#define SS2_BASE_MIP_LEVEL_MASK (0x1f<<22) +#define SS2_MIP_FILTER_SHIFT 20 +#define SS2_MIP_FILTER_MASK (0x3<<20) +#define MIPFILTER_NONE 0 +#define MIPFILTER_NEAREST 1 +#define MIPFILTER_LINEAR 3 +#define SS2_MAG_FILTER_SHIFT 17 +#define SS2_MAG_FILTER_MASK (0x7<<17) +#define FILTER_NEAREST 0 +#define FILTER_LINEAR 1 +#define FILTER_ANISOTROPIC 2 +#define FILTER_4X4_1 3 +#define FILTER_4X4_2 4 +#define FILTER_4X4_FLAT 5 +#define FILTER_6X5_MONO 6 /* XXX - check */ +#define SS2_MIN_FILTER_SHIFT 14 +#define SS2_MIN_FILTER_MASK (0x7<<14) +#define SS2_LOD_BIAS_SHIFT 5 +#define SS2_LOD_BIAS_ONE (0x10<<5) +#define SS2_LOD_BIAS_MASK (0x1ff<<5) +#define SS2_SHADOW_ENABLE (1<<4) +#define SS2_MAX_ANISO_MASK (1<<3) +#define SS2_MAX_ANISO_2 (0<<3) +#define SS2_MAX_ANISO_4 (1<<3) +#define SS2_SHADOW_FUNC_SHIFT 0 +#define SS2_SHADOW_FUNC_MASK (0x7<<0) +#define SHADOWOP_ALWAYS 0 +#define SHADOWOP_NEVER 1 +#define SHADOWOP_LESS 2 +#define SHADOWOP_EQUAL 3 +#define SHADOWOP_LEQUAL 4 +#define SHADOWOP_GREATER 5 +#define SHADOWOP_NOTEQUAL 6 +#define SHADOWOP_GEQUAL 7 + +#define SS3_MIN_LOD_SHIFT 24 +#define SS3_MIN_LOD_ONE (0x10<<24) +#define SS3_MIN_LOD_MASK (0xff<<24) +#define SS3_KILL_PIXEL_ENABLE (1<<17) +#define SS3_TCX_ADDR_MODE_SHIFT 12 +#define SS3_TCX_ADDR_MODE_MASK (0x7<<12) +#define TEXCOORDMODE_WRAP 0 +#define TEXCOORDMODE_MIRROR 1 +#define TEXCOORDMODE_CLAMP_EDGE 2 +#define TEXCOORDMODE_CUBE 3 +#define TEXCOORDMODE_CLAMP_BORDER 4 +#define TEXCOORDMODE_MIRROR_ONCE 5 +#define SS3_TCY_ADDR_MODE_SHIFT 9 +#define SS3_TCY_ADDR_MODE_MASK (0x7<<9) +#define SS3_TCZ_ADDR_MODE_SHIFT 6 +#define SS3_TCZ_ADDR_MODE_MASK (0x7<<6) +#define SS3_NORMALIZED_COORDS (1<<5) +#define SS3_TEXTUREMAP_INDEX_SHIFT 1 +#define SS3_TEXTUREMAP_INDEX_MASK (0xf<<1) +#define SS3_DEINTERLACER_ENABLE (1<<0) + +#define SS4_BORDER_COLOR_MASK (~0) + +/* 3DSTATE_SPAN_STIPPLE, p258 + */ +#define _3DSTATE_STIPPLE ((0x3<<29)|(0x1d<<24)|(0x83<<16)) +#define ST1_ENABLE (1<<16) +#define ST1_MASK (0xffff) + + +#define MI_FLUSH ((0<<29)|(4<<23)) +#define FLUSH_MAP_CACHE (1<<0) +#define FLUSH_RENDER_CACHE (1<<1) + + +#endif diff --git a/src/mesa/drivers/dri/i915/i915_state.c b/src/mesa/drivers/dri/i915/i915_state.c new file mode 100644 index 0000000..d6c3e90 --- /dev/null +++ b/src/mesa/drivers/dri/i915/i915_state.c @@ -0,0 +1,1073 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + + +#include "glheader.h" +#include "context.h" +#include "macros.h" +#include "enums.h" +#include "dd.h" +#include "tnl/tnl.h" +#include "tnl/t_context.h" + +#include "texmem.h" + +#include "intel_screen.h" +#include "intel_batchbuffer.h" + +#include "i915_context.h" +#include "i915_reg.h" + +static int translate_compare_func( GLenum func ) +{ + switch(func) { + case GL_NEVER: + return COMPAREFUNC_NEVER; + case GL_LESS: + return COMPAREFUNC_LESS; + case GL_LEQUAL: + return COMPAREFUNC_LEQUAL; + case GL_GREATER: + return COMPAREFUNC_GREATER; + case GL_GEQUAL: + return COMPAREFUNC_GEQUAL; + case GL_NOTEQUAL: + return COMPAREFUNC_NOTEQUAL; + case GL_EQUAL: + return COMPAREFUNC_EQUAL; + case GL_ALWAYS: + default: + return COMPAREFUNC_ALWAYS; + } +} + + +static void i915StencilFunc(GLcontext *ctx, GLenum func, GLint ref, + GLuint mask) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + int test = translate_compare_func( func ); + + mask = mask & 0xff; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s : func: %s, ref : 0x%x, mask: 0x%x\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(func), ref, mask); + + + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + i915->state.Ctx[I915_CTXREG_STATE4] &= ~MODE4_ENABLE_STENCIL_TEST_MASK; + i915->state.Ctx[I915_CTXREG_STATE4] |= (ENABLE_STENCIL_TEST_MASK | + STENCIL_TEST_MASK(mask)); + + i915->state.Ctx[I915_CTXREG_LIS5] &= ~(S5_STENCIL_REF_MASK | + S5_STENCIL_TEST_FUNC_MASK); + + i915->state.Ctx[I915_CTXREG_LIS5] |= ((ref << S5_STENCIL_REF_SHIFT) | + (test << S5_STENCIL_TEST_FUNC_SHIFT)); +} + +static void i915StencilMask(GLcontext *ctx, GLuint mask) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s : mask 0x%x\n", __FUNCTION__, mask); + + mask = mask & 0xff; + + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + i915->state.Ctx[I915_CTXREG_STATE4] &= ~MODE4_ENABLE_STENCIL_WRITE_MASK; + i915->state.Ctx[I915_CTXREG_STATE4] |= (ENABLE_STENCIL_WRITE_MASK | + STENCIL_WRITE_MASK(mask)); +} + +static int translate_stencil_op( GLenum op ) +{ + switch(op) { + case GL_KEEP: + return STENCILOP_KEEP; + case GL_ZERO: + return STENCILOP_ZERO; + case GL_REPLACE: + return STENCILOP_REPLACE; + case GL_INCR: + return STENCILOP_INCRSAT; + case GL_DECR: + return STENCILOP_DECRSAT; + case GL_INCR_WRAP: + return STENCILOP_INCR; + case GL_DECR_WRAP: + return STENCILOP_DECR; + case GL_INVERT: + return STENCILOP_INVERT; + default: + return 0; + } +} + +static void i915StencilOp(GLcontext *ctx, GLenum fail, GLenum zfail, + GLenum zpass) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + int fop = translate_stencil_op(fail); + int dfop = translate_stencil_op(zfail); + int dpop = translate_stencil_op(zpass); + + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s: fail : %s, zfail: %s, zpass : %s\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(fail), + _mesa_lookup_enum_by_nr(zfail), + _mesa_lookup_enum_by_nr(zpass)); + + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + + i915->state.Ctx[I915_CTXREG_LIS5] &= ~(S5_STENCIL_FAIL_MASK | + S5_STENCIL_PASS_Z_FAIL_MASK | + S5_STENCIL_PASS_Z_PASS_MASK); + + i915->state.Ctx[I915_CTXREG_LIS5] |= ((fop << S5_STENCIL_FAIL_SHIFT) | + (dfop << S5_STENCIL_PASS_Z_FAIL_SHIFT) | + (dpop << S5_STENCIL_PASS_Z_PASS_SHIFT)); +} + +static void i915AlphaFunc(GLcontext *ctx, GLenum func, GLfloat ref) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + int test = translate_compare_func( func ); + GLubyte refByte; + + UNCLAMPED_FLOAT_TO_UBYTE(refByte, ref); + + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + i915->state.Ctx[I915_CTXREG_LIS6] &= ~(S6_ALPHA_TEST_FUNC_MASK | + S6_ALPHA_REF_MASK); + i915->state.Ctx[I915_CTXREG_LIS6] |= ((test << S6_ALPHA_TEST_FUNC_SHIFT) | + (((GLuint)refByte) << S6_ALPHA_REF_SHIFT)); +} + +/* This function makes sure that the proper enables are + * set for LogicOp, Independant Alpha Blend, and Blending. + * It needs to be called from numerous places where we + * could change the LogicOp or Independant Alpha Blend without subsequent + * calls to glEnable. + */ +static void i915EvalLogicOpBlendState(GLcontext *ctx) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + + if (ctx->Color._LogicOpEnabled) { + i915->state.Ctx[I915_CTXREG_LIS5] |= S5_LOGICOP_ENABLE; + i915->state.Ctx[I915_CTXREG_LIS6] &= ~S6_CBUF_BLEND_ENABLE; + } else { + i915->state.Ctx[I915_CTXREG_LIS5] &= ~S5_LOGICOP_ENABLE; + + if (ctx->Color.BlendEnabled) { + i915->state.Ctx[I915_CTXREG_LIS6] |= S6_CBUF_BLEND_ENABLE; + } else { + i915->state.Ctx[I915_CTXREG_LIS6] &= ~S6_CBUF_BLEND_ENABLE; + } + } +} + +static void i915BlendColor(GLcontext *ctx, const GLfloat color[4]) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + GLubyte r, g, b, a; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + UNCLAMPED_FLOAT_TO_UBYTE(r, color[RCOMP]); + UNCLAMPED_FLOAT_TO_UBYTE(g, color[GCOMP]); + UNCLAMPED_FLOAT_TO_UBYTE(b, color[BCOMP]); + UNCLAMPED_FLOAT_TO_UBYTE(a, color[ACOMP]); + + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + i915->state.Ctx[I915_CTXREG_BLENDCOLOR1] = (a<<24) | (r<<16) | (g<<8) | b; +} + +static int translate_blend_factor( GLenum factor ) +{ + switch(factor) { + case GL_ZERO: + return BLENDFACT_ZERO; + case GL_SRC_ALPHA: + return BLENDFACT_SRC_ALPHA; + case GL_ONE: + return BLENDFACT_ONE; + case GL_SRC_COLOR: + return BLENDFACT_SRC_COLR; + case GL_ONE_MINUS_SRC_COLOR: + return BLENDFACT_INV_SRC_COLR; + case GL_DST_COLOR: + return BLENDFACT_DST_COLR; + case GL_ONE_MINUS_DST_COLOR: + return BLENDFACT_INV_DST_COLR; + case GL_ONE_MINUS_SRC_ALPHA: + return BLENDFACT_INV_SRC_ALPHA; + case GL_DST_ALPHA: + return BLENDFACT_DST_ALPHA; + case GL_ONE_MINUS_DST_ALPHA: + return BLENDFACT_INV_DST_ALPHA; + case GL_SRC_ALPHA_SATURATE: + return BLENDFACT_SRC_ALPHA_SATURATE; + case GL_CONSTANT_COLOR: + return BLENDFACT_CONST_COLOR; + case GL_ONE_MINUS_CONSTANT_COLOR: + return BLENDFACT_INV_CONST_COLOR; + case GL_CONSTANT_ALPHA: + return BLENDFACT_CONST_ALPHA; + case GL_ONE_MINUS_CONSTANT_ALPHA: + return BLENDFACT_INV_CONST_ALPHA; + default: + return BLENDFACT_ZERO; + } +} + +#define DST_BLND_FACT(f) ((f)<state.Ctx[I915_CTXREG_IAB] & + ~(IAB_SRC_FACTOR_MASK | + IAB_DST_FACTOR_MASK | + (BLENDFUNC_MASK << IAB_FUNC_SHIFT) | + IAB_ENABLE)); + + GLuint lis6 = (i915->state.Ctx[I915_CTXREG_LIS6] & + ~(S6_CBUF_SRC_BLEND_FACT_MASK | + S6_CBUF_DST_BLEND_FACT_MASK | + S6_CBUF_BLEND_FUNC_MASK)); + + GLuint eqRGB = ctx->Color.BlendEquationRGB; + GLuint eqA = ctx->Color.BlendEquationA; + GLuint srcRGB = ctx->Color.BlendSrcRGB; + GLuint dstRGB = ctx->Color.BlendDstRGB; + GLuint srcA = ctx->Color.BlendSrcA; + GLuint dstA = ctx->Color.BlendDstA; + + if (eqRGB == GL_MIN || eqRGB == GL_MAX) { + srcRGB = dstRGB = GL_ONE; + } + + if (eqA == GL_MIN || eqA == GL_MAX) { + srcA = dstA = GL_ONE; + } + + lis6 |= SRC_BLND_FACT(translate_blend_factor(srcRGB)); + lis6 |= DST_BLND_FACT(translate_blend_factor(dstRGB)); + lis6 |= translate_blend_equation( eqRGB ) << S6_CBUF_BLEND_FUNC_SHIFT; + + iab |= SRC_ABLND_FACT(translate_blend_factor(srcA)); + iab |= DST_ABLND_FACT(translate_blend_factor(dstA)); + iab |= translate_blend_equation( eqA ) << IAB_FUNC_SHIFT; + + if (srcA != srcRGB || dstA != dstRGB || eqA != eqRGB) + iab |= IAB_ENABLE; + + if (iab != i915->state.Ctx[I915_CTXREG_IAB] || + lis6 != i915->state.Ctx[I915_CTXREG_LIS6]) { + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + i915->state.Ctx[I915_CTXREG_IAB] = iab; + i915->state.Ctx[I915_CTXREG_LIS6] = lis6; + } + + /* This will catch a logicop blend equation */ + i915EvalLogicOpBlendState(ctx); +} + + +static void i915BlendFuncSeparate(GLcontext *ctx, GLenum srcRGB, + GLenum dstRGB, GLenum srcA, + GLenum dstA ) +{ + i915UpdateBlendState( ctx ); +} + + +static void i915BlendEquationSeparate(GLcontext *ctx, GLenum eqRGB, + GLenum eqA) +{ + i915UpdateBlendState( ctx ); +} + + +static void i915DepthFunc(GLcontext *ctx, GLenum func) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + int test = translate_compare_func( func ); + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + i915->state.Ctx[I915_CTXREG_LIS6] &= ~S6_DEPTH_TEST_FUNC_MASK; + i915->state.Ctx[I915_CTXREG_LIS6] |= test << S6_DEPTH_TEST_FUNC_SHIFT; +} + +static void i915DepthMask(GLcontext *ctx, GLboolean flag) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s flag (%d)\n", __FUNCTION__, flag); + + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + + if (flag && ctx->Depth.Test) + i915->state.Ctx[I915_CTXREG_LIS6] |= S6_DEPTH_WRITE_ENABLE; + else + i915->state.Ctx[I915_CTXREG_LIS6] &= ~S6_DEPTH_WRITE_ENABLE; +} + +/* ============================================================= + * Polygon stipple + * + * The i915 supports a 4x4 stipple natively, GL wants 32x32. + * Fortunately stipple is usually a repeating pattern. + */ +static void i915PolygonStipple( GLcontext *ctx, const GLubyte *mask ) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + const GLubyte *m = mask; + GLubyte p[4]; + int i,j,k; + int active = (ctx->Polygon.StippleFlag && + i915->intel.reduced_primitive == GL_TRIANGLES); + GLuint newMask; + + if (active) { + I915_STATECHANGE(i915, I915_UPLOAD_STIPPLE); + i915->state.Stipple[I915_STPREG_ST1] &= ~ST1_ENABLE; + } + + p[0] = mask[12] & 0xf; p[0] |= p[0] << 4; + p[1] = mask[8] & 0xf; p[1] |= p[1] << 4; + p[2] = mask[4] & 0xf; p[2] |= p[2] << 4; + p[3] = mask[0] & 0xf; p[3] |= p[3] << 4; + + for (k = 0 ; k < 8 ; k++) + for (j = 3 ; j >= 0; j--) + for (i = 0 ; i < 4 ; i++, m++) + if (*m != p[j]) { + i915->intel.hw_stipple = 0; + return; + } + + newMask = (((p[0] & 0xf) << 0) | + ((p[1] & 0xf) << 4) | + ((p[2] & 0xf) << 8) | + ((p[3] & 0xf) << 12)); + + + if (newMask == 0xffff || newMask == 0x0) { + /* this is needed to make conform pass */ + i915->intel.hw_stipple = 0; + return; + } + + i915->state.Stipple[I915_STPREG_ST1] &= ~0xffff; + i915->state.Stipple[I915_STPREG_ST1] |= newMask; + i915->intel.hw_stipple = 1; + + if (active) + i915->state.Stipple[I915_STPREG_ST1] |= ST1_ENABLE; +} + + +/* ============================================================= + * Hardware clipping + */ +static void i915Scissor(GLcontext *ctx, GLint x, GLint y, + GLsizei w, GLsizei h) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + intelScreenPrivate *screen = i915->intel.intelScreen; + int x1, y1, x2, y2; + + if (!i915->intel.driDrawable) + return; + + x1 = x; + y1 = i915->intel.driDrawable->h - (y + h); + x2 = x + w - 1; + y2 = y1 + h - 1; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "[%s] x(%d) y(%d) w(%d) h(%d)\n", __FUNCTION__, + x, y, w, h); + + if (x1 < 0) x1 = 0; + if (y1 < 0) y1 = 0; + if (x2 < 0) x2 = 0; + if (y2 < 0) y2 = 0; + + if (x2 >= screen->width) x2 = screen->width-1; + if (y2 >= screen->height) y2 = screen->height-1; + if (x1 >= screen->width) x1 = screen->width-1; + if (y1 >= screen->height) y1 = screen->height-1; + + + I915_STATECHANGE(i915, I915_UPLOAD_BUFFERS); + i915->state.Buffer[I915_DESTREG_SR1] = (y1 << 16) | (x1 & 0xffff); + i915->state.Buffer[I915_DESTREG_SR2] = (y2 << 16) | (x2 & 0xffff); +} + +static void i915LogicOp(GLcontext *ctx, GLenum opcode) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + int tmp = 0; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + switch(opcode) { + case GL_CLEAR: + tmp = LOGICOP_CLEAR; + break; + case GL_AND: + tmp = LOGICOP_AND; + break; + case GL_AND_REVERSE: + tmp = LOGICOP_AND_RVRSE; + break; + case GL_COPY: + tmp = LOGICOP_COPY; + break; + case GL_COPY_INVERTED: + tmp = LOGICOP_COPY_INV; + break; + case GL_AND_INVERTED: + tmp = LOGICOP_AND_INV; + break; + case GL_NOOP: + tmp = LOGICOP_NOOP; + break; + case GL_XOR: + tmp = LOGICOP_XOR; + break; + case GL_OR: + tmp = LOGICOP_OR; + break; + case GL_OR_INVERTED: + tmp = LOGICOP_OR_INV; + break; + case GL_NOR: + tmp = LOGICOP_NOR; + break; + case GL_EQUIV: + tmp = LOGICOP_EQUIV; + break; + case GL_INVERT: + tmp = LOGICOP_INV; + break; + case GL_OR_REVERSE: + tmp = LOGICOP_OR_RVRSE; + break; + case GL_NAND: + tmp = LOGICOP_NAND; + break; + case GL_SET: + tmp = LOGICOP_SET; + break; + default: + return; + } + + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + i915->state.Ctx[I915_CTXREG_STATE4] &= ~LOGICOP_MASK; + i915->state.Ctx[I915_CTXREG_STATE4] |= LOGIC_OP_FUNC(tmp); +} + + + +static void i915CullFaceFrontFace(GLcontext *ctx, GLenum unused) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + GLuint mode; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + if (!ctx->Polygon.CullFlag) { + mode = S4_CULLMODE_NONE; + } + else if (ctx->Polygon.CullFaceMode != GL_FRONT_AND_BACK) { + mode = S4_CULLMODE_CW; + + if (ctx->Polygon.CullFaceMode == GL_FRONT) + mode ^= (S4_CULLMODE_CW ^ S4_CULLMODE_CCW); + if (ctx->Polygon.FrontFace != GL_CCW) + mode ^= (S4_CULLMODE_CW ^ S4_CULLMODE_CCW); + } + else { + mode = S4_CULLMODE_BOTH; + } + + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + i915->state.Ctx[I915_CTXREG_LIS4] &= ~S4_CULLMODE_MASK; + i915->state.Ctx[I915_CTXREG_LIS4] |= mode; +} + +static void i915LineWidth( GLcontext *ctx, GLfloat widthf ) +{ + i915ContextPtr i915 = I915_CONTEXT( ctx ); + int lis4 = i915->state.Ctx[I915_CTXREG_LIS4] & ~S4_LINE_WIDTH_MASK; + int width; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + width = (int)(widthf * 2); + CLAMP_SELF(width, 1, 0xf); + lis4 |= width << S4_LINE_WIDTH_SHIFT; + + if (lis4 != i915->state.Ctx[I915_CTXREG_LIS4]) { + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + i915->state.Ctx[I915_CTXREG_LIS4] = lis4; + } +} + +static void i915PointSize(GLcontext *ctx, GLfloat size) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + int lis4 = i915->state.Ctx[I915_CTXREG_LIS4] & ~S4_POINT_WIDTH_MASK; + GLint point_size = (int)size; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + CLAMP_SELF(point_size, 1, 255); + lis4 |= point_size << S4_POINT_WIDTH_SHIFT; + + if (lis4 != i915->state.Ctx[I915_CTXREG_LIS4]) { + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + i915->state.Ctx[I915_CTXREG_LIS4] = lis4; + } +} + + +/* ============================================================= + * Color masks + */ + +static void i915ColorMask(GLcontext *ctx, + GLboolean r, GLboolean g, + GLboolean b, GLboolean a) +{ + i915ContextPtr i915 = I915_CONTEXT( ctx ); + GLuint tmp = i915->state.Ctx[I915_CTXREG_LIS5] & ~S5_WRITEDISABLE_MASK; + + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s r(%d) g(%d) b(%d) a(%d)\n", __FUNCTION__, r, g, b, a); + + if (!r) tmp |= S5_WRITEDISABLE_RED; + if (!g) tmp |= S5_WRITEDISABLE_GREEN; + if (!b) tmp |= S5_WRITEDISABLE_BLUE; + if (!a) tmp |= S5_WRITEDISABLE_ALPHA; + + if (tmp != i915->state.Ctx[I915_CTXREG_LIS5]) { + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + i915->state.Ctx[I915_CTXREG_LIS5] = tmp; + } +} + +static void update_specular( GLcontext *ctx ) +{ + /* A hack to trigger the rebuild of the fragment program. + */ + INTEL_CONTEXT(ctx)->NewGLState |= _NEW_TEXTURE; + I915_CONTEXT(ctx)->tex_program.translated = 0; +} + +static void i915LightModelfv(GLcontext *ctx, GLenum pname, + const GLfloat *param) +{ + if (INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + if (pname == GL_LIGHT_MODEL_COLOR_CONTROL) { + update_specular( ctx ); + } +} + +static void i915ShadeModel(GLcontext *ctx, GLenum mode) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + + if (mode == GL_SMOOTH) { + i915->state.Ctx[I915_CTXREG_LIS4] &= ~(S4_FLATSHADE_ALPHA | + S4_FLATSHADE_COLOR | + S4_FLATSHADE_SPECULAR); + } else { + i915->state.Ctx[I915_CTXREG_LIS4] |= (S4_FLATSHADE_ALPHA | + S4_FLATSHADE_COLOR | + S4_FLATSHADE_SPECULAR); + } +} + +/* ============================================================= + * Fog + */ +static void update_fog( GLcontext *ctx ) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + GLenum mode; + GLboolean enabled; + GLboolean try_pixel_fog; + + if (ctx->FragmentProgram.Enabled && ctx->FragmentProgram.Current) { + /* Pull in static fog state from program */ + + mode = ctx->FragmentProgram.Current->FogOption; + enabled = (mode != GL_NONE); + try_pixel_fog = 1; + } + else { + enabled = ctx->Fog.Enabled; + mode = ctx->Fog.Mode; + + try_pixel_fog = (ctx->Fog.FogCoordinateSource == GL_FRAGMENT_DEPTH_EXT && + ctx->Hint.Fog == GL_NICEST && + 0); /* XXX - DISABLE -- Need ortho fallback */ + } + + if (!enabled) { + i915->vertex_fog = I915_FOG_NONE; + } + else if (try_pixel_fog) { + + I915_STATECHANGE(i915, I915_UPLOAD_FOG); + i915->state.Fog[I915_FOGREG_MODE1] &= ~FMC1_FOGFUNC_MASK; + i915->vertex_fog = I915_FOG_PIXEL; + + switch (mode) { + case GL_LINEAR: + if (ctx->Fog.End <= ctx->Fog.Start) { + /* XXX - this won't work with fragment programs. Need to + * either fallback or append fog instructions to end of + * program in the case of linear fog. + */ + i915->state.Fog[I915_FOGREG_MODE1] |= FMC1_FOGFUNC_VERTEX; + i915->vertex_fog = I915_FOG_VERTEX; + } + else { + GLfloat c1 = ctx->Fog.End/(ctx->Fog.End-ctx->Fog.Start); + GLfloat c2 = 1.0/(ctx->Fog.End-ctx->Fog.Start); + + i915->state.Fog[I915_FOGREG_MODE1] &= ~FMC1_C1_MASK; + i915->state.Fog[I915_FOGREG_MODE1] |= FMC1_FOGFUNC_PIXEL_LINEAR; + i915->state.Fog[I915_FOGREG_MODE1] |= + ((GLuint)(c1 * FMC1_C1_ONE)) & FMC1_C1_MASK; + + if (i915->state.Fog[I915_FOGREG_MODE1] & FMC1_FOGINDEX_Z) { + i915->state.Fog[I915_FOGREG_MODE2] = (GLuint)(c2 * FMC2_C2_ONE); + } + else { + union { float f; int i; } fi; + fi.f = c2; + i915->state.Fog[I915_FOGREG_MODE2] = fi.i; + } + } + break; + case GL_EXP: + i915->state.Fog[I915_FOGREG_MODE1] |= FMC1_FOGFUNC_PIXEL_EXP; + break; + case GL_EXP2: + i915->state.Fog[I915_FOGREG_MODE1] |= FMC1_FOGFUNC_PIXEL_EXP2; + break; + default: + break; + } + } + else /* if (i915->vertex_fog != I915_FOG_VERTEX) */ { + I915_STATECHANGE(i915, I915_UPLOAD_FOG); + i915->state.Fog[I915_FOGREG_MODE1] &= ~FMC1_FOGFUNC_MASK; + i915->state.Fog[I915_FOGREG_MODE1] |= FMC1_FOGFUNC_VERTEX; + i915->vertex_fog = I915_FOG_VERTEX; + } + + { + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + I915_ACTIVESTATE(i915, I915_UPLOAD_FOG, enabled); + if (enabled) + i915->state.Ctx[I915_CTXREG_LIS5] |= S5_FOG_ENABLE; + else + i915->state.Ctx[I915_CTXREG_LIS5] &= ~S5_FOG_ENABLE; + } + + if (enabled) { + _tnl_allow_vertex_fog( ctx, (i915->vertex_fog == I915_FOG_VERTEX) ); + _tnl_allow_pixel_fog( ctx, (i915->vertex_fog != I915_FOG_VERTEX) ); + } +} + +static void i915Fogfv(GLcontext *ctx, GLenum pname, const GLfloat *param) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + + switch (pname) { + case GL_FOG_COORDINATE_SOURCE_EXT: + case GL_FOG_MODE: + case GL_FOG_START: + case GL_FOG_END: + update_fog( ctx ); + break; + + case GL_FOG_DENSITY: + I915_STATECHANGE(i915, I915_UPLOAD_FOG); + + if (i915->state.Fog[I915_FOGREG_MODE1] & FMC1_FOGINDEX_Z) { + i915->state.Fog[I915_FOGREG_MODE3] = (GLuint)(ctx->Fog.Density * + FMC3_D_ONE); + } + else { + union { float f; int i; } fi; + fi.f = ctx->Fog.Density; + i915->state.Fog[I915_FOGREG_MODE3] = fi.i; + } + break; + + case GL_FOG_COLOR: + I915_STATECHANGE(i915, I915_UPLOAD_FOG); + i915->state.Fog[I915_FOGREG_COLOR] = + (_3DSTATE_FOG_COLOR_CMD | + ((GLubyte)(ctx->Fog.Color[0]*255.0F) << 16) | + ((GLubyte)(ctx->Fog.Color[1]*255.0F) << 8) | + ((GLubyte)(ctx->Fog.Color[2]*255.0F) << 0)); + break; + + default: + break; + } +} + +static void i915Hint(GLcontext *ctx, GLenum target, GLenum state) +{ + switch (target) { + case GL_FOG_HINT: + update_fog( ctx ); + break; + default: + break; + } +} + +/* ============================================================= + */ + +static void i915Enable(GLcontext *ctx, GLenum cap, GLboolean state) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + + switch(cap) { + case GL_TEXTURE_2D: + break; + + case GL_LIGHTING: + case GL_COLOR_SUM: + update_specular( ctx ); + break; + + case GL_ALPHA_TEST: + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + if (state) + i915->state.Ctx[I915_CTXREG_LIS6] |= S6_ALPHA_TEST_ENABLE; + else + i915->state.Ctx[I915_CTXREG_LIS6] &= ~S6_ALPHA_TEST_ENABLE; + break; + + case GL_BLEND: + i915EvalLogicOpBlendState(ctx); + break; + + case GL_COLOR_LOGIC_OP: + i915EvalLogicOpBlendState(ctx); + + /* Logicop doesn't seem to work at 16bpp: + */ + if (i915->intel.intelScreen->cpp == 2) + FALLBACK( &i915->intel, I915_FALLBACK_LOGICOP, state ); + break; + + case GL_FRAGMENT_PROGRAM_ARB: + update_fog( ctx ); + break; + + case GL_DITHER: + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + if (state) + i915->state.Ctx[I915_CTXREG_LIS5] |= S5_COLOR_DITHER_ENABLE; + else + i915->state.Ctx[I915_CTXREG_LIS5] &= ~S5_COLOR_DITHER_ENABLE; + break; + + case GL_DEPTH_TEST: + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + if (state) + i915->state.Ctx[I915_CTXREG_LIS6] |= S6_DEPTH_TEST_ENABLE; + else + i915->state.Ctx[I915_CTXREG_LIS6] &= ~S6_DEPTH_TEST_ENABLE; + + i915DepthMask( ctx, ctx->Depth.Mask ); + break; + + case GL_SCISSOR_TEST: + I915_STATECHANGE(i915, I915_UPLOAD_BUFFERS); + if (state) + i915->state.Buffer[I915_DESTREG_SENABLE] = (_3DSTATE_SCISSOR_ENABLE_CMD | + ENABLE_SCISSOR_RECT); + else + i915->state.Buffer[I915_DESTREG_SENABLE] = (_3DSTATE_SCISSOR_ENABLE_CMD | + DISABLE_SCISSOR_RECT); + break; + + case GL_LINE_SMOOTH: + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + if (state) + i915->state.Ctx[I915_CTXREG_LIS4] |= S4_LINE_ANTIALIAS_ENABLE; + else + i915->state.Ctx[I915_CTXREG_LIS4] &= ~S4_LINE_ANTIALIAS_ENABLE; + break; + + case GL_FOG: + update_fog( ctx ); + break; + + case GL_CULL_FACE: + i915CullFaceFrontFace(ctx, 0); + break; + + case GL_STENCIL_TEST: + if (i915->intel.hw_stencil) { + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + if (state) + i915->state.Ctx[I915_CTXREG_LIS5] |= (S5_STENCIL_TEST_ENABLE | + S5_STENCIL_WRITE_ENABLE); + else + i915->state.Ctx[I915_CTXREG_LIS5] &= ~(S5_STENCIL_TEST_ENABLE | + S5_STENCIL_WRITE_ENABLE); + } else { + FALLBACK( &i915->intel, I915_FALLBACK_STENCIL, state ); + } + break; + + case GL_POLYGON_STIPPLE: + /* The stipple command worked on my 855GM box, but not my 845G. + * I'll do more testing later to find out exactly which hardware + * supports it. Disabled for now. + */ + if (i915->intel.hw_stipple && + i915->intel.reduced_primitive == GL_TRIANGLES) + { + I915_STATECHANGE(i915, I915_UPLOAD_STIPPLE); + if (state) + i915->state.Stipple[I915_STPREG_ST1] |= ST1_ENABLE; + else + i915->state.Stipple[I915_STPREG_ST1] &= ~ST1_ENABLE; + } + break; + + default: + ; + } +} + + +static void i915_init_packets( i915ContextPtr i915 ) +{ + intelScreenPrivate *screen = i915->intel.intelScreen; + + /* Zero all state */ + memset(&i915->state, 0, sizeof(i915->state)); + + + { + I915_STATECHANGE(i915, I915_UPLOAD_CTX); + /* Probably don't want to upload all this stuff every time one + * piece changes. + */ + i915->state.Ctx[I915_CTXREG_LI] = (_3DSTATE_LOAD_STATE_IMMEDIATE_1 | + I1_LOAD_S(2) | + I1_LOAD_S(4) | + I1_LOAD_S(5) | + I1_LOAD_S(6) | + (4)); + i915->state.Ctx[I915_CTXREG_LIS2] = 0; + i915->state.Ctx[I915_CTXREG_LIS4] = 0; + i915->state.Ctx[I915_CTXREG_LIS5] = 0; + + if (screen->cpp == 2) + i915->state.Ctx[I915_CTXREG_LIS5] |= S5_COLOR_DITHER_ENABLE; + + + i915->state.Ctx[I915_CTXREG_LIS6] = (S6_COLOR_WRITE_ENABLE | + (2 << S6_TRISTRIP_PV_SHIFT)); + + i915->state.Ctx[I915_CTXREG_STATE4] = (_3DSTATE_MODES_4_CMD | + ENABLE_LOGIC_OP_FUNC | + LOGIC_OP_FUNC(LOGICOP_COPY) | + ENABLE_STENCIL_TEST_MASK | + STENCIL_TEST_MASK(0xff) | + ENABLE_STENCIL_WRITE_MASK | + STENCIL_WRITE_MASK(0xff)); + + + i915->state.Ctx[I915_CTXREG_IAB] = (_3DSTATE_INDEPENDENT_ALPHA_BLEND_CMD | + IAB_MODIFY_ENABLE | + IAB_MODIFY_FUNC | + IAB_MODIFY_SRC_FACTOR | + IAB_MODIFY_DST_FACTOR); + + i915->state.Ctx[I915_CTXREG_BLENDCOLOR0] = _3DSTATE_CONST_BLEND_COLOR_CMD; + i915->state.Ctx[I915_CTXREG_BLENDCOLOR1] = 0; + + } + + { + I915_STATECHANGE(i915, I915_UPLOAD_STIPPLE); + i915->state.Stipple[I915_STPREG_ST0] = _3DSTATE_STIPPLE; + } + + + { + I915_STATECHANGE(i915, I915_UPLOAD_FOG); + i915->state.Fog[I915_FOGREG_MODE0] = _3DSTATE_FOG_MODE_CMD; + i915->state.Fog[I915_FOGREG_MODE1] = (FMC1_FOGFUNC_MODIFY_ENABLE | + FMC1_FOGFUNC_VERTEX | + FMC1_FOGINDEX_MODIFY_ENABLE | + FMC1_FOGINDEX_W | + FMC1_C1_C2_MODIFY_ENABLE | + FMC1_DENSITY_MODIFY_ENABLE); + i915->state.Fog[I915_FOGREG_COLOR] = _3DSTATE_FOG_COLOR_CMD; + } + + + { + I915_STATECHANGE(i915, I915_UPLOAD_BUFFERS); + i915->state.Buffer[I915_DESTREG_CBUFADDR0] = _3DSTATE_BUF_INFO_CMD; + i915->state.Buffer[I915_DESTREG_CBUFADDR1] = + (BUF_3D_ID_COLOR_BACK | + BUF_3D_PITCH(screen->frontPitch * screen->cpp) | + BUF_3D_USE_FENCE); + + + i915->state.Buffer[I915_DESTREG_DBUFADDR0] = _3DSTATE_BUF_INFO_CMD; + i915->state.Buffer[I915_DESTREG_DBUFADDR1] = + (BUF_3D_ID_DEPTH | + BUF_3D_PITCH(screen->depthPitch * screen->cpp) | + BUF_3D_USE_FENCE); + i915->state.Buffer[I915_DESTREG_DBUFADDR2] = screen->depthOffset; + + + i915->state.Buffer[I915_DESTREG_DV0] = _3DSTATE_DST_BUF_VARS_CMD; + + switch (screen->fbFormat) { + case DV_PF_555: + case DV_PF_565: + i915->state.Buffer[I915_DESTREG_DV1] = (DSTORG_HORT_BIAS(0x8) | /* .5 */ + DSTORG_VERT_BIAS(0x8) | /* .5 */ + LOD_PRECLAMP_OGL | + TEX_DEFAULT_COLOR_OGL | + DITHER_FULL_ALWAYS | + screen->fbFormat | + DEPTH_FRMT_16_FIXED); + break; + case DV_PF_8888: + i915->state.Buffer[I915_DESTREG_DV1] = (DSTORG_HORT_BIAS(0x8) | /* .5 */ + DSTORG_VERT_BIAS(0x8) | /* .5 */ + LOD_PRECLAMP_OGL | + TEX_DEFAULT_COLOR_OGL | + screen->fbFormat | + DEPTH_FRMT_24_FIXED_8_OTHER); + break; + } + i915->state.Buffer[I915_DESTREG_SENABLE] = (_3DSTATE_SCISSOR_ENABLE_CMD | + DISABLE_SCISSOR_RECT); + i915->state.Buffer[I915_DESTREG_SR0] = _3DSTATE_SCISSOR_RECT_0_CMD; + i915->state.Buffer[I915_DESTREG_SR1] = 0; + i915->state.Buffer[I915_DESTREG_SR2] = 0; + } + + + /* These will be emitted every at the head of every buffer, unless + * we get hardware contexts working. + */ + i915->state.active = (I915_UPLOAD_PROGRAM | + I915_UPLOAD_STIPPLE | + I915_UPLOAD_CTX | + I915_UPLOAD_BUFFERS); +} + +void i915InitStateFunctions( struct dd_function_table *functions ) +{ + functions->AlphaFunc = i915AlphaFunc; + functions->BlendColor = i915BlendColor; + functions->BlendEquationSeparate = i915BlendEquationSeparate; + functions->BlendFuncSeparate = i915BlendFuncSeparate; + functions->ColorMask = i915ColorMask; + functions->CullFace = i915CullFaceFrontFace; + functions->DepthFunc = i915DepthFunc; + functions->DepthMask = i915DepthMask; + functions->Enable = i915Enable; + functions->Fogfv = i915Fogfv; + functions->FrontFace = i915CullFaceFrontFace; + functions->Hint = i915Hint; + functions->LightModelfv = i915LightModelfv; + functions->LineWidth = i915LineWidth; + functions->LogicOpcode = i915LogicOp; + functions->PointSize = i915PointSize; + functions->PolygonStipple = i915PolygonStipple; + functions->Scissor = i915Scissor; + functions->ShadeModel = i915ShadeModel; + functions->StencilFunc = i915StencilFunc; + functions->StencilMask = i915StencilMask; + functions->StencilOp = i915StencilOp; +} + + +void i915InitState( i915ContextPtr i915 ) +{ + GLcontext *ctx = &i915->intel.ctx; + + i915_init_packets( i915 ); + + intelInitState( ctx ); + + memcpy( &i915->initial, &i915->state, sizeof(i915->state) ); + i915->current = &i915->state; +} + + + + + + + diff --git a/src/mesa/drivers/dri/i915/i915_tex.c b/src/mesa/drivers/dri/i915/i915_tex.c new file mode 100644 index 0000000..8d37151 --- /dev/null +++ b/src/mesa/drivers/dri/i915/i915_tex.c @@ -0,0 +1,155 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "glheader.h" +#include "mtypes.h" +#include "imports.h" +#include "simple_list.h" +#include "enums.h" +#include "image.h" +#include "texstore.h" +#include "texformat.h" +#include "texmem.h" +#include "swrast/swrast.h" + +#include "mm.h" + +#include "intel_ioctl.h" + +#include "i915_context.h" +#include "i915_reg.h" + + + + + + +/** + * Allocate space for and load the mesa images into the texture memory block. + * This will happen before drawing with a new texture, or drawing with a + * texture after it was swapped out or teximaged again. + */ + +intelTextureObjectPtr i915AllocTexObj( struct gl_texture_object *texObj ) +{ + i915TextureObjectPtr t = CALLOC_STRUCT( i915_texture_object ); + if ( !t ) + return NULL; + + texObj->DriverData = t; + t->intel.base.tObj = texObj; + t->intel.dirty = I915_UPLOAD_TEX_ALL; + make_empty_list( &t->intel.base ); + return &t->intel; +} + + +static void i915TexParameter( GLcontext *ctx, GLenum target, + struct gl_texture_object *tObj, + GLenum pname, const GLfloat *params ) +{ + i915TextureObjectPtr t = (i915TextureObjectPtr) tObj->DriverData; + + switch (pname) { + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_MAG_FILTER: + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + case GL_TEXTURE_WRAP_R: + case GL_TEXTURE_BORDER_COLOR: + t->intel.dirty = I915_UPLOAD_TEX_ALL; + break; + + case GL_TEXTURE_BASE_LEVEL: + case GL_TEXTURE_MAX_LEVEL: + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + /* The i915 and its successors can do a lot of this without + * reloading the textures. A project for someone? + */ + intelFlush( ctx ); + driSwapOutTextureObject( (driTextureObject *) t ); + t->intel.dirty = I915_UPLOAD_TEX_ALL; + break; + + default: + return; + } +} + + +static void i915TexEnv( GLcontext *ctx, GLenum target, + GLenum pname, const GLfloat *param ) +{ + i915ContextPtr i915 = I915_CONTEXT( ctx ); + GLuint unit = ctx->Texture.CurrentUnit; + + switch (pname) { + case GL_TEXTURE_ENV_COLOR: /* Should be a tracked param */ + case GL_TEXTURE_ENV_MODE: + case GL_COMBINE_RGB: + case GL_COMBINE_ALPHA: + case GL_SOURCE0_RGB: + case GL_SOURCE1_RGB: + case GL_SOURCE2_RGB: + case GL_SOURCE0_ALPHA: + case GL_SOURCE1_ALPHA: + case GL_SOURCE2_ALPHA: + case GL_OPERAND0_RGB: + case GL_OPERAND1_RGB: + case GL_OPERAND2_RGB: + case GL_OPERAND0_ALPHA: + case GL_OPERAND1_ALPHA: + case GL_OPERAND2_ALPHA: + case GL_RGB_SCALE: + case GL_ALPHA_SCALE: + i915->tex_program.translated = 0; + break; + + case GL_TEXTURE_LOD_BIAS: { + int b = (int) ((*param) * 16.0); + if (b > 255) b = 255; + if (b < -256) b = -256; + I915_STATECHANGE(i915, I915_UPLOAD_TEX(unit)); + i915->state.Tex[unit][I915_TEXREG_SS2] &= ~SS2_LOD_BIAS_MASK; + i915->state.Tex[unit][I915_TEXREG_SS2] |= + ((b << SS2_LOD_BIAS_SHIFT) & SS2_LOD_BIAS_MASK); + break; + } + + default: + break; + } +} + + +static void i915BindTexture( GLcontext *ctx, GLenum target, + struct gl_texture_object *texObj ) +{ + i915TextureObjectPtr tex = (i915TextureObjectPtr)texObj->DriverData; + + if (tex->lastTarget != texObj->Target) { + tex->intel.dirty = I915_UPLOAD_TEX_ALL; + tex->lastTarget = texObj->Target; + } + + /* Need this if image format changes between bound textures. + * Could try and shortcircuit by checking for differences in + * state between incoming and outgoing textures: + */ + I915_CONTEXT(ctx)->tex_program.translated = 0; +} + + + +void i915InitTextureFuncs( struct dd_function_table *functions ) +{ + functions->BindTexture = i915BindTexture; + functions->TexEnv = i915TexEnv; + functions->TexParameter = i915TexParameter; +} diff --git a/src/mesa/drivers/dri/i915/i915_texprog.c b/src/mesa/drivers/dri/i915/i915_texprog.c new file mode 100644 index 0000000..33132df --- /dev/null +++ b/src/mesa/drivers/dri/i915/i915_texprog.c @@ -0,0 +1,635 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include + +#include "glheader.h" +#include "macros.h" +#include "enums.h" + +#include "tnl/t_context.h" +#include "intel_batchbuffer.h" + +#include "i915_reg.h" +#include "i915_context.h" +#include "i915_program.h" + +static GLuint translate_tex_src_bit( struct i915_fragment_program *p, + GLubyte bit ) +{ + switch (bit) { + case TEXTURE_1D_BIT: return D0_SAMPLE_TYPE_2D; + case TEXTURE_2D_BIT: return D0_SAMPLE_TYPE_2D; + case TEXTURE_RECT_BIT: return D0_SAMPLE_TYPE_2D; + case TEXTURE_3D_BIT: return D0_SAMPLE_TYPE_VOLUME; + case TEXTURE_CUBE_BIT: return D0_SAMPLE_TYPE_CUBE; + default: i915_program_error(p, "TexSrcBit"); return 0; + } +} + +static GLuint get_source( struct i915_fragment_program *p, + GLenum src, GLuint unit ) +{ + switch (src) { + case GL_TEXTURE: + if (p->src_texture == UREG_BAD) { + + /* TODO: Use D0_CHANNEL_XY where possible. + */ + GLuint dim = translate_tex_src_bit( p, p->ctx->Texture.Unit[unit]._ReallyEnabled); + GLuint sampler = i915_emit_decl(p, REG_TYPE_S, unit, dim); + GLuint texcoord = i915_emit_decl(p, REG_TYPE_T, unit, D0_CHANNEL_ALL); + GLuint tmp = i915_get_temp( p ); + GLuint op = T0_TEXLD; + + if (p->VB->TexCoordPtr[unit]->size == 4) + op = T0_TEXLDP; + + p->src_texture = i915_emit_texld( p, tmp, A0_DEST_CHANNEL_ALL, + sampler, texcoord, op ); + } + + return p->src_texture; + case GL_CONSTANT: + return i915_emit_const4fv( p, p->ctx->Texture.Unit[unit].EnvColor ); + case GL_PRIMARY_COLOR: + return i915_emit_decl(p, REG_TYPE_T, T_DIFFUSE, D0_CHANNEL_ALL); + case GL_PREVIOUS: + default: + i915_emit_decl(p, + GET_UREG_TYPE(p->src_previous), + GET_UREG_NR(p->src_previous), D0_CHANNEL_ALL); + return p->src_previous; + } +} + + +static GLuint emit_combine_source( struct i915_fragment_program *p, + GLuint mask, + GLuint unit, + GLenum source, + GLenum operand ) +{ + GLuint arg, src; + + src = get_source(p, source, unit); + + switch (operand) { + case GL_ONE_MINUS_SRC_COLOR: + /* Get unused tmp, + * Emit tmp = 1.0 + arg.-x-y-z-w + */ + arg = i915_get_temp( p ); + return i915_emit_arith( p, A0_ADD, arg, mask, 0, + swizzle(src, ONE, ONE, ONE, ONE ), + negate(src, 1,1,1,1), 0); + + case GL_SRC_ALPHA: + if (mask == A0_DEST_CHANNEL_W) + return src; + else + return swizzle( src, W, W, W, W ); + case GL_ONE_MINUS_SRC_ALPHA: + /* Get unused tmp, + * Emit tmp = 1.0 + arg.-w-w-w-w + */ + arg = i915_get_temp( p ); + return i915_emit_arith( p, A0_ADD, arg, mask, 0, + swizzle(src, ONE, ONE, ONE, ONE ), + negate( swizzle(src,W,W,W,W), 1,1,1,1), 0); + case GL_SRC_COLOR: + default: + return src; + } +} + + + +static int nr_args( GLenum mode ) +{ + switch (mode) { + case GL_REPLACE: return 1; + case GL_MODULATE: return 2; + case GL_ADD: return 2; + case GL_ADD_SIGNED: return 2; + case GL_INTERPOLATE: return 3; + case GL_SUBTRACT: return 2; + case GL_DOT3_RGB_EXT: return 2; + case GL_DOT3_RGBA_EXT: return 2; + case GL_DOT3_RGB: return 2; + case GL_DOT3_RGBA: return 2; + default: return 0; + } +} + + +static GLboolean args_match( struct gl_texture_unit *texUnit ) +{ + int i, nr = nr_args(texUnit->Combine.ModeRGB); + + for (i = 0 ; i < nr ; i++) { + if (texUnit->Combine.SourceA[i] != texUnit->Combine.SourceRGB[i]) + return GL_FALSE; + + switch(texUnit->Combine.OperandA[i]) { + case GL_SRC_ALPHA: + switch(texUnit->Combine.OperandRGB[i]) { + case GL_SRC_COLOR: + case GL_SRC_ALPHA: + break; + default: + return GL_FALSE; + } + break; + case GL_ONE_MINUS_SRC_ALPHA: + switch(texUnit->Combine.OperandRGB[i]) { + case GL_ONE_MINUS_SRC_COLOR: + case GL_ONE_MINUS_SRC_ALPHA: + break; + default: + return GL_FALSE; + } + break; + default: + return GL_FALSE; /* impossible */ + } + } + + return GL_TRUE; +} + + +static GLuint emit_combine( struct i915_fragment_program *p, + GLuint dest, + GLuint mask, + GLuint saturate, + GLuint unit, + GLenum mode, + const GLenum *source, + const GLenum *operand) +{ + int tmp, src[3], nr = nr_args(mode); + int i; + + for (i = 0; i < nr; i++) + src[i] = emit_combine_source( p, mask, unit, source[i], operand[i] ); + + switch (mode) { + case GL_REPLACE: + if (mask == A0_DEST_CHANNEL_ALL && !saturate) + return src[0]; + else + return i915_emit_arith( p, A0_MOV, dest, mask, saturate, src[0], 0, 0 ); + case GL_MODULATE: + return i915_emit_arith( p, A0_MUL, dest, mask, saturate, + src[0], src[1], 0 ); + case GL_ADD: + return i915_emit_arith( p, A0_ADD, dest, mask, saturate, + src[0], src[1], 0 ); + case GL_ADD_SIGNED: + /* tmp = arg0 + arg1 + * result = tmp + -.5 + */ + tmp = i915_emit_const1f(p, .5); + tmp = negate(swizzle(tmp,X,X,X,X),1,1,1,1); + i915_emit_arith( p, A0_ADD, dest, mask, 0, src[0], src[1], 0 ); + i915_emit_arith( p, A0_ADD, dest, mask, saturate, dest, tmp, 0 ); + return dest; + case GL_INTERPOLATE: /* TWO INSTRUCTIONS */ + /* Arg0 * (Arg2) + Arg1 * (1-Arg2) + * + * Arg0*Arg2 + Arg1 - Arg1Arg2 + * + * tmp = Arg0*Arg2 + Arg1, + * result = (-Arg1)Arg2 + tmp + */ + tmp = i915_get_temp( p ); + i915_emit_arith( p, A0_MAD, tmp, mask, 0, src[0], src[2], src[1] ); + i915_emit_arith( p, A0_MAD, dest, mask, saturate, + negate(src[1], 1,1,1,1), src[2], tmp ); + return dest; + case GL_SUBTRACT: + /* negate src[1] */ + return i915_emit_arith( p, A0_ADD, dest, mask, saturate, src[0], + negate(src[1],1,1,1,1), 0 ); + + case GL_DOT3_RGBA: + case GL_DOT3_RGBA_EXT: + case GL_DOT3_RGB_EXT: + case GL_DOT3_RGB: { + GLuint tmp0 = i915_get_temp( p ); + GLuint tmp1 = i915_get_temp( p ); + GLuint neg1 = negate(swizzle(i915_emit_const1f(p, 1),X,X,X,X), 1,1,1,1); + GLuint two = swizzle(i915_emit_const1f(p, 2),X,X,X,X); + i915_emit_arith( p, A0_MAD, tmp0, A0_DEST_CHANNEL_ALL, 0, + two, src[0], neg1); + if (src[0] == src[1]) + tmp1 = tmp0; + else + i915_emit_arith( p, A0_MAD, tmp1, A0_DEST_CHANNEL_ALL, 0, + two, src[1], neg1); + i915_emit_arith( p, A0_DP3, dest, mask, saturate, tmp0, tmp1, 0); + return dest; + } + + default: + return src[0]; + } +} + +static GLuint get_dest( struct i915_fragment_program *p, int unit ) +{ + if (p->ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) + return i915_get_temp( p ); + else if (unit != p->last_tex_stage) + return i915_get_temp( p ); + else + return UREG(REG_TYPE_OC, 0); +} + + + +static GLuint emit_texenv( struct i915_fragment_program *p, int unit ) +{ + struct gl_texture_unit *texUnit = &p->ctx->Texture.Unit[unit]; + GLenum envMode = texUnit->EnvMode; + struct gl_texture_object *tObj = texUnit->_Current; + GLenum format = tObj->Image[0][tObj->BaseLevel]->Format; + GLuint saturate = unit < p->last_tex_stage ? A0_DEST_SATURATE : 0; + + switch(envMode) { + case GL_BLEND: { + const int cf = get_source(p, GL_PREVIOUS, unit); + const int cc = get_source(p, GL_CONSTANT, unit); + const int cs = get_source(p, GL_TEXTURE, unit); + const int out = get_dest(p, unit); + + if (format == GL_INTENSITY) { + /* cv = cf(1 - cs) + cc.cs + * cv = cf - cf.cs + cc.cs + */ + /* u[2] = MAD( -cf * cs + cf ) + * cv = MAD( cc * cs + u[2] ) + */ + + i915_emit_arith( p, A0_MAD, out, A0_DEST_CHANNEL_ALL, 0, + negate(cf,1,1,1,1), cs, cf ); + + i915_emit_arith( p, A0_MAD, out, A0_DEST_CHANNEL_ALL, saturate, + cc, cs, out ); + + return out; + } else { + /* cv = cf(1 - cs) + cc.cs + * cv = cf - cf.cs + cc.cs + * av = af.as + */ + /* u[2] = MAD( cf.-x-y-zw * cs.xyzw + cf.xyz0 ) + * oC = MAD( cc.xyz0 * cs.xyz0 + u[2].xyzw ) + */ + i915_emit_arith( p, A0_MAD, out, A0_DEST_CHANNEL_ALL, 0, + negate(cf,1,1,1,0), + cs, + swizzle(cf,X,Y,Z,ZERO) ); + + + i915_emit_arith( p, A0_MAD, out, A0_DEST_CHANNEL_ALL, saturate, + swizzle(cc,X,Y,Z,ZERO), + swizzle(cs,X,Y,Z,ZERO), + out ); + + return out; + } + } + + case GL_DECAL: { + if (format == GL_RGB || + format == GL_RGBA) { + int cf = get_source( p, GL_PREVIOUS, unit ); + int cs = get_source( p, GL_TEXTURE, unit ); + int out = get_dest(p, unit); + + /* cv = cf(1-as) + cs.as + * cv = cf.(-as) + cf + cs.as + * av = af + */ + + /* u[2] = mad( cf.xyzw * cs.-w-w-w1 + cf.xyz0 ) + * oc = mad( cs.xyz0 * cs.www0 + u[2].xyzw ) + */ + i915_emit_arith( p, A0_MAD, out, A0_DEST_CHANNEL_ALL, 0, + cf, + negate(swizzle(cs,W,W,W,ONE),1,1,1,0), + swizzle(cf,X,Y,Z,ZERO) ); + + i915_emit_arith( p, A0_MAD, out, A0_DEST_CHANNEL_ALL, saturate, + swizzle(cs,X,Y,Z,ZERO), + swizzle(cs,W,W,W,ZERO), + out ); + return out; + } + else { + return get_source( p, GL_PREVIOUS, unit ); + } + } + + case GL_REPLACE: { + const int cs = get_source( p, GL_TEXTURE, unit ); /* saturated */ + switch (format) { + case GL_ALPHA: { + const int cf = get_source( p, GL_PREVIOUS, unit ); /* saturated */ + i915_emit_arith( p, A0_MOV, cs, A0_DEST_CHANNEL_XYZ, 0, cf, 0, 0 ); + return cs; + } + case GL_RGB: + case GL_LUMINANCE: { + const int cf = get_source( p, GL_PREVIOUS, unit ); /* saturated */ + i915_emit_arith( p, A0_MOV, cs, A0_DEST_CHANNEL_W, 0, cf, 0, 0 ); + return cs; + } + default: + return cs; + } + } + + case GL_MODULATE: { + const int cf = get_source( p, GL_PREVIOUS, unit ); + const int cs = get_source( p, GL_TEXTURE, unit ); + const int out = get_dest(p, unit); + switch (format) { + case GL_ALPHA: + i915_emit_arith( p, A0_MUL, out, A0_DEST_CHANNEL_ALL, saturate, + swizzle(cs, ONE, ONE, ONE, W), cf, 0 ); + break; + default: + i915_emit_arith( p, A0_MUL, out, A0_DEST_CHANNEL_ALL, saturate, + cs, cf, 0 ); + break; + } + return out; + } + case GL_ADD: { + int cf = get_source( p, GL_PREVIOUS, unit ); + int cs = get_source( p, GL_TEXTURE, unit ); + const int out = get_dest( p, unit ); + + if (format == GL_INTENSITY) { + /* output-color.rgba = add( incoming, u[1] ) + */ + i915_emit_arith( p, A0_ADD, out, A0_DEST_CHANNEL_ALL, saturate, + cs, cf, 0 ); + return out; + } + else { + /* cv.xyz = cf.xyz + cs.xyz + * cv.w = cf.w * cs.w + * + * cv.xyzw = MAD( cf.111w * cs.xyzw + cf.xyz0 ) + */ + i915_emit_arith( p, A0_MAD, out, A0_DEST_CHANNEL_ALL, saturate, + swizzle(cf,ONE,ONE,ONE,W), + cs, + swizzle(cf,X,Y,Z,ZERO) ); + return out; + } + break; + } + case GL_COMBINE: { + GLuint rgb_shift, alpha_shift, out, shift; + GLuint dest = get_dest(p, unit); + + /* The EXT version of the DOT3 extension does not support the + * scale factor, but the ARB version (and the version in OpenGL + * 1.3) does. + */ + switch (texUnit->Combine.ModeRGB) { + case GL_DOT3_RGB_EXT: + alpha_shift = texUnit->Combine.ScaleShiftA; + rgb_shift = 0; + break; + + case GL_DOT3_RGBA_EXT: + alpha_shift = 0; + rgb_shift = 0; + break; + + default: + rgb_shift = texUnit->Combine.ScaleShiftRGB; + alpha_shift = texUnit->Combine.ScaleShiftA; + break; + } + + + /* Emit the RGB and A combine ops + */ + if (texUnit->Combine.ModeRGB == texUnit->Combine.ModeA && + args_match( texUnit )) { + out = emit_combine( p, dest, A0_DEST_CHANNEL_ALL, saturate, + unit, + texUnit->Combine.ModeRGB, + texUnit->Combine.SourceRGB, + texUnit->Combine.OperandRGB ); + } + else if (texUnit->Combine.ModeRGB == GL_DOT3_RGBA_EXT || + texUnit->Combine.ModeRGB == GL_DOT3_RGBA) { + + out = emit_combine( p, dest, A0_DEST_CHANNEL_ALL, saturate, + unit, + texUnit->Combine.ModeRGB, + texUnit->Combine.SourceRGB, + texUnit->Combine.OperandRGB ); + } + else { + /* Need to do something to stop from re-emitting identical + * argument calculations here: + */ + out = emit_combine( p, dest, A0_DEST_CHANNEL_XYZ, saturate, + unit, + texUnit->Combine.ModeRGB, + texUnit->Combine.SourceRGB, + texUnit->Combine.OperandRGB ); + out = emit_combine( p, dest, A0_DEST_CHANNEL_W, saturate, + unit, + texUnit->Combine.ModeA, + texUnit->Combine.SourceA, + texUnit->Combine.OperandA ); + } + + /* Deal with the final shift: + */ + if (alpha_shift || rgb_shift) { + if (rgb_shift == alpha_shift) { + shift = i915_emit_const1f(p, 1<ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) { + /* Emit specular add. + */ + GLuint s = i915_emit_decl(p, REG_TYPE_T, T_SPECULAR, D0_CHANNEL_ALL); + i915_emit_arith( p, A0_ADD, out, A0_DEST_CHANNEL_ALL, 0, cf, + swizzle(s, X,Y,Z,ZERO), 0 ); + } + else if (cf != out) { + /* Will wind up in here if no texture enabled or a couple of + * other scenarios (GL_REPLACE for instance). + */ + i915_emit_arith( p, A0_MOV, out, A0_DEST_CHANNEL_ALL, 0, cf, 0, 0 ); + } +} + + +static void i915EmitTextureProgram( i915ContextPtr i915 ) +{ + GLcontext *ctx = &i915->intel.ctx; + struct i915_fragment_program *p = &i915->tex_program; + GLuint unit; + + if (0) fprintf(stderr, "%s\n", __FUNCTION__); + + i915_init_program( i915, p ); + + if (ctx->Texture._EnabledUnits) { + for (unit = 0 ; unit < ctx->Const.MaxTextureUnits ; unit++) + if (ctx->Texture.Unit[unit]._ReallyEnabled) { + p->last_tex_stage = unit; + } + + for (unit = 0 ; unit < ctx->Const.MaxTextureUnits; unit++) + if (ctx->Texture.Unit[unit]._ReallyEnabled) { + p->src_previous = emit_texenv( p, unit ); + p->src_texture = UREG_BAD; + p->temp_flag = 0xffff000; + p->temp_flag |= 1 << GET_UREG_NR(p->src_previous); + } + } + + emit_program_fini( p ); + + i915_fini_program( p ); + i915_upload_program( i915, p ); + + p->translated = 1; +} + + +void i915ValidateTextureProgram( i915ContextPtr i915 ) +{ + intelContextPtr intel = &i915->intel; + GLcontext *ctx = &intel->ctx; + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_buffer *VB = &tnl->vb; + GLuint index = tnl->render_inputs; + int i, offset; + GLuint s4 = i915->state.Ctx[I915_CTXREG_LIS4] & ~S4_VFMT_MASK; + GLuint s2 = S2_TEXCOORD_NONE; + + /* Important: + */ + VB->AttribPtr[VERT_ATTRIB_POS] = VB->NdcPtr; + intel->vertex_attr_count = 0; + intel->coloroffset = 0; + intel->specoffset = 0; + offset = 0; + + if (i915->vertex_fog == I915_FOG_PIXEL) { + EMIT_ATTR( _TNL_ATTRIB_POS, EMIT_4F_VIEWPORT, S4_VFMT_XYZW, 16 ); + index &= ~_TNL_BIT_FOG; + } + else if (index & _TNL_BITS_TEX_ANY) { + EMIT_ATTR( _TNL_ATTRIB_POS, EMIT_4F_VIEWPORT, S4_VFMT_XYZW, 16 ); + } + else { + EMIT_ATTR( _TNL_ATTRIB_POS, EMIT_3F_VIEWPORT, S4_VFMT_XYZ, 12 ); + } + + /* How undefined is undefined? */ + if (index & _TNL_BIT_POINTSIZE) { + EMIT_ATTR( _TNL_ATTRIB_POINTSIZE, EMIT_1F, S4_VFMT_POINT_WIDTH, 4 ); + } + + intel->coloroffset = offset / 4; + EMIT_ATTR( _TNL_ATTRIB_COLOR0, EMIT_4UB_4F_RGBA, S4_VFMT_COLOR, 4 ); + + if (index & (_TNL_BIT_COLOR1|_TNL_BIT_FOG)) { + if (index & _TNL_BIT_COLOR1) { + intel->specoffset = offset / 4; + EMIT_ATTR( _TNL_ATTRIB_COLOR1, EMIT_3UB_3F_RGB, S4_VFMT_SPEC_FOG, 3 ); + } else + EMIT_PAD( 3 ); + + if (index & _TNL_BIT_FOG) + EMIT_ATTR( _TNL_ATTRIB_FOG, EMIT_1UB_1F, S4_VFMT_SPEC_FOG, 1 ); + else + EMIT_PAD( 1 ); + } + + if (index & _TNL_BITS_TEX_ANY) { + for (i = 0; i < 8; i++) { + if (index & _TNL_BIT_TEX(i)) { + int sz = VB->TexCoordPtr[i]->size; + + s2 &= ~S2_TEXCOORD_FMT(i, S2_TEXCOORD_FMT0_MASK); + s2 |= S2_TEXCOORD_FMT(i, SZ_TO_HW(sz)); + + EMIT_ATTR( _TNL_ATTRIB_TEX0+i, EMIT_SZ(sz), 0, sz * 4 ); + } + } + } + + /* Only need to change the vertex emit code if there has been a + * statechange to a new hardware vertex format: + */ + if (s2 != i915->state.Ctx[I915_CTXREG_LIS2] || + s4 != i915->state.Ctx[I915_CTXREG_LIS4]) { + + I915_STATECHANGE( i915, I915_UPLOAD_CTX ); + + i915->tex_program.translated = 0; + + /* Must do this *after* statechange, so as not to affect + * buffered vertices reliant on the old state: + */ + intel->vertex_size = _tnl_install_attrs( ctx, + intel->vertex_attrs, + intel->vertex_attr_count, + intel->ViewportMatrix.m, 0 ); + + intel->vertex_size >>= 2; + + i915->state.Ctx[I915_CTXREG_LIS2] = s2; + i915->state.Ctx[I915_CTXREG_LIS4] = s4; + + assert(intel->vtbl.check_vertex_size( intel, intel->vertex_size )); + } + + if (!i915->tex_program.translated || + i915->last_ReallyEnabled != ctx->Texture._EnabledUnits) { + i915EmitTextureProgram( i915 ); + i915->last_ReallyEnabled = ctx->Texture._EnabledUnits; + } +} diff --git a/src/mesa/drivers/dri/i915/i915_texstate.c b/src/mesa/drivers/dri/i915/i915_texstate.c new file mode 100644 index 0000000..93656dd --- /dev/null +++ b/src/mesa/drivers/dri/i915/i915_texstate.c @@ -0,0 +1,625 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "glheader.h" +#include "macros.h" +#include "mtypes.h" +#include "simple_list.h" +#include "enums.h" +#include "texformat.h" +#include "texstore.h" + +#include "mm.h" + +#include "intel_screen.h" +#include "intel_ioctl.h" +#include "intel_tex.h" + +#include "i915_context.h" +#include "i915_reg.h" + +static GLint initial_offsets[6][2] = { {0,0}, + {0,2}, + {1,0}, + {1,2}, + {1,1}, + {1,3} }; + + +static GLint step_offsets[6][2] = { {0,2}, + {0,2}, + {-1,2}, + {-1,2}, + {-1,1}, + {-1,1} }; + + +#define I915_TEX_UNIT_ENABLED(unit) (1<DriverData; + const struct gl_texture_image *baseImage = tObj->Image[0][tObj->BaseLevel]; + GLint firstLevel, lastLevel, numLevels; + GLint ss2 = 0; + + switch( baseImage->TexFormat->MesaFormat ) { + case MESA_FORMAT_L8: + t->intel.texelBytes = 1; + textureFormat = MAPSURF_8BIT | MT_8BIT_L8; + break; + + case MESA_FORMAT_I8: + t->intel.texelBytes = 1; + textureFormat = MAPSURF_8BIT | MT_8BIT_I8; + break; + + case MESA_FORMAT_A8: + t->intel.texelBytes = 1; + textureFormat = MAPSURF_8BIT | MT_8BIT_A8; + break; + + case MESA_FORMAT_AL88: + t->intel.texelBytes = 2; + textureFormat = MAPSURF_16BIT | MT_16BIT_AY88; + break; + + case MESA_FORMAT_RGB565: + t->intel.texelBytes = 2; + textureFormat = MAPSURF_16BIT | MT_16BIT_RGB565; + break; + + case MESA_FORMAT_ARGB1555: + t->intel.texelBytes = 2; + textureFormat = MAPSURF_16BIT | MT_16BIT_ARGB1555; + break; + + case MESA_FORMAT_ARGB4444: + t->intel.texelBytes = 2; + textureFormat = MAPSURF_16BIT | MT_16BIT_ARGB4444; + break; + + case MESA_FORMAT_ARGB8888: + t->intel.texelBytes = 4; + textureFormat = MAPSURF_32BIT | MT_32BIT_ARGB8888; + break; + + case MESA_FORMAT_YCBCR_REV: + t->intel.texelBytes = 2; + textureFormat = (MAPSURF_422 | MT_422_YCRCB_NORMAL); + ss2 |= SS2_COLORSPACE_CONVERSION; + break; + + case MESA_FORMAT_YCBCR: + t->intel.texelBytes = 2; + textureFormat = (MAPSURF_422 | MT_422_YCRCB_SWAPY); + ss2 |= SS2_COLORSPACE_CONVERSION; + break; + + default: + fprintf(stderr, "%s: bad image format\n", __FUNCTION__); + abort(); + } + + /* Compute which mipmap levels we really want to send to the hardware. + */ + driCalculateTextureFirstLastLevel( (driTextureObject *) t ); + + + /* Figure out the amount of memory required to hold all the mipmap + * levels. Choose the smallest pitch to accomodate the largest + * mipmap: + */ + firstLevel = t->intel.base.firstLevel; + lastLevel = t->intel.base.lastLevel; + numLevels = lastLevel - firstLevel + 1; + + + + /* All images must be loaded at this pitch. Count the number of + * lines required: + */ + switch (tObj->Target) { + case GL_TEXTURE_CUBE_MAP: { + const GLuint dim = tObj->Image[0][firstLevel]->Width; + GLuint face; + + pitch = dim * t->intel.texelBytes; + pitch *= 2; /* double pitch for cube layouts */ + pitch = (pitch + 3) & ~3; + + total_height = dim * 4; + + for ( face = 0 ; face < 6 ; face++) { + GLuint x = initial_offsets[face][0] * dim; + GLuint y = initial_offsets[face][1] * dim; + GLuint d = dim; + + t->intel.base.dirty_images[face] = ~0; + + assert(tObj->Image[face][firstLevel]->Width == dim); + assert(tObj->Image[face][firstLevel]->Height == dim); + + for (i = 0; i < numLevels; i++) { + t->intel.image[face][i].image = tObj->Image[face][firstLevel + i]; + if (!t->intel.image[face][i].image) { + fprintf(stderr, "no image %d %d\n", face, i); + break; /* can't happen */ + } + + t->intel.image[face][i].offset = + y * pitch + x * t->intel.texelBytes; + t->intel.image[face][i].internalFormat = baseImage->Format; + + d >>= 1; + x += step_offsets[face][0] * d; + y += step_offsets[face][1] * d; + } + } + break; + } + case GL_TEXTURE_3D: { + GLuint virtual_height; + GLuint tmp_numLevels = numLevels; + pitch = tObj->Image[0][firstLevel]->Width * t->intel.texelBytes; + pitch = (pitch + 3) & ~3; + t->intel.base.dirty_images[0] = ~0; + + /* Calculate the size of a single slice. Hardware demands a + * minimum of 8 mipmaps, some of which might ultimately not be + * used: + */ + if (tmp_numLevels < 9) + tmp_numLevels = 9; + + virtual_height = tObj->Image[0][firstLevel]->Height; + + for ( total_height = i = 0 ; i < tmp_numLevels ; i++ ) { + t->intel.image[0][i].image = tObj->Image[0][firstLevel + i]; + if (t->intel.image[0][i].image) { + t->intel.image[0][i].offset = total_height * pitch; + t->intel.image[0][i].internalFormat = baseImage->Format; + } + + total_height += MAX2(2, virtual_height); + virtual_height >>= 1; + } + + t->intel.depth_pitch = total_height * pitch; + + /* Multiply slice size by texture depth for total size. It's + * remarkable how wasteful of memory all the i8x0 texture + * layouts are. + */ + total_height *= t->intel.image[0][0].image->Depth; + break; + } + default: + pitch = tObj->Image[0][firstLevel]->Width * t->intel.texelBytes; + pitch = (pitch + 3) & ~3; + t->intel.base.dirty_images[0] = ~0; + + for ( total_height = i = 0 ; i < numLevels ; i++ ) { + t->intel.image[0][i].image = tObj->Image[0][firstLevel + i]; + if (!t->intel.image[0][i].image) + break; + + t->intel.image[0][i].offset = total_height * pitch; + t->intel.image[0][i].internalFormat = baseImage->Format; + total_height += MAX2(2, t->intel.image[0][i].image->Height); + } + break; + } + + t->intel.Pitch = pitch; + t->intel.base.totalSize = total_height*pitch; + t->intel.max_level = numLevels-1; + t->Setup[I915_TEXREG_MS3] = + (((tObj->Image[0][firstLevel]->Height - 1) << MS3_HEIGHT_SHIFT) | + ((tObj->Image[0][firstLevel]->Width - 1) << MS3_WIDTH_SHIFT) | + textureFormat | + MS3_USE_FENCE_REGS); + t->Setup[I915_TEXREG_MS4] = + ((((pitch / 4) - 1) << MS4_PITCH_SHIFT) | + MS4_CUBE_FACE_ENA_MASK | + (((t->intel.max_level * 4)) << MS4_MAX_LOD_SHIFT) | + ((tObj->Image[0][firstLevel]->Depth - 1) << MS4_VOLUME_DEPTH_SHIFT)); + + t->Setup[I915_TEXREG_SS2] &= ~SS2_COLORSPACE_CONVERSION; + t->Setup[I915_TEXREG_SS2] |= ss2; + + t->intel.dirty = I915_UPLOAD_TEX_ALL; +} + + +/* The i915 (and related graphics cores) do not support GL_CLAMP. The + * Intel drivers for "other operating systems" implement GL_CLAMP as + * GL_CLAMP_TO_EDGE, so the same is done here. + */ +static GLuint translate_wrap_mode( GLenum wrap ) +{ + switch( wrap ) { + case GL_REPEAT: return TEXCOORDMODE_WRAP; + case GL_CLAMP: return TEXCOORDMODE_CLAMP_EDGE; /* not quite correct */ + case GL_CLAMP_TO_EDGE: return TEXCOORDMODE_CLAMP_EDGE; + case GL_CLAMP_TO_BORDER: return TEXCOORDMODE_CLAMP_BORDER; + case GL_MIRRORED_REPEAT: return TEXCOORDMODE_MIRROR; + default: return TEXCOORDMODE_WRAP; + } +} + + +/** + */ +static void i915ImportTexObjState( struct gl_texture_object *texObj ) +{ + i915TextureObjectPtr t = (i915TextureObjectPtr)texObj->DriverData; + int minFilt = 0, mipFilt = 0, magFilt = 0; + + if(INTEL_DEBUG&DEBUG_DRI) + fprintf(stderr, "%s\n", __FUNCTION__); + + switch (texObj->MinFilter) { + case GL_NEAREST: + minFilt = FILTER_NEAREST; + mipFilt = MIPFILTER_NONE; + break; + case GL_LINEAR: + minFilt = FILTER_LINEAR; + mipFilt = MIPFILTER_NONE; + break; + case GL_NEAREST_MIPMAP_NEAREST: + minFilt = FILTER_NEAREST; + mipFilt = MIPFILTER_NEAREST; + break; + case GL_LINEAR_MIPMAP_NEAREST: + minFilt = FILTER_LINEAR; + mipFilt = MIPFILTER_NEAREST; + break; + case GL_NEAREST_MIPMAP_LINEAR: + minFilt = FILTER_NEAREST; + mipFilt = MIPFILTER_LINEAR; + break; + case GL_LINEAR_MIPMAP_LINEAR: + minFilt = FILTER_LINEAR; + mipFilt = MIPFILTER_LINEAR; + break; + default: + break; + } + + if ( texObj->MaxAnisotropy > 1.0 ) { + minFilt = FILTER_ANISOTROPIC; + magFilt = FILTER_ANISOTROPIC; + } + else { + switch (texObj->MagFilter) { + case GL_NEAREST: + magFilt = FILTER_NEAREST; + break; + case GL_LINEAR: + magFilt = FILTER_LINEAR; + break; + default: + break; + } + } + + t->Setup[I915_TEXREG_SS2] &= ~SS2_MIN_FILTER_MASK; + t->Setup[I915_TEXREG_SS2] &= ~SS2_MIP_FILTER_MASK; + t->Setup[I915_TEXREG_SS2] &= ~SS2_MAG_FILTER_MASK; + t->Setup[I915_TEXREG_SS2] |= ((minFilt << SS2_MIN_FILTER_SHIFT) | + (mipFilt << SS2_MIP_FILTER_SHIFT) | + (magFilt << SS2_MAG_FILTER_SHIFT)); + + { + GLuint ss3 = t->Setup[I915_TEXREG_SS3] & ~(SS3_TCX_ADDR_MODE_MASK | + SS3_TCY_ADDR_MODE_MASK | + SS3_TCZ_ADDR_MODE_MASK); + GLenum ws = texObj->WrapS; + GLenum wt = texObj->WrapT; + GLenum wr = texObj->WrapR; + + t->refs_border_color = 0; + + if (texObj->Target == GL_TEXTURE_3D && + (texObj->MinFilter != GL_NEAREST || + texObj->MagFilter != GL_NEAREST)) { + + /* Try to mimic GL_CLAMP functionality a little better - + * switch to CLAMP_TO_BORDER whenever a non-NEAREST filter is + * in use. Only do this for 3D textures at the moment -- + * doing it universally would fix the conform texbc.c + * failure, though. + */ + if (ws == GL_CLAMP) ws = GL_CLAMP_TO_BORDER; + if (wt == GL_CLAMP) wt = GL_CLAMP_TO_BORDER; + if (wr == GL_CLAMP) wr = GL_CLAMP_TO_BORDER; + + /* 3D textures don't seem to respect the border color. + * Fallback if there's ever a danger that they might refer to + * it. + */ + if (ws == GL_CLAMP_TO_BORDER) t->refs_border_color = 1; + if (wt == GL_CLAMP_TO_BORDER) t->refs_border_color = 1; + if (wr == GL_CLAMP_TO_BORDER) t->refs_border_color = 1; + } + + ss3 |= translate_wrap_mode(ws) << SS3_TCX_ADDR_MODE_SHIFT; + ss3 |= translate_wrap_mode(wt) << SS3_TCY_ADDR_MODE_SHIFT; + ss3 |= translate_wrap_mode(wr) << SS3_TCZ_ADDR_MODE_SHIFT; + + if (ss3 != t->Setup[I915_TEXREG_SS3]) { + t->intel.dirty = I915_UPLOAD_TEX_ALL; + t->Setup[I915_TEXREG_SS3] = ss3; + } + } + + { + const GLubyte *color = texObj->_BorderChan; + + t->Setup[I915_TEXREG_SS4] = INTEL_PACKCOLOR8888(color[0],color[1], + color[2],color[3]); + } +} + + + +static void i915_import_tex_unit( i915ContextPtr i915, + i915TextureObjectPtr t, + GLuint unit ) +{ + GLuint state[I915_TEX_SETUP_SIZE]; + + if(INTEL_DEBUG&DEBUG_TEXTURE) + fprintf(stderr, "%s unit(%d)\n", __FUNCTION__, unit); + + if (i915->intel.CurrentTexObj[unit]) + i915->intel.CurrentTexObj[unit]->base.bound &= ~(1U << unit); + + i915->intel.CurrentTexObj[unit] = (intelTextureObjectPtr)t; + t->intel.base.bound |= (1 << unit); + + if (t->intel.dirty & I915_UPLOAD_TEX(unit)) { + i915ImportTexObjState( t->intel.base.tObj ); + t->intel.dirty &= ~I915_UPLOAD_TEX(unit); + } + + state[I915_TEXREG_MS2] = t->intel.TextureOffset; + state[I915_TEXREG_MS3] = t->Setup[I915_TEXREG_MS3]; + state[I915_TEXREG_MS4] = t->Setup[I915_TEXREG_MS4]; + + state[I915_TEXREG_SS2] = (i915->state.Tex[unit][I915_TEXREG_SS2] & + SS2_LOD_BIAS_MASK); + state[I915_TEXREG_SS2] |= (t->Setup[I915_TEXREG_SS2] & ~SS2_LOD_BIAS_MASK); + + state[I915_TEXREG_SS3] = (i915->state.Tex[unit][I915_TEXREG_SS3] & + SS3_NORMALIZED_COORDS); + state[I915_TEXREG_SS3] |= (t->Setup[I915_TEXREG_SS3] & + ~(SS3_NORMALIZED_COORDS| + SS3_TEXTUREMAP_INDEX_MASK)); + + state[I915_TEXREG_SS3] |= (unit<Setup[I915_TEXREG_SS4]; + + + if (memcmp(state, i915->state.Tex[unit], sizeof(state)) != 0) { + I915_STATECHANGE( i915, I915_UPLOAD_TEX(unit) ); + memcpy(i915->state.Tex[unit], state, sizeof(state)); + } +} + + + +static GLboolean enable_tex_common( GLcontext *ctx, GLuint unit ) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + i915TextureObjectPtr t = (i915TextureObjectPtr)tObj->DriverData; + + if (0) fprintf(stderr, "%s %d\n", __FUNCTION__, unit); + + if (!(i915->state.active & I915_UPLOAD_TEX(unit))) { + I915_ACTIVESTATE(i915, I915_UPLOAD_TEX(unit), GL_TRUE); + } + + /* Fallback if there's a texture border */ + if ( tObj->Image[0][tObj->BaseLevel]->Border > 0 ) { + return GL_FALSE; + } + + + /* Update state if this is a different texture object to last + * time. + */ + if (i915->intel.CurrentTexObj[unit] != &t->intel || + (t->intel.dirty & I915_UPLOAD_TEX(unit))) { + i915_import_tex_unit( i915, t, unit); + i915->tex_program.translated = 0; + } + + return GL_TRUE; +} + +static GLboolean enable_tex_rect( GLcontext *ctx, GLuint unit ) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + i915TextureObjectPtr t = (i915TextureObjectPtr)tObj->DriverData; + GLuint ss3 = i915->state.Tex[unit][I915_TEXREG_SS3]; + + ss3 &= ~SS3_NORMALIZED_COORDS; + + if (ss3 != i915->state.Tex[unit][I915_TEXREG_SS3]) { + I915_STATECHANGE(i915, I915_UPLOAD_TEX(unit)); + i915->state.Tex[unit][I915_TEXREG_SS3] = ss3; + } + + /* Upload teximages (not pipelined) + */ + if (t->intel.base.dirty_images[0]) { + i915SetTexImages( i915, tObj ); + if (!intelUploadTexImages( &i915->intel, &t->intel, 0 )) { + return GL_FALSE; + } + } + + return GL_TRUE; +} + + +static GLboolean enable_tex_2d( GLcontext *ctx, GLuint unit ) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + i915TextureObjectPtr t = (i915TextureObjectPtr)tObj->DriverData; + GLuint ss3 = i915->state.Tex[unit][I915_TEXREG_SS3]; + + ss3 |= SS3_NORMALIZED_COORDS; + + if (ss3 != i915->state.Tex[unit][I915_TEXREG_SS3]) { + I915_STATECHANGE(i915, I915_UPLOAD_TEX(unit)); + i915->state.Tex[unit][I915_TEXREG_SS3] = ss3; + } + + /* Upload teximages (not pipelined) + */ + if (t->intel.base.dirty_images[0]) { + i915SetTexImages( i915, tObj ); + if (!intelUploadTexImages( &i915->intel, &t->intel, 0 )) { + return GL_FALSE; + } + } + + return GL_TRUE; +} + +static GLboolean enable_tex_cube( GLcontext *ctx, GLuint unit ) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + i915TextureObjectPtr t = (i915TextureObjectPtr)tObj->DriverData; + GLuint ss3 = i915->state.Tex[unit][I915_TEXREG_SS3]; + GLuint face; + + ss3 |= SS3_NORMALIZED_COORDS; + + if (ss3 != i915->state.Tex[unit][I915_TEXREG_SS3]) { + I915_STATECHANGE(i915, I915_UPLOAD_TEX(unit)); + i915->state.Tex[unit][I915_TEXREG_SS3] = ss3; + } + + /* Upload teximages (not pipelined) + */ + if ( t->intel.base.dirty_images[0] || t->intel.base.dirty_images[1] || + t->intel.base.dirty_images[2] || t->intel.base.dirty_images[3] || + t->intel.base.dirty_images[4] || t->intel.base.dirty_images[5] ) { + i915SetTexImages( i915, tObj ); + } + + /* upload (per face) */ + for (face = 0; face < 6; face++) { + if (t->intel.base.dirty_images[face]) { + if (!intelUploadTexImages( &i915->intel, &t->intel, face )) { + return GL_FALSE; + } + } + } + + + return GL_TRUE; +} + +static GLboolean enable_tex_3d( GLcontext *ctx, GLuint unit ) +{ + struct gl_texture_object *tObj = ctx->Texture.Unit[unit]._Current; + i915TextureObjectPtr t = (i915TextureObjectPtr)tObj->DriverData; + + /* 3D textures on I915 seem to get bogus border colors, hence this + * fallback: + */ + if (t->refs_border_color) + return GL_FALSE; + + return GL_TRUE; +} + + + + +static GLboolean disable_tex( GLcontext *ctx, GLuint unit ) +{ + i915ContextPtr i915 = I915_CONTEXT(ctx); + + if (i915->state.active & I915_UPLOAD_TEX(unit)) { + I915_ACTIVESTATE(i915, I915_UPLOAD_TEX(unit), GL_FALSE); + } + + /* The old texture is no longer bound to this texture unit. + * Mark it as such. + */ + if ( i915->intel.CurrentTexObj[unit] != NULL ) { + i915->intel.CurrentTexObj[unit]->base.bound &= ~(1U << 0); + i915->intel.CurrentTexObj[unit] = NULL; + } + + return GL_TRUE; +} + +static GLboolean i915UpdateTexUnit( GLcontext *ctx, GLuint unit ) +{ + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + + if (texUnit->_ReallyEnabled && + INTEL_CONTEXT(ctx)->intelScreen->textureSize < 2048 * 1024) + return GL_FALSE; + + switch (texUnit->_ReallyEnabled) { + case TEXTURE_1D_BIT: + case TEXTURE_2D_BIT: + return (enable_tex_2d( ctx, unit ) && + enable_tex_common( ctx, unit )); + case TEXTURE_RECT_BIT: + return (enable_tex_rect( ctx, unit ) && + enable_tex_common( ctx, unit )); + case TEXTURE_CUBE_BIT: + return (enable_tex_cube( ctx, unit ) && + enable_tex_common( ctx, unit )); + case TEXTURE_3D_BIT: + return (enable_tex_2d( ctx, unit ) && + enable_tex_common( ctx, unit ) && + enable_tex_3d( ctx, unit)); + case 0: + return disable_tex( ctx, unit ); + default: + return GL_FALSE; + } +} + + +void i915UpdateTextureState( intelContextPtr intel ) +{ + GLcontext *ctx = &intel->ctx; + GLboolean ok = GL_TRUE; + GLuint i; + + for (i = 0 ; i < I915_TEX_UNITS && ok ; i++) { + ok = i915UpdateTexUnit( ctx, i ); + } + + FALLBACK( intel, I915_FALLBACK_TEXTURE, !ok ); +} + + + diff --git a/src/mesa/drivers/dri/i915/i915_vtbl.c b/src/mesa/drivers/dri/i915/i915_vtbl.c new file mode 100644 index 0000000..cfea354 --- /dev/null +++ b/src/mesa/drivers/dri/i915/i915_vtbl.c @@ -0,0 +1,332 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + + + +#include "glheader.h" +#include "mtypes.h" +#include "imports.h" +#include "macros.h" +#include "colormac.h" + +#include "tnl/t_context.h" +#include "tnl/t_vertex.h" + +#include "intel_batchbuffer.h" + +#include "i915_reg.h" +#include "i915_context.h" + +static void i915_render_start( intelContextPtr intel ) +{ + GLcontext *ctx = &intel->ctx; + i915ContextPtr i915 = I915_CONTEXT(intel); + + if (ctx->FragmentProgram.Enabled && ctx->FragmentProgram.Current) + i915ValidateFragmentProgram( i915 ); + else + i915ValidateTextureProgram( i915 ); +} + + +static void i915_reduced_primitive_state( intelContextPtr intel, + GLenum rprim ) +{ + i915ContextPtr i915 = I915_CONTEXT(intel); + GLuint st1 = i915->state.Stipple[I915_STPREG_ST1]; + + st1 &= ~ST1_ENABLE; + + switch (rprim) { + case GL_TRIANGLES: + if (intel->ctx.Polygon.StippleFlag && + intel->hw_stipple) + st1 |= ST1_ENABLE; + break; + case GL_LINES: + case GL_POINTS: + default: + break; + } + + i915->intel.reduced_primitive = rprim; + + if (st1 != i915->state.Stipple[I915_STPREG_ST1]) { + I915_STATECHANGE(i915, I915_UPLOAD_STIPPLE); + i915->state.Stipple[I915_STPREG_ST1] = st1; + } +} + + +/* Pull apart the vertex format registers and figure out how large a + * vertex is supposed to be. + */ +static GLboolean i915_check_vertex_size( intelContextPtr intel, + GLuint expected ) +{ + i915ContextPtr i915 = I915_CONTEXT(intel); + int lis2 = i915->current->Ctx[I915_CTXREG_LIS2]; + int lis4 = i915->current->Ctx[I915_CTXREG_LIS4]; + int i, sz = 0; + + switch (lis4 & S4_VFMT_XYZW_MASK) { + case S4_VFMT_XY: sz = 2; break; + case S4_VFMT_XYZ: sz = 3; break; + case S4_VFMT_XYW: sz = 3; break; + case S4_VFMT_XYZW: sz = 4; break; + default: + fprintf(stderr, "no xyzw specified\n"); + return 0; + } + + if (lis4 & S4_VFMT_SPEC_FOG) sz++; + if (lis4 & S4_VFMT_COLOR) sz++; + if (lis4 & S4_VFMT_DEPTH_OFFSET) sz++; + if (lis4 & S4_VFMT_POINT_WIDTH) sz++; + + for (i = 0 ; i < 8 ; i++) { + switch (lis2 & S2_TEXCOORD_FMT0_MASK) { + case TEXCOORDFMT_2D: sz += 2; break; + case TEXCOORDFMT_3D: sz += 3; break; + case TEXCOORDFMT_4D: sz += 4; break; + case TEXCOORDFMT_1D: sz += 1; break; + case TEXCOORDFMT_2D_16: sz += 1; break; + case TEXCOORDFMT_4D_16: sz += 2; break; + case TEXCOORDFMT_NOT_PRESENT: break; + default: + fprintf(stderr, "bad texcoord fmt %d\n", i); + return GL_FALSE; + } + lis2 >>= S2_TEXCOORD_FMT1_SHIFT; + } + + if (sz != expected) + fprintf(stderr, "vertex size mismatch %d/%d\n", sz, expected); + + return sz == expected; +} + + +static void i915_emit_invarient_state( intelContextPtr intel ) +{ + BATCH_LOCALS; + + BEGIN_BATCH( 200 ); + + OUT_BATCH(_3DSTATE_AA_CMD | + AA_LINE_ECAAR_WIDTH_ENABLE | + AA_LINE_ECAAR_WIDTH_1_0 | + AA_LINE_REGION_WIDTH_ENABLE | + AA_LINE_REGION_WIDTH_1_0); + + OUT_BATCH(_3DSTATE_DFLT_DIFFUSE_CMD); + OUT_BATCH(0); + + OUT_BATCH(_3DSTATE_DFLT_SPEC_CMD); + OUT_BATCH(0); + + OUT_BATCH(_3DSTATE_DFLT_Z_CMD); + OUT_BATCH(0); + + /* Don't support texture crossbar yet */ + OUT_BATCH(_3DSTATE_COORD_SET_BINDINGS | + CSB_TCB(0, 0) | + CSB_TCB(1, 1) | + CSB_TCB(2, 2) | + CSB_TCB(3, 3) | + CSB_TCB(4, 4) | + CSB_TCB(5, 5) | + CSB_TCB(6, 6) | + CSB_TCB(7, 7)); + + OUT_BATCH(_3DSTATE_RASTER_RULES_CMD | + ENABLE_POINT_RASTER_RULE | + OGL_POINT_RASTER_RULE | + ENABLE_LINE_STRIP_PROVOKE_VRTX | + ENABLE_TRI_FAN_PROVOKE_VRTX | + LINE_STRIP_PROVOKE_VRTX(1) | + TRI_FAN_PROVOKE_VRTX(2) | + ENABLE_TEXKILL_3D_4D | + TEXKILL_4D); + + /* Need to initialize this to zero. + */ + OUT_BATCH(_3DSTATE_LOAD_STATE_IMMEDIATE_1 | + I1_LOAD_S(3) | + (1)); + OUT_BATCH(0); + + /* XXX: Use this */ + OUT_BATCH(_3DSTATE_SCISSOR_ENABLE_CMD | + DISABLE_SCISSOR_RECT); + + OUT_BATCH(_3DSTATE_SCISSOR_RECT_0_CMD); + OUT_BATCH(0); + OUT_BATCH(0); + + OUT_BATCH(_3DSTATE_DEPTH_SUBRECT_DISABLE); + + OUT_BATCH(_3DSTATE_LOAD_INDIRECT | 0); /* disable indirect state */ + OUT_BATCH(0); + + + /* Don't support twosided stencil yet */ + OUT_BATCH(_3DSTATE_BACKFACE_STENCIL_OPS | + BFO_ENABLE_STENCIL_TWO_SIDE | + 0 ); + + ADVANCE_BATCH(); +} + + +#define emit( intel, state, size ) \ +do { \ + int k; \ + BEGIN_BATCH( (size) / sizeof(GLuint)); \ + for (k = 0 ; k < (size) / sizeof(GLuint) ; k++) \ + OUT_BATCH((state)[k]); \ + ADVANCE_BATCH(); \ +} while (0); + + +/* Push the state into the sarea and/or texture memory. + */ +static void i915_emit_state( intelContextPtr intel ) +{ + i915ContextPtr i915 = I915_CONTEXT(intel); + struct i915_hw_state *state = i915->current; + BATCH_LOCALS; + int i; + GLuint dirty; + + /* More to workaround the multitex hang - if one texture unit state + * is modified, emit all texture units. + */ + dirty = state->active & ~state->emitted; + if (dirty & I915_UPLOAD_TEX_ALL) + state->emitted &= ~I915_UPLOAD_TEX_ALL; + dirty = state->active & ~state->emitted; + + + if (VERBOSE) + fprintf(stderr, "%s dirty: %x\n", __FUNCTION__, dirty); + + if (dirty & I915_UPLOAD_CTX) { + if (VERBOSE) fprintf(stderr, "I915_UPLOAD_CTX:\n"); + emit( i915, state->Ctx, sizeof(state->Ctx) ); + } + + if (dirty & I915_UPLOAD_BUFFERS) { + if (VERBOSE) fprintf(stderr, "I915_UPLOAD_BUFFERS:\n"); + emit( i915, state->Buffer, sizeof(state->Buffer) ); + } + + if (dirty & I915_UPLOAD_STIPPLE) { + if (VERBOSE) fprintf(stderr, "I915_UPLOAD_STIPPLE:\n"); + emit( i915, state->Stipple, sizeof(state->Stipple) ); + } + + if (dirty & I915_UPLOAD_FOG) { + if (VERBOSE) fprintf(stderr, "I915_UPLOAD_FOG:\n"); + emit( i915, state->Fog, sizeof(state->Fog) ); + } + + /* Combine all the dirty texture state into a single command to + * avoid lockups on I915 hardware. + */ + if (dirty & I915_UPLOAD_TEX_ALL) { + int nr = 0; + + for (i = 0; i < I915_TEX_UNITS; i++) + if (dirty & I915_UPLOAD_TEX(i)) + nr++; + + BEGIN_BATCH(2+nr*3); + OUT_BATCH(_3DSTATE_MAP_STATE | (3*nr)); + OUT_BATCH((dirty & I915_UPLOAD_TEX_ALL) >> I915_UPLOAD_TEX_0_SHIFT); + for (i = 0 ; i < I915_TEX_UNITS ; i++) + if (dirty & I915_UPLOAD_TEX(i)) { + OUT_BATCH(state->Tex[i][I915_TEXREG_MS2]); + OUT_BATCH(state->Tex[i][I915_TEXREG_MS3]); + OUT_BATCH(state->Tex[i][I915_TEXREG_MS4]); + } + ADVANCE_BATCH(); + + BEGIN_BATCH(2+nr*3); + OUT_BATCH(_3DSTATE_SAMPLER_STATE | (3*nr)); + OUT_BATCH((dirty & I915_UPLOAD_TEX_ALL) >> I915_UPLOAD_TEX_0_SHIFT); + for (i = 0 ; i < I915_TEX_UNITS ; i++) + if (dirty & I915_UPLOAD_TEX(i)) { + OUT_BATCH(state->Tex[i][I915_TEXREG_SS2]); + OUT_BATCH(state->Tex[i][I915_TEXREG_SS3]); + OUT_BATCH(state->Tex[i][I915_TEXREG_SS4]); + } + ADVANCE_BATCH(); + } + + if (dirty & I915_UPLOAD_CONSTANTS) { + if (VERBOSE) fprintf(stderr, "I915_UPLOAD_CONSTANTS:\n"); + emit( i915, state->Constant, state->ConstantSize * sizeof(GLuint) ); + } + + if (dirty & I915_UPLOAD_PROGRAM) { + if (VERBOSE) fprintf(stderr, "I915_UPLOAD_PROGRAM:\n"); + + assert((state->Program[0] & 0x1ff)+2 == state->ProgramSize); + + emit( i915, state->Program, state->ProgramSize * sizeof(GLuint) ); + if (VERBOSE) + i915_disassemble_program( state->Program, state->ProgramSize ); + } + + state->emitted |= dirty; +} + +static void i915_destroy_context( intelContextPtr intel ) +{ + _tnl_free_vertices(&intel->ctx); +} + +static void i915_set_draw_offset( intelContextPtr intel, int offset ) +{ + i915ContextPtr i915 = I915_CONTEXT(intel); + I915_STATECHANGE( i915, I915_UPLOAD_BUFFERS ); + i915->state.Buffer[I915_DESTREG_CBUFADDR2] = offset; +} + +static void i915_lost_hardware( intelContextPtr intel ) +{ + I915_CONTEXT(intel)->state.emitted = 0; +} + +static void i915_emit_flush( intelContextPtr intel ) +{ + BATCH_LOCALS; + + BEGIN_BATCH(2); + OUT_BATCH( MI_FLUSH | FLUSH_MAP_CACHE | FLUSH_RENDER_CACHE ); + OUT_BATCH( 0 ); + ADVANCE_BATCH(); +} + + +void i915InitVtbl( i915ContextPtr i915 ) +{ + i915->intel.vtbl.alloc_tex_obj = i915AllocTexObj; + i915->intel.vtbl.check_vertex_size = i915_check_vertex_size; + i915->intel.vtbl.clear_with_tris = i915ClearWithTris; + i915->intel.vtbl.destroy = i915_destroy_context; + i915->intel.vtbl.emit_invarient_state = i915_emit_invarient_state; + i915->intel.vtbl.emit_state = i915_emit_state; + i915->intel.vtbl.lost_hardware = i915_lost_hardware; + i915->intel.vtbl.reduced_primitive_state = i915_reduced_primitive_state; + i915->intel.vtbl.render_start = i915_render_start; + i915->intel.vtbl.set_draw_offset = i915_set_draw_offset; + i915->intel.vtbl.update_texture_state = i915UpdateTextureState; + i915->intel.vtbl.emit_flush = i915_emit_flush; +} + diff --git a/src/mesa/drivers/dri/i915/intel_batchbuffer.c b/src/mesa/drivers/dri/i915/intel_batchbuffer.c new file mode 100644 index 0000000..9146cbe --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_batchbuffer.c @@ -0,0 +1,668 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + + +#include +#include + +#include "mtypes.h" +#include "context.h" +#include "enums.h" + +#include "intel_reg.h" +#include "intel_batchbuffer.h" +#include "intel_context.h" + + + + +/* ================================================================ + * Performance monitoring functions + */ + +static void intel_fill_box( intelContextPtr intel, + GLshort x, GLshort y, + GLshort w, GLshort h, + GLubyte r, GLubyte g, GLubyte b ) +{ + intelEmitFillBlitLocked( intel, + intel->intelScreen->cpp, + intel->intelScreen->backPitch, + intel->intelScreen->frontOffset, + x, y, w, h, + INTEL_PACKCOLOR(intel->intelScreen->fbFormat, + r,g,b,0xff)); +} + +static void intel_draw_performance_boxes( intelContextPtr intel ) +{ + /* Purple box for page flipping + */ + if ( intel->perf_boxes & I830_BOX_FLIP ) + intel_fill_box( intel, 4, 4, 8, 8, 255, 0, 255 ); + + /* Red box if we have to wait for idle at any point + */ + if ( intel->perf_boxes & I830_BOX_WAIT ) + intel_fill_box( intel, 16, 4, 8, 8, 255, 0, 0 ); + + /* Blue box: lost context? + */ + if ( intel->perf_boxes & I830_BOX_LOST_CONTEXT ) + intel_fill_box( intel, 28, 4, 8, 8, 0, 0, 255 ); + + /* Yellow box for texture swaps + */ + if ( intel->perf_boxes & I830_BOX_TEXTURE_LOAD ) + intel_fill_box( intel, 40, 4, 8, 8, 255, 255, 0 ); + + /* Green box if hardware never idles (as far as we can tell) + */ + if ( !(intel->perf_boxes & I830_BOX_RING_EMPTY) ) + intel_fill_box( intel, 64, 4, 8, 8, 0, 255, 0 ); + + + /* Draw bars indicating number of buffers allocated + * (not a great measure, easily confused) + */ +#if 0 + if (intel->dma_used) { + int bar = intel->dma_used / 10240; + if (bar > 100) bar = 100; + if (bar < 1) bar = 1; + intel_fill_box( intel, 4, 16, bar, 4, 196, 128, 128 ); + intel->dma_used = 0; + } +#endif + + intel->perf_boxes = 0; +} + + + + + + +static int bad_prim_vertex_nr( int primitive, int nr ) +{ + switch (primitive & PRIM3D_MASK) { + case PRIM3D_POINTLIST: + return nr < 1; + case PRIM3D_LINELIST: + return (nr & 1) || nr == 0; + case PRIM3D_LINESTRIP: + return nr < 2; + case PRIM3D_TRILIST: + case PRIM3D_RECTLIST: + return nr % 3 || nr == 0; + case PRIM3D_POLY: + case PRIM3D_TRIFAN: + case PRIM3D_TRISTRIP: + case PRIM3D_TRISTRIP_RVRSE: + return nr < 3; + default: + return 1; + } +} + +static void intel_flush_inline_primitive( GLcontext *ctx ) +{ + intelContextPtr intel = INTEL_CONTEXT( ctx ); + GLuint used = intel->batch.ptr - intel->prim.start_ptr; + GLuint vertcount; + + assert(intel->prim.primitive != ~0); + + if (1) { + /* Check vertex size against the vertex we're specifying to + * hardware. If it's wrong, ditch the primitive. + */ + if (!intel->vtbl.check_vertex_size( intel, intel->vertex_size )) + goto do_discard; + + vertcount = (used - 4)/ (intel->vertex_size * 4); + + if (!vertcount) + goto do_discard; + + if (vertcount * intel->vertex_size * 4 != used - 4) { + fprintf(stderr, "vertex size confusion %d %d\n", used, + intel->vertex_size * vertcount * 4); + goto do_discard; + } + + if (bad_prim_vertex_nr( intel->prim.primitive, vertcount )) { + fprintf(stderr, "bad_prim_vertex_nr %x %d\n", intel->prim.primitive, + vertcount); + goto do_discard; + } + } + + if (used < 8) + goto do_discard; + + *(int *)intel->prim.start_ptr = (_3DPRIMITIVE | + intel->prim.primitive | + (used/4-2)); + + goto finished; + + do_discard: + intel->batch.ptr -= used; + intel->batch.space += used; + assert(intel->batch.space >= 0); + + finished: + intel->prim.primitive = ~0; + intel->prim.start_ptr = 0; + intel->prim.flush = 0; +} + + +/* Emit a primitive referencing vertices in a vertex buffer. + */ +void intelStartInlinePrimitive( intelContextPtr intel, GLuint prim ) +{ + BATCH_LOCALS; + + if (0) + fprintf(stderr, "%s %x\n", __FUNCTION__, prim); + + + /* Finish any in-progress primitive: + */ + INTEL_FIREVERTICES( intel ); + + /* Emit outstanding state: + */ + intel->vtbl.emit_state( intel ); + + /* Make sure there is some space in this buffer: + */ + if (intel->vertex_size * 10 * sizeof(GLuint) >= intel->batch.space) + intelFlushBatch(intel, GL_TRUE); + + +#if 1 + if (((int)intel->batch.ptr) & 0x4) { + BEGIN_BATCH(1); + OUT_BATCH(0); + ADVANCE_BATCH(); + } +#endif + + /* Emit a slot which will be filled with the inline primitive + * command later. + */ + BEGIN_BATCH(2); + OUT_BATCH( 0 ); + + intel->prim.start_ptr = batch_ptr; + intel->prim.primitive = prim; + intel->prim.flush = intel_flush_inline_primitive; + + OUT_BATCH( 0 ); + ADVANCE_BATCH(); +} + + +void intelRestartInlinePrimitive( intelContextPtr intel ) +{ + GLuint prim = intel->prim.primitive; + + intel_flush_inline_primitive( &intel->ctx ); + if (1) intelFlushBatch(intel, GL_TRUE); /* GL_TRUE - is critical */ + intelStartInlinePrimitive( intel, prim ); +} + + + +void intelWrapInlinePrimitive( intelContextPtr intel ) +{ + GLuint prim = intel->prim.primitive; + + if (0) + fprintf(stderr, "%s\n", __FUNCTION__); + intel_flush_inline_primitive( &intel->ctx ); + intelFlushBatch(intel, GL_TRUE); + intelStartInlinePrimitive( intel, prim ); +} + + +/* Emit a primitive with space for inline vertices. + */ +GLuint *intelEmitInlinePrimitiveLocked(intelContextPtr intel, + int primitive, + int dwords, + int vertex_size ) +{ + GLuint *tmp = 0; + BATCH_LOCALS; + + if (0) + fprintf(stderr, "%s 0x%x %d\n", __FUNCTION__, primitive, dwords); + + /* Emit outstanding state: + */ + intel->vtbl.emit_state( intel ); + + + if (1) { + int used = dwords * 4; + int vertcount; + + /* Check vertex size against the vertex we're specifying to + * hardware. If it's wrong, ditch the primitive. + */ + if (!intel->vtbl.check_vertex_size( intel, vertex_size )) + goto do_discard; + + vertcount = dwords / vertex_size; + + if (dwords % vertex_size) { + fprintf(stderr, "did not request a whole number of vertices\n"); + goto do_discard; + } + + if (bad_prim_vertex_nr( primitive, vertcount )) { + fprintf(stderr, "bad_prim_vertex_nr %x %d\n", primitive, vertcount); + goto do_discard; + } + + if (used < 8) + goto do_discard; + } + + /* Emit 3D_PRIMITIVE commands: + */ + BEGIN_BATCH(1 + dwords); + OUT_BATCH( _3DPRIMITIVE | + primitive | + (dwords-1) ); + + tmp = (GLuint *)batch_ptr; + batch_ptr += dwords * 4; + + ADVANCE_BATCH(); + + do_discard: + return tmp; +} + + + +/* + * Copy the back buffer to the front buffer. + */ +void intelCopyBuffer( const __DRIdrawablePrivate *dPriv ) +{ + intelContextPtr intel; + + if (0) + fprintf(stderr, "%s\n", __FUNCTION__); + + assert(dPriv); + assert(dPriv->driContextPriv); + assert(dPriv->driContextPriv->driverPrivate); + + intel = (intelContextPtr) dPriv->driContextPriv->driverPrivate; + + intelFlush( &intel->ctx ); + LOCK_HARDWARE( intel ); + { + intelScreenPrivate *intelScreen = intel->intelScreen; + __DRIdrawablePrivate *dPriv = intel->driDrawable; + int nbox = dPriv->numClipRects; + drm_clip_rect_t *pbox = dPriv->pClipRects; + int pitch = intelScreen->frontPitch; + int cpp = intelScreen->cpp; + int i; + GLuint CMD, BR13; + BATCH_LOCALS; + + switch(cpp) { + case 2: + BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24); + CMD = XY_SRC_COPY_BLT_CMD; + break; + case 4: + BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24) | (1<<25); + CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + break; + default: + BR13 = (pitch * cpp) | (0xCC << 16) | (1<<24); + CMD = XY_SRC_COPY_BLT_CMD; + break; + } + + if (0) + intel_draw_performance_boxes( intel ); + + for (i = 0 ; i < nbox; i++, pbox++) + { + if (pbox->x1 > pbox->x2 || + pbox->y1 > pbox->y2 || + pbox->x2 > intelScreen->width || + pbox->y2 > intelScreen->height) + continue; + + BEGIN_BATCH( 8); + OUT_BATCH( CMD ); + OUT_BATCH( BR13 ); + OUT_BATCH( (pbox->y1 << 16) | pbox->x1 ); + OUT_BATCH( (pbox->y2 << 16) | pbox->x2 ); + + if (intel->sarea->pf_current_page == 0) + OUT_BATCH( intelScreen->frontOffset ); + else + OUT_BATCH( intelScreen->backOffset ); + + OUT_BATCH( (pbox->y1 << 16) | pbox->x1 ); + OUT_BATCH( BR13 & 0xffff ); + + if (intel->sarea->pf_current_page == 0) + OUT_BATCH( intelScreen->backOffset ); + else + OUT_BATCH( intelScreen->frontOffset ); + + ADVANCE_BATCH(); + } + } + intelFlushBatchLocked( intel, GL_TRUE, GL_TRUE, GL_TRUE ); + UNLOCK_HARDWARE( intel ); +} + + + + +void intelEmitFillBlitLocked( intelContextPtr intel, + GLuint cpp, + GLshort dst_pitch, + GLuint dst_offset, + GLshort x, GLshort y, + GLshort w, GLshort h, + GLuint color ) +{ + GLuint BR13, CMD; + BATCH_LOCALS; + + dst_pitch *= cpp; + + switch(cpp) { + case 1: + case 2: + case 3: + BR13 = dst_pitch | (0xF0 << 16) | (1<<24); + CMD = XY_COLOR_BLT_CMD; + break; + case 4: + BR13 = dst_pitch | (0xF0 << 16) | (1<<24) | (1<<25); + CMD = (XY_COLOR_BLT_CMD | XY_COLOR_BLT_WRITE_ALPHA | + XY_COLOR_BLT_WRITE_RGB); + break; + default: + return; + } + + BEGIN_BATCH( 6); + OUT_BATCH( CMD ); + OUT_BATCH( BR13 ); + OUT_BATCH( (y << 16) | x ); + OUT_BATCH( ((y+h) << 16) | (x+w) ); + OUT_BATCH( dst_offset ); + OUT_BATCH( color ); + ADVANCE_BATCH(); +} + + +/* Copy BitBlt + */ +void intelEmitCopyBlitLocked( intelContextPtr intel, + GLuint cpp, + GLshort src_pitch, + GLuint src_offset, + GLshort dst_pitch, + GLuint dst_offset, + GLshort src_x, GLshort src_y, + GLshort dst_x, GLshort dst_y, + GLshort w, GLshort h ) +{ + GLuint CMD, BR13; + int dst_y2 = dst_y + h; + int dst_x2 = dst_x + w; + BATCH_LOCALS; + + src_pitch *= cpp; + dst_pitch *= cpp; + + switch(cpp) { + case 1: + case 2: + case 3: + BR13 = dst_pitch | (0xCC << 16) | (1<<24); + CMD = XY_SRC_COPY_BLT_CMD; + break; + case 4: + BR13 = dst_pitch | (0xCC << 16) | (1<<24) | (1<<25); + CMD = (XY_SRC_COPY_BLT_CMD | XY_SRC_COPY_BLT_WRITE_ALPHA | + XY_SRC_COPY_BLT_WRITE_RGB); + break; + default: + return; + } + + if (dst_y2 < dst_y || + dst_x2 < dst_x) { + return; + } + + BEGIN_BATCH( 12); + OUT_BATCH( CMD ); + OUT_BATCH( BR13 ); + OUT_BATCH( (dst_y << 16) | dst_x ); + OUT_BATCH( (dst_y2 << 16) | dst_x2 ); + OUT_BATCH( dst_offset ); + OUT_BATCH( (src_y << 16) | src_x ); + OUT_BATCH( src_pitch ); + OUT_BATCH( src_offset ); + ADVANCE_BATCH(); +} + + + +void intelClearWithBlit(GLcontext *ctx, GLbitfield flags, GLboolean all, + GLint cx1, GLint cy1, GLint cw, GLint ch) +{ + intelContextPtr intel = INTEL_CONTEXT( ctx ); + intelScreenPrivate *intelScreen = intel->intelScreen; + GLuint clear_depth, clear_color; + GLint cx, cy; + GLint pitch = intelScreen->frontPitch; + GLint cpp = intelScreen->cpp; + GLint i; + GLuint BR13, CMD, D_CMD; + BATCH_LOCALS; + + + clear_color = intel->ClearColor; + clear_depth = 0; + + if (flags & DD_DEPTH_BIT) { + clear_depth = (GLuint)(ctx->Depth.Clear * intel->ClearDepth); + } + + if (flags & DD_STENCIL_BIT) { + clear_depth |= (ctx->Stencil.Clear & 0xff) << 24; + } + + switch(cpp) { + case 2: + BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24); + D_CMD = CMD = XY_COLOR_BLT_CMD; + break; + case 4: + BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24) | (1<<25); + CMD = (XY_COLOR_BLT_CMD | + XY_COLOR_BLT_WRITE_ALPHA | + XY_COLOR_BLT_WRITE_RGB); + D_CMD = XY_COLOR_BLT_CMD; + if (flags & DD_DEPTH_BIT) D_CMD |= XY_COLOR_BLT_WRITE_RGB; + if (flags & DD_STENCIL_BIT) D_CMD |= XY_COLOR_BLT_WRITE_ALPHA; + break; + default: + BR13 = (0xF0 << 16) | (pitch * cpp) | (1<<24); + D_CMD = CMD = XY_COLOR_BLT_CMD; + break; + } + + intelFlush( &intel->ctx ); + LOCK_HARDWARE( intel ); + { + /* flip top to bottom */ + cy = intel->driDrawable->h-cy1-ch; + cx = cx1 + intel->drawX; + cy += intel->drawY; + + /* adjust for page flipping */ + if ( intel->sarea->pf_current_page == 1 ) { + GLuint tmp = flags; + + flags &= ~(DD_FRONT_LEFT_BIT | DD_BACK_LEFT_BIT); + if ( tmp & DD_FRONT_LEFT_BIT ) flags |= DD_BACK_LEFT_BIT; + if ( tmp & DD_BACK_LEFT_BIT ) flags |= DD_FRONT_LEFT_BIT; + } + + for (i = 0 ; i < intel->numClipRects ; i++) + { + drm_clip_rect_t *box = &intel->pClipRects[i]; + drm_clip_rect_t b; + + if (!all) { + GLint x = box[i].x1; + GLint y = box[i].y1; + GLint w = box[i].x2 - x; + GLint h = box[i].y2 - y; + + if (x < cx) w -= cx - x, x = cx; + if (y < cy) h -= cy - y, y = cy; + if (x + w > cx + cw) w = cx + cw - x; + if (y + h > cy + ch) h = cy + ch - y; + if (w <= 0) continue; + if (h <= 0) continue; + + b.x1 = x; + b.y1 = y; + b.x2 = x + w; + b.y2 = y + h; + } else { + b = *box; + } + + + if (b.x1 > b.x2 || + b.y1 > b.y2 || + b.x2 > intelScreen->width || + b.y2 > intelScreen->height) + continue; + + if ( flags & DD_FRONT_LEFT_BIT ) { + BEGIN_BATCH( 6); + OUT_BATCH( CMD ); + OUT_BATCH( BR13 ); + OUT_BATCH( (b.y1 << 16) | b.x1 ); + OUT_BATCH( (b.y2 << 16) | b.x2 ); + OUT_BATCH( intelScreen->frontOffset ); + OUT_BATCH( clear_color ); + ADVANCE_BATCH(); + } + + if ( flags & DD_BACK_LEFT_BIT ) { + BEGIN_BATCH( 6); + OUT_BATCH( CMD ); + OUT_BATCH( BR13 ); + OUT_BATCH( (b.y1 << 16) | b.x1 ); + OUT_BATCH( (b.y2 << 16) | b.x2 ); + OUT_BATCH( intelScreen->backOffset ); + OUT_BATCH( clear_color ); + ADVANCE_BATCH(); + } + + if ( flags & (DD_STENCIL_BIT | DD_DEPTH_BIT) ) { + BEGIN_BATCH( 6); + OUT_BATCH( D_CMD ); + OUT_BATCH( BR13 ); + OUT_BATCH( (b.y1 << 16) | b.x1 ); + OUT_BATCH( (b.y2 << 16) | b.x2 ); + OUT_BATCH( intelScreen->depthOffset ); + OUT_BATCH( clear_depth ); + ADVANCE_BATCH(); + } + } + } + intelFlushBatchLocked( intel, GL_TRUE, GL_FALSE, GL_TRUE ); + UNLOCK_HARDWARE( intel ); +} + + + + +void intelDestroyBatchBuffer( GLcontext *ctx ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + + if (intel->alloc.ptr) { + intelFreeAGP( intel, intel->alloc.ptr ); + intel->alloc.ptr = 0; + } +} + + +void intelInitBatchBuffer( GLcontext *ctx ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + + if (!intel->intelScreen->allow_batchbuffer || getenv("INTEL_NO_BATCH")) { + intel->alloc.size = 8 * 1024; + intel->alloc.ptr = malloc( intel->alloc.size ); + intel->alloc.offset = 0; + } + else { + switch (intel->intelScreen->deviceID) { + case PCI_CHIP_I865_G: + /* HW bug? Seems to crash if batchbuffer crosses 4k boundary. + */ + intel->alloc.size = 8 * 1024; + break; + default: + /* This is the smallest amount of memory the kernel deals with. + * We'd ideally like to make this smaller. + */ + intel->alloc.size = 1 << intel->intelScreen->logTextureGranularity; + break; + } + + intel->alloc.ptr = intelAllocateAGP( intel, intel->alloc.size ); + if (intel->alloc.ptr) + intel->alloc.offset = + intelAgpOffsetFromVirtual( intel, intel->alloc.ptr ); + } + + if (!intel->alloc.ptr) { + FALLBACK(intel, INTEL_FALLBACK_NO_BATCHBUFFER, 1); + } + else { + intel->prim.flush = 0; + intel->vtbl.emit_invarient_state( intel ); + + /* Make sure this gets to the hardware, even if we have no cliprects: + */ + LOCK_HARDWARE( intel ); + intelFlushBatchLocked( intel, GL_TRUE, GL_FALSE, GL_TRUE ); + UNLOCK_HARDWARE( intel ); + } +} diff --git a/src/mesa/drivers/dri/i915/intel_batchbuffer.h b/src/mesa/drivers/dri/i915/intel_batchbuffer.h new file mode 100644 index 0000000..d96b3e2 --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_batchbuffer.h @@ -0,0 +1,103 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#ifndef INTEL_BATCHBUFFER_H +#define INTEL_BATCHBUFFER_H + +#include "intel_context.h" +#include "intel_ioctl.h" + + +#define BATCH_LOCALS GLubyte *batch_ptr; + +/* #define VERBOSE 0 */ +#ifndef VERBOSE +extern int VERBOSE; +#endif + + +#define BEGIN_BATCH(n) \ +do { \ + if (VERBOSE) fprintf(stderr, \ + "BEGIN_BATCH(%d) in %s, %d dwords free\n", \ + (n), __FUNCTION__, intel->batch.space/4); \ + if (intel->batch.space < (n)*4) \ + intelFlushBatch(intel, GL_TRUE); \ + batch_ptr = intel->batch.ptr; \ +} while (0) + +#define OUT_BATCH(n) \ +do { \ + *(GLuint *)batch_ptr = (n); \ + if (VERBOSE) fprintf(stderr, " -- %08x at %s/%d\n", (n), __FILE__, __LINE__); \ + batch_ptr += 4; \ +} while (0) + +#define ADVANCE_BATCH() \ +do { \ + if (VERBOSE) fprintf(stderr, "ADVANCE_BATCH()\n"); \ + intel->batch.space -= (batch_ptr - intel->batch.ptr); \ + intel->batch.ptr = batch_ptr; \ + assert(intel->batch.space >= 0); \ +} while(0) + +extern void intelInitBatchBuffer( GLcontext *ctx ); +extern void intelDestroyBatchBuffer( GLcontext *ctx ); + +extern void intelStartInlinePrimitive( intelContextPtr intel, GLuint prim ); +extern void intelWrapInlinePrimitive( intelContextPtr intel ); +extern void intelRestartInlinePrimitive( intelContextPtr intel ); +extern GLuint *intelEmitInlinePrimitiveLocked(intelContextPtr intel, + int primitive, int dwords, + int vertex_size); +extern void intelCopyBuffer( const __DRIdrawablePrivate *dpriv ); +extern void intelClearWithBlit(GLcontext *ctx, GLbitfield mask, GLboolean all, + GLint cx1, GLint cy1, GLint cw, GLint ch); + +extern void intelEmitCopyBlitLocked( intelContextPtr intel, + GLuint cpp, + GLshort src_pitch, + GLuint src_offset, + GLshort dst_pitch, + GLuint dst_offset, + GLshort srcx, GLshort srcy, + GLshort dstx, GLshort dsty, + GLshort w, GLshort h ); + +extern void intelEmitFillBlitLocked( intelContextPtr intel, + GLuint cpp, + GLshort dst_pitch, + GLuint dst_offset, + GLshort x, GLshort y, + GLshort w, GLshort h, + GLuint color ); + + + + +static __inline GLuint *intelExtendInlinePrimitive( intelContextPtr intel, + GLuint dwords ) +{ + GLuint sz = dwords * sizeof(GLuint); + GLuint *ptr; + + if (intel->batch.space < sz) { + intelWrapInlinePrimitive( intel ); +/* assert(intel->batch.space >= sz); */ + } + +/* assert(intel->prim.primitive != ~0); */ + ptr = (GLuint *)intel->batch.ptr; + intel->batch.ptr += sz; + intel->batch.space -= sz; + + return ptr; +} + + + +#endif diff --git a/src/mesa/drivers/dri/i915/intel_context.c b/src/mesa/drivers/dri/i915/intel_context.c new file mode 100644 index 0000000..9e11646 --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_context.c @@ -0,0 +1,666 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + + +#include "glheader.h" +#include "context.h" +#include "matrix.h" +#include "simple_list.h" +#include "extensions.h" +#include "imports.h" + +#include "swrast/swrast.h" +#include "swrast_setup/swrast_setup.h" +#include "tnl/tnl.h" +#include "array_cache/acache.h" + +#include "tnl/t_pipeline.h" +#include "tnl/t_vertex.h" + +#include "drivers/common/driverfuncs.h" + +#include "intel_screen.h" + +#include "i830_dri.h" +#include "i830_common.h" + +#include "intel_tex.h" +#include "intel_span.h" +#include "intel_tris.h" +#include "intel_ioctl.h" +#include "intel_batchbuffer.h" + +#include "utils.h" +#ifndef INTEL_DEBUG +int INTEL_DEBUG = (0); +#endif + +#ifndef VERBOSE +int VERBOSE = 0; +#endif + +#if DEBUG_LOCKING +char *prevLockFile; +int prevLockLine; +#endif + +const char __driConfigOptions[] = { 0 }; +const GLuint __driNConfigOptions = 0; + +/*************************************** + * Mesa's Driver Functions + ***************************************/ + +#define DRIVER_DATE "20040528" + +const GLubyte *intelGetString( GLcontext *ctx, GLenum name ) +{ + const char * chipset; + static char buffer[128]; + + switch (name) { + case GL_VENDOR: + return (GLubyte *)"Tungsten Graphics, Inc"; + break; + + case GL_RENDERER: + switch (INTEL_CONTEXT(ctx)->intelScreen->deviceID) { + case PCI_CHIP_845_G: + chipset = "Intel(R) 845G"; break; + case PCI_CHIP_I830_M: + chipset = "Intel(R) 830M"; break; + case PCI_CHIP_I855_GM: + chipset = "Intel(R) 852GM/855GM"; break; + case PCI_CHIP_I865_G: + chipset = "Intel(R) 865G"; break; + case PCI_CHIP_I915_G: + chipset = "Intel(R) 915G"; break; + default: + chipset = "Unknown Intel Chipset"; break; + } + + (void) driGetRendererString( buffer, chipset, DRIVER_DATE, 0 ); + return (GLubyte *) buffer; + + default: + return NULL; + } +} + +static void intelBufferSize(GLframebuffer *buffer, + GLuint *width, GLuint *height) +{ + GET_CURRENT_CONTEXT(ctx); + intelContextPtr intel = INTEL_CONTEXT(ctx); + /* Need to lock to make sure the driDrawable is uptodate. This + * information is used to resize Mesa's software buffers, so it has + * to be correct. + */ + LOCK_HARDWARE(intel); + *width = intel->driDrawable->w; + *height = intel->driDrawable->h; + UNLOCK_HARDWARE(intel); +} + + + +/* Extension strings exported by the intel driver. + * + * NOTE: See implementation of glGetString in each hw_context.c file: + * This set of extensions is overridden and many are not actually + * exported to the driver. They are however enabled internally as + * Mesa requires this when calculating things like GL version number. + */ +static const char * const card_extensions[] = +{ + "GL_APPLE_client_storage", + "GL_ARB_multisample", + "GL_ARB_multitexture", + "GL_ARB_texture_border_clamp", + "GL_ARB_texture_compression", + "GL_ARB_texture_env_add", + "GL_ARB_texture_env_combine", + "GL_ARB_texture_env_dot3", + "GL_ARB_texture_mirrored_repeat", + "GL_ARB_vertex_program", + "GL_EXT_blend_color", + "GL_EXT_blend_func_separate", + "GL_EXT_blend_minmax", + "GL_EXT_blend_subtract", + "GL_EXT_fog_coord", + "GL_EXT_secondary_color", + "GL_EXT_stencil_wrap", + "GL_EXT_texture_edge_clamp", + "GL_EXT_texture_env_add", + "GL_EXT_texture_env_combine", + "GL_EXT_texture_env_dot3", + "GL_EXT_texture_filter_anisotropic", + "GL_EXT_texture_lod_bias", + "GL_IBM_texture_mirrored_repeat", + "GL_INGR_blend_func_separate", + "GL_MESA_pack_invert", + "GL_MESA_ycbcr_texture", + "GL_NV_texture_rectangle", + "GL_NV_vertex_program", + +/* New in final: + */ + "GL_ARB_vertex_buffer_object", + "GL_ARB_window_pos", + "GL_EXT_multi_draw_arrays", + "GL_EXT_abgr", + "GL_EXT_bgra", + + + "GL_SGIS_generate_mipmap", + "GL_SGIS_texture_border_clamp", + "GL_SGIS_texture_edge_clamp", + NULL +}; + + +extern const struct tnl_pipeline_stage _intel_render_stage; + +static 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, +}; + + +static const struct dri_debug_control debug_control[] = +{ + { "fall", DEBUG_FALLBACKS }, + { "tex", DEBUG_TEXTURE }, + { "ioctl", DEBUG_IOCTL }, + { "prim", DEBUG_PRIMS }, + { "vert", DEBUG_VERTS }, + { "state", DEBUG_STATE }, + { "verb", DEBUG_VERBOSE }, + { "dri", DEBUG_DRI }, + { "dma", DEBUG_DMA }, + { "san", DEBUG_SANITY }, + { "sync", DEBUG_SYNC }, + { "sleep", DEBUG_SLEEP }, + { "pix", DEBUG_PIXEL }, + { NULL, 0 } +}; + + +static void intelInvalidateState( GLcontext *ctx, GLuint new_state ) +{ + _swrast_InvalidateState( ctx, new_state ); + _swsetup_InvalidateState( ctx, new_state ); + _ac_InvalidateState( ctx, new_state ); + _tnl_InvalidateState( ctx, new_state ); + _tnl_invalidate_vertex_state( ctx, new_state ); + INTEL_CONTEXT(ctx)->NewGLState |= new_state; +} + + +void intelInitDriverFunctions( struct dd_function_table *functions ) +{ + _mesa_init_driver_functions( functions ); + + functions->Flush = intelFlush; + functions->Clear = intelClear; + functions->Finish = intelFinish; + functions->GetBufferSize = intelBufferSize; + functions->ResizeBuffers = _swrast_alloc_buffers; + functions->GetString = intelGetString; + functions->UpdateState = intelInvalidateState; + functions->CopyColorTable = _swrast_CopyColorTable; + functions->CopyColorSubTable = _swrast_CopyColorSubTable; + functions->CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D; + functions->CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D; + + intelInitTextureFuncs( functions ); + intelInitPixelFuncs( functions ); + intelInitStateFuncs( functions ); +} + + + +GLboolean intelInitContext( intelContextPtr intel, + const __GLcontextModes *mesaVis, + __DRIcontextPrivate *driContextPriv, + void *sharedContextPrivate, + struct dd_function_table *functions ) +{ + GLcontext *ctx = &intel->ctx; + GLcontext *shareCtx = (GLcontext *) sharedContextPrivate; + __DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv; + intelScreenPrivate *intelScreen = (intelScreenPrivate *)sPriv->private; + drmI830Sarea *saPriv = (drmI830Sarea *) + (((GLubyte *)sPriv->pSAREA)+intelScreen->sarea_priv_offset); + + if (!_mesa_initialize_context(&intel->ctx, + mesaVis, shareCtx, + functions, + (void*) intel)) + return GL_FALSE; + + driContextPriv->driverPrivate = intel; + intel->intelScreen = intelScreen; + intel->driScreen = sPriv; + intel->sarea = saPriv; + + + (void) memset( intel->texture_heaps, 0, sizeof( intel->texture_heaps ) ); + make_empty_list( & intel->swapped ); + + ctx->Const.MaxTextureMaxAnisotropy = 2.0; + + ctx->Const.MinLineWidth = 1.0; + ctx->Const.MinLineWidthAA = 1.0; + ctx->Const.MaxLineWidth = 3.0; + ctx->Const.MaxLineWidthAA = 3.0; + ctx->Const.LineWidthGranularity = 1.0; + + ctx->Const.MinPointSize = 1.0; + ctx->Const.MinPointSizeAA = 1.0; + ctx->Const.MaxPointSize = 255.0; + ctx->Const.MaxPointSizeAA = 3.0; + ctx->Const.PointSizeGranularity = 1.0; + + /* Initialize the software rasterizer and helper modules. */ + _swrast_CreateContext( ctx ); + _ac_CreateContext( ctx ); + _tnl_CreateContext( ctx ); + _swsetup_CreateContext( ctx ); + + /* Install the customized pipeline: */ + _tnl_destroy_pipeline( ctx ); + _tnl_install_pipeline( ctx, intel_pipeline ); + + /* Configure swrast to match hardware characteristics: */ + _swrast_allow_pixel_fog( ctx, GL_FALSE ); + _swrast_allow_vertex_fog( ctx, GL_TRUE ); + + /* Dri stuff */ + intel->hHWContext = driContextPriv->hHWContext; + intel->driFd = sPriv->fd; + intel->driHwLock = (drmLock *) &sPriv->pSAREA->lock; + + intel->hw_stencil = mesaVis->stencilBits && mesaVis->depthBits == 24; + intel->hw_stipple = 1; + + switch(mesaVis->depthBits) { + case 0: /* what to do in this case? */ + case 16: + intel->depth_scale = 1.0/0xffff; + intel->polygon_offset_scale = 1.0/0xffff; + intel->depth_clear_mask = ~0; + intel->ClearDepth = 0xffff; + break; + case 24: + intel->depth_scale = 1.0/0xffffff; + intel->polygon_offset_scale = 2.0/0xffffff; /* req'd to pass glean */ + intel->depth_clear_mask = 0x00ffffff; + intel->stencil_clear_mask = 0xff000000; + intel->ClearDepth = 0x00ffffff; + break; + default: + assert(0); + break; + } + + /* Initialize swrast, tnl driver tables: */ + intelInitSpanFuncs( ctx ); + intelInitTriFuncs( ctx ); + + + intel->RenderIndex = ~0; + + intel->do_irqs = (intel->intelScreen->irq_active && + !getenv("INTEL_NO_IRQS")); + + _math_matrix_ctr (&intel->ViewportMatrix); + + driInitExtensions( ctx, card_extensions, GL_TRUE ); + +/* driInitTextureObjects( ctx, & intel->swapped, */ +/* DRI_TEXMGR_DO_TEXTURE_1D | */ +/* DRI_TEXMGR_DO_TEXTURE_2D | */ +/* DRI_TEXMGR_DO_TEXTURE_RECT ); */ + + + intel->prim.flush = intelInitBatchBuffer; + intel->prim.primitive = ~0; + + +#if DO_DEBUG + INTEL_DEBUG = driParseDebugString( getenv( "INTEL_DEBUG" ), + debug_control ); + INTEL_DEBUG |= driParseDebugString( getenv( "INTEL_DEBUG" ), + debug_control ); +#endif + +#ifndef VERBOSE + if (getenv("INTEL_VERBOSE")) + VERBOSE=1; +#endif + + if (getenv("INTEL_NO_RAST") || + getenv("INTEL_NO_RAST")) { + fprintf(stderr, "disabling 3D rasterization\n"); + FALLBACK(intel, INTEL_FALLBACK_USER, 1); + } + + return GL_TRUE; +} + +void intelDestroyContext(__DRIcontextPrivate *driContextPriv) +{ + intelContextPtr intel = (intelContextPtr) driContextPriv->driverPrivate; + + assert(intel); /* should never be null */ + if (intel) { + GLboolean release_texture_heaps; + + + intel->vtbl.destroy( intel ); + + release_texture_heaps = (intel->ctx.Shared->RefCount == 1); + _swsetup_DestroyContext (&intel->ctx); + _tnl_DestroyContext (&intel->ctx); + _ac_DestroyContext (&intel->ctx); + + _swrast_DestroyContext (&intel->ctx); + intel->Fallback = 0; /* don't call _swrast_Flush later */ + + intelDestroyBatchBuffer(&intel->ctx); + + + if ( release_texture_heaps ) { + /* This share group is about to go away, free our private + * texture object data. + */ + int i; + + for ( i = 0 ; i < intel->nr_heaps ; i++ ) { + driDestroyTextureHeap( intel->texture_heaps[ i ] ); + intel->texture_heaps[ i ] = NULL; + } + + assert( is_empty_list( & intel->swapped ) ); + } + + /* free the Mesa context */ + _mesa_destroy_context(&intel->ctx); + } +} + +void intelSetFrontClipRects( intelContextPtr intel ) +{ + __DRIdrawablePrivate *dPriv = intel->driDrawable; + + if (!dPriv) return; + + intel->numClipRects = dPriv->numClipRects; + intel->pClipRects = dPriv->pClipRects; + intel->drawX = dPriv->x; + intel->drawY = dPriv->y; +} + + +void intelSetBackClipRects( intelContextPtr intel ) +{ + __DRIdrawablePrivate *dPriv = intel->driDrawable; + + if (!dPriv) return; + + if (intel->sarea->pf_enabled == 0 && dPriv->numBackClipRects == 0) { + intel->numClipRects = dPriv->numClipRects; + intel->pClipRects = dPriv->pClipRects; + intel->drawX = dPriv->x; + intel->drawY = dPriv->y; + } else { + intel->numClipRects = dPriv->numBackClipRects; + intel->pClipRects = dPriv->pBackClipRects; + intel->drawX = dPriv->backX; + intel->drawY = dPriv->backY; + + if (dPriv->numBackClipRects == 1 && + dPriv->x == dPriv->backX && + dPriv->y == dPriv->backY) { + + /* Repeat the calculation of the back cliprect dimensions here + * as early versions of dri.a in the Xserver are incorrect. Try + * very hard not to restrict future versions of dri.a which + * might eg. allocate truly private back buffers. + */ + int x1, y1; + int x2, y2; + + x1 = dPriv->x; + y1 = dPriv->y; + x2 = dPriv->x + dPriv->w; + y2 = dPriv->y + dPriv->h; + + if (x1 < 0) x1 = 0; + if (y1 < 0) y1 = 0; + if (x2 > intel->intelScreen->width) x2 = intel->intelScreen->width; + if (y2 > intel->intelScreen->height) y2 = intel->intelScreen->height; + + if (x1 == dPriv->pBackClipRects[0].x1 && + y1 == dPriv->pBackClipRects[0].y1) { + + dPriv->pBackClipRects[0].x2 = x2; + dPriv->pBackClipRects[0].y2 = y2; + } + } + } +} + + +void intelWindowMoved( intelContextPtr intel ) +{ + switch (intel->ctx.Color._DrawDestMask) { + case DD_FRONT_LEFT_BIT: + intelSetFrontClipRects( intel ); + break; + case DD_BACK_LEFT_BIT: + intelSetBackClipRects( intel ); + break; + default: + /* glDrawBuffer(GL_NONE or GL_FRONT_AND_BACK): software fallback */ + intelSetFrontClipRects( intel ); + } +} + +GLboolean intelUnbindContext(__DRIcontextPrivate *driContextPriv) +{ + return GL_TRUE; +} + +GLboolean intelMakeCurrent(__DRIcontextPrivate *driContextPriv, + __DRIdrawablePrivate *driDrawPriv, + __DRIdrawablePrivate *driReadPriv) +{ + + if (driContextPriv) { + intelContextPtr intel = (intelContextPtr) driContextPriv->driverPrivate; + + if ( intel->driDrawable != driDrawPriv ) { + /* Shouldn't the readbuffer be stored also? */ + intel->driDrawable = driDrawPriv; + intelWindowMoved( intel ); + } + + _mesa_make_current2(&intel->ctx, + (GLframebuffer *) driDrawPriv->driverPrivate, + (GLframebuffer *) driReadPriv->driverPrivate); + + if (!intel->ctx.Viewport.Width) + _mesa_set_viewport(&intel->ctx, 0, 0, driDrawPriv->w, driDrawPriv->h); + } else { + _mesa_make_current(0,0); + } + + return GL_TRUE; +} + +void intelGetLock( intelContextPtr intel, GLuint flags ) +{ + __DRIdrawablePrivate *dPriv = intel->driDrawable; + __DRIscreenPrivate *sPriv = intel->driScreen; + drmI830Sarea * sarea = intel->sarea; + int me = intel->hHWContext; + unsigned i; + + drmGetLock(intel->driFd, intel->hHWContext, flags); + + /* If the window moved, may need to set a new cliprect now. + * + * NOTE: This releases and regains the hw lock, so all state + * checking must be done *after* this call: + */ + if (dPriv) + DRI_VALIDATE_DRAWABLE_INFO(sPriv, dPriv); + + /* If we lost context, need to dump all registers to hardware. + * Note that we don't care about 2d contexts, even if they perform + * accelerated commands, so the DRI locking in the X server is even + * more broken than usual. + */ + + if (sarea->ctxOwner != me) { + intel->perf_boxes |= I830_BOX_LOST_CONTEXT; + sarea->ctxOwner = me; + } + + /* Shared texture managment - if another client has played with + * texture space, figure out which if any of our textures have been + * ejected, and update our global LRU. + */ + + for ( i = 0 ; i < intel->nr_heaps ; i++ ) { + DRI_AGE_TEXTURES( intel->texture_heaps[ i ] ); + } + + if (dPriv && intel->lastStamp != dPriv->lastStamp) { + intelWindowMoved( intel ); + intel->lastStamp = dPriv->lastStamp; + } +} + +void intelSwapBuffers( __DRIdrawablePrivate *dPriv ) +{ + if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) { + intelContextPtr intel; + GLcontext *ctx; + intel = (intelContextPtr) dPriv->driContextPriv->driverPrivate; + ctx = &intel->ctx; + if (ctx->Visual.doubleBufferMode) { + _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */ + if ( 0 /*intel->doPageFlip*/ ) { /* doPageFlip is never set !!! */ + intelPageFlip( dPriv ); + } else { + intelCopyBuffer( dPriv ); + } + } + } else { + /* XXX this shouldn't be an error but we can't handle it for now */ + fprintf(stderr, "%s: drawable has no context!\n", __FUNCTION__); + } +} + + +void intelInitState( GLcontext *ctx ) +{ + /* Mesa should do this for us: + */ + ctx->Driver.AlphaFunc( ctx, + ctx->Color.AlphaFunc, + ctx->Color.AlphaRef); + + ctx->Driver.BlendColor( ctx, + ctx->Color.BlendColor ); + + ctx->Driver.BlendEquationSeparate( ctx, + ctx->Color.BlendEquationRGB, + ctx->Color.BlendEquationA); + + ctx->Driver.BlendFuncSeparate( ctx, + ctx->Color.BlendSrcRGB, + ctx->Color.BlendDstRGB, + ctx->Color.BlendSrcA, + ctx->Color.BlendDstA); + + ctx->Driver.ColorMask( ctx, + ctx->Color.ColorMask[RCOMP], + ctx->Color.ColorMask[GCOMP], + ctx->Color.ColorMask[BCOMP], + ctx->Color.ColorMask[ACOMP]); + + ctx->Driver.CullFace( ctx, ctx->Polygon.CullFaceMode ); + ctx->Driver.DepthFunc( ctx, ctx->Depth.Func ); + ctx->Driver.DepthMask( ctx, ctx->Depth.Mask ); + + ctx->Driver.Enable( ctx, GL_ALPHA_TEST, ctx->Color.AlphaEnabled ); + ctx->Driver.Enable( ctx, GL_BLEND, ctx->Color.BlendEnabled ); + ctx->Driver.Enable( ctx, GL_COLOR_LOGIC_OP, ctx->Color.ColorLogicOpEnabled ); + ctx->Driver.Enable( ctx, GL_COLOR_SUM, ctx->Fog.ColorSumEnabled ); + ctx->Driver.Enable( ctx, GL_CULL_FACE, ctx->Polygon.CullFlag ); + ctx->Driver.Enable( ctx, GL_DEPTH_TEST, ctx->Depth.Test ); + ctx->Driver.Enable( ctx, GL_DITHER, ctx->Color.DitherFlag ); + ctx->Driver.Enable( ctx, GL_FOG, ctx->Fog.Enabled ); + ctx->Driver.Enable( ctx, GL_LIGHTING, ctx->Light.Enabled ); + ctx->Driver.Enable( ctx, GL_LINE_SMOOTH, ctx->Line.SmoothFlag ); + ctx->Driver.Enable( ctx, GL_POLYGON_STIPPLE, ctx->Polygon.StippleFlag ); + ctx->Driver.Enable( ctx, GL_SCISSOR_TEST, ctx->Scissor.Enabled ); + ctx->Driver.Enable( ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled ); + ctx->Driver.Enable( ctx, GL_TEXTURE_1D, GL_FALSE ); + ctx->Driver.Enable( ctx, GL_TEXTURE_2D, GL_FALSE ); + ctx->Driver.Enable( ctx, GL_TEXTURE_RECTANGLE_NV, GL_FALSE ); + ctx->Driver.Enable( ctx, GL_TEXTURE_3D, GL_FALSE ); + ctx->Driver.Enable( ctx, GL_TEXTURE_CUBE_MAP, GL_FALSE ); + + ctx->Driver.Fogfv( ctx, GL_FOG_COLOR, ctx->Fog.Color ); + ctx->Driver.Fogfv( ctx, GL_FOG_MODE, 0 ); + ctx->Driver.Fogfv( ctx, GL_FOG_DENSITY, &ctx->Fog.Density ); + ctx->Driver.Fogfv( ctx, GL_FOG_START, &ctx->Fog.Start ); + ctx->Driver.Fogfv( ctx, GL_FOG_END, &ctx->Fog.End ); + + ctx->Driver.FrontFace( ctx, ctx->Polygon.FrontFace ); + + { + GLfloat f = (GLfloat)ctx->Light.Model.ColorControl; + ctx->Driver.LightModelfv( ctx, GL_LIGHT_MODEL_COLOR_CONTROL, &f ); + } + + ctx->Driver.LineWidth( ctx, ctx->Line.Width ); + ctx->Driver.LogicOpcode( ctx, ctx->Color.LogicOp ); + ctx->Driver.PointSize( ctx, ctx->Point.Size ); + ctx->Driver.PolygonStipple( ctx, (const GLubyte *)ctx->PolygonStipple ); + ctx->Driver.Scissor( ctx, ctx->Scissor.X, ctx->Scissor.Y, + ctx->Scissor.Width, ctx->Scissor.Height ); + ctx->Driver.ShadeModel( ctx, ctx->Light.ShadeModel ); + ctx->Driver.StencilFunc( ctx, + ctx->Stencil.Function[0], + ctx->Stencil.Ref[0], + ctx->Stencil.ValueMask[0] ); + ctx->Driver.StencilMask( ctx, ctx->Stencil.WriteMask[0] ); + ctx->Driver.StencilOp( ctx, + ctx->Stencil.FailFunc[0], + ctx->Stencil.ZFailFunc[0], + ctx->Stencil.ZPassFunc[0]); + + + ctx->Driver.DrawBuffer( ctx, ctx->Color.DrawBuffer ); +} diff --git a/src/mesa/drivers/dri/i915/intel_context.h b/src/mesa/drivers/dri/i915/intel_context.h new file mode 100644 index 0000000..c72ef61 --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_context.h @@ -0,0 +1,431 @@ + +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#ifndef INTELCONTEXT_INC +#define INTELCONTEXT_INC + + + +#include "mtypes.h" +#include "drm.h" +#include "mm.h" +#include "texmem.h" + +#include "intel_screen.h" +#include "i830_common.h" +#include "tnl/t_vertex.h" + +#define TAG(x) intel##x +#include "tnl_dd/t_dd_vertex.h" +#undef TAG + +#define DV_PF_555 (1<<8) +#define DV_PF_565 (2<<8) +#define DV_PF_8888 (3<<8) + +#define INTEL_CONTEXT(ctx) ((intelContextPtr)(ctx)) + +typedef struct intel_context intelContext; +typedef struct intel_context *intelContextPtr; +typedef struct intel_texture_object *intelTextureObjectPtr; + +typedef void (*intel_tri_func)(intelContextPtr, intelVertex *, intelVertex *, + intelVertex *); +typedef void (*intel_line_func)(intelContextPtr, intelVertex *, intelVertex *); +typedef void (*intel_point_func)(intelContextPtr, intelVertex *); + +#define INTEL_FALLBACK_DRAW_BUFFER 0x1 +#define INTEL_FALLBACK_READ_BUFFER 0x2 +#define INTEL_FALLBACK_USER 0x4 +#define INTEL_FALLBACK_NO_BATCHBUFFER 0x8 +#define INTEL_FALLBACK_NO_TEXMEM 0x10 +#define INTEL_FALLBACK_RENDERMODE 0x20 + +extern void intelFallback( intelContextPtr intel, GLuint bit, GLboolean mode ); +#define FALLBACK( intel, bit, mode ) intelFallback( intel, bit, mode ) + + +#define INTEL_TEX_MAXLEVELS 10 + + +struct intel_texture_object +{ + driTextureObject base; /* the parent class */ + + GLuint texelBytes; + GLuint age; + GLuint Pitch; + GLuint Height; + GLuint TextureOffset; + GLubyte *BufAddr; + + GLuint min_level; + GLuint max_level; + GLuint depth_pitch; + + struct { + const struct gl_texture_image *image; + GLuint offset; /* into BufAddr */ + GLuint height; + GLuint internalFormat; + } image[6][INTEL_TEX_MAXLEVELS]; + + GLuint dirty; + GLuint firstLevel,lastLevel; +}; + + +struct intel_context +{ + GLcontext ctx; /* the parent class */ + + struct { + void (*destroy)( intelContextPtr intel ); + void (*emit_state)( intelContextPtr intel ); + void (*emit_invarient_state)( intelContextPtr intel ); + void (*lost_hardware)( intelContextPtr intel ); + void (*update_texture_state)( intelContextPtr intel ); + + void (*render_start)( intelContextPtr intel ); + void (*set_draw_offset)( intelContextPtr intel, int offset ); + void (*emit_flush)( intelContextPtr intel ); + + void (*reduced_primitive_state)( intelContextPtr intel, GLenum rprim ); + + GLboolean (*check_vertex_size)( intelContextPtr intel, GLuint expected ); + + void (*clear_with_tris)( intelContextPtr intel, GLbitfield mask, + GLboolean all, + GLint cx, GLint cy, GLint cw, GLint ch); + + intelTextureObjectPtr (*alloc_tex_obj)( struct gl_texture_object *tObj ); + + } vtbl; + + GLint refcount; + GLuint Fallback; + GLuint NewGLState; + + struct { + GLuint start_offset; + GLint size; + GLint space; + GLubyte *ptr; + } batch; + + struct { + void *ptr; + GLint size; + GLuint offset; + GLuint active_buf; + GLuint irq_emitted; + } alloc; + + struct { + GLuint primitive; + GLubyte *start_ptr; + void (*flush)( GLcontext * ); + } prim; + + GLboolean locked; + + GLubyte clear_red; + GLubyte clear_green; + GLubyte clear_blue; + GLubyte clear_alpha; + GLuint ClearColor; + GLuint ClearDepth; + + GLuint coloroffset; + GLuint specoffset; + + /* Support for duplicating XYZW as WPOS parameter (crutch for I915). + */ + GLuint wpos_offset; + GLuint wpos_size; + + struct tnl_attr_map vertex_attrs[VERT_ATTRIB_MAX]; + GLuint vertex_attr_count; + + GLfloat depth_scale; + GLfloat polygon_offset_scale; /* dependent on depth_scale, bpp */ + GLuint depth_clear_mask; + GLuint stencil_clear_mask; + + GLboolean hw_stencil; + GLboolean hw_stipple; + + /* Texture object bookkeeping + */ + GLuint nr_heaps; + driTexHeap * texture_heaps[1]; + driTextureObject swapped; + GLuint lastStamp; + + struct intel_texture_object *CurrentTexObj[MAX_TEXTURE_UNITS]; + + /* State for intelvb.c and inteltris.c. + */ + GLuint RenderIndex; + GLmatrix ViewportMatrix; + GLenum render_primitive; + GLenum reduced_primitive; + GLuint vertex_size; + char *verts; /* points to tnl->clipspace.vertex_buf */ + + + /* Fallback rasterization functions + */ + intel_point_func draw_point; + intel_line_func draw_line; + intel_tri_func draw_tri; + + /* These refer to the current draw (front vs. back) buffer: + */ + char *drawMap; /* draw buffer address in virtual mem */ + char *readMap; + GLuint drawOffset; /* agp offset of drawbuffer */ + int drawX; /* origin of drawable in draw buffer */ + int drawY; + GLuint numClipRects; /* cliprects for that buffer */ + drm_clip_rect_t *pClipRects; + + int dirtyAge; + int perf_boxes; + int do_irqs; + + GLboolean scissor; + drm_clip_rect_t draw_rect; + drm_clip_rect_t scissor_rect; + + drm_context_t hHWContext; + drmLock *driHwLock; + int driFd; + + __DRIdrawablePrivate *driDrawable; + __DRIscreenPrivate *driScreen; + intelScreenPrivate *intelScreen; + drmI830Sarea *sarea; +}; + + +#define DEBUG_LOCKING 1 + +#if DEBUG_LOCKING +extern char *prevLockFile; +extern int prevLockLine; + +#define DEBUG_LOCK() \ + do { \ + prevLockFile = (__FILE__); \ + prevLockLine = (__LINE__); \ + } while (0) + +#define DEBUG_RESET() \ + do { \ + prevLockFile = 0; \ + prevLockLine = 0; \ + } while (0) + +/* Slightly less broken way of detecting recursive locking in a + * threaded environment. The right way to do this would be to make + * prevLockFile, prevLockLine thread-local. + * + * This technique instead checks to see if the same context is + * requesting the lock twice -- this will not catch application + * breakages where the same context is active in two different threads + * at once, but it will catch driver breakages (recursive locking) in + * threaded apps. + */ +#define DEBUG_CHECK_LOCK() \ + do { \ + if ( *((volatile int *)intel->driHwLock) == \ + (DRM_LOCK_HELD | intel->hHWContext) ) { \ + fprintf( stderr, \ + "LOCK SET!\n\tPrevious %s:%d\n\tCurrent: %s:%d\n", \ + prevLockFile, prevLockLine, __FILE__, __LINE__ ); \ + abort(); \ + } \ + } while (0) + +#else + +#define DEBUG_LOCK() +#define DEBUG_RESET() +#define DEBUG_CHECK_LOCK() + +#endif + + + + +/* Lock the hardware and validate our state. + */ +#define LOCK_HARDWARE( intel ) \ +do { \ + char __ret=0; \ + DEBUG_CHECK_LOCK(); \ + assert(!(intel)->locked); \ + DRM_CAS((intel)->driHwLock, (intel)->hHWContext, \ + (DRM_LOCK_HELD|(intel)->hHWContext), __ret); \ + if (__ret) \ + intelGetLock( (intel), 0 ); \ + DEBUG_LOCK(); \ + (intel)->locked = 1; \ +}while (0) + + + /* Unlock the hardware using the global current context + */ +#define UNLOCK_HARDWARE(intel) \ +do { \ + intel->locked = 0; \ + if (0) { \ + intel->perf_boxes |= intel->sarea->perf_boxes; \ + intel->sarea->perf_boxes = 0; \ + } \ + DRM_UNLOCK((intel)->driFd, (intel)->driHwLock, (intel)->hHWContext); \ + DEBUG_RESET(); \ +} while (0) + + +#define SUBPIXEL_X 0.125 +#define SUBPIXEL_Y 0.125 + +#define INTEL_FIREVERTICES(intel) \ +do { \ + if ((intel)->prim.flush) \ + (intel)->prim.flush(&(intel)->ctx); \ +} while (0) + +/* ================================================================ + * Color packing: + */ + +#define INTEL_PACKCOLOR4444(r,g,b,a) \ + ((((a) & 0xf0) << 8) | (((r) & 0xf0) << 4) | ((g) & 0xf0) | ((b) >> 4)) + +#define INTEL_PACKCOLOR1555(r,g,b,a) \ + ((((r) & 0xf8) << 7) | (((g) & 0xf8) << 2) | (((b) & 0xf8) >> 3) | \ + ((a) ? 0x8000 : 0)) + +#define INTEL_PACKCOLOR565(r,g,b) \ + ((((r) & 0xf8) << 8) | (((g) & 0xfc) << 3) | (((b) & 0xf8) >> 3)) + +#define INTEL_PACKCOLOR8888(r,g,b,a) \ + ((a<<24) | (r<<16) | (g<<8) | b) + + +#define INTEL_PACKCOLOR(format, r, g, b, a) \ +(format == DV_PF_555 ? INTEL_PACKCOLOR1555(r,g,b,a) : \ + (format == DV_PF_565 ? INTEL_PACKCOLOR565(r,g,b) : \ + (format == DV_PF_8888 ? INTEL_PACKCOLOR8888(r,g,b,a) : \ + 0))) + + + +/* ================================================================ + * From linux kernel i386 header files, copes with odd sizes better + * than COPY_DWORDS would: + */ +static __inline__ void * __memcpy(void * to, const void * from, size_t n) +{ + int d0, d1, d2; + __asm__ __volatile__( + "rep ; movsl\n\t" + "testb $2,%b4\n\t" + "je 1f\n\t" + "movsw\n" + "1:\ttestb $1,%b4\n\t" + "je 2f\n\t" + "movsb\n" + "2:" + : "=&c" (d0), "=&D" (d1), "=&S" (d2) + :"0" (n/4), "q" (n),"1" ((long) to),"2" ((long) from) + : "memory"); + return (to); +} + + + +/* ================================================================ + * Debugging: + */ +#define DO_DEBUG 1 +#if DO_DEBUG +extern int INTEL_DEBUG; +#else +#define INTEL_DEBUG 0 +#endif + +#define DEBUG_TEXTURE 0x1 +#define DEBUG_STATE 0x2 +#define DEBUG_IOCTL 0x4 +#define DEBUG_PRIMS 0x8 +#define DEBUG_VERTS 0x10 +#define DEBUG_FALLBACKS 0x20 +#define DEBUG_VERBOSE 0x40 +#define DEBUG_DRI 0x80 +#define DEBUG_DMA 0x100 +#define DEBUG_SANITY 0x200 +#define DEBUG_SYNC 0x400 +#define DEBUG_SLEEP 0x800 +#define DEBUG_PIXEL 0x1000 + + +#define PCI_CHIP_845_G 0x2562 +#define PCI_CHIP_I830_M 0x3577 +#define PCI_CHIP_I855_GM 0x3582 +#define PCI_CHIP_I865_G 0x2572 +#define PCI_CHIP_I915_G 0x2582 + + +/* ================================================================ + * intel_context.c: + */ + +extern void intelInitDriverFunctions( struct dd_function_table *functions ); + +extern GLboolean intelInitContext( intelContextPtr intel, + const __GLcontextModes *mesaVis, + __DRIcontextPrivate *driContextPriv, + void *sharedContextPrivate, + struct dd_function_table *functions ); + +extern void intelGetLock(intelContextPtr intel, GLuint flags); +extern void intelSetBackClipRects(intelContextPtr intel); +extern void intelSetFrontClipRects(intelContextPtr intel); +extern void intelWindowMoved( intelContextPtr intel ); + +extern void intelInitState( GLcontext *ctx ); +extern const GLubyte *intelGetString( GLcontext *ctx, GLenum name ); + + +/* ================================================================ + * intel_state.c: + */ +extern void intelInitStateFuncs( struct dd_function_table *functions ); + + +/* ================================================================ + * intel_ioctl.c: + */ +extern void intel_dump_batchbuffer( long offset, + int *ptr, + int count ); + + +/* ================================================================ + * intel_pixel.c: + */ +extern void intelInitPixelFuncs( struct dd_function_table *functions ); + + + +#endif + diff --git a/src/mesa/drivers/dri/i915/intel_ioctl.c b/src/mesa/drivers/dri/i915/intel_ioctl.c new file mode 100644 index 0000000..2fa88b5 --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_ioctl.c @@ -0,0 +1,585 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + + +#include +#include +#include + +#include "mtypes.h" +#include "context.h" +#include "swrast/swrast.h" + +#include "intel_context.h" +#include "intel_ioctl.h" +#include "intel_batchbuffer.h" +#include "drm.h" + + + +static int intelEmitIrqLocked( intelContextPtr intel ) +{ + drmI830IrqEmit ie; + int ret, seq; + + assert(((*(int *)intel->driHwLock) & ~DRM_LOCK_CONT) == + (DRM_LOCK_HELD|intel->hHWContext)); + + ie.irq_seq = &seq; + + ret = drmCommandWriteRead( intel->driFd, DRM_I830_IRQ_EMIT, + &ie, sizeof(ie) ); + if ( ret ) { + fprintf( stderr, "%s: drmI830IrqEmit: %d\n", __FUNCTION__, ret ); + exit(1); + } + + if (0) + fprintf(stderr, "%s --> %d\n", __FUNCTION__, seq ); + + return seq; +} + +static void intelWaitIrq( intelContextPtr intel, int seq ) +{ + drmI830IrqWait iw; + int ret; + + if (0) + fprintf(stderr, "%s %d\n", __FUNCTION__, seq ); + + iw.irq_seq = seq; + + do { + ret = drmCommandWrite( intel->driFd, DRM_I830_IRQ_WAIT, &iw, sizeof(iw) ); + } while (ret == -EAGAIN || ret == -EINTR); + + if ( ret ) { + fprintf( stderr, "%s: drmI830IrqWait: %d\n", __FUNCTION__, ret ); + if (0) + intel_dump_batchbuffer( intel->alloc.offset, + intel->alloc.ptr, + intel->alloc.size ); + exit(1); + } +} + + + +static void age_intel( intelContextPtr intel, int age ) +{ + GLuint i; + + for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++) + if (intel->CurrentTexObj[i]) + intel->CurrentTexObj[i]->age = age; +} + +void intel_dump_batchbuffer( long offset, + int *ptr, + int count ) +{ + int i; + fprintf(stderr, "\n\n\nSTART BATCH (%d dwords):\n", count); + for (i = 0; i < count/4; i += 4) + fprintf(stderr, "\t0x%x: 0x%08x 0x%08x 0x%08x 0x%08x\n", + offset + i*4, ptr[i], ptr[i+1], ptr[i+2], ptr[i+3]); + fprintf(stderr, "END BATCH\n\n\n"); +} + +void intelRefillBatchLocked( intelContextPtr intel, GLboolean allow_unlock ) +{ + GLuint last_irq = intel->alloc.irq_emitted; + GLuint half = intel->alloc.size / 2; + GLuint buf = (intel->alloc.active_buf ^= 1); + + intel->alloc.irq_emitted = intelEmitIrqLocked( intel ); + + if (last_irq) { + if (allow_unlock) UNLOCK_HARDWARE( intel ); + intelWaitIrq( intel, last_irq ); + if (allow_unlock) LOCK_HARDWARE( intel ); + } + + if (0) + fprintf(stderr, "%s: now using half %d\n", __FUNCTION__, buf); + + intel->batch.start_offset = intel->alloc.offset + buf * half; + intel->batch.ptr = (char *)intel->alloc.ptr + buf * half; + intel->batch.size = half - 8; + intel->batch.space = half - 8; + assert(intel->batch.space >= 0); +} + +#define MI_BATCH_BUFFER_END (0xA<<23) + + +void intelFlushBatchLocked( intelContextPtr intel, + GLboolean ignore_cliprects, + GLboolean refill, + GLboolean allow_unlock) +{ + drmI830BatchBuffer batch; + + assert(intel->locked); + + if (0) + fprintf(stderr, "%s used %d of %d offset %x..%x refill %d\n", + __FUNCTION__, + (intel->batch.size - intel->batch.space), + intel->batch.size, + intel->batch.start_offset, + intel->batch.start_offset + + (intel->batch.size - intel->batch.space), + refill); + + /* Throw away non-effective packets. Won't work once we have + * hardware contexts which would preserve statechanges beyond a + * single buffer. + */ + if (intel->numClipRects == 0 && !ignore_cliprects) { + intel->batch.space = intel->batch.size; + + /* Without this yeild, an application with no cliprects can hog + * the hardware. Without unlocking, the effect is much worse - + * effectively a lock-out of other contexts. + */ + if (allow_unlock) { + UNLOCK_HARDWARE( intel ); + sched_yield(); + LOCK_HARDWARE( intel ); + } + + /* Note that any state thought to have been emitted actually + * hasn't: + */ + intel->vtbl.lost_hardware( intel ); + } + + if (intel->batch.space != intel->batch.size) { + batch.start = intel->batch.start_offset; + batch.used = intel->batch.size - intel->batch.space; + batch.cliprects = intel->pClipRects; + batch.num_cliprects = ignore_cliprects ? 0 : intel->numClipRects; + batch.DR1 = 0; + batch.DR4 = ((((GLuint)intel->drawX) & 0xffff) | + (((GLuint)intel->drawY) << 16)); + + if (intel->alloc.offset) { + if ((batch.used & 0x4) == 0) { + ((int *)intel->batch.ptr)[0] = 0; + ((int *)intel->batch.ptr)[1] = MI_BATCH_BUFFER_END; + batch.used += 0x8; + intel->batch.ptr += 0x8; + } + else { + ((int *)intel->batch.ptr)[0] = MI_BATCH_BUFFER_END; + batch.used += 0x4; + intel->batch.ptr += 0x4; + } + } + + if (0) + intel_dump_batchbuffer( batch.start, + (int *)(intel->batch.ptr - batch.used), + batch.used ); + + if (0) + fprintf(stderr, "%s: 0x%x..0x%x DR4: %x cliprects: %d\n", + __FUNCTION__, + batch.start, + batch.start + batch.used, + batch.DR4, batch.num_cliprects); + + intel->batch.start_offset += batch.used; + intel->batch.size -= batch.used; + + if (intel->batch.size < 8) { + refill = GL_TRUE; + intel->batch.space = intel->batch.size = 0; + } + else { + intel->batch.size -= 8; + intel->batch.space = intel->batch.size; + } + + + assert(intel->batch.space >= 0); + assert(batch.start >= intel->alloc.offset); + assert(batch.start < intel->alloc.offset + intel->alloc.size); + assert(batch.start + batch.used > intel->alloc.offset); + assert(batch.start + batch.used <= + intel->alloc.offset + intel->alloc.size); + + + if (intel->alloc.offset) { + if (drmCommandWrite (intel->driFd, DRM_I830_BATCHBUFFER, &batch, + sizeof(batch))) { + fprintf(stderr, "DRM_I830_BATCHBUFFER: %d\n", -errno); + UNLOCK_HARDWARE(intel); + exit(1); + } + } else { + drmI830CmdBuffer cmd; + cmd.buf = intel->alloc.ptr + batch.start; + cmd.sz = batch.used; + cmd.DR1 = batch.DR1; + cmd.DR4 = batch.DR4; + cmd.num_cliprects = batch.num_cliprects; + cmd.cliprects = batch.cliprects; + + if (drmCommandWrite (intel->driFd, DRM_I830_CMDBUFFER, &cmd, + sizeof(cmd))) { + fprintf(stderr, "DRM_I830_CMDBUFFER: %d\n", -errno); + UNLOCK_HARDWARE(intel); + exit(1); + } + } + + + age_intel(intel, intel->sarea->last_enqueue); + + /* FIXME: use hardware contexts to avoid 'losing' hardware after + * each buffer flush. + */ + intel->vtbl.lost_hardware( intel ); + } + + if (refill) + intelRefillBatchLocked( intel, allow_unlock ); +} + +void intelFlushBatch( intelContextPtr intel, GLboolean refill ) +{ + if (intel->locked) { + intelFlushBatchLocked( intel, GL_FALSE, refill, GL_FALSE ); + } + else { + LOCK_HARDWARE(intel); + intelFlushBatchLocked( intel, GL_FALSE, refill, GL_TRUE ); + UNLOCK_HARDWARE(intel); + } +} + + + + + + + +void intelWaitForIdle( intelContextPtr intel ) +{ + if (0) + fprintf(stderr, "%s\n", __FUNCTION__); + + intel->vtbl.emit_flush( intel ); + intelFlushBatch( intel, GL_TRUE ); + + /* Use an irq to wait for dma idle -- Need to track lost contexts + * to shortcircuit consecutive calls to this function: + */ + intelWaitIrq( intel, intel->alloc.irq_emitted ); + intel->alloc.irq_emitted = 0; +} + + + +void intelFlush( GLcontext *ctx ) +{ + intelContextPtr intel = INTEL_CONTEXT( ctx ); + + if (intel->Fallback) + _swrast_flush( ctx ); + + INTEL_FIREVERTICES( intel ); + + if (intel->batch.size != intel->batch.space) + intelFlushBatch( intel, GL_FALSE ); +} + +void intelFinish( GLcontext *ctx ) +{ + intelContextPtr intel = INTEL_CONTEXT( ctx ); + intelFlush( ctx ); + intelWaitForIdle( intel ); +} + + +void intelClear(GLcontext *ctx, GLbitfield mask, GLboolean all, + GLint cx, GLint cy, GLint cw, GLint ch) +{ + intelContextPtr intel = INTEL_CONTEXT( ctx ); + const GLuint colorMask = *((GLuint *) &ctx->Color.ColorMask); + GLbitfield tri_mask = 0; + GLbitfield blit_mask = 0; + GLbitfield swrast_mask = 0; + + if (0) + fprintf(stderr, "%s\n", __FUNCTION__); + + /* Take care of cliprects, which are handled differently for + * clears, etc. + */ + intelFlush( &intel->ctx ); + + if (mask & DD_FRONT_LEFT_BIT) { + if (colorMask == ~0) { + blit_mask |= DD_FRONT_LEFT_BIT; + } + else { + tri_mask |= DD_FRONT_LEFT_BIT; + } + } + + if (mask & DD_BACK_LEFT_BIT) { + if (colorMask == ~0) { + blit_mask |= DD_BACK_LEFT_BIT; + } + else { + tri_mask |= DD_BACK_LEFT_BIT; + } + } + + if (mask & DD_DEPTH_BIT) { + blit_mask |= DD_DEPTH_BIT; + } + + if (mask & DD_STENCIL_BIT) { + if (!intel->hw_stencil) { + swrast_mask |= DD_STENCIL_BIT; + } + else if (ctx->Stencil.WriteMask[0] != 0xff) { + tri_mask |= DD_STENCIL_BIT; + } + else { + blit_mask |= DD_STENCIL_BIT; + } + } + + swrast_mask |= (mask & DD_ACCUM_BIT); + + if (blit_mask) + intelClearWithBlit( ctx, blit_mask, all, cx, cy, cw, ch ); + + if (tri_mask) + intel->vtbl.clear_with_tris( intel, tri_mask, all, cx, cy, cw, ch); + + if (swrast_mask) + _swrast_Clear( ctx, swrast_mask, all, cx, cy, cw, ch ); +} + + + +void *intelAllocateAGP( intelContextPtr intel, GLsizei size ) +{ + int region_offset; + drmI830MemAlloc alloc; + int ret; + + if (0) + fprintf(stderr, "%s: %d bytes\n", __FUNCTION__, size); + + alloc.region = I830_MEM_REGION_AGP; + alloc.alignment = 0; + alloc.size = size; + alloc.region_offset = ®ion_offset; + + LOCK_HARDWARE(intel); + + /* Make sure the global heap is initialized + */ + if (intel->texture_heaps[0]) + driAgeTextures( intel->texture_heaps[0] ); + + + ret = drmCommandWriteRead( intel->driFd, + DRM_I830_ALLOC, + &alloc, sizeof(alloc)); + + if (ret) { + fprintf(stderr, "%s: DRM_I830_ALLOC ret %d\n", __FUNCTION__, ret); + UNLOCK_HARDWARE(intel); + return NULL; + } + + if (0) + fprintf(stderr, "%s: allocated %d bytes\n", __FUNCTION__, size); + + /* Need to propogate this information (agp memory in use) to our + * local texture lru. The kernel has already updated the global + * lru. An alternative would have been to allocate memory the + * usual way and then notify the kernel to pin the allocation. + */ + if (intel->texture_heaps[0]) + driAgeTextures( intel->texture_heaps[0] ); + + UNLOCK_HARDWARE(intel); + + return (void *)((char *)intel->intelScreen->tex.map + region_offset); +} + +void intelFreeAGP( intelContextPtr intel, void *pointer ) +{ + int region_offset; + drmI830MemFree memfree; + int ret; + + region_offset = (char *)pointer - (char *)intel->intelScreen->tex.map; + + if (region_offset < 0 || + region_offset > intel->intelScreen->tex.size) { + fprintf(stderr, "offset %d outside range 0..%d\n", region_offset, + intel->intelScreen->tex.size); + return; + } + + memfree.region = I830_MEM_REGION_AGP; + memfree.region_offset = region_offset; + + ret = drmCommandWrite( intel->driFd, + DRM_I830_FREE, + &memfree, sizeof(memfree)); + + if (ret) + fprintf(stderr, "%s: DRM_I830_FREE ret %d\n", __FUNCTION__, ret); +} + +/* This version of AllocateMemoryMESA allocates only agp memory, and + * only does so after the point at which the driver has been + * initialized. + * + * Theoretically a valid context isn't required. However, in this + * implementation, it is, as I'm using the hardware lock to protect + * the kernel data structures, and the current context to get the + * device fd. + */ +void *intelAllocateMemoryMESA(__DRInativeDisplay *dpy, int scrn, + GLsizei size, GLfloat readfreq, + GLfloat writefreq, GLfloat priority) +{ + GET_CURRENT_CONTEXT(ctx); + + if (INTEL_DEBUG & DEBUG_IOCTL) + fprintf(stderr, "%s sz %d %f/%f/%f\n", __FUNCTION__, size, readfreq, + writefreq, priority); + + if (getenv("INTEL_NO_ALLOC")) + return NULL; + + if (!ctx || INTEL_CONTEXT(ctx) == 0) + return NULL; + + return intelAllocateAGP( INTEL_CONTEXT(ctx), size ); +} + + +/* Called via glXFreeMemoryMESA() */ +void intelFreeMemoryMESA(__DRInativeDisplay *dpy, int scrn, GLvoid *pointer) +{ + GET_CURRENT_CONTEXT(ctx); + if (INTEL_DEBUG & DEBUG_IOCTL) + fprintf(stderr, "%s %p\n", __FUNCTION__, pointer); + + if (!ctx || INTEL_CONTEXT(ctx) == 0) { + fprintf(stderr, "%s: no context\n", __FUNCTION__); + return; + } + + intelFreeAGP( INTEL_CONTEXT(ctx), pointer ); +} + +/* Called via glXGetMemoryOffsetMESA() + * + * Returns offset of pointer from the start of agp aperture. + */ +GLuint intelGetMemoryOffsetMESA(__DRInativeDisplay *dpy, int scrn, + const GLvoid *pointer) +{ + GET_CURRENT_CONTEXT(ctx); + intelContextPtr intel; + + if (!ctx || !(intel = INTEL_CONTEXT(ctx)) ) { + fprintf(stderr, "%s: no context\n", __FUNCTION__); + return ~0; + } + + if (!intelIsAgpMemory( intel, pointer, 0 )) + return ~0; + + return intelAgpOffsetFromVirtual( intel, pointer ); +} + + +GLboolean intelIsAgpMemory( intelContextPtr intel, const GLvoid *pointer, + GLint size ) +{ + int offset = (char *)pointer - (char *)intel->intelScreen->tex.map; + int valid = (size >= 0 && + offset >= 0 && + offset + size < intel->intelScreen->tex.size); + + if (INTEL_DEBUG & DEBUG_IOCTL) + fprintf(stderr, "intelIsAgpMemory( %p ) : %d\n", pointer, valid ); + + return valid; +} + + +GLuint intelAgpOffsetFromVirtual( intelContextPtr intel, const GLvoid *pointer ) +{ + int offset = (char *)pointer - (char *)intel->intelScreen->tex.map; + + if (offset < 0 || offset > intel->intelScreen->tex.size) + return ~0; + else + return intel->intelScreen->textureOffset + offset; +} + + + + + +/* Flip the front & back buffes + */ +void intelPageFlip( const __DRIdrawablePrivate *dPriv ) +{ +#if 0 + intelContextPtr intel; + int tmp, ret; + + if (INTEL_DEBUG & DEBUG_IOCTL) + fprintf(stderr, "%s\n", __FUNCTION__); + + assert(dPriv); + assert(dPriv->driContextPriv); + assert(dPriv->driContextPriv->driverPrivate); + + intel = (intelContextPtr) dPriv->driContextPriv->driverPrivate; + + intelFlush( &intel->ctx ); + LOCK_HARDWARE( intel ); + + if (dPriv->pClipRects) { + *(drm_clip_rect_t *)intel->sarea->boxes = dPriv->pClipRects[0]; + intel->sarea->nbox = 1; + } + + ret = drmCommandNone(intel->driFd, DRM_I830_FLIP); + if (ret) { + fprintf(stderr, "%s: %d\n", __FUNCTION__, ret); + UNLOCK_HARDWARE( intel ); + exit(1); + } + + tmp = intel->sarea->last_enqueue; + intelRefillBatchLocked( intel ); + UNLOCK_HARDWARE( intel ); + + + intelSetDrawBuffer( &intel->ctx, intel->ctx.Color.DriverDrawBuffer ); +#endif +} diff --git a/src/mesa/drivers/dri/i915/intel_ioctl.h b/src/mesa/drivers/dri/i915/intel_ioctl.h new file mode 100644 index 0000000..c6a8c7f --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_ioctl.h @@ -0,0 +1,46 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#ifndef INTEL_IOCTL_H +#define INTEL_IOCTL_H + +#include "intel_context.h" + +extern void intelWaitAgeLocked( intelContextPtr intel, int age, GLboolean unlock ); + +extern void intelClear(GLcontext *ctx, GLbitfield mask, GLboolean all, + GLint cx, GLint cy, GLint cw, GLint ch); + +extern void intelPageFlip( const __DRIdrawablePrivate *dpriv ); +extern void intelWaitForIdle( intelContextPtr intel ); +extern void intelFlushBatch( intelContextPtr intel, GLboolean refill ); +extern void intelFlushBatchLocked( intelContextPtr intel, + GLboolean ignore_cliprects, + GLboolean refill, + GLboolean allow_unlock); +extern void intelRefillBatchLocked( intelContextPtr intel, GLboolean allow_unlock ); +extern void intelFinish( GLcontext *ctx ); +extern void intelFlush( GLcontext *ctx ); + +extern void *intelAllocateAGP( intelContextPtr intel, GLsizei size ); +extern void intelFreeAGP( intelContextPtr intel, void *pointer ); + +extern void *intelAllocateMemoryMESA( __DRInativeDisplay *dpy, int scrn, + GLsizei size, GLfloat readfreq, + GLfloat writefreq, GLfloat priority ); + +extern void intelFreeMemoryMESA( __DRInativeDisplay *dpy, int scrn, + GLvoid *pointer ); + +extern GLuint intelGetMemoryOffsetMESA( __DRInativeDisplay *dpy, int scrn, const GLvoid *pointer ); +extern GLboolean intelIsAgpMemory( intelContextPtr intel, const GLvoid *pointer, + GLint size ); + +extern GLuint intelAgpOffsetFromVirtual( intelContextPtr intel, const GLvoid *p ); + + +#endif diff --git a/src/mesa/drivers/dri/i915/intel_pixel.c b/src/mesa/drivers/dri/i915/intel_pixel.c new file mode 100644 index 0000000..6ffc33a --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_pixel.c @@ -0,0 +1,469 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "glheader.h" +#include "enums.h" +#include "mtypes.h" +#include "macros.h" +#include "swrast/swrast.h" + +#include "intel_screen.h" +#include "intel_context.h" +#include "intel_ioctl.h" +#include "intel_batchbuffer.h" + + + +static GLboolean +check_color( const GLcontext *ctx, GLenum type, GLenum format, + const struct gl_pixelstore_attrib *packing, + const void *pixels, GLint sz, GLint pitch ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + GLuint cpp = intel->intelScreen->cpp; + + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s\n", __FUNCTION__); + + if ( (pitch & 63) || + ctx->_ImageTransferState || + packing->SwapBytes || + packing->LsbFirst) { + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s: failed 1\n", __FUNCTION__); + return GL_FALSE; + } + + if ( type == GL_UNSIGNED_INT_8_8_8_8_REV && + cpp == 4 && + format == GL_BGRA ) { + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s: passed 2\n", __FUNCTION__); + return GL_TRUE; + } + + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s: failed\n", __FUNCTION__); + + return GL_FALSE; +} + +static GLboolean +check_color_per_fragment_ops( const GLcontext *ctx ) +{ + int result; + result = (!( ctx->Color.AlphaEnabled || + ctx->Depth.Test || + ctx->Fog.Enabled || + ctx->Scissor.Enabled || + ctx->Stencil.Enabled || + !ctx->Color.ColorMask[0] || + !ctx->Color.ColorMask[1] || + !ctx->Color.ColorMask[2] || + !ctx->Color.ColorMask[3] || + ctx->Color.ColorLogicOpEnabled || + ctx->Texture._EnabledUnits || + ctx->Depth.OcclusionTest + ) && + ctx->Current.RasterPosValid); + + return result; +} + + + +static GLboolean +clip_pixelrect( const GLcontext *ctx, + const GLframebuffer *buffer, + GLint *x, GLint *y, + GLsizei *width, GLsizei *height, + GLint *size ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + + /* left clipping */ + if (*x < buffer->_Xmin) { + *width -= (buffer->_Xmin - *x); + *x = buffer->_Xmin; + } + + /* right clipping */ + if (*x + *width > buffer->_Xmax) + *width -= (*x + *width - buffer->_Xmax - 1); + + if (*width <= 0) + return GL_FALSE; + + /* bottom clipping */ + if (*y < buffer->_Ymin) { + *height -= (buffer->_Ymin - *y); + *y = buffer->_Ymin; + } + + /* top clipping */ + if (*y + *height > buffer->_Ymax) + *height -= (*y + *height - buffer->_Ymax - 1); + + if (*height <= 0) + return GL_FALSE; + + *size = ((*y + *height - 1) * intel->intelScreen->frontPitch + + (*x + *width - 1) * intel->intelScreen->cpp); + + return GL_TRUE; +} + +static GLboolean +intelTryReadPixels( GLcontext *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + GLvoid *pixels ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + GLint size; + GLint pitch = pack->RowLength ? pack->RowLength : width; + + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s\n", __FUNCTION__); + + /* Only accelerate reading to agp buffers. + */ + if ( !intelIsAgpMemory(intel, pixels, + pitch * height * intel->intelScreen->cpp ) ) { + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s: dest not agp\n", __FUNCTION__); + return GL_FALSE; + } + + /* Need GL_PACK_INVERT_MESA to cope with upsidedown results from + * blitter: + */ + if (!pack->Invert) { + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s: MESA_PACK_INVERT not set\n", __FUNCTION__); + return GL_FALSE; + } + + if (!check_color(ctx, type, format, pack, pixels, size, pitch)) + return GL_FALSE; + + switch ( intel->intelScreen->cpp ) { + case 4: + break; + default: + return GL_FALSE; + } + + + /* Although the blits go on the command buffer, need to do this and + * fire with lock held to guarentee cliprects and drawOffset are + * correct. + * + * This is an unusual situation however, as the code which flushes + * a full command buffer expects to be called unlocked. As a + * workaround, immediately flush the buffer on aquiring the lock. + */ + intelFlush( &intel->ctx ); + LOCK_HARDWARE( intel ); + { + __DRIdrawablePrivate *dPriv = intel->driDrawable; + int nbox = dPriv->numClipRects; + int src_offset = intel->drawOffset; + int src_pitch = intel->intelScreen->frontPitch; + int dst_offset = intelAgpOffsetFromVirtual( intel, pixels); + drm_clip_rect_t *box = dPriv->pClipRects; + int i; + + if (!clip_pixelrect(ctx, ctx->ReadBuffer, &x, &y, &width, &height, + &size)) { + UNLOCK_HARDWARE( intel ); + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s totally clipped -- nothing to do\n", + __FUNCTION__); + return GL_TRUE; + } + + + y = dPriv->h - y - height; + x += dPriv->x; + y += dPriv->y; + + + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "readpixel blit src_pitch %d dst_pitch %d\n", + src_pitch, pitch); + + for (i = 0 ; i < nbox ; i++) + { + GLint bx = box[i].x1; + GLint by = box[i].y1; + GLint bw = box[i].x2 - bx; + GLint bh = box[i].y2 - by; + + if (bx < x) bw -= x - bx, bx = x; + if (by < y) bh -= y - by, by = y; + if (bx + bw > x + width) bw = x + width - bx; + if (by + bh > y + height) bh = y + height - by; + if (bw <= 0) continue; + if (bh <= 0) continue; + + intelEmitCopyBlitLocked( intel, + intel->intelScreen->cpp, + src_pitch, src_offset, + pitch, dst_offset, + bx, by, + bx - x, by - y, + bw, bh ); + } + } + UNLOCK_HARDWARE( intel ); + intelFinish( &intel->ctx ); + + return GL_TRUE; +} + +static void +intelReadPixels( GLcontext *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *pack, + GLvoid *pixels ) +{ + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s\n", __FUNCTION__); + + if (!intelTryReadPixels( ctx, x, y, width, height, format, type, pack, + pixels)) + _swrast_ReadPixels( ctx, x, y, width, height, format, type, pack, + pixels); +} + + + + +static void do_draw_pix( GLcontext *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLint pitch, + const void *pixels, + GLuint dest ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + __DRIdrawablePrivate *dPriv = intel->driDrawable; + drm_clip_rect_t *box = dPriv->pClipRects; + int nbox = dPriv->numClipRects; + int i; + int size; + int src_offset = intelAgpOffsetFromVirtual( intel, pixels); + int src_pitch = pitch; + + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s\n", __FUNCTION__); + + intelFlush( &intel->ctx ); + LOCK_HARDWARE( intel ); + { + y -= height; /* cope with pixel zoom */ + + if (!clip_pixelrect(ctx, ctx->DrawBuffer, + &x, &y, &width, &height, + &size)) { + UNLOCK_HARDWARE( intel ); + return; + } + + y = dPriv->h - y - height; /* convert from gl to hardware coords */ + x += dPriv->x; + y += dPriv->y; + + + for (i = 0 ; i < nbox ; i++ ) + { + GLint bx = box[i].x1; + GLint by = box[i].y1; + GLint bw = box[i].x2 - bx; + GLint bh = box[i].y2 - by; + + if (bx < x) bw -= x - bx, bx = x; + if (by < y) bh -= y - by, by = y; + if (bx + bw > x + width) bw = x + width - bx; + if (by + bh > y + height) bh = y + height - by; + if (bw <= 0) continue; + if (bh <= 0) continue; + + intelEmitCopyBlitLocked( intel, + intel->intelScreen->cpp, + src_pitch, src_offset, + intel->intelScreen->frontPitch, + intel->drawOffset, + bx - x, by - y, + bx, by, + bw, bh ); + } + } + UNLOCK_HARDWARE( intel ); + intelFinish( &intel->ctx ); +} + + + + +static GLboolean +intelTryDrawPixels( GLcontext *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + GLint pitch = unpack->RowLength ? unpack->RowLength : width; + GLuint dest; + GLuint cpp = intel->intelScreen->cpp; + GLint size = width * pitch * cpp; + + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s\n", __FUNCTION__); + + switch (format) { + case GL_RGB: + case GL_RGBA: + case GL_BGRA: + dest = intel->drawOffset; + + /* Planemask doesn't have full support in blits. + */ + if (!ctx->Color.ColorMask[RCOMP] || + !ctx->Color.ColorMask[GCOMP] || + !ctx->Color.ColorMask[BCOMP] || + !ctx->Color.ColorMask[ACOMP]) { + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s: planemask\n", __FUNCTION__); + return GL_FALSE; + } + + /* Can't do conversions on agp reads/draws. + */ + if ( !intelIsAgpMemory( intel, pixels, size ) ) { + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s: not agp memory\n", __FUNCTION__); + return GL_FALSE; + } + + if (!check_color(ctx, type, format, unpack, pixels, size, pitch)) { + return GL_FALSE; + } + if (!check_color_per_fragment_ops(ctx)) { + return GL_FALSE; + } + + if (ctx->Pixel.ZoomX != 1.0F || + ctx->Pixel.ZoomY != -1.0F) + return GL_FALSE; + break; + + default: + return GL_FALSE; + } + + if ( intelIsAgpMemory(intel, pixels, size) ) + { + do_draw_pix( ctx, x, y, width, height, pitch, pixels, + dest ); + return GL_TRUE; + } + else if (0) + { + /* Pixels is in regular memory -- get dma buffers and perform + * upload through them. No point doing this for regular uploads + * but once we remove some of the restrictions above (colormask, + * pixelformat conversion, zoom?, etc), this could be a win. + */ + } + else + return GL_FALSE; +} + +static void +intelDrawPixels( GLcontext *ctx, + GLint x, GLint y, GLsizei width, GLsizei height, + GLenum format, GLenum type, + const struct gl_pixelstore_attrib *unpack, + const GLvoid *pixels ) +{ + if (INTEL_DEBUG & DEBUG_PIXEL) + fprintf(stderr, "%s\n", __FUNCTION__); + + if (!intelTryDrawPixels( ctx, x, y, width, height, format, type, + unpack, pixels )) + _swrast_DrawPixels( ctx, x, y, width, height, format, type, + unpack, pixels ); +} + + + + +/** + * Implement glCopyPixels for the front color buffer (or back buffer Pixmap) + * for the color buffer. Don't support zooming, pixel transfer, etc. + * We do support copying from one window to another, ala glXMakeCurrentRead. + */ +static void +intelCopyPixels( GLcontext *ctx, + GLint srcx, GLint srcy, GLsizei width, GLsizei height, + GLint destx, GLint desty, GLenum type ) +{ +#if 0 + const XMesaContext xmesa = XMESA_CONTEXT(ctx); + const SWcontext *swrast = SWRAST_CONTEXT( ctx ); + XMesaDisplay *dpy = xmesa->xm_visual->display; + const XMesaDrawable drawBuffer = xmesa->xm_draw_buffer->buffer; + const XMesaDrawable readBuffer = xmesa->xm_read_buffer->buffer; + const XMesaGC gc = xmesa->xm_draw_buffer->gc; + + ASSERT(dpy); + ASSERT(gc); + + if (drawBuffer && /* buffer != 0 means it's a Window or Pixmap */ + readBuffer && + type == GL_COLOR && + (swrast->_RasterMask & ~CLIP_BIT) == 0 && /* no blend, z-test, etc */ + ctx->_ImageTransferState == 0 && /* no color tables, scale/bias, etc */ + ctx->Pixel.ZoomX == 1.0 && /* no zooming */ + ctx->Pixel.ZoomY == 1.0) { + /* Note: we don't do any special clipping work here. We could, + * but X will do it for us. + */ + srcy = FLIP(xmesa->xm_read_buffer, srcy) - height + 1; + desty = FLIP(xmesa->xm_draw_buffer, desty) - height + 1; + XCopyArea(dpy, readBuffer, drawBuffer, gc, + srcx, srcy, width, height, destx, desty); + } +#else + _swrast_CopyPixels(ctx, srcx, srcy, width, height, destx, desty, type ); +#endif +} + + + + +void intelInitPixelFuncs( struct dd_function_table *functions ) +{ + /* Pixel path fallbacks. + */ + functions->Accum = _swrast_Accum; + functions->Bitmap = _swrast_Bitmap; + functions->CopyPixels = intelCopyPixels; + + if (!getenv("INTEL_NO_BLITS")) { + functions->ReadPixels = intelReadPixels; + functions->DrawPixels = intelDrawPixels; + } + else { + functions->ReadPixels = _swrast_ReadPixels; + functions->DrawPixels = _swrast_DrawPixels; + } +} diff --git a/src/mesa/drivers/dri/i915/intel_reg.h b/src/mesa/drivers/dri/i915/intel_reg.h new file mode 100644 index 0000000..7c4e716 --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_reg.h @@ -0,0 +1,64 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + + +#ifndef _INTEL_REG_H_ +#define _INTEL_REG_H_ + + + +#define CMD_3D (0x3<<29) + + +#define _3DPRIMITIVE ((0x3<<29)|(0x1f<<24)) +#define PRIM_INDIRECT (1<<23) +#define PRIM_INLINE (0<<23) +#define PRIM_INDIRECT_SEQUENTIAL (0<<17) +#define PRIM_INDIRECT_ELTS (1<<17) + +#define PRIM3D_TRILIST (0x0<<18) +#define PRIM3D_TRISTRIP (0x1<<18) +#define PRIM3D_TRISTRIP_RVRSE (0x2<<18) +#define PRIM3D_TRIFAN (0x3<<18) +#define PRIM3D_POLY (0x4<<18) +#define PRIM3D_LINELIST (0x5<<18) +#define PRIM3D_LINESTRIP (0x6<<18) +#define PRIM3D_RECTLIST (0x7<<18) +#define PRIM3D_POINTLIST (0x8<<18) +#define PRIM3D_DIB (0x9<<18) +#define PRIM3D_MASK (0x1f<<18) + +#define I915PACKCOLOR4444(r,g,b,a) \ + ((((a) & 0xf0) << 8) | (((r) & 0xf0) << 4) | ((g) & 0xf0) | ((b) >> 4)) + +#define I915PACKCOLOR1555(r,g,b,a) \ + ((((r) & 0xf8) << 7) | (((g) & 0xf8) << 2) | (((b) & 0xf8) >> 3) | \ + ((a) ? 0x8000 : 0)) + +#define I915PACKCOLOR565(r,g,b) \ + ((((r) & 0xf8) << 8) | (((g) & 0xfc) << 3) | (((b) & 0xf8) >> 3)) + +#define I915PACKCOLOR8888(r,g,b,a) \ + ((a<<24) | (r<<16) | (g<<8) | b) + + + + +#define BR00_BITBLT_CLIENT 0x40000000 +#define BR00_OP_COLOR_BLT 0x10000000 +#define BR00_OP_SRC_COPY_BLT 0x10C00000 +#define BR13_SOLID_PATTERN 0x80000000 + +#define XY_COLOR_BLT_CMD ((2<<29)|(0x50<<22)|0x4) +#define XY_COLOR_BLT_WRITE_ALPHA (1<<21) +#define XY_COLOR_BLT_WRITE_RGB (1<<20) + +#define XY_SRC_COPY_BLT_CMD ((2<<29)|(0x53<<22)|6) +#define XY_SRC_COPY_BLT_WRITE_ALPHA (1<<21) +#define XY_SRC_COPY_BLT_WRITE_RGB (1<<20) + +#endif diff --git a/src/mesa/drivers/dri/i915/intel_render.c b/src/mesa/drivers/dri/i915/intel_render.c new file mode 100644 index 0000000..5441115 --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_render.c @@ -0,0 +1,239 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +/* + * Render unclipped vertex buffers by emitting vertices directly to + * dma buffers. Use strip/fan hardware acceleration where possible. + * + */ +#include "glheader.h" +#include "context.h" +#include "macros.h" +#include "imports.h" +#include "mtypes.h" +#include "enums.h" + +#include "tnl/t_context.h" +#include "tnl/t_vertex.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 GLuint 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( intelContextPtr 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] ); + intelStartInlinePrimitive( intel, hw_prim[prim] ); +} + + +#define LOCAL_VARS intelContextPtr 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->alloc.size / 2) - 1500) / (intel->vertex_size*4)) +#define GET_CURRENT_VB_MAX_VERTS() GET_SUBSEQUENT_VB_MAX_VERTS() + +#define ALLOC_VERTS( nr ) \ + intelExtendInlinePrimitive( intel, (nr) * intel->vertex_size ) + +#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 GLboolean choose_render( intelContextPtr 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 GL_FALSE; + + return GL_TRUE; +} + + +static GLboolean intel_run_render( GLcontext *ctx, + struct tnl_pipeline_stage *stage ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_buffer *VB = &tnl->vb; + GLuint i; + + /* Don't handle clipping or indexed vertices. + */ + if (intel->RenderIndex != 0 || + !intel_validate_render( ctx, VB ) || + !choose_render( intel, VB )) { + return GL_TRUE; + } + + tnl->clipspace.new_inputs |= VERT_BIT_POS; + + tnl->Driver.Render.Start( ctx ); + + for (i = 0 ; i < VB->PrimitiveCount ; i++) + { + GLuint prim = VB->Primitive[i].mode; + 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 ); + + return GL_FALSE; /* finished the pipe */ +} + + +static void intel_check_render( GLcontext *ctx, + struct tnl_pipeline_stage *stage ) +{ + stage->inputs = TNL_CONTEXT(ctx)->render_inputs; +} + +static void dtr( struct tnl_pipeline_stage *stage ) +{ + (void)stage; +} + + +const struct tnl_pipeline_stage _intel_render_stage = +{ + "intel render", + (_DD_NEW_SEPARATE_SPECULAR | + _NEW_TEXTURE| + _NEW_FOG| + _NEW_RENDERMODE), /* re-check (new inputs) */ + 0, /* re-run (always runs) */ + GL_TRUE, /* active */ + 0, 0, /* inputs (set in check_render), outputs */ + 0, 0, /* changed_inputs, private */ + dtr, /* destructor */ + intel_check_render, /* check - initially set to alloc data */ + intel_run_render /* run */ +}; diff --git a/src/mesa/drivers/dri/i915/intel_screen.c b/src/mesa/drivers/dri/i915/intel_screen.c new file mode 100644 index 0000000..d34f7ac --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_screen.c @@ -0,0 +1,543 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "glheader.h" +#include "context.h" +#include "matrix.h" +#include "simple_list.h" +#include "utils.h" + + +#include "intel_screen.h" + +#include "intel_tex.h" +#include "intel_span.h" +#include "intel_tris.h" +#include "intel_ioctl.h" + + + +#include "i830_dri.h" + +#ifdef USE_NEW_INTERFACE +static PFNGLXCREATECONTEXTMODES create_context_modes = NULL; +#endif /*USE_NEW_INTERFACE*/ + + +static void intelPrintDRIInfo(intelScreenPrivate *intelScreen, + __DRIscreenPrivate *sPriv, + I830DRIPtr gDRIPriv) +{ + fprintf(stderr, "Front size : 0x%x\n", sPriv->fbSize); + fprintf(stderr, "Front offset : 0x%x\n", intelScreen->frontOffset); + fprintf(stderr, "Back size : 0x%x\n", intelScreen->back.size); + fprintf(stderr, "Back offset : 0x%x\n", intelScreen->backOffset); + fprintf(stderr, "Depth size : 0x%x\n", intelScreen->depth.size); + fprintf(stderr, "Depth offset : 0x%x\n", intelScreen->depthOffset); + fprintf(stderr, "Texture size : 0x%x\n", intelScreen->textureSize); + fprintf(stderr, "Texture offset : 0x%x\n", intelScreen->textureOffset); + fprintf(stderr, "Memory : 0x%x\n", gDRIPriv->mem); +} + +static GLboolean intelInitDriver(__DRIscreenPrivate *sPriv) +{ + intelScreenPrivate *intelScreen; + I830DRIPtr gDRIPriv = (I830DRIPtr)sPriv->pDevPriv; + + + /* Allocate the private area */ + intelScreen = (intelScreenPrivate *)MALLOC(sizeof(intelScreenPrivate)); + if (!intelScreen) { + fprintf(stderr,"\nERROR! Allocating private area failed\n"); + return GL_FALSE; + } + + intelScreen->driScrnPriv = sPriv; + sPriv->private = (void *)intelScreen; + + intelScreen->deviceID = gDRIPriv->deviceID; + intelScreen->width = gDRIPriv->width; + intelScreen->height = gDRIPriv->height; + intelScreen->mem = gDRIPriv->mem; + intelScreen->cpp = gDRIPriv->cpp; + intelScreen->frontPitch = gDRIPriv->fbStride; + intelScreen->frontOffset = gDRIPriv->fbOffset; + + switch (gDRIPriv->bitsPerPixel) { + case 15: intelScreen->fbFormat = DV_PF_555; break; + case 16: intelScreen->fbFormat = DV_PF_565; break; + case 32: intelScreen->fbFormat = DV_PF_8888; break; + } + + intelScreen->backOffset = gDRIPriv->backOffset; + intelScreen->backPitch = gDRIPriv->backPitch; + intelScreen->depthOffset = gDRIPriv->depthOffset; + intelScreen->depthPitch = gDRIPriv->depthPitch; + intelScreen->textureOffset = gDRIPriv->textureOffset; + intelScreen->textureSize = gDRIPriv->textureSize; + intelScreen->logTextureGranularity = gDRIPriv->logTextureGranularity; + intelScreen->back.handle = gDRIPriv->backbuffer; + intelScreen->back.size = gDRIPriv->backbufferSize; + + if (drmMap(sPriv->fd, + intelScreen->back.handle, + intelScreen->back.size, + (drmAddress *)&intelScreen->back.map) != 0) { + fprintf(stderr, "\nERROR: line %d, Function %s, File %s\n", + __LINE__, __FUNCTION__, __FILE__); + FREE(intelScreen); + sPriv->private = NULL; + return GL_FALSE; + } + + intelScreen->depth.handle = gDRIPriv->depthbuffer; + intelScreen->depth.size = gDRIPriv->depthbufferSize; + + if (drmMap(sPriv->fd, + intelScreen->depth.handle, + intelScreen->depth.size, + (drmAddress *)&intelScreen->depth.map) != 0) { + fprintf(stderr, "\nERROR: line %d, Function %s, File %s\n", + __LINE__, __FUNCTION__, __FILE__); + FREE(intelScreen); + drmUnmap(intelScreen->back.map, intelScreen->back.size); + sPriv->private = NULL; + return GL_FALSE; + } + + intelScreen->tex.handle = gDRIPriv->textures; + intelScreen->tex.size = gDRIPriv->textureSize; + + if (drmMap(sPriv->fd, + intelScreen->tex.handle, + intelScreen->tex.size, + (drmAddress *)&intelScreen->tex.map) != 0) { + fprintf(stderr, "\nERROR: line %d, Function %s, File %s\n", + __LINE__, __FUNCTION__, __FILE__); + FREE(intelScreen); + drmUnmap(intelScreen->back.map, intelScreen->back.size); + drmUnmap(intelScreen->depth.map, intelScreen->depth.size); + sPriv->private = NULL; + return GL_FALSE; + } + + intelScreen->sarea_priv_offset = gDRIPriv->sarea_priv_offset; + + if (0) intelPrintDRIInfo(intelScreen, sPriv, gDRIPriv); + + intelScreen->drmMinor = sPriv->drmMinor; + + { + int ret; + drmI830GetParam gp; + + gp.param = I830_PARAM_IRQ_ACTIVE; + gp.value = &intelScreen->irq_active; + + ret = drmCommandWriteRead( sPriv->fd, DRM_I830_GETPARAM, + &gp, sizeof(gp)); + if (ret) { + fprintf(stderr, "drmI830GetParam: %d\n", ret); + return GL_FALSE; + } + } + + { + int ret; + drmI830GetParam gp; + + gp.param = I830_PARAM_ALLOW_BATCHBUFFER; + gp.value = &intelScreen->allow_batchbuffer; + + ret = drmCommandWriteRead( sPriv->fd, DRM_I830_GETPARAM, + &gp, sizeof(gp)); + if (ret) { + fprintf(stderr, "drmI830GetParam: (%d) %d\n", gp.param, ret); + return GL_FALSE; + } + } + +#ifndef _SOLO + if ( driCompareGLXAPIVersion( 20030813 ) >= 0 ) { + PFNGLXSCRENABLEEXTENSIONPROC glx_enable_extension = + (PFNGLXSCRENABLEEXTENSIONPROC) glXGetProcAddress( (const GLubyte *) "__glXScrEnableExtension" ); + void * const psc = sPriv->psc->screenConfigs; + + if (glx_enable_extension != NULL) { + (*glx_enable_extension)( psc, "GLX_SGI_make_current_read" ); + + if ( driCompareGLXAPIVersion( 20030915 ) >= 0 ) { + (*glx_enable_extension)( psc, "GLX_SGIX_fbconfig" ); + (*glx_enable_extension)( psc, "GLX_OML_swap_method" ); + } + + if ( driCompareGLXAPIVersion( 20030818 ) >= 0 ) { + sPriv->psc->allocateMemory = (void *) intelAllocateMemoryMESA; + sPriv->psc->freeMemory = (void *) intelFreeMemoryMESA; + sPriv->psc->memoryOffset = (void *) intelGetMemoryOffsetMESA; + + (*glx_enable_extension)( psc, "GLX_MESA_allocate_memory" ); + } + } + } +#endif + + return GL_TRUE; +} + + +static void intelDestroyScreen(__DRIscreenPrivate *sPriv) +{ + intelScreenPrivate *intelScreen = (intelScreenPrivate *)sPriv->private; + + /* Need to unmap all the bufs and maps here: + */ + drmUnmap(intelScreen->back.map, intelScreen->back.size); + drmUnmap(intelScreen->depth.map, intelScreen->depth.size); + drmUnmap(intelScreen->tex.map, intelScreen->tex.size); + FREE(intelScreen); + sPriv->private = NULL; +} + +static GLboolean intelCreateBuffer( __DRIscreenPrivate *driScrnPriv, + __DRIdrawablePrivate *driDrawPriv, + const __GLcontextModes *mesaVis, + GLboolean isPixmap ) +{ + if (isPixmap) { + return GL_FALSE; /* not implemented */ + } else { + GLboolean swStencil = (mesaVis->stencilBits > 0 && + mesaVis->depthBits != 24); + + driDrawPriv->driverPrivate = (void *) + _mesa_create_framebuffer(mesaVis, + GL_FALSE, /* software depth buffer? */ + swStencil, + mesaVis->accumRedBits > 0, + GL_FALSE /* s/w alpha planes */); + + return (driDrawPriv->driverPrivate != NULL); + } +} + +static void intelDestroyBuffer(__DRIdrawablePrivate *driDrawPriv) +{ + _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate)); +} + + +/* There are probably better ways to do this, such as an + * init-designated function to register chipids and createcontext + * functions. + */ +extern GLboolean i830CreateContext( const __GLcontextModes *mesaVis, + __DRIcontextPrivate *driContextPriv, + void *sharedContextPrivate); + +extern GLboolean i915CreateContext( const __GLcontextModes *mesaVis, + __DRIcontextPrivate *driContextPriv, + void *sharedContextPrivate); + + + + +static GLboolean intelCreateContext( const __GLcontextModes *mesaVis, + __DRIcontextPrivate *driContextPriv, + void *sharedContextPrivate) +{ + __DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv; + intelScreenPrivate *intelScreen = (intelScreenPrivate *)sPriv->private; + + switch (intelScreen->deviceID) { + case PCI_CHIP_845_G: + case PCI_CHIP_I830_M: + case PCI_CHIP_I855_GM: + case PCI_CHIP_I865_G: + return i830CreateContext( mesaVis, driContextPriv, + sharedContextPrivate ); + + case PCI_CHIP_I915_G: + return i915CreateContext( mesaVis, driContextPriv, + sharedContextPrivate ); + + default: + fprintf(stderr, "Unrecognized deviceID %x\n", intelScreen->deviceID); + return GL_FALSE; + } +} + + +static const struct __DriverAPIRec intelAPI = { + .InitDriver = intelInitDriver, + .DestroyScreen = intelDestroyScreen, + .CreateContext = intelCreateContext, + .DestroyContext = intelDestroyContext, + .CreateBuffer = intelCreateBuffer, + .DestroyBuffer = intelDestroyBuffer, + .SwapBuffers = intelSwapBuffers, + .MakeCurrent = intelMakeCurrent, + .UnbindContext = intelUnbindContext, + .GetSwapInfo = NULL, + .GetMSC = NULL, + .WaitForMSC = NULL, + .WaitForSBC = NULL, + .SwapBuffersMSC = NULL +}; + +/* + * This is the bootstrap function for the driver. + * The __driCreateScreen name is the symbol that libGL.so fetches. + * Return: pointer to a __DRIscreenPrivate. + */ +#if !defined(DRI_NEW_INTERFACE_ONLY) +#ifndef _SOLO +void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc, + int numConfigs, __GLXvisualConfig *config) +{ + __DRIscreenPrivate *psp; + psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &intelAPI); + return (void *) psp; +} +#else +void *__driCreateScreen(struct DRIDriverRec *driver, + struct DRIDriverContextRec *driverContext) +{ + __DRIscreenPrivate *psp; + psp = __driUtilCreateScreen(driver, driverContext, &i830API); + return (void *) psp; +} +#endif +#endif /* !defined(DRI_NEW_INTERFACE_ONLY) */ + + +/* This function is called by libGL.so as soon as libGL.so is loaded. + * This is where we'd register new extension functions with the dispatcher. + * + * Note: Most of these are probably already registered - just doing + * this for the benefit of old libGL.so's out there. + */ +#include "glapioffsets.h" + +void __driRegisterExtensions( void ) +{ + int i; + static struct { const char *name; int offset; } funcs[] = { + { "glSecondaryColor3bEXT", _gloffset_SecondaryColor3bEXT }, + { "glSecondaryColor3dEXT", _gloffset_SecondaryColor3dEXT }, + { "glSecondaryColor3fEXT", _gloffset_SecondaryColor3fEXT }, + { "glSecondaryColor3iEXT", _gloffset_SecondaryColor3iEXT }, + { "glSecondaryColor3sEXT", _gloffset_SecondaryColor3sEXT }, + { "glSecondaryColor3ubEXT", _gloffset_SecondaryColor3ubEXT }, + { "glSecondaryColor3uiEXT", _gloffset_SecondaryColor3uiEXT }, + { "glSecondaryColor3usEXT", _gloffset_SecondaryColor3usEXT }, + { "glSecondaryColor3bvEXT", _gloffset_SecondaryColor3bvEXT }, + { "glSecondaryColor3dvEXT", _gloffset_SecondaryColor3dvEXT }, + { "glSecondaryColor3fvEXT", _gloffset_SecondaryColor3fvEXT }, + { "glSecondaryColor3ivEXT", _gloffset_SecondaryColor3ivEXT }, + { "glSecondaryColor3svEXT", _gloffset_SecondaryColor3svEXT }, + { "glSecondaryColor3ubvEXT", _gloffset_SecondaryColor3ubvEXT }, + { "glSecondaryColor3uivEXT", _gloffset_SecondaryColor3uivEXT }, + { "glSecondaryColor3usvEXT", _gloffset_SecondaryColor3usvEXT }, + { "glSecondaryColorPointerEXT", _gloffset_SecondaryColorPointerEXT } + }; + + for (i = 0 ; i < sizeof(funcs) / sizeof(*funcs) ; i++ ) + _glapi_add_entrypoint( funcs[i].name, funcs[i].offset ); +} + + +#ifdef USE_NEW_INTERFACE +static __GLcontextModes * fill_in_modes( __GLcontextModes * modes, + unsigned pixel_bits, + unsigned depth_bits, + unsigned stencil_bits, + const GLenum * db_modes, + unsigned num_db_modes, + int visType ) +{ + static const uint8_t bits[2][4] = { + { 5, 6, 5, 0 }, + { 8, 8, 8, 8 } + }; + + static const uint32_t masks[2][4] = { + { 0x0000F800, 0x000007E0, 0x0000001F, 0x00000000 }, + { 0x00FF0000, 0x0000FF00, 0x000000FF, 0xFF000000 } + }; + + unsigned i; + unsigned j; + const unsigned index = ((pixel_bits + 15) / 16) - 1; + + for ( i = 0 ; i < num_db_modes ; i++ ) { + for ( j = 0 ; j < 2 ; j++ ) { + + modes->redBits = bits[index][0]; + modes->greenBits = bits[index][1]; + modes->blueBits = bits[index][2]; + modes->alphaBits = bits[index][3]; + modes->redMask = masks[index][0]; + modes->greenMask = masks[index][1]; + modes->blueMask = masks[index][2]; + modes->alphaMask = masks[index][3]; + modes->rgbBits = modes->redBits + modes->greenBits + + modes->blueBits + modes->alphaBits; + + modes->accumRedBits = 16 * j; + modes->accumGreenBits = 16 * j; + modes->accumBlueBits = 16 * j; + modes->accumAlphaBits = (masks[index][3] != 0) ? 16 * j : 0; + modes->visualRating = (j == 0) ? GLX_NONE : GLX_SLOW_CONFIG; + + modes->stencilBits = stencil_bits; + modes->depthBits = depth_bits; + + modes->visualType = visType; + modes->renderType = GLX_RGBA_BIT; + modes->drawableType = GLX_WINDOW_BIT; + modes->rgbMode = GL_TRUE; + + if ( db_modes[i] == GLX_NONE ) { + modes->doubleBufferMode = GL_FALSE; + } + else { + modes->doubleBufferMode = GL_TRUE; + modes->swapMethod = db_modes[i]; + } + + modes = modes->next; + } + } + + return modes; +} +#endif /* USE_NEW_INTERFACE */ + + +#ifdef USE_NEW_INTERFACE +static __GLcontextModes * +intelFillInModes( unsigned pixel_bits, unsigned depth_bits, + unsigned stencil_bits, GLboolean have_back_buffer ) +{ + __GLcontextModes * modes; + __GLcontextModes * m; + unsigned num_modes; + unsigned depth_buffer_factor; + unsigned back_buffer_factor; + unsigned i; + + /* GLX_SWAP_COPY_OML is only supported because the MGA driver doesn't + * support pageflipping at all. + */ + static const GLenum back_buffer_modes[] = { + GLX_NONE, GLX_SWAP_UNDEFINED_OML, GLX_SWAP_COPY_OML + }; + + int depth_buffer_modes[2][2]; + + + depth_buffer_modes[0][0] = depth_bits; + depth_buffer_modes[1][0] = depth_bits; + + /* Just like with the accumulation buffer, always provide some modes + * with a stencil buffer. It will be a sw fallback, but some apps won't + * care about that. + */ + depth_buffer_modes[0][1] = 0; + depth_buffer_modes[1][1] = (stencil_bits == 0) ? 8 : stencil_bits; + + depth_buffer_factor = ((depth_bits != 0) || (stencil_bits != 0)) ? 2 : 1; + back_buffer_factor = (have_back_buffer) ? 3 : 1; + + num_modes = depth_buffer_factor * back_buffer_factor * 4; + + modes = (*create_context_modes)( num_modes, sizeof( __GLcontextModes ) ); + m = modes; + for ( i = 0 ; i < depth_buffer_factor ; i++ ) { + m = fill_in_modes( m, pixel_bits, + depth_buffer_modes[i][0], depth_buffer_modes[i][1], + back_buffer_modes, back_buffer_factor, + GLX_TRUE_COLOR ); + } + + /* There's no direct color modes on intel? */ +#if 0 + for ( i = 0 ; i < depth_buffer_factor ; i++ ) { + m = fill_in_modes( m, pixel_bits, + depth_buffer_modes[i][0], depth_buffer_modes[i][1], + back_buffer_modes, back_buffer_factor, + GLX_DIRECT_COLOR ); + } +#endif + + /* Mark the visual as slow if there are "fake" stencil bits. + */ + for ( m = modes ; m != NULL ; m = m->next ) { + if ( (m->stencilBits != 0) && (m->stencilBits != stencil_bits) ) { + m->visualRating = GLX_SLOW_CONFIG; + } + } + + return modes; +} +#endif /* USE_NEW_INTERFACE */ + + +/** + * This is the bootstrap function for the driver. libGL supplies all of the + * requisite information about the system, and the driver initializes itself. + * This routine also fills in the linked list pointed to by \c driver_modes + * with the \c __GLcontextModes that the driver can support for windows or + * pbuffers. + * + * \return A pointer to a \c __DRIscreenPrivate on success, or \c NULL on + * failure. + */ +#ifdef USE_NEW_INTERFACE +void * __driCreateNewScreen( __DRInativeDisplay *dpy, int scrn, __DRIscreen *psc, + const __GLcontextModes * modes, + const __DRIversion * ddx_version, + const __DRIversion * dri_version, + const __DRIversion * drm_version, + const __DRIframebuffer * frame_buffer, + drmAddress pSAREA, int fd, + int internal_api_version, + __GLcontextModes ** driver_modes ) + +{ + __DRIscreenPrivate *psp; + static const __DRIversion ddx_expected = { 1, 0, 0 }; + static const __DRIversion dri_expected = { 4, 0, 0 }; + static const __DRIversion drm_expected = { 1, 1, 0 }; + + if ( ! driCheckDriDdxDrmVersions2( "i915", + dri_version, & dri_expected, + ddx_version, & ddx_expected, + drm_version, & drm_expected ) ) { + return NULL; + } + + psp = __driUtilCreateNewScreen(dpy, scrn, psc, NULL, + ddx_version, dri_version, drm_version, + frame_buffer, pSAREA, fd, + internal_api_version, &intelAPI); + if ( psp != NULL ) { + create_context_modes = (PFNGLXCREATECONTEXTMODES) + glXGetProcAddress( (const GLubyte *) "__glXCreateContextModes" ); + if ( create_context_modes != NULL ) { + I830DRIPtr dri_priv = (I830DRIPtr) psp->pDevPriv; + *driver_modes = intelFillInModes( dri_priv->cpp * 8, + (dri_priv->cpp == 2) ? 16 : 24, + (dri_priv->cpp == 2) ? 0 : 8, + (dri_priv->backOffset != dri_priv->depthOffset) ); + } + } + + return (void *) psp; +} +#endif /* USE_NEW_INTERFACE */ diff --git a/src/mesa/drivers/dri/i915/intel_screen.h b/src/mesa/drivers/dri/i915/intel_screen.h new file mode 100644 index 0000000..88d02ca --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_screen.h @@ -0,0 +1,76 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#ifndef _INTEL_INIT_H_ +#define _INTEL_INIT_H_ + +#include +#include "dri_util.h" + + +typedef struct { + drm_handle_t handle; + drmSize size; + char *map; +} intelRegion; + +typedef struct +{ + intelRegion front; + intelRegion back; + intelRegion depth; + intelRegion tex; + + int deviceID; + int width; + int height; + int mem; + + int cpp; /* for front and back buffers */ + int bitsPerPixel; + + int fbFormat; + + int frontOffset; + int frontPitch; + + int backOffset; + int backPitch; + + int depthOffset; + int depthPitch; + + + int textureOffset; + int textureSize; + int logTextureGranularity; + + __DRIscreenPrivate *driScrnPriv; + unsigned int sarea_priv_offset; + + int drmMinor; + + int irq_active; + int allow_batchbuffer; +} intelScreenPrivate; + + +extern void +intelDestroyContext(__DRIcontextPrivate *driContextPriv); + +extern GLboolean +intelUnbindContext(__DRIcontextPrivate *driContextPriv); + +extern GLboolean +intelMakeCurrent(__DRIcontextPrivate *driContextPriv, + __DRIdrawablePrivate *driDrawPriv, + __DRIdrawablePrivate *driReadPriv); + +extern void +intelSwapBuffers( __DRIdrawablePrivate *dPriv); + +#endif diff --git a/src/mesa/drivers/dri/i915/intel_span.c b/src/mesa/drivers/dri/i915/intel_span.c new file mode 100644 index 0000000..f9f7eb9 --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_span.c @@ -0,0 +1,323 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "glheader.h" +#include "macros.h" +#include "mtypes.h" +#include "colormac.h" + +#include "intel_screen.h" + +#include "intel_span.h" +#include "intel_ioctl.h" +#include "swrast/swrast.h" + + +#define DBG 0 + +#define LOCAL_VARS \ + intelContextPtr intel = INTEL_CONTEXT(ctx); \ + __DRIdrawablePrivate *dPriv = intel->driDrawable; \ + intelScreenPrivate *intelScreen = intel->intelScreen; \ + GLuint pitch = intelScreen->backPitch * intelScreen->cpp; \ + GLuint height = dPriv->h; \ + char *buf = (char *)(intel->drawMap + \ + dPriv->x * intelScreen->cpp + \ + dPriv->y * pitch); \ + char *read_buf = (char *)(intel->readMap + \ + dPriv->x * intelScreen->cpp + \ + dPriv->y * pitch); \ + GLushort p; \ + (void) read_buf; (void) buf; (void) p + +#define LOCAL_DEPTH_VARS \ + intelContextPtr intel = INTEL_CONTEXT(ctx); \ + __DRIdrawablePrivate *dPriv = intel->driDrawable; \ + intelScreenPrivate *intelScreen = intel->intelScreen; \ + GLuint pitch = intelScreen->backPitch * intelScreen->cpp; \ + GLuint height = dPriv->h; \ + char *buf = (char *)(intelScreen->depth.map + \ + dPriv->x * intelScreen->cpp + \ + dPriv->y * pitch) + +#define LOCAL_STENCIL_VARS LOCAL_DEPTH_VARS + +#define INIT_MONO_PIXEL(p,color)\ + p = PACK_COLOR_565(color[0],color[1],color[2]) + +#define CLIPPIXEL(_x,_y) (_x >= minx && _x < maxx && \ + _y >= miny && _y < maxy) + +#define CLIPSPAN( _x, _y, _n, _x1, _n1, _i ) \ + if ( _y < miny || _y >= maxy ) { \ + _n1 = 0, _x1 = x; \ + } else { \ + _n1 = _n; \ + _x1 = _x; \ + if ( _x1 < minx ) _i += (minx-_x1), n1 -= (minx-_x1), _x1 = minx; \ + if ( _x1 + _n1 >= maxx ) n1 -= (_x1 + n1 - maxx); \ + } + +#define Y_FLIP(_y) (height - _y - 1) + + +#define HW_LOCK() + +#define HW_CLIPLOOP() \ + do { \ + __DRIdrawablePrivate *dPriv = intel->driDrawable; \ + int _nc = dPriv->numClipRects; \ + while (_nc--) { \ + int minx = dPriv->pClipRects[_nc].x1 - dPriv->x; \ + int miny = dPriv->pClipRects[_nc].y1 - dPriv->y; \ + int maxx = dPriv->pClipRects[_nc].x2 - dPriv->x; \ + int maxy = dPriv->pClipRects[_nc].y2 - dPriv->y; + + +#define HW_ENDCLIPLOOP() \ + } \ + } while (0) + +#define HW_UNLOCK() + +/* 16 bit, 565 rgb color spanline and pixel functions + */ +#define WRITE_RGBA( _x, _y, r, g, b, a ) \ + *(GLushort *)(buf + _x*2 + _y*pitch) = ( (((int)r & 0xf8) << 8) | \ + (((int)g & 0xfc) << 3) | \ + (((int)b & 0xf8) >> 3)) +#define WRITE_PIXEL( _x, _y, p ) \ + *(GLushort *)(buf + _x*2 + _y*pitch) = p + +#define READ_RGBA( rgba, _x, _y ) \ +do { \ + GLushort p = *(GLushort *)(read_buf + _x*2 + _y*pitch); \ + rgba[0] = (((p >> 11) & 0x1f) * 255) / 31; \ + rgba[1] = (((p >> 5) & 0x3f) * 255) / 63; \ + rgba[2] = (((p >> 0) & 0x1f) * 255) / 31; \ + rgba[3] = 255; \ +} while(0) + +#define TAG(x) intel##x##_565 +#include "spantmp.h" + + + + +/* 15 bit, 555 rgb color spanline and pixel functions + */ +#define WRITE_RGBA( _x, _y, r, g, b, a ) \ + *(GLushort *)(buf + _x*2 + _y*pitch) = (((r & 0xf8) << 7) | \ + ((g & 0xf8) << 3) | \ + ((b & 0xf8) >> 3)) + +#define WRITE_PIXEL( _x, _y, p ) \ + *(GLushort *)(buf + _x*2 + _y*pitch) = p + +#define READ_RGBA( rgba, _x, _y ) \ +do { \ + GLushort p = *(GLushort *)(read_buf + _x*2 + _y*pitch); \ + rgba[0] = (p >> 7) & 0xf8; \ + rgba[1] = (p >> 3) & 0xf8; \ + rgba[2] = (p << 3) & 0xf8; \ + rgba[3] = 255; \ +} while(0) + +#define TAG(x) intel##x##_555 +#include "spantmp.h" + +/* 16 bit depthbuffer functions. + */ +#define WRITE_DEPTH( _x, _y, d ) \ + *(GLushort *)(buf + _x*2 + _y*pitch) = d; + +#define READ_DEPTH( d, _x, _y ) \ + d = *(GLushort *)(buf + _x*2 + _y*pitch); + + +#define TAG(x) intel##x##_16 +#include "depthtmp.h" + + +#undef LOCAL_VARS +#define LOCAL_VARS \ + intelContextPtr intel = INTEL_CONTEXT(ctx); \ + __DRIdrawablePrivate *dPriv = intel->driDrawable; \ + intelScreenPrivate *intelScreen = intel->intelScreen; \ + GLuint pitch = intelScreen->backPitch * intelScreen->cpp; \ + GLuint height = dPriv->h; \ + char *buf = (char *)(intel->drawMap + \ + dPriv->x * intelScreen->cpp + \ + dPriv->y * pitch); \ + char *read_buf = (char *)(intel->readMap + \ + dPriv->x * intelScreen->cpp + \ + dPriv->y * pitch); \ + GLuint p; \ + (void) read_buf; (void) buf; (void) p + +#undef INIT_MONO_PIXEL +#define INIT_MONO_PIXEL(p,color)\ + p = PACK_COLOR_888(color[0],color[1],color[2]) + +/* 32 bit, 8888 argb color spanline and pixel functions + */ +#define WRITE_RGBA(_x, _y, r, g, b, a) \ + *(GLuint *)(buf + _x*4 + _y*pitch) = ((r << 16) | \ + (g << 8) | \ + (b << 0) | \ + (a << 24) ) + +#define WRITE_PIXEL(_x, _y, p) \ + *(GLuint *)(buf + _x*4 + _y*pitch) = p + + +#define READ_RGBA(rgba, _x, _y) \ + do { \ + GLuint p = *(GLuint *)(read_buf + _x*4 + _y*pitch); \ + rgba[0] = (p >> 16) & 0xff; \ + rgba[1] = (p >> 8) & 0xff; \ + rgba[2] = (p >> 0) & 0xff; \ + rgba[3] = (p >> 24) & 0xff; \ + } while (0) + +#define TAG(x) intel##x##_8888 +#include "spantmp.h" + + +/* 24/8 bit interleaved depth/stencil functions + */ +#define WRITE_DEPTH( _x, _y, d ) { \ + GLuint tmp = *(GLuint *)(buf + (_x)*4 + (_y)*pitch); \ + tmp &= 0xff000000; \ + tmp |= (d) & 0xffffff; \ + *(GLuint *)(buf + (_x)*4 + (_y)*pitch) = tmp; \ +} + +#define READ_DEPTH( d, _x, _y ) \ + d = *(GLuint *)(buf + (_x)*4 + (_y)*pitch) & 0xffffff; + + +#define TAG(x) intel##x##_24_8 +#include "depthtmp.h" + +#define WRITE_STENCIL( _x, _y, d ) { \ + GLuint tmp = *(GLuint *)(buf + (_x)*4 + (_y)*pitch); \ + tmp &= 0xffffff; \ + tmp |= ((d)<<24); \ + *(GLuint *)(buf + (_x)*4 + (_y)*pitch) = tmp; \ +} + +#define READ_STENCIL( d, _x, _y ) \ + d = *(GLuint *)(buf + (_x)*4 + (_y)*pitch) >> 24; + +#define TAG(x) intel##x##_24_8 +#include "stenciltmp.h" + + +/* + * This function is called to specify which buffer to read and write + * for software rasterization (swrast) fallbacks. This doesn't necessarily + * correspond to glDrawBuffer() or glReadBuffer() calls. + */ +static void intelSetBuffer(GLcontext *ctx, GLframebuffer *colorBuffer, + GLuint bufferBit) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + if (bufferBit == DD_FRONT_LEFT_BIT) { + intel->drawMap = (char *)intel->driScreen->pFB; + intel->readMap = (char *)intel->driScreen->pFB; + } else if (bufferBit == DD_BACK_LEFT_BIT) { + intel->drawMap = intel->intelScreen->back.map; + intel->readMap = intel->intelScreen->back.map; + } else { + ASSERT(0); + } +} + + +/* Move locking out to get reasonable span performance. + */ +void intelSpanRenderStart( GLcontext *ctx ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + + intelFlush(&intel->ctx); + LOCK_HARDWARE(intel); + intelWaitForIdle(intel); +} + +void intelSpanRenderFinish( GLcontext *ctx ) +{ + intelContextPtr intel = INTEL_CONTEXT( ctx ); + _swrast_flush( ctx ); + UNLOCK_HARDWARE( intel ); +} + +void intelInitSpanFuncs( GLcontext *ctx ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + intelScreenPrivate *intelScreen = intel->intelScreen; + + struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference(ctx); + + swdd->SetBuffer = intelSetBuffer; + + switch (intelScreen->fbFormat) { + case DV_PF_555: + swdd->WriteRGBASpan = intelWriteRGBASpan_555; + swdd->WriteRGBSpan = intelWriteRGBSpan_555; + swdd->WriteMonoRGBASpan = intelWriteMonoRGBASpan_555; + swdd->WriteRGBAPixels = intelWriteRGBAPixels_555; + swdd->WriteMonoRGBAPixels = intelWriteMonoRGBAPixels_555; + swdd->ReadRGBASpan = intelReadRGBASpan_555; + swdd->ReadRGBAPixels = intelReadRGBAPixels_555; + + swdd->ReadDepthSpan = intelReadDepthSpan_16; + swdd->WriteDepthSpan = intelWriteDepthSpan_16; + swdd->ReadDepthPixels = intelReadDepthPixels_16; + swdd->WriteDepthPixels = intelWriteDepthPixels_16; + break; + + case DV_PF_565: + swdd->WriteRGBASpan = intelWriteRGBASpan_565; + swdd->WriteRGBSpan = intelWriteRGBSpan_565; + swdd->WriteMonoRGBASpan = intelWriteMonoRGBASpan_565; + swdd->WriteRGBAPixels = intelWriteRGBAPixels_565; + swdd->WriteMonoRGBAPixels = intelWriteMonoRGBAPixels_565; + swdd->ReadRGBASpan = intelReadRGBASpan_565; + swdd->ReadRGBAPixels = intelReadRGBAPixels_565; + + swdd->ReadDepthSpan = intelReadDepthSpan_16; + swdd->WriteDepthSpan = intelWriteDepthSpan_16; + swdd->ReadDepthPixels = intelReadDepthPixels_16; + swdd->WriteDepthPixels = intelWriteDepthPixels_16; + break; + + case DV_PF_8888: + swdd->WriteRGBASpan = intelWriteRGBASpan_8888; + swdd->WriteRGBSpan = intelWriteRGBSpan_8888; + swdd->WriteMonoRGBASpan = intelWriteMonoRGBASpan_8888; + swdd->WriteRGBAPixels = intelWriteRGBAPixels_8888; + swdd->WriteMonoRGBAPixels = intelWriteMonoRGBAPixels_8888; + swdd->ReadRGBASpan = intelReadRGBASpan_8888; + swdd->ReadRGBAPixels = intelReadRGBAPixels_8888; + + swdd->ReadDepthSpan = intelReadDepthSpan_24_8; + swdd->WriteDepthSpan = intelWriteDepthSpan_24_8; + swdd->ReadDepthPixels = intelReadDepthPixels_24_8; + swdd->WriteDepthPixels = intelWriteDepthPixels_24_8; + + swdd->WriteStencilSpan = intelWriteStencilSpan_24_8; + swdd->ReadStencilSpan = intelReadStencilSpan_24_8; + swdd->WriteStencilPixels = intelWriteStencilPixels_24_8; + swdd->ReadStencilPixels = intelReadStencilPixels_24_8; + break; + } + + swdd->SpanRenderStart = intelSpanRenderStart; + swdd->SpanRenderFinish = intelSpanRenderFinish; +} diff --git a/src/mesa/drivers/dri/i915/intel_span.h b/src/mesa/drivers/dri/i915/intel_span.h new file mode 100644 index 0000000..3498bd4 --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_span.h @@ -0,0 +1,16 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#ifndef _INTEL_SPAN_H +#define _INTEL_SPAN_H + +extern void intelInitSpanFuncs( GLcontext *ctx ); + +extern void intelSpanRenderFinish( GLcontext *ctx ); +extern void intelSpanRenderStart( GLcontext *ctx ); + +#endif diff --git a/src/mesa/drivers/dri/i915/intel_state.c b/src/mesa/drivers/dri/i915/intel_state.c new file mode 100644 index 0000000..23e4955 --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_state.c @@ -0,0 +1,135 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + + +#include "glheader.h" +#include "context.h" +#include "macros.h" +#include "enums.h" +#include "dd.h" + +#include "intel_screen.h" +#include "intel_context.h" +#include "swrast/swrast.h" + + +static void intelDrawBuffer(GLcontext *ctx, GLenum mode ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + intelScreenPrivate *screen = intel->intelScreen; + int front = 0; + + switch ( ctx->Color._DrawDestMask ) { + case DD_FRONT_LEFT_BIT: + front = 1; + FALLBACK( intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE ); + break; + case DD_BACK_LEFT_BIT: + front = 0; + FALLBACK( intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE ); + break; + default: + FALLBACK( intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE ); + return; + } + + /* We want to update the s/w rast state too so that r200SetBuffer() + * gets called. + */ + _swrast_DrawBuffer(ctx, mode); + + if ( intel->sarea->pf_current_page == 1 ) + front ^= 1; + + intelSetFrontClipRects( intel ); + + if (front) { + intel->drawOffset = screen->frontOffset; + intel->drawMap = (char *)intel->driScreen->pFB; + intel->readMap = (char *)intel->driScreen->pFB; + } else { + intel->drawOffset = screen->backOffset; + intel->drawMap = screen->back.map; + intel->readMap = screen->back.map; + } + + intel->vtbl.set_draw_offset( intel, intel->drawOffset ); +} + +static void intelReadBuffer( GLcontext *ctx, GLenum mode ) +{ + /* nothing, until we implement h/w glRead/CopyPixels or CopyTexImage */ +} + + +static void intelClearColor(GLcontext *ctx, const GLfloat color[4]) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + intelScreenPrivate *screen = intel->intelScreen; + + CLAMPED_FLOAT_TO_UBYTE(intel->clear_red, color[0]); + CLAMPED_FLOAT_TO_UBYTE(intel->clear_green, color[1]); + CLAMPED_FLOAT_TO_UBYTE(intel->clear_blue, color[2]); + CLAMPED_FLOAT_TO_UBYTE(intel->clear_alpha, color[3]); + + intel->ClearColor = INTEL_PACKCOLOR(screen->fbFormat, + intel->clear_red, + intel->clear_green, + intel->clear_blue, + intel->clear_alpha); +} + + +static void intelCalcViewport( GLcontext *ctx ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + const GLfloat *v = ctx->Viewport._WindowMap.m; + GLfloat *m = intel->ViewportMatrix.m; + + /* See also intel_translate_vertex. SUBPIXEL adjustments can be done + * via state vars, too. + */ + m[MAT_SX] = v[MAT_SX]; + m[MAT_TX] = v[MAT_TX] + SUBPIXEL_X; + m[MAT_SY] = - v[MAT_SY]; + m[MAT_TY] = - v[MAT_TY] + intel->driDrawable->h + SUBPIXEL_Y; + m[MAT_SZ] = v[MAT_SZ] * intel->depth_scale; + m[MAT_TZ] = v[MAT_TZ] * intel->depth_scale; +} + +static void intelViewport( GLcontext *ctx, + GLint x, GLint y, + GLsizei width, GLsizei height ) +{ + intelCalcViewport( ctx ); +} + +static void intelDepthRange( GLcontext *ctx, + GLclampd nearval, GLclampd farval ) +{ + intelCalcViewport( ctx ); +} + +/* Fallback to swrast for select and feedback. + */ +static void intelRenderMode( GLcontext *ctx, GLenum mode ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + FALLBACK( intel, INTEL_FALLBACK_RENDERMODE, (mode != GL_RENDER) ); +} + + +void intelInitStateFuncs( struct dd_function_table *functions ) +{ + functions->DrawBuffer = intelDrawBuffer; + functions->ReadBuffer = intelReadBuffer; + functions->RenderMode = intelRenderMode; + functions->Viewport = intelViewport; + functions->DepthRange = intelDepthRange; + functions->ClearColor = intelClearColor; +} + diff --git a/src/mesa/drivers/dri/i915/intel_tex.c b/src/mesa/drivers/dri/i915/intel_tex.c new file mode 100644 index 0000000..fac6efa --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_tex.c @@ -0,0 +1,665 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "glheader.h" +#include "mtypes.h" +#include "imports.h" +#include "simple_list.h" +#include "enums.h" +#include "image.h" +#include "texstore.h" +#include "texformat.h" +#include "teximage.h" +#include "texmem.h" +#include "texobj.h" +#include "swrast/swrast.h" + +#include "mm.h" + +#include "intel_screen.h" +#include "intel_batchbuffer.h" +#include "intel_context.h" +#include "intel_tex.h" +#include "intel_ioctl.h" + + + +static GLboolean +intelValidateClientStorage( intelContextPtr intel, GLenum target, + GLint internalFormat, + GLint srcWidth, GLint srcHeight, + GLenum format, GLenum type, const void *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage) + +{ + GLcontext *ctx = &intel->ctx; + int texelBytes; + + if (0) + fprintf(stderr, "intformat %s format %s type %s\n", + _mesa_lookup_enum_by_nr( internalFormat ), + _mesa_lookup_enum_by_nr( format ), + _mesa_lookup_enum_by_nr( type )); + + if (!ctx->Unpack.ClientStorage) + return 0; + + if (ctx->_ImageTransferState || + texImage->IsCompressed || + texObj->GenerateMipmap) + return 0; + + + /* This list is incomplete + */ + switch ( internalFormat ) { + case GL_RGBA: + if ( format == GL_BGRA && type == GL_UNSIGNED_INT_8_8_8_8_REV ) { + texImage->TexFormat = &_mesa_texformat_argb8888; + texelBytes = 4; + } + else + return 0; + break; + + case GL_RGB: + if ( format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5 ) { + texImage->TexFormat = &_mesa_texformat_rgb565; + texelBytes = 2; + } + else + return 0; + break; + + case GL_YCBCR_MESA: + if ( format == GL_YCBCR_MESA && + type == GL_UNSIGNED_SHORT_8_8_REV_APPLE ) { + texImage->TexFormat = &_mesa_texformat_ycbcr_rev; + texelBytes = 2; + } + else if ( format == GL_YCBCR_MESA && + (type == GL_UNSIGNED_SHORT_8_8_APPLE || + type == GL_UNSIGNED_BYTE)) { + texImage->TexFormat = &_mesa_texformat_ycbcr; + texelBytes = 2; + } + else + return 0; + break; + + + default: + return 0; + } + + /* Could deal with these packing issues, but currently don't: + */ + if (packing->SkipPixels || + packing->SkipRows || + packing->SwapBytes || + packing->LsbFirst) { + return 0; + } + + { + GLint srcRowStride = _mesa_image_row_stride(packing, srcWidth, + format, type); + + + if (0) + fprintf(stderr, "%s: srcRowStride %d/%x\n", + __FUNCTION__, srcRowStride, srcRowStride); + + /* Could check this later in upload, pitch restrictions could be + * relaxed, but would need to store the image pitch somewhere, + * as packing details might change before image is uploaded: + */ + if (!intelIsAgpMemory( intel, pixels, srcHeight * srcRowStride ) || + (srcRowStride & 63)) + return 0; + + + /* Have validated that _mesa_transfer_teximage would be a straight + * memcpy at this point. NOTE: future calls to TexSubImage will + * overwrite the client data. This is explicitly mentioned in the + * extension spec. + */ + texImage->Data = (void *)pixels; + texImage->IsClientData = GL_TRUE; + texImage->RowStride = srcRowStride / texelBytes; + return 1; + } +} + + + +static void intelTexImage1D( GLcontext *ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint border, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + assert(t); + intelFlush( ctx ); + driSwapOutTextureObject( t ); + + texImage->IsClientData = GL_FALSE; + + _mesa_store_teximage1d( ctx, target, level, internalFormat, + width, border, format, type, + pixels, packing, texObj, texImage ); + + t->dirty_images[0] |= (1 << level); +} + +static void intelTexSubImage1D( GLcontext *ctx, + GLenum target, + GLint level, + GLint xoffset, + GLsizei width, + GLenum format, GLenum type, + const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + assert(t); + intelFlush( ctx ); + driSwapOutTextureObject( t ); + + _mesa_store_texsubimage1d(ctx, target, level, xoffset, width, + format, type, pixels, packing, texObj, + texImage); +} + + +/* Handles 2D, CUBE, RECT: + */ +static void intelTexImage2D( GLcontext *ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint border, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + GLuint face; + + /* which cube face or ordinary 2D image */ + switch (target) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; + ASSERT(face < 6); + break; + default: + face = 0; + } + + assert(t); + intelFlush( ctx ); + driSwapOutTextureObject( t ); + texImage->IsClientData = GL_FALSE; + + if (intelValidateClientStorage( INTEL_CONTEXT(ctx), target, + internalFormat, + width, height, + format, type, pixels, + packing, texObj, texImage)) { + if (INTEL_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "%s: Using client storage\n", __FUNCTION__); + } + else { + _mesa_store_teximage2d( ctx, target, level, internalFormat, + width, height, border, format, type, + pixels, packing, texObj, texImage ); + + t->dirty_images[face] |= (1 << level); + } +} + +static void intelTexSubImage2D( GLcontext *ctx, + GLenum target, + GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + GLuint face; + + /* which cube face or ordinary 2D image */ + switch (target) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; + ASSERT(face < 6); + break; + default: + face = 0; + } + + if (texImage->IsClientData && + (char *)pixels == (char *)texImage->Data + + ((xoffset + yoffset * texImage->RowStride) * + texImage->TexFormat->TexelBytes)) { + + /* Notification only - no upload required */ + } + else { + assert( t ); /* this _should_ be true */ + intelFlush( ctx ); + driSwapOutTextureObject( t ); + + _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width, + height, format, type, pixels, packing, texObj, + texImage); + + t->dirty_images[face] |= (1 << level); + } +} + + + +static void intelTexImage3D( GLcontext *ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint depth, + GLint border, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + assert(t); + driSwapOutTextureObject( t ); + texImage->IsClientData = GL_FALSE; + + _mesa_store_teximage3d(ctx, target, level, internalFormat, + width, height, depth, border, + format, type, pixels, + &ctx->Unpack, texObj, texImage); + + t->dirty_images[0] |= (1 << level); +} + + +static void +intelTexSubImage3D( GLcontext *ctx, GLenum target, GLint level, + GLint xoffset, GLint yoffset, GLint zoffset, + GLsizei width, GLsizei height, GLsizei depth, + GLenum format, GLenum type, + const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + assert( t ); /* this _should_ be true */ + driSwapOutTextureObject( t ); + + _mesa_store_texsubimage3d(ctx, target, level, xoffset, yoffset, zoffset, + width, height, depth, + format, type, pixels, packing, texObj, texImage); + + t->dirty_images[0] |= (1 << level); +} + + + + +static void intelDeleteTexture( GLcontext *ctx, struct gl_texture_object *tObj ) +{ + driTextureObject * t = (driTextureObject *) tObj->DriverData; + + if ( t != NULL ) { + intelFlush( ctx ); + driDestroyTextureObject( t ); + } + + /* Free mipmap images and the texture object itself */ + _mesa_delete_texture_object(ctx, tObj); +} + + +static const struct gl_texture_format * +intelChooseTextureFormat( GLcontext *ctx, GLint internalFormat, + GLenum format, GLenum type ) +{ + intelContextPtr intel = INTEL_CONTEXT( ctx ); + const GLboolean do32bpt = ( intel->intelScreen->cpp == 4 && + intel->intelScreen->textureSize > 4*1024*1024); + + switch ( internalFormat ) { + case 4: + case GL_RGBA: + case GL_COMPRESSED_RGBA: + if ( format == GL_BGRA ) { + if ( type == GL_UNSIGNED_INT_8_8_8_8_REV ) { + return &_mesa_texformat_argb8888; + } + else if ( type == GL_UNSIGNED_SHORT_4_4_4_4_REV ) { + return &_mesa_texformat_argb4444; + } + else if ( type == GL_UNSIGNED_SHORT_1_5_5_5_REV ) { + return &_mesa_texformat_argb1555; + } + } + return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444; + + case 3: + case GL_RGB: + case GL_COMPRESSED_RGB: + if ( format == GL_RGB && type == GL_UNSIGNED_SHORT_5_6_5 ) { + return &_mesa_texformat_rgb565; + } + return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565; + + case GL_RGBA8: + case GL_RGB10_A2: + case GL_RGBA12: + case GL_RGBA16: + return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444; + + case GL_RGBA4: + case GL_RGBA2: + return &_mesa_texformat_argb4444; + + case GL_RGB5_A1: + return &_mesa_texformat_argb1555; + + case GL_RGB8: + case GL_RGB10: + case GL_RGB12: + case GL_RGB16: + return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565; + + case GL_RGB5: + case GL_RGB4: + case GL_R3_G3_B2: + return &_mesa_texformat_rgb565; + + case GL_ALPHA: + case GL_ALPHA4: + case GL_ALPHA8: + case GL_ALPHA12: + case GL_ALPHA16: + case GL_COMPRESSED_ALPHA: +/* if (1 || intel->intelScreen->deviceID == PCI_CHIP_I915_G) */ + return &_mesa_texformat_a8; +/* else */ +/* return &_mesa_texformat_al88; */ + + case 1: + case GL_LUMINANCE: + case GL_LUMINANCE4: + case GL_LUMINANCE8: + case GL_LUMINANCE12: + case GL_LUMINANCE16: + case GL_COMPRESSED_LUMINANCE: + return &_mesa_texformat_l8; + + case 2: + case GL_LUMINANCE_ALPHA: + case GL_LUMINANCE4_ALPHA4: + case GL_LUMINANCE6_ALPHA2: + case GL_LUMINANCE8_ALPHA8: + case GL_LUMINANCE12_ALPHA4: + case GL_LUMINANCE12_ALPHA12: + case GL_LUMINANCE16_ALPHA16: + case GL_COMPRESSED_LUMINANCE_ALPHA: + return &_mesa_texformat_al88; + + case GL_INTENSITY: + case GL_INTENSITY4: + case GL_INTENSITY8: + case GL_INTENSITY12: + case GL_INTENSITY16: + case GL_COMPRESSED_INTENSITY: + return &_mesa_texformat_i8; + + case GL_YCBCR_MESA: + if (type == GL_UNSIGNED_SHORT_8_8_MESA || + type == GL_UNSIGNED_BYTE) + return &_mesa_texformat_ycbcr; + else + return &_mesa_texformat_ycbcr_rev; + + default: + fprintf(stderr, "unexpected texture format in %s\n", __FUNCTION__); + return NULL; + } + + return NULL; /* never get here */ +} + + + +void intelDestroyTexObj(intelContextPtr intel, intelTextureObjectPtr t) +{ + unsigned i; + + if ( intel == NULL ) + return; + + if ( t->age > intel->dirtyAge ) + intel->dirtyAge = t->age; + + for ( i = 0 ; i < MAX_TEXTURE_UNITS ; i++ ) { + if ( t == intel->CurrentTexObj[ i ] ) + intel->CurrentTexObj[ i ] = NULL; + } +} + + + +/* Upload an image from mesa's internal copy. Image may be 1D, 2D or + * 3D. Cubemaps are expanded elsewhere. + */ +static void intelUploadTexImage( intelContextPtr intel, + intelTextureObjectPtr t, + const struct gl_texture_image *image, + const GLuint offset ) +{ + + if (!image || !image->Data) + return; + + if (image->Depth == 1 && image->IsClientData) { + if (INTEL_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "Blit uploading\n"); + + /* Do it with a blit. + */ + intelEmitCopyBlitLocked( intel, + image->TexFormat->TexelBytes, + image->RowStride, /* ? */ + intelGetMemoryOffsetMESA( NULL, 0, image->Data ), + t->Pitch / image->TexFormat->TexelBytes, + intelGetMemoryOffsetMESA( NULL, 0, t->BufAddr + offset ), + 0, 0, + 0, 0, + image->Width, + image->Height); + } + else { + GLuint row_len = image->Width * image->TexFormat->TexelBytes; + GLubyte *dst = (GLubyte *)(t->BufAddr + offset); + GLubyte *src = (GLubyte *)image->Data; + GLuint d, j; + + if (INTEL_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, + "Upload image %dx%dx%d offset %xm row_len %x " + "pitch %x depth_pitch %x\n", + image->Width, image->Height, image->Depth, offset, + row_len, t->Pitch, t->depth_pitch); + + if (row_len == t->Pitch) { + for (d = 0; d < image->Depth; d++) { + memcpy( dst, src, t->Pitch * image->Height ); + dst += t->depth_pitch; + src += row_len * image->Height; + } + } + else { + for (d = 0 ; d < image->Depth ; d++) { + for (j = 0 ; j < image->Height ; j++) { + __memcpy(dst, src, row_len ); + src += row_len; + dst += t->Pitch; + } + + dst += t->depth_pitch - (t->Pitch * image->Height); + } + } + } +} + + + +int intelUploadTexImages( intelContextPtr intel, + intelTextureObjectPtr t, + GLuint face) +{ + const int numLevels = t->base.lastLevel - t->base.firstLevel + 1; + const struct gl_texture_image *firstImage = t->image[face][t->base.firstLevel].image; + int pitch = firstImage->RowStride * firstImage->TexFormat->TexelBytes; + + /* Can we texture out of the existing client data? */ + if ( numLevels == 1 && + firstImage->IsClientData && + (pitch & 3) == 0) { + + if (INTEL_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "AGP texturing from client memory\n"); + + t->TextureOffset = intelAgpOffsetFromVirtual( intel, firstImage->Data ); + t->BufAddr = 0; + t->dirty = ~0; + return GL_TRUE; + } + else { + if (INTEL_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "Uploading client data to agp\n"); + + INTEL_FIREVERTICES( intel ); + LOCK_HARDWARE( intel ); + + if ( t->base.memBlock == NULL ) { + int heap; + + heap = driAllocateTexture( intel->texture_heaps, intel->nr_heaps, + (driTextureObject *) t ); + if ( heap == -1 ) { + UNLOCK_HARDWARE( intel ); + return GL_FALSE; + } + + /* Set the base offset of the texture image */ + t->BufAddr = intel->intelScreen->tex.map + t->base.memBlock->ofs; + t->TextureOffset = intel->intelScreen->textureOffset + t->base.memBlock->ofs; + t->dirty = ~0; + } + + + /* Let the world know we've used this memory recently. + */ + driUpdateTextureLRU( (driTextureObject *) t ); + + + /* Upload any images that are new */ + if (t->base.dirty_images[face]) { + int i; + + intelWaitForIdle( intel ); + + for (i = 0 ; i < numLevels ; i++) { + int level = i + t->base.firstLevel; + + if (t->base.dirty_images[face] & (1<image[face][i].image; + GLuint offset = t->image[face][i].offset; + + if (INTEL_DEBUG & DEBUG_TEXTURE) + fprintf(stderr, "upload level %d, offset %x\n", + level, offset); + + intelUploadTexImage( intel, t, image, offset ); + } + } + t->base.dirty_images[face] = 0; + intel->perf_boxes |= I830_BOX_TEXTURE_LOAD; + } + + UNLOCK_HARDWARE( intel ); + return GL_TRUE; + } +} + +/** + * Allocate a new texture object. + * Called via ctx->Driver.NewTextureObject. + * Note: this function will be called during context creation to + * allocate the default texture objects. + * Note: we could use containment here to 'derive' the driver-specific + * texture object from the core mesa gl_texture_object. Not done at this time. + */ +static struct gl_texture_object * +intelNewTextureObject( GLcontext *ctx, GLuint name, GLenum target ) +{ + struct gl_texture_object *obj = _mesa_new_texture_object(ctx, name, target); + INTEL_CONTEXT(ctx)->vtbl.alloc_tex_obj( obj ); + return obj; +} + + +void intelInitTextureFuncs( struct dd_function_table *functions ) +{ + functions->NewTextureObject = intelNewTextureObject; + functions->ChooseTextureFormat = intelChooseTextureFormat; + functions->TexImage1D = intelTexImage1D; + functions->TexImage2D = intelTexImage2D; + functions->TexImage3D = intelTexImage3D; + functions->TexSubImage1D = intelTexSubImage1D; + functions->TexSubImage2D = intelTexSubImage2D; + functions->TexSubImage3D = intelTexSubImage3D; + functions->CopyTexImage1D = _swrast_copy_teximage1d; + functions->CopyTexImage2D = _swrast_copy_teximage2d; + functions->CopyTexSubImage1D = _swrast_copy_texsubimage1d; + functions->CopyTexSubImage2D = _swrast_copy_texsubimage2d; + functions->CopyTexSubImage3D = _swrast_copy_texsubimage3d; + functions->DeleteTexture = intelDeleteTexture; + functions->UpdateTexturePalette = NULL; + functions->IsTextureResident = driIsTextureResident; + functions->TestProxyTexImage = _mesa_test_proxy_teximage; + functions->DeleteTexture = intelDeleteTexture; +} diff --git a/src/mesa/drivers/dri/i915/intel_tex.h b/src/mesa/drivers/dri/i915/intel_tex.h new file mode 100644 index 0000000..fd4b926 --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_tex.h @@ -0,0 +1,22 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#ifndef INTELTEX_INC +#define INTELTEX_INC + +#include "mtypes.h" +#include "intel_context.h" +#include "texmem.h" + + +void intelInitTextureFuncs( struct dd_function_table *functions ); + +void intelDestroyTexObj( intelContextPtr intel, intelTextureObjectPtr t ); +int intelUploadTexImages( intelContextPtr intel, intelTextureObjectPtr t, + GLuint face ); + +#endif diff --git a/src/mesa/drivers/dri/i915/intel_tris.c b/src/mesa/drivers/dri/i915/intel_tris.c new file mode 100644 index 0000000..07d9878 --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_tris.c @@ -0,0 +1,900 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#include "glheader.h" +#include "context.h" +#include "macros.h" +#include "enums.h" +#include "dd.h" + +#include "swrast/swrast.h" +#include "swrast_setup/swrast_setup.h" +#include "tnl/t_context.h" +#include "tnl/t_pipeline.h" +#include "tnl/t_vertex.h" + +#include "intel_screen.h" +#include "intel_tris.h" +#include "intel_batchbuffer.h" +#include "intel_reg.h" +#include "intel_span.h" + +static void intelRenderPrimitive( GLcontext *ctx, GLenum prim ); +static void intelRasterPrimitive( GLcontext *ctx, GLenum rprim, GLuint hwprim ); + +/*********************************************************************** + * Emit primitives as inline vertices * + ***********************************************************************/ + +#if 1 +#define COPY_DWORDS( j, vb, vertsize, v ) \ +do { \ + int __tmp; \ + __asm__ __volatile__( "rep ; movsl" \ + : "=%c" (j), "=D" (vb), "=S" (__tmp) \ + : "0" (vertsize), \ + "D" ((long)vb), \ + "S" ((long)v) ); \ +} while (0) +#else +#define COPY_DWORDS( j, vb, vertsize, v ) \ +do { \ + if (1) fprintf(stderr, "\n"); \ + for ( j = 0 ; j < vertsize ; j++ ) { \ + if (1) fprintf(stderr, " -- v(%d): %x/%f\n",j, \ + ((GLuint *)v)[j], \ + ((GLfloat *)v)[j]); \ + vb[j] = ((GLuint *)v)[j]; \ + } \ + vb += vertsize; \ +} while (0) +#endif + +static void __inline__ intel_draw_quad( intelContextPtr intel, + intelVertexPtr v0, + intelVertexPtr v1, + intelVertexPtr v2, + intelVertexPtr v3 ) +{ + GLuint vertsize = intel->vertex_size; + GLuint *vb = intelExtendInlinePrimitive( intel, 6 * vertsize ); + int j; + + COPY_DWORDS( j, vb, vertsize, v0 ); + COPY_DWORDS( j, vb, vertsize, v1 ); + COPY_DWORDS( j, vb, vertsize, v3 ); + COPY_DWORDS( j, vb, vertsize, v1 ); + COPY_DWORDS( j, vb, vertsize, v2 ); + COPY_DWORDS( j, vb, vertsize, v3 ); +} + +static void __inline__ intel_draw_triangle( intelContextPtr intel, + intelVertexPtr v0, + intelVertexPtr v1, + intelVertexPtr v2 ) +{ + GLuint vertsize = intel->vertex_size; + GLuint *vb = intelExtendInlinePrimitive( intel, 3 * vertsize ); + int j; + + COPY_DWORDS( j, vb, vertsize, v0 ); + COPY_DWORDS( j, vb, vertsize, v1 ); + COPY_DWORDS( j, vb, vertsize, v2 ); +} + + +static __inline__ void intel_draw_line( intelContextPtr intel, + intelVertexPtr v0, + intelVertexPtr v1 ) +{ + GLuint vertsize = intel->vertex_size; + GLuint *vb = intelExtendInlinePrimitive( intel, 2 * vertsize ); + int j; + + COPY_DWORDS( j, vb, vertsize, v0 ); + COPY_DWORDS( j, vb, vertsize, v1 ); +} + + +static __inline__ void intel_draw_point( intelContextPtr intel, + intelVertexPtr v0 ) +{ + GLuint vertsize = intel->vertex_size; + GLuint *vb = intelExtendInlinePrimitive( intel, vertsize ); + int j; + + /* Adjust for sub pixel position -- still required for conform. */ + *(float *)&vb[0] = v0->v.x - 0.125; + *(float *)&vb[1] = v0->v.y - 0.125; + for (j = 2 ; j < vertsize ; j++) + vb[j] = v0->ui[j]; +} + + + +/*********************************************************************** + * Fixup for ARB_point_parameters * + ***********************************************************************/ + +static void intel_atten_point( intelContextPtr intel, intelVertexPtr v0 ) +{ + GLcontext *ctx = &intel->ctx; + GLfloat psz[4], col[4], restore_psz, restore_alpha; + + _tnl_get_attr( ctx, v0, _TNL_ATTRIB_POINTSIZE, psz ); + _tnl_get_attr( ctx, v0, _TNL_ATTRIB_COLOR0, col ); + + restore_psz = psz[0]; + restore_alpha = col[3]; + + if (psz[0] >= ctx->Point.Threshold) { + psz[0] = MIN2(psz[0], ctx->Point.MaxSize); + } + else { + GLfloat dsize = psz[0] / ctx->Point.Threshold; + psz[0] = MAX2(ctx->Point.Threshold, ctx->Point.MinSize); + col[3] *= dsize * dsize; + } + + if (psz[0] < 1.0) + psz[0] = 1.0; + + if (restore_psz != psz[0] || restore_alpha != col[3]) { + _tnl_set_attr( ctx, v0, _TNL_ATTRIB_POINTSIZE, psz); + _tnl_set_attr( ctx, v0, _TNL_ATTRIB_COLOR0, col); + + intel_draw_point( intel, v0 ); + + psz[0] = restore_psz; + col[3] = restore_alpha; + + _tnl_set_attr( ctx, v0, _TNL_ATTRIB_POINTSIZE, psz); + _tnl_set_attr( ctx, v0, _TNL_ATTRIB_COLOR0, col); + } + else + intel_draw_point( intel, v0 ); +} + + + + + +/*********************************************************************** + * Fixup for I915 WPOS texture coordinate * + ***********************************************************************/ + + + +static void intel_wpos_triangle( intelContextPtr intel, + intelVertexPtr v0, + intelVertexPtr v1, + intelVertexPtr v2 ) +{ + GLuint offset = intel->wpos_offset; + GLuint size = intel->wpos_size; + + __memcpy( ((char *)v0) + offset, v0, size ); + __memcpy( ((char *)v1) + offset, v1, size ); + __memcpy( ((char *)v2) + offset, v2, size ); + + intel_draw_triangle( intel, v0, v1, v2 ); +} + + +static void intel_wpos_line( intelContextPtr intel, + intelVertexPtr v0, + intelVertexPtr v1 ) +{ + GLuint offset = intel->wpos_offset; + GLuint size = intel->wpos_size; + + __memcpy( ((char *)v0) + offset, v0, size ); + __memcpy( ((char *)v1) + offset, v1, size ); + + intel_draw_line( intel, v0, v1 ); +} + + +static void intel_wpos_point( intelContextPtr intel, + intelVertexPtr v0 ) +{ + GLuint offset = intel->wpos_offset; + GLuint size = intel->wpos_size; + + __memcpy( ((char *)v0) + offset, v0, size ); + + intel_draw_point( intel, v0 ); +} + + + + + + +/*********************************************************************** + * Macros for t_dd_tritmp.h to draw basic primitives * + ***********************************************************************/ + +#define TRI( a, b, c ) \ +do { \ + if (DO_FALLBACK) \ + intel->draw_tri( intel, a, b, c ); \ + else \ + intel_draw_triangle( intel, a, b, c ); \ +} while (0) + +#define QUAD( a, b, c, d ) \ +do { \ + if (DO_FALLBACK) { \ + intel->draw_tri( intel, a, b, d ); \ + intel->draw_tri( intel, b, c, d ); \ + } else \ + intel_draw_quad( intel, a, b, c, d ); \ +} while (0) + +#define LINE( v0, v1 ) \ +do { \ + if (DO_FALLBACK) \ + intel->draw_line( intel, v0, v1 ); \ + else \ + intel_draw_line( intel, v0, v1 ); \ +} while (0) + +#define POINT( v0 ) \ +do { \ + if (DO_FALLBACK) \ + intel->draw_point( intel, v0 ); \ + else \ + intel_draw_point( intel, v0 ); \ +} while (0) + + +/*********************************************************************** + * Build render functions from dd templates * + ***********************************************************************/ + +#define INTEL_OFFSET_BIT 0x01 +#define INTEL_TWOSIDE_BIT 0x02 +#define INTEL_UNFILLED_BIT 0x04 +#define INTEL_FALLBACK_BIT 0x08 +#define INTEL_MAX_TRIFUNC 0x10 + + +static struct { + points_func points; + line_func line; + triangle_func triangle; + quad_func quad; +} rast_tab[INTEL_MAX_TRIFUNC]; + + +#define DO_FALLBACK (IND & INTEL_FALLBACK_BIT) +#define DO_OFFSET (IND & INTEL_OFFSET_BIT) +#define DO_UNFILLED (IND & INTEL_UNFILLED_BIT) +#define DO_TWOSIDE (IND & INTEL_TWOSIDE_BIT) +#define DO_FLAT 0 +#define DO_TRI 1 +#define DO_QUAD 1 +#define DO_LINE 1 +#define DO_POINTS 1 +#define DO_FULL_QUAD 1 + +#define HAVE_RGBA 1 +#define HAVE_SPEC 1 +#define HAVE_BACK_COLORS 0 +#define HAVE_HW_FLATSHADE 1 +#define VERTEX intelVertex +#define TAB rast_tab + +/* Only used to pull back colors into vertices (ie, we know color is + * floating point). + */ +#define INTEL_COLOR( dst, src ) \ +do { \ + UNCLAMPED_FLOAT_TO_UBYTE((dst)[0], (src)[2]); \ + UNCLAMPED_FLOAT_TO_UBYTE((dst)[1], (src)[1]); \ + UNCLAMPED_FLOAT_TO_UBYTE((dst)[2], (src)[0]); \ + UNCLAMPED_FLOAT_TO_UBYTE((dst)[3], (src)[3]); \ +} while (0) + +#define INTEL_SPEC( dst, src ) \ +do { \ + UNCLAMPED_FLOAT_TO_UBYTE((dst)[0], (src)[2]); \ + UNCLAMPED_FLOAT_TO_UBYTE((dst)[1], (src)[1]); \ + UNCLAMPED_FLOAT_TO_UBYTE((dst)[2], (src)[0]); \ +} while (0) + + +#define DEPTH_SCALE intel->polygon_offset_scale +#define UNFILLED_TRI unfilled_tri +#define UNFILLED_QUAD unfilled_quad +#define VERT_X(_v) _v->v.x +#define VERT_Y(_v) _v->v.y +#define VERT_Z(_v) _v->v.z +#define AREA_IS_CCW( a ) (a > 0) +#define GET_VERTEX(e) (intel->verts + (e * intel->vertex_size * sizeof(GLuint))) + +#define VERT_SET_RGBA( v, c ) if (coloroffset) INTEL_COLOR( v->ub4[coloroffset], c ) +#define VERT_COPY_RGBA( v0, v1 ) if (coloroffset) v0->ui[coloroffset] = v1->ui[coloroffset] +#define VERT_SAVE_RGBA( idx ) if (coloroffset) color[idx] = v[idx]->ui[coloroffset] +#define VERT_RESTORE_RGBA( idx ) if (coloroffset) v[idx]->ui[coloroffset] = color[idx] + +#define VERT_SET_SPEC( v, c ) if (specoffset) INTEL_SPEC( v->ub4[specoffset], c ) +#define VERT_COPY_SPEC( v0, v1 ) if (specoffset) COPY_3V(v0->ub4[specoffset], v1->ub4[specoffset]) +#define VERT_SAVE_SPEC( idx ) if (specoffset) spec[idx] = v[idx]->ui[specoffset] +#define VERT_RESTORE_SPEC( idx ) if (specoffset) v[idx]->ui[specoffset] = spec[idx] + +#define LOCAL_VARS(n) \ + intelContextPtr intel = INTEL_CONTEXT(ctx); \ + GLuint color[n], spec[n]; \ + GLuint coloroffset = intel->coloroffset; \ + GLboolean specoffset = intel->specoffset; \ + (void) color; (void) spec; (void) coloroffset; (void) specoffset; + + +/*********************************************************************** + * Helpers for rendering unfilled primitives * + ***********************************************************************/ + +static const GLuint hw_prim[GL_POLYGON+1] = { + PRIM3D_POINTLIST, + PRIM3D_LINELIST, + PRIM3D_LINELIST, + PRIM3D_LINELIST, + PRIM3D_TRILIST, + PRIM3D_TRILIST, + PRIM3D_TRILIST, + PRIM3D_TRILIST, + PRIM3D_TRILIST, + PRIM3D_TRILIST +}; + +#define RASTERIZE(x) intelRasterPrimitive( ctx, x, hw_prim[x] ) +#define RENDER_PRIMITIVE intel->render_primitive +#define TAG(x) x +#define IND INTEL_FALLBACK_BIT +#include "tnl_dd/t_dd_unfilled.h" +#undef IND + +/*********************************************************************** + * Generate GL render functions * + ***********************************************************************/ + +#define IND (0) +#define TAG(x) x +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (INTEL_OFFSET_BIT) +#define TAG(x) x##_offset +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (INTEL_TWOSIDE_BIT) +#define TAG(x) x##_twoside +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (INTEL_TWOSIDE_BIT|INTEL_OFFSET_BIT) +#define TAG(x) x##_twoside_offset +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (INTEL_UNFILLED_BIT) +#define TAG(x) x##_unfilled +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (INTEL_OFFSET_BIT|INTEL_UNFILLED_BIT) +#define TAG(x) x##_offset_unfilled +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (INTEL_TWOSIDE_BIT|INTEL_UNFILLED_BIT) +#define TAG(x) x##_twoside_unfilled +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (INTEL_TWOSIDE_BIT|INTEL_OFFSET_BIT|INTEL_UNFILLED_BIT) +#define TAG(x) x##_twoside_offset_unfilled +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (INTEL_FALLBACK_BIT) +#define TAG(x) x##_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (INTEL_OFFSET_BIT|INTEL_FALLBACK_BIT) +#define TAG(x) x##_offset_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (INTEL_TWOSIDE_BIT|INTEL_FALLBACK_BIT) +#define TAG(x) x##_twoside_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (INTEL_TWOSIDE_BIT|INTEL_OFFSET_BIT|INTEL_FALLBACK_BIT) +#define TAG(x) x##_twoside_offset_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (INTEL_UNFILLED_BIT|INTEL_FALLBACK_BIT) +#define TAG(x) x##_unfilled_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (INTEL_OFFSET_BIT|INTEL_UNFILLED_BIT|INTEL_FALLBACK_BIT) +#define TAG(x) x##_offset_unfilled_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (INTEL_TWOSIDE_BIT|INTEL_UNFILLED_BIT|INTEL_FALLBACK_BIT) +#define TAG(x) x##_twoside_unfilled_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (INTEL_TWOSIDE_BIT|INTEL_OFFSET_BIT|INTEL_UNFILLED_BIT| \ + INTEL_FALLBACK_BIT) +#define TAG(x) x##_twoside_offset_unfilled_fallback +#include "tnl_dd/t_dd_tritmp.h" + + +static void init_rast_tab( void ) +{ + init(); + init_offset(); + init_twoside(); + init_twoside_offset(); + init_unfilled(); + init_offset_unfilled(); + init_twoside_unfilled(); + init_twoside_offset_unfilled(); + init_fallback(); + init_offset_fallback(); + init_twoside_fallback(); + init_twoside_offset_fallback(); + init_unfilled_fallback(); + init_offset_unfilled_fallback(); + init_twoside_unfilled_fallback(); + init_twoside_offset_unfilled_fallback(); +} + + +/*********************************************************************** + * Rasterization fallback helpers * + ***********************************************************************/ + + +/* This code is hit only when a mix of accelerated and unaccelerated + * primitives are being drawn, and only for the unaccelerated + * primitives. + */ +static void +intel_fallback_tri( intelContextPtr intel, + intelVertex *v0, + intelVertex *v1, + intelVertex *v2 ) +{ + GLcontext *ctx = &intel->ctx; + SWvertex v[3]; + + if (0) + fprintf(stderr, "\n%s\n", __FUNCTION__); + + _swsetup_Translate( ctx, v0, &v[0] ); + _swsetup_Translate( ctx, v1, &v[1] ); + _swsetup_Translate( ctx, v2, &v[2] ); + intelSpanRenderStart( ctx ); + _swrast_Triangle( ctx, &v[0], &v[1], &v[2] ); + intelSpanRenderFinish( ctx ); +} + + +static void +intel_fallback_line( intelContextPtr intel, + intelVertex *v0, + intelVertex *v1 ) +{ + GLcontext *ctx = &intel->ctx; + SWvertex v[2]; + + if (0) + fprintf(stderr, "\n%s\n", __FUNCTION__); + + _swsetup_Translate( ctx, v0, &v[0] ); + _swsetup_Translate( ctx, v1, &v[1] ); + intelSpanRenderStart( ctx ); + _swrast_Line( ctx, &v[0], &v[1] ); + intelSpanRenderFinish( ctx ); +} + + +static void +intel_fallback_point( intelContextPtr intel, + intelVertex *v0 ) +{ + GLcontext *ctx = &intel->ctx; + SWvertex v[1]; + + if (0) + fprintf(stderr, "\n%s\n", __FUNCTION__); + + _swsetup_Translate( ctx, v0, &v[0] ); + intelSpanRenderStart( ctx ); + _swrast_Point( ctx, &v[0] ); + intelSpanRenderFinish( ctx ); +} + + + +/**********************************************************************/ +/* Render unclipped begin/end objects */ +/**********************************************************************/ + +#define IND 0 +#define V(x) (intelVertex *)(vertptr + ((x)*vertsize*sizeof(GLuint))) +#define RENDER_POINTS( start, count ) \ + for ( ; start < count ; start++) POINT( V(ELT(start)) ); +#define RENDER_LINE( v0, v1 ) LINE( V(v0), V(v1) ) +#define RENDER_TRI( v0, v1, v2 ) TRI( V(v0), V(v1), V(v2) ) +#define RENDER_QUAD( v0, v1, v2, v3 ) QUAD( V(v0), V(v1), V(v2), V(v3) ) +#define INIT(x) intelRenderPrimitive( ctx, x ) +#undef LOCAL_VARS +#define LOCAL_VARS \ + intelContextPtr intel = INTEL_CONTEXT(ctx); \ + GLubyte *vertptr = (GLubyte *)intel->verts; \ + const GLuint vertsize = intel->vertex_size; \ + const GLuint * const elt = TNL_CONTEXT(ctx)->vb.Elts; \ + (void) elt; +#define RESET_STIPPLE +#define RESET_OCCLUSION +#define PRESERVE_VB_DEFS +#define ELT(x) x +#define TAG(x) intel_##x##_verts +#include "tnl/t_vb_rendertmp.h" +#undef ELT +#undef TAG +#define TAG(x) intel_##x##_elts +#define ELT(x) elt[x] +#include "tnl/t_vb_rendertmp.h" + +/**********************************************************************/ +/* Render clipped primitives */ +/**********************************************************************/ + + + +static void intelRenderClippedPoly( GLcontext *ctx, const GLuint *elts, + GLuint n ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLuint prim = intel->render_primitive; + + /* Render the new vertices as an unclipped polygon. + */ + { + GLuint *tmp = VB->Elts; + VB->Elts = (GLuint *)elts; + tnl->Driver.Render.PrimTabElts[GL_POLYGON]( ctx, 0, n, + PRIM_BEGIN|PRIM_END ); + VB->Elts = tmp; + } + + /* Restore the render primitive + */ + if (prim != GL_POLYGON) + tnl->Driver.Render.PrimitiveNotify( ctx, prim ); +} + +static void intelRenderClippedLine( GLcontext *ctx, GLuint ii, GLuint jj ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + + tnl->Driver.Render.Line( ctx, ii, jj ); +} + +static void intelFastRenderClippedPoly( GLcontext *ctx, const GLuint *elts, + GLuint n ) +{ + intelContextPtr intel = INTEL_CONTEXT( ctx ); + const GLuint vertsize = intel->vertex_size; + GLuint *vb = intelExtendInlinePrimitive( intel, (n-2) * 3 * vertsize ); + GLubyte *vertptr = (GLubyte *)intel->verts; + const GLuint *start = (const GLuint *)V(elts[0]); + int i,j; + + for (i = 2 ; i < n ; i++) { + COPY_DWORDS( j, vb, vertsize, V(elts[i-1]) ); + COPY_DWORDS( j, vb, vertsize, V(elts[i]) ); + COPY_DWORDS( j, vb, vertsize, start ); + } +} + +/**********************************************************************/ +/* Choose render functions */ +/**********************************************************************/ + + + + +#define POINT_FALLBACK (0) +#define LINE_FALLBACK (DD_LINE_STIPPLE) +#define TRI_FALLBACK (0) +#define ANY_FALLBACK_FLAGS (POINT_FALLBACK|LINE_FALLBACK|TRI_FALLBACK|\ + DD_TRI_STIPPLE|DD_POINT_ATTEN) +#define ANY_RASTER_FLAGS (DD_TRI_LIGHT_TWOSIDE|DD_TRI_OFFSET|DD_TRI_UNFILLED) + +void intelChooseRenderState(GLcontext *ctx) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + intelContextPtr intel = INTEL_CONTEXT(ctx); + GLuint flags = ctx->_TriangleCaps; + struct fragment_program *program = ctx->FragmentProgram.Current; + GLboolean have_wpos = (program && (program->InputsRead & FRAG_BIT_WPOS)); + GLuint index = 0; + + if (INTEL_DEBUG & DEBUG_STATE) + fprintf(stderr,"\n%s\n",__FUNCTION__); + + if ((flags & (ANY_FALLBACK_FLAGS|ANY_RASTER_FLAGS)) || have_wpos) { + + if (flags & ANY_RASTER_FLAGS) { + if (flags & DD_TRI_LIGHT_TWOSIDE) index |= INTEL_TWOSIDE_BIT; + if (flags & DD_TRI_OFFSET) index |= INTEL_OFFSET_BIT; + if (flags & DD_TRI_UNFILLED) index |= INTEL_UNFILLED_BIT; + } + + if (have_wpos) { + intel->draw_point = intel_wpos_point; + intel->draw_line = intel_wpos_line; + intel->draw_tri = intel_wpos_triangle; + + /* Make sure these get called: + */ + index |= INTEL_FALLBACK_BIT; + } + else { + intel->draw_point = intel_draw_point; + intel->draw_line = intel_draw_line; + intel->draw_tri = intel_draw_triangle; + } + + /* Hook in fallbacks for specific primitives. + */ + if (flags & ANY_FALLBACK_FLAGS) + { + if (flags & POINT_FALLBACK) + intel->draw_point = intel_fallback_point; + + if (flags & LINE_FALLBACK) + intel->draw_line = intel_fallback_line; + + if (flags & TRI_FALLBACK) + intel->draw_tri = intel_fallback_tri; + + if ((flags & DD_TRI_STIPPLE) && !intel->hw_stipple) + intel->draw_tri = intel_fallback_tri; + + if (flags & DD_POINT_ATTEN) + intel->draw_point = intel_atten_point; + + index |= INTEL_FALLBACK_BIT; + } + } + + if (intel->RenderIndex != index) { + intel->RenderIndex = index; + + tnl->Driver.Render.Points = rast_tab[index].points; + tnl->Driver.Render.Line = rast_tab[index].line; + tnl->Driver.Render.Triangle = rast_tab[index].triangle; + tnl->Driver.Render.Quad = rast_tab[index].quad; + + if (index == 0) { + tnl->Driver.Render.PrimTabVerts = intel_render_tab_verts; + tnl->Driver.Render.PrimTabElts = intel_render_tab_elts; + tnl->Driver.Render.ClippedLine = line; /* from tritmp.h */ + tnl->Driver.Render.ClippedPolygon = intelFastRenderClippedPoly; + } else { + tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts; + tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts; + tnl->Driver.Render.ClippedLine = intelRenderClippedLine; + tnl->Driver.Render.ClippedPolygon = intelRenderClippedPoly; + } + } +} + +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 +}; + + +/**********************************************************************/ +/* High level hooks for t_vb_render.c */ +/**********************************************************************/ + + + + +static void intelRunPipeline( GLcontext *ctx ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + + if (intel->NewGLState) { + if (intel->NewGLState & _NEW_TEXTURE) { + intel->vtbl.update_texture_state( intel ); + } + + if (!intel->Fallback) { + if (intel->NewGLState & _INTEL_NEW_RENDERSTATE) + intelChooseRenderState( ctx ); + } + + intel->NewGLState = 0; + } + + _tnl_run_pipeline( ctx ); +} + +static void intelRenderStart( GLcontext *ctx ) +{ + INTEL_CONTEXT(ctx)->vtbl.render_start( INTEL_CONTEXT(ctx) ); +} + +static void intelRenderFinish( GLcontext *ctx ) +{ + if (INTEL_CONTEXT(ctx)->RenderIndex & INTEL_FALLBACK_BIT) + _swrast_flush( ctx ); +} + + + + + /* System to flush dma and emit state changes based on the rasterized + * primitive. + */ +static void intelRasterPrimitive( GLcontext *ctx, GLenum rprim, GLuint hwprim ) +{ + intelContextPtr intel = INTEL_CONTEXT(ctx); + + if (0) + fprintf(stderr, "%s %s %x\n", __FUNCTION__, + _mesa_lookup_enum_by_nr(rprim), hwprim); + + intel->vtbl.reduced_primitive_state( intel, rprim ); + + /* Start a new primitive. Arrange to have it flushed later on. + */ + if (hwprim != intel->prim.primitive) + intelStartInlinePrimitive( intel, hwprim ); +} + + + /* + */ + static void intelRenderPrimitive( GLcontext *ctx, GLenum prim ) + { + intelContextPtr intel = INTEL_CONTEXT(ctx); + + if (0) + fprintf(stderr, "%s %s\n", __FUNCTION__, _mesa_lookup_enum_by_nr(prim)); + + /* Let some clipping routines know which primitive they're dealing + * with. + */ + intel->render_primitive = prim; + + /* Shortcircuit this when called from t_dd_rendertmp.h for unfilled + * triangles. The rasterized primitive will always be reset by + * lower level functions in that case, potentially pingponging the + * state: + */ + if (reduced_prim[prim] == GL_TRIANGLES && + (ctx->_TriangleCaps & DD_TRI_UNFILLED)) + return; + + /* Set some primitive-dependent state and Start? a new primitive. + */ + intelRasterPrimitive( ctx, reduced_prim[prim], hw_prim[prim] ); + } + + + /**********************************************************************/ + /* Transition to/from hardware rasterization. */ + /**********************************************************************/ + + static char *fallbackStrings[] = { + "Texture", + "Draw buffer", + "Read buffer", + "Color mask", + "Render mode", + "Stencil", + "Stipple", + "User disable" + }; + + + static char *getFallbackString(GLuint bit) + { + int i = 0; + while (bit > 1) { + i++; + bit >>= 1; + } + return fallbackStrings[i]; + } + + + + void intelFallback( intelContextPtr intel, GLuint bit, GLboolean mode ) + { + GLcontext *ctx = &intel->ctx; + TNLcontext *tnl = TNL_CONTEXT(ctx); + GLuint oldfallback = intel->Fallback; + + if (mode) { + intel->Fallback |= bit; + if (oldfallback == 0) { + intelFlush(ctx); + if (INTEL_DEBUG & DEBUG_FALLBACKS) + fprintf(stderr, "ENTER FALLBACK %x: %s\n", + bit, getFallbackString( bit )); + _swsetup_Wakeup( ctx ); + intel->RenderIndex = ~0; + } + } + else { + intel->Fallback &= ~bit; + if (oldfallback == bit) { + _swrast_flush( ctx ); + if (INTEL_DEBUG & DEBUG_FALLBACKS) + fprintf(stderr, "LEAVE FALLBACK %s\n", getFallbackString( bit )); + tnl->Driver.Render.Start = intelRenderStart; + tnl->Driver.Render.PrimitiveNotify = intelRenderPrimitive; + tnl->Driver.Render.Finish = intelRenderFinish; + tnl->Driver.Render.BuildVertices = _tnl_build_vertices; + tnl->Driver.Render.CopyPV = _tnl_copy_pv; + tnl->Driver.Render.Interp = _tnl_interp; + + _tnl_invalidate_vertex_state( ctx, ~0 ); + _tnl_invalidate_vertices( ctx, ~0 ); + _tnl_install_attrs( ctx, + intel->vertex_attrs, + intel->vertex_attr_count, + intel->ViewportMatrix.m, 0 ); + + intel->NewGLState |= _INTEL_NEW_RENDERSTATE; + } + } + } + + + + +/**********************************************************************/ +/* Initialization. */ +/**********************************************************************/ + + +void intelInitTriFuncs( GLcontext *ctx ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + static int firsttime = 1; + + if (firsttime) { + init_rast_tab(); + firsttime = 0; + } + + tnl->Driver.RunPipeline = intelRunPipeline; + tnl->Driver.Render.Start = intelRenderStart; + tnl->Driver.Render.Finish = intelRenderFinish; + tnl->Driver.Render.PrimitiveNotify = intelRenderPrimitive; + tnl->Driver.Render.ResetLineStipple = _swrast_ResetLineStipple; + tnl->Driver.Render.BuildVertices = _tnl_build_vertices; + tnl->Driver.Render.CopyPV = _tnl_copy_pv; + tnl->Driver.Render.Interp = _tnl_interp; +} diff --git a/src/mesa/drivers/dri/i915/intel_tris.h b/src/mesa/drivers/dri/i915/intel_tris.h new file mode 100644 index 0000000..928bfb1 --- /dev/null +++ b/src/mesa/drivers/dri/i915/intel_tris.h @@ -0,0 +1,26 @@ +/************************************************************************** + * + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + * + **************************************************************************/ + +#ifndef INTELTRIS_INC +#define INTELTRIS_INC + +#include "mtypes.h" + +#define _INTEL_NEW_RENDERSTATE (_DD_NEW_LINE_STIPPLE | \ + _DD_NEW_TRI_UNFILLED | \ + _DD_NEW_TRI_LIGHT_TWOSIDE | \ + _DD_NEW_TRI_OFFSET | \ + _DD_NEW_TRI_STIPPLE | \ + _NEW_PROGRAM | \ + _NEW_POLYGONSTIPPLE) + +extern void intelInitTriFuncs( GLcontext *ctx ); + +extern void intelPrintRenderState( const char *msg, GLuint state ); +extern void intelChooseRenderState( GLcontext *ctx ); + +#endif diff --git a/src/mesa/drivers/dri/i915/server/i830_common.h b/src/mesa/drivers/dri/i915/server/i830_common.h new file mode 100644 index 0000000..c03f742 --- /dev/null +++ b/src/mesa/drivers/dri/i915/server/i830_common.h @@ -0,0 +1,169 @@ +/************************************************************************** + +Copyright 2001 VA Linux Systems Inc., Fremont, California. +Copyright 2002 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 +on 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 +ATI, VA LINUX SYSTEMS AND/OR THEIR 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. + +**************************************************************************/ + +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i830_common.h,v 1.1 2002/09/11 00:29:32 dawes Exp $ */ + +#ifndef _I830_COMMON_H_ +#define _I830_COMMON_H_ + + +#define I830_NR_TEX_REGIONS 255 /* maximum due to use of chars for next/prev */ +#define I830_LOG_MIN_TEX_REGION_SIZE 14 + + +/* Driver specific DRM command indices + * NOTE: these are not OS specific, but they are driver specific + */ +#define DRM_I830_INIT 0x00 +#define DRM_I830_FLUSH 0x01 +#define DRM_I830_FLIP 0x02 +#define DRM_I830_BATCHBUFFER 0x03 +#define DRM_I830_IRQ_EMIT 0x04 +#define DRM_I830_IRQ_WAIT 0x05 +#define DRM_I830_GETPARAM 0x06 +#define DRM_I830_SETPARAM 0x07 +#define DRM_I830_ALLOC 0x08 +#define DRM_I830_FREE 0x09 +#define DRM_I830_INIT_HEAP 0x0a +#define DRM_I830_CMDBUFFER 0x0b + +typedef struct { + enum { + I830_INIT_DMA = 0x01, + I830_CLEANUP_DMA = 0x02, + I830_RESUME_DMA = 0x03 + } func; + unsigned int mmio_offset; + int sarea_priv_offset; + unsigned int ring_start; + unsigned int ring_end; + unsigned int ring_size; + unsigned int front_offset; + unsigned int back_offset; + unsigned int depth_offset; + unsigned int w; + unsigned int h; + unsigned int pitch; + unsigned int pitch_bits; + unsigned int back_pitch; + unsigned int depth_pitch; + unsigned int cpp; + unsigned int chipset; +} drmI830Init; + +typedef struct { + drmTextureRegion texList[I830_NR_TEX_REGIONS+1]; + int last_upload; /* last time texture was uploaded */ + int last_enqueue; /* last time a buffer was enqueued */ + int last_dispatch; /* age of the most recently dispatched buffer */ + int ctxOwner; /* last context to upload state */ + int texAge; + int pf_enabled; /* is pageflipping allowed? */ + int pf_active; + int pf_current_page; /* which buffer is being displayed? */ + int perf_boxes; /* performance boxes to be displayed */ +} drmI830Sarea; + +/* Flags for perf_boxes + */ +#define I830_BOX_RING_EMPTY 0x1 /* populated by kernel */ +#define I830_BOX_FLIP 0x2 /* populated by kernel */ +#define I830_BOX_WAIT 0x4 /* populated by kernel & client */ +#define I830_BOX_TEXTURE_LOAD 0x8 /* populated by kernel */ +#define I830_BOX_LOST_CONTEXT 0x10 /* populated by client */ + + +typedef struct { + int start; /* agp offset */ + int used; /* nr bytes in use */ + int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ + int DR4; /* window origin for GFX_OP_DRAWRECT_INFO*/ + int num_cliprects; /* mulitpass with multiple cliprects? */ + drm_clip_rect_t *cliprects; /* pointer to userspace cliprects */ +} drmI830BatchBuffer; + +typedef struct { + char *buf; /* agp offset */ + int sz; /* nr bytes in use */ + int DR1; /* hw flags for GFX_OP_DRAWRECT_INFO */ + int DR4; /* window origin for GFX_OP_DRAWRECT_INFO*/ + int num_cliprects; /* mulitpass with multiple cliprects? */ + drm_clip_rect_t *cliprects; /* pointer to userspace cliprects */ +} drmI830CmdBuffer; + + +typedef struct { + int *irq_seq; +} drmI830IrqEmit; + +typedef struct { + int irq_seq; +} drmI830IrqWait; + +typedef struct { + int param; + int *value; +} drmI830GetParam; + +#define I830_PARAM_IRQ_ACTIVE 1 +#define I830_PARAM_ALLOW_BATCHBUFFER 2 + +typedef struct { + int param; + int value; +} drmI830SetParam; + +#define I830_SETPARAM_USE_MI_BATCHBUFFER_START 1 +#define I830_SETPARAM_TEX_LRU_LOG_GRANULARITY 2 +#define I830_SETPARAM_ALLOW_BATCHBUFFER 3 + + +/* A memory manager for regions of shared memory: + */ +#define I830_MEM_REGION_AGP 1 + +typedef struct { + int region; + int alignment; + int size; + int *region_offset; /* offset from start of fb or agp */ +} drmI830MemAlloc; + +typedef struct { + int region; + int region_offset; +} drmI830MemFree; + +typedef struct { + int region; + int size; + int start; +} drmI830MemInitHeap; + + +#endif /* _I830_DRM_H_ */ diff --git a/src/mesa/drivers/dri/i915/server/i830_dri.h b/src/mesa/drivers/dri/i915/server/i830_dri.h new file mode 100644 index 0000000..29a5988 --- /dev/null +++ b/src/mesa/drivers/dri/i915/server/i830_dri.h @@ -0,0 +1,70 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/i810/i830_dri.h,v 1.4 2002/10/30 12:52:18 alanh Exp $ */ + +#ifndef _I830_DRI_H +#define _I830_DRI_H + +#include "xf86drm.h" +#include "i830_common.h" + +#define I830_MAX_DRAWABLES 256 + +#define I830_MAJOR_VERSION 1 +#define I830_MINOR_VERSION 3 +#define I830_PATCHLEVEL 0 + +#define I830_REG_SIZE 0x80000 + +/* Note: This structure has changed slightly from what is expected by + * the i830_drv.o driver. Maybe that should be reverted. + */ +typedef struct _I830DRIRec { + drm_handle_t regs; + drmSize regsSize; + drmAddress regsMap; + + drmSize backbufferSize; + drm_handle_t backbuffer; + + drmSize depthbufferSize; + drm_handle_t depthbuffer; + + drm_handle_t textures; + int textureSize; + + drm_handle_t agp_buffers; + drmSize agp_buf_size; + + int deviceID; + int width; + int height; + int mem; + int cpp; + int bitsPerPixel; + int fbOffset; + int fbStride; + + int backOffset; + int backPitch; + + int depthOffset; + int depthPitch; + + int logTextureGranularity; + int textureOffset; + + int irq; + int sarea_priv_offset; +} I830DRIRec, *I830DRIPtr; + +typedef struct { + /* Nothing here yet */ + int dummy; +} I830ConfigPrivRec, *I830ConfigPrivPtr; + +typedef struct { + /* Nothing here yet */ + int dummy; +} I830DRIContextRec, *I830DRIContextPtr; + + +#endif -- 2.7.4