From 6b9e31f3eb3dbe20cbc8493b963bbc6530e392c6 Mon Sep 17 00:00:00 2001 From: Keith Whitwell Date: Wed, 1 Nov 2006 12:03:11 +0000 Subject: [PATCH] Import texmem i915 driver to its new location as i915tex. --- src/mesa/drivers/dri/i915tex/Makefile | 65 + src/mesa/drivers/dri/i915tex/i830_context.c | 104 ++ src/mesa/drivers/dri/i915tex/i830_context.h | 208 +++ src/mesa/drivers/dri/i915tex/i830_metaops.c | 485 +++++++ src/mesa/drivers/dri/i915tex/i830_reg.h | 641 +++++++++ src/mesa/drivers/dri/i915tex/i830_state.c | 1113 ++++++++++++++ src/mesa/drivers/dri/i915tex/i830_tex.c | 100 ++ src/mesa/drivers/dri/i915tex/i830_texblend.c | 463 ++++++ src/mesa/drivers/dri/i915tex/i830_texstate.c | 316 ++++ src/mesa/drivers/dri/i915tex/i830_vtbl.c | 606 ++++++++ src/mesa/drivers/dri/i915tex/i915_context.c | 174 +++ src/mesa/drivers/dri/i915tex/i915_context.h | 367 +++++ src/mesa/drivers/dri/i915tex/i915_debug.c | 334 +++++ src/mesa/drivers/dri/i915tex/i915_fragprog.c | 1069 ++++++++++++++ src/mesa/drivers/dri/i915tex/i915_metaops.c | 509 +++++++ src/mesa/drivers/dri/i915tex/i915_program.c | 518 +++++++ src/mesa/drivers/dri/i915tex/i915_program.h | 160 ++ src/mesa/drivers/dri/i915tex/i915_reg.h | 841 +++++++++++ src/mesa/drivers/dri/i915tex/i915_state.c | 1019 +++++++++++++ src/mesa/drivers/dri/i915tex/i915_tex.c | 113 ++ .../drivers/dri/i915tex/i915_tex_layout.c | 380 +++++ src/mesa/drivers/dri/i915tex/i915_texstate.c | 338 +++++ src/mesa/drivers/dri/i915tex/i915_vtbl.c | 549 +++++++ .../drivers/dri/i915tex/intel_batchbuffer.c | 342 +++++ .../drivers/dri/i915tex/intel_batchbuffer.h | 124 ++ .../drivers/dri/i915tex/intel_batchpool.c | 418 ++++++ src/mesa/drivers/dri/i915tex/intel_blit.c | 556 +++++++ src/mesa/drivers/dri/i915tex/intel_blit.h | 63 + .../dri/i915tex/intel_buffer_objects.c | 250 ++++ .../dri/i915tex/intel_buffer_objects.h | 86 ++ src/mesa/drivers/dri/i915tex/intel_buffers.c | 966 +++++++++++++ src/mesa/drivers/dri/i915tex/intel_buffers.h | 56 + src/mesa/drivers/dri/i915tex/intel_context.c | 707 +++++++++ src/mesa/drivers/dri/i915tex/intel_context.h | 502 +++++++ .../drivers/dri/i915tex/intel_depthstencil.c | 282 ++++ .../drivers/dri/i915tex/intel_depthstencil.h | 14 + src/mesa/drivers/dri/i915tex/intel_fbo.c | 622 ++++++++ src/mesa/drivers/dri/i915tex/intel_fbo.h | 80 + src/mesa/drivers/dri/i915tex/intel_ioctl.c | 138 ++ src/mesa/drivers/dri/i915tex/intel_ioctl.h | 40 + .../drivers/dri/i915tex/intel_mipmap_tree.c | 341 +++++ .../drivers/dri/i915tex/intel_mipmap_tree.h | 198 +++ src/mesa/drivers/dri/i915tex/intel_pixel.c | 119 ++ src/mesa/drivers/dri/i915tex/intel_pixel.h | 63 + .../drivers/dri/i915tex/intel_pixel_bitmap.c | 350 +++++ .../drivers/dri/i915tex/intel_pixel_copy.c | 380 +++++ .../drivers/dri/i915tex/intel_pixel_draw.c | 365 +++++ .../drivers/dri/i915tex/intel_pixel_read.c | 317 ++++ src/mesa/drivers/dri/i915tex/intel_reg.h | 84 ++ src/mesa/drivers/dri/i915tex/intel_regions.c | 466 ++++++ src/mesa/drivers/dri/i915tex/intel_regions.h | 141 ++ src/mesa/drivers/dri/i915tex/intel_render.c | 242 ++++ src/mesa/drivers/dri/i915tex/intel_rotate.c | 237 +++ src/mesa/drivers/dri/i915tex/intel_rotate.h | 39 + src/mesa/drivers/dri/i915tex/intel_screen.c | 862 +++++++++++ src/mesa/drivers/dri/i915tex/intel_screen.h | 132 ++ src/mesa/drivers/dri/i915tex/intel_span.c | 409 ++++++ src/mesa/drivers/dri/i915tex/intel_span.h | 38 + src/mesa/drivers/dri/i915tex/intel_state.c | 363 +++++ src/mesa/drivers/dri/i915tex/intel_structs.h | 132 ++ src/mesa/drivers/dri/i915tex/intel_tex.c | 182 +++ src/mesa/drivers/dri/i915tex/intel_tex.h | 134 ++ src/mesa/drivers/dri/i915tex/intel_tex_copy.c | 301 ++++ .../drivers/dri/i915tex/intel_tex_format.c | 146 ++ .../drivers/dri/i915tex/intel_tex_image.c | 626 ++++++++ .../drivers/dri/i915tex/intel_tex_subimage.c | 183 +++ .../drivers/dri/i915tex/intel_tex_validate.c | 252 ++++ src/mesa/drivers/dri/i915tex/intel_tris.c | 1149 +++++++++++++++ src/mesa/drivers/dri/i915tex/intel_tris.h | 69 + .../drivers/dri/i915tex/server/i830_common.h | 212 +++ .../drivers/dri/i915tex/server/i830_dri.h | 73 + src/mesa/drivers/dri/i915tex/server/intel.h | 328 +++++ .../drivers/dri/i915tex/server/intel_dri.c | 1282 +++++++++++++++++ 73 files changed, 25933 insertions(+) create mode 100644 src/mesa/drivers/dri/i915tex/Makefile create mode 100644 src/mesa/drivers/dri/i915tex/i830_context.c create mode 100644 src/mesa/drivers/dri/i915tex/i830_context.h create mode 100644 src/mesa/drivers/dri/i915tex/i830_metaops.c create mode 100644 src/mesa/drivers/dri/i915tex/i830_reg.h create mode 100644 src/mesa/drivers/dri/i915tex/i830_state.c create mode 100644 src/mesa/drivers/dri/i915tex/i830_tex.c create mode 100644 src/mesa/drivers/dri/i915tex/i830_texblend.c create mode 100644 src/mesa/drivers/dri/i915tex/i830_texstate.c create mode 100644 src/mesa/drivers/dri/i915tex/i830_vtbl.c create mode 100644 src/mesa/drivers/dri/i915tex/i915_context.c create mode 100644 src/mesa/drivers/dri/i915tex/i915_context.h create mode 100644 src/mesa/drivers/dri/i915tex/i915_debug.c create mode 100644 src/mesa/drivers/dri/i915tex/i915_fragprog.c create mode 100644 src/mesa/drivers/dri/i915tex/i915_metaops.c create mode 100644 src/mesa/drivers/dri/i915tex/i915_program.c create mode 100644 src/mesa/drivers/dri/i915tex/i915_program.h create mode 100644 src/mesa/drivers/dri/i915tex/i915_reg.h create mode 100644 src/mesa/drivers/dri/i915tex/i915_state.c create mode 100644 src/mesa/drivers/dri/i915tex/i915_tex.c create mode 100644 src/mesa/drivers/dri/i915tex/i915_tex_layout.c create mode 100644 src/mesa/drivers/dri/i915tex/i915_texstate.c create mode 100644 src/mesa/drivers/dri/i915tex/i915_vtbl.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_batchbuffer.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_batchbuffer.h create mode 100644 src/mesa/drivers/dri/i915tex/intel_batchpool.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_blit.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_blit.h create mode 100644 src/mesa/drivers/dri/i915tex/intel_buffer_objects.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_buffer_objects.h create mode 100644 src/mesa/drivers/dri/i915tex/intel_buffers.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_buffers.h create mode 100644 src/mesa/drivers/dri/i915tex/intel_context.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_context.h create mode 100644 src/mesa/drivers/dri/i915tex/intel_depthstencil.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_depthstencil.h create mode 100644 src/mesa/drivers/dri/i915tex/intel_fbo.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_fbo.h create mode 100644 src/mesa/drivers/dri/i915tex/intel_ioctl.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_ioctl.h create mode 100644 src/mesa/drivers/dri/i915tex/intel_mipmap_tree.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_mipmap_tree.h create mode 100644 src/mesa/drivers/dri/i915tex/intel_pixel.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_pixel.h create mode 100644 src/mesa/drivers/dri/i915tex/intel_pixel_bitmap.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_pixel_copy.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_pixel_draw.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_pixel_read.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_reg.h create mode 100644 src/mesa/drivers/dri/i915tex/intel_regions.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_regions.h create mode 100644 src/mesa/drivers/dri/i915tex/intel_render.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_rotate.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_rotate.h create mode 100644 src/mesa/drivers/dri/i915tex/intel_screen.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_screen.h create mode 100644 src/mesa/drivers/dri/i915tex/intel_span.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_span.h create mode 100644 src/mesa/drivers/dri/i915tex/intel_state.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_structs.h create mode 100644 src/mesa/drivers/dri/i915tex/intel_tex.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_tex.h create mode 100644 src/mesa/drivers/dri/i915tex/intel_tex_copy.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_tex_format.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_tex_image.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_tex_subimage.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_tex_validate.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_tris.c create mode 100644 src/mesa/drivers/dri/i915tex/intel_tris.h create mode 100644 src/mesa/drivers/dri/i915tex/server/i830_common.h create mode 100644 src/mesa/drivers/dri/i915tex/server/i830_dri.h create mode 100644 src/mesa/drivers/dri/i915tex/server/intel.h create mode 100644 src/mesa/drivers/dri/i915tex/server/intel_dri.c diff --git a/src/mesa/drivers/dri/i915tex/Makefile b/src/mesa/drivers/dri/i915tex/Makefile new file mode 100644 index 00000000000..d57a651466b --- /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 00000000000..2ff8621c42f --- /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 00000000000..e5377b300aa --- /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 00000000000..c90f5022229 --- /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 00000000000..24ac5245005 --- /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 00000000000..83d82882a65 --- /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 00000000000..fed464d1aac --- /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 00000000000..58f220eb7ce --- /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 00000000000..ba79cf94599 --- /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 00000000000..45502da290a --- /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 00000000000..924de169c74 --- /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 00000000000..5ae76fcd185 --- /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 00000000000..974527e14cc --- /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 + + +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 00000000000..ac5cf2ead28 --- /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 00000000000..3ab62bc806b --- /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)<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 00000000000..4fb56222c63 --- /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 + +#include "glheader.h" +#include "macros.h" +#include "enums.h" + +#include "tnl/t_context.h" +#include "intel_batchbuffer.h" + +#include "i915_reg.h" +#include "i915_context.h" +#include "i915_program.h" + + +#define A0_DEST( reg ) (((reg)&UREG_TYPE_NR_MASK)>>UREG_A0_DEST_SHIFT_LEFT) +#define D0_DEST( reg ) (((reg)&UREG_TYPE_NR_MASK)>>UREG_A0_DEST_SHIFT_LEFT) +#define T0_DEST( reg ) (((reg)&UREG_TYPE_NR_MASK)>>UREG_A0_DEST_SHIFT_LEFT) +#define A0_SRC0( reg ) (((reg)&UREG_MASK)>>UREG_A0_SRC0_SHIFT_LEFT) +#define A1_SRC0( reg ) (((reg)&UREG_MASK)<>UREG_A1_SRC1_SHIFT_LEFT) +#define A2_SRC1( reg ) (((reg)&UREG_MASK)<>UREG_A2_SRC2_SHIFT_LEFT) + +/* These are special, and don't have swizzle/negate bits. + */ +#define T0_SAMPLER( reg ) (GET_UREG_NR(reg)<temp_flag); + if (!bit) { + fprintf(stderr, "%s: out of temporaries\n", __FILE__); + exit(1); + } + + p->temp_flag |= 1 << (bit - 1); + return UREG(REG_TYPE_R, (bit - 1)); +} + + +GLuint +i915_get_utemp(struct i915_fragment_program * p) +{ + int bit = ffs(~p->utemp_flag); + if (!bit) { + fprintf(stderr, "%s: out of temporaries\n", __FILE__); + exit(1); + } + + p->utemp_flag |= 1 << (bit - 1); + return UREG(REG_TYPE_U, (bit - 1)); +} + +void +i915_release_utemps(struct i915_fragment_program *p) +{ + p->utemp_flag = ~0x7; +} + + +GLuint +i915_emit_decl(struct i915_fragment_program *p, + GLuint type, GLuint nr, GLuint d0_flags) +{ + GLuint reg = UREG(type, nr); + + if (type == REG_TYPE_T) { + if (p->decl_t & (1 << 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 00000000000..3c12b34f163 --- /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 00000000000..04b199905c1 --- /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 00000000000..d68801d3f94 --- /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)<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 00000000000..a53abe9a92f --- /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 00000000000..e9360ecea83 --- /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 00000000000..e0ecdfde24a --- /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 00000000000..827990d2cfb --- /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 00000000000..b4e0b74f161 --- /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 00000000000..a83dbf423df --- /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 00000000000..3c17c50204b --- /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 + */ + +#include +#include +#include +#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 00000000000..cbf993fc0e6 --- /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 +#include + +#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 00000000000..1d99988c3c6 --- /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 00000000000..31c41d86857 --- /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 00000000000..afe9b2f7cf2 --- /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 00000000000..fe7ef7ec36f --- /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 00000000000..0faf0553474 --- /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 00000000000..3d51a6341c7 --- /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 00000000000..fa3cf585718 --- /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 00000000000..d269a85a3c9 --- /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 00000000000..2d3fc48b3a3 --- /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 00000000000..ab0e569bd94 --- /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 00000000000..221f09b39ab --- /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 00000000000..3250c6b3a9c --- /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 +#include +#include +#include + +#include "mtypes.h" +#include "context.h" +#include "swrast/swrast.h" + +#include "intel_context.h" +#include "intel_ioctl.h" +#include "intel_batchbuffer.h" +#include "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 00000000000..e8d07de893e --- /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 00000000000..2ebe3ae14e1 --- /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 00000000000..e6dd5bb6008 --- /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 00000000000..4fe128deea1 --- /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 00000000000..a6fcf90ce03 --- /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 00000000000..65bf338589e --- /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 00000000000..5eb021f008b --- /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 00000000000..616101aef99 --- /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 00000000000..c1cc65674d1 --- /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 00000000000..1ec153266c7 --- /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 00000000000..064a34cda81 --- /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 00000000000..1415bace690 --- /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 00000000000..f9fa55051ea --- /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 00000000000..12d98c4ad2f --- /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 + +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 00000000000..9c8802ca477 --- /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 00000000000..c04831be1b1 --- /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 00000000000..17698773f3d --- /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 +#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 00000000000..ab0874e4fd6 --- /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 00000000000..5201f6d6c6e --- /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 00000000000..f85d8ef8353 --- /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 00000000000..522e3bd92c2 --- /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 00000000000..51875ab2921 --- /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 00000000000..2f3d4ec2d11 --- /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 00000000000..88b62e781c0 --- /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 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 00000000000..d7612dcbaab --- /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 00000000000..48c2f35d3b9 --- /dev/null +++ b/src/mesa/drivers/dri/i915tex/intel_tex_image.c @@ -0,0 +1,626 @@ + +#include +#include + +#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 00000000000..25a2dca6857 --- /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 00000000000..e273716b090 --- /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 00000000000..1ba49d8f6ec --- /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 00000000000..b7bae8cd3bc --- /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 00000000000..fb6ceaa52d4 --- /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 00000000000..6c9a7090215 --- /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 00000000000..d7858a20c8d --- /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 + +# 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 00000000000..169fdbece30 --- /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 +#include +#include +#include +#include + +#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 +}; -- 2.30.2