diff options
| author | Keith Whitwell <keith@tungstengraphics.com> | 2006-11-01 12:03:11 +0000 | 
|---|---|---|
| committer | Keith Whitwell <keith@tungstengraphics.com> | 2006-11-01 12:03:11 +0000 | 
| commit | 6b9e31f3eb3dbe20cbc8493b963bbc6530e392c6 (patch) | |
| tree | be747898011b6bf7e45d89f2f35699973445620a /src | |
| parent | 3c6e99ce95bdee526f95ce8aaadd0c8923b83af0 (diff) | |
Import texmem i915 driver to its new location as i915tex.
Diffstat (limited to 'src')
73 files changed, 25933 insertions, 0 deletions
diff --git a/src/mesa/drivers/dri/i915tex/Makefile b/src/mesa/drivers/dri/i915tex/Makefile new file mode 100644 index 0000000000..d57a651466 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/Makefile @@ -0,0 +1,65 @@ + +TOP = ../../../../.. +include $(TOP)/configs/current + +LIBNAME = i915tex_dri.so + +MINIGLX_SOURCES = server/intel_dri.c + +DRIVER_SOURCES = \ +	i830_context.c \ +	i830_metaops.c \ +	i830_state.c \ +	i830_texblend.c \ +	i830_tex.c \ +	i830_texstate.c \ +	i830_vtbl.c \ +	intel_render.c \ +	intel_regions.c \ +	intel_buffer_objects.c \ +	intel_batchbuffer.c \ +	intel_mipmap_tree.c \ +	i915_tex_layout.c \ +	intel_tex_image.c \ +	intel_tex_subimage.c \ +	intel_tex_copy.c \ +	intel_tex_validate.c \ +	intel_tex_format.c \ +	intel_tex.c \ +	intel_pixel.c \ +	intel_pixel_copy.c \ +	intel_pixel_read.c \ +	intel_pixel_draw.c \ +	intel_buffers.c \ +	intel_blit.c \ +	i915_tex.c \ +	i915_texstate.c \ +	i915_context.c \ +	i915_debug.c \ +	i915_fragprog.c \ +	i915_metaops.c \ +	i915_program.c \ +	i915_state.c \ +	i915_vtbl.c \ +	intel_context.c \ +	intel_ioctl.c \ +	intel_rotate.c \ +	intel_screen.c \ +	intel_span.c \ +	intel_state.c \ +	intel_tris.c \ +	intel_fbo.c \ +	intel_depthstencil.c \ +	intel_batchpool.c + +C_SOURCES = \ +	$(COMMON_SOURCES) \ +	$(DRIVER_SOURCES) + +ASM_SOURCES =  + + + +include ../Makefile.template + +symlinks: diff --git a/src/mesa/drivers/dri/i915tex/i830_context.c b/src/mesa/drivers/dri/i915tex/i830_context.c new file mode 100644 index 0000000000..2ff8621c42 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i830_context.c @@ -0,0 +1,104 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#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" +#include "utils.h" + +/*************************************** + * Mesa's Driver Functions + ***************************************/ + +static const struct dri_extension i830_extensions[] = { +   {"GL_ARB_texture_env_crossbar", NULL}, +   {NULL, NULL} +}; + + +static void +i830InitDriverFunctions(struct dd_function_table *functions) +{ +   intelInitDriverFunctions(functions); +   i830InitStateFuncs(functions); +   i830InitTextureFuncs(functions); +} + + +GLboolean +i830CreateContext(const __GLcontextModes * mesaVis, +                  __DRIcontextPrivate * driContextPriv, +                  void *sharedContextPrivate) +{ +   struct dd_function_table functions; +   struct i830_context *i830 = CALLOC_STRUCT(i830_context); +   struct intel_context *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; + +   /* Advertise the full hardware capabilities.  The new memory +    * manager should cope much better with overload situations: +    */ +   ctx->Const.MaxTextureLevels = 12; +   ctx->Const.Max3DTextureLevels = 9; +   ctx->Const.MaxCubeTextureLevels = 11; +   ctx->Const.MaxTextureRectSize = (1 << 11); +   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; + +   driInitExtensions(ctx, i830_extensions, GL_FALSE); + +   i830InitState(i830); +   i830InitMetaFuncs(i830); + +   _tnl_allow_vertex_fog(ctx, 1); +   _tnl_allow_pixel_fog(ctx, 0); + +   return GL_TRUE; +} diff --git a/src/mesa/drivers/dri/i915tex/i830_context.h b/src/mesa/drivers/dri/i915tex/i830_context.h new file mode 100644 index 0000000000..e5377b300a --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i830_context.h @@ -0,0 +1,208 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#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_INVARIENT        0x8 +#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_DBUFADDR0 2 +#define I830_DESTREG_DBUFADDR1 3 +#define I830_DESTREG_DV0 4 +#define I830_DESTREG_DV1 5 +#define I830_DESTREG_SENABLE 6 +#define I830_DESTREG_SR0 7 +#define I830_DESTREG_SR1 8 +#define I830_DESTREG_SR2 9 +#define I830_DEST_SETUP_SIZE 10 + +#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_TM0S1      1 +#define I830_TEXREG_TM0S2      2 +#define I830_TEXREG_TM0S3      3 +#define I830_TEXREG_TM0S4      4 +#define I830_TEXREG_MCS	       5        /* _3DSTATE_MAP_COORD_SETS */ +#define I830_TEXREG_CUBE       6        /* _3DSTATE_MAP_SUBE */ +#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]; + +   struct intel_region *draw_region; +   struct intel_region *depth_region; + +   /* Regions aren't actually that appropriate here as the memory may +    * be from a PBO or FBO.  Just use the buffer id.  Will have to do +    * this for draw and depth for FBO's... +    */ +   struct _DriBufferObject *tex_buffer[I830_TEX_UNITS]; +   GLuint tex_offset[I830_TEX_UNITS]; + +   GLuint emitted;              /* I810_UPLOAD_* */ +   GLuint active; +}; + +struct i830_context +{ +   struct intel_context intel; + +   GLuint lodbias_tm0s3[MAX_TEXTURE_UNITS]; +     DECLARE_RENDERINPUTS(last_index_bitset); + +   struct i830_hw_state meta, initial, state, *current; +}; + + + + +#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(struct i830_context *i830); + +/* i830_context.c + */ +extern GLboolean +i830CreateContext(const __GLcontextModes * mesaVis, +                  __DRIcontextPrivate * driContextPriv, +                  void *sharedContextPrivate); + +/* i830_tex.c, i830_texstate.c + */ +extern void i830UpdateTextureState(struct intel_context *intel); + +extern void i830InitTextureFuncs(struct dd_function_table *functions); + +/* i830_texblend.c + */ +extern GLuint i830SetTexEnvCombine(struct i830_context *i830, +                                   const struct gl_tex_env_combine_state +                                   *combine, GLint blendUnit, GLuint texel_op, +                                   GLuint * state, const GLfloat * factor); + +extern void i830EmitTextureBlend(struct i830_context *i830); + + +/* i830_state.c + */ +extern void i830InitStateFuncs(struct dd_function_table *functions); + +extern void i830EmitState(struct i830_context *i830); + +extern void i830InitState(struct i830_context *i830); + +/* i830_metaops.c + */ +extern void i830InitMetaFuncs(struct i830_context *i830); + +extern void +i830RotateWindow(struct intel_context *intel, __DRIdrawablePrivate * dPriv, +                 GLuint srcBuf); + +/*====================================================================== + * Inline conversion functions.  These are better-typed than the + * macros used previously: + */ +static INLINE struct i830_context * +i830_context(GLcontext * ctx) +{ +   return (struct i830_context *) ctx; +} + +#endif diff --git a/src/mesa/drivers/dri/i915tex/i830_metaops.c b/src/mesa/drivers/dri/i915tex/i830_metaops.c new file mode 100644 index 0000000000..c90f502222 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i830_metaops.c @@ -0,0 +1,485 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#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 "intel_regions.h" + +#include "i830_context.h" +#include "i830_reg.h" + +/* A large amount of state doesn't need to be uploaded. + */ +#define ACTIVE (I830_UPLOAD_INVARIENT |         \ +		I830_UPLOAD_CTX |		\ +		I830_UPLOAD_BUFFERS |		\ +		I830_UPLOAD_STIPPLE |		\ +		I830_UPLOAD_TEXBLEND(0) |	\ +		I830_UPLOAD_TEX(0)) + + +#define SET_STATE( i830, STATE )		\ +do {						\ +   i830->current->emitted &= ~ACTIVE;			\ +   i830->current = &i830->STATE;		\ +   i830->current->emitted &= ~ACTIVE;			\ +} while (0) + + +static void +set_no_stencil_write(struct intel_context *intel) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); + +   /* 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; + +   i830->meta.emitted &= ~I830_UPLOAD_CTX; +} + +static void +set_no_depth_write(struct intel_context *intel) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); + +   /* 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 depth unit to replace. + */ +static void +set_depth_replace(struct intel_context *intel) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); + +   /* ctx->Driver.Enable( ctx, GL_DEPTH_TEST, GL_FALSE ) +    * ctx->Driver.DepthMask( ctx, GL_TRUE ) +    */ +   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] |= ENABLE_DEPTH_TEST; +   i830->meta.Ctx[I830_CTXREG_ENABLES_2] |= ENABLE_DEPTH_WRITE; + +   /* ctx->Driver.DepthFunc( ctx, GL_ALWAYS ) +    */ +   i830->meta.Ctx[I830_CTXREG_STATE3] &= ~DEPTH_TEST_FUNC_MASK; +   i830->meta.Ctx[I830_CTXREG_STATE3] |= (ENABLE_DEPTH_TEST_FUNC | +                                          DEPTH_TEST_FUNC +                                          (COMPAREFUNC_ALWAYS)); + +   i830->meta.emitted &= ~I830_UPLOAD_CTX; +} + + +/* Set stencil unit to replace always with the reference value. + */ +static void +set_stencil_replace(struct intel_context *intel, +                    GLuint s_mask, GLuint s_clear) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); + +   /* 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.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(struct intel_context *intel, GLboolean state) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); + +   const GLuint mask = ((1 << WRITEMASK_RED_SHIFT) | +                        (1 << WRITEMASK_GREEN_SHIFT) | +                        (1 << WRITEMASK_BLUE_SHIFT) | +                        (1 << WRITEMASK_ALPHA_SHIFT)); + +   i830->meta.Ctx[I830_CTXREG_ENABLES_2] &= ~mask; + +   if (state) { +      i830->meta.Ctx[I830_CTXREG_ENABLES_2] |= +         (i830->state.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(struct intel_context *intel) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); +   static const struct gl_tex_env_combine_state comb = { +      GL_NONE, GL_NONE, +      {GL_TEXTURE, 0, 0,}, {GL_TEXTURE, 0, 0,}, +      {GL_SRC_COLOR, 0, 0}, {GL_SRC_ALPHA, 0, 0}, +      0, 0, 0, 0 +   }; + +   i830->meta.TexBlendWordsUsed[0] = +      i830SetTexEnvCombine(i830, &comb, 0, TEXBLENDARG_TEXEL0, +                           i830->meta.TexBlend[0], NULL); + +   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 +set_texture_blend_replace(struct intel_context *intel) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); +   static const struct gl_tex_env_combine_state comb = { +      GL_REPLACE, GL_REPLACE, +      {GL_TEXTURE, GL_TEXTURE, GL_TEXTURE,}, {GL_TEXTURE, GL_TEXTURE, +                                              GL_TEXTURE,}, +      {GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR}, {GL_SRC_ALPHA, GL_SRC_ALPHA, +                                                   GL_SRC_ALPHA}, +      0, 0, 1, 1 +   }; + +   i830->meta.TexBlendWordsUsed[0] = +      i830SetTexEnvCombine(i830, &comb, 0, TEXBLENDARG_TEXEL0, +                           i830->meta.TexBlend[0], NULL); + +   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 GLboolean +set_tex_rect_source(struct intel_context *intel, +                    struct _DriBufferObject *buffer, +                    GLuint offset, +                    GLuint pitch, GLuint height, GLenum format, GLenum type) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); +   GLuint *setup = i830->meta.Tex[0]; +   GLint numLevels = 1; +   GLuint textureFormat; +   GLuint cpp; + +   /* A full implementation of this would do the upload through +    * glTexImage2d, and get all the conversion operations at that +    * point.  We are restricted, but still at least have access to the +    * fragment program swizzle. +    */ +   switch (format) { +   case GL_BGRA: +      switch (type) { +      case GL_UNSIGNED_INT_8_8_8_8_REV: +      case GL_UNSIGNED_BYTE: +         textureFormat = (MAPSURF_32BIT | MT_32BIT_ARGB8888); +         cpp = 4; +         break; +      default: +         return GL_FALSE; +      } +      break; +   case GL_RGBA: +      switch (type) { +      case GL_UNSIGNED_INT_8_8_8_8_REV: +      case GL_UNSIGNED_BYTE: +         textureFormat = (MAPSURF_32BIT | MT_32BIT_ABGR8888); +         cpp = 4; +         break; +      default: +         return GL_FALSE; +      } +      break; +   case GL_BGR: +      switch (type) { +      case GL_UNSIGNED_SHORT_5_6_5_REV: +         textureFormat = (MAPSURF_16BIT | MT_16BIT_RGB565); +         cpp = 2; +         break; +      default: +         return GL_FALSE; +      } +      break; +   case GL_RGB: +      switch (type) { +      case GL_UNSIGNED_SHORT_5_6_5: +         textureFormat = (MAPSURF_16BIT | MT_16BIT_RGB565); +         cpp = 2; +         break; +      default: +         return GL_FALSE; +      } +      break; + +   default: +      return GL_FALSE; +   } + +   i830->meta.tex_buffer[0] = buffer; +   i830->meta.tex_offset[0] = offset; + +   setup[I830_TEXREG_TM0LI] = (_3DSTATE_LOAD_STATE_IMMEDIATE_2 | +                               (LOAD_TEXTURE_MAP0 << 0) | 4); +   setup[I830_TEXREG_TM0S1] = (((height - 1) << TM0S1_HEIGHT_SHIFT) | +                               ((pitch - 1) << TM0S1_WIDTH_SHIFT) | +                               textureFormat); +   setup[I830_TEXREG_TM0S2] = +      (((((pitch * cpp) / 4) - +         1) << TM0S2_PITCH_SHIFT) | TM0S2_CUBE_FACE_ENA_MASK); + +   setup[I830_TEXREG_TM0S3] = +      ((((numLevels - +          1) * +         4) << TM0S3_MIN_MIP_SHIFT) | (FILTER_NEAREST << +                                       TM0S3_MIN_FILTER_SHIFT) | +       (MIPFILTER_NONE << TM0S3_MIP_FILTER_SHIFT) | (FILTER_NEAREST << +                                                     TM0S3_MAG_FILTER_SHIFT)); + +   setup[I830_TEXREG_CUBE] = (_3DSTATE_MAP_CUBE | MAP_UNIT(0)); + +   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); +   return GL_TRUE; +} + + +static void +set_vertex_format(struct intel_context *intel) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); +   i830->meta.Ctx[I830_CTXREG_VF] = (_3DSTATE_VFT0_CMD | +                                     VFT0_TEX_COUNT(1) | +                                     VFT0_DIFFUSE | VFT0_XYZ); +   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 +meta_import_pixel_state(struct intel_context *intel) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); + +   i830->meta.Ctx[I830_CTXREG_STATE1] = i830->state.Ctx[I830_CTXREG_STATE1]; +   i830->meta.Ctx[I830_CTXREG_STATE2] = i830->state.Ctx[I830_CTXREG_STATE2]; +   i830->meta.Ctx[I830_CTXREG_STATE3] = i830->state.Ctx[I830_CTXREG_STATE3]; +   i830->meta.Ctx[I830_CTXREG_STATE4] = i830->state.Ctx[I830_CTXREG_STATE4]; +   i830->meta.Ctx[I830_CTXREG_STATE5] = i830->state.Ctx[I830_CTXREG_STATE5]; +   i830->meta.Ctx[I830_CTXREG_IALPHAB] = i830->state.Ctx[I830_CTXREG_IALPHAB]; +   i830->meta.Ctx[I830_CTXREG_STENCILTST] = +      i830->state.Ctx[I830_CTXREG_STENCILTST]; +   i830->meta.Ctx[I830_CTXREG_ENABLES_1] = +      i830->state.Ctx[I830_CTXREG_ENABLES_1]; +   i830->meta.Ctx[I830_CTXREG_ENABLES_2] = +      i830->state.Ctx[I830_CTXREG_ENABLES_2]; +   i830->meta.Ctx[I830_CTXREG_AA] = i830->state.Ctx[I830_CTXREG_AA]; +   i830->meta.Ctx[I830_CTXREG_FOGCOLOR] = +      i830->state.Ctx[I830_CTXREG_FOGCOLOR]; +   i830->meta.Ctx[I830_CTXREG_BLENDCOLOR0] = +      i830->state.Ctx[I830_CTXREG_BLENDCOLOR0]; +   i830->meta.Ctx[I830_CTXREG_BLENDCOLOR1] = +      i830->state.Ctx[I830_CTXREG_BLENDCOLOR1]; +   i830->meta.Ctx[I830_CTXREG_MCSB0] = i830->state.Ctx[I830_CTXREG_MCSB0]; +   i830->meta.Ctx[I830_CTXREG_MCSB1] = i830->state.Ctx[I830_CTXREG_MCSB1]; + + +   i830->meta.Ctx[I830_CTXREG_STATE3] &= ~CULLMODE_MASK; +   i830->meta.Stipple[I830_STPREG_ST1] &= ~ST1_ENABLE; +   i830->meta.emitted &= ~I830_UPLOAD_CTX; + + +   i830->meta.Buffer[I830_DESTREG_SENABLE] = +      i830->state.Buffer[I830_DESTREG_SENABLE]; +   i830->meta.Buffer[I830_DESTREG_SR1] = i830->state.Buffer[I830_DESTREG_SR1]; +   i830->meta.Buffer[I830_DESTREG_SR2] = i830->state.Buffer[I830_DESTREG_SR2]; +   i830->meta.emitted &= ~I830_UPLOAD_BUFFERS; +} + + + +/* Select between front and back draw buffers. + */ +static void +meta_draw_region(struct intel_context *intel, +                 struct intel_region *draw_region, +                 struct intel_region *depth_region) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); +   GLuint format; +   GLuint depth_format = DEPTH_FRMT_16_FIXED; + +   intel_region_release(&i830->meta.draw_region); +   intel_region_reference(&i830->meta.draw_region, draw_region); + +   intel_region_release(&i830->meta.depth_region); +   intel_region_reference(&i830->meta.depth_region, depth_region); + +   /* XXX FBO: grab code from i915 meta_draw_region */ + +   /* XXX: 555 support? +    */ +   if (draw_region->cpp == 2) +      format = DV_PF_565; +   else +      format = DV_PF_8888; + +   if (depth_region) { +      if (depth_region->cpp == 2) +         depth_format = DEPTH_FRMT_16_FIXED; +      else +         depth_format = DEPTH_FRMT_24_FIXED_8_OTHER; +   } + +   i830->meta.Buffer[I830_DESTREG_DV1] = (DSTORG_HORT_BIAS(0x8) |       /* .5 */ +                                          DSTORG_VERT_BIAS(0x8) |       /* .5 */ +                                          format | DEPTH_IS_Z | depth_format); + +   i830->meta.emitted &= ~I830_UPLOAD_BUFFERS; +} + + +/* 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 +install_meta_state(struct intel_context *intel) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); +   memcpy(&i830->meta, &i830->initial, sizeof(i830->meta)); + +   i830->meta.active = ACTIVE; +   i830->meta.emitted = 0; + +   SET_STATE(i830, meta); +   set_vertex_format(intel); +   set_no_texture(intel); +} + +static void +leave_meta_state(struct intel_context *intel) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); +   intel_region_release(&i830->meta.draw_region); +   intel_region_release(&i830->meta.depth_region); +/*    intel_region_release(intel, &i830->meta.tex_region[0]); */ +   SET_STATE(i830, state); +} + + + +void +i830InitMetaFuncs(struct i830_context *i830) +{ +   i830->intel.vtbl.install_meta_state = install_meta_state; +   i830->intel.vtbl.leave_meta_state = leave_meta_state; +   i830->intel.vtbl.meta_no_depth_write = set_no_depth_write; +   i830->intel.vtbl.meta_no_stencil_write = set_no_stencil_write; +   i830->intel.vtbl.meta_stencil_replace = set_stencil_replace; +   i830->intel.vtbl.meta_depth_replace = set_depth_replace; +   i830->intel.vtbl.meta_color_mask = set_color_mask; +   i830->intel.vtbl.meta_no_texture = set_no_texture; +   i830->intel.vtbl.meta_texture_blend_replace = set_texture_blend_replace; +   i830->intel.vtbl.meta_tex_rect_source = set_tex_rect_source; +   i830->intel.vtbl.meta_draw_region = meta_draw_region; +   i830->intel.vtbl.meta_import_pixel_state = meta_import_pixel_state; +} diff --git a/src/mesa/drivers/dri/i915tex/i830_reg.h b/src/mesa/drivers/dri/i915tex/i830_reg.h new file mode 100644 index 0000000000..24ac524500 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i830_reg.h @@ -0,0 +1,641 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + + +#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) + + +/* _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) + + +/* _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 + +/* _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)&0xff)<<8) +#define MODE4_ENABLE_STENCIL_WRITE_MASK	((1<<16)|(0x00ff)) +#define ENABLE_STENCIL_WRITE_MASK	(1<<16) +#define STENCIL_WRITE_MASK(x)		((x)&0xff) + +/* _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 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_CUBE_FACE_ENA_MASK        (1<<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/i915tex/i830_state.c b/src/mesa/drivers/dri/i915tex/i830_state.c new file mode 100644 index 0000000000..83d82882a6 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i830_state.c @@ -0,0 +1,1113 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + + +#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 "intel_fbo.h" + +#include "i830_context.h" +#include "i830_reg.h" + +#define FILE_DEBUG_FLAG DEBUG_STATE + +static void +i830StencilFuncSeparate(GLcontext * ctx, GLenum face, GLenum func, GLint ref, +                        GLuint mask) +{ +   struct i830_context *i830 = i830_context(ctx); +   int test = intel_translate_compare_func(func); + +   mask = mask & 0xff; + +   DBG("%s : func: %s, ref : 0x%x, mask: 0x%x\n", __FUNCTION__, +       _mesa_lookup_enum_by_nr(func), ref, mask); + + +   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 +i830StencilMaskSeparate(GLcontext * ctx, GLenum face, GLuint mask) +{ +   struct i830_context *i830 = i830_context(ctx); + +   DBG("%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 +i830StencilOpSeparate(GLcontext * ctx, GLenum face, GLenum fail, GLenum zfail, +                      GLenum zpass) +{ +   struct i830_context *i830 = i830_context(ctx); +   int fop, dfop, dpop; + +   DBG("%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) +{ +   struct i830_context *i830 = i830_context(ctx); +   int test = intel_translate_compare_func(func); +   GLubyte refByte; +   GLuint refInt; + +   UNCLAMPED_FLOAT_TO_UBYTE(refByte, ref); +   refInt = (GLuint) refByte; + +   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)); +} + +/** + * 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. + *  + * \todo + * This function is substantially different from the old i830-specific driver. + * I'm not sure which is correct. + */ +static void +i830EvalLogicOpBlendState(GLcontext * ctx) +{ +   struct i830_context *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]) +{ +   struct i830_context *i830 = i830_context(ctx); +   GLubyte r, g, b, a; + +   DBG("%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; +} + +/** + * Sets both the blend equation (called "function" in i830 docs) and the + * blend function (called "factor" in i830 docs).  This is done in a single + * function because some blend equations (i.e., \c GL_MIN and \c GL_MAX) + * change the interpretation of the blend function. + */ +static void +i830_set_blend_state(GLcontext * ctx) +{ +   struct i830_context *i830 = i830_context(ctx); +   int funcA; +   int funcRGB; +   int eqnA; +   int eqnRGB; +   int iab; +   int s1; + + +   funcRGB = +      SRC_BLND_FACT(intel_translate_blend_factor(ctx->Color.BlendSrcRGB)) +      | DST_BLND_FACT(intel_translate_blend_factor(ctx->Color.BlendDstRGB)); + +   switch (ctx->Color.BlendEquationRGB) { +   case GL_FUNC_ADD: +      eqnRGB = BLENDFUNC_ADD; +      break; +   case GL_MIN: +      eqnRGB = BLENDFUNC_MIN; +      funcRGB = SRC_BLND_FACT(BLENDFACT_ONE) | DST_BLND_FACT(BLENDFACT_ONE); +      break; +   case GL_MAX: +      eqnRGB = BLENDFUNC_MAX; +      funcRGB = SRC_BLND_FACT(BLENDFACT_ONE) | DST_BLND_FACT(BLENDFACT_ONE); +      break; +   case GL_FUNC_SUBTRACT: +      eqnRGB = BLENDFUNC_SUB; +      break; +   case GL_FUNC_REVERSE_SUBTRACT: +      eqnRGB = BLENDFUNC_RVRSE_SUB; +      break; +   default: +      fprintf(stderr, "[%s:%u] Invalid RGB blend equation (0x%04x).\n", +              __FUNCTION__, __LINE__, ctx->Color.BlendEquationRGB); +      return; +   } + + +   funcA = SRC_ABLEND_FACT(intel_translate_blend_factor(ctx->Color.BlendSrcA)) +      | DST_ABLEND_FACT(intel_translate_blend_factor(ctx->Color.BlendDstA)); + +   switch (ctx->Color.BlendEquationA) { +   case GL_FUNC_ADD: +      eqnA = BLENDFUNC_ADD; +      break; +   case GL_MIN: +      eqnA = BLENDFUNC_MIN; +      funcA = SRC_BLND_FACT(BLENDFACT_ONE) | DST_BLND_FACT(BLENDFACT_ONE); +      break; +   case GL_MAX: +      eqnA = BLENDFUNC_MAX; +      funcA = SRC_BLND_FACT(BLENDFACT_ONE) | DST_BLND_FACT(BLENDFACT_ONE); +      break; +   case GL_FUNC_SUBTRACT: +      eqnA = BLENDFUNC_SUB; +      break; +   case GL_FUNC_REVERSE_SUBTRACT: +      eqnA = BLENDFUNC_RVRSE_SUB; +      break; +   default: +      fprintf(stderr, "[%s:%u] Invalid alpha blend equation (0x%04x).\n", +              __FUNCTION__, __LINE__, ctx->Color.BlendEquationA); +      return; +   } + +   iab = eqnA | funcA +      | _3DSTATE_INDPT_ALPHA_BLEND_CMD +      | ENABLE_SRC_ABLEND_FACTOR | ENABLE_DST_ABLEND_FACTOR +      | ENABLE_ALPHA_BLENDFUNC; +   s1 = eqnRGB | funcRGB +      | _3DSTATE_MODES_1_CMD +      | ENABLE_SRC_BLND_FACTOR | ENABLE_DST_BLND_FACTOR +      | ENABLE_COLR_BLND_FUNC; + +   if ((eqnA | funcA) != (eqnRGB | funcRGB)) +      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; +   } + +   /* This will catch a logicop blend equation.  It will also ensure +    * independant alpha blend is really in the correct state (either enabled +    * or disabled) if blending is already enabled. +    */ + +   i830EvalLogicOpBlendState(ctx); + +   if (0) { +      fprintf(stderr, +              "[%s:%u] STATE1: 0x%08x IALPHAB: 0x%08x blend is %sabled\n", +              __FUNCTION__, __LINE__, i830->state.Ctx[I830_CTXREG_STATE1], +              i830->state.Ctx[I830_CTXREG_IALPHAB], +              (ctx->Color.BlendEnabled) ? "en" : "dis"); +   } +} + + +static void +i830BlendEquationSeparate(GLcontext * ctx, GLenum modeRGB, GLenum modeA) +{ +   DBG("%s -> %s, %s\n", __FUNCTION__, +       _mesa_lookup_enum_by_nr(modeRGB), +       _mesa_lookup_enum_by_nr(modeA)); + +   (void) modeRGB; +   (void) modeA; +   i830_set_blend_state(ctx); +} + + +static void +i830BlendFuncSeparate(GLcontext * ctx, GLenum sfactorRGB, +                      GLenum dfactorRGB, GLenum sfactorA, GLenum dfactorA) +{ +   DBG("%s -> RGB(%s, %s) A(%s, %s)\n", __FUNCTION__, +       _mesa_lookup_enum_by_nr(sfactorRGB), +       _mesa_lookup_enum_by_nr(dfactorRGB), +       _mesa_lookup_enum_by_nr(sfactorA), +       _mesa_lookup_enum_by_nr(dfactorA)); + +   (void) sfactorRGB; +   (void) dfactorRGB; +   (void) sfactorA; +   (void) dfactorA; +   i830_set_blend_state(ctx); +} + + + +static void +i830DepthFunc(GLcontext * ctx, GLenum func) +{ +   struct i830_context *i830 = i830_context(ctx); +   int test = intel_translate_compare_func(func); + +   DBG("%s\n", __FUNCTION__); +    +   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) +{ +   struct i830_context *i830 = i830_context(ctx); + +   DBG("%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) +{ +   struct i830_context *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) +{ +   struct i830_context *i830 = i830_context(ctx); +   int x1, y1, x2, y2; + +   if (!ctx->DrawBuffer) +      return; + +   DBG("%s %d,%d %dx%d\n", __FUNCTION__, x, y, w, h); + +   if (ctx->DrawBuffer->Name == 0) { +      x1 = x; +      y1 = ctx->DrawBuffer->Height - (y + h); +      x2 = x + w - 1; +      y2 = y1 + h - 1; +      DBG("%s %d..%d,%d..%d (inverted)\n", __FUNCTION__, x1, x2, y1, y2); +   } +   else { +      /* FBO - not inverted +       */ +      x1 = x; +      y1 = y; +      x2 = x + w - 1; +      y2 = y + h - 1; +      DBG("%s %d..%d,%d..%d (not inverted)\n", __FUNCTION__, x1, x2, y1, y2); +   } + +   x1 = CLAMP(x1, 0, ctx->DrawBuffer->Width - 1); +   y1 = CLAMP(y1, 0, ctx->DrawBuffer->Height - 1); +   x2 = CLAMP(x2, 0, ctx->DrawBuffer->Width - 1); +   y2 = CLAMP(y2, 0, ctx->DrawBuffer->Height - 1); +    +   DBG("%s %d..%d,%d..%d (clamped)\n", __FUNCTION__, x1, x2, y1, y2); + +   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) +{ +   struct i830_context *i830 = i830_context(ctx); +   int tmp = intel_translate_logic_op(opcode); + +   DBG("%s\n", __FUNCTION__); +    +   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) +{ +   struct i830_context *i830 = i830_context(ctx); +   GLuint mode; + +   DBG("%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) +{ +   struct i830_context *i830 = i830_context(ctx); +   int width; +   int state5; + +   DBG("%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) +{ +   struct i830_context *i830 = i830_context(ctx); +   GLint point_size = (int) size; + +   DBG("%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) +{ +   struct i830_context *i830 = i830_context(ctx); +   GLuint tmp = 0; + +   DBG("%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) +{ +   struct i830_context *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) +{ +   DBG("%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) +{ +   struct i830_context *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) +{ +   struct i830_context *i830 = i830_context(ctx); + +   DBG("%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) +{ +   struct i830_context *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: +      { +         GLboolean hw_stencil = GL_FALSE; +         if (ctx->DrawBuffer) { +            struct intel_renderbuffer *irbStencil +               = intel_get_renderbuffer(ctx->DrawBuffer, BUFFER_STENCIL); +            hw_stencil = (irbStencil && irbStencil->region); +         } +         if (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(struct i830_context *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 000                         /* XXX all the stencil enable state is set in i830Enable(), right? */ +   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 +#endif +   { +      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->front.pitch) |     /* pitch in bytes */ +                                                 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->depth.pitch) |  /* pitch in bytes */ +                                                 BUF_3D_USE_FENCE); + +   i830->state.Buffer[I830_DESTREG_DV0] = _3DSTATE_DST_BUF_VARS_CMD; + +   switch (screen->fbFormat) { +   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->StencilFuncSeparate = i830StencilFuncSeparate; +   functions->StencilMaskSeparate = i830StencilMaskSeparate; +   functions->StencilOpSeparate = i830StencilOpSeparate; +} + +void +i830InitState(struct i830_context *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_INVARIENT | +                         I830_UPLOAD_TEXBLEND(0) | +                         I830_UPLOAD_STIPPLE | +                         I830_UPLOAD_CTX | I830_UPLOAD_BUFFERS); +} diff --git a/src/mesa/drivers/dri/i915tex/i830_tex.c b/src/mesa/drivers/dri/i915tex/i830_tex.c new file mode 100644 index 0000000000..fed464d1aa --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i830_tex.c @@ -0,0 +1,100 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#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" + + + +static void +i830TexEnv(GLcontext * ctx, GLenum target, +           GLenum pname, const GLfloat * param) +{ + +   switch (pname) { +   case GL_TEXTURE_ENV_COLOR: +   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:{ +         struct i830_context *i830 = i830_context(ctx); +         GLuint unit = ctx->Texture.CurrentUnit; +         int b = (int) ((*param) * 16.0); +         if (b > 63) +            b = 63; +         if (b < -64) +            b = -64; +         I830_STATECHANGE(i830, I830_UPLOAD_TEX(unit)); +         i830->lodbias_tm0s3[unit] = +            ((b << TM0S3_LOD_BIAS_SHIFT) & TM0S3_LOD_BIAS_MASK); +         break; +      } + +   default: +      break; +   } +} + + + + +void +i830InitTextureFuncs(struct dd_function_table *functions) +{ +   functions->TexEnv = i830TexEnv; +} diff --git a/src/mesa/drivers/dri/i915tex/i830_texblend.c b/src/mesa/drivers/dri/i915tex/i830_texblend.c new file mode 100644 index 0000000000..58f220eb7c --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i830_texblend.c @@ -0,0 +1,463 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#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; +   } +} + + +/** + * Calculate the hardware instuctions to setup the current texture enviromnemt + * settings.  Since \c gl_texture_unit::_CurrentCombine is used, both + * "classic" texture enviroments and GL_ARB_texture_env_combine type texture + * environments are treated identically. + * + * \todo + * This function should return \c GLboolean.  When \c GL_FALSE is returned, + * it means that an environment is selected that the hardware cannot do.  This + * is the way the Radeon and R200 drivers work. + *  + * \todo + * Looking at i830_3d_regs.h, it seems the i830 can do part of + * GL_ATI_texture_env_combine3.  It can handle using \c GL_ONE and + * \c GL_ZERO as combine inputs (which the code already supports).  It can + * also handle the \c GL_MODULATE_ADD_ATI mode.  Is it worth investigating + * partial support for the extension? + */ +GLuint +i830SetTexEnvCombine(struct i830_context * i830, +                     const struct gl_tex_env_combine_state * combine, +                     GLint blendUnit, +                     GLuint texel_op, GLuint * state, const GLfloat * factor) +{ +   const GLuint numColorArgs = combine->_NumArgsRGB; +   const GLuint numAlphaArgs = combine->_NumArgsA; + +   GLuint blendop; +   GLuint ablendop; +   GLuint args_RGB[3]; +   GLuint args_A[3]; +   GLuint rgb_shift; +   GLuint alpha_shift; +   GLboolean need_factor = 0; +   int i; +   unsigned used; +   static const GLuint tex_blend_rgb[3] = { +      TEXPIPE_COLOR | TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS, +      TEXPIPE_COLOR | TEXBLEND_ARG2 | TEXBLENDARG_MODIFY_PARMS, +      TEXPIPE_COLOR | TEXBLEND_ARG0 | TEXBLENDARG_MODIFY_PARMS, +   }; +   static const GLuint tex_blend_a[3] = { +      TEXPIPE_ALPHA | TEXBLEND_ARG1 | TEXBLENDARG_MODIFY_PARMS, +      TEXPIPE_ALPHA | TEXBLEND_ARG2 | TEXBLENDARG_MODIFY_PARMS, +      TEXPIPE_ALPHA | TEXBLEND_ARG0 | TEXBLENDARG_MODIFY_PARMS, +   }; + +   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 (combine->ModeRGB) { +   case GL_DOT3_RGB_EXT: +      alpha_shift = combine->ScaleShiftA; +      rgb_shift = 0; +      break; + +   case GL_DOT3_RGBA_EXT: +      alpha_shift = 0; +      rgb_shift = 0; +      break; + +   default: +      rgb_shift = combine->ScaleShiftRGB; +      alpha_shift = combine->ScaleShiftA; +      break; +   } + + +   switch (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 (combine->SourceRGB[i]) { +      case GL_TEXTURE: +         args_RGB[i] = texel_op; +         break; +      case GL_TEXTURE0: +      case GL_TEXTURE1: +      case GL_TEXTURE2: +      case GL_TEXTURE3: +         args_RGB[i] = GetTexelOp(combine->SourceRGB[i] - GL_TEXTURE0); +         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 (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 (combine->ModeRGB == GL_DOT3_RGBA_EXT || +       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 (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 (combine->SourceA[i]) { +         case GL_TEXTURE: +            args_A[i] = texel_op; +            break; +         case GL_TEXTURE0: +         case GL_TEXTURE1: +         case GL_TEXTURE2: +         case GL_TEXTURE3: +            args_A[i] = GetTexelOp(combine->SourceA[i] - GL_TEXTURE0); +            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 (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 & alpha pipelines */ + +   used = 0; +   state[used++] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | +                    TEXPIPE_COLOR | +                    ENABLE_TEXOUTPUT_WRT_SEL | +                    TEXOP_OUTPUT_CURRENT | +                    DISABLE_TEX_CNTRL_STAGE | TEXOP_MODIFY_PARMS | blendop); +   state[used++] = (_3DSTATE_MAP_BLEND_OP_CMD(blendUnit) | +                    TEXPIPE_ALPHA | +                    ENABLE_TEXOUTPUT_WRT_SEL | +                    TEXOP_OUTPUT_CURRENT | TEXOP_MODIFY_PARMS | ablendop); + +   for (i = 0; i < numColorArgs; i++) { +      state[used++] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | +                       tex_blend_rgb[i] | args_RGB[i]); +   } + +   for (i = 0; i < numAlphaArgs; i++) { +      state[used++] = (_3DSTATE_MAP_BLEND_ARG_CMD(blendUnit) | +                       tex_blend_a[i] | args_A[i]); +   } + + +   if (need_factor) +      return emit_factor(blendUnit, state, used, factor); +   else +      return used; +} + + +static void +emit_texblend(struct i830_context *i830, GLuint unit, GLuint blendUnit, +              GLboolean last_stage) +{ +   struct gl_texture_unit *texUnit = &i830->intel.ctx.Texture.Unit[unit]; +   GLuint tmp[I830_TEXBLEND_SIZE], tmp_sz; + + +   if (0) +      fprintf(stderr, "%s unit %d\n", __FUNCTION__, unit); + +   /* Update i830->state.TexBlend +    */ +   tmp_sz = i830SetTexEnvCombine(i830, texUnit->_CurrentCombine, blendUnit, +                                 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(struct i830_context *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(struct i830_context *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/i915tex/i830_texstate.c b/src/mesa/drivers/dri/i915tex/i830_texstate.c new file mode 100644 index 0000000000..ba79cf9459 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i830_texstate.c @@ -0,0 +1,316 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#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 "intel_mipmap_tree.h" +#include "intel_regions.h" + +#include "i830_context.h" +#include "i830_reg.h" + + + +static GLuint +translate_texture_format(GLuint mesa_format) +{ +   switch (mesa_format) { +   case MESA_FORMAT_L8: +      return MAPSURF_8BIT | MT_8BIT_L8; +   case MESA_FORMAT_I8: +      return MAPSURF_8BIT | MT_8BIT_I8; +   case MESA_FORMAT_A8: +      return MAPSURF_8BIT | MT_8BIT_I8; /* Kludge! */ +   case MESA_FORMAT_AL88: +      return MAPSURF_16BIT | MT_16BIT_AY88; +   case MESA_FORMAT_RGB565: +      return MAPSURF_16BIT | MT_16BIT_RGB565; +   case MESA_FORMAT_ARGB1555: +      return MAPSURF_16BIT | MT_16BIT_ARGB1555; +   case MESA_FORMAT_ARGB4444: +      return MAPSURF_16BIT | MT_16BIT_ARGB4444; +   case MESA_FORMAT_ARGB8888: +      return MAPSURF_32BIT | MT_32BIT_ARGB8888; +   case MESA_FORMAT_YCBCR_REV: +      return (MAPSURF_422 | MT_422_YCRCB_NORMAL); +   case MESA_FORMAT_YCBCR: +      return (MAPSURF_422 | MT_422_YCRCB_SWAPY); +   case MESA_FORMAT_RGB_FXT1: +   case MESA_FORMAT_RGBA_FXT1: +      return (MAPSURF_COMPRESSED | MT_COMPRESS_FXT1); +   case MESA_FORMAT_RGBA_DXT1: +   case MESA_FORMAT_RGB_DXT1: +      return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT1); +   case MESA_FORMAT_RGBA_DXT3: +      return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT2_3); +   case MESA_FORMAT_RGBA_DXT5: +      return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT4_5); +   default: +      fprintf(stderr, "%s: bad image format %x\n", __FUNCTION__, mesa_format); +      abort(); +      return 0; +   } +} + + + + +/* 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: +   case GL_CLAMP_TO_EDGE: +      return TEXCOORDMODE_CLAMP;        /* not really correct */ +   case GL_CLAMP_TO_BORDER: +      return TEXCOORDMODE_CLAMP_BORDER; +   case GL_MIRRORED_REPEAT: +      return TEXCOORDMODE_MIRROR; +   default: +      return TEXCOORDMODE_WRAP; +   } +} + + +/* Recalculate all state from scratch.  Perhaps not the most + * efficient, but this has gotten complex enough that we need + * something which is understandable and reliable. + */ +static GLboolean +i830_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3) +{ +   GLcontext *ctx = &intel->ctx; +   struct i830_context *i830 = i830_context(ctx); +   struct gl_texture_object *tObj = ctx->Texture.Unit[unit]._Current; +   struct intel_texture_object *intelObj = intel_texture_object(tObj); +   struct gl_texture_image *firstImage; +   GLuint *state = i830->state.Tex[unit]; + +   memset(state, 0, sizeof(state)); + +   if (!intel_finalize_mipmap_tree(intel, unit)) +      return GL_FALSE; + +   /* Get first image here, since intelObj->firstLevel will get set in +    * the intel_finalize_mipmap_tree() call above. +    */ +   firstImage = tObj->Image[0][intelObj->firstLevel]; + +   i830->state.tex_buffer[unit] = intelObj->mt->region->buffer; +   i830->state.tex_offset[unit] = intel_miptree_image_offset(intelObj->mt, 0, +                                                             intelObj-> +                                                             firstLevel); + + +   state[I830_TEXREG_TM0LI] = (_3DSTATE_LOAD_STATE_IMMEDIATE_2 | +                               (LOAD_TEXTURE_MAP0 << unit) | 4); + +/*    state[I830_TEXREG_TM0S0] = (TM0S0_USE_FENCE | */ +/* 			       t->intel.TextureOffset); */ + + +   state[I830_TEXREG_TM0S1] = +      (((firstImage->Height - 1) << TM0S1_HEIGHT_SHIFT) | +       ((firstImage->Width - 1) << TM0S1_WIDTH_SHIFT) | +       translate_texture_format(firstImage->TexFormat->MesaFormat)); + +   state[I830_TEXREG_TM0S2] = +      (((((intelObj->mt->pitch * intelObj->mt->cpp) / 4) - +         1) << TM0S2_PITCH_SHIFT) | TM0S2_CUBE_FACE_ENA_MASK); + +   { +      if (tObj->Target == GL_TEXTURE_CUBE_MAP) +         state[I830_TEXREG_CUBE] = (_3DSTATE_MAP_CUBE | MAP_UNIT(unit) | +                                    CUBE_NEGX_ENABLE | +                                    CUBE_POSX_ENABLE | +                                    CUBE_NEGY_ENABLE | +                                    CUBE_POSY_ENABLE | +                                    CUBE_NEGZ_ENABLE | CUBE_POSZ_ENABLE); +      else +         state[I830_TEXREG_CUBE] = (_3DSTATE_MAP_CUBE | MAP_UNIT(unit)); +   } + + + + +   { +      GLuint minFilt, mipFilt, magFilt; + +      switch (tObj->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: +         return GL_FALSE; +      } + +      if (tObj->MaxAnisotropy > 1.0) { +         minFilt = FILTER_ANISOTROPIC; +         magFilt = FILTER_ANISOTROPIC; +      } +      else { +         switch (tObj->MagFilter) { +         case GL_NEAREST: +            magFilt = FILTER_NEAREST; +            break; +         case GL_LINEAR: +            magFilt = FILTER_LINEAR; +            break; +         default: +            return GL_FALSE; +         } +      } + +      state[I830_TEXREG_TM0S3] = i830->lodbias_tm0s3[unit]; + +#if 0 +      /* YUV conversion: +       */ +      if (firstImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR || +          firstImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR_REV) +         state[I830_TEXREG_TM0S3] |= SS2_COLORSPACE_CONVERSION; +#endif + +      state[I830_TEXREG_TM0S3] |= ((intelObj->lastLevel - +                                    intelObj->firstLevel) * +                                   4) << TM0S3_MIN_MIP_SHIFT; + +      state[I830_TEXREG_TM0S3] |= ((minFilt << TM0S3_MIN_FILTER_SHIFT) | +                                   (mipFilt << TM0S3_MIP_FILTER_SHIFT) | +                                   (magFilt << TM0S3_MAG_FILTER_SHIFT)); +   } + +   { +      GLenum ws = tObj->WrapS; +      GLenum wt = tObj->WrapT; + + +      /* 3D textures not available on i830 +       */ +      if (tObj->Target == GL_TEXTURE_3D) +         return GL_FALSE; + +      state[I830_TEXREG_MCS] = (_3DSTATE_MAP_COORD_SET_CMD | +                                MAP_UNIT(unit) | +                                ENABLE_TEXCOORD_PARAMS | +                                ss3 | +                                ENABLE_ADDR_V_CNTL | +                                TEXCOORD_ADDR_V_MODE(translate_wrap_mode(wt)) +                                | ENABLE_ADDR_U_CNTL | +                                TEXCOORD_ADDR_U_MODE(translate_wrap_mode +                                                     (ws))); +   } + + +   state[I830_TEXREG_TM0S4] = INTEL_PACKCOLOR8888(tObj->_BorderChan[0], +                                                  tObj->_BorderChan[1], +                                                  tObj->_BorderChan[2], +                                                  tObj->_BorderChan[3]); + + +   I830_ACTIVESTATE(i830, I830_UPLOAD_TEX(unit), GL_TRUE); +   /* memcmp was already disabled, but definitely won't work as the +    * region might now change and that wouldn't be detected: +    */ +   I830_STATECHANGE(i830, I830_UPLOAD_TEX(unit)); +   return GL_TRUE; +} + + + + +void +i830UpdateTextureState(struct intel_context *intel) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); +   GLboolean ok = GL_TRUE; +   GLuint i; + +   for (i = 0; i < I830_TEX_UNITS && ok; i++) { +      switch (intel->ctx.Texture.Unit[i]._ReallyEnabled) { +      case TEXTURE_1D_BIT: +      case TEXTURE_2D_BIT: +      case TEXTURE_CUBE_BIT: +         ok = i830_update_tex_unit(intel, i, TEXCOORDS_ARE_NORMAL); +         break; +      case TEXTURE_RECT_BIT: +         ok = i830_update_tex_unit(intel, i, TEXCOORDS_ARE_IN_TEXELUNITS); +         break; +      case 0: +         if (i830->state.active & I830_UPLOAD_TEX(i)) +            I830_ACTIVESTATE(i830, I830_UPLOAD_TEX(i), GL_FALSE); +         break; +      case TEXTURE_3D_BIT: +      default: +         ok = GL_FALSE; +         break; +      } +   } + +   FALLBACK(intel, I830_FALLBACK_TEXTURE, !ok); + +   if (ok) +      i830EmitTextureBlend(i830); +} diff --git a/src/mesa/drivers/dri/i915tex/i830_vtbl.c b/src/mesa/drivers/dri/i915tex/i830_vtbl.c new file mode 100644 index 0000000000..45502da290 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i830_vtbl.c @@ -0,0 +1,606 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + + +#include "i830_context.h" +#include "i830_reg.h" +#include "intel_batchbuffer.h" +#include "intel_regions.h" +#include "tnl/t_context.h" +#include "tnl/t_vertex.h" + +#define FILE_DEBUG_FLAG DEBUG_STATE + +static GLboolean i830_check_vertex_size(struct intel_context *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(struct intel_context *intel) +{ +   GLcontext *ctx = &intel->ctx; +   struct i830_context *i830 = i830_context(ctx); +   TNLcontext *tnl = TNL_CONTEXT(ctx); +   struct vertex_buffer *VB = &tnl->vb; +   DECLARE_RENDERINPUTS(index_bitset); +   GLuint v0 = _3DSTATE_VFT0_CMD; +   GLuint v2 = _3DSTATE_VFT1_CMD; +   GLuint mcsb1 = 0; + +   RENDERINPUTS_COPY(index_bitset, tnl->render_inputs_bitset); + +   /* 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 (RENDERINPUTS_TEST_RANGE(index_bitset, _TNL_FIRST_TEX, _TNL_LAST_TEX)) { +      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; +   } + +   if (RENDERINPUTS_TEST(index_bitset, _TNL_ATTRIB_POINTSIZE)) { +      EMIT_ATTR(_TNL_ATTRIB_POINTSIZE, EMIT_1F, VFT0_POINT_WIDTH); +   } + +   EMIT_ATTR(_TNL_ATTRIB_COLOR0, EMIT_4UB_4F_BGRA, VFT0_DIFFUSE); + +   intel->specoffset = 0; +   if (RENDERINPUTS_TEST(index_bitset, _TNL_ATTRIB_COLOR1) || +       RENDERINPUTS_TEST(index_bitset, _TNL_ATTRIB_FOG)) { +      if (RENDERINPUTS_TEST(index_bitset, _TNL_ATTRIB_COLOR1)) { +         intel->specoffset = intel->coloroffset + 1; +         EMIT_ATTR(_TNL_ATTRIB_COLOR1, EMIT_3UB_3F_BGR, VFT0_SPEC); +      } +      else +         EMIT_PAD(3); + +      if (RENDERINPUTS_TEST(index_bitset, _TNL_ATTRIB_FOG)) +         EMIT_ATTR(_TNL_ATTRIB_FOG, EMIT_1UB_1F, VFT0_SPEC); +      else +         EMIT_PAD(1); +   } + +   if (RENDERINPUTS_TEST_RANGE(index_bitset, _TNL_FIRST_TEX, _TNL_LAST_TEX)) { +      int i, count = 0; + +      for (i = 0; i < I830_TEX_UNITS; i++) { +         if (RENDERINPUTS_TEST(index_bitset, _TNL_ATTRIB_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: +               emit = EMIT_2F; +               sz = 2; +               mcs |= TEXCOORDTYPE_CARTESIAN; +               break; +            case 3: +               emit = EMIT_3F; +               sz = 3; +               mcs |= TEXCOORDTYPE_VECTOR; +               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] || +       !RENDERINPUTS_EQUAL(index_bitset, i830->last_index_bitset)) { +      int k; + +      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; +      RENDERINPUTS_COPY(i830->last_index_bitset, index_bitset); + +      k = i830_check_vertex_size(intel, intel->vertex_size); +      assert(k); +   } +} + +static void +i830_reduced_primitive_state(struct intel_context *intel, GLenum rprim) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); +   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]) { +      INTEL_FIREVERTICES(intel); + +      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(struct intel_context *intel, GLuint expected) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); +   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(struct intel_context *intel) +{ +   BATCH_LOCALS; + +   BEGIN_BATCH(40, 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); + +   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_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), 0);		\ +   for (k = 0 ; k < size / sizeof(GLuint) ; k++) {	\ +      if (0) _mesa_printf("  0x%08x\n", state[k]);		\ +      OUT_BATCH(state[k]);				\ +   }							\ +   ADVANCE_BATCH();					\ +} while (0) + +static GLuint +get_state_size(struct i830_hw_state *state) +{ +   GLuint dirty = state->active & ~state->emitted; +   GLuint sz = 0; +   GLuint i; + +   if (dirty & I830_UPLOAD_INVARIENT) +      sz += 40 * sizeof(int); + +   if (dirty & I830_UPLOAD_CTX) +      sz += sizeof(state->Ctx); + +   if (dirty & I830_UPLOAD_BUFFERS) +      sz += sizeof(state->Buffer); + +   if (dirty & I830_UPLOAD_STIPPLE) +      sz += sizeof(state->Stipple); + +   for (i = 0; i < I830_TEX_UNITS; i++) { +      if ((dirty & I830_UPLOAD_TEX(i))) +         sz += sizeof(state->Tex[i]); + +      if (dirty & I830_UPLOAD_TEXBLEND(i)) +         sz += state->TexBlendWordsUsed[i] * 4; +   } + +   return sz; +} + + +/* Push the state into the sarea and/or texture memory. + */ +static void +i830_emit_state(struct intel_context *intel) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); +   struct i830_hw_state *state = i830->current; +   int i; +   GLuint dirty; +   BATCH_LOCALS; + +   /* We don't hold the lock at this point, so want to make sure that +    * there won't be a buffer wrap.   +    * +    * It might be better to talk about explicit places where +    * scheduling is allowed, rather than assume that it is whenever a +    * batchbuffer fills up. +    */ +   intel_batchbuffer_require_space(intel->batch, get_state_size(state), 0); + +   /* Do this here as we may have flushed the batchbuffer above, +    * causing more state to be dirty! +    */ +   dirty = state->active & ~state->emitted; + +   if (dirty & I830_UPLOAD_INVARIENT) { +      DBG("I830_UPLOAD_INVARIENT:\n"); +      i830_emit_invarient_state(intel); +   } + +   if (dirty & I830_UPLOAD_CTX) { +      DBG("I830_UPLOAD_CTX:\n"); +      emit(i830, state->Ctx, sizeof(state->Ctx)); + +   } + +   if (dirty & I830_UPLOAD_BUFFERS) { +      DBG("I830_UPLOAD_BUFFERS:\n"); +      BEGIN_BATCH(I830_DEST_SETUP_SIZE + 2, 0); +      OUT_BATCH(state->Buffer[I830_DESTREG_CBUFADDR0]); +      OUT_BATCH(state->Buffer[I830_DESTREG_CBUFADDR1]); +      OUT_RELOC(state->draw_region->buffer, +                DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, +                DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, 0); + +      if (state->depth_region) { +         OUT_BATCH(state->Buffer[I830_DESTREG_DBUFADDR0]); +         OUT_BATCH(state->Buffer[I830_DESTREG_DBUFADDR1]); +         OUT_RELOC(state->depth_region->buffer, +                   DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, +                   DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, 0); +      } + +      OUT_BATCH(state->Buffer[I830_DESTREG_DV0]); +      OUT_BATCH(state->Buffer[I830_DESTREG_DV1]); +      OUT_BATCH(state->Buffer[I830_DESTREG_SENABLE]); +      OUT_BATCH(state->Buffer[I830_DESTREG_SR0]); +      OUT_BATCH(state->Buffer[I830_DESTREG_SR1]); +      OUT_BATCH(state->Buffer[I830_DESTREG_SR2]); +      ADVANCE_BATCH(); +   } + +   if (dirty & I830_UPLOAD_STIPPLE) { +      DBG("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))) { +         DBG("I830_UPLOAD_TEX(%d):\n", i); + +         BEGIN_BATCH(I830_TEX_SETUP_SIZE + 1, 0); +         OUT_BATCH(state->Tex[i][I830_TEXREG_TM0LI]); + +         if (state->tex_buffer[i]) { +            OUT_RELOC(state->tex_buffer[i], +                      DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ, +                      DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, +                      state->tex_offset[i] | TM0S0_USE_FENCE); +         } +         else { +            assert(i == 0); +            assert(state == &i830->meta); +            OUT_BATCH(0); +         } + +         OUT_BATCH(state->Tex[i][I830_TEXREG_TM0S1]); +         OUT_BATCH(state->Tex[i][I830_TEXREG_TM0S2]); +         OUT_BATCH(state->Tex[i][I830_TEXREG_TM0S3]); +         OUT_BATCH(state->Tex[i][I830_TEXREG_TM0S4]); +         OUT_BATCH(state->Tex[i][I830_TEXREG_MCS]); +         OUT_BATCH(state->Tex[i][I830_TEXREG_CUBE]); +      } + +      if (dirty & I830_UPLOAD_TEXBLEND(i)) { +         DBG("I830_UPLOAD_TEXBLEND(%d): %d words\n", i, +             state->TexBlendWordsUsed[i]); +         emit(i830, state->TexBlend[i], state->TexBlendWordsUsed[i] * 4); +      } +   } + +   state->emitted |= dirty; +} + +static void +i830_destroy_context(struct intel_context *intel) +{ +   _tnl_free_vertices(&intel->ctx); +} + +static void +i830_set_draw_region(struct intel_context *intel, +                     struct intel_region *draw_region, +                     struct intel_region *depth_region) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); + +   intel_region_release(&i830->state.draw_region); +   intel_region_release(&i830->state.depth_region); +   intel_region_reference(&i830->state.draw_region, draw_region); +   intel_region_reference(&i830->state.depth_region, depth_region); + +   /* XXX FBO: Need code from i915_set_draw_region() */ + +   I830_STATECHANGE(i830, I830_UPLOAD_BUFFERS); +   I830_STATECHANGE(i830, I830_UPLOAD_BUFFERS); +   i830->state.Buffer[I830_DESTREG_CBUFADDR1] = +      (BUF_3D_ID_COLOR_BACK | BUF_3D_PITCH(draw_region->pitch) | +       BUF_3D_USE_FENCE); +   i830->state.Buffer[I830_DESTREG_DBUFADDR1] = +      (BUF_3D_ID_DEPTH | BUF_3D_PITCH(depth_region->pitch) | +       BUF_3D_USE_FENCE); +} + +#if 0 +static void +i830_update_color_z_regions(intelContextPtr intel, +                            const intelRegion * colorRegion, +                            const intelRegion * depthRegion) +{ +   i830ContextPtr i830 = I830_CONTEXT(intel); + +   i830->state.Buffer[I830_DESTREG_CBUFADDR1] = +      (BUF_3D_ID_COLOR_BACK | BUF_3D_PITCH(colorRegion->pitch) | +       BUF_3D_USE_FENCE); +   i830->state.Buffer[I830_DESTREG_CBUFADDR2] = colorRegion->offset; + +   i830->state.Buffer[I830_DESTREG_DBUFADDR1] = +      (BUF_3D_ID_DEPTH | BUF_3D_PITCH(depthRegion->pitch) | BUF_3D_USE_FENCE); +   i830->state.Buffer[I830_DESTREG_DBUFADDR2] = depthRegion->offset; +} +#endif + + +/* This isn't really handled at the moment. + */ +static void +i830_lost_hardware(struct intel_context *intel) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); +   i830->state.emitted = 0; +} + + + +static GLuint +i830_flush_cmd(void) +{ +   return MI_FLUSH | FLUSH_MAP_CACHE; +} + + +static void  +i830_assert_not_dirty( struct intel_context *intel ) +{ +   struct i830_context *i830 = i830_context(&intel->ctx); +   struct i830_hw_state *state = i830->current; +   GLuint dirty = state->active & ~state->emitted; +   assert(!dirty); +} + + +void +i830InitVtbl(struct i830_context *i830) +{ +   i830->intel.vtbl.check_vertex_size = i830_check_vertex_size; +   i830->intel.vtbl.destroy = i830_destroy_context; +   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_region = i830_set_draw_region; +   i830->intel.vtbl.update_texture_state = i830UpdateTextureState; +   i830->intel.vtbl.flush_cmd = i830_flush_cmd; +   i830->intel.vtbl.render_start = i830_render_start; +   i830->intel.vtbl.assert_not_dirty = i830_assert_not_dirty; +} diff --git a/src/mesa/drivers/dri/i915tex/i915_context.c b/src/mesa/drivers/dri/i915tex/i915_context.c new file mode 100644 index 0000000000..924de169c7 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i915_context.c @@ -0,0 +1,174 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#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" + +#include "intel_regions.h" +#include "intel_batchbuffer.h" + +/*************************************** + * Mesa's Driver Functions + ***************************************/ + +static const struct dri_extension i915_extensions[] = { +   {"GL_ARB_depth_texture", NULL}, +   {"GL_ARB_fragment_program", NULL}, +   {"GL_ARB_shadow", NULL}, +   {"GL_ARB_texture_env_crossbar", NULL}, +   {"GL_ARB_texture_non_power_of_two", NULL}, +   {"GL_EXT_shadow_funcs", NULL}, +   /* ARB extn won't work if not enabled */ +   {"GL_SGIX_depth_texture", NULL}, +   {NULL, 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 && p->nr_params) +         p->params_uptodate = 0; +   } + +   if (new_state & (_NEW_FOG | _NEW_HINT | _NEW_PROGRAM)) +      i915_update_fog(ctx); +} + + +static void +i915InitDriverFunctions(struct dd_function_table *functions) +{ +   intelInitDriverFunctions(functions); +   i915InitStateFunctions(functions); +   i915InitTextureFuncs(functions); +   i915InitFragProgFuncs(functions); +   functions->UpdateState = i915InvalidateState; +} + + + +GLboolean +i915CreateContext(const __GLcontextModes * mesaVis, +                  __DRIcontextPrivate * driContextPriv, +                  void *sharedContextPrivate) +{ +   struct dd_function_table functions; +   struct i915_context *i915 = +      (struct i915_context *) CALLOC_STRUCT(i915_context); +   struct intel_context *intel = &i915->intel; +   GLcontext *ctx = &intel->ctx; + +   if (!i915) +      return GL_FALSE; + +   _mesa_printf("\ntexmem-0-3 branch\n\n"); + +   i915InitVtbl(i915); +   i915InitMetaFuncs(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; + + +   /* Advertise the full hardware capabilities.  The new memory +    * manager should cope much better with overload situations: +    */ +   ctx->Const.MaxTextureLevels = 12; +   ctx->Const.Max3DTextureLevels = 9; +   ctx->Const.MaxCubeTextureLevels = 12; +   ctx->Const.MaxTextureRectSize = (1 << 11); +   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.FragmentProgram.MaxNativeTemps = I915_MAX_TEMPORARY; +   ctx->Const.FragmentProgram.MaxNativeAttribs = 11;    /* 8 tex, 2 color, fog */ +   ctx->Const.FragmentProgram.MaxNativeParameters = I915_MAX_CONSTANT; +   ctx->Const.FragmentProgram.MaxNativeAluInstructions = I915_MAX_ALU_INSN; +   ctx->Const.FragmentProgram.MaxNativeTexInstructions = I915_MAX_TEX_INSN; +   ctx->Const.FragmentProgram.MaxNativeInstructions = (I915_MAX_ALU_INSN + +                                                       I915_MAX_TEX_INSN); +   ctx->Const.FragmentProgram.MaxNativeTexIndirections = +      I915_MAX_TEX_INDIRECT; +   ctx->Const.FragmentProgram.MaxNativeAddressRegs = 0; /* I don't think we have one */ + +   ctx->_MaintainTexEnvProgram = 1; +   ctx->_UseTexEnvProgram = 1; + +   driInitExtensions(ctx, i915_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/i915tex/i915_context.h b/src/mesa/drivers/dri/i915tex/i915_context.h new file mode 100644 index 0000000000..5ae76fcd18 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i915_context.h @@ -0,0 +1,367 @@ + /************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#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_FALLBACK_POLYGON_SMOOTH	 0x40000 +#define I915_FALLBACK_POINT_SMOOTH	 0x80000 + +#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_INVARIENT        0x40 +#define I915_UPLOAD_DEFAULTS         0x80 +#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_DBUFADDR0 3 +#define I915_DESTREG_DBUFADDR1 4 +#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_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_DEFREG_C0    0 +#define I915_DEFREG_C1    1 +#define I915_DEFREG_S0    2 +#define I915_DEFREG_S1    3 +#define I915_DEFREG_Z0    4 +#define I915_DEFREG_Z1    5 +#define I915_DEF_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 gl_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; +}; + + + + + + + +#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 Defaults[I915_DEF_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; + +   /* Region pointers for relocation:  +    */ +   struct intel_region *draw_region; +   struct intel_region *depth_region; +/*    struct intel_region *tex_region[I915_TEX_UNITS]; */ + +   /* Regions aren't actually that appropriate here as the memory may +    * be from a PBO or FBO.  Just use the buffer id.  Will have to do +    * this for draw and depth for FBO's... +    */ +   struct _DriBufferObject *tex_buffer[I915_TEX_UNITS]; +   GLuint tex_offset[I915_TEX_UNITS]; + + +   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; +   GLuint lodbias_ss2[MAX_TEXTURE_UNITS]; + + +   struct i915_fragment_program tex_program; +   struct i915_fragment_program *current_program; + +   struct i915_hw_state meta, initial, state, *current; +}; + + +#define I915_STATECHANGE(i915, flag)					\ +do {									\ +   INTEL_FIREVERTICES( &(i915)->intel );					\ +   (i915)->state.emitted &= ~(flag);					\ +} while (0) + +#define I915_ACTIVESTATE(i915, flag, mode)			\ +do {								\ +   INTEL_FIREVERTICES( &(i915)->intel );				\ +   if (mode)							\ +      (i915)->state.active |= (flag);				\ +   else								\ +      (i915)->state.active &= ~(flag);				\ +} while (0) + + +/*====================================================================== + * i915_vtbl.c + */ +extern void i915InitVtbl(struct i915_context *i915); + +extern void +i915_state_draw_region(struct intel_context *intel, +                       struct i915_hw_state *state, +                       struct intel_region *color_region, +                       struct intel_region *depth_region); + + + +#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(struct i915_context *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(struct i915_context *i915); +extern void i915_update_fog(GLcontext * ctx); + + +/*====================================================================== + * i915_tex.c + */ +extern void i915UpdateTextureState(struct intel_context *intel); +extern void i915InitTextureFuncs(struct dd_function_table *functions); + +/*====================================================================== + * i915_metaops.c + */ +void i915InitMetaFuncs(struct i915_context *i915); + + +/*====================================================================== + * i915_fragprog.c + */ +extern void i915ValidateFragmentProgram(struct i915_context *i915); +extern void i915InitFragProgFuncs(struct dd_function_table *functions); + +/*====================================================================== + * Inline conversion functions.  These are better-typed than the + * macros used previously: + */ +static INLINE struct i915_context * +i915_context(GLcontext * ctx) +{ +   return (struct i915_context *) ctx; +} + + + +#define I915_CONTEXT(ctx)	i915_context(ctx) + + + +#endif diff --git a/src/mesa/drivers/dri/i915tex/i915_debug.c b/src/mesa/drivers/dri/i915tex/i915_debug.c new file mode 100644 index 0000000000..974527e14c --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i915_debug.c @@ -0,0 +1,334 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#include "i915_reg.h" +#include "i915_context.h" +#include <stdio.h> + + +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 ((GLint) 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/i915tex/i915_fragprog.c b/src/mesa/drivers/dri/i915tex/i915_fragprog.c new file mode 100644 index 0000000000..ac5cf2ead2 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i915_fragprog.c @@ -0,0 +1,1069 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#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 "program_instruction.h" +#include "program.h" + + + +/* 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 prog_src_register *source, +           const struct gl_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->Base.Parameters->ParameterValues[source-> +                                                                      Index]); +      break; + +   default: +      i915_program_error(p, "Bad source->File"); +      return 0; +   } + +   src = swizzle(src, +                 GET_SWZ(source->Swizzle, 0), +                 GET_SWZ(source->Swizzle, 1), +                 GET_SWZ(source->Swizzle, 2), GET_SWZ(source->Swizzle, 3)); + +   if (source->NegateBase) +      src = negate(src, +                   GET_BIT(source->NegateBase, 0), +                   GET_BIT(source->NegateBase, 1), +                   GET_BIT(source->NegateBase, 2), +                   GET_BIT(source->NegateBase, 3)); + +   return src; +} + + +static GLuint +get_result_vector(struct i915_fragment_program *p, +                  const struct prog_instruction *inst) +{ +   switch (inst->DstReg.File) { +   case PROGRAM_OUTPUT: +      switch (inst->DstReg.Index) { +      case FRAG_RESULT_COLR: +         return UREG(REG_TYPE_OC, 0); +      case FRAG_RESULT_DEPR: +         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 prog_instruction *inst) +{ +   GLuint flags = 0; + +   if (inst->SaturateMode == SATURATE_ZERO_ONE) +      flags |= A0_DEST_SATURATE; +   if (inst->DstReg.WriteMask & WRITEMASK_X) +      flags |= A0_DEST_CHANNEL_X; +   if (inst->DstReg.WriteMask & WRITEMASK_Y) +      flags |= A0_DEST_CHANNEL_Y; +   if (inst->DstReg.WriteMask & WRITEMASK_Z) +      flags |= A0_DEST_CHANNEL_Z; +   if (inst->DstReg.WriteMask & WRITEMASK_W) +      flags |= A0_DEST_CHANNEL_W; + +   return flags; +} + +static GLuint +translate_tex_src_target(struct i915_fragment_program *p, GLubyte bit) +{ +   switch (bit) { +   case TEXTURE_1D_INDEX: +      return D0_SAMPLE_TYPE_2D; +   case TEXTURE_2D_INDEX: +      return D0_SAMPLE_TYPE_2D; +   case TEXTURE_RECT_INDEX: +      return D0_SAMPLE_TYPE_2D; +   case TEXTURE_3D_INDEX: +      return D0_SAMPLE_TYPE_VOLUME; +   case TEXTURE_CUBE_INDEX: +      return D0_SAMPLE_TYPE_CUBE; +   default: +      i915_program_error(p, "TexSrcBit"); +      return 0; +   } +} + +#define EMIT_TEX( OP )						\ +do {								\ +   GLuint dim = translate_tex_src_target( p, inst->TexSrcTarget );	\ +   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 gl_fragment_program *program = +      p->ctx->FragmentProgram._Current; +   const struct prog_instruction *inst = program->Base.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 == 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 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 OPCODE_ADD: +         EMIT_2ARG_ARITH(A0_ADD); +         break; + +      case 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 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 / (M_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, (M_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 OPCODE_DP3: +         EMIT_2ARG_ARITH(A0_DP3); +         break; + +      case OPCODE_DP4: +         EMIT_2ARG_ARITH(A0_DP4); +         break; + +      case 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 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 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 OPCODE_FLR: +         EMIT_1ARG_ARITH(A0_FLR); +         break; + +      case OPCODE_FRC: +         EMIT_1ARG_ARITH(A0_FRC); +         break; + +      case 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 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 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 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 OPCODE_MAD: +         EMIT_3ARG_ARITH(A0_MAD); +         break; + +      case OPCODE_MAX: +         EMIT_2ARG_ARITH(A0_MAX); +         break; + +      case 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 OPCODE_MOV: +         EMIT_1ARG_ARITH(A0_MOV); +         break; + +      case OPCODE_MUL: +         EMIT_2ARG_ARITH(A0_MUL); +         break; + +      case 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 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 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 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 & WRITEMASK_Y) { +            GLuint tmp1; + +            if (inst->DstReg.WriteMask & WRITEMASK_X) +               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 & WRITEMASK_X) { +            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 OPCODE_SGE: +         EMIT_2ARG_ARITH(A0_SGE); +         break; + +      case 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 / (M_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, (M_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 OPCODE_SLT: +         EMIT_2ARG_ARITH(A0_SLT); +         break; + +      case 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 OPCODE_SWZ: +         EMIT_1ARG_ARITH(A0_MOV);       /* extended swizzle handled natively */ +         break; + +      case OPCODE_TEX: +         EMIT_TEX(T0_TEXLD); +         break; + +      case OPCODE_TXB: +         EMIT_TEX(T0_TEXLDB); +         break; + +      case OPCODE_TXP: +         EMIT_TEX(T0_TEXLDP); +         break; + +      case 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 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.Base.InputsRead; +   GLint i; + +   p->wpos_tex = -1; + +   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) +{ +   struct i915_context *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.Base.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 gl_program *prog) +{ +   if (target == GL_FRAGMENT_PROGRAM_ARB) { +      struct i915_context *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 gl_program * +i915NewProgram(GLcontext * ctx, GLenum target, GLuint id) +{ +   switch (target) { +   case GL_VERTEX_PROGRAM_ARB: +      return _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_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; +      } + +   default: +      /* Just fallback: +       */ +      return _mesa_new_program(ctx, target, id); +   } +} + +static void +i915DeleteProgram(GLcontext * ctx, struct gl_program *prog) +{ +   if (prog->Target == GL_FRAGMENT_PROGRAM_ARB) { +      struct i915_context *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 gl_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 gl_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(struct i915_context *i915) +{ +   GLcontext *ctx = &i915->intel.ctx; +   struct intel_context *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; + +   const GLuint inputsRead = p->FragProg.Base.InputsRead; +   GLuint s4 = i915->state.Ctx[I915_CTXREG_LIS4] & ~S4_VFMT_MASK; +   GLuint s2 = S2_TEXCOORD_NONE; +   int i, offset = 0; + +   if (i915->current_program != p) { +      if (i915->current_program) { +         i915->current_program->on_hardware = 0; +         i915->current_program->params_uptodate = 0; +      } + +      i915->current_program = p; +   } + + +   /* 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_BGRA, S4_VFMT_COLOR, 4); +   } + +   if ((inputsRead & (FRAG_BIT_COL1 | FRAG_BIT_FOGC)) || +       i915->vertex_fog != I915_FOG_NONE) { + +      if (inputsRead & FRAG_BIT_COL1) { +         intel->specoffset = offset / 4; +         EMIT_ATTR(_TNL_ATTRIB_COLOR1, EMIT_3UB_3F_BGR, S4_VFMT_SPEC_FOG, 3); +      } +      else +         EMIT_PAD(3); + +      if ((inputsRead & FRAG_BIT_FOGC) || i915->vertex_fog != I915_FOG_NONE) +         EMIT_ATTR(_TNL_ATTRIB_FOG, EMIT_1UB_1F, S4_VFMT_SPEC_FOG, 1); +      else +         EMIT_PAD(1); +   } + +#if 0 +   if ((inputsRead & FRAG_BIT_FOGC) || i915->vertex_fog != I915_FOG_NONE) { +      EMIT_ATTR(_TNL_ATTRIB_FOG, EMIT_1F, S4_VFMT_FOG_PARAM, 4); +   } +#endif + +   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]) { +      int k; + +      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; + +      k = intel->vtbl.check_vertex_size(intel, intel->vertex_size); +      assert(k); +   } + +   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/i915tex/i915_metaops.c b/src/mesa/drivers/dri/i915tex/i915_metaops.c new file mode 100644 index 0000000000..3ab62bc806 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i915_metaops.c @@ -0,0 +1,509 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#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 "intel_regions.h" +#include "intel_rotate.h" + +#include "i915_context.h" +#include "i915_reg.h" + +/* We touch almost everything: + */ +#define ACTIVE (I915_UPLOAD_INVARIENT | 	\ +		I915_UPLOAD_CTX |		\ +		I915_UPLOAD_BUFFERS |		\ +		I915_UPLOAD_STIPPLE |		\ +                I915_UPLOAD_PROGRAM | 		\ +                I915_UPLOAD_FOG | 		\ +		I915_UPLOAD_TEX(0)) + +#define SET_STATE( i915, STATE )		\ +do {						\ +   i915->current->emitted &= ~ACTIVE;		\ +   i915->current = &i915->STATE;		\ +   i915->current->emitted &= ~ACTIVE;		\ +} while (0) + + +static void +meta_no_stencil_write(struct intel_context *intel) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); + +   /* ctx->Driver.Enable( ctx, GL_STENCIL_TEST, GL_FALSE ) +    */ +   i915->meta.Ctx[I915_CTXREG_LIS5] &= ~(S5_STENCIL_TEST_ENABLE | +                                         S5_STENCIL_WRITE_ENABLE); + +   i915->meta.emitted &= ~I915_UPLOAD_CTX; +} + +static void +meta_no_depth_write(struct intel_context *intel) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); + +   /* 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; +} + +static void +meta_depth_replace(struct intel_context *intel) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); + +   /* ctx->Driver.Enable( ctx, GL_DEPTH_TEST, GL_TRUE ) +    * ctx->Driver.DepthMask( ctx, GL_TRUE ) +    */ +   i915->meta.Ctx[I915_CTXREG_LIS6] |= (S6_DEPTH_TEST_ENABLE | +                                        S6_DEPTH_WRITE_ENABLE); + +   /* ctx->Driver.DepthFunc( ctx, GL_REPLACE ) +    */ +   i915->meta.Ctx[I915_CTXREG_LIS6] &= ~S6_DEPTH_TEST_FUNC_MASK; +   i915->meta.Ctx[I915_CTXREG_LIS6] |= +      COMPAREFUNC_ALWAYS << S6_DEPTH_TEST_FUNC_SHIFT; + +   i915->meta.emitted &= ~I915_UPLOAD_CTX; +} + + +/* Set stencil unit to replace always with the reference value. + */ +static void +meta_stencil_replace(struct intel_context *intel, +                     GLuint s_mask, GLuint s_clear) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); +   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.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 +meta_color_mask(struct intel_context *intel, GLboolean state) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); +   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; +} + + + +static void +meta_import_pixel_state(struct intel_context *intel) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); +   memcpy(i915->meta.Fog, i915->state.Fog, I915_FOG_SETUP_SIZE * 4); + +   i915->meta.Ctx[I915_CTXREG_LIS5] = i915->state.Ctx[I915_CTXREG_LIS5]; +   i915->meta.Ctx[I915_CTXREG_LIS6] = i915->state.Ctx[I915_CTXREG_LIS6]; +   i915->meta.Ctx[I915_CTXREG_STATE4] = i915->state.Ctx[I915_CTXREG_STATE4]; +   i915->meta.Ctx[I915_CTXREG_BLENDCOLOR1] = +      i915->state.Ctx[I915_CTXREG_BLENDCOLOR1]; +   i915->meta.Ctx[I915_CTXREG_IAB] = i915->state.Ctx[I915_CTXREG_IAB]; + +   i915->meta.Buffer[I915_DESTREG_SENABLE] = +      i915->state.Buffer[I915_DESTREG_SENABLE]; +   i915->meta.Buffer[I915_DESTREG_SR1] = i915->state.Buffer[I915_DESTREG_SR1]; +   i915->meta.Buffer[I915_DESTREG_SR2] = i915->state.Buffer[I915_DESTREG_SR2]; + +   i915->meta.emitted &= ~I915_UPLOAD_FOG; +   i915->meta.emitted &= ~I915_UPLOAD_BUFFERS; +   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)<<T0_SAMPLER_NR_SHIFT) + +#define T1_ADDRESS_REG( type, nr ) (((type)<<T1_ADDRESS_REG_TYPE_SHIFT)| \ +				    ((nr)<<T1_ADDRESS_REG_NR_SHIFT)) + + +#define A1_SRC0_XYZW ((SRC_X << A1_SRC0_CHANNEL_X_SHIFT) |	\ +		      (SRC_Y << A1_SRC0_CHANNEL_Y_SHIFT) |	\ +		      (SRC_Z << A1_SRC0_CHANNEL_Z_SHIFT) |	\ +		      (SRC_W << A1_SRC0_CHANNEL_W_SHIFT)) + +#define A1_SRC1_XY   ((SRC_X << A1_SRC1_CHANNEL_X_SHIFT) |	\ +		      (SRC_Y << A1_SRC1_CHANNEL_Y_SHIFT)) + +#define A2_SRC1_ZW   ((SRC_Z << A2_SRC1_CHANNEL_Z_SHIFT) |	\ +		      (SRC_W << A2_SRC1_CHANNEL_W_SHIFT)) + +#define A2_SRC2_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 +meta_no_texture(struct intel_context *intel) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); + +   static const GLuint prog[] = { +      _3DSTATE_PIXEL_SHADER_PROGRAM, + +      /* Declare incoming diffuse color: +       */ +      (D0_DCL | D0_DECL_REG(REG_T_DIFFUSE) | D0_CHANNEL_ALL), +      D1_MBZ, +      D2_MBZ, + +      /* output-color = mov(t_diffuse) +       */ +      (A0_MOV | +       A0_DEST_REG(REG_OC) | +       A0_DEST_CHANNEL_ALL | A0_SRC0_REG(REG_T_DIFFUSE)), +      (A1_SRC0_XYZW), +      0, +   }; + + +   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; +} + +static void +meta_texture_blend_replace(struct intel_context *intel) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); + +   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 GLboolean +meta_tex_rect_source(struct intel_context *intel, +                     struct _DriBufferObject *buffer, +                     GLuint offset, +                     GLuint pitch, GLuint height, GLenum format, GLenum type) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); +   GLuint unit = 0; +   GLint numLevels = 1; +   GLuint *state = i915->meta.Tex[0]; +   GLuint textureFormat; +   GLuint cpp; + +   /* A full implementation of this would do the upload through +    * glTexImage2d, and get all the conversion operations at that +    * point.  We are restricted, but still at least have access to the +    * fragment program swizzle. +    */ +   switch (format) { +   case GL_BGRA: +      switch (type) { +      case GL_UNSIGNED_INT_8_8_8_8_REV: +      case GL_UNSIGNED_BYTE: +         textureFormat = (MAPSURF_32BIT | MT_32BIT_ARGB8888); +         cpp = 4; +         break; +      default: +         return GL_FALSE; +      } +      break; +   case GL_RGBA: +      switch (type) { +      case GL_UNSIGNED_INT_8_8_8_8_REV: +      case GL_UNSIGNED_BYTE: +         textureFormat = (MAPSURF_32BIT | MT_32BIT_ABGR8888); +         cpp = 4; +         break; +      default: +         return GL_FALSE; +      } +      break; +   case GL_BGR: +      switch (type) { +      case GL_UNSIGNED_SHORT_5_6_5_REV: +         textureFormat = (MAPSURF_16BIT | MT_16BIT_RGB565); +         cpp = 2; +         break; +      default: +         return GL_FALSE; +      } +      break; +   case GL_RGB: +      switch (type) { +      case GL_UNSIGNED_SHORT_5_6_5: +         textureFormat = (MAPSURF_16BIT | MT_16BIT_RGB565); +         cpp = 2; +         break; +      default: +         return GL_FALSE; +      } +      break; + +   default: +      return GL_FALSE; +   } + + +   if ((pitch * cpp) & 3) { +      _mesa_printf("%s: texture is not dword pitch\n", __FUNCTION__); +      return GL_FALSE; +   } + +/*    intel_region_release(&i915->meta.tex_region[0]); */ +/*    intel_region_reference(&i915->meta.tex_region[0], region); */ +   i915->meta.tex_buffer[0] = buffer; +   i915->meta.tex_offset[0] = offset; + +   state[I915_TEXREG_MS3] = (((height - 1) << MS3_HEIGHT_SHIFT) | +                             ((pitch - 1) << MS3_WIDTH_SHIFT) | +                             textureFormat | MS3_USE_FENCE_REGS); + +   state[I915_TEXREG_MS4] = (((((pitch * cpp) / 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 << SS3_TEXTUREMAP_INDEX_SHIFT)); + +   state[I915_TEXREG_SS4] = 0; + +   i915->meta.emitted &= ~I915_UPLOAD_TEX(0); +   return GL_TRUE; +} + + +/** + * Set the color and depth drawing region for meta ops. + */ +static void +meta_draw_region(struct intel_context *intel, +                 struct intel_region *color_region, +                 struct intel_region *depth_region) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); +   i915_state_draw_region(intel, &i915->meta, color_region, depth_region); +} + + +static void +set_vertex_format(struct intel_context *intel) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); + +   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_XYZ); + +   i915->meta.emitted &= ~I915_UPLOAD_CTX; +} + + + +/* 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 +install_meta_state(struct intel_context *intel) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); +   memcpy(&i915->meta, &i915->initial, sizeof(i915->meta)); +   i915->meta.active = ACTIVE; +   i915->meta.emitted = 0; + +   SET_STATE(i915, meta); +   set_vertex_format(intel); +   meta_no_texture(intel); +} + +static void +leave_meta_state(struct intel_context *intel) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); +   intel_region_release(&i915->meta.draw_region); +   intel_region_release(&i915->meta.depth_region); +/*    intel_region_release(&i915->meta.tex_region[0]); */ +   SET_STATE(i915, state); +} + + + +void +i915InitMetaFuncs(struct i915_context *i915) +{ +   i915->intel.vtbl.install_meta_state = install_meta_state; +   i915->intel.vtbl.leave_meta_state = leave_meta_state; +   i915->intel.vtbl.meta_no_depth_write = meta_no_depth_write; +   i915->intel.vtbl.meta_no_stencil_write = meta_no_stencil_write; +   i915->intel.vtbl.meta_stencil_replace = meta_stencil_replace; +   i915->intel.vtbl.meta_depth_replace = meta_depth_replace; +   i915->intel.vtbl.meta_color_mask = meta_color_mask; +   i915->intel.vtbl.meta_no_texture = meta_no_texture; +   i915->intel.vtbl.meta_texture_blend_replace = meta_texture_blend_replace; +   i915->intel.vtbl.meta_tex_rect_source = meta_tex_rect_source; +   i915->intel.vtbl.meta_draw_region = meta_draw_region; +   i915->intel.vtbl.meta_import_pixel_state = meta_import_pixel_state; +} diff --git a/src/mesa/drivers/dri/i915tex/i915_program.c b/src/mesa/drivers/dri/i915tex/i915_program.c new file mode 100644 index 0000000000..4fb56222c6 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i915_program.c @@ -0,0 +1,518 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#include <strings.h> + +#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_SRC0_SHIFT_RIGHT) +#define A1_SRC1( reg ) (((reg)&UREG_MASK)>>UREG_A1_SRC1_SHIFT_LEFT) +#define A2_SRC1( reg ) (((reg)&UREG_MASK)<<UREG_A2_SRC1_SHIFT_RIGHT) +#define A2_SRC2( 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)<<T0_SAMPLER_NR_SHIFT) +#define T1_ADDRESS_REG( reg ) ((GET_UREG_NR(reg)<<T1_ADDRESS_REG_NR_SHIFT) | \ +			       (GET_UREG_TYPE(reg)<<T1_ADDRESS_REG_TYPE_SHIFT)) + + +/* Macros for translating UREG's into the various register fields used + * by the I915 programmable unit. + */ +#define UREG_A0_DEST_SHIFT_LEFT  (UREG_TYPE_SHIFT - A0_DEST_TYPE_SHIFT) +#define UREG_A0_SRC0_SHIFT_LEFT  (UREG_TYPE_SHIFT - A0_SRC0_TYPE_SHIFT) +#define UREG_A1_SRC0_SHIFT_RIGHT (A1_SRC0_CHANNEL_W_SHIFT - UREG_CHANNEL_W_SHIFT) +#define UREG_A1_SRC1_SHIFT_LEFT  (UREG_TYPE_SHIFT - A1_SRC1_TYPE_SHIFT) +#define UREG_A2_SRC1_SHIFT_RIGHT (A2_SRC1_CHANNEL_W_SHIFT - UREG_CHANNEL_W_SHIFT) +#define UREG_A2_SRC2_SHIFT_LEFT  (UREG_TYPE_SHIFT - A2_SRC2_TYPE_SHIFT) + +#define UREG_MASK         0xffffff00 +#define UREG_TYPE_NR_MASK ((REG_TYPE_MASK << UREG_TYPE_SHIFT) | \ +  			   (REG_NR_MASK << UREG_NR_SHIFT)) + + +#define I915_CONSTFLAG_PARAM 0x1f + +GLuint +i915_get_temp(struct i915_fragment_program *p) +{ +   int bit = ffs(~p->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 << nr)) +         return reg; + +      p->decl_t |= (1 << nr); +   } +   else if (type == REG_TYPE_S) { +      if (p->decl_s & (1 << nr)) +         return reg; + +      p->decl_s |= (1 << nr); +   } +   else +      return reg; + +   *(p->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); +   dest = UREG(GET_UREG_TYPE(dest), GET_UREG_NR(dest)); +   assert(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 ) +{ +   if (coord != UREG(GET_UREG_TYPE(coord), GET_UREG_NR(coord))) { +      /* No real way to work around this in the general case - need to +       * allocate and declare a new temporary register (a utemp won't +       * do).  Will fallback for now. +       */ +      i915_program_error(p, "Can't (yet) swizzle TEX arguments"); +      return 0; +   } + +   /* Don't worry about saturate as we only support   +    */ +   if (destmask != A0_DEST_CHANNEL_ALL) { +      GLuint tmp = i915_get_utemp(p); +      i915_emit_texld( p, tmp, A0_DEST_CHANNEL_ALL, sampler, coord, op ); +      i915_emit_arith( p, A0_MOV, dest, destmask, 0, tmp, 0, 0 ); +      return dest; +   } +   else { +      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 ) | +		     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 << idx)) || +             p->constant[reg][idx] == c0) { +            p->constant[reg][idx] = c0; +            p->constant_flags[reg] |= 1 << idx; +            if (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 << idx))) { +            p->constant[reg][idx] = c0; +            p->constant[reg][idx + 1] = c1; +            p->constant_flags[reg] |= 3 << idx; +            if (reg + 1 > 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 char *msg) +{ +   /* XXX we shouldn't print anything to stdout, record GL error or +    * call _mesa_problem() +    */ +   fprintf(stderr, "%s\n", msg); +   p->error = 1; +} + +void +i915_init_program(struct i915_context *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 = -1; +   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"); + +   if (p->error) { +      p->FragProg.Base.NumNativeInstructions = 0; +      p->FragProg.NumNativeAluInstructions = 0; +      p->FragProg.NumNativeTexInstructions = 0; +      p->FragProg.NumNativeTexIndirections = 0; +   } +   else { +      p->FragProg.Base.NumNativeInstructions = (p->nr_alu_insn + +                                                p->nr_tex_insn + +                                                p->nr_decl_insn); +      p->FragProg.NumNativeAluInstructions = p->nr_alu_insn; +      p->FragProg.NumNativeTexInstructions = p->nr_tex_insn; +      p->FragProg.NumNativeTexIndirections = p->nr_tex_indirect; +   } + +   p->declarations[0] |= program_size + decl_size - 2; +} + +void +i915_upload_program(struct i915_context *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/i915tex/i915_program.h b/src/mesa/drivers/dri/i915tex/i915_program.h new file mode 100644 index 0000000000..3c12b34f16 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i915_program.h @@ -0,0 +1,160 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + + +#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) << UREG_CHANNEL_X_NEGATE_SHIFT) | +                 ((y & 1) << UREG_CHANNEL_Y_NEGATE_SHIFT) | +                 ((z & 1) << UREG_CHANNEL_Z_NEGATE_SHIFT) | +                 ((w & 1) << UREG_CHANNEL_W_NEGATE_SHIFT)); +} + + +extern GLuint i915_get_temp(struct i915_fragment_program *p); +extern GLuint i915_get_utemp(struct i915_fragment_program *p); +extern void i915_release_utemps(struct i915_fragment_program *p); + + +extern GLuint i915_emit_texld(struct i915_fragment_program *p, +                              GLuint dest, +                              GLuint destmask, +                              GLuint sampler, GLuint coord, GLuint op); + +extern GLuint i915_emit_arith(struct i915_fragment_program *p, +                              GLuint op, +                              GLuint dest, +                              GLuint mask, +                              GLuint saturate, +                              GLuint src0, GLuint src1, GLuint src2); + +extern GLuint i915_emit_decl(struct i915_fragment_program *p, +                             GLuint type, GLuint nr, GLuint d0_flags); + + +extern GLuint i915_emit_const1f(struct i915_fragment_program *p, GLfloat c0); + +extern GLuint i915_emit_const2f(struct i915_fragment_program *p, +                                GLfloat c0, GLfloat c1); + +extern GLuint i915_emit_const4fv(struct i915_fragment_program *p, +                                 const GLfloat * c); + +extern GLuint i915_emit_const4f(struct i915_fragment_program *p, +                                GLfloat c0, GLfloat c1, +                                GLfloat c2, GLfloat c3); + + +extern GLuint i915_emit_param4fv(struct i915_fragment_program *p, +                                 const GLfloat * values); + +extern void i915_program_error(struct i915_fragment_program *p, +                               const char *msg); + +extern void i915_init_program(struct i915_context *i915, +                              struct i915_fragment_program *p); + +extern void i915_upload_program(struct i915_context *i915, +                                struct i915_fragment_program *p); + +extern void i915_fini_program(struct i915_fragment_program *p); + + + + +#endif diff --git a/src/mesa/drivers/dri/i915tex/i915_reg.h b/src/mesa/drivers/dri/i915tex/i915_reg.h new file mode 100644 index 0000000000..04b199905c --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i915_reg.h @@ -0,0 +1,841 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + + +#ifndef _I915_REG_H_ +#define _I915_REG_H_ + + +#include "intel_reg.h" + +#define I915_SET_FIELD( var, mask, value ) (var &= ~(mask), var |= value) + +#define CMD_3D (0x3<<29) + +#define PRIM3D_INLINE		(CMD_3D | (0x1f<<24)) +#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_CLEAR_RECT	(0xa<<18) +#define PRIM3D_ZONE_INIT	(0xd<<18) +#define PRIM3D_MASK		(0x1f<<18) + +/* p137 */ +#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) + +/* 3DSTATE_BACKFACE_STENCIL_OPS, p138*/ +#define _3DSTATE_BACKFACE_STENCIL_OPS    (CMD_3D | (0x8<<24)) +#define BFO_ENABLE_STENCIL_REF          (1<<23) +#define BFO_STENCIL_REF_SHIFT           15 +#define BFO_STENCIL_REF_MASK            (0xff<<15) +#define BFO_ENABLE_STENCIL_FUNCS        (1<<14) +#define BFO_STENCIL_TEST_SHIFT          11 +#define BFO_STENCIL_TEST_MASK           (0x7<<11) +#define BFO_STENCIL_FAIL_SHIFT          8 +#define BFO_STENCIL_FAIL_MASK           (0x7<<8) +#define BFO_STENCIL_PASS_Z_FAIL_SHIFT   5 +#define BFO_STENCIL_PASS_Z_FAIL_MASK    (0x7<<5) +#define BFO_STENCIL_PASS_Z_PASS_SHIFT   2 +#define BFO_STENCIL_PASS_Z_PASS_MASK    (0x7<<2) +#define BFO_ENABLE_STENCIL_TWO_SIDE     (1<<1) +#define BFO_STENCIL_TWO_SIDE            (1<<0) + + +/* 3DSTATE_BACKFACE_STENCIL_MASKS, p140 */ +#define _3DSTATE_BACKFACE_STENCIL_MASKS    (CMD_3D | (0x9<<24)) +#define BFM_ENABLE_STENCIL_TEST_MASK      (1<<17) +#define BFM_ENABLE_STENCIL_WRITE_MASK     (1<<16) +#define BFM_STENCIL_TEST_MASK_SHIFT       8 +#define BFM_STENCIL_TEST_MASK_MASK        (0xff<<8) +#define BFM_STENCIL_WRITE_MASK_SHIFT      0 +#define BFM_STENCIL_WRITE_MASK_MASK       (0xff<<0) + + + +/* 3DSTATE_BIN_CONTROL p141 */ + +/* p143 */ +#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) + + +/* 3DSTATE_CHROMA_KEY */ + +/* 3DSTATE_CLEAR_PARAMETERS, p150 */ + +/* 3DSTATE_CONSTANT_BLEND_COLOR, p153 */ +#define _3DSTATE_CONST_BLEND_COLOR_CMD	(CMD_3D | (0x1d<<24) | (0x88<<16)) + + + +/* 3DSTATE_COORD_SET_BINDINGS, p154 */ +#define _3DSTATE_COORD_SET_BINDINGS      (CMD_3D | (0x16<<24)) +#define CSB_TCB(iunit, eunit)           ((eunit)<<(iunit*3)) + +/* p156 */ +#define _3DSTATE_DFLT_DIFFUSE_CMD	(CMD_3D | (0x1d<<24) | (0x99<<16)) + +/* p157 */ +#define _3DSTATE_DFLT_SPEC_CMD		(CMD_3D | (0x1d<<24) | (0x9a<<16)) + +/* p158 */ +#define _3DSTATE_DFLT_Z_CMD		(CMD_3D | (0x1d<<24) | (0x98<<16)) + + +/* 3DSTATE_DEPTH_OFFSET_SCALE, p159 */ +#define _3DSTATE_DEPTH_OFFSET_SCALE       (CMD_3D | (0x1d<<24) | (0x97<<16)) +/* scale in dword 1 */ + + +/* 3DSTATE_DEPTH_SUBRECT_DISABLE, p160 */ +#define _3DSTATE_DEPTH_SUBRECT_DISABLE    (CMD_3D | (0x1c<<24) | (0x11<19) | 0x2) + +/* p161 */ +#define _3DSTATE_DST_BUF_VARS_CMD	(CMD_3D | (0x1d<<24) | (0x85<<16)) +/* Dword 1 */ +#define TEX_DEFAULT_COLOR_OGL           (0<<30) +#define TEX_DEFAULT_COLOR_D3D           (1<<30) +#define ZR_EARLY_DEPTH                  (1<<29) +#define LOD_PRECLAMP_OGL                (1<<28) +#define LOD_PRECLAMP_D3D                (0<<28) +#define DITHER_FULL_ALWAYS              (0<<26) +#define DITHER_FULL_ON_FB_BLEND         (1<<26) +#define DITHER_CLAMPED_ALWAYS           (2<<26) +#define LINEAR_GAMMA_BLEND_32BPP        (1<<25) +#define DEBUG_DISABLE_ENH_DITHER        (1<<24) +#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_FRMT_16_FIXED		0 +#define DEPTH_FRMT_16_FLOAT		(1<<2) +#define DEPTH_FRMT_24_FIXED_8_OTHER	(2<<2) +#define VERT_LINE_STRIDE_1		(1<<1) +#define VERT_LINE_STRIDE_0		(0<<1) +#define VERT_LINE_STRIDE_OFS_1		1 +#define VERT_LINE_STRIDE_OFS_0		0 + +/* p166 */ +#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) + + +/* 3DSTATE_FILTER_COEFFICIENTS_4X4, p170 */ + +/* 3DSTATE_FILTER_COEFFICIENTS_6X5, p172 */ + + +/* _3DSTATE_FOG_COLOR, p173 */ +#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, p174 */ +#define _3DSTATE_FOG_MODE_CMD		(CMD_3D|(0x1d<<24)|(0x89<<16)|2) +/* Dword 1 */ +#define FMC1_FOGFUNC_MODIFY_ENABLE	(1<<31) +#define FMC1_FOGFUNC_VERTEX		(0<<28) +#define FMC1_FOGFUNC_PIXEL_EXP		(1<<28) +#define FMC1_FOGFUNC_PIXEL_EXP2		(2<<28) +#define FMC1_FOGFUNC_PIXEL_LINEAR	(3<<28) +#define FMC1_FOGFUNC_MASK		(3<<28) +#define FMC1_FOGINDEX_MODIFY_ENABLE     (1<<27) +#define FMC1_FOGINDEX_Z		        (0<<25) +#define FMC1_FOGINDEX_W   		(1<<25) +#define FMC1_C1_C2_MODIFY_ENABLE	(1<<24) +#define FMC1_DENSITY_MODIFY_ENABLE	(1<<23) +#define FMC1_C1_ONE      	        (1<<13) +#define FMC1_C1_MASK		        (0xffff<<4) +/* Dword 2 */ +#define FMC2_C2_ONE		        (1<<16) +/* Dword 3 */ +#define FMC3_D_ONE      		(1<<16) + + + +/* _3DSTATE_INDEPENDENT_ALPHA_BLEND, p177 */ +#define _3DSTATE_INDEPENDENT_ALPHA_BLEND_CMD	(CMD_3D|(0x0b<<24)) +#define IAB_MODIFY_ENABLE	        (1<<23) +#define IAB_ENABLE       	        (1<<22) +#define IAB_MODIFY_FUNC         	(1<<21) +#define IAB_FUNC_SHIFT          	16 +#define IAB_MODIFY_SRC_FACTOR   	(1<<11) +#define IAB_SRC_FACTOR_SHIFT		6 +#define IAB_SRC_FACTOR_MASK		(BLENDFACT_MASK<<6) +#define IAB_MODIFY_DST_FACTOR	        (1<<5) +#define IAB_DST_FACTOR_SHIFT		0 +#define IAB_DST_FACTOR_MASK		(BLENDFACT_MASK<<0) + + +#define BLENDFUNC_ADD			0x0 +#define BLENDFUNC_SUBTRACT		0x1 +#define BLENDFUNC_REVERSE_SUBTRACT	0x2 +#define BLENDFUNC_MIN			0x3 +#define BLENDFUNC_MAX			0x4 +#define BLENDFUNC_MASK			0x7 + +/* 3DSTATE_LOAD_INDIRECT, p180 */ + +#define _3DSTATE_LOAD_INDIRECT	        (CMD_3D|(0x1d<<24)|(0x7<<16)) +#define LI0_STATE_STATIC_INDIRECT       (0x01<<8) +#define LI0_STATE_DYNAMIC_INDIRECT      (0x02<<8) +#define LI0_STATE_SAMPLER               (0x04<<8) +#define LI0_STATE_MAP                   (0x08<<8) +#define LI0_STATE_PROGRAM               (0x10<<8) +#define LI0_STATE_CONSTANTS             (0x20<<8) + +#define SIS0_BUFFER_ADDRESS(x)          ((x)&~0x3) +#define SIS0_FORCE_LOAD                 (1<<1) +#define SIS0_BUFFER_VALID               (1<<0) +#define SIS1_BUFFER_LENGTH(x)           ((x)&0xff) + +#define DIS0_BUFFER_ADDRESS(x)          ((x)&~0x3) +#define DIS0_BUFFER_RESET               (1<<1) +#define DIS0_BUFFER_VALID               (1<<0) + +#define SSB0_BUFFER_ADDRESS(x)          ((x)&~0x3) +#define SSB0_FORCE_LOAD                 (1<<1) +#define SSB0_BUFFER_VALID               (1<<0) +#define SSB1_BUFFER_LENGTH(x)           ((x)&0xff) + +#define MSB0_BUFFER_ADDRESS(x)          ((x)&~0x3) +#define MSB0_FORCE_LOAD                 (1<<1) +#define MSB0_BUFFER_VALID               (1<<0) +#define MSB1_BUFFER_LENGTH(x)           ((x)&0xff) + +#define PSP0_BUFFER_ADDRESS(x)          ((x)&~0x3) +#define PSP0_FORCE_LOAD                 (1<<1) +#define PSP0_BUFFER_VALID               (1<<0) +#define PSP1_BUFFER_LENGTH(x)           ((x)&0xff) + +#define PSC0_BUFFER_ADDRESS(x)          ((x)&~0x3) +#define PSC0_FORCE_LOAD                 (1<<1) +#define PSC0_BUFFER_VALID               (1<<0) +#define PSC1_BUFFER_LENGTH(x)           ((x)&0xff) + + + + + +/* _3DSTATE_RASTERIZATION_RULES */ +#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_TEXKILL_3D_4D            (1<<10) +#define TEXKILL_3D                      (0<<9) +#define TEXKILL_4D                      (1<<9) +#define ENABLE_LINE_STRIP_PROVOKE_VRTX	(1<<8) +#define ENABLE_TRI_FAN_PROVOKE_VRTX	(1<<5) +#define LINE_STRIP_PROVOKE_VRTX(x)	((x)<<6) +#define TRI_FAN_PROVOKE_VRTX(x) 	((x)<<3) + +/* _3DSTATE_SCISSOR_ENABLE, p256 */ +#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, p257 */ +#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) + +/* p189 */ +#define _3DSTATE_LOAD_STATE_IMMEDIATE_1   ((0x3<<29)|(0x1d<<24)|(0x04<<16)) +#define I1_LOAD_S(n)                      (1<<(4+n)) + +#define S0_VB_OFFSET_MASK              0xffffffc +#define S0_AUTO_CACHE_INV_DISABLE      (1<<0) + +#define S1_VERTEX_WIDTH_SHIFT          24 +#define S1_VERTEX_WIDTH_MASK           (0x3f<<24) +#define S1_VERTEX_PITCH_SHIFT          16 +#define S1_VERTEX_PITCH_MASK           (0x3f<<16) + +#define TEXCOORDFMT_2D                 0x0 +#define TEXCOORDFMT_3D                 0x1 +#define TEXCOORDFMT_4D                 0x2 +#define TEXCOORDFMT_1D                 0x3 +#define TEXCOORDFMT_2D_16              0x4 +#define TEXCOORDFMT_4D_16              0x5 +#define TEXCOORDFMT_NOT_PRESENT        0xf +#define S2_TEXCOORD_FMT0_MASK            0xf +#define S2_TEXCOORD_FMT1_SHIFT           4 +#define S2_TEXCOORD_FMT(unit, type)    ((type)<<(unit*4)) +#define S2_TEXCOORD_NONE               (~0) + +/* S3 not interesting */ + +#define S4_POINT_WIDTH_SHIFT           23 +#define S4_POINT_WIDTH_MASK            (0x1ff<<23) +#define S4_LINE_WIDTH_SHIFT            19 +#define S4_LINE_WIDTH_ONE              (0x2<<19) +#define S4_LINE_WIDTH_MASK             (0xf<<19) +#define S4_FLATSHADE_ALPHA             (1<<18) +#define S4_FLATSHADE_FOG               (1<<17) +#define S4_FLATSHADE_SPECULAR          (1<<16) +#define S4_FLATSHADE_COLOR             (1<<15) +#define S4_CULLMODE_BOTH	       (0<<13) +#define S4_CULLMODE_NONE	       (1<<13) +#define S4_CULLMODE_CW		       (2<<13) +#define S4_CULLMODE_CCW		       (3<<13) +#define S4_CULLMODE_MASK	       (3<<13) +#define S4_VFMT_POINT_WIDTH            (1<<12) +#define S4_VFMT_SPEC_FOG               (1<<11) +#define S4_VFMT_COLOR                  (1<<10) +#define S4_VFMT_DEPTH_OFFSET           (1<<9) +#define S4_VFMT_XYZ     	       (1<<6) +#define S4_VFMT_XYZW     	       (2<<6) +#define S4_VFMT_XY     		       (3<<6) +#define S4_VFMT_XYW     	       (4<<6) +#define S4_VFMT_XYZW_MASK              (7<<6) +#define S4_FORCE_DEFAULT_DIFFUSE       (1<<5) +#define S4_FORCE_DEFAULT_SPECULAR      (1<<4) +#define S4_LOCAL_DEPTH_OFFSET_ENABLE   (1<<3) +#define S4_VFMT_FOG_PARAM              (1<<2) +#define S4_SPRITE_POINT_ENABLE         (1<<1) +#define S4_LINE_ANTIALIAS_ENABLE       (1<<0) + +#define S4_VFMT_MASK (S4_VFMT_POINT_WIDTH   | 	\ +		      S4_VFMT_SPEC_FOG      |	\ +		      S4_VFMT_COLOR         |	\ +		      S4_VFMT_DEPTH_OFFSET  |	\ +		      S4_VFMT_XYZW_MASK     |	\ +		      S4_VFMT_FOG_PARAM) + + +#define S5_WRITEDISABLE_ALPHA          (1<<31) +#define S5_WRITEDISABLE_RED            (1<<30) +#define S5_WRITEDISABLE_GREEN          (1<<29) +#define S5_WRITEDISABLE_BLUE           (1<<28) +#define S5_WRITEDISABLE_MASK           (0xf<<28) +#define S5_FORCE_DEFAULT_POINT_SIZE    (1<<27) +#define S5_LAST_PIXEL_ENABLE           (1<<26) +#define S5_GLOBAL_DEPTH_OFFSET_ENABLE  (1<<25) +#define S5_FOG_ENABLE                  (1<<24) +#define S5_STENCIL_REF_SHIFT           16 +#define S5_STENCIL_REF_MASK            (0xff<<16) +#define S5_STENCIL_TEST_FUNC_SHIFT     13 +#define S5_STENCIL_TEST_FUNC_MASK      (0x7<<13) +#define S5_STENCIL_FAIL_SHIFT          10 +#define S5_STENCIL_FAIL_MASK           (0x7<<10) +#define S5_STENCIL_PASS_Z_FAIL_SHIFT   7 +#define S5_STENCIL_PASS_Z_FAIL_MASK    (0x7<<7) +#define S5_STENCIL_PASS_Z_PASS_SHIFT   4 +#define S5_STENCIL_PASS_Z_PASS_MASK    (0x7<<4) +#define S5_STENCIL_WRITE_ENABLE        (1<<3) +#define S5_STENCIL_TEST_ENABLE         (1<<2) +#define S5_COLOR_DITHER_ENABLE         (1<<1) +#define S5_LOGICOP_ENABLE              (1<<0) + + +#define S6_ALPHA_TEST_ENABLE           (1<<31) +#define S6_ALPHA_TEST_FUNC_SHIFT       28 +#define S6_ALPHA_TEST_FUNC_MASK        (0x7<<28) +#define S6_ALPHA_REF_SHIFT             20 +#define S6_ALPHA_REF_MASK              (0xff<<20) +#define S6_DEPTH_TEST_ENABLE           (1<<19) +#define S6_DEPTH_TEST_FUNC_SHIFT       16 +#define S6_DEPTH_TEST_FUNC_MASK        (0x7<<16) +#define S6_CBUF_BLEND_ENABLE           (1<<15) +#define S6_CBUF_BLEND_FUNC_SHIFT       12 +#define S6_CBUF_BLEND_FUNC_MASK        (0x7<<12) +#define S6_CBUF_SRC_BLEND_FACT_SHIFT   8 +#define S6_CBUF_SRC_BLEND_FACT_MASK    (0xf<<8) +#define S6_CBUF_DST_BLEND_FACT_SHIFT   4 +#define S6_CBUF_DST_BLEND_FACT_MASK    (0xf<<4) +#define S6_DEPTH_WRITE_ENABLE          (1<<3) +#define S6_COLOR_WRITE_ENABLE          (1<<2) +#define S6_TRISTRIP_PV_SHIFT           0 +#define S6_TRISTRIP_PV_MASK            (0x3<<0) + +#define S7_DEPTH_OFFSET_CONST_MASK     ~0 + +/* 3DSTATE_MAP_DEINTERLACER_PARAMETERS */ + +/* 3DSTATE_MAP_PALETTE_LOAD_32, p206 */ +#define _3DSTATE_MAP_PALETTE_LOAD_32    (CMD_3D|(0x1d<<24)|(0x8f<<16)) +/* subsequent dwords up to length (max 16) are ARGB8888 color values */ + +/* _3DSTATE_MODES_4, p218 */ +#define _3DSTATE_MODES_4_CMD		(CMD_3D|(0x0d<<24)) +#define ENABLE_LOGIC_OP_FUNC		(1<<23) +#define LOGIC_OP_FUNC(x)		((x)<<18) +#define LOGICOP_MASK			(0xf<<18) +#define MODE4_ENABLE_STENCIL_TEST_MASK	((1<<17)|(0xff00)) +#define ENABLE_STENCIL_TEST_MASK	(1<<17) +#define STENCIL_TEST_MASK(x)		(((x)&0xff)<<8) +#define MODE4_ENABLE_STENCIL_WRITE_MASK	((1<<16)|(0x00ff)) +#define ENABLE_STENCIL_WRITE_MASK	(1<<16) +#define STENCIL_WRITE_MASK(x)		((x)&0xff) + +/* _3DSTATE_MODES_5, p220 */ +#define _3DSTATE_MODES_5_CMD		(CMD_3D|(0x0c<<24)) +#define PIPELINE_FLUSH_RENDER_CACHE	(1<<18) +#define PIPELINE_FLUSH_TEXTURE_CACHE	(1<<16) + + +/* p221 */ +#define _3DSTATE_PIXEL_SHADER_CONSTANTS  (CMD_3D|(0x1d<<24)|(0x6<<16)) +#define PS1_REG(n)                      (1<<(n)) +#define PS2_CONST_X(n)                  (n) +#define PS3_CONST_Y(n)                  (n) +#define PS4_CONST_Z(n)                  (n) +#define PS5_CONST_W(n)                  (n) + +/* p222 */ + + +#define I915_MAX_TEX_INDIRECT 4 +#define I915_MAX_TEX_INSN     32 +#define I915_MAX_ALU_INSN     64 +#define I915_MAX_DECL_INSN    27 +#define I915_MAX_TEMPORARY    16 + + +/* Each instruction is 3 dwords long, though most don't require all + * this space.  Maximum of 123 instructions.  Smaller maxes per insn + * type. + */ +#define _3DSTATE_PIXEL_SHADER_PROGRAM    (CMD_3D|(0x1d<<24)|(0x5<<16)) + +#define REG_TYPE_R                 0    /* temporary regs, no need to +                                         * dcl, must be written before +                                         * read -- Preserved between +                                         * phases.  +                                         */ +#define REG_TYPE_T                 1    /* Interpolated values, must be +                                         * dcl'ed before use. +                                         * +                                         * 0..7: texture coord, +                                         * 8: diffuse spec, +                                         * 9: specular color, +                                         * 10: fog parameter in w. +                                         */ +#define REG_TYPE_CONST             2    /* Restriction: only one const +                                         * can be referenced per +                                         * instruction, though it may be +                                         * selected for multiple inputs. +                                         * Constants not initialized +                                         * default to zero. +                                         */ +#define REG_TYPE_S                 3    /* sampler */ +#define REG_TYPE_OC                4    /* output color (rgba) */ +#define REG_TYPE_OD                5    /* output depth (w), xyz are +                                         * temporaries.  If not written, +                                         * interpolated depth is used? +                                         */ +#define REG_TYPE_U                 6    /* unpreserved temporaries */ +#define REG_TYPE_MASK              0x7 +#define REG_NR_MASK                0xf + + +/* REG_TYPE_T: + */ +#define T_TEX0     0 +#define T_TEX1     1 +#define T_TEX2     2 +#define T_TEX3     3 +#define T_TEX4     4 +#define T_TEX5     5 +#define T_TEX6     6 +#define T_TEX7     7 +#define T_DIFFUSE  8 +#define T_SPECULAR 9 +#define T_FOG_W    10           /* interpolated fog is in W coord */ + +/* Arithmetic instructions */ + +/* .replicate_swizzle == selection and replication of a particular + * scalar channel, ie., .xxxx, .yyyy, .zzzz or .wwww  + */ +#define A0_NOP    (0x0<<24)     /* no operation */ +#define A0_ADD    (0x1<<24)     /* dst = src0 + src1 */ +#define A0_MOV    (0x2<<24)     /* dst = src0 */ +#define A0_MUL    (0x3<<24)     /* dst = src0 * src1 */ +#define A0_MAD    (0x4<<24)     /* dst = src0 * src1 + src2 */ +#define A0_DP2ADD (0x5<<24)     /* dst.xyzw = src0.xy dot src1.xy + src2.replicate_swizzle */ +#define A0_DP3    (0x6<<24)     /* dst.xyzw = src0.xyz dot src1.xyz */ +#define A0_DP4    (0x7<<24)     /* dst.xyzw = src0.xyzw dot src1.xyzw */ +#define A0_FRC    (0x8<<24)     /* dst = src0 - floor(src0) */ +#define A0_RCP    (0x9<<24)     /* dst.xyzw = 1/(src0.replicate_swizzle) */ +#define A0_RSQ    (0xa<<24)     /* dst.xyzw = 1/(sqrt(abs(src0.replicate_swizzle))) */ +#define A0_EXP    (0xb<<24)     /* dst.xyzw = exp2(src0.replicate_swizzle) */ +#define A0_LOG    (0xc<<24)     /* dst.xyzw = log2(abs(src0.replicate_swizzle)) */ +#define A0_CMP    (0xd<<24)     /* dst = (src0 >= 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_32BIT_AWVU2101010	           (0xA<<3) +#define    MT_32BIT_GR1616	           (0xB<<3) +#define    MT_32BIT_VU1616	           (0xC<<3) +#define    MT_32BIT_xI824	           (0xD<<3) +#define    MT_32BIT_xA824	           (0xE<<3) +#define    MT_32BIT_xL824	           (0xF<<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_MIP_LAYOUT_LEGACY           (0<<8) +#define MS4_MIP_LAYOUT_BELOW_LPT        (0<<8) +#define MS4_MIP_LAYOUT_RIGHT_LPT        (1<<8) +#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) +/* Shadow requires: + *  MT_X8{I,L,A}24 or MT_{I,L,A}16 texture format + *  FILTER_4X4_x  MIN and MAG filters + */ +#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) +/* SS2_SHADOW_FUNC values: see COMPAREFUNC_* */ + +#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 _3DSTATE_DEFAULT_Z          ((0x3<<29)|(0x1d<<24)|(0x98<<16)) +#define _3DSTATE_DEFAULT_DIFFUSE    ((0x3<<29)|(0x1d<<24)|(0x99<<16)) +#define _3DSTATE_DEFAULT_SPECULAR   ((0x3<<29)|(0x1d<<24)|(0x9a<<16)) + + +#define MI_FLUSH                   ((0<<29)|(4<<23)) +#define FLUSH_MAP_CACHE            (1<<0) +#define INHIBIT_FLUSH_RENDER_CACHE (1<<2) + + +#endif diff --git a/src/mesa/drivers/dri/i915tex/i915_state.c b/src/mesa/drivers/dri/i915tex/i915_state.c new file mode 100644 index 0000000000..d68801d3f9 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i915_state.c @@ -0,0 +1,1019 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + + +#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_fbo.h" +#include "intel_screen.h" +#include "intel_batchbuffer.h" + +#include "i915_context.h" +#include "i915_reg.h" + +#define FILE_DEBUG_FLAG DEBUG_STATE + +static void +i915StencilFuncSeparate(GLcontext * ctx, GLenum face, GLenum func, GLint ref, +                        GLuint mask) +{ +   struct i915_context *i915 = I915_CONTEXT(ctx); +   int test = intel_translate_compare_func(func); + +   mask = mask & 0xff; + +   DBG("%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 +i915StencilMaskSeparate(GLcontext * ctx, GLenum face, GLuint mask) +{ +   struct i915_context *i915 = I915_CONTEXT(ctx); + +   DBG("%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 void +i915StencilOpSeparate(GLcontext * ctx, GLenum face, GLenum fail, GLenum zfail, +                      GLenum zpass) +{ +   struct i915_context *i915 = I915_CONTEXT(ctx); +   int fop = intel_translate_stencil_op(fail); +   int dfop = intel_translate_stencil_op(zfail); +   int dpop = intel_translate_stencil_op(zpass); + + +   DBG("%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) +{ +   struct i915_context *i915 = I915_CONTEXT(ctx); +   int test = intel_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) +{ +   struct i915_context *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]) +{ +   struct i915_context *i915 = I915_CONTEXT(ctx); +   GLubyte r, g, b, a; + +   DBG("%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; +} + + +#define DST_BLND_FACT(f) ((f)<<S6_CBUF_DST_BLEND_FACT_SHIFT) +#define SRC_BLND_FACT(f) ((f)<<S6_CBUF_SRC_BLEND_FACT_SHIFT) +#define DST_ABLND_FACT(f) ((f)<<IAB_DST_FACTOR_SHIFT) +#define SRC_ABLND_FACT(f) ((f)<<IAB_SRC_FACTOR_SHIFT) + + + +static GLuint +translate_blend_equation(GLenum mode) +{ +   switch (mode) { +   case GL_FUNC_ADD: +      return BLENDFUNC_ADD; +   case GL_MIN: +      return BLENDFUNC_MIN; +   case GL_MAX: +      return BLENDFUNC_MAX; +   case GL_FUNC_SUBTRACT: +      return BLENDFUNC_SUBTRACT; +   case GL_FUNC_REVERSE_SUBTRACT: +      return BLENDFUNC_REVERSE_SUBTRACT; +   default: +      return 0; +   } +} + +static void +i915UpdateBlendState(GLcontext * ctx) +{ +   struct i915_context *i915 = I915_CONTEXT(ctx); +   GLuint iab = (i915->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(intel_translate_blend_factor(srcRGB)); +   lis6 |= DST_BLND_FACT(intel_translate_blend_factor(dstRGB)); +   lis6 |= translate_blend_equation(eqRGB) << S6_CBUF_BLEND_FUNC_SHIFT; + +   iab |= SRC_ABLND_FACT(intel_translate_blend_factor(srcA)); +   iab |= DST_ABLND_FACT(intel_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) +{ +   struct i915_context *i915 = I915_CONTEXT(ctx); +   int test = intel_translate_compare_func(func); + +   DBG("%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) +{ +   struct i915_context *i915 = I915_CONTEXT(ctx); + +   DBG("%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) +{ +   struct i915_context *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) +{ +   struct i915_context *i915 = I915_CONTEXT(ctx); +   int x1, y1, x2, y2; + +   if (!ctx->DrawBuffer) +      return; + +   DBG("%s %d,%d %dx%d\n", __FUNCTION__, x, y, w, h); + +   if (ctx->DrawBuffer->Name == 0) { +      x1 = x; +      y1 = ctx->DrawBuffer->Height - (y + h); +      x2 = x + w - 1; +      y2 = y1 + h - 1; +      DBG("%s %d..%d,%d..%d (inverted)\n", __FUNCTION__, x1, x2, y1, y2); +   } +   else { +      /* FBO - not inverted +       */ +      x1 = x; +      y1 = y; +      x2 = x + w - 1; +      y2 = y + h - 1; +      DBG("%s %d..%d,%d..%d (not inverted)\n", __FUNCTION__, x1, x2, y1, y2); +   } +    +   x1 = CLAMP(x1, 0, ctx->DrawBuffer->Width - 1); +   y1 = CLAMP(y1, 0, ctx->DrawBuffer->Height - 1); +   x2 = CLAMP(x2, 0, ctx->DrawBuffer->Width - 1); +   y2 = CLAMP(y2, 0, ctx->DrawBuffer->Height - 1); +    +   DBG("%s %d..%d,%d..%d (clamped)\n", __FUNCTION__, x1, x2, y1, y2); + +   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) +{ +   struct i915_context *i915 = I915_CONTEXT(ctx); +   int tmp = intel_translate_logic_op(opcode); + +   DBG("%s\n", __FUNCTION__); +    +   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) +{ +   struct i915_context *i915 = I915_CONTEXT(ctx); +   GLuint mode; + +   DBG("%s %d\n", __FUNCTION__, +       ctx->DrawBuffer ? ctx->DrawBuffer->Name : 0); + +   if (!ctx->Polygon.CullFlag) { +      mode = S4_CULLMODE_NONE; +   } +   else if (ctx->Polygon.CullFaceMode != GL_FRONT_AND_BACK) { +      mode = S4_CULLMODE_CW; + +      if (ctx->DrawBuffer && ctx->DrawBuffer->Name != 0) +         mode ^= (S4_CULLMODE_CW ^ S4_CULLMODE_CCW); +      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) +{ +   struct i915_context *i915 = I915_CONTEXT(ctx); +   int lis4 = i915->state.Ctx[I915_CTXREG_LIS4] & ~S4_LINE_WIDTH_MASK; +   int width; + +   DBG("%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) +{ +   struct i915_context *i915 = I915_CONTEXT(ctx); +   int lis4 = i915->state.Ctx[I915_CTXREG_LIS4] & ~S4_POINT_WIDTH_MASK; +   GLint point_size = (int) size; + +   DBG("%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) +{ +   struct i915_context *i915 = I915_CONTEXT(ctx); +   GLuint tmp = i915->state.Ctx[I915_CTXREG_LIS5] & ~S5_WRITEDISABLE_MASK; + +   DBG("%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) +{ +   DBG("%s\n", __FUNCTION__); +    +   if (pname == GL_LIGHT_MODEL_COLOR_CONTROL) { +      update_specular(ctx); +   } +} + +static void +i915ShadeModel(GLcontext * ctx, GLenum mode) +{ +   struct i915_context *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 + */ +void +i915_update_fog(GLcontext * ctx) +{ +   struct i915_context *i915 = I915_CONTEXT(ctx); +   GLenum mode; +   GLboolean enabled; +   GLboolean try_pixel_fog; + +   if (ctx->FragmentProgram._Active) { +      /* Pull in static fog state from program */ + +      mode = ctx->FragmentProgram._Current->FogOption; +      enabled = (mode != GL_NONE); +      try_pixel_fog = 0; +   } +   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) +{ +   struct i915_context *i915 = I915_CONTEXT(ctx); + +   switch (pname) { +   case GL_FOG_COORDINATE_SOURCE_EXT: +   case GL_FOG_MODE: +   case GL_FOG_START: +   case GL_FOG_END: +      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: +      break; +   default: +      break; +   } +} + +/* ============================================================= + */ + +static void +i915Enable(GLcontext * ctx, GLenum cap, GLboolean state) +{ +   struct i915_context *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)    /* XXX FBO fix */ +         FALLBACK(&i915->intel, I915_FALLBACK_LOGICOP, state); +      break; + +   case GL_FRAGMENT_PROGRAM_ARB: +      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: +      break; + +   case GL_CULL_FACE: +      i915CullFaceFrontFace(ctx, 0); +      break; + +   case GL_STENCIL_TEST: +      { +         GLboolean hw_stencil = GL_FALSE; +         if (ctx->DrawBuffer) { +            struct intel_renderbuffer *irbStencil +               = intel_get_renderbuffer(ctx->DrawBuffer, BUFFER_STENCIL); +            hw_stencil = (irbStencil && irbStencil->region); +         } +         if (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; + +   case GL_POLYGON_SMOOTH: +      break; + +   case GL_POINT_SMOOTH: +      break; + +   default: +      ; +   } +} + + +static void +i915_init_packets(struct i915_context *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)     /* XXX FBO fix */ +         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); +      /* color buffer offset/stride */ +      i915->state.Buffer[I915_DESTREG_CBUFADDR0] = _3DSTATE_BUF_INFO_CMD; +      /* XXX FBO: remove this?  Also get set in i915_set_draw_region() */ +      i915->state.Buffer[I915_DESTREG_CBUFADDR1] = (BUF_3D_ID_COLOR_BACK | BUF_3D_PITCH(screen->front.pitch) |  /* pitch in bytes */ +                                                    BUF_3D_USE_FENCE); + +      i915->state.Buffer[I915_DESTREG_DBUFADDR0] = _3DSTATE_BUF_INFO_CMD; +      /* XXX FBO: remove this?  Also get set in i915_set_draw_region() */ +      i915->state.Buffer[I915_DESTREG_DBUFADDR1] = (BUF_3D_ID_DEPTH | BUF_3D_PITCH(screen->depth.pitch) |       /* pitch in bytes */ +                                                    BUF_3D_USE_FENCE); + +      i915->state.Buffer[I915_DESTREG_DV0] = _3DSTATE_DST_BUF_VARS_CMD; + +      /* XXX FBO: remove this?  Also get set in i915_set_draw_region() */ +#if 0                           /* seems we don't need this */ +      switch (screen->fbFormat) { +      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; +      } +#endif + + +      /* scissor */ +      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; +   } + + +#if 0 +   { +      I915_STATECHANGE(i915, I915_UPLOAD_DEFAULTS); +      i915->state.Default[I915_DEFREG_C0] = _3DSTATE_DEFAULT_DIFFUSE; +      i915->state.Default[I915_DEFREG_C1] = 0; +      i915->state.Default[I915_DEFREG_S0] = _3DSTATE_DEFAULT_SPECULAR; +      i915->state.Default[I915_DEFREG_S1] = 0; +      i915->state.Default[I915_DEFREG_Z0] = _3DSTATE_DEFAULT_Z; +      i915->state.Default[I915_DEFREG_Z1] = 0; +   } +#endif + + +   /* 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 | I915_UPLOAD_INVARIENT); +} + +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->StencilFuncSeparate = i915StencilFuncSeparate; +   functions->StencilMaskSeparate = i915StencilMaskSeparate; +   functions->StencilOpSeparate = i915StencilOpSeparate; +} + + +void +i915InitState(struct i915_context *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/i915tex/i915_tex.c b/src/mesa/drivers/dri/i915tex/i915_tex.c new file mode 100644 index 0000000000..a53abe9a92 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i915_tex.c @@ -0,0 +1,113 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#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" + + + +static void +i915TexEnv(GLcontext * ctx, GLenum target, +           GLenum pname, const GLfloat * param) +{ +   struct i915_context *i915 = I915_CONTEXT(ctx); + +   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:{ +         GLuint unit = ctx->Texture.CurrentUnit; +         GLint b = (int) ((*param) * 16.0); +         if (b > 255) +            b = 255; +         if (b < -256) +            b = -256; +         I915_STATECHANGE(i915, I915_UPLOAD_TEX(unit)); +         i915->lodbias_ss2[unit] = +            ((b << SS2_LOD_BIAS_SHIFT) & SS2_LOD_BIAS_MASK); +         break; +      } + +   default: +      break; +   } +} + + +static void +i915BindTexture(GLcontext * ctx, GLenum target, +                struct gl_texture_object *texobj) +{ +   /* 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; +} diff --git a/src/mesa/drivers/dri/i915tex/i915_tex_layout.c b/src/mesa/drivers/dri/i915tex/i915_tex_layout.c new file mode 100644 index 0000000000..e9360ecea8 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i915_tex_layout.c @@ -0,0 +1,380 @@ +/************************************************************************** + *  + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +/* Code to layout images in a mipmap tree for i915 and i945 + * respectively. + */ + +#include "intel_mipmap_tree.h" +#include "macros.h" +#include "intel_context.h" + +#define FILE_DEBUG_FLAG DEBUG_TEXTURE + +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} +}; + +static GLuint +minify(GLuint d) +{ +   return MAX2(1, d >> 1); +} + +GLboolean +i915_miptree_layout(struct intel_mipmap_tree * mt) +{ +   GLint level; + +   switch (mt->target) { +   case GL_TEXTURE_CUBE_MAP:{ +         const GLuint dim = mt->width0; +         GLuint face; + +         /* double pitch for cube layouts */ +         mt->pitch = ((dim * mt->cpp * 2 + 3) & ~3) / mt->cpp; +         mt->total_height = dim * 4; + +         for (level = mt->first_level; level <= mt->last_level; level++) +            intel_miptree_set_level_info(mt, level, 6, +                                         0, 0, +                                         mt->pitch, mt->total_height, 1); + +         for (face = 0; face < 6; face++) { +            GLuint x = initial_offsets[face][0] * dim; +            GLuint y = initial_offsets[face][1] * dim; +            GLuint d = dim; + +            for (level = mt->first_level; level <= mt->last_level; level++) { +               intel_miptree_set_image_offset(mt, level, face, x, y); + +               if (d == 0) +                  _mesa_printf("cube mipmap %d/%d (%d..%d) is 0x0\n", +                               face, level, mt->first_level, mt->last_level); + +               d >>= 1; +               x += step_offsets[face][0] * d; +               y += step_offsets[face][1] * d; +            } +         } +         break; +      } +   case GL_TEXTURE_3D:{ +         GLuint width = mt->width0; +         GLuint height = mt->height0; +         GLuint depth = mt->depth0; +         GLuint stack_height = 0; + +         /* Calculate the size of a single slice.  +          */ +         mt->pitch = ((mt->width0 * mt->cpp + 3) & ~3) / mt->cpp; + +         /* XXX: hardware expects/requires 9 levels at minimum. +          */ +         for (level = mt->first_level; level <= MAX2(8, mt->last_level); +              level++) { +            intel_miptree_set_level_info(mt, level, 1, 0, mt->total_height, +                                         width, height, depth); + + +            stack_height += MAX2(2, height); + +            width = minify(width); +            height = minify(height); +            depth = minify(depth); +         } + +         /* Fixup depth image_offsets:  +          */ +         depth = mt->depth0; +         for (level = mt->first_level; level <= mt->last_level; level++) { +            GLuint i; +            for (i = 0; i < depth; i++)  +               intel_miptree_set_image_offset(mt, level, i, +                                              0, i * stack_height); + +            depth = minify(depth); +         } + + +         /* Multiply slice size by texture depth for total size.  It's +          * remarkable how wasteful of memory the i915 texture layouts +          * are.  They are largely fixed in the i945. +          */ +         mt->total_height = stack_height * mt->depth0; +         break; +      } + +   default:{ +         GLuint width = mt->width0; +         GLuint height = mt->height0; +	 GLuint img_height; + +         mt->pitch = ((mt->width0 * mt->cpp + 3) & ~3) / mt->cpp; +         mt->total_height = 0; + +         for (level = mt->first_level; level <= mt->last_level; level++) { +            intel_miptree_set_level_info(mt, level, 1, +                                         0, mt->total_height, +                                         width, height, 1); + +            if (mt->compressed) +               img_height = MAX2(1, height / 4); +            else +               img_height = MAX2(2, height); + +	    mt->total_height += img_height; +	    mt->total_height += 1; +	    mt->total_height &= ~1; + +            width = minify(width); +            height = minify(height); +         } +         break; +      } +   } +   DBG("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__, +       mt->pitch, +       mt->total_height, mt->cpp, mt->pitch * mt->total_height * mt->cpp); + +   return GL_TRUE; +} + + +GLboolean +i945_miptree_layout(struct intel_mipmap_tree * mt) +{ +   GLint level; + +   switch (mt->target) { +   case GL_TEXTURE_CUBE_MAP:{ +         const GLuint dim = mt->width0; +         GLuint face; + +         /* Depending on the size of the largest images, pitch can be +          * determined either by the old-style packing of cubemap faces, +          * or the final row of 4x4, 2x2 and 1x1 faces below this.  +          */ +         if (dim > 32) +            mt->pitch = ((dim * mt->cpp * 2 + 3) & ~3) / mt->cpp; +         else +            mt->pitch = 14 * 8; + +         mt->total_height = dim * 4 + 4; + +         /* Set all the levels to effectively occupy the whole rectangular region.  +          */ +         for (level = mt->first_level; level <= mt->last_level; level++) +            intel_miptree_set_level_info(mt, level, 6, +                                         0, 0, +                                         mt->pitch, mt->total_height, 1); + + + +         for (face = 0; face < 6; face++) { +            GLuint x = initial_offsets[face][0] * dim; +            GLuint y = initial_offsets[face][1] * dim; +            GLuint d = dim; + +            if (dim == 4 && face >= 4) { +               y = mt->total_height - 4; +               x = (face - 4) * 8; +            } +            else if (dim < 4) { +               y = mt->total_height - 4; +               x = face * 8; +            } + +            for (level = mt->first_level; level <= mt->last_level; level++) { +               intel_miptree_set_image_offset(mt, level, face, x, y); + +               d >>= 1; + +               switch (d) { +               case 4: +                  switch (face) { +                  case FACE_POS_X: +                  case FACE_NEG_X: +                     x += step_offsets[face][0] * d; +                     y += step_offsets[face][1] * d; +                     break; +                  case FACE_POS_Y: +                  case FACE_NEG_Y: +                     y += 12; +                     x -= 8; +                     break; +                  case FACE_POS_Z: +                  case FACE_NEG_Z: +                     y = mt->total_height - 4; +                     x = (face - 4) * 8; +                     break; +                  } + +               case 2: +                  y = mt->total_height - 4; +                  x = 16 + face * 8; +                  break; + +               case 1: +                  x += 48; +                  break; + +               default: +                  x += step_offsets[face][0] * d; +                  y += step_offsets[face][1] * d; +                  break; +               } +            } +         } +         break; +      } +   case GL_TEXTURE_3D:{ +         GLuint width = mt->width0; +         GLuint height = mt->height0; +         GLuint depth = mt->depth0; +         GLuint pack_x_pitch, pack_x_nr; +         GLuint pack_y_pitch; +         GLuint level; + +         mt->pitch = ((mt->width0 * mt->cpp + 3) & ~3) / mt->cpp; +         mt->total_height = 0; + +         pack_y_pitch = MAX2(mt->height0, 2); +         pack_x_pitch = mt->pitch; +         pack_x_nr = 1; + +         for (level = mt->first_level; level <= mt->last_level; level++) { +            GLuint nr_images = mt->target == GL_TEXTURE_3D ? depth : 6; +            GLint x = 0; +            GLint y = 0; +            GLint q, j; + +            intel_miptree_set_level_info(mt, level, nr_images, +                                         0, mt->total_height, +                                         width, height, depth); + +            for (q = 0; q < nr_images;) { +               for (j = 0; j < pack_x_nr && q < nr_images; j++, q++) { +                  intel_miptree_set_image_offset(mt, level, q, x, y); +                  x += pack_x_pitch; +               } + +               x = 0; +               y += pack_y_pitch; +            } + + +            mt->total_height += y; + +            if (pack_x_pitch > 4) { +               pack_x_pitch >>= 1; +               pack_x_nr <<= 1; +               assert(pack_x_pitch * pack_x_nr <= mt->pitch); +            } + +            if (pack_y_pitch > 2) { +               pack_y_pitch >>= 1; +            } + +            width = minify(width); +            height = minify(height); +            depth = minify(depth); +         } +         break; +      } + +   case GL_TEXTURE_1D: +   case GL_TEXTURE_2D: +   case GL_TEXTURE_RECTANGLE_ARB:{ +         GLuint x = 0; +         GLuint y = 0; +         GLuint width = mt->width0; +         GLuint height = mt->height0; +	 GLint align_h = 2; + +         mt->pitch = ((mt->width0 * mt->cpp + 3) & ~3) / mt->cpp; +         mt->total_height = 0; + +         for (level = mt->first_level; level <= mt->last_level; level++) { +	    GLuint img_height; + +            intel_miptree_set_level_info(mt, level, 1, +                                         x, y,  +					 width,  +					 mt->compressed ? height/4 : height, 1); + + +	    if (mt->compressed) +               img_height = MAX2(1, height / 4); +            else +               img_height = MAX2(align_h, height); + +            /* LPT change: step right after second mipmap. +             */ +            if (level == mt->first_level + 1) { +               x += mt->pitch / 2; +	       x = (x + 3) & ~3; +	    } +            else { +	       y += img_height; +	       y += align_h - 1; +	       y &= ~(align_h - 1); +	    } + +            /* Because the images are packed better, the final offset +             * might not be the maximal one: +             */ +            mt->total_height = MAX2(mt->total_height, y); + +            width = minify(width); +            height = minify(height); +         } +         break; +      } +   default: +      _mesa_problem(NULL, "Unexpected tex target in i945_miptree_layout()"); +   } + +   DBG("%s: %dx%dx%d - sz 0x%x\n", __FUNCTION__, +       mt->pitch, +       mt->total_height, mt->cpp, mt->pitch * mt->total_height * mt->cpp); + +   return GL_TRUE; +} diff --git a/src/mesa/drivers/dri/i915tex/i915_texstate.c b/src/mesa/drivers/dri/i915tex/i915_texstate.c new file mode 100644 index 0000000000..e0ecdfde24 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i915_texstate.c @@ -0,0 +1,338 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#include "mtypes.h" +#include "enums.h" +#include "texformat.h" +#include "dri_bufmgr.h" + +#include "intel_mipmap_tree.h" +#include "intel_tex.h" + +#include "i915_context.h" +#include "i915_reg.h" + + +static GLuint +translate_texture_format(GLuint mesa_format) +{ +   switch (mesa_format) { +   case MESA_FORMAT_L8: +      return MAPSURF_8BIT | MT_8BIT_L8; +   case MESA_FORMAT_I8: +      return MAPSURF_8BIT | MT_8BIT_I8; +   case MESA_FORMAT_A8: +      return MAPSURF_8BIT | MT_8BIT_A8; +   case MESA_FORMAT_AL88: +      return MAPSURF_16BIT | MT_16BIT_AY88; +   case MESA_FORMAT_RGB565: +      return MAPSURF_16BIT | MT_16BIT_RGB565; +   case MESA_FORMAT_ARGB1555: +      return MAPSURF_16BIT | MT_16BIT_ARGB1555; +   case MESA_FORMAT_ARGB4444: +      return MAPSURF_16BIT | MT_16BIT_ARGB4444; +   case MESA_FORMAT_ARGB8888: +      return MAPSURF_32BIT | MT_32BIT_ARGB8888; +   case MESA_FORMAT_YCBCR_REV: +      return (MAPSURF_422 | MT_422_YCRCB_NORMAL); +   case MESA_FORMAT_YCBCR: +      return (MAPSURF_422 | MT_422_YCRCB_SWAPY); +   case MESA_FORMAT_RGB_FXT1: +   case MESA_FORMAT_RGBA_FXT1: +      return (MAPSURF_COMPRESSED | MT_COMPRESS_FXT1); +   case MESA_FORMAT_Z16: +      return (MAPSURF_16BIT | MT_16BIT_L16); +   case MESA_FORMAT_RGBA_DXT1: +   case MESA_FORMAT_RGB_DXT1: +      return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT1); +   case MESA_FORMAT_RGBA_DXT3: +      return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT2_3); +   case MESA_FORMAT_RGBA_DXT5: +      return (MAPSURF_COMPRESSED | MT_COMPRESS_DXT4_5); +   case MESA_FORMAT_Z24_S8: +      return (MAPSURF_32BIT | MT_32BIT_xL824); +   default: +      fprintf(stderr, "%s: bad image format %x\n", __FUNCTION__, mesa_format); +      abort(); +      return 0; +   } +} + + + + +/* 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; +   } +} + + + +/* Recalculate all state from scratch.  Perhaps not the most + * efficient, but this has gotten complex enough that we need + * something which is understandable and reliable. + */ +static GLboolean +i915_update_tex_unit(struct intel_context *intel, GLuint unit, GLuint ss3) +{ +   GLcontext *ctx = &intel->ctx; +   struct i915_context *i915 = i915_context(ctx); +   struct gl_texture_object *tObj = ctx->Texture.Unit[unit]._Current; +   struct intel_texture_object *intelObj = intel_texture_object(tObj); +   struct gl_texture_image *firstImage; +   GLuint *state = i915->state.Tex[unit]; + +   memset(state, 0, sizeof(state)); + +   /*We need to refcount these. */ + +   if (i915->state.tex_buffer[unit] != NULL) { +       driBOUnReference(i915->state.tex_buffer[unit]); +       i915->state.tex_buffer[unit] = NULL; +   } + +   if (!intel_finalize_mipmap_tree(intel, unit)) +      return GL_FALSE; + +   /* Get first image here, since intelObj->firstLevel will get set in +    * the intel_finalize_mipmap_tree() call above. +    */ +   firstImage = tObj->Image[0][intelObj->firstLevel]; + +   i915->state.tex_buffer[unit] = driBOReference(intelObj->mt->region->buffer); +   i915->state.tex_offset[unit] = intel_miptree_image_offset(intelObj->mt, 0, +                                                             intelObj-> +                                                             firstLevel); + +   state[I915_TEXREG_MS3] = +      (((firstImage->Height - 1) << MS3_HEIGHT_SHIFT) | +       ((firstImage->Width - 1) << MS3_WIDTH_SHIFT) | +       translate_texture_format(firstImage->TexFormat->MesaFormat) | +       MS3_USE_FENCE_REGS); + +   state[I915_TEXREG_MS4] = +      (((((intelObj->mt->pitch * intelObj->mt->cpp) / 4) - +         1) << MS4_PITCH_SHIFT) | MS4_CUBE_FACE_ENA_MASK | +       ((((intelObj->lastLevel - +           intelObj->firstLevel) * +          4)) << MS4_MAX_LOD_SHIFT) | ((firstImage->Depth - +                                        1) << MS4_VOLUME_DEPTH_SHIFT)); + + +   { +      GLuint minFilt, mipFilt, magFilt; + +      switch (tObj->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: +         return GL_FALSE; +      } + +      if (tObj->MaxAnisotropy > 1.0) { +         minFilt = FILTER_ANISOTROPIC; +         magFilt = FILTER_ANISOTROPIC; +      } +      else { +         switch (tObj->MagFilter) { +         case GL_NEAREST: +            magFilt = FILTER_NEAREST; +            break; +         case GL_LINEAR: +            magFilt = FILTER_LINEAR; +            break; +         default: +            return GL_FALSE; +         } +      } + +      state[I915_TEXREG_SS2] = i915->lodbias_ss2[unit]; + +      /* YUV conversion: +       */ +      if (firstImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR || +          firstImage->TexFormat->MesaFormat == MESA_FORMAT_YCBCR_REV) +         state[I915_TEXREG_SS2] |= SS2_COLORSPACE_CONVERSION; + +      /* Shadow: +       */ +      if (tObj->CompareMode == GL_COMPARE_R_TO_TEXTURE_ARB && +          tObj->Target != GL_TEXTURE_3D) { + +         state[I915_TEXREG_SS2] |= +            (SS2_SHADOW_ENABLE | +             intel_translate_compare_func(tObj->CompareFunc)); + +         minFilt = FILTER_4X4_FLAT; +         magFilt = FILTER_4X4_FLAT; +      } + +      state[I915_TEXREG_SS2] |= ((minFilt << SS2_MIN_FILTER_SHIFT) | +                                 (mipFilt << SS2_MIP_FILTER_SHIFT) | +                                 (magFilt << SS2_MAG_FILTER_SHIFT)); +   } + +   { +      GLenum ws = tObj->WrapS; +      GLenum wt = tObj->WrapT; +      GLenum wr = tObj->WrapR; + + +      /* 3D textures don't seem to respect the border color. +       * Fallback if there's ever a danger that they might refer to +       * it.   +       *  +       * Effectively this means fallback on 3D clamp or +       * clamp_to_border. +       */ +      if (tObj->Target == GL_TEXTURE_3D && +          (tObj->MinFilter != GL_NEAREST || +           tObj->MagFilter != GL_NEAREST) && +          (ws == GL_CLAMP || +           wt == GL_CLAMP || +           wr == GL_CLAMP || +           ws == GL_CLAMP_TO_BORDER || +           wt == GL_CLAMP_TO_BORDER || wr == GL_CLAMP_TO_BORDER)) +         return GL_FALSE; + + +      state[I915_TEXREG_SS3] = ss3;     /* SS3_NORMALIZED_COORDS */ + +      state[I915_TEXREG_SS3] |= +         ((translate_wrap_mode(ws) << SS3_TCX_ADDR_MODE_SHIFT) | +          (translate_wrap_mode(wt) << SS3_TCY_ADDR_MODE_SHIFT) | +          (translate_wrap_mode(wr) << SS3_TCZ_ADDR_MODE_SHIFT)); + +      state[I915_TEXREG_SS3] |= (unit << SS3_TEXTUREMAP_INDEX_SHIFT); +   } + + +   state[I915_TEXREG_SS4] = INTEL_PACKCOLOR8888(tObj->_BorderChan[0], +                                                tObj->_BorderChan[1], +                                                tObj->_BorderChan[2], +                                                tObj->_BorderChan[3]); + + +   I915_ACTIVESTATE(i915, I915_UPLOAD_TEX(unit), GL_TRUE); +   /* memcmp was already disabled, but definitely won't work as the +    * region might now change and that wouldn't be detected: +    */ +   I915_STATECHANGE(i915, I915_UPLOAD_TEX(unit)); + + +#if 0 +   DBG(TEXTURE, "state[I915_TEXREG_SS2] = 0x%x\n", state[I915_TEXREG_SS2]); +   DBG(TEXTURE, "state[I915_TEXREG_SS3] = 0x%x\n", state[I915_TEXREG_SS3]); +   DBG(TEXTURE, "state[I915_TEXREG_SS4] = 0x%x\n", state[I915_TEXREG_SS4]); +   DBG(TEXTURE, "state[I915_TEXREG_MS2] = 0x%x\n", state[I915_TEXREG_MS2]); +   DBG(TEXTURE, "state[I915_TEXREG_MS3] = 0x%x\n", state[I915_TEXREG_MS3]); +   DBG(TEXTURE, "state[I915_TEXREG_MS4] = 0x%x\n", state[I915_TEXREG_MS4]); +#endif + +   return GL_TRUE; +} + + + + +void +i915UpdateTextureState(struct intel_context *intel) +{ +   GLboolean ok = GL_TRUE; +   GLuint i; + +   for (i = 0; i < I915_TEX_UNITS && ok; i++) { +      switch (intel->ctx.Texture.Unit[i]._ReallyEnabled) { +      case TEXTURE_1D_BIT: +      case TEXTURE_2D_BIT: +      case TEXTURE_CUBE_BIT: +      case TEXTURE_3D_BIT: +         ok = i915_update_tex_unit(intel, i, SS3_NORMALIZED_COORDS); +         break; +      case TEXTURE_RECT_BIT: +         ok = i915_update_tex_unit(intel, i, 0); +         break; +      case 0:{ +            struct i915_context *i915 = i915_context(&intel->ctx); +            if (i915->state.active & I915_UPLOAD_TEX(i)) +               I915_ACTIVESTATE(i915, I915_UPLOAD_TEX(i), GL_FALSE); + +	    if (i915->state.tex_buffer[i] != NULL) { +	       driBOUnReference(i915->state.tex_buffer[i]); +	       i915->state.tex_buffer[i] = NULL; +	    } + +            break; +         } +      default: +         ok = GL_FALSE; +         break; +      } +   } + +   FALLBACK(intel, I915_FALLBACK_TEXTURE, !ok); +} diff --git a/src/mesa/drivers/dri/i915tex/i915_vtbl.c b/src/mesa/drivers/dri/i915tex/i915_vtbl.c new file mode 100644 index 0000000000..827990d2cf --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/i915_vtbl.c @@ -0,0 +1,549 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + + + +#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 "intel_tex.h" +#include "intel_regions.h" + +#include "i915_reg.h" +#include "i915_context.h" + +static void +i915_render_start(struct intel_context *intel) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); + +   i915ValidateFragmentProgram(i915); +} + + +static void +i915_reduced_primitive_state(struct intel_context *intel, GLenum rprim) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); +   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]) { +      INTEL_FIREVERTICES(intel); + +      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(struct intel_context *intel, GLuint expected) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); +   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++; +   if (lis4 & S4_VFMT_FOG_PARAM) +      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(struct intel_context *intel) +{ +   BATCH_LOCALS; + +   BEGIN_BATCH(200, 0); + +   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 )		     \ +   intel_batchbuffer_data(intel->batch, state, size, 0 ) + +static GLuint +get_dirty(struct i915_hw_state *state) +{ +   GLuint dirty; + +   /* 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; +   return dirty; +} + + +static GLuint +get_state_size(struct i915_hw_state *state) +{ +   GLuint dirty = get_dirty(state); +   GLuint i; +   GLuint sz = 0; + +   if (dirty & I915_UPLOAD_CTX) +      sz += sizeof(state->Ctx); + +   if (dirty & I915_UPLOAD_BUFFERS) +      sz += sizeof(state->Buffer); + +   if (dirty & I915_UPLOAD_STIPPLE) +      sz += sizeof(state->Stipple); + +   if (dirty & I915_UPLOAD_FOG) +      sz += sizeof(state->Fog); + +   if (dirty & I915_UPLOAD_TEX_ALL) { +      int nr = 0; +      for (i = 0; i < I915_TEX_UNITS; i++) +         if (dirty & I915_UPLOAD_TEX(i)) +            nr++; + +      sz += (2 + nr * 3) * sizeof(GLuint) * 2; +   } + +   if (dirty & I915_UPLOAD_CONSTANTS) +      sz += state->ConstantSize * sizeof(GLuint); + +   if (dirty & I915_UPLOAD_PROGRAM) +      sz += state->ProgramSize * sizeof(GLuint); + +   return sz; +} + + +/* Push the state into the sarea and/or texture memory. + */ +static void +i915_emit_state(struct intel_context *intel) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); +   struct i915_hw_state *state = i915->current; +   int i; +   GLuint dirty; +   BATCH_LOCALS; + +   /* We don't hold the lock at this point, so want to make sure that +    * there won't be a buffer wrap.   +    * +    * It might be better to talk about explicit places where +    * scheduling is allowed, rather than assume that it is whenever a +    * batchbuffer fills up. +    */ +   intel_batchbuffer_require_space(intel->batch, get_state_size(state), 0); + +   /* Do this here as we may have flushed the batchbuffer above, +    * causing more state to be dirty! +    */ +   dirty = get_dirty(state); + +   if (INTEL_DEBUG & DEBUG_STATE) +      fprintf(stderr, "%s dirty: %x\n", __FUNCTION__, dirty); + +   if (dirty & I915_UPLOAD_INVARIENT) { +      if (INTEL_DEBUG & DEBUG_STATE) +         fprintf(stderr, "I915_UPLOAD_INVARIENT:\n"); +      i915_emit_invarient_state(intel); +   } + +   if (dirty & I915_UPLOAD_CTX) { +      if (INTEL_DEBUG & DEBUG_STATE) +         fprintf(stderr, "I915_UPLOAD_CTX:\n"); +      emit(intel, state->Ctx, sizeof(state->Ctx)); +   } + +   if (dirty & I915_UPLOAD_BUFFERS) { +      if (INTEL_DEBUG & DEBUG_STATE) +         fprintf(stderr, "I915_UPLOAD_BUFFERS:\n"); +      BEGIN_BATCH(I915_DEST_SETUP_SIZE + 2, 0); +      OUT_BATCH(state->Buffer[I915_DESTREG_CBUFADDR0]); +      OUT_BATCH(state->Buffer[I915_DESTREG_CBUFADDR1]); +      OUT_RELOC(state->draw_region->buffer, +                DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, +                DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, +                state->draw_region->draw_offset); + +      if (state->depth_region) { +         OUT_BATCH(state->Buffer[I915_DESTREG_DBUFADDR0]); +         OUT_BATCH(state->Buffer[I915_DESTREG_DBUFADDR1]); +         OUT_RELOC(state->depth_region->buffer, +                   DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, +                   DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, +                   state->depth_region->draw_offset); +      } + +      OUT_BATCH(state->Buffer[I915_DESTREG_DV0]); +      OUT_BATCH(state->Buffer[I915_DESTREG_DV1]); +      OUT_BATCH(state->Buffer[I915_DESTREG_SENABLE]); +      OUT_BATCH(state->Buffer[I915_DESTREG_SR0]); +      OUT_BATCH(state->Buffer[I915_DESTREG_SR1]); +      OUT_BATCH(state->Buffer[I915_DESTREG_SR2]); +      ADVANCE_BATCH(); +   } + +   if (dirty & I915_UPLOAD_STIPPLE) { +      if (INTEL_DEBUG & DEBUG_STATE) +         fprintf(stderr, "I915_UPLOAD_STIPPLE:\n"); +      emit(intel, state->Stipple, sizeof(state->Stipple)); +   } + +   if (dirty & I915_UPLOAD_FOG) { +      if (INTEL_DEBUG & DEBUG_STATE) +         fprintf(stderr, "I915_UPLOAD_FOG:\n"); +      emit(intel, 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, 0); +      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)) { + +            if (state->tex_buffer[i]) { +               OUT_RELOC(state->tex_buffer[i], +                         DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ, +                         DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, +                         state->tex_offset[i]); +            } +            else { +               assert(i == 0); +               assert(state == &i915->meta); +               OUT_BATCH(0); +            } + +            OUT_BATCH(state->Tex[i][I915_TEXREG_MS3]); +            OUT_BATCH(state->Tex[i][I915_TEXREG_MS4]); +         } +      ADVANCE_BATCH(); + +      BEGIN_BATCH(2 + nr * 3, 0); +      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 (INTEL_DEBUG & DEBUG_STATE) +         fprintf(stderr, "I915_UPLOAD_CONSTANTS:\n"); +      emit(intel, state->Constant, state->ConstantSize * sizeof(GLuint)); +   } + +   if (dirty & I915_UPLOAD_PROGRAM) { +      if (INTEL_DEBUG & DEBUG_STATE) +         fprintf(stderr, "I915_UPLOAD_PROGRAM:\n"); + +      assert((state->Program[0] & 0x1ff) + 2 == state->ProgramSize); + +      emit(intel, state->Program, state->ProgramSize * sizeof(GLuint)); +      if (INTEL_DEBUG & DEBUG_STATE) +         i915_disassemble_program(state->Program, state->ProgramSize); +   } + +   state->emitted |= dirty; +} + +static void +i915_destroy_context(struct intel_context *intel) +{ +   _tnl_free_vertices(&intel->ctx); +} + + +/** + * Set the drawing regions for the color and depth/stencil buffers. + * This involves setting the pitch, cpp and buffer ID/location. + * Also set pixel format for color and Z rendering + * Used for setting both regular and meta state. + */ +void +i915_state_draw_region(struct intel_context *intel, +                       struct i915_hw_state *state, +                       struct intel_region *color_region, +                       struct intel_region *depth_region) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); +   GLuint value; + +   ASSERT(state == &i915->state || state == &i915->meta); + +   if (state->draw_region != color_region) { +      intel_region_release(&state->draw_region); +      intel_region_reference(&state->draw_region, color_region); +   } +   if (state->depth_region != depth_region) { +      intel_region_release(&state->depth_region); +      intel_region_reference(&state->depth_region, depth_region); +   } + +   /* +    * Set stride/cpp values +    */ +   if (color_region) { +      state->Buffer[I915_DESTREG_CBUFADDR0] = _3DSTATE_BUF_INFO_CMD; +      state->Buffer[I915_DESTREG_CBUFADDR1] = +         (BUF_3D_ID_COLOR_BACK | +          BUF_3D_PITCH(color_region->pitch * color_region->cpp) | +          BUF_3D_USE_FENCE); +   } + +   if (depth_region) { +      state->Buffer[I915_DESTREG_DBUFADDR0] = _3DSTATE_BUF_INFO_CMD; +      state->Buffer[I915_DESTREG_DBUFADDR1] = +         (BUF_3D_ID_DEPTH | +          BUF_3D_PITCH(depth_region->pitch * depth_region->cpp) | +          BUF_3D_USE_FENCE); +   } + +   /* +    * Compute/set I915_DESTREG_DV1 value +    */ +   value = (DSTORG_HORT_BIAS(0x8) |     /* .5 */ +            DSTORG_VERT_BIAS(0x8) |     /* .5 */ +            LOD_PRECLAMP_OGL | TEX_DEFAULT_COLOR_OGL); +   if (color_region && color_region->cpp == 4) { +      value |= DV_PF_8888; +   } +   else { +      value |= (DITHER_FULL_ALWAYS | DV_PF_565); +   } +   if (depth_region && depth_region->cpp == 4) { +      value |= DEPTH_FRMT_24_FIXED_8_OTHER; +   } +   else { +      value |= DEPTH_FRMT_16_FIXED; +   } +   state->Buffer[I915_DESTREG_DV1] = value; + +   I915_STATECHANGE(i915, I915_UPLOAD_BUFFERS); +} + + +static void +i915_set_draw_region(struct intel_context *intel, +                     struct intel_region *color_region, +                     struct intel_region *depth_region) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); +   i915_state_draw_region(intel, &i915->state, color_region, depth_region); +} + + + +static void +i915_lost_hardware(struct intel_context *intel) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); +   i915->state.emitted = 0; +} + +static GLuint +i915_flush_cmd(void) +{ +   return MI_FLUSH | FLUSH_MAP_CACHE; +} + +static void  +i915_assert_not_dirty( struct intel_context *intel ) +{ +   struct i915_context *i915 = i915_context(&intel->ctx); +   struct i915_hw_state *state = i915->current; +   GLuint dirty = get_dirty(state); +   assert(!dirty); +} + + +void +i915InitVtbl(struct i915_context *i915) +{ +   i915->intel.vtbl.check_vertex_size = i915_check_vertex_size; +   i915->intel.vtbl.destroy = i915_destroy_context; +   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_region = i915_set_draw_region; +   i915->intel.vtbl.update_texture_state = i915UpdateTextureState; +   i915->intel.vtbl.flush_cmd = i915_flush_cmd; +   i915->intel.vtbl.assert_not_dirty = i915_assert_not_dirty; +} diff --git a/src/mesa/drivers/dri/i915tex/intel_batchbuffer.c b/src/mesa/drivers/dri/i915tex/intel_batchbuffer.c new file mode 100644 index 0000000000..b4e0b74f16 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_batchbuffer.c @@ -0,0 +1,342 @@ +/************************************************************************** + *  + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#include "intel_batchbuffer.h" +#include "intel_ioctl.h" + +/* Relocations in kernel space: + *    - pass dma buffer seperately + *    - memory manager knows how to patch + *    - pass list of dependent buffers + *    - pass relocation list + * + * Either: + *    - get back an offset for buffer to fire + *    - memory manager knows how to fire buffer + * + * Really want the buffer to be AGP and pinned. + * + */ + +/* Cliprect fence: The highest fence protecting a dma buffer + * containing explicit cliprect information.  Like the old drawable + * lock but irq-driven.  X server must wait for this fence to expire + * before changing cliprects [and then doing sw rendering?].  For + * other dma buffers, the scheduler will grab current cliprect info + * and mix into buffer.  X server must hold the lock while changing + * cliprects???  Make per-drawable.  Need cliprects in shared memory + * -- beats storing them with every cmd buffer in the queue. + * + * ==> X server must wait for this fence to expire before touching the + * framebuffer with new cliprects. + * + * ==> Cliprect-dependent buffers associated with a + * cliprect-timestamp.  All of the buffers associated with a timestamp + * must go to hardware before any buffer with a newer timestamp. + * + * ==> Dma should be queued per-drawable for correct X/GL + * synchronization.  Or can fences be used for this? + * + * Applies to: Blit operations, metaops, X server operations -- X + * server automatically waits on its own dma to complete before + * modifying cliprects ??? + */ + +static void +intel_dump_batchbuffer(GLuint offset, GLuint * ptr, GLuint count) +{ +   int i; +   fprintf(stderr, "\n\n\nSTART BATCH (%d dwords):\n", count / 4); +   for (i = 0; i < count / 4; i += 4) +      fprintf(stderr, "0x%x:\t0x%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 +intel_batchbuffer_reset(struct intel_batchbuffer *batch) +{ + +   int i; + +   /* +    * Get a new, free batchbuffer. +    */ + +   batch->size =  batch->intel->intelScreen->maxBatchSize; +   driBOData(batch->buffer, batch->size, NULL, 0); + +   driBOResetList(&batch->list); + +   /* +    * Unreference buffers previously on the relocation list. +    */ + +   for (i = 0; i < batch->nr_relocs; i++) { +      struct buffer_reloc *r = &batch->reloc[i]; +      driBOUnReference(r->buf); +   } + +   batch->list_count = 0; +   batch->nr_relocs = 0; +   batch->flags = 0; + +   /* +    * We don't refcount the batchbuffer itself since we can't destroy it +    * while it's on the list. +    */ + + +   driBOAddListItem(&batch->list, batch->buffer, +                    DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_EXE, +                    DRM_BO_MASK_MEM | DRM_BO_FLAG_EXE); + + +   batch->map = driBOMap(batch->buffer, DRM_BO_FLAG_WRITE, 0); +   batch->ptr = batch->map; +} + +/*====================================================================== + * Public functions + */ +struct intel_batchbuffer * +intel_batchbuffer_alloc(struct intel_context *intel) +{ +   struct intel_batchbuffer *batch = calloc(sizeof(*batch), 1); + +   batch->intel = intel; + +   driGenBuffers(intel->intelScreen->batchPool, "batchbuffer", 1, +                 &batch->buffer, 4096, +                 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_EXE, 0); +   batch->last_fence = NULL; +   driBOCreateList(20, &batch->list); +   intel_batchbuffer_reset(batch); +   return batch; +} + +void +intel_batchbuffer_free(struct intel_batchbuffer *batch) +{ +   if (batch->last_fence) { +      driFenceFinish(batch->last_fence, +      DRM_FENCE_TYPE_EXE | DRM_I915_FENCE_TYPE_RW, GL_FALSE); +      driFenceUnReference(batch->last_fence); +      batch->last_fence = NULL; +   } +   if (batch->map) { +      driBOUnmap(batch->buffer); +      batch->map = NULL; +   } +   driBOUnReference(batch->buffer); +   batch->buffer = NULL; +   free(batch); +} + +/* TODO: Push this whole function into bufmgr. + */ +static void +do_flush_locked(struct intel_batchbuffer *batch, +                GLuint used, +                GLboolean ignore_cliprects, GLboolean allow_unlock) +{ +   GLuint *ptr; +   GLuint i; +   struct intel_context *intel = batch->intel; +   unsigned fenceFlags; +   struct _DriFenceObject *fo; + +   driBOValidateList(batch->intel->driFd, &batch->list); + +   /* Apply the relocations.  This nasty map indicates to me that the +    * whole task should be done internally by the memory manager, and +    * that dma buffers probably need to be pinned within agp space. +    */ +   ptr = (GLuint *) driBOMap(batch->buffer, DRM_BO_FLAG_WRITE, +                             DRM_BO_HINT_ALLOW_UNFENCED_MAP); + + +   for (i = 0; i < batch->nr_relocs; i++) { +      struct buffer_reloc *r = &batch->reloc[i]; + +      ptr[r->offset / 4] = driBOOffset(r->buf) + r->delta; +   } + +   if (INTEL_DEBUG & DEBUG_BATCH) +      intel_dump_batchbuffer(0, ptr, used); + +   driBOUnmap(batch->buffer); +   batch->map = NULL; + +   /* 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_ioctl(batch->intel, +                        driBOOffset(batch->buffer), +                        used, ignore_cliprects, allow_unlock); +   } + + +   /* +    * Kernel fencing. The flags tells the kernel that we've  +    * programmed an MI_FLUSH. +    */ +    +   fenceFlags = DRM_I915_FENCE_FLAG_FLUSHED; +   fo = driFenceBuffers(batch->intel->driFd, +			"Batch fence", fenceFlags); + +   /* +    * User space fencing. +    */ + +   driBOFence(batch->buffer, fo); + +   if (driFenceType(fo) == DRM_FENCE_TYPE_EXE) { + +     /* +      * Oops. We only validated a batch buffer. This means we +      * didn't do any proper rendering. Discard this fence object. +      */ + +      driFenceUnReference(fo); +   } else { +      driFenceUnReference(batch->last_fence); +      batch->last_fence = fo; +      for (i = 0; i < batch->nr_relocs; i++) { +	struct buffer_reloc *r = &batch->reloc[i]; +	driBOFence(r->buf, fo); +      } +   } + +   if (intel->numClipRects == 0 && !ignore_cliprects) { +      if (allow_unlock) { +         UNLOCK_HARDWARE(intel); +         sched_yield(); +         LOCK_HARDWARE(intel); +      } +      intel->vtbl.lost_hardware(intel); +   } +} + + +struct _DriFenceObject * +intel_batchbuffer_flush(struct intel_batchbuffer *batch) +{ +   struct intel_context *intel = batch->intel; +   GLuint used = batch->ptr - batch->map; + +   if (used == 0) +      return batch->last_fence; + +   /* Add the MI_BATCH_BUFFER_END.  Always add an MI_FLUSH - this is a +    * performance drain that we would like to avoid. +    */ +   if (used & 4) { +      ((int *) batch->ptr)[0] = intel->vtbl.flush_cmd(); +      ((int *) batch->ptr)[1] = 0; +      ((int *) batch->ptr)[2] = MI_BATCH_BUFFER_END; +      used += 12; +   } +   else { +      ((int *) batch->ptr)[0] = intel->vtbl.flush_cmd(); +      ((int *) batch->ptr)[1] = MI_BATCH_BUFFER_END; +      used += 8; +   } + +   driBOUnmap(batch->buffer); +   batch->ptr = NULL; +   batch->map = NULL; + +   /* TODO: Just pass the relocation list and dma buffer up to the +    * kernel. +    */ +   if (!intel->locked) { +      assert(!(batch->flags & INTEL_BATCH_NO_CLIPRECTS)); + +      LOCK_HARDWARE(intel); +      do_flush_locked(batch, used, GL_FALSE, GL_TRUE); +      UNLOCK_HARDWARE(intel); +   } +   else { +      GLboolean ignore_cliprects = !(batch->flags & INTEL_BATCH_CLIPRECTS); +      do_flush_locked(batch, used, ignore_cliprects, GL_FALSE); +   } + +   /* Reset the buffer: +    */ +   intel_batchbuffer_reset(batch); +   return batch->last_fence; +} + +void +intel_batchbuffer_finish(struct intel_batchbuffer *batch) +{ +   struct _DriFenceObject *fence = intel_batchbuffer_flush(batch); +   driFenceReference(fence); +   driFenceFinish(fence, 3, GL_FALSE); +   driFenceUnReference(fence); +} + + +/*  This is the only way buffers get added to the validate list. + */ +GLboolean +intel_batchbuffer_emit_reloc(struct intel_batchbuffer *batch, +                             struct _DriBufferObject *buffer, +                             GLuint flags, GLuint mask, GLuint delta) +{ +   assert(batch->nr_relocs <= MAX_RELOCS); + +   driBOAddListItem(&batch->list, buffer, flags, mask); + +   { +      struct buffer_reloc *r = &batch->reloc[batch->nr_relocs++]; +      driBOReference(buffer); +      r->buf = buffer; +      r->offset = batch->ptr - batch->map; +      r->delta = delta; +   } + +   batch->ptr += 4; +   return GL_TRUE; +} + + + +void +intel_batchbuffer_data(struct intel_batchbuffer *batch, +                       const void *data, GLuint bytes, GLuint flags) +{ +   assert((bytes & 3) == 0); +   intel_batchbuffer_require_space(batch, bytes, flags); +   __memcpy(batch->ptr, data, bytes); +   batch->ptr += bytes; +} diff --git a/src/mesa/drivers/dri/i915tex/intel_batchbuffer.h b/src/mesa/drivers/dri/i915tex/intel_batchbuffer.h new file mode 100644 index 0000000000..a83dbf423d --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_batchbuffer.h @@ -0,0 +1,124 @@ +#ifndef INTEL_BATCHBUFFER_H +#define INTEL_BATCHBUFFER_H + +#include "mtypes.h" +#include "dri_bufmgr.h" + +struct intel_context; + +#define BATCH_SZ 16384 +#define BATCH_RESERVED 16 + +#define MAX_RELOCS 100 + +#define INTEL_BATCH_NO_CLIPRECTS 0x1 +#define INTEL_BATCH_CLIPRECTS    0x2 + +struct buffer_reloc +{ +   struct _DriBufferObject *buf; +   GLuint offset; +   GLuint delta;                /* not needed? */ +}; + +struct intel_batchbuffer +{ +   struct bufmgr *bm; +   struct intel_context *intel; + +   struct _DriBufferObject *buffer; +   struct _DriFenceObject *last_fence; +   GLuint flags; + +   drmBOList list; +   GLuint list_count; +   GLubyte *map; +   GLubyte *ptr; + +   struct buffer_reloc reloc[MAX_RELOCS]; +   GLuint nr_relocs; +   GLuint size; +}; + +struct intel_batchbuffer *intel_batchbuffer_alloc(struct intel_context +                                                  *intel); + +void intel_batchbuffer_free(struct intel_batchbuffer *batch); + + +void intel_batchbuffer_finish(struct intel_batchbuffer *batch); + +struct _DriFenceObject *intel_batchbuffer_flush(struct intel_batchbuffer +                                                *batch); + +void intel_batchbuffer_reset(struct intel_batchbuffer *batch); + + +/* Unlike bmBufferData, this currently requires the buffer be mapped. + * Consider it a convenience function wrapping multple + * intel_buffer_dword() calls. + */ +void intel_batchbuffer_data(struct intel_batchbuffer *batch, +                            const void *data, GLuint bytes, GLuint flags); + +void intel_batchbuffer_release_space(struct intel_batchbuffer *batch, +                                     GLuint bytes); + +GLboolean intel_batchbuffer_emit_reloc(struct intel_batchbuffer *batch, +                                       struct _DriBufferObject *buffer, +                                       GLuint flags, +                                       GLuint mask, GLuint offset); + +/* Inline functions - might actually be better off with these + * non-inlined.  Certainly better off switching all command packets to + * be passed as structs rather than dwords, but that's a little bit of + * work... + */ +static INLINE GLuint +intel_batchbuffer_space(struct intel_batchbuffer *batch) +{ +   return (batch->size - BATCH_RESERVED) - (batch->ptr - batch->map); +} + + +static INLINE void +intel_batchbuffer_emit_dword(struct intel_batchbuffer *batch, GLuint dword) +{ +   assert(batch->map); +   assert(intel_batchbuffer_space(batch) >= 4); +   *(GLuint *) (batch->ptr) = dword; +   batch->ptr += 4; +} + +static INLINE void +intel_batchbuffer_require_space(struct intel_batchbuffer *batch, +                                GLuint sz, GLuint flags) +{ +   assert(sz < batch->size - 8); +   if (intel_batchbuffer_space(batch) < sz || +       (batch->flags != 0 && flags != 0 && batch->flags != flags)) +      intel_batchbuffer_flush(batch); + +   batch->flags |= flags; +} + +/* Here are the crusty old macros, to be removed: + */ +#define BATCH_LOCALS + +#define BEGIN_BATCH(n, flags) do {				\ +   assert(!intel->prim.flush);					\ +   intel_batchbuffer_require_space(intel->batch, (n)*4, flags);	\ +} while (0) + +#define OUT_BATCH(d)  intel_batchbuffer_emit_dword(intel->batch, d) + +#define OUT_RELOC(buf,flags,mask,delta) do { 				\ +   assert((delta) >= 0);							\ +   intel_batchbuffer_emit_reloc(intel->batch, buf, flags, mask, delta);	\ +} while (0) + +#define ADVANCE_BATCH() do { } while(0) + + +#endif diff --git a/src/mesa/drivers/dri/i915tex/intel_batchpool.c b/src/mesa/drivers/dri/i915tex/intel_batchpool.c new file mode 100644 index 0000000000..3c17c50204 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_batchpool.c @@ -0,0 +1,418 @@ +/************************************************************************** + *  + * Copyright 2006 Tungsten Graphics, Inc., Bismarck, ND., USA + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * THE 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 + * THE COPYRIGHT HOLDERS, AUTHORS AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR  + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE  + * USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + *  + **************************************************************************/ +/* + * Authors: Thomas Hellström <thomas-at-tungstengraphics-dot-com> + */ + +#include <xf86drm.h> +#include <stdlib.h> +#include <errno.h> +#include "imports.h" +#include "glthread.h" +#include "dri_bufpool.h" +#include "dri_bufmgr.h" +#include "intel_screen.h" + +typedef struct +{ +   drmMMListHead head; +   struct _BPool *parent; +   struct _DriFenceObject *fence; +   unsigned long start; +   int unfenced; +   int mapped; +} BBuf; + +typedef struct _BPool +{ +   _glthread_Mutex mutex; +   unsigned long bufSize; +   unsigned poolSize; +   unsigned numFree; +   unsigned numTot; +   unsigned numDelayed; +   unsigned checkDelayed; +   drmMMListHead free; +   drmMMListHead delayed; +   drmMMListHead head; +   drmBO kernelBO; +   void *virtual; +   BBuf *bufs; +} BPool; + + +static BPool * +createBPool(int fd, unsigned long bufSize, unsigned numBufs, unsigned flags, +            unsigned checkDelayed) +{ +   BPool *p = (BPool *) malloc(sizeof(*p)); +   BBuf *buf; +   int i; + +   if (!p) +      return NULL; + +   p->bufs = (BBuf *) malloc(numBufs * sizeof(*p->bufs)); +   if (!p->bufs) { +      free(p); +      return NULL; +   } + +   DRMINITLISTHEAD(&p->free); +   DRMINITLISTHEAD(&p->head); +   DRMINITLISTHEAD(&p->delayed); + +   p->numTot = numBufs; +   p->numFree = numBufs; +   p->bufSize = bufSize; +   p->numDelayed = 0; +   p->checkDelayed = checkDelayed; + +   _glthread_INIT_MUTEX(p->mutex); + +   if (drmBOCreate(fd, 0, numBufs * bufSize, 0, NULL, drm_bo_type_dc, +                   flags, 0, &p->kernelBO)) { +      free(p->bufs); +      free(p); +      return NULL; +   } +   if (drmBOMap(fd, &p->kernelBO, DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0, +                &p->virtual)) { +      drmBODestroy(fd, &p->kernelBO); +      free(p->bufs); +      free(p); +      return NULL; +   } + +   /* +    * We unmap the buffer so that we can validate it later. Note that this is +    * just a synchronizing operation. The buffer will have a virtual mapping +    * until it is destroyed. +    */ + +   drmBOUnmap(fd, &p->kernelBO); + +   buf = p->bufs; +   for (i = 0; i < numBufs; ++i) { +      buf->parent = p; +      buf->fence = NULL; +      buf->start = i * bufSize; +      buf->mapped = 0; +      buf->unfenced = 0; +      DRMLISTADDTAIL(&buf->head, &p->free); +      buf++; +   } + +   return p; +} + + +static void +pool_checkFree(BPool * p, int wait) +{ +   drmMMListHead *list, *prev; +   BBuf *buf; +   int signaled = 0; +   int i; + +   list = p->delayed.next; + +   if (p->numDelayed > 3) { +      for (i = 0; i < p->numDelayed; i += 3) { +         list = list->next; +      } +   } + +   prev = list->prev; +   for (; list != &p->delayed; list = prev, prev = list->prev) { + +      buf = DRMLISTENTRY(BBuf, list, head); + +      if (!signaled) { +         if (wait) { +            driFenceFinish(buf->fence, DRM_FENCE_TYPE_EXE, 1); +            signaled = 1; +         } +         else { +            signaled = driFenceSignaled(buf->fence, DRM_FENCE_TYPE_EXE); +         } +      } + +      if (!signaled) +         break; + +      driFenceUnReference(buf->fence); +      buf->fence = NULL; +      DRMLISTDEL(list); +      p->numDelayed--; +      DRMLISTADD(list, &p->free); +      p->numFree++; +   } +} + +static void * +pool_create(struct _DriBufferPool *pool, +            unsigned long size, unsigned flags, unsigned hint, +            unsigned alignment) +{ +   BPool *p = (BPool *) pool->data; + +   drmMMListHead *item; + +   if (alignment && (alignment != 4096)) +      return NULL; + +   _glthread_LOCK_MUTEX(p->mutex); + +   if (p->numFree == 0) +      pool_checkFree(p, GL_TRUE); + +   if (p->numFree == 0) { +      fprintf(stderr, "Out of fixed size buffer objects\n"); +      BM_CKFATAL(-ENOMEM); +   } + +   item = p->free.next; + +   if (item == &p->free) { +      fprintf(stderr, "Fixed size buffer pool corruption\n"); +   } + +   DRMLISTDEL(item); +   --p->numFree; + +   _glthread_UNLOCK_MUTEX(p->mutex); +   return (void *) DRMLISTENTRY(BBuf, item, head); +} + + +static int +pool_destroy(struct _DriBufferPool *pool, void *private) +{ +   BBuf *buf = (BBuf *) private; +   BPool *p = buf->parent; + +   _glthread_LOCK_MUTEX(p->mutex); + +   if (buf->fence) { +      DRMLISTADDTAIL(&buf->head, &p->delayed); +      p->numDelayed++; +   } +   else { +      buf->unfenced = 0; +      DRMLISTADD(&buf->head, &p->free); +      p->numFree++; +   } + +   if ((p->numDelayed % p->checkDelayed) == 0) +      pool_checkFree(p, 0); + +   _glthread_UNLOCK_MUTEX(p->mutex); +   return 0; +} + + +static int +pool_map(struct _DriBufferPool *pool, void *private, unsigned flags, +         int hint, void **virtual) +{ + +   BBuf *buf = (BBuf *) private; +   BPool *p = buf->parent; + +   _glthread_LOCK_MUTEX(p->mutex); + +   /* +    * Currently Mesa doesn't have any condition variables to resolve this +    * cleanly in a multithreading environment. +    * We bail out instead. +    */ + +   if (buf->mapped) { +      fprintf(stderr, "Trying to map already mapped buffer object\n"); +      BM_CKFATAL(-EINVAL); +   } + +#if 0 +   if (buf->unfenced && !(hint & DRM_BO_HINT_ALLOW_UNFENCED_MAP)) { +      fprintf(stderr, "Trying to map an unfenced buffer object 0x%08x" +              " 0x%08x %d\n", hint, flags, buf->start); +      BM_CKFATAL(-EINVAL); +   } + +#endif + +   if (buf->fence) { +      _glthread_UNLOCK_MUTEX(p->mutex); +      return -EBUSY; +   } + +   buf->mapped = GL_TRUE; +   *virtual = (unsigned char *) p->virtual + buf->start; +   _glthread_UNLOCK_MUTEX(p->mutex); +   return 0; +} + +static int +pool_waitIdle(struct _DriBufferPool *pool, void *private, int lazy) +{ +   BBuf *buf = (BBuf *) private; +   driFenceFinish(buf->fence, 0, lazy); +   return 0; +} + +static int +pool_unmap(struct _DriBufferPool *pool, void *private) +{ +   BBuf *buf = (BBuf *) private; + +   buf->mapped = 0; +   return 0; +} + +static unsigned long +pool_offset(struct _DriBufferPool *pool, void *private) +{ +   BBuf *buf = (BBuf *) private; +   BPool *p = buf->parent; + +   return p->kernelBO.offset + buf->start; +} + +static unsigned +pool_flags(struct _DriBufferPool *pool, void *private) +{ +   BPool *p = (BPool *) pool->data; + +   return p->kernelBO.flags; +} + +static unsigned long +pool_size(struct _DriBufferPool *pool, void *private) +{ +   BPool *p = (BPool *) pool->data; + +   return p->bufSize; +} + + +static int +pool_fence(struct _DriBufferPool *pool, void *private, +           struct _DriFenceObject *fence) +{ +   BBuf *buf = (BBuf *) private; +   BPool *p = buf->parent; + +   _glthread_LOCK_MUTEX(p->mutex); +   if (buf->fence) { +      driFenceUnReference(buf->fence); +   } +   buf->fence = fence; +   buf->unfenced = 0; +   driFenceReference(buf->fence); +   _glthread_UNLOCK_MUTEX(p->mutex); + +   return 0; +} + +static drmBO * +pool_kernel(struct _DriBufferPool *pool, void *private) +{ +   BBuf *buf = (BBuf *) private; +   BPool *p = buf->parent; + +   return &p->kernelBO; +} + +static int +pool_validate(struct _DriBufferPool *pool, void *private) +{ +   BBuf *buf = (BBuf *) private; +   BPool *p = buf->parent; +   _glthread_LOCK_MUTEX(p->mutex); +   buf->unfenced = GL_TRUE; +   _glthread_UNLOCK_MUTEX(p->mutex); +   return 0; +} + +static void +pool_takedown(struct _DriBufferPool *pool) +{ +   BPool *p = (BPool *) pool->data; + +   /* +    * Wait on outstanding fences.  +    */ + +   _glthread_LOCK_MUTEX(p->mutex); +   while ((p->numFree < p->numTot) && p->numDelayed) { +      _glthread_UNLOCK_MUTEX(p->mutex); +      sched_yield(); +      pool_checkFree(p, GL_TRUE); +      _glthread_LOCK_MUTEX(p->mutex); +   } + +   drmBODestroy(pool->fd, &p->kernelBO); +   free(p->bufs); +   _glthread_UNLOCK_MUTEX(p->mutex); +   free(p); +   free(pool); +} + + +struct _DriBufferPool * +driBatchPoolInit(int fd, unsigned flags, +                 unsigned long bufSize, +                 unsigned numBufs, unsigned checkDelayed) +{ +   struct _DriBufferPool *pool; + +   pool = (struct _DriBufferPool *) malloc(sizeof(*pool)); +   if (!pool) +      return NULL; + +   pool->data = createBPool(fd, bufSize, numBufs, flags, checkDelayed); +   if (!pool->data) +      return NULL; + +   pool->fd = fd; +   pool->map = &pool_map; +   pool->unmap = &pool_unmap; +   pool->destroy = &pool_destroy; +   pool->offset = &pool_offset; +   pool->flags = &pool_flags; +   pool->size = &pool_size; +   pool->create = &pool_create; +   pool->fence = &pool_fence; +   pool->kernel = &pool_kernel; +   pool->validate = &pool_validate; +   pool->waitIdle = &pool_waitIdle; +   pool->setstatic = NULL; +   pool->takeDown = &pool_takedown; +   return pool; +} diff --git a/src/mesa/drivers/dri/i915tex/intel_blit.c b/src/mesa/drivers/dri/i915tex/intel_blit.c new file mode 100644 index 0000000000..cbf993fc0e --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_blit.c @@ -0,0 +1,556 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + + +#include <stdio.h> +#include <errno.h> + +#include "mtypes.h" +#include "context.h" +#include "enums.h" + +#include "intel_batchbuffer.h" +#include "intel_blit.h" +#include "intel_buffers.h" +#include "intel_context.h" +#include "intel_fbo.h" +#include "intel_reg.h" +#include "intel_regions.h" +#include "vblank.h" + +#define FILE_DEBUG_FLAG DEBUG_BLIT + +/** + * Copy the back color buffer to the front color buffer.  + * Used for SwapBuffers(). + */ +void +intelCopyBuffer(const __DRIdrawablePrivate * dPriv, +                const drm_clip_rect_t * rect) +{ + +   struct intel_context *intel; +   const intelScreenPrivate *intelScreen; +   GLboolean missed_target; +   int64_t ust; + +   DBG("%s\n", __FUNCTION__); + +   assert(dPriv); + +   intel = intelScreenContext(dPriv->driScreenPriv->private); +   if (!intel) +      return; + +   intelScreen = intel->intelScreen; + +   if (!rect && !intel->swap_scheduled && intelScreen->drmMinor >= 6 && +	!(intel->vblank_flags & VBLANK_FLAG_NO_IRQ) && +	intelScreen->current_rotation == 0) { +      unsigned int interval = driGetVBlankInterval(dPriv, intel->vblank_flags); +      unsigned int target; +      drm_i915_vblank_swap_t swap; +  +      swap.drawable = dPriv->hHWDrawable; +      swap.seqtype = DRM_VBLANK_ABSOLUTE; +      target = swap.sequence = intel->vbl_seq + interval; + +      if (intel->vblank_flags & VBLANK_FLAG_SYNC) { +	 swap.seqtype |= DRM_VBLANK_NEXTONMISS; +      } else if (interval == 0) { +	 goto noschedule; +      } + +      if ( intel->vblank_flags & VBLANK_FLAG_SECONDARY ) { +	 swap.seqtype |= DRM_VBLANK_SECONDARY; +      } + +      intel_batchbuffer_flush(intel->batch); + +      if (!drmCommandWriteRead(intel->driFd, DRM_I915_VBLANK_SWAP, &swap, +			       sizeof(swap))) { +	 intel->swap_scheduled = 1; +	 intel->vbl_seq = swap.sequence; +	 swap.sequence -= target; +	 missed_target = swap.sequence > 0 && swap.sequence <= (1 << 23); +      } +   } else { +      intel->swap_scheduled = 0; +   } +noschedule: +   +   if (intel->last_swap_fence) { +      driFenceFinish(intel->last_swap_fence, DRM_FENCE_TYPE_EXE, GL_TRUE); +      driFenceUnReference(intel->last_swap_fence); +      intel->last_swap_fence = NULL; +   } +   intel->last_swap_fence = intel->first_swap_fence; +   intel->first_swap_fence = NULL; + +   if (!intel->swap_scheduled) { +      if (!rect) { +	 driWaitForVBlank(dPriv, &intel->vbl_seq, intel->vblank_flags, +			  &missed_target); +      } + + +      /* The LOCK_HARDWARE is required for the cliprects.  Buffer offsets +       * should work regardless. +       */ +      LOCK_HARDWARE(intel); + +      if (intel->driDrawable && intel->driDrawable->numClipRects) { +	 const intelScreenPrivate *intelScreen = intel->intelScreen; +	 struct gl_framebuffer *fb +	    = (struct gl_framebuffer *) dPriv->driverPrivate; +	 const struct intel_region *frontRegion +	    = intel_get_rb_region(fb, BUFFER_FRONT_LEFT); +	 const struct intel_region *backRegion +	    = intel_get_rb_region(fb, BUFFER_BACK_LEFT); +	 const int nbox = dPriv->numClipRects; +	 const drm_clip_rect_t *pbox = dPriv->pClipRects; +	 const int pitch = frontRegion->pitch; +	 const int cpp = frontRegion->cpp; +	 int BR13, CMD; +	 int i; + +	 ASSERT(fb); +	 ASSERT(fb->Name == 0);    /* Not a user-created FBO */ +	 ASSERT(frontRegion); +	 ASSERT(backRegion); +	 ASSERT(frontRegion->pitch == backRegion->pitch); +	 ASSERT(frontRegion->cpp == backRegion->cpp); + +	 if (cpp == 2) { +	    BR13 = (pitch * cpp) | (0xCC << 16) | (1 << 24); +	    CMD = XY_SRC_COPY_BLT_CMD; +	 } +	 else { +	    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); +	 } + +	 for (i = 0; i < nbox; i++, pbox++) { +	    drm_clip_rect_t box; + +	    if (pbox->x1 > pbox->x2 || +		pbox->y1 > pbox->y2 || +		pbox->x2 > intelScreen->width || pbox->y2 > intelScreen->height) +	       continue; + +	    box = *pbox; + +	    if (rect) { +	       if (rect->x1 > box.x1) +		  box.x1 = rect->x1; +	       if (rect->y1 > box.y1) +		  box.y1 = rect->y1; +	       if (rect->x2 < box.x2) +		  box.x2 = rect->x2; +	       if (rect->y2 < box.y2) +		  box.y2 = rect->y2; + +	       if (box.x1 > box.x2 || box.y1 > box.y2) +		  continue; +	    } + +	    BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS); +	    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_RELOC(frontRegion->buffer, +			 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, +			 DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, 0); +	    else +	       OUT_RELOC(backRegion->buffer, +			 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, +			 DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, 0); +	    OUT_BATCH((pbox->y1 << 16) | pbox->x1); +	    OUT_BATCH(BR13 & 0xffff); + +	    if (intel->sarea->pf_current_page == 0) +	       OUT_RELOC(backRegion->buffer, +			 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ, +			 DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, 0); +	    else +	       OUT_RELOC(frontRegion->buffer, +			 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ, +			 DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, 0); + +	    ADVANCE_BATCH(); +	 } + +	 if (intel->first_swap_fence) +	    driFenceUnReference(intel->first_swap_fence); +	 intel->first_swap_fence = intel_batchbuffer_flush(intel->batch); +	 driFenceReference(intel->first_swap_fence); +      } + +      UNLOCK_HARDWARE(intel); +   } + +   if (!rect) { +      intel->swap_count++; +      (*dri_interface->getUST) (&ust); +      if (missed_target) { +         intel->swap_missed_count++; +         intel->swap_missed_ust = ust - intel->swap_ust; +      } + +      intel->swap_ust = ust; +   } +} + + + + +void +intelEmitFillBlit(struct intel_context *intel, +                  GLuint cpp, +                  GLshort dst_pitch, +                  struct _DriBufferObject *dst_buffer, +                  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; +   } + +   DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n", +       __FUNCTION__, dst_buffer, dst_pitch, dst_offset, x, y, w, h); + + +   BEGIN_BATCH(6, INTEL_BATCH_NO_CLIPRECTS); +   OUT_BATCH(CMD); +   OUT_BATCH(BR13); +   OUT_BATCH((y << 16) | x); +   OUT_BATCH(((y + h) << 16) | (x + w)); +   OUT_RELOC(dst_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, +             DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, dst_offset); +   OUT_BATCH(color); +   ADVANCE_BATCH(); +} + + +/* Copy BitBlt + */ +void +intelEmitCopyBlit(struct intel_context *intel, +                  GLuint cpp, +                  GLshort src_pitch, +                  struct _DriBufferObject *src_buffer, +                  GLuint src_offset, +                  GLshort dst_pitch, +                  struct _DriBufferObject *dst_buffer, +                  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; + + +   DBG("%s src:buf(%p)/%d+%d %d,%d dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n", +       __FUNCTION__, +       src_buffer, src_pitch, src_offset, src_x, src_y, +       dst_buffer, dst_pitch, dst_offset, dst_x, dst_y, w, h); + +   src_pitch *= cpp; +   dst_pitch *= cpp; + +   switch (cpp) { +   case 1: +   case 2: +   case 3: +      BR13 = (((GLint) dst_pitch) & 0xffff) | (0xCC << 16) | (1 << 24); +      CMD = XY_SRC_COPY_BLT_CMD; +      break; +   case 4: +      BR13 = +         (((GLint) dst_pitch) & 0xffff) | (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; +   } + +   /* Initial y values don't seem to work with negative pitches.  If +    * we adjust the offsets manually (below), it seems to work fine. +    * +    * On the other hand, if we always adjust, the hardware doesn't +    * know which blit directions to use, so overlapping copypixels get +    * the wrong result. +    */ +   if (dst_pitch > 0 && src_pitch > 0) { +      BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS); +      OUT_BATCH(CMD); +      OUT_BATCH(BR13); +      OUT_BATCH((dst_y << 16) | dst_x); +      OUT_BATCH((dst_y2 << 16) | dst_x2); +      OUT_RELOC(dst_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, +                DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, dst_offset); +      OUT_BATCH((src_y << 16) | src_x); +      OUT_BATCH(((GLint) src_pitch & 0xffff)); +      OUT_RELOC(src_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ, +                DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, src_offset); +      ADVANCE_BATCH(); +   } +   else { +      BEGIN_BATCH(8, INTEL_BATCH_NO_CLIPRECTS); +      OUT_BATCH(CMD); +      OUT_BATCH(BR13); +      OUT_BATCH((0 << 16) | dst_x); +      OUT_BATCH((h << 16) | dst_x2); +      OUT_RELOC(dst_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, +                DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, +                dst_offset + dst_y * dst_pitch); +      OUT_BATCH((0 << 16) | src_x); +      OUT_BATCH(((GLint) src_pitch & 0xffff)); +      OUT_RELOC(src_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_READ, +                DRM_BO_MASK_MEM | DRM_BO_FLAG_READ, +                src_offset + src_y * src_pitch); +      ADVANCE_BATCH(); +   } +} + + +/** + * Use blitting to clear the renderbuffers named by 'flags'. + * Note: we can't use the ctx->DrawBuffer->_ColorDrawBufferMask field + * since that might include software renderbuffers or renderbuffers + * which we're clearing with triangles. + * \param mask  bitmask of BUFFER_BIT_* values indicating buffers to clear + */ +void +intelClearWithBlit(GLcontext * ctx, GLbitfield mask, GLboolean all, +                   GLint cx, GLint cy, GLint cw, GLint ch) +{ +   struct intel_context *intel = intel_context(ctx); +   GLuint clear_depth; +   GLbitfield skipBuffers = 0; +   BATCH_LOCALS; + +   DBG("%s %x\n", __FUNCTION__, mask); + +   /* +    * Compute values for clearing the buffers. +    */ +   clear_depth = 0; +   if (mask & BUFFER_BIT_DEPTH) { +      clear_depth = (GLuint) (ctx->DrawBuffer->_DepthMax * ctx->Depth.Clear); +   } +   if (mask & BUFFER_BIT_STENCIL) { +      clear_depth |= (ctx->Stencil.Clear & 0xff) << 24; +   } + +   /* If clearing both depth and stencil, skip BUFFER_BIT_STENCIL in +    * the loop below. +    */ +   if ((mask & BUFFER_BIT_DEPTH) && (mask & BUFFER_BIT_STENCIL)) { +      skipBuffers = BUFFER_BIT_STENCIL; +   } + +   /* XXX Move this flush/lock into the following conditional? */ +   intelFlush(&intel->ctx); +   LOCK_HARDWARE(intel); + +   if (intel->numClipRects) { +      drm_clip_rect_t clear; +      int i; + +      /* Refresh the cx/y/w/h values as they may have been invalidated +       * by a new window position or size picked up when we did +       * LOCK_HARDWARE above.  The values passed by mesa are not +       * reliable. +       */ +      { +         cx = ctx->DrawBuffer->_Xmin; +         cy = ctx->DrawBuffer->_Ymin; +         ch = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; +         cw = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; +      } + +      if (intel->ctx.DrawBuffer->Name == 0) { +         /* clearing a window */ + +         /* flip top to bottom */ +         clear.x1 = cx + intel->drawX; +         clear.y1 = intel->driDrawable->y + intel->driDrawable->h - cy - ch; +         clear.x2 = clear.x1 + cw; +         clear.y2 = clear.y1 + ch; + +         /* adjust for page flipping */ +         if (intel->sarea->pf_current_page == 1) { +            const GLuint tmp = mask; +            mask &= ~(BUFFER_BIT_FRONT_LEFT | BUFFER_BIT_BACK_LEFT); +            if (tmp & BUFFER_BIT_FRONT_LEFT) +               mask |= BUFFER_BIT_BACK_LEFT; +            if (tmp & BUFFER_BIT_BACK_LEFT) +               mask |= BUFFER_BIT_FRONT_LEFT; +         } +      } +      else { +         /* clearing FBO */ +         assert(intel->numClipRects == 1); +         assert(intel->pClipRects == &intel->fboRect); +         clear.x1 = cx; +         clear.y1 = cy; +         clear.x2 = clear.x1 + cw; +         clear.y2 = clear.y1 + ch; +         /* no change to mask */ +      } + +      for (i = 0; i < intel->numClipRects; i++) { +         const drm_clip_rect_t *box = &intel->pClipRects[i]; +         drm_clip_rect_t b; +         GLuint buf; +         GLuint clearMask = mask;       /* use copy, since we modify it below */ + +         if (!all) { +            intel_intersect_cliprects(&b, &clear, box); +         } +         else { +            b = *box; +         } + +         if (0) +            _mesa_printf("clear %d,%d..%d,%d, mask %x\n", +                         b.x1, b.y1, b.x2, b.y2, mask); + +         /* Loop over all renderbuffers */ +         for (buf = 0; buf < BUFFER_COUNT && clearMask; buf++) { +            const GLbitfield bufBit = 1 << buf; +            if ((clearMask & bufBit) && !(bufBit & skipBuffers)) { +               /* OK, clear this renderbuffer */ +               const struct intel_renderbuffer *irb +                  = intel_renderbuffer(ctx->DrawBuffer-> +                                       Attachment[buf].Renderbuffer); +               struct _DriBufferObject *write_buffer = +                  intel_region_buffer(intel->intelScreen, irb->region, +                                      all ? INTEL_WRITE_FULL : +                                      INTEL_WRITE_PART); + +               GLuint clearVal; +               GLint pitch, cpp; +               GLuint BR13, CMD; + +               ASSERT(irb); +               ASSERT(irb->region); + +               pitch = irb->region->pitch; +               cpp = irb->region->cpp; + +               DBG("%s dst:buf(%p)/%d+%d %d,%d sz:%dx%d\n", +                   __FUNCTION__, +                   irb->region->buffer, (pitch * cpp), +                   irb->region->draw_offset, +                   b.x1, b.y1, b.x2 - b.x1, b.y2 - b.y1); + + +               /* Setup the blit command */ +               if (cpp == 4) { +                  BR13 = (0xF0 << 16) | (pitch * cpp) | (1 << 24) | (1 << 25); +                  if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) { +                     CMD = XY_COLOR_BLT_CMD; +                     if (clearMask & BUFFER_BIT_DEPTH) +                        CMD |= XY_COLOR_BLT_WRITE_RGB; +                     if (clearMask & BUFFER_BIT_STENCIL) +                        CMD |= XY_COLOR_BLT_WRITE_ALPHA; +                  } +                  else { +                     /* clearing RGBA */ +                     CMD = (XY_COLOR_BLT_CMD | +                            XY_COLOR_BLT_WRITE_ALPHA | +                            XY_COLOR_BLT_WRITE_RGB); +                  } +               } +               else { +                  ASSERT(cpp == 2 || cpp == 0); +                  BR13 = (0xF0 << 16) | (pitch * cpp) | (1 << 24); +                  CMD = XY_COLOR_BLT_CMD; +               } + +               if (buf == BUFFER_DEPTH || buf == BUFFER_STENCIL) { +                  clearVal = clear_depth; +               } +               else { +                  clearVal = (cpp == 4) +                     ? intel->ClearColor8888 : intel->ClearColor565; +               } +               /* +                  _mesa_debug(ctx, "hardware blit clear buf %d rb id %d\n", +                  buf, irb->Base.Name); +                */ +               BEGIN_BATCH(6, INTEL_BATCH_NO_CLIPRECTS); +               OUT_BATCH(CMD); +               OUT_BATCH(BR13); +               OUT_BATCH((b.y1 << 16) | b.x1); +               OUT_BATCH((b.y2 << 16) | b.x2); +               OUT_RELOC(write_buffer, DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_WRITE, +                         DRM_BO_MASK_MEM | DRM_BO_FLAG_WRITE, +                         irb->region->draw_offset); +               OUT_BATCH(clearVal); +               ADVANCE_BATCH(); +               clearMask &= ~bufBit;    /* turn off bit, for faster loop exit */ +            } +         } +      } +      intel_batchbuffer_flush(intel->batch); +   } + +   UNLOCK_HARDWARE(intel); +} diff --git a/src/mesa/drivers/dri/i915tex/intel_blit.h b/src/mesa/drivers/dri/i915tex/intel_blit.h new file mode 100644 index 0000000000..1d99988c3c --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_blit.h @@ -0,0 +1,63 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#ifndef INTEL_BLIT_H +#define INTEL_BLIT_H + +#include "intel_context.h" +#include "intel_ioctl.h" +#include "dri_bufmgr.h" + +extern void intelCopyBuffer(const __DRIdrawablePrivate * dpriv, +                            const drm_clip_rect_t * rect); + +extern void intelClearWithBlit(GLcontext * ctx, GLbitfield mask, +                               GLboolean all, GLint cx1, GLint cy1, GLint cw, +                               GLint ch); + +extern void intelEmitCopyBlit(struct intel_context *intel, +                              GLuint cpp, +                              GLshort src_pitch, +                              struct _DriBufferObject *src_buffer, +                              GLuint src_offset, +                              GLshort dst_pitch, +                              struct _DriBufferObject *dst_buffer, +                              GLuint dst_offset, +                              GLshort srcx, GLshort srcy, +                              GLshort dstx, GLshort dsty, +                              GLshort w, GLshort h); + +extern void intelEmitFillBlit(struct intel_context *intel, +                              GLuint cpp, +                              GLshort dst_pitch, +                              struct _DriBufferObject *dst_buffer, +                              GLuint dst_offset, +                              GLshort x, GLshort y, +                              GLshort w, GLshort h, GLuint color); + + +#endif diff --git a/src/mesa/drivers/dri/i915tex/intel_buffer_objects.c b/src/mesa/drivers/dri/i915tex/intel_buffer_objects.c new file mode 100644 index 0000000000..31c41d8685 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_buffer_objects.c @@ -0,0 +1,250 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + + +#include "imports.h" +#include "mtypes.h" +#include "bufferobj.h" + +#include "intel_context.h" +#include "intel_buffer_objects.h" +#include "intel_regions.h" +#include "dri_bufmgr.h" + +/** + * There is some duplication between mesa's bufferobjects and our + * bufmgr buffers.  Both have an integer handle and a hashtable to + * lookup an opaque structure.  It would be nice if the handles and + * internal structure where somehow shared. + */ +static struct gl_buffer_object * +intel_bufferobj_alloc(GLcontext * ctx, GLuint name, GLenum target) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_buffer_object *obj = CALLOC_STRUCT(intel_buffer_object); + +   _mesa_initialize_buffer_object(&obj->Base, name, target); + +   driGenBuffers(intel->intelScreen->regionPool, +                 "bufferobj", 1, &obj->buffer, 64, 0, 0); + +   return &obj->Base; +} + + +/* Break the COW tie to the region.  The region gets to keep the data. + */ +void +intel_bufferobj_release_region(struct intel_context *intel, +                               struct intel_buffer_object *intel_obj) +{ +   assert(intel_obj->region->buffer == intel_obj->buffer); +   intel_obj->region->pbo = NULL; +   intel_obj->region = NULL; +   driBOUnReference(intel_obj->buffer); +   intel_obj->buffer = NULL; + +   /* This leads to a large number of buffer deletion/creation events. +    * Currently the drm doesn't like that: +    */ +   driGenBuffers(intel->intelScreen->regionPool, +                 "buffer object", 1, &intel_obj->buffer, 64, 0, 0); +   driBOData(intel_obj->buffer, intel_obj->Base.Size, NULL, 0); +} + +/* Break the COW tie to the region.  Both the pbo and the region end + * up with a copy of the data. + */ +void +intel_bufferobj_cow(struct intel_context *intel, +                    struct intel_buffer_object *intel_obj) +{ +   assert(intel_obj->region); +   intel_region_cow(intel->intelScreen, intel_obj->region); +} + + +/** + * Deallocate/free a vertex/pixel buffer object. + * Called via glDeleteBuffersARB(). + */ +static void +intel_bufferobj_free(GLcontext * ctx, struct gl_buffer_object *obj) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_buffer_object *intel_obj = intel_buffer_object(obj); + +   assert(intel_obj); + +   if (intel_obj->region) { +      intel_bufferobj_release_region(intel, intel_obj); +   } +   else if (intel_obj->buffer) { +      driDeleteBuffers(1, &intel_obj->buffer); +   } + +   _mesa_free(intel_obj); +} + + + +/** + * Allocate space for and store data in a buffer object.  Any data that was + * previously stored in the buffer object is lost.  If data is NULL, + * memory will be allocated, but no copy will occur. + * Called via glBufferDataARB(). + */ +static void +intel_bufferobj_data(GLcontext * ctx, +                     GLenum target, +                     GLsizeiptrARB size, +                     const GLvoid * data, +                     GLenum usage, struct gl_buffer_object *obj) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_buffer_object *intel_obj = intel_buffer_object(obj); + +   intel_obj->Base.Size = size; +   intel_obj->Base.Usage = usage; + +   if (intel_obj->region) +      intel_bufferobj_release_region(intel, intel_obj); + +   driBOData(intel_obj->buffer, size, data, 0); +} + + +/** + * Replace data in a subrange of buffer object.  If the data range + * specified by size + offset extends beyond the end of the buffer or + * if data is NULL, no copy is performed. + * Called via glBufferSubDataARB(). + */ +static void +intel_bufferobj_subdata(GLcontext * ctx, +                        GLenum target, +                        GLintptrARB offset, +                        GLsizeiptrARB size, +                        const GLvoid * data, struct gl_buffer_object *obj) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_buffer_object *intel_obj = intel_buffer_object(obj); + +   assert(intel_obj); + +   if (intel_obj->region) +      intel_bufferobj_cow(intel, intel_obj); + +   driBOSubData(intel_obj->buffer, offset, size, data); +} + + +/** + * Called via glGetBufferSubDataARB(). + */ +static void +intel_bufferobj_get_subdata(GLcontext * ctx, +                            GLenum target, +                            GLintptrARB offset, +                            GLsizeiptrARB size, +                            GLvoid * data, struct gl_buffer_object *obj) +{ +   struct intel_buffer_object *intel_obj = intel_buffer_object(obj); + +   assert(intel_obj); +   driBOGetSubData(intel_obj->buffer, offset, size, data); +} + + + +/** + * Called via glMapBufferARB(). + */ +static void * +intel_bufferobj_map(GLcontext * ctx, +                    GLenum target, +                    GLenum access, struct gl_buffer_object *obj) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_buffer_object *intel_obj = intel_buffer_object(obj); + +   /* XXX: Translate access to flags arg below: +    */ +   assert(intel_obj); + +   if (intel_obj->region) +      intel_bufferobj_cow(intel, intel_obj); + +   obj->Pointer = driBOMap(intel_obj->buffer, +                           DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0); +   return obj->Pointer; +} + + +/** + * Called via glMapBufferARB(). + */ +static GLboolean +intel_bufferobj_unmap(GLcontext * ctx, +                      GLenum target, struct gl_buffer_object *obj) +{ +   struct intel_buffer_object *intel_obj = intel_buffer_object(obj); + +   assert(intel_obj); +   assert(obj->Pointer); +   driBOUnmap(intel_obj->buffer); +   obj->Pointer = NULL; +   return GL_TRUE; +} + +struct _DriBufferObject * +intel_bufferobj_buffer(struct intel_context *intel, +                       struct intel_buffer_object *intel_obj, GLuint flag) +{ +   if (intel_obj->region) { +      if (flag == INTEL_WRITE_PART) +         intel_bufferobj_cow(intel, intel_obj); +      else if (flag == INTEL_WRITE_FULL) +         intel_bufferobj_release_region(intel, intel_obj); +   } + +   return intel_obj->buffer; +} + +void +intel_bufferobj_init(struct intel_context *intel) +{ +   GLcontext *ctx = &intel->ctx; + +   ctx->Driver.NewBufferObject = intel_bufferobj_alloc; +   ctx->Driver.DeleteBuffer = intel_bufferobj_free; +   ctx->Driver.BufferData = intel_bufferobj_data; +   ctx->Driver.BufferSubData = intel_bufferobj_subdata; +   ctx->Driver.GetBufferSubData = intel_bufferobj_get_subdata; +   ctx->Driver.MapBuffer = intel_bufferobj_map; +   ctx->Driver.UnmapBuffer = intel_bufferobj_unmap; +} diff --git a/src/mesa/drivers/dri/i915tex/intel_buffer_objects.h b/src/mesa/drivers/dri/i915tex/intel_buffer_objects.h new file mode 100644 index 0000000000..afe9b2f7cf --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_buffer_objects.h @@ -0,0 +1,86 @@ + /************************************************************************** + *  + * Copyright 2005 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#ifndef INTEL_BUFFEROBJ_H +#define INTEL_BUFFEROBJ_H + +#include "mtypes.h" + +struct intel_context; +struct intel_region; +struct gl_buffer_object; + + +/** + * Intel vertex/pixel buffer object, derived from Mesa's gl_buffer_object. + */ +struct intel_buffer_object +{ +   struct gl_buffer_object Base; +   struct _DriBufferObject *buffer;     /* the low-level buffer manager's buffer handle */ + +   struct intel_region *region; /* Is there a zero-copy texture +                                   associated with this (pixel) +                                   buffer object? */ +}; + + +/* Get the bm buffer associated with a GL bufferobject: + */ +struct _DriBufferObject *intel_bufferobj_buffer(struct intel_context *intel, +                                                struct intel_buffer_object +                                                *obj, GLuint flag); + +/* Hook the bufferobject implementation into mesa:  + */ +void intel_bufferobj_init(struct intel_context *intel); + + + +/* Are the obj->Name tests necessary?  Unfortunately yes, mesa + * allocates a couple of gl_buffer_object structs statically, and + * the Name == 0 test is the only way to identify them and avoid + * casting them erroneously to our structs. + */ +static INLINE struct intel_buffer_object * +intel_buffer_object(struct gl_buffer_object *obj) +{ +   if (obj->Name) +      return (struct intel_buffer_object *) obj; +   else +      return NULL; +} + +/* Helpers for zerocopy image uploads.  See also intel_regions.h: + */ +void intel_bufferobj_cow(struct intel_context *intel, +                         struct intel_buffer_object *intel_obj); +void intel_bufferobj_release_region(struct intel_context *intel, +                                    struct intel_buffer_object *intel_obj); + + +#endif diff --git a/src/mesa/drivers/dri/i915tex/intel_buffers.c b/src/mesa/drivers/dri/i915tex/intel_buffers.c new file mode 100644 index 0000000000..fe7ef7ec36 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_buffers.c @@ -0,0 +1,966 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#include "intel_screen.h" +#include "intel_context.h" +#include "intel_blit.h" +#include "intel_buffers.h" +#include "intel_depthstencil.h" +#include "intel_fbo.h" +#include "intel_tris.h" +#include "intel_regions.h" +#include "intel_batchbuffer.h" +#include "context.h" +#include "utils.h" +#include "framebuffer.h" +#include "swrast/swrast.h" +#include "vblank.h" + + +/** + * XXX move this into a new dri/common/cliprects.c file. + */ +GLboolean +intel_intersect_cliprects(drm_clip_rect_t * dst, +                          const drm_clip_rect_t * a, +                          const drm_clip_rect_t * b) +{ +   GLint bx = b->x1; +   GLint by = b->y1; +   GLint bw = b->x2 - bx; +   GLint bh = b->y2 - by; + +   if (bx < a->x1) +      bw -= a->x1 - bx, bx = a->x1; +   if (by < a->y1) +      bh -= a->y1 - by, by = a->y1; +   if (bx + bw > a->x2) +      bw = a->x2 - bx; +   if (by + bh > a->y2) +      bh = a->y2 - by; +   if (bw <= 0) +      return GL_FALSE; +   if (bh <= 0) +      return GL_FALSE; + +   dst->x1 = bx; +   dst->y1 = by; +   dst->x2 = bx + bw; +   dst->y2 = by + bh; + +   return GL_TRUE; +} + +/** + * Return pointer to current color drawing region, or NULL. + */ +struct intel_region * +intel_drawbuf_region(struct intel_context *intel) +{ +   struct intel_renderbuffer *irbColor = +      intel_renderbuffer(intel->ctx.DrawBuffer->_ColorDrawBuffers[0][0]); +   if (irbColor) +      return irbColor->region; +   else +      return NULL; +} + +/** + * Return pointer to current color reading region, or NULL. + */ +struct intel_region * +intel_readbuf_region(struct intel_context *intel) +{ +   struct intel_renderbuffer *irb +      = intel_renderbuffer(intel->ctx.ReadBuffer->_ColorReadBuffer); +   if (irb) +      return irb->region; +   else +      return NULL; +} + + + +static void +intelBufferSize(GLframebuffer * buffer, GLuint * width, GLuint * height) +{ +   GET_CURRENT_CONTEXT(ctx); +   struct intel_context *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. +    */ +   /* XXX This isn't 100% correct, the given buffer might not be +    * bound to the current context! +    */ +   LOCK_HARDWARE(intel); +   if (intel->driDrawable) { +      *width = intel->driDrawable->w; +      *height = intel->driDrawable->h; +   } +   else { +      *width = 0; +      *height = 0; +   } +   UNLOCK_HARDWARE(intel); +} + + + +/** + * Update the following fields for rendering to a user-created FBO: + *   intel->numClipRects + *   intel->pClipRects + *   intel->drawX + *   intel->drawY + */ +static void +intelSetRenderbufferClipRects(struct intel_context *intel) +{ +   assert(intel->ctx.DrawBuffer->Width > 0); +   assert(intel->ctx.DrawBuffer->Height > 0); +   intel->fboRect.x1 = 0; +   intel->fboRect.y1 = 0; +   intel->fboRect.x2 = intel->ctx.DrawBuffer->Width; +   intel->fboRect.y2 = intel->ctx.DrawBuffer->Height; +   intel->numClipRects = 1; +   intel->pClipRects = &intel->fboRect; +   intel->drawX = 0; +   intel->drawY = 0; +} + + +/** + * As above, but for rendering to front buffer of a window. + * \sa intelSetRenderbufferClipRects + */ +static void +intelSetFrontClipRects(struct intel_context *intel) +{ +   __DRIdrawablePrivate *dPriv = intel->driDrawable; + +   if (!dPriv) +      return; + +   intel->numClipRects = dPriv->numClipRects; +   intel->pClipRects = dPriv->pClipRects; +   intel->drawX = dPriv->x; +   intel->drawY = dPriv->y; +} + + +/** + * As above, but for rendering to back buffer of a window. + */ +static void +intelSetBackClipRects(struct intel_context *intel) +{ +   __DRIdrawablePrivate *dPriv = intel->driDrawable; + +   if (!dPriv) +      return; + +   if (intel->sarea->pf_enabled == 0 && dPriv->numBackClipRects == 0) { +      /* use the front clip rects */ +      intel->numClipRects = dPriv->numClipRects; +      intel->pClipRects = dPriv->pClipRects; +      intel->drawX = dPriv->x; +      intel->drawY = dPriv->y; +   } +   else { +      /* use the back clip rects */ +      intel->numClipRects = dPriv->numBackClipRects; +      intel->pClipRects = dPriv->pBackClipRects; +      intel->drawX = dPriv->backX; +      intel->drawY = dPriv->backY; +   } +} + + +/** + * This will be called whenever the currently bound window is moved/resized. + * XXX: actually, it seems to NOT be called when the window is only moved (BP). + */ +void +intelWindowMoved(struct intel_context *intel) +{ +   GLcontext *ctx = &intel->ctx; + +   if (!intel->ctx.DrawBuffer) { +      /* when would this happen? -BP */ +      intelSetFrontClipRects(intel); +   } +   else if (intel->ctx.DrawBuffer->Name != 0) { +      /* drawing to user-created FBO - do nothing */ +      /* Cliprects would be set from intelDrawBuffer() */ +   } +   else { +      /* drawing to a window */ +      switch (intel->ctx.DrawBuffer->_ColorDrawBufferMask[0]) { +      case BUFFER_BIT_FRONT_LEFT: +         intelSetFrontClipRects(intel); +         break; +      case BUFFER_BIT_BACK_LEFT: +         intelSetBackClipRects(intel); +         break; +      default: +         /* glDrawBuffer(GL_NONE or GL_FRONT_AND_BACK): software fallback */ +         intelSetFrontClipRects(intel); +      } +   } + +   /* this update Mesa's notion of window size */ +   if (ctx->WinSysDrawBuffer) { +      _mesa_resize_framebuffer(ctx, ctx->WinSysDrawBuffer, +                               intel->driDrawable->w, intel->driDrawable->h); +   } + +   if (intel->intelScreen->driScrnPriv->ddxMinor >= 7 && intel->driDrawable) { +      __DRIdrawablePrivate *dPriv = intel->driDrawable; +      drmI830Sarea *sarea = intel->sarea; +      drm_clip_rect_t drw_rect = { .x1 = dPriv->x, .x2 = dPriv->x + dPriv->w, +				   .y1 = dPriv->y, .y2 = dPriv->y + dPriv->h }; +      drm_clip_rect_t pipeA_rect = { .x1 = sarea->pipeA_x, .y1 = sarea->pipeA_y, +				     .x2 = sarea->pipeA_x + sarea->pipeA_w, +				     .y2 = sarea->pipeA_y + sarea->pipeA_h }; +      drm_clip_rect_t pipeB_rect = { .x1 = sarea->pipeB_x, .y1 = sarea->pipeB_y, +				     .x2 = sarea->pipeB_x + sarea->pipeB_w, +				     .y2 = sarea->pipeB_y + sarea->pipeB_h }; +      GLint areaA = driIntersectArea( drw_rect, pipeA_rect ); +      GLint areaB = driIntersectArea( drw_rect, pipeB_rect ); +      GLuint flags = intel->vblank_flags; + +      if (areaB > areaA || (areaA == areaB && areaB > 0)) { +	 flags = intel->vblank_flags | VBLANK_FLAG_SECONDARY; +      } else { +	 flags = intel->vblank_flags & ~VBLANK_FLAG_SECONDARY; +      } + +      if (flags != intel->vblank_flags) { +	 intel->vblank_flags = flags; +	 driGetCurrentVBlank(dPriv, intel->vblank_flags, &intel->vbl_seq); +      } +   } else { +      intel->vblank_flags &= ~VBLANK_FLAG_SECONDARY; +   } + +   /* Update hardware scissor */ +   ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y, +                       ctx->Scissor.Width, ctx->Scissor.Height); +} + + + +/* A true meta version of this would be very simple and additionally + * machine independent.  Maybe we'll get there one day. + */ +static void +intelClearWithTris(struct intel_context *intel, +                   GLbitfield mask, +                   GLboolean all, GLint cx, GLint cy, GLint cw, GLint ch) +{ +   GLcontext *ctx = &intel->ctx; +   drm_clip_rect_t clear; + +   if (INTEL_DEBUG & DEBUG_BLIT) +      _mesa_printf("%s 0x%x\n", __FUNCTION__, mask); + +   LOCK_HARDWARE(intel); + +   /* XXX FBO: was: intel->driDrawable->numClipRects */ +   if (intel->numClipRects) { +      GLuint buf; + +      intel->vtbl.install_meta_state(intel); + + +      /* Refresh the cx/y/w/h values as they may have been invalidated +       * by a new window position or size picked up when we did +       * LOCK_HARDWARE above.  The values passed by mesa are not +       * reliable. +       */ +      { +         cx = ctx->DrawBuffer->_Xmin; +         cy = ctx->DrawBuffer->_Ymin; +         ch = ctx->DrawBuffer->_Ymax - ctx->DrawBuffer->_Ymin; +         cw = ctx->DrawBuffer->_Xmax - ctx->DrawBuffer->_Xmin; +      } + +      /* note: regardless of 'all', cx, cy, cw, ch are now correct */ +      clear.x1 = cx; +      clear.y1 = cy; +      clear.x2 = cx + cw; +      clear.y2 = cy + ch; + +      /* Back and stencil cliprects are the same.  Try and do both +       * buffers at once: +       */ +      if (mask & +          (BUFFER_BIT_BACK_LEFT | BUFFER_BIT_STENCIL | BUFFER_BIT_DEPTH)) { +         struct intel_region *backRegion = +            intel_get_rb_region(ctx->DrawBuffer, BUFFER_BACK_LEFT); +         struct intel_region *depthRegion = +            intel_get_rb_region(ctx->DrawBuffer, BUFFER_DEPTH); +         const GLuint clearColor = (backRegion && backRegion->cpp == 4) +            ? intel->ClearColor8888 : intel->ClearColor565; + +         intel->vtbl.meta_draw_region(intel, backRegion, depthRegion); + +         if (mask & BUFFER_BIT_BACK_LEFT) +            intel->vtbl.meta_color_mask(intel, GL_TRUE); +         else +            intel->vtbl.meta_color_mask(intel, GL_FALSE); + +         if (mask & BUFFER_BIT_STENCIL) +            intel->vtbl.meta_stencil_replace(intel, +                                             intel->ctx.Stencil.WriteMask[0], +                                             intel->ctx.Stencil.Clear); +         else +            intel->vtbl.meta_no_stencil_write(intel); + +         if (mask & BUFFER_BIT_DEPTH) +            intel->vtbl.meta_depth_replace(intel); +         else +            intel->vtbl.meta_no_depth_write(intel); + +         /* XXX: Using INTEL_BATCH_NO_CLIPRECTS here is dangerous as the +          * drawing origin may not be correctly emitted. +          */ +         intel_meta_draw_quad(intel, clear.x1, clear.x2, clear.y1, clear.y2, intel->ctx.Depth.Clear, clearColor, 0, 0, 0, 0);   /* texcoords */ + +         mask &= +            ~(BUFFER_BIT_BACK_LEFT | BUFFER_BIT_STENCIL | BUFFER_BIT_DEPTH); +      } + +      /* clear the remaining (color) renderbuffers */ +      for (buf = 0; buf < BUFFER_COUNT && mask; buf++) { +         const GLuint bufBit = 1 << buf; +         if (mask & bufBit) { +            struct intel_renderbuffer *irbColor = +               intel_renderbuffer(ctx->DrawBuffer-> +                                  Attachment[buf].Renderbuffer); +            GLuint color = (irbColor->region->cpp == 4) +               ? intel->ClearColor8888 : intel->ClearColor565; + +            ASSERT(irbColor); + +            intel->vtbl.meta_no_depth_write(intel); +            intel->vtbl.meta_no_stencil_write(intel); +            intel->vtbl.meta_color_mask(intel, GL_TRUE); +            intel->vtbl.meta_draw_region(intel, irbColor->region, NULL); + +            /* XXX: Using INTEL_BATCH_NO_CLIPRECTS here is dangerous as the +             * drawing origin may not be correctly emitted. +             */ +            intel_meta_draw_quad(intel, clear.x1, clear.x2, clear.y1, clear.y2, 0,      /* depth clear val */ +                                 color, 0, 0, 0, 0);    /* texcoords */ + +            mask &= ~bufBit; +         } +      } + +      intel->vtbl.leave_meta_state(intel); +      intel_batchbuffer_flush(intel->batch); +   } +   UNLOCK_HARDWARE(intel); +} + + + + +/** + * Copy the window contents named by dPriv to the rotated (or reflected) + * color buffer. + * srcBuf is BUFFER_BIT_FRONT_LEFT or BUFFER_BIT_BACK_LEFT to indicate the source. + */ +void +intelRotateWindow(struct intel_context *intel, +                  __DRIdrawablePrivate * dPriv, GLuint srcBuf) +{ +   intelScreenPrivate *screen = intel->intelScreen; +   drm_clip_rect_t fullRect; +   struct intel_region *src; +   const drm_clip_rect_t *clipRects; +   int numClipRects; +   int i; +   GLenum format, type; + +   int xOrig, yOrig; +   int origNumClipRects; +   drm_clip_rect_t *origRects; + +   /* +    * set up hardware state +    */ +   intelFlush(&intel->ctx); + +   LOCK_HARDWARE(intel); + +   if (!intel->numClipRects) { +      UNLOCK_HARDWARE(intel); +      return; +   } + +   intel->vtbl.install_meta_state(intel); + +   intel->vtbl.meta_no_depth_write(intel); +   intel->vtbl.meta_no_stencil_write(intel); +   intel->vtbl.meta_color_mask(intel, GL_FALSE); + + +   /* save current drawing origin and cliprects (restored at end) */ +   xOrig = intel->drawX; +   yOrig = intel->drawY; +   origNumClipRects = intel->numClipRects; +   origRects = intel->pClipRects; + +   /* +    * set drawing origin, cliprects for full-screen access to rotated screen +    */ +   fullRect.x1 = 0; +   fullRect.y1 = 0; +   fullRect.x2 = screen->rotatedWidth; +   fullRect.y2 = screen->rotatedHeight; +   intel->drawX = 0; +   intel->drawY = 0; +   intel->numClipRects = 1; +   intel->pClipRects = &fullRect; + +   intel->vtbl.meta_draw_region(intel, screen->rotated_region, NULL);    /* ? */ + +   if (srcBuf == BUFFER_BIT_FRONT_LEFT) { +      src = intel->intelScreen->front_region; +      clipRects = dPriv->pClipRects; +      numClipRects = dPriv->numClipRects; +   } +   else { +      src = intel->intelScreen->back_region; +      clipRects = dPriv->pBackClipRects; +      numClipRects = dPriv->numBackClipRects; +   } + +   if (src->cpp == 4) { +      format = GL_BGRA; +      type = GL_UNSIGNED_BYTE; +   } +   else { +      format = GL_BGR; +      type = GL_UNSIGNED_SHORT_5_6_5_REV; +   } + +   /* set the whole screen up as a texture to avoid alignment issues */ +   intel->vtbl.meta_tex_rect_source(intel, +                                    src->buffer, +                                    screen->width, +                                    screen->height, src->pitch, format, type); + +   intel->vtbl.meta_texture_blend_replace(intel); + +   /* +    * loop over the source window's cliprects +    */ +   for (i = 0; i < numClipRects; i++) { +      int srcX0 = clipRects[i].x1; +      int srcY0 = clipRects[i].y1; +      int srcX1 = clipRects[i].x2; +      int srcY1 = clipRects[i].y2; +      GLfloat verts[4][2], tex[4][2]; +      int j; + +      /* build vertices for four corners of clip rect */ +      verts[0][0] = srcX0; +      verts[0][1] = srcY0; +      verts[1][0] = srcX1; +      verts[1][1] = srcY0; +      verts[2][0] = srcX1; +      verts[2][1] = srcY1; +      verts[3][0] = srcX0; +      verts[3][1] = srcY1; + +      /* .. and texcoords */ +      tex[0][0] = srcX0; +      tex[0][1] = srcY0; +      tex[1][0] = srcX1; +      tex[1][1] = srcY0; +      tex[2][0] = srcX1; +      tex[2][1] = srcY1; +      tex[3][0] = srcX0; +      tex[3][1] = srcY1; + +      /* transform coords to rotated screen coords */ + +      for (j = 0; j < 4; j++) { +         matrix23TransformCoordf(&screen->rotMatrix, +                                 &verts[j][0], &verts[j][1]); +      } + +      /* draw polygon to map source image to dest region */ +      intel_meta_draw_poly(intel, 4, verts, 0, 0, tex); + +   }                            /* cliprect loop */ + +   intel->vtbl.leave_meta_state(intel); +   intel_batchbuffer_flush(intel->batch); + +   /* restore original drawing origin and cliprects */ +   intel->drawX = xOrig; +   intel->drawY = yOrig; +   intel->numClipRects = origNumClipRects; +   intel->pClipRects = origRects; + +   UNLOCK_HARDWARE(intel); +} + + +/** + * Called by ctx->Driver.Clear. + */ +static void +intelClear(GLcontext * ctx, +           GLbitfield mask, +           GLboolean all, GLint cx, GLint cy, GLint cw, GLint ch) +{ +   struct intel_context *intel = intel_context(ctx); +   const GLuint colorMask = *((GLuint *) & ctx->Color.ColorMask); +   GLbitfield tri_mask = 0; +   GLbitfield blit_mask = 0; +   GLbitfield swrast_mask = 0; +   GLuint i; + +   if (0) +      fprintf(stderr, "%s\n", __FUNCTION__); + +   /* HW color buffers (front, back, aux, generic FBO, etc) */ +   if (colorMask == ~0) { +      /* clear all R,G,B,A */ +      /* XXX FBO: need to check if colorbuffers are software RBOs! */ +      blit_mask |= (mask & BUFFER_BITS_COLOR); +   } +   else { +      /* glColorMask in effect */ +      tri_mask |= (mask & BUFFER_BITS_COLOR); +   } + +   /* HW stencil */ +   if (mask & BUFFER_BIT_STENCIL) { +      const struct intel_region *stencilRegion +         = intel_get_rb_region(ctx->DrawBuffer, BUFFER_STENCIL); +      if (stencilRegion) { +         /* have hw stencil */ +         if ((ctx->Stencil.WriteMask[0] & 0xff) != 0xff) { +            /* not clearing all stencil bits, so use triangle clearing */ +            tri_mask |= BUFFER_BIT_STENCIL; +         } +         else { +            /* clearing all stencil bits, use blitting */ +            blit_mask |= BUFFER_BIT_STENCIL; +         } +      } +   } + +   /* HW depth */ +   if (mask & BUFFER_BIT_DEPTH) { +      /* clear depth with whatever method is used for stencil (see above) */ +      if (tri_mask & BUFFER_BIT_STENCIL) +         tri_mask |= BUFFER_BIT_DEPTH; +      else +         blit_mask |= BUFFER_BIT_DEPTH; +   } + +   /* SW fallback clearing */ +   swrast_mask = mask & ~tri_mask & ~blit_mask; + +   for (i = 0; i < BUFFER_COUNT; i++) { +      GLuint bufBit = 1 << i; +      if ((blit_mask | tri_mask) & bufBit) { +         if (!ctx->DrawBuffer->Attachment[i].Renderbuffer->ClassID) { +            blit_mask &= ~bufBit; +            tri_mask &= ~bufBit; +            swrast_mask |= bufBit; +         } +      } +   } + + +   intelFlush(ctx);             /* XXX intelClearWithBlit also does this */ + +   if (blit_mask) +      intelClearWithBlit(ctx, blit_mask, all, cx, cy, cw, ch); + +   if (tri_mask) +      intelClearWithTris(intel, tri_mask, all, cx, cy, cw, ch); + +   if (swrast_mask) +      _swrast_Clear(ctx, swrast_mask, all, cx, cy, cw, ch); +} + + + +/* Flip the front & back buffers + */ +static void +intelPageFlip(const __DRIdrawablePrivate * dPriv) +{ +#if 0 +   struct intel_context *intel; +   int tmp, ret; + +   if (INTEL_DEBUG & DEBUG_IOCTL) +      fprintf(stderr, "%s\n", __FUNCTION__); + +   assert(dPriv); +   assert(dPriv->driContextPriv); +   assert(dPriv->driContextPriv->driverPrivate); + +   intel = (struct intel_context *) 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 +} + +#if 0 +void +intelSwapBuffers(__DRIdrawablePrivate * dPriv) +{ +   if (dPriv->driverPrivate) { +      const struct gl_framebuffer *fb +         = (struct gl_framebuffer *) dPriv->driverPrivate; +      if (fb->Visual.doubleBufferMode) { +         GET_CURRENT_CONTEXT(ctx); +         if (ctx && ctx->DrawBuffer == fb) { +            _mesa_notifySwapBuffers(ctx);       /* flush pending rendering */ +         } +         if (0 /*intel->doPageFlip */ ) {       /* doPageFlip is never set !!! */ +            intelPageFlip(dPriv); +         } +         else { +            intelCopyBuffer(dPriv); +         } +      } +   } +   else { +      _mesa_problem(NULL, +                    "dPriv has no gl_framebuffer pointer in intelSwapBuffers"); +   } +} +#else +/* Trunk version: + */ +void +intelSwapBuffers(__DRIdrawablePrivate * dPriv) +{ +   if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) { +      GET_CURRENT_CONTEXT(ctx); +      struct intel_context *intel; + +      if (ctx == NULL) +	 return; + +      intel = intel_context(ctx); + +      if (ctx->Visual.doubleBufferMode) { +         intelScreenPrivate *screen = intel->intelScreen; +         _mesa_notifySwapBuffers(ctx);  /* flush pending rendering comands */ +         if (0 /*intel->doPageFlip */ ) {       /* doPageFlip is never set !!! */ +            intelPageFlip(dPriv); +         } +         else { +            intelCopyBuffer(dPriv, NULL); +         } +         if (screen->current_rotation != 0) { +            intelRotateWindow(intel, dPriv, BUFFER_BIT_FRONT_LEFT); +         } +      } +   } +   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__); +   } +} +#endif + +void +intelCopySubBuffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h) +{ +   if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) { +      struct intel_context *intel = +         (struct intel_context *) dPriv->driContextPriv->driverPrivate; +      GLcontext *ctx = &intel->ctx; + +      if (ctx->Visual.doubleBufferMode) { +         drm_clip_rect_t rect; +         rect.x1 = x + dPriv->x; +         rect.y1 = (dPriv->h - y - h) + dPriv->y; +         rect.x2 = rect.x1 + w; +         rect.y2 = rect.y1 + h; +         _mesa_notifySwapBuffers(ctx);  /* flush pending rendering comands */ +         intelCopyBuffer(dPriv, &rect); +      } +   } +   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__); +   } +} + + +/** + * Update the hardware state for drawing into a window or framebuffer object. + * + * Called by glDrawBuffer, glBindFramebufferEXT, MakeCurrent, and other + * places within the driver. + * + * Basically, this needs to be called any time the current framebuffer + * changes, the renderbuffers change, or we need to draw into different + * color buffers. + */ +void +intel_draw_buffer(GLcontext * ctx, struct gl_framebuffer *fb) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_region *colorRegion, *depthRegion = NULL; +   struct intel_renderbuffer *irbDepth = NULL, *irbStencil = NULL; +   int front = 0;               /* drawing to front color buffer? */ + +   if (!fb) { +      /* this can happen during the initial context initialization */ +      return; +   } + +   /* Do this here, note core Mesa, since this function is called from +    * many places within the driver. +    */ +   if (ctx->NewState & (_NEW_BUFFERS | _NEW_COLOR | _NEW_PIXEL)) { +      /* this updates the DrawBuffer->_NumColorDrawBuffers fields, etc */ +      _mesa_update_framebuffer(ctx); +      /* this updates the DrawBuffer's Width/Height if it's a FBO */ +      _mesa_update_draw_buffer_bounds(ctx); +   } + +   if (fb->_Status != GL_FRAMEBUFFER_COMPLETE_EXT) { +      /* this may occur when we're called by glBindFrameBuffer() during +       * the process of someone setting up renderbuffers, etc. +       */ +      /*_mesa_debug(ctx, "DrawBuffer: incomplete user FBO\n");*/ +      return; +   } + +   if (fb->Name) +      intel_validate_paired_depth_stencil(ctx, fb); + +   /* +    * How many color buffers are we drawing into? +    */ +   if (fb->_NumColorDrawBuffers[0] != 1 +#if 0 +       /* XXX FBO temporary - always use software rendering */ +       || 1 +#endif +      ) { +      /* writing to 0 or 2 or 4 color buffers */ +      /*_mesa_debug(ctx, "Software rendering\n");*/ +      FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE); +      front = 1;                /* might not have back color buffer */ +   } +   else { +      /* draw to exactly one color buffer */ +      /*_mesa_debug(ctx, "Hardware rendering\n");*/ +      FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE); +      if (fb->_ColorDrawBufferMask[0] == BUFFER_BIT_FRONT_LEFT) { +         front = 1; +      } +   } + +   /* +    * Get the intel_renderbuffer for the colorbuffer we're drawing into. +    * And set up cliprects. +    */ +   if (fb->Name == 0) { +      /* drawing to window system buffer */ +      if (intel->sarea->pf_current_page == 1) { +         /* page flipped back/front */ +         front ^= 1; +      } +      if (front) { +         intelSetFrontClipRects(intel); +         colorRegion = intel_get_rb_region(fb, BUFFER_FRONT_LEFT); +      } +      else { +         intelSetBackClipRects(intel); +         colorRegion = intel_get_rb_region(fb, BUFFER_BACK_LEFT); +      } +   } +   else { +      /* drawing to user-created FBO */ +      struct intel_renderbuffer *irb; +      intelSetRenderbufferClipRects(intel); +      irb = intel_renderbuffer(fb->_ColorDrawBuffers[0][0]); +      colorRegion = (irb && irb->region) ? irb->region : NULL; +   } + +   /* Update culling direction which changes depending on the +    * orientation of the buffer: +    */ +   if (ctx->Driver.FrontFace) +      ctx->Driver.FrontFace(ctx, ctx->Polygon.FrontFace); +   else +      ctx->NewState |= _NEW_POLYGON; + +   if (!colorRegion) { +      FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_TRUE); +   } +   else { +      FALLBACK(intel, INTEL_FALLBACK_DRAW_BUFFER, GL_FALSE); +   } + +   /*** +    *** Get depth buffer region and check if we need a software fallback. +    *** Note that the depth buffer is usually a DEPTH_STENCIL buffer. +    ***/ +   if (fb->_DepthBuffer && fb->_DepthBuffer->Wrapped) { +      irbDepth = intel_renderbuffer(fb->_DepthBuffer->Wrapped); +      if (irbDepth->region) { +         FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE); +         depthRegion = irbDepth->region; +      } +      else { +         FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_TRUE); +         depthRegion = NULL; +      } +   } +   else { +      /* not using depth buffer */ +      FALLBACK(intel, INTEL_FALLBACK_DEPTH_BUFFER, GL_FALSE); +      depthRegion = NULL; +   } + +   /*** +    *** Stencil buffer +    *** This can only be hardware accelerated if we're using a +    *** combined DEPTH_STENCIL buffer (for now anyway). +    ***/ +   if (fb->_StencilBuffer && fb->_StencilBuffer->Wrapped) { +      irbStencil = intel_renderbuffer(fb->_StencilBuffer->Wrapped); +      if (irbStencil && irbStencil->region) { +         ASSERT(irbStencil->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); +         FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE); +         /* need to re-compute stencil hw state */ +         ctx->Driver.Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled); +         if (!depthRegion) +            depthRegion = irbStencil->region; +      } +      else { +         FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_TRUE); +      } +   } +   else { +      /* XXX FBO: instead of FALSE, pass ctx->Stencil.Enabled ??? */ +      FALLBACK(intel, INTEL_FALLBACK_STENCIL_BUFFER, GL_FALSE); +      /* need to re-compute stencil hw state */ +      ctx->Driver.Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled); +   } + + +   /** +    ** Release old regions, reference new regions +    **/ +#if 0                           /* XXX FBO: this seems to be redundant with i915_state_draw_region() */ +   if (intel->draw_region != colorRegion) { +      intel_region_release(&intel->draw_region); +      intel_region_reference(&intel->draw_region, colorRegion); +   } +   if (intel->intelScreen->depth_region != depthRegion) { +      intel_region_release(&intel->intelScreen->depth_region); +      intel_region_reference(&intel->intelScreen->depth_region, depthRegion); +   } +#endif + +   intel->vtbl.set_draw_region(intel, colorRegion, depthRegion); + +   /* update viewport since it depends on window size */ +   ctx->Driver.Viewport(ctx, ctx->Viewport.X, ctx->Viewport.Y, +                        ctx->Viewport.Width, ctx->Viewport.Height); + +   /* Update hardware scissor */ +   ctx->Driver.Scissor(ctx, ctx->Scissor.X, ctx->Scissor.Y, +                       ctx->Scissor.Width, ctx->Scissor.Height); +} + + +static void +intelDrawBuffer(GLcontext * ctx, GLenum mode) +{ +   intel_draw_buffer(ctx, ctx->DrawBuffer); +} + + +static void +intelReadBuffer(GLcontext * ctx, GLenum mode) +{ +   if (ctx->ReadBuffer == ctx->DrawBuffer) { +      /* This will update FBO completeness status. +       * A framebuffer will be incomplete if the GL_READ_BUFFER setting +       * refers to a missing renderbuffer.  Calling glReadBuffer can set +       * that straight and can make the drawing buffer complete. +       */ +      intel_draw_buffer(ctx, ctx->DrawBuffer); +   } +   /* Generally, functions which read pixels (glReadPixels, glCopyPixels, etc) +    * reference ctx->ReadBuffer and do appropriate state checks. +    */ +} + + +void +intelInitBufferFuncs(struct dd_function_table *functions) +{ +   functions->Clear = intelClear; +   functions->GetBufferSize = intelBufferSize; +   functions->ResizeBuffers = _mesa_resize_framebuffer; +   functions->DrawBuffer = intelDrawBuffer; +   functions->ReadBuffer = intelReadBuffer; +} diff --git a/src/mesa/drivers/dri/i915tex/intel_buffers.h b/src/mesa/drivers/dri/i915tex/intel_buffers.h new file mode 100644 index 0000000000..0faf055347 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_buffers.h @@ -0,0 +1,56 @@ +/************************************************************************** + *  + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#ifndef INTEL_BUFFERS_H +#define INTEL_BUFFERS_H + + +struct intel_context; + + +extern GLboolean +intel_intersect_cliprects(drm_clip_rect_t * dest, +                          const drm_clip_rect_t * a, +                          const drm_clip_rect_t * b); + +extern struct intel_region *intel_readbuf_region(struct intel_context *intel); + +extern struct intel_region *intel_drawbuf_region(struct intel_context *intel); + +extern void intelSwapBuffers(__DRIdrawablePrivate * dPriv); + +extern void intelWindowMoved(struct intel_context *intel); + +extern void intel_draw_buffer(GLcontext * ctx, struct gl_framebuffer *fb); + +extern void intelInitBufferFuncs(struct dd_function_table *functions); + +extern void +intelRotateWindow(struct intel_context *intel, +                  __DRIdrawablePrivate * dPriv, GLuint srcBuf); + +#endif /* INTEL_BUFFERS_H */ diff --git a/src/mesa/drivers/dri/i915tex/intel_context.c b/src/mesa/drivers/dri/i915tex/intel_context.c new file mode 100644 index 0000000000..3d51a6341c --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_context.c @@ -0,0 +1,707 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + + +#include "glheader.h" +#include "context.h" +#include "matrix.h" +#include "simple_list.h" +#include "extensions.h" +#include "framebuffer.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 "intel_buffers.h" +#include "intel_tex.h" +#include "intel_span.h" +#include "intel_tris.h" +#include "intel_ioctl.h" +#include "intel_batchbuffer.h" +#include "intel_blit.h" +#include "intel_pixel.h" +#include "intel_regions.h" +#include "intel_buffer_objects.h" +#include "intel_fbo.h" + +#include "vblank.h" +#include "utils.h" +#include "xmlpool.h"            /* for symbolic values of enum-type options */ +#ifndef INTEL_DEBUG +int INTEL_DEBUG = (0); +#endif + +#define need_GL_ARB_multisample +#define need_GL_ARB_point_parameters +#define need_GL_ARB_texture_compression +#define need_GL_ARB_vertex_buffer_object +#define need_GL_ARB_vertex_program +#define need_GL_ARB_window_pos +#define need_GL_EXT_blend_color +#define need_GL_EXT_blend_equation_separate +#define need_GL_EXT_blend_func_separate +#define need_GL_EXT_blend_minmax +#define need_GL_EXT_cull_vertex +#define need_GL_EXT_fog_coord +#define need_GL_EXT_framebuffer_object +#define need_GL_EXT_multi_draw_arrays +#define need_GL_EXT_secondary_color +#define need_GL_NV_vertex_program +#include "extension_helper.h" + + +#define DRIVER_DATE                     "20060929" + +_glthread_Mutex lockMutex; +static GLboolean lockMutexInit = GL_FALSE; + + +static 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; +      case PCI_CHIP_I915_GM: +         chipset = "Intel(R) 915GM"; +         break; +      case PCI_CHIP_I945_G: +         chipset = "Intel(R) 945G"; +         break; +      case PCI_CHIP_I945_GM: +         chipset = "Intel(R) 945GM"; +         break; +      default: +         chipset = "Unknown Intel Chipset"; +         break; +      } + +      (void) driGetRendererString(buffer, chipset, DRIVER_DATE, 0); +      return (GLubyte *) buffer; + +   default: +      return NULL; +   } +} + + +/** + * Extension strings exported by the intel driver. + * + * \note + * It appears that ARB_texture_env_crossbar has "disappeared" compared to the + * old i830-specific driver. + */ +const struct dri_extension card_extensions[] = { +   {"GL_ARB_multisample", GL_ARB_multisample_functions}, +   {"GL_ARB_multitexture", NULL}, +   {"GL_ARB_point_parameters", GL_ARB_point_parameters_functions}, +   {"GL_ARB_texture_border_clamp", NULL}, +   {"GL_ARB_texture_compression", GL_ARB_texture_compression_functions}, +   {"GL_ARB_texture_cube_map", NULL}, +   {"GL_ARB_texture_env_add", NULL}, +   {"GL_ARB_texture_env_combine", NULL}, +   {"GL_ARB_texture_env_dot3", NULL}, +   {"GL_ARB_texture_mirrored_repeat", NULL}, +   {"GL_ARB_texture_rectangle", NULL}, +   {"GL_ARB_vertex_buffer_object", GL_ARB_vertex_buffer_object_functions}, +   {"GL_ARB_pixel_buffer_object", NULL}, +   {"GL_ARB_vertex_program", GL_ARB_vertex_program_functions}, +   {"GL_ARB_window_pos", GL_ARB_window_pos_functions}, +   {"GL_EXT_blend_color", GL_EXT_blend_color_functions}, +   {"GL_EXT_blend_equation_separate", +    GL_EXT_blend_equation_separate_functions}, +   {"GL_EXT_blend_func_separate", GL_EXT_blend_func_separate_functions}, +   {"GL_EXT_blend_minmax", GL_EXT_blend_minmax_functions}, +   {"GL_EXT_blend_subtract", NULL}, +   {"GL_EXT_cull_vertex", GL_EXT_cull_vertex_functions}, +   {"GL_EXT_fog_coord", GL_EXT_fog_coord_functions}, +   {"GL_EXT_framebuffer_object", GL_EXT_framebuffer_object_functions}, +   {"GL_EXT_multi_draw_arrays", GL_EXT_multi_draw_arrays_functions}, +#if 1                           /* XXX FBO temporary? */ +   {"GL_EXT_packed_depth_stencil", NULL}, +#endif +   {"GL_EXT_secondary_color", GL_EXT_secondary_color_functions}, +   {"GL_EXT_stencil_wrap", NULL}, +   {"GL_EXT_texture_edge_clamp", NULL}, +   {"GL_EXT_texture_env_combine", NULL}, +   {"GL_EXT_texture_env_dot3", NULL}, +   {"GL_EXT_texture_filter_anisotropic", NULL}, +   {"GL_EXT_texture_lod_bias", NULL}, +   {"GL_3DFX_texture_compression_FXT1", NULL}, +   {"GL_APPLE_client_storage", NULL}, +   {"GL_MESA_pack_invert", NULL}, +   {"GL_MESA_ycbcr_texture", NULL}, +   {"GL_NV_blend_square", NULL}, +   {"GL_NV_vertex_program", GL_NV_vertex_program_functions}, +   {"GL_NV_vertex_program1_1", NULL}, +/*     { "GL_SGIS_generate_mipmap",           NULL }, */ +   {NULL, NULL} +}; + +extern const struct tnl_pipeline_stage _intel_render_stage; + +static const struct tnl_pipeline_stage *intel_pipeline[] = { +   &_tnl_vertex_transform_stage, +   &_tnl_vertex_cull_stage, +   &_tnl_normal_transform_stage, +   &_tnl_lighting_stage, +   &_tnl_fog_coordinate_stage, +   &_tnl_texgen_stage, +   &_tnl_texture_transform_stage, +   &_tnl_point_attenuation_stage, +   &_tnl_arb_vertex_program_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[] = { +   {"tex", DEBUG_TEXTURE}, +   {"state", DEBUG_STATE}, +   {"ioctl", DEBUG_IOCTL}, +   {"blit", DEBUG_BLIT}, +   {"mip", DEBUG_MIPTREE}, +   {"fall", DEBUG_FALLBACKS}, +   {"verb", DEBUG_VERBOSE}, +   {"bat", DEBUG_BATCH}, +   {"pix", DEBUG_PIXEL}, +   {"buf", DEBUG_BUFMGR}, +   {"reg", DEBUG_REGION}, +   {"fbo", DEBUG_FBO}, +   {"lock", DEBUG_LOCK}, +   {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 +intelFlush(GLcontext * ctx) +{ +   struct intel_context *intel = intel_context(ctx); + +   if (intel->Fallback) +      _swrast_flush(ctx); + +   INTEL_FIREVERTICES(intel); + +   if (intel->batch->map != intel->batch->ptr) +      intel_batchbuffer_flush(intel->batch); + +   /* XXX: Need to do an MI_FLUSH here. +    */ +} + + +/** + * Check if we need to rotate/warp the front color buffer to the + * rotated screen.  We generally need to do this when we get a glFlush + * or glFinish after drawing to the front color buffer. + */ +static void +intelCheckFrontRotate(GLcontext * ctx) +{ +   struct intel_context *intel = intel_context(ctx); +   if (intel->ctx.DrawBuffer->_ColorDrawBufferMask[0] == +       BUFFER_BIT_FRONT_LEFT) { +      intelScreenPrivate *screen = intel->intelScreen; +      if (screen->current_rotation != 0) { +         __DRIdrawablePrivate *dPriv = intel->driDrawable; +         intelRotateWindow(intel, dPriv, BUFFER_BIT_FRONT_LEFT); +      } +   } +} + + +/** + * Called via glFlush. + */ +static void +intelglFlush(GLcontext * ctx) +{ +   intelFlush(ctx); +   intelCheckFrontRotate(ctx); +} + +void +intelFinish(GLcontext * ctx) +{ +   struct intel_context *intel = intel_context(ctx); +   intelFlush(ctx); +   if (intel->batch->last_fence) { +      driFenceFinish(intel->batch->last_fence, +                     0, GL_FALSE); +      driFenceUnReference(intel->batch->last_fence); +      intel->batch->last_fence = NULL; +   } +   intelCheckFrontRotate(ctx); +} + + +void +intelInitDriverFunctions(struct dd_function_table *functions) +{ +   _mesa_init_driver_functions(functions); + +   functions->Flush = intelglFlush; +   functions->Finish = intelFinish; +   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); +   intelInitBufferFuncs(functions); +} + + +GLboolean +intelInitContext(struct intel_context *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); +   int fthrottle_mode; + +   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; + +   if (!lockMutexInit) { +      lockMutexInit = GL_TRUE; +      _glthread_INIT_MUTEX(lockMutex); +   } + +   driParseConfigFiles(&intel->optionCache, &intelScreen->optionCache, +                       intel->driScreen->myNum, "i915"); + +   ctx->Const.MaxTextureMaxAnisotropy = 2.0; + +   /* This doesn't yet catch all non-conformant rendering, but it's a +    * start. +    */ +   if (getenv("INTEL_STRICT_CONFORMANCE")) { +      intel->strict_conformance = 1; +   } + +   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; + +   ctx->Const.MaxColorAttachments = 4;  /* XXX FBO: review this */ + +   /* 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_stipple = 1; + +   /* XXX FBO: this doesn't seem to be used anywhere */ +   switch (mesaVis->depthBits) { +   case 0:                     /* what to do in this case? */ +   case 16: +      intel->polygon_offset_scale = 1.0 / 0xffff; +      break; +   case 24: +      intel->polygon_offset_scale = 2.0 / 0xffffff;     /* req'd to pass glean */ +      break; +   default: +      assert(0); +      break; +   } + +   /* Initialize swrast, tnl driver tables: */ +   intelInitSpanFuncs(ctx); +   intelInitTriFuncs(ctx); + + +   intel->RenderIndex = ~0; + +   fthrottle_mode = driQueryOptioni(&intel->optionCache, "fthrottle_mode"); +   intel->iw.irq_seq = -1; +   intel->irqsEmitted = 0; + +   intel->do_irqs = (intel->intelScreen->irq_active && +                     fthrottle_mode == DRI_CONF_FTHROTTLE_IRQS); + +   intel->do_usleeps = (fthrottle_mode == DRI_CONF_FTHROTTLE_USLEEPS); + +   intel->vblank_flags = (intel->intelScreen->irq_active != 0) +      ? driGetDefaultVBlankFlags(&intel->optionCache) : VBLANK_FLAG_NO_IRQ; + +   (*dri_interface->getUST) (&intel->swap_ust); +   _math_matrix_ctr(&intel->ViewportMatrix); + +   /* Disable imaging extension until convolution is working in +    * teximage paths: +    */ +   driInitExtensions(ctx, card_extensions, +/* 		      GL_TRUE, */ +                     GL_FALSE); + + +   intel->batch = intel_batchbuffer_alloc(intel); +   intel->last_swap_fence = NULL; +   intel->first_swap_fence = NULL; + +   intel_bufferobj_init(intel); +   intel_fbo_init(intel); + +   if (intel->ctx.Mesa_DXTn) { +      _mesa_enable_extension(ctx, "GL_EXT_texture_compression_s3tc"); +      _mesa_enable_extension(ctx, "GL_S3_s3tc"); +   } +   else if (driQueryOptionb(&intel->optionCache, "force_s3tc_enable")) { +      _mesa_enable_extension(ctx, "GL_EXT_texture_compression_s3tc"); +   } + +   intel->prim.primitive = ~0; + + +#if DO_DEBUG +   INTEL_DEBUG = driParseDebugString(getenv("INTEL_DEBUG"), debug_control); +#endif + +   if (getenv("INTEL_NO_RAST")) { +      fprintf(stderr, "disabling 3D rasterization\n"); +      FALLBACK(intel, INTEL_FALLBACK_USER, 1); +   } + +   return GL_TRUE; +} + +void +intelDestroyContext(__DRIcontextPrivate * driContextPriv) +{ +   struct intel_context *intel = +      (struct intel_context *) driContextPriv->driverPrivate; + +   assert(intel);               /* should never be null */ +   if (intel) { +      GLboolean release_texture_heaps; + +      INTEL_FIREVERTICES(intel); + +      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 */ + +      intel_batchbuffer_free(intel->batch); + +      if (intel->last_swap_fence) { +	 driFenceFinish(intel->last_swap_fence, DRM_FENCE_TYPE_EXE, GL_TRUE); +	 driFenceUnReference(intel->last_swap_fence); +	 intel->last_swap_fence = NULL; +      } +      if (intel->first_swap_fence) { +	 driFenceFinish(intel->first_swap_fence, DRM_FENCE_TYPE_EXE, GL_TRUE); +	 driFenceUnReference(intel->first_swap_fence); +	 intel->first_swap_fence = NULL; +      } + + +      if (release_texture_heaps) { +         /* This share group is about to go away, free our private +          * texture object data. +          */ +         if (INTEL_DEBUG & DEBUG_TEXTURE) +            fprintf(stderr, "do something to free texture heaps\n"); +      } + +      /* free the Mesa context */ +      _mesa_free_context_data(&intel->ctx); +   } +} + +GLboolean +intelUnbindContext(__DRIcontextPrivate * driContextPriv) +{ +   return GL_TRUE; +} + +GLboolean +intelMakeCurrent(__DRIcontextPrivate * driContextPriv, +                 __DRIdrawablePrivate * driDrawPriv, +                 __DRIdrawablePrivate * driReadPriv) +{ + +   if (driContextPriv) { +      struct intel_context *intel = +         (struct intel_context *) driContextPriv->driverPrivate; +      GLframebuffer *drawFb = (GLframebuffer *) driDrawPriv->driverPrivate; +      GLframebuffer *readFb = (GLframebuffer *) driReadPriv->driverPrivate; + + +      /* XXX FBO temporary fix-ups! */ +      /* if the renderbuffers don't have regions, init them from the context */ +      { +         struct intel_renderbuffer *irbFront +            = intel_get_renderbuffer(drawFb, BUFFER_FRONT_LEFT); +         struct intel_renderbuffer *irbBack +            = intel_get_renderbuffer(drawFb, BUFFER_BACK_LEFT); +         struct intel_renderbuffer *irbDepth +            = intel_get_renderbuffer(drawFb, BUFFER_DEPTH); +         struct intel_renderbuffer *irbStencil +            = intel_get_renderbuffer(drawFb, BUFFER_STENCIL); + +         if (irbFront && !irbFront->region) { +            intel_region_reference(&irbFront->region, intel->intelScreen->front_region); +         } +         if (irbBack && !irbBack->region) { +            intel_region_reference(&irbBack->region, intel->intelScreen->back_region); +         } +         if (irbDepth && !irbDepth->region) { +            intel_region_reference(&irbDepth->region, intel->intelScreen->depth_region); +         } +         if (irbStencil && !irbStencil->region) { +            intel_region_reference(&irbStencil->region, intel->intelScreen->depth_region); +         } +      } + +      _mesa_make_current(&intel->ctx, drawFb, readFb); + +      /* The drawbuffer won't always be updated by _mesa_make_current:  +       */ +      if (intel->ctx.DrawBuffer == drawFb) { + +	 if (intel->driDrawable != driDrawPriv) { +	    driDrawableInitVBlank(driDrawPriv, intel->vblank_flags, &intel->vbl_seq);	     +	    intel->driDrawable = driDrawPriv; +	    intelWindowMoved(intel); +	 } + +	 intel_draw_buffer(&intel->ctx, drawFb); +      } +   } +   else { +      _mesa_make_current(NULL, NULL, NULL); +   } + +   return GL_TRUE; +} + +static void +intelContendedLock(struct intel_context *intel, GLuint flags) +{ +   __DRIdrawablePrivate *dPriv = intel->driDrawable; +   __DRIscreenPrivate *sPriv = intel->driScreen; +   intelScreenPrivate *intelScreen = (intelScreenPrivate *) sPriv->private; +   drmI830Sarea *sarea = intel->sarea; + +   drmGetLock(intel->driFd, intel->hHWContext, flags); + +   if (INTEL_DEBUG & DEBUG_LOCK) +      _mesa_printf("%s - got contended lock\n", __progname); + +   /* 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 (sarea->width != intelScreen->width || +       sarea->height != intelScreen->height || +       sarea->rotation != intelScreen->current_rotation) { + +      intelUpdateScreenRotation(sPriv, sarea); + +      /*  +       * This will drop the outstanding batchbuffer on the floor +       * FIXME: This should be done for all contexts? +       */ + +      intel_batchbuffer_reset(intel->batch); + +      /* lose all primitives */ +      intel->prim.primitive = ~0; +      intel->prim.start_ptr = 0; +      intel->prim.flush = 0; + +      /* re-emit all state */ +      intel->vtbl.lost_hardware(intel); + +      /* force window update */ +      intel->lastStamp = 0; +   } + + +   /* Drawable changed? +    */ +   if (dPriv && intel->lastStamp != dPriv->lastStamp) { +      intelWindowMoved(intel); +      intel->lastStamp = dPriv->lastStamp; +   } +} + + +extern _glthread_Mutex lockMutex; + + +/* Lock the hardware and validate our state.   + */ +void LOCK_HARDWARE( struct intel_context *intel ) +{ +    char __ret=0; + +    _glthread_LOCK_MUTEX(lockMutex); +    assert(!intel->locked); + +    if (intel->swap_scheduled) { +	drmVBlank vbl; +	vbl.request.type = DRM_VBLANK_ABSOLUTE; +	if ( intel->vblank_flags & VBLANK_FLAG_SECONDARY ) { +	    vbl.request.type |= DRM_VBLANK_SECONDARY; +	} +	vbl.request.sequence = intel->vbl_seq; +	drmWaitVBlank(intel->driFd, &vbl); +	intel->swap_scheduled = 0; +    } + +    DRM_CAS(intel->driHwLock, intel->hHWContext, +        (DRM_LOCK_HELD|intel->hHWContext), __ret); + +    if (__ret) +        intelContendedLock( intel, 0 ); + +    if (INTEL_DEBUG & DEBUG_LOCK) +      _mesa_printf("%s - locked\n", __progname); + +    intel->locked = 1; +} + + +  /* Unlock the hardware using the global current context  +   */ +void UNLOCK_HARDWARE( struct intel_context *intel ) +{ +   intel->locked = 0; + +   DRM_UNLOCK(intel->driFd, intel->driHwLock, intel->hHWContext); + +   _glthread_UNLOCK_MUTEX(lockMutex); + +   if (INTEL_DEBUG & DEBUG_LOCK) +      _mesa_printf("%s - unlocked\n", __progname); +}  + diff --git a/src/mesa/drivers/dri/i915tex/intel_context.h b/src/mesa/drivers/dri/i915tex/intel_context.h new file mode 100644 index 0000000000..fa3cf58571 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_context.h @@ -0,0 +1,502 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#ifndef INTELCONTEXT_INC +#define INTELCONTEXT_INC + + + +#include "mtypes.h" +#include "drm.h" +#include "mm.h" +#include "texmem.h" + +#include "intel_screen.h" +#include "i915_drm.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) + +struct intel_region; +struct intel_context; +struct _DriBufferObject; + +typedef void (*intel_tri_func) (struct intel_context *, intelVertex *, +                                intelVertex *, intelVertex *); +typedef void (*intel_line_func) (struct intel_context *, intelVertex *, +                                 intelVertex *); +typedef void (*intel_point_func) (struct intel_context *, intelVertex *); + +#define INTEL_FALLBACK_DRAW_BUFFER	 0x1 +#define INTEL_FALLBACK_READ_BUFFER	 0x2 +#define INTEL_FALLBACK_DEPTH_BUFFER      0x4 +#define INTEL_FALLBACK_STENCIL_BUFFER    0x8 +#define INTEL_FALLBACK_USER		 0x10 +#define INTEL_FALLBACK_RENDERMODE	 0x20 + +extern void intelFallback(struct intel_context *intel, GLuint bit, +                          GLboolean mode); +#define FALLBACK( intel, bit, mode ) intelFallback( intel, bit, mode ) + + +#define INTEL_WRITE_PART  0x1 +#define INTEL_WRITE_FULL  0x2 +#define INTEL_READ        0x4 + +struct intel_texture_object +{ +   struct gl_texture_object base;       /* The "parent" object */ + +   /* The mipmap tree must include at least these levels once +    * validated: +    */ +   GLuint firstLevel; +   GLuint lastLevel; + +   /* Offset for firstLevel image: +    */ +   GLuint textureOffset; + +   /* On validation any active images held in main memory or in other +    * regions will be copied to this region and the old storage freed. +    */ +   struct intel_mipmap_tree *mt; +}; + + + +struct intel_texture_image +{ +   struct gl_texture_image base; + +   /* These aren't stored in gl_texture_image  +    */ +   GLuint level; +   GLuint face; + +   /* If intelImage->mt != NULL, image data is stored here. +    * Else if intelImage->base.Data != NULL, image is stored there. +    * Else there is no image data. +    */ +   struct intel_mipmap_tree *mt; +}; + + +#define INTEL_MAX_FIXUP 64 + +struct intel_context +{ +   GLcontext ctx;               /* the parent class */ + +   struct +   { +      void (*destroy) (struct intel_context * intel); +      void (*emit_state) (struct intel_context * intel); +      void (*lost_hardware) (struct intel_context * intel); +      void (*update_texture_state) (struct intel_context * intel); + +      void (*render_start) (struct intel_context * intel); +      void (*set_draw_region) (struct intel_context * intel, +                               struct intel_region * draw_region, +                               struct intel_region * depth_region); + +        GLuint(*flush_cmd) (void); + +      void (*reduced_primitive_state) (struct intel_context * intel, +                                       GLenum rprim); + +        GLboolean(*check_vertex_size) (struct intel_context * intel, +                                       GLuint expected); + + +      /* Metaops:  +       */ +      void (*install_meta_state) (struct intel_context * intel); +      void (*leave_meta_state) (struct intel_context * intel); + +      void (*meta_draw_region) (struct intel_context * intel, +                                struct intel_region * draw_region, +                                struct intel_region * depth_region); + +      void (*meta_color_mask) (struct intel_context * intel, GLboolean); + +      void (*meta_stencil_replace) (struct intel_context * intel, +                                    GLuint mask, GLuint clear); + +      void (*meta_depth_replace) (struct intel_context * intel); + +      void (*meta_texture_blend_replace) (struct intel_context * intel); + +      void (*meta_no_stencil_write) (struct intel_context * intel); +      void (*meta_no_depth_write) (struct intel_context * intel); +      void (*meta_no_texture) (struct intel_context * intel); + +      void (*meta_import_pixel_state) (struct intel_context * intel); + +        GLboolean(*meta_tex_rect_source) (struct intel_context * intel, +                                          struct _DriBufferObject * buffer, +                                          GLuint offset, +                                          GLuint pitch, +                                          GLuint height, +                                          GLenum format, GLenum type); +      void (*rotate_window) (struct intel_context * intel, +                             __DRIdrawablePrivate * dPriv, GLuint srcBuf); + +      void (*assert_not_dirty) (struct intel_context *intel); + +   } vtbl; + +   GLint refcount; +   GLuint Fallback; +   GLuint NewGLState; + +   struct _DriFenceObject *last_swap_fence; +   struct _DriFenceObject *first_swap_fence; + +   struct intel_batchbuffer *batch; + +   struct +   { +      GLuint id; +      GLuint primitive; +      GLubyte *start_ptr; +      void (*flush) (struct intel_context *); +   } prim; + +   GLboolean locked; +   char *prevLockFile; +   int prevLockLine; + +   GLuint ClearColor565; +   GLuint ClearColor8888; + +   /* Offsets of fields within the current vertex: +    */ +   GLuint coloroffset; +   GLuint specoffset; +   GLuint wpos_offset; +   GLuint wpos_size; + +   struct tnl_attr_map vertex_attrs[VERT_ATTRIB_MAX]; +   GLuint vertex_attr_count; + +   GLfloat polygon_offset_scale;        /* dependent on depth_scale, bpp */ + +   GLboolean hw_stipple; +   GLboolean strict_conformance; + +   /* AGP memory buffer manager: +    */ +   struct bufmgr *bm; + + +   /* State for intelvb.c and inteltris.c. +    */ +   GLuint RenderIndex; +   GLmatrix ViewportMatrix; +   GLenum render_primitive; +   GLenum reduced_primitive; +   GLuint vertex_size; +   GLubyte *verts;              /* points to tnl->clipspace.vertex_buf */ + +#if 0 +   struct intel_region *front_region;   /* XXX FBO: obsolete */ +   struct intel_region *rotated_region; /* XXX FBO: obsolete */ +   struct intel_region *back_region;    /* XXX FBO: obsolete */ +   struct intel_region *draw_region;    /* XXX FBO: rename to color_region */ +   struct intel_region *depth_region;   /**< currently bound depth/Z region */ +#endif + +   /* Fallback rasterization functions  +    */ +   intel_point_func draw_point; +   intel_line_func draw_line; +   intel_tri_func draw_tri; + +   /* These refer to the current drawing buffer: +    */ +   int drawX, drawY;            /**< origin of drawing area within region */ +   GLuint numClipRects;         /**< cliprects for drawing */ +   drm_clip_rect_t *pClipRects; +   drm_clip_rect_t fboRect;     /**< cliprect for FBO rendering */ + +   int perf_boxes; + +   GLuint do_usleeps; +   int do_irqs; +   GLuint irqsEmitted; +   drm_i915_irq_wait_t iw; + +   drm_context_t hHWContext; +   drmLock *driHwLock; +   int driFd; + +   __DRIdrawablePrivate *driDrawable; +   __DRIscreenPrivate *driScreen; +   intelScreenPrivate *intelScreen; +   drmI830Sarea *sarea; + +   GLuint lastStamp; + +   /** +    * Configuration cache +    */ +   driOptionCache optionCache; + +   /* VBI +    */ +   GLuint vbl_seq; +   GLuint vblank_flags; + +   int64_t swap_ust; +   int64_t swap_missed_ust; + +   GLuint swap_count; +   GLuint swap_missed_count; + +   GLuint swap_scheduled; +}; + +/* These are functions now: + */ +void LOCK_HARDWARE( struct intel_context *intel ); +void UNLOCK_HARDWARE( struct intel_context *intel ); + +extern char *__progname; + + +#define SUBPIXEL_X 0.125 +#define SUBPIXEL_Y 0.125 + +#define INTEL_FIREVERTICES(intel)		\ +do {						\ +   if ((intel)->prim.flush)			\ +      (intel)->prim.flush(intel);		\ +} 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) + + + +/* ================================================================ + * From linux kernel i386 header files, copes with odd sizes better + * than COPY_DWORDS would: + * XXX Put this in src/mesa/main/imports.h ??? + */ +#if defined(i386) || defined(__i386__) +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); +} +#else +#define __memcpy(a,b,c) memcpy(a,b,c) +#endif + + + +/* ================================================================ + * 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_BLIT	0x8 +#define DEBUG_MIPTREE   0x10 +#define DEBUG_FALLBACKS	0x20 +#define DEBUG_VERBOSE	0x40 +#define DEBUG_BATCH     0x80 +#define DEBUG_PIXEL     0x100 +#define DEBUG_BUFMGR    0x200 +#define DEBUG_REGION    0x400 +#define DEBUG_FBO       0x800 +#define DEBUG_LOCK      0x1000 + +#define DBG(...)  do { if (INTEL_DEBUG & FILE_DEBUG_FLAG) _mesa_printf(__VA_ARGS__); } while(0) + + +#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 +#define PCI_CHIP_I915_GM		0x2592 +#define PCI_CHIP_I945_G			0x2772 +#define PCI_CHIP_I945_GM		0x27A2 + + +/* ================================================================ + * intel_context.c: + */ + +extern GLboolean intelInitContext(struct intel_context *intel, +                                  const __GLcontextModes * mesaVis, +                                  __DRIcontextPrivate * driContextPriv, +                                  void *sharedContextPrivate, +                                  struct dd_function_table *functions); + +extern void intelGetLock(struct intel_context *intel, GLuint flags); + +extern void intelInitState(GLcontext * ctx); +extern void intelFinish(GLcontext * ctx); +extern void intelFlush(GLcontext * ctx); + +extern void intelInitDriverFunctions(struct dd_function_table *functions); + + +/* ================================================================ + * intel_state.c: + */ +extern void intelInitStateFuncs(struct dd_function_table *functions); + +#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 + +#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 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 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 +#define BLENDFACT_MASK          	0x0f + +#define MI_BATCH_BUFFER_END 	(0xA<<23) + + +extern int intel_translate_compare_func(GLenum func); +extern int intel_translate_stencil_op(GLenum op); +extern int intel_translate_blend_factor(GLenum factor); +extern int intel_translate_logic_op(GLenum opcode); + + +/*====================================================================== + * Inline conversion functions.   + * These are better-typed than the macros used previously: + */ +static INLINE struct intel_context * +intel_context(GLcontext * ctx) +{ +   return (struct intel_context *) ctx; +} + +static INLINE struct intel_texture_object * +intel_texture_object(struct gl_texture_object *obj) +{ +   return (struct intel_texture_object *) obj; +} + +static INLINE struct intel_texture_image * +intel_texture_image(struct gl_texture_image *img) +{ +   return (struct intel_texture_image *) img; +} + +extern struct intel_renderbuffer *intel_renderbuffer(struct gl_renderbuffer +                                                     *rb); + + +#endif diff --git a/src/mesa/drivers/dri/i915tex/intel_depthstencil.c b/src/mesa/drivers/dri/i915tex/intel_depthstencil.c new file mode 100644 index 0000000000..d269a85a3c --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_depthstencil.c @@ -0,0 +1,282 @@ +/************************************************************************** + *  + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#include "glheader.h" +#include "imports.h" +#include "context.h" +#include "depthstencil.h" +#include "fbobject.h" +#include "framebuffer.h" +#include "hash.h" +#include "mtypes.h" +#include "renderbuffer.h" + +#include "intel_context.h" +#include "intel_fbo.h" +#include "intel_depthstencil.h" +#include "intel_regions.h" + + +/** + * The GL_EXT_framebuffer_object allows the user to create their own + * framebuffer objects consisting of color renderbuffers (0 or more), + * depth renderbuffers (0 or 1) and stencil renderbuffers (0 or 1). + * + * The spec considers depth and stencil renderbuffers to be totally independent + * buffers.  In reality, most graphics hardware today uses a combined + * depth+stencil buffer (one 32-bit pixel = 24 bits of Z + 8 bits of stencil). + * + * This causes difficulty because the user may create some number of depth + * renderbuffers and some number of stencil renderbuffers and bind them + * together in framebuffers in any combination. + * + * This code manages all that. + * + * 1. Depth renderbuffers are always allocated in hardware as 32bpp + *    GL_DEPTH24_STENCIL8 buffers. + * + * 2. Stencil renderbuffers are initially allocated in software as 8bpp + *    GL_STENCIL_INDEX8 buffers. + * + * 3. Depth and Stencil renderbuffers use the PairedStencil and PairedDepth + *    fields (respectively) to indicate if the buffer's currently paired + *    with another stencil or depth buffer (respectively). + * + * 4. When a depth and stencil buffer are initially both attached to the + *    current framebuffer, we merge the stencil buffer values into the + *    depth buffer (really a depth+stencil buffer).  The then hardware uses + *    the combined buffer. + * + * 5. Whenever a depth or stencil buffer is reallocated (with + *    glRenderbufferStorage) we undo the pairing and copy the stencil values + *    from the combined depth/stencil buffer back to the stencil-only buffer. + * + * 6. We also undo the pairing when we find a change in buffer bindings. + * + * 7. If a framebuffer is only using a depth renderbuffer (no stencil), we + *    just use the combined depth/stencil buffer and ignore the stencil values. + * + * 8. If a framebuffer is only using a stencil renderbuffer (no depth) we have + *    to promote the 8bpp software stencil buffer to a 32bpp hardware + *    depth+stencil buffer. + * + */ + + + +static void +map_regions(GLcontext * ctx, +            struct intel_renderbuffer *depthRb, +            struct intel_renderbuffer *stencilRb) +{ +   struct intel_context *intel = intel_context(ctx); +   if (depthRb && depthRb->region) { +      intel_region_map(intel->intelScreen, depthRb->region); +      depthRb->pfMap = depthRb->region->map; +      depthRb->pfPitch = depthRb->region->pitch; +   } +   if (stencilRb && stencilRb->region) { +      intel_region_map(intel->intelScreen, stencilRb->region); +      stencilRb->pfMap = stencilRb->region->map; +      stencilRb->pfPitch = stencilRb->region->pitch; +   } +} + +static void +unmap_regions(GLcontext * ctx, +              struct intel_renderbuffer *depthRb, +              struct intel_renderbuffer *stencilRb) +{ +   struct intel_context *intel = intel_context(ctx); +   if (depthRb && depthRb->region) { +      intel_region_unmap(intel->intelScreen, depthRb->region); +      depthRb->pfMap = NULL; +      depthRb->pfPitch = 0; +   } +   if (stencilRb && stencilRb->region) { +      intel_region_unmap(intel->intelScreen, stencilRb->region); +      stencilRb->pfMap = NULL; +      stencilRb->pfPitch = 0; +   } +} + + + +/** + * Undo the pairing/interleaving between depth and stencil buffers. + * irb should be a depth/stencil or stencil renderbuffer. + */ +void +intel_unpair_depth_stencil(GLcontext * ctx, struct intel_renderbuffer *irb) +{ +   if (irb->PairedStencil) { +      /* irb is a depth/stencil buffer */ +      struct gl_renderbuffer *stencilRb; +      struct intel_renderbuffer *stencilIrb; + +      ASSERT(irb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); + +      stencilRb = _mesa_lookup_renderbuffer(ctx, irb->PairedStencil); +      stencilIrb = intel_renderbuffer(stencilRb); +      if (stencilIrb) { +         /* need to extract stencil values from the depth buffer */ +         ASSERT(stencilIrb->PairedDepth == irb->Base.Name); +         map_regions(ctx, irb, stencilIrb); +         _mesa_extract_stencil(ctx, &irb->Base, &stencilIrb->Base); +         unmap_regions(ctx, irb, stencilIrb); +         stencilIrb->PairedDepth = 0; +      } +      irb->PairedStencil = 0; +   } +   else if (irb->PairedDepth) { +      /* irb is a stencil buffer */ +      struct gl_renderbuffer *depthRb; +      struct intel_renderbuffer *depthIrb; + +      ASSERT(irb->Base._ActualFormat == GL_STENCIL_INDEX8_EXT || +             irb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); + +      depthRb = _mesa_lookup_renderbuffer(ctx, irb->PairedDepth); +      depthIrb = intel_renderbuffer(depthRb); +      if (depthIrb) { +         /* need to extract stencil values from the depth buffer */ +         ASSERT(depthIrb->PairedStencil == irb->Base.Name); +         map_regions(ctx, depthIrb, irb); +         _mesa_extract_stencil(ctx, &depthIrb->Base, &irb->Base); +         unmap_regions(ctx, depthIrb, irb); +         depthIrb->PairedStencil = 0; +      } +      irb->PairedDepth = 0; +   } +   else { +      _mesa_problem(ctx, "Problem in undo_depth_stencil_pairing"); +   } + +   ASSERT(irb->PairedStencil == 0); +   ASSERT(irb->PairedDepth == 0); +} + + +/** + * Examine the depth and stencil renderbuffers which are attached to the + * framebuffer.  If both depth and stencil are attached, make sure that the + * renderbuffers are 'paired' (combined).  If only depth or only stencil is + * attached, undo any previous pairing. + * + * Must be called if NewState & _NEW_BUFFER (when renderbuffer attachments + * change, for example). + */ +void +intel_validate_paired_depth_stencil(GLcontext * ctx, +                                    struct gl_framebuffer *fb) +{ +   struct intel_renderbuffer *depthRb, *stencilRb; + +   depthRb = intel_get_renderbuffer(fb, BUFFER_DEPTH); +   stencilRb = intel_get_renderbuffer(fb, BUFFER_STENCIL); + +   if (depthRb && stencilRb) { +      if (depthRb == stencilRb) { +         /* Using a user-created combined depth/stencil buffer. +          * Nothing to do. +          */ +         ASSERT(depthRb->Base._BaseFormat == GL_DEPTH_STENCIL_EXT); +         ASSERT(depthRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); +      } +      else { +         /* Separate depth/stencil buffers, need to interleave now */ +         ASSERT(depthRb->Base._BaseFormat == GL_DEPTH_COMPONENT); +         ASSERT(stencilRb->Base._BaseFormat == GL_STENCIL_INDEX); +         /* may need to interleave depth/stencil now */ +         if (depthRb->PairedStencil == stencilRb->Base.Name) { +            /* OK, the depth and stencil buffers are already interleaved */ +            ASSERT(stencilRb->PairedDepth == depthRb->Base.Name); +         } +         else { +            /* need to setup new pairing/interleaving */ +            if (depthRb->PairedStencil) { +               intel_unpair_depth_stencil(ctx, depthRb); +            } +            if (stencilRb->PairedDepth) { +               intel_unpair_depth_stencil(ctx, stencilRb); +            } + +            ASSERT(depthRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); +            ASSERT(stencilRb->Base._ActualFormat == GL_STENCIL_INDEX8_EXT || +                   stencilRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); + +            /* establish new pairing: interleave stencil into depth buffer */ +            map_regions(ctx, depthRb, stencilRb); +            _mesa_insert_stencil(ctx, &depthRb->Base, &stencilRb->Base); +            unmap_regions(ctx, depthRb, stencilRb); +            depthRb->PairedStencil = stencilRb->Base.Name; +            stencilRb->PairedDepth = depthRb->Base.Name; +         } + +      } +   } +   else if (depthRb) { +      /* Depth buffer but no stencil buffer. +       * We'll use a GL_DEPTH24_STENCIL8 buffer and ignore the stencil bits. +       */ +      /* can't assert this until storage is allocated: +         ASSERT(depthRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); +       */ +      /* intel_undo any previous pairing */ +      if (depthRb->PairedStencil) { +         intel_unpair_depth_stencil(ctx, depthRb); +      } +   } +   else if (stencilRb) { +      /* Stencil buffer but no depth buffer. +       * Since h/w doesn't typically support just 8bpp stencil w/out Z, +       * we'll use a GL_DEPTH24_STENCIL8 buffer and ignore the depth bits. +       */ +      /* undo any previous pairing */ +      if (stencilRb->PairedDepth) { +         intel_unpair_depth_stencil(ctx, stencilRb); +      } +      if (stencilRb->Base._ActualFormat == GL_STENCIL_INDEX8_EXT) { +         /* promote buffer to GL_DEPTH24_STENCIL8 for hw rendering */ +         _mesa_promote_stencil(ctx, &stencilRb->Base); +         ASSERT(stencilRb->Base._ActualFormat == GL_DEPTH24_STENCIL8_EXT); +      } +   } + +   /* Finally, update the fb->_DepthBuffer and fb->_StencilBuffer fields */ +   _mesa_update_depth_buffer(ctx, fb, BUFFER_DEPTH); +   if (depthRb && depthRb->PairedStencil) +      _mesa_update_stencil_buffer(ctx, fb, BUFFER_DEPTH); +   else +      _mesa_update_stencil_buffer(ctx, fb, BUFFER_STENCIL); + + +   /* The hardware should use fb->Attachment[BUFFER_DEPTH].Renderbuffer +    * first, if present, then fb->Attachment[BUFFER_STENCIL].Renderbuffer +    * if present. +    */ +} diff --git a/src/mesa/drivers/dri/i915tex/intel_depthstencil.h b/src/mesa/drivers/dri/i915tex/intel_depthstencil.h new file mode 100644 index 0000000000..2d3fc48b3a --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_depthstencil.h @@ -0,0 +1,14 @@ + +#ifndef INTEL_DEPTH_STENCIL_H +#define INTEL_DEPTH_STENCIL_H + + +extern void +intel_unpair_depth_stencil(GLcontext * ctx, struct intel_renderbuffer *irb); + +extern void +intel_validate_paired_depth_stencil(GLcontext * ctx, +                                    struct gl_framebuffer *fb); + + +#endif /* INTEL_DEPTH_STENCIL_H */ diff --git a/src/mesa/drivers/dri/i915tex/intel_fbo.c b/src/mesa/drivers/dri/i915tex/intel_fbo.c new file mode 100644 index 0000000000..ab0e569bd9 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_fbo.c @@ -0,0 +1,622 @@ +/************************************************************************** + *  + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + + +#include "imports.h" +#include "mtypes.h" +#include "fbobject.h" +#include "framebuffer.h" +#include "renderbuffer.h" +#include "context.h" +#include "texformat.h" +#include "texrender.h" + +#include "intel_context.h" +#include "intel_buffers.h" +#include "intel_depthstencil.h" +#include "intel_fbo.h" +#include "intel_mipmap_tree.h" +#include "intel_regions.h" +#include "intel_span.h" + + +#define FILE_DEBUG_FLAG DEBUG_FBO + +#define INTEL_RB_CLASS 0x12345678 + + +/* XXX FBO: move this to intel_context.h (inlined) */ +/** + * Return a gl_renderbuffer ptr casted to intel_renderbuffer. + * NULL will be returned if the rb isn't really an intel_renderbuffer. + * This is determiend by checking the ClassID. + */ +struct intel_renderbuffer * +intel_renderbuffer(struct gl_renderbuffer *rb) +{ +   struct intel_renderbuffer *irb = (struct intel_renderbuffer *) rb; +   if (irb && irb->Base.ClassID == INTEL_RB_CLASS) { +      /*_mesa_warning(NULL, "Returning non-intel Rb\n");*/ +      return irb; +   } +   else +      return NULL; +} + + +struct intel_renderbuffer * +intel_get_renderbuffer(struct gl_framebuffer *fb, GLuint attIndex) +{ +   return intel_renderbuffer(fb->Attachment[attIndex].Renderbuffer); +} + + +struct intel_region * +intel_get_rb_region(struct gl_framebuffer *fb, GLuint attIndex) +{ +   struct intel_renderbuffer *irb +      = intel_renderbuffer(fb->Attachment[attIndex].Renderbuffer); +   if (irb) +      return irb->region; +   else +      return NULL; +} + + + +/** + * Create a new framebuffer object. + */ +static struct gl_framebuffer * +intel_new_framebuffer(GLcontext * ctx, GLuint name) +{ +   /* there's no intel_framebuffer at this time, just use Mesa's class */ +   return _mesa_new_framebuffer(ctx, name); +} + + +static void +intel_delete_renderbuffer(struct gl_renderbuffer *rb) +{ +   GET_CURRENT_CONTEXT(ctx); +   struct intel_context *intel = intel_context(ctx); +   struct intel_renderbuffer *irb = intel_renderbuffer(rb); + +   ASSERT(irb); + +   if (irb->PairedStencil || irb->PairedDepth) { +      intel_unpair_depth_stencil(ctx, irb); +   } + +   if (intel && irb->region) { +      intel_region_release(&irb->region); +   } + +   _mesa_free(irb); +} + + + +/** + * Return a pointer to a specific pixel in a renderbuffer. + */ +static void * +intel_get_pointer(GLcontext * ctx, struct gl_renderbuffer *rb, +                  GLint x, GLint y) +{ +   /* By returning NULL we force all software rendering to go through +    * the span routines. +    */ +   return NULL; +} + + + +/** + * Called via glRenderbufferStorageEXT() to set the format and allocate + * storage for a user-created renderbuffer. + */ +static GLboolean +intel_alloc_renderbuffer_storage(GLcontext * ctx, struct gl_renderbuffer *rb, +                                 GLenum internalFormat, +                                 GLuint width, GLuint height) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_renderbuffer *irb = intel_renderbuffer(rb); +   GLboolean softwareBuffer = GL_FALSE; +   int cpp; + +   ASSERT(rb->Name != 0); + +   switch (internalFormat) { +   case GL_R3_G3_B2: +   case GL_RGB4: +   case GL_RGB5: +      rb->_ActualFormat = GL_RGB5; +      rb->DataType = GL_UNSIGNED_BYTE; +      rb->RedBits = 5; +      rb->GreenBits = 6; +      rb->BlueBits = 5; +      cpp = 2; +      break; +   case GL_RGB: +   case GL_RGB8: +   case GL_RGB10: +   case GL_RGB12: +   case GL_RGB16: +   case GL_RGBA: +   case GL_RGBA2: +   case GL_RGBA4: +   case GL_RGB5_A1: +   case GL_RGBA8: +   case GL_RGB10_A2: +   case GL_RGBA12: +   case GL_RGBA16: +      rb->_ActualFormat = GL_RGBA8; +      rb->DataType = GL_UNSIGNED_BYTE; +      rb->RedBits = 8; +      rb->GreenBits = 8; +      rb->BlueBits = 8; +      rb->AlphaBits = 8; +      cpp = 4; +      break; +   case GL_STENCIL_INDEX: +   case GL_STENCIL_INDEX1_EXT: +   case GL_STENCIL_INDEX4_EXT: +   case GL_STENCIL_INDEX8_EXT: +   case GL_STENCIL_INDEX16_EXT: +      /* alloc a depth+stencil buffer */ +      rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT; +      rb->DataType = GL_UNSIGNED_INT_24_8_EXT; +      rb->StencilBits = 8; +      cpp = 4; +      break; +   case GL_DEPTH_COMPONENT16: +      rb->_ActualFormat = GL_DEPTH_COMPONENT16; +      rb->DataType = GL_UNSIGNED_SHORT; +      rb->DepthBits = 16; +      cpp = 2; +      break; +   case GL_DEPTH_COMPONENT: +   case GL_DEPTH_COMPONENT24: +   case GL_DEPTH_COMPONENT32: +      rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT; +      rb->DataType = GL_UNSIGNED_INT_24_8_EXT; +      rb->DepthBits = 24; +      cpp = 4; +      break; +   case GL_DEPTH_STENCIL_EXT: +   case GL_DEPTH24_STENCIL8_EXT: +      rb->_ActualFormat = GL_DEPTH24_STENCIL8_EXT; +      rb->DataType = GL_UNSIGNED_INT_24_8_EXT; +      rb->DepthBits = 24; +      rb->StencilBits = 8; +      cpp = 4; +      break; +   default: +      _mesa_problem(ctx, +                    "Unexpected format in intel_alloc_renderbuffer_storage"); +      return GL_FALSE; +   } + +   intelFlush(ctx); + +   /* free old region */ +   if (irb->region) { +      intel_region_release(&irb->region); +   } + +   /* allocate new memory region/renderbuffer */ +   if (softwareBuffer) { +      return _mesa_soft_renderbuffer_storage(ctx, rb, internalFormat, +                                             width, height); +   } +   else { +      /* Choose a pitch to match hardware requirements: +       */ +      GLuint pitch = ((cpp * width + 63) & ~63) / cpp; + +      /* alloc hardware renderbuffer */ +      DBG("Allocating %d x %d Intel RBO (pitch %d)\n", width, +	  height, pitch); + +      irb->region = intel_region_alloc(intel->intelScreen, cpp, pitch, height); +      if (!irb->region) +         return GL_FALSE;       /* out of memory? */ + +      ASSERT(irb->region->buffer); + +      rb->Width = width; +      rb->Height = height; + +      /* This sets the Get/PutRow/Value functions */ +      intel_set_span_functions(&irb->Base); + +      return GL_TRUE; +   } +} + + + +/** + * Called for each hardware renderbuffer when a _window_ is resized. + * Just update fields. + * Not used for user-created renderbuffers! + */ +static GLboolean +intel_alloc_window_storage(GLcontext * ctx, struct gl_renderbuffer *rb, +                           GLenum internalFormat, GLuint width, GLuint height) +{ +   ASSERT(rb->Name == 0); +   rb->Width = width; +   rb->Height = height; +   rb->_ActualFormat = internalFormat; +   return GL_TRUE; +} + + +static GLboolean +intel_nop_alloc_storage(GLcontext * ctx, struct gl_renderbuffer *rb, +                        GLenum internalFormat, GLuint width, GLuint height) +{ +   _mesa_problem(ctx, "intel_op_alloc_storage should never be called."); +   return GL_FALSE; +} + + + +/** + * Create a new intel_renderbuffer which corresponds to an on-screen window, + * not a user-created renderbuffer. + * \param width  the screen width + * \param height  the screen height + */ +struct intel_renderbuffer * +intel_create_renderbuffer(GLenum intFormat, GLsizei width, GLsizei height, +                          int offset, int pitch, int cpp, void *map) +{ +   GET_CURRENT_CONTEXT(ctx); + +   struct intel_renderbuffer *irb; +   const GLuint name = 0; + +   irb = CALLOC_STRUCT(intel_renderbuffer); +   if (!irb) { +      _mesa_error(ctx, GL_OUT_OF_MEMORY, "creating renderbuffer"); +      return NULL; +   } + +   _mesa_init_renderbuffer(&irb->Base, name); +   irb->Base.ClassID = INTEL_RB_CLASS; + +   switch (intFormat) { +   case GL_RGB5: +      irb->Base._ActualFormat = GL_RGB5; +      irb->Base._BaseFormat = GL_RGBA; +      irb->Base.RedBits = 5; +      irb->Base.GreenBits = 6; +      irb->Base.BlueBits = 5; +      irb->Base.DataType = GL_UNSIGNED_BYTE; +      cpp = 2; +      break; +   case GL_RGBA8: +      irb->Base._ActualFormat = GL_RGBA8; +      irb->Base._BaseFormat = GL_RGBA; +      irb->Base.RedBits = 8; +      irb->Base.GreenBits = 8; +      irb->Base.BlueBits = 8; +      irb->Base.AlphaBits = 8; +      irb->Base.DataType = GL_UNSIGNED_BYTE; +      cpp = 4; +      break; +   case GL_STENCIL_INDEX8_EXT: +      irb->Base._ActualFormat = GL_STENCIL_INDEX8_EXT; +      irb->Base._BaseFormat = GL_STENCIL_INDEX; +      irb->Base.StencilBits = 8; +      irb->Base.DataType = GL_UNSIGNED_BYTE; +      cpp = 1; +      break; +   case GL_DEPTH_COMPONENT16: +      irb->Base._ActualFormat = GL_DEPTH_COMPONENT16; +      irb->Base._BaseFormat = GL_DEPTH_COMPONENT; +      irb->Base.DepthBits = 16; +      irb->Base.DataType = GL_UNSIGNED_SHORT; +      cpp = 2; +      break; +   case GL_DEPTH_COMPONENT24: +      irb->Base._ActualFormat = GL_DEPTH24_STENCIL8_EXT; +      irb->Base._BaseFormat = GL_DEPTH_COMPONENT; +      irb->Base.DepthBits = 24; +      irb->Base.DataType = GL_UNSIGNED_INT; +      cpp = 4; +      break; +   case GL_DEPTH24_STENCIL8_EXT: +      irb->Base._ActualFormat = GL_DEPTH24_STENCIL8_EXT; +      irb->Base._BaseFormat = GL_DEPTH_STENCIL_EXT; +      irb->Base.DepthBits = 24; +      irb->Base.StencilBits = 8; +      irb->Base.DataType = GL_UNSIGNED_INT_24_8_EXT; +      cpp = 4; +      break; +   default: +      _mesa_problem(NULL, +                    "Unexpected intFormat in intel_create_renderbuffer"); +      return NULL; +   } + +   irb->Base.InternalFormat = intFormat; + +   /* intel-specific methods */ +   irb->Base.Delete = intel_delete_renderbuffer; +   irb->Base.AllocStorage = intel_alloc_window_storage; +   irb->Base.GetPointer = intel_get_pointer; +   /* This sets the Get/PutRow/Value functions */ +   intel_set_span_functions(&irb->Base); + +   irb->pfMap = map; +   irb->pfPitch = pitch / cpp;	/* in pixels */ + +#if 00 +   irb->region = intel_region_create_static(intel, +                                            DRM_MM_TT, +                                            offset, map, cpp, width, height); +#endif + +   return irb; +} + + +/** + * Create a new renderbuffer object. + * Typically called via glBindRenderbufferEXT(). + */ +static struct gl_renderbuffer * +intel_new_renderbuffer(GLcontext * ctx, GLuint name) +{ +   /*struct intel_context *intel = intel_context(ctx); */ +   struct intel_renderbuffer *irb; + +   irb = CALLOC_STRUCT(intel_renderbuffer); +   if (!irb) { +      _mesa_error(ctx, GL_OUT_OF_MEMORY, "creating renderbuffer"); +      return NULL; +   } + +   _mesa_init_renderbuffer(&irb->Base, name); +   irb->Base.ClassID = INTEL_RB_CLASS; + +   /* intel-specific methods */ +   irb->Base.Delete = intel_delete_renderbuffer; +   irb->Base.AllocStorage = intel_alloc_renderbuffer_storage; +   irb->Base.GetPointer = intel_get_pointer; +   /* span routines set in alloc_storage function */ + +   return &irb->Base; +} + + +/** + * Called via glBindFramebufferEXT(). + */ +static void +intel_bind_framebuffer(GLcontext * ctx, GLenum target, +                       struct gl_framebuffer *fb) +{ +   if (target == GL_FRAMEBUFFER_EXT || target == GL_DRAW_FRAMEBUFFER_EXT) { +      intel_draw_buffer(ctx, fb); +      /* Integer depth range depends on depth buffer bits */ +      ctx->Driver.DepthRange(ctx, ctx->Viewport.Near, ctx->Viewport.Far); +   } +   else { +      /* don't need to do anything if target == GL_READ_FRAMEBUFFER_EXT */ +   } +} + + +/** + * Called via glFramebufferRenderbufferEXT(). + */ +static void +intel_framebuffer_renderbuffer(GLcontext * ctx, +                               struct gl_framebuffer *fb, +                               GLenum attachment, struct gl_renderbuffer *rb) +{ +   DBG("Intel FramebufferRenderbuffer %u %u\n", fb->Name, rb ? rb->Name : 0); + +   intelFlush(ctx); + +   _mesa_framebuffer_renderbuffer(ctx, fb, attachment, rb); +   intel_draw_buffer(ctx, fb); +} + + +/** + * When glFramebufferTexture[123]D is called this function sets up the + * gl_renderbuffer wrapp around the texture image. + * This will have the region info needed for hardware rendering. + */ +static struct intel_renderbuffer * +intel_wrap_texture(GLcontext * ctx, struct gl_texture_image *texImage) +{ +   const GLuint name = ~0;      /* not significant, but distinct for debugging */ +   struct intel_renderbuffer *irb; + +   /* make an intel_renderbuffer to wrap the texture image */ +   irb = CALLOC_STRUCT(intel_renderbuffer); +   if (!irb) { +      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glFramebufferTexture"); +      return NULL; +   } + +   _mesa_init_renderbuffer(&irb->Base, name); +   irb->Base.ClassID = INTEL_RB_CLASS; + +   if (texImage->TexFormat == &_mesa_texformat_argb8888) { +      irb->Base._ActualFormat = GL_RGBA8; +      irb->Base._BaseFormat = GL_RGBA; +      DBG("Render to RGBA8 texture OK\n"); +   } +   else if (texImage->TexFormat == &_mesa_texformat_rgb565) { +      irb->Base._ActualFormat = GL_RGB5; +      irb->Base._BaseFormat = GL_RGB; +      DBG("Render to RGB5 texture OK\n"); +   } +   else if (texImage->TexFormat == &_mesa_texformat_z16) { +      irb->Base._ActualFormat = GL_DEPTH_COMPONENT16; +      irb->Base._BaseFormat = GL_DEPTH_COMPONENT; +      DBG("Render to DEPTH16 texture OK\n"); +   } +   else { +      DBG("Render to texture BAD FORMAT %d\n", +	  texImage->TexFormat->MesaFormat); +      _mesa_free(irb); +      return NULL; +   } + +   irb->Base.InternalFormat = irb->Base._ActualFormat; +   irb->Base.Width = texImage->Width; +   irb->Base.Height = texImage->Height; +   irb->Base.DataType = GL_UNSIGNED_BYTE;       /* FBO XXX fix */ +   irb->Base.RedBits = texImage->TexFormat->RedBits; +   irb->Base.GreenBits = texImage->TexFormat->GreenBits; +   irb->Base.BlueBits = texImage->TexFormat->BlueBits; +   irb->Base.AlphaBits = texImage->TexFormat->AlphaBits; +   irb->Base.DepthBits = texImage->TexFormat->DepthBits; + +   irb->Base.Delete = intel_delete_renderbuffer; +   irb->Base.AllocStorage = intel_nop_alloc_storage; +   intel_set_span_functions(&irb->Base); + +   irb->RenderToTexture = GL_TRUE; + +   return irb; +} + + +/** + * Called by glFramebufferTexture[123]DEXT() (and other places) to + * prepare for rendering into texture memory.  This might be called + * many times to choose different texture levels, cube faces, etc + * before intel_finish_render_texture() is ever called. + */ +static void +intel_render_texture(GLcontext * ctx, +                     struct gl_framebuffer *fb, +                     struct gl_renderbuffer_attachment *att) +{ +   struct gl_texture_image *newImage +      = att->Texture->Image[att->CubeMapFace][att->TextureLevel]; +   struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer); +   struct intel_texture_image *intel_image; +   GLuint imageOffset; + +   (void) fb; + +   ASSERT(newImage); + +   if (!irb) { +      irb = intel_wrap_texture(ctx, newImage); +      if (irb) { +         /* bind the wrapper to the attachment point */ +         att->Renderbuffer = &irb->Base; +      } +      else { +         /* fallback to software rendering */ +         _mesa_render_texture(ctx, fb, att); +         return; +      } +   } + +   DBG("Begin render texture tid %x tex=%u w=%d h=%d refcount=%d\n", +       _glthread_GetID(), +       att->Texture->Name, newImage->Width, newImage->Height, +       irb->Base.RefCount); + +   /* point the renderbufer's region to the texture image region */ +   intel_image = intel_texture_image(newImage); +   if (irb->region != intel_image->mt->region) { +      if (irb->region) +	 intel_region_release(&irb->region); +      intel_region_reference(&irb->region, intel_image->mt->region); +   } + +   /* compute offset of the particular 2D image within the texture region */ +   imageOffset = intel_miptree_image_offset(intel_image->mt, +                                            att->CubeMapFace, +                                            att->TextureLevel); + +   if (att->Texture->Target == GL_TEXTURE_3D) { +      const GLuint *offsets = intel_miptree_depth_offsets(intel_image->mt, +                                                          att->TextureLevel); +      imageOffset += offsets[att->Zoffset]; +   } + +   /* store that offset in the region */ +   intel_image->mt->region->draw_offset = imageOffset; + +   /* update drawing region, etc */ +   intel_draw_buffer(ctx, fb); +} + + +/** + * Called by Mesa when rendering to a texture is done. + */ +static void +intel_finish_render_texture(GLcontext * ctx, +                            struct gl_renderbuffer_attachment *att) +{ +   struct intel_renderbuffer *irb = intel_renderbuffer(att->Renderbuffer); + +   DBG("End render texture (tid %x) tex %u\n", _glthread_GetID(), att->Texture->Name); + +   if (irb) { +      /* just release the region */ +      intel_region_release(&irb->region); +   } +   else if (att->Renderbuffer) { +      /* software fallback */ +      _mesa_finish_render_texture(ctx, att); +      /* XXX FBO: Need to unmap the buffer (or in intelSpanRenderStart???) */ +   } +} + + +/** + * Do one-time context initializations related to GL_EXT_framebuffer_object. + * Hook in device driver functions. + */ +void +intel_fbo_init(struct intel_context *intel) +{ +   intel->ctx.Driver.NewFramebuffer = intel_new_framebuffer; +   intel->ctx.Driver.NewRenderbuffer = intel_new_renderbuffer; +   intel->ctx.Driver.BindFramebuffer = intel_bind_framebuffer; +   intel->ctx.Driver.FramebufferRenderbuffer = intel_framebuffer_renderbuffer; +   intel->ctx.Driver.RenderTexture = intel_render_texture; +   intel->ctx.Driver.FinishRenderTexture = intel_finish_render_texture; +} diff --git a/src/mesa/drivers/dri/i915tex/intel_fbo.h b/src/mesa/drivers/dri/i915tex/intel_fbo.h new file mode 100644 index 0000000000..221f09b39a --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_fbo.h @@ -0,0 +1,80 @@ +/************************************************************************** + *  + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#ifndef INTEL_FBO_H +#define INTEL_FBO_H + + +struct intel_context; +struct intel_region; + + +/** + * Intel renderbuffer, derived from gl_renderbuffer. + * Note: The PairedDepth and PairedStencil fields use renderbuffer IDs, + * not pointers because in some circumstances a deleted renderbuffer could + * result in a dangling pointer here. + */ +struct intel_renderbuffer +{ +   struct gl_renderbuffer Base; +   struct intel_region *region; +   void *pfMap;                 /* possibly paged flipped map pointer */ +   GLuint pfPitch;              /* possibly paged flipped pitch */ +   GLboolean RenderToTexture;   /* RTT? */ + +   GLuint PairedDepth;   /**< only used if this is a depth renderbuffer */ +   GLuint PairedStencil; /**< only used if this is a stencil renderbuffer */ +}; + + +extern struct intel_renderbuffer *intel_create_renderbuffer(GLenum intFormat, +                                                            GLsizei width, +                                                            GLsizei height, +                                                            int offset, +                                                            int pitch, +                                                            int cpp, +                                                            void *map); + + +extern void intel_fbo_init(struct intel_context *intel); + + +/* XXX make inline or macro */ +extern struct intel_renderbuffer *intel_get_renderbuffer(struct gl_framebuffer +                                                         *fb, +                                                         GLuint attIndex); + + +/* XXX make inline or macro */ +extern struct intel_region *intel_get_rb_region(struct gl_framebuffer *fb, +                                                GLuint attIndex); + + + + +#endif /* INTEL_FBO_H */ diff --git a/src/mesa/drivers/dri/i915tex/intel_ioctl.c b/src/mesa/drivers/dri/i915tex/intel_ioctl.c new file mode 100644 index 0000000000..3250c6b3a9 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_ioctl.c @@ -0,0 +1,138 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + + +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <sched.h> + +#include "mtypes.h" +#include "context.h" +#include "swrast/swrast.h" + +#include "intel_context.h" +#include "intel_ioctl.h" +#include "intel_batchbuffer.h" +#include "intel_blit.h" +#include "intel_regions.h" +#include "drm.h" + +#define FILE_DEBUG_FLAG DEBUG_IOCTL + +int +intelEmitIrqLocked(struct intel_context *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); +   } + +   DBG("%s -->  %d\n", __FUNCTION__, seq); + +   return seq; +} + +void +intelWaitIrq(struct intel_context *intel, int seq) +{ +   int ret; + +   DBG("%s %d\n", __FUNCTION__, seq); + +   intel->iw.irq_seq = seq; + +   do { +      ret = +         drmCommandWrite(intel->driFd, DRM_I830_IRQ_WAIT, &intel->iw, +                         sizeof(intel->iw)); +   } while (ret == -EAGAIN || ret == -EINTR); + +   if (ret) { +      fprintf(stderr, "%s: drmI830IrqWait: %d\n", __FUNCTION__, ret); +      exit(1); +   } +} + + +void +intel_batch_ioctl(struct intel_context *intel, +                  GLuint start_offset, +                  GLuint used, +                  GLboolean ignore_cliprects, GLboolean allow_unlock) +{ +   drmI830BatchBuffer batch; + +   assert(intel->locked); +   assert(used); + +   DBG("%s used %d offset %x..%x ignore_cliprects %d\n", +       __FUNCTION__, +       used, start_offset, start_offset + used, ignore_cliprects); + +   /* Throw away non-effective packets.  Won't work once we have +    * hardware contexts which would preserve statechanges beyond a +    * single buffer. +    */ + + + +   batch.start = start_offset; +   batch.used = used; +   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)); + +   DBG("%s: 0x%x..0x%x DR4: %x cliprects: %d\n", +       __FUNCTION__, +       batch.start, +       batch.start + batch.used * 4, batch.DR4, batch.num_cliprects); + +   if (drmCommandWrite(intel->driFd, DRM_I830_BATCHBUFFER, &batch, +                       sizeof(batch))) { +      fprintf(stderr, "DRM_I830_BATCHBUFFER: %d\n", -errno); +      UNLOCK_HARDWARE(intel); +      exit(1); +   } + +   /* FIXME: use hardware contexts to avoid 'losing' hardware after +    * each buffer flush. +    */ +   intel->vtbl.lost_hardware(intel); +} diff --git a/src/mesa/drivers/dri/i915tex/intel_ioctl.h b/src/mesa/drivers/dri/i915tex/intel_ioctl.h new file mode 100644 index 0000000000..e8d07de893 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_ioctl.h @@ -0,0 +1,40 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#ifndef INTEL_IOCTL_H +#define INTEL_IOCTL_H + +#include "intel_context.h" + +void intelWaitIrq(struct intel_context *intel, int seq); +int intelEmitIrqLocked(struct intel_context *intel); + +void intel_batch_ioctl(struct intel_context *intel, +                       GLuint start_offset, +                       GLuint used, +                       GLboolean ignore_cliprects, GLboolean allow_unlock); +#endif diff --git a/src/mesa/drivers/dri/i915tex/intel_mipmap_tree.c b/src/mesa/drivers/dri/i915tex/intel_mipmap_tree.c new file mode 100644 index 0000000000..2ebe3ae14e --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_mipmap_tree.c @@ -0,0 +1,341 @@ +/************************************************************************** + *  + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#include "intel_context.h" +#include "intel_mipmap_tree.h" +#include "intel_regions.h" +#include "enums.h" + +#define FILE_DEBUG_FLAG DEBUG_MIPTREE + +static GLenum +target_to_target(GLenum target) +{ +   switch (target) { +   case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: +   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: +   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: +   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: +   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: +   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: +      return GL_TEXTURE_CUBE_MAP_ARB; +   default: +      return target; +   } +} + +struct intel_mipmap_tree * +intel_miptree_create(struct intel_context *intel, +                     GLenum target, +                     GLenum internal_format, +                     GLuint first_level, +                     GLuint last_level, +                     GLuint width0, +                     GLuint height0, +                     GLuint depth0, GLuint cpp, GLboolean compressed) +{ +   GLboolean ok; +   struct intel_mipmap_tree *mt = calloc(sizeof(*mt), 1); + +   DBG("%s target %s format %s level %d..%d\n", __FUNCTION__, +       _mesa_lookup_enum_by_nr(target), +       _mesa_lookup_enum_by_nr(internal_format), first_level, last_level); + +   mt->target = target_to_target(target); +   mt->internal_format = internal_format; +   mt->first_level = first_level; +   mt->last_level = last_level; +   mt->width0 = width0; +   mt->height0 = height0; +   mt->depth0 = depth0; +   mt->cpp = compressed ? 2 : cpp; +   mt->compressed = compressed; +   mt->refcount = 1;  + +   switch (intel->intelScreen->deviceID) { +   case PCI_CHIP_I945_G: +   case PCI_CHIP_I945_GM: +      ok = i945_miptree_layout(mt); +      break; +   case PCI_CHIP_I915_G: +   case PCI_CHIP_I915_GM: +   case PCI_CHIP_I830_M: +   case PCI_CHIP_I855_GM: +   case PCI_CHIP_I865_G: +   default: +      /* All the i830 chips and the i915 use this layout: +       */ +      ok = i915_miptree_layout(mt); +      break; +   } + +   if (ok) +      mt->region = intel_region_alloc(intel->intelScreen, +                                      mt->cpp, mt->pitch, mt->total_height); + +   if (!mt->region) { +      free(mt); +      return NULL; +   } + +   return mt; +} + + +void +intel_miptree_reference(struct intel_mipmap_tree **dst, +                        struct intel_mipmap_tree *src) +{ +   src->refcount++; +   *dst = src; +   DBG("%s %p refcount now %d\n", __FUNCTION__, src, src->refcount); +} + +void +intel_miptree_release(struct intel_context *intel, +                      struct intel_mipmap_tree **mt) +{ +   if (!*mt) +      return; + +   DBG("%s %p refcount will be %d\n", __FUNCTION__, *mt, (*mt)->refcount - 1); +   if (--(*mt)->refcount <= 0) { +      GLuint i; + +      DBG("%s deleting %p\n", __FUNCTION__, *mt); + +      intel_region_release(&((*mt)->region)); + +      for (i = 0; i < MAX_TEXTURE_LEVELS; i++) +         if ((*mt)->level[i].image_offset) +            free((*mt)->level[i].image_offset); + +      free(*mt); +   } +   *mt = NULL; +} + + + + +/* Can the image be pulled into a unified mipmap tree.  This mirrors + * the completeness test in a lot of ways. + * + * Not sure whether I want to pass gl_texture_image here. + */ +GLboolean +intel_miptree_match_image(struct intel_mipmap_tree *mt, +                          struct gl_texture_image *image, +                          GLuint face, GLuint level) +{ +   /* Images with borders are never pulled into mipmap trees.  +    */ +   if (image->Border)  +      return GL_FALSE; + +   if (image->InternalFormat != mt->internal_format || +       image->IsCompressed != mt->compressed) +      return GL_FALSE; + +   /* Test image dimensions against the base level image adjusted for +    * minification.  This will also catch images not present in the +    * tree, changed targets, etc. +    */ +   if (image->Width != mt->level[level].width || +       image->Height != mt->level[level].height || +       image->Depth != mt->level[level].depth) +      return GL_FALSE; + +   return GL_TRUE; +} + + +void +intel_miptree_set_level_info(struct intel_mipmap_tree *mt, +                             GLuint level, +                             GLuint nr_images, +                             GLuint x, GLuint y, GLuint w, GLuint h, GLuint d) +{ + +   mt->level[level].width = w; +   mt->level[level].height = h; +   mt->level[level].depth = d; +   mt->level[level].level_offset = (x + y * mt->pitch) * mt->cpp; +   mt->level[level].nr_images = nr_images; + +   DBG("%s level %d size: %d,%d,%d offset %d,%d (0x%x)\n", __FUNCTION__, +       level, w, h, d, x, y, mt->level[level].level_offset); + +   /* Not sure when this would happen, but anyway:  +    */ +   if (mt->level[level].image_offset) { +      free(mt->level[level].image_offset); +      mt->level[level].image_offset = NULL; +   } + +   assert(nr_images); + +   mt->level[level].image_offset = malloc(nr_images * sizeof(GLuint)); +   mt->level[level].image_offset[0] = 0; +} + + + +void +intel_miptree_set_image_offset(struct intel_mipmap_tree *mt, +                               GLuint level, GLuint img, GLuint x, GLuint y) +{ +   if (img == 0 && level == 0) +      assert(x == 0 && y == 0); + +   assert(img < mt->level[level].nr_images); + +   mt->level[level].image_offset[img] = (x + y * mt->pitch); + +   DBG("%s level %d img %d pos %d,%d image_offset %x\n", +       __FUNCTION__, level, img, x, y, mt->level[level].image_offset[img]); +} + + +/* Although we use the image_offset[] array to store relative offsets + * to cube faces, Mesa doesn't know anything about this and expects + * each cube face to be treated as a separate image. + * + * These functions present that view to mesa: + */ +const GLuint * +intel_miptree_depth_offsets(struct intel_mipmap_tree *mt, GLuint level) +{ +   static const GLuint zero = 0; + +   if (mt->target != GL_TEXTURE_3D || mt->level[level].nr_images == 1) +      return &zero; +   else +      return mt->level[level].image_offset; +} + + +GLuint +intel_miptree_image_offset(struct intel_mipmap_tree * mt, +                           GLuint face, GLuint level) +{ +   if (mt->target == GL_TEXTURE_CUBE_MAP_ARB) +      return (mt->level[level].level_offset + +              mt->level[level].image_offset[face] * mt->cpp); +   else +      return mt->level[level].level_offset; +} + + + +/** + * Map a teximage in a mipmap tree. + * \param row_stride  returns row stride in bytes + * \param image_stride  returns image stride in bytes (for 3D textures). + * \return address of mapping + */ +GLubyte * +intel_miptree_image_map(struct intel_context * intel, +                        struct intel_mipmap_tree * mt, +                        GLuint face, +                        GLuint level, +                        GLuint * row_stride, GLuint * image_offsets) +{ +   DBG("%s \n", __FUNCTION__); + +   if (row_stride) +      *row_stride = mt->pitch * mt->cpp; + +   if (image_offsets) +      memcpy(image_offsets, mt->level[level].image_offset, +             mt->level[level].depth * sizeof(GLuint)); + +   return (intel_region_map(intel->intelScreen, mt->region) + +           intel_miptree_image_offset(mt, face, level)); +} + +void +intel_miptree_image_unmap(struct intel_context *intel, +                          struct intel_mipmap_tree *mt) +{ +   DBG("%s\n", __FUNCTION__); +   intel_region_unmap(intel->intelScreen, mt->region); +} + + + +/* Upload data for a particular image. + */ +void +intel_miptree_image_data(struct intel_context *intel, +                         struct intel_mipmap_tree *dst, +                         GLuint face, +                         GLuint level, +                         void *src, +                         GLuint src_row_pitch, GLuint src_image_pitch) +{ +   GLuint depth = dst->level[level].depth; +   GLuint dst_offset = intel_miptree_image_offset(dst, face, level); +   const GLuint *dst_depth_offset = intel_miptree_depth_offsets(dst, level); +   GLuint i; + +   DBG("%s\n", __FUNCTION__); +   for (i = 0; i < depth; i++) { +      intel_region_data(intel->intelScreen, dst->region, dst_offset + dst_depth_offset[i], 0, 0, src, src_row_pitch, 0, 0,   /* source x,y */ +                        dst->level[level].width, dst->level[level].height); + +      src += src_image_pitch; +   } +} + +/* Copy mipmap image between trees + */ +void +intel_miptree_image_copy(struct intel_context *intel, +                         struct intel_mipmap_tree *dst, +                         GLuint face, GLuint level, +                         struct intel_mipmap_tree *src) +{ +   GLuint width = src->level[level].width; +   GLuint height = src->level[level].height; +   GLuint depth = src->level[level].depth; +   GLuint dst_offset = intel_miptree_image_offset(dst, face, level); +   GLuint src_offset = intel_miptree_image_offset(src, face, level); +   const GLuint *dst_depth_offset = intel_miptree_depth_offsets(dst, level); +   const GLuint *src_depth_offset = intel_miptree_depth_offsets(src, level); +   GLuint i; + +   for (i = 0; i < depth; i++) { +      intel_region_copy(intel->intelScreen, +                        dst->region, dst_offset + dst_depth_offset[i], +                        0, +                        0, +                        src->region, src_offset + src_depth_offset[i], +                        0, 0, width, height); +   } + +} diff --git a/src/mesa/drivers/dri/i915tex/intel_mipmap_tree.h b/src/mesa/drivers/dri/i915tex/intel_mipmap_tree.h new file mode 100644 index 0000000000..e6dd5bb600 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_mipmap_tree.h @@ -0,0 +1,198 @@ +/************************************************************************** + *  + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#ifndef INTEL_MIPMAP_TREE_H +#define INTEL_MIPMAP_TREE_H + +#include "intel_regions.h" + +/* A layer on top of the intel_regions code which adds: + * + * - Code to size and layout a region to hold a set of mipmaps. + * - Query to determine if a new image fits in an existing tree. + * - More refcounting  + *     - maybe able to remove refcounting from intel_region? + * - ? + * + * The fixed mipmap layout of intel hardware where one offset + * specifies the position of all images in a mipmap hierachy + * complicates the implementation of GL texture image commands, + * compared to hardware where each image is specified with an + * independent offset. + * + * In an ideal world, each texture object would be associated with a + * single bufmgr buffer or 2d intel_region, and all the images within + * the texture object would slot into the tree as they arrive.  The + * reality can be a little messier, as images can arrive from the user + * with sizes that don't fit in the existing tree, or in an order + * where the tree layout cannot be guessed immediately.   + *  + * This structure encodes an idealized mipmap tree.  The GL image + * commands build these where possible, otherwise store the images in + * temporary system buffers. + */ + + +/** + * Describes the location of each texture image within a texture region. + */ +struct intel_mipmap_level +{ +   GLuint level_offset; +   GLuint width; +   GLuint height; +   GLuint depth; +   GLuint nr_images; + +   /* Explicitly store the offset of each image for each cube face or +    * depth value.  Pretty much have to accept that hardware formats +    * are going to be so diverse that there is no unified way to +    * compute the offsets of depth/cube images within a mipmap level, +    * so have to store them as a lookup table: +    */ +   GLuint *image_offset; +}; + +struct intel_mipmap_tree +{ +   /* Effectively the key: +    */ +   GLenum target; +   GLenum internal_format; + +   GLuint first_level; +   GLuint last_level; + +   GLuint width0, height0, depth0; /**< Level zero image dimensions */ +   GLuint cpp; +   GLboolean compressed; + +   /* Derived from the above: +    */ +   GLuint pitch; +   GLuint depth_pitch;          /* per-image on i945? */ +   GLuint total_height; + +   /* Includes image offset tables: +    */ +   struct intel_mipmap_level level[MAX_TEXTURE_LEVELS]; + +   /* The data is held here: +    */ +   struct intel_region *region; + +   /* These are also refcounted: +    */ +   GLuint refcount; +}; + + + +struct intel_mipmap_tree *intel_miptree_create(struct intel_context *intel, +                                               GLenum target, +                                               GLenum internal_format, +                                               GLuint first_level, +                                               GLuint last_level, +                                               GLuint width0, +                                               GLuint height0, +                                               GLuint depth0, +                                               GLuint cpp, +                                               GLboolean compressed); + +void intel_miptree_reference(struct intel_mipmap_tree **dst, +                             struct intel_mipmap_tree *src); + +void intel_miptree_release(struct intel_context *intel, +                           struct intel_mipmap_tree **mt); + +/* Check if an image fits an existing mipmap tree layout + */ +GLboolean intel_miptree_match_image(struct intel_mipmap_tree *mt, +                                    struct gl_texture_image *image, +                                    GLuint face, GLuint level); + +/* Return a pointer to an image within a tree.  Return image stride as + * well. + */ +GLubyte *intel_miptree_image_map(struct intel_context *intel, +                                 struct intel_mipmap_tree *mt, +                                 GLuint face, +                                 GLuint level, +                                 GLuint * row_stride, GLuint * image_stride); + +void intel_miptree_image_unmap(struct intel_context *intel, +                               struct intel_mipmap_tree *mt); + + +/* Return the linear offset of an image relative to the start of the + * tree: + */ +GLuint intel_miptree_image_offset(struct intel_mipmap_tree *mt, +                                  GLuint face, GLuint level); + +/* Return pointers to each 2d slice within an image.  Indexed by depth + * value. + */ +const GLuint *intel_miptree_depth_offsets(struct intel_mipmap_tree *mt, +                                          GLuint level); + + +void intel_miptree_set_level_info(struct intel_mipmap_tree *mt, +                                  GLuint level, +                                  GLuint nr_images, +                                  GLuint x, GLuint y, +                                  GLuint w, GLuint h, GLuint d); + +void intel_miptree_set_image_offset(struct intel_mipmap_tree *mt, +                                    GLuint level, +                                    GLuint img, GLuint x, GLuint y); + + +/* Upload an image into a tree + */ +void intel_miptree_image_data(struct intel_context *intel, +                              struct intel_mipmap_tree *dst, +                              GLuint face, +                              GLuint level, +                              void *src, +                              GLuint src_row_pitch, GLuint src_image_pitch); + +/* Copy an image between two trees + */ +void intel_miptree_image_copy(struct intel_context *intel, +                              struct intel_mipmap_tree *dst, +                              GLuint face, GLuint level, +                              struct intel_mipmap_tree *src); + +/* i915_mipmap_tree.c: + */ +GLboolean i915_miptree_layout(struct intel_mipmap_tree *mt); +GLboolean i945_miptree_layout(struct intel_mipmap_tree *mt); + + + +#endif diff --git a/src/mesa/drivers/dri/i915tex/intel_pixel.c b/src/mesa/drivers/dri/i915tex/intel_pixel.c new file mode 100644 index 0000000000..4fe128deea --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_pixel.c @@ -0,0 +1,119 @@ +/************************************************************************** + *  + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portionsalloc + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#include "enums.h" +#include "state.h" +#include "swrast/swrast.h" + +#include "intel_context.h" +#include "intel_pixel.h" +#include "intel_regions.h" + + +/** + * Check if any fragment operations are in effect which might effect + * glDraw/CopyPixels. + */ +GLboolean +intel_check_blit_fragment_ops(GLcontext * ctx) +{ +   if (ctx->NewState) +      _mesa_update_state(ctx); + +   /* XXX Note: Scissor could be done with the blitter: +    */ +   return !(ctx->_ImageTransferState || +            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->FragmentProgram._Enabled); +} + + +GLboolean +intel_check_meta_tex_fragment_ops(GLcontext * ctx) +{ +   if (ctx->NewState) +      _mesa_update_state(ctx); + +   /* Some of _ImageTransferState (scale, bias) could be done with +    * fragment programs on i915. +    */ +   return !(ctx->_ImageTransferState || ctx->Fog.Enabled ||     /* not done yet */ +            ctx->Texture._EnabledUnits || ctx->FragmentProgram._Enabled); +} + +/* The intel_region struct doesn't really do enough to capture the + * format of the pixels in the region.  For now this code assumes that + * the region is a display surface and hence is either ARGB8888 or + * RGB565. + * XXX FBO: If we'd pass in the intel_renderbuffer instead of region, we'd + * know the buffer's pixel format. + * + * \param format  as given to glDraw/ReadPixels + * \param type  as given to glDraw/ReadPixels + */ +GLboolean +intel_check_blit_format(struct intel_region * region, +                        GLenum format, GLenum type) +{ +   if (region->cpp == 4 && +       (type == GL_UNSIGNED_INT_8_8_8_8_REV || +        type == GL_UNSIGNED_BYTE) && format == GL_BGRA) { +      return GL_TRUE; +   } + +   if (region->cpp == 2 && +       type == GL_UNSIGNED_SHORT_5_6_5_REV && format == GL_BGR) { +      return GL_TRUE; +   } + +   if (INTEL_DEBUG & DEBUG_PIXEL) +      fprintf(stderr, "%s: bad format for blit (cpp %d, type %s format %s)\n", +              __FUNCTION__, region->cpp, +              _mesa_lookup_enum_by_nr(type), _mesa_lookup_enum_by_nr(format)); + +   return GL_FALSE; +} + + +void +intelInitPixelFuncs(struct dd_function_table *functions) +{ +   functions->Accum = _swrast_Accum; +   functions->Bitmap = _swrast_Bitmap; +   functions->CopyPixels = intelCopyPixels; +   functions->ReadPixels = intelReadPixels; +   functions->DrawPixels = intelDrawPixels; +} diff --git a/src/mesa/drivers/dri/i915tex/intel_pixel.h b/src/mesa/drivers/dri/i915tex/intel_pixel.h new file mode 100644 index 0000000000..a6fcf90ce0 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_pixel.h @@ -0,0 +1,63 @@ +/************************************************************************** + *  + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#ifndef INTEL_PIXEL_H +#define INTEL_PIXEL_H + +#include "mtypes.h" + +void intelInitPixelFuncs(struct dd_function_table *functions); + +GLboolean intel_check_blit_fragment_ops(GLcontext * ctx); + +GLboolean intel_check_meta_tex_fragment_ops(GLcontext * ctx); + +GLboolean intel_check_blit_format(struct intel_region *region, +                                  GLenum format, GLenum type); + + +void intelReadPixels(GLcontext * ctx, +                     GLint x, GLint y, +                     GLsizei width, GLsizei height, +                     GLenum format, GLenum type, +                     const struct gl_pixelstore_attrib *pack, +                     GLvoid * pixels); + +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); + +void intelCopyPixels(GLcontext * ctx, +                     GLint srcx, GLint srcy, +                     GLsizei width, GLsizei height, +                     GLint destx, GLint desty, GLenum type); + +#endif diff --git a/src/mesa/drivers/dri/i915tex/intel_pixel_bitmap.c b/src/mesa/drivers/dri/i915tex/intel_pixel_bitmap.c new file mode 100644 index 0000000000..65bf338589 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_pixel_bitmap.c @@ -0,0 +1,350 @@ +/************************************************************************** + *  + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portionsalloc + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#include "glheader.h" +#include "enums.h" +#include "image.h" +#include "colormac.h" +#include "mtypes.h" +#include "macros.h" +#include "bufferobj.h" +#include "swrast/swrast.h" + +#include "intel_screen.h" +#include "intel_context.h" +#include "intel_ioctl.h" +#include "intel_batchbuffer.h" +#include "intel_blit.h" +#include "intel_regions.h" +#include "intel_buffer_objects.h" + + + +#define FILE_DEBUG_FLAG DEBUG_PIXEL + + +/* Unlike the other intel_pixel_* functions, the expectation here is + * that the incoming data is not in a PBO.  With the XY_TEXT blit + * method, there's no benefit haveing it in a PBO, but we could + * implement a path based on XY_MONO_SRC_COPY_BLIT which might benefit + * PBO bitmaps.  I think they are probably pretty rare though - I + * wonder if Xgl uses them? + */ +static const GLubyte *map_pbo( GLcontext *ctx, +			       GLsizei width, GLsizei height, +			       const struct gl_pixelstore_attrib *unpack, +			       const GLubyte *bitmap ) +{ +   GLubyte *buf; + +   if (!_mesa_validate_pbo_access(2, unpack, width, height, 1, +				  GL_COLOR_INDEX, GL_BITMAP, +				  (GLvoid *) bitmap)) { +      _mesa_error(ctx, GL_INVALID_OPERATION,"glBitmap(invalid PBO access)"); +      return NULL; +   } + +   buf = (GLubyte *) ctx->Driver.MapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, +					   GL_READ_ONLY_ARB, +					   unpack->BufferObj); +   if (!buf) { +      _mesa_error(ctx, GL_INVALID_OPERATION, "glBitmap(PBO is mapped)"); +      return NULL; +   } + +   return ADD_POINTERS(buf, bitmap); +} + +static GLboolean test_bit( const GLubyte *src, +			    GLuint bit ) +{ +   return (src[bit/8] & (1<<(bit % 8))) ? 1 : 0; +} + +static void set_bit( GLubyte *dest, +			  GLuint bit ) +{ +   dest[bit/8] |= 1 << (bit % 8); +} + +static int align(int x, int align) +{ +   return (x + align - 1) & ~(align - 1); +} + +/* Extract a rectangle's worth of data from the bitmap.  Called + * per-cliprect. + */ +static GLuint get_bitmap_rect(GLsizei width, GLsizei height, +			      const struct gl_pixelstore_attrib *unpack, +			      const GLubyte *bitmap, +			      GLuint x, GLuint y,  +			      GLuint w, GLuint h, +			      GLubyte *dest, +			      GLuint row_align, +			      GLboolean invert) +{ +   GLuint src_offset = (x + unpack->SkipPixels) & 0x7; +   GLuint mask = unpack->LsbFirst ? 0 : 7; +   GLuint bit = 0; +   GLint row, col; +   GLint first, last; +   GLint incr; +   GLuint count = 0; + +   if (INTEL_DEBUG & DEBUG_PIXEL) +      _mesa_printf("%s %d,%d %dx%d bitmap %dx%d skip %d src_offset %d mask %d\n", +		   __FUNCTION__, x,y,w,h,width,height,unpack->SkipPixels, src_offset, mask); + +   if (invert) { +      first = h-1; +      last = 0; +      incr = -1; +   } +   else { +      first = 0; +      last = h-1; +      incr = 1; +   } + +   /* Require that dest be pre-zero'd. +    */ +   for (row = first; row != (last+incr); row += incr) { +      const GLubyte *rowsrc = _mesa_image_address2d(unpack, bitmap,  +						    width, height,  +						    GL_COLOR_INDEX, GL_BITMAP,  +						    y + row, x); + +      for (col = 0; col < w; col++, bit++) { +	 if (test_bit(rowsrc, (col + src_offset) ^ mask)) { +	    set_bit(dest, bit ^ 7); +	    count++; +	 } +      } + +      if (row_align) +	 bit = (bit + row_align - 1) & ~(row_align - 1); +   } + +   return count; +} + + + + +/* + * Render a bitmap. + */ +static GLboolean +do_blit_bitmap( GLcontext *ctx,  +		GLint dstx, GLint dsty, +		GLsizei width, GLsizei height, +		const struct gl_pixelstore_attrib *unpack, +		const GLubyte *bitmap ) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_region *dst = intel_drawbuf_region(intel); +    +   union { +      GLuint ui; +      GLubyte ub[4]; +   } color; + + +   if (unpack->BufferObj->Name) { +      bitmap = map_pbo(ctx, width, height, unpack, bitmap); +      if (bitmap == NULL) +	 return GL_TRUE;	/* even though this is an error, we're done */ +   } + +   UNCLAMPED_FLOAT_TO_CHAN(color.ub[0], ctx->Current.RasterColor[2]); +   UNCLAMPED_FLOAT_TO_CHAN(color.ub[1], ctx->Current.RasterColor[1]); +   UNCLAMPED_FLOAT_TO_CHAN(color.ub[2], ctx->Current.RasterColor[0]); +   UNCLAMPED_FLOAT_TO_CHAN(color.ub[3], ctx->Current.RasterColor[3]); + +   /* Does zoom apply to bitmaps? +    */ +   if (!intel_check_blit_fragment_ops(ctx) || +       ctx->Pixel.ZoomX != 1.0F ||  +       ctx->Pixel.ZoomY != 1.0F) +      return GL_FALSE; + +   LOCK_HARDWARE(intel); + +   if (intel->driDrawable->numClipRects) { +      __DRIdrawablePrivate *dPriv = intel->driDrawable; +      drm_clip_rect_t *box = dPriv->pClipRects; +      drm_clip_rect_t dest_rect; +      GLint nbox = dPriv->numClipRects; +      GLint srcx = 0, srcy = 0; +      GLint orig_screen_x1, orig_screen_y2; +      GLuint i; + + +      orig_screen_x1 = dPriv->x + dstx; +      orig_screen_y2 = dPriv->y + (dPriv->h - dsty); + +      /* Do scissoring in GL coordinates: +       */ +x      if (ctx->Scissor.Enabled) +      { +	 GLint x = ctx->Scissor.X; +	 GLint y = ctx->Scissor.Y; +	 GLuint w = ctx->Scissor.Width; +	 GLuint h = ctx->Scissor.Height; + +         if (!_mesa_clip_to_region(x, y, x+w-1, y+h-1, &dstx, &dsty, &width, &height)) +            goto out; +      } + +      /* Convert from GL to hardware coordinates: +       */ +      dsty = dPriv->y + (dPriv->h - dsty - height);   +      dstx = dPriv->x + dstx; + +      dest_rect.x1 = dstx; +      dest_rect.y1 = dsty; +      dest_rect.x2 = dstx + width; +      dest_rect.y2 = dsty + height; + +      for (i = 0; i < nbox; i++) { +         drm_clip_rect_t rect; +	 int box_w, box_h; +	 GLint px, py; +	 GLuint stipple[32];   + +         if (!intel_intersect_cliprects(&rect, &dest_rect, &box[i])) +            continue; + +	 /* Now go back to GL coordinates to figure out what subset of +	  * the bitmap we are uploading for this cliprect: +	  */ +	 box_w = rect.x2 - rect.x1; +	 box_h = rect.y2 - rect.y1; +	 srcx = rect.x1 - orig_screen_x1; +	 srcy = orig_screen_y2 - rect.y2; + + +#define DY 32 +#define DX 32 + +	 /* Then, finally, chop it all into chunks that can be +	  * digested by hardware: +	  */ +	 for (py = 0; py < box_h; py += DY) {  +	    for (px = 0; px < box_w; px += DX) {  +	       int h = MIN2(DY, box_h - py); +	       int w = MIN2(DX, box_w - px);  +	       GLuint sz = align(align(w,8) * h, 64)/8; +	     +	       assert(sz <= sizeof(stipple)); +	       memset(stipple, 0, sz); + +	       /* May need to adjust this when padding has been introduced in +		* sz above: +		*/ +	       if (get_bitmap_rect(width, height, unpack,  +				   bitmap, +				   srcx + px, srcy + py, w, h, +				   (GLubyte *)stipple, +				   8, +				   GL_TRUE) == 0) +		  continue; + +	       /*  +		*/ +	       intelEmitImmediateColorExpandBlit( intel, +						  dst->cpp, +						  (GLubyte *)stipple,  +						  sz, +						  color.ui, +						  dst->pitch, +						  dst->buffer, +						  0, +						  dst->tiled, +						  rect.x1 + px, +						  rect.y2 - (py + h), +						  w, h); +	    }  +	 }  +      } +      intel->need_flush = GL_TRUE; +   out: +      intel_batchbuffer_flush(intel->batch); +   } +   UNLOCK_HARDWARE(intel); + + +   if (unpack->BufferObj->Name) { +      /* done with PBO so unmap it now */ +      ctx->Driver.UnmapBuffer(ctx, GL_PIXEL_UNPACK_BUFFER_EXT, +                              unpack->BufferObj); +   } + +   return GL_TRUE; +} + + + + + +/* There are a large number of possible ways to implement bitmap on + * this hardware, most of them have some sort of drawback.  Here are a + * few that spring to mind: + *  + * Blit: + *    - XY_MONO_SRC_BLT_CMD + *         - use XY_SETUP_CLIP_BLT for cliprect clipping. + *    - XY_TEXT_BLT + *    - XY_TEXT_IMMEDIATE_BLT + *         - blit per cliprect, subject to maximum immediate data size. + *    - XY_COLOR_BLT  + *         - per pixel or run of pixels + *    - XY_PIXEL_BLT + *         - good for sparse bitmaps + * + * 3D engine: + *    - Point per pixel + *    - Translate bitmap to an alpha texture and render as a quad + *    - Chop bitmap up into 32x32 squares and render w/polygon stipple. + */ +void +intelBitmap(GLcontext * ctx, +	    GLint x, GLint y, +	    GLsizei width, GLsizei height, +	    const struct gl_pixelstore_attrib *unpack, +	    const GLubyte * pixels) +{ +   if (do_blit_bitmap(ctx, x, y, width, height, +                          unpack, pixels)) +      return; + +   if (INTEL_DEBUG & DEBUG_PIXEL) +      _mesa_printf("%s: fallback to swrast\n", __FUNCTION__); + +   _swrast_Bitmap(ctx, x, y, width, height, unpack, pixels); +} diff --git a/src/mesa/drivers/dri/i915tex/intel_pixel_copy.c b/src/mesa/drivers/dri/i915tex/intel_pixel_copy.c new file mode 100644 index 0000000000..5eb021f008 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_pixel_copy.c @@ -0,0 +1,380 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#include "glheader.h" +#include "enums.h" +#include "image.h" +#include "state.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" +#include "intel_buffers.h" +#include "intel_blit.h" +#include "intel_regions.h" +#include "intel_tris.h" +#include "intel_pixel.h" + +#define FILE_DEBUG_FLAG DEBUG_PIXEL + +static struct intel_region * +copypix_src_region(struct intel_context *intel, GLenum type) +{ +   switch (type) { +   case GL_COLOR: +      return intel_readbuf_region(intel); +   case GL_DEPTH: +      /* Don't think this is really possible execpt at 16bpp, when we have no stencil. +       */ +      if (intel->intelScreen->depth_region &&  +	  intel->intelScreen->depth_region->cpp == 2) +         return intel->intelScreen->depth_region; +   case GL_STENCIL: +      /* Don't think this is really possible.  +       */ +      break; +   case GL_DEPTH_STENCIL_EXT: +      /* Does it matter whether it is stencil/depth or depth/stencil? +       */ +      return intel->intelScreen->depth_region; +   default: +      break; +   } + +   return NULL; +} + + +/** + * Check if any fragment operations are in effect which might effect + * glCopyPixels.  Differs from intel_check_blit_fragment_ops in that + * we allow Scissor. + */ +static GLboolean +intel_check_copypixel_blit_fragment_ops(GLcontext * ctx) +{ +   if (ctx->NewState) +      _mesa_update_state(ctx); + +   /* Could do logicop with the blitter:  +    */ +   return !(ctx->_ImageTransferState || +            ctx->Color.AlphaEnabled || +            ctx->Depth.Test || +            ctx->Fog.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->FragmentProgram._Enabled); +} + +/* Doesn't work for overlapping regions.  Could do a double copy or + * just fallback. + */ +static GLboolean +do_texture_copypixels(GLcontext * ctx, +                      GLint srcx, GLint srcy, +                      GLsizei width, GLsizei height, +                      GLint dstx, GLint dsty, GLenum type) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_region *dst = intel_drawbuf_region(intel); +   struct intel_region *src = copypix_src_region(intel, type); +   GLenum src_format; +   GLenum src_type; + +   DBG("%s %d,%d %dx%d --> %d,%d\n", __FUNCTION__,  +       srcx, srcy, width, height, dstx, dsty); + +   if (!src || !dst || type != GL_COLOR) +      return GL_FALSE; + +   /* Can't handle overlapping regions.  Don't have sufficient control +    * over rasterization to pull it off in-place.  Punt on these for +    * now. +    *  +    * XXX: do a copy to a temporary.  +    */ +   if (src->buffer == dst->buffer) { +      drm_clip_rect_t srcbox; +      drm_clip_rect_t dstbox; +      drm_clip_rect_t tmp; + +      srcbox.x1 = srcx; +      srcbox.y1 = srcy; +      srcbox.x2 = srcx + width; +      srcbox.y2 = srcy + height; + +      dstbox.x1 = dstx; +      dstbox.y1 = dsty; +      dstbox.x2 = dstx + width * ctx->Pixel.ZoomX; +      dstbox.y2 = dsty + height * ctx->Pixel.ZoomY; + +      DBG("src %d,%d %d,%d\n", srcbox.x1, srcbox.y1, srcbox.x2, srcbox.y2); +      DBG("dst %d,%d %d,%d (%dx%d) (%f,%f)\n", dstbox.x1, dstbox.y1, dstbox.x2, dstbox.y2, +	  width, height, ctx->Pixel.ZoomX, ctx->Pixel.ZoomY); + +      if (intel_intersect_cliprects(&tmp, &srcbox, &dstbox)) { +         DBG("%s: regions overlap\n", __FUNCTION__); +         return GL_FALSE; +      } +   } + +   intelFlush(&intel->ctx); + +   intel->vtbl.install_meta_state(intel); + +   /* Is this true?  Also will need to turn depth testing on according +    * to state: +    */ +   intel->vtbl.meta_no_stencil_write(intel); +   intel->vtbl.meta_no_depth_write(intel); + +   /* Set the 3d engine to draw into the destination region: +    */ +   intel->vtbl.meta_draw_region(intel, dst, intel->intelScreen->depth_region); + +   intel->vtbl.meta_import_pixel_state(intel); + +   if (src->cpp == 2) { +      src_format = GL_RGB; +      src_type = GL_UNSIGNED_SHORT_5_6_5; +   } +   else { +      src_format = GL_BGRA; +      src_type = GL_UNSIGNED_BYTE; +   } + +   /* Set the frontbuffer up as a large rectangular texture. +    */ +   if (!intel->vtbl.meta_tex_rect_source(intel, src->buffer, 0, +                                         src->pitch, +                                         src->height, src_format, src_type)) { +      intel->vtbl.leave_meta_state(intel); +      return GL_FALSE; +   } + + +   intel->vtbl.meta_texture_blend_replace(intel); + +   LOCK_HARDWARE(intel); + +   if (intel->driDrawable->numClipRects) { +      __DRIdrawablePrivate *dPriv = intel->driDrawable; + + +      srcy = dPriv->h - srcy - height;  /* convert from gl to hardware coords */ + +      srcx += dPriv->x; +      srcy += dPriv->y; + +      /* Clip against the source region.  This is the only source +       * clipping we do.  XXX: Just set the texcord wrap mode to clamp +       * or similar. +       * +       */ +      if (0) { +         GLint orig_x = srcx; +         GLint orig_y = srcy; + +         if (!_mesa_clip_to_region(0, 0, src->pitch, src->height, +                                   &srcx, &srcy, &width, &height)) +            goto out; + +         dstx += srcx - orig_x; +         dsty += (srcy - orig_y) * ctx->Pixel.ZoomY; +      } + +      /* Just use the regular cliprect mechanism...  Does this need to +       * even hold the lock??? +       */ +      intel_meta_draw_quad(intel,  +			   dstx,  +			   dstx + width * ctx->Pixel.ZoomX,  +			   dPriv->h - (dsty + height * ctx->Pixel.ZoomY),  +			   dPriv->h - (dsty), 0,   /* XXX: what z value? */ +                           0x00ff00ff, +                           srcx, srcx + width, srcy, srcy + height); + +    out: +      intel->vtbl.leave_meta_state(intel); +      intel_batchbuffer_flush(intel->batch); +   } +   UNLOCK_HARDWARE(intel); + +   DBG("%s: success\n", __FUNCTION__); +   return GL_TRUE; +} + + + + + +/** + * CopyPixels with the blitter.  Don't support zooming, pixel transfer, etc. + */ +static GLboolean +do_blit_copypixels(GLcontext * ctx, +                   GLint srcx, GLint srcy, +                   GLsizei width, GLsizei height, +                   GLint dstx, GLint dsty, GLenum type) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_region *dst = intel_drawbuf_region(intel); +   struct intel_region *src = copypix_src_region(intel, type); + +   /* Copypixels can be more than a straight copy.  Ensure all the +    * extra operations are disabled: +    */ +   if (!intel_check_copypixel_blit_fragment_ops(ctx) || +       ctx->Pixel.ZoomX != 1.0F || ctx->Pixel.ZoomY != 1.0F) +      return GL_FALSE; + +   if (!src || !dst) +      return GL_FALSE; + + + +   intelFlush(&intel->ctx); + +   LOCK_HARDWARE(intel); + +   if (intel->driDrawable->numClipRects) { +      __DRIdrawablePrivate *dPriv = intel->driDrawable; +      drm_clip_rect_t *box = dPriv->pClipRects; +      drm_clip_rect_t dest_rect; +      GLint nbox = dPriv->numClipRects; +      GLint delta_x = 0; +      GLint delta_y = 0; +      GLuint i; + +      /* Do scissoring in GL coordinates: +       */ +      if (ctx->Scissor.Enabled) +      { +	 GLint x = ctx->Scissor.X; +	 GLint y = ctx->Scissor.Y; +	 GLuint w = ctx->Scissor.Width; +	 GLuint h = ctx->Scissor.Height; +	 GLint dx = dstx - srcx; +         GLint dy = dsty - srcy; + +         if (!_mesa_clip_to_region(x, y, x+w-1, y+h-1, &dstx, &dsty, &width, &height)) +            goto out; +	  +         srcx = dstx - dx; +         srcy = dsty - dy; +      } + +      /* Convert from GL to hardware coordinates: +       */ +      dsty = dPriv->h - dsty - height;   +      srcy = dPriv->h - srcy - height;   +      dstx += dPriv->x; +      dsty += dPriv->y; +      srcx += dPriv->x; +      srcy += dPriv->y; + +      /* Clip against the source region.  This is the only source +       * clipping we do.  Dst is clipped with cliprects below. +       */ +      { +         delta_x = srcx - dstx; +         delta_y = srcy - dsty; + +         if (!_mesa_clip_to_region(0, 0, src->pitch, src->height, +                                   &srcx, &srcy, &width, &height)) +            goto out; + +         dstx = srcx - delta_x; +         dsty = srcy - delta_y; +      } + +      dest_rect.x1 = dstx; +      dest_rect.y1 = dsty; +      dest_rect.x2 = dstx + width; +      dest_rect.y2 = dsty + height; + +      /* Could do slightly more clipping: Eg, take the intersection of +       * the existing set of cliprects and those cliprects translated +       * by delta_x, delta_y: +       *  +       * This code will not overwrite other windows, but will +       * introduce garbage when copying from obscured window regions. +       */ +      for (i = 0; i < nbox; i++) { +         drm_clip_rect_t rect; + +         if (!intel_intersect_cliprects(&rect, &dest_rect, &box[i])) +            continue; + + +         intelEmitCopyBlit(intel, dst->cpp,  +			   src->pitch, src->buffer, 0,  +			   dst->pitch, dst->buffer, 0,  +			   rect.x1 + delta_x, rect.y1 + delta_y,       /* srcx, srcy */ +                           rect.x1, rect.y1,    /* dstx, dsty */ +                           rect.x2 - rect.x1, rect.y2 - rect.y1); +      } + +    out: +      intel_batchbuffer_flush(intel->batch); +   } +   UNLOCK_HARDWARE(intel); + +   DBG("%s: success\n", __FUNCTION__); +   return GL_TRUE; +} + + +void +intelCopyPixels(GLcontext * ctx, +                GLint srcx, GLint srcy, +                GLsizei width, GLsizei height, +                GLint destx, GLint desty, GLenum type) +{ +   if (INTEL_DEBUG & DEBUG_PIXEL) +      fprintf(stderr, "%s\n", __FUNCTION__); + +   if (do_blit_copypixels(ctx, srcx, srcy, width, height, destx, desty, type)) +      return; + +   if (do_texture_copypixels(ctx, srcx, srcy, width, height, destx, desty, type)) +      return; + +   DBG("fallback to _swrast_CopyPixels\n"); + +   _swrast_CopyPixels(ctx, srcx, srcy, width, height, destx, desty, type); +} diff --git a/src/mesa/drivers/dri/i915tex/intel_pixel_draw.c b/src/mesa/drivers/dri/i915tex/intel_pixel_draw.c new file mode 100644 index 0000000000..616101aef9 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_pixel_draw.c @@ -0,0 +1,365 @@ +/************************************************************************** + *  + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portionsalloc + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#include "glheader.h" +#include "enums.h" +#include "image.h" +#include "mtypes.h" +#include "macros.h" +#include "bufferobj.h" +#include "swrast/swrast.h" + +#include "intel_screen.h" +#include "intel_context.h" +#include "intel_ioctl.h" +#include "intel_batchbuffer.h" +#include "intel_blit.h" +#include "intel_buffers.h" +#include "intel_regions.h" +#include "intel_pixel.h" +#include "intel_buffer_objects.h" +#include "intel_tris.h" + + + +static GLboolean +do_texture_drawpixels(GLcontext * ctx, +                      GLint x, GLint y, +                      GLsizei width, GLsizei height, +                      GLenum format, GLenum type, +                      const struct gl_pixelstore_attrib *unpack, +                      const GLvoid * pixels) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_region *dst = intel_drawbuf_region(intel); +   struct intel_buffer_object *src = intel_buffer_object(unpack->BufferObj); +   GLuint rowLength = unpack->RowLength ? unpack->RowLength : width; +   GLuint src_offset; + +   if (INTEL_DEBUG & DEBUG_PIXEL) +      fprintf(stderr, "%s\n", __FUNCTION__); + +   intelFlush(&intel->ctx); +   intel->vtbl.render_start(intel); +   intel->vtbl.emit_state(intel); + +   if (!dst) +      return GL_FALSE; + +   if (src) { +      if (!_mesa_validate_pbo_access(2, unpack, width, height, 1, +                                     format, type, pixels)) { +         _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels"); +         return GL_TRUE; +      } +   } +   else { +      /* PBO only for now: +       */ +/*       _mesa_printf("%s - not PBO\n", __FUNCTION__); */ +      return GL_FALSE; +   } + +   /* There are a couple of things we can't do yet, one of which is +    * set the correct state for pixel operations when GL texturing is +    * enabled.  That's a pretty rare state and probably not worth the +    * effort.  A completely device-independent version of this may do +    * more. +    * +    * Similarly, we make no attempt to merge metaops processing with +    * an enabled fragment program, though it would certainly be +    * possible. +    */ +   if (!intel_check_meta_tex_fragment_ops(ctx)) { +      if (INTEL_DEBUG & DEBUG_PIXEL) +         _mesa_printf("%s - bad GL fragment state for metaops texture\n", +                      __FUNCTION__); +      return GL_FALSE; +   } + +   intel->vtbl.install_meta_state(intel); + + +   /* Is this true?  Also will need to turn depth testing on according +    * to state: +    */ +   intel->vtbl.meta_no_stencil_write(intel); +   intel->vtbl.meta_no_depth_write(intel); + +   /* Set the 3d engine to draw into the destination region: +    */ +   intel->vtbl.meta_draw_region(intel, dst, intel->intelScreen->depth_region); + +   intel->vtbl.meta_import_pixel_state(intel); + +   src_offset = (GLuint) _mesa_image_address(2, unpack, pixels, width, height, +                                             format, type, 0, 0, 0); + + +   /* Setup the pbo up as a rectangular texture, if possible. +    * +    * TODO: This is almost always possible if the i915 fragment +    * program is adjusted to correctly swizzle the sampled colors. +    * The major exception is any 24bit texture, like RGB888, for which +    * there is no hardware support.   +    */ +   if (!intel->vtbl.meta_tex_rect_source(intel, src->buffer, src_offset, +                                         rowLength, height, format, type)) { +      intel->vtbl.leave_meta_state(intel); +      return GL_FALSE; +   } + +   intel->vtbl.meta_texture_blend_replace(intel); + + +   LOCK_HARDWARE(intel); + +   if (intel->driDrawable->numClipRects) { +      __DRIdrawablePrivate *dPriv = intel->driDrawable; +      GLint srcx, srcy; +      GLint dstx, dsty; + +      dstx = x; +      dsty = dPriv->h - (y + height); + +      srcx = 0;                 /* skiprows/pixels already done */ +      srcy = 0; + +      if (0) { +         const GLint orig_x = dstx; +         const GLint orig_y = dsty; + +         if (!_mesa_clip_to_region(0, 0, dst->pitch, dst->height, +                                   &dstx, &dsty, &width, &height)) +            goto out; + +         srcx += dstx - orig_x; +         srcy += dsty - orig_y; +      } + + +      if (INTEL_DEBUG & DEBUG_PIXEL) +         _mesa_printf("draw %d,%d %dx%d\n", dstx, dsty, width, height); + +      /* Must use the regular cliprect mechanism in order to get the +       * drawing origin set correctly.  Otherwise scissor state is in +       * incorrect coordinate space.  Does this even need to hold the +       * lock??? +       */ +      intel_meta_draw_quad(intel, +                           dstx, dstx + width * ctx->Pixel.ZoomX, +                           dPriv->h - (y + height * ctx->Pixel.ZoomY), +                           dPriv->h - (y), +                           -ctx->Current.RasterPos[2] * .5, +                           0x00ff00ff, +                           srcx, srcx + width, srcy + height, srcy); +    out: +      intel->vtbl.leave_meta_state(intel); +      intel_batchbuffer_flush(intel->batch); +   } +   UNLOCK_HARDWARE(intel); +   return GL_TRUE; +} + + + + + +/* Pros:   + *   - no waiting for idle before updating framebuffer. + *    + * Cons: + *   - if upload is by memcpy, this may actually be slower than fallback path. + *   - uploads the whole image even if destination is clipped + *    + * Need to benchmark. + * + * Given the questions about performance, implement for pbo's only. + * This path is definitely a win if the pbo is already in agp.  If it + * turns out otherwise, we can add the code necessary to upload client + * data to agp space before performing the blit.  (Though it may turn + * out to be better/simpler just to use the texture engine). + */ +static GLboolean +do_blit_drawpixels(GLcontext * ctx, +                   GLint x, GLint y, +                   GLsizei width, GLsizei height, +                   GLenum format, GLenum type, +                   const struct gl_pixelstore_attrib *unpack, +                   const GLvoid * pixels) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_region *dest = intel_drawbuf_region(intel); +   struct intel_buffer_object *src = intel_buffer_object(unpack->BufferObj); +   GLuint src_offset; +   GLuint rowLength; +   struct _DriFenceObject *fence = NULL; + +   if (INTEL_DEBUG & DEBUG_PIXEL) +      _mesa_printf("%s\n", __FUNCTION__); + + +   if (!dest) { +      if (INTEL_DEBUG & DEBUG_PIXEL) +         _mesa_printf("%s - no dest\n", __FUNCTION__); +      return GL_FALSE; +   } + +   if (src) { +      /* This validation should be done by core mesa: +       */ +      if (!_mesa_validate_pbo_access(2, unpack, width, height, 1, +                                     format, type, pixels)) { +         _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels"); +         return GL_TRUE; +      } +   } +   else { +      /* PBO only for now: +       */ +      if (INTEL_DEBUG & DEBUG_PIXEL) +         _mesa_printf("%s - not PBO\n", __FUNCTION__); +      return GL_FALSE; +   } + +   if (!intel_check_blit_format(dest, format, type)) { +      if (INTEL_DEBUG & DEBUG_PIXEL) +         _mesa_printf("%s - bad format for blit\n", __FUNCTION__); +      return GL_FALSE; +   } + +   if (!intel_check_meta_tex_fragment_ops(ctx)) { +      if (INTEL_DEBUG & DEBUG_PIXEL) +         _mesa_printf("%s - bad GL fragment state for meta tex\n", +                      __FUNCTION__); +      return GL_FALSE; +   } + +   if (ctx->Pixel.ZoomX != 1.0F) { +      if (INTEL_DEBUG & DEBUG_PIXEL) +         _mesa_printf("%s - bad PixelZoomX for blit\n", __FUNCTION__); +      return GL_FALSE; +   } + + +   if (unpack->RowLength > 0) +      rowLength = unpack->RowLength; +   else +      rowLength = width; + +   if (ctx->Pixel.ZoomY == -1.0F) { +      if (INTEL_DEBUG & DEBUG_PIXEL) +         _mesa_printf("%s - bad PixelZoomY for blit\n", __FUNCTION__); +      return GL_FALSE;          /* later */ +      y -= height; +   } +   else if (ctx->Pixel.ZoomY == 1.0F) { +      rowLength = -rowLength; +   } +   else { +      if (INTEL_DEBUG & DEBUG_PIXEL) +         _mesa_printf("%s - bad PixelZoomY for blit\n", __FUNCTION__); +      return GL_FALSE; +   } + +   src_offset = (GLuint) _mesa_image_address(2, unpack, pixels, width, height, +                                             format, type, 0, 0, 0); + +   intelFlush(&intel->ctx); +   LOCK_HARDWARE(intel); + +   if (intel->driDrawable->numClipRects) { +      __DRIdrawablePrivate *dPriv = intel->driDrawable; +      int nbox = dPriv->numClipRects; +      drm_clip_rect_t *box = dPriv->pClipRects; +      drm_clip_rect_t rect; +      drm_clip_rect_t dest_rect; +      struct _DriBufferObject *src_buffer = +         intel_bufferobj_buffer(intel, src, INTEL_READ); +      int i; + +      dest_rect.x1 = dPriv->x + x; +      dest_rect.y1 = dPriv->y + dPriv->h - (y + height); +      dest_rect.x2 = dest_rect.x1 + width; +      dest_rect.y2 = dest_rect.y1 + height; + +      for (i = 0; i < nbox; i++) { +         if (!intel_intersect_cliprects(&rect, &dest_rect, &box[i])) +            continue; + +         intelEmitCopyBlit(intel, +                           dest->cpp, +                           rowLength, +                           src_buffer, src_offset, +                           dest->pitch, +                           dest->buffer, 0, +                           rect.x1 - dest_rect.x1, +                           rect.y2 - dest_rect.y2, +                           rect.x1, +                           rect.y1, rect.x2 - rect.x1, rect.y2 - rect.y1); +      } +      fence = intel_batchbuffer_flush(intel->batch); +      driFenceReference(fence); +   } +   UNLOCK_HARDWARE(intel); + +   if (intel->driDrawable->numClipRects) +      driFenceFinish(fence, DRM_FENCE_TYPE_EXE | DRM_I915_FENCE_TYPE_RW, GL_FALSE); + +   driFenceUnReference(fence); + +   if (INTEL_DEBUG & DEBUG_PIXEL) +      _mesa_printf("%s - DONE\n", __FUNCTION__); + +   return GL_TRUE; +} + + + +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 (do_blit_drawpixels(ctx, x, y, width, height, format, type, +                          unpack, pixels)) +      return; + +   if (do_texture_drawpixels(ctx, x, y, width, height, format, type, +                             unpack, pixels)) +      return; + + +   if (INTEL_DEBUG & DEBUG_PIXEL) +      _mesa_printf("%s: fallback to swrast\n", __FUNCTION__); + +   _swrast_DrawPixels(ctx, x, y, width, height, format, type, unpack, pixels); +} diff --git a/src/mesa/drivers/dri/i915tex/intel_pixel_read.c b/src/mesa/drivers/dri/i915tex/intel_pixel_read.c new file mode 100644 index 0000000000..c1cc65674d --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_pixel_read.c @@ -0,0 +1,317 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#include "glheader.h" +#include "enums.h" +#include "mtypes.h" +#include "macros.h" +#include "image.h" +#include "bufferobj.h" +#include "swrast/swrast.h" + +#include "intel_screen.h" +#include "intel_context.h" +#include "intel_ioctl.h" +#include "intel_batchbuffer.h" +#include "intel_blit.h" +#include "intel_buffers.h" +#include "intel_regions.h" +#include "intel_pixel.h" +#include "intel_buffer_objects.h" + +/* For many applications, the new ability to pull the source buffers + * back out of the GTT and then do the packing/conversion operations + * in software will be as much of an improvement as trying to get the + * blitter and/or texture engine to do the work.  + * + * This step is gated on private backbuffers. + *  + * Obviously the frontbuffer can't be pulled back, so that is either + * an argument for blit/texture readpixels, or for blitting to a + * temporary and then pulling that back. + * + * When the destination is a pbo, however, it's not clear if it is + * ever going to be pulled to main memory (though the access param + * will be a good hint).  So it sounds like we do want to be able to + * choose between blit/texture implementation on the gpu and pullback + * and cpu-based copying. + * + * Unless you can magically turn client memory into a PBO for the + * duration of this call, there will be a cpu-based copying step in + * any case. + */ + + +static GLboolean +do_texture_readpixels(GLcontext * ctx, +                      GLint x, GLint y, GLsizei width, GLsizei height, +                      GLenum format, GLenum type, +                      const struct gl_pixelstore_attrib *pack, +                      struct intel_region *dest_region) +{ +#if 0 +   struct intel_context *intel = intel_context(ctx); +   intelScreenPrivate *screen = intel->intelScreen; +   GLint pitch = pack->RowLength ? pack->RowLength : width; +   __DRIdrawablePrivate *dPriv = intel->driDrawable; +   int textureFormat; +   GLenum glTextureFormat; +   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) { +      if (INTEL_DEBUG & DEBUG_PIXEL) +         fprintf(stderr, "%s: check_color failed\n", __FUNCTION__); +      return GL_FALSE; +   } + +   intel->vtbl.meta_texrect_source(intel, intel_readbuf_region(intel)); + +   if (!intel->vtbl.meta_render_dest(intel, dest_region, type, format)) { +      if (INTEL_DEBUG & DEBUG_PIXEL) +         fprintf(stderr, "%s: couldn't set dest %s/%s\n", +                 __FUNCTION__, +                 _mesa_lookup_enum_by_nr(type), +                 _mesa_lookup_enum_by_nr(format)); +      return GL_FALSE; +   } + +   LOCK_HARDWARE(intel); + +   if (intel->driDrawable->numClipRects) { +      intel->vtbl.install_meta_state(intel); +      intel->vtbl.meta_no_depth_write(intel); +      intel->vtbl.meta_no_stencil_write(intel); + +      if (!driClipRectToFramebuffer(ctx->ReadBuffer, &x, &y, &width, &height)) { +         UNLOCK_HARDWARE(intel); +         SET_STATE(i830, state); +         if (INTEL_DEBUG & DEBUG_PIXEL) +            fprintf(stderr, "%s: cliprect failed\n", __FUNCTION__); +         return GL_TRUE; +      } + +      y = dPriv->h - y - height; +      x += dPriv->x; +      y += dPriv->y; + + +      /* Set the frontbuffer up as a large rectangular texture. +       */ +      intel->vtbl.meta_tex_rect_source(intel, src_region, textureFormat); + + +      intel->vtbl.meta_texture_blend_replace(i830, glTextureFormat); + + +      /* Set the 3d engine to draw into the destination region: +       */ + +      intel->vtbl.meta_draw_region(intel, dest_region); +      intel->vtbl.meta_draw_format(intel, destFormat, depthFormat);     /* ?? */ + + +      /* Draw a single quad, no cliprects: +       */ +      intel->vtbl.meta_disable_cliprects(intel); + +      intel->vtbl.draw_quad(intel, +                            0, width, 0, height, +                            0x00ff00ff, x, x + width, y, y + height); + +      intel->vtbl.leave_meta_state(intel); +   } +   UNLOCK_HARDWARE(intel); + +   intel_region_wait_fence(ctx, dest_region);   /* required by GL */ +   return GL_TRUE; +#endif + +   return GL_FALSE; +} + + + + +static GLboolean +do_blit_readpixels(GLcontext * ctx, +                   GLint x, GLint y, GLsizei width, GLsizei height, +                   GLenum format, GLenum type, +                   const struct gl_pixelstore_attrib *pack, GLvoid * pixels) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_region *src = intel_readbuf_region(intel); +   struct intel_buffer_object *dst = intel_buffer_object(pack->BufferObj); +   GLuint dst_offset; +   GLuint rowLength; +   struct _DriFenceObject *fence = NULL; + +   if (INTEL_DEBUG & DEBUG_PIXEL) +      _mesa_printf("%s\n", __FUNCTION__); + +   if (!src) +      return GL_FALSE; + +   if (dst) { +      /* XXX This validation should be done by core mesa: +       */ +      if (!_mesa_validate_pbo_access(2, pack, width, height, 1, +                                     format, type, pixels)) { +         _mesa_error(ctx, GL_INVALID_OPERATION, "glDrawPixels"); +         return GL_TRUE; +      } +   } +   else { +      /* PBO only for now: +       */ +      if (INTEL_DEBUG & DEBUG_PIXEL) +         _mesa_printf("%s - not PBO\n", __FUNCTION__); +      return GL_FALSE; +   } + + +   if (ctx->_ImageTransferState || +       !intel_check_blit_format(src, format, type)) { +      if (INTEL_DEBUG & DEBUG_PIXEL) +         _mesa_printf("%s - bad format for blit\n", __FUNCTION__); +      return GL_FALSE; +   } + +   if (pack->Alignment != 1 || pack->SwapBytes || pack->LsbFirst) { +      if (INTEL_DEBUG & DEBUG_PIXEL) +         _mesa_printf("%s: bad packing params\n", __FUNCTION__); +      return GL_FALSE; +   } + +   if (pack->RowLength > 0) +      rowLength = pack->RowLength; +   else +      rowLength = width; + +   if (pack->Invert) { +      if (INTEL_DEBUG & DEBUG_PIXEL) +         _mesa_printf("%s: MESA_PACK_INVERT not done yet\n", __FUNCTION__); +      return GL_FALSE; +   } +   else { +      rowLength = -rowLength; +   } + +   /* XXX 64-bit cast? */ +   dst_offset = (GLuint) _mesa_image_address(2, pack, pixels, width, height, +                                             format, type, 0, 0, 0); + + +   /* Although the blits go on the command buffer, need to do this and +    * fire with lock held to guarentee cliprects are correct. +    */ +   intelFlush(&intel->ctx); +   LOCK_HARDWARE(intel); + +   if (intel->driDrawable->numClipRects) { +      GLboolean all = (width * height * src->cpp == dst->Base.Size && +                       x == 0 && dst_offset == 0); + +      struct _DriBufferObject *dst_buffer = +         intel_bufferobj_buffer(intel, dst, all ? INTEL_WRITE_FULL : +                                INTEL_WRITE_PART); +      __DRIdrawablePrivate *dPriv = intel->driDrawable; +      int nbox = dPriv->numClipRects; +      drm_clip_rect_t *box = dPriv->pClipRects; +      drm_clip_rect_t rect; +      drm_clip_rect_t src_rect; +      int i; + +      src_rect.x1 = dPriv->x + x; +      src_rect.y1 = dPriv->y + dPriv->h - (y + height); +      src_rect.x2 = src_rect.x1 + width; +      src_rect.y2 = src_rect.y1 + height; + + + +      for (i = 0; i < nbox; i++) { +         if (!intel_intersect_cliprects(&rect, &src_rect, &box[i])) +            continue; + +         intelEmitCopyBlit(intel, +                           src->cpp, +                           src->pitch, src->buffer, 0, +                           rowLength, +                           dst_buffer, dst_offset, +                           rect.x1, +                           rect.y1, +                           rect.x1 - src_rect.x1, +                           rect.y2 - src_rect.y2, +                           rect.x2 - rect.x1, rect.y2 - rect.y1); +      } + +      fence = intel_batchbuffer_flush(intel->batch); +      driFenceReference(fence); + +   } +   UNLOCK_HARDWARE(intel); + +   if (intel->driDrawable->numClipRects) +      driFenceFinish(fence, DRM_FENCE_TYPE_EXE | DRM_I915_FENCE_TYPE_RW,  +		     GL_FALSE); + +   driFenceUnReference(fence); +   if (INTEL_DEBUG & DEBUG_PIXEL) +      _mesa_printf("%s - DONE\n", __FUNCTION__); + +   return GL_TRUE; +} + +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__); + +   intelFlush(ctx); + +   if (do_blit_readpixels +       (ctx, x, y, width, height, format, type, pack, pixels)) +      return; + +   if (do_texture_readpixels +       (ctx, x, y, width, height, format, type, pack, pixels)) +      return; + +   if (INTEL_DEBUG & DEBUG_PIXEL) +      _mesa_printf("%s: fallback to swrast\n", __FUNCTION__); + +   _swrast_ReadPixels(ctx, x, y, width, height, format, type, pack, pixels); +} diff --git a/src/mesa/drivers/dri/i915tex/intel_reg.h b/src/mesa/drivers/dri/i915tex/intel_reg.h new file mode 100644 index 0000000000..1ec153266c --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_reg.h @@ -0,0 +1,84 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + + +#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/i915tex/intel_regions.c b/src/mesa/drivers/dri/i915tex/intel_regions.c new file mode 100644 index 0000000000..064a34cda8 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_regions.c @@ -0,0 +1,466 @@ +/************************************************************************** + *  + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +/* Provide additional functionality on top of bufmgr buffers: + *   - 2d semantics and blit operations + *   - refcounting of buffers for multiple images in a buffer. + *   - refcounting of buffer mappings. + *   - some logic for moving the buffers to the best memory pools for + *     given operations. + * + * Most of this is to make it easier to implement the fixed-layout + * mipmap tree required by intel hardware in the face of GL's + * programming interface where each image can be specifed in random + * order and it isn't clear what layout the tree should have until the + * last moment. + */ + +#include "intel_context.h" +#include "intel_regions.h" +#include "intel_blit.h" +#include "intel_buffer_objects.h" +#include "dri_bufmgr.h" +#include "intel_batchbuffer.h" + +#define FILE_DEBUG_FLAG DEBUG_REGION + +void +intel_region_idle(intelScreenPrivate *intelScreen, struct intel_region *region) +{ +   DBG("%s\n", __FUNCTION__); +   if (region && region->buffer) +      driBOWaitIdle(region->buffer, GL_FALSE); +} + +/* XXX: Thread safety? + */ +GLubyte * +intel_region_map(intelScreenPrivate *intelScreen, struct intel_region *region) +{ +   DBG("%s\n", __FUNCTION__); +   if (!region->map_refcount++) { +      if (region->pbo) +         intel_region_cow(intelScreen, region); + +      region->map = driBOMap(region->buffer, +                             DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0); +   } + +   return region->map; +} + +void +intel_region_unmap(intelScreenPrivate *intelScreen, struct intel_region *region) +{ +   DBG("%s\n", __FUNCTION__); +   if (!--region->map_refcount) { +      driBOUnmap(region->buffer); +      region->map = NULL; +   } +} + +#undef TEST_CACHED_TEXTURES + +struct intel_region * +intel_region_alloc(intelScreenPrivate *intelScreen, +                   GLuint cpp, GLuint pitch, GLuint height) +{ +   struct intel_region *region = calloc(sizeof(*region), 1); + +   DBG("%s\n", __FUNCTION__); + +   region->cpp = cpp; +   region->pitch = pitch; +   region->height = height;     /* needed? */ +   region->refcount = 1; + +   driGenBuffers(intelScreen->regionPool, +                 "region", 1, ®ion->buffer, 64, +#ifdef TEST_CACHED_TEXTURES		  +		 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_BIND_CACHED | +		 DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE,  +#else +		 0, +#endif +		 0); +   driBOData(region->buffer, pitch * cpp * height, NULL, 0); +   return region; +} + +void +intel_region_reference(struct intel_region **dst, struct intel_region *src) +{ +   assert(*dst == NULL); +   if (src) { +      src->refcount++; +      *dst = src; +   } +} + +void +intel_region_release(struct intel_region **region) +{ +   if (!*region) +      return; + +   DBG("%s %d\n", __FUNCTION__, (*region)->refcount - 1); + +   ASSERT((*region)->refcount > 0); +   (*region)->refcount--; + +   if ((*region)->refcount == 0) { +      assert((*region)->map_refcount == 0); + +      if ((*region)->pbo) +	 (*region)->pbo->region = NULL; +      (*region)->pbo = NULL; +      driBOUnReference((*region)->buffer); +      free(*region); +   } +   *region = NULL; +} + + +struct intel_region * +intel_region_create_static(intelScreenPrivate *intelScreen, +                           GLuint mem_type, +                           GLuint offset, +                           void *virtual, +                           GLuint cpp, GLuint pitch, GLuint height) +{ +   struct intel_region *region = calloc(sizeof(*region), 1); +   DBG("%s\n", __FUNCTION__); + +   region->cpp = cpp; +   region->pitch = pitch; +   region->height = height;     /* needed? */ +   region->refcount = 1; + +   /* +    * We use a "shared" buffer type to indicate buffers created and +    * shared by others. +    */ + +   driGenBuffers(intelScreen->staticPool, "static region", 1, +                 ®ion->buffer, 64, +                 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_NO_MOVE | +                 DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0); +   driBOSetStatic(region->buffer, offset, pitch * cpp * height, virtual, 0); + +   return region; +} + + + +void +intel_region_update_static(intelScreenPrivate *intelScreen, +			   struct intel_region *region, +                           GLuint mem_type, +                           GLuint offset, +                           void *virtual, +                           GLuint cpp, GLuint pitch, GLuint height) +{ +   DBG("%s\n", __FUNCTION__); + +   region->cpp = cpp; +   region->pitch = pitch; +   region->height = height;     /* needed? */ + +   /* +    * We use a "shared" buffer type to indicate buffers created and +    * shared by others. +    */ + +   driDeleteBuffers(1, ®ion->buffer); +   driGenBuffers(intelScreen->staticPool, "static region", 1, +                 ®ion->buffer, 64, +                 DRM_BO_FLAG_MEM_TT | DRM_BO_FLAG_NO_MOVE | +                 DRM_BO_FLAG_READ | DRM_BO_FLAG_WRITE, 0); +   driBOSetStatic(region->buffer, offset, pitch * cpp * height, virtual, 0); + +} + + + +/* + * XXX Move this into core Mesa? + */ +static void +_mesa_copy_rect(GLubyte * dst, +                GLuint cpp, +                GLuint dst_pitch, +                GLuint dst_x, +                GLuint dst_y, +                GLuint width, +                GLuint height, +                GLubyte * src, GLuint src_pitch, GLuint src_x, GLuint src_y) +{ +   GLuint i; + +   dst_pitch *= cpp; +   src_pitch *= cpp; +   dst += dst_x * cpp; +   src += src_x * cpp; +   dst += dst_y * dst_pitch; +   src += src_y * dst_pitch; +   width *= cpp; + +   if (width == dst_pitch && width == src_pitch) +      memcpy(dst, src, height * width); +   else { +      for (i = 0; i < height; i++) { +         memcpy(dst, src, width); +         dst += dst_pitch; +         src += src_pitch; +      } +   } +} + + +/* Upload data to a rectangular sub-region.  Lots of choices how to do this: + * + * - memcpy by span to current destination + * - upload data as new buffer and blit + * + * Currently always memcpy. + */ +void +intel_region_data(intelScreenPrivate *intelScreen, +                  struct intel_region *dst, +                  GLuint dst_offset, +                  GLuint dstx, GLuint dsty, +                  void *src, GLuint src_pitch, +                  GLuint srcx, GLuint srcy, GLuint width, GLuint height) +{ +   struct intel_context *intel = intelScreenContext(intelScreen); + +   DBG("%s\n", __FUNCTION__); + +   if (intel == NULL) +      return; + +   if (dst->pbo) { +      if (dstx == 0 && +          dsty == 0 && width == dst->pitch && height == dst->height) +         intel_region_release_pbo(intelScreen, dst); +      else +         intel_region_cow(intelScreen, dst); +   } + + +   LOCK_HARDWARE(intel); + +   _mesa_copy_rect(intel_region_map(intelScreen, dst) + dst_offset, +                   dst->cpp, +                   dst->pitch, +                   dstx, dsty, width, height, src, src_pitch, srcx, srcy); + +   intel_region_unmap(intelScreen, dst); + +   UNLOCK_HARDWARE(intel); + +} + +/* Copy rectangular sub-regions. Need better logic about when to + * push buffers into AGP - will currently do so whenever possible. + */ +void +intel_region_copy(intelScreenPrivate *intelScreen, +                  struct intel_region *dst, +                  GLuint dst_offset, +                  GLuint dstx, GLuint dsty, +                  struct intel_region *src, +                  GLuint src_offset, +                  GLuint srcx, GLuint srcy, GLuint width, GLuint height) +{ +   struct intel_context *intel = intelScreenContext(intelScreen); + +   DBG("%s\n", __FUNCTION__); + +   if (intel == NULL) +      return; + +   if (dst->pbo) { +      if (dstx == 0 && +          dsty == 0 && width == dst->pitch && height == dst->height) +         intel_region_release_pbo(intelScreen, dst); +      else +         intel_region_cow(intelScreen, dst); +   } + +   assert(src->cpp == dst->cpp); + +   intelEmitCopyBlit(intel, +                     dst->cpp, +                     src->pitch, src->buffer, src_offset, +                     dst->pitch, dst->buffer, dst_offset, +                     srcx, srcy, dstx, dsty, width, height); +} + +/* Fill a rectangular sub-region.  Need better logic about when to + * push buffers into AGP - will currently do so whenever possible. + */ +void +intel_region_fill(intelScreenPrivate *intelScreen, +                  struct intel_region *dst, +                  GLuint dst_offset, +                  GLuint dstx, GLuint dsty, +                  GLuint width, GLuint height, GLuint color) +{ +   struct intel_context *intel = intelScreenContext(intelScreen); + +   DBG("%s\n", __FUNCTION__); + +   if (intel == NULL) +      return;    + +   if (dst->pbo) { +      if (dstx == 0 && +          dsty == 0 && width == dst->pitch && height == dst->height) +         intel_region_release_pbo(intelScreen, dst); +      else +         intel_region_cow(intelScreen, dst); +   } + +   intelEmitFillBlit(intel, +                     dst->cpp, +                     dst->pitch, dst->buffer, dst_offset, +                     dstx, dsty, width, height, color); +} + +/* Attach to a pbo, discarding our data.  Effectively zero-copy upload + * the pbo's data. + */ +void +intel_region_attach_pbo(intelScreenPrivate *intelScreen, +                        struct intel_region *region, +                        struct intel_buffer_object *pbo) +{ +   if (region->pbo == pbo) +      return; + +   /* If there is already a pbo attached, break the cow tie now. +    * Don't call intel_region_release_pbo() as that would +    * unnecessarily allocate a new buffer we would have to immediately +    * discard. +    */ +   if (region->pbo) { +      region->pbo->region = NULL; +      region->pbo = NULL; +   } + +   if (region->buffer) { +      driDeleteBuffers(1, ®ion->buffer); +      region->buffer = NULL; +   } + +   region->pbo = pbo; +   region->pbo->region = region; +   region->buffer = driBOReference(pbo->buffer); +} + + +/* Break the COW tie to the pbo.  The pbo gets to keep the data. + */ +void +intel_region_release_pbo(intelScreenPrivate *intelScreen, +                         struct intel_region *region) +{ +   assert(region->buffer == region->pbo->buffer); +   region->pbo->region = NULL; +   region->pbo = NULL; +   driBOUnReference(region->buffer); +   region->buffer = NULL; + +   driGenBuffers(intelScreen->regionPool, +                 "region", 1, ®ion->buffer, 64, 0, 0); +   driBOData(region->buffer, +             region->cpp * region->pitch * region->height, NULL, 0); +} + +/* Break the COW tie to the pbo.  Both the pbo and the region end up + * with a copy of the data. + */ +void +intel_region_cow(intelScreenPrivate *intelScreen, struct intel_region *region) +{ +   struct intel_context *intel = intelScreenContext(intelScreen); +   struct intel_buffer_object *pbo = region->pbo; + +   if (intel == NULL) +      return; + +   intel_region_release_pbo(intelScreen, region); + +   assert(region->cpp * region->pitch * region->height == pbo->Base.Size); + +   DBG("%s (%d bytes)\n", __FUNCTION__, pbo->Base.Size); + +   /* Now blit from the texture buffer to the new buffer:  +    */ + +   intel_batchbuffer_flush(intel->batch); + +   if (!intel->locked) { +      LOCK_HARDWARE(intel); +      intelEmitCopyBlit(intel, +			region->cpp, +			region->pitch, +			region->buffer, 0, +			region->pitch, +			pbo->buffer, 0, +			0, 0, 0, 0, region->pitch, region->height); +       +      intel_batchbuffer_flush(intel->batch); +      UNLOCK_HARDWARE(intel); +   } +   else { +      intelEmitCopyBlit(intel, +			region->cpp, +			region->pitch, +			region->buffer, 0, +			region->pitch, +			pbo->buffer, 0, +			0, 0, 0, 0, region->pitch, region->height); +       +      intel_batchbuffer_flush(intel->batch); +   } +} + +struct _DriBufferObject * +intel_region_buffer(intelScreenPrivate *intelScreen, +                    struct intel_region *region, GLuint flag) +{ +   if (region->pbo) { +      if (flag == INTEL_WRITE_PART) +         intel_region_cow(intelScreen, region); +      else if (flag == INTEL_WRITE_FULL) +         intel_region_release_pbo(intelScreen, region); +   } + +   return region->buffer; +} diff --git a/src/mesa/drivers/dri/i915tex/intel_regions.h b/src/mesa/drivers/dri/i915tex/intel_regions.h new file mode 100644 index 0000000000..1415bace69 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_regions.h @@ -0,0 +1,141 @@ +/************************************************************************** + *  + * Copyright 2006 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#ifndef INTEL_REGIONS_H +#define INTEL_REGIONS_H + +#include "mtypes.h" +#include "intel_screen.h" + +struct intel_context; +struct intel_buffer_object; + +/** + * A layer on top of the bufmgr buffers that adds a few useful things: + * + * - Refcounting for local buffer references. + * - Refcounting for buffer maps + * - Buffer dimensions - pitch and height. + * - Blitter commands for copying 2D regions between buffers. (really???) + */ +struct intel_region +{ +   struct _DriBufferObject *buffer;   /**< buffer manager's buffer ID */ +   GLuint refcount; /**< Reference count for region */ +   GLuint cpp;      /**< bytes per pixel */ +   GLuint pitch;    /**< in pixels */ +   GLuint height;   /**< in pixels */ +   GLubyte *map;    /**< only non-NULL when region is actually mapped */ +   GLuint map_refcount;  /**< Reference count for mapping */ + +   GLuint draw_offset; /**< Offset of drawing address within the region */ + +   struct intel_buffer_object *pbo;     /* zero-copy uploads */ +}; + + +/* Allocate a refcounted region.  Pointers to regions should only be + * copied by calling intel_reference_region(). + */ +struct intel_region *intel_region_alloc(intelScreenPrivate *intelScreen, +                                        GLuint cpp, +                                        GLuint pitch, GLuint height); + +void intel_region_reference(struct intel_region **dst, +                            struct intel_region *src); + +void intel_region_release(struct intel_region **ib); + +extern struct intel_region  +*intel_region_create_static(intelScreenPrivate *intelScreen, +			    GLuint mem_type, +			    GLuint offset, +			    void *virtual, +			    GLuint cpp, +			    GLuint pitch, GLuint height); +extern void  +intel_region_update_static(intelScreenPrivate *intelScreen, +			   struct intel_region *region, +			   GLuint mem_type, +			   GLuint offset, +			   void *virtual, +			   GLuint cpp, GLuint pitch, GLuint height); + + +void intel_region_idle(intelScreenPrivate *intelScreen, +		       struct intel_region *ib); + +/* Map/unmap regions.  This is refcounted also:  + */ +GLubyte *intel_region_map(intelScreenPrivate *intelScreen, +                          struct intel_region *ib); + +void intel_region_unmap(intelScreenPrivate *intelScreen, struct intel_region *ib); + + +/* Upload data to a rectangular sub-region + */ +void intel_region_data(intelScreenPrivate *intelScreen, +                       struct intel_region *dest, +                       GLuint dest_offset, +                       GLuint destx, GLuint desty, +                       void *src, GLuint src_stride, +                       GLuint srcx, GLuint srcy, GLuint width, GLuint height); + +/* Copy rectangular sub-regions + */ +void intel_region_copy(intelScreenPrivate *intelScreen, +                       struct intel_region *dest, +                       GLuint dest_offset, +                       GLuint destx, GLuint desty, +                       struct intel_region *src, +                       GLuint src_offset, +                       GLuint srcx, GLuint srcy, GLuint width, GLuint height); + +/* Fill a rectangular sub-region + */ +void intel_region_fill(intelScreenPrivate *intelScreen, +                       struct intel_region *dest, +                       GLuint dest_offset, +                       GLuint destx, GLuint desty, +                       GLuint width, GLuint height, GLuint color); + +/* Helpers for zerocopy uploads, particularly texture image uploads: + */ +void intel_region_attach_pbo(intelScreenPrivate *intelScreen, +                             struct intel_region *region, +                             struct intel_buffer_object *pbo); +void intel_region_release_pbo(intelScreenPrivate *intelScreen, +                              struct intel_region *region); +void intel_region_cow(intelScreenPrivate *intelScreen, +                      struct intel_region *region); + +struct _DriBufferObject *intel_region_buffer(intelScreenPrivate *intelScreen, +                                             struct intel_region *region, +                                             GLuint flag); + +#endif diff --git a/src/mesa/drivers/dri/i915tex/intel_render.c b/src/mesa/drivers/dri/i915tex/intel_render.c new file mode 100644 index 0000000000..f9fa55051e --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_render.c @@ -0,0 +1,242 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +/* + * Render unclipped vertex buffers by emitting vertices directly to + * dma buffers.  Use strip/fan hardware acceleration where possible. + * + */ +#include "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(struct intel_context *intel, GLenum prim) +{ +   if (0) +      fprintf(stderr, "%s %s\n", __FUNCTION__, _mesa_lookup_enum_by_nr(prim)); +   INTEL_FIREVERTICES(intel); +   intel->vtbl.reduced_primitive_state(intel, reduced_prim[prim]); +   intelStartInlinePrimitive(intel, hw_prim[prim], INTEL_BATCH_CLIPRECTS); +} + + +#define LOCAL_VARS struct intel_context *intel = intel_context(ctx) +#define INIT( prim ) 				\ +do {						\ +   intelDmaPrimitive( intel, prim );		\ +} while (0) + +#define FLUSH() INTEL_FIREVERTICES(intel) + +#define GET_SUBSEQUENT_VB_MAX_VERTS() \ +  ((intel->batch->size - 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(struct intel_context *intel, struct vertex_buffer *VB) +{ +   int vertsz = intel->vertex_size; +   int cost_render = 0; +   int cost_fallback = 0; +   int nr_prims = 0; +   int nr_rprims = 0; +   int nr_rverts = 0; +   int rprim = intel->reduced_primitive; +   int i = 0; + +   for (i = 0; i < VB->PrimitiveCount; i++) { +      GLuint prim = VB->Primitive[i].mode; +      GLuint length = VB->Primitive[i].count; + +      if (!length) +         continue; + +      nr_prims++; +      nr_rverts += length * scale_prim[prim & PRIM_MODE_MASK]; + +      if (reduced_prim[prim & PRIM_MODE_MASK] != rprim) { +         nr_rprims++; +         rprim = reduced_prim[prim & PRIM_MODE_MASK]; +      } +   } + +   /* One point for each generated primitive: +    */ +   cost_render = nr_prims; +   cost_fallback = nr_rprims; + +   /* One point for every 1024 dwords (4k) of dma: +    */ +   cost_render += (vertsz * i) / 1024; +   cost_fallback += (vertsz * nr_rverts) / 1024; + +   if (0) +      fprintf(stderr, "cost render: %d fallback: %d\n", +              cost_render, cost_fallback); + +   if (cost_render > cost_fallback) +      return GL_FALSE; + +   return GL_TRUE; +} + + +static GLboolean +intel_run_render(GLcontext * ctx, struct tnl_pipeline_stage *stage) +{ +   struct intel_context *intel = intel_context(ctx); +   TNLcontext *tnl = TNL_CONTEXT(ctx); +   struct vertex_buffer *VB = &tnl->vb; +   GLuint i; + +   /* 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); + +   INTEL_FIREVERTICES(intel); + +   return GL_FALSE;             /* finished the pipe */ +} + +const struct tnl_pipeline_stage _intel_render_stage = { +   "intel render", +   NULL, +   NULL, +   NULL, +   NULL, +   intel_run_render             /* run */ +}; diff --git a/src/mesa/drivers/dri/i915tex/intel_rotate.c b/src/mesa/drivers/dri/i915tex/intel_rotate.c new file mode 100644 index 0000000000..12d98c4ad2 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_rotate.c @@ -0,0 +1,237 @@ + +/** + * Routines for simple 2D->2D transformations for rotated, flipped screens. + * + * XXX This code is not intel-specific.  Move it into a common/utility + * someday. + */ + +#include "intel_rotate.h" + +#define MIN2(A, B)   ( ((A) < (B)) ? (A) : (B) ) + +#define ABS(A)  ( ((A) < 0) ? -(A) : (A) ) + + +void +matrix23Set(struct matrix23 *m, +            int m00, int m01, int m02, int m10, int m11, int m12) +{ +   m->m00 = m00; +   m->m01 = m01; +   m->m02 = m02; +   m->m10 = m10; +   m->m11 = m11; +   m->m12 = m12; +} + + +/* + * Transform (x,y) coordinate by the given matrix. + */ +void +matrix23TransformCoordf(const struct matrix23 *m, float *x, float *y) +{ +   const float x0 = *x; +   const float y0 = *y; + +   *x = m->m00 * x0 + m->m01 * y0 + m->m02; +   *y = m->m10 * x0 + m->m11 * y0 + m->m12; +} + + +void +matrix23TransformCoordi(const struct matrix23 *m, int *x, int *y) +{ +   const int x0 = *x; +   const int y0 = *y; + +   *x = m->m00 * x0 + m->m01 * y0 + m->m02; +   *y = m->m10 * x0 + m->m11 * y0 + m->m12; +} + + +/* + * Transform a width and height by the given matrix. + * XXX this could be optimized quite a bit. + */ +void +matrix23TransformDistance(const struct matrix23 *m, int *xDist, int *yDist) +{ +   int x0 = 0, y0 = 0; +   int x1 = *xDist, y1 = 0; +   int x2 = 0, y2 = *yDist; +   matrix23TransformCoordi(m, &x0, &y0); +   matrix23TransformCoordi(m, &x1, &y1); +   matrix23TransformCoordi(m, &x2, &y2); + +   *xDist = (x1 - x0) + (x2 - x0); +   *yDist = (y1 - y0) + (y2 - y0); + +   if (*xDist < 0) +      *xDist = -*xDist; +   if (*yDist < 0) +      *yDist = -*yDist; +} + + +/** + * Transform the rect defined by (x, y, w, h) by m. + */ +void +matrix23TransformRect(const struct matrix23 *m, int *x, int *y, int *w, +                      int *h) +{ +   int x0 = *x, y0 = *y; +   int x1 = *x + *w, y1 = *y; +   int x2 = *x + *w, y2 = *y + *h; +   int x3 = *x, y3 = *y + *h; +   matrix23TransformCoordi(m, &x0, &y0); +   matrix23TransformCoordi(m, &x1, &y1); +   matrix23TransformCoordi(m, &x2, &y2); +   matrix23TransformCoordi(m, &x3, &y3); +   *w = ABS(x1 - x0) + ABS(x2 - x1); +   /**w = ABS(*w);*/ +   *h = ABS(y1 - y0) + ABS(y2 - y1); +   /**h = ABS(*h);*/ +   *x = MIN2(x0, x1); +   *x = MIN2(*x, x2); +   *y = MIN2(y0, y1); +   *y = MIN2(*y, y2); +} + + +/* + * Make rotation matrix for width X height screen. + */ +void +matrix23Rotate(struct matrix23 *m, int width, int height, int angle) +{ +   switch (angle) { +   case 0: +      matrix23Set(m, 1, 0, 0, 0, 1, 0); +      break; +   case 90: +      matrix23Set(m, 0, 1, 0, -1, 0, width); +      break; +   case 180: +      matrix23Set(m, -1, 0, width, 0, -1, height); +      break; +   case 270: +      matrix23Set(m, 0, -1, height, 1, 0, 0); +      break; +   default: +      /*abort() */ ; +   } +} + + +/* + * Make flip/reflection matrix for width X height screen. + */ +void +matrix23Flip(struct matrix23 *m, int width, int height, int xflip, int yflip) +{ +   if (xflip) { +      m->m00 = -1; +      m->m01 = 0; +      m->m02 = width - 1; +   } +   else { +      m->m00 = 1; +      m->m01 = 0; +      m->m02 = 0; +   } +   if (yflip) { +      m->m10 = 0; +      m->m11 = -1; +      m->m12 = height - 1; +   } +   else { +      m->m10 = 0; +      m->m11 = 1; +      m->m12 = 0; +   } +} + + +/* + * result = a * b + */ +void +matrix23Multiply(struct matrix23 *result, +                 const struct matrix23 *a, const struct matrix23 *b) +{ +   result->m00 = a->m00 * b->m00 + a->m01 * b->m10; +   result->m01 = a->m00 * b->m01 + a->m01 * b->m11; +   result->m02 = a->m00 * b->m02 + a->m01 * b->m12 + a->m02; + +   result->m10 = a->m10 * b->m00 + a->m11 * b->m10; +   result->m11 = a->m10 * b->m01 + a->m11 * b->m11; +   result->m12 = a->m10 * b->m02 + a->m11 * b->m12 + a->m12; +} + + +#if 000 + +#include <stdio.h> + +int +main(int argc, char *argv[]) +{ +   int width = 500, height = 400; +   int rot; +   int fx = 0, fy = 0;          /* flip x and/or y ? */ +   int coords[4][2]; + +   /* four corner coords to test with */ +   coords[0][0] = 0; +   coords[0][1] = 0; +   coords[1][0] = width - 1; +   coords[1][1] = 0; +   coords[2][0] = width - 1; +   coords[2][1] = height - 1; +   coords[3][0] = 0; +   coords[3][1] = height - 1; + + +   for (rot = 0; rot < 360; rot += 90) { +      struct matrix23 rotate, flip, m; +      int i; + +      printf("Rot %d, xFlip %d, yFlip %d:\n", rot, fx, fy); + +      /* make transformation matrix 'm' */ +      matrix23Rotate(&rotate, width, height, rot); +      matrix23Flip(&flip, width, height, fx, fy); +      matrix23Multiply(&m, &rotate, &flip); + +      /* xform four coords */ +      for (i = 0; i < 4; i++) { +         int x = coords[i][0]; +         int y = coords[i][1]; +         matrix23TransformCoordi(&m, &x, &y); +         printf("  %d, %d  -> %d %d\n", coords[i][0], coords[i][1], x, y); +      } + +      /* xform width, height */ +      { +         int x = width; +         int y = height; +         matrix23TransformDistance(&m, &x, &y); +         printf("  %d x %d -> %d x %d\n", width, height, x, y); +      } + +      /* xform rect */ +      { +         int x = 50, y = 10, w = 200, h = 100; +         matrix23TransformRect(&m, &x, &y, &w, &h); +         printf("  %d,%d %d x %d -> %d, %d %d x %d\n", 50, 10, 200, 100, +                x, y, w, h); +      } + +   } + +   return 0; +} +#endif diff --git a/src/mesa/drivers/dri/i915tex/intel_rotate.h b/src/mesa/drivers/dri/i915tex/intel_rotate.h new file mode 100644 index 0000000000..9c8802ca47 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_rotate.h @@ -0,0 +1,39 @@ +#ifndef INTEL_ROTATE_H +#define INTEL_ROTATE_H 1 + +struct matrix23 +{ +   int m00, m01, m02; +   int m10, m11, m12; +}; + + + +extern void +matrix23Set(struct matrix23 *m, +            int m00, int m01, int m02, int m10, int m11, int m12); + +extern void matrix23TransformCoordi(const struct matrix23 *m, int *x, int *y); + +extern void +matrix23TransformCoordf(const struct matrix23 *m, float *x, float *y); + +extern void +matrix23TransformDistance(const struct matrix23 *m, int *xDist, int *yDist); + +extern void +matrix23TransformRect(const struct matrix23 *m, +                      int *x, int *y, int *w, int *h); + +extern void +matrix23Rotate(struct matrix23 *m, int width, int height, int angle); + +extern void +matrix23Flip(struct matrix23 *m, int width, int height, int xflip, int yflip); + +extern void +matrix23Multiply(struct matrix23 *result, +                 const struct matrix23 *a, const struct matrix23 *b); + + +#endif /* INTEL_ROTATE_H */ diff --git a/src/mesa/drivers/dri/i915tex/intel_screen.c b/src/mesa/drivers/dri/i915tex/intel_screen.c new file mode 100644 index 0000000000..c04831be1b --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_screen.c @@ -0,0 +1,862 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#include "glheader.h" +#include "context.h" +#include "framebuffer.h" +#include "matrix.h" +#include "renderbuffer.h" +#include "simple_list.h" +#include "utils.h" +#include "vblank.h" +#include "xmlpool.h" + + +#include "intel_screen.h" + +#include "intel_buffers.h" +#include "intel_tex.h" +#include "intel_span.h" +#include "intel_tris.h" +#include "intel_ioctl.h" +#include "intel_fbo.h" + +#include "i830_dri.h" +#include "dri_bufpool.h" +#include "intel_regions.h" +#include "intel_batchbuffer.h" + +PUBLIC const char __driConfigOptions[] = +   DRI_CONF_BEGIN DRI_CONF_SECTION_PERFORMANCE +   DRI_CONF_FTHROTTLE_MODE(DRI_CONF_FTHROTTLE_IRQS) +   DRI_CONF_VBLANK_MODE(DRI_CONF_VBLANK_DEF_INTERVAL_0) +   DRI_CONF_SECTION_END DRI_CONF_SECTION_QUALITY +   DRI_CONF_FORCE_S3TC_ENABLE(false) +   DRI_CONF_ALLOW_LARGE_TEXTURES(1) +   DRI_CONF_SECTION_END DRI_CONF_END; +     const GLuint __driNConfigOptions = 4; + +#ifdef USE_NEW_INTERFACE +     static PFNGLXCREATECONTEXTMODES create_context_modes = NULL; +#endif /*USE_NEW_INTERFACE */ + +     extern const struct dri_extension card_extensions[]; + +/** + * Map all the memory regions described by the screen. + * \return GL_TRUE if success, GL_FALSE if error. + */ +GLboolean +intelMapScreenRegions(__DRIscreenPrivate * sPriv) +{ +   intelScreenPrivate *intelScreen = (intelScreenPrivate *) sPriv->private; + +   if (intelScreen->front.handle) { +      if (drmMap(sPriv->fd, +                 intelScreen->front.handle, +                 intelScreen->front.size, +                 (drmAddress *) & intelScreen->front.map) != 0) { +         _mesa_problem(NULL, "drmMap(frontbuffer) failed!"); +         return GL_FALSE; +      } +   } +   else { +      _mesa_warning(NULL, "no front buffer handle in intelMapScreenRegions!"); +   } + +   _mesa_printf("Back 0x%08x ", intelScreen->back.handle); +   if (drmMap(sPriv->fd, +              intelScreen->back.handle, +              intelScreen->back.size, +              (drmAddress *) & intelScreen->back.map) != 0) { +      intelUnmapScreenRegions(intelScreen); +      return GL_FALSE; +   } + +   _mesa_printf("Depth 0x%08x ", intelScreen->depth.handle); +   if (drmMap(sPriv->fd, +              intelScreen->depth.handle, +              intelScreen->depth.size, +              (drmAddress *) & intelScreen->depth.map) != 0) { +      intelUnmapScreenRegions(intelScreen); +      return GL_FALSE; +   } + +#if 0 +   _mesa_printf("TEX 0x%08x ", intelScreen->tex.handle); +   if (drmMap(sPriv->fd, +              intelScreen->tex.handle, +              intelScreen->tex.size, +              (drmAddress *) & intelScreen->tex.map) != 0) { +      intelUnmapScreenRegions(intelScreen); +      return GL_FALSE; +   } +#endif +   if (0) +      printf("Mappings:  front: %p  back: %p  depth: %p  tex: %p\n", +             intelScreen->front.map, +             intelScreen->back.map, +             intelScreen->depth.map, intelScreen->tex.map); +   return GL_TRUE; +} + + +static struct intel_region * +intel_recreate_static(intelScreenPrivate *intelScreen, +		      struct intel_region *region, +		      GLuint mem_type, +		      GLuint offset, +		      void *virtual, +		      GLuint cpp, GLuint pitch, GLuint height) +{ +  if (region) { +    intel_region_update_static(intelScreen, region, mem_type, offset, +			       virtual, cpp, pitch, height); +  } else { +    region = intel_region_create_static(intelScreen, mem_type, offset, +					virtual, cpp, pitch, height); +  } +  return region; +} +     + +/* Create intel_region structs to describe the static front,back,depth + * buffers created by the xserver.  + * + * Although FBO's mean we now no longer use these as render targets in + * all circumstances, they won't go away until the back and depth + * buffers become private, and the front and rotated buffers will + * remain even then. + * + * Note that these don't allocate video memory, just describe + * allocations alread made by the X server. + */ +static void +intel_recreate_static_regions(intelScreenPrivate *intelScreen) +{ +   intelScreen->front_region = +      intel_recreate_static(intelScreen, +			    intelScreen->front_region, +			    DRM_BO_FLAG_MEM_TT, +			    intelScreen->front.offset, +			    intelScreen->front.map, +			    intelScreen->cpp, +			    intelScreen->front.pitch / intelScreen->cpp, +			    intelScreen->height); + +   intelScreen->rotated_region = +      intel_recreate_static(intelScreen, +			    intelScreen->rotated_region, +			    DRM_BO_FLAG_MEM_TT, +			    intelScreen->rotated.offset, +			    intelScreen->rotated.map, +			    intelScreen->cpp, +			    intelScreen->rotated.pitch / +			    intelScreen->cpp, intelScreen->height); + + +   intelScreen->back_region = +      intel_recreate_static(intelScreen, +			    intelScreen->back_region, +			    DRM_BO_FLAG_MEM_TT, +			    intelScreen->back.offset, +			    intelScreen->back.map, +			    intelScreen->cpp, +			    intelScreen->back.pitch / intelScreen->cpp, +			    intelScreen->height); + +   /* Still assuming front.cpp == depth.cpp +    */ +   intelScreen->depth_region = +      intel_recreate_static(intelScreen, +			    intelScreen->depth_region, +			    DRM_BO_FLAG_MEM_TT, +			    intelScreen->depth.offset, +			    intelScreen->depth.map, +			    intelScreen->cpp, +			    intelScreen->depth.pitch / intelScreen->cpp, +			    intelScreen->height); +} + +/** + * Use the information in the sarea to update the screen parameters + * related to screen rotation. Needs to be called locked. + */ +void +intelUpdateScreenRotation(__DRIscreenPrivate * sPriv, drmI830Sarea * sarea) +{ +   intelScreenPrivate *intelScreen = (intelScreenPrivate *) sPriv->private; + +   intelUnmapScreenRegions(intelScreen); +   intelUpdateScreenFromSAREA(intelScreen, sarea); +   if (!intelMapScreenRegions(sPriv)) { +      fprintf(stderr, "ERROR Remapping screen regions!!!\n"); +   } +   intel_recreate_static_regions(intelScreen); +} + + +void +intelUnmapScreenRegions(intelScreenPrivate * intelScreen) +{ +#define REALLY_UNMAP 1 +   if (intelScreen->front.map) { +#if REALLY_UNMAP +      if (drmUnmap(intelScreen->front.map, intelScreen->front.size) != 0) +         printf("drmUnmap front failed!\n"); +#endif +      intelScreen->front.map = NULL; +   } +   if (intelScreen->back.map) { +#if REALLY_UNMAP +      if (drmUnmap(intelScreen->back.map, intelScreen->back.size) != 0) +         printf("drmUnmap back failed!\n"); +#endif +      intelScreen->back.map = NULL; +   } +   if (intelScreen->depth.map) { +#if REALLY_UNMAP +      drmUnmap(intelScreen->depth.map, intelScreen->depth.size); +      intelScreen->depth.map = NULL; +#endif +   } +   if (intelScreen->tex.map) { +#if REALLY_UNMAP +      drmUnmap(intelScreen->tex.map, intelScreen->tex.size); +      intelScreen->tex.map = NULL; +#endif +   } +} + + +static void +intelPrintDRIInfo(intelScreenPrivate * intelScreen, +                  __DRIscreenPrivate * sPriv, I830DRIPtr gDRIPriv) +{ +   fprintf(stderr, "*** Front size:   0x%x  offset: 0x%x  pitch: %d\n", +           intelScreen->front.size, intelScreen->front.offset, +           intelScreen->front.pitch); +   fprintf(stderr, "*** Back size:    0x%x  offset: 0x%x  pitch: %d\n", +           intelScreen->back.size, intelScreen->back.offset, +           intelScreen->back.pitch); +   fprintf(stderr, "*** Depth size:   0x%x  offset: 0x%x  pitch: %d\n", +           intelScreen->depth.size, intelScreen->depth.offset, +           intelScreen->depth.pitch); +   fprintf(stderr, "*** Rotated size: 0x%x  offset: 0x%x  pitch: %d\n", +           intelScreen->rotated.size, intelScreen->rotated.offset, +           intelScreen->rotated.pitch); +   fprintf(stderr, "*** Texture size: 0x%x  offset: 0x%x\n", +           intelScreen->tex.size, intelScreen->tex.offset); +   fprintf(stderr, "*** Memory : 0x%x\n", gDRIPriv->mem); +} + + +static void +intelPrintSAREA(const drmI830Sarea * sarea) +{ +   fprintf(stderr, "SAREA: sarea width %d  height %d\n", sarea->width, +           sarea->height); +   fprintf(stderr, "SAREA: pitch: %d\n", sarea->pitch); +   fprintf(stderr, +           "SAREA: front offset: 0x%08x  size: 0x%x  handle: 0x%x\n", +           sarea->front_offset, sarea->front_size, +           (unsigned) sarea->front_handle); +   fprintf(stderr, +           "SAREA: back  offset: 0x%08x  size: 0x%x  handle: 0x%x\n", +           sarea->back_offset, sarea->back_size, +           (unsigned) sarea->back_handle); +   fprintf(stderr, "SAREA: depth offset: 0x%08x  size: 0x%x  handle: 0x%x\n", +           sarea->depth_offset, sarea->depth_size, +           (unsigned) sarea->depth_handle); +   fprintf(stderr, "SAREA: tex   offset: 0x%08x  size: 0x%x  handle: 0x%x\n", +           sarea->tex_offset, sarea->tex_size, (unsigned) sarea->tex_handle); +   fprintf(stderr, "SAREA: rotation: %d\n", sarea->rotation); +   fprintf(stderr, +           "SAREA: rotated offset: 0x%08x  size: 0x%x\n", +           sarea->rotated_offset, sarea->rotated_size); +   fprintf(stderr, "SAREA: rotated pitch: %d\n", sarea->rotated_pitch); +} + + +/** + * A number of the screen parameters are obtained/computed from + * information in the SAREA.  This function updates those parameters. + */ +void +intelUpdateScreenFromSAREA(intelScreenPrivate * intelScreen, +                           drmI830Sarea * sarea) +{ +   intelScreen->width = sarea->width; +   intelScreen->height = sarea->height; + +   intelScreen->front.offset = sarea->front_offset; +   intelScreen->front.pitch = sarea->pitch * intelScreen->cpp; +   intelScreen->front.handle = sarea->front_handle; +   intelScreen->front.size = sarea->front_size; + +   intelScreen->back.offset = sarea->back_offset; +   intelScreen->back.pitch = sarea->pitch * intelScreen->cpp; +   intelScreen->back.handle = sarea->back_handle; +   intelScreen->back.size = sarea->back_size; + +   intelScreen->depth.offset = sarea->depth_offset; +   intelScreen->depth.pitch = sarea->pitch * intelScreen->cpp; +   intelScreen->depth.handle = sarea->depth_handle; +   intelScreen->depth.size = sarea->depth_size; + +   intelScreen->tex.offset = sarea->tex_offset; +   intelScreen->logTextureGranularity = sarea->log_tex_granularity; +   intelScreen->tex.handle = sarea->tex_handle; +   intelScreen->tex.size = sarea->tex_size; + +   intelScreen->rotated.offset = sarea->rotated_offset; +   intelScreen->rotated.pitch = sarea->rotated_pitch * intelScreen->cpp; +   intelScreen->rotated.size = sarea->rotated_size; +   intelScreen->current_rotation = sarea->rotation; +   matrix23Rotate(&intelScreen->rotMatrix, +                  sarea->width, sarea->height, sarea->rotation); +   intelScreen->rotatedWidth = sarea->virtualX; +   intelScreen->rotatedHeight = sarea->virtualY; + +   if (0) +      intelPrintSAREA(sarea); +} + + +static GLboolean +intelInitDriver(__DRIscreenPrivate * sPriv) +{ +   intelScreenPrivate *intelScreen; +   I830DRIPtr gDRIPriv = (I830DRIPtr) sPriv->pDevPriv; +   drmI830Sarea *sarea; +   unsigned batchPoolSize = 1024*1024; + +   PFNGLXSCRENABLEEXTENSIONPROC glx_enable_extension = +      (PFNGLXSCRENABLEEXTENSIONPROC) (*dri_interface-> +                                      getProcAddress("glxEnableExtension")); +   void *const psc = sPriv->psc->screenConfigs; + +   if (sPriv->devPrivSize != sizeof(I830DRIRec)) { +      fprintf(stderr, +              "\nERROR!  sizeof(I830DRIRec) does not match passed size from device driver\n"); +      return GL_FALSE; +   } + +   /* Allocate the private area */ +   intelScreen = (intelScreenPrivate *) CALLOC(sizeof(intelScreenPrivate)); +   if (!intelScreen) { +      fprintf(stderr, "\nERROR!  Allocating private area failed\n"); +      return GL_FALSE; +   } +   /* parse information in __driConfigOptions */ +   driParseOptionInfo(&intelScreen->optionCache, +                      __driConfigOptions, __driNConfigOptions); + +   intelScreen->driScrnPriv = sPriv; +   sPriv->private = (void *) intelScreen; +   intelScreen->sarea_priv_offset = gDRIPriv->sarea_priv_offset; +   sarea = (drmI830Sarea *) +      (((GLubyte *) sPriv->pSAREA) + intelScreen->sarea_priv_offset); + +   intelScreen->maxBatchSize = BATCH_SZ; +   intelScreen->deviceID = gDRIPriv->deviceID; +   if (intelScreen->deviceID == PCI_CHIP_I865_G) +      intelScreen->maxBatchSize = 4096; +   batchPoolSize /= intelScreen->maxBatchSize; + +   intelScreen->mem = gDRIPriv->mem; +   intelScreen->cpp = gDRIPriv->cpp; + +   switch (gDRIPriv->bitsPerPixel) { +   case 16: +      intelScreen->fbFormat = DV_PF_565; +      break; +   case 32: +      intelScreen->fbFormat = DV_PF_8888; +      break; +   default: +      exit(1); +      break; +   } + +   intelUpdateScreenFromSAREA(intelScreen, sarea); + +   if (!intelMapScreenRegions(sPriv)) { +      fprintf(stderr, "\nERROR!  mapping regions\n"); +      _mesa_free(intelScreen); +      sPriv->private = NULL; +      return GL_FALSE; +   } + +#if 0 + +   /* +    * FIXME: Remove this code and its references. +    */ + +   intelScreen->tex.offset = gDRIPriv->textureOffset; +   intelScreen->logTextureGranularity = gDRIPriv->logTextureGranularity; +   intelScreen->tex.handle = gDRIPriv->textures; +   intelScreen->tex.size = gDRIPriv->textureSize; + +#else +   intelScreen->tex.offset = 0; +   intelScreen->logTextureGranularity = 0; +   intelScreen->tex.handle = 0; +   intelScreen->tex.size = 0; +#endif + +   intelScreen->sarea_priv_offset = gDRIPriv->sarea_priv_offset; + +   if (1) +      intelPrintDRIInfo(intelScreen, sPriv, gDRIPriv); + +   intelScreen->drmMinor = sPriv->drmMinor; + +   /* Determine if IRQs are active? */ +   { +      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; +      } +   } + +   /* Determine if batchbuffers are allowed */ +   { +      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; +      } +   } + +   if (glx_enable_extension != NULL) { +      (*glx_enable_extension) (psc, "GLX_SGI_swap_control"); +      (*glx_enable_extension) (psc, "GLX_SGI_video_sync"); +      (*glx_enable_extension) (psc, "GLX_MESA_swap_control"); +      (*glx_enable_extension) (psc, "GLX_MESA_swap_frame_usage"); +      (*glx_enable_extension) (psc, "GLX_SGI_make_current_read"); +   } + +   intelScreen->regionPool = driDRMPoolInit(sPriv->fd); + +   if (!intelScreen->regionPool) +      return GL_FALSE; + +   intelScreen->staticPool = driDRMStaticPoolInit(sPriv->fd); + +   if (!intelScreen->staticPool) +      return GL_FALSE; + +   intelScreen->texPool = intelScreen->regionPool; + +   intelScreen->batchPool = driBatchPoolInit(sPriv->fd, +                                             DRM_BO_FLAG_EXE | +                                             DRM_BO_FLAG_MEM_TT | +                                             DRM_BO_FLAG_MEM_LOCAL, +                                             intelScreen->maxBatchSize,  +					     batchPoolSize, 5); +   if (!intelScreen->batchPool) { +      fprintf(stderr, "Failed to initialize batch pool - possible incorrect agpgart installed\n"); +      return GL_FALSE; +   } + +   intel_recreate_static_regions(intelScreen); + +   return GL_TRUE; +} + + +static void +intelDestroyScreen(__DRIscreenPrivate * sPriv) +{ +   intelScreenPrivate *intelScreen = (intelScreenPrivate *) sPriv->private; + +   intelUnmapScreenRegions(intelScreen); + +   driPoolTakeDown(intelScreen->regionPool); +   driPoolTakeDown(intelScreen->staticPool); +   driPoolTakeDown(intelScreen->batchPool); +   FREE(intelScreen); +   sPriv->private = NULL; +} + + +/** + * This is called when we need to set up GL rendering to a new X window. + */ +static GLboolean +intelCreateBuffer(__DRIscreenPrivate * driScrnPriv, +                  __DRIdrawablePrivate * driDrawPriv, +                  const __GLcontextModes * mesaVis, GLboolean isPixmap) +{ +   intelScreenPrivate *screen = (intelScreenPrivate *) driScrnPriv->private; + +   if (isPixmap) { +      return GL_FALSE;          /* not implemented */ +   } +   else { +      GLboolean swStencil = (mesaVis->stencilBits > 0 && +                             mesaVis->depthBits != 24); +      GLenum rgbFormat = (mesaVis->redBits == 5 ? GL_RGB5 : GL_RGBA8); + +      struct gl_framebuffer *fb = _mesa_create_framebuffer(mesaVis); + +      /* setup the hardware-based renderbuffers */ +      { +         struct intel_renderbuffer *frontRb +            = intel_create_renderbuffer(rgbFormat, +                                        screen->width, screen->height, +                                        screen->front.offset, +                                        screen->front.pitch, +                                        screen->cpp, +                                        screen->front.map); +         intel_set_span_functions(&frontRb->Base); +         _mesa_add_renderbuffer(fb, BUFFER_FRONT_LEFT, &frontRb->Base); +      } + +      if (mesaVis->doubleBufferMode) { +         struct intel_renderbuffer *backRb +            = intel_create_renderbuffer(rgbFormat, +                                        screen->width, screen->height, +                                        screen->back.offset, +                                        screen->back.pitch, +                                        screen->cpp, +                                        screen->back.map); +         intel_set_span_functions(&backRb->Base); +         _mesa_add_renderbuffer(fb, BUFFER_BACK_LEFT, &backRb->Base); +      } + +      if (mesaVis->depthBits == 24 && mesaVis->stencilBits == 8) { +         /* combined depth/stencil buffer */ +         struct intel_renderbuffer *depthStencilRb +            = intel_create_renderbuffer(GL_DEPTH24_STENCIL8_EXT, +                                        screen->width, screen->height, +                                        screen->depth.offset, +                                        screen->depth.pitch, +                                        screen->cpp,    /* 4! */ +                                        screen->depth.map); +         intel_set_span_functions(&depthStencilRb->Base); +         /* note: bind RB to two attachment points */ +         _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthStencilRb->Base); +         _mesa_add_renderbuffer(fb, BUFFER_STENCIL, &depthStencilRb->Base); +      } +      else if (mesaVis->depthBits == 16) { +         /* just 16-bit depth buffer, no hw stencil */ +         struct intel_renderbuffer *depthRb +            = intel_create_renderbuffer(GL_DEPTH_COMPONENT16, +                                        screen->width, screen->height, +                                        screen->depth.offset, +                                        screen->depth.pitch, +                                        screen->cpp,    /* 2! */ +                                        screen->depth.map); +         intel_set_span_functions(&depthRb->Base); +         _mesa_add_renderbuffer(fb, BUFFER_DEPTH, &depthRb->Base); +      } + +      /* now add any/all software-based renderbuffers we may need */ +      _mesa_add_soft_renderbuffers(fb, GL_FALSE,        /* never sw color */ +                                   GL_FALSE,    /* never sw depth */ +                                   swStencil, mesaVis->accumRedBits > 0, GL_FALSE,      /* never sw alpha */ +                                   GL_FALSE /* never sw aux */ ); +      driDrawPriv->driverPrivate = (void *) fb; + +      return (driDrawPriv->driverPrivate != NULL); +   } +} + +static void +intelDestroyBuffer(__DRIdrawablePrivate * driDrawPriv) +{ +   _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate)); +} + + +/** + * Get information about previous buffer swaps. + */ +static int +intelGetSwapInfo(__DRIdrawablePrivate * dPriv, __DRIswapInfo * sInfo) +{ +   struct intel_context *intel; + +   if ((dPriv == NULL) || (dPriv->driContextPriv == NULL) +       || (dPriv->driContextPriv->driverPrivate == NULL) +       || (sInfo == NULL)) { +      return -1; +   } + +   intel = dPriv->driContextPriv->driverPrivate; +   sInfo->swap_count = intel->swap_count; +   sInfo->swap_ust = intel->swap_ust; +   sInfo->swap_missed_count = intel->swap_missed_count; + +   sInfo->swap_missed_usage = (sInfo->swap_missed_count != 0) +      ? driCalculateSwapUsage(dPriv, 0, intel->swap_missed_ust) +      : 0.0; + +   return 0; +} + + +/* 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) { +      /* Don't deal with i830 until texture work complete: +       */ +   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: +   case PCI_CHIP_I915_GM: +   case PCI_CHIP_I945_G: +   case PCI_CHIP_I945_GM: +      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 = intelGetSwapInfo, +   .GetMSC = driGetMSC32, +   .WaitForMSC = driWaitForMSC32, +   .WaitForSBC = NULL, +   .SwapBuffersMSC = NULL, +   .CopySubBuffer = intelCopySubBuffer +}; + + +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; +   GLenum fb_format; +   GLenum fb_type; + +   /* GLX_SWAP_COPY_OML is only supported because the Intel driver doesn't +    * support pageflipping at all. +    */ +   static const GLenum back_buffer_modes[] = { +      GLX_NONE, GLX_SWAP_UNDEFINED_OML, GLX_SWAP_COPY_OML +   }; + +   u_int8_t depth_bits_array[3]; +   u_int8_t stencil_bits_array[3]; + + +   depth_bits_array[0] = 0; +   depth_bits_array[1] = depth_bits; +   depth_bits_array[2] = 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. +    */ +   stencil_bits_array[0] = 0; +   stencil_bits_array[1] = 0; +   stencil_bits_array[2] = (stencil_bits == 0) ? 8 : stencil_bits; + +   depth_buffer_factor = ((depth_bits != 0) || (stencil_bits != 0)) ? 3 : 1; +   back_buffer_factor = (have_back_buffer) ? 3 : 1; + +   num_modes = depth_buffer_factor * back_buffer_factor * 4; + +   if (pixel_bits == 16) { +      fb_format = GL_RGB; +      fb_type = GL_UNSIGNED_SHORT_5_6_5; +   } +   else { +      fb_format = GL_BGRA; +      fb_type = GL_UNSIGNED_INT_8_8_8_8_REV; +   } + +   modes = +      (*dri_interface->createContextModes) (num_modes, +                                            sizeof(__GLcontextModes)); +   m = modes; +   if (!driFillInModes(&m, fb_format, fb_type, +                       depth_bits_array, stencil_bits_array, +                       depth_buffer_factor, back_buffer_modes, +                       back_buffer_factor, GLX_TRUE_COLOR)) { +      fprintf(stderr, "[%s:%u] Error creating FBConfig!\n", __func__, +              __LINE__); +      return NULL; +   } +   if (!driFillInModes(&m, fb_format, fb_type, +                       depth_bits_array, stencil_bits_array, +                       depth_buffer_factor, back_buffer_modes, +                       back_buffer_factor, GLX_DIRECT_COLOR)) { +      fprintf(stderr, "[%s:%u] Error creating FBConfig!\n", __func__, +              __LINE__); +      return NULL; +   } + +   /* 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; +} + + +/** + * 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. + */ +PUBLIC void * +__driCreateNewScreen_20050727(__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, +                              const __DRIinterfaceMethods * interface, +                              __GLcontextModes ** driver_modes) +{ +   __DRIscreenPrivate *psp; +   static const __DRIversion ddx_expected = { 1, 5, 0 }; +   static const __DRIversion dri_expected = { 4, 0, 0 }; +   static const __DRIversion drm_expected = { 1, 7, 0 }; + +   dri_interface = interface; + +   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) { +      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, 1); + +      /* Calling driInitExtensions here, with a NULL context pointer, does not actually +       * enable the extensions.  It just makes sure that all the dispatch offsets for all +       * the extensions that *might* be enables are known.  This is needed because the +       * dispatch offsets need to be known when _mesa_context_create is called, but we can't +       * enable the extensions until we have a context pointer. +       * +       * Hello chicken.  Hello egg.  How are you two today? +       */ +      driInitExtensions(NULL, card_extensions, GL_FALSE); +   } + +   return (void *) psp; +} + +struct intel_context *intelScreenContext(intelScreenPrivate *intelScreen) +{ +  /* +   * This should probably change to have the screen allocate a dummy +   * context at screen creation. For now just use the current context. +   */ + +  GET_CURRENT_CONTEXT(ctx); +  if (ctx == NULL) { +     _mesa_problem(NULL, "No current context in intelScreenContext\n"); +     return NULL; +  } +  return intel_context(ctx); +} + diff --git a/src/mesa/drivers/dri/i915tex/intel_screen.h b/src/mesa/drivers/dri/i915tex/intel_screen.h new file mode 100644 index 0000000000..17698773f3 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_screen.h @@ -0,0 +1,132 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#ifndef _INTEL_INIT_H_ +#define _INTEL_INIT_H_ + +#include <sys/time.h> +#include "dri_util.h" +#include "intel_rotate.h" +#include "i830_common.h" +#include "xmlconfig.h" +#include "dri_bufpool.h" + +/* XXX: change name or eliminate to avoid conflict with "struct + * intel_region"!!! + */ +typedef struct +{ +   drm_handle_t handle; +   drmSize size;                /* region size in bytes */ +   char *map;                   /* memory map */ +   int offset;                  /* from start of video mem, in bytes */ +   int pitch;                   /* row stride, in bytes */ +} intelRegion; + +typedef struct +{ +   intelRegion front; +   intelRegion back; +   intelRegion rotated; +   intelRegion depth; +   intelRegion tex; + +   struct intel_region *front_region; +   struct intel_region *back_region; +   struct intel_region *depth_region; +   struct intel_region *rotated_region; + +   int deviceID; +   int width; +   int height; +   int mem;                     /* unused */ + +   int cpp;                     /* for front and back buffers */ +/*    int bitsPerPixel;   */ +   int fbFormat;                /* XXX FBO: this is obsolete - remove after i830 updates */ + +   int logTextureGranularity; + +   __DRIscreenPrivate *driScrnPriv; +   unsigned int sarea_priv_offset; + +   int drmMinor; + +   int irq_active; +   int allow_batchbuffer; + +   struct matrix23 rotMatrix; + +   int current_rotation;        /* 0, 90, 180 or 270 */ +   int rotatedWidth, rotatedHeight; + +   /** +   * Configuration cache with default values for all contexts +   */ +   driOptionCache optionCache; +   struct _DriBufferPool *batchPool; +   struct _DriBufferPool *texPool; +   struct _DriBufferPool *regionPool; +   struct _DriBufferPool *staticPool; +   unsigned int maxBatchSize; +} intelScreenPrivate; + + + +extern GLboolean intelMapScreenRegions(__DRIscreenPrivate * sPriv); + +extern void intelUnmapScreenRegions(intelScreenPrivate * intelScreen); + +extern void +intelUpdateScreenFromSAREA(intelScreenPrivate * intelScreen, +                           drmI830Sarea * sarea); + +extern void intelDestroyContext(__DRIcontextPrivate * driContextPriv); + +extern GLboolean intelUnbindContext(__DRIcontextPrivate * driContextPriv); + +extern GLboolean +intelMakeCurrent(__DRIcontextPrivate * driContextPriv, +                 __DRIdrawablePrivate * driDrawPriv, +                 __DRIdrawablePrivate * driReadPriv); + +extern void intelSwapBuffers(__DRIdrawablePrivate * dPriv); + +extern void +intelCopySubBuffer(__DRIdrawablePrivate * dPriv, int x, int y, int w, int h); + +extern struct _DriBufferPool *driBatchPoolInit(int fd, unsigned flags, +                                               unsigned long bufSize, +                                               unsigned numBufs, +                                               unsigned checkDelayed); + +extern struct intel_context *intelScreenContext(intelScreenPrivate *intelScreen); + +extern void +intelUpdateScreenRotation(__DRIscreenPrivate * sPriv, drmI830Sarea * sarea); + +#endif diff --git a/src/mesa/drivers/dri/i915tex/intel_span.c b/src/mesa/drivers/dri/i915tex/intel_span.c new file mode 100644 index 0000000000..ab0874e4fd --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_span.c @@ -0,0 +1,409 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#include "glheader.h" +#include "macros.h" +#include "mtypes.h" +#include "colormac.h" + +#include "intel_fbo.h" +#include "intel_screen.h" +#include "intel_span.h" +#include "intel_regions.h" +#include "intel_ioctl.h" +#include "intel_tex.h" + +#include "swrast/swrast.h" + +/* +  break intelWriteRGBASpan_ARGB8888 +*/ + +#undef DBG +#define DBG 0 + +#define LOCAL_VARS							\ +   struct intel_context *intel = intel_context(ctx);			\ +   struct intel_renderbuffer *irb = intel_renderbuffer(rb);		\ +   const GLint yScale = irb->RenderToTexture ? 1 : -1;			\ +   const GLint yBias = irb->RenderToTexture ? 0 : irb->Base.Height - 1;	\ +   GLubyte *buf = (GLubyte *) irb->pfMap				\ +      + (intel->drawY * irb->pfPitch + intel->drawX) * irb->region->cpp;\ +   GLuint p;								\ +   assert(irb->pfMap);\ +   (void) p; + +/* XXX FBO: this is identical to the macro in spantmp2.h except we get + * the cliprect info from the context, not the driDrawable. + * Move this into spantmp2.h someday. + */ +#define HW_CLIPLOOP()							\ +   do {									\ +      int _nc = intel->numClipRects;					\ +      while ( _nc-- ) {							\ +	 int minx = intel->pClipRects[_nc].x1 - intel->drawX;		\ +	 int miny = intel->pClipRects[_nc].y1 - intel->drawY;		\ +	 int maxx = intel->pClipRects[_nc].x2 - intel->drawX;		\ +	 int maxy = intel->pClipRects[_nc].y2 - intel->drawY; + + + + +#define Y_FLIP(_y) ((_y) * yScale + yBias) + +#define HW_LOCK() + +#define HW_UNLOCK() + +/* 16 bit, RGB565 color spanline and pixel functions + */ +#define SPANTMP_PIXEL_FMT GL_RGB +#define SPANTMP_PIXEL_TYPE GL_UNSIGNED_SHORT_5_6_5 + +#define TAG(x)    intel##x##_RGB565 +#define TAG2(x,y) intel##x##_RGB565##y +#define GET_PTR(X,Y) (buf + ((Y) * irb->pfPitch + (X)) * 2) +#include "spantmp2.h" + +/* 32 bit, ARGB8888 color spanline and pixel functions + */ +#define SPANTMP_PIXEL_FMT GL_BGRA +#define SPANTMP_PIXEL_TYPE GL_UNSIGNED_INT_8_8_8_8_REV + +#define TAG(x)    intel##x##_ARGB8888 +#define TAG2(x,y) intel##x##_ARGB8888##y +#define GET_PTR(X,Y) (buf + ((Y) * irb->pfPitch + (X)) * 4) +#include "spantmp2.h" + + +#define LOCAL_DEPTH_VARS						\ +   struct intel_context *intel = intel_context(ctx);			\ +   struct intel_renderbuffer *irb = intel_renderbuffer(rb);		\ +   const GLuint pitch = irb->pfPitch/***XXX region->pitch*/; /* in pixels */ \ +   const GLint yScale = irb->RenderToTexture ? 1 : -1;			\ +   const GLint yBias = irb->RenderToTexture ? 0 : irb->Base.Height - 1;	\ +   char *buf = (char *) irb->pfMap/*XXX use region->map*/ +             \ +      (intel->drawY * pitch + intel->drawX) * irb->region->cpp; + + +#define LOCAL_STENCIL_VARS LOCAL_DEPTH_VARS + +/** + ** 16-bit depthbuffer functions. + **/ +#define WRITE_DEPTH( _x, _y, d ) \ +   ((GLushort *)buf)[(_x) + (_y) * pitch] = d; + +#define READ_DEPTH( d, _x, _y )	\ +   d = ((GLushort *)buf)[(_x) + (_y) * pitch]; + + +#define TAG(x) intel##x##_z16 +#include "depthtmp.h" + + +/** + ** 24/8-bit interleaved depth/stencil functions + ** Note: we're actually reading back combined depth+stencil values. + ** The wrappers in main/depthstencil.c are used to extract the depth + ** and stencil values. + **/ +/* Change ZZZS -> SZZZ */ +#define WRITE_DEPTH( _x, _y, d ) {				\ +   GLuint tmp = ((d) >> 8) | ((d) << 24);			\ +   ((GLuint *)buf)[(_x) + (_y) * pitch] = tmp;			\ +} + +/* Change SZZZ -> ZZZS */ +#define READ_DEPTH( d, _x, _y ) {				\ +   GLuint tmp = ((GLuint *)buf)[(_x) + (_y) * pitch];		\ +   d = (tmp << 8) | (tmp >> 24);				\ +} + +#define TAG(x) intel##x##_z24_s8 +#include "depthtmp.h" + + +/** + ** 8-bit stencil function (XXX FBO: This is obsolete) + **/ +#define WRITE_STENCIL( _x, _y, d ) {				\ +   GLuint tmp = ((GLuint *)buf)[(_x) + (_y) * pitch];		\ +   tmp &= 0xffffff;						\ +   tmp |= ((d) << 24);						\ +   ((GLuint *) buf)[(_x) + (_y) * pitch] = tmp;			\ +} + +#define READ_STENCIL( d, _x, _y )				\ +   d = ((GLuint *)buf)[(_x) + (_y) * pitch] >> 24; + +#define TAG(x) intel##x##_z24_s8 +#include "stenciltmp.h" + + + +/** + * Map or unmap all the renderbuffers which we may need during + * software rendering. + * XXX in the future, we could probably convey extra information to + * reduce the number of mappings needed.  I.e. if doing a glReadPixels + * from the depth buffer, we really only need one mapping. + * + * XXX Rewrite this function someday. + * We can probably just loop over all the renderbuffer attachments, + * map/unmap all of them, and not worry about the _ColorDrawBuffers + * _ColorReadBuffer, _DepthBuffer or _StencilBuffer fields. + */ +static void +intel_map_unmap_buffers(struct intel_context *intel, GLboolean map) +{ +   GLcontext *ctx = &intel->ctx; +   GLuint i, j; +   struct intel_renderbuffer *irb; + +   /* color draw buffers */ +   for (i = 0; i < ctx->Const.MaxDrawBuffers; i++) { +      for (j = 0; j < ctx->DrawBuffer->_NumColorDrawBuffers[i]; j++) { +         struct gl_renderbuffer *rb = +            ctx->DrawBuffer->_ColorDrawBuffers[i][j]; +         irb = intel_renderbuffer(rb); +         if (irb) { +            /* this is a user-created intel_renderbuffer */ +            if (irb->region) { +               if (map) +                  intel_region_map(intel->intelScreen, irb->region); +               else +                  intel_region_unmap(intel->intelScreen, irb->region); +            } +            irb->pfMap = irb->region->map; +            irb->pfPitch = irb->region->pitch; +         } +      } +   } + +   /* check for render to textures */ +   for (i = 0; i < BUFFER_COUNT; i++) { +      struct gl_renderbuffer_attachment *att = +         ctx->DrawBuffer->Attachment + i; +      struct gl_texture_object *tex = att->Texture; +      if (tex) { +         /* render to texture */ +         ASSERT(att->Renderbuffer); +         if (map) { +            struct gl_texture_image *texImg; +            texImg = tex->Image[att->CubeMapFace][att->TextureLevel]; +            intel_tex_map_images(intel, intel_texture_object(tex)); +         } +         else { +            intel_tex_unmap_images(intel, intel_texture_object(tex)); +         } +      } +   } + +   /* color read buffers */ +   irb = intel_renderbuffer(ctx->ReadBuffer->_ColorReadBuffer); +   if (irb && irb->region) { +      if (map) +         intel_region_map(intel->intelScreen, irb->region); +      else +         intel_region_unmap(intel->intelScreen, irb->region); +      irb->pfMap = irb->region->map; +      irb->pfPitch = irb->region->pitch; +   } + +   /* Account for front/back color page flipping. +    * The span routines use the pfMap and pfPitch fields which will +    * swap the front/back region map/pitch if we're page flipped. +    * Do this after mapping, above, so the map field is valid. +    */ +#if 0 +   if (map && ctx->DrawBuffer->Name == 0) { +      struct intel_renderbuffer *irbFront +         = intel_get_renderbuffer(ctx->DrawBuffer, BUFFER_FRONT_LEFT); +      struct intel_renderbuffer *irbBack +         = intel_get_renderbuffer(ctx->DrawBuffer, BUFFER_BACK_LEFT); +      if (irbBack) { +         /* double buffered */ +         if (intel->sarea->pf_current_page == 0) { +            irbFront->pfMap = irbFront->region->map; +            irbFront->pfPitch = irbFront->region->pitch; +            irbBack->pfMap = irbBack->region->map; +            irbBack->pfPitch = irbBack->region->pitch; +         } +         else { +            irbFront->pfMap = irbBack->region->map; +            irbFront->pfPitch = irbBack->region->pitch; +            irbBack->pfMap = irbFront->region->map; +            irbBack->pfPitch = irbFront->region->pitch; +         } +      } +   } +#endif + +   /* depth buffer (Note wrapper!) */ +   if (ctx->DrawBuffer->_DepthBuffer) { +      irb = intel_renderbuffer(ctx->DrawBuffer->_DepthBuffer->Wrapped); +      if (irb && irb->region && irb->Base.Name != 0) { +         if (map) { +            intel_region_map(intel->intelScreen, irb->region); +            irb->pfMap = irb->region->map; +            irb->pfPitch = irb->region->pitch; +         } +         else { +            intel_region_unmap(intel->intelScreen, irb->region); +            irb->pfMap = NULL; +            irb->pfPitch = 0; +         } +      } +   } + +   /* stencil buffer (Note wrapper!) */ +   if (ctx->DrawBuffer->_StencilBuffer) { +      irb = intel_renderbuffer(ctx->DrawBuffer->_StencilBuffer->Wrapped); +      if (irb && irb->region && irb->Base.Name != 0) { +         if (map) { +            intel_region_map(intel->intelScreen, irb->region); +            irb->pfMap = irb->region->map; +            irb->pfPitch = irb->region->pitch; +         } +         else { +            intel_region_unmap(intel->intelScreen, irb->region); +            irb->pfMap = NULL; +            irb->pfPitch = 0; +         } +      } +   } +} + + + +/** + * Prepare for softare rendering.  Map current read/draw framebuffers' + * renderbuffes and all currently bound texture objects. + * + * Old note: Moved locking out to get reasonable span performance. + */ +void +intelSpanRenderStart(GLcontext * ctx) +{ +   struct intel_context *intel = intel_context(ctx); +   GLuint i; + +   intelFinish(&intel->ctx); +   LOCK_HARDWARE(intel); + +#if 0 +   /* Just map the framebuffer and all textures.  Bufmgr code will +    * take care of waiting on the necessary fences: +    */ +   intel_region_map(intel->intelScreen, intel->front_region); +   intel_region_map(intel->intelScreen, intel->back_region); +   intel_region_map(intel->intelScreen, intel->intelScreen->depth_region); +#endif + +   for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) { +      if (ctx->Texture.Unit[i]._ReallyEnabled) { +         struct gl_texture_object *texObj = ctx->Texture.Unit[i]._Current; +         intel_tex_map_images(intel, intel_texture_object(texObj)); +      } +   } + +   intel_map_unmap_buffers(intel, GL_TRUE); +} + +/** + * Called when done softare rendering.  Unmap the buffers we mapped in + * the above function. + */ +void +intelSpanRenderFinish(GLcontext * ctx) +{ +   struct intel_context *intel = intel_context(ctx); +   GLuint i; + +   _swrast_flush(ctx); + +   /* Now unmap the framebuffer: +    */ +#if 0 +   intel_region_unmap(intel, intel->front_region); +   intel_region_unmap(intel, intel->back_region); +   intel_region_unmap(intel, intel->intelScreen->depth_region); +#endif + +   for (i = 0; i < ctx->Const.MaxTextureCoordUnits; i++) { +      if (ctx->Texture.Unit[i]._ReallyEnabled) { +         struct gl_texture_object *texObj = ctx->Texture.Unit[i]._Current; +         intel_tex_unmap_images(intel, intel_texture_object(texObj)); +      } +   } + +   intel_map_unmap_buffers(intel, GL_FALSE); + +   UNLOCK_HARDWARE(intel); +} + + +void +intelInitSpanFuncs(GLcontext * ctx) +{ +   struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference(ctx); +   swdd->SpanRenderStart = intelSpanRenderStart; +   swdd->SpanRenderFinish = intelSpanRenderFinish; +} + + +/** + * Plug in appropriate span read/write functions for the given renderbuffer. + * These are used for the software fallbacks. + */ +void +intel_set_span_functions(struct gl_renderbuffer *rb) +{ +   if (rb->_ActualFormat == GL_RGB5) { +      /* 565 RGB */ +      intelInitPointers_RGB565(rb); +   } +   else if (rb->_ActualFormat == GL_RGBA8) { +      /* 8888 RGBA */ +      intelInitPointers_ARGB8888(rb); +   } +   else if (rb->_ActualFormat == GL_DEPTH_COMPONENT16) { +      intelInitDepthPointers_z16(rb); +   } +   else if (rb->_ActualFormat == GL_DEPTH_COMPONENT24 ||        /* XXX FBO remove */ +            rb->_ActualFormat == GL_DEPTH24_STENCIL8_EXT) { +      intelInitDepthPointers_z24_s8(rb); +   } +   else if (rb->_ActualFormat == GL_STENCIL_INDEX8_EXT) {       /* XXX FBO remove */ +      intelInitStencilPointers_z24_s8(rb); +   } +   else { +      _mesa_problem(NULL, +                    "Unexpected _ActualFormat in intelSetSpanFunctions"); +   } +} diff --git a/src/mesa/drivers/dri/i915tex/intel_span.h b/src/mesa/drivers/dri/i915tex/intel_span.h new file mode 100644 index 0000000000..5201f6d6c6 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_span.h @@ -0,0 +1,38 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#ifndef _INTEL_SPAN_H +#define _INTEL_SPAN_H + +extern void intelInitSpanFuncs(GLcontext * ctx); + +extern void intelSpanRenderFinish(GLcontext * ctx); +extern void intelSpanRenderStart(GLcontext * ctx); + +extern void intel_set_span_functions(struct gl_renderbuffer *rb); + +#endif diff --git a/src/mesa/drivers/dri/i915tex/intel_state.c b/src/mesa/drivers/dri/i915tex/intel_state.c new file mode 100644 index 0000000000..f85d8ef835 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_state.c @@ -0,0 +1,363 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + + +#include "glheader.h" +#include "context.h" +#include "macros.h" +#include "enums.h" +#include "colormac.h" +#include "dd.h" + +#include "intel_screen.h" +#include "intel_context.h" +#include "intel_fbo.h" +#include "intel_regions.h" +#include "swrast/swrast.h" + +int +intel_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: +      return COMPAREFUNC_ALWAYS; +   } + +   fprintf(stderr, "Unknown value in %s: %x\n", __FUNCTION__, func); +   return COMPAREFUNC_ALWAYS; +} + +int +intel_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 STENCILOP_ZERO; +   } +} + +int +intel_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; +   } + +   fprintf(stderr, "Unknown value in %s: %x\n", __FUNCTION__, factor); +   return BLENDFACT_ZERO; +} + +int +intel_translate_logic_op(GLenum opcode) +{ +   switch (opcode) { +   case GL_CLEAR: +      return LOGICOP_CLEAR; +   case GL_AND: +      return LOGICOP_AND; +   case GL_AND_REVERSE: +      return LOGICOP_AND_RVRSE; +   case GL_COPY: +      return LOGICOP_COPY; +   case GL_COPY_INVERTED: +      return LOGICOP_COPY_INV; +   case GL_AND_INVERTED: +      return LOGICOP_AND_INV; +   case GL_NOOP: +      return LOGICOP_NOOP; +   case GL_XOR: +      return LOGICOP_XOR; +   case GL_OR: +      return LOGICOP_OR; +   case GL_OR_INVERTED: +      return LOGICOP_OR_INV; +   case GL_NOR: +      return LOGICOP_NOR; +   case GL_EQUIV: +      return LOGICOP_EQUIV; +   case GL_INVERT: +      return LOGICOP_INV; +   case GL_OR_REVERSE: +      return LOGICOP_OR_RVRSE; +   case GL_NAND: +      return LOGICOP_NAND; +   case GL_SET: +      return LOGICOP_SET; +   default: +      return LOGICOP_SET; +   } +} + + +static void +intelClearColor(GLcontext * ctx, const GLfloat color[4]) +{ +   struct intel_context *intel = intel_context(ctx); +   GLubyte clear[4]; + +   CLAMPED_FLOAT_TO_UBYTE(clear[0], color[0]); +   CLAMPED_FLOAT_TO_UBYTE(clear[1], color[1]); +   CLAMPED_FLOAT_TO_UBYTE(clear[2], color[2]); +   CLAMPED_FLOAT_TO_UBYTE(clear[3], color[3]); + +   /* compute both 32 and 16-bit clear values */ +   intel->ClearColor8888 = INTEL_PACKCOLOR8888(clear[0], clear[1], +                                               clear[2], clear[3]); +   intel->ClearColor565 = INTEL_PACKCOLOR565(clear[0], clear[1], clear[2]); +} + + +/** + * Update the viewport transformation matrix.  Depends on: + *  - viewport pos/size + *  - depthrange + *  - window pos/size or FBO size + */ +static void +intelCalcViewport(GLcontext * ctx) +{ +   struct intel_context *intel = intel_context(ctx); +   const GLfloat *v = ctx->Viewport._WindowMap.m; +   const GLfloat depthScale = 1.0F / ctx->DrawBuffer->_DepthMaxF; +   GLfloat *m = intel->ViewportMatrix.m; +   GLfloat yScale, yBias; + +   if (ctx->DrawBuffer->Name) { +      /* User created FBO */ +      struct intel_renderbuffer *irb +         = intel_renderbuffer(ctx->DrawBuffer->_ColorDrawBuffers[0][0]); +      if (irb && !irb->RenderToTexture) { +         /* y=0=top */ +         yScale = -1.0; +         yBias = irb->Base.Height; +      } +      else { +         /* y=0=bottom */ +         yScale = 1.0; +         yBias = 0.0; +      } +   } +   else { +      /* window buffer, y=0=top */ +      yScale = -1.0; +      yBias = (intel->driDrawable) ? intel->driDrawable->h : 0.0F; +   } + +   m[MAT_SX] = v[MAT_SX]; +   m[MAT_TX] = v[MAT_TX] + SUBPIXEL_X; + +   m[MAT_SY] = v[MAT_SY] * yScale; +   m[MAT_TY] = v[MAT_TY] * yScale + yBias + SUBPIXEL_Y; + +   m[MAT_SZ] = v[MAT_SZ] * depthScale; +   m[MAT_TZ] = v[MAT_TZ] * depthScale; +} + +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) +{ +   struct intel_context *intel = intel_context(ctx); +   FALLBACK(intel, INTEL_FALLBACK_RENDERMODE, (mode != GL_RENDER)); +} + + +void +intelInitStateFuncs(struct dd_function_table *functions) +{ +   functions->RenderMode = intelRenderMode; +   functions->Viewport = intelViewport; +   functions->DepthRange = intelDepthRange; +   functions->ClearColor = intelClearColor; +} + + + + +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.StencilFuncSeparate(ctx, GL_FRONT, +                                   ctx->Stencil.Function[0], +                                   ctx->Stencil.Ref[0], +                                   ctx->Stencil.ValueMask[0]); +   ctx->Driver.StencilFuncSeparate(ctx, GL_BACK, +                                   ctx->Stencil.Function[1], +                                   ctx->Stencil.Ref[1], +                                   ctx->Stencil.ValueMask[1]); +   ctx->Driver.StencilMaskSeparate(ctx, GL_FRONT, ctx->Stencil.WriteMask[0]); +   ctx->Driver.StencilMaskSeparate(ctx, GL_BACK, ctx->Stencil.WriteMask[1]); +   ctx->Driver.StencilOpSeparate(ctx, GL_FRONT, +                                 ctx->Stencil.FailFunc[0], +                                 ctx->Stencil.ZFailFunc[0], +                                 ctx->Stencil.ZPassFunc[0]); +   ctx->Driver.StencilOpSeparate(ctx, GL_BACK, +                                 ctx->Stencil.FailFunc[1], +                                 ctx->Stencil.ZFailFunc[1], +                                 ctx->Stencil.ZPassFunc[1]); + + +   /* XXX this isn't really needed */ +   ctx->Driver.DrawBuffer(ctx, ctx->Color.DrawBuffer[0]); +} diff --git a/src/mesa/drivers/dri/i915tex/intel_structs.h b/src/mesa/drivers/dri/i915tex/intel_structs.h new file mode 100644 index 0000000000..522e3bd92c --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_structs.h @@ -0,0 +1,132 @@ +#ifndef INTEL_STRUCTS_H +#define INTEL_STRUCTS_H + +struct br0 { +   GLuint length:8; +   GLuint pad0:3; +   GLuint dst_tiled:1; +   GLuint pad1:8; +   GLuint write_rgb:1; +   GLuint write_alpha:1; +   GLuint opcode:7; +   GLuint client:3; +}; + +    +struct br13 { +   GLint dest_pitch:16; +   GLuint rop:8; +   GLuint color_depth:2; +   GLuint pad1:3; +   GLuint mono_source_transparency:1; +   GLuint clipping_enable:1; +   GLuint pad0:1; +}; + + + +/* This is an attempt to move some of the 2D interaction in this + * driver to using structs for packets rather than a bunch of #defines + * and dwords. + */ +struct xy_color_blit { +   struct br0 br0; +   struct br13 br13; + +   struct { +      GLuint dest_x1:16; +      GLuint dest_y1:16; +   } dw2; + +   struct { +      GLuint dest_x2:16; +      GLuint dest_y2:16; +   } dw3; +    +   GLuint dest_base_addr; +   GLuint color; +}; + +struct xy_src_copy_blit { +   struct br0 br0; +   struct br13 br13; + +   struct { +      GLuint dest_x1:16; +      GLuint dest_y1:16; +   } dw2; + +   struct { +      GLuint dest_x2:16; +      GLuint dest_y2:16; +   } dw3; +    +   GLuint dest_base_addr; + +   struct { +      GLuint src_x1:16; +      GLuint src_y1:16; +   } dw5; + +   struct { +      GLint src_pitch:16; +      GLuint pad:16; +   } dw6; +    +   GLuint src_base_addr; +}; + +struct xy_setup_blit { +   struct br0 br0; +   struct br13 br13; + +   struct { +      GLuint clip_x1:16; +      GLuint clip_y1:16; +   } dw2; + +   struct { +      GLuint clip_x2:16; +      GLuint clip_y2:16; +   } dw3; +       +   GLuint dest_base_addr; +   GLuint background_color; +   GLuint foreground_color; +   GLuint pattern_base_addr; +}; + + +struct xy_text_immediate_blit { +   struct { +      GLuint length:8; +      GLuint pad2:3; +      GLuint dst_tiled:1; +      GLuint pad1:4; +      GLuint byte_packed:1; +      GLuint pad0:5; +      GLuint opcode:7; +      GLuint client:3; +   } dw0; + +   struct { +      GLuint dest_x1:16; +      GLuint dest_y1:16; +   } dw1; + +   struct { +      GLuint dest_x2:16; +      GLuint dest_y2:16; +   } dw2;    + +   /* Src bitmap data follows as inline dwords. +    */ +}; + + +#define CLIENT_2D 0x2 +#define OPCODE_XY_SETUP_BLT 0x1 +#define OPCODE_XY_COLOR_BLT 0x50 +#define OPCODE_XY_TEXT_IMMEDIATE_BLT 0x31 + +#endif diff --git a/src/mesa/drivers/dri/i915tex/intel_tex.c b/src/mesa/drivers/dri/i915tex/intel_tex.c new file mode 100644 index 0000000000..51875ab292 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_tex.c @@ -0,0 +1,182 @@ +#include "texobj.h" +#include "intel_context.h" +#include "intel_mipmap_tree.h" +#include "intel_tex.h" + +#define FILE_DEBUG_FLAG DEBUG_TEXTURE + +static GLboolean +intelIsTextureResident(GLcontext * ctx, struct gl_texture_object *texObj) +{ +#if 0 +   struct intel_context *intel = intel_context(ctx); +   struct intel_texture_object *intelObj = intel_texture_object(texObj); + +   return +      intelObj->mt && +      intelObj->mt->region && +      intel_is_region_resident(intel, intelObj->mt->region); +#endif +   return 1; +} + + + +static struct gl_texture_image * +intelNewTextureImage(GLcontext * ctx) +{ +   DBG("%s\n", __FUNCTION__); +   (void) ctx; +   return (struct gl_texture_image *) CALLOC_STRUCT(intel_texture_image); +} + + +static struct gl_texture_object * +intelNewTextureObject(GLcontext * ctx, GLuint name, GLenum target) +{ +   struct intel_texture_object *obj = CALLOC_STRUCT(intel_texture_object); + +   DBG("%s\n", __FUNCTION__); +   _mesa_initialize_texture_object(&obj->base, name, target); + +   return &obj->base; +} + +static void  +intelDeleteTextureObject(GLcontext *ctx, +			 struct gl_texture_object *texObj) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_texture_object *intelObj = intel_texture_object(texObj); + +   if (intelObj->mt) +      intel_miptree_release(intel, &intelObj->mt); + +   _mesa_delete_texture_object(ctx, texObj); +} + + +static void +intelFreeTextureImageData(GLcontext * ctx, struct gl_texture_image *texImage) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_texture_image *intelImage = intel_texture_image(texImage); + +   DBG("%s\n", __FUNCTION__); + +   if (intelImage->mt) { +      intel_miptree_release(intel, &intelImage->mt); +   } + +   if (texImage->Data) { +      free(texImage->Data); +      texImage->Data = NULL; +   } +} + + +#ifndef __x86_64__ +static unsigned +fastrdtsc(void) +{ +   unsigned eax; +   __asm__ volatile ("\t" +                     "pushl  %%ebx\n\t" +                     "cpuid\n\t" ".byte 0x0f, 0x31\n\t" +                     "popl %%ebx\n":"=a" (eax) +                     :"0"(0) +                     :"ecx", "edx", "cc"); + +   return eax; +} +#else +static unsigned +fastrdtsc(void) +{ +   unsigned eax; +   __asm__ volatile ("\t" "cpuid\n\t" ".byte 0x0f, 0x31\n\t":"=a" (eax) +                     :"0"(0) +                     :"ecx", "edx", "ebx", "cc"); + +   return eax; +} +#endif + +static unsigned +time_diff(unsigned t, unsigned t2) +{ +   return ((t < t2) ? t2 - t : 0xFFFFFFFFU - (t - t2 - 1)); +} + + +/* The system memcpy (at least on ubuntu 5.10) has problems copying + * to agp (writecombined) memory from a source which isn't 64-byte + * aligned - there is a 4x performance falloff. + * + * The x86 __memcpy is immune to this but is slightly slower + * (10%-ish) than the system memcpy. + * + * The sse_memcpy seems to have a slight cliff at 64/32 bytes, but + * isn't much faster than x86_memcpy for agp copies. + *  + * TODO: switch dynamically. + */ +static void * +do_memcpy(void *dest, const void *src, size_t n) +{ +   if ((((unsigned) src) & 63) || (((unsigned) dest) & 63)) { +      return __memcpy(dest, src, n); +   } +   else +      return memcpy(dest, src, n); +} + + +static void * +timed_memcpy(void *dest, const void *src, size_t n) +{ +   void *ret; +   unsigned t1, t2; +   double rate; + +   if ((((unsigned) src) & 63) || (((unsigned) dest) & 63)) +      _mesa_printf("Warning - non-aligned texture copy!\n"); + +   t1 = fastrdtsc(); +   ret = do_memcpy(dest, src, n); +   t2 = fastrdtsc(); + +   rate = time_diff(t1, t2); +   rate /= (double) n; +   _mesa_printf("timed_memcpy: %u %u --> %f clocks/byte\n", t1, t2, rate); +   return ret; +} + + +void +intelInitTextureFuncs(struct dd_function_table *functions) +{ +   functions->ChooseTextureFormat = intelChooseTextureFormat; +   functions->TexImage1D = intelTexImage1D; +   functions->TexImage2D = intelTexImage2D; +   functions->TexImage3D = intelTexImage3D; +   functions->TexSubImage1D = intelTexSubImage1D; +   functions->TexSubImage2D = intelTexSubImage2D; +   functions->TexSubImage3D = intelTexSubImage3D; +   functions->CopyTexImage1D = intelCopyTexImage1D; +   functions->CopyTexImage2D = intelCopyTexImage2D; +   functions->CopyTexSubImage1D = intelCopyTexSubImage1D; +   functions->CopyTexSubImage2D = intelCopyTexSubImage2D; +   functions->GetTexImage = intelGetTexImage; +   functions->NewTextureObject = intelNewTextureObject; +   functions->NewTextureImage = intelNewTextureImage; +   functions->DeleteTexture = intelDeleteTextureObject; +   functions->FreeTexImageData = intelFreeTextureImageData; +   functions->UpdateTexturePalette = 0; +   functions->IsTextureResident = intelIsTextureResident; + +   if (INTEL_DEBUG & DEBUG_BUFMGR) +      functions->TextureMemCpy = timed_memcpy; +   else +      functions->TextureMemCpy = do_memcpy; +} diff --git a/src/mesa/drivers/dri/i915tex/intel_tex.h b/src/mesa/drivers/dri/i915tex/intel_tex.h new file mode 100644 index 0000000000..2f3d4ec2d1 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_tex.h @@ -0,0 +1,134 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#ifndef INTELTEX_INC +#define INTELTEX_INC + +#include "mtypes.h" +#include "intel_context.h" +#include "texmem.h" + + +void intelInitTextureFuncs(struct dd_function_table *functions); + +const struct gl_texture_format *intelChooseTextureFormat(GLcontext * ctx, +                                                         GLint internalFormat, +                                                         GLenum format, +                                                         GLenum type); + + +void intelTexImage3D(GLcontext * ctx, +                     GLenum target, GLint level, +                     GLint internalFormat, +                     GLint width, GLint height, GLint depth, +                     GLint border, +                     GLenum format, GLenum type, const void *pixels, +                     const struct gl_pixelstore_attrib *packing, +                     struct gl_texture_object *texObj, +                     struct gl_texture_image *texImage); + +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); + +void intelTexImage2D(GLcontext * ctx, +                     GLenum target, GLint level, +                     GLint internalFormat, +                     GLint width, GLint height, GLint border, +                     GLenum format, GLenum type, const void *pixels, +                     const struct gl_pixelstore_attrib *packing, +                     struct gl_texture_object *texObj, +                     struct gl_texture_image *texImage); + +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); + +void intelTexImage1D(GLcontext * ctx, +                     GLenum target, GLint level, +                     GLint internalFormat, +                     GLint width, GLint border, +                     GLenum format, GLenum type, const void *pixels, +                     const struct gl_pixelstore_attrib *packing, +                     struct gl_texture_object *texObj, +                     struct gl_texture_image *texImage); + +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); + +void intelCopyTexImage1D(GLcontext * ctx, GLenum target, GLint level, +                         GLenum internalFormat, +                         GLint x, GLint y, GLsizei width, GLint border); + +void intelCopyTexImage2D(GLcontext * ctx, GLenum target, GLint level, +                         GLenum internalFormat, +                         GLint x, GLint y, GLsizei width, GLsizei height, +                         GLint border); + +void intelCopyTexSubImage1D(GLcontext * ctx, GLenum target, GLint level, +                            GLint xoffset, GLint x, GLint y, GLsizei width); + +void intelCopyTexSubImage2D(GLcontext * ctx, GLenum target, GLint level, +                            GLint xoffset, GLint yoffset, +                            GLint x, GLint y, GLsizei width, GLsizei height); + +void intelGetTexImage(GLcontext * ctx, GLenum target, GLint level, +                      GLenum format, GLenum type, GLvoid * pixels, +                      struct gl_texture_object *texObj, +                      struct gl_texture_image *texImage); + +GLuint intel_finalize_mipmap_tree(struct intel_context *intel, GLuint unit); + +void intel_tex_map_images(struct intel_context *intel, +                          struct intel_texture_object *intelObj); + +void intel_tex_unmap_images(struct intel_context *intel, +                            struct intel_texture_object *intelObj); + +#endif diff --git a/src/mesa/drivers/dri/i915tex/intel_tex_copy.c b/src/mesa/drivers/dri/i915tex/intel_tex_copy.c new file mode 100644 index 0000000000..88b62e781c --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_tex_copy.c @@ -0,0 +1,301 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#include "mtypes.h" +#include "enums.h" +#include "image.h" +#include "teximage.h" +#include "swrast/swrast.h" + +#include "intel_screen.h" +#include "intel_context.h" +#include "intel_batchbuffer.h" +#include "intel_buffers.h" +#include "intel_mipmap_tree.h" +#include "intel_regions.h" +#include "intel_fbo.h" +#include "intel_tex.h" +#include "intel_blit.h" +#include "intel_pixel.h" + +#define FILE_DEBUG_FLAG DEBUG_TEXTURE + +/** + * Get the intel_region which is the source for any glCopyTex[Sub]Image call. + * + * Do the best we can using the blitter.  A future project is to use + * the texture engine and fragment programs for these copies. + */ +static const struct intel_region * +get_teximage_source(struct intel_context *intel, GLenum internalFormat) +{ +   struct intel_renderbuffer *irb; + +   DBG("%s %s\n", __FUNCTION__, +       _mesa_lookup_enum_by_nr(internalFormat)); + +   switch (internalFormat) { +   case GL_DEPTH_COMPONENT: +   case GL_DEPTH_COMPONENT16_ARB: +      irb = intel_get_renderbuffer(intel->ctx.ReadBuffer, BUFFER_DEPTH); +      if (irb && irb->region && irb->region->cpp == 2) +         return irb->region; +      return NULL; +   case GL_DEPTH24_STENCIL8_EXT: +   case GL_DEPTH_STENCIL_EXT: +      irb = intel_get_renderbuffer(intel->ctx.ReadBuffer, BUFFER_DEPTH); +      if (irb && irb->region && irb->region->cpp == 4) +         return irb->region; +      return NULL; +   case GL_RGBA: +   case GL_RGBA8: +      return intel_readbuf_region(intel); +   case GL_RGB: +      if (intel->intelScreen->cpp == 2) +         return intel_readbuf_region(intel); +      return NULL; +   default: +      return NULL; +   } +} + + +static GLboolean +do_copy_texsubimage(struct intel_context *intel, +                    struct intel_texture_image *intelImage, +                    GLenum internalFormat, +                    GLint dstx, GLint dsty, +                    GLint x, GLint y, GLsizei width, GLsizei height) +{ +   GLcontext *ctx = &intel->ctx; +   const struct intel_region *src = +      get_teximage_source(intel, internalFormat); + +   if (!intelImage->mt || !src) { +      DBG("%s fail %p %p\n", __FUNCTION__, intelImage->mt, src); +      return GL_FALSE; +   } + +   intelFlush(ctx); +   LOCK_HARDWARE(intel); +   { +      GLuint image_offset = intel_miptree_image_offset(intelImage->mt, +                                                       intelImage->face, +                                                       intelImage->level); +      const GLint orig_x = x; +      const GLint orig_y = y; +      const struct gl_framebuffer *fb = ctx->DrawBuffer; + +      if (_mesa_clip_to_region(fb->_Xmin, fb->_Ymin, fb->_Xmax, fb->_Ymax, +                               &x, &y, &width, &height)) { +         /* Update dst for clipped src.  Need to also clip the source rect. +          */ +         dstx += x - orig_x; +         dsty += y - orig_y; + +         if (ctx->ReadBuffer->Name == 0) { +            /* reading from a window, adjust x, y */ +            __DRIdrawablePrivate *dPriv = intel->driDrawable; +            GLuint window_y; +            /* window_y = position of window on screen if y=0=bottom */ +            window_y = intel->intelScreen->height - (dPriv->y + dPriv->h); +            y = window_y + y; +            x += dPriv->x; +         } +         else { +            /* reading from a FBO */ +            /* invert Y */ +            y = ctx->ReadBuffer->Height - y - 1; +         } + + +         /* A bit of fiddling to get the blitter to work with -ve +          * pitches.  But we get a nice inverted blit this way, so it's +          * worth it: +          */ +         intelEmitCopyBlit(intel, +                           intelImage->mt->cpp, +                           -src->pitch, +                           src->buffer, +                           src->height * src->pitch * src->cpp, +                           intelImage->mt->pitch, +                           intelImage->mt->region->buffer, +                           image_offset, +                           x, y + height, dstx, dsty, width, height); + +         intel_batchbuffer_flush(intel->batch); +      } +   } + + +   UNLOCK_HARDWARE(intel); + +#if 0 +   /* GL_SGIS_generate_mipmap -- this can be accelerated now. +    * XXX Add a ctx->Driver.GenerateMipmaps() function? +    */ +   if (level == texObj->BaseLevel && texObj->GenerateMipmap) { +      intel_generate_mipmap(ctx, target, +                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit], +                            texObj); +   } +#endif + +   return GL_TRUE; +} + + + + + +void +intelCopyTexImage1D(GLcontext * ctx, GLenum target, GLint level, +                    GLenum internalFormat, +                    GLint x, GLint y, GLsizei width, GLint border) +{ +   struct gl_texture_unit *texUnit = +      &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; +   struct gl_texture_object *texObj = +      _mesa_select_tex_object(ctx, texUnit, target); +   struct gl_texture_image *texImage = +      _mesa_select_tex_image(ctx, texObj, target, level); + +   if (border) +      goto fail; + +   /* Setup or redefine the texture object, mipmap tree and texture +    * image.  Don't populate yet.   +    */ +   ctx->Driver.TexImage1D(ctx, target, level, internalFormat, +                          width, border, +                          GL_RGBA, CHAN_TYPE, NULL, +                          &ctx->DefaultPacking, texObj, texImage); + +   if (!do_copy_texsubimage(intel_context(ctx), +                            intel_texture_image(texImage), +                            internalFormat, 0, 0, x, y, width, 1)) +      goto fail; + +   return; + + fail: +   _swrast_copy_teximage1d(ctx, target, level, internalFormat, x, y, +                           width, border); +} + +void +intelCopyTexImage2D(GLcontext * ctx, GLenum target, GLint level, +                    GLenum internalFormat, +                    GLint x, GLint y, GLsizei width, GLsizei height, +                    GLint border) +{ +   struct gl_texture_unit *texUnit = +      &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; +   struct gl_texture_object *texObj = +      _mesa_select_tex_object(ctx, texUnit, target); +   struct gl_texture_image *texImage = +      _mesa_select_tex_image(ctx, texObj, target, level); + +   if (border) +      goto fail; + +   /* Setup or redefine the texture object, mipmap tree and texture +    * image.  Don't populate yet.   +    */ +   ctx->Driver.TexImage2D(ctx, target, level, internalFormat, +                          width, height, border, +                          GL_RGBA, CHAN_TYPE, NULL, +                          &ctx->DefaultPacking, texObj, texImage); + + +   if (!do_copy_texsubimage(intel_context(ctx), +                            intel_texture_image(texImage), +                            internalFormat, 0, 0, x, y, width, height)) +      goto fail; + +   return; + + fail: +   _swrast_copy_teximage2d(ctx, target, level, internalFormat, x, y, +                           width, height, border); +} + + +void +intelCopyTexSubImage1D(GLcontext * ctx, GLenum target, GLint level, +                       GLint xoffset, GLint x, GLint y, GLsizei width) +{ +   struct gl_texture_unit *texUnit = +      &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; +   struct gl_texture_object *texObj = +      _mesa_select_tex_object(ctx, texUnit, target); +   struct gl_texture_image *texImage = +      _mesa_select_tex_image(ctx, texObj, target, level); +   GLenum internalFormat = texImage->InternalFormat; + +   /* XXX need to check <border> as in above function? */ + +   /* Need to check texture is compatible with source format.  +    */ + +   if (!do_copy_texsubimage(intel_context(ctx), +                            intel_texture_image(texImage), +                            internalFormat, xoffset, 0, x, y, width, 1)) { +      _swrast_copy_texsubimage1d(ctx, target, level, xoffset, x, y, width); +   } +} + + + +void +intelCopyTexSubImage2D(GLcontext * ctx, GLenum target, GLint level, +                       GLint xoffset, GLint yoffset, +                       GLint x, GLint y, GLsizei width, GLsizei height) +{ +   struct gl_texture_unit *texUnit = +      &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; +   struct gl_texture_object *texObj = +      _mesa_select_tex_object(ctx, texUnit, target); +   struct gl_texture_image *texImage = +      _mesa_select_tex_image(ctx, texObj, target, level); +   GLenum internalFormat = texImage->InternalFormat; + + +   /* Need to check texture is compatible with source format.  +    */ + +   if (!do_copy_texsubimage(intel_context(ctx), +                            intel_texture_image(texImage), +                            internalFormat, +                            xoffset, yoffset, x, y, width, height)) { + +      DBG("%s - fallback to swrast\n", __FUNCTION__); + +      _swrast_copy_texsubimage2d(ctx, target, level, +                                 xoffset, yoffset, x, y, width, height); +   } +} diff --git a/src/mesa/drivers/dri/i915tex/intel_tex_format.c b/src/mesa/drivers/dri/i915tex/intel_tex_format.c new file mode 100644 index 0000000000..d7612dcbaa --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_tex_format.c @@ -0,0 +1,146 @@ +#include "intel_context.h" +#include "intel_tex.h" +#include "texformat.h" +#include "enums.h" + +/* It works out that this function is fine for all the supported + * hardware.  However, there is still a need to map the formats onto + * hardware descriptors. + */ +/* Note that the i915 can actually support many more formats than + * these if we take the step of simply swizzling the colors + * immediately after sampling... + */ +const struct gl_texture_format * +intelChooseTextureFormat(GLcontext * ctx, GLint internalFormat, +                         GLenum format, GLenum type) +{ +   struct intel_context *intel = intel_context(ctx); +   const GLboolean do32bpt = (intel->intelScreen->cpp == 4); + +   switch (internalFormat) { +   case 4: +   case GL_RGBA: +   case GL_COMPRESSED_RGBA: +      if (format == GL_BGRA) { +         if (type == GL_UNSIGNED_BYTE || 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 &_mesa_texformat_argb8888; + +   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: +      return &_mesa_texformat_a8; + +   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; + +   case GL_COMPRESSED_RGB_FXT1_3DFX: +      return &_mesa_texformat_rgb_fxt1; +   case GL_COMPRESSED_RGBA_FXT1_3DFX: +      return &_mesa_texformat_rgba_fxt1; + +   case GL_RGB_S3TC: +   case GL_RGB4_S3TC: +   case GL_COMPRESSED_RGB_S3TC_DXT1_EXT: +      return &_mesa_texformat_rgb_dxt1; + +   case GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: +      return &_mesa_texformat_rgba_dxt1; + +   case GL_RGBA_S3TC: +   case GL_RGBA4_S3TC: +   case GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: +      return &_mesa_texformat_rgba_dxt3; + +   case GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: +      return &_mesa_texformat_rgba_dxt5; + +   case GL_DEPTH_COMPONENT: +   case GL_DEPTH_COMPONENT16: +   case GL_DEPTH_COMPONENT24: +   case GL_DEPTH_COMPONENT32: +      return &_mesa_texformat_z16; + +   default: +      fprintf(stderr, "unexpected texture format %s in %s\n", +              _mesa_lookup_enum_by_nr(internalFormat), __FUNCTION__); +      return NULL; +   } + +   return NULL;                 /* never get here */ +} diff --git a/src/mesa/drivers/dri/i915tex/intel_tex_image.c b/src/mesa/drivers/dri/i915tex/intel_tex_image.c new file mode 100644 index 0000000000..48c2f35d3b --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_tex_image.c @@ -0,0 +1,626 @@ + +#include <stdlib.h> +#include <stdio.h> + +#include "glheader.h" +#include "macros.h" +#include "mtypes.h" +#include "enums.h" +#include "colortab.h" +#include "convolve.h" +#include "context.h" +#include "simple_list.h" +#include "texcompress.h" +#include "texformat.h" +#include "texobj.h" +#include "texstore.h" + +#include "intel_context.h" +#include "intel_mipmap_tree.h" +#include "intel_buffer_objects.h" +#include "intel_batchbuffer.h" +#include "intel_tex.h" +#include "intel_ioctl.h" +#include "intel_blit.h" + +#define FILE_DEBUG_FLAG DEBUG_TEXTURE + +/* Functions to store texture images.  Where possible, mipmap_tree's + * will be created or further instantiated with image data, otherwise + * images will be stored in malloc'd memory.  A validation step is + * required to pull those images into a mipmap tree, or otherwise + * decide a fallback is required. + */ + + +static int +logbase2(int n) +{ +   GLint i = 1; +   GLint log2 = 0; + +   while (n > i) { +      i *= 2; +      log2++; +   } + +   return log2; +} + + +/* Otherwise, store it in memory if (Border != 0) or (any dimension == + * 1). + *     + * Otherwise, if max_level >= level >= min_level, create tree with + * space for textures from min_level down to max_level. + * + * Otherwise, create tree with space for textures from (level + * 0)..(1x1).  Consider pruning this tree at a validation if the + * saving is worth it. + */ +static void +guess_and_alloc_mipmap_tree(struct intel_context *intel, +                            struct intel_texture_object *intelObj, +                            struct intel_texture_image *intelImage) +{ +   GLuint firstLevel; +   GLuint lastLevel; +   GLuint width = intelImage->base.Width; +   GLuint height = intelImage->base.Height; +   GLuint depth = intelImage->base.Depth; +   GLuint l2width, l2height, l2depth; +   GLuint i; + +   DBG("%s\n", __FUNCTION__); + +   if (intelImage->base.Border) +      return; + +   if (intelImage->level > intelObj->base.BaseLevel && +       (intelImage->base.Width == 1 || +        (intelObj->base.Target != GL_TEXTURE_1D && +         intelImage->base.Height == 1) || +        (intelObj->base.Target == GL_TEXTURE_3D && +         intelImage->base.Depth == 1))) +      return; + +   /* If this image disrespects BaseLevel, allocate from level zero. +    * Usually BaseLevel == 0, so it's unlikely to happen. +    */ +   if (intelImage->level < intelObj->base.BaseLevel) +      firstLevel = 0; +   else +      firstLevel = intelObj->base.BaseLevel; + + +   /* Figure out image dimensions at start level.  +    */ +   for (i = intelImage->level; i > firstLevel; i--) { +      width <<= 1; +      if (height != 1) +         height <<= 1; +      if (depth != 1) +         depth <<= 1; +   } + +   /* Guess a reasonable value for lastLevel.  This is probably going +    * to be wrong fairly often and might mean that we have to look at +    * resizable buffers, or require that buffers implement lazy +    * pagetable arrangements. +    */ +   if ((intelObj->base.MinFilter == GL_NEAREST || +        intelObj->base.MinFilter == GL_LINEAR) && +       intelImage->level == firstLevel) { +      lastLevel = firstLevel; +   } +   else { +      l2width = logbase2(width); +      l2height = logbase2(height); +      l2depth = logbase2(depth); +      lastLevel = firstLevel + MAX2(MAX2(l2width, l2height), l2depth); +   } + +   assert(!intelObj->mt); +   intelObj->mt = intel_miptree_create(intel, +                                       intelObj->base.Target, +                                       intelImage->base.InternalFormat, +                                       firstLevel, +                                       lastLevel, +                                       width, +                                       height, +                                       depth, +                                       intelImage->base.TexFormat->TexelBytes, +                                       intelImage->base.IsCompressed); + +   DBG("%s - success\n", __FUNCTION__); +} + + + + +static GLuint +target_to_face(GLenum target) +{ +   switch (target) { +   case GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB: +   case GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB: +   case GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB: +   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB: +   case GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB: +   case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB: +      return ((GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X); +   default: +      return 0; +   } +} + +/* There are actually quite a few combinations this will work for, + * more than what I've listed here. + */ +static GLboolean +check_pbo_format(GLint internalFormat, +                 GLenum format, GLenum type, +                 const struct gl_texture_format *mesa_format) +{ +   switch (internalFormat) { +   case 4: +   case GL_RGBA: +      return (format == GL_BGRA && +              (type == GL_UNSIGNED_BYTE || +               type == GL_UNSIGNED_INT_8_8_8_8_REV) && +              mesa_format == &_mesa_texformat_argb8888); +   case 3: +   case GL_RGB: +      return (format == GL_RGB && +              type == GL_UNSIGNED_SHORT_5_6_5 && +              mesa_format == &_mesa_texformat_rgb565); +   case GL_YCBCR_MESA: +      return (type == GL_UNSIGNED_SHORT_8_8_MESA || type == GL_UNSIGNED_BYTE); +   default: +      return GL_FALSE; +   } +} + + +/* XXX: Do this for TexSubImage also: + */ +static GLboolean +try_pbo_upload(struct intel_context *intel, +               struct intel_texture_image *intelImage, +               const struct gl_pixelstore_attrib *unpack, +               GLint internalFormat, +               GLint width, GLint height, +               GLenum format, GLenum type, const void *pixels) +{ +   struct intel_buffer_object *pbo = intel_buffer_object(unpack->BufferObj); +   GLuint src_offset, src_stride; +   GLuint dst_offset, dst_stride; + +   if (!pbo || +       intel->ctx._ImageTransferState || +       unpack->SkipPixels || unpack->SkipRows) { +      _mesa_printf("%s: failure 1\n", __FUNCTION__); +      return GL_FALSE; +   } + +   src_offset = (GLuint) pixels; + +   if (unpack->RowLength > 0) +      src_stride = unpack->RowLength; +   else +      src_stride = width; + +   dst_offset = intel_miptree_image_offset(intelImage->mt, +                                           intelImage->face, +                                           intelImage->level); + +   dst_stride = intelImage->mt->pitch; + +   intelFlush(&intel->ctx); +   LOCK_HARDWARE(intel); +   { +      struct _DriBufferObject *src_buffer = +         intel_bufferobj_buffer(intel, pbo, INTEL_READ); +      struct _DriBufferObject *dst_buffer = +         intel_region_buffer(intel->intelScreen, intelImage->mt->region, +                             INTEL_WRITE_FULL); + + +      intelEmitCopyBlit(intel, +                        intelImage->mt->cpp, +                        src_stride, src_buffer, src_offset, +                        dst_stride, dst_buffer, dst_offset, +                        0, 0, 0, 0, width, height); + +      intel_batchbuffer_flush(intel->batch); +   } +   UNLOCK_HARDWARE(intel); + +   return GL_TRUE; +} + + + +static GLboolean +try_pbo_zcopy(struct intel_context *intel, +              struct intel_texture_image *intelImage, +              const struct gl_pixelstore_attrib *unpack, +              GLint internalFormat, +              GLint width, GLint height, +              GLenum format, GLenum type, const void *pixels) +{ +   struct intel_buffer_object *pbo = intel_buffer_object(unpack->BufferObj); +   GLuint src_offset, src_stride; +   GLuint dst_offset, dst_stride; + +   if (!pbo || +       intel->ctx._ImageTransferState || +       unpack->SkipPixels || unpack->SkipRows) { +      _mesa_printf("%s: failure 1\n", __FUNCTION__); +      return GL_FALSE; +   } + +   src_offset = (GLuint) pixels; + +   if (unpack->RowLength > 0) +      src_stride = unpack->RowLength; +   else +      src_stride = width; + +   dst_offset = intel_miptree_image_offset(intelImage->mt, +                                           intelImage->face, +                                           intelImage->level); + +   dst_stride = intelImage->mt->pitch; + +   if (src_stride != dst_stride || dst_offset != 0 || src_offset != 0) { +      _mesa_printf("%s: failure 2\n", __FUNCTION__); +      return GL_FALSE; +   } + +   intel_region_attach_pbo(intel->intelScreen, intelImage->mt->region, pbo); + +   return GL_TRUE; +} + + + + + + +static void +intelTexImage(GLcontext * ctx, +              GLint dims, +              GLenum target, GLint level, +              GLint internalFormat, +              GLint width, GLint height, GLint depth, +              GLint border, +              GLenum format, GLenum type, const void *pixels, +              const struct gl_pixelstore_attrib *unpack, +              struct gl_texture_object *texObj, +              struct gl_texture_image *texImage) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_texture_object *intelObj = intel_texture_object(texObj); +   struct intel_texture_image *intelImage = intel_texture_image(texImage); +   GLint postConvWidth = width; +   GLint postConvHeight = height; +   GLint texelBytes, sizeInBytes; +   GLuint dstRowStride; + + +   DBG("%s target %s level %d %dx%dx%d border %d\n", __FUNCTION__, +       _mesa_lookup_enum_by_nr(target), level, width, height, depth, border); + +   intelFlush(ctx); + +   intelImage->face = target_to_face(target); +   intelImage->level = level; + +   if (ctx->_ImageTransferState & IMAGE_CONVOLUTION_BIT) { +      _mesa_adjust_image_for_convolution(ctx, dims, &postConvWidth, +                                         &postConvHeight); +   } + +   /* choose the texture format */ +   texImage->TexFormat = intelChooseTextureFormat(ctx, internalFormat, +                                                  format, type); + +   assert(texImage->TexFormat); + +   switch (dims) { +   case 1: +      texImage->FetchTexelc = texImage->TexFormat->FetchTexel1D; +      texImage->FetchTexelf = texImage->TexFormat->FetchTexel1Df; +      break; +   case 2: +      texImage->FetchTexelc = texImage->TexFormat->FetchTexel2D; +      texImage->FetchTexelf = texImage->TexFormat->FetchTexel2Df; +      break; +   case 3: +      texImage->FetchTexelc = texImage->TexFormat->FetchTexel3D; +      texImage->FetchTexelf = texImage->TexFormat->FetchTexel3Df; +      break; +   default: +      assert(0); +      break; +   } + +   texelBytes = texImage->TexFormat->TexelBytes; + + +   /* Minimum pitch of 32 bytes */ +   if (postConvWidth * texelBytes < 32) { +      postConvWidth = 32 / texelBytes; +      texImage->RowStride = postConvWidth; +   } + +   assert(texImage->RowStride == postConvWidth); + +   /* Release the reference to a potentially orphaned buffer.    +    * Release any old malloced memory. +    */ +   if (intelImage->mt) { +      intel_miptree_release(intel, &intelImage->mt); +      assert(!texImage->Data); +   } +   else if (texImage->Data) { +      _mesa_align_free(texImage->Data); +   } + +   /* If this is the only texture image in the tree, could call +    * bmBufferData with NULL data to free the old block and avoid +    * waiting on any outstanding fences. +    */ +   if (intelObj->mt && +       intelObj->mt->first_level == level && +       intelObj->mt->last_level == level && +       intelObj->mt->target != GL_TEXTURE_CUBE_MAP_ARB && +       !intel_miptree_match_image(intelObj->mt, &intelImage->base, +                                  intelImage->face, intelImage->level)) { + +      DBG("release it\n"); +      intel_miptree_release(intel, &intelObj->mt); +      assert(!intelObj->mt); +   } + +   if (!intelObj->mt) { +      guess_and_alloc_mipmap_tree(intel, intelObj, intelImage); +      if (!intelObj->mt) { +	 DBG("guess_and_alloc_mipmap_tree: failed\n"); +      } +   } + + +   assert(!intelImage->mt); + +   if (intelObj->mt && +       intel_miptree_match_image(intelObj->mt, &intelImage->base, +                                 intelImage->face, intelImage->level)) { + +      intel_miptree_reference(&intelImage->mt, intelObj->mt); +      assert(intelImage->mt); +   } + +   if (!intelImage->mt) +      DBG("XXX: Image did not fit into tree - storing in local memory!\n"); + +   /* PBO fastpaths: +    */ +   if (dims <= 2 && +       intelImage->mt && +       intel_buffer_object(unpack->BufferObj) && +       check_pbo_format(internalFormat, format, +                        type, intelImage->base.TexFormat)) { + +      DBG("trying pbo upload\n"); + +      /* Attempt to texture directly from PBO data (zero copy upload). +       * +       * Currently disable as it can lead to worse as well as better +       * performance (in particular when intel_region_cow() is +       * required). +       */ +      if (intelObj->mt == intelImage->mt && +          intelObj->mt->first_level == level && +          intelObj->mt->last_level == level) { + +         if (try_pbo_zcopy(intel, intelImage, unpack, +                           internalFormat, +                           width, height, format, type, pixels)) { + +            DBG("pbo zcopy upload succeeded\n"); +            return; +         } +      } + + +      /* Otherwise, attempt to use the blitter for PBO image uploads. +       */ +      if (try_pbo_upload(intel, intelImage, unpack, +                         internalFormat, +                         width, height, format, type, pixels)) { +         DBG("pbo upload succeeded\n"); +         return; +      } + +      DBG("pbo upload failed\n"); +   } + + + +   /* intelCopyTexImage calls this function with pixels == NULL, with +    * the expectation that the mipmap tree will be set up but nothing +    * more will be done.  This is where those calls return: +    */ +   pixels = _mesa_validate_pbo_teximage(ctx, dims, width, height, 1, +                                        format, type, +                                        pixels, unpack, "glTexImage"); +   if (!pixels) +      return; + + +   if (intelImage->mt) +      intel_region_idle(intel->intelScreen, intelImage->mt->region); + +   LOCK_HARDWARE(intel); + +   if (intelImage->mt) { +      texImage->Data = intel_miptree_image_map(intel, +                                               intelImage->mt, +                                               intelImage->face, +                                               intelImage->level, +                                               &dstRowStride, +                                               intelImage->base.ImageOffsets); +   } +   else { +      /* Allocate regular memory and store the image there temporarily.   */ +      if (texImage->IsCompressed) { +         sizeInBytes = texImage->CompressedSize; +         dstRowStride = +            _mesa_compressed_row_stride(texImage->InternalFormat, width); +         assert(dims != 3); +      } +      else { +         dstRowStride = postConvWidth * texelBytes; +         sizeInBytes = depth * dstRowStride * postConvHeight; +      } + +      texImage->Data = malloc(sizeInBytes); +   } + +   DBG("Upload image %dx%dx%d row_len %x " +       "pitch %x\n", +       width, height, depth, width * texelBytes, dstRowStride); + +   /* Copy data.  Would like to know when it's ok for us to eg. use +    * the blitter to copy.  Or, use the hardware to do the format +    * conversion and copy: +    */ +   if (!texImage->TexFormat->StoreImage(ctx, dims,  +					texImage->_BaseFormat,  +					texImage->TexFormat,  +					texImage->Data, 0, 0, 0, /* dstX/Y/Zoffset */ +                                        dstRowStride, +                                        texImage->ImageOffsets, +                                        width, height, depth, +                                        format, type, pixels, unpack)) { +      _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage"); +   } + +   _mesa_unmap_teximage_pbo(ctx, unpack); + +   if (intelImage->mt) { +      intel_miptree_image_unmap(intel, intelImage->mt); +      texImage->Data = NULL; +   } + +   UNLOCK_HARDWARE(intel); + +#if 0 +   /* GL_SGIS_generate_mipmap -- this can be accelerated now. +    */ +   if (level == texObj->BaseLevel && texObj->GenerateMipmap) { +      intel_generate_mipmap(ctx, target, +                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit], +                            texObj); +   } +#endif +} + +void +intelTexImage3D(GLcontext * ctx, +                GLenum target, GLint level, +                GLint internalFormat, +                GLint width, GLint height, GLint depth, +                GLint border, +                GLenum format, GLenum type, const void *pixels, +                const struct gl_pixelstore_attrib *unpack, +                struct gl_texture_object *texObj, +                struct gl_texture_image *texImage) +{ +   intelTexImage(ctx, 3, target, level, +                 internalFormat, width, height, depth, border, +                 format, type, pixels, unpack, texObj, texImage); +} + + +void +intelTexImage2D(GLcontext * ctx, +                GLenum target, GLint level, +                GLint internalFormat, +                GLint width, GLint height, GLint border, +                GLenum format, GLenum type, const void *pixels, +                const struct gl_pixelstore_attrib *unpack, +                struct gl_texture_object *texObj, +                struct gl_texture_image *texImage) +{ +   intelTexImage(ctx, 2, target, level, +                 internalFormat, width, height, 1, border, +                 format, type, pixels, unpack, texObj, texImage); +} + +void +intelTexImage1D(GLcontext * ctx, +                GLenum target, GLint level, +                GLint internalFormat, +                GLint width, GLint border, +                GLenum format, GLenum type, const void *pixels, +                const struct gl_pixelstore_attrib *unpack, +                struct gl_texture_object *texObj, +                struct gl_texture_image *texImage) +{ +   intelTexImage(ctx, 1, target, level, +                 internalFormat, width, 1, 1, border, +                 format, type, pixels, unpack, texObj, texImage); +} + + + +/** + * Need to map texture image into memory before copying image data, + * then unmap it. + */ +void +intelGetTexImage(GLcontext * ctx, GLenum target, GLint level, +                 GLenum format, GLenum type, GLvoid * pixels, +                 struct gl_texture_object *texObj, +                 struct gl_texture_image *texImage) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_texture_image *intelImage = intel_texture_image(texImage); + +   /* Map */ +   if (intelImage->mt) { +      /* Image is stored in hardware format in a buffer managed by the +       * kernel.  Need to explicitly map and unmap it. +       */ +      intelImage->base.Data = +         intel_miptree_image_map(intel, +                                 intelImage->mt, +                                 intelImage->face, +                                 intelImage->level, +                                 &intelImage->base.RowStride, +                                 intelImage->base.ImageOffsets); +   } +   else { +      /* Otherwise, the image should actually be stored in +       * intelImage->base.Data.  This is pretty confusing for +       * everybody, I'd much prefer to separate the two functions of +       * texImage->Data - storage for texture images in main memory +       * and access (ie mappings) of images.  In other words, we'd +       * create a new texImage->Map field and leave Data simply for +       * storage. +       */ +      assert(intelImage->base.Data); +   } + +   _mesa_get_teximage(ctx, target, level, format, type, pixels, +                      texObj, texImage); + +   /* Unmap */ +   if (intelImage->mt) { +      intel_miptree_image_unmap(intel, intelImage->mt); +      intelImage->base.Data = NULL; +   } +} diff --git a/src/mesa/drivers/dri/i915tex/intel_tex_subimage.c b/src/mesa/drivers/dri/i915tex/intel_tex_subimage.c new file mode 100644 index 0000000000..25a2dca685 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_tex_subimage.c @@ -0,0 +1,183 @@ + +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#include "mtypes.h" +#include "texobj.h" +#include "texstore.h" +#include "enums.h" + +#include "intel_context.h" +#include "intel_tex.h" +#include "intel_mipmap_tree.h" + +#define FILE_DEBUG_FLAG DEBUG_TEXTURE + +static void +intelTexSubimage(GLcontext * ctx, +                 GLint dims, +                 GLenum target, GLint level, +                 GLint xoffset, GLint yoffset, GLint zoffset, +                 GLint width, GLint height, GLint depth, +                 GLenum format, GLenum type, const void *pixels, +                 const struct gl_pixelstore_attrib *packing, +                 struct gl_texture_object *texObj, +                 struct gl_texture_image *texImage) +{ +   struct intel_context *intel = intel_context(ctx); +   struct intel_texture_image *intelImage = intel_texture_image(texImage); +   GLuint dstImageStride; +   GLuint dstRowStride; + +   DBG("%s target %s level %d offset %d,%d %dx%d\n", __FUNCTION__, +       _mesa_lookup_enum_by_nr(target), +       level, xoffset, yoffset, width, height); + +   intelFlush(ctx); + +   pixels = +      _mesa_validate_pbo_teximage(ctx, dims, width, height, depth, format, +                                  type, pixels, packing, "glTexSubImage2D"); +   if (!pixels) +      return; + +   if (intelImage->mt) +      intel_region_idle(intel->intelScreen, intelImage->mt->region); + +   LOCK_HARDWARE(intel); + +   /* Map buffer if necessary.  Need to lock to prevent other contexts +    * from uploading the buffer under us. +    */ +   if (intelImage->mt)  +      texImage->Data = intel_miptree_image_map(intel, +                                               intelImage->mt, +                                               intelImage->face, +                                               intelImage->level, +                                               &dstRowStride, +                                               &dstImageStride); + +   assert(dstRowStride); + +   if (!texImage->TexFormat->StoreImage(ctx, dims, texImage->_BaseFormat, +                                        texImage->TexFormat, +                                        texImage->Data, +                                        xoffset, yoffset, zoffset, +                                        dstRowStride, +                                        texImage->ImageOffsets, +                                        width, height, depth, +                                        format, type, pixels, packing)) { +      _mesa_error(ctx, GL_OUT_OF_MEMORY, "intelTexSubImage"); +   } + +#if 0 +   /* GL_SGIS_generate_mipmap */ +   if (level == texObj->BaseLevel && texObj->GenerateMipmap) { +      _mesa_generate_mipmap(ctx, target, +                            &ctx->Texture.Unit[ctx->Texture.CurrentUnit], +                            texObj); +   } +#endif + +   _mesa_unmap_teximage_pbo(ctx, packing); + +   if (intelImage->mt) { +      intel_miptree_image_unmap(intel, intelImage->mt); +      texImage->Data = NULL; +   } + +   UNLOCK_HARDWARE(intel); +} + + + + + +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) +{ + +   intelTexSubimage(ctx, 3, +                    target, level, +                    xoffset, yoffset, zoffset, +                    width, height, depth, +                    format, type, pixels, packing, texObj, texImage); + +} + + + +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) +{ + +   intelTexSubimage(ctx, 2, +                    target, level, +                    xoffset, yoffset, 0, +                    width, height, 1, +                    format, type, pixels, packing, texObj, texImage); + +} + + +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) +{ +   intelTexSubimage(ctx, 1, +                    target, level, +                    xoffset, 0, 0, +                    width, 1, 1, +                    format, type, pixels, packing, texObj, texImage); + +} diff --git a/src/mesa/drivers/dri/i915tex/intel_tex_validate.c b/src/mesa/drivers/dri/i915tex/intel_tex_validate.c new file mode 100644 index 0000000000..e273716b09 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_tex_validate.c @@ -0,0 +1,252 @@ +#include "mtypes.h" +#include "macros.h" + +#include "intel_context.h" +#include "intel_mipmap_tree.h" +#include "intel_tex.h" + +#define FILE_DEBUG_FLAG DEBUG_TEXTURE + +/** + * Compute which mipmap levels that really need to be sent 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. + */ +static void +intel_calculate_first_last_level(struct intel_texture_object *intelObj) +{ +   struct gl_texture_object *tObj = &intelObj->base; +   const struct gl_texture_image *const baseImage = +      tObj->Image[0][tObj->BaseLevel]; + +   /* These must be signed values.  MinLod and MaxLod can be negative numbers, +    * and having firstLevel and lastLevel as signed prevents the need for +    * extra sign checks. +    */ +   int firstLevel; +   int lastLevel; + +   /* Yes, this looks overly complicated, but it's all needed. +    */ +   switch (tObj->Target) { +   case GL_TEXTURE_1D: +   case GL_TEXTURE_2D: +   case GL_TEXTURE_3D: +   case GL_TEXTURE_CUBE_MAP: +      if (tObj->MinFilter == GL_NEAREST || tObj->MinFilter == GL_LINEAR) { +         /* GL_NEAREST and GL_LINEAR only care about GL_TEXTURE_BASE_LEVEL. +          */ +         firstLevel = lastLevel = tObj->BaseLevel; +      } +      else { +         firstLevel = tObj->BaseLevel + (GLint) (tObj->MinLod + 0.5); +         firstLevel = MAX2(firstLevel, tObj->BaseLevel); +         lastLevel = tObj->BaseLevel + (GLint) (tObj->MaxLod + 0.5); +         lastLevel = MAX2(lastLevel, tObj->BaseLevel); +         lastLevel = MIN2(lastLevel, tObj->BaseLevel + baseImage->MaxLog2); +         lastLevel = MIN2(lastLevel, tObj->MaxLevel); +         lastLevel = MAX2(firstLevel, lastLevel);       /* need at least one level */ +      } +      break; +   case GL_TEXTURE_RECTANGLE_NV: +   case GL_TEXTURE_4D_SGIS: +      firstLevel = lastLevel = 0; +      break; +   default: +      return; +   } + +   /* save these values */ +   intelObj->firstLevel = firstLevel; +   intelObj->lastLevel = lastLevel; +} + +static void +copy_image_data_to_tree(struct intel_context *intel, +                        struct intel_texture_object *intelObj, +                        struct intel_texture_image *intelImage) +{ +   if (intelImage->mt) { +      /* Copy potentially with the blitter: +       */ +      intel_miptree_image_copy(intel, +                               intelObj->mt, +                               intelImage->face, +                               intelImage->level, intelImage->mt); + +      intel_miptree_release(intel, &intelImage->mt); +   } +   else { +      assert(intelImage->base.Data != NULL); + +      /* More straightforward upload.   +       */ +      intel_miptree_image_data(intel, +                               intelObj->mt, +                               intelImage->face, +                               intelImage->level, +                               intelImage->base.Data, +                               intelImage->base.RowStride, +                               intelImage->base.RowStride * +                               intelImage->base.Height); +      _mesa_align_free(intelImage->base.Data); +      intelImage->base.Data = NULL; +   } + +   intel_miptree_reference(&intelImage->mt, intelObj->mt); +} + + +/*   + */ +GLuint +intel_finalize_mipmap_tree(struct intel_context *intel, GLuint unit) +{ +   struct gl_texture_object *tObj = intel->ctx.Texture.Unit[unit]._Current; +   struct intel_texture_object *intelObj = intel_texture_object(tObj); + +   GLuint face, i; +   GLuint nr_faces = 0; +   struct intel_texture_image *firstImage; + +   /* We know/require this is true by now:  +    */ +   assert(intelObj->base.Complete); + +   /* What levels must the tree include at a minimum? +    */ +   intel_calculate_first_last_level(intelObj); +   firstImage = +      intel_texture_image(intelObj->base.Image[0][intelObj->firstLevel]); + +   /* Fallback case: +    */ +   if (firstImage->base.Border) { +      if (intelObj->mt) { +         intel_miptree_release(intel, &intelObj->mt); +      } +      return GL_FALSE; +   } + + +   /* If both firstImage and intelObj have a tree which can contain +    * all active images, favour firstImage.  Note that because of the +    * completeness requirement, we know that the image dimensions +    * will match. +    */ +   if (firstImage->mt && +       firstImage->mt != intelObj->mt && +       firstImage->mt->first_level <= intelObj->firstLevel && +       firstImage->mt->last_level >= intelObj->lastLevel) { + +      if (intelObj->mt) +         intel_miptree_release(intel, &intelObj->mt); + +      intel_miptree_reference(&intelObj->mt, firstImage->mt); +   } + +   /* Check tree can hold all active levels.  Check tree matches +    * target, imageFormat, etc. +    *  +    * XXX: For some layouts (eg i945?), the test might have to be +    * first_level == firstLevel, as the tree isn't valid except at the +    * original start level.  Hope to get around this by +    * programming minLod, maxLod, baseLevel into the hardware and +    * leaving the tree alone. +    */ +   if (intelObj->mt && +       ((intelObj->mt->first_level > intelObj->firstLevel) || +        (intelObj->mt->last_level < intelObj->lastLevel) || +        (intelObj->mt->internal_format != firstImage->base.InternalFormat))) { +      intel_miptree_release(intel, &intelObj->mt); +   } + + +   /* May need to create a new tree: +    */ +   if (!intelObj->mt) { +      intelObj->mt = intel_miptree_create(intel, +                                          intelObj->base.Target, +                                          firstImage->base.InternalFormat, +                                          intelObj->firstLevel, +                                          intelObj->lastLevel, +                                          firstImage->base.Width, +                                          firstImage->base.Height, +                                          firstImage->base.Depth, +                                          firstImage->base.TexFormat-> +                                          TexelBytes, +                                          firstImage->base.IsCompressed); +   } + +   /* Pull in any images not in the object's tree: +    */ +   nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; +   for (face = 0; face < nr_faces; face++) { +      for (i = intelObj->firstLevel; i <= intelObj->lastLevel; i++) { +         struct intel_texture_image *intelImage = +            intel_texture_image(intelObj->base.Image[face][i]); + +         /* Need to import images in main memory or held in other trees. +          */ +         if (intelObj->mt != intelImage->mt) { +            copy_image_data_to_tree(intel, intelObj, intelImage); +         } +      } +   } + +   return GL_TRUE; +} + + + +void +intel_tex_map_images(struct intel_context *intel, +                     struct intel_texture_object *intelObj) +{ +   GLuint nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; +   GLuint face, i; + +   DBG("%s\n", __FUNCTION__); + +   for (face = 0; face < nr_faces; face++) { +      for (i = intelObj->firstLevel; i <= intelObj->lastLevel; i++) { +         struct intel_texture_image *intelImage = +            intel_texture_image(intelObj->base.Image[face][i]); + +         if (intelImage->mt) { +            intelImage->base.Data = +               intel_miptree_image_map(intel, +                                       intelImage->mt, +                                       intelImage->face, +                                       intelImage->level, +                                       &intelImage->base.RowStride, +                                       intelImage->base.ImageOffsets); +            /* convert stride to texels, not bytes */ +            intelImage->base.RowStride /= intelImage->mt->cpp; +/*             intelImage->base.ImageStride /= intelImage->mt->cpp; */ +         } +      } +   } +} + + + +void +intel_tex_unmap_images(struct intel_context *intel, +                       struct intel_texture_object *intelObj) +{ +   GLuint nr_faces = (intelObj->base.Target == GL_TEXTURE_CUBE_MAP) ? 6 : 1; +   GLuint face, i; + +   for (face = 0; face < nr_faces; face++) { +      for (i = intelObj->firstLevel; i <= intelObj->lastLevel; i++) { +         struct intel_texture_image *intelImage = +            intel_texture_image(intelObj->base.Image[face][i]); + +         if (intelImage->mt) { +            intel_miptree_image_unmap(intel, intelImage->mt); +            intelImage->base.Data = NULL; +         } +      } +   } +} diff --git a/src/mesa/drivers/dri/i915tex/intel_tris.c b/src/mesa/drivers/dri/i915tex/intel_tris.c new file mode 100644 index 0000000000..1ba49d8f6e --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_tris.c @@ -0,0 +1,1149 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#include "glheader.h" +#include "context.h" +#include "macros.h" +#include "enums.h" +#include "texobj.h" +#include "state.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_context.h" +#include "intel_tris.h" +#include "intel_batchbuffer.h" +#include "intel_reg.h" +#include "intel_span.h" +#include "intel_tex.h" + +static void intelRenderPrimitive(GLcontext * ctx, GLenum prim); +static void intelRasterPrimitive(GLcontext * ctx, GLenum rprim, +                                 GLuint hwprim); + +/* + */ +static void +intel_flush_inline_primitive(struct intel_context *intel) +{ +   GLuint used = intel->batch->ptr - intel->prim.start_ptr; + +   assert(intel->prim.primitive != ~0); + +/*    _mesa_printf("/\n"); */ + +   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; + + 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(struct intel_context *intel, +                          GLuint prim, GLuint batch_flags) +{ +   BATCH_LOCALS; + +   intel->vtbl.emit_state(intel); + +   /* Need to make sure at the very least that we don't wrap +    * batchbuffers in BEGIN_BATCH below, otherwise the primitive will +    * be emitted to a batchbuffer missing the required full-state +    * preamble. +    */ +   if (intel_batchbuffer_space(intel->batch) < 100) { +      intel_batchbuffer_flush(intel->batch); +      intel->vtbl.emit_state(intel); +   } + +/*    _mesa_printf("%s *", __progname); */ + +   /* Emit a slot which will be filled with the inline primitive +    * command later. +    */ +   BEGIN_BATCH(2, batch_flags); +   OUT_BATCH(0); + +   intel->prim.start_ptr = intel->batch->ptr; +   intel->prim.primitive = prim; +   intel->prim.flush = intel_flush_inline_primitive; + +   OUT_BATCH(0); +   ADVANCE_BATCH(); + +/*    _mesa_printf(">"); */ +} + + +void +intelWrapInlinePrimitive(struct intel_context *intel) +{ +   GLuint prim = intel->prim.primitive; +   GLuint batchflags = intel->batch->flags; + +   intel_flush_inline_primitive(intel); +   intel_batchbuffer_flush(intel->batch); +   intelStartInlinePrimitive(intel, prim, batchflags);  /* ??? */ +} + +GLuint * +intelExtendInlinePrimitive(struct intel_context *intel, GLuint dwords) +{ +   GLuint sz = dwords * sizeof(GLuint); +   GLuint *ptr; + +   assert(intel->prim.flush == intel_flush_inline_primitive); + +   if (intel_batchbuffer_space(intel->batch) < sz) +      intelWrapInlinePrimitive(intel); + +/*    _mesa_printf("."); */ + +   intel->vtbl.assert_not_dirty(intel); + +   ptr = (GLuint *) intel->batch->ptr; +   intel->batch->ptr += sz; + +   return ptr; +} + + + +/*********************************************************************** + *                    Emit primitives as inline vertices               * + ***********************************************************************/ + +#ifdef __i386__ +#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 {						\ +   for ( j = 0 ; j < vertsize ; j++ ) {		\ +      vb[j] = ((GLuint *)v)[j];			\ +   }						\ +   vb += vertsize;				\ +} while (0) +#endif + +static void +intel_draw_quad(struct intel_context *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); + +   /* If smooth shading, draw like a trifan which gives better +    * rasterization.  Otherwise draw as two triangles with provoking +    * vertex in third position as required for flat shading. +    */ +   if (intel->ctx.Light.ShadeModel == GL_FLAT) { +      COPY_DWORDS(j, vb, vertsize, v3); +      COPY_DWORDS(j, vb, vertsize, v1); +   } +   else { +      COPY_DWORDS(j, vb, vertsize, v2); +      COPY_DWORDS(j, vb, vertsize, v0); +   } + +   COPY_DWORDS(j, vb, vertsize, v2); +   COPY_DWORDS(j, vb, vertsize, v3); +} + +static void +intel_draw_triangle(struct intel_context *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 void +intel_draw_line(struct intel_context *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 void +intel_draw_point(struct intel_context *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                       * + ***********************************************************************/ + +/* Currently not working - VERT_ATTRIB_POINTSIZE isn't correctly + * represented in the fragment program InputsRead field. + */ +static void +intel_atten_point(struct intel_context *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(struct intel_context *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(struct intel_context *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(struct intel_context *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 +{ +   tnl_points_func points; +   tnl_line_func line; +   tnl_triangle_func triangle; +   tnl_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)							\ +   struct intel_context *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(struct intel_context *intel, +                   intelVertex * v0, intelVertex * v1, intelVertex * v2) +{ +   GLcontext *ctx = &intel->ctx; +   SWvertex v[3]; + +   if (0) +      fprintf(stderr, "\n%s\n", __FUNCTION__); + +   INTEL_FIREVERTICES(intel); + +   _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(struct intel_context *intel, +                    intelVertex * v0, intelVertex * v1) +{ +   GLcontext *ctx = &intel->ctx; +   SWvertex v[2]; + +   if (0) +      fprintf(stderr, "\n%s\n", __FUNCTION__); + +   INTEL_FIREVERTICES(intel); + +   _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(struct intel_context *intel, +		     intelVertex * v0) +{ +   GLcontext *ctx = &intel->ctx; +   SWvertex v[1]; + +   if (0) +      fprintf(stderr, "\n%s\n", __FUNCTION__); + +   INTEL_FIREVERTICES(intel); + +   _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						\ +    struct intel_context *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) +{ +   struct intel_context *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) +{ +   struct intel_context *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 ANY_FALLBACK_FLAGS (DD_LINE_STIPPLE | DD_TRI_STIPPLE | DD_POINT_ATTEN | DD_POINT_SMOOTH | DD_TRI_SMOOTH) +#define ANY_RASTER_FLAGS (DD_TRI_LIGHT_TWOSIDE | DD_TRI_OFFSET | DD_TRI_UNFILLED) + +void +intelChooseRenderState(GLcontext * ctx) +{ +   TNLcontext *tnl = TNL_CONTEXT(ctx); +   struct intel_context *intel = intel_context(ctx); +   GLuint flags = ctx->_TriangleCaps; +   const struct gl_fragment_program *fprog = ctx->FragmentProgram._Current; +   GLboolean have_wpos = (fprog && (fprog->Base.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 & DD_LINE_STIPPLE) +            intel->draw_line = intel_fallback_line; + +         if ((flags & DD_TRI_STIPPLE) && !intel->hw_stipple) +            intel->draw_tri = intel_fallback_tri; + +         if (flags & DD_TRI_SMOOTH) { +	    if (intel->strict_conformance) +	       intel->draw_tri = intel_fallback_tri; +	 } + +         if (flags & DD_POINT_ATTEN) { +	    if (0) +	       intel->draw_point = intel_atten_point; +	    else +	       intel->draw_point = intel_fallback_point; +	 } + +	 if (flags & DD_POINT_SMOOTH) { +	    if (intel->strict_conformance) +	       intel->draw_point = intel_fallback_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) +{ +   struct intel_context *intel = intel_context(ctx); + +   _mesa_lock_context_textures(ctx); +    +   if (ctx->NewState) +      _mesa_update_state_locked(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); + +   _mesa_unlock_context_textures(ctx); +} + +static void +intelRenderStart(GLcontext * ctx) +{ +   struct intel_context *intel = intel_context(ctx); + +   intel->vtbl.render_start(intel_context(ctx)); +   intel->vtbl.emit_state(intel); +} + +static void +intelRenderFinish(GLcontext * ctx) +{ +   struct intel_context *intel = intel_context(ctx); + +   if (intel->RenderIndex & INTEL_FALLBACK_BIT) +      _swrast_flush(ctx); + +   INTEL_FIREVERTICES(intel); +} + + + + + /* System to flush dma and emit state changes based on the rasterized +  * primitive. +  */ +static void +intelRasterPrimitive(GLcontext * ctx, GLenum rprim, GLuint hwprim) +{ +   struct intel_context *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) { +      INTEL_FIREVERTICES(intel); + +      intelStartInlinePrimitive(intel, hwprim, INTEL_BATCH_CLIPRECTS); +   } +} + + + /*  +  */ +static void +intelRenderPrimitive(GLcontext * ctx, GLenum prim) +{ +   struct intel_context *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[] = { +   [0] = "Draw buffer", +   [1] = "Read buffer", +   [2] = "Depth buffer", +   [3] = "Stencil buffer", +   [4] = "User disable", +   [5] = "Render mode", + +   [12] = "Texture", +   [13] = "Color mask", +   [14] = "Stencil", +   [15] = "Stipple", +   [16] = "Program", +   [17] = "Logic op", +   [18] = "Smooth polygon", +   [19] = "Smooth point", +}; + + +static char * +getFallbackString(GLuint bit) +{ +   int i = 0; +   while (bit > 1) { +      i++; +      bit >>= 1; +   } +   return fallbackStrings[i]; +} + + + +void +intelFallback(struct intel_context *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; +      } +   } +} + +union fi +{ +   GLfloat f; +   GLint i; +}; + + +/**********************************************************************/ +/*             Used only with the metaops callbacks.                  */ +/**********************************************************************/ +void +intel_meta_draw_poly(struct intel_context *intel, +                     GLuint n, +                     GLfloat xy[][2], +                     GLfloat z, GLuint color, GLfloat tex[][2]) +{ +   union fi *vb; +   GLint i; + +   /* All 3d primitives should be emitted with INTEL_BATCH_CLIPRECTS, +    * otherwise the drawing origin (DR4) might not be set correctly. +    */ +   intelStartInlinePrimitive(intel, PRIM3D_TRIFAN, INTEL_BATCH_CLIPRECTS); +   vb = (union fi *) intelExtendInlinePrimitive(intel, n * 6); + +   for (i = 0; i < n; i++) { +      vb[0].f = xy[i][0]; +      vb[1].f = xy[i][1]; +      vb[2].f = z; +      vb[3].i = color; +      vb[4].f = tex[i][0]; +      vb[5].f = tex[i][1]; +      vb += 6; +   } + +   INTEL_FIREVERTICES(intel); +} + +void +intel_meta_draw_quad(struct intel_context *intel, +                     GLfloat x0, GLfloat x1, +                     GLfloat y0, GLfloat y1, +                     GLfloat z, +                     GLuint color, +                     GLfloat s0, GLfloat s1, GLfloat t0, GLfloat t1) +{ +   GLfloat xy[4][2]; +   GLfloat tex[4][2]; + +   xy[0][0] = x0; +   xy[0][1] = y0; +   xy[1][0] = x1; +   xy[1][1] = y0; +   xy[2][0] = x1; +   xy[2][1] = y1; +   xy[3][0] = x0; +   xy[3][1] = y1; + +   tex[0][0] = s0; +   tex[0][1] = t0; +   tex[1][0] = s1; +   tex[1][1] = t0; +   tex[2][0] = s1; +   tex[2][1] = t1; +   tex[3][0] = s0; +   tex[3][1] = t1; + +   intel_meta_draw_poly(intel, 4, xy, z, color, tex); +} + + + +/**********************************************************************/ +/*                            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/i915tex/intel_tris.h b/src/mesa/drivers/dri/i915tex/intel_tris.h new file mode 100644 index 0000000000..b7bae8cd3b --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_tris.h @@ -0,0 +1,69 @@ +/************************************************************************** + *  + * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas. + * All Rights Reserved. + *  + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + *  + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + *  + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + *  + **************************************************************************/ + +#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 intelChooseRenderState(GLcontext * ctx); + +extern void intelStartInlinePrimitive(struct intel_context *intel, +                                      GLuint prim, GLuint flags); +extern void intelWrapInlinePrimitive(struct intel_context *intel); + +GLuint *intelExtendInlinePrimitive(struct intel_context *intel, +                                   GLuint dwords); + + +void intel_meta_draw_quad(struct intel_context *intel, +                          GLfloat x0, GLfloat x1, +                          GLfloat y0, GLfloat y1, +                          GLfloat z, +                          GLuint color, +                          GLfloat s0, GLfloat s1, GLfloat t0, GLfloat t1); + +void intel_meta_draw_poly(struct intel_context *intel, +                          GLuint n, +                          GLfloat xy[][2], +                          GLfloat z, GLuint color, GLfloat tex[][2]); + + + +#endif diff --git a/src/mesa/drivers/dri/i915tex/server/i830_common.h b/src/mesa/drivers/dri/i915tex/server/i830_common.h new file mode 100644 index 0000000000..fb6ceaa52d --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/server/i830_common.h @@ -0,0 +1,212 @@ +/************************************************************************** + +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 +#define DRM_I830_DESTROY_HEAP             0x0c + +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 */    +	int width, height;      /* screen size in pixels */ + +	drm_handle_t front_handle; +	int front_offset; +	int front_size; + +	drm_handle_t back_handle; +	int back_offset; +	int back_size; + +	drm_handle_t depth_handle; +	int depth_offset; +	int depth_size; + +	drm_handle_t tex_handle; +	int tex_offset; +	int tex_size; +	int log_tex_granularity; +	int pitch; +	int rotation;           /* 0, 90, 180 or 270 */ +	int rotated_offset; +	int rotated_size; +	int rotated_pitch; +	int virtualX, virtualY; + +	unsigned int front_tiled; +	unsigned int back_tiled; +	unsigned int depth_tiled; +	unsigned int rotated_tiled; +	unsigned int rotated2_tiled; + +	int pipeA_x; +	int pipeA_y; +	int pipeA_w; +	int pipeA_h; +	int pipeB_x; +	int pipeB_y; +	int pipeB_w; +	int pipeB_h; +} 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; + +typedef struct { +	int region; +} drmI830MemDestroyHeap; + + +#endif /* _I830_DRM_H_ */ diff --git a/src/mesa/drivers/dri/i915tex/server/i830_dri.h b/src/mesa/drivers/dri/i915tex/server/i830_dri.h new file mode 100644 index 0000000000..6c9a709021 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/server/i830_dri.h @@ -0,0 +1,73 @@ +/* $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 + +typedef struct _I830DRIRec { +   drm_handle_t regs; +   drmSize regsSize; + +   drmSize backbufferSize; +   drm_handle_t backbuffer; + +   drmSize depthbufferSize; +   drm_handle_t depthbuffer; + +   drmSize rotatedSize; +   drm_handle_t rotatedbuffer; + +   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 rotatedOffset; +   int rotatedPitch; + +   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 diff --git a/src/mesa/drivers/dri/i915tex/server/intel.h b/src/mesa/drivers/dri/i915tex/server/intel.h new file mode 100644 index 0000000000..d7858a20c8 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/server/intel.h @@ -0,0 +1,328 @@ +#ifndef _INTEL_H_ +#define _INTEL_H_ + +#include "xf86drm.h"		/* drm_handle_t, etc */ + +/* Intel */ +#ifndef PCI_CHIP_I810 +#define PCI_CHIP_I810              0x7121 +#define PCI_CHIP_I810_DC100        0x7123 +#define PCI_CHIP_I810_E            0x7125 +#define PCI_CHIP_I815              0x1132 +#define PCI_CHIP_I810_BRIDGE       0x7120 +#define PCI_CHIP_I810_DC100_BRIDGE 0x7122 +#define PCI_CHIP_I810_E_BRIDGE     0x7124 +#define PCI_CHIP_I815_BRIDGE       0x1130 +#endif + +#define PCI_CHIP_845_G			0x2562 +#define PCI_CHIP_I830_M			0x3577 + +#ifndef PCI_CHIP_I855_GM +#define PCI_CHIP_I855_GM	   0x3582 +#define PCI_CHIP_I855_GM_BRIDGE	   0x3580 +#endif + +#ifndef PCI_CHIP_I865_G +#define PCI_CHIP_I865_G		   0x2572 +#define PCI_CHIP_I865_G_BRIDGE	   0x2570 +#endif + +#ifndef PCI_CHIP_I915_G +#define PCI_CHIP_I915_G		   0x2582 +#define PCI_CHIP_I915_G_BRIDGE	   0x2580 +#endif + +#ifndef PCI_CHIP_I915_GM +#define PCI_CHIP_I915_GM	   0x2592 +#define PCI_CHIP_I915_GM_BRIDGE	   0x2590 +#endif + +#ifndef PCI_CHIP_E7221_G +#define PCI_CHIP_E7221_G	   0x258A +/* Same as I915_G_BRIDGE */ +#define PCI_CHIP_E7221_G_BRIDGE	   0x2580 +#endif + +#ifndef PCI_CHIP_I945_G +#define PCI_CHIP_I945_G        0x2772 +#define PCI_CHIP_I945_G_BRIDGE 0x2770 +#endif + +#ifndef PCI_CHIP_I945_GM +#define PCI_CHIP_I945_GM        0x27A2 +#define PCI_CHIP_I945_GM_BRIDGE 0x27A0 +#endif + +#define IS_I810(pI810) (pI810->Chipset == PCI_CHIP_I810 ||	\ +			pI810->Chipset == PCI_CHIP_I810_DC100 || \ +			pI810->Chipset == PCI_CHIP_I810_E) +#define IS_I815(pI810) (pI810->Chipset == PCI_CHIP_I815) +#define IS_I830(pI810) (pI810->Chipset == PCI_CHIP_I830_M) +#define IS_845G(pI810) (pI810->Chipset == PCI_CHIP_845_G) +#define IS_I85X(pI810)  (pI810->Chipset == PCI_CHIP_I855_GM) +#define IS_I852(pI810)  (pI810->Chipset == PCI_CHIP_I855_GM && (pI810->variant == I852_GM || pI810->variant == I852_GME)) +#define IS_I855(pI810)  (pI810->Chipset == PCI_CHIP_I855_GM && (pI810->variant == I855_GM || pI810->variant == I855_GME)) +#define IS_I865G(pI810) (pI810->Chipset == PCI_CHIP_I865_G) + +#define IS_I915G(pI810) (pI810->Chipset == PCI_CHIP_I915_G || pI810->Chipset == PCI_CHIP_E7221_G) +#define IS_I915GM(pI810) (pI810->Chipset == PCI_CHIP_I915_GM) +#define IS_I945G(pI810) (pI810->Chipset == PCI_CHIP_I945_G) +#define IS_I945GM(pI810) (pI810->Chipset == PCI_CHIP_I945_GM) +#define IS_I9XX(pI810) (IS_I915G(pI810) || IS_I915GM(pI810) || IS_I945G(pI810) || IS_I945GM(pI810)) + +#define IS_MOBILE(pI810) (IS_I830(pI810) || IS_I85X(pI810) || IS_I915GM(pI810) || IS_I945GM(pI810)) + +#define I830_GMCH_CTRL		0x52 + + +#define I830_GMCH_GMS_MASK			0x70 +#define I830_GMCH_GMS_DISABLED		0x00 +#define I830_GMCH_GMS_LOCAL			0x10 +#define I830_GMCH_GMS_STOLEN_512	0x20 +#define I830_GMCH_GMS_STOLEN_1024	0x30 +#define I830_GMCH_GMS_STOLEN_8192	0x40 + +#define I855_GMCH_GMS_MASK			(0x7 << 4) +#define I855_GMCH_GMS_DISABLED			0x00 +#define I855_GMCH_GMS_STOLEN_1M			(0x1 << 4) +#define I855_GMCH_GMS_STOLEN_4M			(0x2 << 4) +#define I855_GMCH_GMS_STOLEN_8M			(0x3 << 4) +#define I855_GMCH_GMS_STOLEN_16M		(0x4 << 4) +#define I855_GMCH_GMS_STOLEN_32M		(0x5 << 4) +#define I915G_GMCH_GMS_STOLEN_48M		(0x6 << 4) +#define I915G_GMCH_GMS_STOLEN_64M		(0x7 << 4) + +typedef unsigned char Bool; +#define TRUE 1 +#define FALSE 0 + +#define PIPE_NONE	0<<0 +#define PIPE_CRT	1<<0 +#define PIPE_TV		1<<1 +#define PIPE_DFP	1<<2 +#define PIPE_LFP	1<<3 +#define PIPE_CRT2	1<<4 +#define PIPE_TV2	1<<5 +#define PIPE_DFP2	1<<6 +#define PIPE_LFP2	1<<7 + +typedef struct _I830MemPool *I830MemPoolPtr; +typedef struct _I830MemRange *I830MemRangePtr; +typedef struct _I830MemRange { +   long Start; +   long End; +   long Size; +   unsigned long Physical; +   unsigned long Offset;		/* Offset of AGP-allocated portion */ +   unsigned long Alignment; +   drm_handle_t Key; +   unsigned long Pitch; // add pitch +   I830MemPoolPtr Pool; +} I830MemRange; + +typedef struct _I830MemPool { +   I830MemRange Total; +   I830MemRange Free; +   I830MemRange Fixed; +   I830MemRange Allocated; +} I830MemPool; + +typedef struct { +   int tail_mask; +   I830MemRange mem; +   unsigned char *virtual_start; +   int head; +   int tail; +   int space; +} I830RingBuffer; + +typedef struct _I830Rec { +   unsigned char *MMIOBase; +   unsigned char *FbBase; +   int cpp; + +   unsigned int bios_version; + +   /* These are set in PreInit and never changed. */ +   long FbMapSize; +   long TotalVideoRam; +   I830MemRange StolenMemory;		/* pre-allocated memory */ +   long BIOSMemorySize;			/* min stolen pool size */ +   int BIOSMemSizeLoc; + +   /* These change according to what has been allocated. */ +   long FreeMemory; +   I830MemRange MemoryAperture; +   I830MemPool StolenPool; +   long allocatedMemory; + +   /* Regions allocated either from the above pools, or from agpgart. */ +   /* for single and dual head configurations */ +   I830MemRange FrontBuffer; +   I830MemRange FrontBuffer2; +   I830MemRange Scratch; +   I830MemRange Scratch2; + +   I830RingBuffer *LpRing; + +   I830MemRange BackBuffer; +   I830MemRange DepthBuffer; +   I830MemRange TexMem; +   int TexGranularity; +   I830MemRange ContextMem; +   int drmMinor; +   Bool have3DWindows; + +   Bool NeedRingBufferLow; +   Bool allowPageFlip; +   Bool disableTiling; + +   int Chipset; +   unsigned long LinearAddr; +   unsigned long MMIOAddr; + +   drmSize           registerSize;     /**< \brief MMIO register map size */ +   drm_handle_t         registerHandle;   /**< \brief MMIO register map handle */ +  //   IOADDRESS ioBase; +   int               irq;              /**< \brief IRQ number */ +   int GttBound; + +   drm_handle_t ring_map; +   unsigned int Fence[8]; + +} I830Rec; + +/* + * 12288 is set as the maximum, chosen because it is enough for + * 1920x1440@32bpp with a 2048 pixel line pitch with some to spare. + */ +#define I830_MAXIMUM_VBIOS_MEM		12288 +#define I830_DEFAULT_VIDEOMEM_2D	(MB(32) / 1024) +#define I830_DEFAULT_VIDEOMEM_3D	(MB(64) / 1024) + +/* Flags for memory allocation function */ +#define FROM_ANYWHERE			0x00000000 +#define FROM_POOL_ONLY			0x00000001 +#define FROM_NEW_ONLY			0x00000002 +#define FROM_MASK			0x0000000f + +#define ALLOCATE_AT_TOP			0x00000010 +#define ALLOCATE_AT_BOTTOM		0x00000020 +#define FORCE_GAPS			0x00000040 + +#define NEED_PHYSICAL_ADDR		0x00000100 +#define ALIGN_BOTH_ENDS			0x00000200 +#define FORCE_LOW			0x00000400 + +#define ALLOC_NO_TILING			0x00001000 +#define ALLOC_INITIAL			0x00002000 + +#define ALLOCATE_DRY_RUN		0x80000000 + +/* Chipset registers for VIDEO BIOS memory RW access */ +#define _855_DRAM_RW_CONTROL 0x58 +#define _845_DRAM_RW_CONTROL 0x90 +#define DRAM_WRITE    0x33330000 + +#define KB(x) ((x) * 1024) +#define MB(x) ((x) * KB(1024)) + +#define GTT_PAGE_SIZE			KB(4) +#define ROUND_TO(x, y)			(((x) + (y) - 1) / (y) * (y)) +#define ROUND_DOWN_TO(x, y)		((x) / (y) * (y)) +#define ROUND_TO_PAGE(x)		ROUND_TO((x), GTT_PAGE_SIZE) +#define ROUND_TO_MB(x)			ROUND_TO((x), MB(1)) +#define PRIMARY_RINGBUFFER_SIZE		KB(128) + + +/* Ring buffer registers, p277, overview p19 + */ +#define LP_RING     0x2030 +#define HP_RING     0x2040 + +#define RING_TAIL      0x00 +#define TAIL_ADDR           0x000FFFF8 +#define I830_TAIL_MASK	    0x001FFFF8 + +#define RING_HEAD      0x04 +#define HEAD_WRAP_COUNT     0xFFE00000 +#define HEAD_WRAP_ONE       0x00200000 +#define HEAD_ADDR           0x001FFFFC +#define I830_HEAD_MASK      0x001FFFFC + +#define RING_START     0x08 +#define START_ADDR          0x03FFFFF8 +#define I830_RING_START_MASK	0xFFFFF000 + +#define RING_LEN       0x0C +#define RING_NR_PAGES       0x001FF000  +#define I830_RING_NR_PAGES	0x001FF000 +#define RING_REPORT_MASK    0x00000006 +#define RING_REPORT_64K     0x00000002 +#define RING_REPORT_128K    0x00000004 +#define RING_NO_REPORT      0x00000000 +#define RING_VALID_MASK     0x00000001 +#define RING_VALID          0x00000001 +#define RING_INVALID        0x00000000 + + +/* Fence/Tiling ranges [0..7] + */ +#define FENCE            0x2000 +#define FENCE_NR         8 + +#define I915G_FENCE_START_MASK	0x0ff00000 + +#define I830_FENCE_START_MASK	0x07f80000 + +#define FENCE_START_MASK    0x03F80000 +#define FENCE_X_MAJOR       0x00000000 +#define FENCE_Y_MAJOR       0x00001000 +#define FENCE_SIZE_MASK     0x00000700 +#define FENCE_SIZE_512K     0x00000000 +#define FENCE_SIZE_1M       0x00000100 +#define FENCE_SIZE_2M       0x00000200 +#define FENCE_SIZE_4M       0x00000300 +#define FENCE_SIZE_8M       0x00000400 +#define FENCE_SIZE_16M      0x00000500 +#define FENCE_SIZE_32M      0x00000600 +#define FENCE_SIZE_64M	    0x00000700 +#define I915G_FENCE_SIZE_1M       0x00000000 +#define I915G_FENCE_SIZE_2M       0x00000100 +#define I915G_FENCE_SIZE_4M       0x00000200 +#define I915G_FENCE_SIZE_8M       0x00000300 +#define I915G_FENCE_SIZE_16M      0x00000400 +#define I915G_FENCE_SIZE_32M      0x00000500 +#define I915G_FENCE_SIZE_64M	0x00000600 +#define I915G_FENCE_SIZE_128M	0x00000700 +#define FENCE_PITCH_1       0x00000000 +#define FENCE_PITCH_2       0x00000010 +#define FENCE_PITCH_4       0x00000020 +#define FENCE_PITCH_8       0x00000030 +#define FENCE_PITCH_16      0x00000040 +#define FENCE_PITCH_32      0x00000050 +#define FENCE_PITCH_64	    0x00000060 +#define FENCE_VALID         0x00000001 + +#include <mmio.h> + +#  define MMIO_IN8(base, offset) \ +	*(volatile unsigned char *)(((unsigned char*)(base)) + (offset)) +#  define MMIO_IN32(base, offset) \ +	read_MMIO_LE32(base, offset) +#  define MMIO_OUT8(base, offset, val) \ +	*(volatile unsigned char *)(((unsigned char*)(base)) + (offset)) = (val) +#  define MMIO_OUT32(base, offset, val) \ +	*(volatile unsigned int *)(void *)(((unsigned char*)(base)) + (offset)) = CPU_TO_LE32(val) + + +				/* Memory mapped register access macros */ +#define INREG8(addr)        MMIO_IN8(MMIO, addr) +#define INREG(addr)         MMIO_IN32(MMIO, addr) +#define OUTREG8(addr, val)  MMIO_OUT8(MMIO, addr, val) +#define OUTREG(addr, val)   MMIO_OUT32(MMIO, addr, val) + +#define DSPABASE		0x70184 + +#endif diff --git a/src/mesa/drivers/dri/i915tex/server/intel_dri.c b/src/mesa/drivers/dri/i915tex/server/intel_dri.c new file mode 100644 index 0000000000..169fdbece3 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/server/intel_dri.c @@ -0,0 +1,1282 @@ +/** + * \file server/intel_dri.c + * \brief File to perform the device-specific initialization tasks typically + * done in the X server. + * + * Here they are converted to run in the client (or perhaps a standalone + * process), and to work with the frame buffer device rather than the X + * server infrastructure. + *  + * Copyright (C) 2006 Dave Airlie (airlied@linux.ie) + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the + "Software"), to deal in the Software without restriction, including + without limitation the rights to use, copy, modify, merge, publish, + distribute, sub license, and/or sell copies of the Software, and to + permit persons to whom the Software is furnished to do so, subject to + the following conditions: +  + The above copyright notice and this permission notice (including the + next paragraph) shall be included in all copies or substantial portions + of the Software. +  + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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. +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> + +#include "driver.h" +#include "drm.h" + +#include "intel.h" +#include "i830_dri.h" + +#include "memops.h" +#include "pciaccess.h" + +static size_t drm_page_size; +static int nextTile = 0; +#define xf86DrvMsg(...) do {} while(0) + +static const int pitches[] = { +  128 * 8, +  128 * 16, +  128 * 32, +  128 * 64, +  0 +}; + +static Bool I830DRIDoMappings(DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea); + +static unsigned long +GetBestTileAlignment(unsigned long size) +{ +   unsigned long i; + +   for (i = KB(512); i < size; i <<= 1) +      ; + +   if (i > MB(64)) +      i = MB(64); + +   return i; +} + +static void SetFenceRegs(const DRIDriverContext *ctx, I830Rec *pI830) +{ +  int i; +  unsigned char *MMIO = ctx->MMIOAddress; + +  for (i = 0; i < 8; i++) { +    OUTREG(FENCE + i * 4, pI830->Fence[i]); +    //    if (I810_DEBUG & DEBUG_VERBOSE_VGA) +    fprintf(stderr,"Fence Register : %x\n", pI830->Fence[i]); +  } +} + +/* Tiled memory is good... really, really good... + * + * Need to make it less likely that we miss out on this - probably + * need to move the frontbuffer away from the 'guarenteed' alignment + * of the first memory segment, or perhaps allocate a discontigous + * framebuffer to get more alignment 'sweet spots'. + */ +static void +SetFence(const DRIDriverContext *ctx, I830Rec *pI830, +	 int nr, unsigned int start, unsigned int pitch, +         unsigned int size) +{ +   unsigned int val; +   unsigned int fence_mask = 0; +   unsigned int fence_pitch; + +   if (nr < 0 || nr > 7) { +      fprintf(stderr, +		 "SetFence: fence %d out of range\n",nr); +      return; +   } + +   pI830->Fence[nr] = 0; + +   if (IS_I9XX(pI830)) +   	fence_mask = ~I915G_FENCE_START_MASK; +   else +   	fence_mask = ~I830_FENCE_START_MASK; + +   if (start & fence_mask) { +      fprintf(stderr, +		 "SetFence: %d: start (0x%08x) is not %s aligned\n", +		 nr, start, (IS_I9XX(pI830)) ? "1MB" : "512k"); +      return; +   } + +   if (start % size) { +      fprintf(stderr, +		 "SetFence: %d: start (0x%08x) is not size (%dk) aligned\n", +		 nr, start, size / 1024); +      return; +   } + +   if (pitch & 127) { +      fprintf(stderr, +		 "SetFence: %d: pitch (%d) not a multiple of 128 bytes\n", +		 nr, pitch); +      return; +   } + +   val = (start | FENCE_X_MAJOR | FENCE_VALID); + +   if (IS_I9XX(pI830)) { +   	switch (size) { +	   case MB(1): +      		val |= I915G_FENCE_SIZE_1M; +      		break; +   	   case MB(2): +      		val |= I915G_FENCE_SIZE_2M; +      		break; +   	   case MB(4): +      		val |= I915G_FENCE_SIZE_4M; +      		break; +   	   case MB(8): +      		val |= I915G_FENCE_SIZE_8M; +      		break; +   	   case MB(16): +      		val |= I915G_FENCE_SIZE_16M; +      		break; +   	   case MB(32): +      		val |= I915G_FENCE_SIZE_32M; +      		break; +   	   case MB(64): +      		val |= I915G_FENCE_SIZE_64M; +      		break; +   	   default: +      		fprintf(stderr, +		 "SetFence: %d: illegal size (%d kByte)\n", nr, size / 1024); +      		return; +   	} +    } else { +   	switch (size) { +	   case KB(512): +      		val |= FENCE_SIZE_512K; +      		break; +	   case MB(1): +      		val |= FENCE_SIZE_1M; +      		break; +   	   case MB(2): +      		val |= FENCE_SIZE_2M; +      		break; +   	   case MB(4): +      		val |= FENCE_SIZE_4M; +      		break; +   	   case MB(8): +      		val |= FENCE_SIZE_8M; +      		break; +   	   case MB(16): +      		val |= FENCE_SIZE_16M; +      		break; +   	   case MB(32): +      		val |= FENCE_SIZE_32M; +      		break; +   	   case MB(64): +      		val |= FENCE_SIZE_64M; +      		break; +   	   default: +      		fprintf(stderr, +		 "SetFence: %d: illegal size (%d kByte)\n", nr, size / 1024); +      		return; +   	} +   } + +   if (IS_I9XX(pI830)) +	fence_pitch = pitch / 512; +   else +	fence_pitch = pitch / 128; + +   switch (fence_pitch) { +   case 1: +      val |= FENCE_PITCH_1; +      break; +   case 2: +      val |= FENCE_PITCH_2; +      break; +   case 4: +      val |= FENCE_PITCH_4; +      break; +   case 8: +      val |= FENCE_PITCH_8; +      break; +   case 16: +      val |= FENCE_PITCH_16; +      break; +   case 32: +      val |= FENCE_PITCH_32; +      break; +   case 64: +      val |= FENCE_PITCH_64; +      break; +   default: +      fprintf(stderr, +		 "SetFence: %d: illegal pitch (%d)\n", nr, pitch); +      return; +   } + +   pI830->Fence[nr] = val; +} + +static Bool +MakeTiles(const DRIDriverContext *ctx, I830Rec *pI830, I830MemRange *pMem) +{ +   int pitch, ntiles, i; + +   pitch = pMem->Pitch * ctx->cpp; +   /* +    * Simply try to break the region up into at most four pieces of size +    * equal to the alignment. +    */ +   ntiles = ROUND_TO(pMem->Size, pMem->Alignment) / pMem->Alignment; +   if (ntiles >= 4) { +      return FALSE; +   } + +   for (i = 0; i < ntiles; i++, nextTile++) { +     SetFence(ctx, pI830, nextTile, pMem->Start + i * pMem->Alignment, +	       pitch, pMem->Alignment); +   } +   return TRUE; +} + +static void I830SetupMemoryTiling(const DRIDriverContext *ctx, I830Rec *pI830) +{ +  int i; + +  /* Clear out */ +  for (i = 0; i < 8; i++) +    pI830->Fence[i] = 0; +   +  nextTile = 0; + +  if (pI830->BackBuffer.Alignment >= KB(512)) { +    if (MakeTiles(ctx, pI830, &(pI830->BackBuffer))) { +      fprintf(stderr, +		 "Activating tiled memory for the back buffer.\n"); +    } else { +      fprintf(stderr, +		 "MakeTiles failed for the back buffer.\n"); +      pI830->allowPageFlip = FALSE; +    } +  } +   +  if (pI830->DepthBuffer.Alignment >= KB(512)) { +    if (MakeTiles(ctx, pI830, &(pI830->DepthBuffer))) { +      fprintf(stderr, +		 "Activating tiled memory for the depth buffer.\n"); +    } else { +      fprintf(stderr, +		 "MakeTiles failed for the depth buffer.\n"); +    } +  } + +  return; +} + +static int I830DetectMemory(const DRIDriverContext *ctx, I830Rec *pI830) +{ +  struct pci_device host_bridge; +  uint32_t gmch_ctrl; +  int memsize = 0; +  int range; + +  memset(&host_bridge, 0, sizeof(host_bridge)); + +  pci_device_cfg_read_u32(&host_bridge, &gmch_ctrl, I830_GMCH_CTRL); +   +  /* We need to reduce the stolen size, by the GTT and the popup. +   * The GTT varying according the the FbMapSize and the popup is 4KB */ +  range = (ctx->shared.fbSize / (1024*1024)) + 4; + +   if (IS_I85X(pI830) || IS_I865G(pI830) || IS_I9XX(pI830)) { +      switch (gmch_ctrl & I830_GMCH_GMS_MASK) { +      case I855_GMCH_GMS_STOLEN_1M: +	 memsize = MB(1) - KB(range); +	 break; +      case I855_GMCH_GMS_STOLEN_4M: +	 memsize = MB(4) - KB(range); +	 break; +      case I855_GMCH_GMS_STOLEN_8M: +	 memsize = MB(8) - KB(range); +	 break; +      case I855_GMCH_GMS_STOLEN_16M: +	 memsize = MB(16) - KB(range); +	 break; +      case I855_GMCH_GMS_STOLEN_32M: +	 memsize = MB(32) - KB(range); +	 break; +      case I915G_GMCH_GMS_STOLEN_48M: +	 if (IS_I9XX(pI830)) +	    memsize = MB(48) - KB(range); +	 break; +      case I915G_GMCH_GMS_STOLEN_64M: +	 if (IS_I9XX(pI830)) +	    memsize = MB(64) - KB(range); +	 break; +      } +   } else { +      switch (gmch_ctrl & I830_GMCH_GMS_MASK) { +      case I830_GMCH_GMS_STOLEN_512: +	 memsize = KB(512) - KB(range); +	 break; +      case I830_GMCH_GMS_STOLEN_1024: +	 memsize = MB(1) - KB(range); +	 break; +      case I830_GMCH_GMS_STOLEN_8192: +	 memsize = MB(8) - KB(range); +	 break; +      case I830_GMCH_GMS_LOCAL: +	 memsize = 0; +	 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, +		    "Local memory found, but won't be used.\n"); +	 break; +      } +   } +   if (memsize > 0) { +     fprintf(stderr, +		 "detected %d kB stolen memory.\n", memsize / 1024); +   } else { +     fprintf(stderr, +		 "no video memory detected.\n"); +   } +   return memsize; +} + +static int AgpInit(const DRIDriverContext *ctx, I830Rec *info) +{ +  unsigned long mode = 0x4; + +  if (drmAgpAcquire(ctx->drmFD) < 0) { +    fprintf(stderr, "[gart] AGP not available\n"); +    return 0; +  } +   +  if (drmAgpEnable(ctx->drmFD, mode) < 0) { +    fprintf(stderr, "[gart] AGP not enabled\n"); +    drmAgpRelease(ctx->drmFD); +    return 0; +  } +  else +    fprintf(stderr, "[gart] AGP enabled at %dx\n", ctx->agpmode); + +  return 1; +} + +/* + * Allocate memory from the given pool.  Grow the pool if needed and if + * possible. + */ +static unsigned long +AllocFromPool(const DRIDriverContext *ctx, I830Rec *pI830,  +	      I830MemRange *result, I830MemPool *pool, +	      long size, unsigned long alignment, int flags) +{ +   long needed, start, end; + +   if (!result || !pool || !size) +      return 0; + +   /* Calculate how much space is needed. */ +   if (alignment <= GTT_PAGE_SIZE) +      needed = size; +   else { +	 start = ROUND_TO(pool->Free.Start, alignment); +	 end = ROUND_TO(start + size, alignment); +	 needed = end - pool->Free.Start; +   } +   if (needed > pool->Free.Size) { +     return 0; +   } + +   result->Start = ROUND_TO(pool->Free.Start, alignment); +   pool->Free.Start += needed; +   result->End = pool->Free.Start; + +   pool->Free.Size = pool->Free.End - pool->Free.Start; +   result->Size = result->End - result->Start; +   result->Pool = pool; +   result->Alignment = alignment; +   return needed; +} + +static unsigned long AllocFromAGP(const DRIDriverContext *ctx, I830Rec *pI830, long size, unsigned long alignment, I830MemRange  *result) +{ +   unsigned long start, end; +   unsigned long newApStart, newApEnd; +   int ret; +   if (!result || !size) +      return 0; +    +   if (!alignment) +     alignment = 4; + +   start = ROUND_TO(pI830->MemoryAperture.Start, alignment); +   end = ROUND_TO(start + size, alignment); +   newApStart = end; +   newApEnd = pI830->MemoryAperture.End; + +   ret=drmAgpAlloc(ctx->drmFD, size, 0, &(result->Physical), (drm_handle_t *)&(result->Key)); +    +   if (ret) +   { +     fprintf(stderr,"drmAgpAlloc failed %d\n", ret); +     return 0; +   } +   pI830->allocatedMemory += size; +   pI830->MemoryAperture.Start = newApStart; +   pI830->MemoryAperture.End = newApEnd; +   pI830->MemoryAperture.Size = newApEnd - newApStart; +   //   pI830->FreeMemory -= size; +   result->Start = start; +   result->End = start + size; +   result->Size = size; +   result->Offset = start; +   result->Alignment = alignment; +   result->Pool = NULL; +   +   return size; +} + +unsigned long +I830AllocVidMem(const DRIDriverContext *ctx, I830Rec *pI830, I830MemRange *result, I830MemPool *pool, long size, unsigned long alignment, int flags) +{ +  int ret; + +  if (!result) +    return 0; + +   /* Make sure these are initialised. */ +   result->Size = 0; +   result->Key = -1; + +   if (!size) { +      return 0; +   } + +   if (pool->Free.Size < size) +     return AllocFromAGP(ctx, pI830, size, alignment, result); +   else +   { +     ret = AllocFromPool(ctx, pI830, result, pool, size, alignment, flags); + +     if (ret==0) +       return AllocFromAGP(ctx, pI830, size, alignment, result); +     return ret; +   } +} + +static Bool BindAgpRange(const DRIDriverContext *ctx, I830MemRange *mem) +{ +  if (!mem) +    return FALSE; +   +  if (mem->Key == -1) +    return TRUE; + +  return !drmAgpBind(ctx->drmFD, mem->Key, mem->Offset); +} + +/* simple memory allocation routines needed */ +/* put ring buffer in low memory */ +/* need to allocate front, back, depth buffers aligned correctly, +   allocate ring buffer,  +*/ + +/* */ +static Bool +I830AllocateMemory(const DRIDriverContext *ctx, I830Rec *pI830) +{ +  unsigned long size, ret; +  unsigned long lines, lineSize, align; + +  /* allocate ring buffer */ +  memset(pI830->LpRing, 0, sizeof(I830RingBuffer)); +  pI830->LpRing->mem.Key = -1; + +  size = PRIMARY_RINGBUFFER_SIZE; +   +  ret = I830AllocVidMem(ctx, pI830, &pI830->LpRing->mem, &pI830->StolenPool, size, 0x1000, 0); +   +  if (ret != size) +  { +    fprintf(stderr,"unable to allocate ring buffer %ld\n", ret); +    return FALSE; +  } + +  pI830->LpRing->tail_mask = pI830->LpRing->mem.Size - 1; + +   +  /* allocate front buffer */ +  memset(&(pI830->FrontBuffer), 0, sizeof(pI830->FrontBuffer)); +  pI830->FrontBuffer.Key = -1; +  pI830->FrontBuffer.Pitch = ctx->shared.virtualWidth; + +  align = KB(512);   + +  lineSize = ctx->shared.virtualWidth * ctx->cpp; +  lines = (ctx->shared.virtualHeight + 15) / 16 * 16; +  size = lineSize * lines; +  size = ROUND_TO_PAGE(size); + +  align = GetBestTileAlignment(size); + +  ret = I830AllocVidMem(ctx, pI830, &pI830->FrontBuffer, &pI830->StolenPool, size, align, 0); +  if (ret < size) +  { +    fprintf(stderr,"unable to allocate front buffer %ld\n", ret); +    return FALSE; +  } + +  memset(&(pI830->BackBuffer), 0, sizeof(pI830->BackBuffer)); +  pI830->BackBuffer.Key = -1; +  pI830->BackBuffer.Pitch = ctx->shared.virtualWidth; + +  ret = I830AllocVidMem(ctx, pI830, &pI830->BackBuffer, &pI830->StolenPool, size, align, 0); +  if (ret < size) +  { +    fprintf(stderr,"unable to allocate back buffer %ld\n", ret); +    return FALSE; +  } +   +  memset(&(pI830->DepthBuffer), 0, sizeof(pI830->DepthBuffer)); +  pI830->DepthBuffer.Key = -1; +  pI830->DepthBuffer.Pitch = ctx->shared.virtualWidth; + +  ret = I830AllocVidMem(ctx, pI830, &pI830->DepthBuffer, &pI830->StolenPool, size, align, 0); +  if (ret < size) +  { +    fprintf(stderr,"unable to allocate depth buffer %ld\n", ret); +    return FALSE; +  } + +  memset(&(pI830->ContextMem), 0, sizeof(pI830->ContextMem)); +  pI830->ContextMem.Key = -1; +  size = KB(32); + +  ret = I830AllocVidMem(ctx, pI830, &pI830->ContextMem, &pI830->StolenPool, size, align, 0); +  if (ret < size) +  { +    fprintf(stderr,"unable to allocate context buffer %ld\n", ret); +    return FALSE; +  } +   +  memset(&(pI830->TexMem), 0, sizeof(pI830->TexMem)); +  pI830->TexMem.Key = -1; + +  size = 32768 * 1024; +  ret = AllocFromAGP(ctx, pI830, size, align, &pI830->TexMem); +  if (ret < size) +  { +    fprintf(stderr,"unable to allocate texture memory %ld\n", ret); +    return FALSE; +  } + +  return TRUE; +} + +static Bool +I830BindMemory(const DRIDriverContext *ctx, I830Rec *pI830) +{ +  if (!BindAgpRange(ctx, &pI830->LpRing->mem)) +    return FALSE; +  if (!BindAgpRange(ctx, &pI830->FrontBuffer)) +    return FALSE; +  if (!BindAgpRange(ctx, &pI830->BackBuffer)) +    return FALSE; +  if (!BindAgpRange(ctx, &pI830->DepthBuffer)) +    return FALSE; +  if (!BindAgpRange(ctx, &pI830->ContextMem)) +    return FALSE; +  if (!BindAgpRange(ctx, &pI830->TexMem)) +    return FALSE; + +  return TRUE; +} + +static Bool +I830CleanupDma(const DRIDriverContext *ctx) +{ +   drmI830Init info; + +   memset(&info, 0, sizeof(drmI830Init)); +   info.func = I830_CLEANUP_DMA; + +   if (drmCommandWrite(ctx->drmFD, DRM_I830_INIT, +		       &info, sizeof(drmI830Init))) { +     fprintf(stderr, "I830 Dma Cleanup Failed\n"); +      return FALSE; +   } + +   return TRUE; +} + +static Bool +I830InitDma(const DRIDriverContext *ctx, I830Rec *pI830) +{ +   I830RingBuffer *ring = pI830->LpRing; +   drmI830Init info; + +   memset(&info, 0, sizeof(drmI830Init)); +   info.func = I830_INIT_DMA; + +   info.ring_start = ring->mem.Start + pI830->LinearAddr; +   info.ring_end = ring->mem.End + pI830->LinearAddr; +   info.ring_size = ring->mem.Size; + +   info.mmio_offset = (unsigned int)ctx->MMIOStart; + +   info.sarea_priv_offset = sizeof(drm_sarea_t); + +   info.front_offset = pI830->FrontBuffer.Start; +   info.back_offset = pI830->BackBuffer.Start; +   info.depth_offset = pI830->DepthBuffer.Start; +   info.w = ctx->shared.virtualWidth; +   info.h = ctx->shared.virtualHeight; +   info.pitch = ctx->shared.virtualWidth; +   info.back_pitch = pI830->BackBuffer.Pitch; +   info.depth_pitch = pI830->DepthBuffer.Pitch; +   info.cpp = ctx->cpp; + +   if (drmCommandWrite(ctx->drmFD, DRM_I830_INIT, +		       &info, sizeof(drmI830Init))) { +      fprintf(stderr, +		 "I830 Dma Initialization Failed\n"); +      return FALSE; +   } + +   return TRUE; +} + +static int I830CheckDRMVersion( const DRIDriverContext *ctx, +				  I830Rec *pI830 ) +{ +   drmVersionPtr  version; + +   version = drmGetVersion(ctx->drmFD); + +   if (version) { +     int req_minor, req_patch; + +     req_minor = 4; +     req_patch = 0;	 + +     if (version->version_major != 1 || +	 version->version_minor < req_minor || +	 (version->version_minor == req_minor &&  +	  version->version_patchlevel < req_patch)) { +       /* Incompatible drm version */ +       fprintf(stderr, +	       "[dri] I830DRIScreenInit failed because of a version " +	       "mismatch.\n" +	       "[dri] i915.o kernel module version is %d.%d.%d " +	       "but version 1.%d.%d or newer is needed.\n" +	       "[dri] Disabling DRI.\n", +	       version->version_major, +	       version->version_minor, +	       version->version_patchlevel, +	       req_minor, +	       req_patch); +       drmFreeVersion(version); +       return 0; +     } +      +     pI830->drmMinor = version->version_minor; +     drmFreeVersion(version); +   } +   return 1; +} + +static void +I830SetRingRegs(const DRIDriverContext *ctx, I830Rec *pI830) +{ +  unsigned int itemp; +  unsigned char *MMIO = ctx->MMIOAddress; + +   OUTREG(LP_RING + RING_LEN, 0); +   OUTREG(LP_RING + RING_TAIL, 0); +   OUTREG(LP_RING + RING_HEAD, 0); + +   if ((long)(pI830->LpRing->mem.Start & I830_RING_START_MASK) != +       pI830->LpRing->mem.Start) { +      fprintf(stderr, +		 "I830SetRingRegs: Ring buffer start (%lx) violates its " +		 "mask (%x)\n", pI830->LpRing->mem.Start, I830_RING_START_MASK); +   } +   /* Don't care about the old value.  Reserved bits must be zero anyway. */ +   itemp = pI830->LpRing->mem.Start & I830_RING_START_MASK; +   OUTREG(LP_RING + RING_START, itemp); + +   if (((pI830->LpRing->mem.Size - 4096) & I830_RING_NR_PAGES) != +       pI830->LpRing->mem.Size - 4096) { +      fprintf(stderr, +		 "I830SetRingRegs: Ring buffer size - 4096 (%lx) violates its " +		 "mask (%x)\n", pI830->LpRing->mem.Size - 4096, +		 I830_RING_NR_PAGES); +   } +   /* Don't care about the old value.  Reserved bits must be zero anyway. */ +   itemp = (pI830->LpRing->mem.Size - 4096) & I830_RING_NR_PAGES; +   itemp |= (RING_NO_REPORT | RING_VALID); +   OUTREG(LP_RING + RING_LEN, itemp); + +   pI830->LpRing->head = INREG(LP_RING + RING_HEAD) & I830_HEAD_MASK; +   pI830->LpRing->tail = INREG(LP_RING + RING_TAIL); +   pI830->LpRing->space = pI830->LpRing->head - (pI830->LpRing->tail + 8); +   if (pI830->LpRing->space < 0) +      pI830->LpRing->space += pI830->LpRing->mem.Size; + +   SetFenceRegs(ctx, pI830); +    +   /* RESET THE DISPLAY PIPE TO POINT TO THE FRONTBUFFER - hacky +      hacky hacky */ +   OUTREG(DSPABASE, pI830->FrontBuffer.Start + pI830->LinearAddr); + +} + +static Bool +I830SetParam(const DRIDriverContext *ctx, int param, int value) +{ +   drmI830SetParam sp; + +   memset(&sp, 0, sizeof(sp)); +   sp.param = param; +   sp.value = value; + +   if (drmCommandWrite(ctx->drmFD, DRM_I830_SETPARAM, &sp, sizeof(sp))) { +      fprintf(stderr, "I830 SetParam Failed\n"); +      return FALSE; +   } + +   return TRUE; +} + +static Bool +I830DRIMapScreenRegions(DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea) +{ +   fprintf(stderr, +              "[drm] Mapping front buffer\n"); + +   if (drmAddMap(ctx->drmFD, +                 (drm_handle_t)(sarea->front_offset + pI830->LinearAddr), +                 sarea->front_size, +                 DRM_FRAME_BUFFER,  /*DRM_AGP,*/ +                 0, +                 &sarea->front_handle) < 0) { +     fprintf(stderr, +	     "[drm] drmAddMap(front_handle) failed. Disabling DRI\n"); +      return FALSE; +   } +   ctx->shared.hFrameBuffer = sarea->front_handle; +   ctx->shared.fbSize = sarea->front_size; +   fprintf(stderr, "[drm] Front Buffer = 0x%08x\n", +	   sarea->front_handle); + +   if (drmAddMap(ctx->drmFD, +                 (drm_handle_t)(sarea->back_offset), +                 sarea->back_size, DRM_AGP, 0, +                 &sarea->back_handle) < 0) { +      fprintf(stderr, +                 "[drm] drmAddMap(back_handle) failed. Disabling DRI\n"); +      return FALSE; +   } +   fprintf(stderr, "[drm] Back Buffer = 0x%08x\n", +              sarea->back_handle); + +   if (drmAddMap(ctx->drmFD, +                 (drm_handle_t)sarea->depth_offset, +                 sarea->depth_size, DRM_AGP, 0, +                 &sarea->depth_handle) < 0) { +      fprintf(stderr, +                 "[drm] drmAddMap(depth_handle) failed. Disabling DRI\n"); +      return FALSE; +   } +   fprintf(stderr, "[drm] Depth Buffer = 0x%08x\n", +              sarea->depth_handle); + +   if (drmAddMap(ctx->drmFD, +		 (drm_handle_t)sarea->tex_offset, +		 sarea->tex_size, DRM_AGP, 0, +		 &sarea->tex_handle) < 0) { +      fprintf(stderr, +		 "[drm] drmAddMap(tex_handle) failed. Disabling DRI\n"); +      return FALSE; +   } +   fprintf(stderr, "[drm] textures = 0x%08x\n", +	      sarea->tex_handle); + +   return TRUE; +} + + +static void +I830DRIUnmapScreenRegions(const DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea) +{ +#if 1 +   if (sarea->front_handle) { +      drmRmMap(ctx->drmFD, sarea->front_handle); +      sarea->front_handle = 0; +   } +#endif +   if (sarea->back_handle) { +      drmRmMap(ctx->drmFD, sarea->back_handle); +      sarea->back_handle = 0; +   } +   if (sarea->depth_handle) { +      drmRmMap(ctx->drmFD, sarea->depth_handle); +      sarea->depth_handle = 0; +   } +   if (sarea->tex_handle) { +      drmRmMap(ctx->drmFD, sarea->tex_handle); +      sarea->tex_handle = 0; +   } +} + +static void +I830InitTextureHeap(const DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea) +{ +   /* Start up the simple memory manager for agp space */ +   drmI830MemInitHeap drmHeap; +   drmHeap.region = I830_MEM_REGION_AGP; +   drmHeap.start  = 0; +   drmHeap.size   = sarea->tex_size; +       +   if (drmCommandWrite(ctx->drmFD, DRM_I830_INIT_HEAP, +			  &drmHeap, sizeof(drmHeap))) { +      fprintf(stderr, +		    "[drm] Failed to initialized agp heap manager\n"); +   } else { +      fprintf(stderr, +		    "[drm] Initialized kernel agp heap manager, %d\n", +		    sarea->tex_size); + +      I830SetParam(ctx, I830_SETPARAM_TEX_LRU_LOG_GRANULARITY,  +		      sarea->log_tex_granularity); +   } +} + +static Bool +I830DRIDoMappings(DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea) +{ +  if (drmAddMap(ctx->drmFD, +		(drm_handle_t)pI830->LpRing->mem.Start, +		pI830->LpRing->mem.Size, DRM_AGP, 0, +		&pI830->ring_map) < 0) { +    fprintf(stderr, +	    "[drm] drmAddMap(ring_map) failed. Disabling DRI\n"); +    return FALSE; +  } +  fprintf(stderr, "[drm] ring buffer = 0x%08x\n", +	  pI830->ring_map); + +  if (I830InitDma(ctx, pI830) == FALSE) { +    return FALSE; +  } +   +   /* init to zero to be safe */ + +  I830DRIMapScreenRegions(ctx, pI830, sarea); +  I830InitTextureHeap(ctx, pI830, sarea); + +   if (ctx->pciDevice != PCI_CHIP_845_G && +       ctx->pciDevice != PCI_CHIP_I830_M) { +      I830SetParam(ctx, I830_SETPARAM_USE_MI_BATCHBUFFER_START, 1 ); +   } + +   /* Okay now initialize the dma engine */ +   { +      pI830->irq = drmGetInterruptFromBusID(ctx->drmFD, +					    ctx->pciBus, +					    ctx->pciDevice, +					    ctx->pciFunc); + +      if (drmCtlInstHandler(ctx->drmFD, pI830->irq)) { +	 fprintf(stderr, +		    "[drm] failure adding irq handler\n"); +	 pI830->irq = 0; +	 return FALSE; +      } +      else +	 fprintf(stderr, +		    "[drm] dma control initialized, using IRQ %d\n", +		    pI830->irq); +   } + +   fprintf(stderr, "[dri] visual configs initialized\n"); + +   return TRUE; +} + +static Bool +I830ClearScreen(DRIDriverContext *ctx, I830Rec *pI830, drmI830Sarea *sarea) +{ +  /* need to drmMap front and back buffers and zero them */ +  drmAddress map_addr; +  int ret; + +  ret = drmMap(ctx->drmFD, +	       sarea->front_handle, +	       sarea->front_size, +	       &map_addr); + +  if (ret) +  { +    fprintf(stderr, "Unable to map front buffer\n"); +    return FALSE; +  } + +  drimemsetio((char *)map_addr, +	      0, +	      sarea->front_size); +  drmUnmap(map_addr, sarea->front_size); + + +  ret = drmMap(ctx->drmFD, +	       sarea->back_handle, +	       sarea->back_size, +	       &map_addr); + +  if (ret) +  { +    fprintf(stderr, "Unable to map back buffer\n"); +    return FALSE; +  } + +  drimemsetio((char *)map_addr, +	      0, +	      sarea->back_size); +  drmUnmap(map_addr, sarea->back_size); + +  return TRUE; +} + +static Bool +I830ScreenInit(DRIDriverContext *ctx, I830Rec *pI830) +		   +{ +   I830DRIPtr pI830DRI; +   drmI830Sarea *pSAREAPriv; +   int err; +       +   drm_page_size = getpagesize();    + +   pI830->registerSize = ctx->MMIOSize; +   /* This is a hack for now.  We have to have more than a 4k page here +    * because of the size of the state.  However, the state should be +    * in a per-context mapping.  This will be added in the Mesa 3.5 port +    * of the I830 driver. +    */ +   ctx->shared.SAREASize = SAREA_MAX; + +   /* Note that drmOpen will try to load the kernel module, if needed. */ +   ctx->drmFD = drmOpen("i915", NULL ); +   if (ctx->drmFD < 0) { +      fprintf(stderr, "[drm] drmOpen failed\n"); +      return 0; +   } + +   if ((err = drmSetBusid(ctx->drmFD, ctx->pciBusID)) < 0) { +      fprintf(stderr, "[drm] drmSetBusid failed (%d, %s), %s\n", +	      ctx->drmFD, ctx->pciBusID, strerror(-err)); +      return 0; +   } + +   if (drmAddMap( ctx->drmFD, +		  0, +		  ctx->shared.SAREASize, +		  DRM_SHM, +		  DRM_CONTAINS_LOCK, +		  &ctx->shared.hSAREA) < 0) +   { +     fprintf(stderr, "[drm] drmAddMap failed\n"); +     return 0; +   } + +   fprintf(stderr, "[drm] added %d byte SAREA at 0x%08x\n", +	   ctx->shared.SAREASize, ctx->shared.hSAREA); +    +   if (drmMap( ctx->drmFD, +	       ctx->shared.hSAREA, +	       ctx->shared.SAREASize, +	       (drmAddressPtr)(&ctx->pSAREA)) < 0) +   { +      fprintf(stderr, "[drm] drmMap failed\n"); +      return 0; +    +   } +    +   memset(ctx->pSAREA, 0, ctx->shared.SAREASize); +   fprintf(stderr, "[drm] mapped SAREA 0x%08x to %p, size %d\n", +	   ctx->shared.hSAREA, ctx->pSAREA, ctx->shared.SAREASize); +    + +   if (drmAddMap(ctx->drmFD,  +		 ctx->MMIOStart, +		 ctx->MMIOSize, +		 DRM_REGISTERS,  +		 DRM_READ_ONLY,  +		 &pI830->registerHandle) < 0) { +      fprintf(stderr, "[drm] drmAddMap mmio failed\n");	 +      return 0; +   } +   fprintf(stderr, +	   "[drm] register handle = 0x%08x\n", pI830->registerHandle); + + +   if (!I830CheckDRMVersion(ctx, pI830)) { +     return FALSE; +   } + +   /* Create a 'server' context so we can grab the lock for +    * initialization ioctls. +    */ +   if ((err = drmCreateContext(ctx->drmFD, &ctx->serverContext)) != 0) { +      fprintf(stderr, "%s: drmCreateContext failed %d\n", __FUNCTION__, err); +      return 0; +   } + +   DRM_LOCK(ctx->drmFD, ctx->pSAREA, ctx->serverContext, 0);  + +   /* Initialize the SAREA private data structure */ +   pSAREAPriv = (drmI830Sarea *)(((char*)ctx->pSAREA) +  +				 sizeof(drm_sarea_t)); +   memset(pSAREAPriv, 0, sizeof(*pSAREAPriv)); + +   pI830->StolenMemory.Size = I830DetectMemory(ctx, pI830); +   pI830->StolenMemory.Start = 0; +   pI830->StolenMemory.End = pI830->StolenMemory.Size; + +   pI830->MemoryAperture.Start = pI830->StolenMemory.End; +   pI830->MemoryAperture.End = KB(40000); +   pI830->MemoryAperture.Size = pI830->MemoryAperture.End - pI830->MemoryAperture.Start; + +   pI830->StolenPool.Fixed = pI830->StolenMemory; +   pI830->StolenPool.Total = pI830->StolenMemory; +   pI830->StolenPool.Free = pI830->StolenPool.Total; +   pI830->FreeMemory = pI830->StolenPool.Total.Size; + +   if (!AgpInit(ctx, pI830)) +     return FALSE; + +   if (I830AllocateMemory(ctx, pI830) == FALSE) +   { +     return FALSE; +   } + +   if (I830BindMemory(ctx, pI830) == FALSE) +   { +     return FALSE; +   } + +   pSAREAPriv->front_offset = pI830->FrontBuffer.Start; +   pSAREAPriv->front_size = pI830->FrontBuffer.Size; +   pSAREAPriv->width = ctx->shared.virtualWidth; +   pSAREAPriv->height = ctx->shared.virtualHeight; +   pSAREAPriv->pitch = ctx->shared.virtualWidth; +   pSAREAPriv->virtualX = ctx->shared.virtualWidth; +   pSAREAPriv->virtualY = ctx->shared.virtualHeight; +   pSAREAPriv->back_offset = pI830->BackBuffer.Start; +   pSAREAPriv->back_size = pI830->BackBuffer.Size; +   pSAREAPriv->depth_offset = pI830->DepthBuffer.Start; +   pSAREAPriv->depth_size = pI830->DepthBuffer.Size; +   pSAREAPriv->tex_offset = pI830->TexMem.Start; +   pSAREAPriv->tex_size = pI830->TexMem.Size; +   pSAREAPriv->log_tex_granularity = pI830->TexGranularity; + +   ctx->driverClientMsg = malloc(sizeof(I830DRIRec)); +   ctx->driverClientMsgSize = sizeof(I830DRIRec); +   pI830DRI = (I830DRIPtr)ctx->driverClientMsg; +   pI830DRI->deviceID = pI830->Chipset; +   pI830DRI->regsSize = I830_REG_SIZE; +   pI830DRI->width = ctx->shared.virtualWidth; +   pI830DRI->height = ctx->shared.virtualHeight; +   pI830DRI->mem = ctx->shared.fbSize; +   pI830DRI->cpp = ctx->cpp; +   pI830DRI->backOffset = pI830->BackBuffer.Start; +   pI830DRI->backPitch = pI830->BackBuffer.Pitch;  + +   pI830DRI->depthOffset = pI830->DepthBuffer.Start; +   pI830DRI->depthPitch = pI830->DepthBuffer.Pitch;  + +   pI830DRI->fbOffset = pI830->FrontBuffer.Start; +   pI830DRI->fbStride = pI830->FrontBuffer.Pitch; + +   pI830DRI->bitsPerPixel = ctx->bpp; +   pI830DRI->sarea_priv_offset = sizeof(drm_sarea_t); +    +   err = I830DRIDoMappings(ctx, pI830, pSAREAPriv); +   if (err == FALSE) +       return FALSE; + +   I830SetupMemoryTiling(ctx, pI830); + +   /* Quick hack to clear the front & back buffers.  Could also use +    * the clear ioctl to do this, but would need to setup hw state +    * first. +    */ +   I830ClearScreen(ctx, pI830, pSAREAPriv); + +   I830SetRingRegs(ctx, pI830); + +   return TRUE; +} + + +/** + * \brief Validate the fbdev mode. + *  + * \param ctx display handle. + * + * \return one on success, or zero on failure. + * + * Saves some registers and returns 1. + * + * \sa radeonValidateMode(). + */ +static int i830ValidateMode( const DRIDriverContext *ctx ) +{ +  return 1; +} + +/** + * \brief Examine mode returned by fbdev. + *  + * \param ctx display handle. + * + * \return one on success, or zero on failure. + * + * Restores registers that fbdev has clobbered and returns 1. + * + * \sa i810ValidateMode(). + */ +static int i830PostValidateMode( const DRIDriverContext *ctx ) +{ +  I830Rec *pI830 = ctx->driverPrivate; + +  I830SetRingRegs(ctx, pI830); +  return 1; +} + + +/** + * \brief Initialize the framebuffer device mode + * + * \param ctx display handle. + * + * \return one on success, or zero on failure. + * + * Fills in \p info with some default values and some information from \p ctx + * and then calls I810ScreenInit() for the screen initialization. + *  + * Before exiting clears the framebuffer memory accessing it directly. + */ +static int i830InitFBDev( DRIDriverContext *ctx ) +{ +  I830Rec *pI830 = calloc(1, sizeof(I830Rec)); +  int i; + +   { +      int  dummy = ctx->shared.virtualWidth; + +      switch (ctx->bpp / 8) { +      case 1: dummy = (ctx->shared.virtualWidth + 127) & ~127; break; +      case 2: dummy = (ctx->shared.virtualWidth +  31) &  ~31; break; +      case 3: +      case 4: dummy = (ctx->shared.virtualWidth +  15) &  ~15; break; +      } + +      ctx->shared.virtualWidth = dummy; +      ctx->shared.Width = ctx->shared.virtualWidth; +   } + + +   for (i = 0; pitches[i] != 0; i++) { +     if (pitches[i] >= ctx->shared.virtualWidth) { +       ctx->shared.virtualWidth = pitches[i]; +       break; +     } +   } + +   ctx->driverPrivate = (void *)pI830; +    +   pI830->LpRing = calloc(1, sizeof(I830RingBuffer)); +   pI830->Chipset = ctx->chipset; +   pI830->LinearAddr = ctx->FBStart; + +   if (!I830ScreenInit( ctx, pI830 )) +      return 0; + +    +   return 1; +} + + +/** + * \brief The screen is being closed, so clean up any state and free any + * resources used by the DRI. + * + * \param ctx display handle. + * + * Unmaps the SAREA, closes the DRM device file descriptor and frees the driver + * private data. + */ +static void i830HaltFBDev( DRIDriverContext *ctx ) +{ +  drmI830Sarea *pSAREAPriv; +  I830Rec *pI830 = ctx->driverPrivate; + +   if (pI830->irq) { +       drmCtlUninstHandler(ctx->drmFD); +       pI830->irq = 0;   } + +   I830CleanupDma(ctx); + +  pSAREAPriv = (drmI830Sarea *)(((char*)ctx->pSAREA) +  +				sizeof(drm_sarea_t)); + +  I830DRIUnmapScreenRegions(ctx, pI830, pSAREAPriv); +  drmUnmap( ctx->pSAREA, ctx->shared.SAREASize ); +  drmClose(ctx->drmFD); +   +  if (ctx->driverPrivate) { +    free(ctx->driverPrivate); +    ctx->driverPrivate = 0; +  } +} + + +extern void i810NotifyFocus( int ); + +/** + * \brief Exported driver interface for Mini GLX. + * + * \sa DRIDriverRec. + */ +const struct DRIDriverRec __driDriver = { +   i830ValidateMode, +   i830PostValidateMode, +   i830InitFBDev, +   i830HaltFBDev, +   NULL,//I830EngineShutdown, +   NULL, //I830EngineRestore,   +#ifndef _EMBEDDED +   0, +#else +   i810NotifyFocus,  +#endif +};  | 
