diff options
author | Brian Paul <brian.paul@tungstengraphics.com> | 2003-08-22 20:11:43 +0000 |
---|---|---|
committer | Brian Paul <brian.paul@tungstengraphics.com> | 2003-08-22 20:11:43 +0000 |
commit | 5df82c82bd53db90eb72c5aad4dd20cf6f1116b1 (patch) | |
tree | f04fc69df71104df2a4cec03346abc3d4c3f4bbb /src/mesa/drivers | |
parent | 1a84876d7907df90add3f59d3396ce0bbb905040 (diff) |
patch to import Jon Smirl's work from Bitkeeper
Diffstat (limited to 'src/mesa/drivers')
107 files changed, 35757 insertions, 2488 deletions
diff --git a/src/mesa/drivers/dri/mga/Doxyfile b/src/mesa/drivers/dri/mga/Doxyfile new file mode 100644 index 0000000000..0d0c134a72 --- /dev/null +++ b/src/mesa/drivers/dri/mga/Doxyfile @@ -0,0 +1,234 @@ +# Doxyfile 1.3.3-Gideon + +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = mga +PROJECT_NUMBER = $VERSION$ +OUTPUT_DIRECTORY = +OUTPUT_LANGUAGE = English +USE_WINDOWS_ENCODING = NO +EXTRACT_ALL = NO +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = NO +EXTRACT_LOCAL_CLASSES = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = NO +STRIP_FROM_PATH = +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = YES +SHORT_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +JAVADOC_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = NO +DETAILS_AT_TOP = NO +INHERIT_DOCS = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 8 +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ALIASES = +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = NO +SHOW_USED_FILES = YES +SUBGROUPING = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = /home/newtree/temp/src/mesa/drivers/dri/mga +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.idl \ + *.odl \ + *.cs \ + *.C \ + *.H \ + *.tlh \ + *.diff \ + *.patch \ + *.moc \ + *.xpm \ + *.dox +RECURSIVE = yes +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = * +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = NO +#--------------------------------------------------------------------------- +# configuration options related to source browsing +#--------------------------------------------------------------------------- +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = YES +REFERENCES_RELATION = YES +VERBATIM_HEADERS = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = NO +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = YES +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +#--------------------------------------------------------------------------- +# configuration options related to the XML output +#--------------------------------------------------------------------------- +GENERATE_XML = yes +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +#--------------------------------------------------------------------------- +# configuration options for the AutoGen Definitions output +#--------------------------------------------------------------------------- +GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# configuration options related to the Perl module output +#--------------------------------------------------------------------------- +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +CLASS_DIAGRAMS = YES +HIDE_UNDOC_RELATIONS = YES +HAVE_DOT = NO +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +UML_LOOK = NO +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = NO +GRAPHICAL_HIERARCHY = YES +DOT_IMAGE_FORMAT = png +DOT_PATH = +DOTFILE_DIRS = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +MAX_DOT_GRAPH_DEPTH = 1000 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO +CGI_NAME = search.cgi +CGI_URL = +DOC_URL = +DOC_ABSPATH = +BIN_ABSPATH = /usr/local/bin/ +EXT_DOC_PATHS = diff --git a/src/mesa/drivers/dri/mga/Makefile.X11 b/src/mesa/drivers/dri/mga/Makefile.X11 index c69d6e5989..0dce6e7b1a 100644 --- a/src/mesa/drivers/dri/mga/Makefile.X11 +++ b/src/mesa/drivers/dri/mga/Makefile.X11 @@ -1,4 +1,4 @@ -# $Id: Makefile.X11,v 1.1 2003/08/06 18:01:13 keithw Exp $ +# $Id: Makefile.X11,v 1.2 2003/08/22 20:11:44 brianp Exp $ # Mesa 3-D graphics library # Version: 5.0 @@ -6,8 +6,10 @@ TOP = ../../../../.. +default: linux-solo + SHARED_INCLUDES = $(INCLUDE_DIRS) -I. -I../common -Iserver -MINIGLX_INCLUDES = -I$(TOP)/src/miniglx +MINIGLX_INCLUDES = -I$(TOP)/src/glx/mini DEFINES += \ -D_HAVE_SWRAST=1 \ @@ -16,24 +18,27 @@ DEFINES += \ -D_HAVE_CODEGEN=1 \ -D_HAVE_LIGHTING=1 \ -D_HAVE_TEXGEN=1 \ - -D_HAVE_USERCLIP=1 + -D_HAVE_USERCLIP=1 \ + -DGLX_DIRECT_RENDERING MINIGLX_SOURCES = server/mga_dri.c -DRIVER_SOURCES = mgabuffers.c \ - mgadd.c \ +DRIVER_SOURCES = mgadd.c \ mgaioctl.c \ mgarender.c \ mgastate.c \ mgatris.c \ - ../common/mm.c + ../common/mm.c \ + ../common/utils.c \ + ../common/texmem.c \ + ../common/vblank.c FULL_DRIVER_SOURCES = \ mgapixel.c \ mgaspan.c \ mgatex.c \ - mgatexcnv.c \ mgatexmem.c \ + mga_texstate.c \ mgavb.c \ mga_xmesa.c @@ -54,7 +59,7 @@ WINOBJ=$(MESABUILDDIR)/dri/dri.a WINLIB= else WINOBJ= -WINLIB=-L$(MESA)/src/miniglx +WINLIB=-L$(MESA)/src/glx/mini endif ASM_SOURCES = @@ -87,7 +92,7 @@ INCLUDE_DIRS = \ ##### TARGETS ##### -targets: mga_dri.so +targets: depend mga_dri.so mga_dri.so: $(OBJECTS) $(MESA_MODULES) $(WINOBJ) Makefile.X11 rm -f $@ && gcc -o $@ -shared $(OBJECTS) $(MESA_MODULES) $(WINOBJ) $(WINLIB) -lc -lm @@ -96,7 +101,7 @@ mga_dri.so: $(OBJECTS) $(MESA_MODULES) $(WINOBJ) Makefile.X11 # Run 'make -f Makefile.X11 dep' to update the dependencies if you change # what's included by any source file. -dep: $(C_SOURCES) $(ASM_SOURCES) +depend: $(C_SOURCES) $(ASM_SOURCES) makedepend -fdepend -Y $(SHARED_INCLUDES) \ $(C_SOURCES) $(ASM_SOURCES) @@ -108,7 +113,7 @@ tags: # Remove .o and backup files clean: - -rm -f *.o *~ *.o *~ *.so + -rm -f *.o *~ *.o *~ *.so server/*.o include $(TOP)/Make-config diff --git a/src/mesa/drivers/dri/mga/mga_texstate.c b/src/mesa/drivers/dri/mga/mga_texstate.c new file mode 100644 index 0000000000..fc1406cab9 --- /dev/null +++ b/src/mesa/drivers/dri/mga/mga_texstate.c @@ -0,0 +1,747 @@ +/* + * Copyright 2000-2001 VA Linux Systems, Inc. + * (c) Copyright IBM Corporation 2002 + * 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 + * VA LINUX SYSTEMS, IBM 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. + * + * Authors: + * Ian Romanick <idr@us.ibm.com> + * Keith Whitwell <keithw@tungstengraphics.com> + */ +/* $XFree86:$ */ + +#include "mm.h" +#include "mgacontext.h" +#include "mgatex.h" +#include "mgaregs.h" +#include "mgatris.h" +#include "mgaioctl.h" + +#include "context.h" +#include "enums.h" +#include "macros.h" +#include "imports.h" + +#include "simple_list.h" +#include "texformat.h" + +#define MGA_USE_TABLE_FOR_FORMAT +#ifdef MGA_USE_TABLE_FOR_FORMAT +#define TMC_nr_tformat (MESA_FORMAT_YCBCR_REV + 1) +static const unsigned TMC_tformat[ TMC_nr_tformat ] = +{ + [MESA_FORMAT_ARGB8888] = TMC_tformat_tw32 | TMC_takey_1 | TMC_tamask_0, + [MESA_FORMAT_RGB565] = TMC_tformat_tw16 | TMC_takey_1 | TMC_tamask_0, + [MESA_FORMAT_ARGB4444] = TMC_tformat_tw12 | TMC_takey_1 | TMC_tamask_0, + [MESA_FORMAT_ARGB1555] = TMC_tformat_tw15 | TMC_takey_1 | TMC_tamask_0, + [MESA_FORMAT_CI8] = TMC_tformat_tw8 | TMC_takey_1 | TMC_tamask_0, + [MESA_FORMAT_YCBCR] = TMC_tformat_tw422uyvy | TMC_takey_1 | TMC_tamask_0, + [MESA_FORMAT_YCBCR_REV] = TMC_tformat_tw422 | TMC_takey_1 | TMC_tamask_0, +}; +#endif + +static void +mgaSetTexImages( mgaContextPtr mmesa, + const struct gl_texture_object * tObj ) +{ + mgaTextureObjectPtr t = (mgaTextureObjectPtr) tObj->DriverData; + struct gl_texture_image *baseImage = tObj->Image[ tObj->BaseLevel ]; + GLint totalSize; + GLint width, height; + GLint i; + GLint firstLevel, lastLevel, numLevels; + GLint log2Width, log2Height; + GLuint txformat = 0; + GLint ofs; + + /* Set the hardware texture format + */ +#ifndef MGA_USE_TABLE_FOR_FORMAT + switch (baseImage->TexFormat->MesaFormat) { + + case MESA_FORMAT_ARGB8888: txformat = TMC_tformat_tw32; break; + case MESA_FORMAT_RGB565: txformat = TMC_tformat_tw16; break; + case MESA_FORMAT_ARGB4444: txformat = TMC_tformat_tw12; break; + case MESA_FORMAT_ARGB1555: txformat = TMC_tformat_tw15; break; + case MESA_FORMAT_CI8: txformat = TMC_tformat_tw8; break; + case MESA_FORMAT_YCBCR: txformat = TMC_tformat_tw422uyvy; break; + case MESA_FORMAT_YCBCR_REV: txformat = TMC_tformat_tw422; break; + + default: + _mesa_problem(NULL, "unexpected texture format in %s", __FUNCTION__); + return; + } +#else + if ( (baseImage->TexFormat->MesaFormat >= TMC_nr_tformat) + || (TMC_tformat[ baseImage->TexFormat->MesaFormat ] == 0) ) + { + _mesa_problem(NULL, "unexpected texture format in %s", __FUNCTION__); + return; + } + + txformat = TMC_tformat[ baseImage->TexFormat->MesaFormat ]; + +#endif /* MGA_USE_TABLE_FOR_FORMAT */ + + 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 { + /* Compute which mipmap levels we really want to send to the hardware. + * This depends on the base image size, GL_TEXTURE_MIN_LOD, + * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL. + * Yes, this looks overly complicated, but it's all needed. + */ + + 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 */ + } + + log2Width = tObj->Image[firstLevel]->WidthLog2; + log2Height = tObj->Image[firstLevel]->HeightLog2; + width = tObj->Image[firstLevel]->Width; + height = tObj->Image[firstLevel]->Height; + + numLevels = MIN2( lastLevel - firstLevel + 1, + MGA_IS_G200(mmesa) ? G200_TEX_MAXLEVELS : G400_TEX_MAXLEVELS); + + + totalSize = 0; + for ( i = 0 ; i < numLevels ; i++ ) { + const struct gl_texture_image * const texImage = tObj->Image[i+firstLevel]; + + if ( (texImage == NULL) + || ((i != 0) + && ((texImage->Width < 8) || (texImage->Height < 8))) ) { + break; + } + + t->offsets[i] = totalSize; + t->base.dirty_images[0] |= (1<<i); + + totalSize += ((MAX2( texImage->Width, 8 ) * + MAX2( texImage->Height, 8 ) * + baseImage->TexFormat->TexelBytes) + 31) & ~31; + } + + numLevels = i; + lastLevel = firstLevel + numLevels - 1; + + /* save these values */ + t->base.firstLevel = firstLevel; + t->base.lastLevel = lastLevel; + + t->base.totalSize = totalSize; + + /* setup hardware register values */ + t->setup.texctl &= (TMC_tformat_MASK & TMC_tpitch_MASK + & TMC_tpitchext_MASK); + t->setup.texctl |= txformat; + + + /* Set the texture width. In order to support non-power of 2 textures and + * textures larger than 1024 texels wide, "linear" pitch must be used. For + * the linear pitch, if the width is 2048, a value of zero is used. + */ + + t->setup.texctl |= TMC_tpitchlin_enable; + t->setup.texctl |= (width & (2048 - 1)) << TMC_tpitchext_SHIFT; + + + /* G400 specifies the number of mip levels in a strange way. Since there + * are up to 12 levels, it requires 4 bits. Three of the bits are at the + * high end of TEXFILTER. The other bit is in the middle. Weird. + */ + + t->setup.texfilter &= TF_mapnb_MASK & TF_mapnbhigh_MASK & TF_reserved_MASK; + t->setup.texfilter |= (((numLevels-1) & 0x07) << (TF_mapnb_SHIFT)); + t->setup.texfilter |= (((numLevels-1) & 0x08) << (TF_mapnbhigh_SHIFT - 3)); + + /* warp texture registers */ + ofs = MGA_IS_G200(mmesa) ? 28 : 11; + + t->setup.texwidth = (MGA_FIELD(TW_twmask, width - 1) | + MGA_FIELD(TW_rfw, (10 - log2Width - 8) & 63 ) | + MGA_FIELD(TW_tw, (log2Width + ofs ) | 0x40 )); + + t->setup.texheight = (MGA_FIELD(TH_thmask, height - 1) | + MGA_FIELD(TH_rfh, (10 - log2Height - 8) & 63 ) | + MGA_FIELD(TH_th, (log2Height + ofs ) | 0x40 )); + + mgaUploadTexImages( mmesa, t ); +} + + +/* ================================================================ + * Texture unit state management + */ + +static void mgaUpdateTextureEnvG200( GLcontext *ctx, GLuint unit ) +{ + struct gl_texture_object *tObj = ctx->Texture.Unit[0]._Current; + mgaTextureObjectPtr t; + + if (!tObj || !tObj->DriverData) + return; + + t = (mgaTextureObjectPtr)tObj->DriverData; + + t->setup.texctl2 &= ~TMC_decalblend_enable; + + switch (ctx->Texture.Unit[0].EnvMode) { + case GL_REPLACE: + t->setup.texctl &= ~TMC_tmodulate_enable; + break; + case GL_MODULATE: + t->setup.texctl |= TMC_tmodulate_enable; + break; + case GL_DECAL: + t->setup.texctl &= ~TMC_tmodulate_enable; + t->setup.texctl2 |= TMC_decalblend_enable; + break; + case GL_BLEND: + FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE ); + break; + default: + break; + } +} + + +#define MGA_DISABLE 0 +#define MGA_REPLACE 1 +#define MGA_MODULATE 2 +#define MGA_DECAL 3 +#define MGA_BLEND 4 +#define MGA_ADD 5 +#define MGA_MAX_COMBFUNC 6 + +static const GLuint g400_color_combine[][MGA_MAX_COMBFUNC] = +{ + /* Unit 0: + */ + { + /* Disable combiner stage + */ + (0), + + /* GL_REPLACE + */ + (TD0_color_sel_arg1 | + TD0_alpha_arg2_diffuse | + TD0_alpha_sel_arg2 ), + + /* GL_MODULATE + */ + (TD0_color_arg2_diffuse | + TD0_color_sel_mul | + TD0_alpha_arg2_diffuse | + TD0_alpha_sel_mul), + + /* GL_DECAL + */ + (TD0_color_sel_arg1 | + TD0_alpha_arg2_diffuse | + TD0_alpha_sel_arg2), + + /* GL_BLEND + */ + (0), + + /* GL_ADD + */ + (TD0_color_arg2_diffuse | + TD0_color_add_add | + TD0_color_sel_add | + TD0_alpha_arg2_diffuse | + TD0_alpha_sel_mul), + }, + + /* Unit 1: + */ + { + /* Disable combiner stage + */ + (0), + + /* GL_REPLACE + */ + (TD0_color_sel_arg1 | + TD0_alpha_arg2_diffuse | + TD0_alpha_sel_arg2 ), + + /* GL_MODULATE + */ + (TD0_color_arg2_prevstage | + TD0_color_alpha_prevstage | + TD0_color_sel_mul | + TD0_alpha_arg2_prevstage | + TD0_alpha_sel_mul), + + /* GL_DECAL + */ + (TD0_color_sel_arg1 | + TD0_alpha_arg2_prevstage | + TD0_alpha_sel_arg2 ), + + /* GL_BLEND + */ + (0), + + /* GL_ADD + */ + (TD0_color_arg2_prevstage | + TD0_color_alpha_prevstage | + TD0_color_add_add | + TD0_color_sel_add | + TD0_alpha_arg2_prevstage | + TD0_alpha_sel_mul), + }, +}; + +static const GLuint g400_alpha_combine[][MGA_MAX_COMBFUNC] = +{ + /* Unit 0: + */ + { + /* Disable combiner stage + */ + (0), + + /* GL_REPLACE + */ + (TD0_color_sel_arg2 | + TD0_color_arg2_diffuse | + TD0_alpha_sel_arg1 ), + + /* GL_MODULATE + * FIXME: Is this correct? + */ + (TD0_color_arg2_diffuse | + TD0_color_sel_mul | + TD0_alpha_arg2_diffuse | + TD0_alpha_sel_mul), + + /* GL_DECAL + */ + (TD0_color_arg2_diffuse | + TD0_color_sel_arg2 | + TD0_alpha_arg2_diffuse | + TD0_alpha_sel_arg2), + + /* GL_BLEND + */ + (TD0_color_arg2_diffuse | + TD0_color_sel_mul | + TD0_alpha_arg2_diffuse | + TD0_alpha_sel_mul), + + /* GL_ADD + */ + (TD0_color_arg2_diffuse | + TD0_color_sel_mul | + TD0_alpha_arg2_diffuse | + TD0_alpha_sel_mul), + }, + + /* Unit 1: + */ + { + /* Disable combiner stage + */ + (0), + + /* GL_REPLACE + */ + (TD0_color_sel_arg2 | + TD0_color_arg2_diffuse | + TD0_alpha_sel_arg1 ), + + /* GL_MODULATE + * FIXME: Is this correct? + */ + (TD0_color_arg2_prevstage | + TD0_color_alpha_prevstage | + TD0_color_sel_mul | + TD0_alpha_arg2_prevstage | + TD0_alpha_sel_mul), + + /* GL_DECAL + */ + (TD0_color_arg2_prevstage | + TD0_color_sel_arg2 | + TD0_alpha_arg2_prevstage | + TD0_alpha_sel_arg2), + + /* GL_BLEND + */ + (TD0_color_arg2_diffuse | + TD0_color_sel_mul | + TD0_alpha_arg2_diffuse | + TD0_alpha_sel_mul), + + /* GL_ADD + */ + (TD0_color_arg2_prevstage | + TD0_color_sel_mul | + TD0_alpha_arg2_prevstage | + TD0_alpha_sel_mul), + }, +}; + +static void mgaUpdateTextureEnvG400( GLcontext *ctx, GLuint unit ) +{ + mgaContextPtr mmesa = MGA_CONTEXT( ctx ); + const int source = mmesa->tmu_source[unit]; + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source]; + const struct gl_texture_object *tObj = texUnit->_Current; + GLuint *reg = ((GLuint *)&mmesa->setup.tdualstage0 + unit); + GLenum format; + + if ( tObj != ctx->Texture.Unit[source].Current2D || !tObj ) + return; + + format = tObj->Image[tObj->BaseLevel]->Format; + + switch (ctx->Texture.Unit[source].EnvMode) { + case GL_REPLACE: + if (format == GL_RGB || format == GL_LUMINANCE) { + *reg = g400_color_combine[unit][MGA_REPLACE]; + } + else if (format == GL_ALPHA) { + *reg = g400_alpha_combine[unit][MGA_REPLACE]; + } + else { + *reg = (TD0_color_sel_arg1 | + TD0_alpha_sel_arg1 ); + } + break; + + case GL_MODULATE: + *reg = g400_color_combine[unit][MGA_MODULATE]; + break; + case GL_DECAL: + if (format == GL_RGB) { + *reg = g400_color_combine[unit][MGA_DECAL]; + } + else if ( format == GL_RGBA ) { +#if 0 + if (unit == 0) { + /* this doesn't work */ + *reg = (TD0_color_arg2_diffuse | + TD0_color_alpha_currtex | + TD0_color_alpha2inv_enable | + TD0_color_arg2mul_alpha2 | + TD0_color_arg1mul_alpha1 | + TD0_color_blend_enable | + TD0_color_arg1add_mulout | + TD0_color_arg2add_mulout | + TD0_color_add_add | + TD0_color_sel_mul | + TD0_alpha_arg2_diffuse | + TD0_alpha_sel_arg2 ); + } + else { + *reg = (TD0_color_arg2_prevstage | + TD0_color_alpha_currtex | + TD0_color_alpha2inv_enable | + TD0_color_arg2mul_alpha2 | + TD0_color_arg1mul_alpha1 | + TD0_color_add_add | + TD0_color_sel_add | + TD0_alpha_arg2_prevstage | + TD0_alpha_sel_arg2 ); + } +#else + /* s/w fallback, pretty sure we can't do in h/w */ + FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE ); + if ( MGA_DEBUG & DEBUG_VERBOSE_FALLBACK ) + fprintf( stderr, "FALLBACK: GL_DECAL RGBA texture, unit=%d\n", + unit ); +#endif + } + else { + *reg = g400_alpha_combine[unit][MGA_DECAL]; + } + break; + + case GL_ADD: + if (format == GL_INTENSITY) { + if (unit == 0) { + *reg = ( TD0_color_arg2_diffuse | + TD0_color_add_add | + TD0_color_sel_add | + TD0_alpha_arg2_diffuse | + TD0_alpha_add_enable | + TD0_alpha_sel_add); + } + else { + *reg = ( TD0_color_arg2_prevstage | + TD0_color_add_add | + TD0_color_sel_add | + TD0_alpha_arg2_prevstage | + TD0_alpha_add_enable | + TD0_alpha_sel_add); + } + } + else if (format == GL_ALPHA) { + *reg = g400_alpha_combine[unit][MGA_ADD]; + } + else { + *reg = g400_color_combine[unit][MGA_ADD]; + } + break; + + case GL_BLEND: + if (format == GL_ALPHA) { + *reg = g400_alpha_combine[unit][MGA_BLEND]; + } + else { + FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE ); + if ( MGA_DEBUG & DEBUG_VERBOSE_FALLBACK ) + fprintf( stderr, "FALLBACK: GL_BLEND envcolor=0x%08x\n", + mmesa->envcolor ); + + /* Do singletexture GL_BLEND with 'all ones' env-color + * by using both texture units. Multitexture gl_blend + * is a fallback. + */ + if (unit == 0) { + /* Part 1: R1 = Rf ( 1 - Rt ) + * A1 = Af At + */ + *reg = ( TD0_color_arg2_diffuse | + TD0_color_arg1_inv_enable | + TD0_color_sel_mul | + TD0_alpha_arg2_diffuse | + TD0_alpha_sel_arg1); + } else { + /* Part 2: R2 = R1 + Rt + * A2 = A1 + */ + *reg = ( TD0_color_arg2_prevstage | + TD0_color_add_add | + TD0_color_sel_add | + TD0_alpha_arg2_prevstage | + TD0_alpha_sel_arg2); + } + } + break; + default: + break; + } +} + + +static void disable_tex( GLcontext *ctx, int unit ) +{ + mgaContextPtr mmesa = MGA_CONTEXT( ctx ); + + /* Texture unit disabled */ + + if ( mmesa->CurrentTexObj[unit] != NULL ) { + /* The old texture is no longer bound to this texture unit. + * Mark it as such. + */ + + mmesa->CurrentTexObj[unit]->base.bound &= ~(1UL << unit); + mmesa->CurrentTexObj[unit] = NULL; + } + + if ( unit != 0 ) { + mmesa->setup.tdualstage1 = mmesa->setup.tdualstage0; + } + + if ( ctx->Texture._EnabledUnits == 0 ) { + mmesa->setup.dwgctl &= DC_opcod_MASK; + mmesa->setup.dwgctl |= DC_opcod_trap; + mmesa->hw.alpha_sel = AC_alphasel_diffused; + } + + mmesa->dirty |= MGA_UPLOAD_CONTEXT | (MGA_UPLOAD_TEX0 << unit); +} + +static GLboolean enable_tex_2d( GLcontext *ctx, int unit ) +{ + mgaContextPtr mmesa = MGA_CONTEXT(ctx); + const int source = mmesa->tmu_source[unit]; + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source]; + const struct gl_texture_object *tObj = texUnit->_Current; + mgaTextureObjectPtr t = (mgaTextureObjectPtr) tObj->DriverData; + + /* Upload teximages (not pipelined) + */ + if (t->base.dirty_images[0]) { + FLUSH_BATCH( mmesa ); + mgaSetTexImages( mmesa, tObj ); + if ( t->base.memBlock == NULL ) { + return GL_FALSE; + } + } + + return GL_TRUE; +} + +static GLboolean update_tex_common( GLcontext *ctx, int unit ) +{ + mgaContextPtr mmesa = MGA_CONTEXT(ctx); + const int source = mmesa->tmu_source[unit]; + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source]; + struct gl_texture_object *tObj = texUnit->_Current; + mgaTextureObjectPtr t = (mgaTextureObjectPtr) tObj->DriverData; + + /* Fallback if there's a texture border */ + if ( tObj->Image[tObj->BaseLevel]->Border > 0 ) { + return GL_FALSE; + } + + + /* Update state if this is a different texture object to last + * time. + */ + if ( mmesa->CurrentTexObj[unit] != t ) { + if ( mmesa->CurrentTexObj[unit] != NULL ) { + /* The old texture is no longer bound to this texture unit. + * Mark it as such. + */ + + mmesa->CurrentTexObj[unit]->base.bound &= ~(1UL << unit); + } + + mmesa->CurrentTexObj[unit] = t; + t->base.bound |= (1UL << unit); + + driUpdateTextureLRU( (driTextureObject *) t ); /* done too often */ + } + + /* register setup */ + if ( unit == 1 ) { + mmesa->setup.tdualstage1 = mmesa->setup.tdualstage0; + } + + t->setup.texctl2 &= TMC_dualtex_MASK; + if (ctx->Texture._EnabledUnits == 0x03) { + t->setup.texctl2 |= TMC_dualtex_enable; + } + + /* FIXME: The Radeon has some cached state so that it can avoid calling + * FIXME: UpdateTextureEnv in some cases. Is that possible here? + */ + if (MGA_IS_G400(mmesa)) { + /* G400: Regardless of texture env mode, we use the alpha from the + * texture unit (AC_alphasel_fromtex) since it will have already + * been modulated by the incoming fragment color, if needed. + * We don't want (AC_alphasel_modulate) since that'll effectively + * do the modulation twice. + */ + mmesa->hw.alpha_sel = AC_alphasel_fromtex; + + mgaUpdateTextureEnvG400( ctx, unit ); + } else { + mmesa->hw.alpha_sel = 0; + switch (ctx->Texture.Unit[0].EnvMode) { + case GL_DECAL: + mmesa->hw.alpha_sel |= AC_alphasel_diffused; + case GL_REPLACE: + mmesa->hw.alpha_sel |= AC_alphasel_fromtex; + break; + case GL_BLEND: + case GL_MODULATE: + mmesa->hw.alpha_sel |= AC_alphasel_modulated; + break; + default: + break; + } + + mgaUpdateTextureEnvG200( ctx, unit ); + } + + mmesa->setup.dwgctl &= DC_opcod_MASK; + mmesa->setup.dwgctl |= DC_opcod_texture_trap; + mmesa->dirty |= MGA_UPLOAD_CONTEXT | (MGA_UPLOAD_TEX0 << unit); + + FALLBACK( ctx, MGA_FALLBACK_BORDER_MODE, t->border_fallback ); + return !t->border_fallback; +} + + +static GLboolean updateTextureUnit( GLcontext *ctx, int unit ) +{ + mgaContextPtr mmesa = MGA_CONTEXT( ctx ); + const int source = mmesa->tmu_source[unit]; + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source]; + + + if ( texUnit->_ReallyEnabled == TEXTURE_2D_BIT) { + return(enable_tex_2d( ctx, unit ) && + update_tex_common( ctx, unit )); + } + else if ( texUnit->_ReallyEnabled ) { + return GL_FALSE; + } + else { + disable_tex( ctx, unit ); + return GL_TRUE; + } +} + +/* The G400 is now programmed quite differently wrt texture environment. + */ +void mgaUpdateTextureState( GLcontext *ctx ) +{ + mgaContextPtr mmesa = MGA_CONTEXT( ctx ); + GLboolean ok; + unsigned i; + + + /* This works around a quirk with the MGA hardware. If only OpenGL + * TEXTURE1 is enabled, then the hardware TEXTURE0 must be used. The + * hardware TEXTURE1 can ONLY be used when hardware TEXTURE0 is also used. + */ + + mmesa->tmu_source[0] = 0; + mmesa->tmu_source[1] = 1; + + if ((ctx->Texture._EnabledUnits & 0x03) == 0x02) { + /* only texture 1 enabled */ + mmesa->tmu_source[0] = 1; + mmesa->tmu_source[1] = 0; + } + + for ( i = 0, ok = GL_TRUE + ; (i < ctx->Const.MaxTextureUnits) && ok + ; i++ ) { + ok = updateTextureUnit( ctx, i ); + } + + FALLBACK( ctx, MGA_FALLBACK_TEXTURE, !ok ); + + /* FIXME: I believe that ChooseVertexState should be called here instead of + * FIXME: in mgaDDValidateState. + */ +} diff --git a/src/mesa/drivers/dri/mga/mga_xmesa.c b/src/mesa/drivers/dri/mga/mga_xmesa.c index de1bcc2a0f..16dc349cac 100644 --- a/src/mesa/drivers/dri/mga/mga_xmesa.c +++ b/src/mesa/drivers/dri/mga/mga_xmesa.c @@ -1,4 +1,4 @@ -/* $XFree86: xc/lib/GL/mesa/src/drv/mga/mga_xmesa.c,v 1.19 2003/03/26 20:43:49 tsi Exp $ */ +/* $XFree86: xc/lib/GL/mesa/src/drv/mga/mga_xmesa.c,v 1.18 2002/12/16 16:18:52 dawes Exp $ */ /* * Copyright 2000-2001 VA Linux Systems, Inc. * All Rights Reserved. @@ -26,15 +26,14 @@ * Keith Whitwell <keith@tungstengraphics.com> */ -#include <stdio.h> +#ifdef GLX_DIRECT_RENDERING #include "mga_common.h" #include "mga_xmesa.h" #include "context.h" #include "matrix.h" -/*#include "mmath.h"*/ #include "simple_list.h" -/*#include "mem.h"*/ +#include "imports.h" #include "swrast/swrast.h" #include "swrast_setup/swrast_setup.h" @@ -50,26 +49,23 @@ #include "mgaioctl.h" #include "mgatris.h" #include "mgavb.h" -#include "mgabuffers.h" #include "mgapixel.h" - #include "mga_xmesa.h" - #include "mga_dri.h" +#include "utils.h" +#include "vblank.h" +#include "dri_util.h" +#ifndef _SOLO +#include "glxextensions.h" +#endif + #ifndef MGA_DEBUG -int MGA_DEBUG = (0 -/* | DEBUG_ALWAYS_SYNC */ -/* | DEBUG_VERBOSE_MSG */ -/* | DEBUG_VERBOSE_LRU */ -/* | DEBUG_VERBOSE_DRI */ -/* | DEBUG_VERBOSE_IOCTL */ -/* | DEBUG_VERBOSE_2D */ -/* | DEBUG_VERBOSE_FALLBACK */ - ); +int MGA_DEBUG = 0; #endif +static int getSwapInfo( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo ); static GLboolean mgaInitDriver(__DRIscreenPrivate *sPriv) @@ -77,16 +73,8 @@ mgaInitDriver(__DRIscreenPrivate *sPriv) mgaScreenPrivate *mgaScreen; MGADRIPtr serverInfo = (MGADRIPtr)sPriv->pDevPriv; - if (MGA_DEBUG&DEBUG_VERBOSE_DRI) - fprintf(stderr, "mgaInitDriver\n"); - - /* Check that the DRM driver version is compatible */ - if (sPriv->drmMajor != 3 || - sPriv->drmMinor < 0) { - __driUtilMessage("MGA DRI driver expected DRM driver version 3.0.x but got version %d.%d.%d", sPriv->drmMajor, sPriv->drmMinor, sPriv->drmPatch); + if ( ! driCheckDriDdxDrmVersions( sPriv, "MGA", 4, 0, 1, 0, 3, 0 ) ) return GL_FALSE; - } - /* Allocate the private area */ mgaScreen = (mgaScreenPrivate *)MALLOC(sizeof(mgaScreenPrivate)); @@ -103,21 +91,37 @@ mgaInitDriver(__DRIscreenPrivate *sPriv) drmMGAGetParam gp; gp.param = MGA_PARAM_IRQ_NR; - gp.value = (int *) &mgaScreen->irq; + gp.value = &mgaScreen->irq; ret = drmCommandWriteRead( sPriv->fd, DRM_MGA_GETPARAM, &gp, sizeof(gp)); if (ret) { fprintf(stderr, "drmMgaGetParam (MGA_PARAM_IRQ_NR): %d\n", ret); - FREE(mgaScreen); + free(mgaScreen); sPriv->private = NULL; return GL_FALSE; } } + mgaScreen->linecomp_sane = (sPriv->ddxMajor > 1) || (sPriv->ddxMinor > 1) + || ((sPriv->ddxMinor == 1) && (sPriv->ddxPatch > 0)); +#ifndef _SOLO + if ( ! mgaScreen->linecomp_sane ) { + PFNGLXDISABLEEXTENSIONPROC glx_disable_extension; + + glx_disable_extension = (PFNGLXDISABLEEXTENSIONPROC) + glXGetProcAddress( "__glXDisableExtension" ); + + if ( glx_disable_extension != NULL ) { + (*glx_disable_extension)( "GLX_SGI_swap_control" ); + (*glx_disable_extension)( "GLX_SGI_video_sync" ); + (*glx_disable_extension)( "GLX_MESA_swap_control" ); + } + } +#endif if (serverInfo->chipset != MGA_CARD_TYPE_G200 && serverInfo->chipset != MGA_CARD_TYPE_G400) { - FREE(mgaScreen); + free(mgaScreen); sPriv->private = NULL; __driUtilMessage("Unrecognized chipset"); return GL_FALSE; @@ -164,7 +168,7 @@ mgaInitDriver(__DRIscreenPrivate *sPriv) mgaScreen->agp.size, (drmAddress *)&mgaScreen->agp.map) != 0) { - Xfree(mgaScreen); + free(mgaScreen); sPriv->private = NULL; __driUtilMessage("Couldn't map agp region"); return GL_FALSE; @@ -210,7 +214,7 @@ mgaInitDriver(__DRIscreenPrivate *sPriv) mgaScreen->bufs = drmMapBufs(sPriv->fd); if (!mgaScreen->bufs) { /*drmUnmap(mgaScreen->agp_tex.map, mgaScreen->agp_tex.size);*/ - FREE(mgaScreen); + free(mgaScreen); sPriv->private = NULL; __driUtilMessage("Couldn't map dma buffers"); return GL_FALSE; @@ -254,12 +258,63 @@ static const struct gl_pipeline_stage *mga_pipeline[] = { }; +static const char * const g400_extensions[] = +{ + "GL_ARB_multitexture", + "GL_ARB_texture_env_add", + "GL_EXT_texture_env_add", + "GL_EXT_texture_edge_clamp", + "GL_SGIS_texture_edge_clamp", +#if defined (MESA_packed_depth_stencil) + "GL_MESA_packed_depth_stencil", +#endif + NULL +}; + +static const char * const card_extensions[] = +{ + "GL_ARB_multisample", + "GL_ARB_texture_compression", + "GL_EXT_fog_coord", + /* paletted_textures currently doesn't work, but we could fix them later */ +#if 0 + "GL_EXT_shared_texture_palette", + "GL_EXT_paletted_texture", +#endif + "GL_EXT_secondary_color", + "GL_EXT_stencil_wrap", + "GL_MESA_ycbcr_texture", + "GL_SGIS_generate_mipmap", + "GL_SGIS_texture_lod", + NULL +}; + +static const struct dri_debug_control debug_control[] = +{ + { "fall", DEBUG_VERBOSE_FALLBACK }, + { "tex", DEBUG_VERBOSE_TEXTURE }, + { "ioctl", DEBUG_VERBOSE_IOCTL }, + { "verb", DEBUG_VERBOSE_MSG }, + { "dri", DEBUG_VERBOSE_DRI }, + { NULL, 0 } +}; + + +static int +get_ust_nop( uint64_t * ust ) +{ + *ust = 1; + return 0; +} + + static GLboolean mgaCreateContext( const __GLcontextModes *mesaVis, __DRIcontextPrivate *driContextPriv, void *sharedContextPrivate ) { int i; + unsigned maxlevels; GLcontext *ctx, *shareCtx; mgaContextPtr mmesa; __DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv; @@ -281,7 +336,7 @@ mgaCreateContext( const __GLcontextModes *mesaVis, shareCtx = ((mgaContextPtr) sharedContextPrivate)->glCtx; else shareCtx = NULL; - mmesa->glCtx = _mesa_create_context(mesaVis, shareCtx, mmesa, GL_TRUE); + mmesa->glCtx = _mesa_create_context(mesaVis, shareCtx, (void *) mmesa, GL_TRUE); if (!mmesa->glCtx) { FREE(mmesa); return GL_FALSE; @@ -298,13 +353,20 @@ mgaCreateContext( const __GLcontextModes *mesaVis, mmesa->sarea = (void *)saPriv; mmesa->glBuffer = NULL; - make_empty_list(&mmesa->SwappedOut); - - mmesa->lastTexHeap = mgaScreen->texVirtual[MGA_AGP_HEAP] ? 2 : 1; - - for (i = 0 ; i < mmesa->lastTexHeap ; i++) { - mmesa->texHeap[i] = mmInit( 0, mgaScreen->textureSize[i]); - make_empty_list(&mmesa->TexObjList[i]); + (void) memset( mmesa->texture_heaps, 0, sizeof( mmesa->texture_heaps ) ); + make_empty_list( & mmesa->swapped ); + + mmesa->nr_heaps = mgaScreen->texVirtual[MGA_AGP_HEAP] ? 2 : 1; + for ( i = 0 ; i < mmesa->nr_heaps ; i++ ) { + mmesa->texture_heaps[i] = driCreateTextureHeap( i, mmesa, + mgaScreen->textureSize[i], + 6, + MGA_NR_TEX_REGIONS, + mmesa->sarea->texList[i], + & mmesa->sarea->texAge[i], + & mmesa->swapped, + sizeof( mgaTextureObject_t ), + (destroy_texture_object_t *) mgaDestroyTexObj ); } /* Set the maximum texture size small enough that we can guarentee @@ -312,22 +374,26 @@ mgaCreateContext( const __GLcontextModes *mesaVis, * on the card at once. */ ctx = mmesa->glCtx; - { - int nr = 2; - - if (mgaScreen->chipset == MGA_CARD_TYPE_G200) - nr = 1; - - if (mgaScreen->textureSize[0] < nr*1024*1024) { - ctx->Const.MaxTextureLevels = 9; - } else if (mgaScreen->textureSize[0] < nr*4*1024*1024) { - ctx->Const.MaxTextureLevels = 10; - } else { - ctx->Const.MaxTextureLevels = 11; - } + if ( mgaScreen->chipset == MGA_CARD_TYPE_G200 ) { + ctx->Const.MaxTextureUnits = 1; + maxlevels = G200_TEX_MAXLEVELS; - ctx->Const.MaxTextureUnits = nr; } + else { + ctx->Const.MaxTextureUnits = 2; + maxlevels = G400_TEX_MAXLEVELS; + } + + driCalculateMaxTextureLevels( mmesa->texture_heaps, + mmesa->nr_heaps, + & ctx->Const, + 4, + 11, /* max 2D texture size is 1024x1024 */ + 0, /* 3D textures unsupported. */ + 0, /* cube textures unsupported. */ + 0, /* texture rectangles unsupported. */ + maxlevels, + GL_FALSE ); ctx->Const.MinLineWidth = 1.0; ctx->Const.MinLineWidthAA = 1.0; @@ -335,6 +401,7 @@ mgaCreateContext( const __GLcontextModes *mesaVis, ctx->Const.MaxLineWidthAA = 10.0; ctx->Const.LineWidthGranularity = 1.0; + mmesa->default32BitTextures = (mesaVis->rgbBits >= 24); mmesa->hw_stencil = mesaVis->stencilBits && mesaVis->depthBits == 24; switch (mesaVis->depthBits) { @@ -361,7 +428,6 @@ mgaCreateContext( const __GLcontextModes *mesaVis, mmesa->haveHwStipple = GL_FALSE; mmesa->RenderIndex = -1; /* impossible value */ - mmesa->new_state = ~0; mmesa->dirty = ~0; mmesa->vertex_format = 0; mmesa->CurrentTexObj[0] = 0; @@ -395,7 +461,11 @@ mgaCreateContext( const __GLcontextModes *mesaVis, ctx->DriverCtx = (void *) mmesa; mmesa->glCtx = ctx; - mgaDDExtensionsInit( ctx ); + driInitExtensions( ctx, card_extensions, GL_FALSE ); + + if (MGA_IS_G400(MGA_CONTEXT(ctx))) { + driInitExtensions( ctx, g400_extensions, GL_FALSE ); + } mgaDDInitStateFuncs( ctx ); mgaDDInitTextureFuncs( ctx ); @@ -410,6 +480,24 @@ mgaCreateContext( const __GLcontextModes *mesaVis, driContextPriv->driverPrivate = (void *) mmesa; +#if DO_DEBUG + MGA_DEBUG = driParseDebugString( getenv( "MGA_DEBUG" ), + debug_control ); +#endif + + mmesa->vblank_flags = ((mmesa->mgaScreen->irq == 0) + || !mmesa->mgaScreen->linecomp_sane) + ? VBLANK_FLAG_NO_IRQ : driGetDefaultVBlankFlags(); +#ifndef _SOLO + mmesa->get_ust = (PFNGLXGETUSTPROC) glXGetProcAddress( "__glXGetUST" ); + if ( mmesa->get_ust == NULL ) +#endif + { + mmesa->get_ust = get_ust_nop; + } + + (*mmesa->get_ust)( & mmesa->swap_ust ); + return GL_TRUE; } @@ -419,10 +507,15 @@ mgaDestroyContext(__DRIcontextPrivate *driContextPriv) mgaContextPtr mmesa = (mgaContextPtr) driContextPriv->driverPrivate; if (MGA_DEBUG&DEBUG_VERBOSE_DRI) - fprintf(stderr, "mgaDestroyContext\n"); + fprintf( stderr, "[%s:%d] mgaDestroyContext start\n", + __FILE__, __LINE__ ); assert(mmesa); /* should never be null */ if (mmesa) { + GLboolean release_texture_heaps; + + + release_texture_heaps = (mmesa->glCtx->Shared->RefCount == 1); _swsetup_DestroyContext( mmesa->glCtx ); _tnl_DestroyContext( mmesa->glCtx ); _ac_DestroyContext( mmesa->glCtx ); @@ -433,9 +526,27 @@ mgaDestroyContext(__DRIcontextPrivate *driContextPriv) /* free the Mesa context */ mmesa->glCtx->DriverCtx = NULL; _mesa_destroy_context(mmesa->glCtx); - /* free the mga context */ + + if ( release_texture_heaps ) { + /* This share group is about to go away, free our private + * texture object data. + */ + int i; + + assert( is_empty_list( & mmesa->swapped ) ); + + for ( i = 0 ; i < mmesa->nr_heaps ; i++ ) { + driDestroyTextureHeap( mmesa->texture_heaps[ i ] ); + mmesa->texture_heaps[ i ] = NULL; + } + } + FREE(mmesa); } + + if (MGA_DEBUG&DEBUG_VERBOSE_DRI) + fprintf( stderr, "[%s:%d] mgaDestroyContext done\n", + __FILE__, __LINE__ ); } @@ -482,13 +593,7 @@ mgaUnbindContext(__DRIcontextPrivate *driContextPriv) } static GLboolean -mgaOpenFullScreen(__DRIcontextPrivate *driContextPriv) -{ - return GL_TRUE; -} - -static GLboolean -mgaCloseFullScreen(__DRIcontextPrivate *driContextPriv) +mgaOpenCloseFullScreen(__DRIcontextPrivate *driContextPriv) { return GL_TRUE; } @@ -505,8 +610,6 @@ mgaMakeCurrent(__DRIcontextPrivate *driContextPriv, __DRIdrawablePrivate *driDrawPriv, __DRIdrawablePrivate *driReadPriv) { - fprintf(stderr, "%s\n", __FUNCTION__); - if (driContextPriv) { mgaContextPtr mmesa = (mgaContextPtr) driContextPriv->driverPrivate; @@ -532,6 +635,7 @@ mgaMakeCurrent(__DRIcontextPrivate *driContextPriv, return GL_TRUE; } + void mgaGetLock( mgaContextPtr mmesa, GLuint flags ) { __DRIdrawablePrivate *dPriv = mmesa->driDrawable; @@ -539,29 +643,10 @@ void mgaGetLock( mgaContextPtr mmesa, GLuint flags ) int me = mmesa->hHWContext; int i; - fprintf(stderr, "%s\n", __FUNCTION__); - drmGetLock(mmesa->driFd, mmesa->hHWContext, flags); - - fprintf(stderr, - "mmesa->lastStamp %d dpriv->lastStamp %d *(dpriv->pStamp) %d\n", - mmesa->lastStamp, - dPriv->lastStamp, - *(dPriv->pStamp)); - - /* The window might have moved, so we might need to get new clip - * rects. - * - * NOTE: This releases and regrabs the hw lock to allow the X server - * to respond to the DRI protocol request for new drawable info. - * Since the hardware state depends on having the latest drawable - * clip rects, all state checking must be done _after_ this call. - */ - DRI_VALIDATE_DRAWABLE_INFO( sPriv, dPriv ); - if ( mmesa->lastStamp == 0 || - mmesa->lastStamp != dPriv->lastStamp ) { - mmesa->lastStamp = dPriv->lastStamp; + if (*(dPriv->pStamp) != mmesa->lastStamp) { + mmesa->lastStamp = *(dPriv->pStamp); mmesa->SetupNewInputs |= VERT_BIT_CLIP; mmesa->dirty_cliprects = (MGA_FRONT|MGA_BACK); mgaUpdateRects( mmesa, (MGA_FRONT|MGA_BACK) ); @@ -569,7 +654,7 @@ void mgaGetLock( mgaContextPtr mmesa, GLuint flags ) mmesa->dirty |= MGA_UPLOAD_CONTEXT | MGA_UPLOAD_CLIPRECTS; - mmesa->sarea->dirty |= MGA_UPLOAD_CONTEXT; + mmesa->sarea->dirty |= MGA_UPLOAD_CONTEXT; if (sarea->ctxOwner != me) { mmesa->dirty |= (MGA_UPLOAD_CONTEXT | MGA_UPLOAD_TEX0 | @@ -577,36 +662,48 @@ void mgaGetLock( mgaContextPtr mmesa, GLuint flags ) sarea->ctxOwner=me; } - for (i = 0 ; i < mmesa->lastTexHeap ; i++) - if (sarea->texAge[i] != mmesa->texAge[i]) - mgaAgeTextures( mmesa, i ); + for ( i = 0 ; i < mmesa->nr_heaps ; i++ ) { + DRI_AGE_TEXTURES( mmesa->texture_heaps[ i ] ); + } sarea->last_quiescent = -1; /* just kill it for now */ } - static const struct __DriverAPIRec mgaAPI = { - mgaInitDriver, - mgaDestroyScreen, - mgaCreateContext, - mgaDestroyContext, - mgaCreateBuffer, - mgaDestroyBuffer, - mgaSwapBuffers, - mgaMakeCurrent, - mgaUnbindContext, - mgaOpenFullScreen, - mgaCloseFullScreen + .InitDriver = mgaInitDriver, + .DestroyScreen = mgaDestroyScreen, + .CreateContext = mgaCreateContext, + .DestroyContext = mgaDestroyContext, + .CreateBuffer = mgaCreateBuffer, + .DestroyBuffer = mgaDestroyBuffer, + .SwapBuffers = mgaSwapBuffers, + .MakeCurrent = mgaMakeCurrent, + .UnbindContext = mgaUnbindContext, + .OpenFullScreen = mgaOpenCloseFullScreen, + .CloseFullScreen = mgaOpenCloseFullScreen, + .GetSwapInfo = getSwapInfo, + .GetMSC = driGetMSC32, + .WaitForMSC = driWaitForMSC32, + .WaitForSBC = NULL, + .SwapBuffersMSC = NULL }; - /* * This is the bootstrap function for the driver. * The __driCreateScreen name is the symbol that libGL.so fetches. * Return: pointer to a __DRIscreenPrivate. */ +#ifndef _SOLO +void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc, + int numConfigs, __GLXvisualConfig *config) +{ + __DRIscreenPrivate *psp; + psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &mgaAPI); + return (void *) psp; +} +#else void *__driCreateScreen(struct DRIDriverRec *driver, struct DRIDriverContextRec *driverContext) { @@ -614,3 +711,56 @@ void *__driCreateScreen(struct DRIDriverRec *driver, psp = __driUtilCreateScreen(driver, driverContext, &mgaAPI); return (void *) psp; } +#endif + + +#ifndef _SOLO +/* This function is called by libGL.so as soon as libGL.so is loaded. + * This is where we'd register new extension functions with the dispatcher. + */ +void +__driRegisterExtensions( void ) +{ + PFNGLXENABLEEXTENSIONPROC glx_enable_extension; + + + if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) { + glx_enable_extension = (PFNGLXENABLEEXTENSIONPROC) + glXGetProcAddress( "__glXEnableExtension" ); + + if ( glx_enable_extension != NULL ) { + (*glx_enable_extension)( "GLX_SGI_swap_control", GL_FALSE ); + (*glx_enable_extension)( "GLX_SGI_video_sync", GL_FALSE ); + (*glx_enable_extension)( "GLX_MESA_swap_control", GL_FALSE ); + (*glx_enable_extension)( "GLX_MESA_swap_frame_usage", GL_FALSE ); + } + } +} +#endif + +/** + * Get information about previous buffer swaps. + */ +static int +getSwapInfo( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo ) +{ + mgaContextPtr mmesa; + + if ( (dPriv == NULL) || (dPriv->driContextPriv == NULL) + || (dPriv->driContextPriv->driverPrivate == NULL) + || (sInfo == NULL) ) { + return -1; + } + + mmesa = (mgaContextPtr) dPriv->driContextPriv->driverPrivate; + sInfo->swap_count = mmesa->swap_count; + sInfo->swap_ust = mmesa->swap_ust; + sInfo->swap_missed_count = mmesa->swap_missed_count; + + sInfo->swap_missed_usage = (sInfo->swap_missed_count != 0) + ? driCalculateSwapUsage( dPriv, 0, mmesa->swap_missed_ust ) + : 0.0; + + return 0; +} +#endif diff --git a/src/mesa/drivers/dri/mga/mga_xmesa.h b/src/mesa/drivers/dri/mga/mga_xmesa.h index eda996f5a4..de349da089 100644 --- a/src/mesa/drivers/dri/mga/mga_xmesa.h +++ b/src/mesa/drivers/dri/mga/mga_xmesa.h @@ -29,8 +29,9 @@ #ifndef _MGA_INIT_H_ #define _MGA_INIT_H_ +#ifdef GLX_DIRECT_RENDERING + #include <sys/time.h> -#include <linux/types.h> #include "dri_util.h" #include "mtypes.h" #include "mgaregs.h" @@ -46,6 +47,9 @@ typedef struct mga_screen_private_s { int cpp; /* for front and back buffers */ GLint agpMode; unsigned int irq; /* IRQ number (0 means none) */ + GLboolean linecomp_sane; /* GL_TRUE if line comp. programmed correctly + * by the DDX driver. + */ unsigned int mAccess; @@ -136,8 +140,9 @@ do { \ #define MGA_BASE( reg ) ((unsigned long)(mmesa->mgaScreen->mmio.map)) #define MGA_ADDR( reg ) (MGA_BASE(reg) + reg) -#define MGA_DEREF( reg ) *(volatile __u32 *)MGA_ADDR( reg ) +#define MGA_DEREF( reg ) *(volatile CARD32 *)MGA_ADDR( reg ) #define MGA_READ( reg ) MGA_DEREF( reg ) #define MGA_WRITE( reg, val ) do { MGA_DEREF( reg ) = val; } while (0) #endif +#endif diff --git a/src/mesa/drivers/dri/mga/mgacontext.h b/src/mesa/drivers/dri/mga/mgacontext.h index 3065ea9fd1..7188f6d955 100644 --- a/src/mesa/drivers/dri/mga/mgacontext.h +++ b/src/mesa/drivers/dri/mga/mgacontext.h @@ -29,14 +29,15 @@ #ifndef MGALIB_INC #define MGALIB_INC -/*#include <X11/Xlibint.h>*/ +#include <inttypes.h> #include "dri_util.h" #include "mtypes.h" +#include "colormac.h" #include "xf86drm.h" #include "mm.h" -/*#include "mem.h"*/ #include "mga_sarea.h" - +#include "texmem.h" +#include "macros.h" #define MGA_SET_FIELD(reg,mask,val) reg = ((reg) & (mask)) | ((val) & ~(mask)) #define MGA_FIELD(field,val) (((val) << (field ## _SHIFT)) & ~(field ## _MASK)) @@ -59,19 +60,9 @@ #define MGA_FALLBACK_RENDERMODE 0x10 #define MGA_FALLBACK_STENCIL 0x20 #define MGA_FALLBACK_DEPTH 0x40 +#define MGA_FALLBACK_BORDER_MODE 0x80 -/* For mgaCtx->new_state. - */ -#define MGA_NEW_DEPTH 0x1 -#define MGA_NEW_ALPHA 0x2 -#define MGA_NEW_CLIP 0x8 -#define MGA_NEW_TEXTURE 0x20 -#define MGA_NEW_CULL 0x40 -#define MGA_NEW_WARP 0x80 -#define MGA_NEW_STENCIL 0x100 -#define MGA_NEW_CONTEXT 0x200 - /* Use the templated vertex formats: */ #define TAG(x) mga##x @@ -96,43 +87,103 @@ typedef void (*mga_point_func)( mgaContextPtr, mgaVertex * ); struct mga_texture_object_s; struct mga_screen_private_s; -#define MGA_TEX_MAXLEVELS 5 +#define G200_TEX_MAXLEVELS 5 +#define G400_TEX_MAXLEVELS 11 typedef struct mga_texture_object_s { - struct mga_texture_object_s *next; - struct mga_texture_object_s *prev; - struct gl_texture_object *tObj; - struct mga_context_t *ctx; - PMemBlock MemBlock; - GLuint offsets[MGA_TEX_MAXLEVELS]; - int lastLevel; - GLuint dirty_images; - GLuint totalSize; - int texelBytes; - GLuint age; - int bound; - int heap; /* agp or card */ + driTextureObject base; + + /* The G200 only has the ability to use 5 mipmap levels (including the + * base level). The G400 does not have this restriction, but it still + * only has 5 offset pointers in the hardware. The trick on the G400 is + * upto the first 4 offset pointers point to mipmap levels. The last + * offset pointer tells how large the preceeding mipmap is. This value is + * then used to determine where the remaining mipmaps are. + * + * For example, if the first offsets[0] through offsets[2] are used as + * pointers, then offset[3] will be the size of the mipmap pointed to by + * offsets[2]. So mipmap level 3 will be at (offsets[2]+offsets[3]). For + * each successive mipmap level, offsets[3] is divided by 4 and added to + * the previous address. So mipmap level 4 will be at + * (offsets[2]+offsets[3]+(offsets[3] / 4)). + * + * The last pointer is selected by setting TO_texorgoffsetsel in its + * pointer. In the previous example, offset[2] would have + * TO_texorgoffsetsel or'ed in before writing it to the hardware. + * + * In the current driver all of the mipmaps are packed together linearly + * with mipmap level 0. Therefore offsets[0] points to the base of the + * texture (and has TO_texorgoffsetsel or'ed in), and offsets[1] is the + * size of the base texture. + * + * There is a possible optimization available here. At times the driver + * may not be able to allocate a single block of memory for the complete + * texture without ejecting some other textures from memory. It may be + * possible to put some of the lower mipmap levels (i.e., the larger + * mipmaps) in memory separate from the higher levels. + * + * The implementation should be fairly obvious, but getting "right" would + * likely be non-trivial. A first allocation for the entire texture would + * be attempted with a flag that says "don't eject other textures." If + * that failed, an additional allocation would be attmpted for just the + * base map. The process would repeat with the block of lower maps. The + * tricky parts would be in detecting when some of the levels had been + * ejected from texture memory by other textures and preventing the + * 4th allocation (for all the smallest mipmap levels) from kicking out + * any of the first three. + * + * This array holds G400_TEX_MAXLEVELS pointers to remove an if-statement + * in a loop in mgaSetTexImages. Values past G200_TEX_MAXLEVELS are not + * used. + */ + GLuint offsets[G400_TEX_MAXLEVELS]; + + int texelBytes; + GLuint age; mga_texture_regs_t setup; + + /* If one texture dimension wraps with GL_CLAMP and the other with + * GL_CLAMP_TO_EDGE, we have to fallback to software. We would also have + * to fallback for GL_CLAMP_TO_BORDER. + */ + GLboolean border_fallback; } mgaTextureObject_t; +struct mga_hw_state { + GLuint specen; + GLuint cull; + GLuint cull_dualtex; + GLuint stencil; + GLuint stencilctl; + GLuint stencil_enable; + GLuint zmode; + GLuint rop; + GLuint alpha_func; + GLuint alpha_func_enable; + GLuint blend_func; + GLuint blend_func_enable; + GLuint alpha_sel; +}; + struct mga_context_t { GLcontext *glCtx; - unsigned int lastStamp; /* fullscreen breaks dpriv->laststamp, - * need to shadow it here. */ + unsigned int lastStamp; /* fullscreen breaks dpriv->laststamp, + * need to shadow it here. */ + + /* Hardware state management + */ + struct mga_hw_state hw; /* Bookkeeping for texturing */ - int lastTexHeap; - struct mga_texture_object_s TexObjList[MGA_NR_TEX_HEAPS]; - struct mga_texture_object_s SwappedOut; + unsigned nr_heaps; + driTexHeap * texture_heaps[ MGA_NR_TEX_HEAPS ]; + driTextureObject swapped; + struct mga_texture_object_s *CurrentTexObj[2]; - memHeap_t *texHeap[MGA_NR_TEX_HEAPS]; - int c_texupload; - int c_texusage; - int tex_thrash; /* Map GL texture units onto hardware. @@ -166,7 +217,7 @@ struct mga_context_t { GLenum raster_primitive; GLenum render_primitive; - char *verts; + GLubyte *verts; GLint vertex_stride_shift; GLuint vertex_format; GLuint vertex_size; @@ -180,8 +231,7 @@ struct mga_context_t { /* Manage driver and hardware state */ - GLuint new_gl_state; - GLuint new_state; + GLuint NewGLState; GLuint dirty; mga_context_regs_t setup; @@ -205,13 +255,21 @@ struct mga_context_t { /* VBI */ GLuint vbl_seq; + GLuint vblank_flags; + + uint64_t swap_ust; + uint64_t swap_missed_ust; + + GLuint swap_count; + GLuint swap_missed_count; + + PFNGLXGETUSTPROC get_ust; /* Drawable, cliprect and scissor information */ int dirty_cliprects; /* which sets of cliprects are uptodate? */ int draw_buffer; /* which buffer are we rendering to */ unsigned int drawOffset; /* draw buffer address in space */ - int read_buffer; int readOffset; int drawX, drawY; /* origin of drawable in draw buffer */ int lastX, lastY; /* detect DSTORG bug */ @@ -245,51 +303,38 @@ struct mga_context_t { #define MGA_CONTEXT(ctx) ((mgaContextPtr)(ctx->DriverCtx)) -#define MGAPACKCOLOR555(r,g,b,a) \ - ((((r) & 0xf8) << 7) | (((g) & 0xf8) << 2) | (((b) & 0xf8) >> 3) | \ - ((a) ? 0x8000 : 0)) -#define MGAPACKCOLOR565(r,g,b) \ - ((((r) & 0xf8) << 8) | (((g) & 0xfc) << 3) | (((b) & 0xf8) >> 3)) -#define MGAPACKCOLOR88(l, a) \ - (((l) << 8) | (a)) - -#define MGAPACKCOLOR888(r,g,b) \ - (((r) << 16) | ((g) << 8) | (b)) - -#define MGAPACKCOLOR8888(r,g,b,a) \ - (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) - -#define MGAPACKCOLOR4444(r,g,b,a) \ - ((((a) & 0xf0) << 8) | (((r) & 0xf0) << 4) | ((g) & 0xf0) | ((b) >> 4)) +/* ================================================================ + * Debugging: + */ +#define DO_DEBUG 1 -#define MGA_DEBUG 0 -#ifndef MGA_DEBUG +#if DO_DEBUG extern int MGA_DEBUG; +#else +#define MGA_DEBUG 0 #endif -#define DEBUG_ALWAYS_SYNC 0x1 -#define DEBUG_VERBOSE_MSG 0x2 -#define DEBUG_VERBOSE_LRU 0x4 -#define DEBUG_VERBOSE_DRI 0x8 -#define DEBUG_VERBOSE_IOCTL 0x10 -#define DEBUG_VERBOSE_2D 0x20 -#define DEBUG_VERBOSE_FALLBACK 0x40 +#define DEBUG_VERBOSE_MSG 0x01 +#define DEBUG_VERBOSE_DRI 0x02 +#define DEBUG_VERBOSE_IOCTL 0x04 +#define DEBUG_VERBOSE_TEXTURE 0x08 +#define DEBUG_VERBOSE_FALLBACK 0x10 static __inline__ GLuint mgaPackColor(GLuint cpp, GLubyte r, GLubyte g, GLubyte b, GLubyte a) { - switch (cpp) { - case 2: - return MGAPACKCOLOR565(r,g,b); - case 4: - return MGAPACKCOLOR8888(r,g,b,a); - default: - return 0; - } + switch (cpp) { + case 2: + return PACK_COLOR_565( r, g, b ); + case 4: + return PACK_COLOR_8888( a, r, g, b ); + default: + return 0; + } } diff --git a/src/mesa/drivers/dri/mga/mgadd.c b/src/mesa/drivers/dri/mga/mgadd.c index 6ce50e6726..d2f11d8d45 100644 --- a/src/mesa/drivers/dri/mga/mgadd.c +++ b/src/mesa/drivers/dri/mga/mgadd.c @@ -29,10 +29,6 @@ #include "mtypes.h" - -#include <stdio.h> -#include <stdlib.h> - #include "mm.h" #include "mgacontext.h" #include "mgadd.h" @@ -42,12 +38,9 @@ #include "mgatris.h" #include "mgavb.h" #include "mga_xmesa.h" -#include "extensions.h" -#if defined(USE_X86_ASM) -#include "X86/common_x86_asm.h" -#endif +#include "utils.h" -#define MGA_DATE "20020221" +#define DRIVER_DATE "20030328" /*************************************** @@ -59,52 +52,19 @@ static const GLubyte *mgaDDGetString( GLcontext *ctx, GLenum name ) { mgaContextPtr mmesa = MGA_CONTEXT( ctx ); static char buffer[128]; + unsigned offset; switch ( name ) { case GL_VENDOR: return (GLubyte *) "VA Linux Systems Inc."; case GL_RENDERER: - sprintf( buffer, "Mesa DRI %s " MGA_DATE, - MGA_IS_G400(mmesa) ? "G400" : - MGA_IS_G200(mmesa) ? "G200" : "MGA" ); - - /* Append any AGP-specific information. - */ - switch ( mmesa->mgaScreen->agpMode ) { - case 1: - strncat( buffer, " AGP 1x", 7 ); - break; - case 2: - strncat( buffer, " AGP 2x", 7 ); - break; - case 4: - strncat( buffer, " AGP 4x", 7 ); - break; - } - - /* Append any CPU-specific information. - */ -#ifdef USE_X86_ASM - if ( _mesa_x86_cpu_features ) { - strncat( buffer, " x86", 4 ); - } -#endif -#ifdef USE_MMX_ASM - if ( cpu_has_mmx ) { - strncat( buffer, "/MMX", 4 ); - } -#endif -#ifdef USE_3DNOW_ASM - if ( cpu_has_3dnow ) { - strncat( buffer, "/3DNow!", 7 ); - } -#endif -#ifdef USE_SSE_ASM - if ( cpu_has_xmm ) { - strncat( buffer, "/SSE", 4 ); - } -#endif + offset = driGetRendererString( buffer, + MGA_IS_G400(mmesa) ? "G400" : + MGA_IS_G200(mmesa) ? "G200" : "MGA", + DRIVER_DATE, + mmesa->mgaScreen->agpMode ); + return (GLubyte *)buffer; default: @@ -129,40 +89,6 @@ static void mgaBufferSize(GLframebuffer *buffer, GLuint *width, GLuint *height) UNLOCK_HARDWARE( mmesa ); } -void mgaDDExtensionsInit( GLcontext *ctx ) -{ - /* paletted_textures currently doesn't work, but we could fix them later */ - /* - _mesa_enable_extension( ctx, "GL_EXT_shared_texture_palette" ); - _mesa_enable_extension( ctx, "GL_EXT_paletted_texture" ); - */ - - _mesa_enable_extension( ctx, "GL_ARB_texture_compression" ); - _mesa_enable_extension( ctx, "GL_ARB_multisample" ); - - _mesa_enable_extension( ctx, "GL_SGIS_generate_mipmap" ); - - /* Turn on multitexture and texenv_add for the G400. - */ - if (MGA_IS_G400(MGA_CONTEXT(ctx))) { - _mesa_enable_extension( ctx, "GL_ARB_multitexture" ); - _mesa_enable_extension( ctx, "GL_ARB_texture_env_add" ); - - _mesa_enable_extension( ctx, "GL_EXT_texture_env_add" ); - -#if defined (MESA_packed_depth_stencil) - _mesa_enable_extension( ctx, "GL_MESA_packed_depth_stencil" ); -#endif - -#if defined (MESA_experimetal_agp_allocator) - if (!getenv("MGA_DISABLE_AGP_ALLOCATOR")) - _mesa_enable_extension( ctx, "GL_MESA_experimental_agp_allocator" ); -#endif - } -} - - - void mgaDDInitDriverFuncs( GLcontext *ctx ) { ctx->Driver.GetBufferSize = mgaBufferSize; diff --git a/src/mesa/drivers/dri/mga/mgadd.h b/src/mesa/drivers/dri/mga/mgadd.h index 6072e6cfc9..919fd742d6 100644 --- a/src/mesa/drivers/dri/mga/mgadd.h +++ b/src/mesa/drivers/dri/mga/mgadd.h @@ -32,6 +32,5 @@ #include "context.h" void mgaDDInitDriverFuncs( GLcontext *ctx ); -void mgaDDExtensionsInit( GLcontext *ctx ); #endif diff --git a/src/mesa/drivers/dri/mga/mgaioctl.c b/src/mesa/drivers/dri/mga/mgaioctl.c index f88c878060..6b50af202a 100644 --- a/src/mesa/drivers/dri/mga/mgaioctl.c +++ b/src/mesa/drivers/dri/mga/mgaioctl.c @@ -27,7 +27,7 @@ */ /* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgaioctl.c,v 1.16 2002/12/16 16:18:52 dawes Exp $ */ -#include <stdio.h> +#include <sched.h> #include <errno.h> #include "mtypes.h" @@ -43,11 +43,10 @@ #include "mgavb.h" #include "mgaioctl.h" #include "mgatris.h" -#include "mgabuffers.h" +#include "mga_common.h" +#include "vblank.h" -#include "xf86drm.h" -#include "mga_common.h" static void mga_iload_dma_ioctl(mgaContextPtr mmesa, unsigned long dest, @@ -61,6 +60,13 @@ static void mga_iload_dma_ioctl(mgaContextPtr mmesa, fprintf(stderr, "DRM_IOCTL_MGA_ILOAD idx %d dst %x length %d\n", buf->idx, (int) dest, length); + if ( (length & MGA_ILOAD_MASK) != 0 ) { + UNLOCK_HARDWARE( mmesa ); + fprintf( stderr, "%s: Invalid ILOAD datasize (%d), must be " + "multiple of %u.\n", __FUNCTION__, length, MGA_ILOAD_ALIGN ); + exit( 1 ); + } + iload.idx = buf->idx; iload.dstorg = dest; iload.length = length; @@ -278,65 +284,11 @@ mgaDDClear( GLcontext *ctx, GLbitfield mask, GLboolean all, } -int nrswaps; - - -void mgaWaitForVBlank( mgaContextPtr mmesa ) -{ -#if 0 - drmVBlank vbl; - int ret; - - if ( !mmesa->mgaScreen->irq ) - return; - - if ( getenv("LIBGL_SYNC_REFRESH") ) { - /* Wait for until the next vertical blank */ - vbl.request.type = DRM_VBLANK_RELATIVE; - vbl.request.sequence = 1; - } else if ( getenv("LIBGL_THROTTLE_REFRESH") ) { - /* Wait for at least one vertical blank since the last call */ - vbl.request.type = DRM_VBLANK_ABSOLUTE; - vbl.request.sequence = mmesa->vbl_seq + 1; - } else { - return; - } - - if ((ret = drmWaitVBlank( mmesa->driFd, &vbl ))) { - fprintf(stderr, "%s: drmWaitVBlank returned %d, IRQs don't seem to be" - " working correctly.\nTry running with LIBGL_THROTTLE_REFRESH" - " and LIBL_SYNC_REFRESH unset.\n", __FUNCTION__, ret); - exit(1); - } - - mmesa->vbl_seq = vbl.reply.sequence; -#endif -} - - -/* - * Copy the back buffer to the front buffer. - */ -void mgaSwapBuffers(__DRIdrawablePrivate *dPriv) +static void mgaWaitForFrameCompletion( mgaContextPtr mmesa ) { - mgaContextPtr mmesa; - XF86DRIClipRectPtr pbox; - GLint nbox; - GLint ret, wait = 0; - GLint i; + unsigned wait = 0; GLuint last_frame, last_wrap; - assert(dPriv); - assert(dPriv->driContextPriv); - assert(dPriv->driContextPriv->driverPrivate); - - mmesa = (mgaContextPtr) dPriv->driContextPriv->driverPrivate; - - FLUSH_BATCH( mmesa ); - - mgaWaitForVBlank( mmesa ); - - LOCK_HARDWARE( mmesa ); last_frame = mmesa->sarea->last_frame.head; last_wrap = mmesa->sarea->last_frame.wrap; @@ -360,12 +312,46 @@ void mgaSwapBuffers(__DRIdrawablePrivate *dPriv) } UPDATE_LOCK( mmesa, DRM_LOCK_FLUSH ); - for ( i = 0 ; i < 1024 ; i++ ) { - /* Don't just hammer the register... */ - } + UNLOCK_HARDWARE( mmesa ); + DO_USLEEP( 1 ); + LOCK_HARDWARE( mmesa ); } if ( wait ) fprintf( stderr, "\n" ); +} + + +/* + * Copy the back buffer to the front buffer. + */ +void mgaSwapBuffers( __DRIdrawablePrivate *dPriv ) +{ + mgaContextPtr mmesa; + XF86DRIClipRectPtr pbox; + GLint nbox; + GLint ret; + GLint i; + GLboolean missed_target; + + + assert(dPriv); + assert(dPriv->driContextPriv); + assert(dPriv->driContextPriv->driverPrivate); + + mmesa = (mgaContextPtr) dPriv->driContextPriv->driverPrivate; + + FLUSH_BATCH( mmesa ); + + LOCK_HARDWARE( mmesa ); + mgaWaitForFrameCompletion( mmesa ); + UNLOCK_HARDWARE( mmesa ); + driWaitForVBlank( dPriv, & mmesa->vbl_seq, mmesa->vblank_flags, + & missed_target ); + if ( missed_target ) { + mmesa->swap_missed_count++; + (void) (*mmesa->get_ust)( & mmesa->swap_missed_ust ); + } + LOCK_HARDWARE( mmesa ); /* Use the frontbuffer cliprects */ @@ -399,6 +385,8 @@ void mgaSwapBuffers(__DRIdrawablePrivate *dPriv) UNLOCK_HARDWARE( mmesa ); mmesa->dirty |= MGA_UPLOAD_CLIPRECTS; + mmesa->swap_count++; + (void) (*mmesa->get_ust)( & mmesa->swap_ust ); } @@ -442,18 +430,17 @@ void mgaWaitAge( mgaContextPtr mmesa, int age ) } -static int intersect_rect( XF86DRIClipRectPtr out, - XF86DRIClipRectPtr a, - XF86DRIClipRectPtr b ) +static GLboolean intersect_rect( XF86DRIClipRectPtr out, + const XF86DRIClipRectPtr a, + const XF86DRIClipRectPtr b ) { *out = *a; if (b->x1 > out->x1) out->x1 = b->x1; if (b->y1 > out->y1) out->y1 = b->y1; if (b->x2 < out->x2) out->x2 = b->x2; if (b->y2 < out->y2) out->y2 = b->y2; - if (out->x1 > out->x2) return 0; - if (out->y1 > out->y2) return 0; - return 1; + + return ((out->x1 < out->x2) && (out->y1 < out->y2)); } @@ -559,7 +546,7 @@ void mgaFlushVerticesLocked( mgaContextPtr mmesa ) vertex.idx = buffer->idx; vertex.used = buffer->used; vertex.discard = discard; - drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX, + drmCommandWrite( mmesa->driFd, DRM_MGA_VERTEX, &vertex, sizeof(drmMGAVertex) ); age_mmesa(mmesa, mmesa->sarea->last_enqueue); diff --git a/src/mesa/drivers/dri/mga/mgaioctl.h b/src/mesa/drivers/dri/mga/mgaioctl.h index b7cf44d6ff..2d959d8246 100644 --- a/src/mesa/drivers/dri/mga/mgaioctl.h +++ b/src/mesa/drivers/dri/mga/mgaioctl.h @@ -34,6 +34,7 @@ #include "mga_xmesa.h" void mgaSwapBuffers( __DRIdrawablePrivate *dPriv ); +void mgaWaitForVBlank( mgaContextPtr mmesa ); GLuint *mgaAllocVertexDwords( mgaContextPtr mmesa, int dwords ); @@ -41,7 +42,6 @@ GLuint *mgaAllocVertexDwords( mgaContextPtr mmesa, int dwords ); void mgaGetILoadBufferLocked( mgaContextPtr mmesa ); drmBufPtr mgaGetBufferLocked( mgaContextPtr mmesa ); -void mgaWaitForVBlank( mgaContextPtr mmesa ); void mgaFireILoadLocked( mgaContextPtr mmesa, GLuint offset, GLuint length ); @@ -104,8 +104,9 @@ do { \ if ( ret < 0 ) { \ drmCommandNone( mmesa->driFd, DRM_MGA_RESET ); \ UNLOCK_HARDWARE( mmesa ); \ - fprintf( stderr, "%s: flush ret=%d\n", __FUNCTION__, ret ); \ - /*fprintf( stderr, "drmMGAFlushDMA: return = %d\n", ret );*/ \ + fprintf( stderr, "%s: flush return = %s (%d), flags = 0x%08x\n", \ + __FUNCTION__, strerror( -ret ), -ret, \ + (unsigned)(flags) ); \ exit( 1 ); \ } \ } while (0) diff --git a/src/mesa/drivers/dri/mga/mgapixel.c b/src/mesa/drivers/dri/mga/mgapixel.c index 0bc4b3fac5..07e0c3a756 100644 --- a/src/mesa/drivers/dri/mga/mgapixel.c +++ b/src/mesa/drivers/dri/mga/mgapixel.c @@ -35,12 +35,12 @@ #include "mgacontext.h" #include "mgaioctl.h" #include "mgapixel.h" -#include "mgabuffers.h" +#include "mgastate.h" -#include "xf86drm.h" #include "mga_common.h" #include "swrast/swrast.h" +#include "imports.h" #define IS_AGP_MEM( mmesa, p ) \ ((unsigned long)mmesa->mgaScreen->buffers.map <= ((unsigned long)p) && \ @@ -134,7 +134,7 @@ check_color_per_fragment_ops( const GLcontext *ctx ) !ctx->Color.ColorMask[2] || !ctx->Color.ColorMask[3] || ctx->Color.ColorLogicOpEnabled || - ctx->Texture.Unit[0]._ReallyEnabled || + ctx->Texture._EnabledUnits || ctx->Depth.OcclusionTest ) && ctx->Current.RasterPosValid && @@ -596,7 +596,7 @@ mgaTryDrawPixels( GLcontext *ctx, } } #else - memcpy( address, pixels, rows*bufferpitch ); + MEMCPY( address, pixels, rows*bufferpitch ); #endif do_draw_pix( ctx, x, y, width, rows, @@ -639,42 +639,8 @@ mgaDDDrawPixels( GLcontext *ctx, * the same block of agp space which isn't used for anything else at * present. */ -#if defined(MESA_hacked_agp_allocator) -static void mgaDDFreeAgpMemory( GLcontext *ctx, void *ptr ) -{ - (void) ptr; -} - -static void *mgaDDAllocateAgpMemory( GLcontext *ctx, GLsizei size ) -{ - mgaContextPtr mmesa = MGA_CONTEXT(ctx); - - if (size < mmesa->mgaScreen->textureSize[MGA_AGP_HEAP]) - return mmesa->mgaScreen->texVirtual[MGA_AGP_HEAP]; - else - return 0; -} - -static GLint mgaDDGetAgpOffset( GLcontext *ctx, const void *ptr ) -{ - mgaContextPtr mmesa = MGA_CONTEXT(ctx); - - if (!IS_AGP_MEM(mmesa, ptr)) - return -1; - - return AGP_OFFSET(mmesa, ptr); -} -#endif - - void mgaDDInitPixelFuncs( GLcontext *ctx ) { -#if defined (MESA_experimetal_agp_allocator) - ctx->Driver.AllocateAgpMemory = mgaDDAllocateAgpMemory; - ctx->Driver.GetAgpOffset = mgaDDGetAgpOffset; - ctx->Driver.FreeAgpMemory = mgaDDFreeAgpMemory; -#endif - /* Pixel path fallbacks. */ ctx->Driver.Accum = _swrast_Accum; diff --git a/src/mesa/drivers/dri/mga/mgaregs.h b/src/mesa/drivers/dri/mga/mgaregs.h index f07dc2de0b..e1291ca01b 100644 --- a/src/mesa/drivers/dri/mga/mgaregs.h +++ b/src/mesa/drivers/dri/mga/mgaregs.h @@ -1052,6 +1052,7 @@ # define TMC_tformat_tw8a 0x7 /* val 7, shift 0 */ # define TMC_tformat_tw8al 0x8 /* val 8, shift 0 */ # define TMC_tformat_tw422 0xa /* val 10, shift 0 */ +# define TMC_tformat_tw422uyvy 0xb /* val 11, shift 0 */ # define TMC_tpitchlin_MASK 0xfffffeff /* bit 8 */ # define TMC_tpitchlin_disable 0x0 # define TMC_tpitchlin_enable 0x100 @@ -1137,6 +1138,13 @@ # define TF_magfilter_nrst 0x0 /* val 0, shift 4 */ # define TF_magfilter_bilin 0x20 /* val 2, shift 4 */ # define TF_magfilter_cnst 0x30 /* val 3, shift 4 */ +# define TF_uvoffset_SHIFT 17 +# define TF_uvoffset_OGL (0U << TF_uvoffset_SHIFT) +# define TF_uvoffset_D3D (1U << TF_uvoffset_SHIFT) +# define TF_uvoffset_MASK (~(1U << TF_uvoffset_SHIFT)) +# define TF_reserved_MASK (~0x1ff00) /* bits 8-16 */ +# define TF_mapnbhigh_SHIFT 18 +# define TF_mapnbhigh_MASK (~(1U << TF_mapnbhigh_SHIFT)) # define TF_avgstride_MASK 0xfff7ffff /* bit 19 */ # define TF_avgstride_disable 0x0 # define TF_avgstride_enable 0x80000 @@ -1377,5 +1385,11 @@ /**************** (END) AUTOMATICLY GENERATED REGISTER FILE ******************/ +/* Copied from mga_drv.h kernel file. + */ + +#define MGA_ILOAD_ALIGN 64 +#define MGA_ILOAD_MASK (MGA_ILOAD_ALIGN - 1) + #endif /* _MGAREGS_H_ */ diff --git a/src/mesa/drivers/dri/mga/mgarender.c b/src/mesa/drivers/dri/mga/mgarender.c index 53614c223f..516a99099f 100644 --- a/src/mesa/drivers/dri/mga/mgarender.c +++ b/src/mesa/drivers/dri/mga/mgarender.c @@ -42,9 +42,8 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #include "glheader.h" #include "context.h" #include "macros.h" -/*//#include "mem.h"*/ +#include "imports.h" #include "mtypes.h" -/*#include "mmath.h" */ #include "tnl/t_context.h" @@ -165,7 +164,7 @@ static GLboolean mga_run_render( GLcontext *ctx, static void mga_check_render( GLcontext *ctx, struct gl_pipeline_stage *stage ) { - GLuint inputs = VERT_BIT_POS | VERT_BIT_CLIP | VERT_BIT_COLOR0; + GLuint inputs = VERT_BIT_CLIP | VERT_BIT_COLOR0; if (ctx->RenderMode == GL_RENDER) { if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) diff --git a/src/mesa/drivers/dri/mga/mgaspan.c b/src/mesa/drivers/dri/mga/mgaspan.c index 8dc971cfc5..684239865f 100644 --- a/src/mesa/drivers/dri/mga/mgaspan.c +++ b/src/mesa/drivers/dri/mga/mgaspan.c @@ -116,7 +116,7 @@ #undef INIT_MONO_PIXEL #define INIT_MONO_PIXEL(p, color) \ - p = MGAPACKCOLOR565( color[0], color[1], color[2] ) + p = PACK_COLOR_565( color[0], color[1], color[2] ) #define WRITE_RGBA( _x, _y, r, g, b, a ) \ @@ -148,7 +148,7 @@ do { \ #undef INIT_MONO_PIXEL #define INIT_MONO_PIXEL(p, color) \ - p = MGAPACKCOLOR8888( color[0], color[1], color[2], color[3] ) + p = PACK_COLOR_8888( color[3], color[0], color[1], color[2] ) #define WRITE_RGBA(_x, _y, r, g, b, a) \ @@ -233,11 +233,38 @@ do { \ +/* + * This function is called to specify which buffer to read and write + * for software rasterization (swrast) fallbacks. This doesn't necessarily + * correspond to glDrawBuffer() or glReadBuffer() calls. + */ +static void mgaDDSetBuffer(GLcontext *ctx, GLframebuffer *buffer, + GLuint bufferBit) +{ + mgaContextPtr mmesa = MGA_CONTEXT(ctx); + + if (bufferBit == FRONT_LEFT_BIT) + { + mmesa->drawOffset = mmesa->mgaScreen->frontOffset; + mmesa->readOffset = mmesa->mgaScreen->frontOffset; + } + else if (bufferBit == BACK_LEFT_BIT) + { + mmesa->drawOffset = mmesa->mgaScreen->backOffset; + mmesa->readOffset = mmesa->mgaScreen->backOffset; + } + else { + assert(0); + } +} + void mgaDDInitSpanFuncs( GLcontext *ctx ) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference(ctx); + swdd->SetBuffer = mgaDDSetBuffer; + switch (mmesa->mgaScreen->cpp) { case 2: swdd->WriteRGBASpan = mgaWriteRGBASpan_565; diff --git a/src/mesa/drivers/dri/mga/mgastate.c b/src/mesa/drivers/dri/mga/mgastate.c index 02b98fdb76..0d304966d7 100644 --- a/src/mesa/drivers/dri/mga/mgastate.c +++ b/src/mesa/drivers/dri/mga/mgastate.c @@ -26,9 +26,9 @@ */ /* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgastate.c,v 1.13 2002/10/30 12:51:36 alanh Exp $ */ -#include <stdio.h> #include "mtypes.h" +#include "colormac.h" #include "dd.h" #include "mm.h" @@ -40,19 +40,22 @@ #include "mgatris.h" #include "mgaioctl.h" #include "mgaregs.h" -#include "mgabuffers.h" #include "swrast/swrast.h" #include "array_cache/acache.h" #include "tnl/tnl.h" +#include "tnl/t_context.h" +#include "tnl/t_pipeline.h" #include "swrast_setup/swrast_setup.h" +static void updateSpecularLighting( GLcontext *ctx ); + /* Some outstanding problems with accelerating logic ops... */ #if defined(ACCEL_ROP) -static GLuint mgarop_NoBLK[16] = { +static const GLuint mgarop_NoBLK[16] = { DC_atype_rpl | 0x00000000, DC_atype_rstr | 0x00080000, DC_atype_rstr | 0x00040000, DC_atype_rpl | 0x000c0000, DC_atype_rstr | 0x00020000, DC_atype_rstr | 0x000a0000, @@ -65,221 +68,57 @@ static GLuint mgarop_NoBLK[16] = { #endif -static void mgaUpdateStencil(const GLcontext *ctx) -{ - mgaContextPtr mmesa = MGA_CONTEXT(ctx); - GLuint stencil = 0, stencilctl = 0; - - if (ctx->Stencil.Enabled) - { - stencil = ctx->Stencil.Ref[0] | - ( ctx->Stencil.ValueMask[0] << 8 ) | - ( ctx->Stencil.WriteMask[0] << 16 ); - - switch (ctx->Stencil.Function[0]) - { - case GL_NEVER: - MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_snever); - break; - case GL_LESS: - MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_slt); - break; - case GL_LEQUAL: - MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_slte); - break; - case GL_GREATER: - MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_sgt); - break; - case GL_GEQUAL: - MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_sgte); - break; - case GL_NOTEQUAL: - MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_sne); - break; - case GL_EQUAL: - MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_se); - break; - case GL_ALWAYS: - MGA_SET_FIELD(stencilctl, SC_smode_MASK, SC_smode_salways); - default: - break; - } - - switch (ctx->Stencil.FailFunc[0]) - { - case GL_KEEP: - MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_keep); - break; - case GL_ZERO: - MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_zero); - break; - case GL_REPLACE: - MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_replace); - break; - case GL_INCR: - MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_incrsat); - break; - case GL_DECR: - MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_decrsat); - break; - case GL_INVERT: - MGA_SET_FIELD(stencilctl, SC_sfailop_MASK, SC_sfailop_invert); - break; - default: - break; - } - - switch (ctx->Stencil.ZFailFunc[0]) - { - case GL_KEEP: - MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_keep); - break; - case GL_ZERO: - MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_zero); - break; - case GL_REPLACE: - MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_replace); - break; - case GL_INCR: - MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_incrsat); - break; - case GL_DECR: - MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_decrsat); - break; - case GL_INVERT: - MGA_SET_FIELD(stencilctl, SC_szfailop_MASK, SC_szfailop_invert); - break; - default: - break; - } - - switch (ctx->Stencil.ZPassFunc[0]) - { - case GL_KEEP: - MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_keep); - break; - case GL_ZERO: - MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_zero); - break; - case GL_REPLACE: - MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_replace); - break; - case GL_INCR: - MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_incrsat); - break; - case GL_DECR: - MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_decrsat); - break; - case GL_INVERT: - MGA_SET_FIELD(stencilctl, SC_szpassop_MASK, SC_szpassop_invert); - break; - default: - break; - } - } - - mmesa->setup.stencil = stencil; - mmesa->setup.stencilctl = stencilctl; - mmesa->dirty |= MGA_UPLOAD_CONTEXT; -} - -static void mgaDDStencilFunc(GLcontext *ctx, GLenum func, GLint ref, - GLuint mask) -{ - FLUSH_BATCH( MGA_CONTEXT(ctx) ); - MGA_CONTEXT(ctx)->new_state |= MGA_NEW_STENCIL; -} - -static void mgaDDStencilMask(GLcontext *ctx, GLuint mask) -{ - FLUSH_BATCH( MGA_CONTEXT(ctx) ); - MGA_CONTEXT(ctx)->new_state |= MGA_NEW_STENCIL; -} - -static void mgaDDStencilOp(GLcontext *ctx, GLenum fail, GLenum zfail, - GLenum zpass) -{ - FLUSH_BATCH( MGA_CONTEXT(ctx) ); - MGA_CONTEXT(ctx)->new_state |= MGA_NEW_STENCIL; -} +/* ============================================================= + * Alpha blending + */ -static void mgaDDClearDepth(GLcontext *ctx, GLclampd d) +static void mgaDDAlphaFunc(GLcontext *ctx, GLenum func, GLfloat ref) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); + GLubyte refByte; + GLuint a; - /* KW: should the ~ be there? */ - switch (mmesa->setup.maccess & ~MA_zwidth_MASK) { - case MA_zwidth_16: mmesa->ClearDepth = d * 0x0000ffff; break; - case MA_zwidth_24: mmesa->ClearDepth = d * 0xffffff00; break; - case MA_zwidth_32: mmesa->ClearDepth = d * 0xffffffff; break; - default: return; - } -} - -static void mgaUpdateZMode(const GLcontext *ctx) -{ - mgaContextPtr mmesa = MGA_CONTEXT( ctx ); - int zmode = 0; - - if (ctx->Depth.Test) { - switch(ctx->Depth.Func) { - case GL_NEVER: - /* can't do this in h/w, we'll use a s/w fallback */ - zmode = DC_zmode_nozcmp; - break; - case GL_ALWAYS: - zmode = DC_zmode_nozcmp; break; - case GL_LESS: - zmode = DC_zmode_zlt; break; - case GL_LEQUAL: - zmode = DC_zmode_zlte; break; - case GL_EQUAL: - zmode = DC_zmode_ze; break; - case GL_GREATER: - zmode = DC_zmode_zgt; break; - case GL_GEQUAL: - zmode = DC_zmode_zgte; break; - case GL_NOTEQUAL: - zmode = DC_zmode_zne; break; - default: - break; - } + CLAMPED_FLOAT_TO_UBYTE(refByte, ref); - if (ctx->Depth.Mask) - zmode |= DC_atype_zi; - else - zmode |= DC_atype_i; - } - else { - zmode |= DC_zmode_nozcmp; - zmode |= DC_atype_i; /* don't write to zbuffer */ + switch ( func ) { + case GL_NEVER: + a = AC_atmode_alt; + refByte = 0; + break; + case GL_LESS: + a = AC_atmode_alt; + break; + case GL_GEQUAL: + a = AC_atmode_agte; + break; + case GL_LEQUAL: + a = AC_atmode_alte; + break; + case GL_GREATER: + a = AC_atmode_agt; + break; + case GL_NOTEQUAL: + a = AC_atmode_ane; + break; + case GL_EQUAL: + a = AC_atmode_ae; + break; + case GL_ALWAYS: + a = AC_atmode_noacmp; + break; + default: + a = 0; + break; } -#if defined(ACCEL_ROP) - mmesa->setup.dwgctl &= DC_bop_MASK; - if (ctx->Color.ColorLogicOpEnabled) - zmode |= mgarop_NoBLK[(ctx->Color.LogicOp)&0xf]; - else - zmode |= mgarop_NoBLK[GL_COPY & 0xf]; -#endif - - mmesa->setup.dwgctl &= DC_zmode_MASK & DC_atype_MASK; - mmesa->setup.dwgctl |= zmode; + FLUSH_BATCH( mmesa ); + mmesa->hw.alpha_func = a | MGA_FIELD( AC_atref, refByte ); mmesa->dirty |= MGA_UPLOAD_CONTEXT; } - -static void mgaDDAlphaFunc(GLcontext *ctx, GLenum func, GLfloat ref) -{ - FLUSH_BATCH( MGA_CONTEXT(ctx) ); - MGA_CONTEXT(ctx)->new_state |= MGA_NEW_ALPHA; -} - - static void mgaDDBlendEquation(GLcontext *ctx, GLenum mode) { FLUSH_BATCH( MGA_CONTEXT(ctx) ); - MGA_CONTEXT(ctx)->new_state |= MGA_NEW_ALPHA; /* BlendEquation sets ColorLogicOpEnabled in an unexpected * manner. @@ -291,247 +130,169 @@ static void mgaDDBlendEquation(GLcontext *ctx, GLenum mode) static void mgaDDBlendFunc(GLcontext *ctx, GLenum sfactor, GLenum dfactor) { - FLUSH_BATCH( MGA_CONTEXT(ctx) ); - MGA_CONTEXT(ctx)->new_state |= MGA_NEW_ALPHA; + mgaContextPtr mmesa = MGA_CONTEXT(ctx); + mgaScreenPrivate *mgaScreen = mmesa->mgaScreen; + GLuint src; + GLuint dst; + + switch (ctx->Color.BlendSrcRGB) { + case GL_ZERO: + src = AC_src_zero; break; + case GL_SRC_ALPHA: + src = AC_src_src_alpha; break; + case GL_ONE: + default: /* never happens */ + src = AC_src_one; break; + case GL_DST_COLOR: + src = AC_src_dst_color; break; + case GL_ONE_MINUS_DST_COLOR: + src = AC_src_om_dst_color; break; + case GL_ONE_MINUS_SRC_ALPHA: + src = AC_src_om_src_alpha; break; + case GL_DST_ALPHA: + src = (mgaScreen->cpp == 4) + ? AC_src_dst_alpha : AC_src_one; + break; + case GL_ONE_MINUS_DST_ALPHA: + src = (mgaScreen->cpp == 4) + ? AC_src_om_dst_alpha : AC_src_zero; + break; + case GL_SRC_ALPHA_SATURATE: + src = (ctx->Visual.alphaBits > 0) + ? AC_src_src_alpha_sat : AC_src_zero; + break; + } + + switch (ctx->Color.BlendDstRGB) { + case GL_SRC_ALPHA: + dst = AC_dst_src_alpha; break; + case GL_ONE_MINUS_SRC_ALPHA: + dst = AC_dst_om_src_alpha; break; + default: /* never happens */ + case GL_ZERO: + dst = AC_dst_zero; break; + case GL_ONE: + dst = AC_dst_one; break; + case GL_SRC_COLOR: + dst = AC_dst_src_color; break; + case GL_ONE_MINUS_SRC_COLOR: + dst = AC_dst_om_src_color; break; + case GL_DST_ALPHA: + dst = (mgaScreen->cpp == 4) + ? AC_dst_dst_alpha : AC_dst_one; + break; + case GL_ONE_MINUS_DST_ALPHA: + dst = (mgaScreen->cpp == 4) + ? AC_dst_om_dst_alpha : AC_dst_zero; + break; + } + + FLUSH_BATCH( mmesa ); + mmesa->hw.blend_func = (src | dst); + mmesa->dirty |= MGA_UPLOAD_CONTEXT; } static void mgaDDBlendFuncSeparate( GLcontext *ctx, GLenum sfactorRGB, GLenum dfactorRGB, GLenum sfactorA, GLenum dfactorA ) { - FLUSH_BATCH( MGA_CONTEXT(ctx) ); - MGA_CONTEXT(ctx)->new_state |= MGA_NEW_ALPHA; + mgaDDBlendFunc( ctx, sfactorRGB, dfactorRGB ); } +/* ============================================================= + * Depth testing + */ -static void mgaDDLightModelfv(GLcontext *ctx, GLenum pname, - const GLfloat *param) +static void mgaDDDepthFunc(GLcontext *ctx, GLenum func) { - if (pname == GL_LIGHT_MODEL_COLOR_CONTROL) { - FLUSH_BATCH( MGA_CONTEXT(ctx) ); - MGA_CONTEXT(ctx)->new_state |= MGA_NEW_TEXTURE; + mgaContextPtr mmesa = MGA_CONTEXT( ctx ); + int zmode; + + switch (func) { + case GL_NEVER: + /* can't do this in h/w, we'll use a s/w fallback */ + FALLBACK (ctx, MGA_FALLBACK_DEPTH, ctx->Depth.Test); + + /* FALLTHROUGH */ + case GL_ALWAYS: + zmode = DC_zmode_nozcmp; break; + case GL_LESS: + zmode = DC_zmode_zlt; break; + case GL_LEQUAL: + zmode = DC_zmode_zlte; break; + case GL_EQUAL: + zmode = DC_zmode_ze; break; + case GL_GREATER: + zmode = DC_zmode_zgt; break; + case GL_GEQUAL: + zmode = DC_zmode_zgte; break; + case GL_NOTEQUAL: + zmode = DC_zmode_zne; break; + default: + zmode = 0; break; } -} - -static void mgaDDShadeModel(GLcontext *ctx, GLenum mode) -{ - FLUSH_BATCH( MGA_CONTEXT(ctx) ); - MGA_CONTEXT(ctx)->new_state |= MGA_NEW_TEXTURE; -} - - -static void mgaDDDepthFunc(GLcontext *ctx, GLenum func) -{ - FLUSH_BATCH( MGA_CONTEXT(ctx) ); - MGA_CONTEXT(ctx)->new_state |= MGA_NEW_DEPTH; + FLUSH_BATCH( mmesa ); + mmesa->hw.zmode &= DC_zmode_MASK; + mmesa->hw.zmode |= zmode; + mmesa->dirty |= MGA_UPLOAD_CONTEXT; } static void mgaDDDepthMask(GLcontext *ctx, GLboolean flag) { - FLUSH_BATCH( MGA_CONTEXT(ctx) ); - MGA_CONTEXT(ctx)->new_state |= MGA_NEW_DEPTH; -} + mgaContextPtr mmesa = MGA_CONTEXT( ctx ); -#if defined(ACCEL_ROP) -static void mgaDDLogicOp( GLcontext *ctx, GLenum opcode ) -{ - FLUSH_BATCH( MGA_CONTEXT(ctx) ); - MGA_CONTEXT(ctx)->new_state |= MGA_NEW_DEPTH; -} -#else -static void mgaDDLogicOp( GLcontext *ctx, GLenum opcode ) -{ - FLUSH_BATCH( MGA_CONTEXT(ctx) ); - FALLBACK( ctx, MGA_FALLBACK_LOGICOP, - (ctx->Color.ColorLogicOpEnabled && opcode != GL_COPY) ); -} -#endif + FLUSH_BATCH( mmesa ); + mmesa->hw.zmode &= DC_atype_MASK; + mmesa->hw.zmode |= (flag) ? DC_atype_zi : DC_atype_i; + mmesa->dirty |= MGA_UPLOAD_CONTEXT; +} -static void mgaDDFogfv(GLcontext *ctx, GLenum pname, const GLfloat *param) +static void mgaDDClearDepth(GLcontext *ctx, GLclampd d) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); - if (pname == GL_FOG_COLOR) { - GLuint color = MGAPACKCOLOR888((GLubyte)(ctx->Fog.Color[0]*255.0F), - (GLubyte)(ctx->Fog.Color[1]*255.0F), - (GLubyte)(ctx->Fog.Color[2]*255.0F)); - - MGA_STATECHANGE(mmesa, MGA_UPLOAD_CONTEXT); - mmesa->setup.fogcolor = color; + /* Select the Z depth. The ~ is used because the _MASK values in the + * MGA driver are used to mask OFF the selected bits. In this case, + * we want to mask off everything except the MA_zwidth bits. + */ + switch (mmesa->setup.maccess & ~MA_zwidth_MASK) { + case MA_zwidth_16: mmesa->ClearDepth = d * 0x0000ffff; break; + case MA_zwidth_24: mmesa->ClearDepth = d * 0xffffff00; break; + case MA_zwidth_32: mmesa->ClearDepth = d * 0xffffffff; break; + default: return; } } - - /* ============================================================= - * Alpha blending + * Fog */ -static void mgaUpdateAlphaMode(GLcontext *ctx) +static void mgaDDFogfv(GLcontext *ctx, GLenum pname, const GLfloat *param) { - mgaContextPtr mmesa = MGA_CONTEXT( ctx ); - mgaScreenPrivate *mgaScreen = mmesa->mgaScreen; - int a = 0; - - /* determine source of alpha for blending and testing */ - if ( !ctx->Texture.Unit[0]._ReallyEnabled ) { - a |= AC_alphasel_diffused; - } - else { - /* G400: Regardless of texture env mode, we use the alpha from the - * texture unit (AC_alphasel_fromtex) since it will have already - * been modulated by the incoming fragment color, if needed. - * We don't want (AC_alphasel_modulate) since that'll effectively - * do the modulation twice. - */ - if (MGA_IS_G400(mmesa)) { - a |= AC_alphasel_fromtex; - } - else { - /* G200 */ - switch (ctx->Texture.Unit[0].EnvMode) { - case GL_DECAL: - a |= AC_alphasel_diffused; - case GL_REPLACE: - a |= AC_alphasel_fromtex; - break; - case GL_BLEND: - case GL_MODULATE: - a |= AC_alphasel_modulated; - break; - default: - break; - } - } - } - - - /* alpha test control. - */ - if (ctx->Color.AlphaEnabled) { - GLubyte ref = ctx->Color.AlphaRef; - switch (ctx->Color.AlphaFunc) { - case GL_NEVER: - a |= AC_atmode_alt; - ref = 0; - break; - case GL_LESS: - a |= AC_atmode_alt; - break; - case GL_GEQUAL: - a |= AC_atmode_agte; - break; - case GL_LEQUAL: - a |= AC_atmode_alte; - break; - case GL_GREATER: - a |= AC_atmode_agt; - break; - case GL_NOTEQUAL: - a |= AC_atmode_ane; - break; - case GL_EQUAL: - a |= AC_atmode_ae; - break; - case GL_ALWAYS: - a |= AC_atmode_noacmp; - break; - default: - break; - } - a |= MGA_FIELD(AC_atref,ref); - } + mgaContextPtr mmesa = MGA_CONTEXT(ctx); - /* blending control */ - if (ctx->Color.BlendEnabled) { - switch (ctx->Color.BlendSrcRGB) { - case GL_ZERO: - a |= AC_src_zero; break; - case GL_SRC_ALPHA: - a |= AC_src_src_alpha; break; - case GL_ONE: - a |= AC_src_one; break; - case GL_DST_COLOR: - a |= AC_src_dst_color; break; - case GL_ONE_MINUS_DST_COLOR: - a |= AC_src_om_dst_color; break; - case GL_ONE_MINUS_SRC_ALPHA: - a |= AC_src_om_src_alpha; break; - case GL_DST_ALPHA: - if (mgaScreen->cpp == 4) - a |= AC_src_dst_alpha; - else - a |= AC_src_one; - break; - case GL_ONE_MINUS_DST_ALPHA: - if (mgaScreen->cpp == 4) - a |= AC_src_om_dst_alpha; - else - a |= AC_src_zero; - break; - case GL_SRC_ALPHA_SATURATE: - if (ctx->Visual.alphaBits > 0) - a |= AC_src_src_alpha_sat; - else - a |= AC_src_zero; - break; - default: /* never happens */ - break; - } + if (pname == GL_FOG_COLOR) { + GLuint color = PACK_COLOR_888((GLubyte)(ctx->Fog.Color[0]*255.0F), + (GLubyte)(ctx->Fog.Color[1]*255.0F), + (GLubyte)(ctx->Fog.Color[2]*255.0F)); - switch (ctx->Color.BlendDstRGB) { - case GL_SRC_ALPHA: - a |= AC_dst_src_alpha; break; - case GL_ONE_MINUS_SRC_ALPHA: - a |= AC_dst_om_src_alpha; break; - case GL_ZERO: - a |= AC_dst_zero; break; - case GL_ONE: - a |= AC_dst_one; break; - case GL_SRC_COLOR: - a |= AC_dst_src_color; break; - case GL_ONE_MINUS_SRC_COLOR: - a |= AC_dst_om_src_color; break; - case GL_DST_ALPHA: - if (mgaScreen->cpp == 4) - a |= AC_dst_dst_alpha; - else - a |= AC_dst_one; - break; - case GL_ONE_MINUS_DST_ALPHA: - if (mgaScreen->cpp == 4) - a |= AC_dst_om_dst_alpha; - else - a |= AC_dst_zero; - break; - default: /* never happens */ - break; - } - } else { - a |= AC_src_one|AC_dst_zero; + MGA_STATECHANGE(mmesa, MGA_UPLOAD_CONTEXT); + mmesa->setup.fogcolor = color; } - - mmesa->setup.alphactrl = (AC_amode_alpha_channel | - AC_astipple_disable | - AC_aten_disable | - AC_atmode_noacmp | - a); - - mmesa->dirty |= MGA_UPLOAD_CONTEXT; } - /* ============================================================= - * Hardware clipping + * Scissoring */ + void mgaUpdateClipping(const GLcontext *ctx) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); @@ -554,13 +315,6 @@ void mgaUpdateClipping(const GLcontext *ctx) mmesa->scissor_rect.x2 = x2; mmesa->scissor_rect.y2 = y2; - if (MGA_DEBUG&DEBUG_VERBOSE_2D) - fprintf(stderr, "SET SCISSOR %d,%d-%d,%d\n", - mmesa->scissor_rect.x1, - mmesa->scissor_rect.y1, - mmesa->scissor_rect.x2, - mmesa->scissor_rect.y2); - mmesa->dirty |= MGA_UPLOAD_CLIPRECTS; } } @@ -569,19 +323,10 @@ void mgaUpdateClipping(const GLcontext *ctx) static void mgaDDScissor( GLcontext *ctx, GLint x, GLint y, GLsizei w, GLsizei h ) { - FLUSH_BATCH( MGA_CONTEXT(ctx) ); - MGA_CONTEXT(ctx)->new_state |= MGA_NEW_CLIP; -} - - -static void mgaDDClearColor(GLcontext *ctx, - const GLfloat color[4] ) -{ - mgaContextPtr mmesa = MGA_CONTEXT(ctx); - - mmesa->ClearColor = mgaPackColor( mmesa->mgaScreen->cpp, - color[0], color[1], - color[2], color[3]); + if ( ctx->Scissor.Enabled ) { + FLUSH_BATCH( MGA_CONTEXT(ctx) ); /* don't pipeline cliprect changes */ + mgaUpdateClipping( ctx ); + } } @@ -589,46 +334,42 @@ static void mgaDDClearColor(GLcontext *ctx, * Culling */ + #define _CULL_DISABLE 0 #define _CULL_NEGATIVE ((1<<11)|(1<<5)|(1<<16)) #define _CULL_POSITIVE (1<<11) - -void mgaUpdateCull( GLcontext *ctx ) +static void mgaDDCullFaceFrontFace(GLcontext *ctx, GLenum unused) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); - GLuint mode = _CULL_DISABLE; + + FLUSH_BATCH( mmesa ); if (ctx->Polygon.CullFlag && - mmesa->raster_primitive == GL_TRIANGLES && ctx->Polygon.CullFaceMode != GL_FRONT_AND_BACK) { - mode = _CULL_NEGATIVE; + mmesa->hw.cull = _CULL_NEGATIVE; + if (ctx->Polygon.CullFaceMode == GL_FRONT) - mode ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE); + mmesa->hw.cull ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE); + if (ctx->Polygon.FrontFace != GL_CCW) - mode ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE); - if ((ctx->Texture.Unit[0]._ReallyEnabled & TEXTURE_2D_BIT) && - (ctx->Texture.Unit[1]._ReallyEnabled & TEXTURE_2D_BIT)) - mode ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE); /* warp bug? */ + mmesa->hw.cull ^= (_CULL_POSITIVE ^ _CULL_NEGATIVE); + + mmesa->hw.cull_dualtex = mmesa->hw.cull ^ + (_CULL_POSITIVE ^ _CULL_NEGATIVE); /* warp bug? */ + } + else { + mmesa->hw.cull = _CULL_DISABLE; + mmesa->hw.cull_dualtex = _CULL_DISABLE; } - mmesa->setup.wflag = mode; mmesa->dirty |= MGA_UPLOAD_CONTEXT; } -static void mgaDDCullFaceFrontFace(GLcontext *ctx, GLenum mode) -{ - FLUSH_BATCH( MGA_CONTEXT(ctx) ); - MGA_CONTEXT(ctx)->new_state |= MGA_NEW_CULL; -} - - - - /* ============================================================= - * Color masks + * Masks */ static void mgaDDColorMask(GLcontext *ctx, @@ -654,15 +395,11 @@ static void mgaDDColorMask(GLcontext *ctx, } } + /* ============================================================= - * Polygon stipple - * - * The mga supports a subset of possible 4x4 stipples natively, GL - * wants 32x32. Fortunately stipple is usually a repeating pattern. - * - * Note: the fully opaque pattern (0xffff) has been disabled in order - * to work around a conformance issue. + * Polygon state */ + static int mgaStipples[16] = { 0xffff1, /* See above note */ 0xa5a5, @@ -682,6 +419,17 @@ static int mgaStipples[16] = { 0x0000 }; +/** + * The MGA supports a subset of possible 4x4 stipples natively, GL + * wants 32x32. Fortunately stipple is usually a repeating pattern. + * + * \param ctx GL rendering context to be affected + * \param mask Pointer to the 32x32 stipple mask + * + * \note the fully opaque pattern (0xffff) has been disabled in order + * to work around a conformance issue. + */ + static void mgaDDPolygonStipple( GLcontext *ctx, const GLubyte *mask ) { mgaContextPtr mmesa = MGA_CONTEXT(ctx); @@ -730,93 +478,216 @@ static void mgaDDPolygonStipple( GLcontext *ctx, const GLubyte *mask ) } } + /* ============================================================= + * Rendering attributes + * + * We really don't want to recalculate all this every time we bind a + * texture. These things shouldn't change all that often, so it makes + * sense to break them out of the core texture state update routines. */ -static void mgaDDPrintDirty( const char *msg, GLuint state ) +static void updateSpecularLighting( GLcontext *ctx ) { - fprintf(stderr, "%s (0x%x): %s%s%s%s%s%s%s\n", - msg, - (unsigned int) state, - (state & MGA_WAIT_AGE) ? "wait-age, " : "", - (state & MGA_UPLOAD_TEX0IMAGE) ? "upload-tex0-img, " : "", - (state & MGA_UPLOAD_TEX1IMAGE) ? "upload-tex1-img, " : "", - (state & MGA_UPLOAD_CONTEXT) ? "upload-ctx, " : "", - (state & MGA_UPLOAD_TEX0) ? "upload-tex0, " : "", - (state & MGA_UPLOAD_TEX1) ? "upload-tex1, " : "", - (state & MGA_UPLOAD_PIPE) ? "upload-pipe, " : "" - ); + mgaContextPtr mmesa = MGA_CONTEXT(ctx); + unsigned int specen; + + specen = (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR && + ctx->Light.Enabled) ? TMC_specen_enable : 0; + + if ( specen != mmesa->hw.specen ) { + mmesa->hw.specen = specen; + mmesa->dirty |= MGA_UPLOAD_TEX0 | MGA_UPLOAD_TEX1; + + mgaChooseVertexState( ctx ); + } } -/* Push the state into the sarea and/or texture memory. + +/* ============================================================= + * Materials */ -void mgaEmitHwStateLocked( mgaContextPtr mmesa ) -{ - MGASAREAPrivPtr sarea = mmesa->sarea; - if (MGA_DEBUG & DEBUG_VERBOSE_MSG) - mgaDDPrintDirty( "mgaEmitHwStateLocked", mmesa->dirty ); - if ((mmesa->dirty & MGA_UPLOAD_TEX0IMAGE) && mmesa->CurrentTexObj[0]) - mgaUploadTexImages(mmesa, mmesa->CurrentTexObj[0]); +static void mgaDDLightModelfv(GLcontext *ctx, GLenum pname, + const GLfloat *param) +{ + if (pname == GL_LIGHT_MODEL_COLOR_CONTROL) { + FLUSH_BATCH( MGA_CONTEXT(ctx) ); + updateSpecularLighting( ctx ); + } +} - if ((mmesa->dirty & MGA_UPLOAD_TEX1IMAGE) && mmesa->CurrentTexObj[1]) - mgaUploadTexImages(mmesa, mmesa->CurrentTexObj[1]); - if (mmesa->dirty & MGA_UPLOAD_CONTEXT) { - memcpy( &sarea->ContextState, &mmesa->setup, sizeof(mmesa->setup)); - } +static void mgaDDShadeModel(GLcontext *ctx, GLenum mode) +{ + /* FIXME: This used to FLUSH_BATCH and set MGA_NEW_TEXTURE in new_state, + * FIXME: so I'm not sure what to do here now. + */ +} - if ((mmesa->dirty & MGA_UPLOAD_TEX0) && mmesa->CurrentTexObj[0]) { - memcpy(&sarea->TexState[0], - &mmesa->CurrentTexObj[0]->setup, - sizeof(sarea->TexState[0])); - } - if ((mmesa->dirty & MGA_UPLOAD_TEX1) && mmesa->CurrentTexObj[1]) { - memcpy(&sarea->TexState[1], - &mmesa->CurrentTexObj[1]->setup, - sizeof(sarea->TexState[1])); - } +/* ============================================================= + * Stencil + */ - if (sarea->TexState[0].texctl2 != - sarea->TexState[1].texctl2) { - memcpy(&sarea->TexState[1], - &sarea->TexState[0], - sizeof(sarea->TexState[0])); - mmesa->dirty |= MGA_UPLOAD_TEX1|MGA_UPLOAD_TEX0; - } - if (mmesa->dirty & MGA_UPLOAD_PIPE) { -/* mmesa->sarea->wacceptseq = mmesa->hw_primitive; */ - mmesa->sarea->WarpPipe = mmesa->vertex_format; - mmesa->sarea->vertsize = mmesa->vertex_size; +static void mgaDDStencilFunc(GLcontext *ctx, GLenum func, GLint ref, + GLuint mask) +{ + mgaContextPtr mmesa = MGA_CONTEXT(ctx); + GLuint stencil; + GLuint stencilctl; + + stencil = (ref << S_sref_SHIFT) | (mask << S_smsk_SHIFT); + switch (func) + { + case GL_NEVER: + stencilctl = SC_smode_snever; + break; + case GL_LESS: + stencilctl = SC_smode_slt; + break; + case GL_LEQUAL: + stencilctl = SC_smode_slte; + break; + case GL_GREATER: + stencilctl = SC_smode_sgt; + break; + case GL_GEQUAL: + stencilctl = SC_smode_sgte; + break; + case GL_NOTEQUAL: + stencilctl = SC_smode_sne; + break; + case GL_EQUAL: + stencilctl = SC_smode_se; + break; + case GL_ALWAYS: + default: + stencilctl = SC_smode_salways; + break; } - mmesa->sarea->dirty |= mmesa->dirty; + FLUSH_BATCH( mmesa ); + mmesa->hw.stencil &= (S_sref_MASK & S_smsk_MASK); + mmesa->hw.stencil |= stencil; + mmesa->hw.stencilctl &= SC_smode_MASK; + mmesa->hw.stencilctl |= stencilctl; + mmesa->dirty |= MGA_UPLOAD_CONTEXT; +} - mmesa->dirty &= (MGA_UPLOAD_CLIPRECTS|MGA_WAIT_AGE); +static void mgaDDStencilMask(GLcontext *ctx, GLuint mask) +{ + mgaContextPtr mmesa = MGA_CONTEXT(ctx); - /* This is a bit of a hack but seems to be the best place to ensure - * that separate specular is disabled when not needed. - */ - if (mmesa->glCtx->Texture.Unit[0]._ReallyEnabled == 0 || - !mmesa->glCtx->Light.Enabled || - mmesa->glCtx->Light.Model.ColorControl == GL_SINGLE_COLOR) { - sarea->TexState[0].texctl2 &= ~TMC_specen_enable; - sarea->TexState[1].texctl2 &= ~TMC_specen_enable; - } + FLUSH_BATCH( mmesa ); + mmesa->hw.stencil &= S_swtmsk_MASK; + mmesa->hw.stencil |= (mask << S_swtmsk_SHIFT); + mmesa->dirty |= MGA_UPLOAD_CONTEXT; } -/* Fallback to swrast for select and feedback. - */ -static void mgaRenderMode( GLcontext *ctx, GLenum mode ) +static void mgaDDStencilOp(GLcontext *ctx, GLenum fail, GLenum zfail, + GLenum zpass) { - FALLBACK( ctx, MGA_FALLBACK_RENDERMODE, (mode != GL_RENDER) ); + mgaContextPtr mmesa = MGA_CONTEXT(ctx); + GLuint stencilctl; + + stencilctl = 0; + switch (ctx->Stencil.FailFunc[0]) + { + case GL_KEEP: + stencilctl |= SC_sfailop_keep; + break; + case GL_ZERO: + stencilctl |= SC_sfailop_zero; + break; + case GL_REPLACE: + stencilctl |= SC_sfailop_replace; + break; + case GL_INCR: + stencilctl |= SC_sfailop_incrsat; + break; + case GL_DECR: + stencilctl |= SC_sfailop_decrsat; + break; + case GL_INCR_WRAP: + stencilctl |= SC_sfailop_incr; + break; + case GL_DECR_WRAP: + stencilctl |= SC_sfailop_decr; + break; + case GL_INVERT: + stencilctl |= SC_sfailop_invert; + break; + default: + break; + } + + switch (ctx->Stencil.ZFailFunc[0]) + { + case GL_KEEP: + stencilctl |= SC_szfailop_keep; + break; + case GL_ZERO: + stencilctl |= SC_szfailop_zero; + break; + case GL_REPLACE: + stencilctl |= SC_szfailop_replace; + break; + case GL_INCR: + stencilctl |= SC_szfailop_incrsat; + break; + case GL_DECR: + stencilctl |= SC_szfailop_decrsat; + break; + case GL_INCR_WRAP: + stencilctl |= SC_szfailop_incr; + break; + case GL_DECR_WRAP: + stencilctl |= SC_szfailop_decr; + break; + case GL_INVERT: + stencilctl |= SC_szfailop_invert; + break; + default: + break; + } + + switch (ctx->Stencil.ZPassFunc[0]) + { + case GL_KEEP: + stencilctl |= SC_szpassop_keep; + break; + case GL_ZERO: + stencilctl |= SC_szpassop_zero; + break; + case GL_REPLACE: + stencilctl |= SC_szpassop_replace; + break; + case GL_INCR: + stencilctl |= SC_szpassop_incrsat; + break; + case GL_DECR: + stencilctl |= SC_szpassop_decrsat; + break; + case GL_INVERT: + stencilctl |= SC_szpassop_invert; + break; + default: + break; + } + + FLUSH_BATCH( mmesa ); + mmesa->hw.stencilctl &= (SC_sfailop_MASK & SC_szfailop_MASK + & SC_szpassop_MASK); + mmesa->hw.stencilctl |= stencilctl; + mmesa->dirty |= MGA_UPLOAD_CONTEXT; } /* ============================================================= + * Window position and viewport transformation */ void mgaCalcViewport( GLcontext *ctx ) @@ -850,8 +721,167 @@ static void mgaDepthRange( GLcontext *ctx, mgaCalcViewport( ctx ); } + /* ============================================================= + * Miscellaneous + */ + +static void mgaDDClearColor(GLcontext *ctx, + const GLfloat color[4] ) +{ + mgaContextPtr mmesa = MGA_CONTEXT(ctx); + GLubyte c[4]; + CLAMPED_FLOAT_TO_UBYTE(c[0], color[0]); + CLAMPED_FLOAT_TO_UBYTE(c[1], color[1]); + CLAMPED_FLOAT_TO_UBYTE(c[2], color[2]); + CLAMPED_FLOAT_TO_UBYTE(c[3], color[3]); + + mmesa->ClearColor = mgaPackColor( mmesa->mgaScreen->cpp, + c[0], c[1], c[2], c[3]); +} + + +/* Fallback to swrast for select and feedback. */ +static void mgaRenderMode( GLcontext *ctx, GLenum mode ) +{ + FALLBACK( ctx, MGA_FALLBACK_RENDERMODE, (mode != GL_RENDER) ); +} + + +static void mgaDDLogicOp( GLcontext *ctx, GLenum opcode ) +{ + mgaContextPtr mmesa = MGA_CONTEXT( ctx ); + + FLUSH_BATCH( mmesa ); +#if defined(ACCEL_ROP) + mmesa->hw.rop = mgarop_NoBLK[ opcode & 0x0f ]; + mmesa->dirty |= MGA_UPLOAD_CONTEXT; +#else + FALLBACK( ctx, MGA_FALLBACK_LOGICOP, + (ctx->Color.ColorLogicOpEnabled && opcode != GL_COPY) ); +#endif +} + + +static void mgaXMesaSetFrontClipRects( mgaContextPtr mmesa ) +{ + __DRIdrawablePrivate *driDrawable = mmesa->driDrawable; + + if (driDrawable->numClipRects == 0) { + static XF86DRIClipRectRec zeroareacliprect = {0,0,0,0}; + mmesa->numClipRects = 1; + mmesa->pClipRects = &zeroareacliprect; + } else { + mmesa->numClipRects = driDrawable->numClipRects; + mmesa->pClipRects = driDrawable->pClipRects; + } + mmesa->drawX = driDrawable->x; + mmesa->drawY = driDrawable->y; + + mmesa->setup.dstorg = mmesa->drawOffset; + mmesa->dirty |= MGA_UPLOAD_CONTEXT | MGA_UPLOAD_CLIPRECTS; +} + + +static void mgaXMesaSetBackClipRects( mgaContextPtr mmesa ) +{ + __DRIdrawablePrivate *driDrawable = mmesa->driDrawable; + + if (driDrawable->numBackClipRects == 0) + { + if (driDrawable->numClipRects == 0) { + static XF86DRIClipRectRec zeroareacliprect = {0,0,0,0}; + mmesa->numClipRects = 1; + mmesa->pClipRects = &zeroareacliprect; + } else { + mmesa->numClipRects = driDrawable->numClipRects; + mmesa->pClipRects = driDrawable->pClipRects; + } + mmesa->drawX = driDrawable->x; + mmesa->drawY = driDrawable->y; + } else { + mmesa->numClipRects = driDrawable->numBackClipRects; + mmesa->pClipRects = driDrawable->pBackClipRects; + mmesa->drawX = driDrawable->backX; + mmesa->drawY = driDrawable->backY; + } + + mmesa->setup.dstorg = mmesa->drawOffset; + mmesa->dirty |= MGA_UPLOAD_CONTEXT | MGA_UPLOAD_CLIPRECTS; +} + + +void mgaUpdateRects( mgaContextPtr mmesa, GLuint buffers ) +{ + __DRIdrawablePrivate *driDrawable = mmesa->driDrawable; + MGASAREAPrivPtr sarea = mmesa->sarea; + + + DRI_VALIDATE_DRAWABLE_INFO(mmesa->driScreen, driDrawable); + mmesa->dirty_cliprects = 0; + + if (mmesa->draw_buffer == MGA_FRONT) + mgaXMesaSetFrontClipRects( mmesa ); + else + mgaXMesaSetBackClipRects( mmesa ); + + sarea->req_draw_buffer = mmesa->draw_buffer; + + mgaUpdateClipping( mmesa->glCtx ); + mgaCalcViewport( mmesa->glCtx ); + + mmesa->dirty |= MGA_UPLOAD_CLIPRECTS; +} + + +static void mgaDDDrawBuffer(GLcontext *ctx, GLenum mode ) +{ + mgaContextPtr mmesa = MGA_CONTEXT(ctx); + + FLUSH_BATCH( mmesa ); + + /* + * _DrawDestMask is easier to cope with than <mode>. + */ + switch ( ctx->Color._DrawDestMask ) { + case FRONT_LEFT_BIT: + mmesa->setup.dstorg = mmesa->mgaScreen->frontOffset; + mmesa->dirty |= MGA_UPLOAD_CONTEXT; + mmesa->draw_buffer = MGA_FRONT; + mgaXMesaSetFrontClipRects( mmesa ); + FALLBACK( ctx, MGA_FALLBACK_DRAW_BUFFER, GL_FALSE ); + break; + case BACK_LEFT_BIT: + mmesa->setup.dstorg = mmesa->mgaScreen->backOffset; + mmesa->draw_buffer = MGA_BACK; + mmesa->dirty |= MGA_UPLOAD_CONTEXT; + mgaXMesaSetBackClipRects( mmesa ); + FALLBACK( ctx, MGA_FALLBACK_DRAW_BUFFER, GL_FALSE ); + break; + default: + /* GL_NONE or GL_FRONT_AND_BACK or stereo left&right, etc */ + FALLBACK( ctx, MGA_FALLBACK_DRAW_BUFFER, GL_TRUE ); + return; + } + + /* We want to update the s/w rast state too so that r200SetBuffer() + * gets called. + */ + _swrast_DrawBuffer(ctx, mode); +} + + +static void mgaDDReadBuffer(GLcontext *ctx, GLenum mode ) +{ + /* nothing, until we implement h/w glRead/CopyPixels or CopyTexImage */ +} + + +/* ============================================================= + * State enable/disable + */ + static void mgaDDEnable(GLcontext *ctx, GLenum cap, GLboolean state) { @@ -860,11 +890,11 @@ static void mgaDDEnable(GLcontext *ctx, GLenum cap, GLboolean state) switch(cap) { case GL_ALPHA_TEST: FLUSH_BATCH( mmesa ); - mmesa->new_state |= MGA_NEW_ALPHA; + mmesa->hw.alpha_func_enable = (state) ? ~0 : 0; break; case GL_BLEND: FLUSH_BATCH( mmesa ); - mmesa->new_state |= MGA_NEW_ALPHA; + mmesa->hw.blend_func_enable = (state) ? ~0 : 0; /* For some reason enable(GL_BLEND) affects ColorLogicOpEnabled. */ @@ -874,31 +904,31 @@ static void mgaDDEnable(GLcontext *ctx, GLenum cap, GLboolean state) break; case GL_DEPTH_TEST: FLUSH_BATCH( mmesa ); - mmesa->new_state |= MGA_NEW_DEPTH; FALLBACK (ctx, MGA_FALLBACK_DEPTH, ctx->Depth.Func == GL_NEVER && ctx->Depth.Test); break; + case GL_SCISSOR_TEST: FLUSH_BATCH( mmesa ); mmesa->scissor = state; - mmesa->new_state |= MGA_NEW_CLIP; + mgaUpdateClipping( ctx ); break; + case GL_FOG: MGA_STATECHANGE( mmesa, MGA_UPLOAD_CONTEXT ); if (ctx->Fog.Enabled) mmesa->setup.maccess |= MA_fogen_enable; else mmesa->setup.maccess &= ~MA_fogen_enable; + + mgaChooseVertexState( ctx ); break; case GL_CULL_FACE: - FLUSH_BATCH( mmesa ); - mmesa->new_state |= MGA_NEW_CULL; + mgaDDCullFaceFrontFace( ctx, 0 ); break; case GL_TEXTURE_1D: case GL_TEXTURE_2D: case GL_TEXTURE_3D: - FLUSH_BATCH( mmesa ); - mmesa->new_state |= (MGA_NEW_TEXTURE|MGA_NEW_ALPHA); break; case GL_POLYGON_STIPPLE: if (mmesa->haveHwStipple && mmesa->raster_primitive == GL_TRIANGLES) { @@ -914,16 +944,16 @@ static void mgaDDEnable(GLcontext *ctx, GLenum cap, GLboolean state) #if !defined(ACCEL_ROP) FALLBACK( ctx, MGA_FALLBACK_LOGICOP, (state && ctx->Color.LogicOp != GL_COPY)); -#else - mmesa->new_state |= MGA_NEW_DEPTH; #endif break; case GL_STENCIL_TEST: FLUSH_BATCH( mmesa ); - if (mmesa->hw_stencil) - mmesa->new_state |= MGA_NEW_STENCIL; - else + if (mmesa->hw_stencil) { + mmesa->hw.stencil_enable = ( state ) ? ~0 : 0; + } + else { FALLBACK( ctx, MGA_FALLBACK_STENCIL, state ); + } default: break; } @@ -933,56 +963,150 @@ static void mgaDDEnable(GLcontext *ctx, GLenum cap, GLboolean state) /* ============================================================= */ - - -/* ============================================================= - */ - -static void mgaDDPrintState( const char *msg, GLuint state ) +static void mgaDDPrintDirty( const char *msg, GLuint state ) { - fprintf(stderr, "%s (0x%x): %s%s%s%s%s%s\n", + fprintf(stderr, "%s (0x%03x): %s%s%s%s%s%s%s\n", msg, - state, - (state & MGA_NEW_DEPTH) ? "depth, " : "", - (state & MGA_NEW_ALPHA) ? "alpha, " : "", - (state & MGA_NEW_CLIP) ? "clip, " : "", - (state & MGA_NEW_CULL) ? "cull, " : "", - (state & MGA_NEW_TEXTURE) ? "texture, " : "", - (state & MGA_NEW_CONTEXT) ? "context, " : ""); + (unsigned int) state, + (state & MGA_WAIT_AGE) ? "wait-age " : "", + (state & MGA_UPLOAD_TEX0IMAGE) ? "upload-tex0-img " : "", + (state & MGA_UPLOAD_TEX1IMAGE) ? "upload-tex1-img " : "", + (state & MGA_UPLOAD_CONTEXT) ? "upload-ctx " : "", + (state & MGA_UPLOAD_TEX0) ? "upload-tex0 " : "", + (state & MGA_UPLOAD_TEX1) ? "upload-tex1 " : "", + (state & MGA_UPLOAD_PIPE) ? "upload-pipe " : "" + ); } -void mgaDDUpdateHwState( GLcontext *ctx ) +/* Push the state into the sarea and/or texture memory. + */ +void mgaEmitHwStateLocked( mgaContextPtr mmesa ) { - mgaContextPtr mmesa = MGA_CONTEXT( ctx ); - int new_state = mmesa->new_state; + MGASAREAPrivPtr sarea = mmesa->sarea; + GLcontext * ctx = mmesa->glCtx; - if (new_state) - { - FLUSH_BATCH( mmesa ); + if (MGA_DEBUG & DEBUG_VERBOSE_MSG) + mgaDDPrintDirty( __FUNCTION__, mmesa->dirty ); - mmesa->new_state = 0; + if (mmesa->dirty & MGA_UPLOAD_CONTEXT) { + mmesa->setup.wflag = _CULL_DISABLE; + if (mmesa->raster_primitive == GL_TRIANGLES) { + if ((ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT && + ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT)) { + mmesa->setup.wflag = mmesa->hw.cull_dualtex; + } + else { + mmesa->setup.wflag = mmesa->hw.cull; + } + } - if (MESA_VERBOSE&VERBOSE_DRIVER) - mgaDDPrintState("UpdateHwState", new_state); + mmesa->setup.stencil = mmesa->hw.stencil + & mmesa->hw.stencil_enable; + mmesa->setup.stencilctl = mmesa->hw.stencilctl + & mmesa->hw.stencil_enable; - if (new_state & MGA_NEW_DEPTH) - mgaUpdateZMode(ctx); + /* If depth testing is not enabled, then use the no Z-compare / no + * Z-write mode. Otherwise, use whatever is set in hw.zmode. + */ + mmesa->setup.dwgctl &= (DC_zmode_MASK & DC_atype_MASK); + mmesa->setup.dwgctl |= (ctx->Depth.Test) + ? mmesa->hw.zmode : (DC_zmode_nozcmp | DC_atype_i); - if (new_state & MGA_NEW_ALPHA) - mgaUpdateAlphaMode(ctx); +#if defined(ACCEL_ROP) + mmesa->setup.dwgctl &= DC_bop_MASK; + mmesa->setup.dwgctl |= (ctx->Color.ColorLogicOpEnabled) + ? mmesa->hw.rop : mgarop_NoBLK[ GL_COPY & 0x0f ]; +#endif - if (new_state & MGA_NEW_CLIP) - mgaUpdateClipping(ctx); + mmesa->setup.alphactrl &= AC_src_MASK & AC_dst_MASK & AC_atmode_MASK + & AC_atref_MASK & AC_alphasel_MASK; + mmesa->setup.alphactrl |= + ((mmesa->hw.alpha_func & mmesa->hw.alpha_func_enable) + | ((mmesa->hw.blend_func & mmesa->hw.blend_func_enable) + | ((AC_src_one | AC_dst_zero) & ~mmesa->hw.blend_func_enable)) + | mmesa->hw.alpha_sel + | (AC_amode_alpha_channel + | AC_astipple_disable + | AC_aten_disable + | AC_atmode_noacmp)); - if (new_state & MGA_NEW_STENCIL) - mgaUpdateStencil(ctx); + memcpy( &sarea->ContextState, &mmesa->setup, sizeof(mmesa->setup)); + } - if (new_state & (MGA_NEW_WARP|MGA_NEW_CULL)) - mgaUpdateCull(ctx); + if ((mmesa->dirty & MGA_UPLOAD_TEX0) && mmesa->CurrentTexObj[0]) { + mmesa->CurrentTexObj[0]->setup.texctl2 &= ~TMC_specen_enable; + mmesa->CurrentTexObj[0]->setup.texctl2 |= mmesa->hw.specen; - if (new_state & (MGA_NEW_WARP|MGA_NEW_TEXTURE)) - mgaUpdateTextureState(ctx); + memcpy(&sarea->TexState[0], + &mmesa->CurrentTexObj[0]->setup, + sizeof(sarea->TexState[0])); } + + if ((mmesa->dirty & MGA_UPLOAD_TEX1) && mmesa->CurrentTexObj[1]) { + mmesa->CurrentTexObj[1]->setup.texctl2 &= ~TMC_specen_enable; + mmesa->CurrentTexObj[1]->setup.texctl2 |= mmesa->hw.specen; + + memcpy(&sarea->TexState[1], + &mmesa->CurrentTexObj[1]->setup, + sizeof(sarea->TexState[1])); + } + + if ( (sarea->TexState[0].texctl2 & TMC_borderen_MASK) != + (sarea->TexState[1].texctl2 & TMC_borderen_MASK) ) { + const int borderen = sarea->TexState[1].texctl2 & ~TMC_borderen_MASK; + + memcpy( &sarea->TexState[1], &sarea->TexState[0], + sizeof(sarea->TexState[0]) ); + sarea->TexState[1].texctl2 |= borderen; + mmesa->dirty |= MGA_UPLOAD_TEX1|MGA_UPLOAD_TEX0; + } + + if (mmesa->dirty & MGA_UPLOAD_PIPE) { +/* mmesa->sarea->wacceptseq = mmesa->hw_primitive; */ + mmesa->sarea->WarpPipe = mmesa->vertex_format; + mmesa->sarea->vertsize = mmesa->vertex_size; + } + + mmesa->sarea->dirty |= mmesa->dirty; + mmesa->dirty &= MGA_UPLOAD_CLIPRECTS; + + /* This is a bit of a hack but seems to be the best place to ensure + * that separate specular is disabled when not needed. + */ + if (ctx->Texture._EnabledUnits == 0 || + !ctx->Light.Enabled || + ctx->Light.Model.ColorControl == GL_SINGLE_COLOR) { + sarea->TexState[0].texctl2 &= ~TMC_specen_enable; + sarea->TexState[1].texctl2 &= ~TMC_specen_enable; + } +} + + +/* ============================================================= + */ + + +static void mgaDDValidateState( GLcontext *ctx ) +{ + mgaContextPtr mmesa = MGA_CONTEXT( ctx ); + int new_state = mmesa->NewGLState; + + + FLUSH_BATCH( mmesa ); + + if (mmesa->NewGLState & _MGA_NEW_RASTERSETUP) { + mgaChooseVertexState( ctx ); + } + + if (mmesa->NewGLState & _MGA_NEW_RENDERSTATE) { + mgaChooseRenderState( ctx ); + } + + if (new_state & _NEW_TEXTURE) { + mgaUpdateTextureState(ctx); + } + + mmesa->NewGLState = 0; } @@ -992,25 +1116,40 @@ static void mgaDDInvalidateState( GLcontext *ctx, GLuint new_state ) _swsetup_InvalidateState( ctx, new_state ); _ac_InvalidateState( ctx, new_state ); _tnl_InvalidateState( ctx, new_state ); - MGA_CONTEXT(ctx)->new_gl_state |= new_state; + MGA_CONTEXT(ctx)->NewGLState |= new_state; } +static void mgaRunPipeline( GLcontext *ctx ) +{ + mgaContextPtr mmesa = MGA_CONTEXT(ctx); + + if (mmesa->NewGLState) { + mgaDDValidateState( ctx ); + } + + if (mmesa->dirty) { + mgaEmitHwStateLocked( mmesa ); + } + + _tnl_run_pipeline( ctx ); +} + void mgaInitState( mgaContextPtr mmesa ) { mgaScreenPrivate *mgaScreen = mmesa->mgaScreen; GLcontext *ctx = mmesa->glCtx; - if (ctx->Color._DrawDestMask == BACK_LEFT_BIT) { + if (ctx->Visual.doubleBufferMode) { + /* use back buffer by default */ mmesa->draw_buffer = MGA_BACK; - mmesa->read_buffer = MGA_BACK; mmesa->drawOffset = mmesa->mgaScreen->backOffset; mmesa->readOffset = mmesa->mgaScreen->backOffset; mmesa->setup.dstorg = mgaScreen->backOffset; } else { + /* use front buffer by default */ mmesa->draw_buffer = MGA_FRONT; - mmesa->read_buffer = MGA_FRONT; mmesa->drawOffset = mmesa->mgaScreen->frontOffset; mmesa->readOffset = mmesa->mgaScreen->frontOffset; mmesa->setup.dstorg = mgaScreen->frontOffset; @@ -1043,14 +1182,21 @@ void mgaInitState( mgaContextPtr mmesa ) mmesa->setup.maccess |= MA_zwidth_24; break; case 32: - mmesa->setup.maccess |= MA_pwidth_32; + mmesa->setup.maccess |= MA_zwidth_32; break; } + mmesa->hw.zmode = DC_zmode_zlt | DC_atype_zi; + mmesa->hw.stencil = (0x0ff << S_smsk_SHIFT) | (0x0ff << S_swtmsk_SHIFT); + mmesa->hw.stencilctl = SC_smode_salways | SC_sfailop_keep + | SC_szfailop_keep | SC_szpassop_keep; + mmesa->hw.stencil_enable = 0; + mmesa->hw.cull = _CULL_NEGATIVE; + mmesa->hw.cull_dualtex = _CULL_POSITIVE; + mmesa->hw.specen = 0; + mmesa->setup.dwgctl = (DC_opcod_trap | - DC_atype_i | DC_linear_xy | - DC_zmode_nozcmp | DC_solid_disable | DC_arzero_disable | DC_sgnzero_disable | @@ -1072,16 +1218,15 @@ void mgaInitState( mgaContextPtr mmesa ) AC_atmode_noacmp | AC_alphasel_fromtex ); - mmesa->setup.fogcolor = - MGAPACKCOLOR888((GLubyte)(ctx->Fog.Color[0]*255.0F), - (GLubyte)(ctx->Fog.Color[1]*255.0F), - (GLubyte)(ctx->Fog.Color[2]*255.0F)); + mmesa->setup.fogcolor = PACK_COLOR_888((GLubyte)(ctx->Fog.Color[0]*255.0F), + (GLubyte)(ctx->Fog.Color[1]*255.0F), + (GLubyte)(ctx->Fog.Color[2]*255.0F)); mmesa->setup.wflag = 0; mmesa->setup.tdualstage0 = 0; mmesa->setup.tdualstage1 = 0; mmesa->setup.fcol = 0; - mmesa->new_state = ~0; + mmesa->dirty |= MGA_UPLOAD_CONTEXT; } @@ -1103,8 +1248,8 @@ void mgaDDInitStateFuncs( GLcontext *ctx ) ctx->Driver.FrontFace = mgaDDCullFaceFrontFace; ctx->Driver.ColorMask = mgaDDColorMask; - ctx->Driver.DrawBuffer = mgaDDSetDrawBuffer; - ctx->Driver.ReadBuffer = mgaDDSetReadBuffer; + ctx->Driver.DrawBuffer = mgaDDDrawBuffer; + ctx->Driver.ReadBuffer = mgaDDReadBuffer; ctx->Driver.ClearColor = mgaDDClearColor; ctx->Driver.ClearDepth = mgaDDClearDepth; ctx->Driver.LogicOpcode = mgaDDLogicOp; @@ -1128,4 +1273,6 @@ void mgaDDInitStateFuncs( GLcontext *ctx ) ctx->Driver.CopyColorSubTable = _swrast_CopyColorSubTable; ctx->Driver.CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D; ctx->Driver.CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D; + + TNL_CONTEXT(ctx)->Driver.RunPipeline = mgaRunPipeline; } diff --git a/src/mesa/drivers/dri/mga/mgastate.h b/src/mesa/drivers/dri/mga/mgastate.h index a9f1039d76..afbe0aaf90 100644 --- a/src/mesa/drivers/dri/mga/mgastate.h +++ b/src/mesa/drivers/dri/mga/mgastate.h @@ -29,14 +29,11 @@ #ifndef _MGA_STATE_H #define _MGA_STATE_H - extern void mgaInitState( mgaContextPtr mmesa ); extern void mgaDDInitStateFuncs(GLcontext *ctx); -extern void mgaDDUpdateHwState( GLcontext *ctx ); extern void mgaUpdateClipping(const GLcontext *ctx); extern void mgaUpdateCull( GLcontext *ctx ); extern void mgaCalcViewport( GLcontext *ctx ); - - +extern void mgaUpdateRects( mgaContextPtr mmesa, GLuint buffers ); #endif diff --git a/src/mesa/drivers/dri/mga/mgatex.c b/src/mesa/drivers/dri/mga/mgatex.c index b4ee787e0b..82eccc8149 100644 --- a/src/mesa/drivers/dri/mga/mgatex.c +++ b/src/mesa/drivers/dri/mga/mgatex.c @@ -26,10 +26,7 @@ */ /* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgatex.c,v 1.14 2002/10/30 12:51:36 alanh Exp $ */ -#include <stdlib.h> -#include <stdio.h> -#include <GL/gl.h> - +#include "glheader.h" #include "mm.h" #include "mgacontext.h" #include "mgatex.h" @@ -37,9 +34,11 @@ #include "mgatris.h" #include "mgaioctl.h" +#include "colormac.h" +#include "context.h" #include "enums.h" #include "simple_list.h" -/*#include "mem.h"*/ +#include "imports.h" #include "macros.h" #include "texformat.h" #include "texstore.h" @@ -47,67 +46,72 @@ #include "swrast/swrast.h" -#define TEX_0 1 -#define TEX_1 2 - -/* - * mgaDestroyTexObj - * Free all memory associated with a texture and NULL any pointers - * to it. +/** + * Set the texture wrap modes. + * Currently \c GL_REPEAT, \c GL_CLAMP and \c GL_CLAMP_TO_EDGE are supported. + * + * \param t Texture object whose wrap modes are to be set + * \param swrap Wrap mode for the \a s texture coordinate + * \param twrap Wrap mode for the \a t texture coordinate */ -void -mgaDestroyTexObj( mgaContextPtr mmesa, mgaTextureObjectPtr t ) + +static void +mgaSetTexWrapping( mgaTextureObjectPtr t, GLenum swrap, GLenum twrap ) { - if ( !t ) return; + GLboolean is_clamp = GL_FALSE; + GLboolean is_clamp_to_edge = GL_FALSE; - /* free the texture memory */ - if (t->MemBlock) { - mmFreeMem( t->MemBlock ); - t->MemBlock = 0; + t->setup.texctl &= (TMC_clampu_MASK & TMC_clampv_MASK); + t->setup.texctl2 &= (TMC_borderen_MASK); - if (mmesa && t->age > mmesa->dirtyAge) - mmesa->dirtyAge = t->age; + switch( swrap ) { + case GL_REPEAT: + break; + case GL_CLAMP: + t->setup.texctl |= TMC_clampu_enable; + is_clamp = GL_TRUE; + break; + case GL_CLAMP_TO_EDGE: + t->setup.texctl |= TMC_clampu_enable; + is_clamp_to_edge = GL_TRUE; + break; + default: + _mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__); } - /* free mesa's link */ - if (t->tObj) - t->tObj->DriverData = NULL; - - /* see if it was the driver's current object */ - if (mmesa) { - if (t->bound & TEX_0) mmesa->CurrentTexObj[0] = 0; - if (t->bound & TEX_1) mmesa->CurrentTexObj[1] = 0; + switch( twrap ) { + case GL_REPEAT: + break; + case GL_CLAMP: + t->setup.texctl |= TMC_clampv_enable; + is_clamp = GL_TRUE; + break; + case GL_CLAMP_TO_EDGE: + t->setup.texctl |= TMC_clampv_enable; + is_clamp_to_edge = GL_TRUE; + break; + default: + _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__); } - - remove_from_list(t); - free( t ); -} + if ( is_clamp ) { + t->setup.texctl2 |= TMC_borderen_enable; + } -/* - * mgaSetTexWrappings - */ -static void mgaSetTexWrapping( mgaTextureObjectPtr t, - GLenum sWrap, - GLenum tWrap ) -{ - GLuint val = 0; - - if (sWrap != GL_REPEAT) - val |= TMC_clampu_enable; - - if (tWrap != GL_REPEAT) - val |= TMC_clampv_enable; - - t->setup.texctl &= ~(TMC_clampu_enable|TMC_clampv_enable); - t->setup.texctl |= val; + t->border_fallback = (is_clamp && is_clamp_to_edge); } -/* - * mgaSetTexFilter +/** + * Set the texture magnification and minification modes. + * + * \param t Texture whose filter modes are to be set + * \param minf Texture minification mode + * \param magf Texture magnification mode */ -static void mgaSetTexFilter(mgaTextureObjectPtr t, GLenum minf, GLenum magf) + +static void +mgaSetTexFilter( mgaTextureObjectPtr t, GLenum minf, GLenum magf ) { GLuint val = 0; @@ -136,123 +140,79 @@ static void mgaSetTexFilter(mgaTextureObjectPtr t, GLenum minf, GLenum magf) } - t->setup.texfilter &= (TF_minfilter_MASK | - TF_magfilter_MASK | + /* Mask off the bits for the fields we are setting. Remember, the MGA mask + * defines have 0s for the bits in the named fields. This is the opposite + * of most of the other drivers. + */ + + t->setup.texfilter &= (TF_minfilter_MASK & + TF_magfilter_MASK & TF_fthres_MASK); t->setup.texfilter |= val; } -/* - * mgaSetTexBorderColor - */ static void mgaSetTexBorderColor(mgaTextureObjectPtr t, GLubyte color[4]) { - t->setup.texbordercol = MGAPACKCOLOR8888(color[0],color[1], - color[2],color[3]); + t->setup.texbordercol = PACK_COLOR_8888(color[3], color[0], + color[1], color[2] ); } -static GLint mgaChooseTexFormat( mgaContextPtr mmesa, - struct gl_texture_image *texImage, - GLenum format, GLenum type ) +static const struct gl_texture_format * +mgaChooseTextureFormat( GLcontext *ctx, GLint internalFormat, + GLenum format, GLenum type ) { + mgaContextPtr mmesa = MGA_CONTEXT(ctx); const GLboolean do32bpt = mmesa->default32BitTextures; - const struct gl_texture_format *texFormat; - GLint ret; - - if ( 0 ) - fprintf( stderr, "internal=%s format=%s type=%s\n", - texImage->IntFormat == 3 ? "GL_RGB (3)" : - texImage->IntFormat == 4 ? "GL_RGBA (4)" : - _mesa_lookup_enum_by_nr( texImage->IntFormat ), - _mesa_lookup_enum_by_nr( format ), - _mesa_lookup_enum_by_nr( type ) ); - -#define SET_FORMAT( r, gl ) \ - do { \ - ret = (r); \ - texFormat = &(gl); \ - } while (0) - -#define SET_FORMAT_32BPT( r32, gl32, r16, gl16 ) \ - do { \ - if ( do32bpt ) { \ - ret = (r32); \ - texFormat = &(gl32); \ - } else { \ - ret = (r16); \ - texFormat = &(gl16); \ - } \ - } while (0) - - switch ( texImage->IntFormat ) { - /* GH: Bias towards GL_RGB, GL_RGBA texture formats. This has - * got to be better than sticking them way down the end of this - * huge list. - */ + + switch ( internalFormat ) { case 4: case GL_RGBA: case GL_COMPRESSED_RGBA: if ( format == GL_BGRA ) { if ( type == GL_UNSIGNED_INT_8_8_8_8_REV ) { - SET_FORMAT( TMC_tformat_tw32, _mesa_texformat_argb8888 ); - break; - } else if ( type == GL_UNSIGNED_SHORT_4_4_4_4_REV ) { - SET_FORMAT( TMC_tformat_tw12, _mesa_texformat_argb4444 ); - break; - } else if ( type == GL_UNSIGNED_SHORT_1_5_5_5_REV ) { - SET_FORMAT( TMC_tformat_tw15, _mesa_texformat_argb1555 ); - break; + 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; } } - SET_FORMAT_32BPT( TMC_tformat_tw32, _mesa_texformat_argb8888, - TMC_tformat_tw12, _mesa_texformat_argb4444 ); - break; + 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 ) { - SET_FORMAT( TMC_tformat_tw16, _mesa_texformat_rgb565 ); - break; + return &_mesa_texformat_rgb565; } - SET_FORMAT_32BPT( TMC_tformat_tw32, _mesa_texformat_argb8888, - TMC_tformat_tw16, _mesa_texformat_rgb565 ); - break; + return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565; - /* GH: Okay, keep checking as normal. Still test for GL_RGB, - * GL_RGBA formats first. - */ case GL_RGBA8: case GL_RGB10_A2: case GL_RGBA12: case GL_RGBA16: - SET_FORMAT_32BPT( TMC_tformat_tw32, _mesa_texformat_argb8888, - TMC_tformat_tw12, _mesa_texformat_argb4444 ); - break; + return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_argb4444; case GL_RGBA4: case GL_RGBA2: - SET_FORMAT( TMC_tformat_tw12, _mesa_texformat_argb4444 ); - break; + return &_mesa_texformat_argb4444; case GL_RGB5_A1: - SET_FORMAT( TMC_tformat_tw15, _mesa_texformat_argb1555 ); - break; + return &_mesa_texformat_argb1555; case GL_RGB8: case GL_RGB10: case GL_RGB12: case GL_RGB16: - SET_FORMAT_32BPT( TMC_tformat_tw32, _mesa_texformat_argb8888, - TMC_tformat_tw16, _mesa_texformat_rgb565 ); - break; + return do32bpt ? &_mesa_texformat_argb8888 : &_mesa_texformat_rgb565; case GL_RGB5: case GL_RGB4: case GL_R3_G3_B2: - SET_FORMAT( TMC_tformat_tw16, _mesa_texformat_rgb565 ); - break; + return &_mesa_texformat_rgb565; case GL_ALPHA: case GL_ALPHA4: @@ -261,8 +221,7 @@ static GLint mgaChooseTexFormat( mgaContextPtr mmesa, case GL_ALPHA16: case GL_COMPRESSED_ALPHA: /* FIXME: This will report incorrect component sizes... */ - SET_FORMAT( TMC_tformat_tw12, _mesa_texformat_argb4444 ); - break; + return &_mesa_texformat_argb4444; case 1: case GL_LUMINANCE: @@ -272,8 +231,7 @@ static GLint mgaChooseTexFormat( mgaContextPtr mmesa, case GL_LUMINANCE16: case GL_COMPRESSED_LUMINANCE: /* FIXME: This will report incorrect component sizes... */ - SET_FORMAT( TMC_tformat_tw16, _mesa_texformat_rgb565 ); - break; + return &_mesa_texformat_rgb565; case 2: case GL_LUMINANCE_ALPHA: @@ -285,8 +243,7 @@ static GLint mgaChooseTexFormat( mgaContextPtr mmesa, case GL_LUMINANCE16_ALPHA16: case GL_COMPRESSED_LUMINANCE_ALPHA: /* FIXME: This will report incorrect component sizes... */ - SET_FORMAT( TMC_tformat_tw12, _mesa_texformat_argb4444 ); - break; + return &_mesa_texformat_argb4444; case GL_INTENSITY: case GL_INTENSITY4: @@ -295,8 +252,15 @@ static GLint mgaChooseTexFormat( mgaContextPtr mmesa, case GL_INTENSITY16: case GL_COMPRESSED_INTENSITY: /* FIXME: This will report incorrect component sizes... */ - SET_FORMAT( TMC_tformat_tw12, _mesa_texformat_argb4444 ); - break; + return &_mesa_texformat_argb4444; + + case GL_YCBCR_MESA: + if (MGA_IS_G400(mmesa) && + (type == GL_UNSIGNED_SHORT_8_8_APPLE || + type == GL_UNSIGNED_BYTE)) + return &_mesa_texformat_ycbcr; + else + return &_mesa_texformat_ycbcr_rev; case GL_COLOR_INDEX: case GL_COLOR_INDEX1_EXT: @@ -305,502 +269,78 @@ static GLint mgaChooseTexFormat( mgaContextPtr mmesa, case GL_COLOR_INDEX8_EXT: case GL_COLOR_INDEX12_EXT: case GL_COLOR_INDEX16_EXT: - SET_FORMAT( TMC_tformat_tw8, _mesa_texformat_ci8 ); - break; + return &_mesa_texformat_ci8; default: - fprintf( stderr, "bad texture format in mgaChooseTexFormat() %d", - texImage->IntFormat ); - return -1; + _mesa_problem( ctx, "unexpected texture format in %s", __FUNCTION__ ); + return NULL; } - texImage->TexFormat = texFormat; - - return ret; + return NULL; /* never get here */ } -/* - * mgaCreateTexObj + + +/** * Allocate space for and load the mesa images into the texture memory block. * This will happen before drawing with a new texture, or drawing with a * texture after it was swapped out or teximaged again. */ -static void mgaCreateTexObj(mgaContextPtr mmesa, - struct gl_texture_object *tObj) -{ - const GLint baseLevel = tObj->BaseLevel; - struct gl_texture_image *image = tObj->Image[baseLevel]; - mgaTextureObjectPtr t; - int i, ofs; - int LastLevel; - int s, s2; - int tformat; - - if (!image) return; - - tObj->DriverData = t = calloc( 1, sizeof( *t ) ); - if (!t) { - fprintf(stderr, "mgaCreateTexObj: Failed to malloc mgaTextureObject\n" ); - return; - } - - /* FIXME: Use the real DD interface... - */ - tformat = mgaChooseTexFormat( mmesa, image, image->Format, - GL_UNSIGNED_BYTE ); - t->texelBytes = image->TexFormat->TexelBytes; - - /* We are going to upload all levels that are present, even if - * later levels wouldn't be used by the current filtering mode. This - * allows the filtering mode to change without forcing another upload - * of the images. - */ - LastLevel = MGA_TEX_MAXLEVELS-1; - - ofs = 0; - for ( i = 0 ; i <= LastLevel ; i++ ) { - if ( !tObj->Image[i] ) { - LastLevel = i - 1; - break; - } - - t->offsets[i] = ofs; - t->dirty_images |= (1<<i); - - ofs += ((MAX2( tObj->Image[i]->Width, 8 ) * - MAX2( tObj->Image[i]->Height, 8 ) * - t->texelBytes) + 31) & ~31; - } - t->totalSize = ofs; - t->lastLevel = LastLevel; - t->tObj = tObj; - t->ctx = mmesa; - t->age = 0; - t->bound = 0; - t->MemBlock = 0; - - insert_at_tail(&(mmesa->SwappedOut), t); - - - /* setup hardware register values */ - t->setup.texctl = TMC_takey_1 | TMC_tamask_0 | tformat; - - if (image->WidthLog2 >= 3) - t->setup.texctl |= ((image->WidthLog2 - 3) << TMC_tpitch_SHIFT); - else - t->setup.texctl |= (TMC_tpitchlin_enable | - (image->Width << TMC_tpitchext_SHIFT)); - - - t->setup.texctl2 = TMC_ckstransdis_enable; - - if ( mmesa->glCtx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR ) - t->setup.texctl2 |= TMC_specen_enable; - - - t->setup.texfilter = (TF_minfilter_nrst | - TF_magfilter_nrst | - TF_filteralpha_enable | - (0x10 << TF_fthres_SHIFT) | - (LastLevel << TF_mapnb_SHIFT)); - - /* warp texture registers */ - ofs = MGA_IS_G200(mmesa) ? 28 : 11; - s = image->Width; - s2 = image->WidthLog2; - t->setup.texwidth = (MGA_FIELD(TW_twmask, s - 1) | - MGA_FIELD(TW_rfw, (10 - s2 - 8) & 63 ) | - MGA_FIELD(TW_tw, (s2 + ofs ) | 0x40 )); - - s = image->Height; - s2 = image->HeightLog2; - t->setup.texheight = (MGA_FIELD(TH_thmask, s - 1) | - MGA_FIELD(TH_rfh, (10 - s2 - 8) & 63 ) | - MGA_FIELD(TH_th, (s2 + ofs ) | 0x40 )); - - - /* set all the register values for filtering, border, etc */ - mgaSetTexWrapping( t, tObj->WrapS, tObj->WrapT ); - mgaSetTexFilter( t, tObj->MinFilter, tObj->MagFilter ); - mgaSetTexBorderColor( t, tObj->_BorderChan ); -} - - - - -static void mgaUpdateTextureEnvG200( GLcontext *ctx ) +static mgaTextureObjectPtr +mgaAllocTexObj( struct gl_texture_object *tObj ) { - struct gl_texture_object *tObj = ctx->Texture.Unit[0]._Current; mgaTextureObjectPtr t; - if (!tObj || !tObj->DriverData) - return; - - t = (mgaTextureObjectPtr)tObj->DriverData; - - t->setup.texctl2 &= ~TMC_decalblend_enable; - - switch (ctx->Texture.Unit[0].EnvMode) { - case GL_REPLACE: - t->setup.texctl &= ~TMC_tmodulate_enable; - break; - case GL_MODULATE: - t->setup.texctl |= TMC_tmodulate_enable; - break; - case GL_DECAL: - t->setup.texctl &= ~TMC_tmodulate_enable; - t->setup.texctl2 |= TMC_decalblend_enable; - break; - case GL_BLEND: - FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE ); - break; - default: - break; - } -} - -static void mgaUpdateTextureEnvG400( GLcontext *ctx, int unit ) -{ - mgaContextPtr mmesa = MGA_CONTEXT( ctx ); - GLuint *reg = ((GLuint *)&mmesa->setup.tdualstage0 + unit); - GLuint source = mmesa->tmu_source[unit]; - struct gl_texture_object *tObj = ctx->Texture.Unit[source]._Current; - GLenum format; - - if ( tObj != ctx->Texture.Unit[source].Current2D || !tObj ) - return; - - format = tObj->Image[tObj->BaseLevel]->Format; - - switch (ctx->Texture.Unit[source].EnvMode) { - case GL_REPLACE: - if (format == GL_RGB || format == GL_LUMINANCE) { - *reg = (TD0_color_sel_arg1 | - TD0_alpha_arg2_diffuse | - TD0_alpha_sel_arg2 ); - } - else if (format == GL_ALPHA) { - *reg = (TD0_color_sel_arg2 | - TD0_color_arg2_diffuse | - TD0_alpha_sel_arg1 ); - } - else { - *reg = (TD0_color_sel_arg1 | - TD0_alpha_sel_arg1 ); - } - break; - - case GL_MODULATE: - if (unit == 0) { - *reg = ( TD0_color_arg2_diffuse | - TD0_color_sel_mul | - TD0_alpha_arg2_diffuse | - TD0_alpha_sel_mul); - } - else { - *reg = ( TD0_color_arg2_prevstage | - TD0_color_alpha_prevstage | - TD0_color_sel_mul | - TD0_alpha_arg2_prevstage | - TD0_alpha_sel_mul); - } - break; - case GL_DECAL: - if (format == GL_RGB) { - if (unit == 0) { - *reg = (TD0_color_sel_arg1 | - TD0_alpha_arg2_diffuse | - TD0_alpha_sel_arg2 ); - } - else { - *reg = (TD0_color_sel_arg1 | - TD0_alpha_arg2_prevstage | - TD0_alpha_sel_arg2 ); - } - } - else if ( format == GL_RGBA ) { -#if 0 - if (unit == 0) { - /* this doesn't work */ - *reg = (TD0_color_arg2_diffuse | - TD0_color_alpha_currtex | - TD0_color_alpha2inv_enable | - TD0_color_arg2mul_alpha2 | - TD0_color_arg1mul_alpha1 | - TD0_color_blend_enable | - TD0_color_arg1add_mulout | - TD0_color_arg2add_mulout | - TD0_color_add_add | - TD0_color_sel_mul | - TD0_alpha_arg2_diffuse | - TD0_alpha_sel_arg2 ); - } - else { - *reg = (TD0_color_arg2_prevstage | - TD0_color_alpha_currtex | - TD0_color_alpha2inv_enable | - TD0_color_arg2mul_alpha2 | - TD0_color_arg1mul_alpha1 | - TD0_color_add_add | - TD0_color_sel_add | - TD0_alpha_arg2_prevstage | - TD0_alpha_sel_arg2 ); - } -#else - /* s/w fallback, pretty sure we can't do in h/w */ - FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE ); - if ( MGA_DEBUG & DEBUG_VERBOSE_FALLBACK ) - fprintf( stderr, "FALLBACK: GL_DECAL RGBA texture, unit=%d\n", - unit ); -#endif - } - else { - if (unit == 0) { - *reg = ( TD0_color_arg2_diffuse | - TD0_color_sel_arg2 | - TD0_alpha_arg2_diffuse | - TD0_alpha_sel_arg2); - } - else { - *reg = ( TD0_color_arg2_prevstage | - TD0_color_sel_arg2 | - TD0_alpha_arg2_prevstage | - TD0_alpha_sel_arg2); - } - } - break; - - case GL_ADD: - if (unit == 0) { - if (format == GL_INTENSITY) - *reg = ( TD0_color_arg2_diffuse | - TD0_color_add_add | - TD0_color_sel_add | - TD0_alpha_arg2_diffuse | - TD0_alpha_add_enable | - TD0_alpha_sel_add); - else if (format == GL_ALPHA) - *reg = ( TD0_color_arg2_diffuse | - TD0_color_sel_mul | - TD0_alpha_arg2_diffuse | - TD0_alpha_sel_mul); - else - *reg = ( TD0_color_arg2_diffuse | - TD0_color_add_add | - TD0_color_sel_add | - TD0_alpha_arg2_diffuse | - TD0_alpha_sel_mul); - } - else { - if (format == GL_INTENSITY) { - *reg = ( TD0_color_arg2_prevstage | - TD0_color_add_add | - TD0_color_sel_add | - TD0_alpha_arg2_prevstage | - TD0_alpha_add_enable | - TD0_alpha_sel_add); - } - else if (format == GL_ALPHA) { - *reg = ( TD0_color_arg2_prevstage | - TD0_color_sel_mul | - TD0_alpha_arg2_prevstage | - TD0_alpha_sel_mul); - } - else { - *reg = ( TD0_color_arg2_prevstage | - TD0_color_alpha_prevstage | - TD0_color_add_add | - TD0_color_sel_add | - TD0_alpha_arg2_prevstage | - TD0_alpha_sel_mul); - } - } - break; - - case GL_BLEND: - if (format == GL_ALPHA) { - *reg = ( TD0_color_arg2_diffuse | - TD0_color_sel_mul | - TD0_alpha_arg2_diffuse | - TD0_alpha_sel_mul); - } - else { - FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE ); - if ( MGA_DEBUG & DEBUG_VERBOSE_FALLBACK ) - fprintf( stderr, "FALLBACK: GL_BLEND envcolor=0x%08x\n", - mmesa->envcolor ); - - /* Do singletexture GL_BLEND with 'all ones' env-color - * by using both texture units. Multitexture gl_blend - * is a fallback. - */ - if (unit == 0) { - /* Part 1: R1 = Rf ( 1 - Rt ) - * A1 = Af At - */ - *reg = ( TD0_color_arg2_diffuse | - TD0_color_arg1_inv_enable | - TD0_color_sel_mul | - TD0_alpha_arg2_diffuse | - TD0_alpha_sel_arg1); - } else { - /* Part 2: R2 = R1 + Rt - * A2 = A1 - */ - *reg = ( TD0_color_arg2_prevstage | - TD0_color_add_add | - TD0_color_sel_add | - TD0_alpha_arg2_prevstage | - TD0_alpha_sel_arg2); - } - } - break; - default: - break; - } -} - - - -static void mgaUpdateTextureObject( GLcontext *ctx, int hw_unit ) -{ - mgaTextureObjectPtr t; - struct gl_texture_object *tObj; - GLuint enabled; - mgaContextPtr mmesa = MGA_CONTEXT( ctx ); - GLuint gl_unit = mmesa->tmu_source[hw_unit]; - - - enabled = ctx->Texture.Unit[gl_unit]._ReallyEnabled; - tObj = ctx->Texture.Unit[gl_unit]._Current; - - if (enabled != TEXTURE_2D_BIT) { - if (enabled) - FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE ); - return; - } - - if (tObj->Image[tObj->BaseLevel]->Border > 0) { - FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE ); - if ( MGA_DEBUG & DEBUG_VERBOSE_FALLBACK ) - fprintf( stderr, "FALLBACK: texture border\n" ); - return; - } - - if ( !tObj->DriverData ) { - mgaCreateTexObj( mmesa, tObj ); - if ( !tObj->DriverData ) { - FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_TRUE ); - return; - } - } - - t = (mgaTextureObjectPtr)tObj->DriverData; - - if (t->dirty_images) - mmesa->dirty |= (MGA_UPLOAD_TEX0IMAGE << hw_unit); - - mmesa->CurrentTexObj[hw_unit] = t; - t->bound |= hw_unit+1; - -/* if (t->MemBlock) */ -/* mgaUpdateTexLRU( mmesa, t ); */ - - t->setup.texctl2 &= ~TMC_dualtex_enable; - if ((ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT) && - (ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT)) - t->setup.texctl2 |= TMC_dualtex_enable; - - t->setup.texctl2 &= ~TMC_specen_enable; - if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) - t->setup.texctl2 |= TMC_specen_enable; -} - - + t = CALLOC( sizeof( *t ) ); + tObj->DriverData = t; + if ( t != NULL ) { + /* Initialize non-image-dependent parts of the state: + */ + t->base.tObj = tObj; + t->setup.texctl = TMC_takey_1 | TMC_tamask_0; + t->setup.texctl2 = TMC_ckstransdis_enable; + t->setup.texfilter = (TF_minfilter_nrst + | TF_magfilter_nrst + | TF_filteralpha_enable + | TF_uvoffset_OGL); + t->border_fallback = GL_FALSE; -/* The G400 is now programmed quite differently wrt texture environment. - */ -void mgaUpdateTextureState( GLcontext *ctx ) -{ - mgaContextPtr mmesa = MGA_CONTEXT( ctx ); - FALLBACK( ctx, MGA_FALLBACK_TEXTURE, GL_FALSE ); + make_empty_list( & t->base ); - if (mmesa->CurrentTexObj[0]) { - mmesa->CurrentTexObj[0]->bound = 0; - mmesa->CurrentTexObj[0] = 0; - } - - if (mmesa->CurrentTexObj[1]) { - mmesa->CurrentTexObj[1]->bound = 0; - mmesa->CurrentTexObj[1] = 0; - } - - if (ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT) { - mmesa->tmu_source[0] = 1; - } else { - mmesa->tmu_source[0] = 0; - } - - if (MGA_IS_G400(mmesa)) { - mgaUpdateTextureObject( ctx, 0 ); - mgaUpdateTextureEnvG400( ctx, 0 ); - - mmesa->setup.tdualstage1 = mmesa->setup.tdualstage0; - - if ((ctx->Texture.Unit[0]._ReallyEnabled == TEXTURE_2D_BIT) && - (ctx->Texture.Unit[1]._ReallyEnabled == TEXTURE_2D_BIT)) { - mgaUpdateTextureObject( ctx, 1 ); - mgaUpdateTextureEnvG400( ctx, 1 ); - mmesa->dirty |= MGA_UPLOAD_TEX1; - } - } else { - mgaUpdateTextureObject( ctx, 0 ); - mgaUpdateTextureEnvG200( ctx ); + mgaSetTexWrapping( t, tObj->WrapS, tObj->WrapT ); + mgaSetTexFilter( t, tObj->MinFilter, tObj->MagFilter ); + mgaSetTexBorderColor( t, tObj->_BorderChan ); } - mmesa->dirty |= MGA_UPLOAD_CONTEXT | MGA_UPLOAD_TEX0; - - mmesa->setup.dwgctl &= DC_opcod_MASK; - mmesa->setup.dwgctl |= (ctx->Texture.Unit[0]._ReallyEnabled - ? DC_opcod_texture_trap - : DC_opcod_trap); + return( t ); } - - static void mgaDDTexEnv( GLcontext *ctx, GLenum target, GLenum pname, const GLfloat *param ) { + GLuint unit = ctx->Texture.CurrentUnit; + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; mgaContextPtr mmesa = MGA_CONTEXT(ctx); - if (pname == GL_TEXTURE_ENV_MODE) { - /* force the texture state to be updated */ - FLUSH_BATCH( MGA_CONTEXT(ctx) ); - MGA_CONTEXT(ctx)->new_state |= (MGA_NEW_TEXTURE | - MGA_NEW_ALPHA); - } - else if (pname == GL_TEXTURE_ENV_COLOR) - { - struct gl_texture_unit *texUnit = - &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; - GLfloat *fc = texUnit->EnvColor; + switch( pname ) { + case GL_TEXTURE_ENV_COLOR: { GLubyte c[4]; - GLuint col; + GLuint envColor; - COPY_4V(c, fc); - col = mgaPackColor( mmesa->mgaScreen->cpp, c[0], c[1], c[2], c[3] ); - mmesa->envcolor = (c[3]<<24) | (c[0]<<16) | (c[1]<<8) | (c[2]); + UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor ); + envColor = mgaPackColor( mmesa->mgaScreen->cpp, c[0], c[1], c[2], c[3] ); + mmesa->envcolor = PACK_COLOR_8888( c[3], c[0], c[1], c[2] ); - if (mmesa->setup.fcol != col) { + if (mmesa->setup.fcol != envColor) { FLUSH_BATCH(mmesa); - mmesa->setup.fcol = col; + mmesa->setup.fcol = envColor; mmesa->dirty |= MGA_UPLOAD_CONTEXT; mmesa->blend_flags &= ~MGA_BLEND_ENV_COLOR; @@ -814,6 +354,8 @@ static void mgaDDTexEnv( GLcontext *ctx, GLenum target, if (mmesa->envcolor != 0x0 && mmesa->envcolor != 0xffffffff) mmesa->blend_flags |= MGA_BLEND_ENV_COLOR; } + break; + } } } @@ -826,14 +368,26 @@ static void mgaTexImage2D( GLcontext *ctx, GLenum target, GLint level, struct gl_texture_object *texObj, struct gl_texture_image *texImage ) { - mgaTextureObjectPtr t = (mgaTextureObjectPtr) texObj->DriverData; - if (t) { - mgaDestroyTexObj( MGA_CONTEXT(ctx), t ); - texObj->DriverData = 0; + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + + if ( t != NULL ) { + driSwapOutTextureObject( t ); + } + else { + t = (driTextureObject *) mgaAllocTexObj( texObj ); + if ( t == NULL ) { + _mesa_error( ctx, GL_OUT_OF_MEMORY, "glTexImage2D" ); + return; + } } + _mesa_store_teximage2d( ctx, target, level, internalFormat, width, height, border, format, type, pixels, packing, texObj, texImage ); + level -= t->firstLevel; + if (level >= 0) + t->dirty_images[0] |= (1UL << level); } static void mgaTexSubImage2D( GLcontext *ctx, @@ -847,44 +401,59 @@ static void mgaTexSubImage2D( GLcontext *ctx, struct gl_texture_object *texObj, struct gl_texture_image *texImage ) { - mgaTextureObjectPtr t = (mgaTextureObjectPtr) texObj->DriverData; - if (t) { - mgaDestroyTexObj( MGA_CONTEXT(ctx), t ); - texObj->DriverData = 0; + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + + assert( t != NULL ); /* this _should_ be true */ + if ( t != NULL ) { + driSwapOutTextureObject( t ); + } + else { + t = (driTextureObject *) mgaAllocTexObj( texObj ); + if ( t == NULL ) { + _mesa_error( ctx, GL_OUT_OF_MEMORY, "glTexImage2D" ); + return; + } } + _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width, height, format, type, pixels, packing, texObj, texImage); - + level -= t->firstLevel; + if (level >= 0) + t->dirty_images[0] |= (1UL << level); } - - -/* - * mgaTexParameter - * This just changes variables and flags for a state update, which - * will happen at the next mgaUpdateTextureState +/** + * Changes variables and flags for a state update, which will happen at the + * next UpdateTextureState */ + static void mgaDDTexParameter( GLcontext *ctx, GLenum target, struct gl_texture_object *tObj, GLenum pname, const GLfloat *params ) { - mgaContextPtr mmesa = MGA_CONTEXT( ctx ); + mgaContextPtr mmesa = MGA_CONTEXT( ctx ); mgaTextureObjectPtr t; t = (mgaTextureObjectPtr) tObj->DriverData; - /* if we don't have a hardware texture, it will be automatically - created with current state before it is used, so we don't have - to do anything now */ - if ( !t || !t->bound || target != GL_TEXTURE_2D ) { + /* If we don't have a hardware texture, it will be automatically + * created with current state before it is used, so we don't have + * to do anything now + */ + + if ( (t == NULL) + || (target != GL_TEXTURE_2D) ) { return; } switch (pname) { case GL_TEXTURE_MIN_FILTER: + driSwapOutTextureObject( (driTextureObject *) t ); + /* FALLTHROUGH */ case GL_TEXTURE_MAG_FILTER: FLUSH_BATCH(mmesa); mgaSetTexFilter( t, tObj->MinFilter, tObj->MagFilter ); @@ -898,14 +467,24 @@ mgaDDTexParameter( GLcontext *ctx, GLenum target, case GL_TEXTURE_BORDER_COLOR: FLUSH_BATCH(mmesa); - mgaSetTexBorderColor(t,tObj->_BorderChan); + mgaSetTexBorderColor(t, tObj->_BorderChan); + break; + + case GL_TEXTURE_BASE_LEVEL: + case GL_TEXTURE_MAX_LEVEL: + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + /* This isn't the most efficient solution but there doesn't appear to + * be a nice alternative. Since there's no LOD clamping, + * we just have to rely on loading the right subset of mipmap levels + * to simulate a clamped LOD. + */ + driSwapOutTextureObject( (driTextureObject *) t ); break; default: return; } - - mmesa->new_state |= MGA_NEW_TEXTURE; } @@ -913,19 +492,11 @@ static void mgaDDBindTexture( GLcontext *ctx, GLenum target, struct gl_texture_object *tObj ) { - mgaContextPtr mmesa = MGA_CONTEXT( ctx ); - int unit = ctx->Texture.CurrentUnit; - - FLUSH_BATCH(mmesa); - - if (mmesa->CurrentTexObj[unit]) { - mmesa->CurrentTexObj[unit]->bound &= ~(unit+1); - mmesa->CurrentTexObj[unit] = 0; + if ( target == GL_TEXTURE_2D ) { + if ( tObj->DriverData == NULL ) { + mgaAllocTexObj( tObj ); + } } - - /* force the texture state to be updated - */ - MGA_CONTEXT(ctx)->new_state |= MGA_NEW_TEXTURE; } @@ -933,53 +504,48 @@ static void mgaDDDeleteTexture( GLcontext *ctx, struct gl_texture_object *tObj ) { mgaContextPtr mmesa = MGA_CONTEXT( ctx ); - mgaTextureObjectPtr t = (mgaTextureObjectPtr)tObj->DriverData; + driTextureObject * t = (driTextureObject *) tObj->DriverData; if ( t ) { - if (mmesa) { - if (t->bound) { - FLUSH_BATCH(mmesa); - if (t->bound & TEX_0) mmesa->CurrentTexObj[0] = 0; - if (t->bound & TEX_1) mmesa->CurrentTexObj[1] = 0; - } - mmesa->new_state |= MGA_NEW_TEXTURE; + if ( mmesa ) { + FLUSH_BATCH( mmesa ); } - mgaDestroyTexObj( mmesa, t ); + driDestroyTextureObject( t ); } } -static GLboolean -mgaDDIsTextureResident( GLcontext *ctx, struct gl_texture_object *t ) -{ - mgaTextureObjectPtr mt = (mgaTextureObjectPtr)t->DriverData; - return mt && mt->MemBlock; -} - - void mgaDDInitTextureFuncs( GLcontext *ctx ) { - ctx->Driver.TexEnv = mgaDDTexEnv; - - ctx->Driver.ChooseTextureFormat = _mesa_choose_tex_format; - ctx->Driver.TexImage1D = _mesa_store_teximage1d; - ctx->Driver.TexImage2D = mgaTexImage2D; - ctx->Driver.TexImage3D = _mesa_store_teximage3d; - ctx->Driver.TexSubImage1D = _mesa_store_texsubimage1d; - ctx->Driver.TexSubImage2D = mgaTexSubImage2D; - ctx->Driver.TexSubImage3D = _mesa_store_texsubimage3d; - ctx->Driver.CopyTexImage1D = _swrast_copy_teximage1d; - ctx->Driver.CopyTexImage2D = _swrast_copy_teximage2d; - ctx->Driver.CopyTexSubImage1D = _swrast_copy_texsubimage1d; - ctx->Driver.CopyTexSubImage2D = _swrast_copy_texsubimage2d; - ctx->Driver.CopyTexSubImage3D = _swrast_copy_texsubimage3d; - ctx->Driver.TestProxyTexImage = _mesa_test_proxy_teximage; - - ctx->Driver.BindTexture = mgaDDBindTexture; - ctx->Driver.DeleteTexture = mgaDDDeleteTexture; - ctx->Driver.TexParameter = mgaDDTexParameter; - ctx->Driver.UpdateTexturePalette = 0; - ctx->Driver.IsTextureResident = mgaDDIsTextureResident; + mgaContextPtr mmesa = MGA_CONTEXT(ctx); + + + ctx->Driver.ChooseTextureFormat = mgaChooseTextureFormat; + ctx->Driver.TexImage1D = _mesa_store_teximage1d; + ctx->Driver.TexImage2D = mgaTexImage2D; + ctx->Driver.TexImage3D = _mesa_store_teximage3d; + ctx->Driver.TexSubImage1D = _mesa_store_texsubimage1d; + ctx->Driver.TexSubImage2D = mgaTexSubImage2D; + ctx->Driver.TexSubImage3D = _mesa_store_texsubimage3d; + ctx->Driver.CopyTexImage1D = _swrast_copy_teximage1d; + ctx->Driver.CopyTexImage2D = _swrast_copy_teximage2d; + ctx->Driver.CopyTexSubImage1D = _swrast_copy_texsubimage1d; + ctx->Driver.CopyTexSubImage2D = _swrast_copy_texsubimage2d; + ctx->Driver.CopyTexSubImage3D = _swrast_copy_texsubimage3d; + ctx->Driver.TestProxyTexImage = _mesa_test_proxy_teximage; + + ctx->Driver.BindTexture = mgaDDBindTexture; + ctx->Driver.CreateTexture = NULL; /* FIXME: Is this used??? */ + ctx->Driver.DeleteTexture = mgaDDDeleteTexture; + ctx->Driver.IsTextureResident = driIsTextureResident; + ctx->Driver.PrioritizeTexture = NULL; + ctx->Driver.ActiveTexture = NULL; + ctx->Driver.UpdateTexturePalette = NULL; + + ctx->Driver.TexEnv = mgaDDTexEnv; + ctx->Driver.TexParameter = mgaDDTexParameter; + + driInitTextureObjects( ctx, & mmesa->swapped, DRI_TEXMGR_DO_TEXTURE_2D ); } diff --git a/src/mesa/drivers/dri/mga/mgatex.h b/src/mesa/drivers/dri/mga/mgatex.h index c9f87d997e..282577e9f8 100644 --- a/src/mesa/drivers/dri/mga/mgatex.h +++ b/src/mesa/drivers/dri/mga/mgatex.h @@ -40,23 +40,10 @@ typedef struct mga_texture_object_s *mgaTextureObjectPtr; */ void mgaUpdateTextureState( GLcontext *ctx ); -void mgaConvertTexture( GLuint *dest, int texelBytes, - struct gl_texture_image *image, - int x, int y, int width, int height ); - - -void mgaUploadSubImageLocked( mgaContextPtr mmesa, - mgaTextureObjectPtr t, - int level, - int x, int y, int width, int height ); - int mgaUploadTexImages( mgaContextPtr mmesa, mgaTextureObjectPtr t ); void mgaDestroyTexObj( mgaContextPtr mmesa, mgaTextureObjectPtr t ); -void mgaAgeTextures( mgaContextPtr mmesa, int heap ); - void mgaDDInitTextureFuncs( GLcontext *ctx ); - #endif diff --git a/src/mesa/drivers/dri/mga/mgatexmem.c b/src/mesa/drivers/dri/mga/mgatexmem.c index 7dbdbc582f..4e7fd6b24b 100644 --- a/src/mesa/drivers/dri/mga/mgatexmem.c +++ b/src/mesa/drivers/dri/mga/mgatexmem.c @@ -26,539 +26,257 @@ */ /* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgatexmem.c,v 1.7 2002/10/30 12:51:36 alanh Exp $ */ -#include <stdlib.h> -#include <stdio.h> -#include <GL/gl.h> +#include "glheader.h" #include "mm.h" #include "mgacontext.h" #include "mgatex.h" #include "mgaregs.h" #include "mgaioctl.h" +#include "mga_xmesa.h" -/*#include "mem.h" */ +#include "imports.h" #include "simple_list.h" -static void -mgaSwapOutTexObj(mgaContextPtr mmesa, mgaTextureObjectPtr t) -{ - if (t->MemBlock) { - mmFreeMem(t->MemBlock); - t->MemBlock = 0; - - if (t->age > mmesa->dirtyAge) - mmesa->dirtyAge = t->age; - } - - t->dirty_images = ~0; - move_to_tail(&(mmesa->SwappedOut), t); -} - -static void -mgaPrintLocalLRU( mgaContextPtr mmesa, int heap ) -{ - mgaTextureObjectPtr t; - int sz = 1 << (mmesa->mgaScreen->logTextureGranularity[heap]); - - fprintf(stderr, "\nLocal LRU, heap %d:\n", heap); - - foreach( t, &(mmesa->TexObjList[heap]) ) { - if (!t->tObj) - fprintf(stderr, "Placeholder %d at %x sz %x\n", - t->MemBlock->ofs / sz, - t->MemBlock->ofs, - t->MemBlock->size); - else - fprintf(stderr, "Texture (bound %d) at %x sz %x\n", - t->bound, - t->MemBlock->ofs, - t->MemBlock->size); - } - - fprintf(stderr, "\n\n"); -} - -static void -mgaPrintGlobalLRU( mgaContextPtr mmesa, int heap ) +/** + * Destroy any device-dependent state associated with the texture. This may + * include NULLing out hardware state that points to the texture. + */ +void +mgaDestroyTexObj( mgaContextPtr mmesa, mgaTextureObjectPtr t ) { - int i, j; - drmTextureRegion *list = mmesa->sarea->texList[heap]; + unsigned i; - fprintf(stderr, "\nGlobal LRU, heap %d list %p:\n", heap, list); - for (i = 0, j = MGA_NR_TEX_REGIONS ; i < MGA_NR_TEX_REGIONS ; i++) { - fprintf(stderr, "list[%d] age %d next %d prev %d\n", - j, list[j].age, list[j].next, list[j].prev); - j = list[j].next; - if (j == MGA_NR_TEX_REGIONS) break; - } + /* See if it was the driver's current object. + */ - if (j != MGA_NR_TEX_REGIONS) { - fprintf(stderr, "Loop detected in global LRU\n\n\n"); - for (i = 0 ; i < MGA_NR_TEX_REGIONS ; i++) { - fprintf(stderr, "list[%d] age %d next %d prev %d\n", - i, list[i].age, list[i].next, list[i].prev); - } - } + if ( mmesa != NULL ) + { + if ( t->age > mmesa->dirtyAge ) + mmesa->dirtyAge = t->age; - fprintf(stderr, "\n\n"); + for ( i = 0 ; i < mmesa->glCtx->Const.MaxTextureUnits ; i++ ) + { + if ( t == mmesa->CurrentTexObj[ i ] ) { + mmesa->CurrentTexObj[ i ] = NULL; + } + } + } } -static void mgaResetGlobalLRU( mgaContextPtr mmesa, GLuint heap ) +/** + * Upload a texture image from system memory to either on-card or AGP + * memory. Uploads to on-card memory are performed using an ILOAD operation. + * This is used for both initial loading of the entire image, and texSubImage + * updates. + * + * Performed with the hardware lock held. + * + * Even though this function is named "upload subimage," the entire image + * is uploaded. + * + * \param mmesa Driver context. + * \param t Texture to be uploaded. + * \param hwlevel Mipmap level of the texture to be uploaded. + * + * \bug As mentioned above, this fuction actually copies the entier mipmap + * level. There should be a version of this function that performs + * sub-rectangle uploads. This will perform quite a bit better if only + * a small portion of a larger texture has been updated. Care would + * need to be take with such an implementation once glCopyTexImage has + * been hardware accelerated. + */ +static void mgaUploadSubImage( mgaContextPtr mmesa, + mgaTextureObjectPtr t, GLint hwlevel ) { - drmTextureRegion *list = mmesa->sarea->texList[heap]; - int sz = 1 << mmesa->mgaScreen->logTextureGranularity[heap]; - int i; - - mmesa->texAge[heap] = ++mmesa->sarea->texAge[heap]; + struct gl_texture_image * texImage; + unsigned offset; + unsigned texelBytes; + unsigned length; + const int level = hwlevel + t->base.firstLevel; - if (0) fprintf(stderr, "mgaResetGlobalLRU %d\n", (int)heap); - /* (Re)initialize the global circular LRU list. The last element - * in the array (MGA_NR_TEX_REGIONS) is the sentinal. Keeping it - * at the end of the array allows it to be addressed rationally - * when looking up objects at a particular location in texture - * memory. - */ - for (i = 0 ; (i+1) * sz <= mmesa->mgaScreen->textureSize[heap] ; i++) { - list[i].prev = i-1; - list[i].next = i+1; - list[i].age = mmesa->sarea->texAge[heap]; + if ( (hwlevel < 0) + || (hwlevel >= (MGA_IS_G200(mmesa) + ? G200_TEX_MAXLEVELS : G400_TEX_MAXLEVELS)) ) { + fprintf( stderr, "[%s:%d] level = %d\n", __FILE__, __LINE__, level ); + return; } - i--; - list[0].prev = MGA_NR_TEX_REGIONS; - list[i].prev = i-1; - list[i].next = MGA_NR_TEX_REGIONS; - list[MGA_NR_TEX_REGIONS].prev = i; - list[MGA_NR_TEX_REGIONS].next = 0; - -} - - -static void mgaUpdateTexLRU( mgaContextPtr mmesa, mgaTextureObjectPtr t ) -{ - int i; - int heap = t->heap; - int logsz = mmesa->mgaScreen->logTextureGranularity[heap]; - int start = t->MemBlock->ofs >> logsz; - int end = (t->MemBlock->ofs + t->MemBlock->size - 1) >> logsz; - drmTextureRegion *list = mmesa->sarea->texList[heap]; - - mmesa->texAge[heap] = ++mmesa->sarea->texAge[heap]; - - if (!t->MemBlock) { - fprintf(stderr, "no memblock\n\n"); + texImage = t->base.tObj->Image[level]; + if ( texImage == NULL ) { + fprintf( stderr, "[%s:%d] Image[%d] = NULL\n", __FILE__, __LINE__, + level ); return; } - /* Update our local LRU - */ - move_to_head( &(mmesa->TexObjList[heap]), t ); - - - if (0) - fprintf(stderr, "mgaUpdateTexLRU heap %d list %p\n", heap, list); - - /* Update the global LRU - */ - for (i = start ; i <= end ; i++) { - - list[i].in_use = 1; - list[i].age = mmesa->texAge[heap]; - - /* remove_from_list(i) - */ - list[(unsigned)list[i].next].prev = list[i].prev; - list[(unsigned)list[i].prev].next = list[i].next; - - /* insert_at_head(list, i) - */ - list[i].prev = MGA_NR_TEX_REGIONS; - list[i].next = list[MGA_NR_TEX_REGIONS].next; - list[(unsigned)list[MGA_NR_TEX_REGIONS].next].prev = i; - list[MGA_NR_TEX_REGIONS].next = i; - } - - if (0) { - mgaPrintGlobalLRU(mmesa, t->heap); - mgaPrintLocalLRU(mmesa, t->heap); + if (texImage->Data == NULL) { + fprintf(stderr, "null texture image data tObj %p level %d\n", + t->base.tObj, level); + return; } -} - -/* Called for every shared texture region which has increased in age - * since we last held the lock. - * - * Figures out which of our textures have been ejected by other clients, - * and pushes a placeholder texture onto the LRU list to represent - * the other client's textures. - */ -static void mgaTexturesGone( mgaContextPtr mmesa, - GLuint heap, - GLuint offset, - GLuint size, - GLuint in_use ) -{ - mgaTextureObjectPtr t, tmp; - - - foreach_s ( t, tmp, &(mmesa->TexObjList[heap]) ) { - if (t->MemBlock->ofs >= offset + size || - t->MemBlock->ofs + t->MemBlock->size <= offset) - continue; - - - - - /* It overlaps - kick it off. Need to hold onto the currently bound - * objects, however. - */ - if (t->bound) - mgaSwapOutTexObj( mmesa, t ); - else - mgaDestroyTexObj( mmesa, t ); + /* find the proper destination offset for this level */ + if ( MGA_IS_G200(mmesa) ) { + offset = (t->base.memBlock->ofs + t->offsets[hwlevel]); } + else { + unsigned i; - - if (in_use) { - t = (mgaTextureObjectPtr) calloc(1, sizeof(*t)); - if (!t) return; - - t->heap = heap; - t->MemBlock = mmAllocMem( mmesa->texHeap[heap], size, 0, offset); - if (!t->MemBlock) { - fprintf(stderr, "Couldn't alloc placeholder sz %x ofs %x\n", - (int)size, (int)offset); - mmDumpMemInfo( mmesa->texHeap[heap]); - return; + offset = t->base.memBlock->ofs; + for ( i = 0 ; i < hwlevel ; i++ ) { + offset += (t->offsets[1] >> (i * 2)); } - insert_at_head( &(mmesa->TexObjList[heap]), t ); - } -} - - -void mgaAgeTextures( mgaContextPtr mmesa, int heap ) -{ - MGASAREAPrivPtr sarea = mmesa->sarea; - int sz = 1 << (mmesa->mgaScreen->logTextureGranularity[heap]); - int idx, nr = 0; - /* Have to go right round from the back to ensure stuff ends up - * LRU in our local list... Fix with a cursor pointer. - */ - for (idx = sarea->texList[heap][MGA_NR_TEX_REGIONS].prev ; - idx != MGA_NR_TEX_REGIONS && nr < MGA_NR_TEX_REGIONS ; - idx = sarea->texList[heap][idx].prev, nr++) - { - /* If switching texturing schemes, then the SAREA might not - * have been properly cleared, so we need to reset the - * global texture LRU. + /* Each mipmap must be DWORD aligned. */ - if ( idx * sz > mmesa->mgaScreen->textureSize[heap] ) { - nr = MGA_NR_TEX_REGIONS; - break; - } - - if (sarea->texList[heap][idx].age > mmesa->texAge[heap]) { - mgaTexturesGone(mmesa, heap, idx * sz, sz, - sarea->texList[heap][idx].in_use); - } - } - - if (nr == MGA_NR_TEX_REGIONS) { - mgaTexturesGone(mmesa, heap, 0, - mmesa->mgaScreen->textureSize[heap], 0); - mgaResetGlobalLRU( mmesa, heap ); + offset &= ~0x03; } - if (0) { - mgaPrintGlobalLRU( mmesa, heap ); - mgaPrintLocalLRU( mmesa, heap ); - } - - mmesa->texAge[heap] = sarea->texAge[heap]; - mmesa->dirty |= MGA_UPLOAD_TEX0IMAGE | MGA_UPLOAD_TEX1IMAGE; -} - -/* - * mgaUploadSubImageLocked - * - * Perform an iload based update of a resident buffer. This is used for - * both initial loading of the entire image, and texSubImage updates. - * - * Performed with the hardware lock held. - */ -void mgaUploadSubImageLocked( mgaContextPtr mmesa, - mgaTextureObjectPtr t, - int level, - int x, int y, int width, int height ) -{ - int x2; - int dwords; - int offset; - struct gl_texture_image *image; - int texelBytes, texelsPerDword, texelMaccess, length; - - if ( level < 0 || level >= MGA_TEX_MAXLEVELS ) - return; + /* Copy the texture from system memory to a memory space that can be + * directly used by the hardware for texturing. + */ - image = t->tObj->Image[level]; - if ( !image ) return; + texelBytes = texImage->TexFormat->TexelBytes; + length = texImage->Width * texImage->Height * texelBytes; + if ( t->base.heap->heapId == MGA_CARD_HEAP ) { + unsigned tex_offset = 0; + unsigned to_copy; - if (image->Data == 0) { - fprintf(stderr, "null texture image data tObj %p level %d\n", - t->tObj, level); - return; - } + /* We may not be able to upload the entire texture in one batch due to + * register limits or dma buffer limits. Split the copy up into maximum + * sized chunks. + */ + offset += mmesa->mgaScreen->textureOffset[ t->base.heap->heapId ]; + while ( length != 0 ) { + mgaGetILoadBufferLocked( mmesa ); - /* find the proper destination offset for this level */ - offset = (t->MemBlock->ofs + - t->offsets[level]); - - - texelBytes = t->texelBytes; - switch( texelBytes ) { - case 1: - texelsPerDword = 4; - texelMaccess = 0; - break; - case 2: - texelsPerDword = 2; - texelMaccess = 1; - break; - case 4: - texelsPerDword = 1; - texelMaccess = 2; - break; - default: - return; - } + /* The kernel ILOAD ioctl requires that the lenght be an even multiple + * of MGA_ILOAD_ALIGN. + */ + length = ((length) + MGA_ILOAD_MASK) & ~MGA_ILOAD_MASK; + to_copy = MIN2( length, MGA_BUFFER_SIZE ); + (void) memcpy( mmesa->iload_buffer->address, + (GLubyte *) texImage->Data + tex_offset, to_copy ); - /* We can't do a subimage update if pitch is < 32 texels due - * to hardware XY addressing limits, so we will need to - * linearly upload all modified rows. - */ - if ( image->Width < 32 ) { - x = 0; - width = image->Width * height; - height = 1; - - /* Assume that 1x1 textures aren't going to cause a - * bus error if we read up to four texels from that - * location: - */ -/* if ( width < texelsPerDword ) { */ -/* width = texelsPerDword; */ -/* } */ - } else { - /* pad the size out to dwords. The image is a pointer - to the entire image, so we can safely reference - outside the x,y,width,height bounds if we need to */ - x2 = x + width; - x2 = (x2 + (texelsPerDword-1)) & ~(texelsPerDword-1); - x = (x + (texelsPerDword-1)) & ~(texelsPerDword-1); - width = x2 - x; - } + if ( MGA_DEBUG & DEBUG_VERBOSE_TEXTURE ) + fprintf(stderr, "[%s:%d] address/size = 0x%08lx/%d\n", + __FILE__, __LINE__, + (long) (offset + tex_offset), + to_copy ); - /* we may not be able to upload the entire texture in one - batch due to register limits or dma buffer limits. - Recursively split it up. */ - while ( 1 ) { - dwords = height * width / texelsPerDword; - if ( dwords * 4 <= MGA_BUFFER_SIZE ) { - break; + mgaFireILoadLocked( mmesa, offset + tex_offset, to_copy ); + tex_offset += to_copy; + length -= to_copy; } - - mgaUploadSubImageLocked( mmesa, t, level, x, y, - width, height >> 1 ); - y += ( height >> 1 ); - height -= ( height >> 1 ); - } - - length = dwords * 4; - - /* Fill in the secondary buffer with properly converted texels - * from the mesa buffer. */ - /* FIXME: the sync for direct copy reduces speed.. */ - if(t->heap == MGA_CARD_HEAP ) { - mgaGetILoadBufferLocked( mmesa ); - mgaConvertTexture( (GLuint *)mmesa->iload_buffer->address, - texelBytes, image, x, y, width, height ); - if(length < 64) length = 64; - - if (0) - fprintf(stderr, "TexelBytes : %d, offset: %d, length : %d\n", - texelBytes, - mmesa->mgaScreen->textureOffset[t->heap] + - offset + - y * width * 4/texelsPerDword, - length); - - mgaFireILoadLocked( mmesa, - mmesa->mgaScreen->textureOffset[t->heap] + - offset + - y * width * 4/texelsPerDword, - length); } else { + /* FIXME: the sync for direct copy reduces speed.. */ /* This works, is slower for uploads to card space and needs * additional synchronization with the dma stream. */ UPDATE_LOCK(mmesa, DRM_LOCK_FLUSH | DRM_LOCK_QUIESCENT); - mgaConvertTexture( (GLuint *) - (mmesa->mgaScreen->texVirtual[t->heap] + - offset + - y * width * 4/texelsPerDword), - texelBytes, image, x, y, width, height ); - } -} - - -static void mgaUploadTexLevel( mgaContextPtr mmesa, - mgaTextureObjectPtr t, - int l ) -{ - mgaUploadSubImageLocked( mmesa, - t, - l, - 0, 0, - t->tObj->Image[l]->Width, - t->tObj->Image[l]->Height); -} - - - - -#if 0 -static void mgaMigrateTexture( mgaContextPtr mmesa, mgaTextureObjectPtr t ) -{ - /* NOT DONE */ -} -#endif - - -static int mgaChooseTexHeap( mgaContextPtr mmesa, mgaTextureObjectPtr t ) -{ - int freeagp, freecard; - int fitincard, fitinagp; - int totalcard, totalagp; - TMemBlock *b; - - totalcard = totalagp = fitincard = fitinagp = freeagp = freecard = 0; - - b = mmesa->texHeap[0]; - while(b) - { - totalcard += b->size; - if(b->free) if(t->totalSize <= b->size)fitincard = 1; - b = b->next; - } - - b = mmesa->texHeap[1]; - while(b) - { - totalagp += b->size; - if(b->free) if(t->totalSize <= b->size)fitinagp = 1; - b = b->next; - } - if(fitincard)return 0; - if(fitinagp)return 1; + memcpy( mmesa->mgaScreen->texVirtual[t->base.heap->heapId] + offset, + texImage->Data, length ); - if(totalcard && totalagp) - { - int ages; - int ratio = (totalcard > totalagp) ? totalcard / totalagp : totalagp / totalcard; - ages = mmesa->sarea->texAge[0] + mmesa->sarea->texAge[1]; - if( (ages % ratio) == 0)return totalcard > totalagp ? 1 : 0; - else return totalcard > totalagp ? 0 : 1; + if ( MGA_DEBUG & DEBUG_VERBOSE_TEXTURE ) + fprintf(stderr, "[%s:%d] address/size = 0x%08lx/%d\n", + __FILE__, __LINE__, + (long) (mmesa->mgaScreen->texVirtual[t->base.heap->heapId] + + offset), + length); } - - if(totalagp) return 1; - return 0; } +/** + * Upload the texture images associated with texture \a t. This might + * require the allocation of texture memory. + * + * \param mmesa Context pointer + * \param t Texture to be uploaded + */ + int mgaUploadTexImages( mgaContextPtr mmesa, mgaTextureObjectPtr t ) { - int heap; int i; int ofs; - heap = t->heap = mgaChooseTexHeap( mmesa, t ); - /* Do we need to eject LRU texture objects? - */ - if (!t->MemBlock) { - while (1) - { - mgaTextureObjectPtr tmp = mmesa->TexObjList[heap].prev; - - t->MemBlock = mmAllocMem( mmesa->texHeap[heap], - t->totalSize, - 6, 0 ); - if (t->MemBlock) - break; - - if (mmesa->TexObjList[heap].prev->bound) { - fprintf(stderr, "Hit bound texture in upload\n"); - return -1; - } + if ( (t == NULL) || (t->base.totalSize == 0) ) + return 0; - if (mmesa->TexObjList[heap].prev == - &(mmesa->TexObjList[heap])) - { - fprintf(stderr, "Failed to upload texture, sz %d\n", t->totalSize); - mmDumpMemInfo( mmesa->texHeap[heap] ); - return -1; - } + LOCK_HARDWARE( mmesa ); - mgaDestroyTexObj( mmesa, tmp ); + if (t->base.memBlock == NULL ) { + int heap; + + heap = driAllocateTexture( mmesa->texture_heaps, mmesa->nr_heaps, + (driTextureObject *) t ); + if ( heap == -1 ) { + UNLOCK_HARDWARE( mmesa ); + return -1; } - ofs = t->MemBlock->ofs - + mmesa->mgaScreen->textureOffset[heap] - ; + ofs = mmesa->mgaScreen->textureOffset[ heap ] + + t->base.memBlock->ofs; - t->setup.texorg = ofs; - t->setup.texorg1 = ofs + t->offsets[1]; - t->setup.texorg2 = ofs + t->offsets[2]; - t->setup.texorg3 = ofs + t->offsets[3]; - t->setup.texorg4 = ofs + t->offsets[4]; + if ( MGA_IS_G200(mmesa) ) { + t->setup.texorg = ofs; + t->setup.texorg1 = ofs + t->offsets[1]; + t->setup.texorg2 = ofs + t->offsets[2]; + t->setup.texorg3 = ofs + t->offsets[3]; + t->setup.texorg4 = ofs + t->offsets[4]; + } + else { + t->setup.texorg = ofs | TO_texorgoffsetsel; + t->setup.texorg1 = t->offsets[1]; + t->setup.texorg2 = 0; + t->setup.texorg3 = 0; + t->setup.texorg4 = 0; + } mmesa->dirty |= MGA_UPLOAD_CONTEXT; } /* Let the world know we've used this memory recently. */ - mgaUpdateTexLRU( mmesa, t ); - + driUpdateTextureLRU( (driTextureObject *) t ); - if (MGA_DEBUG&DEBUG_VERBOSE_LRU) - fprintf(stderr, "dispatch age: %d age freed memory: %d\n", + if (MGA_DEBUG&DEBUG_VERBOSE_TEXTURE) + fprintf(stderr, "[%s:%d] dispatch age: %d age freed memory: %d\n", + __FILE__, __LINE__, GET_DISPATCH_AGE(mmesa), mmesa->dirtyAge); if (mmesa->dirtyAge >= GET_DISPATCH_AGE(mmesa)) mgaWaitAgeLocked( mmesa, mmesa->dirtyAge ); - if (t->dirty_images) { - if (MGA_DEBUG&DEBUG_VERBOSE_LRU) - fprintf(stderr, "*"); + if (t->base.dirty_images[0]) { + const int numLevels = t->base.lastLevel - t->base.firstLevel + 1; - for (i = 0 ; i <= t->lastLevel ; i++) - if (t->dirty_images & (1<<i)) - mgaUploadTexLevel( mmesa, t, i ); + if (MGA_DEBUG&DEBUG_VERBOSE_TEXTURE) + fprintf(stderr, "[%s:%d] dirty_images[0] = 0x%04x\n", + __FILE__, __LINE__, t->base.dirty_images[0] ); + + for (i = 0 ; i < numLevels ; i++) { + if ( (t->base.dirty_images[0] & (1U << i)) != 0 ) { + mgaUploadSubImage( mmesa, t, i ); + } + } + t->base.dirty_images[0] = 0; } - t->dirty_images = 0; + UNLOCK_HARDWARE( mmesa ); + return 0; } diff --git a/src/mesa/drivers/dri/mga/mgatris.c b/src/mesa/drivers/dri/mga/mgatris.c index e47cfc171f..054c7f0635 100644 --- a/src/mesa/drivers/dri/mga/mgatris.c +++ b/src/mesa/drivers/dri/mga/mgatris.c @@ -26,9 +26,6 @@ */ /* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgatris.c,v 1.10 2002/10/30 12:51:36 alanh Exp $ */ -#include <stdio.h> -#include <math.h> - #include "mtypes.h" #include "macros.h" #include "colormac.h" @@ -676,15 +673,6 @@ static void mgaFastRenderClippedPoly( GLcontext *ctx, const GLuint *elts, /**********************************************************************/ - -#define _MGA_NEW_RENDERSTATE (_DD_NEW_LINE_STIPPLE | \ - _DD_NEW_TRI_UNFILLED | \ - _DD_NEW_TRI_LIGHT_TWOSIDE | \ - _DD_NEW_TRI_OFFSET | \ - _DD_NEW_TRI_STIPPLE | \ - _NEW_POLYGONSTIPPLE) - - #define POINT_FALLBACK (DD_POINT_SMOOTH) #define LINE_FALLBACK (DD_LINE_SMOOTH | DD_LINE_STIPPLE) #define TRI_FALLBACK (DD_TRI_SMOOTH | DD_TRI_UNFILLED) @@ -693,7 +681,7 @@ static void mgaFastRenderClippedPoly( GLcontext *ctx, const GLuint *elts, #define ANY_RASTER_FLAGS (DD_FLATSHADE|DD_TRI_LIGHT_TWOSIDE|DD_TRI_OFFSET| \ DD_TRI_UNFILLED) -static void mgaChooseRenderState(GLcontext *ctx) +void mgaChooseRenderState(GLcontext *ctx) { TNLcontext *tnl = TNL_CONTEXT(ctx); mgaContextPtr mmesa = MGA_CONTEXT(ctx); @@ -759,36 +747,6 @@ static void mgaChooseRenderState(GLcontext *ctx) /**********************************************************************/ -static void mgaRunPipeline( GLcontext *ctx ) -{ - mgaContextPtr mmesa = MGA_CONTEXT(ctx); - - if (mmesa->new_state) { - mgaDDUpdateHwState( ctx ); - } - - if (!mmesa->Fallback && mmesa->new_gl_state) { - if (mmesa->new_gl_state & _MGA_NEW_RASTERSETUP) - mgaChooseVertexState( ctx ); - - if (mmesa->new_gl_state & _MGA_NEW_RENDERSTATE) - mgaChooseRenderState( ctx ); - - mmesa->new_gl_state = 0; - - /* Circularity: mgaDDUpdateHwState can affect mmesa->Fallback, - * but mgaChooseVertexState can affect mmesa->new_state. Hence - * the second check. (Fix this...) - */ - if (mmesa->new_state) { - mgaDDUpdateHwState( ctx ); - } - } - - _tnl_run_pipeline( ctx ); -} - - static GLenum reduced_prim[GL_POLYGON+1] = { GL_POINTS, GL_LINES, @@ -812,10 +770,14 @@ void mgaRasterPrimitive( GLcontext *ctx, GLenum prim, GLuint hwprim ) mgaContextPtr mmesa = MGA_CONTEXT( ctx ); FLUSH_BATCH( mmesa ); + + /* Update culling */ + if (mmesa->raster_primitive != prim) + mmesa->dirty |= MGA_UPLOAD_CONTEXT; + mmesa->raster_primitive = prim; /* mmesa->hw_primitive = hwprim; */ mmesa->hw_primitive = MGA_WA_TRIANGLES; /* disable mgarender.c for now */ - mgaUpdateCull(ctx); if (ctx->Polygon.StippleFlag && mmesa->haveHwStipple) { @@ -864,6 +826,28 @@ static void mgaRenderFinish( GLcontext *ctx ) /* Manage total rasterization fallbacks */ /**********************************************************************/ +static const char * const fallbackStrings[] = { + "Texture mode", + "glDrawBuffer(GL_FRONT_AND_BACK)", + "read buffer", + "LogicOp != GL_COPY", + "glRenderMode(selection or feedback)", + "No hardware stencil", + "glDepthFunc( GL_NEVER )", + "Mixing GL_CLAMP_TO_EDGE and GL_CLAMP" +}; + +static const char *getFallbackString(GLuint bit) +{ + int i = 0; + while (bit > 1) { + i++; + bit >>= 1; + } + return fallbackStrings[i]; +} + + void mgaFallback( GLcontext *ctx, GLuint bit, GLboolean mode ) { TNLcontext *tnl = TNL_CONTEXT(ctx); @@ -876,6 +860,10 @@ void mgaFallback( GLcontext *ctx, GLuint bit, GLboolean mode ) FLUSH_BATCH(mmesa); _swsetup_Wakeup( ctx ); mmesa->RenderIndex = ~0; + if (MGA_DEBUG & DEBUG_VERBOSE_FALLBACK) { + fprintf(stderr, "MGA begin rasterization fallback: 0x%x %s\n", + bit, getFallbackString(bit)); + } } } else { @@ -886,8 +874,12 @@ void mgaFallback( GLcontext *ctx, GLuint bit, GLboolean mode ) tnl->Driver.Render.PrimitiveNotify = mgaRenderPrimitive; tnl->Driver.Render.Finish = mgaRenderFinish; tnl->Driver.Render.BuildVertices = mgaBuildVertices; - mmesa->new_gl_state |= (_MGA_NEW_RENDERSTATE | - _MGA_NEW_RASTERSETUP); + mmesa->NewGLState |= (_MGA_NEW_RENDERSTATE | + _MGA_NEW_RASTERSETUP); + if (MGA_DEBUG & DEBUG_VERBOSE_FALLBACK) { + fprintf(stderr, "MGA end rasterization fallback: 0x%x %s\n", + bit, getFallbackString(bit)); + } } } } @@ -905,7 +897,6 @@ void mgaDDInitTriFuncs( GLcontext *ctx ) mmesa->RenderIndex = ~0; - tnl->Driver.RunPipeline = mgaRunPipeline; tnl->Driver.Render.Start = mgaCheckTexSizes; tnl->Driver.Render.Finish = mgaRenderFinish; tnl->Driver.Render.PrimitiveNotify = mgaRenderPrimitive; diff --git a/src/mesa/drivers/dri/mga/mgatris.h b/src/mesa/drivers/dri/mga/mgatris.h index 88eda91e13..a8c0b8936b 100644 --- a/src/mesa/drivers/dri/mga/mgatris.h +++ b/src/mesa/drivers/dri/mga/mgatris.h @@ -32,12 +32,17 @@ #include "mtypes.h" extern void mgaDDInitTriFuncs( GLcontext *ctx ); - +extern void mgaChooseRenderState( GLcontext *ctx ); extern void mgaRasterPrimitive( GLcontext *ctx, GLenum prim, GLuint hwprim ); extern void mgaFallback( GLcontext *ctx, GLuint bit, GLboolean mode ); #define FALLBACK( ctx, bit, mode ) mgaFallback( ctx, bit, mode ) - +#define _MGA_NEW_RENDERSTATE (_DD_NEW_LINE_STIPPLE | \ + _DD_NEW_TRI_UNFILLED | \ + _DD_NEW_TRI_LIGHT_TWOSIDE | \ + _DD_NEW_TRI_OFFSET | \ + _DD_NEW_TRI_STIPPLE | \ + _NEW_POLYGONSTIPPLE) #endif diff --git a/src/mesa/drivers/dri/mga/mgavb.c b/src/mesa/drivers/dri/mga/mgavb.c index d354fa43d2..34906865e8 100644 --- a/src/mesa/drivers/dri/mga/mgavb.c +++ b/src/mesa/drivers/dri/mga/mgavb.c @@ -24,7 +24,7 @@ * Authors: * Keith Whitwell <keith@tungstengraphics.com> */ -/* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgavb.c,v 1.15 2003/03/26 20:43:49 tsi Exp $ */ +/* $XFree86: xc/lib/GL/mesa/src/drv/mga/mgavb.c,v 1.14 2002/10/30 12:51:36 alanh Exp $ */ #include "mgacontext.h" #include "mgavb.h" @@ -34,18 +34,14 @@ #include "glheader.h" #include "mtypes.h" -/*#include "mem.h" */ +#include "imports.h" #include "macros.h" #include "colormac.h" -/*#include "mmath.h"*/ #include "tnl/t_context.h" #include "swrast_setup/swrast_setup.h" #include "swrast/swrast.h" -#include <stdio.h> -#include <stdlib.h> - #define MGA_TEX1_BIT 0x1 #define MGA_TEX0_BIT 0x2 @@ -93,7 +89,7 @@ static struct { #define GET_VIEWPORT_MAT() mmesa->hw_viewport #define GET_TEXSOURCE(n) mmesa->tmu_source[n] #define GET_VERTEX_FORMAT() mmesa->vertex_format -#define GET_VERTEX_STORE() ((GLubyte *)mmesa->verts) +#define GET_VERTEX_STORE() mmesa->verts #define GET_VERTEX_STRIDE_SHIFT() mmesa->vertex_stride_shift #define GET_UBYTE_COLOR_STORE() &mmesa->UbyteColor #define GET_UBYTE_SPEC_COLOR_STORE() &mmesa->UbyteSecondaryColor @@ -407,15 +403,18 @@ void mgaChooseVertexState( GLcontext *ctx ) if (ctx->Fog.Enabled) ind |= MGA_FOG_BIT; - if (ctx->Texture.Unit[1]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) { - if (ctx->Texture.Unit[0]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) { + if (ctx->Texture._EnabledUnits & 0x2) { + /* unit 1 enabled */ + if (ctx->Texture._EnabledUnits & 0x1) { + /* unit 0 enabled */ ind |= MGA_TEX1_BIT|MGA_TEX0_BIT; } else { ind |= MGA_TEX0_BIT; } } - else if (ctx->Texture.Unit[0]._ReallyEnabled & (TEXTURE_1D_BIT|TEXTURE_2D_BIT)) { + else if (ctx->Texture._EnabledUnits & 0x1) { + /* unit 0 enabled */ ind |= MGA_TEX0_BIT; } @@ -431,7 +430,6 @@ void mgaChooseVertexState( GLcontext *ctx ) if (setup_tab[ind].vertex_format != mmesa->vertex_format) { FLUSH_BATCH(mmesa); - mmesa->new_state |= MGA_NEW_WARP; mmesa->dirty |= MGA_UPLOAD_PIPE; mmesa->vertex_format = setup_tab[ind].vertex_format; mmesa->vertex_size = setup_tab[ind].vertex_size; @@ -458,7 +456,7 @@ void mgaInitVB( GLcontext *ctx ) mgaContextPtr mmesa = MGA_CONTEXT(ctx); GLuint size = TNL_CONTEXT(ctx)->vb.Size; - mmesa->verts = (char *)ALIGN_MALLOC(size * sizeof(mgaVertex), 32); + mmesa->verts = ALIGN_MALLOC(size * sizeof(mgaVertex), 32); { static int firsttime = 1; @@ -468,7 +466,6 @@ void mgaInitVB( GLcontext *ctx ) } } - mmesa->new_state |= MGA_NEW_WARP; mmesa->dirty |= MGA_UPLOAD_PIPE; mmesa->vertex_format = setup_tab[0].vertex_format; mmesa->vertex_size = setup_tab[0].vertex_size; diff --git a/src/mesa/drivers/dri/mga/server/mga_common.h b/src/mesa/drivers/dri/mga/server/mga_common.h index 90f6b37f4e..dcc260a1a5 100644 --- a/src/mesa/drivers/dri/mga/server/mga_common.h +++ b/src/mesa/drivers/dri/mga/server/mga_common.h @@ -146,7 +146,7 @@ typedef struct { typedef struct { int param; - int *value; + void *value; } drmMGAGetParam; #endif diff --git a/src/mesa/drivers/dri/r128/Makefile.X11 b/src/mesa/drivers/dri/r128/Makefile.X11 new file mode 100644 index 0000000000..8ae146af91 --- /dev/null +++ b/src/mesa/drivers/dri/r128/Makefile.X11 @@ -0,0 +1,116 @@ +# $Id: Makefile.X11,v 1.1 2003/08/22 20:11:44 brianp Exp $ + +# Mesa 3-D graphics library +# Version: 5.0 +# Copyright (C) 1995-2002 Brian Paul + +TOP = ../../../../.. + +default: linux-solo + +SHARED_INCLUDES = $(INCLUDE_DIRS) -I. -I../common -Iserver +MINIGLX_INCLUDES = -I$(TOP)/src/glx/mini + +DEFINES += \ + -D_HAVE_SWRAST=1 \ + -D_HAVE_SWTNL=1 \ + -D_HAVE_SANITY=1 \ + -D_HAVE_CODEGEN=1 \ + -D_HAVE_LIGHTING=1 \ + -D_HAVE_TEXGEN=1 \ + -D_HAVE_USERCLIP=1 \ + -DGLX_DIRECT_RENDERING + +MINIGLX_SOURCES = server/r128_dri.c + +DRIVER_SOURCES = \ + r128_context.c \ + r128_lock.c \ + r128_state.c \ + r128_texstate.c \ + r128_dd.c \ + r128_screen.c \ + r128_tex.c \ + r128_tris.c \ + r128_ioctl.c \ + r128_span.c \ + r128_texmem.c \ + r128_vb.c \ + ../common/mm.c \ + ../common/utils.c \ + ../common/texmem.c \ + ../common/vblank.c + +INCLUDES = $(MINIGLX_INCLUDES) \ + $(SHARED_INCLUDES) + + +C_SOURCES = $(DRIVER_SOURCES) \ + $(MINIGLX_SOURCES) + +MESA_MODULES = $(TOP)/src/mesa/mesa.a + + +ifeq ($(WINDOW_SYSTEM),dri) +WINOBJ=$(MESABUILDDIR)/dri/dri.a +WINLIB= +else +WINOBJ= +WINLIB=-L$(MESA)/src/glx/mini +endif + +ASM_SOURCES = +OBJECTS = $(C_SOURCES:.c=.o) \ + $(ASM_SOURCES:.S=.o) + +### Include directories + +INCLUDE_DIRS = \ + -I$(TOP)/include \ + -I$(TOP)/src/mesa \ + -I$(TOP)/src/mesa/main \ + -I$(TOP)/src/mesa/glapi \ + -I$(TOP)/src/mesa/math \ + -I$(TOP)/src/mesa/transform \ + -I$(TOP)/src/mesa/swrast \ + -I$(TOP)/src/mesa/swrast_setup + + +##### RULES ##### + +.c.o: + $(CC) -c $(SHARED_INCLUDES) $(MINIGLX_INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@ + +.S.o: + $(CC) -c $(SHARED_INCLUDES) $(MINIGLX_INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@ + + +##### TARGETS ##### + +targets: depend r128_dri.so + +r128_dri.so: $(OBJECTS) $(MESA_MODULES) $(WINOBJ) Makefile.X11 + rm -f $@ && gcc -o $@ -shared $(OBJECTS) $(MESA_MODULES) $(WINOBJ) $(WINLIB) -lc $(GL_LIB_DEPS) + rm -f $(TOP)/lib/r128_dri.so && \ + install r128_dri.so $(TOP)/lib/r128_dri.so + +# Run 'make -f Makefile.X11 dep' to update the dependencies if you change +# what's included by any source file. +depend: $(C_SOURCES) $(ASM_SOURCES) + makedepend -fdepend -Y $(SHARED_INCLUDES) $(MINIGLX_INCLUDES) \ + $(C_SOURCES) $(ASM_SOURCES) + + +# Emacs tags +tags: + etags `find . -name \*.[ch]` `find ../include` + + +# Remove .o and backup files +clean: + -rm -f *.o */*.o *~ *.o *~ *.so server/*.o + + +include $(TOP)/Make-config + +include depend diff --git a/src/mesa/drivers/dri/r128/r128_context.c b/src/mesa/drivers/dri/r128/r128_context.c new file mode 100644 index 0000000000..f7f6d7141d --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_context.c @@ -0,0 +1,335 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_context.c,v 1.8 2002/10/30 12:51:38 alanh Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#include "glheader.h" +#include "context.h" +#include "simple_list.h" +#include "imports.h" +#include "matrix.h" +#include "extensions.h" + +#include "swrast/swrast.h" +#include "swrast_setup/swrast_setup.h" +#include "array_cache/acache.h" + +#include "tnl/tnl.h" +#include "tnl/t_pipeline.h" + +#include "r128_context.h" +#include "r128_ioctl.h" +#include "r128_dd.h" +#include "r128_state.h" +#include "r128_span.h" +#include "r128_tex.h" +#include "r128_tris.h" +#include "r128_vb.h" + +#include "vblank.h" +#include "utils.h" +#include "texmem.h" + +#ifndef R128_DEBUG +int R128_DEBUG = 0; +#endif + +static const char * const card_extensions[] = +{ + "GL_ARB_multitexture", + "GL_ARB_texture_env_add", + "GL_ARB_texture_mirrored_repeat", + "GL_EXT_texture_edge_clamp", + "GL_EXT_texture_env_add", + "GL_IBM_texture_mirrored_repeat", + "GL_SGIS_generate_mipmap", + "GL_SGIS_texture_edge_clamp", + NULL +}; + +static const struct dri_debug_control debug_control[] = +{ + { "ioctl", DEBUG_VERBOSE_IOCTL }, + { "verb", DEBUG_VERBOSE_MSG }, + { "dri", DEBUG_VERBOSE_DRI }, + { "2d", DEBUG_VERBOSE_2D }, + { "sync", DEBUG_ALWAYS_SYNC }, + { "api", DEBUG_VERBOSE_API }, + { NULL, 0 } +}; + +/* Create the device specific context. + */ +GLboolean r128CreateContext( const __GLcontextModes *glVisual, + __DRIcontextPrivate *driContextPriv, + void *sharedContextPrivate ) +{ + GLcontext *ctx, *shareCtx; + __DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv; + r128ContextPtr rmesa; + r128ScreenPtr r128scrn; + int i; + + /* Allocate the r128 context */ + rmesa = (r128ContextPtr) CALLOC( sizeof(*rmesa) ); + if ( !rmesa ) + return GL_FALSE; + + /* Allocate the Mesa context */ + if (sharedContextPrivate) + shareCtx = ((r128ContextPtr) sharedContextPrivate)->glCtx; + else + shareCtx = NULL; + rmesa->glCtx = _mesa_create_context(glVisual, shareCtx, (void *) rmesa, GL_TRUE); + if (!rmesa->glCtx) { + FREE(rmesa); + return GL_FALSE; + } + driContextPriv->driverPrivate = rmesa; + ctx = rmesa->glCtx; + + rmesa->driContext = driContextPriv; + rmesa->driScreen = sPriv; + rmesa->driDrawable = NULL; + rmesa->hHWContext = driContextPriv->hHWContext; + rmesa->driHwLock = &sPriv->pSAREA->lock; + rmesa->driFd = sPriv->fd; + + r128scrn = rmesa->r128Screen = (r128ScreenPtr)(sPriv->private); + + rmesa->sarea = (R128SAREAPrivPtr)((char *)sPriv->pSAREA + + r128scrn->sarea_priv_offset); + + rmesa->CurrentTexObj[0] = NULL; + rmesa->CurrentTexObj[1] = NULL; + + (void) memset( rmesa->texture_heaps, 0, sizeof( rmesa->texture_heaps ) ); + make_empty_list( & rmesa->swapped ); + + rmesa->nr_heaps = r128scrn->numTexHeaps; + for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) { + rmesa->texture_heaps[i] = driCreateTextureHeap( i, rmesa, + r128scrn->texSize[i], + 12, + R128_NR_TEX_REGIONS, + rmesa->sarea->texList[i], + & rmesa->sarea->texAge[i], + & rmesa->swapped, + sizeof( r128TexObj ), + (destroy_texture_object_t *) r128DestroyTexObj ); + + driSetTextureSwapCounterLocation( rmesa->texture_heaps[i], + & rmesa->c_textureSwaps ); + } + + + rmesa->RenderIndex = -1; /* Impossible value */ + rmesa->vert_buf = NULL; + rmesa->num_verts = 0; + + /* Set the maximum texture size small enough that we can guarentee that + * all texture units can bind a maximal texture and have them both in + * texturable memory at once. + */ + + ctx->Const.MaxTextureUnits = 2; + + driCalculateMaxTextureLevels( rmesa->texture_heaps, + rmesa->nr_heaps, + & ctx->Const, + 4, + 10, /* max 2D texture size is 1024x1024 */ + 0, /* 3D textures unsupported. */ + 0, /* cube textures unsupported. */ + 0, /* texture rectangles unsupported. */ + 11, + GL_FALSE ); + + /* No wide points. + */ + ctx->Const.MinPointSize = 1.0; + ctx->Const.MinPointSizeAA = 1.0; + ctx->Const.MaxPointSize = 1.0; + ctx->Const.MaxPointSizeAA = 1.0; + + /* No wide lines. + */ + ctx->Const.MinLineWidth = 1.0; + ctx->Const.MinLineWidthAA = 1.0; + ctx->Const.MaxLineWidth = 1.0; + ctx->Const.MaxLineWidthAA = 1.0; + ctx->Const.LineWidthGranularity = 1.0; + +#if ENABLE_PERF_BOXES + rmesa->boxes = (getenv( "LIBGL_PERFORMANCE_BOXES" ) != NULL); +#endif + + /* 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, r128_pipeline ); */ + + /* Configure swrast to match hardware characteristics: + */ + _swrast_allow_pixel_fog( ctx, GL_FALSE ); + _swrast_allow_vertex_fog( ctx, GL_TRUE ); + + driInitExtensions( ctx, card_extensions, GL_TRUE ); + if (sPriv->drmMinor >= 4) + _mesa_enable_extension( ctx, "GL_MESA_ycbcr_texture" ); + + r128InitVB( ctx ); + r128InitTriFuncs( ctx ); + r128DDInitDriverFuncs( ctx ); + r128DDInitIoctlFuncs( ctx ); + r128DDInitStateFuncs( ctx ); + r128DDInitSpanFuncs( ctx ); + r128DDInitTextureFuncs( ctx ); + r128DDInitState( rmesa ); + + rmesa->do_irqs = (rmesa->r128Screen->irq && !getenv("R128_NO_IRQS")); + + rmesa->vblank_flags = (rmesa->do_irqs) + ? driGetDefaultVBlankFlags() : VBLANK_FLAG_NO_IRQ; + + driContextPriv->driverPrivate = (void *)rmesa; + +#if DO_DEBUG + R128_DEBUG = driParseDebugString( getenv( "R128_DEBUG" ), + debug_control ); +#endif + + return GL_TRUE; +} + +/* Destroy the device specific context. + */ +void r128DestroyContext( __DRIcontextPrivate *driContextPriv ) +{ + r128ContextPtr rmesa = (r128ContextPtr) driContextPriv->driverPrivate; + + assert(rmesa); /* should never be null */ + if ( rmesa ) { + GLboolean release_texture_heaps; + + + release_texture_heaps = (rmesa->glCtx->Shared->RefCount == 1); + + _swsetup_DestroyContext( rmesa->glCtx ); + _tnl_DestroyContext( rmesa->glCtx ); + _ac_DestroyContext( rmesa->glCtx ); + _swrast_DestroyContext( rmesa->glCtx ); + + r128FreeVB( rmesa->glCtx ); + + /* free the Mesa context */ + rmesa->glCtx->DriverCtx = NULL; + _mesa_destroy_context(rmesa->glCtx); + + if ( release_texture_heaps ) { + /* This share group is about to go away, free our private + * texture object data. + */ + int i; + + assert( is_empty_list( & rmesa->swapped ) ); + + for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) { + driDestroyTextureHeap( rmesa->texture_heaps[ i ] ); + rmesa->texture_heaps[ i ] = NULL; + } + } + + FREE( rmesa ); + } + +#if 0 + /* Use this to force shared object profiling. */ + glx_fini_prof(); +#endif +} + + +/* Force the context `c' to be the current context and associate with it + * buffer `b'. + */ +GLboolean +r128MakeCurrent( __DRIcontextPrivate *driContextPriv, + __DRIdrawablePrivate *driDrawPriv, + __DRIdrawablePrivate *driReadPriv ) +{ + if ( driContextPriv ) { + GET_CURRENT_CONTEXT(ctx); + r128ContextPtr oldR128Ctx = ctx ? R128_CONTEXT(ctx) : NULL; + r128ContextPtr newR128Ctx = (r128ContextPtr) driContextPriv->driverPrivate; + + if ( newR128Ctx != oldR128Ctx ) { + newR128Ctx->new_state |= R128_NEW_CONTEXT; + newR128Ctx->dirty = R128_UPLOAD_ALL; + } + + newR128Ctx->driDrawable = driDrawPriv; + + _mesa_make_current2( newR128Ctx->glCtx, + (GLframebuffer *) driDrawPriv->driverPrivate, + (GLframebuffer *) driReadPriv->driverPrivate ); + + + newR128Ctx->new_state |= R128_NEW_WINDOW | R128_NEW_CLIP; + + if ( !newR128Ctx->glCtx->Viewport.Width ) { + _mesa_set_viewport(newR128Ctx->glCtx, 0, 0, + driDrawPriv->w, driDrawPriv->h); + } + } else { + _mesa_make_current( 0, 0 ); + } + + return GL_TRUE; +} + + +/* Force the context `c' to be unbound from its buffer. + */ +GLboolean +r128UnbindContext( __DRIcontextPrivate *driContextPriv ) +{ + return GL_TRUE; +} diff --git a/src/mesa/drivers/dri/r128/r128_context.h b/src/mesa/drivers/dri/r128/r128_context.h new file mode 100644 index 0000000000..9c93012eb0 --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_context.h @@ -0,0 +1,270 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_context.h,v 1.12 2002/12/16 16:18:52 dawes Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __R128_CONTEXT_H__ +#define __R128_CONTEXT_H__ + +#ifdef GLX_DIRECT_RENDERING + +#include "dri_util.h" + +#include "xf86drm.h" +#include "r128_common.h" + +#include "mtypes.h" + +#include "r128_reg.h" + +#include "texmem.h" + +struct r128_context; +typedef struct r128_context r128ContextRec; +typedef struct r128_context *r128ContextPtr; + +#include "r128_lock.h" +#include "r128_texobj.h" +#include "r128_screen.h" + +/* Flags for what context state needs to be updated: + */ +#define R128_NEW_ALPHA 0x0001 +#define R128_NEW_DEPTH 0x0002 +#define R128_NEW_FOG 0x0004 +#define R128_NEW_CLIP 0x0008 +#define R128_NEW_CULL 0x0010 +#define R128_NEW_MASKS 0x0020 +#define R128_NEW_RENDER_NOT 0x0040 +#define R128_NEW_WINDOW 0x0080 +#define R128_NEW_CONTEXT 0x0100 +#define R128_NEW_ALL 0x01ff + +/* Flags for software fallback cases: + */ +#define R128_FALLBACK_TEXTURE 0x0001 +#define R128_FALLBACK_DRAW_BUFFER 0x0002 +#define R128_FALLBACK_READ_BUFFER 0x0004 +#define R128_FALLBACK_STENCIL 0x0008 +#define R128_FALLBACK_RENDER_MODE 0x0010 +#define R128_FALLBACK_MULTIDRAW 0x0020 +#define R128_FALLBACK_LOGICOP 0x0040 +#define R128_FALLBACK_SEP_SPECULAR 0x0080 +#define R128_FALLBACK_BLEND_EQ 0x0100 +#define R128_FALLBACK_BLEND_FUNC 0x0200 + + +/* Use the templated vertex format: + */ +#define TAG(x) r128##x +#include "tnl_dd/t_dd_vertex.h" +#undef TAG + +/* Reasons why the GL_BLEND fallback mightn't work: + */ +#define R128_BLEND_ENV_COLOR 0x1 +#define R128_BLEND_MULTITEX 0x2 + +/* Subpixel offsets for window coordinates (triangles): + */ +#define SUBPIXEL_X (0.0F) +#define SUBPIXEL_Y (0.125F) + + +typedef void (*r128_tri_func)( r128ContextPtr, + r128Vertex *, + r128Vertex *, + r128Vertex * ); + +typedef void (*r128_line_func)( r128ContextPtr, + r128Vertex *, + r128Vertex * ); + +typedef void (*r128_point_func)( r128ContextPtr, + r128Vertex * ); + + +struct r128_context { + GLcontext *glCtx; /* Mesa context */ + + /* Driver and hardware state management + */ + GLuint new_state; + GLuint dirty; /* Hardware state to be updated */ + r128_context_regs_t setup; + + /* Temporaries for translating away float colors: + */ + struct gl_client_array UbyteColor; + struct gl_client_array UbyteSecondaryColor; + + GLuint NewGLState; + GLuint Fallback; + GLuint SetupIndex; + GLuint SetupNewInputs; + GLuint RenderIndex; + GLfloat hw_viewport[16]; + GLfloat depth_scale; + GLuint vertex_size; + GLuint vertex_stride_shift; + GLuint vertex_format; + GLuint num_verts; + GLubyte *verts; + + CARD32 ClearColor; /* Color used to clear color buffer */ + CARD32 ClearDepth; /* Value used to clear depth buffer */ + CARD32 ClearStencil; /* Value used to clear stencil */ + + /* Map GL texture units onto hardware + */ + GLint multitex; + GLint tmu_source[2]; + GLuint tex_combine[2]; + GLuint blend_flags; + GLuint env_color; + + /* Texture object bookkeeping + */ + unsigned nr_heaps; + driTexHeap * texture_heaps[ R128_NR_TEX_HEAPS ]; + driTextureObject swapped; + + r128TexObjPtr CurrentTexObj[2]; + + /* Fallback rasterization functions + */ + r128_point_func draw_point; + r128_line_func draw_line; + r128_tri_func draw_tri; + + /* Vertex buffers + */ + drmBufPtr vert_buf; + + GLuint hw_primitive; + GLenum render_primitive; + + /* Page flipping + */ + GLuint doPageFlip; + + /* Busy waiting + */ + GLuint do_irqs; + + /* Drawable, cliprect and scissor information + */ + GLint drawOffset, drawPitch; + GLint readOffset, readPitch; + + GLuint numClipRects; /* Cliprects for the draw buffer */ + XF86DRIClipRectPtr pClipRects; + + GLuint scissor; + XF86DRIClipRectRec ScissorRect; /* Current software scissor */ + + /* Mirrors of some DRI state + */ + __DRIcontextPrivate *driContext; /* DRI context */ + __DRIscreenPrivate *driScreen; /* DRI screen */ + __DRIdrawablePrivate *driDrawable; /* DRI drawable bound to this ctx */ + + unsigned int lastStamp; /* mirror driDrawable->lastStamp */ + + drmContext hHWContext; + drmLock *driHwLock; + int driFd; + + r128ScreenPtr r128Screen; /* Screen private DRI data */ + R128SAREAPrivPtr sarea; /* Private SAREA data */ + + /* Performance counters + */ + GLuint boxes; /* Draw performance boxes */ + GLuint hardwareWentIdle; + GLuint c_clears; + GLuint c_drawWaits; + GLuint c_textureSwaps; + GLuint c_textureBytes; + GLuint c_vertexBuffers; + + /* VBI + */ + GLuint vbl_seq; + GLuint vblank_flags; +}; + +#define R128_CONTEXT(ctx) ((r128ContextPtr)(ctx->DriverCtx)) + +#define R128_IS_PLAIN( rmesa ) \ + (rmesa->r128Screen->chipset == R128_CARD_TYPE_R128) +#define R128_IS_PRO( rmesa ) \ + (rmesa->r128Screen->chipset == R128_CARD_TYPE_R128_PRO) +#define R128_IS_MOBILITY( rmesa ) \ + (rmesa->r128Screen->chipset == R128_CARD_TYPE_R128_MOBILITY) + + +extern GLboolean r128CreateContext( const __GLcontextModes *glVisual, + __DRIcontextPrivate *driContextPriv, + void *sharedContextPrivate ); + +extern void r128DestroyContext( __DRIcontextPrivate * ); + +extern GLboolean r128MakeCurrent( __DRIcontextPrivate *driContextPriv, + __DRIdrawablePrivate *driDrawPriv, + __DRIdrawablePrivate *driReadPriv ); + +extern GLboolean r128UnbindContext( __DRIcontextPrivate *driContextPriv ); + +/* ================================================================ + * Debugging: + */ +#define DO_DEBUG 0 +#define ENABLE_PERF_BOXES 0 + +#if DO_DEBUG +extern int R128_DEBUG; +#else +#define R128_DEBUG 0 +#endif + +#define DEBUG_ALWAYS_SYNC 0x01 +#define DEBUG_VERBOSE_API 0x02 +#define DEBUG_VERBOSE_MSG 0x04 +#define DEBUG_VERBOSE_LRU 0x08 +#define DEBUG_VERBOSE_DRI 0x10 +#define DEBUG_VERBOSE_IOCTL 0x20 +#define DEBUG_VERBOSE_2D 0x40 + +#endif +#endif /* __R128_CONTEXT_H__ */ diff --git a/src/mesa/drivers/dri/r128/r128_dd.c b/src/mesa/drivers/dri/r128/r128_dd.c new file mode 100644 index 0000000000..b64c26b4bd --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_dd.c @@ -0,0 +1,148 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_dd.c,v 1.15 2002/10/30 12:51:38 alanh Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * + */ + +#include "r128_context.h" +#include "r128_ioctl.h" +#include "r128_state.h" +#include "r128_vb.h" +#include "r128_dd.h" + +#include "context.h" + +#include "utils.h" + +#define DRIVER_DATE "20030328" + + +/* Return the width and height of the current color buffer. + */ +static void r128DDGetBufferSize( GLframebuffer *buffer, + GLuint *width, GLuint *height ) +{ + GET_CURRENT_CONTEXT(ctx); + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + LOCK_HARDWARE( rmesa ); + *width = rmesa->driDrawable->w; + *height = rmesa->driDrawable->h; + UNLOCK_HARDWARE( rmesa ); +} + +/* Return various strings for glGetString(). + */ +static const GLubyte *r128DDGetString( GLcontext *ctx, GLenum name ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + static char buffer[128]; + unsigned offset; + const char * card_name = "Rage 128"; + GLuint agp_mode = rmesa->r128Screen->IsPCI ? 0 : + rmesa->r128Screen->AGPMode; + + switch ( name ) { + case GL_VENDOR: + return (GLubyte *)"VA Linux Systems, Inc."; + + case GL_RENDERER: + /* Select the spefic chipset. + */ + if ( R128_IS_PRO( rmesa ) ) { + card_name = "Rage 128 Pro"; + } + else if ( R128_IS_MOBILITY( rmesa ) ) { + card_name = "Rage 128 Mobility"; + } + + offset = driGetRendererString( buffer, card_name, DRIVER_DATE, + agp_mode ); + + return (GLubyte *)buffer; + + default: + return NULL; + } +} + +/* Send all commands to the hardware. If vertex buffers or indirect + * buffers are in use, then we need to make sure they are sent to the + * hardware. All commands that are normally sent to the ring are + * already considered `flushed'. + */ +static void r128DDFlush( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + +#if ENABLE_PERF_BOXES + if ( rmesa->boxes ) { + LOCK_HARDWARE( rmesa ); + r128PerformanceBoxesLocked( rmesa ); + UNLOCK_HARDWARE( rmesa ); + } + + /* Log the performance counters if necessary */ + r128PerformanceCounters( rmesa ); +#endif +} + +/* Make sure all commands have been sent to the hardware and have + * completed processing. + */ +static void r128DDFinish( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + +#if ENABLE_PERF_BOXES + /* Bump the performance counter */ + rmesa->c_drawWaits++; +#endif + + r128DDFlush( ctx ); + r128WaitForIdle( rmesa ); +} + + +/* Initialize the driver's misc functions. + */ +void r128DDInitDriverFuncs( GLcontext *ctx ) +{ + ctx->Driver.GetBufferSize = r128DDGetBufferSize; + ctx->Driver.ResizeBuffers = _swrast_alloc_buffers; + ctx->Driver.GetString = r128DDGetString; + ctx->Driver.Finish = r128DDFinish; + ctx->Driver.Flush = r128DDFlush; + ctx->Driver.Error = NULL; +} diff --git a/src/mesa/drivers/dri/r128/r128_dd.h b/src/mesa/drivers/dri/r128/r128_dd.h new file mode 100644 index 0000000000..b8fc7ad9bf --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_dd.h @@ -0,0 +1,44 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_dd.h,v 1.3 2001/01/08 01:07:20 martin Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * + */ + +#ifndef __R128_DD_H__ +#define __R128_DD_H__ + +#ifdef GLX_DIRECT_RENDERING + +extern void r128DDInitDriverFuncs( GLcontext *ctx ); + +#endif +#endif diff --git a/src/mesa/drivers/dri/r128/r128_ioctl.c b/src/mesa/drivers/dri/r128/r128_ioctl.c new file mode 100644 index 0000000000..c5843473e1 --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_ioctl.c @@ -0,0 +1,812 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_ioctl.c,v 1.10 2002/12/16 16:18:53 dawes Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * + */ +#include <errno.h> + +#include "r128_context.h" +#include "r128_state.h" +#include "r128_ioctl.h" +#include "r128_macros.h" + +#include "imports.h" +#include "macros.h" + +#include "swrast/swrast.h" + +#include "vblank.h" + +#define R128_TIMEOUT 2048 +#define R128_IDLE_RETRY 32 + + +/* ============================================================= + * Hardware vertex buffer handling + */ + +/* Get a new VB from the pool of vertex buffers in AGP space. + */ +drmBufPtr r128GetBufferLocked( r128ContextPtr rmesa ) +{ + int fd = rmesa->r128Screen->driScreen->fd; + int index = 0; + int size = 0; + drmDMAReq dma; + drmBufPtr buf = NULL; + int to = 0; + int ret; + + dma.context = rmesa->hHWContext; + dma.send_count = 0; + dma.send_list = NULL; + dma.send_sizes = NULL; + dma.flags = 0; + dma.request_count = 1; + dma.request_size = R128_BUFFER_SIZE; + dma.request_list = &index; + dma.request_sizes = &size; + dma.granted_count = 0; + + while ( !buf && ( to++ < R128_TIMEOUT ) ) { + ret = drmDMA( fd, &dma ); + + if ( ret == 0 ) { + buf = &rmesa->r128Screen->buffers->list[index]; + buf->used = 0; +#if ENABLE_PERF_BOXES + /* Bump the performance counter */ + rmesa->c_vertexBuffers++; +#endif + return buf; + } + } + + if ( !buf ) { + drmCommandNone( fd, DRM_R128_CCE_RESET); + UNLOCK_HARDWARE( rmesa ); + fprintf( stderr, "Error: Could not get new VB... exiting\n" ); + exit( -1 ); + } + + return buf; +} + +void r128FlushVerticesLocked( r128ContextPtr rmesa ) +{ + XF86DRIClipRectPtr pbox = rmesa->pClipRects; + int nbox = rmesa->numClipRects; + drmBufPtr buffer = rmesa->vert_buf; + int count = rmesa->num_verts; + int prim = rmesa->hw_primitive; + int fd = rmesa->driScreen->fd; + drmR128Vertex vertex; + int i; + + rmesa->num_verts = 0; + rmesa->vert_buf = NULL; + + if ( !buffer ) + return; + + if ( rmesa->dirty & ~R128_UPLOAD_CLIPRECTS ) + r128EmitHwStateLocked( rmesa ); + + if ( !nbox ) + count = 0; + + if ( nbox >= R128_NR_SAREA_CLIPRECTS ) + rmesa->dirty |= R128_UPLOAD_CLIPRECTS; + + if ( !count || !(rmesa->dirty & R128_UPLOAD_CLIPRECTS) ) + { + if ( nbox < 3 ) { + rmesa->sarea->nbox = 0; + } else { + rmesa->sarea->nbox = nbox; + } + + vertex.prim = prim; + vertex.idx = buffer->idx; + vertex.count = count; + vertex.discard = 1; + drmCommandWrite( fd, DRM_R128_VERTEX, &vertex, sizeof(drmR128Vertex) ); + } + else + { + for ( i = 0 ; i < nbox ; ) { + int nr = MIN2( i + R128_NR_SAREA_CLIPRECTS, nbox ); + XF86DRIClipRectPtr b = rmesa->sarea->boxes; + int discard = 0; + + rmesa->sarea->nbox = nr - i; + for ( ; i < nr ; i++ ) { + *b++ = pbox[i]; + } + + /* Finished with the buffer? + */ + if ( nr == nbox ) { + discard = 1; + } + + rmesa->sarea->dirty |= R128_UPLOAD_CLIPRECTS; + + vertex.prim = prim; + vertex.idx = buffer->idx; + vertex.count = count; + vertex.discard = discard; + drmCommandWrite( fd, DRM_R128_VERTEX, &vertex, sizeof(drmR128Vertex) ); + } + } + + rmesa->dirty &= ~R128_UPLOAD_CLIPRECTS; +} + + + + + +/* ================================================================ + * Texture uploads + */ + +void r128FireBlitLocked( r128ContextPtr rmesa, drmBufPtr buffer, + GLint offset, GLint pitch, GLint format, + GLint x, GLint y, GLint width, GLint height ) +{ + drmR128Blit blit; + GLint ret; + + blit.idx = buffer->idx; + blit.offset = offset; + blit.pitch = pitch; + blit.format = format; + blit.x = x; + blit.y = y; + blit.width = width; + blit.height = height; + + ret = drmCommandWrite( rmesa->driFd, DRM_R128_BLIT, + &blit, sizeof(drmR128Blit) ); + + if ( ret ) { + UNLOCK_HARDWARE( rmesa ); + fprintf( stderr, "DRM_R128_BLIT: return = %d\n", ret ); + exit( 1 ); + } +} + + +/* ================================================================ + * SwapBuffers with client-side throttling + */ + +static void delay( void ) { +/* Prevent an optimizing compiler from removing a spin loop */ +} + +#define R128_MAX_OUTSTANDING 2 + +/* Throttle the frame rate -- only allow one pending swap buffers + * request at a time. + * GH: We probably don't want a timeout here, as we can wait as + * long as we want for a frame to complete. If it never does, then + * the card has locked. + */ +static int r128WaitForFrameCompletion( r128ContextPtr rmesa ) +{ + unsigned char *R128MMIO = rmesa->r128Screen->mmio.map; + CARD32 frame; + int i; + int wait = 0; + + while ( 1 ) { + frame = INREG( R128_LAST_FRAME_REG ); + if ( rmesa->sarea->last_frame - frame <= R128_MAX_OUTSTANDING ) { + break; + } + + /* Spin in place a bit so we aren't hammering the register */ + wait++; + for ( i = 0 ; i < 1024 ; i++ ) { + delay(); + } + } + + return wait; +} + +/* Copy the back color buffer to the front color buffer. + */ +void r128CopyBuffer( const __DRIdrawablePrivate *dPriv ) +{ + r128ContextPtr rmesa; + GLint nbox, i, ret; + GLboolean missed_target; + + assert(dPriv); + assert(dPriv->driContextPriv); + assert(dPriv->driContextPriv->driverPrivate); + + rmesa = (r128ContextPtr) dPriv->driContextPriv->driverPrivate; + + if ( R128_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "\n********************************\n" ); + fprintf( stderr, "\n%s( %p )\n\n", + __FUNCTION__, rmesa->glCtx ); + fflush( stderr ); + } + + FLUSH_BATCH( rmesa ); + + LOCK_HARDWARE( rmesa ); + + /* Throttle the frame rate -- only allow one pending swap buffers + * request at a time. + */ + if ( !r128WaitForFrameCompletion( rmesa ) ) { + rmesa->hardwareWentIdle = 1; + } else { + rmesa->hardwareWentIdle = 0; + } + + UNLOCK_HARDWARE( rmesa ); + driWaitForVBlank( dPriv, &rmesa->vbl_seq, rmesa->vblank_flags, &missed_target ); + LOCK_HARDWARE( rmesa ); + + nbox = dPriv->numClipRects; /* must be in locked region */ + + for ( i = 0 ; i < nbox ; ) { + GLint nr = MIN2( i + R128_NR_SAREA_CLIPRECTS , nbox ); + XF86DRIClipRectPtr box = dPriv->pClipRects; + XF86DRIClipRectPtr b = rmesa->sarea->boxes; + GLint n = 0; + + for ( ; i < nr ; i++ ) { + *b++ = *(XF86DRIClipRectRec *)&box[i]; + n++; + } + rmesa->sarea->nbox = n; + + ret = drmCommandNone( rmesa->driFd, DRM_R128_SWAP ); + + if ( ret ) { + UNLOCK_HARDWARE( rmesa ); + fprintf( stderr, "DRM_R128_SWAP: return = %d\n", ret ); + exit( 1 ); + } + } + + if ( R128_DEBUG & DEBUG_ALWAYS_SYNC ) { + i = 0; + do { + ret = drmCommandNone(rmesa->driFd, DRM_R128_CCE_IDLE); + } while ( ret && errno == EBUSY && i++ < R128_IDLE_RETRY ); + } + + UNLOCK_HARDWARE( rmesa ); + + rmesa->new_state |= R128_NEW_CONTEXT; + rmesa->dirty |= (R128_UPLOAD_CONTEXT | + R128_UPLOAD_MASKS | + R128_UPLOAD_CLIPRECTS); + +#if ENABLE_PERF_BOXES + /* Log the performance counters if necessary */ + r128PerformanceCounters( rmesa ); +#endif +} + +void r128PageFlip( const __DRIdrawablePrivate *dPriv ) +{ + r128ContextPtr rmesa; + GLint ret; + GLboolean missed_target; + + assert(dPriv); + assert(dPriv->driContextPriv); + assert(dPriv->driContextPriv->driverPrivate); + + rmesa = (r128ContextPtr) dPriv->driContextPriv->driverPrivate; + + if ( R128_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "\n%s( %p ): page=%d\n\n", + __FUNCTION__, rmesa->glCtx, rmesa->sarea->pfCurrentPage ); + } + + FLUSH_BATCH( rmesa ); + + LOCK_HARDWARE( rmesa ); + + /* Throttle the frame rate -- only allow one pending swap buffers + * request at a time. + */ + if ( !r128WaitForFrameCompletion( rmesa ) ) { + rmesa->hardwareWentIdle = 1; + } else { + rmesa->hardwareWentIdle = 0; + } + + UNLOCK_HARDWARE( rmesa ); + driWaitForVBlank( dPriv, &rmesa->vbl_seq, rmesa->vblank_flags, &missed_target ); + LOCK_HARDWARE( rmesa ); + + /* The kernel will have been initialized to perform page flipping + * on a swapbuffers ioctl. + */ + ret = drmCommandNone( rmesa->driFd, DRM_R128_FLIP ); + + UNLOCK_HARDWARE( rmesa ); + + if ( ret ) { + fprintf( stderr, "DRM_R128_FLIP: return = %d\n", ret ); + exit( 1 ); + } + + if ( rmesa->sarea->pfCurrentPage == 1 ) { + rmesa->drawOffset = rmesa->r128Screen->frontOffset; + rmesa->drawPitch = rmesa->r128Screen->frontPitch; + } else { + rmesa->drawOffset = rmesa->r128Screen->backOffset; + rmesa->drawPitch = rmesa->r128Screen->backPitch; + } + + rmesa->setup.dst_pitch_offset_c = (((rmesa->drawPitch/8) << 21) | + (rmesa->drawOffset >> 5)); + rmesa->new_state |= R128_NEW_WINDOW; + + /* FIXME: Do we need this anymore? */ + rmesa->new_state |= R128_NEW_CONTEXT; + rmesa->dirty |= (R128_UPLOAD_CONTEXT | + R128_UPLOAD_MASKS | + R128_UPLOAD_CLIPRECTS); + +#if ENABLE_PERF_BOXES + /* Log the performance counters if necessary */ + r128PerformanceCounters( rmesa ); +#endif +} + + +/* ================================================================ + * Buffer clear + */ + +static void r128DDClear( GLcontext *ctx, GLbitfield mask, GLboolean all, + GLint cx, GLint cy, GLint cw, GLint ch ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + __DRIdrawablePrivate *dPriv = rmesa->driDrawable; + drmR128Clear clear; + GLuint flags = 0; + GLint i; + GLint ret; + + if ( R128_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s:\n", __FUNCTION__ ); + } + + FLUSH_BATCH( rmesa ); + + /* The only state change we care about here is the RGBA colormask + * We'll just update that state, if needed. If we do more then + * there's some strange side-effects that the conformance tests find. + */ + if ( rmesa->new_state & R128_NEW_MASKS) { + const GLuint save_state = rmesa->new_state; + rmesa->new_state = R128_NEW_MASKS; + r128DDUpdateHWState( ctx ); + rmesa->new_state = save_state & ~R128_NEW_MASKS; + } + + if ( mask & DD_FRONT_LEFT_BIT ) { + flags |= DRM_R128_FRONT_BUFFER; + mask &= ~DD_FRONT_LEFT_BIT; + } + + if ( mask & DD_BACK_LEFT_BIT ) { + flags |= DRM_R128_BACK_BUFFER; + mask &= ~DD_BACK_LEFT_BIT; + } + + if ( ( mask & DD_DEPTH_BIT ) && ctx->Depth.Mask ) { + flags |= DRM_R128_DEPTH_BUFFER; + mask &= ~DD_DEPTH_BIT; + } +#if 0 + /* FIXME: Add stencil support */ + if ( mask & DD_STENCIL_BIT ) { + flags |= DRM_R128_DEPTH_BUFFER; + mask &= ~DD_STENCIL_BIT; + } +#endif + + if ( flags ) { + + /* Flip top to bottom */ + cx += dPriv->x; + cy = dPriv->y + dPriv->h - cy - ch; + + LOCK_HARDWARE( rmesa ); + + /* FIXME: Do we actually need this? + */ + if ( rmesa->dirty & ~R128_UPLOAD_CLIPRECTS ) { + r128EmitHwStateLocked( rmesa ); + } + + for ( i = 0 ; i < rmesa->numClipRects ; ) { + GLint nr = MIN2( i + R128_NR_SAREA_CLIPRECTS , rmesa->numClipRects ); + XF86DRIClipRectPtr box = rmesa->pClipRects; + XF86DRIClipRectPtr b = rmesa->sarea->boxes; + GLint n = 0; + + if ( !all ) { + for ( ; i < nr ; i++ ) { + GLint x = box[i].x1; + GLint y = box[i].y1; + GLint w = box[i].x2 - x; + GLint h = box[i].y2 - y; + + if ( x < cx ) w -= cx - x, x = cx; + if ( y < cy ) h -= cy - y, y = cy; + if ( x + w > cx + cw ) w = cx + cw - x; + if ( y + h > cy + ch ) h = cy + ch - y; + if ( w <= 0 ) continue; + if ( h <= 0 ) continue; + + b->x1 = x; + b->y1 = y; + b->x2 = x + w; + b->y2 = y + h; + b++; + n++; + } + } else { + for ( ; i < nr ; i++ ) { + *b++ = *(XF86DRIClipRectPtr)&box[i]; + n++; + } + } + + rmesa->sarea->nbox = n; + + if ( R128_DEBUG & DEBUG_VERBOSE_IOCTL ) { + fprintf( stderr, + "DRM_R128_CLEAR: flag 0x%x color %x depth %x nbox %d\n", + flags, + (GLuint)rmesa->ClearColor, + (GLuint)rmesa->ClearDepth, + rmesa->sarea->nbox ); + } + + clear.flags = flags; + clear.clear_color = rmesa->ClearColor; + clear.clear_depth = rmesa->ClearDepth; + clear.color_mask = rmesa->setup.plane_3d_mask_c; + clear.depth_mask = ~0; + + ret = drmCommandWrite( rmesa->driFd, DRM_R128_CLEAR, + &clear, sizeof(drmR128Clear) ); + + if ( ret ) { + UNLOCK_HARDWARE( rmesa ); + fprintf( stderr, "DRM_R128_CLEAR: return = %d\n", ret ); + exit( 1 ); + } + } + + UNLOCK_HARDWARE( rmesa ); + + rmesa->dirty |= R128_UPLOAD_CLIPRECTS; + } + + if ( mask ) + _swrast_Clear( ctx, mask, all, cx, cy, cw, ch ); +} + + +/* ================================================================ + * Depth spans, pixels + */ + +void r128WriteDepthSpanLocked( r128ContextPtr rmesa, + GLuint n, GLint x, GLint y, + const GLdepth depth[], + const GLubyte mask[] ) +{ + XF86DRIClipRectPtr pbox = rmesa->pClipRects; + drmR128Depth d; + int nbox = rmesa->numClipRects; + int fd = rmesa->driScreen->fd; + int i; + + if ( !nbox || !n ) { + return; + } + if ( nbox >= R128_NR_SAREA_CLIPRECTS ) { + rmesa->dirty |= R128_UPLOAD_CLIPRECTS; + } + + if ( !(rmesa->dirty & R128_UPLOAD_CLIPRECTS) ) + { + if ( nbox < 3 ) { + rmesa->sarea->nbox = 0; + } else { + rmesa->sarea->nbox = nbox; + } + + d.func = DRM_R128_WRITE_SPAN; + d.n = n; + d.x = (int*)&x; + d.y = (int*)&y; + d.buffer = (unsigned int *)depth; + d.mask = (unsigned char *)mask; + + drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(drmR128Depth)); + + } + else + { + for (i = 0 ; i < nbox ; ) { + int nr = MIN2( i + R128_NR_SAREA_CLIPRECTS, nbox ); + XF86DRIClipRectPtr b = rmesa->sarea->boxes; + + rmesa->sarea->nbox = nr - i; + for ( ; i < nr ; i++) { + *b++ = pbox[i]; + } + + rmesa->sarea->dirty |= R128_UPLOAD_CLIPRECTS; + + d.func = DRM_R128_WRITE_SPAN; + d.n = n; + d.x = (int*)&x; + d.y = (int*)&y; + d.buffer = (unsigned int *)depth; + d.mask = (unsigned char *)mask; + + drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(drmR128Depth)); + } + } + + rmesa->dirty &= ~R128_UPLOAD_CLIPRECTS; +} + +void r128WriteDepthPixelsLocked( r128ContextPtr rmesa, GLuint n, + const GLint x[], const GLint y[], + const GLdepth depth[], + const GLubyte mask[] ) +{ + XF86DRIClipRectPtr pbox = rmesa->pClipRects; + drmR128Depth d; + int nbox = rmesa->numClipRects; + int fd = rmesa->driScreen->fd; + int i; + + if ( !nbox || !n ) { + return; + } + if ( nbox >= R128_NR_SAREA_CLIPRECTS ) { + rmesa->dirty |= R128_UPLOAD_CLIPRECTS; + } + + if ( !(rmesa->dirty & R128_UPLOAD_CLIPRECTS) ) + { + if ( nbox < 3 ) { + rmesa->sarea->nbox = 0; + } else { + rmesa->sarea->nbox = nbox; + } + + d.func = DRM_R128_WRITE_PIXELS; + d.n = n; + d.x = (int*)&x; + d.y = (int*)&y; + d.buffer = (unsigned int *)depth; + d.mask = (unsigned char *)mask; + + drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(drmR128Depth)); + } + else + { + for (i = 0 ; i < nbox ; ) { + int nr = MIN2( i + R128_NR_SAREA_CLIPRECTS, nbox ); + XF86DRIClipRectPtr b = rmesa->sarea->boxes; + + rmesa->sarea->nbox = nr - i; + for ( ; i < nr ; i++) { + *b++ = pbox[i]; + } + + rmesa->sarea->dirty |= R128_UPLOAD_CLIPRECTS; + + d.func = DRM_R128_WRITE_PIXELS; + d.n = n; + d.x = (int*)&x; + d.y = (int*)&y; + d.buffer = (unsigned int *)depth; + d.mask = (unsigned char *)mask; + + drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(drmR128Depth)); + } + } + + rmesa->dirty &= ~R128_UPLOAD_CLIPRECTS; +} + +void r128ReadDepthSpanLocked( r128ContextPtr rmesa, + GLuint n, GLint x, GLint y ) +{ + XF86DRIClipRectPtr pbox = rmesa->pClipRects; + drmR128Depth d; + int nbox = rmesa->numClipRects; + int fd = rmesa->driScreen->fd; + int i; + + if ( !nbox || !n ) { + return; + } + if ( nbox >= R128_NR_SAREA_CLIPRECTS ) { + rmesa->dirty |= R128_UPLOAD_CLIPRECTS; + } + + if ( !(rmesa->dirty & R128_UPLOAD_CLIPRECTS) ) + { + if ( nbox < 3 ) { + rmesa->sarea->nbox = 0; + } else { + rmesa->sarea->nbox = nbox; + } + + d.func = DRM_R128_READ_SPAN; + d.n = n; + d.x = (int*)&x; + d.y = (int*)&y; + d.buffer = NULL; + d.mask = NULL; + + drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(drmR128Depth)); + } + else + { + for (i = 0 ; i < nbox ; ) { + int nr = MIN2( i + R128_NR_SAREA_CLIPRECTS, nbox ); + XF86DRIClipRectPtr b = rmesa->sarea->boxes; + + rmesa->sarea->nbox = nr - i; + for ( ; i < nr ; i++) { + *b++ = pbox[i]; + } + + rmesa->sarea->dirty |= R128_UPLOAD_CLIPRECTS; + + d.func = DRM_R128_READ_SPAN; + d.n = n; + d.x = (int*)&x; + d.y = (int*)&y; + d.buffer = NULL; + d.mask = NULL; + + drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(drmR128Depth)); + } + } + + rmesa->dirty &= ~R128_UPLOAD_CLIPRECTS; +} + +void r128ReadDepthPixelsLocked( r128ContextPtr rmesa, GLuint n, + const GLint x[], const GLint y[] ) +{ + XF86DRIClipRectPtr pbox = rmesa->pClipRects; + drmR128Depth d; + int nbox = rmesa->numClipRects; + int fd = rmesa->driScreen->fd; + int i; + + if ( !nbox || !n ) { + return; + } + if ( nbox >= R128_NR_SAREA_CLIPRECTS ) { + rmesa->dirty |= R128_UPLOAD_CLIPRECTS; + } + + if ( !(rmesa->dirty & R128_UPLOAD_CLIPRECTS) ) + { + if ( nbox < 3 ) { + rmesa->sarea->nbox = 0; + } else { + rmesa->sarea->nbox = nbox; + } + + d.func = DRM_R128_READ_PIXELS; + d.n = n; + d.x = (int*)&x; + d.y = (int*)&y; + d.buffer = NULL; + d.mask = NULL; + + drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(drmR128Depth)); + } + else + { + for (i = 0 ; i < nbox ; ) { + int nr = MIN2( i + R128_NR_SAREA_CLIPRECTS, nbox ); + XF86DRIClipRectPtr b = rmesa->sarea->boxes; + + rmesa->sarea->nbox = nr - i; + for ( ; i < nr ; i++) { + *b++ = pbox[i]; + } + + rmesa->sarea->dirty |= R128_UPLOAD_CLIPRECTS; + + d.func = DRM_R128_READ_PIXELS; + d.n = n; + d.x = (int*)&x; + d.y = (int*)&y; + d.buffer = NULL; + d.mask = NULL; + + drmCommandWrite( fd, DRM_R128_DEPTH, &d, sizeof(drmR128Depth)); + } + } + + rmesa->dirty &= ~R128_UPLOAD_CLIPRECTS; +} + + +void r128WaitForIdleLocked( r128ContextPtr rmesa ) +{ + int fd = rmesa->r128Screen->driScreen->fd; + int to = 0; + int ret, i; + + do { + i = 0; + do { + ret = drmCommandNone( fd, DRM_R128_CCE_IDLE); + } while ( ret && errno == EBUSY && i++ < R128_IDLE_RETRY ); + } while ( ( ret == -EBUSY ) && ( to++ < R128_TIMEOUT ) ); + + if ( ret < 0 ) { + drmCommandNone( fd, DRM_R128_CCE_RESET); + UNLOCK_HARDWARE( rmesa ); + fprintf( stderr, "Error: Rage 128 timed out... exiting\n" ); + exit( -1 ); + } +} + +void r128DDInitIoctlFuncs( GLcontext *ctx ) +{ + ctx->Driver.Clear = r128DDClear; +} diff --git a/src/mesa/drivers/dri/r128/r128_ioctl.h b/src/mesa/drivers/dri/r128/r128_ioctl.h new file mode 100644 index 0000000000..b0f6b363a5 --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_ioctl.h @@ -0,0 +1,146 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_ioctl.h,v 1.6 2002/12/16 16:18:53 dawes Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __R128_IOCTL_H__ +#define __R128_IOCTL_H__ + +#ifdef GLX_DIRECT_RENDERING + +#include "r128_dri.h" +#include "r128_reg.h" +#include "r128_lock.h" + +#include "xf86drm.h" +#include "r128_common.h" + +#define R128_BUFFER_MAX_DWORDS (R128_BUFFER_SIZE / sizeof(CARD32)) + + +extern drmBufPtr r128GetBufferLocked( r128ContextPtr rmesa ); +extern void r128FlushVerticesLocked( r128ContextPtr rmesa ); + +static __inline void *r128AllocDmaLow( r128ContextPtr rmesa, int bytes ) +{ + CARD32 *head; + + if ( !rmesa->vert_buf ) { + LOCK_HARDWARE( rmesa ); + rmesa->vert_buf = r128GetBufferLocked( rmesa ); + UNLOCK_HARDWARE( rmesa ); + } else if ( rmesa->vert_buf->used + bytes > rmesa->vert_buf->total ) { + LOCK_HARDWARE( rmesa ); + r128FlushVerticesLocked( rmesa ); + rmesa->vert_buf = r128GetBufferLocked( rmesa ); + UNLOCK_HARDWARE( rmesa ); + } + + head = (CARD32 *)((char *)rmesa->vert_buf->address + rmesa->vert_buf->used); + rmesa->vert_buf->used += bytes; + return head; +} + +extern void r128FireBlitLocked( r128ContextPtr rmesa, drmBufPtr buffer, + GLint offset, GLint pitch, GLint format, + GLint x, GLint y, GLint width, GLint height ); + +extern void r128WriteDepthSpanLocked( r128ContextPtr rmesa, + GLuint n, GLint x, GLint y, + const GLdepth depth[], + const GLubyte mask[] ); +extern void r128WriteDepthPixelsLocked( r128ContextPtr rmesa, GLuint n, + const GLint x[], const GLint y[], + const GLdepth depth[], + const GLubyte mask[] ); +extern void r128ReadDepthSpanLocked( r128ContextPtr rmesa, + GLuint n, GLint x, GLint y ); +extern void r128ReadDepthPixelsLocked( r128ContextPtr rmesa, GLuint n, + const GLint x[], const GLint y[] ); + +extern void r128CopyBuffer( const __DRIdrawablePrivate *dPriv ); +extern void r128PageFlip( const __DRIdrawablePrivate *dPriv ); +void r128WaitForVBlank( r128ContextPtr rmesa ); + +extern void r128WaitForIdleLocked( r128ContextPtr rmesa ); + + +extern void r128DDInitIoctlFuncs( GLcontext *ctx ); + + +/* ================================================================ + * Helper macros: + */ + +#define FLUSH_BATCH( rmesa ) \ +do { \ + if ( R128_DEBUG & DEBUG_VERBOSE_IOCTL ) \ + fprintf( stderr, "FLUSH_BATCH in %s\n", __FUNCTION__ ); \ + if ( rmesa->vert_buf ) { \ + r128FlushVertices( rmesa ); \ + } \ +} while (0) + +/* 64-bit align the next element address, and then make room for the + * next indexed prim packet header. + */ +#define ALIGN_NEXT_ELT( rmesa ) \ +do { \ + rmesa->next_elt = (GLushort *) \ + (((GLuint)rmesa->next_elt + 7) & ~0x7); \ + rmesa->next_elt = (GLushort *) \ + ((GLubyte *)rmesa->next_elt + R128_INDEX_PRIM_OFFSET); \ +} while (0) + +#define r128FlushVertices( rmesa ) \ +do { \ + LOCK_HARDWARE( rmesa ); \ + r128FlushVerticesLocked( rmesa ); \ + UNLOCK_HARDWARE( rmesa ); \ +} while (0) + +#define r128FlushElts( rmesa ) \ +do { \ + LOCK_HARDWARE( rmesa ); \ + r128FlushEltsLocked( rmesa ); \ + UNLOCK_HARDWARE( rmesa ); \ +} while (0) + +#define r128WaitForIdle( rmesa ) \ + do { \ + LOCK_HARDWARE( rmesa ); \ + r128WaitForIdleLocked( rmesa ); \ + UNLOCK_HARDWARE( rmesa ); \ + } while (0) + +#endif +#endif /* __R128_IOCTL_H__ */ diff --git a/src/mesa/drivers/dri/r128/r128_lock.c b/src/mesa/drivers/dri/r128/r128_lock.c new file mode 100644 index 0000000000..12eb0128b0 --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_lock.c @@ -0,0 +1,123 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_lock.c,v 1.5 2002/10/30 12:51:38 alanh Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * + */ + +#include "r128_context.h" +#include "r128_lock.h" +#include "r128_tex.h" +#include "r128_state.h" + +#if DEBUG_LOCKING +char *prevLockFile = NULL; +int prevLockLine = 0; +#endif + + +/* Turn on/off page flipping according to the flags in the sarea: + */ +static void +r128UpdatePageFlipping( r128ContextPtr rmesa ) +{ + int use_back; + + rmesa->doPageFlip = rmesa->sarea->pfAllowPageFlip; + + use_back = (rmesa->glCtx->Color._DrawDestMask == BACK_LEFT_BIT); + use_back ^= (rmesa->sarea->pfCurrentPage == 1); + + if ( R128_DEBUG & DEBUG_VERBOSE_API ) + fprintf(stderr, "%s allow %d current %d\n", __FUNCTION__, + rmesa->doPageFlip, + rmesa->sarea->pfCurrentPage ); + + if ( use_back ) { + rmesa->drawOffset = rmesa->r128Screen->backOffset; + rmesa->drawPitch = rmesa->r128Screen->backPitch; + } else { + rmesa->drawOffset = rmesa->r128Screen->frontOffset; + rmesa->drawPitch = rmesa->r128Screen->frontPitch; + } + + rmesa->setup.dst_pitch_offset_c = (((rmesa->drawPitch/8) << 21) | + (rmesa->drawOffset >> 5)); + rmesa->new_state |= R128_NEW_WINDOW; +} + +/* Update the hardware state. This is called if another context has + * grabbed the hardware lock, which includes the X server. This + * function also updates the driver's window state after the X server + * moves, resizes or restacks a window -- the change will be reflected + * in the drawable position and clip rects. Since the X server grabs + * the hardware lock when it changes the window state, this routine will + * automatically be called after such a change. + */ +void r128GetLock( r128ContextPtr rmesa, GLuint flags ) +{ + __DRIdrawablePrivate *dPriv = rmesa->driDrawable; + __DRIscreenPrivate *sPriv = rmesa->driScreen; + R128SAREAPrivPtr sarea = rmesa->sarea; + int i; + + drmGetLock( rmesa->driFd, rmesa->hHWContext, flags ); + + /* The window might have moved, so we might need to get new clip + * rects. + * + * NOTE: This releases and regrabs the hw lock to allow the X server + * to respond to the DRI protocol request for new drawable info. + * Since the hardware state depends on having the latest drawable + * clip rects, all state checking must be done _after_ this call. + */ + DRI_VALIDATE_DRAWABLE_INFO( sPriv, dPriv ); + + if ( rmesa->lastStamp != dPriv->lastStamp ) { + r128UpdatePageFlipping( rmesa ); + rmesa->lastStamp = dPriv->lastStamp; + rmesa->new_state |= R128_NEW_CLIP; + rmesa->SetupNewInputs = ~0; + } + + rmesa->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_CLIPRECTS; + + rmesa->numClipRects = dPriv->numClipRects; + rmesa->pClipRects = dPriv->pClipRects; + + if ( sarea->ctxOwner != rmesa->hHWContext ) { + sarea->ctxOwner = rmesa->hHWContext; + rmesa->dirty = R128_UPLOAD_ALL; + } + + for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) { + DRI_AGE_TEXTURES( rmesa->texture_heaps[i] ); + } +} diff --git a/src/mesa/drivers/dri/r128/r128_lock.h b/src/mesa/drivers/dri/r128/r128_lock.h new file mode 100644 index 0000000000..e734ba29de --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_lock.h @@ -0,0 +1,111 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_lock.h,v 1.4 2001/01/08 01:07:21 martin Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __R128_LOCK_H__ +#define __R128_LOCK_H__ + +#ifdef GLX_DIRECT_RENDERING + +extern void r128GetLock( r128ContextPtr rmesa, GLuint flags ); + +/* Turn DEBUG_LOCKING on to find locking conflicts. + */ +#define DEBUG_LOCKING 0 + +#if DEBUG_LOCKING +extern char *prevLockFile; +extern int prevLockLine; + +#define DEBUG_LOCK() \ + do { \ + prevLockFile = (__FILE__); \ + prevLockLine = (__LINE__); \ + } while (0) + +#define DEBUG_RESET() \ + do { \ + prevLockFile = 0; \ + prevLockLine = 0; \ + } while (0) + +#define DEBUG_CHECK_LOCK() \ + do { \ + if ( prevLockFile ) { \ + fprintf( stderr, \ + "LOCK SET!\n\tPrevious %s:%d\n\tCurrent: %s:%d\n", \ + prevLockFile, prevLockLine, __FILE__, __LINE__ ); \ + exit( 1 ); \ + } \ + } while (0) + +#else + +#define DEBUG_LOCK() +#define DEBUG_RESET() +#define DEBUG_CHECK_LOCK() + +#endif + +/* + * !!! We may want to separate locks from locks with validation. This + * could be used to improve performance for those things commands that + * do not do any drawing !!! + */ + +/* Lock the hardware and validate our state. + */ +#define LOCK_HARDWARE( rmesa ) \ + do { \ + char __ret = 0; \ + DEBUG_CHECK_LOCK(); \ + DRM_CAS( rmesa->driHwLock, rmesa->hHWContext, \ + (DRM_LOCK_HELD | rmesa->hHWContext), __ret ); \ + if ( __ret ) \ + r128GetLock( rmesa, 0 ); \ + DEBUG_LOCK(); \ + } while (0) + +/* Unlock the hardware. + */ +#define UNLOCK_HARDWARE( rmesa ) \ + do { \ + DRM_UNLOCK( rmesa->driFd, \ + rmesa->driHwLock, \ + rmesa->hHWContext ); \ + DEBUG_RESET(); \ + } while (0) + +#endif +#endif /* __R128_LOCK_H__ */ diff --git a/src/mesa/drivers/dri/r128/r128_screen.c b/src/mesa/drivers/dri/r128/r128_screen.c new file mode 100644 index 0000000000..8a8fc25217 --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_screen.c @@ -0,0 +1,357 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_screen.c,v 1.8 2002/12/16 16:18:53 dawes Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * + */ + +#include "r128_dri.h" + +#include "r128_context.h" +#include "r128_ioctl.h" +#include "r128_tris.h" +#include "r128_vb.h" + +#include "context.h" +#include "imports.h" + +#include "utils.h" +#include "vblank.h" + +#ifndef _SOLO +#include "glxextensions.h" +#endif + +#if 1 +/* Including xf86PciInfo.h introduces a bunch of errors... + */ +#define PCI_CHIP_RAGE128LE 0x4C45 +#define PCI_CHIP_RAGE128LF 0x4C46 +#define PCI_CHIP_RAGE128PD 0x5044 +#define PCI_CHIP_RAGE128PF 0x5046 +#define PCI_CHIP_RAGE128PR 0x5052 +#define PCI_CHIP_RAGE128RE 0x5245 +#define PCI_CHIP_RAGE128RF 0x5246 +#define PCI_CHIP_RAGE128RK 0x524B +#define PCI_CHIP_RAGE128RL 0x524C +#endif + + +/* Create the device specific screen private data struct. + */ +static r128ScreenPtr +r128CreateScreen( __DRIscreenPrivate *sPriv ) +{ + r128ScreenPtr r128Screen; + R128DRIPtr r128DRIPriv = (R128DRIPtr)sPriv->pDevPriv; + + if ( ! driCheckDriDdxDrmVersions( sPriv, "Rage128", 4, 0, 4, 0, 2, 2 ) ) + return NULL; + + /* Allocate the private area */ + r128Screen = (r128ScreenPtr) CALLOC( sizeof(*r128Screen) ); + if ( !r128Screen ) return NULL; + + /* This is first since which regions we map depends on whether or + * not we are using a PCI card. + */ + r128Screen->IsPCI = r128DRIPriv->IsPCI; + r128Screen->sarea_priv_offset = r128DRIPriv->sarea_priv_offset; + + if (sPriv->drmMinor >= 3) { + drmR128GetParam gp; + int ret; + + gp.param = R128_PARAM_IRQ_NR; + gp.value = &r128Screen->irq; + + ret = drmCommandWriteRead( sPriv->fd, DRM_R128_GETPARAM, + &gp, sizeof(gp)); + if (ret) { + fprintf(stderr, "drmR128GetParam (R128_PARAM_IRQ_NR): %d\n", ret); + FREE( r128Screen ); + return NULL; + } + } + + r128Screen->mmio.handle = r128DRIPriv->registerHandle; + r128Screen->mmio.size = r128DRIPriv->registerSize; + if ( drmMap( sPriv->fd, + r128Screen->mmio.handle, + r128Screen->mmio.size, + (drmAddressPtr)&r128Screen->mmio.map ) ) { + FREE( r128Screen ); + return NULL; + } + + r128Screen->buffers = drmMapBufs( sPriv->fd ); + if ( !r128Screen->buffers ) { + drmUnmap( (drmAddress)r128Screen->mmio.map, r128Screen->mmio.size ); + FREE( r128Screen ); + return NULL; + } + + if ( !r128Screen->IsPCI ) { + r128Screen->agpTextures.handle = r128DRIPriv->agpTexHandle; + r128Screen->agpTextures.size = r128DRIPriv->agpTexMapSize; + if ( drmMap( sPriv->fd, + r128Screen->agpTextures.handle, + r128Screen->agpTextures.size, + (drmAddressPtr)&r128Screen->agpTextures.map ) ) { + drmUnmapBufs( r128Screen->buffers ); + drmUnmap( (drmAddress)r128Screen->mmio.map, r128Screen->mmio.size ); + FREE( r128Screen ); + return NULL; + } + } + + switch ( r128DRIPriv->deviceID ) { + case PCI_CHIP_RAGE128RE: + case PCI_CHIP_RAGE128RF: + case PCI_CHIP_RAGE128RK: + case PCI_CHIP_RAGE128RL: + r128Screen->chipset = R128_CARD_TYPE_R128; + break; + case PCI_CHIP_RAGE128PD: + case PCI_CHIP_RAGE128PF: + r128Screen->chipset = R128_CARD_TYPE_R128_PRO; + break; + case PCI_CHIP_RAGE128LE: + case PCI_CHIP_RAGE128LF: + r128Screen->chipset = R128_CARD_TYPE_R128_MOBILITY; + break; + default: + r128Screen->chipset = R128_CARD_TYPE_R128; + break; + } + + r128Screen->cpp = r128DRIPriv->bpp / 8; + r128Screen->AGPMode = r128DRIPriv->AGPMode; + + r128Screen->frontOffset = r128DRIPriv->frontOffset; + r128Screen->frontPitch = r128DRIPriv->frontPitch; + r128Screen->backOffset = r128DRIPriv->backOffset; + r128Screen->backPitch = r128DRIPriv->backPitch; + r128Screen->depthOffset = r128DRIPriv->depthOffset; + r128Screen->depthPitch = r128DRIPriv->depthPitch; + r128Screen->spanOffset = r128DRIPriv->spanOffset; + + r128Screen->texOffset[R128_CARD_HEAP] = r128DRIPriv->textureOffset; + r128Screen->texSize[R128_CARD_HEAP] = r128DRIPriv->textureSize; + r128Screen->logTexGranularity[R128_CARD_HEAP] = r128DRIPriv->log2TexGran; + + if ( r128Screen->IsPCI ) { + r128Screen->numTexHeaps = R128_NR_TEX_HEAPS - 1; + r128Screen->texOffset[R128_AGP_HEAP] = 0; + r128Screen->texSize[R128_AGP_HEAP] = 0; + r128Screen->logTexGranularity[R128_AGP_HEAP] = 0; + } else { + r128Screen->numTexHeaps = R128_NR_TEX_HEAPS; + r128Screen->texOffset[R128_AGP_HEAP] = + r128DRIPriv->agpTexOffset + R128_AGP_TEX_OFFSET; + r128Screen->texSize[R128_AGP_HEAP] = r128DRIPriv->agpTexMapSize; + r128Screen->logTexGranularity[R128_AGP_HEAP] = + r128DRIPriv->log2AGPTexGran; + } + + r128Screen->driScreen = sPriv; + + return r128Screen; +} + +/* Destroy the device specific screen private data struct. + */ +static void +r128DestroyScreen( __DRIscreenPrivate *sPriv ) +{ + r128ScreenPtr r128Screen = (r128ScreenPtr)sPriv->private; + + if ( !r128Screen ) + return; + + if ( !r128Screen->IsPCI ) { + drmUnmap( (drmAddress)r128Screen->agpTextures.map, + r128Screen->agpTextures.size ); + } + drmUnmapBufs( r128Screen->buffers ); + drmUnmap( (drmAddress)r128Screen->mmio.map, r128Screen->mmio.size ); + + FREE( r128Screen ); + sPriv->private = NULL; +} + + +/* Initialize the fullscreen mode. + */ +static GLboolean +r128OpenCloseFullScreen( __DRIcontextPrivate *driContextPriv ) +{ + return GL_TRUE; +} + + +/* Create and initialize the Mesa and driver specific pixmap buffer + * data. + */ +static GLboolean +r128CreateBuffer( __DRIscreenPrivate *driScrnPriv, + __DRIdrawablePrivate *driDrawPriv, + const __GLcontextModes *mesaVis, + GLboolean isPixmap ) +{ + if (isPixmap) { + return GL_FALSE; /* not implemented */ + } + else { + driDrawPriv->driverPrivate = (void *) + _mesa_create_framebuffer( mesaVis, + GL_FALSE, /* software depth buffer? */ + mesaVis->stencilBits > 0, + mesaVis->accumRedBits > 0, + mesaVis->alphaBits > 0 ); + return (driDrawPriv->driverPrivate != NULL); + } +} + + +static void +r128DestroyBuffer(__DRIdrawablePrivate *driDrawPriv) +{ + _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate)); +} + + +/* Copy the back color buffer to the front color buffer */ +static void +r128SwapBuffers(__DRIdrawablePrivate *dPriv) +{ + if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) { + r128ContextPtr rmesa; + GLcontext *ctx; + rmesa = (r128ContextPtr) dPriv->driContextPriv->driverPrivate; + ctx = rmesa->glCtx; + if (ctx->Visual.doubleBufferMode) { + _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */ + if ( rmesa->doPageFlip ) { + r128PageFlip( dPriv ); + } + else { + r128CopyBuffer( dPriv ); + } + } + } + else { + /* XXX this shouldn't be an error but we can't handle it for now */ + _mesa_problem(NULL, "%s: drawable has no context!", __FUNCTION__); + } +} + + +/* Initialize the driver specific screen private data. + */ +static GLboolean +r128InitDriver( __DRIscreenPrivate *sPriv ) +{ + sPriv->private = (void *) r128CreateScreen( sPriv ); + + if ( !sPriv->private ) { + r128DestroyScreen( sPriv ); + return GL_FALSE; + } + + return GL_TRUE; +} + + +#ifndef _SOLO +/* This function is called by libGL.so as soon as libGL.so is loaded. + * This is where we register new extension functions with the dispatcher. + */ +void __driRegisterExtensions( void ) +{ + PFNGLXENABLEEXTENSIONPROC glx_enable_extension; + + if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) { + glx_enable_extension = (PFNGLXENABLEEXTENSIONPROC) + glXGetProcAddress( "__glXEnableExtension" ); + + if ( glx_enable_extension != NULL ) { + glx_enable_extension( "GLX_SGI_swap_control", GL_FALSE ); + glx_enable_extension( "GLX_SGI_video_sync", GL_FALSE ); + glx_enable_extension( "GLX_MESA_swap_control", GL_FALSE ); + } + } +} +#endif + +static struct __DriverAPIRec r128API = { + .InitDriver = r128InitDriver, + .DestroyScreen = r128DestroyScreen, + .CreateContext = r128CreateContext, + .DestroyContext = r128DestroyContext, + .CreateBuffer = r128CreateBuffer, + .DestroyBuffer = r128DestroyBuffer, + .SwapBuffers = r128SwapBuffers, + .MakeCurrent = r128MakeCurrent, + .UnbindContext = r128UnbindContext, + .OpenFullScreen = r128OpenCloseFullScreen, + .CloseFullScreen = r128OpenCloseFullScreen, + .GetSwapInfo = NULL, + .GetMSC = driGetMSC32, + .WaitForMSC = driWaitForMSC32, + .WaitForSBC = NULL, + .SwapBuffersMSC = NULL + +}; + + +/* + * This is the bootstrap function for the driver. + * The __driCreateScreen name is the symbol that libGL.so fetches. + * Return: pointer to a __DRIscreenPrivate. + */ +#ifndef _SOLO +void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc, + int numConfigs, __GLXvisualConfig *config) +{ + __DRIscreenPrivate *psp; + psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &r128API); + return (void *) psp; +} +#else +void *__driCreateScreen(struct DRIDriverRec *driver, + struct DRIDriverContextRec *driverContext) +{ + __DRIscreenPrivate *psp; + psp = __driUtilCreateScreen(driver, driverContext, &r128API); + return (void *) psp; +} +#endif diff --git a/src/mesa/drivers/dri/r128/r128_screen.h b/src/mesa/drivers/dri/r128/r128_screen.h new file mode 100644 index 0000000000..4b1a57292d --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_screen.h @@ -0,0 +1,84 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_screen.h,v 1.7 2002/12/16 16:18:53 dawes Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * + */ + +#ifndef __R128_SCREEN_H__ +#define __R128_SCREEN_H__ + +#ifdef GLX_DIRECT_RENDERING + +#include "r128_sarea.h" + +typedef struct { + drmHandle handle; /* Handle to the DRM region */ + drmSize size; /* Size of the DRM region */ + unsigned char *map; /* Mapping of the DRM region */ +} r128RegionRec, *r128RegionPtr; + +typedef struct { + + GLint chipset; + GLint cpp; + GLint IsPCI; /* Current card is a PCI card */ + GLint AGPMode; + unsigned int irq; /* IRQ number (0 means none) */ + + GLuint frontOffset; + GLuint frontPitch; + GLuint backOffset; + GLuint backPitch; + + GLuint depthOffset; + GLuint depthPitch; + GLuint spanOffset; + + /* Shared texture data */ + GLint numTexHeaps; + GLint texOffset[R128_NR_TEX_HEAPS]; + GLint texSize[R128_NR_TEX_HEAPS]; + GLint logTexGranularity[R128_NR_TEX_HEAPS]; + + r128RegionRec mmio; + r128RegionRec agpTextures; + + drmBufMapPtr buffers; + + __DRIscreenPrivate *driScreen; + unsigned int sarea_priv_offset; + +} r128ScreenRec, *r128ScreenPtr; + + +#endif +#endif /* __R128_SCREEN_H__ */ diff --git a/src/mesa/drivers/dri/r128/r128_span.c b/src/mesa/drivers/dri/r128/r128_span.c new file mode 100644 index 0000000000..c6f3195942 --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_span.c @@ -0,0 +1,475 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_span.c,v 1.8 2002/10/30 12:51:39 alanh Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Keith Whitwell <keith@tungstengraphics.com> + * Kevin E. Martin <martin@valinux.com> + * + */ + +#include "r128_context.h" +#include "r128_ioctl.h" +#include "r128_state.h" +#include "r128_span.h" +#include "r128_tex.h" + +#include "swrast/swrast.h" + +#define DBG 0 + +#define HAVE_HW_DEPTH_SPANS 1 +#define HAVE_HW_DEPTH_PIXELS 1 + +#define LOCAL_VARS \ + r128ContextPtr rmesa = R128_CONTEXT(ctx); \ + r128ScreenPtr r128scrn = rmesa->r128Screen; \ + __DRIscreenPrivate *sPriv = rmesa->driScreen; \ + __DRIdrawablePrivate *dPriv = rmesa->driDrawable; \ + GLuint pitch = r128scrn->frontPitch * r128scrn->cpp; \ + GLuint height = dPriv->h; \ + char *buf = (char *)(sPriv->pFB + \ + rmesa->drawOffset + \ + (dPriv->x * r128scrn->cpp) + \ + (dPriv->y * pitch)); \ + char *read_buf = (char *)(sPriv->pFB + \ + rmesa->readOffset + \ + (dPriv->x * r128scrn->cpp) + \ + (dPriv->y * pitch)); \ + GLuint p; \ + (void) read_buf; (void) buf; (void) p + +#define LOCAL_DEPTH_VARS \ + r128ContextPtr rmesa = R128_CONTEXT(ctx); \ + r128ScreenPtr r128scrn = rmesa->r128Screen; \ + __DRIscreenPrivate *sPriv = rmesa->driScreen; \ + __DRIdrawablePrivate *dPriv = rmesa->driDrawable; \ + GLuint height = dPriv->h; \ + (void) r128scrn; (void) sPriv; (void) height + +#define LOCAL_STENCIL_VARS LOCAL_DEPTH_VARS + + +#define CLIPPIXEL( _x, _y ) \ + ((_x >= minx) && (_x < maxx) && (_y >= miny) && (_y < maxy)) + + +#define CLIPSPAN( _x, _y, _n, _x1, _n1, _i ) \ + if ( _y < miny || _y >= maxy ) { \ + _n1 = 0, _x1 = x; \ + } else { \ + _n1 = _n; \ + _x1 = _x; \ + if ( _x1 < minx ) _i += (minx-_x1), n1 -= (minx-_x1), _x1 = minx; \ + if ( _x1 + _n1 >= maxx ) n1 -= (_x1 + n1 - maxx); \ + } + +#define Y_FLIP( _y ) (height - _y - 1) + + +#define HW_LOCK() \ + r128ContextPtr rmesa = R128_CONTEXT(ctx); \ + FLUSH_BATCH( rmesa ); \ + LOCK_HARDWARE( rmesa ); \ + r128WaitForIdleLocked( rmesa ); + +#define HW_CLIPLOOP() \ + do { \ + __DRIdrawablePrivate *dPriv = rmesa->driDrawable; \ + int _nc = dPriv->numClipRects; \ + \ + while ( _nc-- ) { \ + int minx = dPriv->pClipRects[_nc].x1 - dPriv->x; \ + int miny = dPriv->pClipRects[_nc].y1 - dPriv->y; \ + int maxx = dPriv->pClipRects[_nc].x2 - dPriv->x; \ + int maxy = dPriv->pClipRects[_nc].y2 - dPriv->y; + +#define HW_ENDCLIPLOOP() \ + } \ + } while (0) + +#define HW_UNLOCK() \ + UNLOCK_HARDWARE( rmesa ) + + + +/* ================================================================ + * Color buffer + */ + +/* 16 bit, RGB565 color spanline and pixel functions + */ +#undef INIT_MONO_PIXEL +#define INIT_MONO_PIXEL(p, color) \ + p = R128PACKCOLOR565( color[0], color[1], color[2] ) + +#define WRITE_RGBA( _x, _y, r, g, b, a ) \ + *(GLushort *)(buf + _x*2 + _y*pitch) = ((((int)r & 0xf8) << 8) | \ + (((int)g & 0xfc) << 3) | \ + (((int)b & 0xf8) >> 3)) + +#define WRITE_PIXEL( _x, _y, p ) \ + *(GLushort *)(buf + _x*2 + _y*pitch) = p + +#define READ_RGBA( rgba, _x, _y ) \ + do { \ + GLushort p = *(GLushort *)(read_buf + _x*2 + _y*pitch); \ + rgba[0] = (p >> 8) & 0xf8; \ + rgba[1] = (p >> 3) & 0xfc; \ + rgba[2] = (p << 3) & 0xf8; \ + rgba[3] = 0xff; \ + if ( rgba[0] & 0x08 ) rgba[0] |= 0x07; \ + if ( rgba[1] & 0x04 ) rgba[1] |= 0x03; \ + if ( rgba[2] & 0x08 ) rgba[2] |= 0x07; \ + } while (0) + +#define TAG(x) r128##x##_RGB565 +#include "spantmp.h" + +#define READ_DEPTH(d, _x, _y) \ + d = *(GLushort *)(buf + _x*2 + _y*pitch) + +/* 32 bit, ARGB8888 color spanline and pixel functions + */ +#undef INIT_MONO_PIXEL +#define INIT_MONO_PIXEL(p, color) \ + p = R128PACKCOLOR8888( color[0], color[1], color[2], color[3] ) + +#define WRITE_RGBA( _x, _y, r, g, b, a ) \ + *(GLuint *)(buf + _x*4 + _y*pitch) = ((b << 0) | \ + (g << 8) | \ + (r << 16) | \ + (a << 24) ) + +#define WRITE_PIXEL( _x, _y, p ) \ + *(GLuint *)(buf + _x*4 + _y*pitch) = p + +#define READ_RGBA( rgba, _x, _y ) \ +do { \ + GLuint p = *(GLuint *)(read_buf + _x*4 + _y*pitch); \ + rgba[0] = (p >> 16) & 0xff; \ + rgba[1] = (p >> 8) & 0xff; \ + rgba[2] = (p >> 0) & 0xff; \ + rgba[3] = 0xff;/*(p >> 24) & 0xff;*/ \ +} while (0) + +#define TAG(x) r128##x##_ARGB8888 +#include "spantmp.h" + + +/* 24 bit, RGB888 color spanline and pixel functions */ +#undef INIT_MONO_PIXEL +#define INIT_MONO_PIXEL(p, color) \ + p = R128PACKCOLOR888( color[0], color[1], color[2] ) + +#define WRITE_RGBA(_x, _y, r, g, b, a) \ + *(GLuint *)(buf + _x*3 + _y*pitch) = ((r << 16) | \ + (g << 8) | \ + (b << 0)) + +#define WRITE_PIXEL(_x, _y, p) \ + *(GLuint *)(buf + _x*3 + _y*pitch) = p + +#define READ_RGBA(rgba, _x, _y) \ + do { \ + GLuint p = *(GLuint *)(read_buf + _x*3 + _y*pitch); \ + rgba[0] = (p >> 16) & 0xff; \ + rgba[1] = (p >> 8) & 0xff; \ + rgba[2] = (p >> 0) & 0xff; \ + rgba[3] = 0xff; \ + } while (0) + +/* ================================================================ + * Depth buffer + */ + +/* 16-bit depth buffer functions + */ +#define WRITE_DEPTH_SPAN() \ + r128WriteDepthSpanLocked( rmesa, n, \ + x + dPriv->x, \ + y + dPriv->y, \ + depth, mask ); + +#define WRITE_DEPTH_PIXELS() \ +do { \ + GLint ox[MAX_WIDTH]; \ + GLint oy[MAX_WIDTH]; \ + for ( i = 0 ; i < n ; i++ ) { \ + ox[i] = x[i] + dPriv->x; \ + } \ + for ( i = 0 ; i < n ; i++ ) { \ + oy[i] = Y_FLIP( y[i] ) + dPriv->y; \ + } \ + r128WriteDepthPixelsLocked( rmesa, n, ox, oy, depth, mask ); \ +} while (0) + +#define READ_DEPTH_SPAN() \ +do { \ + GLushort *buf = (GLushort *)((GLubyte *)sPriv->pFB + \ + r128scrn->spanOffset); \ + GLint i; \ + \ + r128ReadDepthSpanLocked( rmesa, n, \ + x + dPriv->x, \ + y + dPriv->y ); \ + r128WaitForIdleLocked( rmesa ); \ + \ + for ( i = 0 ; i < n ; i++ ) { \ + depth[i] = buf[i]; \ + } \ +} while (0) + +#define READ_DEPTH_PIXELS() \ +do { \ + GLushort *buf = (GLushort *)((GLubyte *)sPriv->pFB + \ + r128scrn->spanOffset); \ + GLint i, remaining = n; \ + \ + while ( remaining > 0 ) { \ + GLint ox[MAX_WIDTH]; \ + GLint oy[MAX_WIDTH]; \ + GLint count; \ + \ + if ( remaining <= 128 ) { \ + count = remaining; \ + } else { \ + count = 128; \ + } \ + for ( i = 0 ; i < count ; i++ ) { \ + ox[i] = x[i] + dPriv->x; \ + } \ + for ( i = 0 ; i < count ; i++ ) { \ + oy[i] = Y_FLIP( y[i] ) + dPriv->y; \ + } \ + \ + r128ReadDepthPixelsLocked( rmesa, count, ox, oy ); \ + r128WaitForIdleLocked( rmesa ); \ + \ + for ( i = 0 ; i < count ; i++ ) { \ + depth[i] = buf[i]; \ + } \ + depth += count; \ + x += count; \ + y += count; \ + remaining -= count; \ + } \ +} while (0) + +#define TAG(x) r128##x##_16 +#include "depthtmp.h" + + +/* 24-bit depth, 8-bit stencil buffer functions + */ +#define WRITE_DEPTH_SPAN() \ + r128WriteDepthSpanLocked( rmesa, n, \ + x + dPriv->x, \ + y + dPriv->y, \ + depth, mask ); + +#define WRITE_DEPTH_PIXELS() \ +do { \ + GLint ox[MAX_WIDTH]; \ + GLint oy[MAX_WIDTH]; \ + for ( i = 0 ; i < n ; i++ ) { \ + ox[i] = x[i] + dPriv->x; \ + } \ + for ( i = 0 ; i < n ; i++ ) { \ + oy[i] = Y_FLIP( y[i] ) + dPriv->y; \ + } \ + r128WriteDepthPixelsLocked( rmesa, n, ox, oy, depth, mask ); \ +} while (0) + +#define READ_DEPTH_SPAN() \ +do { \ + GLuint *buf = (GLuint *)((GLubyte *)sPriv->pFB + \ + r128scrn->spanOffset); \ + GLint i; \ + \ + r128ReadDepthSpanLocked( rmesa, n, \ + x + dPriv->x, \ + y + dPriv->y ); \ + r128WaitForIdleLocked( rmesa ); \ + \ + for ( i = 0 ; i < n ; i++ ) { \ + depth[i] = buf[i] & 0x00ffffff; \ + } \ +} while (0) + +#define READ_DEPTH_PIXELS() \ +do { \ + GLuint *buf = (GLuint *)((GLubyte *)sPriv->pFB + \ + r128scrn->spanOffset); \ + GLint i, remaining = n; \ + \ + while ( remaining > 0 ) { \ + GLint ox[MAX_WIDTH]; \ + GLint oy[MAX_WIDTH]; \ + GLint count; \ + \ + if ( remaining <= 128 ) { \ + count = remaining; \ + } else { \ + count = 128; \ + } \ + for ( i = 0 ; i < count ; i++ ) { \ + ox[i] = x[i] + dPriv->x; \ + } \ + for ( i = 0 ; i < count ; i++ ) { \ + oy[i] = Y_FLIP( y[i] ) + dPriv->y; \ + } \ + \ + r128ReadDepthPixelsLocked( rmesa, count, ox, oy ); \ + r128WaitForIdleLocked( rmesa ); \ + \ + for ( i = 0 ; i < count ; i++ ) { \ + depth[i] = buf[i] & 0x00ffffff; \ + } \ + depth += count; \ + x += count; \ + y += count; \ + remaining -= count; \ + } \ +} while (0) + +#define TAG(x) r128##x##_24_8 +#include "depthtmp.h" + + + +/* ================================================================ + * Stencil buffer + */ + +/* FIXME: Add support for hardware stencil buffers. + */ + + +/* 32 bit depthbuffer functions */ +#define WRITE_DEPTH(_x, _y, d) \ + *(GLuint *)(buf + _x*4 + _y*pitch) = d + + + +/* + * This function is called to specify which buffer to read and write + * for software rasterization (swrast) fallbacks. This doesn't necessarily + * correspond to glDrawBuffer() or glReadBuffer() calls. + */ +static void r128DDSetBuffer( GLcontext *ctx, + GLframebuffer *colorBuffer, + GLuint bufferBit ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + switch ( bufferBit ) { + case FRONT_LEFT_BIT: + if ( rmesa->sarea->pfCurrentPage == 1 ) { + rmesa->drawOffset = rmesa->readOffset = rmesa->r128Screen->backOffset; + rmesa->drawPitch = rmesa->readPitch = rmesa->r128Screen->backPitch; + } else { + rmesa->drawOffset = rmesa->readOffset = rmesa->r128Screen->frontOffset; + rmesa->drawPitch = rmesa->readPitch = rmesa->r128Screen->frontPitch; + } + break; + case BACK_LEFT_BIT: + if ( rmesa->sarea->pfCurrentPage == 1 ) { + rmesa->drawOffset = rmesa->readOffset = rmesa->r128Screen->frontOffset; + rmesa->drawPitch = rmesa->readPitch = rmesa->r128Screen->frontPitch; + } else { + rmesa->drawOffset = rmesa->readOffset = rmesa->r128Screen->backOffset; + rmesa->drawPitch = rmesa->readPitch = rmesa->r128Screen->backPitch; + } + break; + default: + break; + } +} + + +void r128DDInitSpanFuncs( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference(ctx); + + swdd->SetBuffer = r128DDSetBuffer; + + switch ( rmesa->r128Screen->cpp ) { + case 2: + swdd->WriteRGBASpan = r128WriteRGBASpan_RGB565; + swdd->WriteRGBSpan = r128WriteRGBSpan_RGB565; + swdd->WriteMonoRGBASpan = r128WriteMonoRGBASpan_RGB565; + swdd->WriteRGBAPixels = r128WriteRGBAPixels_RGB565; + swdd->WriteMonoRGBAPixels = r128WriteMonoRGBAPixels_RGB565; + swdd->ReadRGBASpan = r128ReadRGBASpan_RGB565; + swdd->ReadRGBAPixels = r128ReadRGBAPixels_RGB565; + break; + + case 4: + swdd->WriteRGBASpan = r128WriteRGBASpan_ARGB8888; + swdd->WriteRGBSpan = r128WriteRGBSpan_ARGB8888; + swdd->WriteMonoRGBASpan = r128WriteMonoRGBASpan_ARGB8888; + swdd->WriteRGBAPixels = r128WriteRGBAPixels_ARGB8888; + swdd->WriteMonoRGBAPixels = r128WriteMonoRGBAPixels_ARGB8888; + swdd->ReadRGBASpan = r128ReadRGBASpan_ARGB8888; + swdd->ReadRGBAPixels = r128ReadRGBAPixels_ARGB8888; + break; + + default: + break; + } + + switch ( rmesa->glCtx->Visual.depthBits ) { + case 16: + swdd->ReadDepthSpan = r128ReadDepthSpan_16; + swdd->WriteDepthSpan = r128WriteDepthSpan_16; + swdd->ReadDepthPixels = r128ReadDepthPixels_16; + swdd->WriteDepthPixels = r128WriteDepthPixels_16; + break; + + case 24: + swdd->ReadDepthSpan = r128ReadDepthSpan_24_8; + swdd->WriteDepthSpan = r128WriteDepthSpan_24_8; + swdd->ReadDepthPixels = r128ReadDepthPixels_24_8; + swdd->WriteDepthPixels = r128WriteDepthPixels_24_8; + break; + + default: + break; + } + + swdd->WriteCI8Span = NULL; + swdd->WriteCI32Span = NULL; + swdd->WriteMonoCISpan = NULL; + swdd->WriteCI32Pixels = NULL; + swdd->WriteMonoCIPixels = NULL; + swdd->ReadCI32Span = NULL; + swdd->ReadCI32Pixels = NULL; +} diff --git a/src/mesa/drivers/dri/r128/r128_span.h b/src/mesa/drivers/dri/r128/r128_span.h new file mode 100644 index 0000000000..44356c5b24 --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_span.h @@ -0,0 +1,44 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_span.h,v 1.3 2001/01/08 01:07:21 martin Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * + */ + +#ifndef __R128_SPAN_H__ +#define __R128_SPAN_H__ + +#ifdef GLX_DIRECT_RENDERING + +extern void r128DDInitSpanFuncs( GLcontext *ctx ); + +#endif +#endif diff --git a/src/mesa/drivers/dri/r128/r128_state.c b/src/mesa/drivers/dri/r128/r128_state.c new file mode 100644 index 0000000000..85b3b68402 --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_state.c @@ -0,0 +1,1239 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_state.c,v 1.11 2002/10/30 12:51:39 alanh Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * Keith Whitwell <keith@tungstengraphics.com> + * + */ + +#include "r128_context.h" +#include "r128_state.h" +#include "r128_ioctl.h" +#include "r128_tris.h" +#include "r128_vb.h" +#include "r128_tex.h" + +#include "context.h" +#include "enums.h" +#include "colormac.h" +#include "swrast/swrast.h" +#include "array_cache/acache.h" +#include "tnl/tnl.h" +#include "swrast_setup/swrast_setup.h" + +#include "tnl/t_pipeline.h" + + +/* ============================================================= + * Alpha blending + */ + +static void r128UpdateAlphaMode( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + GLuint a = rmesa->setup.misc_3d_state_cntl_reg; + GLuint t = rmesa->setup.tex_cntl_c; + + if ( ctx->Color.AlphaEnabled ) { + GLubyte ref; + + CLAMPED_FLOAT_TO_UBYTE(ref, ctx->Color.AlphaRef); + + a &= ~(R128_ALPHA_TEST_MASK | R128_REF_ALPHA_MASK); + + switch ( ctx->Color.AlphaFunc ) { + case GL_NEVER: + a |= R128_ALPHA_TEST_NEVER; + break; + case GL_LESS: + a |= R128_ALPHA_TEST_LESS; + break; + case GL_LEQUAL: + a |= R128_ALPHA_TEST_LESSEQUAL; + break; + case GL_EQUAL: + a |= R128_ALPHA_TEST_EQUAL; + break; + case GL_GEQUAL: + a |= R128_ALPHA_TEST_GREATEREQUAL; + break; + case GL_GREATER: + a |= R128_ALPHA_TEST_GREATER; + break; + case GL_NOTEQUAL: + a |= R128_ALPHA_TEST_NEQUAL; + break; + case GL_ALWAYS: + a |= R128_ALPHA_TEST_ALWAYS; + break; + } + + a |= ref & R128_REF_ALPHA_MASK; + t |= R128_ALPHA_TEST_ENABLE; + } else { + t &= ~R128_ALPHA_TEST_ENABLE; + } + + FALLBACK( rmesa, R128_FALLBACK_BLEND_FUNC, GL_FALSE ); + + if ( ctx->Color.BlendEnabled ) { + a &= ~(R128_ALPHA_BLEND_SRC_MASK | R128_ALPHA_BLEND_DST_MASK); + + switch ( ctx->Color.BlendSrcRGB ) { + case GL_ZERO: + a |= R128_ALPHA_BLEND_SRC_ZERO; + break; + case GL_ONE: + a |= R128_ALPHA_BLEND_SRC_ONE; + break; + case GL_DST_COLOR: + a |= R128_ALPHA_BLEND_SRC_DESTCOLOR; + break; + case GL_ONE_MINUS_DST_COLOR: + a |= R128_ALPHA_BLEND_SRC_INVDESTCOLOR; + break; + case GL_SRC_ALPHA: + a |= R128_ALPHA_BLEND_SRC_SRCALPHA; + break; + case GL_ONE_MINUS_SRC_ALPHA: + a |= R128_ALPHA_BLEND_SRC_INVSRCALPHA; + break; + case GL_DST_ALPHA: + a |= R128_ALPHA_BLEND_SRC_DESTALPHA; + break; + case GL_ONE_MINUS_DST_ALPHA: + a |= R128_ALPHA_BLEND_SRC_INVDESTALPHA; + break; + case GL_SRC_ALPHA_SATURATE: + a |= R128_ALPHA_BLEND_SRC_SRCALPHASAT; + break; + default: + FALLBACK( rmesa, R128_FALLBACK_BLEND_FUNC, GL_TRUE ); + } + + switch ( ctx->Color.BlendDstRGB ) { + case GL_ZERO: + a |= R128_ALPHA_BLEND_DST_ZERO; + break; + case GL_ONE: + a |= R128_ALPHA_BLEND_DST_ONE; + break; + case GL_SRC_COLOR: + a |= R128_ALPHA_BLEND_DST_SRCCOLOR; + break; + case GL_ONE_MINUS_SRC_COLOR: + a |= R128_ALPHA_BLEND_DST_INVSRCCOLOR; + break; + case GL_SRC_ALPHA: + a |= R128_ALPHA_BLEND_DST_SRCALPHA; + break; + case GL_ONE_MINUS_SRC_ALPHA: + a |= R128_ALPHA_BLEND_DST_INVSRCALPHA; + break; + case GL_DST_ALPHA: + a |= R128_ALPHA_BLEND_DST_DESTALPHA; + break; + case GL_ONE_MINUS_DST_ALPHA: + a |= R128_ALPHA_BLEND_DST_INVDESTALPHA; + break; + default: + FALLBACK( rmesa, R128_FALLBACK_BLEND_FUNC, GL_TRUE ); + } + + t |= R128_ALPHA_ENABLE; + } else { + t &= ~R128_ALPHA_ENABLE; + } + + if ( rmesa->setup.misc_3d_state_cntl_reg != a ) { + rmesa->setup.misc_3d_state_cntl_reg = a; + rmesa->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_MASKS; + } + if ( rmesa->setup.tex_cntl_c != t ) { + rmesa->setup.tex_cntl_c = t; + rmesa->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_MASKS; + } +} + +static void r128DDAlphaFunc( GLcontext *ctx, GLenum func, GLfloat ref ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= R128_NEW_ALPHA; +} + +static void r128DDBlendEquation( GLcontext *ctx, GLenum mode ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + + /* BlendEquation sets ColorLogicOpEnabled in an unexpected + * manner. + */ + FALLBACK( R128_CONTEXT(ctx), R128_FALLBACK_LOGICOP, + (ctx->Color.ColorLogicOpEnabled && + ctx->Color.LogicOp != GL_COPY)); + + /* Can only do blend addition, not min, max, subtract, etc. */ + FALLBACK( R128_CONTEXT(ctx), R128_FALLBACK_BLEND_EQ, + mode != GL_FUNC_ADD_EXT); + + rmesa->new_state |= R128_NEW_ALPHA; +} + +static void r128DDBlendFunc( GLcontext *ctx, GLenum sfactor, GLenum dfactor ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= R128_NEW_ALPHA; +} + +static void r128DDBlendFuncSeparate( GLcontext *ctx, + GLenum sfactorRGB, GLenum dfactorRGB, + GLenum sfactorA, GLenum dfactorA ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= R128_NEW_ALPHA; +} + + +/* ============================================================= + * Depth testing + */ + +static void r128UpdateZMode( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + GLuint z = rmesa->setup.z_sten_cntl_c; + GLuint t = rmesa->setup.tex_cntl_c; + + if ( ctx->Depth.Test ) { + z &= ~R128_Z_TEST_MASK; + + switch ( ctx->Depth.Func ) { + case GL_NEVER: + z |= R128_Z_TEST_NEVER; + break; + case GL_ALWAYS: + z |= R128_Z_TEST_ALWAYS; + break; + case GL_LESS: + z |= R128_Z_TEST_LESS; + break; + case GL_LEQUAL: + z |= R128_Z_TEST_LESSEQUAL; + break; + case GL_EQUAL: + z |= R128_Z_TEST_EQUAL; + break; + case GL_GEQUAL: + z |= R128_Z_TEST_GREATEREQUAL; + break; + case GL_GREATER: + z |= R128_Z_TEST_GREATER; + break; + case GL_NOTEQUAL: + z |= R128_Z_TEST_NEQUAL; + break; + } + + t |= R128_Z_ENABLE; + } else { + t &= ~R128_Z_ENABLE; + } + + if ( ctx->Depth.Mask ) { + t |= R128_Z_WRITE_ENABLE; + } else { + t &= ~R128_Z_WRITE_ENABLE; + } + + if ( rmesa->setup.z_sten_cntl_c != z ) { + rmesa->setup.z_sten_cntl_c = z; + rmesa->dirty |= R128_UPLOAD_CONTEXT; + } + if ( rmesa->setup.tex_cntl_c != t ) { + rmesa->setup.tex_cntl_c = t; + rmesa->dirty |= R128_UPLOAD_CONTEXT; + } +} + +static void r128DDDepthFunc( GLcontext *ctx, GLenum func ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= R128_NEW_DEPTH; +} + +static void r128DDDepthMask( GLcontext *ctx, GLboolean flag ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= R128_NEW_DEPTH; +} + +static void r128DDClearDepth( GLcontext *ctx, GLclampd d ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + switch ( rmesa->setup.z_sten_cntl_c & R128_Z_PIX_WIDTH_MASK ) { + case R128_Z_PIX_WIDTH_16: + rmesa->ClearDepth = d * 0x0000ffff; + break; + case R128_Z_PIX_WIDTH_24: + rmesa->ClearDepth = d * 0x00ffffff; + break; + case R128_Z_PIX_WIDTH_32: + rmesa->ClearDepth = d * 0xffffffff; + break; + } +} + + +/* ============================================================= + * Fog + */ + +static void r128UpdateFogAttrib( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + GLuint t = rmesa->setup.tex_cntl_c; + GLubyte c[4]; + GLuint col; + + if ( ctx->Fog.Enabled ) { + t |= R128_FOG_ENABLE; + } else { + t &= ~R128_FOG_ENABLE; + } + + c[0] = FLOAT_TO_UBYTE( ctx->Fog.Color[0] ); + c[1] = FLOAT_TO_UBYTE( ctx->Fog.Color[1] ); + c[2] = FLOAT_TO_UBYTE( ctx->Fog.Color[2] ); + + col = r128PackColor( 4, c[0], c[1], c[2], 0 ); + + if ( rmesa->setup.fog_color_c != col ) { + rmesa->setup.fog_color_c = col; + rmesa->dirty |= R128_UPLOAD_CONTEXT; + } + if ( rmesa->setup.tex_cntl_c != t ) { + rmesa->setup.tex_cntl_c = t; + rmesa->dirty |= R128_UPLOAD_CONTEXT; + } +} + +static void r128DDFogfv( GLcontext *ctx, GLenum pname, const GLfloat *param ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= R128_NEW_FOG; +} + + +/* ============================================================= + * Clipping + */ + +static void r128UpdateClipping( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + if ( rmesa->driDrawable ) { + __DRIdrawablePrivate *drawable = rmesa->driDrawable; + int x1 = 0; + int y1 = 0; + int x2 = drawable->w - 1; + int y2 = drawable->h - 1; + + if ( ctx->Scissor.Enabled ) { + if ( ctx->Scissor.X > x1 ) { + x1 = ctx->Scissor.X; + } + if ( drawable->h - ctx->Scissor.Y - ctx->Scissor.Height > y1 ) { + y1 = drawable->h - ctx->Scissor.Y - ctx->Scissor.Height; + } + if ( ctx->Scissor.X + ctx->Scissor.Width - 1 < x2 ) { + x2 = ctx->Scissor.X + ctx->Scissor.Width - 1; + } + if ( drawable->h - ctx->Scissor.Y - 1 < y2 ) { + y2 = drawable->h - ctx->Scissor.Y - 1; + } + } + + x1 += drawable->x; + y1 += drawable->y; + x2 += drawable->x; + y2 += drawable->y; + + rmesa->setup.sc_top_left_c = ((y1 << 16) | x1); + rmesa->setup.sc_bottom_right_c = ((y2 << 16) | x2); + + rmesa->dirty |= R128_UPLOAD_CONTEXT; + } +} + +static void r128DDScissor( GLcontext *ctx, + GLint x, GLint y, GLsizei w, GLsizei h ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= R128_NEW_CLIP; +} + + +/* ============================================================= + * Culling + */ + +static void r128UpdateCull( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + GLuint f = rmesa->setup.pm4_vc_fpu_setup; + + f &= ~R128_FRONT_DIR_MASK; + + switch ( ctx->Polygon.FrontFace ) { + case GL_CW: + f |= R128_FRONT_DIR_CW; + break; + case GL_CCW: + f |= R128_FRONT_DIR_CCW; + break; + } + + f |= R128_BACKFACE_SOLID | R128_FRONTFACE_SOLID; + + if ( ctx->Polygon.CullFlag ) { + switch ( ctx->Polygon.CullFaceMode ) { + case GL_FRONT: + f &= ~R128_FRONTFACE_SOLID; + break; + case GL_BACK: + f &= ~R128_BACKFACE_SOLID; + break; + case GL_FRONT_AND_BACK: + f &= ~(R128_BACKFACE_SOLID | + R128_FRONTFACE_SOLID); + break; + } + } + + if ( 1 || rmesa->setup.pm4_vc_fpu_setup != f ) { + rmesa->setup.pm4_vc_fpu_setup = f; + rmesa->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_SETUP; + } +} + +static void r128DDCullFace( GLcontext *ctx, GLenum mode ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= R128_NEW_CULL; +} + +static void r128DDFrontFace( GLcontext *ctx, GLenum mode ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= R128_NEW_CULL; +} + + +/* ============================================================= + * Masks + */ + +static void r128UpdateMasks( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + GLuint mask = r128PackColor( rmesa->r128Screen->cpp, + ctx->Color.ColorMask[RCOMP], + ctx->Color.ColorMask[GCOMP], + ctx->Color.ColorMask[BCOMP], + ctx->Color.ColorMask[ACOMP] ); + + if ( rmesa->setup.plane_3d_mask_c != mask ) { + rmesa->setup.plane_3d_mask_c = mask; + rmesa->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_MASKS; + } +} + +static void r128DDColorMask( GLcontext *ctx, + GLboolean r, GLboolean g, + GLboolean b, GLboolean a ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + rmesa->new_state |= R128_NEW_MASKS; +} + + +/* ============================================================= + * Rendering attributes + * + * We really don't want to recalculate all this every time we bind a + * texture. These things shouldn't change all that often, so it makes + * sense to break them out of the core texture state update routines. + */ + +static void updateSpecularLighting( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + GLuint t = rmesa->setup.tex_cntl_c; + + if ( ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR && + ctx->Light.Enabled) { + /* XXX separate specular color just doesn't seem to work as it should. + * For now, we fall back to s/w rendering whenever separate specular + * is enabled. + */ +#if 0 + if (ctx->Light.ShadeModel == GL_FLAT) { + /* R128 can't do flat-shaded separate specular */ + t &= ~R128_SPEC_LIGHT_ENABLE; + FALLBACK( rmesa, R128_FALLBACK_SEP_SPECULAR, GL_TRUE ); + /*printf("%s fallback sep spec\n", __FUNCTION__);*/ + } + else { + t |= R128_SPEC_LIGHT_ENABLE; + FALLBACK( rmesa, R128_FALLBACK_SEP_SPECULAR, GL_FALSE ); + /*printf("%s enable sep spec\n", __FUNCTION__);*/ + } +#else + t &= ~R128_SPEC_LIGHT_ENABLE; + FALLBACK( rmesa, R128_FALLBACK_SEP_SPECULAR, GL_TRUE ); + /*printf("%s fallback sep spec\n", __FUNCTION__);*/ +#endif + } + else { + t &= ~R128_SPEC_LIGHT_ENABLE; + FALLBACK( rmesa, R128_FALLBACK_SEP_SPECULAR, GL_FALSE ); + /*printf("%s disable sep spec\n", __FUNCTION__);*/ + } + + if ( rmesa->setup.tex_cntl_c != t ) { + rmesa->setup.tex_cntl_c = t; + rmesa->dirty |= R128_UPLOAD_CONTEXT; + rmesa->dirty |= R128_UPLOAD_SETUP; + rmesa->new_state |= R128_NEW_CONTEXT; + } +} + + +static void r128DDLightModelfv( GLcontext *ctx, GLenum pname, + const GLfloat *param ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + if ( pname == GL_LIGHT_MODEL_COLOR_CONTROL ) { + FLUSH_BATCH( rmesa ); + updateSpecularLighting(ctx); + } +} + +static void r128DDShadeModel( GLcontext *ctx, GLenum mode ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + GLuint s = rmesa->setup.pm4_vc_fpu_setup; + + s &= ~R128_FPU_COLOR_MASK; + + switch ( mode ) { + case GL_FLAT: + s |= R128_FPU_COLOR_FLAT; + break; + case GL_SMOOTH: + s |= R128_FPU_COLOR_GOURAUD; + break; + default: + return; + } + + updateSpecularLighting(ctx); + + if ( rmesa->setup.pm4_vc_fpu_setup != s ) { + FLUSH_BATCH( rmesa ); + rmesa->setup.pm4_vc_fpu_setup = s; + + rmesa->new_state |= R128_NEW_CONTEXT; + rmesa->dirty |= R128_UPLOAD_SETUP; + } +} + + +/* ============================================================= + * Window position + */ + +void r128UpdateWindow( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + int x = rmesa->driDrawable->x; + int y = rmesa->driDrawable->y; + + rmesa->setup.window_xy_offset = ((y << R128_WINDOW_Y_SHIFT) | + (x << R128_WINDOW_X_SHIFT)); + + rmesa->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_WINDOW; +} + +/* ============================================================= + * Viewport + */ + + +static void r128CalcViewport( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + const GLfloat *v = ctx->Viewport._WindowMap.m; + GLfloat *m = rmesa->hw_viewport; + + /* See also r128_translate_vertex. + */ + m[MAT_SX] = v[MAT_SX]; + m[MAT_TX] = v[MAT_TX] + SUBPIXEL_X; + m[MAT_SY] = - v[MAT_SY]; + m[MAT_TY] = - v[MAT_TY] + rmesa->driDrawable->h + SUBPIXEL_Y; + m[MAT_SZ] = v[MAT_SZ] * rmesa->depth_scale; + m[MAT_TZ] = v[MAT_TZ] * rmesa->depth_scale; +} + +static void r128Viewport( GLcontext *ctx, + GLint x, GLint y, + GLsizei width, GLsizei height ) +{ + r128CalcViewport( ctx ); +} + +static void r128DepthRange( GLcontext *ctx, + GLclampd nearval, GLclampd farval ) +{ + r128CalcViewport( ctx ); +} + + +/* ============================================================= + * Miscellaneous + */ + +static void r128DDClearColor( GLcontext *ctx, + const GLfloat color[4] ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + GLubyte c[4]; + + CLAMPED_FLOAT_TO_UBYTE(c[0], color[0]); + CLAMPED_FLOAT_TO_UBYTE(c[1], color[1]); + CLAMPED_FLOAT_TO_UBYTE(c[2], color[2]); + CLAMPED_FLOAT_TO_UBYTE(c[3], color[3]); + + rmesa->ClearColor = r128PackColor( rmesa->r128Screen->cpp, + c[0], c[1], c[2], c[3] ); +} + +static void r128DDLogicOpCode( GLcontext *ctx, GLenum opcode ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + if ( ctx->Color.ColorLogicOpEnabled ) { + FLUSH_BATCH( rmesa ); + + FALLBACK( rmesa, R128_FALLBACK_LOGICOP, opcode != GL_COPY ); + } +} + +static void r128DDDrawBuffer( GLcontext *ctx, GLenum mode ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + + /* + * _DrawDestMask is easier to cope with than <mode>. + */ + switch ( ctx->Color._DrawDestMask ) { + case FRONT_LEFT_BIT: + FALLBACK( rmesa, R128_FALLBACK_DRAW_BUFFER, GL_FALSE ); + break; + case BACK_LEFT_BIT: + FALLBACK( rmesa, R128_FALLBACK_DRAW_BUFFER, GL_FALSE ); + break; + default: + /* GL_NONE or GL_FRONT_AND_BACK or stereo left&right, etc */ + FALLBACK( rmesa, R128_FALLBACK_DRAW_BUFFER, GL_TRUE ); + break; + } + + /* We want to update the s/w rast state too so that r200SetBuffer() + * gets called. + */ + _swrast_DrawBuffer(ctx, mode); + + rmesa->setup.dst_pitch_offset_c = (((rmesa->drawPitch/8) << 21) | + (rmesa->drawOffset >> 5)); + rmesa->new_state |= R128_NEW_WINDOW; +} + +static void r128DDReadBuffer( GLcontext *ctx, GLenum mode ) +{ + /* nothing, until we implement h/w glRead/CopyPixels or CopyTexImage */ +} + + +/* ============================================================= + * Polygon stipple + */ + +static void r128DDPolygonStipple( GLcontext *ctx, const GLubyte *mask ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + GLuint stipple[32], i; + drmR128Stipple stippleRec; + + for (i = 0; i < 32; i++) { + stipple[31 - i] = ((mask[i*4+0] << 24) | + (mask[i*4+1] << 16) | + (mask[i*4+2] << 8) | + (mask[i*4+3])); + } + + FLUSH_BATCH( rmesa ); + LOCK_HARDWARE( rmesa ); + + stippleRec.mask = stipple; + drmCommandWrite( rmesa->driFd, DRM_R128_STIPPLE, + &stippleRec, sizeof(drmR128Stipple) ); + + UNLOCK_HARDWARE( rmesa ); + + rmesa->new_state |= R128_NEW_CONTEXT; + rmesa->dirty |= R128_UPLOAD_CONTEXT; +} + + +/* ============================================================= + * Render mode + */ + +static void r128DDRenderMode( GLcontext *ctx, GLenum mode ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + FALLBACK( rmesa, R128_FALLBACK_RENDER_MODE, (mode != GL_RENDER) ); +} + + + +/* ============================================================= + * State enable/disable + */ + +static void r128DDEnable( GLcontext *ctx, GLenum cap, GLboolean state ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + if ( R128_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %s = %s )\n", + __FUNCTION__, _mesa_lookup_enum_by_nr( cap ), + state ? "GL_TRUE" : "GL_FALSE" ); + } + + switch ( cap ) { + case GL_ALPHA_TEST: + FLUSH_BATCH( rmesa ); + rmesa->new_state |= R128_NEW_ALPHA; + break; + + case GL_BLEND: + FLUSH_BATCH( rmesa ); + rmesa->new_state |= R128_NEW_ALPHA; + + /* For some reason enable(GL_BLEND) affects ColorLogicOpEnabled. + */ + FALLBACK( rmesa, R128_FALLBACK_LOGICOP, + (ctx->Color.ColorLogicOpEnabled && + ctx->Color.LogicOp != GL_COPY)); + break; + + case GL_CULL_FACE: + FLUSH_BATCH( rmesa ); + rmesa->new_state |= R128_NEW_CULL; + break; + + case GL_DEPTH_TEST: + FLUSH_BATCH( rmesa ); + rmesa->new_state |= R128_NEW_DEPTH; + break; + + case GL_DITHER: + do { + GLuint t = rmesa->setup.tex_cntl_c; + FLUSH_BATCH( rmesa ); + + if ( ctx->Color.DitherFlag ) { + t |= R128_DITHER_ENABLE; + } else { + t &= ~R128_DITHER_ENABLE; + } + + if ( rmesa->setup.tex_cntl_c != t ) { + rmesa->setup.tex_cntl_c = t; + rmesa->dirty |= R128_UPLOAD_CONTEXT; + } + } while (0); + break; + + case GL_FOG: + FLUSH_BATCH( rmesa ); + rmesa->new_state |= R128_NEW_FOG; + break; + + case GL_COLOR_LOGIC_OP: + FLUSH_BATCH( rmesa ); + FALLBACK( rmesa, R128_FALLBACK_LOGICOP, + state && ctx->Color.LogicOp != GL_COPY ); + break; + + case GL_LIGHTING: + updateSpecularLighting(ctx); + break; + + case GL_SCISSOR_TEST: + FLUSH_BATCH( rmesa ); + rmesa->scissor = state; + rmesa->new_state |= R128_NEW_CLIP; + break; + + case GL_STENCIL_TEST: + FLUSH_BATCH( rmesa ); + FALLBACK( rmesa, R128_FALLBACK_STENCIL, state ); + break; + + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_3D: + FLUSH_BATCH( rmesa ); + break; + + case GL_POLYGON_STIPPLE: + if ( rmesa->render_primitive == GL_TRIANGLES ) { + FLUSH_BATCH( rmesa ); + rmesa->setup.dp_gui_master_cntl_c &= ~R128_GMC_BRUSH_NONE; + if ( state ) { + rmesa->setup.dp_gui_master_cntl_c |= + R128_GMC_BRUSH_32x32_MONO_FG_LA; + } else { + rmesa->setup.dp_gui_master_cntl_c |= + R128_GMC_BRUSH_SOLID_COLOR; + } + rmesa->new_state |= R128_NEW_CONTEXT; + rmesa->dirty |= R128_UPLOAD_CONTEXT; + } + break; + + default: + return; + } +} + + +/* ============================================================= + * State initialization, management + */ + +static void r128DDPrintDirty( const char *msg, GLuint state ) +{ + fprintf( stderr, + "%s: (0x%x) %s%s%s%s%s%s%s%s%s\n", + msg, + state, + (state & R128_UPLOAD_CORE) ? "core, " : "", + (state & R128_UPLOAD_CONTEXT) ? "context, " : "", + (state & R128_UPLOAD_SETUP) ? "setup, " : "", + (state & R128_UPLOAD_TEX0) ? "tex0, " : "", + (state & R128_UPLOAD_TEX1) ? "tex1, " : "", + (state & R128_UPLOAD_MASKS) ? "masks, " : "", + (state & R128_UPLOAD_WINDOW) ? "window, " : "", + (state & R128_UPLOAD_CLIPRECTS) ? "cliprects, " : "", + (state & R128_REQUIRE_QUIESCENCE) ? "quiescence, " : "" ); +} + +/* + * Load the current context's state into the hardware. + * + * NOTE: Be VERY careful about ensuring the context state is marked for + * upload, the only place it shouldn't be uploaded is when the setup + * state has changed in ReducedPrimitiveChange as this comes right after + * a state update. + * + * Blits of any type should always upload the context and masks after + * they are done. + */ +void r128EmitHwStateLocked( r128ContextPtr rmesa ) +{ + R128SAREAPrivPtr sarea = rmesa->sarea; + r128_context_regs_t *regs = &(rmesa->setup); + const r128TexObjPtr t0 = rmesa->CurrentTexObj[0]; + const r128TexObjPtr t1 = rmesa->CurrentTexObj[1]; + + if ( R128_DEBUG & DEBUG_VERBOSE_MSG ) { + r128DDPrintDirty( "r128EmitHwStateLocked", rmesa->dirty ); + } + + if ( rmesa->dirty & (R128_UPLOAD_CONTEXT | + R128_UPLOAD_SETUP | + R128_UPLOAD_MASKS | + R128_UPLOAD_WINDOW | + R128_UPLOAD_CORE) ) { + memcpy( &sarea->ContextState, regs, sizeof(sarea->ContextState) ); + } + + if ( (rmesa->dirty & R128_UPLOAD_TEX0) && t0 ) { + r128_texture_regs_t *tex = &sarea->TexState[0]; + + tex->tex_cntl = t0->setup.tex_cntl; + tex->tex_combine_cntl = rmesa->tex_combine[0]; + tex->tex_size_pitch = t0->setup.tex_size_pitch; + memcpy( &tex->tex_offset[0], &t0->setup.tex_offset[0], + sizeof(tex->tex_offset ) ); + tex->tex_border_color = t0->setup.tex_border_color; + } + + if ( (rmesa->dirty & R128_UPLOAD_TEX1) && t1 ) { + r128_texture_regs_t *tex = &sarea->TexState[1]; + + tex->tex_cntl = t1->setup.tex_cntl; + tex->tex_combine_cntl = rmesa->tex_combine[1]; + tex->tex_size_pitch = t1->setup.tex_size_pitch; + memcpy( &tex->tex_offset[0], &t1->setup.tex_offset[0], + sizeof(tex->tex_offset ) ); + tex->tex_border_color = t1->setup.tex_border_color; + } + + sarea->vertsize = rmesa->vertex_size; + sarea->vc_format = rmesa->vertex_format; + + /* Turn off the texture cache flushing */ + rmesa->setup.tex_cntl_c &= ~R128_TEX_CACHE_FLUSH; + + sarea->dirty |= rmesa->dirty; + rmesa->dirty &= R128_UPLOAD_CLIPRECTS; +} + +static void r128DDPrintState( const char *msg, GLuint flags ) +{ + fprintf( stderr, + "%s: (0x%x) %s%s%s%s%s%s%s%s\n", + msg, + flags, + (flags & R128_NEW_CONTEXT) ? "context, " : "", + (flags & R128_NEW_ALPHA) ? "alpha, " : "", + (flags & R128_NEW_DEPTH) ? "depth, " : "", + (flags & R128_NEW_FOG) ? "fog, " : "", + (flags & R128_NEW_CLIP) ? "clip, " : "", + (flags & R128_NEW_CULL) ? "cull, " : "", + (flags & R128_NEW_MASKS) ? "masks, " : "", + (flags & R128_NEW_WINDOW) ? "window, " : "" ); +} + +void r128DDUpdateHWState( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + int new_state = rmesa->new_state; + + if ( new_state || rmesa->NewGLState & _NEW_TEXTURE ) + { + FLUSH_BATCH( rmesa ); + + rmesa->new_state = 0; + + if ( R128_DEBUG & DEBUG_VERBOSE_MSG ) + r128DDPrintState( "r128UpdateHwState", new_state ); + + /* Update the various parts of the context's state. + */ + if ( new_state & R128_NEW_ALPHA ) + r128UpdateAlphaMode( ctx ); + + if ( new_state & R128_NEW_DEPTH ) + r128UpdateZMode( ctx ); + + if ( new_state & R128_NEW_FOG ) + r128UpdateFogAttrib( ctx ); + + if ( new_state & R128_NEW_CLIP ) + r128UpdateClipping( ctx ); + + if ( new_state & R128_NEW_CULL ) + r128UpdateCull( ctx ); + + if ( new_state & R128_NEW_MASKS ) + r128UpdateMasks( ctx ); + + if ( new_state & R128_NEW_WINDOW ) + r128UpdateWindow( ctx ); + + if ( rmesa->NewGLState & _NEW_TEXTURE ) { + r128UpdateTextureState( ctx ); + } + } +} + + +static void r128DDInvalidateState( 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 ); + R128_CONTEXT(ctx)->NewGLState |= new_state; +} + + + +/* Initialize the context's hardware state. + */ +void r128DDInitState( r128ContextPtr rmesa ) +{ + int dst_bpp, depth_bpp; + + switch ( rmesa->r128Screen->cpp ) { + case 2: + dst_bpp = R128_GMC_DST_16BPP; + break; + case 4: + dst_bpp = R128_GMC_DST_32BPP; + break; + default: + fprintf( stderr, "Error: Unsupported pixel depth... exiting\n" ); + exit( -1 ); + } + + rmesa->ClearColor = 0x00000000; + + switch ( rmesa->glCtx->Visual.depthBits ) { + case 16: + rmesa->ClearDepth = 0x0000ffff; + depth_bpp = R128_Z_PIX_WIDTH_16; + rmesa->depth_scale = 1.0 / (GLfloat)0xffff; + break; + case 24: + rmesa->ClearDepth = 0x00ffffff; + depth_bpp = R128_Z_PIX_WIDTH_24; + rmesa->depth_scale = 1.0 / (GLfloat)0xffffff; + break; + default: + fprintf( stderr, "Error: Unsupported depth %d... exiting\n", + rmesa->glCtx->Visual.depthBits ); + exit( -1 ); + } + + rmesa->Fallback = 0; + + if ( rmesa->glCtx->Visual.doubleBufferMode && rmesa->sarea->pfCurrentPage == 0 ) { + rmesa->drawOffset = rmesa->readOffset = rmesa->r128Screen->backOffset; + rmesa->drawPitch = rmesa->readPitch = rmesa->r128Screen->backPitch; + } else { + rmesa->drawOffset = rmesa->readOffset = rmesa->r128Screen->frontOffset; + rmesa->drawPitch = rmesa->readPitch = rmesa->r128Screen->frontPitch; + } + + /* Harware state: + */ + rmesa->setup.dst_pitch_offset_c = (((rmesa->drawPitch/8) << 21) | + (rmesa->drawOffset >> 5)); + + rmesa->setup.dp_gui_master_cntl_c = (R128_GMC_DST_PITCH_OFFSET_CNTL | + R128_GMC_DST_CLIPPING | + R128_GMC_BRUSH_SOLID_COLOR | + dst_bpp | + R128_GMC_SRC_DATATYPE_COLOR | + R128_GMC_BYTE_MSB_TO_LSB | + R128_GMC_CONVERSION_TEMP_6500 | + R128_ROP3_S | + R128_DP_SRC_SOURCE_MEMORY | + R128_GMC_3D_FCN_EN | + R128_GMC_CLR_CMP_CNTL_DIS | + R128_GMC_AUX_CLIP_DIS | + R128_GMC_WR_MSK_DIS); + + rmesa->setup.sc_top_left_c = 0x00000000; + rmesa->setup.sc_bottom_right_c = 0x1fff1fff; + + rmesa->setup.z_offset_c = rmesa->r128Screen->depthOffset; + rmesa->setup.z_pitch_c = ((rmesa->r128Screen->depthPitch >> 3) | + R128_Z_TILE); + + rmesa->setup.z_sten_cntl_c = (depth_bpp | + R128_Z_TEST_LESS | + R128_STENCIL_TEST_ALWAYS | + R128_STENCIL_S_FAIL_KEEP | + R128_STENCIL_ZPASS_KEEP | + R128_STENCIL_ZFAIL_KEEP); + + rmesa->setup.tex_cntl_c = (R128_Z_WRITE_ENABLE | + R128_SHADE_ENABLE | + R128_DITHER_ENABLE | + R128_ALPHA_IN_TEX_COMPLETE_A | + R128_LIGHT_DIS | + R128_ALPHA_LIGHT_DIS | + R128_TEX_CACHE_FLUSH | + (0x3f << R128_LOD_BIAS_SHIFT)); + + rmesa->setup.misc_3d_state_cntl_reg = (R128_MISC_SCALE_3D_TEXMAP_SHADE | + R128_MISC_SCALE_PIX_REPLICATE | + R128_ALPHA_COMB_ADD_CLAMP | + R128_FOG_VERTEX | + R128_ALPHA_BLEND_SRC_ONE | + R128_ALPHA_BLEND_DST_ZERO | + R128_ALPHA_TEST_ALWAYS); + + rmesa->setup.texture_clr_cmp_clr_c = 0x00000000; + rmesa->setup.texture_clr_cmp_msk_c = 0xffffffff; + + rmesa->setup.fog_color_c = 0x00000000; + + rmesa->setup.pm4_vc_fpu_setup = (R128_FRONT_DIR_CCW | + R128_BACKFACE_SOLID | + R128_FRONTFACE_SOLID | + R128_FPU_COLOR_GOURAUD | + R128_FPU_SUB_PIX_4BITS | + R128_FPU_MODE_3D | + R128_TRAP_BITS_DISABLE | + R128_XFACTOR_2 | + R128_YFACTOR_2 | + R128_FLAT_SHADE_VERTEX_OGL | + R128_FPU_ROUND_TRUNCATE | + R128_WM_SEL_8DW); + + rmesa->setup.setup_cntl = (R128_COLOR_GOURAUD | + R128_PRIM_TYPE_TRI | + R128_TEXTURE_ST_MULT_W | + R128_STARTING_VERTEX_1 | + R128_ENDING_VERTEX_3 | + R128_SU_POLY_LINE_NOT_LAST | + R128_SUB_PIX_4BITS); + + rmesa->setup.tex_size_pitch_c = 0x00000000; + rmesa->setup.constant_color_c = 0x00ffffff; + + rmesa->setup.dp_write_mask = 0xffffffff; + rmesa->setup.sten_ref_mask_c = 0xffff0000; + rmesa->setup.plane_3d_mask_c = 0xffffffff; + + rmesa->setup.window_xy_offset = 0x00000000; + + rmesa->setup.scale_3d_cntl = (R128_SCALE_DITHER_TABLE | + R128_TEX_CACHE_SIZE_FULL | + R128_DITHER_INIT_RESET | + R128_SCALE_3D_TEXMAP_SHADE | + R128_SCALE_PIX_REPLICATE | + R128_ALPHA_COMB_ADD_CLAMP | + R128_FOG_VERTEX | + R128_ALPHA_BLEND_SRC_ONE | + R128_ALPHA_BLEND_DST_ZERO | + R128_ALPHA_TEST_ALWAYS | + R128_COMPOSITE_SHADOW_CMP_EQUAL | + R128_TEX_MAP_ALPHA_IN_TEXTURE | + R128_TEX_CACHE_LINE_SIZE_4QW); + + rmesa->new_state = R128_NEW_ALL; +} + +/* Initialize the driver's state functions. + */ +void r128DDInitStateFuncs( GLcontext *ctx ) +{ + ctx->Driver.UpdateState = r128DDInvalidateState; + + ctx->Driver.ClearIndex = NULL; + ctx->Driver.ClearColor = r128DDClearColor; + ctx->Driver.DrawBuffer = r128DDDrawBuffer; + ctx->Driver.ReadBuffer = r128DDReadBuffer; + + ctx->Driver.IndexMask = NULL; + ctx->Driver.ColorMask = r128DDColorMask; + ctx->Driver.AlphaFunc = r128DDAlphaFunc; + ctx->Driver.BlendEquation = r128DDBlendEquation; + ctx->Driver.BlendFunc = r128DDBlendFunc; + ctx->Driver.BlendFuncSeparate = r128DDBlendFuncSeparate; + ctx->Driver.ClearDepth = r128DDClearDepth; + ctx->Driver.CullFace = r128DDCullFace; + ctx->Driver.FrontFace = r128DDFrontFace; + ctx->Driver.DepthFunc = r128DDDepthFunc; + ctx->Driver.DepthMask = r128DDDepthMask; + ctx->Driver.Enable = r128DDEnable; + ctx->Driver.Fogfv = r128DDFogfv; + ctx->Driver.Hint = NULL; + ctx->Driver.Lightfv = NULL; + ctx->Driver.LightModelfv = r128DDLightModelfv; + ctx->Driver.LogicOpcode = r128DDLogicOpCode; + ctx->Driver.PolygonMode = NULL; + ctx->Driver.PolygonStipple = r128DDPolygonStipple; + ctx->Driver.RenderMode = r128DDRenderMode; + ctx->Driver.Scissor = r128DDScissor; + ctx->Driver.ShadeModel = r128DDShadeModel; + ctx->Driver.ClearStencil = NULL; + ctx->Driver.StencilFunc = NULL; + ctx->Driver.StencilMask = NULL; + ctx->Driver.StencilOp = NULL; + + ctx->Driver.DepthRange = r128DepthRange; + ctx->Driver.Viewport = r128Viewport; + + /* Pixel path fallbacks. + */ + ctx->Driver.Accum = _swrast_Accum; + ctx->Driver.Bitmap = _swrast_Bitmap; + ctx->Driver.CopyPixels = _swrast_CopyPixels; + ctx->Driver.DrawPixels = _swrast_DrawPixels; + ctx->Driver.ReadPixels = _swrast_ReadPixels; + + /* Swrast hooks for imaging extensions: + */ + ctx->Driver.CopyColorTable = _swrast_CopyColorTable; + ctx->Driver.CopyColorSubTable = _swrast_CopyColorSubTable; + ctx->Driver.CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D; + ctx->Driver.CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D; +} diff --git a/src/mesa/drivers/dri/r128/r128_state.h b/src/mesa/drivers/dri/r128/r128_state.h new file mode 100644 index 0000000000..c51ac23942 --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_state.h @@ -0,0 +1,54 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_state.h,v 1.3 2001/01/08 01:07:21 martin Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * + */ + +#ifndef __R128_STATE_H__ +#define __R128_STATE_H__ + +#ifdef GLX_DIRECT_RENDERING + +#include "r128_context.h" + +extern void r128DDInitState( r128ContextPtr rmesa ); +extern void r128DDInitStateFuncs( GLcontext *ctx ); + +extern void r128DDUpdateState( GLcontext *ctx ); +extern void r128DDUpdateHWState( GLcontext *ctx ); + +extern void r128UpdateWindow( GLcontext *ctx ); + +extern void r128EmitHwStateLocked( r128ContextPtr rmesa ); + +#endif +#endif diff --git a/src/mesa/drivers/dri/r128/r128_tex.c b/src/mesa/drivers/dri/r128/r128_tex.c new file mode 100644 index 0000000000..2793a793a0 --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_tex.c @@ -0,0 +1,598 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_tex.c,v 1.14 2002/11/05 17:46:08 tsi Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * Brian Paul <brianp@valinux.com> + */ + +#include "r128_context.h" +#include "r128_state.h" +#include "r128_ioctl.h" +#include "r128_vb.h" +#include "r128_tris.h" +#include "r128_tex.h" +#include "r128_texobj.h" + +#include "context.h" +#include "macros.h" +#include "simple_list.h" +#include "enums.h" +#include "texstore.h" +#include "texformat.h" +#include "teximage.h" +#include "imports.h" +#include "colormac.h" + +#define TEX_0 1 +#define TEX_1 2 + + +static void r128SetTexWrap( r128TexObjPtr t, GLenum swrap, GLenum twrap ) +{ + t->setup.tex_cntl &= ~(R128_TEX_CLAMP_S_MASK | R128_TEX_CLAMP_T_MASK); + + switch ( swrap ) { + case GL_CLAMP: + t->setup.tex_cntl |= R128_TEX_CLAMP_S_BORDER_COLOR; + break; + case GL_CLAMP_TO_EDGE: + t->setup.tex_cntl |= R128_TEX_CLAMP_S_CLAMP; + break; + case GL_REPEAT: + t->setup.tex_cntl |= R128_TEX_CLAMP_S_WRAP; + break; + case GL_CLAMP_TO_BORDER: + t->setup.tex_cntl |= R128_TEX_CLAMP_S_BORDER_COLOR; + break; + case GL_MIRRORED_REPEAT: + t->setup.tex_cntl |= R128_TEX_CLAMP_S_MIRROR; + break; + } + + switch ( twrap ) { + case GL_CLAMP: + t->setup.tex_cntl |= R128_TEX_CLAMP_T_BORDER_COLOR; + break; + case GL_CLAMP_TO_EDGE: + t->setup.tex_cntl |= R128_TEX_CLAMP_T_CLAMP; + break; + case GL_REPEAT: + t->setup.tex_cntl |= R128_TEX_CLAMP_T_WRAP; + break; + case GL_CLAMP_TO_BORDER: + t->setup.tex_cntl |= R128_TEX_CLAMP_T_BORDER_COLOR; + break; + case GL_MIRRORED_REPEAT: + t->setup.tex_cntl |= R128_TEX_CLAMP_T_MIRROR; + break; + } +} + +static void r128SetTexFilter( r128TexObjPtr t, GLenum minf, GLenum magf ) +{ + t->setup.tex_cntl &= ~(R128_MIN_BLEND_MASK | R128_MAG_BLEND_MASK); + + switch ( minf ) { + case GL_NEAREST: + t->setup.tex_cntl |= R128_MIN_BLEND_NEAREST; + break; + case GL_LINEAR: + t->setup.tex_cntl |= R128_MIN_BLEND_LINEAR; + break; + case GL_NEAREST_MIPMAP_NEAREST: + t->setup.tex_cntl |= R128_MIN_BLEND_MIPNEAREST; + break; + case GL_LINEAR_MIPMAP_NEAREST: + t->setup.tex_cntl |= R128_MIN_BLEND_MIPLINEAR; + break; + case GL_NEAREST_MIPMAP_LINEAR: + t->setup.tex_cntl |= R128_MIN_BLEND_LINEARMIPNEAREST; + break; + case GL_LINEAR_MIPMAP_LINEAR: + t->setup.tex_cntl |= R128_MIN_BLEND_LINEARMIPLINEAR; + break; + } + + switch ( magf ) { + case GL_NEAREST: + t->setup.tex_cntl |= R128_MAG_BLEND_NEAREST; + break; + case GL_LINEAR: + t->setup.tex_cntl |= R128_MAG_BLEND_LINEAR; + break; + } +} + +static void r128SetTexBorderColor( r128TexObjPtr t, GLubyte c[4] ) +{ + t->setup.tex_border_color = r128PackColor( 4, c[0], c[1], c[2], c[3] ); +} + + +static r128TexObjPtr r128AllocTexObj( struct gl_texture_object *texObj ) +{ + r128TexObjPtr t; + + if ( R128_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p )\n", __FUNCTION__, texObj ); + } + + t = (r128TexObjPtr) CALLOC_STRUCT( r128_tex_obj ); + texObj->DriverData = t; + if ( t != NULL ) { + + /* Initialize non-image-dependent parts of the state: + */ + t->base.tObj = texObj; + + /* FIXME Something here to set initial values for other parts of + * FIXME t->setup? + */ + + make_empty_list( (driTextureObject *) t ); + + r128SetTexWrap( t, texObj->WrapS, texObj->WrapT ); + r128SetTexFilter( t, texObj->MinFilter, texObj->MagFilter ); + r128SetTexBorderColor( t, texObj->_BorderChan ); + } + + return t; +} + + +/* Called by the _mesa_store_teximage[123]d() functions. */ +static const struct gl_texture_format * +r128ChooseTextureFormat( GLcontext *ctx, GLint internalFormat, + GLenum format, GLenum type ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + (void) format; + (void) type; + + switch ( internalFormat ) { + case GL_ALPHA: + case GL_ALPHA4: + case GL_ALPHA8: + case GL_ALPHA12: + case GL_ALPHA16: + case GL_COMPRESSED_ALPHA: + 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: + case 4: + case GL_RGBA: + case GL_COMPRESSED_RGBA: + case GL_RGBA2: + case GL_RGB5_A1: + case GL_RGBA8: + case GL_RGB10_A2: + case GL_RGBA12: + case GL_RGBA16: + if (rmesa->r128Screen->cpp == 4) + return &_mesa_texformat_argb8888; + else + return &_mesa_texformat_argb4444; + case GL_RGBA4: + return &_mesa_texformat_argb4444; + + case 3: + case GL_RGB: + case GL_COMPRESSED_RGB: + case GL_R3_G3_B2: + case GL_RGB4: + case GL_RGB5: + case GL_RGB8: + case GL_RGB10: + case GL_RGB12: + case GL_RGB16: + if (rmesa->r128Screen->cpp == 4) + return &_mesa_texformat_argb8888; + else + return &_mesa_texformat_rgb565; + + case 1: + case GL_LUMINANCE: + case GL_LUMINANCE4: + case GL_LUMINANCE8: + case GL_LUMINANCE12: + case GL_LUMINANCE16: + case GL_COMPRESSED_LUMINANCE: + if (rmesa->r128Screen->cpp == 4) + return &_mesa_texformat_argb8888; /* inefficient but accurate */ + else + return &_mesa_texformat_rgb565; + + case GL_INTENSITY4: + return &_mesa_texformat_argb4444; + case GL_INTENSITY: + case GL_INTENSITY8: + case GL_INTENSITY12: + case GL_INTENSITY16: + case GL_COMPRESSED_INTENSITY: + if (rmesa->r128Screen->cpp == 4) + return &_mesa_texformat_argb8888; /* inefficient but accurate */ + else + return &_mesa_texformat_argb4444; + + case GL_COLOR_INDEX: + case GL_COLOR_INDEX1_EXT: + case GL_COLOR_INDEX2_EXT: + case GL_COLOR_INDEX4_EXT: + case GL_COLOR_INDEX8_EXT: + case GL_COLOR_INDEX12_EXT: + case GL_COLOR_INDEX16_EXT: + return &_mesa_texformat_ci8; + + case GL_YCBCR_MESA: + if (type == GL_UNSIGNED_SHORT_8_8_APPLE || + type == GL_UNSIGNED_BYTE) + return &_mesa_texformat_ycbcr; + else + return &_mesa_texformat_ycbcr_rev; + + default: + _mesa_problem( ctx, "unexpected format in %s", __FUNCTION__ ); + return NULL; + } +} + + +static void r128TexImage1D( GLcontext *ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint border, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + if ( t ) { + driSwapOutTextureObject( t ); + } + else { + t = (driTextureObject *) r128AllocTexObj(texObj); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D"); + return; + } + } + + /* Note, this will call r128ChooseTextureFormat */ + _mesa_store_teximage1d( ctx, target, level, internalFormat, + width, border, format, type, + pixels, packing, texObj, texImage ); + + t->dirty_images[0] |= (1 << level); +} + + +static void r128TexSubImage1D( GLcontext *ctx, + GLenum target, + GLint level, + GLint xoffset, + GLsizei width, + GLenum format, GLenum type, + const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + assert( t ); /* this _should_ be true */ + if ( t ) { + driSwapOutTextureObject( t ); + } + else { + t = (driTextureObject *) r128AllocTexObj(texObj); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D"); + return; + } + } + + _mesa_store_texsubimage1d(ctx, target, level, xoffset, width, + format, type, pixels, packing, texObj, + texImage); + + t->dirty_images[0] |= (1 << level); +} + + +static void r128TexImage2D( GLcontext *ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint border, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + if ( t ) { + driSwapOutTextureObject( (driTextureObject *) t ); + } + else { + t = (driTextureObject *) r128AllocTexObj(texObj); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D"); + return; + } + } + + /* Note, this will call r128ChooseTextureFormat */ + _mesa_store_teximage2d(ctx, target, level, internalFormat, + width, height, border, format, type, pixels, + &ctx->Unpack, texObj, texImage); + + t->dirty_images[0] |= (1 << level); +} + + +static void r128TexSubImage2D( GLcontext *ctx, + GLenum target, + GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + assert( t ); /* this _should_ be true */ + if ( t ) { + driSwapOutTextureObject( t ); + } + else { + t = (driTextureObject *) r128AllocTexObj(texObj); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D"); + return; + } + } + + _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width, + height, format, type, pixels, packing, texObj, + texImage); + t->dirty_images[0] |= (1 << level); +} + + +static void r128DDTexEnv( GLcontext *ctx, GLenum target, + GLenum pname, const GLfloat *param ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + struct gl_texture_unit *texUnit; + GLubyte c[4]; + + if ( R128_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %s )\n", + __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) ); + } + + switch ( pname ) { + case GL_TEXTURE_ENV_MODE: + FLUSH_BATCH( rmesa ); + rmesa->new_state |= R128_NEW_ALPHA; + break; + + case GL_TEXTURE_ENV_COLOR: + texUnit = &ctx->Texture.Unit[ctx->Texture.CurrentUnit]; + CLAMPED_FLOAT_TO_UBYTE( c[0], texUnit->EnvColor[0] ); + CLAMPED_FLOAT_TO_UBYTE( c[1], texUnit->EnvColor[1] ); + CLAMPED_FLOAT_TO_UBYTE( c[2], texUnit->EnvColor[2] ); + CLAMPED_FLOAT_TO_UBYTE( c[3], texUnit->EnvColor[3] ); + rmesa->env_color = r128PackColor( 4, c[0], c[1], c[2], c[3] ); + if ( rmesa->setup.constant_color_c != rmesa->env_color ) { + FLUSH_BATCH( rmesa ); + rmesa->setup.constant_color_c = rmesa->env_color; + + /* More complex multitexture/multipass fallbacks for GL_BLEND + * can be done later, but this allows a single pass GL_BLEND + * in some cases (ie. Performer town demo). This is only + * applicable to the regular Rage 128, as the Pro and M3 can + * handle true single-pass GL_BLEND texturing. + */ + rmesa->blend_flags &= ~R128_BLEND_ENV_COLOR; + if ( R128_IS_PLAIN( rmesa ) && + rmesa->env_color != 0x00000000 && + rmesa->env_color != 0xff000000 && + rmesa->env_color != 0x00ffffff && + rmesa->env_color != 0xffffffff ) { + rmesa->blend_flags |= R128_BLEND_ENV_COLOR; + } + } + break; + + case GL_TEXTURE_LOD_BIAS_EXT: + do { + CARD32 t = rmesa->setup.tex_cntl_c; + GLint bias; + CARD32 b; + + /* GTH: This isn't exactly correct, but gives good results up to a + * certain point. It is better than completely ignoring the LOD + * bias. Unfortunately there isn't much range in the bias, the + * spec mentions strides that vary between 0.5 and 2.0 but these + * numbers don't seem to relate the the GL LOD bias value at all. + */ + if ( param[0] >= 1.0 ) { + bias = -128; + } else if ( param[0] >= 0.5 ) { + bias = -64; + } else if ( param[0] >= 0.25 ) { + bias = 0; + } else if ( param[0] >= 0.0 ) { + bias = 63; + } else { + bias = 127; + } + + b = (CARD32)bias & 0xff; + t &= ~R128_LOD_BIAS_MASK; + t |= (b << R128_LOD_BIAS_SHIFT); + + if ( rmesa->setup.tex_cntl_c != t ) { + FLUSH_BATCH( rmesa ); + rmesa->setup.tex_cntl_c = t; + rmesa->dirty |= R128_UPLOAD_CONTEXT; + } + } while (0); + break; + + default: + return; + } +} + + +static void r128DDTexParameter( GLcontext *ctx, GLenum target, + struct gl_texture_object *tObj, + GLenum pname, const GLfloat *params ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + r128TexObjPtr t = (r128TexObjPtr)tObj->DriverData; + + if ( R128_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %s )\n", + __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) ); + } + + if ( ( target != GL_TEXTURE_2D ) && ( target != GL_TEXTURE_1D ) ) + return; + + switch ( pname ) { + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_MAG_FILTER: + if ( t->base.bound ) FLUSH_BATCH( rmesa ); + r128SetTexFilter( t, tObj->MinFilter, tObj->MagFilter ); + break; + + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + if ( t->base.bound ) FLUSH_BATCH( rmesa ); + r128SetTexWrap( t, tObj->WrapS, tObj->WrapT ); + break; + + case GL_TEXTURE_BORDER_COLOR: + if ( t->base.bound ) FLUSH_BATCH( rmesa ); + r128SetTexBorderColor( t, tObj->_BorderChan ); + break; + + case GL_TEXTURE_BASE_LEVEL: + case GL_TEXTURE_MAX_LEVEL: + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + /* This isn't the most efficient solution but there doesn't appear to + * be a nice alternative for R128. Since there's no LOD clamping, + * we just have to rely on loading the right subset of mipmap levels + * to simulate a clamped LOD. + */ + if ( t->base.bound ) FLUSH_BATCH( rmesa ); + driSwapOutTextureObject( (driTextureObject *) t ); + break; + + default: + return; + } +} + +static void r128DDBindTexture( GLcontext *ctx, GLenum target, + struct gl_texture_object *tObj ) +{ + if ( R128_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p ) unit=%d\n", __FUNCTION__, tObj, + ctx->Texture.CurrentUnit ); + } + + if ( target == GL_TEXTURE_2D || target == GL_TEXTURE_1D ) { + if ( tObj->DriverData == NULL ) { + r128AllocTexObj( tObj ); + } + } +} + +static void r128DDDeleteTexture( GLcontext *ctx, + struct gl_texture_object *tObj ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + driTextureObject * t = (driTextureObject *) tObj->DriverData; + + if ( t ) { + if ( t->bound && rmesa ) { + FLUSH_BATCH( rmesa ); + } + + driDestroyTextureObject( t ); + } +} + +void r128DDInitTextureFuncs( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + + ctx->Driver.TexEnv = r128DDTexEnv; + ctx->Driver.ChooseTextureFormat = r128ChooseTextureFormat; + ctx->Driver.TexImage1D = r128TexImage1D; + ctx->Driver.TexSubImage1D = r128TexSubImage1D; + ctx->Driver.TexImage2D = r128TexImage2D; + ctx->Driver.TexSubImage2D = r128TexSubImage2D; + ctx->Driver.TexImage3D = _mesa_store_teximage3d; + ctx->Driver.TexSubImage3D = _mesa_store_texsubimage3d; + ctx->Driver.CopyTexImage1D = _swrast_copy_teximage1d; + ctx->Driver.CopyTexImage2D = _swrast_copy_teximage2d; + ctx->Driver.CopyTexSubImage1D = _swrast_copy_texsubimage1d; + ctx->Driver.CopyTexSubImage2D = _swrast_copy_texsubimage2d; + ctx->Driver.CopyTexSubImage3D = _swrast_copy_texsubimage3d; + ctx->Driver.TestProxyTexImage = _mesa_test_proxy_teximage; + ctx->Driver.TexParameter = r128DDTexParameter; + ctx->Driver.BindTexture = r128DDBindTexture; + ctx->Driver.DeleteTexture = r128DDDeleteTexture; + ctx->Driver.UpdateTexturePalette = NULL; + ctx->Driver.ActiveTexture = NULL; + ctx->Driver.IsTextureResident = driIsTextureResident; + ctx->Driver.PrioritizeTexture = NULL; + + driInitTextureObjects( ctx, & rmesa->swapped, + DRI_TEXMGR_DO_TEXTURE_1D + | DRI_TEXMGR_DO_TEXTURE_2D ); +} diff --git a/src/mesa/drivers/dri/r128/r128_tex.h b/src/mesa/drivers/dri/r128/r128_tex.h new file mode 100644 index 0000000000..2e3d954fbb --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_tex.h @@ -0,0 +1,88 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_tex.h,v 1.7 2002/02/22 21:44:58 dawes Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * + */ + +#ifndef __R128_TEX_H__ +#define __R128_TEX_H__ + +#ifdef GLX_DIRECT_RENDERING + +extern void r128UpdateTextureState( GLcontext *ctx ); + +extern void r128UploadTexImages( r128ContextPtr rmesa, r128TexObjPtr t ); + +extern void r128DestroyTexObj( r128ContextPtr rmesa, r128TexObjPtr t ); + +extern void r128DDInitTextureFuncs( GLcontext *ctx ); + + +/* ================================================================ + * Color conversion macros: + */ + +#define R128PACKCOLOR332( r, g, b ) \ + (((r) & 0xe0) | (((g) & 0xe0) >> 3) | (((b) & 0xc0) >> 6)) + +#define R128PACKCOLOR1555( r, g, b, a ) \ + ((((r) & 0xf8) << 7) | (((g) & 0xf8) << 2) | (((b) & 0xf8) >> 3) | \ + ((a) ? 0x8000 : 0)) + +#define R128PACKCOLOR565( r, g, b ) \ + ((((r) & 0xf8) << 8) | (((g) & 0xfc) << 3) | (((b) & 0xf8) >> 3)) + +#define R128PACKCOLOR888( r, g, b ) \ + (((r) << 16) | ((g) << 8) | (b)) + +#define R128PACKCOLOR8888( r, g, b, a ) \ + (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) + +#define R128PACKCOLOR4444( r, g, b, a ) \ + ((((a) & 0xf0) << 8) | (((r) & 0xf0) << 4) | ((g) & 0xf0) | ((b) >> 4)) + +static __inline__ CARD32 r128PackColor( GLuint cpp, + GLubyte r, GLubyte g, + GLubyte b, GLubyte a ) +{ + switch ( cpp ) { + case 2: + return R128PACKCOLOR565( r, g, b ); + case 4: + return R128PACKCOLOR8888( r, g, b, a ); + default: + return 0; + } +} + +#endif +#endif /* __R128_TEX_H__ */ diff --git a/src/mesa/drivers/dri/r128/r128_texmem.c b/src/mesa/drivers/dri/r128/r128_texmem.c new file mode 100644 index 0000000000..f6a5dfbbcf --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_texmem.c @@ -0,0 +1,302 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_tex.c,v 1.7 2001/01/08 01:07:21 martin Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * Brian Paul <brianp@valinux.com> + */ + +#include "r128_context.h" +#include "r128_state.h" +#include "r128_ioctl.h" +#include "r128_vb.h" +#include "r128_tris.h" +#include "r128_tex.h" + +#include "context.h" +#include "macros.h" +#include "simple_list.h" +#include "texformat.h" +#include "imports.h" + +#define TEX_0 1 +#define TEX_1 2 + + +/* Destroy hardware state associated with texture `t'. + */ +void r128DestroyTexObj( r128ContextPtr rmesa, r128TexObjPtr t ) +{ + unsigned i; + + + /* See if it was the driver's current object. + */ + + if ( rmesa != NULL ) + { + for ( i = 0 ; i < rmesa->glCtx->Const.MaxTextureUnits ; i++ ) + { + if ( t == rmesa->CurrentTexObj[ i ] ) { + assert( t->base.bound & (1 << i) ); + rmesa->CurrentTexObj[ i ] = NULL; + } + } + } +} + + +/** + * Upload the texture image associated with texture \a t at the specified + * level at the address relative to \a start. + */ +static void uploadSubImage( r128ContextPtr rmesa, r128TexObjPtr t, + GLint level, + GLint x, GLint y, GLint width, GLint height ) +{ + struct gl_texture_image *image; + int texelsPerDword = 0; + int imageWidth, imageHeight; + int remaining, rows; + int format, dwords; + CARD32 pitch, offset; + int i; + + /* Ensure we have a valid texture to upload */ + if ( ( level < 0 ) || ( level > R128_MAX_TEXTURE_LEVELS ) ) + return; + + image = t->base.tObj->Image[level]; + if ( !image ) + return; + + switch ( image->TexFormat->TexelBytes ) { + case 1: texelsPerDword = 4; break; + case 2: texelsPerDword = 2; break; + case 4: texelsPerDword = 1; break; + } + +#if 1 + /* FIXME: The subimage index calcs are wrong... */ + x = 0; + y = 0; + width = image->Width; + height = image->Height; +#endif + + imageWidth = image->Width; + imageHeight = image->Height; + + format = t->textureFormat >> 16; + + /* The texel upload routines have a minimum width, so force the size + * if needed. + */ + if ( imageWidth < texelsPerDword ) { + int factor; + + factor = texelsPerDword / imageWidth; + imageWidth = texelsPerDword; + imageHeight /= factor; + if ( imageHeight == 0 ) { + /* In this case, the texel converter will actually walk a + * texel or two off the end of the image, but normal malloc + * alignment should prevent it from ever causing a fault. + */ + imageHeight = 1; + } + } + + /* We can't upload to a pitch less than 8 texels so we will need to + * linearly upload all modified rows for textures smaller than this. + * This makes the x/y/width/height different for the blitter and the + * texture walker. + */ + if ( imageWidth >= 8 ) { + /* The texture walker and the blitter look identical */ + pitch = imageWidth >> 3; + } else { + int factor; + int y2; + int start, end; + + start = (y * imageWidth) & ~7; + end = (y + height) * imageWidth; + + if ( end - start < 8 ) { + /* Handle the case where the total number of texels + * uploaded is < 8. + */ + x = 0; + y = start / 8; + width = end - start; + height = 1; + } else { + /* Upload some number of full 8 texel blit rows */ + factor = 8 / imageWidth; + + y2 = y + height - 1; + y /= factor; + y2 /= factor; + + x = 0; + width = 8; + height = y2 - y + 1; + } + + /* Fixed pitch of 8 */ + pitch = 1; + } + + dwords = width * height / texelsPerDword; + offset = t->bufAddr + t->image[level - t->base.firstLevel].offset; + +#if ENABLE_PERF_BOXES + /* Bump the performace counter */ + rmesa->c_textureBytes += (dwords << 2); +#endif + + if ( R128_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "r128UploadSubImage: %d,%d of %d,%d at %d,%d\n", + width, height, image->Width, image->Height, x, y ); + fprintf( stderr, " blit ofs: 0x%07x pitch: 0x%x dwords: %d " + "level: %d format: %x\n", + (GLuint)offset, (GLuint)pitch, dwords, level, format ); + } + + /* Subdivide the texture if required */ + if ( dwords <= R128_BUFFER_MAX_DWORDS / 2 ) { + rows = height; + } else { + rows = (R128_BUFFER_MAX_DWORDS * texelsPerDword) / (2 * width); + } + + for ( i = 0, remaining = height ; + remaining > 0 ; + remaining -= rows, y += rows, i++ ) + { + CARD32 *dst; + drmBufPtr buffer; + + assert(image->Data); + + height = MIN2(remaining, rows); + + /* Grab the indirect buffer for the texture blit */ + LOCK_HARDWARE( rmesa ); + buffer = r128GetBufferLocked( rmesa ); + + dst = (CARD32 *)((char *)buffer->address + R128_HOSTDATA_BLIT_OFFSET); + + /* Copy the next chunck of the texture image into the blit buffer */ + { + const GLubyte *src = (const GLubyte *) image->Data + + (y * image->Width + x) * image->TexFormat->TexelBytes; + const GLuint bytes = width * height * image->TexFormat->TexelBytes; + memcpy(dst, src, bytes); + } + + r128FireBlitLocked( rmesa, buffer, + offset, pitch, format, + x, y, width, height ); + UNLOCK_HARDWARE( rmesa ); + } + + rmesa->new_state |= R128_NEW_CONTEXT; + rmesa->dirty |= R128_UPLOAD_CONTEXT | R128_UPLOAD_MASKS; +} + + +/* Upload the texture images associated with texture `t'. This might + * require removing our own and/or other client's texture objects to + * make room for these images. + */ +void r128UploadTexImages( r128ContextPtr rmesa, r128TexObjPtr t ) +{ + const GLint numLevels = t->base.lastLevel - t->base.firstLevel + 1; + GLint i; + + if ( R128_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p, %p )\n", + __FUNCTION__, rmesa->glCtx, t ); + } + + assert(t); + + LOCK_HARDWARE( rmesa ); + + if ( !t->base.memBlock ) { + int heap; + + + heap = driAllocateTexture( rmesa->texture_heaps, rmesa->nr_heaps, + (driTextureObject *) t ); + if ( heap == -1 ) { + UNLOCK_HARDWARE( rmesa ); + return; + } + + /* Set the base offset of the texture image */ + t->bufAddr = rmesa->r128Screen->texOffset[heap] + + t->base.memBlock->ofs; + + /* Set texture offsets for each mipmap level */ + if ( t->setup.tex_cntl & R128_MIP_MAP_DISABLE ) { + for ( i = 0 ; i < R128_MAX_TEXTURE_LEVELS ; i++ ) { + t->setup.tex_offset[i] = t->bufAddr; + } + } else { + for ( i = 0; i < numLevels; i++ ) { + const int j = numLevels - i - 1; + t->setup.tex_offset[j] = t->bufAddr + t->image[i].offset; + } + } + } + + /* Let the world know we've used this memory recently. + */ + driUpdateTextureLRU( (driTextureObject *) t ); + UNLOCK_HARDWARE( rmesa ); + + /* Upload any images that are new */ + if ( t->base.dirty_images[0] ) { + for ( i = 0 ; i < numLevels; i++ ) { + const GLint j = t->base.firstLevel + i; /* the texObj's level */ + if ( t->base.dirty_images[0] & (1 << j) ) { + uploadSubImage( rmesa, t, j, 0, 0, + t->image[i].width, t->image[i].height ); + } + } + + rmesa->setup.tex_cntl_c |= R128_TEX_CACHE_FLUSH; + rmesa->dirty |= R128_UPLOAD_CONTEXT; + t->base.dirty_images[0] = 0; + } +} diff --git a/src/mesa/drivers/dri/r128/r128_texobj.h b/src/mesa/drivers/dri/r128/r128_texobj.h new file mode 100644 index 0000000000..e2ff1ac24d --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_texobj.h @@ -0,0 +1,69 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_texobj.h,v 1.5 2002/02/22 21:44:58 dawes Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef _R128_TEXOBJ_H_ +#define _R128_TEXOBJ_H_ + +#include "r128_sarea.h" +#include "mm.h" + +/* Individual texture image information. + */ +typedef struct { + GLuint offset; /* Relative to local texture space */ + GLuint width; + GLuint height; +} r128TexImage; + +typedef struct r128_tex_obj r128TexObj, *r128TexObjPtr; + +/* Texture object in locally shared texture space. + */ +struct r128_tex_obj { + driTextureObject base; + + CARD32 bufAddr; /* Offset to start of locally + shared texture block */ + + GLuint age; + r128TexImage image[R128_MAX_TEXTURE_LEVELS]; /* Image data for all + mipmap levels */ + + CARD32 textureFormat; /* Actual hardware format */ + + r128_texture_regs_t setup; /* Setup regs for texture */ +}; + +#endif /* _R128_TEXOBJ_H_ */ diff --git a/src/mesa/drivers/dri/r128/r128_texstate.c b/src/mesa/drivers/dri/r128/r128_texstate.c new file mode 100644 index 0000000000..3f4347b02e --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_texstate.c @@ -0,0 +1,652 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_tex.c,v 1.7 2001/01/08 01:07:21 martin Exp $ */ +/************************************************************************** + +Copyright 1999, 2000 ATI Technologies Inc. and Precision Insight, 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, PRECISION INSIGHT 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. + +**************************************************************************/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * Brian Paul <brianp@valinux.com> + */ + +#include "glheader.h" +#include "imports.h" +#include "context.h" +#include "macros.h" +#include "texformat.h" + +#include "r128_context.h" +#include "r128_state.h" +#include "r128_ioctl.h" +#include "r128_vb.h" +#include "r128_tris.h" +#include "r128_tex.h" + + +static void r128SetTexImages( r128ContextPtr rmesa, + const struct gl_texture_object *tObj ) +{ + r128TexObjPtr t = (r128TexObjPtr) tObj->DriverData; + struct gl_texture_image *baseImage = tObj->Image[tObj->BaseLevel]; + int log2Pitch, log2Height, log2Size, log2MinSize; + int totalSize; + int i; + GLint firstLevel, lastLevel; + + assert(t); + assert(baseImage); + + if ( R128_DEBUG & DEBUG_VERBOSE_API ) + fprintf( stderr, "%s( %p )\n", __FUNCTION__, tObj ); + + switch (baseImage->TexFormat->MesaFormat) { + case MESA_FORMAT_ARGB8888: + t->textureFormat = R128_DATATYPE_ARGB8888; + break; + case MESA_FORMAT_ARGB4444: + t->textureFormat = R128_DATATYPE_ARGB4444; + break; + case MESA_FORMAT_RGB565: + t->textureFormat = R128_DATATYPE_RGB565; + break; + case MESA_FORMAT_RGB332: + t->textureFormat = R128_DATATYPE_RGB8; + break; + case MESA_FORMAT_CI8: + t->textureFormat = R128_DATATYPE_CI8; + break; + case MESA_FORMAT_YCBCR: + t->textureFormat = R128_DATATYPE_YVYU422; + break; + case MESA_FORMAT_YCBCR_REV: + t->textureFormat = R128_DATATYPE_VYUY422; + break; + default: + _mesa_problem(rmesa->glCtx, "Bad texture format in %s", __FUNCTION__); + }; + + /* Compute which mipmap levels we really want to send to the hardware. + * This depends on the base image size, GL_TEXTURE_MIN_LOD, + * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL. + * Yes, this looks overly complicated, but it's all needed. + */ + 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 */ + + log2Pitch = tObj->Image[firstLevel]->WidthLog2; + log2Height = tObj->Image[firstLevel]->HeightLog2; + log2Size = MAX2(log2Pitch, log2Height); + log2MinSize = log2Size; + + t->base.dirty_images[0] = 0; + totalSize = 0; + for ( i = firstLevel; i <= lastLevel; i++ ) { + const struct gl_texture_image *texImage; + + texImage = tObj->Image[i]; + if ( !texImage || !texImage->Data ) { + lastLevel = i - 1; + break; + } + + log2MinSize = texImage->MaxLog2; + + t->image[i - firstLevel].offset = totalSize; + t->image[i - firstLevel].width = tObj->Image[i]->Width; + t->image[i - firstLevel].height = tObj->Image[i]->Height; + + t->base.dirty_images[0] |= (1 << i); + + totalSize += (tObj->Image[i]->Height * + tObj->Image[i]->Width * + tObj->Image[i]->TexFormat->TexelBytes); + + /* Offsets must be 32-byte aligned for host data blits and tiling */ + totalSize = (totalSize + 31) & ~31; + } + + t->base.totalSize = totalSize; + t->base.firstLevel = firstLevel; + t->base.lastLevel = lastLevel; + + /* Set the texture format */ + t->setup.tex_cntl &= ~(0xf << 16); + t->setup.tex_cntl |= t->textureFormat; + + t->setup.tex_combine_cntl = 0x00000000; /* XXX is this right? */ + + t->setup.tex_size_pitch = ((log2Pitch << R128_TEX_PITCH_SHIFT) | + (log2Size << R128_TEX_SIZE_SHIFT) | + (log2Height << R128_TEX_HEIGHT_SHIFT) | + (log2MinSize << R128_TEX_MIN_SIZE_SHIFT)); + + for ( i = 0 ; i < R128_MAX_TEXTURE_LEVELS ; i++ ) { + t->setup.tex_offset[i] = 0x00000000; + } + + if (firstLevel == lastLevel) + t->setup.tex_cntl |= R128_MIP_MAP_DISABLE; + else + t->setup.tex_cntl &= ~R128_MIP_MAP_DISABLE; + + /* FYI: r128UploadTexImages( rmesa, t ); used to be called here */ +} + + +/* ================================================================ + * Texture combine functions + */ + +#define COLOR_COMB_DISABLE (R128_COMB_DIS | \ + R128_COLOR_FACTOR_TEX) +#define COLOR_COMB_COPY_INPUT (R128_COMB_COPY_INP | \ + R128_COLOR_FACTOR_TEX) +#define COLOR_COMB_MODULATE (R128_COMB_MODULATE | \ + R128_COLOR_FACTOR_TEX) +#define COLOR_COMB_MODULATE_NTEX (R128_COMB_MODULATE | \ + R128_COLOR_FACTOR_NTEX) +#define COLOR_COMB_ADD (R128_COMB_ADD | \ + R128_COLOR_FACTOR_TEX) +#define COLOR_COMB_BLEND_TEX (R128_COMB_BLEND_TEXTURE | \ + R128_COLOR_FACTOR_TEX) +/* Rage 128 Pro/M3 only! */ +#define COLOR_COMB_BLEND_COLOR (R128_COMB_MODULATE2X | \ + R128_COMB_FCN_MSB | \ + R128_COLOR_FACTOR_CONST_COLOR) + +#define ALPHA_COMB_DISABLE (R128_COMB_ALPHA_DIS | \ + R128_ALPHA_FACTOR_TEX_ALPHA) +#define ALPHA_COMB_COPY_INPUT (R128_COMB_ALPHA_COPY_INP | \ + R128_ALPHA_FACTOR_TEX_ALPHA) +#define ALPHA_COMB_MODULATE (R128_COMB_ALPHA_MODULATE | \ + R128_ALPHA_FACTOR_TEX_ALPHA) +#define ALPHA_COMB_MODULATE_NTEX (R128_COMB_ALPHA_MODULATE | \ + R128_ALPHA_FACTOR_NTEX_ALPHA) +#define ALPHA_COMB_ADD (R128_COMB_ALPHA_ADD | \ + R128_ALPHA_FACTOR_TEX_ALPHA) + +#define INPUT_INTERP (R128_INPUT_FACTOR_INT_COLOR | \ + R128_INP_FACTOR_A_INT_ALPHA) +#define INPUT_PREVIOUS (R128_INPUT_FACTOR_PREV_COLOR | \ + R128_INP_FACTOR_A_PREV_ALPHA) + +static GLboolean r128UpdateTextureEnv( GLcontext *ctx, int unit ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + GLint source = rmesa->tmu_source[unit]; + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source]; + const struct gl_texture_object *tObj = texUnit->_Current; + const GLenum format = tObj->Image[tObj->BaseLevel]->Format; + GLuint combine; + + if ( R128_DEBUG & DEBUG_VERBOSE_API ) { + fprintf( stderr, "%s( %p, %d )\n", + __FUNCTION__, ctx, unit ); + } + + if ( unit == 0 ) { + combine = INPUT_INTERP; + } else { + combine = INPUT_PREVIOUS; + } + + /* Set the texture environment state */ + switch ( texUnit->EnvMode ) { + case GL_REPLACE: + switch ( format ) { + case GL_RGBA: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + combine |= (COLOR_COMB_DISABLE | /* C = Ct */ + ALPHA_COMB_DISABLE); /* A = At */ + break; + case GL_RGB: + case GL_LUMINANCE: + combine |= (COLOR_COMB_DISABLE | /* C = Ct */ + ALPHA_COMB_COPY_INPUT); /* A = Af */ + break; + case GL_ALPHA: + combine |= (COLOR_COMB_COPY_INPUT | /* C = Cf */ + ALPHA_COMB_DISABLE); /* A = At */ + break; + case GL_COLOR_INDEX: + default: + return GL_FALSE; + } + break; + + case GL_MODULATE: + switch ( format ) { + case GL_RGBA: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + combine |= (COLOR_COMB_MODULATE | /* C = CfCt */ + ALPHA_COMB_MODULATE); /* A = AfAt */ + break; + case GL_RGB: + case GL_LUMINANCE: + combine |= (COLOR_COMB_MODULATE | /* C = CfCt */ + ALPHA_COMB_COPY_INPUT); /* A = Af */ + break; + case GL_ALPHA: + combine |= (COLOR_COMB_COPY_INPUT | /* C = Cf */ + ALPHA_COMB_MODULATE); /* A = AfAt */ + break; + case GL_COLOR_INDEX: + default: + return GL_FALSE; + } + break; + + case GL_DECAL: + switch ( format ) { + case GL_RGBA: + combine |= (COLOR_COMB_BLEND_TEX | /* C = Cf(1-At)+CtAt */ + ALPHA_COMB_COPY_INPUT); /* A = Af */ + break; + case GL_RGB: + combine |= (COLOR_COMB_DISABLE | /* C = Ct */ + ALPHA_COMB_COPY_INPUT); /* A = Af */ + break; + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + /* Undefined behaviour - just copy the incoming fragment */ + combine |= (COLOR_COMB_COPY_INPUT | /* C = undefined */ + ALPHA_COMB_COPY_INPUT); /* A = undefined */ + break; + case GL_COLOR_INDEX: + default: + return GL_FALSE; + } + break; + + case GL_BLEND: + /* Rage 128 Pro and M3 can handle GL_BLEND texturing. + */ + if ( !R128_IS_PLAIN( rmesa ) ) { + /* XXX this hasn't been fully tested, I don't have a Pro card. -BP */ + switch ( format ) { + case GL_RGBA: + case GL_LUMINANCE_ALPHA: + combine |= (COLOR_COMB_BLEND_COLOR | /* C = Cf(1-Ct)+CcCt */ + ALPHA_COMB_MODULATE); /* A = AfAt */ + break; + + case GL_RGB: + case GL_LUMINANCE: + combine |= (COLOR_COMB_BLEND_COLOR | /* C = Cf(1-Ct)+CcCt */ + ALPHA_COMB_COPY_INPUT); /* A = Af */ + break; + + case GL_ALPHA: + combine |= (COLOR_COMB_COPY_INPUT | /* C = Cf */ + ALPHA_COMB_MODULATE); /* A = AfAt */ + break; + + case GL_INTENSITY: + /* GH: We could be smarter about this... */ + switch ( rmesa->env_color & 0xff000000 ) { + case 0x00000000: + combine |= (COLOR_COMB_BLEND_COLOR | /* C = Cf(1-It)+CcIt */ + ALPHA_COMB_MODULATE_NTEX); /* A = Af(1-It) */ + default: + combine |= (COLOR_COMB_MODULATE | /* C = fallback */ + ALPHA_COMB_MODULATE); /* A = fallback */ + return GL_FALSE; + } + break; + + case GL_COLOR_INDEX: + default: + return GL_FALSE; + } + break; + } + + /* Rage 128 has to fake some cases of GL_BLEND, otherwise fallback + * to software rendering. + */ + if ( rmesa->blend_flags ) { + return GL_FALSE; + } + switch ( format ) { + case GL_RGBA: + case GL_LUMINANCE_ALPHA: + switch ( rmesa->env_color & 0x00ffffff ) { + case 0x00000000: + combine |= (COLOR_COMB_MODULATE_NTEX | /* C = Cf(1-Ct) */ + ALPHA_COMB_MODULATE); /* A = AfAt */ + break; +#if 0 + /* This isn't right - BP */ + case 0x00ffffff: + if ( unit == 0 ) { + combine |= (COLOR_COMB_MODULATE_NTEX | /* C = Cf(1-Ct) */ + ALPHA_COMB_MODULATE); /* A = AfAt */ + } else { + combine |= (COLOR_COMB_ADD | /* C = Cf+Ct */ + ALPHA_COMB_COPY_INPUT); /* A = Af */ + } + break; +#endif + default: + combine |= (COLOR_COMB_MODULATE | /* C = fallback */ + ALPHA_COMB_MODULATE); /* A = fallback */ + return GL_FALSE; + } + break; + case GL_RGB: + case GL_LUMINANCE: + switch ( rmesa->env_color & 0x00ffffff ) { + case 0x00000000: + combine |= (COLOR_COMB_MODULATE_NTEX | /* C = Cf(1-Ct) */ + ALPHA_COMB_COPY_INPUT); /* A = Af */ + break; +#if 0 + /* This isn't right - BP */ + case 0x00ffffff: + if ( unit == 0 ) { + combine |= (COLOR_COMB_MODULATE_NTEX | /* C = Cf(1-Ct) */ + ALPHA_COMB_COPY_INPUT); /* A = Af */ + } else { + combine |= (COLOR_COMB_ADD | /* C = Cf+Ct */ + ALPHA_COMB_COPY_INPUT); /* A = Af */ + } + break; +#endif + default: + combine |= (COLOR_COMB_MODULATE | /* C = fallback */ + ALPHA_COMB_COPY_INPUT); /* A = fallback */ + return GL_FALSE; + } + break; + case GL_ALPHA: + if ( unit == 0 ) { + combine |= (COLOR_COMB_COPY_INPUT | /* C = Cf */ + ALPHA_COMB_MODULATE); /* A = AfAt */ + } else { + combine |= (COLOR_COMB_COPY_INPUT | /* C = Cf */ + ALPHA_COMB_COPY_INPUT); /* A = Af */ + } + break; + case GL_INTENSITY: + switch ( rmesa->env_color & 0x00ffffff ) { + case 0x00000000: + combine |= COLOR_COMB_MODULATE_NTEX; /* C = Cf(1-It) */ + break; +#if 0 + /* This isn't right - BP */ + case 0x00ffffff: + if ( unit == 0 ) { + combine |= COLOR_COMB_MODULATE_NTEX; /* C = Cf(1-It) */ + } else { + combine |= COLOR_COMB_ADD; /* C = Cf+It */ + } + break; +#endif + default: + combine |= (COLOR_COMB_MODULATE | /* C = fallback */ + ALPHA_COMB_MODULATE); /* A = fallback */ + return GL_FALSE; + } + switch ( rmesa->env_color & 0xff000000 ) { + case 0x00000000: + combine |= ALPHA_COMB_MODULATE_NTEX; /* A = Af(1-It) */ + break; +#if 0 + /* This isn't right - BP */ + case 0xff000000: + if ( unit == 0 ) { + combine |= ALPHA_COMB_MODULATE_NTEX; /* A = Af(1-It) */ + } else { + combine |= ALPHA_COMB_ADD; /* A = Af+It */ + } + break; +#endif + default: + combine |= (COLOR_COMB_MODULATE | /* C = fallback */ + ALPHA_COMB_MODULATE); /* A = fallback */ + return GL_FALSE; + } + break; + case GL_COLOR_INDEX: + default: + return GL_FALSE; + } + break; + + case GL_ADD: + switch ( format ) { + case GL_RGBA: + case GL_LUMINANCE_ALPHA: + combine |= (COLOR_COMB_ADD | /* C = Cf+Ct */ + ALPHA_COMB_MODULATE); /* A = AfAt */ + break; + case GL_RGB: + case GL_LUMINANCE: + combine |= (COLOR_COMB_ADD | /* C = Cf+Ct */ + ALPHA_COMB_COPY_INPUT); /* A = Af */ + break; + case GL_ALPHA: + combine |= (COLOR_COMB_COPY_INPUT | /* C = Cf */ + ALPHA_COMB_MODULATE); /* A = AfAt */ + break; + case GL_INTENSITY: + combine |= (COLOR_COMB_ADD | /* C = Cf+Ct */ + ALPHA_COMB_ADD); /* A = Af+At */ + break; + case GL_COLOR_INDEX: + default: + return GL_FALSE; + } + break; + + default: + return GL_FALSE; + } + + if ( rmesa->tex_combine[unit] != combine ) { + rmesa->tex_combine[unit] = combine; + rmesa->dirty |= R128_UPLOAD_TEX0 << unit; + } + return GL_TRUE; +} + +static void disable_tex( GLcontext *ctx, int unit ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + FLUSH_BATCH( rmesa ); + + if ( rmesa->CurrentTexObj[unit] ) { + rmesa->CurrentTexObj[unit]->base.bound &= ~(1 << unit); + rmesa->CurrentTexObj[unit] = NULL; + } + + rmesa->setup.tex_cntl_c &= ~(R128_TEXMAP_ENABLE << unit); + rmesa->setup.tex_size_pitch_c &= ~(R128_TEX_SIZE_PITCH_MASK << + (R128_SEC_TEX_SIZE_PITCH_SHIFT * unit)); + rmesa->dirty |= R128_UPLOAD_CONTEXT; + + /* If either texture unit is disabled, then multitexturing is not + * happening. + */ + + rmesa->blend_flags &= ~R128_BLEND_MULTITEX; +} + +static GLboolean enable_tex_2d( GLcontext *ctx, int unit ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + const int source = rmesa->tmu_source[unit]; + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source]; + const struct gl_texture_object *tObj = texUnit->_Current; + r128TexObjPtr t = (r128TexObjPtr) tObj->DriverData; + + /* Need to load the 2d images associated with this unit. + */ + if ( t->base.dirty_images[0] ) { + /* FIXME: For Radeon, RADEON_FIREVERTICES is called here. Should + * FIXME: something similar be done for R128? + */ + /* FLUSH_BATCH( rmesa ); */ + + r128SetTexImages( rmesa, tObj ); + r128UploadTexImages( rmesa, t ); + if ( !t->base.memBlock ) + return GL_FALSE; + } + + return GL_TRUE; +} + +static GLboolean update_tex_common( GLcontext *ctx, int unit ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + const int source = rmesa->tmu_source[unit]; + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source]; + const struct gl_texture_object *tObj = texUnit->_Current; + r128TexObjPtr t = (r128TexObjPtr) tObj->DriverData; + + + /* Fallback if there's a texture border */ + if ( tObj->Image[tObj->BaseLevel]->Border > 0 ) { + return GL_FALSE; + } + + + /* Update state if this is a different texture object to last + * time. + */ + if ( rmesa->CurrentTexObj[unit] != t ) { + if ( rmesa->CurrentTexObj[unit] != NULL ) { + /* The old texture is no longer bound to this texture unit. + * Mark it as such. + */ + + rmesa->CurrentTexObj[unit]->base.bound &= + ~(1UL << unit); + } + + rmesa->CurrentTexObj[unit] = t; + t->base.bound |= (1UL << unit); + rmesa->dirty |= R128_UPLOAD_TEX0 << unit; + + driUpdateTextureLRU( (driTextureObject *) t ); /* XXX: should be locked! */ + } + + /* FIXME: We need to update the texture unit if any texture parameters have + * changed, but this texture was already bound. This could be changed to + * work like the Radeon driver where the texture object has it's own + * dirty state flags + */ + rmesa->dirty |= R128_UPLOAD_TEX0 << unit; + + /* register setup */ + rmesa->setup.tex_size_pitch_c &= ~(R128_TEX_SIZE_PITCH_MASK << + (R128_SEC_TEX_SIZE_PITCH_SHIFT * unit)); + + if ( unit == 0 ) { + rmesa->setup.tex_cntl_c |= R128_TEXMAP_ENABLE; + rmesa->setup.tex_size_pitch_c |= t->setup.tex_size_pitch << 0; + rmesa->setup.scale_3d_cntl &= ~R128_TEX_CACHE_SPLIT; + t->setup.tex_cntl &= ~R128_SEC_SELECT_SEC_ST; + } + else { + rmesa->setup.tex_cntl_c |= R128_SEC_TEXMAP_ENABLE; + rmesa->setup.tex_size_pitch_c |= t->setup.tex_size_pitch << 16; + rmesa->setup.scale_3d_cntl |= R128_TEX_CACHE_SPLIT; + t->setup.tex_cntl |= R128_SEC_SELECT_SEC_ST; + + /* If the second TMU is enabled, then multitexturing is happening. + */ + if ( R128_IS_PLAIN( rmesa ) ) + rmesa->blend_flags |= R128_BLEND_MULTITEX; + } + + rmesa->dirty |= R128_UPLOAD_CONTEXT; + + + /* FIXME: The Radeon has some cached state so that it can avoid calling + * FIXME: UpdateTextureEnv in some cases. Is that possible here? + */ + return r128UpdateTextureEnv( ctx, unit ); +} + +static GLboolean updateTextureUnit( GLcontext *ctx, int unit ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + const int source = rmesa->tmu_source[unit]; + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[source]; + + + if (texUnit->_ReallyEnabled & (TEXTURE_1D_BIT | TEXTURE_2D_BIT)) { + return (enable_tex_2d( ctx, unit ) && + update_tex_common( ctx, unit )); + } + else if ( texUnit->_ReallyEnabled ) { + return GL_FALSE; + } + else { + disable_tex( ctx, unit ); + return GL_TRUE; + } +} + + +void r128UpdateTextureState( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + GLboolean ok; + + + /* This works around a quirk with the R128 hardware. If only OpenGL + * TEXTURE1 is enabled, then the hardware TEXTURE0 must be used. The + * hardware TEXTURE1 can ONLY be used when hardware TEXTURE0 is also used. + */ + + rmesa->tmu_source[0] = 0; + rmesa->tmu_source[1] = 1; + + if ((ctx->Texture._EnabledUnits & 0x03) == 0x02) { + /* only texture 1 enabled */ + rmesa->tmu_source[0] = 1; + rmesa->tmu_source[1] = 0; + } + + ok = (updateTextureUnit( ctx, 0 ) && + updateTextureUnit( ctx, 1 )); + + FALLBACK( rmesa, R128_FALLBACK_TEXTURE, !ok ); +} diff --git a/src/mesa/drivers/dri/r128/r128_tris.c b/src/mesa/drivers/dri/r128/r128_tris.c new file mode 100644 index 0000000000..4e2860288e --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_tris.c @@ -0,0 +1,721 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_tris.c,v 1.8 2002/10/30 12:51:43 alanh Exp $ */ /* -*- c-basic-offset: 3 -*- */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * + */ + +#include "glheader.h" +#include "mtypes.h" +#include "colormac.h" +#include "macros.h" + +#include "swrast/swrast.h" +#include "swrast_setup/swrast_setup.h" +#include "tnl/tnl.h" +#include "tnl/t_context.h" +#include "tnl/t_pipeline.h" + +#include "r128_tris.h" +#include "r128_state.h" +#include "r128_tex.h" +#include "r128_vb.h" +#include "r128_ioctl.h" + +static const GLuint hw_prim[GL_POLYGON+1] = { + R128_CCE_VC_CNTL_PRIM_TYPE_POINT, + R128_CCE_VC_CNTL_PRIM_TYPE_LINE, + R128_CCE_VC_CNTL_PRIM_TYPE_LINE, + R128_CCE_VC_CNTL_PRIM_TYPE_LINE, + R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST, + R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST, + R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST, + R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST, + R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST, + R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST, +}; + +static void r128RasterPrimitive( GLcontext *ctx, GLuint hwprim ); +static void r128RenderPrimitive( GLcontext *ctx, GLenum prim ); + + +/*********************************************************************** + * Emit primitives as inline vertices * + ***********************************************************************/ + +#if defined(USE_X86_ASM) +#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] = CPU_TO_LE32(((GLuint *)v)[j]); \ + vb += vertsize; \ +} while (0) +#endif + +static __inline void r128_draw_quad( r128ContextPtr rmesa, + r128VertexPtr v0, + r128VertexPtr v1, + r128VertexPtr v2, + r128VertexPtr v3 ) +{ + GLuint vertsize = rmesa->vertex_size; + GLuint *vb = (GLuint *)r128AllocDmaLow( rmesa, 6 * vertsize * 4 ); + GLuint j; + + rmesa->num_verts += 6; + COPY_DWORDS( j, vb, vertsize, v0 ); + COPY_DWORDS( j, vb, vertsize, v1 ); + COPY_DWORDS( j, vb, vertsize, v3 ); + COPY_DWORDS( j, vb, vertsize, v1 ); + COPY_DWORDS( j, vb, vertsize, v2 ); + COPY_DWORDS( j, vb, vertsize, v3 ); +} + + +static __inline void r128_draw_triangle( r128ContextPtr rmesa, + r128VertexPtr v0, + r128VertexPtr v1, + r128VertexPtr v2 ) +{ + GLuint vertsize = rmesa->vertex_size; + GLuint *vb = (GLuint *)r128AllocDmaLow( rmesa, 3 * vertsize * 4 ); + GLuint j; + + rmesa->num_verts += 3; + COPY_DWORDS( j, vb, vertsize, v0 ); + COPY_DWORDS( j, vb, vertsize, v1 ); + COPY_DWORDS( j, vb, vertsize, v2 ); +} + +static __inline void r128_draw_line( r128ContextPtr rmesa, + r128VertexPtr v0, + r128VertexPtr v1 ) +{ + GLuint vertsize = rmesa->vertex_size; + GLuint *vb = (GLuint *)r128AllocDmaLow( rmesa, 2 * vertsize * 4 ); + GLuint j; + + rmesa->num_verts += 2; + COPY_DWORDS( j, vb, vertsize, v0 ); + COPY_DWORDS( j, vb, vertsize, v1 ); +} + +static __inline void r128_draw_point( r128ContextPtr rmesa, + r128VertexPtr v0 ) +{ + int vertsize = rmesa->vertex_size; + GLuint *vb = (GLuint *)r128AllocDmaLow( rmesa, vertsize * 4 ); + int j; + + rmesa->num_verts += 1; + COPY_DWORDS( j, vb, vertsize, v0 ); +} + +/*********************************************************************** + * Macros for t_dd_tritmp.h to draw basic primitives * + ***********************************************************************/ + +#define TRI( a, b, c ) \ +do { \ + if (DO_FALLBACK) \ + rmesa->draw_tri( rmesa, a, b, c ); \ + else \ + r128_draw_triangle( rmesa, a, b, c ); \ +} while (0) + +#define QUAD( a, b, c, d ) \ +do { \ + if (DO_FALLBACK) { \ + rmesa->draw_tri( rmesa, a, b, d ); \ + rmesa->draw_tri( rmesa, b, c, d ); \ + } else \ + r128_draw_quad( rmesa, a, b, c, d ); \ +} while (0) + +#define LINE( v0, v1 ) \ +do { \ + if (DO_FALLBACK) \ + rmesa->draw_line( rmesa, v0, v1 ); \ + else \ + r128_draw_line( rmesa, v0, v1 ); \ +} while (0) + +#define POINT( v0 ) \ +do { \ + if (DO_FALLBACK) \ + rmesa->draw_point( rmesa, v0 ); \ + else \ + r128_draw_point( rmesa, v0 ); \ +} while (0) + + +/*********************************************************************** + * Build render functions from dd templates * + ***********************************************************************/ + +#define R128_OFFSET_BIT 0x01 +#define R128_TWOSIDE_BIT 0x02 +#define R128_UNFILLED_BIT 0x04 +#define R128_FALLBACK_BIT 0x08 +#define R128_MAX_TRIFUNC 0x10 + + +static struct { + points_func points; + line_func line; + triangle_func triangle; + quad_func quad; +} rast_tab[R128_MAX_TRIFUNC]; + + +#define DO_FALLBACK (IND & R128_FALLBACK_BIT) +#define DO_OFFSET (IND & R128_OFFSET_BIT) +#define DO_UNFILLED (IND & R128_UNFILLED_BIT) +#define DO_TWOSIDE (IND & R128_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 r128Vertex +#define TAB rast_tab + +#define DEPTH_SCALE 1.0 +#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) (rmesa->verts + (e<<rmesa->vertex_stride_shift)) + +#define VERT_SET_RGBA( v, c ) do { \ + r128_color_t *vc = (r128_color_t *)&(v)->ui[coloroffset]; \ + vc->blue = (c)[2]; \ + vc->green = (c)[1]; \ + vc->red = (c)[0]; \ + vc->alpha = (c)[3]; \ + } while (0) +#define VERT_COPY_RGBA( v0, v1 ) v0->ui[coloroffset] = v1->ui[coloroffset] +#define VERT_SAVE_RGBA( idx ) color[idx] = v[idx]->ui[coloroffset] +#define VERT_RESTORE_RGBA( idx ) v[idx]->ui[coloroffset] = color[idx] + +#define VERT_SET_SPEC( v0, c ) if (havespec) { \ + (v0)->v.specular.red = (c)[0];\ + (v0)->v.specular.green = (c)[1];\ + (v0)->v.specular.blue = (c)[2]; } +#define VERT_COPY_SPEC( v0, v1 ) if (havespec) { \ + (v0)->v.specular.red = v1->v.specular.red; \ + (v0)->v.specular.green = v1->v.specular.green; \ + (v0)->v.specular.blue = v1->v.specular.blue; } + +#define VERT_SAVE_SPEC( idx ) if (havespec) spec[idx] = v[idx]->ui[5] +#define VERT_RESTORE_SPEC( idx ) if (havespec) v[idx]->ui[5] = spec[idx] + +#define LOCAL_VARS(n) \ + r128ContextPtr rmesa = R128_CONTEXT(ctx); \ + GLuint color[n], spec[n]; \ + GLuint coloroffset = (rmesa->vertex_size == 4 ? 3 : 4); \ + GLboolean havespec = (rmesa->vertex_size == 4 ? 0 : 1); \ + (void) color; (void) spec; (void) coloroffset; (void) havespec; + +/*********************************************************************** + * Helpers for rendering unfilled primitives * + ***********************************************************************/ + +#define RASTERIZE(x) if (rmesa->hw_primitive != hw_prim[x]) \ + r128RasterPrimitive( ctx, hw_prim[x] ) +#define RENDER_PRIMITIVE rmesa->render_primitive +#define IND R128_FALLBACK_BIT +#define TAG(x) x +#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 (R128_OFFSET_BIT) +#define TAG(x) x##_offset +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (R128_TWOSIDE_BIT) +#define TAG(x) x##_twoside +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (R128_TWOSIDE_BIT|R128_OFFSET_BIT) +#define TAG(x) x##_twoside_offset +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (R128_UNFILLED_BIT) +#define TAG(x) x##_unfilled +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (R128_OFFSET_BIT|R128_UNFILLED_BIT) +#define TAG(x) x##_offset_unfilled +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (R128_TWOSIDE_BIT|R128_UNFILLED_BIT) +#define TAG(x) x##_twoside_unfilled +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (R128_TWOSIDE_BIT|R128_OFFSET_BIT|R128_UNFILLED_BIT) +#define TAG(x) x##_twoside_offset_unfilled +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (R128_FALLBACK_BIT) +#define TAG(x) x##_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (R128_OFFSET_BIT|R128_FALLBACK_BIT) +#define TAG(x) x##_offset_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (R128_TWOSIDE_BIT|R128_FALLBACK_BIT) +#define TAG(x) x##_twoside_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (R128_TWOSIDE_BIT|R128_OFFSET_BIT|R128_FALLBACK_BIT) +#define TAG(x) x##_twoside_offset_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (R128_UNFILLED_BIT|R128_FALLBACK_BIT) +#define TAG(x) x##_unfilled_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (R128_OFFSET_BIT|R128_UNFILLED_BIT|R128_FALLBACK_BIT) +#define TAG(x) x##_offset_unfilled_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (R128_TWOSIDE_BIT|R128_UNFILLED_BIT|R128_FALLBACK_BIT) +#define TAG(x) x##_twoside_unfilled_fallback +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (R128_TWOSIDE_BIT|R128_OFFSET_BIT|R128_UNFILLED_BIT| \ + R128_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 +r128_fallback_tri( r128ContextPtr rmesa, + r128Vertex *v0, + r128Vertex *v1, + r128Vertex *v2 ) +{ + GLcontext *ctx = rmesa->glCtx; + SWvertex v[3]; + r128_translate_vertex( ctx, v0, &v[0] ); + r128_translate_vertex( ctx, v1, &v[1] ); + r128_translate_vertex( ctx, v2, &v[2] ); + _swrast_Triangle( ctx, &v[0], &v[1], &v[2] ); +} + + +static void +r128_fallback_line( r128ContextPtr rmesa, + r128Vertex *v0, + r128Vertex *v1 ) +{ + GLcontext *ctx = rmesa->glCtx; + SWvertex v[2]; + r128_translate_vertex( ctx, v0, &v[0] ); + r128_translate_vertex( ctx, v1, &v[1] ); + _swrast_Line( ctx, &v[0], &v[1] ); +} + + +static void +r128_fallback_point( r128ContextPtr rmesa, + r128Vertex *v0 ) +{ + GLcontext *ctx = rmesa->glCtx; + SWvertex v[1]; + r128_translate_vertex( ctx, v0, &v[0] ); + _swrast_Point( ctx, &v[0] ); +} + + + +/**********************************************************************/ +/* Render unclipped begin/end objects */ +/**********************************************************************/ + +#define VERT(x) (r128Vertex *)(r128verts + (x << shift)) +#define RENDER_POINTS( start, count ) \ + for ( ; start < count ; start++) \ + r128_draw_point( rmesa, VERT(start) ) +#define RENDER_LINE( v0, v1 ) \ + r128_draw_line( rmesa, VERT(v0), VERT(v1) ) +#define RENDER_TRI( v0, v1, v2 ) \ + r128_draw_triangle( rmesa, VERT(v0), VERT(v1), VERT(v2) ) +#define RENDER_QUAD( v0, v1, v2, v3 ) \ + r128_draw_quad( rmesa, VERT(v0), VERT(v1), VERT(v2), VERT(v3) ) +#define INIT(x) do { \ + if (0) fprintf(stderr, "%s\n", __FUNCTION__); \ + r128RenderPrimitive( ctx, x ); \ +} while (0) +#undef LOCAL_VARS +#define LOCAL_VARS \ + r128ContextPtr rmesa = R128_CONTEXT(ctx); \ + const GLuint shift = rmesa->vertex_stride_shift; \ + const char *r128verts = (char *)rmesa->verts; \ + 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) r128_##x##_verts +#include "tnl/t_vb_rendertmp.h" +#undef ELT +#undef TAG +#define TAG(x) r128_##x##_elts +#define ELT(x) elt[x] +#include "tnl/t_vb_rendertmp.h" + + +/**********************************************************************/ +/* Render clipped primitives */ +/**********************************************************************/ + +static void r128RenderClippedPoly( GLcontext *ctx, const GLuint *elts, + GLuint n ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + + /* 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; + } +} + +static void r128RenderClippedLine( GLcontext *ctx, GLuint ii, GLuint jj ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + tnl->Driver.Render.Line( ctx, ii, jj ); +} + +static void r128FastRenderClippedPoly( GLcontext *ctx, const GLuint *elts, + GLuint n ) +{ + r128ContextPtr rmesa = R128_CONTEXT( ctx ); + GLuint vertsize = rmesa->vertex_size; + GLuint *vb = r128AllocDmaLow( rmesa, (n-2) * 3 * 4 * vertsize ); + GLubyte *r128verts = (GLubyte *)rmesa->verts; + const GLuint shift = rmesa->vertex_stride_shift; + const GLuint *start = (const GLuint *)VERT(elts[0]); + int i,j; + + rmesa->num_verts += (n-2) * 3; + + for (i = 2 ; i < n ; i++) { + COPY_DWORDS( j, vb, vertsize, (r128VertexPtr) VERT(elts[i-1]) ); + COPY_DWORDS( j, vb, vertsize, (r128VertexPtr) VERT(elts[i]) ); + COPY_DWORDS( j, vb, vertsize, (r128VertexPtr) start ); + } +} + + + + +/**********************************************************************/ +/* Choose render functions */ +/**********************************************************************/ + +#define _R128_NEW_RENDER_STATE (_DD_NEW_LINE_STIPPLE | \ + _DD_NEW_LINE_SMOOTH | \ + _DD_NEW_POINT_SMOOTH | \ + _DD_NEW_TRI_SMOOTH | \ + _DD_NEW_TRI_UNFILLED | \ + _DD_NEW_TRI_LIGHT_TWOSIDE | \ + _DD_NEW_TRI_OFFSET) \ + + +#define POINT_FALLBACK (DD_POINT_SMOOTH) +#define LINE_FALLBACK (DD_LINE_STIPPLE|DD_LINE_SMOOTH) +#define TRI_FALLBACK (DD_TRI_SMOOTH) +#define ANY_FALLBACK_FLAGS (POINT_FALLBACK|LINE_FALLBACK|TRI_FALLBACK) +#define ANY_RASTER_FLAGS (DD_TRI_LIGHT_TWOSIDE|DD_TRI_OFFSET|DD_TRI_UNFILLED) + + +static void r128ChooseRenderState(GLcontext *ctx) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + GLuint flags = ctx->_TriangleCaps; + GLuint index = 0; + + if (flags & (ANY_RASTER_FLAGS|ANY_FALLBACK_FLAGS)) { + rmesa->draw_point = r128_draw_point; + rmesa->draw_line = r128_draw_line; + rmesa->draw_tri = r128_draw_triangle; + + if (flags & ANY_RASTER_FLAGS) { + if (flags & DD_TRI_LIGHT_TWOSIDE) index |= R128_TWOSIDE_BIT; + if (flags & DD_TRI_OFFSET) index |= R128_OFFSET_BIT; + if (flags & DD_TRI_UNFILLED) index |= R128_UNFILLED_BIT; + } + + /* Hook in fallbacks for specific primitives. + */ + if (flags & (POINT_FALLBACK|LINE_FALLBACK|TRI_FALLBACK)) { + if (flags & POINT_FALLBACK) rmesa->draw_point = r128_fallback_point; + if (flags & LINE_FALLBACK) rmesa->draw_line = r128_fallback_line; + if (flags & TRI_FALLBACK) rmesa->draw_tri = r128_fallback_tri; + index |= R128_FALLBACK_BIT; + } + } + + if (index != rmesa->RenderIndex) { + TNLcontext *tnl = TNL_CONTEXT(ctx); + 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 = r128_render_tab_verts; + tnl->Driver.Render.PrimTabElts = r128_render_tab_elts; + tnl->Driver.Render.ClippedLine = rast_tab[index].line; + tnl->Driver.Render.ClippedPolygon = r128FastRenderClippedPoly; + } else { + tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts; + tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts; + tnl->Driver.Render.ClippedLine = r128RenderClippedLine; + tnl->Driver.Render.ClippedPolygon = r128RenderClippedPoly; + } + + rmesa->RenderIndex = index; + } +} + +/**********************************************************************/ +/* Validate state at pipeline start */ +/**********************************************************************/ + +static void r128RunPipeline( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + if (rmesa->new_state || rmesa->NewGLState & _NEW_TEXTURE) + r128DDUpdateHWState( ctx ); + + if (!rmesa->Fallback && rmesa->NewGLState) { + if (rmesa->NewGLState & _R128_NEW_VERTEX_STATE) + r128ChooseVertexState( ctx ); + + if (rmesa->NewGLState & _R128_NEW_RENDER_STATE) + r128ChooseRenderState( ctx ); + + rmesa->NewGLState = 0; + } + + _tnl_run_pipeline( ctx ); +} + +/**********************************************************************/ +/* High level hooks for t_vb_render.c */ +/**********************************************************************/ + +/* This is called when Mesa switches between rendering triangle + * primitives (such as GL_POLYGON, GL_QUADS, GL_TRIANGLE_STRIP, etc), + * and lines, points and bitmaps. + * + * As the r128 uses triangles to render lines and points, it is + * necessary to turn off hardware culling when rendering these + * primitives. + */ + +static void r128RasterPrimitive( GLcontext *ctx, GLuint hwprim ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + + rmesa->setup.dp_gui_master_cntl_c &= ~R128_GMC_BRUSH_NONE; + + if ( ctx->Polygon.StippleFlag && hwprim == GL_TRIANGLES ) { + rmesa->setup.dp_gui_master_cntl_c |= R128_GMC_BRUSH_32x32_MONO_FG_LA; + } + else { + rmesa->setup.dp_gui_master_cntl_c |= R128_GMC_BRUSH_SOLID_COLOR; + } + + rmesa->new_state |= R128_NEW_CONTEXT; + rmesa->dirty |= R128_UPLOAD_CONTEXT; + + if (rmesa->hw_primitive != hwprim) { + FLUSH_BATCH( rmesa ); + rmesa->hw_primitive = hwprim; + } +} + +static void r128RenderPrimitive( GLcontext *ctx, GLenum prim ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + GLuint hw = hw_prim[prim]; + rmesa->render_primitive = prim; + if (prim >= GL_TRIANGLES && (ctx->_TriangleCaps & DD_TRI_UNFILLED)) + return; + r128RasterPrimitive( ctx, hw ); +} + + +static void r128RenderStart( GLcontext *ctx ) +{ + /* Check for projective texturing. Make sure all texcoord + * pointers point to something. (fix in mesa?) + */ + r128CheckTexSizes( ctx ); +} + +static void r128RenderFinish( GLcontext *ctx ) +{ + if (R128_CONTEXT(ctx)->RenderIndex & R128_FALLBACK_BIT) + _swrast_flush( ctx ); +} + + +/**********************************************************************/ +/* Transition to/from hardware rasterization. */ +/**********************************************************************/ + +void r128Fallback( GLcontext *ctx, GLuint bit, GLboolean mode ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + r128ContextPtr rmesa = R128_CONTEXT(ctx); + GLuint oldfallback = rmesa->Fallback; + + if (mode) { + rmesa->Fallback |= bit; + if (oldfallback == 0) { + FLUSH_BATCH( rmesa ); + _swsetup_Wakeup( ctx ); + rmesa->RenderIndex = ~0; + } + } + else { + rmesa->Fallback &= ~bit; + if (oldfallback == bit) { + _swrast_flush( ctx ); + tnl->Driver.Render.Start = r128RenderStart; + tnl->Driver.Render.PrimitiveNotify = r128RenderPrimitive; + tnl->Driver.Render.Finish = r128RenderFinish; + tnl->Driver.Render.BuildVertices = r128BuildVertices; + rmesa->NewGLState |= (_R128_NEW_RENDER_STATE| + _R128_NEW_VERTEX_STATE); + } + } +} + + +/**********************************************************************/ +/* Initialization. */ +/**********************************************************************/ + +void r128InitTriFuncs( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + TNLcontext *tnl = TNL_CONTEXT(ctx); + static int firsttime = 1; + + if (firsttime) { + init_rast_tab(); + firsttime = 0; + } + + tnl->Driver.RunPipeline = r128RunPipeline; + tnl->Driver.Render.Start = r128RenderStart; + tnl->Driver.Render.Finish = r128RenderFinish; + tnl->Driver.Render.PrimitiveNotify = r128RenderPrimitive; + tnl->Driver.Render.ResetLineStipple = _swrast_ResetLineStipple; + tnl->Driver.Render.BuildVertices = r128BuildVertices; + rmesa->NewGLState |= (_R128_NEW_RENDER_STATE| + _R128_NEW_VERTEX_STATE); + +/* r128Fallback( ctx, 0x100000, 1 ); */ +} diff --git a/src/mesa/drivers/dri/r128/r128_tris.h b/src/mesa/drivers/dri/r128/r128_tris.h new file mode 100644 index 0000000000..755d3320b0 --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_tris.h @@ -0,0 +1,48 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_tris.h,v 1.8 2002/10/30 12:51:43 alanh Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * + */ + +#ifndef __R128_TRIS_H__ +#define __R128_TRIS_H__ + +#include "mtypes.h" + +extern void r128InitTriFuncs( GLcontext *ctx ); + + +extern void r128Fallback( GLcontext *ctx, GLuint bit, GLboolean mode ); +#define FALLBACK( rmesa, bit, mode ) r128Fallback( rmesa->glCtx, bit, mode ) + + +#endif /* __R128_TRIS_H__ */ diff --git a/src/mesa/drivers/dri/r128/r128_vb.c b/src/mesa/drivers/dri/r128/r128_vb.c new file mode 100644 index 0000000000..7738901648 --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_vb.c @@ -0,0 +1,522 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_vb.c,v 1.15 2002/10/30 12:51:43 alanh Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * + */ + +#include "glheader.h" +#include "mtypes.h" +#include "imports.h" +#include "macros.h" +#include "colormac.h" + +#include "swrast_setup/swrast_setup.h" +#include "tnl/t_context.h" + +#include "r128_context.h" +#include "r128_vb.h" +#include "r128_ioctl.h" +#include "r128_tris.h" +#include "r128_state.h" + + +#define R128_TEX1_BIT 0x1 +#define R128_TEX0_BIT 0x2 +#define R128_RGBA_BIT 0x4 +#define R128_SPEC_BIT 0x8 +#define R128_FOG_BIT 0x10 +#define R128_XYZW_BIT 0x20 +#define R128_PTEX_BIT 0x40 +#define R128_MAX_SETUP 0x80 + +static struct { + void (*emit)( GLcontext *, GLuint, GLuint, void *, GLuint ); + interp_func interp; + copy_pv_func copy_pv; + GLboolean (*check_tex_sizes)( GLcontext *ctx ); + GLuint vertex_size; + GLuint vertex_stride_shift; + GLuint vertex_format; +} setup_tab[R128_MAX_SETUP]; + +#define TINY_VERTEX_FORMAT (R128_CCE_VC_FRMT_DIFFUSE_ARGB) + +#define NOTEX_VERTEX_FORMAT (R128_CCE_VC_FRMT_RHW | \ + R128_CCE_VC_FRMT_DIFFUSE_ARGB |\ + R128_CCE_VC_FRMT_SPEC_FRGB) + +#define TEX0_VERTEX_FORMAT (R128_CCE_VC_FRMT_RHW | \ + R128_CCE_VC_FRMT_DIFFUSE_ARGB |\ + R128_CCE_VC_FRMT_SPEC_FRGB | \ + R128_CCE_VC_FRMT_S_T) + +#define TEX1_VERTEX_FORMAT (R128_CCE_VC_FRMT_RHW | \ + R128_CCE_VC_FRMT_DIFFUSE_ARGB |\ + R128_CCE_VC_FRMT_SPEC_FRGB | \ + R128_CCE_VC_FRMT_S_T | \ + R128_CCE_VC_FRMT_S2_T2) + + +#define PROJ_TEX1_VERTEX_FORMAT 0 +#define TEX2_VERTEX_FORMAT 0 +#define TEX3_VERTEX_FORMAT 0 +#define PROJ_TEX3_VERTEX_FORMAT 0 + +#define DO_XYZW (IND & R128_XYZW_BIT) +#define DO_RGBA (IND & R128_RGBA_BIT) +#define DO_SPEC (IND & R128_SPEC_BIT) +#define DO_FOG (IND & R128_FOG_BIT) +#define DO_TEX0 (IND & R128_TEX0_BIT) +#define DO_TEX1 (IND & R128_TEX1_BIT) +#define DO_TEX2 0 +#define DO_TEX3 0 +#define DO_PTEX (IND & R128_PTEX_BIT) + +#define VERTEX r128Vertex +#define VERTEX_COLOR r128_color_t +#define LOCALVARS r128ContextPtr rmesa = R128_CONTEXT(ctx); +#define GET_VIEWPORT_MAT() rmesa->hw_viewport +#define GET_TEXSOURCE(n) rmesa->tmu_source[n] +#define GET_VERTEX_FORMAT() rmesa->vertex_format +#define GET_VERTEX_STORE() rmesa->verts +#define GET_VERTEX_STRIDE_SHIFT() rmesa->vertex_stride_shift +#define INVALIDATE_STORED_VERTICES() +#define GET_UBYTE_COLOR_STORE() &rmesa->UbyteColor +#define GET_UBYTE_SPEC_COLOR_STORE() &rmesa->UbyteSecondaryColor + +#define HAVE_HW_VIEWPORT 0 +#define HAVE_HW_DIVIDE 0 +#define HAVE_RGBA_COLOR 0 +#define HAVE_TINY_VERTICES 1 +#define HAVE_NOTEX_VERTICES 1 +#define HAVE_TEX0_VERTICES 1 +#define HAVE_TEX1_VERTICES 1 +#define HAVE_TEX2_VERTICES 0 +#define HAVE_TEX3_VERTICES 0 +#define HAVE_PTEX_VERTICES 0 /* r128 rhw2 not supported by template */ + +#define UNVIEWPORT_VARS GLfloat h = R128_CONTEXT(ctx)->driDrawable->h +#define UNVIEWPORT_X(x) x - SUBPIXEL_X +#define UNVIEWPORT_Y(y) - y + h + SUBPIXEL_Y +#define UNVIEWPORT_Z(z) z / rmesa->depth_scale + +#define PTEX_FALLBACK() FALLBACK(R128_CONTEXT(ctx), R128_FALLBACK_TEXTURE, 1) + +#define IMPORT_FLOAT_COLORS r128_import_float_colors +#define IMPORT_FLOAT_SPEC_COLORS r128_import_float_spec_colors + +#define INTERP_VERTEX setup_tab[rmesa->SetupIndex].interp +#define COPY_PV_VERTEX setup_tab[rmesa->SetupIndex].copy_pv + +/*********************************************************************** + * Generate pv-copying and translation functions * + ***********************************************************************/ + +#define TAG(x) r128_##x +#include "tnl_dd/t_dd_vb.c" + +/*********************************************************************** + * Generate vertex emit and interp functions * + ***********************************************************************/ + + +#define IND (R128_XYZW_BIT|R128_RGBA_BIT) +#define TAG(x) x##_wg +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_SPEC_BIT) +#define TAG(x) x##_wgs +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_TEX0_BIT) +#define TAG(x) x##_wgt0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_TEX0_BIT|R128_TEX1_BIT) +#define TAG(x) x##_wgt0t1 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_TEX0_BIT|R128_PTEX_BIT) +#define TAG(x) x##_wgpt0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_SPEC_BIT|R128_TEX0_BIT) +#define TAG(x) x##_wgst0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_SPEC_BIT|R128_TEX0_BIT|\ + R128_TEX1_BIT) +#define TAG(x) x##_wgst0t1 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_SPEC_BIT|R128_TEX0_BIT|\ + R128_PTEX_BIT) +#define TAG(x) x##_wgspt0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_FOG_BIT) +#define TAG(x) x##_wgf +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_FOG_BIT|R128_SPEC_BIT) +#define TAG(x) x##_wgfs +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_FOG_BIT|R128_TEX0_BIT) +#define TAG(x) x##_wgft0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_FOG_BIT|R128_TEX0_BIT|\ + R128_TEX1_BIT) +#define TAG(x) x##_wgft0t1 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_FOG_BIT|R128_TEX0_BIT|\ + R128_PTEX_BIT) +#define TAG(x) x##_wgfpt0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_FOG_BIT|R128_SPEC_BIT|\ + R128_TEX0_BIT) +#define TAG(x) x##_wgfst0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_FOG_BIT|R128_SPEC_BIT|\ + R128_TEX0_BIT|R128_TEX1_BIT) +#define TAG(x) x##_wgfst0t1 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_XYZW_BIT|R128_RGBA_BIT|R128_FOG_BIT|R128_SPEC_BIT|\ + R128_TEX0_BIT|R128_PTEX_BIT) +#define TAG(x) x##_wgfspt0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_TEX0_BIT) +#define TAG(x) x##_t0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_TEX0_BIT|R128_TEX1_BIT) +#define TAG(x) x##_t0t1 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_FOG_BIT) +#define TAG(x) x##_f +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_FOG_BIT|R128_TEX0_BIT) +#define TAG(x) x##_ft0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_FOG_BIT|R128_TEX0_BIT|R128_TEX1_BIT) +#define TAG(x) x##_ft0t1 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_RGBA_BIT) +#define TAG(x) x##_g +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_RGBA_BIT|R128_SPEC_BIT) +#define TAG(x) x##_gs +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_RGBA_BIT|R128_TEX0_BIT) +#define TAG(x) x##_gt0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_RGBA_BIT|R128_TEX0_BIT|R128_TEX1_BIT) +#define TAG(x) x##_gt0t1 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_RGBA_BIT|R128_SPEC_BIT|R128_TEX0_BIT) +#define TAG(x) x##_gst0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_RGBA_BIT|R128_SPEC_BIT|R128_TEX0_BIT|R128_TEX1_BIT) +#define TAG(x) x##_gst0t1 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_RGBA_BIT|R128_FOG_BIT) +#define TAG(x) x##_gf +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_RGBA_BIT|R128_FOG_BIT|R128_SPEC_BIT) +#define TAG(x) x##_gfs +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_RGBA_BIT|R128_FOG_BIT|R128_TEX0_BIT) +#define TAG(x) x##_gft0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_RGBA_BIT|R128_FOG_BIT|R128_TEX0_BIT|R128_TEX1_BIT) +#define TAG(x) x##_gft0t1 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_RGBA_BIT|R128_FOG_BIT|R128_SPEC_BIT|R128_TEX0_BIT) +#define TAG(x) x##_gfst0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (R128_RGBA_BIT|R128_FOG_BIT|R128_SPEC_BIT|R128_TEX0_BIT|\ + R128_TEX1_BIT) +#define TAG(x) x##_gfst0t1 +#include "tnl_dd/t_dd_vbtmp.h" + + +static void init_setup_tab( void ) +{ + init_wg(); + init_wgs(); + init_wgt0(); + init_wgt0t1(); + init_wgpt0(); + init_wgst0(); + init_wgst0t1(); + init_wgspt0(); + init_wgf(); + init_wgfs(); + init_wgft0(); + init_wgft0t1(); + init_wgfpt0(); + init_wgfst0(); + init_wgfst0t1(); + init_wgfspt0(); + init_t0(); + init_t0t1(); + init_f(); + init_ft0(); + init_ft0t1(); + init_g(); + init_gs(); + init_gt0(); + init_gt0t1(); + init_gst0(); + init_gst0t1(); + init_gf(); + init_gfs(); + init_gft0(); + init_gft0t1(); + init_gfst0(); + init_gfst0t1(); +} + + + +void r128PrintSetupFlags(char *msg, GLuint flags ) +{ + fprintf(stderr, "%s(%x): %s%s%s%s%s%s\n", + msg, + (int)flags, + (flags & R128_XYZW_BIT) ? " xyzw," : "", + (flags & R128_RGBA_BIT) ? " rgba," : "", + (flags & R128_SPEC_BIT) ? " spec," : "", + (flags & R128_FOG_BIT) ? " fog," : "", + (flags & R128_TEX0_BIT) ? " tex-0," : "", + (flags & R128_TEX1_BIT) ? " tex-1," : ""); +} + + + +void r128CheckTexSizes( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT( ctx ); + + if (!setup_tab[rmesa->SetupIndex].check_tex_sizes(ctx)) { + TNLcontext *tnl = TNL_CONTEXT(ctx); + + /* Invalidate stored verts + */ + rmesa->SetupNewInputs = ~0; + rmesa->SetupIndex |= R128_PTEX_BIT; + + if (!rmesa->Fallback && + !(ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED))) { + tnl->Driver.Render.Interp = setup_tab[rmesa->SetupIndex].interp; + tnl->Driver.Render.CopyPV = setup_tab[rmesa->SetupIndex].copy_pv; + } + } +} + +void r128BuildVertices( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint newinputs ) +{ + r128ContextPtr rmesa = R128_CONTEXT( ctx ); + GLubyte *v = ((GLubyte *)rmesa->verts + (start<<rmesa->vertex_stride_shift)); + GLuint stride = 1<<rmesa->vertex_stride_shift; + + newinputs |= rmesa->SetupNewInputs; + rmesa->SetupNewInputs = 0; + + if (!newinputs) + return; + + if (newinputs & VERT_BIT_CLIP) { + setup_tab[rmesa->SetupIndex].emit( ctx, start, count, v, stride ); + } else { + GLuint ind = 0; + + if (newinputs & VERT_BIT_COLOR0) + ind |= R128_RGBA_BIT; + + if (newinputs & VERT_BIT_COLOR1) + ind |= R128_SPEC_BIT; + + if (newinputs & VERT_BIT_TEX0) + ind |= R128_TEX0_BIT; + + if (newinputs & VERT_BIT_TEX1) + ind |= R128_TEX1_BIT; + + if (newinputs & VERT_BIT_FOG) + ind |= R128_FOG_BIT; + + if (rmesa->SetupIndex & R128_PTEX_BIT) + ind = ~0; + + ind &= rmesa->SetupIndex; + + if (ind) { + setup_tab[ind].emit( ctx, start, count, v, stride ); + } + } +} + +void r128ChooseVertexState( GLcontext *ctx ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + r128ContextPtr rmesa = R128_CONTEXT( ctx ); + GLuint ind = R128_XYZW_BIT|R128_RGBA_BIT; + + if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) + ind |= R128_SPEC_BIT; + + if (ctx->Fog.Enabled) + ind |= R128_FOG_BIT; + + if (ctx->Texture._EnabledUnits) { + ind |= R128_TEX0_BIT; + if (ctx->Texture.Unit[0]._ReallyEnabled && + ctx->Texture.Unit[1]._ReallyEnabled) + ind |= R128_TEX1_BIT; + } + + rmesa->SetupIndex = ind; + + if (ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED)) { + tnl->Driver.Render.Interp = r128_interp_extras; + tnl->Driver.Render.CopyPV = r128_copy_pv_extras; + } else { + tnl->Driver.Render.Interp = setup_tab[ind].interp; + tnl->Driver.Render.CopyPV = setup_tab[ind].copy_pv; + } + + if (setup_tab[ind].vertex_format != rmesa->vertex_format) { + FLUSH_BATCH(rmesa); + rmesa->vertex_format = setup_tab[ind].vertex_format; + rmesa->vertex_size = setup_tab[ind].vertex_size; + rmesa->vertex_stride_shift = setup_tab[ind].vertex_stride_shift; + } +} + + + +void r128_emit_contiguous_verts( GLcontext *ctx, + GLuint start, + GLuint count ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + GLuint vertex_size = rmesa->vertex_size * 4; + GLuint *dest = r128AllocDmaLow( rmesa, (count-start) * vertex_size); + setup_tab[rmesa->SetupIndex].emit( ctx, start, count, dest, vertex_size ); +} + + +#if 0 +void r128_emit_indexed_verts( GLcontext *ctx, GLuint start, GLuint count ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + GLuint vertex_size = rmesa->vertex_size * 4; + GLuint bufsz = (count-start) * vertex_size; + CARD32 *dest; + + rmesa->vertex_low = (rmesa->vertex_low + 63) & ~63; /* alignment */ + rmesa->vertex_last_prim = rmesa->vertex_low; + + dest = r128AllocDmaLow( rmesa, bufsz, __FUNCTION__); + setup_tab[rmesa->SetupIndex].emit( ctx, start, count, dest, vertex_size ); + + rmesa->retained_buffer = rmesa->vertex_buffer; + rmesa->vb_offset = (rmesa->vertex_buffer->idx * R128_BUFFER_SIZE + + rmesa->vertex_low - bufsz); + + rmesa->vertex_low = (rmesa->vertex_low + 0x7) & ~0x7; /* alignment */ + rmesa->vertex_last_prim = rmesa->vertex_low; +} +#endif + + +void r128InitVB( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + GLuint size = TNL_CONTEXT(ctx)->vb.Size; + + rmesa->verts = ALIGN_MALLOC(size * 4 * 16, 32); + + { + static int firsttime = 1; + if (firsttime) { + init_setup_tab(); + firsttime = 0; + } + } +} + + +void r128FreeVB( GLcontext *ctx ) +{ + r128ContextPtr rmesa = R128_CONTEXT(ctx); + if (rmesa->verts) { + ALIGN_FREE(rmesa->verts); + rmesa->verts = 0; + } + + + if (rmesa->UbyteSecondaryColor.Ptr) { + ALIGN_FREE(rmesa->UbyteSecondaryColor.Ptr); + rmesa->UbyteSecondaryColor.Ptr = 0; + } + + if (rmesa->UbyteColor.Ptr) { + ALIGN_FREE(rmesa->UbyteColor.Ptr); + rmesa->UbyteColor.Ptr = 0; + } +} diff --git a/src/mesa/drivers/dri/r128/r128_vb.h b/src/mesa/drivers/dri/r128/r128_vb.h new file mode 100644 index 0000000000..31afa74f1c --- /dev/null +++ b/src/mesa/drivers/dri/r128/r128_vb.h @@ -0,0 +1,74 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/r128/r128_vb.h,v 1.8 2002/10/30 12:51:46 alanh Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * + */ + +#ifndef R128VB_INC +#define R128VB_INC + +#include "mtypes.h" +#include "swrast/swrast.h" +#include "r128_context.h" + +#define _R128_NEW_VERTEX_STATE (_DD_NEW_SEPARATE_SPECULAR | \ + _DD_NEW_TRI_LIGHT_TWOSIDE | \ + _DD_NEW_TRI_UNFILLED | \ + _NEW_TEXTURE | \ + _NEW_FOG) + +extern void r128CheckTexSizes( GLcontext *ctx ); +extern void r128ChooseVertexState( GLcontext *ctx ); + +extern void r128BuildVertices( GLcontext *ctx, GLuint start, GLuint count, + GLuint newinputs ); + +extern void r128PrintSetupFlags(char *msg, GLuint flags ); + +extern void r128InitVB( GLcontext *ctx ); +extern void r128FreeVB( GLcontext *ctx ); + +extern void r128_emit_contiguous_verts( GLcontext *ctx, + GLuint start, + GLuint count ); + +extern void r128_emit_indexed_verts( GLcontext *ctx, + GLuint start, + GLuint count ); + +extern void r128_translate_vertex( GLcontext *ctx, + const r128Vertex *src, + SWvertex *dst ); + +extern void r128_print_vertex( GLcontext *ctx, const r128Vertex *v ); + +#endif diff --git a/src/mesa/drivers/dri/r128/server/r128.h b/src/mesa/drivers/dri/r128/server/r128.h new file mode 100644 index 0000000000..fba01d6d60 --- /dev/null +++ b/src/mesa/drivers/dri/r128/server/r128.h @@ -0,0 +1,566 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128.h,v 1.24 2002/12/16 16:19:10 dawes Exp $ */ +/* + * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, + * Precision Insight, Inc., Cedar Park, Texas, and + * VA Linux Systems Inc., Fremont, California. + * + * 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, sublicense, 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, PRECISION INSIGHT, 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. + */ + +/* + * Authors: + * Rickard E. Faith <faith@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * + */ + +#ifndef _R128_H_ +#define _R128_H_ + +#include "dri_util.h" +#ifndef _SOLO +#include "xf86str.h" + + /* PCI support */ +#include "xf86Pci.h" + + /* XAA and Cursor Support */ +#include "xaa.h" +#include "xf86Cursor.h" + + /* DDC support */ +#include "xf86DDC.h" + + /* Xv support */ +#include "xf86xv.h" + + /* DRI support */ +#ifdef XF86DRI +#define _XF86DRI_SERVER_ +#include "r128_dripriv.h" +#include "dri.h" +#include "GL/glxint.h" +#endif +#endif +#ifdef _SOLO +#define XF86DRI +#endif + +#define R128_DEBUG 0 /* Turn off debugging output */ +#define R128_IDLE_RETRY 32 /* Fall out of idle loops after this count */ +#define R128_TIMEOUT 2000000 /* Fall out of wait loops after this count */ +#define R128_MMIOSIZE 0x4000 + +#define R128_VBIOS_SIZE 0x00010000 + +#if R128_DEBUG +#define R128TRACE(x) \ + do { \ + ErrorF("(**) %s(%d): ", R128_NAME, pScrn->scrnIndex); \ + ErrorF x; \ + } while (0); +#else +#define R128TRACE(x) +#endif + + +/* Other macros */ +#define R128_ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0])) +#define R128_ALIGN(x,bytes) (((x) + ((bytes) - 1)) & ~((bytes) - 1)) +#define R128PTR(pScrn) ((R128InfoPtr)(pScrn)->driverPrivate) + +/** + * \brief Chip families. + */ +typedef enum { + CHIP_FAMILY_UNKNOWN, + CHIP_FAMILY_R128_PCI, + CHIP_FAMILY_R128_AGP, +} R128ChipFamily; + +typedef struct { /* All values in XCLKS */ + int ML; /* Memory Read Latency */ + int MB; /* Memory Burst Length */ + int Trcd; /* RAS to CAS delay */ + int Trp; /* RAS percentage */ + int Twr; /* Write Recovery */ + int CL; /* CAS Latency */ + int Tr2w; /* Read to Write Delay */ + int Rloop; /* Loop Latency */ + int Rloop_fudge; /* Add to ML to get Rloop */ + char *name; +} R128RAMRec, *R128RAMPtr; + +typedef struct { + /* Common registers */ + CARD32 ovr_clr; + CARD32 ovr_wid_left_right; + CARD32 ovr_wid_top_bottom; + CARD32 ov0_scale_cntl; + CARD32 mpp_tb_config; + CARD32 mpp_gp_config; + CARD32 subpic_cntl; + CARD32 viph_control; + CARD32 i2c_cntl_1; + CARD32 gen_int_cntl; + CARD32 cap0_trig_cntl; + CARD32 cap1_trig_cntl; + CARD32 bus_cntl; + CARD32 config_cntl; + + /* Other registers to save for VT switches */ + CARD32 dp_datatype; + CARD32 gen_reset_cntl; + CARD32 clock_cntl_index; + CARD32 amcgpio_en_reg; + CARD32 amcgpio_mask; + + /* CRTC registers */ + CARD32 crtc_gen_cntl; + CARD32 crtc_ext_cntl; + CARD32 dac_cntl; + CARD32 crtc_h_total_disp; + CARD32 crtc_h_sync_strt_wid; + CARD32 crtc_v_total_disp; + CARD32 crtc_v_sync_strt_wid; + CARD32 crtc_offset; + CARD32 crtc_offset_cntl; + CARD32 crtc_pitch; + + /* CRTC2 registers */ + CARD32 crtc2_gen_cntl; + + /* Flat panel registers */ + CARD32 fp_crtc_h_total_disp; + CARD32 fp_crtc_v_total_disp; + CARD32 fp_gen_cntl; + CARD32 fp_h_sync_strt_wid; + CARD32 fp_horz_stretch; + CARD32 fp_panel_cntl; + CARD32 fp_v_sync_strt_wid; + CARD32 fp_vert_stretch; + CARD32 lvds_gen_cntl; + CARD32 tmds_crc; + CARD32 tmds_transmitter_cntl; + + /* Computed values for PLL */ + CARD32 dot_clock_freq; + CARD32 pll_output_freq; + int feedback_div; + int post_div; + + /* PLL registers */ + CARD32 ppll_ref_div; + CARD32 ppll_div_3; + CARD32 htotal_cntl; + + /* DDA register */ + CARD32 dda_config; + CARD32 dda_on_off; + + /* Pallet */ + GLboolean palette_valid; + CARD32 palette[256]; +} R128SaveRec, *R128SavePtr; + +#ifndef _SOLO +typedef struct { + CARD16 reference_freq; + CARD16 reference_div; + CARD32 min_pll_freq; + CARD32 max_pll_freq; + CARD16 xclk; +} R128PLLRec, *R128PLLPtr; + +typedef struct { + int bitsPerPixel; + int depth; + int displayWidth; + int pixel_code; + int pixel_bytes; + DisplayModePtr mode; +} R128FBLayout; +#endif + +typedef struct { +#ifndef _SOLO + EntityInfoPtr pEnt; + pciVideoPtr PciInfo; + PCITAG PciTag; +#endif + int Chipset; + GLboolean Primary; + + GLboolean FBDev; + + unsigned long LinearAddr; /* Frame buffer physical address */ + unsigned long BIOSAddr; /* BIOS physical address */ + + unsigned char *MMIO; /* Map of MMIO region */ + unsigned char *FB; /* Map of frame buffer */ + + CARD32 MemCntl; + CARD32 BusCntl; + unsigned long FbMapSize; /* Size of frame buffer, in bytes */ + int Flags; /* Saved copy of mode flags */ + +#ifndef _SOLO + CARD8 BIOSDisplay; /* Device the BIOS is set to display to */ + + GLboolean HasPanelRegs; /* Current chip can connect to a FP */ + CARD8 *VBIOS; /* Video BIOS for mode validation on FPs */ + int FPBIOSstart; /* Start of the flat panel info */ +#endif + /* Computed values for FPs */ + int PanelXRes; + int PanelYRes; + int HOverPlus; + int HSyncWidth; + int HBlank; + int VOverPlus; + int VSyncWidth; + int VBlank; + int PanelPwrDly; +#ifndef _SOLO + R128PLLRec pll; + R128RAMPtr ram; + + R128SaveRec SavedReg; /* Original (text) mode */ + R128SaveRec ModeReg; /* Current mode */ + GLboolean (*CloseScreen)(int, ScreenPtr); + void (*BlockHandler)(int, pointer, pointer, pointer); + + GLboolean PaletteSavedOnVT; /* Palette saved on last VT switch */ + + XAAInfoRecPtr accel; + GLboolean accelOn; + xf86CursorInfoPtr cursor; +#endif + unsigned long cursor_start; + unsigned long cursor_end; + + /* + * XAAForceTransBlit is used to change the behavior of the XAA + * SetupForScreenToScreenCopy function, to make it DGA-friendly. + */ + GLboolean XAAForceTransBlit; + + int fifo_slots; /* Free slots in the FIFO (64 max) */ + int pix24bpp; /* Depth of pixmap for 24bpp framebuffer */ + GLboolean dac6bits; /* Use 6 bit DAC? */ + + /* Computed values for Rage 128 */ + int pitch; + int datatype; + CARD32 dp_gui_master_cntl; + + /* Saved values for ScreenToScreenCopy */ + int xdir; + int ydir; + + /* ScanlineScreenToScreenColorExpand support */ + unsigned char *scratch_buffer[1]; + unsigned char *scratch_save; + int scanline_x; + int scanline_y; + int scanline_w; + int scanline_h; +#ifdef XF86DRI + int scanline_hpass; + int scanline_x1clip; + int scanline_x2clip; + int scanline_rop; + int scanline_fg; + int scanline_bg; +#endif /* XF86DRI */ + int scanline_words; + int scanline_direct; + int scanline_bpp; /* Only used for ImageWrite */ + +#ifndef _SOLO + DGAModePtr DGAModes; + int numDGAModes; + GLboolean DGAactive; + int DGAViewportStatus; + DGAFunctionRec DGAFuncs; + + R128FBLayout CurrentLayout; +#endif +#ifdef XF86DRI + drmContext drmCtx; +#ifndef _SOLO + DRIInfoPtr pDRIInfo; + int numVisualConfigs; + __GLXvisualConfig *pVisualConfigs; + R128ConfigPrivPtr pVisualConfigsPriv; +#endif + + drmSize registerSize; + drmHandle registerHandle; + + GLboolean IsPCI; /* Current card is a PCI card */ + drmSize pciSize; + drmHandle pciMemHandle; + unsigned char *PCI; /* Map */ + + GLboolean allowPageFlip; /* Enable 3d page flipping */ + GLboolean have3DWindows; /* Are there any 3d clients? */ + int drmMinor; + + drmSize agpSize; + drmHandle agpMemHandle; /* Handle from drmAgpAlloc */ + unsigned long agpOffset; + unsigned char *AGP; /* Map */ + int agpMode; + + GLboolean CCEInUse; /* CCE is currently active */ + int CCEMode; /* CCE mode that server/clients use */ + int CCEFifoSize; /* Size of the CCE command FIFO */ + GLboolean CCESecure; /* CCE security enabled */ + int CCEusecTimeout; /* CCE timeout in usecs */ + + /* CCE ring buffer data */ + unsigned long ringStart; /* Offset into AGP space */ + drmHandle ringHandle; /* Handle from drmAddMap */ + drmSize ringMapSize; /* Size of map */ + int ringSize; /* Size of ring (in MB) */ + unsigned char *ring; /* Map */ + int ringSizeLog2QW; + + unsigned long ringReadOffset; /* Offset into AGP space */ + drmHandle ringReadPtrHandle; /* Handle from drmAddMap */ + drmSize ringReadMapSize; /* Size of map */ + unsigned char *ringReadPtr; /* Map */ + + /* CCE vertex/indirect buffer data */ + unsigned long bufStart; /* Offset into AGP space */ + drmHandle bufHandle; /* Handle from drmAddMap */ + drmSize bufMapSize; /* Size of map */ + int bufSize; /* Size of buffers (in MB) */ + unsigned char *buf; /* Map */ + int bufNumBufs; /* Number of buffers */ + drmBufMapPtr buffers; /* Buffer map */ + + /* CCE AGP Texture data */ + unsigned long agpTexStart; /* Offset into AGP space */ + drmHandle agpTexHandle; /* Handle from drmAddMap */ + drmSize agpTexMapSize; /* Size of map */ + int agpTexSize; /* Size of AGP tex space (in MB) */ + unsigned char *agpTex; /* Map */ + int log2AGPTexGran; + + /* CCE 2D accleration */ + drmBufPtr indirectBuffer; + int indirectStart; + + /* DRI screen private data */ + int fbX; + int fbY; + int backX; + int backY; + int depthX; + int depthY; + + int frontOffset; + int frontPitch; + int backOffset; + int backPitch; + int depthOffset; + int depthPitch; + int spanOffset; + int textureOffset; + int textureSize; + int log2TexGran; + + /* Saved scissor values */ + CARD32 sc_left; + CARD32 sc_right; + CARD32 sc_top; + CARD32 sc_bottom; + + CARD32 re_top_left; + CARD32 re_width_height; + + CARD32 aux_sc_cntl; + + int irq; + CARD32 gen_int_cntl; + + GLboolean DMAForXv; +#endif + +#ifndef _SOLO + XF86VideoAdaptorPtr adaptor; + void (*VideoTimerCallback)(ScrnInfoPtr, Time); + int videoKey; + GLboolean showCache; + OptionInfoPtr Options; + + GLboolean isDFP; + GLboolean isPro2; + I2CBusPtr pI2CBus; + CARD32 DDCReg; +#endif +} R128InfoRec, *R128InfoPtr; + +#define R128WaitForFifo(pScrn, entries) \ +do { \ + if (info->fifo_slots < entries) R128WaitForFifoFunction(pScrn, entries); \ + info->fifo_slots -= entries; \ +} while (0) + +extern void r128WaitForFifoFunction(const DRIDriverContext *ctx, int entries); +extern void r128WaitForIdle(const DRIDriverContext *ctx); + +extern void r128WaitForVerticalSync(const DRIDriverContext *ctx); + +extern GLboolean r128AccelInit(const DRIDriverContext *ctx); +extern void r128EngineInit(const DRIDriverContext *ctx); +extern GLboolean r128CursorInit(const DRIDriverContext *ctx); +extern GLboolean r128DGAInit(const DRIDriverContext *ctx); + +extern void r128InitVideo(const DRIDriverContext *ctx); + +extern GLboolean r128DRIScreenInit(const DRIDriverContext *ctx); +extern void r128DRICloseScreen(const DRIDriverContext *ctx); +extern GLboolean r128DRIFinishScreenInit(const DRIDriverContext *ctx); + +#define R128CCE_START(ctx, info) \ +do { \ + int _ret = drmCommandNone(ctx->drmFD, DRM_R128_CCE_START); \ + if (_ret) { \ + fprintf(stderr, \ + "%s: CCE start %d\n", __FUNCTION__, _ret); \ + } \ +} while (0) + +#define R128CCE_STOP(ctx, info) \ +do { \ + int _ret = R128CCEStop(ctx); \ + if (_ret) { \ + fprintf(stderr, \ + "%s: CCE stop %d\n", __FUNCTION__, _ret); \ + } \ +} while (0) + +#define R128CCE_RESET(ctx, info) \ +do { \ + if (info->directRenderingEnabled \ + && R128CCE_USE_RING_BUFFER(info->CCEMode)) { \ + int _ret = drmCommandNone(info->drmFD, DRM_R128_CCE_RESET); \ + if (_ret) { \ + fprintf(stderr, \ + "%s: CCE reset %d\n", __FUNCTION__, _ret); \ + } \ + } \ +} while (0) + + +#define CCE_PACKET0( reg, n ) \ + (R128_CCE_PACKET0 | ((n) << 16) | ((reg) >> 2)) +#define CCE_PACKET1( reg0, reg1 ) \ + (R128_CCE_PACKET1 | (((reg1) >> 2) << 11) | ((reg0) >> 2)) +#define CCE_PACKET2() \ + (R128_CCE_PACKET2) +#define CCE_PACKET3( pkt, n ) \ + (R128_CCE_PACKET3 | (pkt) | ((n) << 16)) + + +#define R128_VERBOSE 0 + +#define RING_LOCALS CARD32 *__head; int __count; + +#define R128CCE_REFRESH(pScrn, info) \ +do { \ + if ( R128_VERBOSE ) { \ + fprintf(stderr, "REFRESH( %d ) in %s\n", \ + !info->CCEInUse , __FUNCTION__ ); \ + } \ + if ( !info->CCEInUse ) { \ + R128CCEWaitForIdle(pScrn); \ + BEGIN_RING( 6 ); \ + OUT_RING_REG( R128_RE_TOP_LEFT, info->re_top_left ); \ + OUT_RING_REG( R128_RE_WIDTH_HEIGHT, info->re_width_height ); \ + OUT_RING_REG( R128_AUX_SC_CNTL, info->aux_sc_cntl ); \ + ADVANCE_RING(); \ + info->CCEInUse = TRUE; \ + } \ +} while (0) + +#define BEGIN_RING( n ) do { \ + if ( R128_VERBOSE ) { \ + fprintf(stderr, \ + "BEGIN_RING( %d ) in %s\n", n, __FUNCTION__ ); \ + } \ + if ( !info->indirectBuffer ) { \ + info->indirectBuffer = R128CCEGetBuffer( pScrn ); \ + info->indirectStart = 0; \ + } else if ( (info->indirectBuffer->used + 4*(n)) > \ + info->indirectBuffer->total ) { \ + R128CCEFlushIndirect( pScrn, 1 ); \ + } \ + __head = (pointer)((char *)info->indirectBuffer->address + \ + info->indirectBuffer->used); \ + __count = 0; \ +} while (0) + +#define ADVANCE_RING() do { \ + if ( R128_VERBOSE ) { \ + fprintf(stderr, \ + "ADVANCE_RING() used: %d+%d=%d/%d\n", \ + info->indirectBuffer->used - info->indirectStart, \ + __count * sizeof(CARD32), \ + info->indirectBuffer->used - info->indirectStart + \ + __count * sizeof(CARD32), \ + info->indirectBuffer->total - info->indirectStart ); \ + } \ + info->indirectBuffer->used += __count * (int)sizeof(CARD32); \ +} while (0) + +#define OUT_RING( x ) do { \ + if ( R128_VERBOSE ) { \ + fprintf(stderr, \ + " OUT_RING( 0x%08x )\n", (unsigned int)(x) ); \ + } \ + MMIO_OUT32(&__head[__count++], 0, (x)); \ +} while (0) + +#define OUT_RING_REG( reg, val ) \ +do { \ + OUT_RING( CCE_PACKET0( reg, 0 ) ); \ + OUT_RING( val ); \ +} while (0) + +#define FLUSH_RING() \ +do { \ + if ( R128_VERBOSE ) \ + fprintf(stderr, \ + "FLUSH_RING in %s\n", __FUNCTION__ ); \ + if ( info->indirectBuffer ) { \ + R128CCEFlushIndirect( pScrn, 0 ); \ + } \ +} while (0) + + +#endif diff --git a/src/mesa/drivers/dri/r128/server/r128_common.h b/src/mesa/drivers/dri/r128/server/r128_common.h new file mode 100644 index 0000000000..fa81360ea5 --- /dev/null +++ b/src/mesa/drivers/dri/r128/server/r128_common.h @@ -0,0 +1,169 @@ +/* r128_common.h -- common header definitions for R128 2D/3D/DRM suite + * Created: Sun Apr 9 18:16:28 2000 by kevin@precisioninsight.com + * + * Copyright 1999, 2000 Precision Insight, Inc., Cedar Park, Texas. + * 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 + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * 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 NONINFRINGEMENT. IN NO EVENT SHALL + * PRECISION INSIGHT 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. + * + * Author: + * Gareth Hughes <gareth@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * + * Converted to common header format: + * Jens Owen <jens@tungstengraphics.com> + * + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/xf86drmR128.h,v 3.11 2001/04/16 15:02:13 tsi Exp $ + * + */ + +#ifndef _R128_COMMON_H_ +#define _R128_COMMON_H_ + +/* + * WARNING: If you change any of these defines, make sure to change + * the kernel include file as well (r128_drm.h) + */ + +/* Driver specific DRM command indices + * NOTE: these are not OS specific, but they are driver specific + */ +#define DRM_R128_INIT 0x00 +#define DRM_R128_CCE_START 0x01 +#define DRM_R128_CCE_STOP 0x02 +#define DRM_R128_CCE_RESET 0x03 +#define DRM_R128_CCE_IDLE 0x04 +#define DRM_R128_UNDEFINED1 0x05 +#define DRM_R128_RESET 0x06 +#define DRM_R128_SWAP 0x07 +#define DRM_R128_CLEAR 0x08 +#define DRM_R128_VERTEX 0x09 +#define DRM_R128_INDICES 0x0a +#define DRM_R128_BLIT 0x0b +#define DRM_R128_DEPTH 0x0c +#define DRM_R128_STIPPLE 0x0d +#define DRM_R128_UNDEFINED2 0x0e +#define DRM_R128_INDIRECT 0x0f +#define DRM_R128_FULLSCREEN 0x10 +#define DRM_R128_CLEAR2 0x11 +#define DRM_R128_GETPARAM 0x12 +#define DRM_R128_FLIP 0x13 + +#define DRM_R128_FRONT_BUFFER 0x1 +#define DRM_R128_BACK_BUFFER 0x2 +#define DRM_R128_DEPTH_BUFFER 0x4 + +typedef struct { + enum { + DRM_R128_INIT_CCE = 0x01, + DRM_R128_CLEANUP_CCE = 0x02 + } func; + unsigned long sarea_priv_offset; + int is_pci; + int cce_mode; + int cce_secure; /* FIXME: Deprecated, we should remove this */ + int ring_size; + int usec_timeout; + + unsigned int fb_bpp; + unsigned int front_offset, front_pitch; + unsigned int back_offset, back_pitch; + unsigned int depth_bpp; + unsigned int depth_offset, depth_pitch; + unsigned int span_offset; + + unsigned long fb_offset; + unsigned long mmio_offset; + unsigned long ring_offset; + unsigned long ring_rptr_offset; + unsigned long buffers_offset; + unsigned long agp_textures_offset; +} drmR128Init; + +typedef struct { + int flush; + int idle; +} drmR128CCEStop; + +typedef struct { + int idx; + int start; + int end; + int discard; +} drmR128Indirect; + +typedef struct { + int idx; + int pitch; + int offset; + int format; + unsigned short x, y; + unsigned short width, height; +} drmR128Blit; + +typedef struct { + enum { + DRM_R128_WRITE_SPAN = 0x01, + DRM_R128_WRITE_PIXELS = 0x02, + DRM_R128_READ_SPAN = 0x03, + DRM_R128_READ_PIXELS = 0x04 + } func; + int n; + int *x; + int *y; + unsigned int *buffer; + unsigned char *mask; +} drmR128Depth; + +typedef struct { + int prim; + int idx; /* Index of vertex buffer */ + int count; /* Number of vertices in buffer */ + int discard; /* Client finished with buffer? */ +} drmR128Vertex; + +typedef struct { + unsigned int *mask; +} drmR128Stipple; + +typedef struct { + unsigned int flags; + unsigned int clear_color; + unsigned int clear_depth; + unsigned int color_mask; + unsigned int depth_mask; +} drmR128Clear; + +typedef struct { + enum { + DRM_R128_INIT_FULLSCREEN = 0x01, + DRM_R128_CLEANUP_FULLSCREEN = 0x02 + } func; +} drmR128Fullscreen; + +typedef struct drm_r128_getparam { + int param; + void *value; +} drmR128GetParam; + +#define R128_PARAM_IRQ_NR 1 + +#endif diff --git a/src/mesa/drivers/dri/r128/server/r128_dri.c b/src/mesa/drivers/dri/r128/server/r128_dri.c new file mode 100644 index 0000000000..aa8f49f9c7 --- /dev/null +++ b/src/mesa/drivers/dri/r128/server/r128_dri.c @@ -0,0 +1,1165 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_dri.c,v 1.28 2003/02/07 20:41:14 martin Exp $ */ +/* + * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, + * Precision Insight, Inc., Cedar Park, Texas, and + * VA Linux Systems Inc., Fremont, California. + * + * 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, sublicense, 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, PRECISION INSIGHT, 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Rickard E. Faith <faith@valinux.com> + * Daryll Strauss <daryll@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#include "sarea.h" +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <unistd.h> +#include <linux/pci_ids.h> + +#include "driver.h" +#include "drm.h" + +#include "sarea.h" +#include "r128.h" +#include "r128_dri.h" +#include "r128_macros.h" +#include "r128_reg.h" +#include "r128_sarea.h" +#include "r128_version.h" + + +/* ?? HACK - for now, put this here... */ +/* ?? Alpha - this may need to be a variable to handle UP1x00 vs TITAN */ +#if defined(__alpha__) +# define DRM_PAGE_SIZE 8192 +#elif defined(__ia64__) +# define DRM_PAGE_SIZE getpagesize() +#else +# define DRM_PAGE_SIZE 4096 +#endif + +/** + * \brief Establish the set of modes available for the display. + * + * \param ctx display handle. + * \param numModes will receive the number of supported modes. + * \param modes will point to the list of supported modes. + * + * \return one on success, or zero on failure. + * + * Allocates a single visual and fills it with information according to the + * display bit depth. Supports only 16 and 32 bpp bit depths, aborting + * otherwise. + */ +const __GLcontextModes __glModes[] = { + + /* 32 bit, RGBA Depth=24 Stencil=8 */ + {.rgbMode = GL_TRUE, .colorIndexMode = GL_FALSE, .doubleBufferMode = GL_TRUE, .stereoMode = GL_FALSE, + .haveAccumBuffer = GL_FALSE, .haveDepthBuffer = GL_TRUE, .haveStencilBuffer = GL_TRUE, + .redBits = 8, .greenBits = 8, .blueBits = 8, .alphaBits = 8, + .redMask = 0xff0000, .greenMask = 0xff00, .blueMask = 0xff, .alphaMask = 0xff000000, + .rgbBits = 32, .indexBits = 0, + .accumRedBits = 0, .accumGreenBits = 0, .accumBlueBits = 0, .accumAlphaBits = 0, + .depthBits = 24, .stencilBits = 8, + .numAuxBuffers= 0, .level = 0, .pixmapMode = GL_FALSE, }, + + /* 16 bit, RGB Depth=16 */ + {.rgbMode = GL_TRUE, .colorIndexMode = GL_FALSE, .doubleBufferMode = GL_TRUE, .stereoMode = GL_FALSE, + .haveAccumBuffer = GL_FALSE, .haveDepthBuffer = GL_TRUE, .haveStencilBuffer = GL_FALSE, + .redBits = 5, .greenBits = 6, .blueBits = 5, .alphaBits = 0, + .redMask = 0xf800, .greenMask = 0x07e0, .blueMask = 0x001f, .alphaMask = 0x0, + .rgbBits = 16, .indexBits = 0, + .accumRedBits = 0, .accumGreenBits = 0, .accumBlueBits = 0, .accumAlphaBits = 0, + .depthBits = 16, .stencilBits = 0, + .numAuxBuffers= 0, .level = 0, .pixmapMode = GL_FALSE, }, +}; +static int R128InitContextModes( const DRIDriverContext *ctx, + int *numModes, const __GLcontextModes **modes) +{ + *numModes = sizeof(__glModes)/sizeof(__GLcontextModes *); + *modes = &__glModes[0]; + return 1; +} + +/* Compute log base 2 of val. */ +static int R128MinBits(int val) +{ + int bits; + + if (!val) return 1; + for (bits = 0; val; val >>= 1, ++bits); + return bits; +} + +/* Initialize the AGP state. Request memory for use in AGP space, and + initialize the Rage 128 registers to point to that memory. */ +static GLboolean R128DRIAgpInit(const DRIDriverContext *ctx) +{ + unsigned char *R128MMIO = ctx->MMIOAddress; + R128InfoPtr info = ctx->driverPrivate; + unsigned long mode; + unsigned int vendor, device; + int ret; + unsigned long cntl, chunk; + int s, l; + int flags; + unsigned long agpBase; + + if (drmAgpAcquire(ctx->drmFD) < 0) { + fprintf(stderr, "[agp] AGP not available\n"); + return GL_FALSE; + } + + /* Modify the mode if the default mode is + not appropriate for this particular + combination of graphics card and AGP + chipset. */ + + mode = drmAgpGetMode(ctx->drmFD); /* Default mode */ + vendor = drmAgpVendorId(ctx->drmFD); + device = drmAgpDeviceId(ctx->drmFD); + + mode &= ~R128_AGP_MODE_MASK; + switch (info->agpMode) { + case 4: mode |= R128_AGP_4X_MODE; + case 2: mode |= R128_AGP_2X_MODE; + case 1: default: mode |= R128_AGP_1X_MODE; + } + + fprintf(stderr, + "[agp] Mode 0x%08lx [AGP 0x%04x/0x%04x; Card 0x%04x/0x%04x]\n", + mode, vendor, device, + 0x1002, + info->Chipset); + + if (drmAgpEnable(ctx->drmFD, mode) < 0) { + fprintf(stderr, "[agp] AGP not enabled\n"); + drmAgpRelease(ctx->drmFD); + return GL_FALSE; + } + + info->agpOffset = 0; + + if ((ret = drmAgpAlloc(ctx->drmFD, info->agpSize*1024*1024, 0, NULL, + &info->agpMemHandle)) < 0) { + fprintf(stderr, "[agp] Out of memory (%d)\n", ret); + drmAgpRelease(ctx->drmFD); + return GL_FALSE; + } + fprintf(stderr, + "[agp] %d kB allocated with handle 0x%08x\n", + info->agpSize*1024, info->agpMemHandle); + + if (drmAgpBind(ctx->drmFD, info->agpMemHandle, info->agpOffset) < 0) { + fprintf(stderr, "[agp] Could not bind\n"); + drmAgpFree(ctx->drmFD, info->agpMemHandle); + drmAgpRelease(ctx->drmFD); + return GL_FALSE; + } + + /* Initialize the CCE ring buffer data */ + info->ringStart = info->agpOffset; + info->ringMapSize = info->ringSize*1024*1024 + DRM_PAGE_SIZE; + info->ringSizeLog2QW = R128MinBits(info->ringSize*1024*1024/8) - 1; + + info->ringReadOffset = info->ringStart + info->ringMapSize; + info->ringReadMapSize = DRM_PAGE_SIZE; + + /* Reserve space for vertex/indirect buffers */ + info->bufStart = info->ringReadOffset + info->ringReadMapSize; + info->bufMapSize = info->bufSize*1024*1024; + + /* Reserve the rest for AGP textures */ + info->agpTexStart = info->bufStart + info->bufMapSize; + s = (info->agpSize*1024*1024 - info->agpTexStart); + l = R128MinBits((s-1) / R128_NR_TEX_REGIONS); + if (l < R128_LOG_TEX_GRANULARITY) l = R128_LOG_TEX_GRANULARITY; + info->agpTexMapSize = (s >> l) << l; + info->log2AGPTexGran = l; + + if (info->CCESecure) flags = DRM_READ_ONLY; + else flags = 0; + + if (drmAddMap(ctx->drmFD, info->ringStart, info->ringMapSize, + DRM_AGP, flags, &info->ringHandle) < 0) { + fprintf(stderr, + "[agp] Could not add ring mapping\n"); + return GL_FALSE; + } + fprintf(stderr, + "[agp] ring handle = 0x%08lx\n", info->ringHandle); + + if (drmMap(ctx->drmFD, info->ringHandle, info->ringMapSize, + (drmAddressPtr)&info->ring) < 0) { + fprintf(stderr, "[agp] Could not map ring\n"); + return GL_FALSE; + } + fprintf(stderr, + "[agp] Ring mapped at 0x%08lx\n", + (unsigned long)info->ring); + + if (drmAddMap(ctx->drmFD, info->ringReadOffset, info->ringReadMapSize, + DRM_AGP, flags, &info->ringReadPtrHandle) < 0) { + fprintf(stderr, + "[agp] Could not add ring read ptr mapping\n"); + return GL_FALSE; + } + fprintf(stderr, + "[agp] ring read ptr handle = 0x%08lx\n", + info->ringReadPtrHandle); + + if (drmMap(ctx->drmFD, info->ringReadPtrHandle, info->ringReadMapSize, + (drmAddressPtr)&info->ringReadPtr) < 0) { + fprintf(stderr, + "[agp] Could not map ring read ptr\n"); + return GL_FALSE; + } + fprintf(stderr, + "[agp] Ring read ptr mapped at 0x%08lx\n", + (unsigned long)info->ringReadPtr); + + if (drmAddMap(ctx->drmFD, info->bufStart, info->bufMapSize, + DRM_AGP, 0, &info->bufHandle) < 0) { + fprintf(stderr, + "[agp] Could not add vertex/indirect buffers mapping\n"); + return GL_FALSE; + } + fprintf(stderr, + "[agp] vertex/indirect buffers handle = 0x%08lx\n", + info->bufHandle); + + if (drmMap(ctx->drmFD, info->bufHandle, info->bufMapSize, + (drmAddressPtr)&info->buf) < 0) { + fprintf(stderr, + "[agp] Could not map vertex/indirect buffers\n"); + return GL_FALSE; + } + fprintf(stderr, + "[agp] Vertex/indirect buffers mapped at 0x%08lx\n", + (unsigned long)info->buf); + + if (drmAddMap(ctx->drmFD, info->agpTexStart, info->agpTexMapSize, + DRM_AGP, 0, &info->agpTexHandle) < 0) { + fprintf(stderr, + "[agp] Could not add AGP texture map mapping\n"); + return GL_FALSE; + } + fprintf(stderr, + "[agp] AGP texture map handle = 0x%08lx\n", + info->agpTexHandle); + + if (drmMap(ctx->drmFD, info->agpTexHandle, info->agpTexMapSize, + (drmAddressPtr)&info->agpTex) < 0) { + fprintf(stderr, + "[agp] Could not map AGP texture map\n"); + return GL_FALSE; + } + fprintf(stderr, + "[agp] AGP Texture map mapped at 0x%08lx\n", + (unsigned long)info->agpTex); + + /* Initialize Rage 128's AGP registers */ + cntl = INREG(R128_AGP_CNTL); + cntl &= ~R128_AGP_APER_SIZE_MASK; + switch (info->agpSize) { + case 256: cntl |= R128_AGP_APER_SIZE_256MB; break; + case 128: cntl |= R128_AGP_APER_SIZE_128MB; break; + case 64: cntl |= R128_AGP_APER_SIZE_64MB; break; + case 32: cntl |= R128_AGP_APER_SIZE_32MB; break; + case 16: cntl |= R128_AGP_APER_SIZE_16MB; break; + case 8: cntl |= R128_AGP_APER_SIZE_8MB; break; + case 4: cntl |= R128_AGP_APER_SIZE_4MB; break; + default: + fprintf(stderr, + "[agp] Illegal aperture size %d kB\n", + info->agpSize*1024); + return GL_FALSE; + } + agpBase = drmAgpBase(ctx->drmFD); + OUTREG(R128_AGP_BASE, agpBase); + OUTREG(R128_AGP_CNTL, cntl); + + /* Disable Rage 128's PCIGART registers */ + chunk = INREG(R128_BM_CHUNK_0_VAL); + chunk &= ~(R128_BM_PTR_FORCE_TO_PCI | + R128_BM_PM4_RD_FORCE_TO_PCI | + R128_BM_GLOBAL_FORCE_TO_PCI); + OUTREG(R128_BM_CHUNK_0_VAL, chunk); + + OUTREG(R128_PCI_GART_PAGE, 1); /* Ensure AGP GART is used (for now) */ + + return GL_TRUE; +} + +static GLboolean R128DRIPciInit(const DRIDriverContext *ctx) +{ + R128InfoPtr info = ctx->driverPrivate; + unsigned char *R128MMIO = ctx->MMIOAddress; + CARD32 chunk; + int ret; + int flags; + + info->agpOffset = 0; + + ret = drmScatterGatherAlloc(ctx->drmFD, info->agpSize*1024*1024, + &info->pciMemHandle); + if (ret < 0) { + fprintf(stderr, "[pci] Out of memory (%d)\n", ret); + return GL_FALSE; + } + fprintf(stderr, + "[pci] %d kB allocated with handle 0x%08x\n", + info->agpSize*1024, info->pciMemHandle); + + /* Initialize the CCE ring buffer data */ + info->ringStart = info->agpOffset; + info->ringMapSize = info->ringSize*1024*1024 + DRM_PAGE_SIZE; + info->ringSizeLog2QW = R128MinBits(info->ringSize*1024*1024/8) - 1; + + info->ringReadOffset = info->ringStart + info->ringMapSize; + info->ringReadMapSize = DRM_PAGE_SIZE; + + /* Reserve space for vertex/indirect buffers */ + info->bufStart = info->ringReadOffset + info->ringReadMapSize; + info->bufMapSize = info->bufSize*1024*1024; + + flags = DRM_READ_ONLY | DRM_LOCKED | DRM_KERNEL; + + if (drmAddMap(ctx->drmFD, info->ringStart, info->ringMapSize, + DRM_SCATTER_GATHER, flags, &info->ringHandle) < 0) { + fprintf(stderr, + "[pci] Could not add ring mapping\n"); + return GL_FALSE; + } + fprintf(stderr, + "[pci] ring handle = 0x%08lx\n", info->ringHandle); + + if (drmMap(ctx->drmFD, info->ringHandle, info->ringMapSize, + (drmAddressPtr)&info->ring) < 0) { + fprintf(stderr, "[pci] Could not map ring\n"); + return GL_FALSE; + } + fprintf(stderr, + "[pci] Ring mapped at 0x%08lx\n", + (unsigned long)info->ring); + fprintf(stderr, + "[pci] Ring contents 0x%08lx\n", + *(unsigned long *)info->ring); + + if (drmAddMap(ctx->drmFD, info->ringReadOffset, info->ringReadMapSize, + DRM_SCATTER_GATHER, flags, &info->ringReadPtrHandle) < 0) { + fprintf(stderr, + "[pci] Could not add ring read ptr mapping\n"); + return GL_FALSE; + } + fprintf(stderr, + "[pci] ring read ptr handle = 0x%08lx\n", + info->ringReadPtrHandle); + + if (drmMap(ctx->drmFD, info->ringReadPtrHandle, info->ringReadMapSize, + (drmAddressPtr)&info->ringReadPtr) < 0) { + fprintf(stderr, + "[pci] Could not map ring read ptr\n"); + return GL_FALSE; + } + fprintf(stderr, + "[pci] Ring read ptr mapped at 0x%08lx\n", + (unsigned long)info->ringReadPtr); + fprintf(stderr, + "[pci] Ring read ptr contents 0x%08lx\n", + *(unsigned long *)info->ringReadPtr); + + if (drmAddMap(ctx->drmFD, info->bufStart, info->bufMapSize, + DRM_SCATTER_GATHER, 0, &info->bufHandle) < 0) { + fprintf(stderr, + "[pci] Could not add vertex/indirect buffers mapping\n"); + return GL_FALSE; + } + fprintf(stderr, + "[pci] vertex/indirect buffers handle = 0x%08lx\n", + info->bufHandle); + + if (drmMap(ctx->drmFD, info->bufHandle, info->bufMapSize, + (drmAddressPtr)&info->buf) < 0) { + fprintf(stderr, + "[pci] Could not map vertex/indirect buffers\n"); + return GL_FALSE; + } + fprintf(stderr, + "[pci] Vertex/indirect buffers mapped at 0x%08lx\n", + (unsigned long)info->buf); + fprintf(stderr, + "[pci] Vertex/indirect buffers contents 0x%08lx\n", + *(unsigned long *)info->buf); + + if (!info->IsPCI) { + /* This is really an AGP card, force PCI GART mode */ + chunk = INREG(R128_BM_CHUNK_0_VAL); + chunk |= (R128_BM_PTR_FORCE_TO_PCI | + R128_BM_PM4_RD_FORCE_TO_PCI | + R128_BM_GLOBAL_FORCE_TO_PCI); + OUTREG(R128_BM_CHUNK_0_VAL, chunk); + OUTREG(R128_PCI_GART_PAGE, 0); /* Ensure PCI GART is used */ + } + + return GL_TRUE; +} + +/* Add a map for the MMIO registers that will be accessed by any + DRI-based clients. */ +static GLboolean R128DRIMapInit(const DRIDriverContext *ctx) +{ + R128InfoPtr info = ctx->driverPrivate; + int flags; + + if (info->CCESecure) flags = DRM_READ_ONLY; + else flags = 0; + + /* Map registers */ + if (drmAddMap(ctx->drmFD, ctx->MMIOStart, ctx->MMIOSize, + DRM_REGISTERS, flags, &info->registerHandle) < 0) { + return GL_FALSE; + } + fprintf(stderr, + "[drm] register handle = 0x%08lx\n", info->registerHandle); + + return GL_TRUE; +} + +/* Initialize the kernel data structures. */ +static int R128DRIKernelInit(const DRIDriverContext *ctx) +{ + R128InfoPtr info = ctx->driverPrivate; + drmR128Init drmInfo; + + memset( &drmInfo, 0, sizeof(drmR128Init) ); + + drmInfo.func = DRM_R128_INIT_CCE; + drmInfo.sarea_priv_offset = sizeof(XF86DRISAREARec); + drmInfo.is_pci = info->IsPCI; + drmInfo.cce_mode = info->CCEMode; + drmInfo.cce_secure = info->CCESecure; + drmInfo.ring_size = info->ringSize*1024*1024; + drmInfo.usec_timeout = info->CCEusecTimeout; + + drmInfo.fb_bpp = ctx->bpp; + drmInfo.depth_bpp = ctx->bpp; + + drmInfo.front_offset = info->frontOffset; + drmInfo.front_pitch = info->frontPitch; + + drmInfo.back_offset = info->backOffset; + drmInfo.back_pitch = info->backPitch; + + drmInfo.depth_offset = info->depthOffset; + drmInfo.depth_pitch = info->depthPitch; + drmInfo.span_offset = info->spanOffset; + + drmInfo.fb_offset = info->LinearAddr; + drmInfo.mmio_offset = info->registerHandle; + drmInfo.ring_offset = info->ringHandle; + drmInfo.ring_rptr_offset = info->ringReadPtrHandle; + drmInfo.buffers_offset = info->bufHandle; + drmInfo.agp_textures_offset = info->agpTexHandle; + + if (drmCommandWrite(ctx->drmFD, DRM_R128_INIT, + &drmInfo, sizeof(drmR128Init)) < 0) + return GL_FALSE; + + return GL_TRUE; +} + +/* Add a map for the vertex buffers that will be accessed by any + DRI-based clients. */ +static GLboolean R128DRIBufInit(const DRIDriverContext *ctx) +{ + R128InfoPtr info = ctx->driverPrivate; + /* Initialize vertex buffers */ + if (info->IsPCI) { + info->bufNumBufs = drmAddBufs(ctx->drmFD, + info->bufMapSize / R128_BUFFER_SIZE, + R128_BUFFER_SIZE, + DRM_SG_BUFFER, + info->bufStart); + } else { + info->bufNumBufs = drmAddBufs(ctx->drmFD, + info->bufMapSize / R128_BUFFER_SIZE, + R128_BUFFER_SIZE, + DRM_AGP_BUFFER, + info->bufStart); + } + if (info->bufNumBufs <= 0) { + fprintf(stderr, + "[drm] Could not create vertex/indirect buffers list\n"); + return GL_FALSE; + } + fprintf(stderr, + "[drm] Added %d %d byte vertex/indirect buffers\n", + info->bufNumBufs, R128_BUFFER_SIZE); + + if (!(info->buffers = drmMapBufs(ctx->drmFD))) { + fprintf(stderr, + "[drm] Failed to map vertex/indirect buffers list\n"); + return GL_FALSE; + } + fprintf(stderr, + "[drm] Mapped %d vertex/indirect buffers\n", + info->buffers->count); + + return GL_TRUE; +} + +static void R128DRIIrqInit(const DRIDriverContext *ctx) +{ + R128InfoPtr info = ctx->driverPrivate; + unsigned char *R128MMIO = ctx->MMIOAddress; + + if (!info->irq) { + info->irq = drmGetInterruptFromBusID( + ctx->drmFD, + ctx->pciBus, + ctx->pciDevice, + ctx->pciFunc); + + if((drmCtlInstHandler(ctx->drmFD, info->irq)) != 0) { + fprintf(stderr, + "[drm] failure adding irq handler, " + "there is a device already using that irq\n" + "[drm] falling back to irq-free operation\n"); + info->irq = 0; + } else { + info->gen_int_cntl = INREG( R128_GEN_INT_CNTL ); + } + } + + if (info->irq) + fprintf(stderr, + "[drm] dma control initialized, using IRQ %d\n", + info->irq); +} + +static int R128CCEStop(const DRIDriverContext *ctx) +{ + R128InfoPtr info = ctx->driverPrivate; + drmR128CCEStop stop; + int ret, i; + + stop.flush = 1; + stop.idle = 1; + + ret = drmCommandWrite( ctx->drmFD, DRM_R128_CCE_STOP, + &stop, sizeof(drmR128CCEStop) ); + + if ( ret == 0 ) { + return 0; + } else if ( errno != EBUSY ) { + return -errno; + } + + stop.flush = 0; + + i = 0; + do { + ret = drmCommandWrite( ctx->drmFD, DRM_R128_CCE_STOP, + &stop, sizeof(drmR128CCEStop) ); + } while ( ret && errno == EBUSY && i++ < R128_IDLE_RETRY ); + + if ( ret == 0 ) { + return 0; + } else if ( errno != EBUSY ) { + return -errno; + } + + stop.idle = 0; + + if ( drmCommandWrite( ctx->drmFD, DRM_R128_CCE_STOP, + &stop, sizeof(drmR128CCEStop) )) { + return -errno; + } else { + return 0; + } +} + +/* Initialize the CCE state, and start the CCE (if used by the X server) */ +static void R128DRICCEInit(const DRIDriverContext *ctx) +{ + R128InfoPtr info = ctx->driverPrivate; + + /* Turn on bus mastering */ + info->BusCntl &= ~R128_BUS_MASTER_DIS; + + /* CCEMode is initialized in r128_driver.c */ + switch (info->CCEMode) { + case R128_PM4_NONPM4: info->CCEFifoSize = 0; break; + case R128_PM4_192PIO: info->CCEFifoSize = 192; break; + case R128_PM4_192BM: info->CCEFifoSize = 192; break; + case R128_PM4_128PIO_64INDBM: info->CCEFifoSize = 128; break; + case R128_PM4_128BM_64INDBM: info->CCEFifoSize = 128; break; + case R128_PM4_64PIO_128INDBM: info->CCEFifoSize = 64; break; + case R128_PM4_64BM_128INDBM: info->CCEFifoSize = 64; break; + case R128_PM4_64PIO_64VCBM_64INDBM: info->CCEFifoSize = 64; break; + case R128_PM4_64BM_64VCBM_64INDBM: info->CCEFifoSize = 64; break; + case R128_PM4_64PIO_64VCPIO_64INDPIO: info->CCEFifoSize = 64; break; + } + + /* Make sure the CCE is on for the X server */ + R128CCE_START(ctx, info); +} + + +static int R128MemoryInit(const DRIDriverContext *ctx) +{ + R128InfoPtr info = ctx->driverPrivate; + int width_bytes = ctx->shared.virtualWidth * ctx->cpp; + int cpp = ctx->cpp; + int bufferSize = ((ctx->shared.virtualHeight * width_bytes + + R128_BUFFER_ALIGN) + & ~R128_BUFFER_ALIGN); + int depthSize = ((((ctx->shared.virtualHeight+15) & ~15) * width_bytes + + R128_BUFFER_ALIGN) + & ~R128_BUFFER_ALIGN); + int l; + + info->frontOffset = 0; + info->frontPitch = ctx->shared.virtualWidth; + + fprintf(stderr, + "Using %d MB AGP aperture\n", info->agpSize); + fprintf(stderr, + "Using %d MB for the ring buffer\n", info->ringSize); + fprintf(stderr, + "Using %d MB for vertex/indirect buffers\n", info->bufSize); + fprintf(stderr, + "Using %d MB for AGP textures\n", info->agpTexSize); + + /* Front, back and depth buffers - everything else texture?? + */ + info->textureSize = ctx->shared.fbSize - 2 * bufferSize - depthSize; + + if (info->textureSize < 0) + return 0; + + l = R128MinBits((info->textureSize-1) / R128_NR_TEX_REGIONS); + if (l < R128_LOG_TEX_GRANULARITY) l = R128_LOG_TEX_GRANULARITY; + + /* Round the texture size up to the nearest whole number of + * texture regions. Again, be greedy about this, don't + * round down. + */ + info->log2TexGran = l; + info->textureSize = (info->textureSize >> l) << l; + + /* Set a minimum usable local texture heap size. This will fit + * two 256x256x32bpp textures. + */ + if (info->textureSize < 512 * 1024) { + info->textureOffset = 0; + info->textureSize = 0; + } + + /* Reserve space for textures */ + info->textureOffset = ((ctx->shared.fbSize - info->textureSize + + R128_BUFFER_ALIGN) & + ~R128_BUFFER_ALIGN); + + /* Reserve space for the shared depth + * buffer. + */ + info->depthOffset = ((info->textureOffset - depthSize + + R128_BUFFER_ALIGN) & + ~R128_BUFFER_ALIGN); + info->depthPitch = ctx->shared.virtualWidth; + + info->backOffset = ((info->depthOffset - bufferSize + + R128_BUFFER_ALIGN) & + ~R128_BUFFER_ALIGN); + info->backPitch = ctx->shared.virtualWidth; + + + fprintf(stderr, + "Will use back buffer at offset 0x%x\n", + info->backOffset); + fprintf(stderr, + "Will use depth buffer at offset 0x%x\n", + info->depthOffset); + fprintf(stderr, + "Will use %d kb for textures at offset 0x%x\n", + info->textureSize/1024, info->textureOffset); + + return 1; +} + + +/* Initialize the screen-specific data structures for the DRI and the + Rage 128. This is the main entry point to the device-specific + initialization code. It calls device-independent DRI functions to + create the DRI data structures and initialize the DRI state. */ +static GLboolean R128DRIScreenInit(DRIDriverContext *ctx) +{ + R128InfoPtr info = ctx->driverPrivate; + R128DRIPtr pR128DRI; + int err, major, minor, patch; + drmVersionPtr version; + + switch (ctx->bpp) { + case 8: + /* These modes are not supported (yet). */ + case 15: + case 24: + fprintf(stderr, + "[dri] R128DRIScreenInit failed (depth %d not supported). " + "[dri] Disabling DRI.\n", ctx->bpp); + return GL_FALSE; + + /* Only 16 and 32 color depths are supports currently. */ + case 16: + case 32: + break; + } + + info->registerSize = ctx->MMIOSize; + ctx->shared.SAREASize = DRM_PAGE_SIZE; + + /* Note that drmOpen will try to load the kernel module, if needed. */ + ctx->drmFD = drmOpen("r128", NULL ); + if (ctx->drmFD < 0) { + fprintf(stderr, "[drm] drmOpen failed\n"); + return 0; + } + + /* Check the r128 DRM version */ + version = drmGetVersion(ctx->drmFD); + if (version) { + if (version->version_major != 2 || + version->version_minor < 2) { + /* incompatible drm version */ + fprintf(stderr, + "[dri] R128DRIScreenInit failed because of a version mismatch.\n" + "[dri] r128.o kernel module version is %d.%d.%d but version 2.2 or greater is needed.\n" + "[dri] Disabling the DRI.\n", + version->version_major, + version->version_minor, + version->version_patchlevel); + drmFreeVersion(version); + return GL_FALSE; + } + info->drmMinor = version->version_minor; + drmFreeVersion(version); + } + + 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%08lx\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%08lx to %p, size %d\n", + ctx->shared.hSAREA, ctx->pSAREA, ctx->shared.SAREASize); + + /* Need to AddMap the framebuffer and mmio regions here: + */ + if (drmAddMap( ctx->drmFD, + (drmHandle)ctx->FBStart, + ctx->FBSize, + DRM_FRAME_BUFFER, + 0, + &ctx->shared.hFrameBuffer) < 0) + { + fprintf(stderr, "[drm] drmAddMap framebuffer failed\n"); + return 0; + } + + fprintf(stderr, "[drm] framebuffer handle = 0x%08lx\n", + ctx->shared.hFrameBuffer); + + if (!R128MemoryInit(ctx)) + return GL_FALSE; + + /* Initialize AGP */ + if (!info->IsPCI && !R128DRIAgpInit(ctx)) { + info->IsPCI = GL_TRUE; + fprintf(stderr, + "[agp] AGP failed to initialize -- falling back to PCI mode.\n"); + fprintf(stderr, + "[agp] Make sure you have the agpgart kernel module loaded.\n"); + } + + /* Initialize PCIGART */ + if (info->IsPCI && !R128DRIPciInit(ctx)) { + return GL_FALSE; + } + + /* DRIScreenInit doesn't add all the + common mappings. Add additional + mappings here. */ + if (!R128DRIMapInit(ctx)) { + return GL_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 kernel data structures */ + if (!R128DRIKernelInit(ctx)) { + return GL_FALSE; + } + + /* Initialize the vertex buffers list */ + if (!R128DRIBufInit(ctx)) { + return GL_FALSE; + } + + /* Initialize IRQ */ + R128DRIIrqInit(ctx); + + /* Initialize and start the CCE if required */ + R128DRICCEInit(ctx); + + /* 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. + */ + memset((char *)ctx->FBAddress + info->frontOffset, + 0, + info->frontPitch * ctx->cpp * ctx->shared.virtualHeight ); + + memset((char *)ctx->FBAddress + info->backOffset, + 0, + info->backPitch * ctx->cpp * ctx->shared.virtualHeight ); + + R128SAREAPrivPtr pSAREAPriv; + pSAREAPriv = (R128SAREAPrivPtr)(((char*)ctx->pSAREA) + + sizeof(XF86DRISAREARec)); + memset(pSAREAPriv, 0, sizeof(*pSAREAPriv)); + + /* This is the struct passed to radeon_dri.so for its initialization */ + ctx->driverClientMsg = malloc(sizeof(R128DRIRec)); + ctx->driverClientMsgSize = sizeof(R128DRIRec); + + pR128DRI = (R128DRIPtr)ctx->driverClientMsg; + pR128DRI->deviceID = info->Chipset; + pR128DRI->width = ctx->shared.virtualWidth; + pR128DRI->height = ctx->shared.virtualHeight; + pR128DRI->depth = ctx->bpp; + pR128DRI->bpp = ctx->bpp; + + pR128DRI->IsPCI = info->IsPCI; + pR128DRI->AGPMode = info->agpMode; + + pR128DRI->frontOffset = info->frontOffset; + pR128DRI->frontPitch = info->frontPitch; + pR128DRI->backOffset = info->backOffset; + pR128DRI->backPitch = info->backPitch; + pR128DRI->depthOffset = info->depthOffset; + pR128DRI->depthPitch = info->depthPitch; + pR128DRI->spanOffset = info->spanOffset; + pR128DRI->textureOffset = info->textureOffset; + pR128DRI->textureSize = info->textureSize; + pR128DRI->log2TexGran = info->log2TexGran; + + pR128DRI->registerHandle = info->registerHandle; + pR128DRI->registerSize = info->registerSize; + + pR128DRI->agpTexHandle = info->agpTexHandle; + pR128DRI->agpTexMapSize = info->agpTexMapSize; + pR128DRI->log2AGPTexGran = info->log2AGPTexGran; + pR128DRI->agpTexOffset = info->agpTexStart; + pR128DRI->sarea_priv_offset = sizeof(XF86DRISAREARec); + + return GL_TRUE; +} + +/* The screen is being closed, so clean up any state and free any + resources used by the DRI. */ +void R128DRICloseScreen(const DRIDriverContext *ctx) +{ + R128InfoPtr info = ctx->driverPrivate; + drmR128Init drmInfo; + + /* Stop the CCE if it is still in use */ + R128CCE_STOP(ctx, info); + + if (info->irq) { + drmCtlUninstHandler(ctx->drmFD); + info->irq = 0; + } + + /* De-allocate vertex buffers */ + if (info->buffers) { + drmUnmapBufs(info->buffers); + info->buffers = NULL; + } + + /* De-allocate all kernel resources */ + memset(&drmInfo, 0, sizeof(drmR128Init)); + drmInfo.func = DRM_R128_CLEANUP_CCE; + drmCommandWrite(ctx->drmFD, DRM_R128_INIT, + &drmInfo, sizeof(drmR128Init)); + + /* De-allocate all AGP resources */ + if (info->agpTex) { + drmUnmap(info->agpTex, info->agpTexMapSize); + info->agpTex = NULL; + } + if (info->buf) { + drmUnmap(info->buf, info->bufMapSize); + info->buf = NULL; + } + if (info->ringReadPtr) { + drmUnmap(info->ringReadPtr, info->ringReadMapSize); + info->ringReadPtr = NULL; + } + if (info->ring) { + drmUnmap(info->ring, info->ringMapSize); + info->ring = NULL; + } + if (info->agpMemHandle != DRM_AGP_NO_HANDLE) { + drmAgpUnbind(ctx->drmFD, info->agpMemHandle); + drmAgpFree(ctx->drmFD, info->agpMemHandle); + info->agpMemHandle = 0; + drmAgpRelease(ctx->drmFD); + } + if (info->pciMemHandle) { + drmScatterGatherFree(ctx->drmFD, info->pciMemHandle); + info->pciMemHandle = 0; + } +} + +static GLboolean R128PreInitDRI(const DRIDriverContext *ctx) +{ + R128InfoPtr info = ctx->driverPrivate; + + /*info->CCEMode = R128_DEFAULT_CCE_PIO_MODE;*/ + info->CCEMode = R128_DEFAULT_CCE_BM_MODE; + info->CCESecure = GL_TRUE; + + info->agpMode = R128_DEFAULT_AGP_MODE; + info->agpSize = R128_DEFAULT_AGP_SIZE; + info->ringSize = R128_DEFAULT_RING_SIZE; + info->bufSize = R128_DEFAULT_BUFFER_SIZE; + info->agpTexSize = R128_DEFAULT_AGP_TEX_SIZE; + + info->CCEusecTimeout = R128_DEFAULT_CCE_TIMEOUT; + + return GL_TRUE; +} + +/** + * \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 R128ScreenInit() for the screen initialization. + * + * Before exiting clears the framebuffer memory accessing it directly. + */ +static int R128InitFBDev( DRIDriverContext *ctx ) +{ + R128InfoPtr info = calloc(1, sizeof(*info)); + + { + 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->driverPrivate = (void *)info; + + info->Chipset = ctx->chipset; + + switch (info->Chipset) { + case PCI_DEVICE_ID_ATI_RAGE128_LE: + case PCI_DEVICE_ID_ATI_RAGE128_RE: + case PCI_DEVICE_ID_ATI_RAGE128_RK: + case PCI_DEVICE_ID_ATI_RAGE128_PD: + case PCI_DEVICE_ID_ATI_RAGE128_PP: + case PCI_DEVICE_ID_ATI_RAGE128_PR: + /* This is a PCI card */ + info->IsPCI = GL_TRUE; + break; + default: + /* This is an AGP card */ + info->IsPCI = GL_FALSE; + break; + } + + info->frontPitch = ctx->shared.virtualWidth; + info->LinearAddr = ctx->FBStart & 0xfc000000; + + if (!R128PreInitDRI(ctx)) + return 0; + + if (!R128DRIScreenInit(ctx)) + 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 R128HaltFBDev( DRIDriverContext *ctx ) +{ + drmUnmap( ctx->pSAREA, ctx->shared.SAREASize ); + drmClose(ctx->drmFD); + + if (ctx->driverPrivate) { + free(ctx->driverPrivate); + ctx->driverPrivate = 0; + } +} + + +/** + * \brief Validate the fbdev mode. + * + * \param ctx display handle. + * + * \return one on success, or zero on failure. + * + * Saves some registers and returns 1. + * + * \sa R128PostValidateMode(). + */ +static int R128ValidateMode( 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 R128ValidateMode(). + */ +static int R128PostValidateMode( const DRIDriverContext *ctx ) +{ + return 1; +} + + +/** + * \brief Shutdown the drawing engine. + * + * \param ctx display handle + * + * Turns off the command processor engine & restores the graphics card + * to a state that fbdev understands. + */ +static int R128EngineShutdown( const DRIDriverContext *ctx ) +{ + return 1; +} + +/** + * \brief Restore the drawing engine. + * + * \param ctx display handle + * + * Resets the graphics card and sets initial values for several registers of + * the card's drawing engine. + * + * Turns on the R128 command processor engine (i.e., the ringbuffer). + */ +static int R128EngineRestore( const DRIDriverContext *ctx ) +{ + return 1; +} + + +/** + * \brief Exported driver interface for Mini GLX. + * + * \sa DRIDriverRec. + */ +const struct DRIDriverRec __driDriver = { + R128InitContextModes, + R128ValidateMode, + R128PostValidateMode, + R128InitFBDev, + R128HaltFBDev, + R128EngineShutdown, + R128EngineRestore, + 0, +}; diff --git a/src/mesa/drivers/dri/r128/server/r128_dri.h b/src/mesa/drivers/dri/r128/server/r128_dri.h new file mode 100644 index 0000000000..80f94ded68 --- /dev/null +++ b/src/mesa/drivers/dri/r128/server/r128_dri.h @@ -0,0 +1,103 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_dri.h,v 1.7 2002/10/30 12:52:12 alanh Exp $ */ +/* + * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, + * Precision Insight, Inc., Cedar Park, Texas, and + * VA Linux Systems Inc., Fremont, California. + * + * 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, sublicense, 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, PRECISION INSIGHT, 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Rickard E. Faith <faith@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef _R128_DRI_ +#define _R128_DRI_ + +#include "xf86drm.h" +#include "r128_common.h" + +/* DRI Driver defaults */ +#define R128_DEFAULT_CCE_PIO_MODE R128_PM4_64PIO_64VCBM_64INDBM +#define R128_DEFAULT_CCE_BM_MODE R128_PM4_64BM_64VCBM_64INDBM +#define R128_DEFAULT_AGP_MODE 1 +#define R128_DEFAULT_AGP_SIZE 8 /* MB (must be a power of 2 and > 4MB) */ +#define R128_DEFAULT_RING_SIZE 1 /* MB (must be page aligned) */ +#define R128_DEFAULT_BUFFER_SIZE 2 /* MB (must be page aligned) */ +#define R128_DEFAULT_AGP_TEX_SIZE 1 /* MB (must be page aligned) */ + +#define R128_DEFAULT_CCE_TIMEOUT 10000 /* usecs */ + +#define R128_AGP_MAX_MODE 4 +#define R128_BUFFER_ALIGN 0x00000fff + +#define R128_CARD_TYPE_R128 1 +#define R128_CARD_TYPE_R128_PRO 2 +#define R128_CARD_TYPE_R128_MOBILITY 3 + +#define R128CCE_USE_RING_BUFFER(m) \ +(((m) == R128_PM4_192BM) || \ + ((m) == R128_PM4_128BM_64INDBM) || \ + ((m) == R128_PM4_64BM_128INDBM) || \ + ((m) == R128_PM4_64BM_64VCBM_64INDBM)) + +typedef struct { + /* DRI screen private data */ + int deviceID; /* PCI device ID */ + int width; /* Width in pixels of display */ + int height; /* Height in scanlines of display */ + int depth; /* Depth of display (8, 15, 16, 24) */ + int bpp; /* Bit depth of display (8, 16, 24, 32) */ + + int IsPCI; /* Current card is a PCI card */ + int AGPMode; + + int frontOffset; /* Start of front buffer */ + int frontPitch; + int backOffset; /* Start of shared back buffer */ + int backPitch; + int depthOffset; /* Start of shared depth buffer */ + int depthPitch; + int spanOffset; /* Start of scratch spanline */ + int textureOffset;/* Start of texture data in frame buffer */ + int textureSize; + int log2TexGran; + + /* MMIO register data */ + drmHandle registerHandle; + drmSize registerSize; + + /* CCE AGP Texture data */ + drmHandle agpTexHandle; + drmSize agpTexMapSize; + int log2AGPTexGran; + int agpTexOffset; + unsigned int sarea_priv_offset; +} R128DRIRec, *R128DRIPtr; + +#endif diff --git a/src/mesa/drivers/dri/r128/server/r128_macros.h b/src/mesa/drivers/dri/r128/server/r128_macros.h new file mode 100644 index 0000000000..93b7feb02c --- /dev/null +++ b/src/mesa/drivers/dri/r128/server/r128_macros.h @@ -0,0 +1,135 @@ +/** + * \file server/R128_macros.h + * \brief Macros for R128 MMIO operation. + * + * \authors Kevin E. Martin <martin@xfree86.org> + * \authors Rickard E. Faith <faith@valinux.com> + * \authors Alan Hourihane <alanh@fairlite.demon.co.uk> + */ + +/* + * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and + * VA Linux Systems Inc., Fremont, California. + * + * 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, sublicense, 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/ati/R128_reg.h,v 1.20 2002/10/12 01:38:07 martin Exp $ */ + +#ifndef _R128_MACROS_H_ +#define _R128_MACROS_H_ + + + +# define MMIO_IN8(base, offset) \ + *(volatile unsigned char *)(((unsigned char*)(base)) + (offset)) +# define MMIO_IN16(base, offset) \ + *(volatile unsigned short *)(void *)(((unsigned char*)(base)) + (offset)) +# define MMIO_IN32(base, offset) \ + *(volatile unsigned int *)(void *)(((unsigned char*)(base)) + (offset)) +# define MMIO_OUT8(base, offset, val) \ + *(volatile unsigned char *)(((unsigned char*)(base)) + (offset)) = (val) +# define MMIO_OUT16(base, offset, val) \ + *(volatile unsigned short *)(void *)(((unsigned char*)(base)) + (offset)) = (val) +# define MMIO_OUT32(base, offset, val) \ + *(volatile unsigned int *)(void *)(((unsigned char*)(base)) + (offset)) = (val) + + + /* Memory mapped register access macros */ +#define INREG8(addr) MMIO_IN8(R128MMIO, addr) +#define INREG16(addr) MMIO_IN16(R128MMIO, addr) +#define INREG(addr) MMIO_IN32(R128MMIO, addr) +#define OUTREG8(addr, val) MMIO_OUT8(R128MMIO, addr, val) +#define OUTREG16(addr, val) MMIO_OUT16(R128MMIO, addr, val) +#define OUTREG(addr, val) MMIO_OUT32(R128MMIO, addr, val) + +#define ADDRREG(addr) ((volatile GLuint *)(pointer)(R128MMIO + (addr))) + + +#define OUTREGP(addr, val, mask) \ +do { \ + GLuint tmp = INREG(addr); \ + tmp &= (mask); \ + tmp |= (val); \ + OUTREG(addr, tmp); \ +} while (0) + +#define INPLL(dpy, addr) r128INPLL(dpy, addr) + +#define OUTPLL(addr, val) \ +do { \ + OUTREG8(R128_CLOCK_CNTL_INDEX, (((addr) & 0x3f) | \ + R128_PLL_WR_EN)); \ + OUTREG(R128_CLOCK_CNTL_DATA, val); \ +} while (0) + +#define OUTPLLP(dpy, addr, val, mask) \ +do { \ + GLuint tmp = INPLL(dpy, addr); \ + tmp &= (mask); \ + tmp |= (val); \ + OUTPLL(addr, tmp); \ +} while (0) + +#define OUTPAL_START(idx) \ +do { \ + OUTREG8(R128_PALETTE_INDEX, (idx)); \ +} while (0) + +#define OUTPAL_NEXT(r, g, b) \ +do { \ + OUTREG(R128_PALETTE_DATA, ((r) << 16) | ((g) << 8) | (b)); \ +} while (0) + +#define OUTPAL_NEXT_CARD32(v) \ +do { \ + OUTREG(R128_PALETTE_DATA, (v & 0x00ffffff)); \ +} while (0) + +#define OUTPAL(idx, r, g, b) \ +do { \ + OUTPAL_START((idx)); \ + OUTPAL_NEXT((r), (g), (b)); \ +} while (0) + +#define INPAL_START(idx) \ +do { \ + OUTREG(R128_PALETTE_INDEX, (idx) << 16); \ +} while (0) + +#define INPAL_NEXT() INREG(R128_PALETTE_DATA) + +#define PAL_SELECT(idx) \ +do { \ + if (!idx) { \ + OUTREG(R128_DAC_CNTL2, INREG(R128_DAC_CNTL2) & \ + (GLuint)~R128_DAC2_PALETTE_ACC_CTL); \ + } else { \ + OUTREG(R128_DAC_CNTL2, INREG(R128_DAC_CNTL2) | \ + R128_DAC2_PALETTE_ACC_CTL); \ + } \ +} while (0) + + +#endif diff --git a/src/mesa/drivers/dri/r128/server/r128_reg.h b/src/mesa/drivers/dri/r128/server/r128_reg.h new file mode 100644 index 0000000000..7ec4004492 --- /dev/null +++ b/src/mesa/drivers/dri/r128/server/r128_reg.h @@ -0,0 +1,1431 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_reg.h,v 1.15 2002/12/16 16:19:11 dawes Exp $ */ +/* + * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, + * Precision Insight, Inc., Cedar Park, Texas, and + * VA Linux Systems Inc., Fremont, California. + * + * 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, sublicense, 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, PRECISION INSIGHT, 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. + */ + +/* + * Authors: + * Rickard E. Faith <faith@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + * References: + * + * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical + * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April + * 1999. + * + * RAGE 128 Software Development Manual (Technical Reference Manual P/N + * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. + * + */ + +#ifndef _R128_REG_H_ +#define _R128_REG_H_ + +#define R128_ADAPTER_ID 0x0f2c /* PCI */ +#define R128_AGP_APER_OFFSET 0x0178 +#define R128_AGP_BASE 0x0170 +#define R128_AGP_CNTL 0x0174 +# define R128_AGP_APER_SIZE_256MB (0x00 << 0) +# define R128_AGP_APER_SIZE_128MB (0x20 << 0) +# define R128_AGP_APER_SIZE_64MB (0x30 << 0) +# define R128_AGP_APER_SIZE_32MB (0x38 << 0) +# define R128_AGP_APER_SIZE_16MB (0x3c << 0) +# define R128_AGP_APER_SIZE_8MB (0x3e << 0) +# define R128_AGP_APER_SIZE_4MB (0x3f << 0) +# define R128_AGP_APER_SIZE_MASK (0x3f << 0) +#define R128_AGP_CNTL_B 0x0b44 +#define R128_AGP_COMMAND 0x0f58 /* PCI */ +#define R128_AGP_PLL_CNTL 0x0010 /* PLL */ +#define R128_AGP_STATUS 0x0f54 /* PCI */ +# define R128_AGP_1X_MODE 0x01 +# define R128_AGP_2X_MODE 0x02 +# define R128_AGP_4X_MODE 0x04 +# define R128_AGP_MODE_MASK 0x07 +#define R128_AMCGPIO_A_REG 0x01a0 +#define R128_AMCGPIO_EN_REG 0x01a8 +#define R128_AMCGPIO_MASK 0x0194 +#define R128_AMCGPIO_Y_REG 0x01a4 +#define R128_ATTRDR 0x03c1 /* VGA */ +#define R128_ATTRDW 0x03c0 /* VGA */ +#define R128_ATTRX 0x03c0 /* VGA */ +#define R128_AUX_SC_CNTL 0x1660 +# define R128_AUX1_SC_EN (1 << 0) +# define R128_AUX1_SC_MODE_OR (0 << 1) +# define R128_AUX1_SC_MODE_NAND (1 << 1) +# define R128_AUX2_SC_EN (1 << 2) +# define R128_AUX2_SC_MODE_OR (0 << 3) +# define R128_AUX2_SC_MODE_NAND (1 << 3) +# define R128_AUX3_SC_EN (1 << 4) +# define R128_AUX3_SC_MODE_OR (0 << 5) +# define R128_AUX3_SC_MODE_NAND (1 << 5) +#define R128_AUX1_SC_BOTTOM 0x1670 +#define R128_AUX1_SC_LEFT 0x1664 +#define R128_AUX1_SC_RIGHT 0x1668 +#define R128_AUX1_SC_TOP 0x166c +#define R128_AUX2_SC_BOTTOM 0x1680 +#define R128_AUX2_SC_LEFT 0x1674 +#define R128_AUX2_SC_RIGHT 0x1678 +#define R128_AUX2_SC_TOP 0x167c +#define R128_AUX3_SC_BOTTOM 0x1690 +#define R128_AUX3_SC_LEFT 0x1684 +#define R128_AUX3_SC_RIGHT 0x1688 +#define R128_AUX3_SC_TOP 0x168c +#define R128_AUX_WINDOW_HORZ_CNTL 0x02d8 +#define R128_AUX_WINDOW_VERT_CNTL 0x02dc + +#define R128_BASE_CODE 0x0f0b +#define R128_BIOS_0_SCRATCH 0x0010 +#define R128_BIOS_1_SCRATCH 0x0014 +#define R128_BIOS_2_SCRATCH 0x0018 +#define R128_BIOS_3_SCRATCH 0x001c +#define R128_BIOS_4_SCRATCH 0x0020 +#define R128_BIOS_5_SCRATCH 0x0024 +# define R128_BIOS_DISPLAY_FP (1 << 0) +# define R128_BIOS_DISPLAY_CRT (2 << 0) +# define R128_BIOS_DISPLAY_FP_CRT (3 << 0) +#define R128_BIOS_6_SCRATCH 0x0028 +#define R128_BIOS_7_SCRATCH 0x002c +#define R128_BIOS_ROM 0x0f30 /* PCI */ +#define R128_BIST 0x0f0f /* PCI */ +#define R128_BM_CHUNK_0_VAL 0x0a18 +# define R128_BM_PTR_FORCE_TO_PCI (1 << 21) +# define R128_BM_PM4_RD_FORCE_TO_PCI (1 << 22) +# define R128_BM_GLOBAL_FORCE_TO_PCI (1 << 23) +#define R128_BRUSH_DATA0 0x1480 +#define R128_BRUSH_DATA1 0x1484 +#define R128_BRUSH_DATA10 0x14a8 +#define R128_BRUSH_DATA11 0x14ac +#define R128_BRUSH_DATA12 0x14b0 +#define R128_BRUSH_DATA13 0x14b4 +#define R128_BRUSH_DATA14 0x14b8 +#define R128_BRUSH_DATA15 0x14bc +#define R128_BRUSH_DATA16 0x14c0 +#define R128_BRUSH_DATA17 0x14c4 +#define R128_BRUSH_DATA18 0x14c8 +#define R128_BRUSH_DATA19 0x14cc +#define R128_BRUSH_DATA2 0x1488 +#define R128_BRUSH_DATA20 0x14d0 +#define R128_BRUSH_DATA21 0x14d4 +#define R128_BRUSH_DATA22 0x14d8 +#define R128_BRUSH_DATA23 0x14dc +#define R128_BRUSH_DATA24 0x14e0 +#define R128_BRUSH_DATA25 0x14e4 +#define R128_BRUSH_DATA26 0x14e8 +#define R128_BRUSH_DATA27 0x14ec +#define R128_BRUSH_DATA28 0x14f0 +#define R128_BRUSH_DATA29 0x14f4 +#define R128_BRUSH_DATA3 0x148c +#define R128_BRUSH_DATA30 0x14f8 +#define R128_BRUSH_DATA31 0x14fc +#define R128_BRUSH_DATA32 0x1500 +#define R128_BRUSH_DATA33 0x1504 +#define R128_BRUSH_DATA34 0x1508 +#define R128_BRUSH_DATA35 0x150c +#define R128_BRUSH_DATA36 0x1510 +#define R128_BRUSH_DATA37 0x1514 +#define R128_BRUSH_DATA38 0x1518 +#define R128_BRUSH_DATA39 0x151c +#define R128_BRUSH_DATA4 0x1490 +#define R128_BRUSH_DATA40 0x1520 +#define R128_BRUSH_DATA41 0x1524 +#define R128_BRUSH_DATA42 0x1528 +#define R128_BRUSH_DATA43 0x152c +#define R128_BRUSH_DATA44 0x1530 +#define R128_BRUSH_DATA45 0x1534 +#define R128_BRUSH_DATA46 0x1538 +#define R128_BRUSH_DATA47 0x153c +#define R128_BRUSH_DATA48 0x1540 +#define R128_BRUSH_DATA49 0x1544 +#define R128_BRUSH_DATA5 0x1494 +#define R128_BRUSH_DATA50 0x1548 +#define R128_BRUSH_DATA51 0x154c +#define R128_BRUSH_DATA52 0x1550 +#define R128_BRUSH_DATA53 0x1554 +#define R128_BRUSH_DATA54 0x1558 +#define R128_BRUSH_DATA55 0x155c +#define R128_BRUSH_DATA56 0x1560 +#define R128_BRUSH_DATA57 0x1564 +#define R128_BRUSH_DATA58 0x1568 +#define R128_BRUSH_DATA59 0x156c +#define R128_BRUSH_DATA6 0x1498 +#define R128_BRUSH_DATA60 0x1570 +#define R128_BRUSH_DATA61 0x1574 +#define R128_BRUSH_DATA62 0x1578 +#define R128_BRUSH_DATA63 0x157c +#define R128_BRUSH_DATA7 0x149c +#define R128_BRUSH_DATA8 0x14a0 +#define R128_BRUSH_DATA9 0x14a4 +#define R128_BRUSH_SCALE 0x1470 +#define R128_BRUSH_Y_X 0x1474 +#define R128_BUS_CNTL 0x0030 +# define R128_BUS_MASTER_DIS (1 << 6) +# define R128_BUS_RD_DISCARD_EN (1 << 24) +# define R128_BUS_RD_ABORT_EN (1 << 25) +# define R128_BUS_MSTR_DISCONNECT_EN (1 << 28) +# define R128_BUS_WRT_BURST (1 << 29) +# define R128_BUS_READ_BURST (1 << 30) +#define R128_BUS_CNTL1 0x0034 +# define R128_BUS_WAIT_ON_LOCK_EN (1 << 4) + +#define R128_CACHE_CNTL 0x1724 +#define R128_CACHE_LINE 0x0f0c /* PCI */ +#define R128_CAP0_TRIG_CNTL 0x0950 /* ? */ +#define R128_CAP1_TRIG_CNTL 0x09c0 /* ? */ +#define R128_CAPABILITIES_ID 0x0f50 /* PCI */ +#define R128_CAPABILITIES_PTR 0x0f34 /* PCI */ +#define R128_CLK_PIN_CNTL 0x0001 /* PLL */ +#define R128_CLOCK_CNTL_DATA 0x000c +#define R128_CLOCK_CNTL_INDEX 0x0008 +# define R128_PLL_WR_EN (1 << 7) +# define R128_PLL_DIV_SEL (3 << 8) +#define R128_CLR_CMP_CLR_3D 0x1a24 +#define R128_CLR_CMP_CLR_DST 0x15c8 +#define R128_CLR_CMP_CLR_SRC 0x15c4 +#define R128_CLR_CMP_CNTL 0x15c0 +# define R128_SRC_CMP_EQ_COLOR (4 << 0) +# define R128_SRC_CMP_NEQ_COLOR (5 << 0) +# define R128_CLR_CMP_SRC_SOURCE (1 << 24) +#define R128_CLR_CMP_MASK 0x15cc +# define R128_CLR_CMP_MSK 0xffffffff +#define R128_CLR_CMP_MASK_3D 0x1A28 +#define R128_COMMAND 0x0f04 /* PCI */ +#define R128_COMPOSITE_SHADOW_ID 0x1a0c +#define R128_CONFIG_APER_0_BASE 0x0100 +#define R128_CONFIG_APER_1_BASE 0x0104 +#define R128_CONFIG_APER_SIZE 0x0108 +#define R128_CONFIG_BONDS 0x00e8 +#define R128_CONFIG_CNTL 0x00e0 +# define APER_0_BIG_ENDIAN_16BPP_SWAP (1 << 0) +# define APER_0_BIG_ENDIAN_32BPP_SWAP (2 << 0) +#define R128_CONFIG_MEMSIZE 0x00f8 +#define R128_CONFIG_MEMSIZE_EMBEDDED 0x0114 +#define R128_CONFIG_REG_1_BASE 0x010c +#define R128_CONFIG_REG_APER_SIZE 0x0110 +#define R128_CONFIG_XSTRAP 0x00e4 +#define R128_CONSTANT_COLOR_C 0x1d34 +# define R128_CONSTANT_COLOR_MASK 0x00ffffff +# define R128_CONSTANT_COLOR_ONE 0x00ffffff +# define R128_CONSTANT_COLOR_ZERO 0x00000000 +#define R128_CRC_CMDFIFO_ADDR 0x0740 +#define R128_CRC_CMDFIFO_DOUT 0x0744 +#define R128_CRTC_CRNT_FRAME 0x0214 +#define R128_CRTC_DEBUG 0x021c +#define R128_CRTC_EXT_CNTL 0x0054 +# define R128_CRTC_VGA_XOVERSCAN (1 << 0) +# define R128_VGA_ATI_LINEAR (1 << 3) +# define R128_XCRT_CNT_EN (1 << 6) +# define R128_CRTC_HSYNC_DIS (1 << 8) +# define R128_CRTC_VSYNC_DIS (1 << 9) +# define R128_CRTC_DISPLAY_DIS (1 << 10) +# define R128_CRTC_CRT_ON (1 << 15) +# define R128_FP_OUT_EN (1 << 22) +# define R128_FP_ACTIVE (1 << 23) +#define R128_CRTC_EXT_CNTL_DPMS_BYTE 0x0055 +# define R128_CRTC_HSYNC_DIS_BYTE (1 << 0) +# define R128_CRTC_VSYNC_DIS_BYTE (1 << 1) +# define R128_CRTC_DISPLAY_DIS_BYTE (1 << 2) +#define R128_CRTC_GEN_CNTL 0x0050 +# define R128_CRTC_DBL_SCAN_EN (1 << 0) +# define R128_CRTC_INTERLACE_EN (1 << 1) +# define R128_CRTC_CSYNC_EN (1 << 4) +# define R128_CRTC_CUR_EN (1 << 16) +# define R128_CRTC_CUR_MODE_MASK (7 << 17) +# define R128_CRTC_ICON_EN (1 << 20) +# define R128_CRTC_EXT_DISP_EN (1 << 24) +# define R128_CRTC_EN (1 << 25) +# define R128_CRTC_DISP_REQ_EN_B (1 << 26) +#define R128_CRTC_GUI_TRIG_VLINE 0x0218 +#define R128_CRTC_H_SYNC_STRT_WID 0x0204 +# define R128_CRTC_H_SYNC_STRT_PIX (0x07 << 0) +# define R128_CRTC_H_SYNC_STRT_CHAR (0x1ff << 3) +# define R128_CRTC_H_SYNC_STRT_CHAR_SHIFT 3 +# define R128_CRTC_H_SYNC_WID (0x3f << 16) +# define R128_CRTC_H_SYNC_WID_SHIFT 16 +# define R128_CRTC_H_SYNC_POL (1 << 23) +#define R128_CRTC_H_TOTAL_DISP 0x0200 +# define R128_CRTC_H_TOTAL (0x01ff << 0) +# define R128_CRTC_H_TOTAL_SHIFT 0 +# define R128_CRTC_H_DISP (0x00ff << 16) +# define R128_CRTC_H_DISP_SHIFT 16 +#define R128_CRTC_OFFSET 0x0224 +#define R128_CRTC_OFFSET_CNTL 0x0228 +#define R128_CRTC_PITCH 0x022c +#define R128_CRTC_STATUS 0x005c +# define R128_CRTC_VBLANK_SAVE (1 << 1) +#define R128_CRTC_V_SYNC_STRT_WID 0x020c +# define R128_CRTC_V_SYNC_STRT (0x7ff << 0) +# define R128_CRTC_V_SYNC_STRT_SHIFT 0 +# define R128_CRTC_V_SYNC_WID (0x1f << 16) +# define R128_CRTC_V_SYNC_WID_SHIFT 16 +# define R128_CRTC_V_SYNC_POL (1 << 23) +#define R128_CRTC_V_TOTAL_DISP 0x0208 +# define R128_CRTC_V_TOTAL (0x07ff << 0) +# define R128_CRTC_V_TOTAL_SHIFT 0 +# define R128_CRTC_V_DISP (0x07ff << 16) +# define R128_CRTC_V_DISP_SHIFT 16 +#define R128_CRTC_VLINE_CRNT_VLINE 0x0210 +# define R128_CRTC_CRNT_VLINE_MASK (0x7ff << 16) +#define R128_CRTC2_CRNT_FRAME 0x0314 +#define R128_CRTC2_DEBUG 0x031c +#define R128_CRTC2_GEN_CNTL 0x03f8 +#define R128_CRTC2_GUI_TRIG_VLINE 0x0318 +#define R128_CRTC2_H_SYNC_STRT_WID 0x0304 +#define R128_CRTC2_H_TOTAL_DISP 0x0300 +#define R128_CRTC2_OFFSET 0x0324 +#define R128_CRTC2_OFFSET_CNTL 0x0328 +#define R128_CRTC2_PITCH 0x032c +#define R128_CRTC2_STATUS 0x03fc +#define R128_CRTC2_V_SYNC_STRT_WID 0x030c +#define R128_CRTC2_V_TOTAL_DISP 0x0308 +#define R128_CRTC2_VLINE_CRNT_VLINE 0x0310 +#define R128_CRTC8_DATA 0x03d5 /* VGA, 0x3b5 */ +#define R128_CRTC8_IDX 0x03d4 /* VGA, 0x3b4 */ +#define R128_CUR_CLR0 0x026c +#define R128_CUR_CLR1 0x0270 +#define R128_CUR_HORZ_VERT_OFF 0x0268 +#define R128_CUR_HORZ_VERT_POSN 0x0264 +#define R128_CUR_OFFSET 0x0260 +# define R128_CUR_LOCK (1 << 31) + +#define R128_DAC_CNTL 0x0058 +# define R128_DAC_RANGE_CNTL (3 << 0) +# define R128_DAC_BLANKING (1 << 2) +# define R128_DAC_CRT_SEL_CRTC2 (1 << 4) +# define R128_DAC_PALETTE_ACC_CTL (1 << 5) +# define R128_DAC_8BIT_EN (1 << 8) +# define R128_DAC_VGA_ADR_EN (1 << 13) +# define R128_DAC_MASK_ALL (0xff << 24) +#define R128_DAC_CRC_SIG 0x02cc +#define R128_DAC_DATA 0x03c9 /* VGA */ +#define R128_DAC_MASK 0x03c6 /* VGA */ +#define R128_DAC_R_INDEX 0x03c7 /* VGA */ +#define R128_DAC_W_INDEX 0x03c8 /* VGA */ +#define R128_DDA_CONFIG 0x02e0 +#define R128_DDA_ON_OFF 0x02e4 +#define R128_DEFAULT_OFFSET 0x16e0 +#define R128_DEFAULT_PITCH 0x16e4 +#define R128_DEFAULT_SC_BOTTOM_RIGHT 0x16e8 +# define R128_DEFAULT_SC_RIGHT_MAX (0x1fff << 0) +# define R128_DEFAULT_SC_BOTTOM_MAX (0x1fff << 16) +#define R128_DESTINATION_3D_CLR_CMP_VAL 0x1820 +#define R128_DESTINATION_3D_CLR_CMP_MSK 0x1824 +#define R128_DEVICE_ID 0x0f02 /* PCI */ +#define R128_DP_BRUSH_BKGD_CLR 0x1478 +#define R128_DP_BRUSH_FRGD_CLR 0x147c +#define R128_DP_CNTL 0x16c0 +# define R128_DST_X_LEFT_TO_RIGHT (1 << 0) +# define R128_DST_Y_TOP_TO_BOTTOM (1 << 1) +#define R128_DP_CNTL_XDIR_YDIR_YMAJOR 0x16d0 +# define R128_DST_Y_MAJOR (1 << 2) +# define R128_DST_Y_DIR_TOP_TO_BOTTOM (1 << 15) +# define R128_DST_X_DIR_LEFT_TO_RIGHT (1 << 31) +#define R128_DP_DATATYPE 0x16c4 +# define R128_HOST_BIG_ENDIAN_EN (1 << 29) +#define R128_DP_GUI_MASTER_CNTL 0x146c +# define R128_GMC_SRC_PITCH_OFFSET_CNTL (1 << 0) +# define R128_GMC_DST_PITCH_OFFSET_CNTL (1 << 1) +# define R128_GMC_SRC_CLIPPING (1 << 2) +# define R128_GMC_DST_CLIPPING (1 << 3) +# define R128_GMC_BRUSH_DATATYPE_MASK (0x0f << 4) +# define R128_GMC_BRUSH_8X8_MONO_FG_BG (0 << 4) +# define R128_GMC_BRUSH_8X8_MONO_FG_LA (1 << 4) +# define R128_GMC_BRUSH_1X8_MONO_FG_BG (4 << 4) +# define R128_GMC_BRUSH_1X8_MONO_FG_LA (5 << 4) +# define R128_GMC_BRUSH_32x1_MONO_FG_BG (6 << 4) +# define R128_GMC_BRUSH_32x1_MONO_FG_LA (7 << 4) +# define R128_GMC_BRUSH_32x32_MONO_FG_BG (8 << 4) +# define R128_GMC_BRUSH_32x32_MONO_FG_LA (9 << 4) +# define R128_GMC_BRUSH_8x8_COLOR (10 << 4) +# define R128_GMC_BRUSH_1X8_COLOR (12 << 4) +# define R128_GMC_BRUSH_SOLID_COLOR (13 << 4) +# define R128_GMC_BRUSH_NONE (15 << 4) +# define R128_GMC_DST_8BPP_CI (2 << 8) +# define R128_GMC_DST_15BPP (3 << 8) +# define R128_GMC_DST_16BPP (4 << 8) +# define R128_GMC_DST_24BPP (5 << 8) +# define R128_GMC_DST_32BPP (6 << 8) +# define R128_GMC_DST_8BPP_RGB (7 << 8) +# define R128_GMC_DST_Y8 (8 << 8) +# define R128_GMC_DST_RGB8 (9 << 8) +# define R128_GMC_DST_VYUY (11 << 8) +# define R128_GMC_DST_YVYU (12 << 8) +# define R128_GMC_DST_AYUV444 (14 << 8) +# define R128_GMC_DST_ARGB4444 (15 << 8) +# define R128_GMC_DST_DATATYPE_MASK (0x0f << 8) +# define R128_GMC_DST_DATATYPE_SHIFT 8 +# define R128_GMC_SRC_DATATYPE_MASK (3 << 12) +# define R128_GMC_SRC_DATATYPE_MONO_FG_BG (0 << 12) +# define R128_GMC_SRC_DATATYPE_MONO_FG_LA (1 << 12) +# define R128_GMC_SRC_DATATYPE_COLOR (3 << 12) +# define R128_GMC_BYTE_PIX_ORDER (1 << 14) +# define R128_GMC_BYTE_MSB_TO_LSB (0 << 14) +# define R128_GMC_BYTE_LSB_TO_MSB (1 << 14) +# define R128_GMC_CONVERSION_TEMP (1 << 15) +# define R128_GMC_CONVERSION_TEMP_6500 (0 << 15) +# define R128_GMC_CONVERSION_TEMP_9300 (1 << 15) +# define R128_GMC_ROP3_MASK (0xff << 16) +# define R128_DP_SRC_SOURCE_MASK (7 << 24) +# define R128_DP_SRC_SOURCE_MEMORY (2 << 24) +# define R128_DP_SRC_SOURCE_HOST_DATA (3 << 24) +# define R128_GMC_3D_FCN_EN (1 << 27) +# define R128_GMC_CLR_CMP_CNTL_DIS (1 << 28) +# define R128_GMC_AUX_CLIP_DIS (1 << 29) +# define R128_GMC_WR_MSK_DIS (1 << 30) +# define R128_GMC_LD_BRUSH_Y_X (1 << 31) +# define R128_ROP3_ZERO 0x00000000 +# define R128_ROP3_DSa 0x00880000 +# define R128_ROP3_SDna 0x00440000 +# define R128_ROP3_S 0x00cc0000 +# define R128_ROP3_DSna 0x00220000 +# define R128_ROP3_D 0x00aa0000 +# define R128_ROP3_DSx 0x00660000 +# define R128_ROP3_DSo 0x00ee0000 +# define R128_ROP3_DSon 0x00110000 +# define R128_ROP3_DSxn 0x00990000 +# define R128_ROP3_Dn 0x00550000 +# define R128_ROP3_SDno 0x00dd0000 +# define R128_ROP3_Sn 0x00330000 +# define R128_ROP3_DSno 0x00bb0000 +# define R128_ROP3_DSan 0x00770000 +# define R128_ROP3_ONE 0x00ff0000 +# define R128_ROP3_DPa 0x00a00000 +# define R128_ROP3_PDna 0x00500000 +# define R128_ROP3_P 0x00f00000 +# define R128_ROP3_DPna 0x000a0000 +# define R128_ROP3_D 0x00aa0000 +# define R128_ROP3_DPx 0x005a0000 +# define R128_ROP3_DPo 0x00fa0000 +# define R128_ROP3_DPon 0x00050000 +# define R128_ROP3_PDxn 0x00a50000 +# define R128_ROP3_PDno 0x00f50000 +# define R128_ROP3_Pn 0x000f0000 +# define R128_ROP3_DPno 0x00af0000 +# define R128_ROP3_DPan 0x005f0000 + + +#define R128_DP_GUI_MASTER_CNTL_C 0x1c84 +#define R128_DP_MIX 0x16c8 +#define R128_DP_SRC_BKGD_CLR 0x15dc +#define R128_DP_SRC_FRGD_CLR 0x15d8 +#define R128_DP_WRITE_MASK 0x16cc +#define R128_DST_BRES_DEC 0x1630 +#define R128_DST_BRES_ERR 0x1628 +#define R128_DST_BRES_INC 0x162c +#define R128_DST_BRES_LNTH 0x1634 +#define R128_DST_BRES_LNTH_SUB 0x1638 +#define R128_DST_HEIGHT 0x1410 +#define R128_DST_HEIGHT_WIDTH 0x143c +#define R128_DST_HEIGHT_WIDTH_8 0x158c +#define R128_DST_HEIGHT_WIDTH_BW 0x15b4 +#define R128_DST_HEIGHT_Y 0x15a0 +#define R128_DST_OFFSET 0x1404 +#define R128_DST_PITCH 0x1408 +#define R128_DST_PITCH_OFFSET 0x142c +#define R128_DST_PITCH_OFFSET_C 0x1c80 +# define R128_PITCH_SHIFT 21 +# define R128_DST_TILE (1 << 31) +#define R128_DST_WIDTH 0x140c +#define R128_DST_WIDTH_HEIGHT 0x1598 +#define R128_DST_WIDTH_X 0x1588 +#define R128_DST_WIDTH_X_INCY 0x159c +#define R128_DST_X 0x141c +#define R128_DST_X_SUB 0x15a4 +#define R128_DST_X_Y 0x1594 +#define R128_DST_Y 0x1420 +#define R128_DST_Y_SUB 0x15a8 +#define R128_DST_Y_X 0x1438 + +#define R128_EXT_MEM_CNTL 0x0144 + +#define R128_FCP_CNTL 0x0012 /* PLL */ +#define R128_FLUSH_1 0x1704 +#define R128_FLUSH_2 0x1708 +#define R128_FLUSH_3 0x170c +#define R128_FLUSH_4 0x1710 +#define R128_FLUSH_5 0x1714 +#define R128_FLUSH_6 0x1718 +#define R128_FLUSH_7 0x171c +#define R128_FOG_3D_TABLE_START 0x1810 +#define R128_FOG_3D_TABLE_END 0x1814 +#define R128_FOG_3D_TABLE_DENSITY 0x181c +#define R128_FOG_TABLE_INDEX 0x1a14 +#define R128_FOG_TABLE_DATA 0x1a18 +#define R128_FP_CRTC_H_TOTAL_DISP 0x0250 +#define R128_FP_CRTC_V_TOTAL_DISP 0x0254 +#define R128_FP_GEN_CNTL 0x0284 +# define R128_FP_FPON (1 << 0) +# define R128_FP_BLANK_DIS (1 << 1) +# define R128_FP_TDMS_EN (1 << 2) +# define R128_FP_DETECT_SENSE (1 << 8) +# define R128_FP_SEL_CRTC2 (1 << 13) +# define R128_FP_CRTC_DONT_SHADOW_VPAR (1 << 16) +# define R128_FP_CRTC_DONT_SHADOW_HEND (1 << 17) +# define R128_FP_CRTC_USE_SHADOW_VEND (1 << 18) +# define R128_FP_CRTC_USE_SHADOW_ROWCUR (1 << 19) +# define R128_FP_CRTC_HORZ_DIV2_EN (1 << 20) +# define R128_FP_CRTC_HOR_CRT_DIV2_DIS (1 << 21) +# define R128_FP_CRT_SYNC_SEL (1 << 23) +# define R128_FP_USE_SHADOW_EN (1 << 24) +#define R128_FP_H_SYNC_STRT_WID 0x02c4 +#define R128_FP_HORZ_STRETCH 0x028c +# define R128_HORZ_STRETCH_RATIO_MASK 0xffff +# define R128_HORZ_STRETCH_RATIO_SHIFT 0 +# define R128_HORZ_STRETCH_RATIO_MAX 4096 +# define R128_HORZ_PANEL_SIZE (0xff << 16) +# define R128_HORZ_PANEL_SHIFT 16 +# define R128_AUTO_HORZ_RATIO (0 << 24) +# define R128_HORZ_STRETCH_PIXREP (0 << 25) +# define R128_HORZ_STRETCH_BLEND (1 << 25) +# define R128_HORZ_STRETCH_ENABLE (1 << 26) +# define R128_HORZ_FP_LOOP_STRETCH (0x7 << 27) +# define R128_HORZ_STRETCH_RESERVED (1 << 30) +# define R128_HORZ_AUTO_RATIO_FIX_EN (1 << 31) + +#define R128_FP_PANEL_CNTL 0x0288 +# define R128_FP_DIGON (1 << 0) +# define R128_FP_BLON (1 << 1) +#define R128_FP_V_SYNC_STRT_WID 0x02c8 +#define R128_FP_VERT_STRETCH 0x0290 +# define R128_VERT_PANEL_SIZE (0x7ff << 0) +# define R128_VERT_PANEL_SHIFT 0 +# define R128_VERT_STRETCH_RATIO_MASK 0x3ff +# define R128_VERT_STRETCH_RATIO_SHIFT 11 +# define R128_VERT_STRETCH_RATIO_MAX 1024 +# define R128_VERT_STRETCH_ENABLE (1 << 24) +# define R128_VERT_STRETCH_LINEREP (0 << 25) +# define R128_VERT_STRETCH_BLEND (1 << 25) +# define R128_VERT_AUTO_RATIO_EN (1 << 26) +# define R128_VERT_STRETCH_RESERVED 0xf8e00000 + +#define R128_GEN_INT_CNTL 0x0040 +#define R128_GEN_INT_STATUS 0x0044 +# define R128_VSYNC_INT_AK (1 << 2) +# define R128_VSYNC_INT (1 << 2) +#define R128_GEN_RESET_CNTL 0x00f0 +# define R128_SOFT_RESET_GUI (1 << 0) +# define R128_SOFT_RESET_VCLK (1 << 8) +# define R128_SOFT_RESET_PCLK (1 << 9) +# define R128_SOFT_RESET_DISPENG_XCLK (1 << 11) +# define R128_SOFT_RESET_MEMCTLR_XCLK (1 << 12) +#define R128_GENENB 0x03c3 /* VGA */ +#define R128_GENFC_RD 0x03ca /* VGA */ +#define R128_GENFC_WT 0x03da /* VGA, 0x03ba */ +#define R128_GENMO_RD 0x03cc /* VGA */ +#define R128_GENMO_WT 0x03c2 /* VGA */ +#define R128_GENS0 0x03c2 /* VGA */ +#define R128_GENS1 0x03da /* VGA, 0x03ba */ +#define R128_GPIO_MONID 0x0068 +# define R128_GPIO_MONID_A_0 (1 << 0) +# define R128_GPIO_MONID_A_1 (1 << 1) +# define R128_GPIO_MONID_A_2 (1 << 2) +# define R128_GPIO_MONID_A_3 (1 << 3) +# define R128_GPIO_MONID_Y_0 (1 << 8) +# define R128_GPIO_MONID_Y_1 (1 << 9) +# define R128_GPIO_MONID_Y_2 (1 << 10) +# define R128_GPIO_MONID_Y_3 (1 << 11) +# define R128_GPIO_MONID_EN_0 (1 << 16) +# define R128_GPIO_MONID_EN_1 (1 << 17) +# define R128_GPIO_MONID_EN_2 (1 << 18) +# define R128_GPIO_MONID_EN_3 (1 << 19) +# define R128_GPIO_MONID_MASK_0 (1 << 24) +# define R128_GPIO_MONID_MASK_1 (1 << 25) +# define R128_GPIO_MONID_MASK_2 (1 << 26) +# define R128_GPIO_MONID_MASK_3 (1 << 27) +#define R128_GPIO_MONIDB 0x006c +#define R128_GRPH8_DATA 0x03cf /* VGA */ +#define R128_GRPH8_IDX 0x03ce /* VGA */ +#define R128_GUI_DEBUG0 0x16a0 +#define R128_GUI_DEBUG1 0x16a4 +#define R128_GUI_DEBUG2 0x16a8 +#define R128_GUI_DEBUG3 0x16ac +#define R128_GUI_DEBUG4 0x16b0 +#define R128_GUI_DEBUG5 0x16b4 +#define R128_GUI_DEBUG6 0x16b8 +#define R128_GUI_PROBE 0x16bc +#define R128_GUI_SCRATCH_REG0 0x15e0 +#define R128_GUI_SCRATCH_REG1 0x15e4 +#define R128_GUI_SCRATCH_REG2 0x15e8 +#define R128_GUI_SCRATCH_REG3 0x15ec +#define R128_GUI_SCRATCH_REG4 0x15f0 +#define R128_GUI_SCRATCH_REG5 0x15f4 +#define R128_GUI_STAT 0x1740 +# define R128_GUI_FIFOCNT_MASK 0x0fff +# define R128_GUI_ACTIVE (1 << 31) + +#define R128_HEADER 0x0f0e /* PCI */ +#define R128_HOST_DATA0 0x17c0 +#define R128_HOST_DATA1 0x17c4 +#define R128_HOST_DATA2 0x17c8 +#define R128_HOST_DATA3 0x17cc +#define R128_HOST_DATA4 0x17d0 +#define R128_HOST_DATA5 0x17d4 +#define R128_HOST_DATA6 0x17d8 +#define R128_HOST_DATA7 0x17dc +#define R128_HOST_DATA_LAST 0x17e0 +#define R128_HOST_PATH_CNTL 0x0130 +#define R128_HTOTAL_CNTL 0x0009 /* PLL */ +#define R128_HW_DEBUG 0x0128 +#define R128_HW_DEBUG2 0x011c + +#define R128_I2C_CNTL_1 0x0094 /* ? */ +#define R128_INTERRUPT_LINE 0x0f3c /* PCI */ +#define R128_INTERRUPT_PIN 0x0f3d /* PCI */ +#define R128_IO_BASE 0x0f14 /* PCI */ + +#define R128_LATENCY 0x0f0d /* PCI */ +#define R128_LEAD_BRES_DEC 0x1608 +#define R128_LEAD_BRES_ERR 0x1600 +#define R128_LEAD_BRES_INC 0x1604 +#define R128_LEAD_BRES_LNTH 0x161c +#define R128_LEAD_BRES_LNTH_SUB 0x1624 +#define R128_LVDS_GEN_CNTL 0x02d0 +# define R128_LVDS_ON (1 << 0) +# define R128_LVDS_DISPLAY_DIS (1 << 1) +# define R128_LVDS_EN (1 << 7) +# define R128_LVDS_DIGON (1 << 18) +# define R128_LVDS_BLON (1 << 19) +# define R128_LVDS_SEL_CRTC2 (1 << 23) +# define R128_HSYNC_DELAY_SHIFT 28 +# define R128_HSYNC_DELAY_MASK (0xf << 28) + +#define R128_MAX_LATENCY 0x0f3f /* PCI */ +#define R128_MCLK_CNTL 0x000f /* PLL */ +# define R128_FORCE_GCP (1 << 16) +# define R128_FORCE_PIPE3D_CP (1 << 17) +# define R128_FORCE_RCP (1 << 18) +#define R128_MDGPIO_A_REG 0x01ac +#define R128_MDGPIO_EN_REG 0x01b0 +#define R128_MDGPIO_MASK 0x0198 +#define R128_MDGPIO_Y_REG 0x01b4 +#define R128_MEM_ADDR_CONFIG 0x0148 +#define R128_MEM_BASE 0x0f10 /* PCI */ +#define R128_MEM_CNTL 0x0140 +#define R128_MEM_INIT_LAT_TIMER 0x0154 +#define R128_MEM_INTF_CNTL 0x014c +#define R128_MEM_SDRAM_MODE_REG 0x0158 +#define R128_MEM_STR_CNTL 0x0150 +#define R128_MEM_VGA_RP_SEL 0x003c +#define R128_MEM_VGA_WP_SEL 0x0038 +#define R128_MIN_GRANT 0x0f3e /* PCI */ +#define R128_MM_DATA 0x0004 +#define R128_MM_INDEX 0x0000 +#define R128_MPLL_CNTL 0x000e /* PLL */ +#define R128_MPP_TB_CONFIG 0x01c0 /* ? */ +#define R128_MPP_GP_CONFIG 0x01c8 /* ? */ + +#define R128_N_VIF_COUNT 0x0248 + +#define R128_OVR_CLR 0x0230 +#define R128_OVR_WID_LEFT_RIGHT 0x0234 +#define R128_OVR_WID_TOP_BOTTOM 0x0238 + +/* first overlay unit (there is only one) */ + +#define R128_OV0_Y_X_START 0x0400 +#define R128_OV0_Y_X_END 0x0404 +#define R128_OV0_EXCLUSIVE_HORZ 0x0408 +# define R128_EXCL_HORZ_START_MASK 0x000000ff +# define R128_EXCL_HORZ_END_MASK 0x0000ff00 +# define R128_EXCL_HORZ_BACK_PORCH_MASK 0x00ff0000 +# define R128_EXCL_HORZ_EXCLUSIVE_EN 0x80000000 +#define R128_OV0_EXCLUSIVE_VERT 0x040C +# define R128_EXCL_VERT_START_MASK 0x000003ff +# define R128_EXCL_VERT_END_MASK 0x03ff0000 +#define R128_OV0_REG_LOAD_CNTL 0x0410 +# define R128_REG_LD_CTL_LOCK 0x00000001L +# define R128_REG_LD_CTL_VBLANK_DURING_LOCK 0x00000002L +# define R128_REG_LD_CTL_STALL_GUI_UNTIL_FLIP 0x00000004L +# define R128_REG_LD_CTL_LOCK_READBACK 0x00000008L +#define R128_OV0_SCALE_CNTL 0x0420 +# define R128_SCALER_PIX_EXPAND 0x00000001L +# define R128_SCALER_Y2R_TEMP 0x00000002L +# define R128_SCALER_HORZ_PICK_NEAREST 0x00000003L +# define R128_SCALER_VERT_PICK_NEAREST 0x00000004L +# define R128_SCALER_SIGNED_UV 0x00000010L +# define R128_SCALER_GAMMA_SEL_MASK 0x00000060L +# define R128_SCALER_GAMMA_SEL_BRIGHT 0x00000000L +# define R128_SCALER_GAMMA_SEL_G22 0x00000020L +# define R128_SCALER_GAMMA_SEL_G18 0x00000040L +# define R128_SCALER_GAMMA_SEL_G14 0x00000060L +# define R128_SCALER_COMCORE_SHIFT_UP_ONE 0x00000080L +# define R128_SCALER_SURFAC_FORMAT 0x00000f00L +# define R128_SCALER_SOURCE_15BPP 0x00000300L +# define R128_SCALER_SOURCE_16BPP 0x00000400L +# define R128_SCALER_SOURCE_32BPP 0x00000600L +# define R128_SCALER_SOURCE_YUV9 0x00000900L +# define R128_SCALER_SOURCE_YUV12 0x00000A00L +# define R128_SCALER_SOURCE_VYUY422 0x00000B00L +# define R128_SCALER_SOURCE_YVYU422 0x00000C00L +# define R128_SCALER_SMART_SWITCH 0x00008000L +# define R128_SCALER_BURST_PER_PLANE 0x00ff0000L +# define R128_SCALER_DOUBLE_BUFFER 0x01000000L +# define R128_SCALER_DIS_LIMIT 0x08000000L +# define R128_SCALER_PRG_LOAD_START 0x10000000L +# define R128_SCALER_INT_EMU 0x20000000L +# define R128_SCALER_ENABLE 0x40000000L +# define R128_SCALER_SOFT_RESET 0x80000000L +#define R128_OV0_V_INC 0x0424 +#define R128_OV0_P1_V_ACCUM_INIT 0x0428 +# define R128_OV0_P1_MAX_LN_IN_PER_LN_OUT 0x00000003L +# define R128_OV0_P1_V_ACCUM_INIT_MASK 0x01ff8000L +#define R128_OV0_P23_V_ACCUM_INIT 0x042C +#define R128_OV0_P1_BLANK_LINES_AT_TOP 0x0430 +# define R128_P1_BLNK_LN_AT_TOP_M1_MASK 0x00000fffL +# define R128_P1_ACTIVE_LINES_M1 0x0fff0000L +#define R128_OV0_P23_BLANK_LINES_AT_TOP 0x0434 +# define R128_P23_BLNK_LN_AT_TOP_M1_MASK 0x000007ffL +# define R128_P23_ACTIVE_LINES_M1 0x07ff0000L +#define R128_OV0_VID_BUF0_BASE_ADRS 0x0440 +# define R128_VIF_BUF0_PITCH_SEL 0x00000001L +# define R128_VIF_BUF0_TILE_ADRS 0x00000002L +# define R128_VIF_BUF0_BASE_ADRS_MASK 0x03fffff0L +# define R128_VIF_BUF0_1ST_LINE_LSBS_MASK 0x48000000L +#define R128_OV0_VID_BUF1_BASE_ADRS 0x0444 +# define R128_VIF_BUF1_PITCH_SEL 0x00000001L +# define R128_VIF_BUF1_TILE_ADRS 0x00000002L +# define R128_VIF_BUF1_BASE_ADRS_MASK 0x03fffff0L +# define R128_VIF_BUF1_1ST_LINE_LSBS_MASK 0x48000000L +#define R128_OV0_VID_BUF2_BASE_ADRS 0x0448 +# define R128_VIF_BUF2_PITCH_SEL 0x00000001L +# define R128_VIF_BUF2_TILE_ADRS 0x00000002L +# define R128_VIF_BUF2_BASE_ADRS_MASK 0x03fffff0L +# define R128_VIF_BUF2_1ST_LINE_LSBS_MASK 0x48000000L +#define R128_OV0_VID_BUF3_BASE_ADRS 0x044C +#define R128_OV0_VID_BUF4_BASE_ADRS 0x0450 +#define R128_OV0_VID_BUF5_BASE_ADRS 0x0454 +#define R128_OV0_VID_BUF_PITCH0_VALUE 0x0460 +#define R128_OV0_VID_BUF_PITCH1_VALUE 0x0464 +#define R128_OV0_AUTO_FLIP_CNTL 0x0470 +#define R128_OV0_DEINTERLACE_PATTERN 0x0474 +#define R128_OV0_H_INC 0x0480 +#define R128_OV0_STEP_BY 0x0484 +#define R128_OV0_P1_H_ACCUM_INIT 0x0488 +#define R128_OV0_P23_H_ACCUM_INIT 0x048C +#define R128_OV0_P1_X_START_END 0x0494 +#define R128_OV0_P2_X_START_END 0x0498 +#define R128_OV0_P3_X_START_END 0x049C +#define R128_OV0_FILTER_CNTL 0x04A0 +#define R128_OV0_FOUR_TAP_COEF_0 0x04B0 +#define R128_OV0_FOUR_TAP_COEF_1 0x04B4 +#define R128_OV0_FOUR_TAP_COEF_2 0x04B8 +#define R128_OV0_FOUR_TAP_COEF_3 0x04BC +#define R128_OV0_FOUR_TAP_COEF_4 0x04C0 +#define R128_OV0_COLOUR_CNTL 0x04E0 +#define R128_OV0_VIDEO_KEY_CLR 0x04E4 +#define R128_OV0_VIDEO_KEY_MSK 0x04E8 +#define R128_OV0_GRAPHICS_KEY_CLR 0x04EC +#define R128_OV0_GRAPHICS_KEY_MSK 0x04F0 +#define R128_OV0_KEY_CNTL 0x04F4 +# define R128_VIDEO_KEY_FN_MASK 0x00000007L +# define R128_VIDEO_KEY_FN_FALSE 0x00000000L +# define R128_VIDEO_KEY_FN_TRUE 0x00000001L +# define R128_VIDEO_KEY_FN_EQ 0x00000004L +# define R128_VIDEO_KEY_FN_NE 0x00000005L +# define R128_GRAPHIC_KEY_FN_MASK 0x00000070L +# define R128_GRAPHIC_KEY_FN_FALSE 0x00000000L +# define R128_GRAPHIC_KEY_FN_TRUE 0x00000010L +# define R128_GRAPHIC_KEY_FN_EQ 0x00000040L +# define R128_GRAPHIC_KEY_FN_NE 0x00000050L +# define R128_CMP_MIX_MASK 0x00000100L +# define R128_CMP_MIX_OR 0x00000000L +# define R128_CMP_MIX_AND 0x00000100L +#define R128_OV0_TEST 0x04F8 + + +#define R128_PALETTE_DATA 0x00b4 +#define R128_PALETTE_INDEX 0x00b0 +#define R128_PC_DEBUG_MODE 0x1760 +#define R128_PC_GUI_CTLSTAT 0x1748 +#define R128_PC_GUI_MODE 0x1744 +# define R128_PC_IGNORE_UNIFY (1 << 5) +#define R128_PC_MISC_CNTL 0x0188 +#define R128_PC_NGUI_CTLSTAT 0x0184 +# define R128_PC_FLUSH_GUI (3 << 0) +# define R128_PC_RI_GUI (1 << 2) +# define R128_PC_FLUSH_ALL 0x00ff +# define R128_PC_BUSY (1 << 31) +#define R128_PC_NGUI_MODE 0x0180 +#define R128_PCI_GART_PAGE 0x017c +#define R128_PLANE_3D_MASK_C 0x1d44 +#define R128_PLL_TEST_CNTL 0x0013 /* PLL */ +#define R128_PMI_CAP_ID 0x0f5c /* PCI */ +#define R128_PMI_DATA 0x0f63 /* PCI */ +#define R128_PMI_NXT_CAP_PTR 0x0f5d /* PCI */ +#define R128_PMI_PMC_REG 0x0f5e /* PCI */ +#define R128_PMI_PMCSR_REG 0x0f60 /* PCI */ +#define R128_PMI_REGISTER 0x0f5c /* PCI */ +#define R128_PPLL_CNTL 0x0002 /* PLL */ +# define R128_PPLL_RESET (1 << 0) +# define R128_PPLL_SLEEP (1 << 1) +# define R128_PPLL_ATOMIC_UPDATE_EN (1 << 16) +# define R128_PPLL_VGA_ATOMIC_UPDATE_EN (1 << 17) +#define R128_PPLL_DIV_0 0x0004 /* PLL */ +#define R128_PPLL_DIV_1 0x0005 /* PLL */ +#define R128_PPLL_DIV_2 0x0006 /* PLL */ +#define R128_PPLL_DIV_3 0x0007 /* PLL */ +# define R128_PPLL_FB3_DIV_MASK 0x07ff +# define R128_PPLL_POST3_DIV_MASK 0x00070000 +#define R128_PPLL_REF_DIV 0x0003 /* PLL */ +# define R128_PPLL_REF_DIV_MASK 0x03ff +# define R128_PPLL_ATOMIC_UPDATE_R (1 << 15) /* same as _W */ +# define R128_PPLL_ATOMIC_UPDATE_W (1 << 15) /* same as _R */ +#define R128_PWR_MNGMT_CNTL_STATUS 0x0f60 /* PCI */ +#define R128_REG_BASE 0x0f18 /* PCI */ +#define R128_REGPROG_INF 0x0f09 /* PCI */ +#define R128_REVISION_ID 0x0f08 /* PCI */ + +#define R128_SC_BOTTOM 0x164c +#define R128_SC_BOTTOM_RIGHT 0x16f0 +#define R128_SC_BOTTOM_RIGHT_C 0x1c8c +#define R128_SC_LEFT 0x1640 +#define R128_SC_RIGHT 0x1644 +#define R128_SC_TOP 0x1648 +#define R128_SC_TOP_LEFT 0x16ec +#define R128_SC_TOP_LEFT_C 0x1c88 +#define R128_SEQ8_DATA 0x03c5 /* VGA */ +#define R128_SEQ8_IDX 0x03c4 /* VGA */ +#define R128_SNAPSHOT_F_COUNT 0x0244 +#define R128_SNAPSHOT_VH_COUNTS 0x0240 +#define R128_SNAPSHOT_VIF_COUNT 0x024c +#define R128_SRC_OFFSET 0x15ac +#define R128_SRC_PITCH 0x15b0 +#define R128_SRC_PITCH_OFFSET 0x1428 +#define R128_SRC_SC_BOTTOM 0x165c +#define R128_SRC_SC_BOTTOM_RIGHT 0x16f4 +#define R128_SRC_SC_RIGHT 0x1654 +#define R128_SRC_X 0x1414 +#define R128_SRC_X_Y 0x1590 +#define R128_SRC_Y 0x1418 +#define R128_SRC_Y_X 0x1434 +#define R128_STATUS 0x0f06 /* PCI */ +#define R128_SUBPIC_CNTL 0x0540 /* ? */ +#define R128_SUB_CLASS 0x0f0a /* PCI */ +#define R128_SURFACE_DELAY 0x0b00 +#define R128_SURFACE0_INFO 0x0b0c +#define R128_SURFACE0_LOWER_BOUND 0x0b04 +#define R128_SURFACE0_UPPER_BOUND 0x0b08 +#define R128_SURFACE1_INFO 0x0b1c +#define R128_SURFACE1_LOWER_BOUND 0x0b14 +#define R128_SURFACE1_UPPER_BOUND 0x0b18 +#define R128_SURFACE2_INFO 0x0b2c +#define R128_SURFACE2_LOWER_BOUND 0x0b24 +#define R128_SURFACE2_UPPER_BOUND 0x0b28 +#define R128_SURFACE3_INFO 0x0b3c +#define R128_SURFACE3_LOWER_BOUND 0x0b34 +#define R128_SURFACE3_UPPER_BOUND 0x0b38 +#define R128_SW_SEMAPHORE 0x013c + +#define R128_TEST_DEBUG_CNTL 0x0120 +#define R128_TEST_DEBUG_MUX 0x0124 +#define R128_TEST_DEBUG_OUT 0x012c +#define R128_TMDS_CRC 0x02a0 +#define R128_TMDS_TRANSMITTER_CNTL 0x02a4 +# define R128_TMDS_PLLEN (1 << 0) +# define R128_TMDS_PLLRST (1 << 1) +#define R128_TRAIL_BRES_DEC 0x1614 +#define R128_TRAIL_BRES_ERR 0x160c +#define R128_TRAIL_BRES_INC 0x1610 +#define R128_TRAIL_X 0x1618 +#define R128_TRAIL_X_SUB 0x1620 + +#define R128_VCLK_ECP_CNTL 0x0008 /* PLL */ +#define R128_VENDOR_ID 0x0f00 /* PCI */ +#define R128_VGA_DDA_CONFIG 0x02e8 +#define R128_VGA_DDA_ON_OFF 0x02ec +#define R128_VID_BUFFER_CONTROL 0x0900 +#define R128_VIDEOMUX_CNTL 0x0190 +#define R128_VIPH_CONTROL 0x01D0 /* ? */ + +#define R128_WAIT_UNTIL 0x1720 + +#define R128_X_MPLL_REF_FB_DIV 0x000a /* PLL */ +#define R128_XCLK_CNTL 0x000d /* PLL */ +#define R128_XDLL_CNTL 0x000c /* PLL */ +#define R128_XPLL_CNTL 0x000b /* PLL */ + + /* Registers for CCE and Microcode Engine */ +#define R128_PM4_MICROCODE_ADDR 0x07d4 +#define R128_PM4_MICROCODE_RADDR 0x07d8 +#define R128_PM4_MICROCODE_DATAH 0x07dc +#define R128_PM4_MICROCODE_DATAL 0x07e0 + +#define R128_PM4_BUFFER_OFFSET 0x0700 +#define R128_PM4_BUFFER_CNTL 0x0704 +# define R128_PM4_NONPM4 (0 << 28) +# define R128_PM4_192PIO (1 << 28) +# define R128_PM4_192BM (2 << 28) +# define R128_PM4_128PIO_64INDBM (3 << 28) +# define R128_PM4_128BM_64INDBM (4 << 28) +# define R128_PM4_64PIO_128INDBM (5 << 28) +# define R128_PM4_64BM_128INDBM (6 << 28) +# define R128_PM4_64PIO_64VCBM_64INDBM (7 << 28) +# define R128_PM4_64BM_64VCBM_64INDBM (8 << 28) +# define R128_PM4_64PIO_64VCPIO_64INDPIO (15 << 28) +#define R128_PM4_BUFFER_WM_CNTL 0x0708 +# define R128_WMA_SHIFT 0 +# define R128_WMB_SHIFT 8 +# define R128_WMC_SHIFT 16 +# define R128_WB_WM_SHIFT 24 +#define R128_PM4_BUFFER_DL_RPTR_ADDR 0x070c +#define R128_PM4_BUFFER_DL_RPTR 0x0710 +#define R128_PM4_BUFFER_DL_WPTR 0x0714 +# define R128_PM4_BUFFER_DL_DONE (1 << 31) +#define R128_PM4_BUFFER_DL_WPTR_DELAY 0x0718 +# define R128_PRE_WRITE_TIMER_SHIFT 0 +# define R128_PRE_WRITE_LIMIT_SHIFT 23 +#define R128_PM4_VC_FPU_SETUP 0x071c +# define R128_FRONT_DIR_CW (0 << 0) +# define R128_FRONT_DIR_CCW (1 << 0) +# define R128_FRONT_DIR_MASK (1 << 0) +# define R128_BACKFACE_CULL (0 << 1) +# define R128_BACKFACE_POINTS (1 << 1) +# define R128_BACKFACE_LINES (2 << 1) +# define R128_BACKFACE_SOLID (3 << 1) +# define R128_BACKFACE_MASK (3 << 1) +# define R128_FRONTFACE_CULL (0 << 3) +# define R128_FRONTFACE_POINTS (1 << 3) +# define R128_FRONTFACE_LINES (2 << 3) +# define R128_FRONTFACE_SOLID (3 << 3) +# define R128_FRONTFACE_MASK (3 << 3) +# define R128_FPU_COLOR_SOLID (0 << 5) +# define R128_FPU_COLOR_FLAT (1 << 5) +# define R128_FPU_COLOR_GOURAUD (2 << 5) +# define R128_FPU_COLOR_GOURAUD2 (3 << 5) +# define R128_FPU_COLOR_MASK (3 << 5) +# define R128_FPU_SUB_PIX_2BITS (0 << 7) +# define R128_FPU_SUB_PIX_4BITS (1 << 7) +# define R128_FPU_MODE_2D (0 << 8) +# define R128_FPU_MODE_3D (1 << 8) +# define R128_TRAP_BITS_DISABLE (1 << 9) +# define R128_EDGE_ANTIALIAS (1 << 10) +# define R128_SUPERSAMPLE (1 << 11) +# define R128_XFACTOR_2 (0 << 12) +# define R128_XFACTOR_4 (1 << 12) +# define R128_YFACTOR_2 (0 << 13) +# define R128_YFACTOR_4 (1 << 13) +# define R128_FLAT_SHADE_VERTEX_D3D (0 << 14) +# define R128_FLAT_SHADE_VERTEX_OGL (1 << 14) +# define R128_FPU_ROUND_TRUNCATE (0 << 15) +# define R128_FPU_ROUND_NEAREST (1 << 15) +# define R128_WM_SEL_8DW (0 << 16) +# define R128_WM_SEL_16DW (1 << 16) +# define R128_WM_SEL_32DW (2 << 16) +#define R128_PM4_VC_DEBUG_CONFIG 0x07a4 +#define R128_PM4_VC_STAT 0x07a8 +#define R128_PM4_VC_TIMESTAMP0 0x07b0 +#define R128_PM4_VC_TIMESTAMP1 0x07b4 +#define R128_PM4_STAT 0x07b8 +# define R128_PM4_FIFOCNT_MASK 0x0fff +# define R128_PM4_BUSY (1 << 16) +# define R128_PM4_GUI_ACTIVE (1 << 31) +#define R128_PM4_BUFFER_ADDR 0x07f0 +#define R128_PM4_MICRO_CNTL 0x07fc +# define R128_PM4_MICRO_FREERUN (1 << 30) +#define R128_PM4_FIFO_DATA_EVEN 0x1000 +#define R128_PM4_FIFO_DATA_ODD 0x1004 + +#define R128_SCALE_3D_CNTL 0x1a00 +# define R128_SCALE_DITHER_ERR_DIFF (0 << 1) +# define R128_SCALE_DITHER_TABLE (1 << 1) +# define R128_TEX_CACHE_SIZE_FULL (0 << 2) +# define R128_TEX_CACHE_SIZE_HALF (1 << 2) +# define R128_DITHER_INIT_CURR (0 << 3) +# define R128_DITHER_INIT_RESET (1 << 3) +# define R128_ROUND_24BIT (1 << 4) +# define R128_TEX_CACHE_DISABLE (1 << 5) +# define R128_SCALE_3D_NOOP (0 << 6) +# define R128_SCALE_3D_SCALE (1 << 6) +# define R128_SCALE_3D_TEXMAP_SHADE (2 << 6) +# define R128_SCALE_PIX_BLEND (0 << 8) +# define R128_SCALE_PIX_REPLICATE (1 << 8) +# define R128_TEX_CACHE_SPLIT (1 << 9) +# define R128_APPLE_YUV_MODE (1 << 10) +# define R128_TEX_CACHE_PALLETE_MODE (1 << 11) +# define R128_ALPHA_COMB_ADD_CLAMP (0 << 12) +# define R128_ALPHA_COMB_ADD_NCLAMP (1 << 12) +# define R128_ALPHA_COMB_SUB_DST_SRC_CLAMP (2 << 12) +# define R128_ALPHA_COMB_SUB_DST_SRC_NCLAMP (3 << 12) +# define R128_FOG_TABLE (1 << 14) +# define R128_SIGNED_DST_CLAMP (1 << 15) +# define R128_ALPHA_BLEND_SRC_ZERO (0 << 16) +# define R128_ALPHA_BLEND_SRC_ONE (1 << 16) +# define R128_ALPHA_BLEND_SRC_SRCCOLOR (2 << 16) +# define R128_ALPHA_BLEND_SRC_INVSRCCOLOR (3 << 16) +# define R128_ALPHA_BLEND_SRC_SRCALPHA (4 << 16) +# define R128_ALPHA_BLEND_SRC_INVSRCALPHA (5 << 16) +# define R128_ALPHA_BLEND_SRC_DSTALPHA (6 << 16) +# define R128_ALPHA_BLEND_SRC_INVDSTALPHA (7 << 16) +# define R128_ALPHA_BLEND_SRC_DSTCOLOR (8 << 16) +# define R128_ALPHA_BLEND_SRC_INVDSTCOLOR (9 << 16) +# define R128_ALPHA_BLEND_SRC_SAT (10 << 16) +# define R128_ALPHA_BLEND_SRC_BLEND (11 << 16) +# define R128_ALPHA_BLEND_SRC_INVBLEND (12 << 16) +# define R128_ALPHA_BLEND_DST_ZERO (0 << 20) +# define R128_ALPHA_BLEND_DST_ONE (1 << 20) +# define R128_ALPHA_BLEND_DST_SRCCOLOR (2 << 20) +# define R128_ALPHA_BLEND_DST_INVSRCCOLOR (3 << 20) +# define R128_ALPHA_BLEND_DST_SRCALPHA (4 << 20) +# define R128_ALPHA_BLEND_DST_INVSRCALPHA (5 << 20) +# define R128_ALPHA_BLEND_DST_DSTALPHA (6 << 20) +# define R128_ALPHA_BLEND_DST_INVDSTALPHA (7 << 20) +# define R128_ALPHA_BLEND_DST_DSTCOLOR (8 << 20) +# define R128_ALPHA_BLEND_DST_INVDSTCOLOR (9 << 20) +# define R128_ALPHA_TEST_NEVER (0 << 24) +# define R128_ALPHA_TEST_LESS (1 << 24) +# define R128_ALPHA_TEST_LESSEQUAL (2 << 24) +# define R128_ALPHA_TEST_EQUAL (3 << 24) +# define R128_ALPHA_TEST_GREATEREQUAL (4 << 24) +# define R128_ALPHA_TEST_GREATER (5 << 24) +# define R128_ALPHA_TEST_NEQUAL (6 << 24) +# define R128_ALPHA_TEST_ALWAYS (7 << 24) +# define R128_COMPOSITE_SHADOW_CMP_EQUAL (0 << 28) +# define R128_COMPOSITE_SHADOW_CMP_NEQUAL (1 << 28) +# define R128_COMPOSITE_SHADOW (1 << 29) +# define R128_TEX_MAP_ALPHA_IN_TEXTURE (1 << 30) +# define R128_TEX_CACHE_LINE_SIZE_8QW (0 << 31) +# define R128_TEX_CACHE_LINE_SIZE_4QW (1 << 31) +#define R128_SCALE_3D_DATATYPE 0x1a20 + +#define R128_SETUP_CNTL 0x1bc4 +# define R128_DONT_START_TRIANGLE (1 << 0) +# define R128_Z_BIAS (0 << 1) +# define R128_DONT_START_ANY_ON (1 << 2) +# define R128_COLOR_SOLID_COLOR (0 << 3) +# define R128_COLOR_FLAT_VERT_1 (1 << 3) +# define R128_COLOR_FLAT_VERT_2 (2 << 3) +# define R128_COLOR_FLAT_VERT_3 (3 << 3) +# define R128_COLOR_GOURAUD (4 << 3) +# define R128_PRIM_TYPE_TRI (0 << 7) +# define R128_PRIM_TYPE_LINE (1 << 7) +# define R128_PRIM_TYPE_POINT (2 << 7) +# define R128_PRIM_TYPE_POLY_EDGE (3 << 7) +# define R128_TEXTURE_ST_MULT_W (0 << 9) +# define R128_TEXTURE_ST_DIRECT (1 << 9) +# define R128_STARTING_VERTEX_1 (1 << 14) +# define R128_STARTING_VERTEX_2 (2 << 14) +# define R128_STARTING_VERTEX_3 (3 << 14) +# define R128_ENDING_VERTEX_1 (1 << 16) +# define R128_ENDING_VERTEX_2 (2 << 16) +# define R128_ENDING_VERTEX_3 (3 << 16) +# define R128_SU_POLY_LINE_LAST (0 << 18) +# define R128_SU_POLY_LINE_NOT_LAST (1 << 18) +# define R128_SUB_PIX_2BITS (0 << 19) +# define R128_SUB_PIX_4BITS (1 << 19) +# define R128_SET_UP_CONTINUE (1 << 31) + +#define R128_WINDOW_XY_OFFSET 0x1bcc +# define R128_WINDOW_Y_SHIFT 4 +# define R128_WINDOW_X_SHIFT 20 + +#define R128_Z_OFFSET_C 0x1c90 +#define R128_Z_PITCH_C 0x1c94 +# define R128_Z_TILE (1 << 16) +#define R128_Z_STEN_CNTL_C 0x1c98 +# define R128_Z_PIX_WIDTH_16 (0 << 1) +# define R128_Z_PIX_WIDTH_24 (1 << 1) +# define R128_Z_PIX_WIDTH_32 (2 << 1) +# define R128_Z_PIX_WIDTH_MASK (3 << 1) +# define R128_Z_TEST_NEVER (0 << 4) +# define R128_Z_TEST_LESS (1 << 4) +# define R128_Z_TEST_LESSEQUAL (2 << 4) +# define R128_Z_TEST_EQUAL (3 << 4) +# define R128_Z_TEST_GREATEREQUAL (4 << 4) +# define R128_Z_TEST_GREATER (5 << 4) +# define R128_Z_TEST_NEQUAL (6 << 4) +# define R128_Z_TEST_ALWAYS (7 << 4) +# define R128_Z_TEST_MASK (7 << 4) +# define R128_STENCIL_TEST_NEVER (0 << 12) +# define R128_STENCIL_TEST_LESS (1 << 12) +# define R128_STENCIL_TEST_LESSEQUAL (2 << 12) +# define R128_STENCIL_TEST_EQUAL (3 << 12) +# define R128_STENCIL_TEST_GREATEREQUAL (4 << 12) +# define R128_STENCIL_TEST_GREATER (5 << 12) +# define R128_STENCIL_TEST_NEQUAL (6 << 12) +# define R128_STENCIL_TEST_ALWAYS (7 << 12) +# define R128_STENCIL_S_FAIL_KEEP (0 << 16) +# define R128_STENCIL_S_FAIL_ZERO (1 << 16) +# define R128_STENCIL_S_FAIL_REPLACE (2 << 16) +# define R128_STENCIL_S_FAIL_INC (3 << 16) +# define R128_STENCIL_S_FAIL_DEC (4 << 16) +# define R128_STENCIL_S_FAIL_INV (5 << 16) +# define R128_STENCIL_ZPASS_KEEP (0 << 20) +# define R128_STENCIL_ZPASS_ZERO (1 << 20) +# define R128_STENCIL_ZPASS_REPLACE (2 << 20) +# define R128_STENCIL_ZPASS_INC (3 << 20) +# define R128_STENCIL_ZPASS_DEC (4 << 20) +# define R128_STENCIL_ZPASS_INV (5 << 20) +# define R128_STENCIL_ZFAIL_KEEP (0 << 24) +# define R128_STENCIL_ZFAIL_ZERO (1 << 24) +# define R128_STENCIL_ZFAIL_REPLACE (2 << 24) +# define R128_STENCIL_ZFAIL_INC (3 << 24) +# define R128_STENCIL_ZFAIL_DEC (4 << 24) +# define R128_STENCIL_ZFAIL_INV (5 << 24) +#define R128_TEX_CNTL_C 0x1c9c +# define R128_Z_ENABLE (1 << 0) +# define R128_Z_WRITE_ENABLE (1 << 1) +# define R128_STENCIL_ENABLE (1 << 3) +# define R128_SHADE_ENABLE (0 << 4) +# define R128_TEXMAP_ENABLE (1 << 4) +# define R128_SEC_TEXMAP_ENABLE (1 << 5) +# define R128_FOG_ENABLE (1 << 7) +# define R128_DITHER_ENABLE (1 << 8) +# define R128_ALPHA_ENABLE (1 << 9) +# define R128_ALPHA_TEST_ENABLE (1 << 10) +# define R128_SPEC_LIGHT_ENABLE (1 << 11) +# define R128_TEX_CHROMA_KEY_ENABLE (1 << 12) +# define R128_ALPHA_IN_TEX_COMPLETE_A (0 << 13) +# define R128_ALPHA_IN_TEX_LSB_A (1 << 13) +# define R128_LIGHT_DIS (0 << 14) +# define R128_LIGHT_COPY (1 << 14) +# define R128_LIGHT_MODULATE (2 << 14) +# define R128_LIGHT_ADD (3 << 14) +# define R128_LIGHT_BLEND_CONSTANT (4 << 14) +# define R128_LIGHT_BLEND_TEXTURE (5 << 14) +# define R128_LIGHT_BLEND_VERTEX (6 << 14) +# define R128_LIGHT_BLEND_CONST_COLOR (7 << 14) +# define R128_ALPHA_LIGHT_DIS (0 << 18) +# define R128_ALPHA_LIGHT_COPY (1 << 18) +# define R128_ALPHA_LIGHT_MODULATE (2 << 18) +# define R128_ALPHA_LIGHT_ADD (3 << 18) +# define R128_ANTI_ALIAS (1 << 21) +# define R128_TEX_CACHE_FLUSH (1 << 23) +# define R128_LOD_BIAS_SHIFT 24 +# define R128_LOD_BIAS_MASK (0xff << 24) +#define R128_MISC_3D_STATE_CNTL_REG 0x1ca0 +# define R128_REF_ALPHA_MASK 0xff +# define R128_MISC_SCALE_3D_NOOP (0 << 8) +# define R128_MISC_SCALE_3D_SCALE (1 << 8) +# define R128_MISC_SCALE_3D_TEXMAP_SHADE (2 << 8) +# define R128_MISC_SCALE_PIX_BLEND (0 << 10) +# define R128_MISC_SCALE_PIX_REPLICATE (1 << 10) +# define R128_ALPHA_COMB_ADD_CLAMP (0 << 12) +# define R128_ALPHA_COMB_ADD_NO_CLAMP (1 << 12) +# define R128_ALPHA_COMB_SUB_SRC_DST_CLAMP (2 << 12) +# define R128_ALPHA_COMB_SUB_SRC_DST_NO_CLAMP (3 << 12) +# define R128_FOG_VERTEX (0 << 14) +# define R128_FOG_TABLE (1 << 14) +# define R128_ALPHA_BLEND_SRC_ZERO (0 << 16) +# define R128_ALPHA_BLEND_SRC_ONE (1 << 16) +# define R128_ALPHA_BLEND_SRC_SRCCOLOR (2 << 16) +# define R128_ALPHA_BLEND_SRC_INVSRCCOLOR (3 << 16) +# define R128_ALPHA_BLEND_SRC_SRCALPHA (4 << 16) +# define R128_ALPHA_BLEND_SRC_INVSRCALPHA (5 << 16) +# define R128_ALPHA_BLEND_SRC_DESTALPHA (6 << 16) +# define R128_ALPHA_BLEND_SRC_INVDESTALPHA (7 << 16) +# define R128_ALPHA_BLEND_SRC_DESTCOLOR (8 << 16) +# define R128_ALPHA_BLEND_SRC_INVDESTCOLOR (9 << 16) +# define R128_ALPHA_BLEND_SRC_SRCALPHASAT (10 << 16) +# define R128_ALPHA_BLEND_SRC_BOTHSRCALPHA (11 << 16) +# define R128_ALPHA_BLEND_SRC_BOTHINVSRCALPHA (12 << 16) +# define R128_ALPHA_BLEND_SRC_MASK (15 << 16) +# define R128_ALPHA_BLEND_DST_ZERO (0 << 20) +# define R128_ALPHA_BLEND_DST_ONE (1 << 20) +# define R128_ALPHA_BLEND_DST_SRCCOLOR (2 << 20) +# define R128_ALPHA_BLEND_DST_INVSRCCOLOR (3 << 20) +# define R128_ALPHA_BLEND_DST_SRCALPHA (4 << 20) +# define R128_ALPHA_BLEND_DST_INVSRCALPHA (5 << 20) +# define R128_ALPHA_BLEND_DST_DESTALPHA (6 << 20) +# define R128_ALPHA_BLEND_DST_INVDESTALPHA (7 << 20) +# define R128_ALPHA_BLEND_DST_DESTCOLOR (8 << 20) +# define R128_ALPHA_BLEND_DST_INVDESTCOLOR (9 << 20) +# define R128_ALPHA_BLEND_DST_SRCALPHASAT (10 << 20) +# define R128_ALPHA_BLEND_DST_MASK (15 << 20) +# define R128_ALPHA_TEST_NEVER (0 << 24) +# define R128_ALPHA_TEST_LESS (1 << 24) +# define R128_ALPHA_TEST_LESSEQUAL (2 << 24) +# define R128_ALPHA_TEST_EQUAL (3 << 24) +# define R128_ALPHA_TEST_GREATEREQUAL (4 << 24) +# define R128_ALPHA_TEST_GREATER (5 << 24) +# define R128_ALPHA_TEST_NEQUAL (6 << 24) +# define R128_ALPHA_TEST_ALWAYS (7 << 24) +# define R128_ALPHA_TEST_MASK (7 << 24) +#define R128_TEXTURE_CLR_CMP_CLR_C 0x1ca4 +#define R128_TEXTURE_CLR_CMP_MSK_C 0x1ca8 +#define R128_FOG_COLOR_C 0x1cac +# define R128_FOG_BLUE_SHIFT 0 +# define R128_FOG_GREEN_SHIFT 8 +# define R128_FOG_RED_SHIFT 16 +#define R128_PRIM_TEX_CNTL_C 0x1cb0 +# define R128_MIN_BLEND_NEAREST (0 << 1) +# define R128_MIN_BLEND_LINEAR (1 << 1) +# define R128_MIN_BLEND_MIPNEAREST (2 << 1) +# define R128_MIN_BLEND_MIPLINEAR (3 << 1) +# define R128_MIN_BLEND_LINEARMIPNEAREST (4 << 1) +# define R128_MIN_BLEND_LINEARMIPLINEAR (5 << 1) +# define R128_MIN_BLEND_MASK (7 << 1) +# define R128_MAG_BLEND_NEAREST (0 << 4) +# define R128_MAG_BLEND_LINEAR (1 << 4) +# define R128_MAG_BLEND_MASK (7 << 4) +# define R128_MIP_MAP_DISABLE (1 << 7) +# define R128_TEX_CLAMP_S_WRAP (0 << 8) +# define R128_TEX_CLAMP_S_MIRROR (1 << 8) +# define R128_TEX_CLAMP_S_CLAMP (2 << 8) +# define R128_TEX_CLAMP_S_BORDER_COLOR (3 << 8) +# define R128_TEX_CLAMP_S_MASK (3 << 8) +# define R128_TEX_WRAP_S (1 << 10) +# define R128_TEX_CLAMP_T_WRAP (0 << 11) +# define R128_TEX_CLAMP_T_MIRROR (1 << 11) +# define R128_TEX_CLAMP_T_CLAMP (2 << 11) +# define R128_TEX_CLAMP_T_BORDER_COLOR (3 << 11) +# define R128_TEX_CLAMP_T_MASK (3 << 11) +# define R128_TEX_WRAP_T (1 << 13) +# define R128_TEX_PERSPECTIVE_DISABLE (1 << 14) +# define R128_DATATYPE_VQ (0 << 16) +# define R128_DATATYPE_CI4 (1 << 16) +# define R128_DATATYPE_CI8 (2 << 16) +# define R128_DATATYPE_ARGB1555 (3 << 16) +# define R128_DATATYPE_RGB565 (4 << 16) +# define R128_DATATYPE_RGB888 (5 << 16) +# define R128_DATATYPE_ARGB8888 (6 << 16) +# define R128_DATATYPE_RGB332 (7 << 16) +# define R128_DATATYPE_Y8 (8 << 16) +# define R128_DATATYPE_RGB8 (9 << 16) +# define R128_DATATYPE_CI16 (10 << 16) +# define R128_DATATYPE_YVYU422 (11 << 16) +# define R128_DATATYPE_VYUY422 (12 << 16) +# define R128_DATATYPE_AYUV444 (14 << 16) +# define R128_DATATYPE_ARGB4444 (15 << 16) +# define R128_PALLETE_EITHER (0 << 20) +# define R128_PALLETE_1 (1 << 20) +# define R128_PALLETE_2 (2 << 20) +# define R128_PSEUDOCOLOR_DT_RGB565 (0 << 24) +# define R128_PSEUDOCOLOR_DT_ARGB1555 (1 << 24) +# define R128_PSEUDOCOLOR_DT_ARGB4444 (2 << 24) +#define R128_PRIM_TEXTURE_COMBINE_CNTL_C 0x1cb4 +# define R128_COMB_DIS (0 << 0) +# define R128_COMB_COPY (1 << 0) +# define R128_COMB_COPY_INP (2 << 0) +# define R128_COMB_MODULATE (3 << 0) +# define R128_COMB_MODULATE2X (4 << 0) +# define R128_COMB_MODULATE4X (5 << 0) +# define R128_COMB_ADD (6 << 0) +# define R128_COMB_ADD_SIGNED (7 << 0) +# define R128_COMB_BLEND_VERTEX (8 << 0) +# define R128_COMB_BLEND_TEXTURE (9 << 0) +# define R128_COMB_BLEND_CONST (10 << 0) +# define R128_COMB_BLEND_PREMULT (11 << 0) +# define R128_COMB_BLEND_PREV (12 << 0) +# define R128_COMB_BLEND_PREMULT_INV (13 << 0) +# define R128_COMB_ADD_SIGNED2X (14 << 0) +# define R128_COMB_BLEND_CONST_COLOR (15 << 0) +# define R128_COMB_MASK (15 << 0) +# define R128_COLOR_FACTOR_CONST_COLOR (0 << 4) +# define R128_COLOR_FACTOR_NCONST_COLOR (1 << 4) +# define R128_COLOR_FACTOR_TEX (4 << 4) +# define R128_COLOR_FACTOR_NTEX (5 << 4) +# define R128_COLOR_FACTOR_ALPHA (6 << 4) +# define R128_COLOR_FACTOR_NALPHA (7 << 4) +# define R128_COLOR_FACTOR_PREV_COLOR (8 << 4) +# define R128_COLOR_FACTOR_MASK (15 << 4) +# define R128_COMB_FCN_MSB (1 << 8) +# define R128_INPUT_FACTOR_CONST_COLOR (2 << 10) +# define R128_INPUT_FACTOR_CONST_ALPHA (3 << 10) +# define R128_INPUT_FACTOR_INT_COLOR (4 << 10) +# define R128_INPUT_FACTOR_INT_ALPHA (5 << 10) +# define R128_INPUT_FACTOR_MASK (15 << 10) +# define R128_COMB_ALPHA_DIS (0 << 14) +# define R128_COMB_ALPHA_COPY (1 << 14) +# define R128_COMB_ALPHA_COPY_INP (2 << 14) +# define R128_COMB_ALPHA_MODULATE (3 << 14) +# define R128_COMB_ALPHA_MODULATE2X (4 << 14) +# define R128_COMB_ALPHA_MODULATE4X (5 << 14) +# define R128_COMB_ALPHA_ADD (6 << 14) +# define R128_COMB_ALPHA_ADD_SIGNED (7 << 14) +# define R128_COMB_ALPHA_ADD_SIGNED2X (14 << 14) +# define R128_COMB_ALPHA_MASK (15 << 14) +# define R128_ALPHA_FACTOR_TEX_ALPHA (6 << 18) +# define R128_ALPHA_FACTOR_NTEX_ALPHA (7 << 18) +# define R128_ALPHA_FACTOR_MASK (15 << 18) +# define R128_INP_FACTOR_A_CONST_ALPHA (1 << 25) +# define R128_INP_FACTOR_A_INT_ALPHA (2 << 25) +# define R128_INP_FACTOR_A_MASK (7 << 25) +#define R128_TEX_SIZE_PITCH_C 0x1cb8 +# define R128_TEX_PITCH_SHIFT 0 +# define R128_TEX_SIZE_SHIFT 4 +# define R128_TEX_HEIGHT_SHIFT 8 +# define R128_TEX_MIN_SIZE_SHIFT 12 +# define R128_SEC_TEX_PITCH_SHIFT 16 +# define R128_SEC_TEX_SIZE_SHIFT 20 +# define R128_SEC_TEX_HEIGHT_SHIFT 24 +# define R128_SEC_TEX_MIN_SIZE_SHIFT 28 +# define R128_TEX_PITCH_MASK (0x0f << 0) +# define R128_TEX_SIZE_MASK (0x0f << 4) +# define R128_TEX_HEIGHT_MASK (0x0f << 8) +# define R128_TEX_MIN_SIZE_MASK (0x0f << 12) +# define R128_SEC_TEX_PITCH_MASK (0x0f << 16) +# define R128_SEC_TEX_SIZE_MASK (0x0f << 20) +# define R128_SEC_TEX_HEIGHT_MASK (0x0f << 24) +# define R128_SEC_TEX_MIN_SIZE_MASK (0x0f << 28) +# define R128_TEX_SIZE_PITCH_SHIFT 0 +# define R128_SEC_TEX_SIZE_PITCH_SHIFT 16 +# define R128_TEX_SIZE_PITCH_MASK (0xffff << 0) +# define R128_SEC_TEX_SIZE_PITCH_MASK (0xffff << 16) +#define R128_PRIM_TEX_0_OFFSET_C 0x1cbc +#define R128_PRIM_TEX_1_OFFSET_C 0x1cc0 +#define R128_PRIM_TEX_2_OFFSET_C 0x1cc4 +#define R128_PRIM_TEX_3_OFFSET_C 0x1cc8 +#define R128_PRIM_TEX_4_OFFSET_C 0x1ccc +#define R128_PRIM_TEX_5_OFFSET_C 0x1cd0 +#define R128_PRIM_TEX_6_OFFSET_C 0x1cd4 +#define R128_PRIM_TEX_7_OFFSET_C 0x1cd8 +#define R128_PRIM_TEX_8_OFFSET_C 0x1cdc +#define R128_PRIM_TEX_9_OFFSET_C 0x1ce0 +#define R128_PRIM_TEX_10_OFFSET_C 0x1ce4 +# define R128_TEX_NO_TILE (0 << 30) +# define R128_TEX_TILED_BY_HOST (1 << 30) +# define R128_TEX_TILED_BY_STORAGE (2 << 30) +# define R128_TEX_TILED_BY_STORAGE2 (3 << 30) + +#define R128_SEC_TEX_CNTL_C 0x1d00 +# define R128_SEC_SELECT_PRIM_ST (0 << 0) +# define R128_SEC_SELECT_SEC_ST (1 << 0) +#define R128_SEC_TEX_COMBINE_CNTL_C 0x1d04 +# define R128_INPUT_FACTOR_PREV_COLOR (8 << 10) +# define R128_INPUT_FACTOR_PREV_ALPHA (9 << 10) +# define R128_INP_FACTOR_A_PREV_ALPHA (4 << 25) +#define R128_SEC_TEX_0_OFFSET_C 0x1d08 +#define R128_SEC_TEX_1_OFFSET_C 0x1d0c +#define R128_SEC_TEX_2_OFFSET_C 0x1d10 +#define R128_SEC_TEX_3_OFFSET_C 0x1d14 +#define R128_SEC_TEX_4_OFFSET_C 0x1d18 +#define R128_SEC_TEX_5_OFFSET_C 0x1d1c +#define R128_SEC_TEX_6_OFFSET_C 0x1d20 +#define R128_SEC_TEX_7_OFFSET_C 0x1d24 +#define R128_SEC_TEX_8_OFFSET_C 0x1d28 +#define R128_SEC_TEX_9_OFFSET_C 0x1d2c +#define R128_SEC_TEX_10_OFFSET_C 0x1d30 +#define R128_CONSTANT_COLOR_C 0x1d34 +# define R128_CONSTANT_BLUE_SHIFT 0 +# define R128_CONSTANT_GREEN_SHIFT 8 +# define R128_CONSTANT_RED_SHIFT 16 +# define R128_CONSTANT_ALPHA_SHIFT 24 +#define R128_PRIM_TEXTURE_BORDER_COLOR_C 0x1d38 +# define R128_PRIM_TEX_BORDER_BLUE_SHIFT 0 +# define R128_PRIM_TEX_BORDER_GREEN_SHIFT 8 +# define R128_PRIM_TEX_BORDER_RED_SHIFT 16 +# define R128_PRIM_TEX_BORDER_ALPHA_SHIFT 24 +#define R128_SEC_TEXTURE_BORDER_COLOR_C 0x1d3c +# define R128_SEC_TEX_BORDER_BLUE_SHIFT 0 +# define R128_SEC_TEX_BORDER_GREEN_SHIFT 8 +# define R128_SEC_TEX_BORDER_RED_SHIFT 16 +# define R128_SEC_TEX_BORDER_ALPHA_SHIFT 24 +#define R128_STEN_REF_MASK_C 0x1d40 +# define R128_STEN_REFERENCE_SHIFT 0 +# define R128_STEN_MASK_SHIFT 16 +# define R128_STEN_WRITE_MASK_SHIFT 24 +#define R128_PLANE_3D_MASK_C 0x1d44 +#define R128_TEX_CACHE_STAT_COUNT 0x1974 + + + /* Constants */ +#define R128_AGP_TEX_OFFSET 0x02000000 + +#define R128_LAST_FRAME_REG R128_GUI_SCRATCH_REG0 + + /* CCE packet types */ +#define R128_CCE_PACKET0 0x00000000 +#define R128_CCE_PACKET0_ONE_REG_WR 0x00008000 +#define R128_CCE_PACKET1 0x40000000 +#define R128_CCE_PACKET2 0x80000000 +#define R128_CCE_PACKET3 0xC0000000 +#define R128_CCE_PACKET3_NOP 0xC0001000 +#define R128_CCE_PACKET3_PAINT 0xC0001100 +#define R128_CCE_PACKET3_BITBLT 0xC0001200 +#define R128_CCE_PACKET3_SMALLTEXT 0xC0001300 +#define R128_CCE_PACKET3_HOSTDATA_BLT 0xC0001400 +#define R128_CCE_PACKET3_POLYLINE 0xC0001500 +#define R128_CCE_PACKET3_SCALING 0xC0001600 +#define R128_CCE_PACKET3_TRANS_SCALING 0xC0001700 +#define R128_CCE_PACKET3_POLYSCANLINES 0xC0001800 +#define R128_CCE_PACKET3_NEXT_CHAR 0xC0001900 +#define R128_CCE_PACKET3_PAINT_MULTI 0xC0001A00 +#define R128_CCE_PACKET3_BITBLT_MULTI 0xC0001B00 +#define R128_CCE_PACKET3_PLY_NEXTSCAN 0xC0001D00 +#define R128_CCE_PACKET3_SET_SCISSORS 0xC0001E00 +#define R128_CCE_PACKET3_SET_MODE24BPP 0xC0001F00 +#define R128_CCE_PACKET3_CNTL_PAINT 0xC0009100 +#define R128_CCE_PACKET3_CNTL_BITBLT 0xC0009200 +#define R128_CCE_PACKET3_CNTL_SMALLTEXT 0xC0009300 +#define R128_CCE_PACKET3_CNTL_HOSTDATA_BLT 0xC0009400 +#define R128_CCE_PACKET3_CNTL_POLYLINE 0xC0009500 +#define R128_CCE_PACKET3_CNTL_SCALING 0xC0009600 +#define R128_CCE_PACKET3_CNTL_TRANS_SCALING 0xC0009700 +#define R128_CCE_PACKET3_CNTL_POLYSCANLINES 0xC0009800 +#define R128_CCE_PACKET3_CNTL_NEXT_CHAR 0xC0009900 +#define R128_CCE_PACKET3_CNTL_PAINT_MULTI 0xC0009A00 +#define R128_CCE_PACKET3_CNTL_BITBLT_MULTI 0xC0009B00 +#define R128_CCE_PACKET3_CNTL_TRANS_BITBLT 0xC0009C00 +#define R128_CCE_PACKET3_3D_SAVE_CONTEXT 0xC0002000 +#define R128_CCE_PACKET3_3D_PLAY_CONTEXT 0xC0002100 +#define R128_CCE_PACKET3_3D_RNDR_GEN_INDX_PRIM 0xC0002300 +#define R128_CCE_PACKET3_3D_RNDR_GEN_PRIM 0xC0002500 +#define R128_CCE_PACKET3_LOAD_PALETTE 0xC0002C00 +#define R128_CCE_PACKET3_PURGE 0xC0002D00 +#define R128_CCE_PACKET3_NEXT_VERTEX_BUNDLE 0xC0002E00 +# define R128_CCE_PACKET_MASK 0xC0000000 +# define R128_CCE_PACKET_COUNT_MASK 0x3fff0000 +# define R128_CCE_PACKET_MAX_DWORDS (1 << 12) +# define R128_CCE_PACKET0_REG_MASK 0x000007ff +# define R128_CCE_PACKET1_REG0_MASK 0x000007ff +# define R128_CCE_PACKET1_REG1_MASK 0x003ff800 + +#define R128_CCE_VC_FRMT_RHW 0x00000001 +#define R128_CCE_VC_FRMT_DIFFUSE_BGR 0x00000002 +#define R128_CCE_VC_FRMT_DIFFUSE_A 0x00000004 +#define R128_CCE_VC_FRMT_DIFFUSE_ARGB 0x00000008 +#define R128_CCE_VC_FRMT_SPEC_BGR 0x00000010 +#define R128_CCE_VC_FRMT_SPEC_F 0x00000020 +#define R128_CCE_VC_FRMT_SPEC_FRGB 0x00000040 +#define R128_CCE_VC_FRMT_S_T 0x00000080 +#define R128_CCE_VC_FRMT_S2_T2 0x00000100 +#define R128_CCE_VC_FRMT_RHW2 0x00000200 + +#define R128_CCE_VC_CNTL_PRIM_TYPE_NONE 0x00000000 +#define R128_CCE_VC_CNTL_PRIM_TYPE_POINT 0x00000001 +#define R128_CCE_VC_CNTL_PRIM_TYPE_LINE 0x00000002 +#define R128_CCE_VC_CNTL_PRIM_TYPE_POLY_LINE 0x00000003 +#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_LIST 0x00000004 +#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_FAN 0x00000005 +#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_STRIP 0x00000006 +#define R128_CCE_VC_CNTL_PRIM_TYPE_TRI_TYPE2 0x00000007 +#define R128_CCE_VC_CNTL_PRIM_WALK_IND 0x00000010 +#define R128_CCE_VC_CNTL_PRIM_WALK_LIST 0x00000020 +#define R128_CCE_VC_CNTL_PRIM_WALK_RING 0x00000030 +#define R128_CCE_VC_CNTL_NUM_SHIFT 16 + +/* hmm copyed blindly (no specs) from radeon.h ... */ +#define R128_RE_TOP_LEFT 0x26c0 +# define R128_RE_LEFT_SHIFT 0 +# define R128_RE_TOP_SHIFT 16 +#define R128_RE_WIDTH_HEIGHT 0x1c44 +# define R128_RE_WIDTH_SHIFT 0 +# define R128_RE_HEIGHT_SHIFT 16 + +#endif diff --git a/src/mesa/drivers/dri/r128/server/r128_sarea.h b/src/mesa/drivers/dri/r128/server/r128_sarea.h new file mode 100644 index 0000000000..8a9f3a4176 --- /dev/null +++ b/src/mesa/drivers/dri/r128/server/r128_sarea.h @@ -0,0 +1,195 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_sarea.h,v 1.7 2002/02/16 21:26:35 herrb Exp $ */ +/* + * Copyright 1999, 2000 ATI Technologies Inc., Markham, Ontario, + * Precision Insight, Inc., Cedar Park, Texas, and + * VA Linux Systems Inc., Fremont, California. + * + * 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, sublicense, 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, PRECISION INSIGHT, 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. + */ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef _R128_SAREA_H_ +#define _R128_SAREA_H_ + +/* WARNING: If you change any of these defines, make sure to change the + * defines in the kernel file (r128_drm.h) + */ +#ifndef __R128_SAREA_DEFINES__ +#define __R128_SAREA_DEFINES__ + +/* What needs to be changed for the current vertex buffer? + */ +#define R128_UPLOAD_CONTEXT 0x001 +#define R128_UPLOAD_SETUP 0x002 +#define R128_UPLOAD_TEX0 0x004 +#define R128_UPLOAD_TEX1 0x008 +#define R128_UPLOAD_TEX0IMAGES 0x010 +#define R128_UPLOAD_TEX1IMAGES 0x020 +#define R128_UPLOAD_CORE 0x040 +#define R128_UPLOAD_MASKS 0x080 +#define R128_UPLOAD_WINDOW 0x100 +#define R128_UPLOAD_CLIPRECTS 0x200 /* handled client-side */ +#define R128_REQUIRE_QUIESCENCE 0x400 +#define R128_UPLOAD_ALL 0x7ff + +#define R128_FRONT 0x1 +#define R128_BACK 0x2 +#define R128_DEPTH 0x4 + +/* Primitive types + */ +#define R128_POINTS 0x1 +#define R128_LINES 0x2 +#define R128_LINE_STRIP 0x3 +#define R128_TRIANGLES 0x4 +#define R128_TRIANGLE_FAN 0x5 +#define R128_TRIANGLE_STRIP 0x6 + +/* Vertex/indirect buffer size + */ +#define R128_BUFFER_SIZE 16384 + +/* Byte offsets for indirect buffer data + */ +#define R128_INDEX_PRIM_OFFSET 20 +#define R128_HOSTDATA_BLIT_OFFSET 32 + +/* Keep these small for testing + */ +#define R128_NR_SAREA_CLIPRECTS 12 + +/* There are 2 heaps (local/AGP). Each region within a heap is a + * minimum of 64k, and there are at most 64 of them per heap. + */ +#define R128_CARD_HEAP 0 +#define R128_AGP_HEAP 1 +#define R128_NR_TEX_HEAPS 2 +#define R128_NR_TEX_REGIONS 64 +#define R128_LOG_TEX_GRANULARITY 16 + +#define R128_NR_CONTEXT_REGS 12 + +#define R128_MAX_TEXTURE_LEVELS 11 +#define R128_MAX_TEXTURE_UNITS 2 + +#endif /* __R128_SAREA_DEFINES__ */ + +typedef struct { + /* Context state - can be written in one large chunk */ + unsigned int dst_pitch_offset_c; + unsigned int dp_gui_master_cntl_c; + unsigned int sc_top_left_c; + unsigned int sc_bottom_right_c; + unsigned int z_offset_c; + unsigned int z_pitch_c; + unsigned int z_sten_cntl_c; + unsigned int tex_cntl_c; + unsigned int misc_3d_state_cntl_reg; + unsigned int texture_clr_cmp_clr_c; + unsigned int texture_clr_cmp_msk_c; + unsigned int fog_color_c; + + /* Texture state */ + unsigned int tex_size_pitch_c; + unsigned int constant_color_c; + + /* Setup state */ + unsigned int pm4_vc_fpu_setup; + unsigned int setup_cntl; + + /* Mask state */ + unsigned int dp_write_mask; + unsigned int sten_ref_mask_c; + unsigned int plane_3d_mask_c; + + /* Window state */ + unsigned int window_xy_offset; + + /* Core state */ + unsigned int scale_3d_cntl; +} r128_context_regs_t; + +/* Setup registers for each texture unit + */ +typedef struct { + unsigned int tex_cntl; + unsigned int tex_combine_cntl; + unsigned int tex_size_pitch; + unsigned int tex_offset[R128_MAX_TEXTURE_LEVELS]; + unsigned int tex_border_color; +} r128_texture_regs_t; + +typedef struct { + /* The channel for communication of state information to the kernel + * on firing a vertex buffer. + */ + r128_context_regs_t ContextState; + r128_texture_regs_t TexState[R128_MAX_TEXTURE_UNITS]; + unsigned int dirty; + unsigned int vertsize; + unsigned int vc_format; + +#if defined(XF86DRI) | defined(_SOLO) + /* The current cliprects, or a subset thereof. + */ + XF86DRIClipRectRec boxes[R128_NR_SAREA_CLIPRECTS]; + unsigned int nbox; +#endif + + /* Counters for throttling of rendering clients. + */ + unsigned int last_frame; + unsigned int last_dispatch; + + /* Maintain an LRU of contiguous regions of texture space. If you + * think you own a region of texture memory, and it has an age + * different to the one you set, then you are mistaken and it has + * been stolen by another client. If global texAge hasn't changed, + * there is no need to walk the list. + * + * These regions can be used as a proxy for the fine-grained texture + * information of other clients - by maintaining them in the same + * lru which is used to age their own textures, clients have an + * approximate lru for the whole of global texture space, and can + * make informed decisions as to which areas to kick out. There is + * no need to choose whether to kick out your own texture or someone + * else's - simply eject them all in LRU order. + */ + /* Last elt is sentinal */ + drmTextureRegion texList[R128_NR_TEX_HEAPS][R128_NR_TEX_REGIONS+1]; + /* last time texture was uploaded */ + unsigned int texAge[R128_NR_TEX_HEAPS]; + + int ctxOwner; /* last context to upload state */ + int pfAllowPageFlip; /* set by the 2d driver, read by the client */ + int pfCurrentPage; /* set by kernel, read by others */ +} R128SAREAPriv, *R128SAREAPrivPtr; + +#endif diff --git a/src/mesa/drivers/dri/r128/server/r128_version.h b/src/mesa/drivers/dri/r128/server/r128_version.h new file mode 100644 index 0000000000..589d8d40bc --- /dev/null +++ b/src/mesa/drivers/dri/r128/server/r128_version.h @@ -0,0 +1,60 @@ +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/r128_version.h,v 1.6 2003/01/01 19:16:35 tsi Exp $ */ +/* + * Copyright 2000 through 2003 by Marc Aurele La France (TSI @ UQV), tsi@xfree86.org + * + * Permission to use, copy, modify, distribute, and sell this software and its + * documentation for any purpose is hereby granted without fee, provided that + * the above copyright notice appear in all copies and that both that copyright + * notice and this permission notice appear in supporting documentation, and + * that the name of Marc Aurele La France not be used in advertising or + * publicity pertaining to distribution of the software without specific, + * written prior permission. Marc Aurele La France makes no representations + * about the suitability of this software for any purpose. It is provided + * "as-is" without express or implied warranty. + * + * MARC AURELE LA FRANCE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO + * EVENT SHALL MARC AURELE LA FRANCE BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, + * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER + * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _R128_VERSION_H_ +#define _R128_VERSION_H_ 1 + +#undef R128_NAME +#undef R128_DRIVER_NAME +#undef R128_VERSION_MAJOR +#undef R128_VERSION_MINOR +#undef R128_VERSION_PATCH +#undef R128_VERSION_CURRENT +#undef R128_VERSION_EVALUATE +#undef R128_VERSION_STRINGIFY +#undef R128_VERSION_NAME + +#define R128_NAME "R128" +#define R128_DRIVER_NAME "r128" + +#define R128_VERSION_MAJOR 4 +#define R128_VERSION_MINOR 0 +#define R128_VERSION_PATCH 1 + +#ifndef R128_VERSION_EXTRA +#define R128_VERSION_EXTRA "" +#endif + +#define R128_VERSION_CURRENT \ + ((R128_VERSION_MAJOR << 20) | \ + (R128_VERSION_MINOR << 10) | \ + (R128_VERSION_PATCH)) + +#define R128_VERSION_EVALUATE(__x) #__x +#define R128_VERSION_STRINGIFY(_x) R128_VERSION_EVALUATE(_x) +#define R128_VERSION_NAME \ + R128_VERSION_STRINGIFY(R128_VERSION_MAJOR) "." \ + R128_VERSION_STRINGIFY(R128_VERSION_MINOR) "." \ + R128_VERSION_STRINGIFY(R128_VERSION_MINOR) R128_VERSION_EXTRA + +#endif /* _R128_VERSION_H_ */ diff --git a/src/mesa/drivers/dri/r200/Makefile.X11 b/src/mesa/drivers/dri/r200/Makefile.X11 index b182ba559a..f1887b5914 100644 --- a/src/mesa/drivers/dri/r200/Makefile.X11 +++ b/src/mesa/drivers/dri/r200/Makefile.X11 @@ -1,4 +1,4 @@ -# $Id: Makefile.X11,v 1.1 2003/08/06 17:59:57 keithw Exp $ +# $Id: Makefile.X11,v 1.2 2003/08/22 20:11:45 brianp Exp $ # Mesa 3-D graphics library # Version: 5.0 @@ -6,8 +6,10 @@ TOP = ../../../../.. +default: linux-solo + SHARED_INCLUDES = $(INCLUDE_DIRS) -I. -I../common -Iserver -MINIGLX_INCLUDES = -I$(TOP)/src/miniglx +MINIGLX_INCLUDES = -I$(TOP)/src/glx/mini DEFINES += \ -D_HAVE_SWRAST=1 \ @@ -62,7 +64,7 @@ WINOBJ=$(MESABUILDDIR)/dri/dri.a WINLIB= else WINOBJ= -WINLIB=-L$(MESA)/src/miniglx +WINLIB=-L$(MESA)/src/glx/mini endif ASM_SOURCES = @@ -107,7 +109,7 @@ INCLUDE_DIRS = \ ##### TARGETS ##### -targets: r200_dri.so +targets: depend r200_dri.so r200_dri.so: $(SYMLINKS) $(OBJECTS) $(MESA_MODULES) $(WINOBJ) Makefile.X11 rm -f $@ && gcc -o $@ -shared $(OBJECTS) $(MESA_MODULES) $(WINOBJ) $(WINLIB) -lc $(GL_LIB_DEPS) @@ -116,8 +118,8 @@ r200_dri.so: $(SYMLINKS) $(OBJECTS) $(MESA_MODULES) $(WINOBJ) Makefile.X11 # Run 'make -f Makefile.X11 dep' to update the dependencies if you change # what's included by any source file. -dep: $(C_SOURCES) $(ASM_SOURCES) - makedepend -fdepend -Y $(SHARED_INCLUDES) \ +depend: $(C_SOURCES) $(ASM_SOURCES) + makedepend -fdepend -Y $(SHARED_INCLUDES) $(MINIGLX_INCLUDES) \ $(C_SOURCES) $(ASM_SOURCES) @@ -128,7 +130,7 @@ tags: # Remove .o and backup files clean: - -rm -f *.o *~ *.o *~ *.so + -rm -f *.o */*.o *~ *.o *~ *.so server/*.o include $(TOP)/Make-config diff --git a/src/mesa/drivers/dri/r200/r200_context.c b/src/mesa/drivers/dri/r200/r200_context.c index c5f23effab..ec95f05e6e 100644 --- a/src/mesa/drivers/dri/r200/r200_context.c +++ b/src/mesa/drivers/dri/r200/r200_context.c @@ -492,8 +492,9 @@ void r200DestroyContext( __DRIcontextPrivate *driContextPriv ) * texture object data. */ int i; - - assert( is_empty_list( & rmesa->swapped ) ); + + /* this assert is wrong. The default textures are always on swap list + assert( is_empty_list( & rmesa->swapped ) ); */ for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) { driDestroyTextureHeap( rmesa->texture_heaps[ i ] ); diff --git a/src/mesa/drivers/dri/r200/r200_context.h b/src/mesa/drivers/dri/r200/r200_context.h index 3802deead9..9e00d7a358 100644 --- a/src/mesa/drivers/dri/r200/r200_context.h +++ b/src/mesa/drivers/dri/r200/r200_context.h @@ -615,7 +615,7 @@ struct r200_swtcl_info { GLuint vertex_size; GLuint vertex_stride_shift; GLuint vertex_format; - char *verts; + GLubyte *verts; /* Fallback rasterization functions */ diff --git a/src/mesa/drivers/dri/r200/r200_ioctl.c b/src/mesa/drivers/dri/r200/r200_ioctl.c index ea67216238..480121a094 100644 --- a/src/mesa/drivers/dri/r200/r200_ioctl.c +++ b/src/mesa/drivers/dri/r200/r200_ioctl.c @@ -320,7 +320,7 @@ static CARD32 r200GetLastFrame(r200ContextPtr rmesa) CARD32 frame; gp.param = RADEON_PARAM_LAST_FRAME; - gp.value = (int *)&frame; + gp.value = &frame; ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_GETPARAM, &gp, sizeof(gp) ); if ( ret ) { @@ -404,7 +404,7 @@ void r200CopyBuffer( const __DRIdrawablePrivate *dPriv ) r200ContextPtr rmesa; GLint nbox, i, ret; GLboolean missed_target; - int64_t ust; + uint64_t ust; assert(dPriv); assert(dPriv->driContextPriv); @@ -616,7 +616,7 @@ static void r200Clear( GLcontext *ctx, GLbitfield mask, GLboolean all, int clear; gp.param = RADEON_PARAM_LAST_CLEAR; - gp.value = (int *)&clear; + gp.value = &clear; ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_GETPARAM, &gp, sizeof(gp) ); diff --git a/src/mesa/drivers/dri/r200/r200_swtcl.c b/src/mesa/drivers/dri/r200/r200_swtcl.c index 6a436509a0..dd4025235b 100644 --- a/src/mesa/drivers/dri/r200/r200_swtcl.c +++ b/src/mesa/drivers/dri/r200/r200_swtcl.c @@ -446,7 +446,7 @@ static __inline void *r200AllocDmaLowVerts( r200ContextPtr rmesa, { - GLubyte *head = rmesa->dma.current.address + rmesa->dma.current.ptr; + char *head = rmesa->dma.current.address + rmesa->dma.current.ptr; rmesa->dma.current.ptr += bytes; rmesa->swtcl.numverts += nverts; return head; @@ -1260,7 +1260,7 @@ void r200InitSwtcl( GLcontext *ctx ) tnl->Driver.Render.ResetLineStipple = r200ResetLineStipple; tnl->Driver.Render.BuildVertices = r200BuildVertices; - rmesa->swtcl.verts = (char *)ALIGN_MALLOC( size * 16 * 4, 32 ); + rmesa->swtcl.verts = (GLubyte *)ALIGN_MALLOC( size * 16 * 4, 32 ); rmesa->swtcl.RenderIndex = ~0; rmesa->swtcl.render_primitive = GL_TRIANGLES; rmesa->swtcl.hw_primitive = 0; diff --git a/src/mesa/drivers/dri/r200/r200_tcl.c b/src/mesa/drivers/dri/r200/r200_tcl.c index 994221d80c..9869ad6196 100644 --- a/src/mesa/drivers/dri/r200/r200_tcl.c +++ b/src/mesa/drivers/dri/r200/r200_tcl.c @@ -102,33 +102,23 @@ static GLboolean discrete_prim[0x10] = { }; -#define LOCAL_VARS r200ContextPtr rmesa = R200_CONTEXT(ctx);rmesa = rmesa -#define ELTS_VARS GLushort *dest +#define LOCAL_VARS r200ContextPtr rmesa = R200_CONTEXT(ctx) +#define ELT_TYPE GLushort #define ELT_INIT(prim, hw_prim) \ r200TclPrimitive( ctx, prim, hw_prim | R200_VF_PRIM_WALK_IND ) -#define GET_ELTS() rmesa->tcl.Elts +#define GET_MESA_ELTS() rmesa->tcl.Elts -#define NEW_PRIMITIVE() R200_NEWPRIM( rmesa ) -#define NEW_BUFFER() r200RefillCurrentDmaRegion( rmesa ) - /* Don't really know how many elts will fit in what's left of cmdbuf, * as there is state to emit, etc: */ -#if 0 -#define GET_CURRENT_VB_MAX_ELTS() \ - ((R200_CMD_BUF_SZ - (rmesa->store.cmd_used + 16)) / 2) -#define GET_SUBSEQUENT_VB_MAX_ELTS() ((R200_CMD_BUF_SZ - 16) / 2) -#else /* Testing on isosurf shows a maximum around here. Don't know if it's * the card or driver or kernel module that is causing the behaviour. */ -#define GET_CURRENT_VB_MAX_ELTS() 300 -#define GET_SUBSEQUENT_VB_MAX_ELTS() 300 -#endif +#define GET_MAX_HW_ELTS() 300 #define RESET_STIPPLE() do { \ R200_STATECHANGE( rmesa, lin ); \ @@ -147,32 +137,22 @@ static GLboolean discrete_prim[0x10] = { } while (0) -/* How do you extend an existing primitive? - */ -#define ALLOC_ELTS(nr) \ -do { \ - if (rmesa->dma.flush == r200FlushElts && \ - rmesa->store.cmd_used + nr*2 < R200_CMD_BUF_SZ) { \ - \ - dest = (GLushort *)(rmesa->store.cmd_buf + \ - rmesa->store.cmd_used); \ - rmesa->store.cmd_used += nr*2; \ - } \ - else { \ - if (rmesa->dma.flush) \ - rmesa->dma.flush( rmesa ); \ - \ - r200EmitAOS( rmesa, \ - rmesa->tcl.aos_components, \ - rmesa->tcl.nr_aos_components, \ - 0 ); \ - \ - dest = r200AllocEltsOpenEnded( rmesa, \ - rmesa->tcl.hw_primitive, \ - nr ); \ - } \ -} while (0) +#define ALLOC_ELTS(nr) r200AllocElts( rmesa, nr ) +static GLushort *r200AllocElts( r200ContextPtr rmesa, GLuint nr ) +{ + if (rmesa->dma.flush) + rmesa->dma.flush( rmesa ); + + r200EmitAOS( rmesa, + rmesa->tcl.aos_components, + rmesa->tcl.nr_aos_components, 0 ); + + return r200AllocEltsOpenEnded( rmesa, rmesa->tcl.hw_primitive, nr ); +} + + +#define CLOSE_ELTS() R200_NEWPRIM( rmesa ) /* TODO: Try to extend existing primitive if both are identical, @@ -217,17 +197,15 @@ static void EMIT_PRIM( GLcontext *ctx, #ifdef MESA_BIG_ENDIAN /* We could do without (most of) this ugliness if dest was always 32 bit word aligned... */ -#define EMIT_ELT(offset, x) do { \ +#define EMIT_ELT(dest, offset, x) do { \ int off = offset + ( ( (GLuint)dest & 0x2 ) >> 1 ); \ GLushort *des = (GLushort *)( (GLuint)dest & ~0x2 ); \ (des)[ off + 1 - 2 * ( off & 1 ) ] = (GLushort)(x); } while (0) #else -#define EMIT_ELT(offset, x) (dest)[offset] = (GLushort) (x) +#define EMIT_ELT(dest, offset, x) (dest)[offset] = (GLushort) (x) #endif -#define EMIT_TWO_ELTS(offset, x, y) *(GLuint *)(dest+offset) = ((y)<<16)|(x); -#define INCR_ELTS( nr ) dest += nr -#define RELEASE_ELT_VERTS() \ - r200ReleaseArrays( ctx, ~0 ) + +#define EMIT_TWO_ELTS(dest, offset, x, y) *(GLuint *)((dest)+offset) = ((y)<<16)|(x); diff --git a/src/mesa/drivers/dri/radeon/Makefile.X11 b/src/mesa/drivers/dri/radeon/Makefile.X11 new file mode 100644 index 0000000000..b73abe8f51 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/Makefile.X11 @@ -0,0 +1,154 @@ +# $Id: Makefile.X11,v 1.1 2003/08/22 20:11:45 brianp Exp $ + +# Mesa 3-D graphics library +# Version: 5.0 +# Copyright (C) 1995-2002 Brian Paul + +TOP = ../../../../.. + +default: linux-solo + +SHARED_INCLUDES = $(INCLUDE_DIRS) -I. -I../common -Iserver +MINIGLX_INCLUDES = -I$(TOP)/src/glx/mini + +ifeq ($(EMBEDDED),true) +TARGET = radeon_es_dri.so +DEFINES += \ + -D_EMBEDDED \ + -D_HAVE_SWRAST=0 \ + -D_HAVE_SWTNL=0 \ + -D_HAVE_SANITY=0 \ + -D_HAVE_CODEGEN=0 \ + -D_HAVE_LIGHTING=0 \ + -D_HAVE_TEXGEN=0 \ + -D_HAVE_USERCLIP=0 \ + -DGLX_DIRECT_RENDERING +else +TARGET = radeon_dri.so +DEFINES += \ + -D_HAVE_SWRAST=1 \ + -D_HAVE_SWTNL=1 \ + -D_HAVE_SANITY=1 \ + -D_HAVE_CODEGEN=1 \ + -D_HAVE_LIGHTING=1 \ + -D_HAVE_TEXGEN=1 \ + -D_HAVE_USERCLIP=1 \ + -DGLX_DIRECT_RENDERING +endif + +MESA_MODULES = $(TOP)/src/mesa/mesa.a + +MINIGLX_SOURCES = server/radeon_dri.c + +DRIVER_SOURCES = radeon_context.c \ + radeon_ioctl.c \ + radeon_lock.c \ + radeon_screen.c \ + radeon_state.c \ + radeon_state_init.c \ + ../common/mm.c \ + ../common/utils.c \ + ../common/texmem.c \ + ../common/vblank.c + +SUBSET_DRIVER_SOURCES = \ + radeon_subset_bitmap.c \ + radeon_subset_readpix.c \ + radeon_subset_select.c \ + radeon_subset_tex.c \ + radeon_subset_vtx.c + +FULL_DRIVER_SOURCES = \ + radeon_tex.c \ + radeon_texmem.c \ + radeon_texstate.c \ + radeon_tcl.c \ + radeon_swtcl.c \ + radeon_span.c \ + radeon_maos.c \ + radeon_sanity.c \ + radeon_compat.c \ + radeon_vtxfmt.c \ + radeon_vtxfmt_c.c \ + radeon_vtxfmt_sse.c \ + radeon_vtxfmt_x86.c + + +INCLUDES = $(MINIGLX_INCLUDES) \ + $(SHARED_INCLUDES) + + +ifeq ($(EMBEDDED),true) +C_SOURCES = $(DRIVER_SOURCES) \ + $(SUBSET_DRIVER_SOURCES) \ + $(MINIGLX_SOURCES) +else +C_SOURCES = $(DRIVER_SOURCES) \ + $(FULL_DRIVER_SOURCES) \ + $(MINIGLX_SOURCES) +endif + + +ifeq ($(WINDOW_SYSTEM),dri) +WINOBJ=$(MESABUILDDIR)/dri/dri.a +WINLIB= +else +WINOBJ= +WINLIB=-L$(MESA)/src/glx/mini +endif + +ASM_SOURCES = +OBJECTS = $(C_SOURCES:.c=.o) \ + $(ASM_SOURCES:.S=.o) + +### Include directories + +INCLUDE_DIRS = \ + -I$(TOP)/include \ + -I$(TOP)/src/mesa \ + -I$(TOP)/src/mesa/main \ + -I$(TOP)/src/mesa/glapi \ + -I$(TOP)/src/mesa/math \ + -I$(TOP)/src/mesa/transform \ + -I$(TOP)/src/mesa/swrast \ + -I$(TOP)/src/mesa/swrast_setup + + +##### RULES ##### + +.c.o: + $(CC) -c $(SHARED_INCLUDES) $(MINIGLX_INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@ + +.S.o: + $(CC) -c $(SHARED_INCLUDES) $(MINIGLX_INCLUDES) $(CFLAGS) $(DEFINES) $< -o $@ + + +##### TARGETS ##### + +targets: depend $(TARGET) + +$(TARGET): $(OBJECTS) $(MESA_MODULES) $(WINOBJ) Makefile.X11 + rm -f $@ && gcc -o $@ -shared $(OBJECTS) $(MESA_MODULES) $(WINOBJ) $(WINLIB) -lc -lm + rm -f $(TOP)/lib/$(TARGET) && \ + install $(TARGET) $(TOP)/lib/$(TARGET) + +# Run 'make -f Makefile.X11 dep' to update the dependencies if you change +# what's included by any source file. +depend: $(C_SOURCES) $(ASM_SOURCES) + makedepend -fdepend -Y $(SHARED_INCLUDES) $(MINIGLX_INCLUDES)\ + $(C_SOURCES) $(ASM_SOURCES) + + +# Emacs tags +tags: + etags `find . -name \*.[ch]` `find ../include` + + +# Remove .o and backup files +clean: + -rm -f *.o *~ *.o *~ *.so server/*.o + + +include $(TOP)/Make-config + +include depend diff --git a/src/mesa/drivers/dri/radeon/radeon_compat.c b/src/mesa/drivers/dri/radeon/radeon_compat.c new file mode 100644 index 0000000000..0c32641530 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_compat.c @@ -0,0 +1,304 @@ +/* $XFree86$ */ +/************************************************************************** + +Copyright 2002 ATI Technologies Inc., Ontario, Canada, and + Tungsten Graphics Inc., Austin, 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, TUNGSTEN GRAPHICS 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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * + */ + +#include "glheader.h" +#include "imports.h" + +#include "radeon_context.h" +#include "radeon_state.h" +#include "radeon_ioctl.h" + + +static struct { + int start; + int len; + const char *name; +} packet[RADEON_MAX_STATE_PACKETS] = { + { RADEON_PP_MISC,7,"RADEON_PP_MISC" }, + { RADEON_PP_CNTL,3,"RADEON_PP_CNTL" }, + { RADEON_RB3D_COLORPITCH,1,"RADEON_RB3D_COLORPITCH" }, + { RADEON_RE_LINE_PATTERN,2,"RADEON_RE_LINE_PATTERN" }, + { RADEON_SE_LINE_WIDTH,1,"RADEON_SE_LINE_WIDTH" }, + { RADEON_PP_LUM_MATRIX,1,"RADEON_PP_LUM_MATRIX" }, + { RADEON_PP_ROT_MATRIX_0,2,"RADEON_PP_ROT_MATRIX_0" }, + { RADEON_RB3D_STENCILREFMASK,3,"RADEON_RB3D_STENCILREFMASK" }, + { RADEON_SE_VPORT_XSCALE,6,"RADEON_SE_VPORT_XSCALE" }, + { RADEON_SE_CNTL,2,"RADEON_SE_CNTL" }, + { RADEON_SE_CNTL_STATUS,1,"RADEON_SE_CNTL_STATUS" }, + { RADEON_RE_MISC,1,"RADEON_RE_MISC" }, + { RADEON_PP_TXFILTER_0,6,"RADEON_PP_TXFILTER_0" }, + { RADEON_PP_BORDER_COLOR_0,1,"RADEON_PP_BORDER_COLOR_0" }, + { RADEON_PP_TXFILTER_1,6,"RADEON_PP_TXFILTER_1" }, + { RADEON_PP_BORDER_COLOR_1,1,"RADEON_PP_BORDER_COLOR_1" }, + { RADEON_PP_TXFILTER_2,6,"RADEON_PP_TXFILTER_2" }, + { RADEON_PP_BORDER_COLOR_2,1,"RADEON_PP_BORDER_COLOR_2" }, + { RADEON_SE_ZBIAS_FACTOR,2,"RADEON_SE_ZBIAS_FACTOR" }, + { RADEON_SE_TCL_OUTPUT_VTX_FMT,11,"RADEON_SE_TCL_OUTPUT_VTX_FMT" }, + { RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED,17,"RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED" }, +}; + + +static void radeonCompatEmitPacket( radeonContextPtr rmesa, + struct radeon_state_atom *state ) +{ + RADEONSAREAPrivPtr sarea = rmesa->sarea; + radeon_context_regs_t *ctx = &sarea->ContextState; + radeon_texture_regs_t *tex0 = &sarea->TexState[0]; + radeon_texture_regs_t *tex1 = &sarea->TexState[1]; + int i; + int *buf = state->cmd; + + for ( i = 0 ; i < state->cmd_size ; ) { + drmRadeonCmdHeader *header = (drmRadeonCmdHeader *)&buf[i++]; + + if (RADEON_DEBUG & DEBUG_STATE) + fprintf(stderr, "%s %d: %s\n", __FUNCTION__, header->packet.packet_id, + packet[(int)header->packet.packet_id].name); + + switch (header->packet.packet_id) { + case RADEON_EMIT_PP_MISC: + ctx->pp_misc = buf[i++]; + ctx->pp_fog_color = buf[i++]; + ctx->re_solid_color = buf[i++]; + ctx->rb3d_blendcntl = buf[i++]; + ctx->rb3d_depthoffset = buf[i++]; + ctx->rb3d_depthpitch = buf[i++]; + ctx->rb3d_zstencilcntl = buf[i++]; + sarea->dirty |= RADEON_UPLOAD_CONTEXT; + break; + case RADEON_EMIT_PP_CNTL: + ctx->pp_cntl = buf[i++]; + ctx->rb3d_cntl = buf[i++]; + ctx->rb3d_coloroffset = buf[i++]; + sarea->dirty |= RADEON_UPLOAD_CONTEXT; + break; + case RADEON_EMIT_RB3D_COLORPITCH: + ctx->rb3d_colorpitch = buf[i++]; + sarea->dirty |= RADEON_UPLOAD_CONTEXT; + break; + case RADEON_EMIT_RE_LINE_PATTERN: + ctx->re_line_pattern = buf[i++]; + ctx->re_line_state = buf[i++]; + sarea->dirty |= RADEON_UPLOAD_LINE; + break; + case RADEON_EMIT_SE_LINE_WIDTH: + ctx->se_line_width = buf[i++]; + sarea->dirty |= RADEON_UPLOAD_LINE; + break; + case RADEON_EMIT_PP_LUM_MATRIX: + ctx->pp_lum_matrix = buf[i++]; + sarea->dirty |= RADEON_UPLOAD_BUMPMAP; + break; + case RADEON_EMIT_PP_ROT_MATRIX_0: + ctx->pp_rot_matrix_0 = buf[i++]; + ctx->pp_rot_matrix_1 = buf[i++]; + sarea->dirty |= RADEON_UPLOAD_BUMPMAP; + break; + case RADEON_EMIT_RB3D_STENCILREFMASK: + ctx->rb3d_stencilrefmask = buf[i++]; + ctx->rb3d_ropcntl = buf[i++]; + ctx->rb3d_planemask = buf[i++]; + sarea->dirty |= RADEON_UPLOAD_MASKS; + break; + case RADEON_EMIT_SE_VPORT_XSCALE: + ctx->se_vport_xscale = buf[i++]; + ctx->se_vport_xoffset = buf[i++]; + ctx->se_vport_yscale = buf[i++]; + ctx->se_vport_yoffset = buf[i++]; + ctx->se_vport_zscale = buf[i++]; + ctx->se_vport_zoffset = buf[i++]; + sarea->dirty |= RADEON_UPLOAD_VIEWPORT; + break; + case RADEON_EMIT_SE_CNTL: + ctx->se_cntl = buf[i++]; + ctx->se_coord_fmt = buf[i++]; + sarea->dirty |= RADEON_UPLOAD_CONTEXT | RADEON_UPLOAD_VERTFMT; + break; + case RADEON_EMIT_SE_CNTL_STATUS: + ctx->se_cntl_status = buf[i++]; + sarea->dirty |= RADEON_UPLOAD_SETUP; + break; + case RADEON_EMIT_RE_MISC: + ctx->re_misc = buf[i++]; + sarea->dirty |= RADEON_UPLOAD_MISC; + break; + case RADEON_EMIT_PP_TXFILTER_0: + tex0->pp_txfilter = buf[i++]; + tex0->pp_txformat = buf[i++]; + tex0->pp_txoffset = buf[i++]; + tex0->pp_txcblend = buf[i++]; + tex0->pp_txablend = buf[i++]; + tex0->pp_tfactor = buf[i++]; + sarea->dirty |= RADEON_UPLOAD_TEX0; + break; + case RADEON_EMIT_PP_BORDER_COLOR_0: + tex0->pp_border_color = buf[i++]; + sarea->dirty |= RADEON_UPLOAD_TEX0; + break; + case RADEON_EMIT_PP_TXFILTER_1: + tex1->pp_txfilter = buf[i++]; + tex1->pp_txformat = buf[i++]; + tex1->pp_txoffset = buf[i++]; + tex1->pp_txcblend = buf[i++]; + tex1->pp_txablend = buf[i++]; + tex1->pp_tfactor = buf[i++]; + sarea->dirty |= RADEON_UPLOAD_TEX1; + break; + case RADEON_EMIT_PP_BORDER_COLOR_1: + tex1->pp_border_color = buf[i++]; + sarea->dirty |= RADEON_UPLOAD_TEX1; + break; + + case RADEON_EMIT_SE_ZBIAS_FACTOR: + i++; + i++; + break; + + case RADEON_EMIT_PP_TXFILTER_2: + case RADEON_EMIT_PP_BORDER_COLOR_2: + case RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT: + case RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED: + default: + /* These states aren't understood by radeon drm 1.1 */ + fprintf(stderr, "Tried to emit unsupported state\n"); + return; + } + } +} + + + +static void radeonCompatEmitStateLocked( radeonContextPtr rmesa ) +{ + struct radeon_state_atom *state, *tmp; + + if (RADEON_DEBUG & (DEBUG_STATE|DEBUG_PRIMS)) + fprintf(stderr, "%s\n", __FUNCTION__); + + if (rmesa->lost_context) { + if (RADEON_DEBUG & (DEBUG_STATE|DEBUG_PRIMS|DEBUG_IOCTL)) + fprintf(stderr, "%s - lost context\n", __FUNCTION__); + + foreach_s( state, tmp, &(rmesa->hw.clean) ) + move_to_tail(&(rmesa->hw.dirty), state ); + + rmesa->lost_context = 0; + } + + foreach_s( state, tmp, &(rmesa->hw.dirty) ) { + if (!state->is_tcl) + radeonCompatEmitPacket( rmesa, state ); + move_to_head( &(rmesa->hw.clean), state ); + } +} + + + +static void radeonCompatEmitPrimitiveLocked( radeonContextPtr rmesa, + GLuint hw_primitive, + GLuint nverts, + XF86DRIClipRectPtr pbox, + GLuint nbox ) +{ + int i; + + for ( i = 0 ; i < nbox ; ) { + int nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS, nbox ); + XF86DRIClipRectPtr b = rmesa->sarea->boxes; + drmRadeonVertex vtx; + + rmesa->sarea->dirty |= RADEON_UPLOAD_CLIPRECTS; + rmesa->sarea->nbox = nr - i; + + for ( ; i < nr ; i++) + *b++ = pbox[i]; + + if (RADEON_DEBUG & DEBUG_IOCTL) + fprintf(stderr, + "RadeonFlushVertexBuffer: prim %x buf %d verts %d " + "disc %d nbox %d\n", + hw_primitive, + rmesa->dma.current.buf->buf->idx, + nverts, + nr == nbox, + rmesa->sarea->nbox ); + + vtx.prim = hw_primitive; + vtx.idx = rmesa->dma.current.buf->buf->idx; + vtx.count = nverts; + vtx.discard = (nr == nbox); + + drmCommandWrite( rmesa->dri.fd, + DRM_RADEON_VERTEX, + &vtx, sizeof(vtx)); + } +} + + + +/* No 'start' for 1.1 vertices ioctl: only one vertex prim/buffer! + */ +void radeonCompatEmitPrimitive( radeonContextPtr rmesa, + GLuint vertex_format, + GLuint hw_primitive, + GLuint nrverts ) +{ + if (RADEON_DEBUG & DEBUG_IOCTL) + fprintf(stderr, "%s\n", __FUNCTION__); + + LOCK_HARDWARE( rmesa ); + + radeonCompatEmitStateLocked( rmesa ); + rmesa->sarea->vc_format = vertex_format; + + if (rmesa->state.scissor.enabled) { + radeonCompatEmitPrimitiveLocked( rmesa, + hw_primitive, + nrverts, + rmesa->state.scissor.pClipRects, + rmesa->state.scissor.numClipRects ); + } + else { + radeonCompatEmitPrimitiveLocked( rmesa, + hw_primitive, + nrverts, + rmesa->pClipRects, + rmesa->numClipRects ); + } + + + UNLOCK_HARDWARE( rmesa ); +} + diff --git a/src/mesa/drivers/dri/radeon/radeon_context.c b/src/mesa/drivers/dri/radeon/radeon_context.c new file mode 100644 index 0000000000..835cecbc3a --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_context.c @@ -0,0 +1,598 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_context.c,v 1.7 2003/02/08 21:26:45 dawes Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "glheader.h" +#include "api_arrayelt.h" +#include "context.h" +#include "simple_list.h" +#include "imports.h" +#include "matrix.h" +#include "extensions.h" + +#include "swrast/swrast.h" +#include "swrast_setup/swrast_setup.h" +#include "array_cache/acache.h" + +#include "tnl/tnl.h" +#include "tnl/t_pipeline.h" + +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_state.h" +#include "radeon_span.h" +#include "radeon_tex.h" +#include "radeon_swtcl.h" +#include "radeon_tcl.h" +#include "radeon_vtxfmt.h" +#include "radeon_maos.h" + +#define DRIVER_DATE "20030328" + +#include "vblank.h" +#include "utils.h" +#ifndef RADEON_DEBUG +int RADEON_DEBUG = (0); +#endif + + + +/* Return the width and height of the given buffer. + */ +static void radeonGetBufferSize( GLframebuffer *buffer, + GLuint *width, GLuint *height ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + LOCK_HARDWARE( rmesa ); + *width = rmesa->dri.drawable->w; + *height = rmesa->dri.drawable->h; + UNLOCK_HARDWARE( rmesa ); +} + +/* Return various strings for glGetString(). + */ +static const GLubyte *radeonGetString( GLcontext *ctx, GLenum name ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + static char buffer[128]; + unsigned offset; + GLuint agp_mode = rmesa->radeonScreen->IsPCI ? 0 : + rmesa->radeonScreen->AGPMode; + + switch ( name ) { + case GL_VENDOR: + return (GLubyte *)"Tungsten Graphics, Inc."; + + case GL_RENDERER: + offset = driGetRendererString( buffer, "Radeon", DRIVER_DATE, + agp_mode ); + + sprintf( & buffer[ offset ], "%s %sTCL", + ( rmesa->dri.drmMinor < 3 ) ? " DRM-COMPAT" : "", + !(rmesa->TclFallback & RADEON_TCL_FALLBACK_TCL_DISABLE) + ? "" : "NO-" ); + + return (GLubyte *)buffer; + + default: + return NULL; + } +} + + +/* Extension strings exported by the R100 driver. + */ +static const char * const card_extensions[] = +{ + "GL_ARB_multisample", + "GL_ARB_multitexture", + "GL_ARB_texture_border_clamp", + "GL_ARB_texture_compression", + "GL_ARB_texture_env_add", + "GL_ARB_texture_env_combine", + "GL_ARB_texture_env_dot3", + "GL_ARB_texture_mirrored_repeat", + "GL_EXT_blend_logic_op", + "GL_EXT_blend_subtract", + "GL_EXT_secondary_color", + "GL_EXT_texture_edge_clamp", + "GL_EXT_texture_env_add", + "GL_EXT_texture_env_combine", + "GL_EXT_texture_env_dot3", + "GL_EXT_texture_filter_anisotropic", + "GL_EXT_texture_lod_bias", + "GL_ATI_texture_env_combine3", + "GL_ATI_texture_mirror_once", + "GL_IBM_texture_mirrored_repeat", + "GL_MESA_ycbcr_texture", + "GL_NV_blend_square", + "GL_SGIS_generate_mipmap", + "GL_SGIS_texture_border_clamp", + "GL_SGIS_texture_edge_clamp", + NULL +}; + +extern const struct gl_pipeline_stage _radeon_texrect_stage; +extern const struct gl_pipeline_stage _radeon_render_stage; +extern const struct gl_pipeline_stage _radeon_tcl_stage; + +static const struct gl_pipeline_stage *radeon_pipeline[] = { + + /* Try and go straight to t&l + */ + &_radeon_tcl_stage, + + /* Catch any t&l fallbacks + */ + &_tnl_vertex_transform_stage, + &_tnl_normal_transform_stage, + &_tnl_lighting_stage, + &_tnl_fog_coordinate_stage, + &_tnl_texgen_stage, + &_tnl_texture_transform_stage, + + /* Scale texture rectangle to 0..1. + */ + &_radeon_texrect_stage, + + &_radeon_render_stage, + &_tnl_render_stage, /* FALLBACK: */ + 0, +}; + + + +/* Initialize the driver's misc functions. + */ +static void radeonInitDriverFuncs( GLcontext *ctx ) +{ + ctx->Driver.GetBufferSize = radeonGetBufferSize; + ctx->Driver.ResizeBuffers = _swrast_alloc_buffers; + ctx->Driver.GetString = radeonGetString; + + ctx->Driver.Error = NULL; + ctx->Driver.DrawPixels = NULL; + ctx->Driver.Bitmap = NULL; +} + +static const struct dri_debug_control debug_control[] = +{ + { "fall", DEBUG_FALLBACKS }, + { "tex", DEBUG_TEXTURE }, + { "ioctl", DEBUG_IOCTL }, + { "prim", DEBUG_PRIMS }, + { "vert", DEBUG_VERTS }, + { "state", DEBUG_STATE }, + { "code", DEBUG_CODEGEN }, + { "vfmt", DEBUG_VFMT }, + { "vtxf", DEBUG_VFMT }, + { "verb", DEBUG_VERBOSE }, + { "dri", DEBUG_DRI }, + { "dma", DEBUG_DMA }, + { "san", DEBUG_SANITY }, + { NULL, 0 } +}; + + +static int +get_ust_nop( uint64_t * ust ) +{ + *ust = 1; + return 0; +} + + +/* Create the device specific context. + */ +GLboolean +radeonCreateContext( const __GLcontextModes *glVisual, + __DRIcontextPrivate *driContextPriv, + void *sharedContextPrivate) +{ + __DRIscreenPrivate *sPriv = driContextPriv->driScreenPriv; + radeonScreenPtr screen = (radeonScreenPtr)(sPriv->private); + radeonContextPtr rmesa; + GLcontext *ctx, *shareCtx; + int i; + + assert(glVisual); + assert(driContextPriv); + assert(screen); + + /* Allocate the Radeon context */ + rmesa = (radeonContextPtr) CALLOC( sizeof(*rmesa) ); + if ( !rmesa ) + return GL_FALSE; + + /* Allocate the Mesa context */ + if (sharedContextPrivate) + shareCtx = ((radeonContextPtr) sharedContextPrivate)->glCtx; + else + shareCtx = NULL; + rmesa->glCtx = _mesa_create_context(glVisual, shareCtx, (void *) rmesa, GL_TRUE); + if (!rmesa->glCtx) { + FREE(rmesa); + return GL_FALSE; + } + driContextPriv->driverPrivate = rmesa; + + /* Init radeon context data */ + rmesa->dri.context = driContextPriv; + rmesa->dri.screen = sPriv; + rmesa->dri.drawable = NULL; /* Set by XMesaMakeCurrent */ + rmesa->dri.hwContext = driContextPriv->hHWContext; + rmesa->dri.hwLock = &sPriv->pSAREA->lock; + rmesa->dri.fd = sPriv->fd; + + /* If we don't have 1.3, fallback to the 1.1 interfaces. + */ + if (getenv("RADEON_COMPAT") || sPriv->drmMinor < 3 ) + rmesa->dri.drmMinor = 1; + else + rmesa->dri.drmMinor = sPriv->drmMinor; + + rmesa->radeonScreen = screen; + rmesa->sarea = (RADEONSAREAPrivPtr)((GLubyte *)sPriv->pSAREA + + screen->sarea_priv_offset); + + + rmesa->dma.buf0_address = rmesa->radeonScreen->buffers->list[0].address; + + (void) memset( rmesa->texture_heaps, 0, sizeof( rmesa->texture_heaps ) ); + make_empty_list( & rmesa->swapped ); + + rmesa->nr_heaps = screen->numTexHeaps; + for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) { + rmesa->texture_heaps[i] = driCreateTextureHeap( i, rmesa, + screen->texSize[i], + 12, + RADEON_NR_TEX_REGIONS, + rmesa->sarea->texList[i], + & rmesa->sarea->texAge[i], + & rmesa->swapped, + sizeof( radeonTexObj ), + (destroy_texture_object_t *) radeonDestroyTexObj ); + + driSetTextureSwapCounterLocation( rmesa->texture_heaps[i], + & rmesa->c_textureSwaps ); + } + + rmesa->swtcl.RenderIndex = ~0; + rmesa->lost_context = 1; + + /* Set the maximum texture size small enough that we can guarentee that + * all texture units can bind a maximal texture and have them both in + * texturable memory at once. + */ + + ctx = rmesa->glCtx; + ctx->Const.MaxTextureUnits = 2; + + driCalculateMaxTextureLevels( rmesa->texture_heaps, + rmesa->nr_heaps, + & ctx->Const, + 4, + 11, /* max 2D texture size is 2048x2048 */ + 0, /* 3D textures unsupported. */ + 0, /* cube textures unsupported. */ + 11, /* max rect texture size is 2048x2048. */ + 12, + GL_FALSE ); + + ctx->Const.MaxTextureMaxAnisotropy = 16.0; + + /* No wide points. + */ + ctx->Const.MinPointSize = 1.0; + ctx->Const.MinPointSizeAA = 1.0; + ctx->Const.MaxPointSize = 1.0; + ctx->Const.MaxPointSizeAA = 1.0; + + ctx->Const.MinLineWidth = 1.0; + ctx->Const.MinLineWidthAA = 1.0; + ctx->Const.MaxLineWidth = 10.0; + ctx->Const.MaxLineWidthAA = 10.0; + ctx->Const.LineWidthGranularity = 0.0625; + + /* Set maxlocksize (and hence vb size) small enough to avoid + * fallbacks in radeon_tcl.c. ie. guarentee that all vertices can + * fit in a single dma buffer for indexed rendering of quad strips, + * etc. + */ + ctx->Const.MaxArrayLockSize = + MIN2( ctx->Const.MaxArrayLockSize, + RADEON_BUFFER_SIZE / RADEON_MAX_TCL_VERTSIZE ); + + rmesa->boxes = (getenv("LIBGL_PERFORMANCE_BOXES") != NULL); + + /* Initialize the software rasterizer and helper modules. + */ + _swrast_CreateContext( ctx ); + _ac_CreateContext( ctx ); + _tnl_CreateContext( ctx ); + _swsetup_CreateContext( ctx ); + _ae_create_context( ctx ); + + /* Install the customized pipeline: + */ + _tnl_destroy_pipeline( ctx ); + _tnl_install_pipeline( ctx, radeon_pipeline ); + ctx->Driver.FlushVertices = radeonFlushVertices; + + /* Try and keep materials and vertices separate: + */ + _tnl_isolate_materials( ctx, GL_TRUE ); + + +/* _mesa_allow_light_in_model( ctx, GL_FALSE ); */ + + /* Try and keep materials and vertices separate: + */ + _tnl_isolate_materials( ctx, GL_TRUE ); + + + /* Configure swrast to match hardware characteristics: + */ + _swrast_allow_pixel_fog( ctx, GL_FALSE ); + _swrast_allow_vertex_fog( ctx, GL_TRUE ); + + + _math_matrix_ctr( &rmesa->TexGenMatrix[0] ); + _math_matrix_ctr( &rmesa->TexGenMatrix[1] ); + _math_matrix_ctr( &rmesa->tmpmat ); + _math_matrix_set_identity( &rmesa->TexGenMatrix[0] ); + _math_matrix_set_identity( &rmesa->TexGenMatrix[1] ); + _math_matrix_set_identity( &rmesa->tmpmat ); + + driInitExtensions( ctx, card_extensions, GL_TRUE ); + + if (rmesa->dri.drmMinor >= 9) + _mesa_enable_extension( ctx, "GL_NV_texture_rectangle"); + + radeonInitDriverFuncs( ctx ); + radeonInitIoctlFuncs( ctx ); + radeonInitStateFuncs( ctx ); + radeonInitSpanFuncs( ctx ); + radeonInitTextureFuncs( ctx ); + radeonInitState( rmesa ); + radeonInitSwtcl( ctx ); + + rmesa->iw.irq_seq = -1; + rmesa->irqsEmitted = 0; + rmesa->do_irqs = (rmesa->radeonScreen->irq && !getenv("RADEON_NO_IRQS")); + + rmesa->do_usleeps = !getenv("RADEON_NO_USLEEPS"); + + rmesa->vblank_flags = (rmesa->do_irqs) + ? driGetDefaultVBlankFlags() : VBLANK_FLAG_NO_IRQ; + +#ifndef _SOLO + rmesa->get_ust = (PFNGLXGETUSTPROC) glXGetProcAddress( "__glXGetUST" ); + if ( rmesa->get_ust == NULL ) +#endif + { + rmesa->get_ust = get_ust_nop; + } + + (*rmesa->get_ust)( & rmesa->swap_ust ); + + +#if DO_DEBUG + RADEON_DEBUG = driParseDebugString( getenv( "RADEON_DEBUG" ), + debug_control ); +#endif + + if (getenv("RADEON_NO_RAST")) { + fprintf(stderr, "disabling 3D acceleration\n"); + FALLBACK(rmesa, RADEON_FALLBACK_DISABLE, 1); + } + else if (getenv("RADEON_TCL_FORCE_ENABLE")) { + fprintf(stderr, "Enabling TCL support... this will probably crash\n"); + fprintf(stderr, " your card if it isn't capable of TCL!\n"); + rmesa->radeonScreen->chipset |= RADEON_CHIPSET_TCL; + } else if (getenv("RADEON_TCL_FORCE_DISABLE") || + rmesa->dri.drmMinor < 3 || + !(rmesa->radeonScreen->chipset & RADEON_CHIPSET_TCL)) { + rmesa->radeonScreen->chipset &= ~RADEON_CHIPSET_TCL; + fprintf(stderr, "disabling TCL support\n"); + TCL_FALLBACK(rmesa->glCtx, RADEON_TCL_FALLBACK_TCL_DISABLE, 1); + } + + if (rmesa->radeonScreen->chipset & RADEON_CHIPSET_TCL) { + if (!getenv("RADEON_NO_VTXFMT")) + radeonVtxfmtInit( ctx ); + + _tnl_need_dlist_norm_lengths( ctx, GL_FALSE ); + } + return GL_TRUE; +} + + +/* Destroy the device specific context. + */ +/* Destroy the Mesa and driver specific context data. + */ +void radeonDestroyContext( __DRIcontextPrivate *driContextPriv ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = (radeonContextPtr) driContextPriv->driverPrivate; + radeonContextPtr current = ctx ? RADEON_CONTEXT(ctx) : NULL; + + /* check if we're deleting the currently bound context */ + if (rmesa == current) { + RADEON_FIREVERTICES( rmesa ); + _mesa_make_current2(NULL, NULL, NULL); + } + + /* Free radeon context resources */ + assert(rmesa); /* should never be null */ + if ( rmesa ) { + GLboolean release_texture_heaps; + + + release_texture_heaps = (rmesa->glCtx->Shared->RefCount == 1); + _swsetup_DestroyContext( rmesa->glCtx ); + _tnl_DestroyContext( rmesa->glCtx ); + _ac_DestroyContext( rmesa->glCtx ); + _swrast_DestroyContext( rmesa->glCtx ); + + radeonDestroySwtcl( rmesa->glCtx ); + radeonReleaseArrays( rmesa->glCtx, ~0 ); + if (rmesa->dma.current.buf) { + radeonReleaseDmaRegion( rmesa, &rmesa->dma.current, __FUNCTION__ ); + radeonFlushCmdBuf( rmesa, __FUNCTION__ ); + } + + if (!rmesa->TclFallback & RADEON_TCL_FALLBACK_TCL_DISABLE) + if (!getenv("RADEON_NO_VTXFMT")) + radeonVtxfmtDestroy( rmesa->glCtx ); + + /* free the Mesa context */ + rmesa->glCtx->DriverCtx = NULL; + _mesa_destroy_context( rmesa->glCtx ); + + if (rmesa->state.scissor.pClipRects) { + FREE(rmesa->state.scissor.pClipRects); + rmesa->state.scissor.pClipRects = 0; + } + + if ( release_texture_heaps ) { + /* This share group is about to go away, free our private + * texture object data. + */ + int i; + + /* this assert is not correct, default textures are always on swap list + assert( is_empty_list( & rmesa->swapped ) ); */ + + for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) { + driDestroyTextureHeap( rmesa->texture_heaps[ i ] ); + rmesa->texture_heaps[ i ] = NULL; + } + } + + FREE( rmesa ); + } +} + + + + +void +radeonSwapBuffers( __DRIdrawablePrivate *dPriv ) +{ + + if (dPriv->driContextPriv && dPriv->driContextPriv->driverPrivate) { + radeonContextPtr rmesa; + GLcontext *ctx; + rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate; + ctx = rmesa->glCtx; + if (ctx->Visual.doubleBufferMode) { + _mesa_notifySwapBuffers( ctx ); /* flush pending rendering comands */ + + if ( rmesa->doPageFlip ) { + radeonPageFlip( dPriv ); + } + else { + radeonCopyBuffer( dPriv ); + } + } + } + else { + /* XXX this shouldn't be an error but we can't handle it for now */ + _mesa_problem(NULL, "%s: drawable has no context!", __FUNCTION__); + } +} + + +/* Force the context `c' to be the current context and associate with it + * buffer `b'. + */ +GLboolean +radeonMakeCurrent( __DRIcontextPrivate *driContextPriv, + __DRIdrawablePrivate *driDrawPriv, + __DRIdrawablePrivate *driReadPriv ) +{ + if ( driContextPriv ) { + radeonContextPtr newCtx = + (radeonContextPtr) driContextPriv->driverPrivate; + + if (RADEON_DEBUG & DEBUG_DRI) + fprintf(stderr, "%s ctx %p\n", __FUNCTION__, newCtx->glCtx); + + if ( newCtx->dri.drawable != driDrawPriv ) { + newCtx->dri.drawable = driDrawPriv; + radeonUpdateWindow( newCtx->glCtx ); + radeonUpdateViewportOffset( newCtx->glCtx ); + } + + _mesa_make_current2( newCtx->glCtx, + (GLframebuffer *) driDrawPriv->driverPrivate, + (GLframebuffer *) driReadPriv->driverPrivate ); + + if ( !newCtx->glCtx->Viewport.Width ) { + _mesa_set_viewport( newCtx->glCtx, 0, 0, + driDrawPriv->w, driDrawPriv->h ); + } + + if (newCtx->vb.enabled) + radeonVtxfmtMakeCurrent( newCtx->glCtx ); + + } else { + if (RADEON_DEBUG & DEBUG_DRI) + fprintf(stderr, "%s ctx is null\n", __FUNCTION__); + _mesa_make_current( 0, 0 ); + } + + if (RADEON_DEBUG & DEBUG_DRI) + fprintf(stderr, "End %s\n", __FUNCTION__); + return GL_TRUE; +} + +/* Force the context `c' to be unbound from its buffer. + */ +GLboolean +radeonUnbindContext( __DRIcontextPrivate *driContextPriv ) +{ + radeonContextPtr rmesa = (radeonContextPtr) driContextPriv->driverPrivate; + + if (RADEON_DEBUG & DEBUG_DRI) + fprintf(stderr, "%s ctx %p\n", __FUNCTION__, rmesa->glCtx); + + return GL_TRUE; +} diff --git a/src/mesa/drivers/dri/radeon/radeon_context.h b/src/mesa/drivers/dri/radeon/radeon_context.h new file mode 100644 index 0000000000..5f1f9659e8 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_context.h @@ -0,0 +1,839 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_context.h,v 1.6 2002/12/16 16:18:58 dawes Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#ifndef __RADEON_CONTEXT_H__ +#define __RADEON_CONTEXT_H__ + +#ifdef GLX_DIRECT_RENDERING + +#include <inttypes.h> +#include "dri_util.h" +#include "radeon_common.h" +#include "texmem.h" + +#include "macros.h" +#include "mtypes.h" +#include "colormac.h" + +struct radeon_context; +typedef struct radeon_context radeonContextRec; +typedef struct radeon_context *radeonContextPtr; + +#include "radeon_lock.h" +#include "radeon_screen.h" +#include "mm.h" + +/* Flags for software fallback cases */ +/* See correponding strings in radeon_swtcl.c */ +#define RADEON_FALLBACK_TEXTURE 0x0001 +#define RADEON_FALLBACK_DRAW_BUFFER 0x0002 +#define RADEON_FALLBACK_STENCIL 0x0004 +#define RADEON_FALLBACK_RENDER_MODE 0x0008 +#define RADEON_FALLBACK_BLEND_EQ 0x0010 +#define RADEON_FALLBACK_BLEND_FUNC 0x0020 +#define RADEON_FALLBACK_DISABLE 0x0040 +#define RADEON_FALLBACK_BORDER_MODE 0x0080 + +/* The blit width for texture uploads + */ +#define BLIT_WIDTH_BYTES 1024 + +/* Use the templated vertex format: + */ +#define COLOR_IS_RGBA +#define TAG(x) radeon##x +#include "tnl_dd/t_dd_vertex.h" +#undef TAG + +typedef void (*radeon_tri_func)( radeonContextPtr, + radeonVertex *, + radeonVertex *, + radeonVertex * ); + +typedef void (*radeon_line_func)( radeonContextPtr, + radeonVertex *, + radeonVertex * ); + +typedef void (*radeon_point_func)( radeonContextPtr, + radeonVertex * ); + + +struct radeon_colorbuffer_state { + GLuint clear; + GLint drawOffset, drawPitch; +}; + + +struct radeon_depthbuffer_state { + GLuint clear; + GLfloat scale; +}; + +struct radeon_pixel_state { + GLint readOffset, readPitch; +}; + +struct radeon_scissor_state { + XF86DRIClipRectRec rect; + GLboolean enabled; + + GLuint numClipRects; /* Cliprects active */ + GLuint numAllocedClipRects; /* Cliprects available */ + XF86DRIClipRectPtr pClipRects; +}; + +struct radeon_stencilbuffer_state { + GLboolean hwBuffer; + GLuint clear; /* rb3d_stencilrefmask value */ +}; + +struct radeon_stipple_state { + GLuint mask[32]; +}; + + + +#define TEX_0 0x1 +#define TEX_1 0x2 +#define TEX_ALL 0x3 + +typedef struct radeon_tex_obj radeonTexObj, *radeonTexObjPtr; + +/* Texture object in locally shared texture space. + */ +struct radeon_tex_obj { + driTextureObject base; + + GLuint bufAddr; /* Offset to start of locally + shared texture block */ + + GLuint dirty_state; /* Flags (1 per texunit) for + whether or not this texobj + has dirty hardware state + (pp_*) that needs to be + brought into the + texunit. */ + + drmRadeonTexImage image[6][RADEON_MAX_TEXTURE_LEVELS]; + /* Six, for the cube faces */ + + GLuint pp_txfilter; /* hardware register values */ + GLuint pp_txformat; + GLuint pp_txoffset; /* Image location in texmem. + All cube faces follow. */ + GLuint pp_txsize; /* npot only */ + GLuint pp_txpitch; /* npot only */ + GLuint pp_border_color; + GLuint pp_cubic_faces; /* cube face 1,2,3,4 log2 sizes */ + + GLboolean border_fallback; +}; + + +struct radeon_texture_env_state { + radeonTexObjPtr texobj; + GLenum format; + GLenum envMode; +}; + +struct radeon_texture_state { + struct radeon_texture_env_state unit[RADEON_MAX_TEXTURE_UNITS]; +}; + + +struct radeon_state_atom { + struct radeon_state_atom *next, *prev; + const char *name; /* for debug */ + int cmd_size; /* size in bytes */ + GLuint is_tcl; + int *cmd; /* one or more cmd's */ + int *lastcmd; /* one or more cmd's */ + GLboolean (*check)( GLcontext * ); /* is this state active? */ +}; + + + +/* Trying to keep these relatively short as the variables are becoming + * extravagently long. Drop the driver name prefix off the front of + * everything - I think we know which driver we're in by now, and keep the + * prefix to 3 letters unless absolutely impossible. + */ + +#define CTX_CMD_0 0 +#define CTX_PP_MISC 1 +#define CTX_PP_FOG_COLOR 2 +#define CTX_RE_SOLID_COLOR 3 +#define CTX_RB3D_BLENDCNTL 4 +#define CTX_RB3D_DEPTHOFFSET 5 +#define CTX_RB3D_DEPTHPITCH 6 +#define CTX_RB3D_ZSTENCILCNTL 7 +#define CTX_CMD_1 8 +#define CTX_PP_CNTL 9 +#define CTX_RB3D_CNTL 10 +#define CTX_RB3D_COLOROFFSET 11 +#define CTX_CMD_2 12 +#define CTX_RB3D_COLORPITCH 13 +#define CTX_STATE_SIZE 14 + +#define SET_CMD_0 0 +#define SET_SE_CNTL 1 +#define SET_SE_COORDFMT 2 +#define SET_CMD_1 3 +#define SET_SE_CNTL_STATUS 4 +#define SET_STATE_SIZE 5 + +#define LIN_CMD_0 0 +#define LIN_RE_LINE_PATTERN 1 +#define LIN_RE_LINE_STATE 2 +#define LIN_CMD_1 3 +#define LIN_SE_LINE_WIDTH 4 +#define LIN_STATE_SIZE 5 + +#define MSK_CMD_0 0 +#define MSK_RB3D_STENCILREFMASK 1 +#define MSK_RB3D_ROPCNTL 2 +#define MSK_RB3D_PLANEMASK 3 +#define MSK_STATE_SIZE 4 + +#define VPT_CMD_0 0 +#define VPT_SE_VPORT_XSCALE 1 +#define VPT_SE_VPORT_XOFFSET 2 +#define VPT_SE_VPORT_YSCALE 3 +#define VPT_SE_VPORT_YOFFSET 4 +#define VPT_SE_VPORT_ZSCALE 5 +#define VPT_SE_VPORT_ZOFFSET 6 +#define VPT_STATE_SIZE 7 + +#define MSC_CMD_0 0 +#define MSC_RE_MISC 1 +#define MSC_STATE_SIZE 2 + +#define TEX_CMD_0 0 +#define TEX_PP_TXFILTER 1 +#define TEX_PP_TXFORMAT 2 +#define TEX_PP_TXOFFSET 3 +#define TEX_PP_TXCBLEND 4 +#define TEX_PP_TXABLEND 5 +#define TEX_PP_TFACTOR 6 +#define TEX_CMD_1 7 +#define TEX_PP_BORDER_COLOR 8 +#define TEX_STATE_SIZE 9 + +#define TXR_CMD_0 0 /* rectangle textures */ +#define TXR_PP_TEX_SIZE 1 /* 0x1d04, 0x1d0c for NPOT! */ +#define TXR_PP_TEX_PITCH 2 /* 0x1d08, 0x1d10 for NPOT! */ +#define TXR_STATE_SIZE 3 + +#define ZBS_CMD_0 0 +#define ZBS_SE_ZBIAS_FACTOR 1 +#define ZBS_SE_ZBIAS_CONSTANT 2 +#define ZBS_STATE_SIZE 3 + +#define TCL_CMD_0 0 +#define TCL_OUTPUT_VTXFMT 1 +#define TCL_OUTPUT_VTXSEL 2 +#define TCL_MATRIX_SELECT_0 3 +#define TCL_MATRIX_SELECT_1 4 +#define TCL_UCP_VERT_BLEND_CTL 5 +#define TCL_TEXTURE_PROC_CTL 6 +#define TCL_LIGHT_MODEL_CTL 7 +#define TCL_PER_LIGHT_CTL_0 8 +#define TCL_PER_LIGHT_CTL_1 9 +#define TCL_PER_LIGHT_CTL_2 10 +#define TCL_PER_LIGHT_CTL_3 11 +#define TCL_STATE_SIZE 12 + +#define MTL_CMD_0 0 +#define MTL_EMMISSIVE_RED 1 +#define MTL_EMMISSIVE_GREEN 2 +#define MTL_EMMISSIVE_BLUE 3 +#define MTL_EMMISSIVE_ALPHA 4 +#define MTL_AMBIENT_RED 5 +#define MTL_AMBIENT_GREEN 6 +#define MTL_AMBIENT_BLUE 7 +#define MTL_AMBIENT_ALPHA 8 +#define MTL_DIFFUSE_RED 9 +#define MTL_DIFFUSE_GREEN 10 +#define MTL_DIFFUSE_BLUE 11 +#define MTL_DIFFUSE_ALPHA 12 +#define MTL_SPECULAR_RED 13 +#define MTL_SPECULAR_GREEN 14 +#define MTL_SPECULAR_BLUE 15 +#define MTL_SPECULAR_ALPHA 16 +#define MTL_SHININESS 17 +#define MTL_STATE_SIZE 18 + +#define VTX_CMD_0 0 +#define VTX_SE_COORD_FMT 1 +#define VTX_STATE_SIZE 2 + +#define MAT_CMD_0 0 +#define MAT_ELT_0 1 +#define MAT_STATE_SIZE 17 + +#define GRD_CMD_0 0 +#define GRD_VERT_GUARD_CLIP_ADJ 1 +#define GRD_VERT_GUARD_DISCARD_ADJ 2 +#define GRD_HORZ_GUARD_CLIP_ADJ 3 +#define GRD_HORZ_GUARD_DISCARD_ADJ 4 +#define GRD_STATE_SIZE 5 + +/* position changes frequently when lighting in modelpos - separate + * out to new state item? + */ +#define LIT_CMD_0 0 +#define LIT_AMBIENT_RED 1 +#define LIT_AMBIENT_GREEN 2 +#define LIT_AMBIENT_BLUE 3 +#define LIT_AMBIENT_ALPHA 4 +#define LIT_DIFFUSE_RED 5 +#define LIT_DIFFUSE_GREEN 6 +#define LIT_DIFFUSE_BLUE 7 +#define LIT_DIFFUSE_ALPHA 8 +#define LIT_SPECULAR_RED 9 +#define LIT_SPECULAR_GREEN 10 +#define LIT_SPECULAR_BLUE 11 +#define LIT_SPECULAR_ALPHA 12 +#define LIT_POSITION_X 13 +#define LIT_POSITION_Y 14 +#define LIT_POSITION_Z 15 +#define LIT_POSITION_W 16 +#define LIT_DIRECTION_X 17 +#define LIT_DIRECTION_Y 18 +#define LIT_DIRECTION_Z 19 +#define LIT_DIRECTION_W 20 +#define LIT_ATTEN_CONST 21 +#define LIT_ATTEN_LINEAR 22 +#define LIT_ATTEN_QUADRATIC 23 +#define LIT_ATTEN_XXX 24 +#define LIT_CMD_1 25 +#define LIT_SPOT_DCD 26 +#define LIT_SPOT_EXPONENT 27 +#define LIT_SPOT_CUTOFF 28 +#define LIT_SPECULAR_THRESH 29 +#define LIT_RANGE_CUTOFF 30 /* ? */ +#define LIT_RANGE_ATTEN 31 /* ? */ +#define LIT_STATE_SIZE 32 + +/* Fog + */ +#define FOG_CMD_0 0 +#define FOG_R 1 +#define FOG_C 2 +#define FOG_D 3 +#define FOG_PAD 4 +#define FOG_STATE_SIZE 5 + +/* UCP + */ +#define UCP_CMD_0 0 +#define UCP_X 1 +#define UCP_Y 2 +#define UCP_Z 3 +#define UCP_W 4 +#define UCP_STATE_SIZE 5 + +/* GLT - Global ambient + */ +#define GLT_CMD_0 0 +#define GLT_RED 1 +#define GLT_GREEN 2 +#define GLT_BLUE 3 +#define GLT_ALPHA 4 +#define GLT_STATE_SIZE 5 + +/* EYE + */ +#define EYE_CMD_0 0 +#define EYE_X 1 +#define EYE_Y 2 +#define EYE_Z 3 +#define EYE_RESCALE_FACTOR 4 +#define EYE_STATE_SIZE 5 + +#define SHN_CMD_0 0 +#define SHN_SHININESS 1 +#define SHN_STATE_SIZE 2 + + + + + +struct radeon_hw_state { + /* All state should be on one of these lists: + */ + struct radeon_state_atom dirty; /* dirty list head placeholder */ + struct radeon_state_atom clean; /* clean list head placeholder */ + + /* Hardware state, stored as cmdbuf commands: + * -- Need to doublebuffer for + * - reviving state after loss of context + * - eliding noop statechange loops? (except line stipple count) + */ + struct radeon_state_atom ctx; + struct radeon_state_atom set; + struct radeon_state_atom lin; + struct radeon_state_atom msk; + struct radeon_state_atom vpt; + struct radeon_state_atom tcl; + struct radeon_state_atom msc; + struct radeon_state_atom tex[2]; + struct radeon_state_atom zbs; + struct radeon_state_atom mtl; + struct radeon_state_atom mat[5]; + struct radeon_state_atom lit[8]; /* includes vec, scl commands */ + struct radeon_state_atom ucp[6]; + struct radeon_state_atom eye; /* eye pos */ + struct radeon_state_atom grd; /* guard band clipping */ + struct radeon_state_atom fog; + struct radeon_state_atom glt; + struct radeon_state_atom txr[2]; /* for NPOT */ +}; + +struct radeon_state { + /* Derived state for internal purposes: + */ + struct radeon_colorbuffer_state color; + struct radeon_depthbuffer_state depth; + struct radeon_pixel_state pixel; + struct radeon_scissor_state scissor; + struct radeon_stencilbuffer_state stencil; + struct radeon_stipple_state stipple; + struct radeon_texture_state texture; +}; + + +/* Need refcounting on dma buffers: + */ +struct radeon_dma_buffer { + int refcount; /* the number of retained regions in buf */ + drmBufPtr buf; +}; + +#define GET_START(rvb) (rmesa->radeonScreen->agp_buffer_offset + \ + (rvb)->address - rmesa->dma.buf0_address + \ + (rvb)->start) + +/* A retained region, eg vertices for indexed vertices. + */ +struct radeon_dma_region { + struct radeon_dma_buffer *buf; + char *address; /* == buf->address */ + int start, end, ptr; /* offsets from start of buf */ + int aos_start; + int aos_stride; + int aos_size; +}; + + +struct radeon_dma { + /* Active dma region. Allocations for vertices and retained + * regions come from here. Also used for emitting random vertices, + * these may be flushed by calling flush_current(); + */ + struct radeon_dma_region current; + + void (*flush)( radeonContextPtr ); + + char *buf0_address; /* start of buf[0], for index calcs */ + GLuint nr_released_bufs; /* flush after so many buffers released */ +}; + +struct radeon_dri_mirror { + __DRIcontextPrivate *context; /* DRI context */ + __DRIscreenPrivate *screen; /* DRI screen */ + __DRIdrawablePrivate *drawable; /* DRI drawable bound to this ctx */ + + drmContext hwContext; + drmLock *hwLock; + int fd; + int drmMinor; +}; + + +#define RADEON_CMD_BUF_SZ (8*1024) + +struct radeon_store { + GLuint statenr; + GLuint primnr; + char cmd_buf[RADEON_CMD_BUF_SZ]; + int cmd_used; + int elts_start; +}; + + +/* radeon_tcl.c + */ +struct radeon_tcl_info { + GLuint vertex_format; + GLint last_offset; + GLuint hw_primitive; + + struct radeon_dma_region *aos_components[8]; + GLuint nr_aos_components; + + GLuint *Elts; + + struct radeon_dma_region indexed_verts; + struct radeon_dma_region obj; + struct radeon_dma_region rgba; + struct radeon_dma_region spec; + struct radeon_dma_region fog; + struct radeon_dma_region tex[RADEON_MAX_TEXTURE_UNITS]; + struct radeon_dma_region norm; +}; + + +/* radeon_swtcl.c + */ +struct radeon_swtcl_info { + GLuint SetupIndex; + GLuint SetupNewInputs; + GLuint RenderIndex; + GLuint vertex_size; + GLuint vertex_stride_shift; + GLuint vertex_format; + GLubyte *verts; + + /* Fallback rasterization functions + */ + radeon_point_func draw_point; + radeon_line_func draw_line; + radeon_tri_func draw_tri; + + GLuint hw_primitive; + GLenum render_primitive; + GLuint numverts; + + struct radeon_dma_region indexed_verts; +}; + + +struct radeon_ioctl { + GLuint vertex_offset; + GLuint vertex_size; +}; + + + +#define RADEON_MAX_PRIMS 64 + + +/* Want to keep a cache of these around. Each is parameterized by + * only a single value which has only a small range. Only expect a + * few, so just rescan the list each time? + */ +struct dynfn { + struct dynfn *next, *prev; + int key; + char *code; +}; + +struct dfn_lists { + struct dynfn Vertex2f; + struct dynfn Vertex2fv; + struct dynfn Vertex3f; + struct dynfn Vertex3fv; + struct dynfn Color4ub; + struct dynfn Color4ubv; + struct dynfn Color3ub; + struct dynfn Color3ubv; + struct dynfn Color4f; + struct dynfn Color4fv; + struct dynfn Color3f; + struct dynfn Color3fv; + struct dynfn SecondaryColor3ubEXT; + struct dynfn SecondaryColor3ubvEXT; + struct dynfn SecondaryColor3fEXT; + struct dynfn SecondaryColor3fvEXT; + struct dynfn Normal3f; + struct dynfn Normal3fv; + struct dynfn TexCoord2f; + struct dynfn TexCoord2fv; + struct dynfn TexCoord1f; + struct dynfn TexCoord1fv; + struct dynfn MultiTexCoord2fARB; + struct dynfn MultiTexCoord2fvARB; + struct dynfn MultiTexCoord1fARB; + struct dynfn MultiTexCoord1fvARB; +}; + +struct dfn_generators { + struct dynfn *(*Vertex2f)( GLcontext *, int ); + struct dynfn *(*Vertex2fv)( GLcontext *, int ); + struct dynfn *(*Vertex3f)( GLcontext *, int ); + struct dynfn *(*Vertex3fv)( GLcontext *, int ); + struct dynfn *(*Color4ub)( GLcontext *, int ); + struct dynfn *(*Color4ubv)( GLcontext *, int ); + struct dynfn *(*Color3ub)( GLcontext *, int ); + struct dynfn *(*Color3ubv)( GLcontext *, int ); + struct dynfn *(*Color4f)( GLcontext *, int ); + struct dynfn *(*Color4fv)( GLcontext *, int ); + struct dynfn *(*Color3f)( GLcontext *, int ); + struct dynfn *(*Color3fv)( GLcontext *, int ); + struct dynfn *(*SecondaryColor3ubEXT)( GLcontext *, int ); + struct dynfn *(*SecondaryColor3ubvEXT)( GLcontext *, int ); + struct dynfn *(*SecondaryColor3fEXT)( GLcontext *, int ); + struct dynfn *(*SecondaryColor3fvEXT)( GLcontext *, int ); + struct dynfn *(*Normal3f)( GLcontext *, int ); + struct dynfn *(*Normal3fv)( GLcontext *, int ); + struct dynfn *(*TexCoord2f)( GLcontext *, int ); + struct dynfn *(*TexCoord2fv)( GLcontext *, int ); + struct dynfn *(*TexCoord1f)( GLcontext *, int ); + struct dynfn *(*TexCoord1fv)( GLcontext *, int ); + struct dynfn *(*MultiTexCoord2fARB)( GLcontext *, int ); + struct dynfn *(*MultiTexCoord2fvARB)( GLcontext *, int ); + struct dynfn *(*MultiTexCoord1fARB)( GLcontext *, int ); + struct dynfn *(*MultiTexCoord1fvARB)( GLcontext *, int ); +}; + + + +struct radeon_prim { + GLuint start; + GLuint end; + GLuint prim; +}; + +struct radeon_vbinfo { + GLint counter, initial_counter; + GLint *dmaptr; + void (*notify)( void ); + GLint vertex_size; + + /* A maximum total of 15 elements per vertex: 3 floats for position, 3 + * floats for normal, 4 floats for color, 4 bytes for secondary color, + * 2 floats for each texture unit (4 floats total). + * + * As soon as the 3rd TMU is supported or cube maps (or 3D textures) are + * supported, this value will grow. + * + * The position data is never actually stored here, so 3 elements could be + * trimmed out of the buffer. + */ + union { float f; int i; radeon_color_t color; } vertex[15]; + + GLfloat *normalptr; + GLfloat *floatcolorptr; + radeon_color_t *colorptr; + GLfloat *floatspecptr; + radeon_color_t *specptr; + GLfloat *texcoordptr[2]; + + GLenum *prim; /* &ctx->Driver.CurrentExecPrimitive */ + GLuint primflags; + GLboolean enabled; /* *_NO_VTXFMT / *_NO_TCL env vars */ + GLboolean installed; + GLboolean fell_back; + GLboolean recheck; + GLint nrverts; + GLuint vertex_format; + + GLuint installed_vertex_format; + GLuint installed_color_3f_sz; + + struct radeon_prim primlist[RADEON_MAX_PRIMS]; + int nrprims; + + struct dfn_lists dfn_cache; + struct dfn_generators codegen; + GLvertexformat vtxfmt; +}; + + + + +struct radeon_context { + GLcontext *glCtx; /* Mesa context */ + + /* Driver and hardware state management + */ + struct radeon_hw_state hw; + struct radeon_state state; + + /* Texture object bookkeeping + */ + unsigned nr_heaps; + driTexHeap * texture_heaps[ RADEON_NR_TEX_HEAPS ]; + driTextureObject swapped; + + + /* Rasterization and vertex state: + */ + GLuint TclFallback; + GLuint Fallback; + GLuint NewGLState; + + + /* Temporaries for translating away float colors: + */ + struct gl_client_array UbyteColor; + struct gl_client_array UbyteSecondaryColor; + + /* Vertex buffers + */ + struct radeon_ioctl ioctl; + struct radeon_dma dma; + struct radeon_store store; + + /* Page flipping + */ + GLuint doPageFlip; + + /* Busy waiting + */ + GLuint do_usleeps; + GLuint do_irqs; + GLuint irqsEmitted; + drmRadeonIrqWait iw; + + /* Drawable, cliprect and scissor information + */ + GLuint numClipRects; /* Cliprects for the draw buffer */ + XF86DRIClipRectPtr pClipRects; + unsigned int lastStamp; + GLboolean lost_context; + radeonScreenPtr radeonScreen; /* Screen private DRI data */ + RADEONSAREAPrivPtr sarea; /* Private SAREA data */ + + /* TCL stuff + */ + GLmatrix TexGenMatrix[RADEON_MAX_TEXTURE_UNITS]; + GLboolean recheck_texgen[RADEON_MAX_TEXTURE_UNITS]; + GLboolean TexGenNeedNormals[RADEON_MAX_TEXTURE_UNITS]; + GLuint TexMatEnabled; + GLuint TexGenEnabled; + GLmatrix tmpmat; + GLuint last_ReallyEnabled; + + /* VBI + */ + GLuint vbl_seq; + GLuint vblank_flags; + + uint64_t swap_ust; + uint64_t swap_missed_ust; + + GLuint swap_count; + GLuint swap_missed_count; + + PFNGLXGETUSTPROC get_ust; + + /* radeon_tcl.c + */ + struct radeon_tcl_info tcl; + + /* radeon_swtcl.c + */ + struct radeon_swtcl_info swtcl; + + /* radeon_vtxfmt.c + */ + struct radeon_vbinfo vb; + + /* Mirrors of some DRI state + */ + struct radeon_dri_mirror dri; + + + /* Performance counters + */ + GLuint boxes; /* Draw performance boxes */ + GLuint hardwareWentIdle; + GLuint c_clears; + GLuint c_drawWaits; + GLuint c_textureSwaps; + GLuint c_textureBytes; + GLuint c_vertexBuffers; +}; + +#define RADEON_CONTEXT(ctx) ((radeonContextPtr)(ctx->DriverCtx)) + + +static __inline GLuint radeonPackColor( GLuint cpp, + GLubyte r, GLubyte g, + GLubyte b, GLubyte a ) +{ + switch ( cpp ) { + case 2: + return PACK_COLOR_565( r, g, b ); + case 4: + return PACK_COLOR_8888( a, r, g, b ); + default: + return 0; + } +} + +#define RADEON_OLD_PACKETS 1 + + +extern void radeonDestroyContext( __DRIcontextPrivate *driContextPriv ); +extern GLboolean radeonCreateContext(const __GLcontextModes *glVisual, + __DRIcontextPrivate *driContextPriv, + void *sharedContextPrivate); +extern void radeonSwapBuffers( __DRIdrawablePrivate *dPriv ); +extern GLboolean radeonMakeCurrent( __DRIcontextPrivate *driContextPriv, + __DRIdrawablePrivate *driDrawPriv, + __DRIdrawablePrivate *driReadPriv ); +extern GLboolean radeonUnbindContext( __DRIcontextPrivate *driContextPriv ); + +/* ================================================================ + * Debugging: + */ +#define DO_DEBUG 1 + +#if DO_DEBUG +extern int RADEON_DEBUG; +#else +#define RADEON_DEBUG 0 +#endif + +#define DEBUG_TEXTURE 0x001 +#define DEBUG_STATE 0x002 +#define DEBUG_IOCTL 0x004 +#define DEBUG_PRIMS 0x008 +#define DEBUG_VERTS 0x010 +#define DEBUG_FALLBACKS 0x020 +#define DEBUG_VFMT 0x040 +#define DEBUG_CODEGEN 0x080 +#define DEBUG_VERBOSE 0x100 +#define DEBUG_DRI 0x200 +#define DEBUG_DMA 0x400 +#define DEBUG_SANITY 0x800 + +#endif +#endif /* __RADEON_CONTEXT_H__ */ diff --git a/src/mesa/drivers/dri/radeon/radeon_ioctl.c b/src/mesa/drivers/dri/radeon/radeon_ioctl.c new file mode 100644 index 0000000000..a388720aba --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_ioctl.c @@ -0,0 +1,1191 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_ioctl.c,v 1.11 2003/01/29 22:04:59 dawes Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * Keith Whitwell <keith@tungstengraphics.com> + */ +#include <sched.h> +#include <errno.h> + +#include "glheader.h" +#include "imports.h" +#include "simple_list.h" +#include "swrast/swrast.h" + +#include "radeon_context.h" +#include "radeon_state.h" +#include "radeon_ioctl.h" +#include "radeon_tcl.h" +#include "radeon_sanity.h" + +#include "radeon_macros.h" /* for INREG() */ + +#include "vblank.h" + +#define RADEON_TIMEOUT 512 +#define RADEON_IDLE_RETRY 16 + + +static void radeonWaitForIdle( radeonContextPtr rmesa ); + +/* ============================================================= + * Kernel command buffer handling + */ + +static void print_state_atom( struct radeon_state_atom *state ) +{ + int i; + + fprintf(stderr, "emit %s/%d\n", state->name, state->cmd_size); + + if (RADEON_DEBUG & DEBUG_VERBOSE) + for (i = 0 ; i < state->cmd_size ; i++) + fprintf(stderr, "\t%s[%d]: %x\n", state->name, i, state->cmd[i]); + +} + +static void radeon_emit_state_list( radeonContextPtr rmesa, + struct radeon_state_atom *list ) +{ + struct radeon_state_atom *state, *tmp; + char *dest; + + /* From Felix Kuhling: similar to some other lockups, glaxium will + * lock with what we believe to be a normal command stream, but + * sprinkling some magic waits arounds allows it to run + * uninterrupted. This has a slight effect on q3 framerates, but + * it might now be possible to remove the zbs hack, below. + * + * Felix reports that this can be narrowed down to just + * tcl,tex0,tex1 state, but that's pretty much every statechange, + * so let's just put the wait in always (unless Felix wants to + * narrow it down further...) + */ + if (1) { + drmRadeonCmdHeader *cmd; + cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, sizeof(*cmd), + __FUNCTION__ ); + cmd->wait.cmd_type = RADEON_CMD_WAIT; + cmd->wait.flags = RADEON_WAIT_3D; + } + + foreach_s( state, tmp, list ) { + if (state->check( rmesa->glCtx )) { + dest = radeonAllocCmdBuf( rmesa, state->cmd_size * 4, __FUNCTION__); + memcpy( dest, state->cmd, state->cmd_size * 4); + move_to_head( &(rmesa->hw.clean), state ); + if (RADEON_DEBUG & DEBUG_STATE) + print_state_atom( state ); + } + else if (RADEON_DEBUG & DEBUG_STATE) + fprintf(stderr, "skip state %s\n", state->name); + } +} + + +void radeonEmitState( radeonContextPtr rmesa ) +{ + struct radeon_state_atom *state, *tmp; + + if (RADEON_DEBUG & (DEBUG_STATE|DEBUG_PRIMS)) + fprintf(stderr, "%s\n", __FUNCTION__); + + /* Somewhat overkill: + */ + if (rmesa->lost_context) { + if (RADEON_DEBUG & (DEBUG_STATE|DEBUG_PRIMS|DEBUG_IOCTL)) + fprintf(stderr, "%s - lost context\n", __FUNCTION__); + + foreach_s( state, tmp, &(rmesa->hw.clean) ) + move_to_tail(&(rmesa->hw.dirty), state ); + + rmesa->lost_context = 0; + } + else if (1) { + /* This is a darstardly kludge to work around a lockup that I + * haven't otherwise figured out. + */ + move_to_tail(&(rmesa->hw.dirty), &(rmesa->hw.zbs) ); + } + + if (!(rmesa->radeonScreen->chipset & RADEON_CHIPSET_TCL)) { + foreach_s( state, tmp, &(rmesa->hw.dirty) ) { + if (state->is_tcl) { + move_to_head( &(rmesa->hw.clean), state ); + } + } + } + + radeon_emit_state_list( rmesa, &rmesa->hw.dirty ); +} + + + +/* Fire a section of the retained (indexed_verts) buffer as a regular + * primtive. + */ +extern void radeonEmitVbufPrim( radeonContextPtr rmesa, + GLuint vertex_format, + GLuint primitive, + GLuint vertex_nr ) +{ + drmRadeonCmdHeader *cmd; + + + assert(rmesa->dri.drmMinor >= 3); + assert(!(primitive & RADEON_CP_VC_CNTL_PRIM_WALK_IND)); + + radeonEmitState( rmesa ); + + if (RADEON_DEBUG & DEBUG_IOCTL) + fprintf(stderr, "%s cmd_used/4: %d\n", __FUNCTION__, + rmesa->store.cmd_used/4); + +#if RADEON_OLD_PACKETS + cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, 6 * sizeof(*cmd), + __FUNCTION__ ); + cmd[0].header.cmd_type = RADEON_CMD_PACKET3_CLIP; + cmd[1].i = RADEON_CP_PACKET3_3D_RNDR_GEN_INDX_PRIM | (3 << 16); + cmd[2].i = rmesa->ioctl.vertex_offset; + cmd[3].i = vertex_nr; + cmd[4].i = vertex_format; + cmd[5].i = (primitive | + RADEON_CP_VC_CNTL_PRIM_WALK_LIST | + RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA | + RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE | + (vertex_nr << RADEON_CP_VC_CNTL_NUM_SHIFT)); + + if (RADEON_DEBUG & DEBUG_PRIMS) + fprintf(stderr, "%s: header 0x%x offt 0x%x vfmt 0x%x vfcntl %x \n", + __FUNCTION__, + cmd[1].i, cmd[2].i, cmd[4].i, cmd[5].i); +#else + cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, 4 * sizeof(*cmd), + __FUNCTION__ ); + cmd[0].i = 0; + cmd[0].header.cmd_type = RADEON_CMD_PACKET3_CLIP; + cmd[1].i = RADEON_CP_PACKET3_3D_DRAW_VBUF | (1 << 16); + cmd[2].i = vertex_format; + cmd[3].i = (primitive | + RADEON_CP_VC_CNTL_PRIM_WALK_LIST | + RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA | + RADEON_CP_VC_CNTL_MAOS_ENABLE | + RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE | + (vertex_nr << RADEON_CP_VC_CNTL_NUM_SHIFT)); + + + if (RADEON_DEBUG & DEBUG_PRIMS) + fprintf(stderr, "%s: header 0x%x vfmt 0x%x vfcntl %x \n", + __FUNCTION__, + cmd[1].i, cmd[2].i, cmd[3].i); +#endif +} + + +void radeonFlushElts( radeonContextPtr rmesa ) +{ + int *cmd = (int *)(rmesa->store.cmd_buf + rmesa->store.elts_start); + int dwords; +#if RADEON_OLD_PACKETS + int nr = (rmesa->store.cmd_used - (rmesa->store.elts_start + 24)) / 2; +#else + int nr = (rmesa->store.cmd_used - (rmesa->store.elts_start + 16)) / 2; +#endif + + if (RADEON_DEBUG & DEBUG_IOCTL) + fprintf(stderr, "%s\n", __FUNCTION__); + + assert( rmesa->dma.flush == radeonFlushElts ); + rmesa->dma.flush = 0; + + /* Cope with odd number of elts: + */ + rmesa->store.cmd_used = (rmesa->store.cmd_used + 2) & ~2; + dwords = (rmesa->store.cmd_used - rmesa->store.elts_start) / 4; + +#if RADEON_OLD_PACKETS + cmd[1] |= (dwords - 3) << 16; + cmd[5] |= nr << RADEON_CP_VC_CNTL_NUM_SHIFT; +#else + cmd[1] |= (dwords - 3) << 16; + cmd[3] |= nr << RADEON_CP_VC_CNTL_NUM_SHIFT; +#endif +} + + +GLushort *radeonAllocEltsOpenEnded( radeonContextPtr rmesa, + GLuint vertex_format, + GLuint primitive, + GLuint min_nr ) +{ + drmRadeonCmdHeader *cmd; + GLushort *retval; + + if (RADEON_DEBUG & DEBUG_IOCTL) + fprintf(stderr, "%s %d\n", __FUNCTION__, min_nr); + + assert(rmesa->dri.drmMinor >= 3); + assert((primitive & RADEON_CP_VC_CNTL_PRIM_WALK_IND)); + + radeonEmitState( rmesa ); + +#if RADEON_OLD_PACKETS + cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, + 24 + min_nr*2, + __FUNCTION__ ); + cmd[0].i = 0; + cmd[0].header.cmd_type = RADEON_CMD_PACKET3_CLIP; + cmd[1].i = RADEON_CP_PACKET3_3D_RNDR_GEN_INDX_PRIM; + cmd[2].i = rmesa->ioctl.vertex_offset; + cmd[3].i = 0xffff; + cmd[4].i = vertex_format; + cmd[5].i = (primitive | + RADEON_CP_VC_CNTL_PRIM_WALK_IND | + RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA | + RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE); + + retval = (GLushort *)(cmd+6); +#else + cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, + 16 + min_nr*2, + __FUNCTION__ ); + cmd[0].i = 0; + cmd[0].header.cmd_type = RADEON_CMD_PACKET3_CLIP; + cmd[1].i = RADEON_CP_PACKET3_3D_DRAW_INDX; + cmd[2].i = vertex_format; + cmd[3].i = (primitive | + RADEON_CP_VC_CNTL_PRIM_WALK_IND | + RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA | + RADEON_CP_VC_CNTL_MAOS_ENABLE | + RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE); + + retval = (GLushort *)(cmd+4); +#endif + + if (RADEON_DEBUG & DEBUG_PRIMS) + fprintf(stderr, "%s: header 0x%x vfmt 0x%x prim %x \n", + __FUNCTION__, + cmd[1].i, vertex_format, primitive); + + assert(!rmesa->dma.flush); + rmesa->glCtx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; + rmesa->dma.flush = radeonFlushElts; + + rmesa->store.elts_start = ((char *)cmd) - rmesa->store.cmd_buf; + + return retval; +} + + + +void radeonEmitVertexAOS( radeonContextPtr rmesa, + GLuint vertex_size, + GLuint offset ) +{ +#if RADEON_OLD_PACKETS + rmesa->ioctl.vertex_size = vertex_size; + rmesa->ioctl.vertex_offset = offset; +#else + drmRadeonCmdHeader *cmd; + assert(rmesa->dri.drmMinor >= 3); + + if (RADEON_DEBUG & (DEBUG_PRIMS|DEBUG_IOCTL)) + fprintf(stderr, "%s: vertex_size 0x%x offset 0x%x \n", + __FUNCTION__, vertex_size, offset); + + cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, 5 * sizeof(int), + __FUNCTION__ ); + + cmd[0].i = 0; + cmd[0].header.cmd_type = RADEON_CMD_PACKET3; + cmd[1].i = RADEON_CP_PACKET3_3D_LOAD_VBPNTR | (2 << 16); + cmd[2].i = 1; + cmd[3].i = vertex_size | (vertex_size << 8); + cmd[4].i = offset; +#endif +} + + +void radeonEmitAOS( radeonContextPtr rmesa, + struct radeon_dma_region **component, + GLuint nr, + GLuint offset ) +{ +#if RADEON_OLD_PACKETS + assert( nr == 1 ); + assert( component[0]->aos_size == component[0]->aos_stride ); + rmesa->ioctl.vertex_size = component[0]->aos_size; + rmesa->ioctl.vertex_offset = + (component[0]->aos_start + offset * component[0]->aos_stride * 4); +#else + drmRadeonCmdHeader *cmd; + int sz = 3 + (nr/2 * 3) + (nr & 1) * 2; + int i; + int *tmp; + + if (RADEON_DEBUG & DEBUG_IOCTL) + fprintf(stderr, "%s\n", __FUNCTION__); + + assert(rmesa->dri.drmMinor >= 3); + + cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, sz * sizeof(int), + __FUNCTION__ ); + cmd[0].i = 0; + cmd[0].header.cmd_type = RADEON_CMD_PACKET3; + cmd[1].i = RADEON_CP_PACKET3_3D_LOAD_VBPNTR | ((sz-3) << 16); + cmd[2].i = nr; + tmp = &cmd[0].i; + cmd += 3; + + for (i = 0 ; i < nr ; i++) { + if (i & 1) { + cmd[0].i |= ((component[i]->aos_stride << 24) | + (component[i]->aos_size << 16)); + cmd[2].i = (component[i]->aos_start + + offset * component[i]->aos_stride * 4); + cmd += 3; + } + else { + cmd[0].i = ((component[i]->aos_stride << 8) | + (component[i]->aos_size << 0)); + cmd[1].i = (component[i]->aos_start + + offset * component[i]->aos_stride * 4); + } + } + + if (RADEON_DEBUG & DEBUG_VERTS) { + fprintf(stderr, "%s:\n", __FUNCTION__); + for (i = 0 ; i < sz ; i++) + fprintf(stderr, " %d: %x\n", i, tmp[i]); + } +#endif +} + +/* using already shifted color_fmt! */ +void radeonEmitBlit( radeonContextPtr rmesa, /* FIXME: which drmMinor is required? */ + GLuint color_fmt, + GLuint src_pitch, + GLuint src_offset, + GLuint dst_pitch, + GLuint dst_offset, + GLint srcx, GLint srcy, + GLint dstx, GLint dsty, + GLuint w, GLuint h ) +{ + drmRadeonCmdHeader *cmd; + + if (RADEON_DEBUG & DEBUG_IOCTL) + fprintf(stderr, "%s src %x/%x %d,%d dst: %x/%x %d,%d sz: %dx%d\n", + __FUNCTION__, + src_pitch, src_offset, srcx, srcy, + dst_pitch, dst_offset, dstx, dsty, + w, h); + + assert( (src_pitch & 63) == 0 ); + assert( (dst_pitch & 63) == 0 ); + assert( (src_offset & 1023) == 0 ); + assert( (dst_offset & 1023) == 0 ); + assert( w < (1<<16) ); + assert( h < (1<<16) ); + + cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, 8 * sizeof(int), + __FUNCTION__ ); + + + cmd[0].i = 0; + cmd[0].header.cmd_type = RADEON_CMD_PACKET3; + cmd[1].i = RADEON_CP_PACKET3_CNTL_BITBLT_MULTI | (5 << 16); + cmd[2].i = (RADEON_GMC_SRC_PITCH_OFFSET_CNTL | + RADEON_GMC_DST_PITCH_OFFSET_CNTL | + RADEON_GMC_BRUSH_NONE | + color_fmt | + RADEON_GMC_SRC_DATATYPE_COLOR | + RADEON_ROP3_S | + RADEON_DP_SRC_SOURCE_MEMORY | + RADEON_GMC_CLR_CMP_CNTL_DIS | + RADEON_GMC_WR_MSK_DIS ); + + cmd[3].i = ((src_pitch/64)<<22) | (src_offset >> 10); + cmd[4].i = ((dst_pitch/64)<<22) | (dst_offset >> 10); + cmd[5].i = (srcx << 16) | srcy; + cmd[6].i = (dstx << 16) | dsty; /* dst */ + cmd[7].i = (w << 16) | h; +} + + +void radeonEmitWait( radeonContextPtr rmesa, GLuint flags ) +{ + if (rmesa->dri.drmMinor >= 6) { + drmRadeonCmdHeader *cmd; + + assert( !(flags & ~(RADEON_WAIT_2D|RADEON_WAIT_3D)) ); + + cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, 1 * sizeof(int), + __FUNCTION__ ); + cmd[0].i = 0; + cmd[0].wait.cmd_type = RADEON_CMD_WAIT; + cmd[0].wait.flags = flags; + } +} + + +static int radeonFlushCmdBufLocked( radeonContextPtr rmesa, + const char * caller ) +{ + int ret, i; + drmRadeonCmdBuffer cmd; + + if (RADEON_DEBUG & DEBUG_IOCTL) { + fprintf(stderr, "%s from %s\n", __FUNCTION__, caller); + + if (RADEON_DEBUG & DEBUG_VERBOSE) + for (i = 0 ; i < rmesa->store.cmd_used ; i += 4 ) + fprintf(stderr, "%d: %x\n", i/4, + *(int *)(&rmesa->store.cmd_buf[i])); + } + + if (RADEON_DEBUG & DEBUG_DMA) + fprintf(stderr, "%s: Releasing %d buffers\n", __FUNCTION__, + rmesa->dma.nr_released_bufs); + + + if (RADEON_DEBUG & DEBUG_SANITY) { + if (rmesa->state.scissor.enabled) + ret = radeonSanityCmdBuffer( rmesa, + rmesa->state.scissor.numClipRects, + rmesa->state.scissor.pClipRects); + else + ret = radeonSanityCmdBuffer( rmesa, + rmesa->numClipRects, + rmesa->pClipRects); + if (ret) { + fprintf(stderr, "drmSanityCommandWrite: %d\n", ret); + goto out; + } + } + + + cmd.bufsz = rmesa->store.cmd_used; + cmd.buf = rmesa->store.cmd_buf; + + if (rmesa->state.scissor.enabled) { + cmd.nbox = rmesa->state.scissor.numClipRects; + cmd.boxes = (drmClipRect *)rmesa->state.scissor.pClipRects; + } else { + cmd.nbox = rmesa->numClipRects; + cmd.boxes = (drmClipRect *)rmesa->pClipRects; + } + + ret = drmCommandWrite( rmesa->dri.fd, + DRM_RADEON_CMDBUF, + &cmd, sizeof(cmd) ); + + if (ret) + fprintf(stderr, "drmCommandWrite: %d\n", ret); + + out: + rmesa->store.primnr = 0; + rmesa->store.statenr = 0; + rmesa->store.cmd_used = 0; + rmesa->dma.nr_released_bufs = 0; + rmesa->lost_context = 1; + return ret; +} + + +/* Note: does not emit any commands to avoid recursion on + * radeonAllocCmdBuf. + */ +void radeonFlushCmdBuf( radeonContextPtr rmesa, const char *caller ) +{ + int ret; + + + assert (rmesa->dri.drmMinor >= 3); + + LOCK_HARDWARE( rmesa ); + + ret = radeonFlushCmdBufLocked( rmesa, caller ); + + UNLOCK_HARDWARE( rmesa ); + + if (ret) { + fprintf(stderr, "drmRadeonCmdBuffer: %d (exiting)\n", ret); + exit(ret); + } +} + +/* ============================================================= + * Hardware vertex buffer handling + */ + + +void radeonRefillCurrentDmaRegion( radeonContextPtr rmesa ) +{ + struct radeon_dma_buffer *dmabuf; + int fd = rmesa->dri.fd; + int index = 0; + int size = 0; + drmDMAReq dma; + int ret; + + if (RADEON_DEBUG & (DEBUG_IOCTL|DEBUG_DMA)) + fprintf(stderr, "%s\n", __FUNCTION__); + + if (rmesa->dma.flush) { + rmesa->dma.flush( rmesa ); + } + + if (rmesa->dma.current.buf) + radeonReleaseDmaRegion( rmesa, &rmesa->dma.current, __FUNCTION__ ); + + if (rmesa->dma.nr_released_bufs > 4) + radeonFlushCmdBuf( rmesa, __FUNCTION__ ); + + dma.context = rmesa->dri.hwContext; + dma.send_count = 0; + dma.send_list = NULL; + dma.send_sizes = NULL; + dma.flags = 0; + dma.request_count = 1; + dma.request_size = RADEON_BUFFER_SIZE; + dma.request_list = &index; + dma.request_sizes = &size; + dma.granted_count = 0; + + LOCK_HARDWARE(rmesa); /* no need to validate */ + + ret = drmDMA( fd, &dma ); + + if (ret != 0) { + /* Free some up this way? + */ + if (rmesa->dma.nr_released_bufs) { + radeonFlushCmdBufLocked( rmesa, __FUNCTION__ ); + } + + if (RADEON_DEBUG & DEBUG_DMA) + fprintf(stderr, "Waiting for buffers\n"); + + radeonWaitForIdleLocked( rmesa ); + ret = drmDMA( fd, &dma ); + + if ( ret != 0 ) { + UNLOCK_HARDWARE( rmesa ); + fprintf( stderr, "Error: Could not get dma buffer... exiting\n" ); + exit( -1 ); + } + } + + UNLOCK_HARDWARE(rmesa); + + if (RADEON_DEBUG & DEBUG_DMA) + fprintf(stderr, "Allocated buffer %d\n", index); + + dmabuf = CALLOC_STRUCT( radeon_dma_buffer ); + dmabuf->buf = &rmesa->radeonScreen->buffers->list[index]; + dmabuf->refcount = 1; + + rmesa->dma.current.buf = dmabuf; + rmesa->dma.current.address = dmabuf->buf->address; + rmesa->dma.current.end = dmabuf->buf->total; + rmesa->dma.current.start = 0; + rmesa->dma.current.ptr = 0; + + rmesa->c_vertexBuffers++; +} + +void radeonReleaseDmaRegion( radeonContextPtr rmesa, + struct radeon_dma_region *region, + const char *caller ) +{ + if (RADEON_DEBUG & DEBUG_IOCTL) + fprintf(stderr, "%s from %s\n", __FUNCTION__, caller); + + if (!region->buf) + return; + + if (rmesa->dma.flush) + rmesa->dma.flush( rmesa ); + + if (--region->buf->refcount == 0) { + drmRadeonCmdHeader *cmd; + + if (RADEON_DEBUG & (DEBUG_IOCTL|DEBUG_DMA)) + fprintf(stderr, "%s -- DISCARD BUF %d\n", __FUNCTION__, + region->buf->buf->idx); + + cmd = (drmRadeonCmdHeader *)radeonAllocCmdBuf( rmesa, sizeof(*cmd), + __FUNCTION__ ); + cmd->dma.cmd_type = RADEON_CMD_DMA_DISCARD; + cmd->dma.buf_idx = region->buf->buf->idx; + FREE(region->buf); + rmesa->dma.nr_released_bufs++; + } + + region->buf = 0; + region->start = 0; +} + +/* Allocates a region from rmesa->dma.current. If there isn't enough + * space in current, grab a new buffer (and discard what was left of current) + */ +void radeonAllocDmaRegion( radeonContextPtr rmesa, + struct radeon_dma_region *region, + int bytes, + int alignment ) +{ + if (RADEON_DEBUG & DEBUG_IOCTL) + fprintf(stderr, "%s %d\n", __FUNCTION__, bytes); + + if (rmesa->dma.flush) + rmesa->dma.flush( rmesa ); + + if (region->buf) + radeonReleaseDmaRegion( rmesa, region, __FUNCTION__ ); + + alignment--; + rmesa->dma.current.start = rmesa->dma.current.ptr = + (rmesa->dma.current.ptr + alignment) & ~alignment; + + if ( rmesa->dma.current.ptr + bytes > rmesa->dma.current.end ) + radeonRefillCurrentDmaRegion( rmesa ); + + region->start = rmesa->dma.current.start; + region->ptr = rmesa->dma.current.start; + region->end = rmesa->dma.current.start + bytes; + region->address = rmesa->dma.current.address; + region->buf = rmesa->dma.current.buf; + region->buf->refcount++; + + rmesa->dma.current.ptr += bytes; /* bug - if alignment > 7 */ + rmesa->dma.current.start = + rmesa->dma.current.ptr = (rmesa->dma.current.ptr + 0x7) & ~0x7; + + if ( rmesa->dri.drmMinor < 3 ) + radeonRefillCurrentDmaRegion( rmesa ); +} + +void radeonAllocDmaRegionVerts( radeonContextPtr rmesa, + struct radeon_dma_region *region, + int numverts, + int vertsize, + int alignment ) +{ + radeonAllocDmaRegion( rmesa, region, vertsize * numverts, alignment ); +} + +/* ================================================================ + * SwapBuffers with client-side throttling + */ + +static CARD32 radeonGetLastFrame (radeonContextPtr rmesa) +{ + unsigned char *RADEONMMIO = rmesa->radeonScreen->mmio.map; + int ret; + CARD32 frame; + + if (rmesa->dri.screen->drmMinor >= 4) { + drmRadeonGetParam gp; + + gp.param = RADEON_PARAM_LAST_FRAME; + gp.value = &frame; + ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_GETPARAM, + &gp, sizeof(gp) ); + } + else + ret = -EINVAL; + +#ifndef __alpha__ + if ( ret == -EINVAL ) { + frame = INREG( RADEON_LAST_FRAME_REG ); + ret = 0; + } +#endif + if ( ret ) { + fprintf( stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__, ret ); + exit(1); + } + + return frame; +} + +static void radeonEmitIrqLocked( radeonContextPtr rmesa ) +{ + drmRadeonIrqEmit ie; + int ret; + + ie.irq_seq = &rmesa->iw.irq_seq; + ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_IRQ_EMIT, + &ie, sizeof(ie) ); + if ( ret ) { + fprintf( stderr, "%s: drmRadeonIrqEmit: %d\n", __FUNCTION__, ret ); + exit(1); + } +} + + +static void radeonWaitIrq( radeonContextPtr rmesa ) +{ + int ret; + + do { + ret = drmCommandWrite( rmesa->dri.fd, DRM_RADEON_IRQ_WAIT, + &rmesa->iw, sizeof(rmesa->iw) ); + } while (ret && (errno == EINTR || errno == EAGAIN)); + + if ( ret ) { + fprintf( stderr, "%s: drmRadeonIrqWait: %d\n", __FUNCTION__, ret ); + exit(1); + } +} + + +static void radeonWaitForFrameCompletion( radeonContextPtr rmesa ) +{ + RADEONSAREAPrivPtr sarea = rmesa->sarea; + + if (rmesa->do_irqs) { + if (radeonGetLastFrame(rmesa) < sarea->last_frame) { + if (!rmesa->irqsEmitted) { + while (radeonGetLastFrame (rmesa) < sarea->last_frame) + ; + } + else { + UNLOCK_HARDWARE( rmesa ); + radeonWaitIrq( rmesa ); + LOCK_HARDWARE( rmesa ); + } + rmesa->irqsEmitted = 10; + } + + if (rmesa->irqsEmitted) { + radeonEmitIrqLocked( rmesa ); + rmesa->irqsEmitted--; + } + } + else { + while (radeonGetLastFrame (rmesa) < sarea->last_frame) { + UNLOCK_HARDWARE( rmesa ); + if (rmesa->do_usleeps) + DO_USLEEP( 1 ); + LOCK_HARDWARE( rmesa ); + } + } +} + +/* Copy the back color buffer to the front color buffer. + */ +void radeonCopyBuffer( const __DRIdrawablePrivate *dPriv ) +{ + radeonContextPtr rmesa; + GLint nbox, i, ret; + GLboolean missed_target; + uint64_t ust; + + assert(dPriv); + assert(dPriv->driContextPriv); + assert(dPriv->driContextPriv->driverPrivate); + + rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate; + + if ( RADEON_DEBUG & DEBUG_IOCTL ) { + fprintf( stderr, "\n%s( %p )\n\n", __FUNCTION__, rmesa->glCtx ); + } + + RADEON_FIREVERTICES( rmesa ); + LOCK_HARDWARE( rmesa ); + + /* Throttle the frame rate -- only allow one pending swap buffers + * request at a time. + */ + radeonWaitForFrameCompletion( rmesa ); + UNLOCK_HARDWARE( rmesa ); + driWaitForVBlank( dPriv, & rmesa->vbl_seq, rmesa->vblank_flags, & missed_target ); + LOCK_HARDWARE( rmesa ); + + nbox = dPriv->numClipRects; /* must be in locked region */ + + for ( i = 0 ; i < nbox ; ) { + GLint nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS , nbox ); + XF86DRIClipRectPtr box = dPriv->pClipRects; + XF86DRIClipRectPtr b = rmesa->sarea->boxes; + GLint n = 0; + + for ( ; i < nr ; i++ ) { + *b++ = box[i]; + n++; + } + rmesa->sarea->nbox = n; + + ret = drmCommandNone( rmesa->dri.fd, DRM_RADEON_SWAP ); + + if ( ret ) { + fprintf( stderr, "DRM_RADEON_SWAP_BUFFERS: return = %d\n", ret ); + UNLOCK_HARDWARE( rmesa ); + exit( 1 ); + } + } + + UNLOCK_HARDWARE( rmesa ); + rmesa->swap_count++; + (*rmesa->get_ust)( & ust ); + if ( missed_target ) { + rmesa->swap_missed_count++; + rmesa->swap_missed_ust = ust - rmesa->swap_ust; + } + + rmesa->swap_ust = ust; +} + +void radeonPageFlip( const __DRIdrawablePrivate *dPriv ) +{ + radeonContextPtr rmesa; + GLint ret; + GLboolean missed_target; + + assert(dPriv); + assert(dPriv->driContextPriv); + assert(dPriv->driContextPriv->driverPrivate); + + rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate; + + if ( RADEON_DEBUG & DEBUG_IOCTL ) { + fprintf(stderr, "%s: pfCurrentPage: %d\n", __FUNCTION__, + rmesa->sarea->pfCurrentPage); + } + + RADEON_FIREVERTICES( rmesa ); + LOCK_HARDWARE( rmesa ); + + /* Need to do this for the perf box placement: + */ + if (dPriv->numClipRects) + { + XF86DRIClipRectPtr box = dPriv->pClipRects; + XF86DRIClipRectPtr b = rmesa->sarea->boxes; + b[0] = box[0]; + rmesa->sarea->nbox = 1; + } + + /* Throttle the frame rate -- only allow a few pending swap buffers + * request at a time. + */ + radeonWaitForFrameCompletion( rmesa ); + UNLOCK_HARDWARE( rmesa ); + driWaitForVBlank( dPriv, & rmesa->vbl_seq, rmesa->vblank_flags, & missed_target ); + if ( missed_target ) { + rmesa->swap_missed_count++; + (void) (*rmesa->get_ust)( & rmesa->swap_missed_ust ); + } + LOCK_HARDWARE( rmesa ); + + ret = drmCommandNone( rmesa->dri.fd, DRM_RADEON_FLIP ); + + UNLOCK_HARDWARE( rmesa ); + + if ( ret ) { + fprintf( stderr, "DRM_RADEON_FLIP: return = %d\n", ret ); + exit( 1 ); + } + + rmesa->swap_count++; + (void) (*rmesa->get_ust)( & rmesa->swap_ust ); + + if ( rmesa->sarea->pfCurrentPage == 1 ) { + rmesa->state.color.drawOffset = rmesa->radeonScreen->frontOffset; + rmesa->state.color.drawPitch = rmesa->radeonScreen->frontPitch; + } else { + rmesa->state.color.drawOffset = rmesa->radeonScreen->backOffset; + rmesa->state.color.drawPitch = rmesa->radeonScreen->backPitch; + } + + RADEON_STATECHANGE( rmesa, ctx ); + rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = rmesa->state.color.drawOffset; + rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = rmesa->state.color.drawPitch; +} + + +/* ================================================================ + * Buffer clear + */ +#define RADEON_MAX_CLEARS 256 + +static void radeonClear( GLcontext *ctx, GLbitfield mask, GLboolean all, + GLint cx, GLint cy, GLint cw, GLint ch ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; + RADEONSAREAPrivPtr sarea = rmesa->sarea; + unsigned char *RADEONMMIO = rmesa->radeonScreen->mmio.map; + CARD32 clear; + GLuint flags = 0; + GLuint color_mask = 0; + GLint ret, i; + + if ( RADEON_DEBUG & DEBUG_IOCTL ) { + fprintf( stderr, "%s: all=%d cx=%d cy=%d cw=%d ch=%d\n", + __FUNCTION__, all, cx, cy, cw, ch ); + } + + radeonEmitState( rmesa ); + + /* Need to cope with lostcontext here as kernel relies on + * some residual state: + */ + RADEON_FIREVERTICES( rmesa ); + + if ( mask & DD_FRONT_LEFT_BIT ) { + flags |= RADEON_FRONT; + color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK]; + mask &= ~DD_FRONT_LEFT_BIT; + } + + if ( mask & DD_BACK_LEFT_BIT ) { + flags |= RADEON_BACK; + color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK]; + mask &= ~DD_BACK_LEFT_BIT; + } + + if ( mask & DD_DEPTH_BIT ) { + if ( ctx->Depth.Mask ) flags |= RADEON_DEPTH; /* FIXME: ??? */ + mask &= ~DD_DEPTH_BIT; + } + + if ( (mask & DD_STENCIL_BIT) && rmesa->state.stencil.hwBuffer ) { + flags |= RADEON_STENCIL; + mask &= ~DD_STENCIL_BIT; + } + + if ( mask ) { + if (RADEON_DEBUG & DEBUG_FALLBACKS) + fprintf(stderr, "%s: swrast clear, mask: %x\n", __FUNCTION__, mask); + _swrast_Clear( ctx, mask, all, cx, cy, cw, ch ); + } + + if ( !flags ) + return; + + + /* Flip top to bottom */ + cx += dPriv->x; + cy = dPriv->y + dPriv->h - cy - ch; + + LOCK_HARDWARE( rmesa ); + + /* Throttle the number of clear ioctls we do. + */ + while ( 1 ) { + int ret; + + if (rmesa->dri.screen->drmMinor >= 4) { + drmRadeonGetParam gp; + + gp.param = RADEON_PARAM_LAST_CLEAR; + gp.value = &clear; + ret = drmCommandWriteRead( rmesa->dri.fd, + DRM_RADEON_GETPARAM, &gp, sizeof(gp) ); + } else + ret = -EINVAL; + +#ifndef __alpha__ + if ( ret == -EINVAL ) { + clear = INREG( RADEON_LAST_CLEAR_REG ); + ret = 0; + } +#endif + if ( ret ) { + fprintf( stderr, "%s: drmRadeonGetParam: %d\n", __FUNCTION__, ret ); + exit(1); + } + if ( RADEON_DEBUG & DEBUG_IOCTL ) { + fprintf( stderr, "%s( %d )\n", __FUNCTION__, (int)clear ); + if ( ret ) fprintf( stderr, " ( RADEON_LAST_CLEAR register read directly )\n" ); + } + + if ( sarea->last_clear - clear <= RADEON_MAX_CLEARS ) { + break; + } + + if ( rmesa->do_usleeps ) { + UNLOCK_HARDWARE( rmesa ); + DO_USLEEP( 1 ); + LOCK_HARDWARE( rmesa ); + } + } + + for ( i = 0 ; i < dPriv->numClipRects ; ) { + GLint nr = MIN2( i + RADEON_NR_SAREA_CLIPRECTS, dPriv->numClipRects ); + XF86DRIClipRectPtr box = dPriv->pClipRects; + XF86DRIClipRectPtr b = rmesa->sarea->boxes; + drmRadeonClearType clear; + drmRadeonClearRect depth_boxes[RADEON_NR_SAREA_CLIPRECTS]; + GLint n = 0; + + if ( !all ) { + for ( ; i < nr ; i++ ) { + GLint x = box[i].x1; + GLint y = box[i].y1; + GLint w = box[i].x2 - x; + GLint h = box[i].y2 - y; + + if ( x < cx ) w -= cx - x, x = cx; + if ( y < cy ) h -= cy - y, y = cy; + if ( x + w > cx + cw ) w = cx + cw - x; + if ( y + h > cy + ch ) h = cy + ch - y; + if ( w <= 0 ) continue; + if ( h <= 0 ) continue; + + b->x1 = x; + b->y1 = y; + b->x2 = x + w; + b->y2 = y + h; + b++; + n++; + } + } else { + for ( ; i < nr ; i++ ) { + *b++ = box[i]; + n++; + } + } + + rmesa->sarea->nbox = n; + + clear.flags = flags; + clear.clear_color = rmesa->state.color.clear; + clear.clear_depth = rmesa->state.depth.clear; + clear.color_mask = rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK]; + clear.depth_mask = rmesa->state.stencil.clear; + clear.depth_boxes = depth_boxes; + + n--; + b = rmesa->sarea->boxes; + for ( ; n >= 0 ; n-- ) { + depth_boxes[n].f[RADEON_CLEAR_X1] = (float)b[n].x1; + depth_boxes[n].f[RADEON_CLEAR_Y1] = (float)b[n].y1; + depth_boxes[n].f[RADEON_CLEAR_X2] = (float)b[n].x2; + depth_boxes[n].f[RADEON_CLEAR_Y2] = (float)b[n].y2; + depth_boxes[n].f[RADEON_CLEAR_DEPTH] = + (float)rmesa->state.depth.clear; + } + + ret = drmCommandWrite( rmesa->dri.fd, DRM_RADEON_CLEAR, + &clear, sizeof(drmRadeonClearType)); + + if ( ret ) { + UNLOCK_HARDWARE( rmesa ); + fprintf( stderr, "DRM_RADEON_CLEAR: return = %d\n", ret ); + exit( 1 ); + } + } + + UNLOCK_HARDWARE( rmesa ); +} + + +void radeonWaitForIdleLocked( radeonContextPtr rmesa ) +{ + int fd = rmesa->dri.fd; + int to = 0; + int ret, i = 0; + + rmesa->c_drawWaits++; + + do { + do { + ret = drmCommandNone( fd, DRM_RADEON_CP_IDLE); + } while ( ret && errno == EBUSY && i++ < RADEON_IDLE_RETRY ); + } while ( ( ret == -EBUSY ) && ( to++ < RADEON_TIMEOUT ) ); + + if ( ret < 0 ) { + UNLOCK_HARDWARE( rmesa ); + fprintf( stderr, "Error: Radeon timed out... exiting\n" ); + exit( -1 ); + } +} + + +static void radeonWaitForIdle( radeonContextPtr rmesa ) +{ + LOCK_HARDWARE(rmesa); + radeonWaitForIdleLocked( rmesa ); + UNLOCK_HARDWARE(rmesa); +} + + +void radeonFlush( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + + if (RADEON_DEBUG & DEBUG_IOCTL) + fprintf(stderr, "%s\n", __FUNCTION__); + + if (rmesa->dma.flush) + rmesa->dma.flush( rmesa ); + + if (rmesa->dri.drmMinor >= 3) { + if (!is_empty_list(&rmesa->hw.dirty)) + radeonEmitState( rmesa ); + + if (rmesa->store.cmd_used) + radeonFlushCmdBuf( rmesa, __FUNCTION__ ); + } +} + +/* Make sure all commands have been sent to the hardware and have + * completed processing. + */ +void radeonFinish( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeonFlush( ctx ); + + if (rmesa->do_irqs) { + LOCK_HARDWARE( rmesa ); + radeonEmitIrqLocked( rmesa ); + UNLOCK_HARDWARE( rmesa ); + radeonWaitIrq( rmesa ); + } + else + radeonWaitForIdle( rmesa ); +} + + +void radeonInitIoctlFuncs( GLcontext *ctx ) +{ + ctx->Driver.Clear = radeonClear; + ctx->Driver.Finish = radeonFinish; + ctx->Driver.Flush = radeonFlush; +} + diff --git a/src/mesa/drivers/dri/radeon/radeon_ioctl.h b/src/mesa/drivers/dri/radeon/radeon_ioctl.h new file mode 100644 index 0000000000..3f6e1751cf --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_ioctl.h @@ -0,0 +1,188 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_ioctl.h,v 1.6 2002/12/16 16:18:58 dawes Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + */ + +#ifndef __RADEON_IOCTL_H__ +#define __RADEON_IOCTL_H__ + +#ifdef GLX_DIRECT_RENDERING + +#include "simple_list.h" +#include "radeon_lock.h" + + +extern void radeonEmitState( radeonContextPtr rmesa ); +extern void radeonEmitVertexAOS( radeonContextPtr rmesa, + GLuint vertex_size, + GLuint offset ); + +extern void radeonEmitVbufPrim( radeonContextPtr rmesa, + GLuint vertex_format, + GLuint primitive, + GLuint vertex_nr ); + +extern void radeonFlushElts( radeonContextPtr rmesa ); + +extern GLushort *radeonAllocEltsOpenEnded( radeonContextPtr rmesa, + GLuint vertex_format, + GLuint primitive, + GLuint min_nr ); + +extern void radeonEmitAOS( radeonContextPtr rmesa, + struct radeon_dma_region **regions, + GLuint n, + GLuint offset ); + +extern void radeonEmitBlit( radeonContextPtr rmesa, + GLuint color_fmt, + GLuint src_pitch, + GLuint src_offset, + GLuint dst_pitch, + GLuint dst_offset, + GLint srcx, GLint srcy, + GLint dstx, GLint dsty, + GLuint w, GLuint h ); + +extern void radeonEmitWait( radeonContextPtr rmesa, GLuint flags ); + +extern void radeonFlushCmdBuf( radeonContextPtr rmesa, const char * ); +extern void radeonRefillCurrentDmaRegion( radeonContextPtr rmesa ); + +extern void radeonAllocDmaRegion( radeonContextPtr rmesa, + struct radeon_dma_region *region, + int bytes, + int alignment ); + +extern void radeonAllocDmaRegionVerts( radeonContextPtr rmesa, + struct radeon_dma_region *region, + int numverts, + int vertsize, + int alignment ); + +extern void radeonReleaseDmaRegion( radeonContextPtr rmesa, + struct radeon_dma_region *region, + const char *caller ); + +extern void radeonCopyBuffer( const __DRIdrawablePrivate *drawable ); +extern void radeonPageFlip( const __DRIdrawablePrivate *drawable ); +extern void radeonFlush( GLcontext *ctx ); +extern void radeonFinish( GLcontext *ctx ); +extern void radeonWaitForIdleLocked( radeonContextPtr rmesa ); +extern void radeonWaitForVBlank( radeonContextPtr rmesa ); +extern void radeonInitIoctlFuncs( GLcontext *ctx ); +extern void radeonGetAllParams( radeonContextPtr rmesa ); + +/* radeon_compat.c: + */ +extern void radeonCompatEmitPrimitive( radeonContextPtr rmesa, + GLuint vertex_format, + GLuint hw_primitive, + GLuint nrverts ); + + +/* ================================================================ + * Helper macros: + */ + +/* Close off the last primitive, if it exists. + */ +#define RADEON_NEWPRIM( rmesa ) \ +do { \ + if ( rmesa->dma.flush ) \ + rmesa->dma.flush( rmesa ); \ +} while (0) + +/* Can accomodate several state changes and primitive changes without + * actually firing the buffer. + */ +#define RADEON_STATECHANGE( rmesa, ATOM ) \ +do { \ + RADEON_NEWPRIM( rmesa ); \ + move_to_head( &(rmesa->hw.dirty), &(rmesa->hw.ATOM)); \ +} while (0) + +#define RADEON_DB_STATE( ATOM ) \ + memcpy( rmesa->hw.ATOM.lastcmd, rmesa->hw.ATOM.cmd, \ + rmesa->hw.ATOM.cmd_size * 4) + +static __inline int RADEON_DB_STATECHANGE( + radeonContextPtr rmesa, + struct radeon_state_atom *atom ) +{ + if (memcmp(atom->cmd, atom->lastcmd, atom->cmd_size*4)) { + int *tmp; + RADEON_NEWPRIM( rmesa ); + move_to_head( &(rmesa->hw.dirty), atom ); + tmp = atom->cmd; + atom->cmd = atom->lastcmd; + atom->lastcmd = tmp; + return 1; + } + else + return 0; +} + + +/* Fire the buffered vertices no matter what. + */ +#define RADEON_FIREVERTICES( rmesa ) \ +do { \ + if ( rmesa->store.cmd_used || rmesa->dma.flush ) { \ + radeonFlush( rmesa->glCtx ); \ + } \ +} while (0) + +/* Alloc space in the command buffer + */ +static __inline char *radeonAllocCmdBuf( radeonContextPtr rmesa, + int bytes, const char *where ) +{ + if (rmesa->store.cmd_used + bytes > RADEON_CMD_BUF_SZ) + radeonFlushCmdBuf( rmesa, __FUNCTION__ ); + + assert(rmesa->dri.drmMinor >= 3); + + { + char *head = rmesa->store.cmd_buf + rmesa->store.cmd_used; + rmesa->store.cmd_used += bytes; + return head; + } +} + + + + +#endif +#endif /* __RADEON_IOCTL_H__ */ diff --git a/src/mesa/drivers/dri/radeon/radeon_lighting.c b/src/mesa/drivers/dri/radeon/radeon_lighting.c new file mode 100644 index 0000000000..b00c9cb6de --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_lighting.c @@ -0,0 +1,682 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_state.c,v 1.5 2002/09/16 18:05:20 eich Exp $ */ +/* + * Copyright 2000, 2001 VA Linux Systems Inc., Fremont, California. + * + * 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 + * VA LINUX SYSTEMS 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. + * + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "glheader.h" +#include "imports.h" +#include "api_arrayelt.h" +/* #include "mmath.h" */ +#include "enums.h" +#include "colormac.h" + + +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_state.h" +#include "radeon_tcl.h" +#include "radeon_tex.h" +#include "radeon_vtxfmt.h" + + + +/* ============================================================= + * Materials + */ + + +/* Update on colormaterial, material emmissive/ambient, + * lightmodel.globalambient + */ +void update_global_ambient( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + float *fcmd = (float *)RADEON_DB_STATE( glt ); + + /* Need to do more if both emmissive & ambient are PREMULT: + */ + if ((rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] & + ((3 << RADEON_EMISSIVE_SOURCE_SHIFT) | + (3 << RADEON_AMBIENT_SOURCE_SHIFT))) == 0) + { + COPY_3V( &fcmd[GLT_RED], + ctx->Light.Material[0].Emission); + ACC_SCALE_3V( &fcmd[GLT_RED], + ctx->Light.Model.Ambient, + ctx->Light.Material[0].Ambient); + } + else + { + COPY_3V( &fcmd[GLT_RED], ctx->Light.Model.Ambient ); + } + + RADEON_DB_STATECHANGE(rmesa, &rmesa->hw.glt); +} + +/* Update on change to + * - light[p].colors + * - light[p].enabled + * - material, + * - colormaterial enabled + * - colormaterial bitmask + */ +void update_light_colors( GLcontext *ctx, GLuint p ) +{ + struct gl_light *l = &ctx->Light.Light[p]; + +/* fprintf(stderr, "%s\n", __FUNCTION__); */ + + if (l->Enabled) { + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + float *fcmd = (float *)RADEON_DB_STATE( lit[p] ); + GLuint bitmask = ctx->Light.ColorMaterialBitmask; + struct gl_material *mat = &ctx->Light.Material[0]; + + COPY_4V( &fcmd[LIT_AMBIENT_RED], l->Ambient ); + COPY_4V( &fcmd[LIT_DIFFUSE_RED], l->Diffuse ); + COPY_4V( &fcmd[LIT_SPECULAR_RED], l->Specular ); + + if (!ctx->Light.ColorMaterialEnabled) + bitmask = 0; + + if ((bitmask & FRONT_AMBIENT_BIT) == 0) + SELF_SCALE_3V( &fcmd[LIT_AMBIENT_RED], mat->Ambient ); + + if ((bitmask & FRONT_DIFFUSE_BIT) == 0) + SELF_SCALE_3V( &fcmd[LIT_DIFFUSE_RED], mat->Diffuse ); + + if ((bitmask & FRONT_SPECULAR_BIT) == 0) + SELF_SCALE_3V( &fcmd[LIT_SPECULAR_RED], mat->Specular ); + + RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.lit[p] ); + } +} + +/* Also fallback for asym colormaterial mode in twoside lighting... + */ +void check_twoside_fallback( GLcontext *ctx ) +{ + GLboolean fallback = GL_FALSE; + + if (ctx->Light.Enabled && ctx->Light.Model.TwoSide) { + if (memcmp( &ctx->Light.Material[0], + &ctx->Light.Material[1], + sizeof(struct gl_material)) != 0) + fallback = GL_TRUE; + else if (ctx->Light.ColorMaterialEnabled && + (ctx->Light.ColorMaterialBitmask & BACK_MATERIAL_BITS) != + ((ctx->Light.ColorMaterialBitmask & FRONT_MATERIAL_BITS)<<1)) + fallback = GL_TRUE; + } + + TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_LIGHT_TWOSIDE, fallback ); +} + +void radeonColorMaterial( GLcontext *ctx, GLenum face, GLenum mode ) +{ + if (ctx->Light.ColorMaterialEnabled) { + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint light_model_ctl = rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]; + GLuint mask = ctx->Light.ColorMaterialBitmask; + + /* Default to PREMULT: + */ + light_model_ctl &= ~((3 << RADEON_EMISSIVE_SOURCE_SHIFT) | + (3 << RADEON_AMBIENT_SOURCE_SHIFT) | + (3 << RADEON_DIFFUSE_SOURCE_SHIFT) | + (3 << RADEON_SPECULAR_SOURCE_SHIFT)); + + if (mask & FRONT_EMISSION_BIT) { + light_model_ctl |= (RADEON_LM_SOURCE_VERTEX_DIFFUSE << + RADEON_EMISSIVE_SOURCE_SHIFT); + } + + if (mask & FRONT_AMBIENT_BIT) { + light_model_ctl |= (RADEON_LM_SOURCE_VERTEX_DIFFUSE << + RADEON_AMBIENT_SOURCE_SHIFT); + } + + if (mask & FRONT_DIFFUSE_BIT) { + light_model_ctl |= (RADEON_LM_SOURCE_VERTEX_DIFFUSE << + RADEON_DIFFUSE_SOURCE_SHIFT); + } + + if (mask & FRONT_SPECULAR_BIT) { + light_model_ctl |= (RADEON_LM_SOURCE_VERTEX_DIFFUSE << + RADEON_SPECULAR_SOURCE_SHIFT); + } + + if (light_model_ctl != rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]) { + GLuint p; + + RADEON_STATECHANGE( rmesa, tcl ); + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] = light_model_ctl; + + for (p = 0 ; p < MAX_LIGHTS; p++) + update_light_colors( ctx, p ); + update_global_ambient( ctx ); + } + } + + check_twoside_fallback( ctx ); +} + +void radeonUpdateMaterial( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *fcmd = (GLfloat *)RADEON_DB_STATE( mtl ); + GLuint p; + GLuint mask = ~0; + + if (ctx->Light.ColorMaterialEnabled) + mask &= ~ctx->Light.ColorMaterialBitmask; + + if (RADEON_DEBUG & DEBUG_STATE) + fprintf(stderr, "%s\n", __FUNCTION__); + + + if (mask & FRONT_EMISSION_BIT) { + fcmd[MTL_EMMISSIVE_RED] = ctx->Light.Material[0].Emission[0]; + fcmd[MTL_EMMISSIVE_GREEN] = ctx->Light.Material[0].Emission[1]; + fcmd[MTL_EMMISSIVE_BLUE] = ctx->Light.Material[0].Emission[2]; + fcmd[MTL_EMMISSIVE_ALPHA] = ctx->Light.Material[0].Emission[3]; + } + if (mask & FRONT_AMBIENT_BIT) { + fcmd[MTL_AMBIENT_RED] = ctx->Light.Material[0].Ambient[0]; + fcmd[MTL_AMBIENT_GREEN] = ctx->Light.Material[0].Ambient[1]; + fcmd[MTL_AMBIENT_BLUE] = ctx->Light.Material[0].Ambient[2]; + fcmd[MTL_AMBIENT_ALPHA] = ctx->Light.Material[0].Ambient[3]; + } + if (mask & FRONT_DIFFUSE_BIT) { + fcmd[MTL_DIFFUSE_RED] = ctx->Light.Material[0].Diffuse[0]; + fcmd[MTL_DIFFUSE_GREEN] = ctx->Light.Material[0].Diffuse[1]; + fcmd[MTL_DIFFUSE_BLUE] = ctx->Light.Material[0].Diffuse[2]; + fcmd[MTL_DIFFUSE_ALPHA] = ctx->Light.Material[0].Diffuse[3]; + } + if (mask & FRONT_SPECULAR_BIT) { + fcmd[MTL_SPECULAR_RED] = ctx->Light.Material[0].Specular[0]; + fcmd[MTL_SPECULAR_GREEN] = ctx->Light.Material[0].Specular[1]; + fcmd[MTL_SPECULAR_BLUE] = ctx->Light.Material[0].Specular[2]; + fcmd[MTL_SPECULAR_ALPHA] = ctx->Light.Material[0].Specular[3]; + } + if (mask & FRONT_SHININESS_BIT) { + fcmd[MTL_SHININESS] = ctx->Light.Material[0].Shininess; + } + + if (RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.mtl )) { + for (p = 0 ; p < MAX_LIGHTS; p++) + update_light_colors( ctx, p ); + + check_twoside_fallback( ctx ); + update_global_ambient( ctx ); + } + else if (RADEON_DEBUG & (DEBUG_PRIMS|DEBUG_STATE)) + fprintf(stderr, "%s: Elided noop material call\n", __FUNCTION__); +} + +/* _NEW_LIGHT + * _NEW_MODELVIEW + * _MESA_NEW_NEED_EYE_COORDS + * + * Uses derived state from mesa: + * _VP_inf_norm + * _h_inf_norm + * _Position + * _NormDirection + * _ModelViewInvScale + * _NeedEyeCoords + * _EyeZDir + * + * which are calculated in light.c and are correct for the current + * lighting space (model or eye), hence dependencies on _NEW_MODELVIEW + * and _MESA_NEW_NEED_EYE_COORDS. + */ +void radeonUpdateLighting( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + /* Have to check these, or have an automatic shortcircuit mechanism + * to remove noop statechanges. (Or just do a better job on the + * front end). + */ + { + GLuint tmp = rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]; + + if (ctx->_NeedEyeCoords) + tmp &= ~RADEON_LIGHT_IN_MODELSPACE; + else + tmp |= RADEON_LIGHT_IN_MODELSPACE; + + + /* Leave this test disabled: (unexplained q3 lockup) (even with + new packets) + */ + if (tmp != rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]) + { + RADEON_STATECHANGE( rmesa, tcl ); + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] = tmp; + } + } + + { + GLfloat *fcmd = (GLfloat *)RADEON_DB_STATE( eye ); + fcmd[EYE_X] = ctx->_EyeZDir[0]; + fcmd[EYE_Y] = ctx->_EyeZDir[1]; + fcmd[EYE_Z] = - ctx->_EyeZDir[2]; + fcmd[EYE_RESCALE_FACTOR] = ctx->_ModelViewInvScale; + RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.eye ); + } + + +/* RADEON_STATECHANGE( rmesa, glt ); */ + + if (ctx->Light.Enabled) { + GLint p; + for (p = 0 ; p < MAX_LIGHTS; p++) { + if (ctx->Light.Light[p].Enabled) { + struct gl_light *l = &ctx->Light.Light[p]; + GLfloat *fcmd = (GLfloat *)RADEON_DB_STATE( lit[p] ); + + if (l->EyePosition[3] == 0.0) { + COPY_3FV( &fcmd[LIT_POSITION_X], l->_VP_inf_norm ); + COPY_3FV( &fcmd[LIT_DIRECTION_X], l->_h_inf_norm ); + fcmd[LIT_POSITION_W] = 0; + fcmd[LIT_DIRECTION_W] = 0; + } else { + COPY_4V( &fcmd[LIT_POSITION_X], l->_Position ); + fcmd[LIT_DIRECTION_X] = -l->_NormDirection[0]; + fcmd[LIT_DIRECTION_Y] = -l->_NormDirection[1]; + fcmd[LIT_DIRECTION_Z] = -l->_NormDirection[2]; + fcmd[LIT_DIRECTION_W] = 0; + } + + RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.lit[p] ); + } + } + } +} + + +void radeonLightfv( GLcontext *ctx, GLenum light, + GLenum pname, const GLfloat *params ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLint p = light - GL_LIGHT0; + struct gl_light *l = &ctx->Light.Light[p]; + GLfloat *fcmd = (GLfloat *)rmesa->hw.lit[p].cmd; + + + switch (pname) { + case GL_AMBIENT: + case GL_DIFFUSE: + case GL_SPECULAR: + update_light_colors( ctx, p ); + break; + + case GL_SPOT_DIRECTION: + /* picked up in update_light */ + break; + + case GL_POSITION: { + /* positions picked up in update_light, but can do flag here */ + GLuint flag = (p&1)? RADEON_LIGHT_1_IS_LOCAL : RADEON_LIGHT_0_IS_LOCAL; + GLuint idx = TCL_PER_LIGHT_CTL_0 + p/2; + + RADEON_STATECHANGE(rmesa, tcl); + if (l->EyePosition[3] != 0.0F) + rmesa->hw.tcl.cmd[idx] |= flag; + else + rmesa->hw.tcl.cmd[idx] &= ~flag; + break; + } + + case GL_SPOT_EXPONENT: + RADEON_STATECHANGE(rmesa, lit[p]); + fcmd[LIT_SPOT_EXPONENT] = params[0]; + break; + + case GL_SPOT_CUTOFF: { + GLuint flag = (p&1) ? RADEON_LIGHT_1_IS_SPOT : RADEON_LIGHT_0_IS_SPOT; + GLuint idx = TCL_PER_LIGHT_CTL_0 + p/2; + + RADEON_STATECHANGE(rmesa, lit[p]); + fcmd[LIT_SPOT_CUTOFF] = l->_CosCutoff; + + RADEON_STATECHANGE(rmesa, tcl); + if (l->SpotCutoff != 180.0F) + rmesa->hw.tcl.cmd[idx] |= flag; + else + rmesa->hw.tcl.cmd[idx] &= ~flag; + break; + } + + case GL_CONSTANT_ATTENUATION: + RADEON_STATECHANGE(rmesa, lit[p]); + fcmd[LIT_ATTEN_CONST] = params[0]; + break; + case GL_LINEAR_ATTENUATION: + RADEON_STATECHANGE(rmesa, lit[p]); + fcmd[LIT_ATTEN_LINEAR] = params[0]; + break; + case GL_QUADRATIC_ATTENUATION: + RADEON_STATECHANGE(rmesa, lit[p]); + fcmd[LIT_ATTEN_QUADRATIC] = params[0]; + break; + default: + return; + } + +} + + + + +void radeonLightModelfv( GLcontext *ctx, GLenum pname, + const GLfloat *param ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + switch (pname) { + case GL_LIGHT_MODEL_AMBIENT: + update_global_ambient( ctx ); + break; + + case GL_LIGHT_MODEL_LOCAL_VIEWER: + RADEON_STATECHANGE( rmesa, tcl ); + if (ctx->Light.Model.LocalViewer) + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LOCAL_VIEWER; + else + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_LOCAL_VIEWER; + break; + + case GL_LIGHT_MODEL_TWO_SIDE: + RADEON_STATECHANGE( rmesa, tcl ); + if (ctx->Light.Model.TwoSide) + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_LIGHT_TWOSIDE; + else + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~RADEON_LIGHT_TWOSIDE; + + check_twoside_fallback( ctx ); + +#if _HAVE_SWTNL + if (rmesa->TclFallback) { + radeonChooseRenderState( ctx ); + radeonChooseVertexState( ctx ); + } +#endif + break; + + case GL_LIGHT_MODEL_COLOR_CONTROL: + radeonUpdateSpecular(ctx); + + RADEON_STATECHANGE( rmesa, tcl ); + if (ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= + ~RADEON_DIFFUSE_SPECULAR_COMBINE; + else + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= + RADEON_DIFFUSE_SPECULAR_COMBINE; + break; + + default: + break; + } +} + + +/* ============================================================= + * Fog + */ + + +static void radeonFogfv( GLcontext *ctx, GLenum pname, const GLfloat *param ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + union { int i; float f; } c, d; + GLchan col[4]; + + c.i = rmesa->hw.fog.cmd[FOG_C]; + d.i = rmesa->hw.fog.cmd[FOG_D]; + + switch (pname) { + case GL_FOG_MODE: + if (!ctx->Fog.Enabled) + return; + RADEON_STATECHANGE(rmesa, tcl); + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~RADEON_TCL_FOG_MASK; + switch (ctx->Fog.Mode) { + case GL_LINEAR: + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_TCL_FOG_LINEAR; + if (ctx->Fog.Start == ctx->Fog.End) { + c.f = 1.0F; + d.f = 1.0F; + } + else { + c.f = ctx->Fog.End/(ctx->Fog.End-ctx->Fog.Start); + d.f = 1.0/(ctx->Fog.End-ctx->Fog.Start); + } + break; + case GL_EXP: + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_TCL_FOG_EXP; + c.f = 0.0; + d.f = ctx->Fog.Density; + break; + case GL_EXP2: + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_TCL_FOG_EXP2; + c.f = 0.0; + d.f = -(ctx->Fog.Density * ctx->Fog.Density); + break; + default: + return; + } + break; + case GL_FOG_DENSITY: + switch (ctx->Fog.Mode) { + case GL_EXP: + c.f = 0.0; + d.f = ctx->Fog.Density; + break; + case GL_EXP2: + c.f = 0.0; + d.f = -(ctx->Fog.Density * ctx->Fog.Density); + break; + default: + break; + } + break; + case GL_FOG_START: + case GL_FOG_END: + if (ctx->Fog.Mode == GL_LINEAR) { + if (ctx->Fog.Start == ctx->Fog.End) { + c.f = 1.0F; + d.f = 1.0F; + } else { + c.f = ctx->Fog.End/(ctx->Fog.End-ctx->Fog.Start); + d.f = 1.0/(ctx->Fog.End-ctx->Fog.Start); + } + } + break; + case GL_FOG_COLOR: + RADEON_STATECHANGE( rmesa, ctx ); + UNCLAMPED_FLOAT_TO_RGB_CHAN( col, ctx->Fog.Color ); + rmesa->hw.ctx.cmd[CTX_PP_FOG_COLOR] = + radeonPackColor( 4, col[0], col[1], col[2], 0 ); + break; + case GL_FOG_COORDINATE_SOURCE_EXT: + /* What to do? + */ + break; + default: + return; + } + + if (c.i != rmesa->hw.fog.cmd[FOG_C] || d.i != rmesa->hw.fog.cmd[FOG_D]) { + RADEON_STATECHANGE( rmesa, fog ); + rmesa->hw.fog.cmd[FOG_C] = c.i; + rmesa->hw.fog.cmd[FOG_D] = d.i; + } +} + +/* Examine lighting and texture state to determine if separate specular + * should be enabled. + */ +void radeonUpdateSpecular( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint p = rmesa->hw.ctx.cmd[CTX_PP_CNTL]; + + if ( ctx->_TriangleCaps & DD_SEPARATE_SPECULAR ) { + p |= RADEON_SPECULAR_ENABLE; + } else { + p &= ~RADEON_SPECULAR_ENABLE; + } + + if ( rmesa->hw.ctx.cmd[CTX_PP_CNTL] != p ) { + RADEON_STATECHANGE( rmesa, ctx ); + rmesa->hw.ctx.cmd[CTX_PP_CNTL] = p; + } + + /* Bizzare: have to leave lighting enabled to get fog. + */ + RADEON_STATECHANGE( rmesa, tcl ); + if ((ctx->Light.Enabled && + ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR)) { + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_SPECULAR; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE; + } + else if (ctx->Fog.Enabled) { + if (ctx->Light.Enabled) { + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_SPECULAR; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE; + } else { + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_SPECULAR; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE; + } + } + else if (ctx->Light.Enabled) { + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_SPECULAR; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~RADEON_TCL_VTX_PK_SPEC; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE; + } else if (ctx->Fog.ColorSumEnabled ) { + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_SPECULAR; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_LIGHTING_ENABLE; + } else { + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_SPECULAR; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~RADEON_TCL_VTX_PK_SPEC; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_LIGHTING_ENABLE; + } + +#if _HAVE_SWTNL + /* Update vertex/render formats + */ + if (rmesa->TclFallback) { + radeonChooseRenderState( ctx ); + radeonChooseVertexState( ctx ); + } +#endif +} + + + +static void radeonLightingSpaceChange( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLboolean tmp; + RADEON_STATECHANGE( rmesa, tcl ); + + if (RADEON_DEBUG & DEBUG_STATE) + fprintf(stderr, "%s %d\n", __FUNCTION__, ctx->_NeedEyeCoords); + + if (ctx->_NeedEyeCoords) + tmp = ctx->Transform.RescaleNormals; + else + tmp = !ctx->Transform.RescaleNormals; + + if ( tmp ) { + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_RESCALE_NORMALS; + } else { + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_RESCALE_NORMALS; + } +} + +void radeonInitLightStateFuncs( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + int i; + + ctx->Driver.LightModelfv = radeonLightModelfv; + ctx->Driver.Lightfv = radeonLightfv; + ctx->Driver.Fogfv = radeonFogfv; + ctx->Driver.LightingSpaceChange = radeonLightingSpaceChange; + + for (i = 0 ; i < 8; i++) { + struct gl_light *l = &ctx->Light.Light[i]; + GLenum p = GL_LIGHT0 + i; + *(float *)&(rmesa->hw.lit[i].cmd[LIT_RANGE_CUTOFF]) = FLT_MAX; + + ctx->Driver.Lightfv( ctx, p, GL_AMBIENT, l->Ambient ); + ctx->Driver.Lightfv( ctx, p, GL_DIFFUSE, l->Diffuse ); + ctx->Driver.Lightfv( ctx, p, GL_SPECULAR, l->Specular ); + ctx->Driver.Lightfv( ctx, p, GL_POSITION, 0 ); + ctx->Driver.Lightfv( ctx, p, GL_SPOT_DIRECTION, 0 ); + ctx->Driver.Lightfv( ctx, p, GL_SPOT_EXPONENT, &l->SpotExponent ); + ctx->Driver.Lightfv( ctx, p, GL_SPOT_CUTOFF, &l->SpotCutoff ); + ctx->Driver.Lightfv( ctx, p, GL_CONSTANT_ATTENUATION, + &l->ConstantAttenuation ); + ctx->Driver.Lightfv( ctx, p, GL_LINEAR_ATTENUATION, + &l->LinearAttenuation ); + ctx->Driver.Lightfv( ctx, p, GL_QUADRATIC_ATTENUATION, + &l->QuadraticAttenuation ); + } + + ctx->Driver.LightModelfv( ctx, GL_LIGHT_MODEL_AMBIENT, + ctx->Light.Model.Ambient ); + + 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.Fogfv( ctx, GL_FOG_COLOR, ctx->Fog.Color ); + ctx->Driver.Fogfv( ctx, GL_FOG_COORDINATE_SOURCE_EXT, 0 ); +} diff --git a/src/mesa/drivers/dri/radeon/radeon_lock.c b/src/mesa/drivers/dri/radeon/radeon_lock.c new file mode 100644 index 0000000000..96a4f9d112 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_lock.c @@ -0,0 +1,128 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_lock.c,v 1.5 2002/10/30 12:51:55 alanh Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + */ + +#include "glheader.h" +#include "radeon_context.h" +#include "radeon_lock.h" +#include "radeon_tex.h" +#include "radeon_state.h" +#include "radeon_ioctl.h" + +#if DEBUG_LOCKING +char *prevLockFile = NULL; +int prevLockLine = 0; +#endif + +/* Turn on/off page flipping according to the flags in the sarea: + */ +static void +radeonUpdatePageFlipping( radeonContextPtr rmesa ) +{ + int use_back; + + if (rmesa->dri.drmMinor < 3) + return; + + rmesa->doPageFlip = rmesa->sarea->pfAllowPageFlip; + + use_back = (rmesa->glCtx->Color._DrawDestMask == BACK_LEFT_BIT); + use_back ^= (rmesa->sarea->pfCurrentPage == 1); + + if ( RADEON_DEBUG & DEBUG_VERBOSE ) + fprintf(stderr, "%s allow %d current %d\n", __FUNCTION__, + rmesa->doPageFlip, + rmesa->sarea->pfCurrentPage ); + + if ( use_back ) { + rmesa->state.color.drawOffset = rmesa->radeonScreen->backOffset; + rmesa->state.color.drawPitch = rmesa->radeonScreen->backPitch; + } else { + rmesa->state.color.drawOffset = rmesa->radeonScreen->frontOffset; + rmesa->state.color.drawPitch = rmesa->radeonScreen->frontPitch; + } + + RADEON_STATECHANGE( rmesa, ctx ); + rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = rmesa->state.color.drawOffset; + rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = rmesa->state.color.drawPitch; +} + + + +/* Update the hardware state. This is called if another context has + * grabbed the hardware lock, which includes the X server. This + * function also updates the driver's window state after the X server + * moves, resizes or restacks a window -- the change will be reflected + * in the drawable position and clip rects. Since the X server grabs + * the hardware lock when it changes the window state, this routine will + * automatically be called after such a change. + */ +void radeonGetLock( radeonContextPtr rmesa, GLuint flags ) +{ + __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; + __DRIscreenPrivate *sPriv = rmesa->dri.screen; + RADEONSAREAPrivPtr sarea = rmesa->sarea; + + drmGetLock( rmesa->dri.fd, rmesa->dri.hwContext, flags ); + + /* The window might have moved, so we might need to get new clip + * rects. + * + * NOTE: This releases and regrabs the hw lock to allow the X server + * to respond to the DRI protocol request for new drawable info. + * Since the hardware state depends on having the latest drawable + * clip rects, all state checking must be done _after_ this call. + */ + DRI_VALIDATE_DRAWABLE_INFO( sPriv, dPriv ); + + if ( rmesa->lastStamp != dPriv->lastStamp ) { + radeonUpdatePageFlipping( rmesa ); + if (rmesa->glCtx->Color._DrawDestMask == BACK_LEFT_BIT) + radeonSetCliprects( rmesa, GL_BACK_LEFT ); + else + radeonSetCliprects( rmesa, GL_FRONT_LEFT ); + radeonUpdateViewportOffset( rmesa->glCtx ); + rmesa->lastStamp = dPriv->lastStamp; + } + + if ( sarea->ctxOwner != rmesa->dri.hwContext ) { + int i; + sarea->ctxOwner = rmesa->dri.hwContext; + + for ( i = 0 ; i < rmesa->nr_heaps ; i++ ) { + DRI_AGE_TEXTURES( rmesa->texture_heaps[ i ] ); + } + } +} diff --git a/src/mesa/drivers/dri/radeon/radeon_lock.h b/src/mesa/drivers/dri/radeon/radeon_lock.h new file mode 100644 index 0000000000..783db7e92a --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_lock.h @@ -0,0 +1,113 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_lock.h,v 1.3 2002/10/30 12:51:55 alanh Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + */ + +#ifndef __RADEON_LOCK_H__ +#define __RADEON_LOCK_H__ + +#ifdef GLX_DIRECT_RENDERING + +extern void radeonGetLock( radeonContextPtr rmesa, GLuint flags ); + +/* Turn DEBUG_LOCKING on to find locking conflicts. + */ +#define DEBUG_LOCKING 0 + +#if DEBUG_LOCKING +extern char *prevLockFile; +extern int prevLockLine; + +#define DEBUG_LOCK() \ + do { \ + prevLockFile = (__FILE__); \ + prevLockLine = (__LINE__); \ + } while (0) + +#define DEBUG_RESET() \ + do { \ + prevLockFile = 0; \ + prevLockLine = 0; \ + } while (0) + +#define DEBUG_CHECK_LOCK() \ + do { \ + if ( prevLockFile ) { \ + fprintf( stderr, \ + "LOCK SET!\n\tPrevious %s:%d\n\tCurrent: %s:%d\n", \ + prevLockFile, prevLockLine, __FILE__, __LINE__ ); \ + exit( 1 ); \ + } \ + } while (0) + +#else + +#define DEBUG_LOCK() +#define DEBUG_RESET() +#define DEBUG_CHECK_LOCK() + +#endif + +/* + * !!! We may want to separate locks from locks with validation. This + * could be used to improve performance for those things commands that + * do not do any drawing !!! + */ + + +/* Lock the hardware and validate our state. + */ +#define LOCK_HARDWARE( rmesa ) \ + do { \ + char __ret = 0; \ + DEBUG_CHECK_LOCK(); \ + DRM_CAS( rmesa->dri.hwLock, rmesa->dri.hwContext, \ + (DRM_LOCK_HELD | rmesa->dri.hwContext), __ret ); \ + if ( __ret ) \ + radeonGetLock( rmesa, 0 ); \ + DEBUG_LOCK(); \ + } while (0) + +/* Unlock the hardware. + */ +#define UNLOCK_HARDWARE( rmesa ) \ + do { \ + DRM_UNLOCK( rmesa->dri.fd, \ + rmesa->dri.hwLock, \ + rmesa->dri.hwContext ); \ + DEBUG_RESET(); \ + } while (0) + +#endif +#endif /* __RADEON_LOCK_H__ */ diff --git a/src/mesa/drivers/dri/radeon/radeon_maos.c b/src/mesa/drivers/dri/radeon/radeon_maos.c new file mode 100644 index 0000000000..c62edd715c --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_maos.c @@ -0,0 +1,12 @@ + + +/* If using new packets, can choose either verts or arrays. + * Otherwise, must use verts. + */ +#include "radeon_context.h" +#define RADEON_MAOS_VERTS 1 +#if (RADEON_MAOS_VERTS) || (RADEON_OLD_PACKETS) +#include "radeon_maos_verts.c" +#else +#include "radeon_maos_arrays.c" +#endif diff --git a/src/mesa/drivers/dri/radeon/radeon_maos.h b/src/mesa/drivers/dri/radeon/radeon_maos.h new file mode 100644 index 0000000000..7e2bd643d3 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_maos.h @@ -0,0 +1,47 @@ +/* $XFree86$ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + Tungsten Grahpics Inc., Austin, 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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#ifndef __RADEON_MAOS_H__ +#define __RADEON_MAOS_H__ + +#ifdef GLX_DIRECT_RENDERING + +#include "radeon_context.h" + +extern void radeonEmitArrays( GLcontext *ctx, GLuint inputs ); +extern void radeonReleaseArrays( GLcontext *ctx, GLuint newinputs ); + +#endif +#endif diff --git a/src/mesa/drivers/dri/radeon/radeon_maos_arrays.c b/src/mesa/drivers/dri/radeon/radeon_maos_arrays.c new file mode 100644 index 0000000000..cec05a89d7 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_maos_arrays.c @@ -0,0 +1,591 @@ +/* $XFree86$ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "glheader.h" +#include "imports.h" +#include "mtypes.h" +#include "mmath.h" +#include "macros.h" + +#include "swrast_setup/swrast_setup.h" +#include "math/m_translate.h" +#include "tnl/tnl.h" +#include "tnl/t_context.h" +#include "tnl/t_imm_debug.h" + +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_state.h" +#include "radeon_swtcl.h" +#include "radeon_maos.h" + +/* Usage: + * - from radeon_tcl_render + * - call radeonEmitArrays to ensure uptodate arrays in dma + * - emit primitives (new type?) which reference the data + * -- need to use elts for lineloop, quads, quadstrip/flat + * -- other primitives are all well-formed (need tristrip-1,fake-poly) + * + */ +static void emit_ubyte_rgba3( GLcontext *ctx, + struct radeon_dma_region *rvb, + char *data, + int stride, + int count ) +{ + int i; + radeon_color_t *out = (radeon_color_t *)(rvb->start + rvb->address); + + if (RADEON_DEBUG & DEBUG_VERTS) + fprintf(stderr, "%s count %d stride %d out %p\n", + __FUNCTION__, count, stride, out); + + for (i = 0; i < count; i++) { + out->red = *data; + out->green = *(data+1); + out->blue = *(data+2); + out->alpha = 0xFF; + out++; + data += stride; + } +} + + +#if defined(USE_X86_ASM) +#define COPY_DWORDS( dst, src, nr ) \ +do { \ + int __tmp; \ + __asm__ __volatile__( "rep ; movsl" \ + : "=%c" (__tmp), "=D" (dst), "=S" (__tmp) \ + : "0" (nr), \ + "D" ((long)dst), \ + "S" ((long)src) ); \ +} while (0) +#else +#define COPY_DWORDS( dst, src, nr ) \ +do { \ + int j; \ + for ( j = 0 ; j < nr ; j++ ) \ + dst[j] = ((int *)src)[j]; \ + dst += nr; \ +} while (0) +#endif + + + +static void emit_ubyte_rgba4( GLcontext *ctx, + struct radeon_dma_region *rvb, + char *data, + int stride, + int count ) +{ + int i; + int *out = (int *)(rvb->address + rvb->start); + + if (RADEON_DEBUG & DEBUG_VERTS) + fprintf(stderr, "%s count %d stride %d\n", + __FUNCTION__, count, stride); + + if (stride == 4) + COPY_DWORDS( out, data, count ); + else + for (i = 0; i < count; i++) { + *out++ = LE32_TO_CPU(*(int *)data); + data += stride; + } +} + + +static void emit_ubyte_rgba( GLcontext *ctx, + struct radeon_dma_region *rvb, + char *data, + int size, + int stride, + int count ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if (RADEON_DEBUG & DEBUG_VERTS) + fprintf(stderr, "%s %d/%d\n", __FUNCTION__, count, size); + + assert (!rvb->buf); + + if (stride == 0) { + radeonAllocDmaRegion( rmesa, rvb, 4, 4 ); + count = 1; + rvb->aos_start = GET_START(rvb); + rvb->aos_stride = 0; + rvb->aos_size = 1; + } + else { + radeonAllocDmaRegion( rmesa, rvb, 4 * count, 4 ); /* alignment? */ + rvb->aos_start = GET_START(rvb); + rvb->aos_stride = 1; + rvb->aos_size = 1; + } + + /* Emit the data + */ + switch (size) { + case 3: + emit_ubyte_rgba3( ctx, rvb, data, stride, count ); + break; + case 4: + emit_ubyte_rgba4( ctx, rvb, data, stride, count ); + break; + default: + assert(0); + exit(1); + break; + } +} + + + + +static void emit_vec8( GLcontext *ctx, + struct radeon_dma_region *rvb, + char *data, + int stride, + int count ) +{ + int i; + int *out = (int *)(rvb->address + rvb->start); + + if (RADEON_DEBUG & DEBUG_VERTS) + fprintf(stderr, "%s count %d stride %d\n", + __FUNCTION__, count, stride); + + if (stride == 8) + COPY_DWORDS( out, data, count*2 ); + else + for (i = 0; i < count; i++) { + out[0] = *(int *)data; + out[1] = *(int *)(data+4); + out += 2; + data += stride; + } +} + +static void emit_vec12( GLcontext *ctx, + struct radeon_dma_region *rvb, + char *data, + int stride, + int count ) +{ + int i; + int *out = (int *)(rvb->address + rvb->start); + + if (RADEON_DEBUG & DEBUG_VERTS) + fprintf(stderr, "%s count %d stride %d out %p data %p\n", + __FUNCTION__, count, stride, out, data); + + if (stride == 12) + COPY_DWORDS( out, data, count*3 ); + else + for (i = 0; i < count; i++) { + out[0] = *(int *)data; + out[1] = *(int *)(data+4); + out[2] = *(int *)(data+8); + out += 3; + data += stride; + } +} + +static void emit_vec16( GLcontext *ctx, + struct radeon_dma_region *rvb, + char *data, + int stride, + int count ) +{ + int i; + int *out = (int *)(rvb->address + rvb->start); + + if (RADEON_DEBUG & DEBUG_VERTS) + fprintf(stderr, "%s count %d stride %d\n", + __FUNCTION__, count, stride); + + if (stride == 16) + COPY_DWORDS( out, data, count*4 ); + else + for (i = 0; i < count; i++) { + out[0] = *(int *)data; + out[1] = *(int *)(data+4); + out[2] = *(int *)(data+8); + out[3] = *(int *)(data+12); + out += 4; + data += stride; + } +} + + +static void emit_vector( GLcontext *ctx, + struct radeon_dma_region *rvb, + char *data, + int size, + int stride, + int count ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if (RADEON_DEBUG & DEBUG_VERTS) + fprintf(stderr, "%s count %d size %d stride %d\n", + __FUNCTION__, count, size, stride); + + assert (!rvb->buf); + + if (stride == 0) { + radeonAllocDmaRegion( rmesa, rvb, size * 4, 4 ); + count = 1; + rvb->aos_start = GET_START(rvb); + rvb->aos_stride = 0; + rvb->aos_size = size; + } + else { + radeonAllocDmaRegion( rmesa, rvb, size * count * 4, 4 ); /* alignment? */ + rvb->aos_start = GET_START(rvb); + rvb->aos_stride = size; + rvb->aos_size = size; + } + + /* Emit the data + */ + switch (size) { + case 2: + emit_vec8( ctx, rvb, data, stride, count ); + break; + case 3: + emit_vec12( ctx, rvb, data, stride, count ); + break; + case 4: + emit_vec16( ctx, rvb, data, stride, count ); + break; + default: + assert(0); + exit(1); + break; + } + +} + + + +static void emit_s0_vec( GLcontext *ctx, + struct radeon_dma_region *rvb, + char *data, + int stride, + int count ) +{ + int i; + int *out = (int *)(rvb->address + rvb->start); + + if (RADEON_DEBUG & DEBUG_VERTS) + fprintf(stderr, "%s count %d stride %d\n", + __FUNCTION__, count, stride); + + for (i = 0; i < count; i++) { + out[0] = *(int *)data; + out[1] = 0; + out += 2; + data += stride; + } +} + +static void emit_stq_vec( GLcontext *ctx, + struct radeon_dma_region *rvb, + char *data, + int stride, + int count ) +{ + int i; + int *out = (int *)(rvb->address + rvb->start); + + if (RADEON_DEBUG & DEBUG_VERTS) + fprintf(stderr, "%s count %d stride %d\n", + __FUNCTION__, count, stride); + + for (i = 0; i < count; i++) { + out[0] = *(int *)data; + out[1] = *(int *)(data+4); + out[2] = *(int *)(data+12); + out += 3; + data += stride; + } +} + + + + +static void emit_tex_vector( GLcontext *ctx, + struct radeon_dma_region *rvb, + char *data, + int size, + int stride, + int count ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + int emitsize; + + if (RADEON_DEBUG & DEBUG_VERTS) + fprintf(stderr, "%s %d/%d\n", __FUNCTION__, count, size); + + assert (!rvb->buf); + + switch (size) { + case 4: emitsize = 3; break; + default: emitsize = 2; break; + } + + + if (stride == 0) { + radeonAllocDmaRegion( rmesa, rvb, 4 * emitsize, 4 ); + count = 1; + rvb->aos_start = GET_START(rvb); + rvb->aos_stride = 0; + rvb->aos_size = emitsize; + } + else { + radeonAllocDmaRegion( rmesa, rvb, 4 * emitsize * count, 4 ); + rvb->aos_start = GET_START(rvb); + rvb->aos_stride = emitsize; + rvb->aos_size = emitsize; + } + + + /* Emit the data + */ + switch (size) { + case 1: + emit_s0_vec( ctx, rvb, data, stride, count ); + break; + case 2: + emit_vec8( ctx, rvb, data, stride, count ); + break; + case 3: + emit_vec8( ctx, rvb, data, stride, count ); + break; + case 4: + emit_stq_vec( ctx, rvb, data, stride, count ); + break; + default: + assert(0); + exit(1); + break; + } +} + + + + +/* Emit any changed arrays to new agp memory, re-emit a packet to + * update the arrays. + */ +void radeonEmitArrays( GLcontext *ctx, GLuint inputs ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + struct vertex_buffer *VB = &TNL_CONTEXT( ctx )->vb; + struct radeon_dma_region **component = rmesa->tcl.aos_components; + GLuint nr = 0; + GLuint vfmt = 0; + GLuint count = VB->Count; + GLuint vtx; + + if (RADEON_DEBUG & DEBUG_VERTS) + _tnl_print_vert_flags( __FUNCTION__, inputs ); + + if (1) { + if (!rmesa->tcl.obj.buf) + emit_vector( ctx, + &rmesa->tcl.obj, + (char *)VB->ObjPtr->data, + VB->ObjPtr->size, + VB->ObjPtr->stride, + count); + + switch( VB->ObjPtr->size ) { + case 4: vfmt |= RADEON_CP_VC_FRMT_W0; + case 3: vfmt |= RADEON_CP_VC_FRMT_Z; + case 2: vfmt |= RADEON_CP_VC_FRMT_XY; + default: + } + component[nr++] = &rmesa->tcl.obj; + } + + + if (inputs & VERT_BIT_NORMAL) { + if (!rmesa->tcl.norm.buf) + emit_vector( ctx, + &(rmesa->tcl.norm), + (char *)VB->NormalPtr->data, + 3, + VB->NormalPtr->stride, + count); + + vfmt |= RADEON_CP_VC_FRMT_N0; + component[nr++] = &rmesa->tcl.norm; + } + + if (inputs & VERT_BIT_COLOR0) { + if (VB->ColorPtr[0]->Type == GL_UNSIGNED_BYTE) { + if (!rmesa->tcl.rgba.buf) + emit_ubyte_rgba( ctx, + &rmesa->tcl.rgba, + (char *)VB->ColorPtr[0]->Ptr, + VB->ColorPtr[0]->Size, + VB->ColorPtr[0]->StrideB, + count); + + vfmt |= RADEON_CP_VC_FRMT_PKCOLOR; + } + else { + int emitsize; + + if (VB->ColorPtr[0]->Size == 4 && + (VB->ColorPtr[0]->StrideB != 0 || + ((GLfloat *)VB->ColorPtr[0]->Ptr)[3] != 1.0)) { + vfmt |= RADEON_CP_VC_FRMT_FPCOLOR | RADEON_CP_VC_FRMT_FPALPHA; + emitsize = 4; + } + else { + vfmt |= RADEON_CP_VC_FRMT_FPCOLOR; + emitsize = 3; + } + + if (!rmesa->tcl.rgba.buf) + emit_vector( ctx, + &(rmesa->tcl.rgba), + (char *)VB->ColorPtr[0]->Ptr, + emitsize, + VB->ColorPtr[0]->StrideB, + count); + } + + component[nr++] = &rmesa->tcl.rgba; + } + + + if (inputs & VERT_BIT_COLOR1) { + if (!rmesa->tcl.spec.buf) { + if (VB->SecondaryColorPtr[0]->Type != GL_UNSIGNED_BYTE) + radeon_import_float_spec_colors( ctx ); + + emit_ubyte_rgba( ctx, + &rmesa->tcl.spec, + (char *)VB->SecondaryColorPtr[0]->Ptr, + 3, + VB->SecondaryColorPtr[0]->StrideB, + count); + } + + vfmt |= RADEON_CP_VC_FRMT_PKSPEC; + component[nr++] = &rmesa->tcl.spec; + } + + vtx = (rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] & + ~(RADEON_TCL_VTX_Q0|RADEON_TCL_VTX_Q1)); + + if (inputs & VERT_BIT_TEX0) { + if (!rmesa->tcl.tex[0].buf) + emit_tex_vector( ctx, + &(rmesa->tcl.tex[0]), + (char *)VB->TexCoordPtr[0]->data, + VB->TexCoordPtr[0]->size, + VB->TexCoordPtr[0]->stride, + count ); + + switch( VB->TexCoordPtr[0]->size ) { + case 4: + vtx |= RADEON_TCL_VTX_Q0; + vfmt |= RADEON_CP_VC_FRMT_Q0; + default: + vfmt |= RADEON_CP_VC_FRMT_ST0; + } + component[nr++] = &rmesa->tcl.tex[0]; + } + + if (inputs & VERT_BIT_TEX1) { + if (!rmesa->tcl.tex[1].buf) + emit_tex_vector( ctx, + &(rmesa->tcl.tex[1]), + (char *)VB->TexCoordPtr[1]->data, + VB->TexCoordPtr[1]->size, + VB->TexCoordPtr[1]->stride, + count ); + + switch( VB->TexCoordPtr[1]->size ) { + case 4: + vtx |= RADEON_TCL_VTX_Q1; + vfmt |= RADEON_CP_VC_FRMT_Q1; + default: + vfmt |= RADEON_CP_VC_FRMT_ST1; + } + component[nr++] = &rmesa->tcl.tex[1]; + } + + if (vtx != rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT]) { + RADEON_STATECHANGE( rmesa, tcl ); + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] = vtx; + } + + rmesa->tcl.nr_aos_components = nr; + rmesa->tcl.vertex_format = vfmt; +} + + +void radeonReleaseArrays( GLcontext *ctx, GLuint newinputs ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + + if (RADEON_DEBUG & DEBUG_VERTS) + _tnl_print_vert_flags( __FUNCTION__, newinputs ); + + if (newinputs & VERT_BIT_POS) + radeonReleaseDmaRegion( rmesa, &rmesa->tcl.obj, __FUNCTION__ ); + + if (newinputs & VERT_BIT_NORMAL) + radeonReleaseDmaRegion( rmesa, &rmesa->tcl.norm, __FUNCTION__ ); + + if (newinputs & VERT_BIT_COLOR0) + radeonReleaseDmaRegion( rmesa, &rmesa->tcl.rgba, __FUNCTION__ ); + + if (newinputs & VERT_BIT_COLOR1) + radeonReleaseDmaRegion( rmesa, &rmesa->tcl.spec, __FUNCTION__ ); + + if (newinputs & VERT_BIT_TEX0) + radeonReleaseDmaRegion( rmesa, &rmesa->tcl.tex[0], __FUNCTION__ ); + + if (newinputs & VERT_BIT_TEX1) + radeonReleaseDmaRegion( rmesa, &rmesa->tcl.tex[1], __FUNCTION__ ); +} diff --git a/src/mesa/drivers/dri/radeon/radeon_maos_vbtmp.h b/src/mesa/drivers/dri/radeon/radeon_maos_vbtmp.h new file mode 100644 index 0000000000..b379bad985 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_maos_vbtmp.h @@ -0,0 +1,368 @@ +/* + * Mesa 3-D graphics library + * Version: 4.1 + * + * Copyright (C) 1999-2002 Brian Paul 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, sublicense, + * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL 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. + * + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#ifndef LOCALVARS +#define LOCALVARS +#endif + +#undef TCL_DEBUG +#ifndef TCL_DEBUG +#define TCL_DEBUG 0 +#endif + +static void TAG(emit)( GLcontext *ctx, + GLuint start, GLuint end, + void *dest ) +{ + LOCALVARS + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLuint (*tc0)[4], (*tc1)[4], (*tc2)[4]; + GLfloat (*fog)[4]; + GLuint (*norm)[4]; + GLubyte (*col)[4], (*spec)[4]; + GLuint tc0_stride, tc1_stride, col_stride, spec_stride, fog_stride; + GLuint tc2_stride, norm_stride; + GLuint (*coord)[4]; + GLuint coord_stride; /* object coordinates */ + GLubyte dummy[4]; + int i; + + union emit_union *v = (union emit_union *)dest; + + if (RADEON_DEBUG & DEBUG_VERTS) + fprintf(stderr, "%s\n", __FUNCTION__); + + /* The vertex code expects Obj to be clean to element 3. To fix + * this, add more vertex code (for obj-2, obj-3) or preferably move + * to maos. + */ + if (VB->ObjPtr->size < 3) { + if (VB->ObjPtr->flags & VEC_NOT_WRITEABLE) { + VB->import_data( ctx, VERT_BIT_POS, VEC_NOT_WRITEABLE ); + } + _mesa_vector4f_clean_elem( VB->ObjPtr, VB->Count, 2 ); + } + + if (DO_W && VB->ObjPtr->size < 4) { + if (VB->ObjPtr->flags & VEC_NOT_WRITEABLE) { + VB->import_data( ctx, VERT_BIT_POS, VEC_NOT_WRITEABLE ); + } + _mesa_vector4f_clean_elem( VB->ObjPtr, VB->Count, 3 ); + } + + coord = (GLuint (*)[4])VB->ObjPtr->data; + coord_stride = VB->ObjPtr->stride; + + if (DO_TEX2) { + const GLuint t2 = GET_TEXSOURCE(2); + tc2 = (GLuint (*)[4])VB->TexCoordPtr[t2]->data; + tc2_stride = VB->TexCoordPtr[t2]->stride; + if (DO_PTEX && VB->TexCoordPtr[t2]->size < 4) { + if (VB->TexCoordPtr[t2]->flags & VEC_NOT_WRITEABLE) { + VB->import_data( ctx, VERT_BIT_TEX2, VEC_NOT_WRITEABLE ); + } + _mesa_vector4f_clean_elem( VB->TexCoordPtr[t2], VB->Count, 3 ); + } + } + + if (DO_TEX1) { + if (VB->TexCoordPtr[1]) { + const GLuint t1 = GET_TEXSOURCE(1); + tc1 = (GLuint (*)[4])VB->TexCoordPtr[t1]->data; + tc1_stride = VB->TexCoordPtr[t1]->stride; + if (DO_PTEX && VB->TexCoordPtr[t1]->size < 4) { + if (VB->TexCoordPtr[t1]->flags & VEC_NOT_WRITEABLE) { + VB->import_data( ctx, VERT_BIT_TEX1, VEC_NOT_WRITEABLE ); + } + _mesa_vector4f_clean_elem( VB->TexCoordPtr[t1], VB->Count, 3 ); + } + } else { + tc1 = (GLuint (*)[4])&ctx->Current.Attrib[VERT_ATTRIB_TEX1]; /* could be anything, really */ + tc1_stride = 0; + } + } + + if (DO_TEX0) { + if (VB->TexCoordPtr[0]) { + const GLuint t0 = GET_TEXSOURCE(0); + tc0_stride = VB->TexCoordPtr[t0]->stride; + tc0 = (GLuint (*)[4])VB->TexCoordPtr[t0]->data; + if (DO_PTEX && VB->TexCoordPtr[t0]->size < 4) { + if (VB->TexCoordPtr[t0]->flags & VEC_NOT_WRITEABLE) { + VB->import_data( ctx, VERT_BIT_TEX0, VEC_NOT_WRITEABLE ); + } + _mesa_vector4f_clean_elem( VB->TexCoordPtr[t0], VB->Count, 3 ); + } + } else { + tc0 = (GLuint (*)[4])&ctx->Current.Attrib[VERT_ATTRIB_TEX0]; /* could be anything, really */ + tc0_stride = 0; + } + + } + + if (DO_NORM) { + if (VB->NormalPtr) { + norm_stride = VB->NormalPtr->stride; + norm = (GLuint (*)[4])VB->NormalPtr->data; + } else { + norm_stride = 0; + norm = (GLuint (*)[4])&ctx->Current.Attrib[VERT_ATTRIB_NORMAL]; + } + } + + if (DO_RGBA) { + if (VB->ColorPtr[0]) { + /* This is incorrect when colormaterial is enabled: + */ + if (VB->ColorPtr[0]->Type != GL_UNSIGNED_BYTE) { + if (0) fprintf(stderr, "IMPORTING FLOAT COLORS\n"); + IMPORT_FLOAT_COLORS( ctx ); + } + col = (GLubyte (*)[4])VB->ColorPtr[0]->Ptr; + col_stride = VB->ColorPtr[0]->StrideB; + } else { + col = &dummy; /* any old memory is fine */ + col_stride = 0; + } + } + + if (DO_SPEC) { + if (VB->SecondaryColorPtr[0]) { + if (VB->SecondaryColorPtr[0]->Type != GL_UNSIGNED_BYTE) + IMPORT_FLOAT_SPEC_COLORS( ctx ); + spec = (GLubyte (*)[4])VB->SecondaryColorPtr[0]->Ptr; + spec_stride = VB->SecondaryColorPtr[0]->StrideB; + } else { + spec = &dummy; + spec_stride = 0; + } + } + + if (DO_FOG) { + if (VB->FogCoordPtr) { + fog = VB->FogCoordPtr->data; + fog_stride = VB->FogCoordPtr->stride; + } else { + fog = (GLfloat (*)[4])&dummy; fog[0][0] = 0.0F; + fog_stride = 0; + } + } + + + if (VB->importable_data) { + if (start) { + coord = (GLuint (*)[4])((GLubyte *)coord + start * coord_stride); + if (DO_TEX0) + tc0 = (GLuint (*)[4])((GLubyte *)tc0 + start * tc0_stride); + if (DO_TEX1) + tc1 = (GLuint (*)[4])((GLubyte *)tc1 + start * tc1_stride); + if (DO_TEX2) + tc2 = (GLuint (*)[4])((GLubyte *)tc2 + start * tc2_stride); + if (DO_NORM) + norm = (GLuint (*)[4])((GLubyte *)norm + start * norm_stride); + if (DO_RGBA) + STRIDE_4UB(col, start * col_stride); + if (DO_SPEC) + STRIDE_4UB(spec, start * spec_stride); + if (DO_FOG) + fog = (GLfloat (*)[4])((GLubyte *)fog + start * fog_stride); + } + + for (i=start; i < end; i++) { + v[0].ui = coord[0][0]; + v[1].ui = coord[0][1]; + v[2].ui = coord[0][2]; + if (TCL_DEBUG) fprintf(stderr, "%d: %.2f %.2f %.2f ", i, v[0].f, v[1].f, v[2].f); + if (DO_W) { + v[3].ui = coord[0][3]; + if (TCL_DEBUG) fprintf(stderr, "%.2f ", v[3].f); + v += 4; + } + else + v += 3; + coord = (GLuint (*)[4])((GLubyte *)coord + coord_stride); + + if (DO_NORM) { + v[0].ui = norm[0][0]; + v[1].ui = norm[0][1]; + v[2].ui = norm[0][2]; + if (TCL_DEBUG) fprintf(stderr, "norm: %.2f %.2f %.2f ", v[0].f, v[1].f, v[2].f); + v += 3; + norm = (GLuint (*)[4])((GLubyte *)norm + norm_stride); + } + if (DO_RGBA) { + v[0].ui = LE32_TO_CPU(*(GLuint *)&col[0]); + STRIDE_4UB(col, col_stride); + if (TCL_DEBUG) fprintf(stderr, "%x ", v[0].ui); + v++; + } + if (DO_SPEC || DO_FOG) { + if (DO_SPEC) { + v[0].specular.red = spec[0][0]; + v[0].specular.green = spec[0][1]; + v[0].specular.blue = spec[0][2]; + STRIDE_4UB(spec, spec_stride); + } + if (DO_FOG) { + v[0].specular.alpha = fog[0][0] * 255.0; + fog = (GLfloat (*)[4])((GLubyte *)fog + fog_stride); + } + if (TCL_DEBUG) fprintf(stderr, "%x ", v[0].ui); + v++; + } + if (DO_TEX0) { + v[0].ui = tc0[0][0]; + v[1].ui = tc0[0][1]; + if (TCL_DEBUG) fprintf(stderr, "t0: %.2f %.2f ", v[0].f, v[1].f); + if (DO_PTEX) { + v[2].ui = tc0[0][3]; + if (TCL_DEBUG) fprintf(stderr, "%.2f ", v[2].f); + v += 3; + } + else + v += 2; + tc0 = (GLuint (*)[4])((GLubyte *)tc0 + tc0_stride); + } + if (DO_TEX1) { + v[0].ui = tc1[0][0]; + v[1].ui = tc1[0][1]; + if (TCL_DEBUG) fprintf(stderr, "t1: %.2f %.2f ", v[0].f, v[1].f); + if (DO_PTEX) { + v[2].ui = tc1[0][3]; + if (TCL_DEBUG) fprintf(stderr, "%.2f ", v[2].f); + v += 3; + } + else + v += 2; + tc1 = (GLuint (*)[4])((GLubyte *)tc1 + tc1_stride); + } + if (DO_TEX2) { + v[0].ui = tc2[0][0]; + v[1].ui = tc2[0][1]; + if (DO_PTEX) { + v[2].ui = tc2[0][3]; + v += 3; + } + else + v += 2; + tc2 = (GLuint (*)[4])((GLubyte *)tc2 + tc2_stride); + } + if (TCL_DEBUG) fprintf(stderr, "\n"); + } + } else { + for (i=start; i < end; i++) { + v[0].ui = coord[i][0]; + v[1].ui = coord[i][1]; + v[2].ui = coord[i][2]; + if (DO_W) { + v[3].ui = coord[i][3]; + v += 4; + } + else + v += 3; + + if (DO_NORM) { + v[0].ui = norm[i][0]; + v[1].ui = norm[i][1]; + v[2].ui = norm[i][2]; + v += 3; + } + if (DO_RGBA) { + v[0].ui = LE32_TO_CPU(*(GLuint *)&col[i]); + v++; + } + if (DO_SPEC || DO_FOG) { + if (DO_SPEC) { + v[0].specular.red = spec[i][0]; + v[0].specular.green = spec[i][1]; + v[0].specular.blue = spec[i][2]; + } + if (DO_FOG) { + GLfloat *f = (GLfloat *) ((GLubyte *)fog + fog_stride); + v[0].specular.alpha = *f * 255.0; + } + v++; + } + if (DO_TEX0) { + v[0].ui = tc0[i][0]; + v[1].ui = tc0[i][1]; + if (DO_PTEX) { + v[2].ui = tc0[i][3]; + v += 3; + } + else + v += 2; + } + if (DO_TEX1) { + v[0].ui = tc1[i][0]; + v[1].ui = tc1[i][1]; + if (DO_PTEX) { + v[2].ui = tc1[i][3]; + v += 3; + } + else + v += 2; + } + if (DO_TEX2) { + v[0].ui = tc2[i][0]; + v[1].ui = tc2[i][1]; + if (DO_PTEX) { + v[2].ui = tc2[i][3]; + v += 3; + } + else + v += 2; + } + } + } +} + + + +static void TAG(init)( void ) +{ + int sz = 3; + if (DO_W) sz++; + if (DO_NORM) sz += 3; + if (DO_RGBA) sz++; + if (DO_SPEC || DO_FOG) sz++; + if (DO_TEX0) sz += 2; + if (DO_TEX0 && DO_PTEX) sz++; + if (DO_TEX1) sz += 2; + if (DO_TEX1 && DO_PTEX) sz++; + if (DO_TEX2) sz += 2; + if (DO_TEX2 && DO_PTEX) sz++; + + setup_tab[IDX].emit = TAG(emit); + setup_tab[IDX].vertex_format = IND; + setup_tab[IDX].vertex_size = sz; +} + + +#undef IND +#undef TAG +#undef IDX diff --git a/src/mesa/drivers/dri/radeon/radeon_maos_verts.c b/src/mesa/drivers/dri/radeon/radeon_maos_verts.c new file mode 100644 index 0000000000..39b1f57507 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_maos_verts.c @@ -0,0 +1,335 @@ +/* $XFree86$ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + Tungsten Graphics Inc., Austin, 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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "glheader.h" +#include "imports.h" +#include "mtypes.h" + +#include "array_cache/acache.h" +#include "tnl/tnl.h" +#include "tnl/t_pipeline.h" +#include "tnl/t_imm_debug.h" + +#include "radeon_context.h" +#include "radeon_state.h" +#include "radeon_ioctl.h" +#include "radeon_tex.h" +#include "radeon_tcl.h" +#include "radeon_swtcl.h" +#include "radeon_maos.h" + + +#define RADEON_TCL_MAX_SETUP 13 + +union emit_union { float f; GLuint ui; radeon_color_t specular; }; + +static struct { + void (*emit)( GLcontext *, GLuint, GLuint, void * ); + GLuint vertex_size; + GLuint vertex_format; +} setup_tab[RADEON_TCL_MAX_SETUP]; + +#define DO_W (IND & RADEON_CP_VC_FRMT_W0) +#define DO_RGBA (IND & RADEON_CP_VC_FRMT_PKCOLOR) +#define DO_SPEC (IND & RADEON_CP_VC_FRMT_PKSPEC) +#define DO_FOG (IND & RADEON_CP_VC_FRMT_PKSPEC) +#define DO_TEX0 (IND & RADEON_CP_VC_FRMT_ST0) +#define DO_TEX1 (IND & RADEON_CP_VC_FRMT_ST1) +#define DO_PTEX (IND & RADEON_CP_VC_FRMT_Q0) +#define DO_NORM (IND & RADEON_CP_VC_FRMT_N0) + +#define DO_TEX2 0 +#define DO_TEX3 0 + +#define GET_TEXSOURCE(n) n +#define GET_UBYTE_COLOR_STORE() &RADEON_CONTEXT(ctx)->UbyteColor +#define GET_UBYTE_SPEC_COLOR_STORE() &RADEON_CONTEXT(ctx)->UbyteSecondaryColor + +#define IMPORT_FLOAT_COLORS radeon_import_float_colors +#define IMPORT_FLOAT_SPEC_COLORS radeon_import_float_spec_colors + +/*********************************************************************** + * Generate vertex emit functions * + ***********************************************************************/ + + +/* Defined in order of increasing vertex size: + */ +#define IDX 0 +#define IND (RADEON_CP_VC_FRMT_XY| \ + RADEON_CP_VC_FRMT_Z| \ + RADEON_CP_VC_FRMT_PKCOLOR) +#define TAG(x) x##_rgba +#include "radeon_maos_vbtmp.h" + +#define IDX 1 +#define IND (RADEON_CP_VC_FRMT_XY| \ + RADEON_CP_VC_FRMT_Z| \ + RADEON_CP_VC_FRMT_N0) +#define TAG(x) x##_n +#include "radeon_maos_vbtmp.h" + +#define IDX 2 +#define IND (RADEON_CP_VC_FRMT_XY| \ + RADEON_CP_VC_FRMT_Z| \ + RADEON_CP_VC_FRMT_PKCOLOR| \ + RADEON_CP_VC_FRMT_ST0) +#define TAG(x) x##_rgba_st +#include "radeon_maos_vbtmp.h" + +#define IDX 3 +#define IND (RADEON_CP_VC_FRMT_XY| \ + RADEON_CP_VC_FRMT_Z| \ + RADEON_CP_VC_FRMT_PKCOLOR| \ + RADEON_CP_VC_FRMT_N0) +#define TAG(x) x##_rgba_n +#include "radeon_maos_vbtmp.h" + +#define IDX 4 +#define IND (RADEON_CP_VC_FRMT_XY| \ + RADEON_CP_VC_FRMT_Z| \ + RADEON_CP_VC_FRMT_ST0| \ + RADEON_CP_VC_FRMT_N0) +#define TAG(x) x##_st_n +#include "radeon_maos_vbtmp.h" + +#define IDX 5 +#define IND (RADEON_CP_VC_FRMT_XY| \ + RADEON_CP_VC_FRMT_Z| \ + RADEON_CP_VC_FRMT_PKCOLOR| \ + RADEON_CP_VC_FRMT_ST0| \ + RADEON_CP_VC_FRMT_ST1) +#define TAG(x) x##_rgba_st_st +#include "radeon_maos_vbtmp.h" + +#define IDX 6 +#define IND (RADEON_CP_VC_FRMT_XY| \ + RADEON_CP_VC_FRMT_Z| \ + RADEON_CP_VC_FRMT_PKCOLOR| \ + RADEON_CP_VC_FRMT_ST0| \ + RADEON_CP_VC_FRMT_N0) +#define TAG(x) x##_rgba_st_n +#include "radeon_maos_vbtmp.h" + +#define IDX 7 +#define IND (RADEON_CP_VC_FRMT_XY| \ + RADEON_CP_VC_FRMT_Z| \ + RADEON_CP_VC_FRMT_PKCOLOR| \ + RADEON_CP_VC_FRMT_PKSPEC| \ + RADEON_CP_VC_FRMT_ST0| \ + RADEON_CP_VC_FRMT_ST1) +#define TAG(x) x##_rgba_spec_st_st +#include "radeon_maos_vbtmp.h" + +#define IDX 8 +#define IND (RADEON_CP_VC_FRMT_XY| \ + RADEON_CP_VC_FRMT_Z| \ + RADEON_CP_VC_FRMT_ST0| \ + RADEON_CP_VC_FRMT_ST1| \ + RADEON_CP_VC_FRMT_N0) +#define TAG(x) x##_st_st_n +#include "radeon_maos_vbtmp.h" + +#define IDX 9 +#define IND (RADEON_CP_VC_FRMT_XY| \ + RADEON_CP_VC_FRMT_Z| \ + RADEON_CP_VC_FRMT_PKCOLOR| \ + RADEON_CP_VC_FRMT_PKSPEC| \ + RADEON_CP_VC_FRMT_ST0| \ + RADEON_CP_VC_FRMT_ST1| \ + RADEON_CP_VC_FRMT_N0) +#define TAG(x) x##_rgpa_spec_st_st_n +#include "radeon_maos_vbtmp.h" + +#define IDX 10 +#define IND (RADEON_CP_VC_FRMT_XY| \ + RADEON_CP_VC_FRMT_Z| \ + RADEON_CP_VC_FRMT_PKCOLOR| \ + RADEON_CP_VC_FRMT_ST0| \ + RADEON_CP_VC_FRMT_Q0) +#define TAG(x) x##_rgba_stq +#include "radeon_maos_vbtmp.h" + +#define IDX 11 +#define IND (RADEON_CP_VC_FRMT_XY| \ + RADEON_CP_VC_FRMT_Z| \ + RADEON_CP_VC_FRMT_PKCOLOR| \ + RADEON_CP_VC_FRMT_ST1| \ + RADEON_CP_VC_FRMT_Q1| \ + RADEON_CP_VC_FRMT_ST0| \ + RADEON_CP_VC_FRMT_Q0) +#define TAG(x) x##_rgba_stq_stq +#include "radeon_maos_vbtmp.h" + +#define IDX 12 +#define IND (RADEON_CP_VC_FRMT_XY| \ + RADEON_CP_VC_FRMT_Z| \ + RADEON_CP_VC_FRMT_W0| \ + RADEON_CP_VC_FRMT_PKCOLOR| \ + RADEON_CP_VC_FRMT_PKSPEC| \ + RADEON_CP_VC_FRMT_ST0| \ + RADEON_CP_VC_FRMT_Q0| \ + RADEON_CP_VC_FRMT_ST1| \ + RADEON_CP_VC_FRMT_Q1| \ + RADEON_CP_VC_FRMT_N0) +#define TAG(x) x##_w_rgpa_spec_stq_stq_n +#include "radeon_maos_vbtmp.h" + + + + + +/*********************************************************************** + * Initialization + ***********************************************************************/ + + +static void init_tcl_verts( void ) +{ + init_rgba(); + init_n(); + init_rgba_n(); + init_rgba_st(); + init_st_n(); + init_rgba_st_st(); + init_rgba_st_n(); + init_rgba_spec_st_st(); + init_st_st_n(); + init_rgpa_spec_st_st_n(); + init_rgba_stq(); + init_rgba_stq_stq(); + init_w_rgpa_spec_stq_stq_n(); +} + + +void radeonEmitArrays( GLcontext *ctx, GLuint inputs ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + GLuint req = 0; + GLuint vtx = (rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] & + ~(RADEON_TCL_VTX_Q0|RADEON_TCL_VTX_Q1)); + int i; + static int firsttime = 1; + + if (firsttime) { + init_tcl_verts(); + firsttime = 0; + } + + if (1) { + req |= RADEON_CP_VC_FRMT_Z; + if (VB->ObjPtr->size == 4) { + req |= RADEON_CP_VC_FRMT_W0; + } + } + + if (inputs & VERT_BIT_NORMAL) { + req |= RADEON_CP_VC_FRMT_N0; + } + + if (inputs & VERT_BIT_COLOR0) { + req |= RADEON_CP_VC_FRMT_PKCOLOR; + } + + if (inputs & VERT_BIT_COLOR1) { + req |= RADEON_CP_VC_FRMT_PKSPEC; + } + + if (inputs & VERT_BIT_TEX0) { + req |= RADEON_CP_VC_FRMT_ST0; + + if (VB->TexCoordPtr[0]->size == 4) { + req |= RADEON_CP_VC_FRMT_Q0; + vtx |= RADEON_TCL_VTX_Q0; + } + } + + if (inputs & VERT_BIT_TEX1) { + req |= RADEON_CP_VC_FRMT_ST1; + + if (VB->TexCoordPtr[1]->size == 4) { + req |= RADEON_CP_VC_FRMT_Q1; + vtx |= RADEON_TCL_VTX_Q1; + } + } + + if (vtx != rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT]) { + RADEON_STATECHANGE( rmesa, tcl ); + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] = vtx; + } + + for (i = 0 ; i < RADEON_TCL_MAX_SETUP ; i++) + if ((setup_tab[i].vertex_format & req) == req) + break; + + if (rmesa->tcl.vertex_format == setup_tab[i].vertex_format && + rmesa->tcl.indexed_verts.buf) + return; + + if (rmesa->tcl.indexed_verts.buf) + radeonReleaseArrays( ctx, ~0 ); + + radeonAllocDmaRegionVerts( rmesa, + &rmesa->tcl.indexed_verts, + VB->Count, + setup_tab[i].vertex_size * 4, + 4); + + setup_tab[i].emit( ctx, 0, VB->Count, + rmesa->tcl.indexed_verts.address + + rmesa->tcl.indexed_verts.start ); + + rmesa->tcl.vertex_format = setup_tab[i].vertex_format; + rmesa->tcl.indexed_verts.aos_start = GET_START( &rmesa->tcl.indexed_verts ); + rmesa->tcl.indexed_verts.aos_size = setup_tab[i].vertex_size; + rmesa->tcl.indexed_verts.aos_stride = setup_tab[i].vertex_size; + + rmesa->tcl.aos_components[0] = &rmesa->tcl.indexed_verts; + rmesa->tcl.nr_aos_components = 1; +} + + + +void radeonReleaseArrays( GLcontext *ctx, GLuint newinputs ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + + if (RADEON_DEBUG & DEBUG_VERTS) + _tnl_print_vert_flags( __FUNCTION__, newinputs ); + + if (newinputs) + radeonReleaseDmaRegion( rmesa, &rmesa->tcl.indexed_verts, __FUNCTION__ ); +} diff --git a/src/mesa/drivers/dri/radeon/radeon_sanity.c b/src/mesa/drivers/dri/radeon/radeon_sanity.c new file mode 100644 index 0000000000..e3b37bf3de --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_sanity.c @@ -0,0 +1,1043 @@ +/* $XFree86$ */ +/************************************************************************** + +Copyright 2002 ATI Technologies Inc., Ontario, Canada, and + Tungsten Graphics Inc, Cedar Park, TX. + +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, TUNGSTEN GRAPHICS 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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * + */ +#include <errno.h> + +#include "glheader.h" + +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_sanity.h" + +/* Set this '1' to get more verbiage. + */ +#define MORE_VERBOSE 1 + +#if MORE_VERBOSE +#define VERBOSE (RADEON_DEBUG & DEBUG_VERBOSE) +#define NORMAL (1) +#else +#define VERBOSE 0 +#define NORMAL (RADEON_DEBUG & DEBUG_VERBOSE) +#endif + + +/* New (1.3) state mechanism. 3 commands (packet, scalar, vector) in + * 1.3 cmdbuffers allow all previous state to be updated as well as + * the tcl scalar and vector areas. + */ +static struct { + int start; + int len; + const char *name; +} packet[RADEON_MAX_STATE_PACKETS] = { + { RADEON_PP_MISC,7,"RADEON_PP_MISC" }, + { RADEON_PP_CNTL,3,"RADEON_PP_CNTL" }, + { RADEON_RB3D_COLORPITCH,1,"RADEON_RB3D_COLORPITCH" }, + { RADEON_RE_LINE_PATTERN,2,"RADEON_RE_LINE_PATTERN" }, + { RADEON_SE_LINE_WIDTH,1,"RADEON_SE_LINE_WIDTH" }, + { RADEON_PP_LUM_MATRIX,1,"RADEON_PP_LUM_MATRIX" }, + { RADEON_PP_ROT_MATRIX_0,2,"RADEON_PP_ROT_MATRIX_0" }, + { RADEON_RB3D_STENCILREFMASK,3,"RADEON_RB3D_STENCILREFMASK" }, + { RADEON_SE_VPORT_XSCALE,6,"RADEON_SE_VPORT_XSCALE" }, + { RADEON_SE_CNTL,2,"RADEON_SE_CNTL" }, + { RADEON_SE_CNTL_STATUS,1,"RADEON_SE_CNTL_STATUS" }, + { RADEON_RE_MISC,1,"RADEON_RE_MISC" }, + { RADEON_PP_TXFILTER_0,6,"RADEON_PP_TXFILTER_0" }, + { RADEON_PP_BORDER_COLOR_0,1,"RADEON_PP_BORDER_COLOR_0" }, + { RADEON_PP_TXFILTER_1,6,"RADEON_PP_TXFILTER_1" }, + { RADEON_PP_BORDER_COLOR_1,1,"RADEON_PP_BORDER_COLOR_1" }, + { RADEON_PP_TXFILTER_2,6,"RADEON_PP_TXFILTER_2" }, + { RADEON_PP_BORDER_COLOR_2,1,"RADEON_PP_BORDER_COLOR_2" }, + { RADEON_SE_ZBIAS_FACTOR,2,"RADEON_SE_ZBIAS_FACTOR" }, + { RADEON_SE_TCL_OUTPUT_VTX_FMT,11,"RADEON_SE_TCL_OUTPUT_VTX_FMT" }, + { RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED,17,"RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED" }, + { 0, 4, "R200_PP_TXCBLEND_0" }, + { 0, 4, "R200_PP_TXCBLEND_1" }, + { 0, 4, "R200_PP_TXCBLEND_2" }, + { 0, 4, "R200_PP_TXCBLEND_3" }, + { 0, 4, "R200_PP_TXCBLEND_4" }, + { 0, 4, "R200_PP_TXCBLEND_5" }, + { 0, 4, "R200_PP_TXCBLEND_6" }, + { 0, 4, "R200_PP_TXCBLEND_7" }, + { 0, 6, "R200_SE_TCL_LIGHT_MODEL_CTL_0" }, + { 0, 6, "R200_PP_TFACTOR_0" }, + { 0, 4, "R200_SE_VTX_FMT_0" }, + { 0, 1, "R200_SE_VAP_CNTL" }, + { 0, 5, "R200_SE_TCL_MATRIX_SEL_0" }, + { 0, 5, "R200_SE_TCL_TEX_PROC_CTL_2" }, + { 0, 1, "R200_SE_TCL_UCP_VERT_BLEND_CTL" }, + { 0, 6, "R200_PP_TXFILTER_0" }, + { 0, 6, "R200_PP_TXFILTER_1" }, + { 0, 6, "R200_PP_TXFILTER_2" }, + { 0, 6, "R200_PP_TXFILTER_3" }, + { 0, 6, "R200_PP_TXFILTER_4" }, + { 0, 6, "R200_PP_TXFILTER_5" }, + { 0, 1, "R200_PP_TXOFFSET_0" }, + { 0, 1, "R200_PP_TXOFFSET_1" }, + { 0, 1, "R200_PP_TXOFFSET_2" }, + { 0, 1, "R200_PP_TXOFFSET_3" }, + { 0, 1, "R200_PP_TXOFFSET_4" }, + { 0, 1, "R200_PP_TXOFFSET_5" }, + { 0, 1, "R200_SE_VTE_CNTL" }, + { 0, 1, "R200_SE_TCL_OUTPUT_VTX_COMP_SEL" }, + { 0, 1, "R200_PP_TAM_DEBUG3" }, + { 0, 1, "R200_PP_CNTL_X" }, + { 0, 1, "R200_RB3D_DEPTHXY_OFFSET" }, + { 0, 1, "R200_RE_AUX_SCISSOR_CNTL" }, + { 0, 2, "R200_RE_SCISSOR_TL_0" }, + { 0, 2, "R200_RE_SCISSOR_TL_1" }, + { 0, 2, "R200_RE_SCISSOR_TL_2" }, + { 0, 1, "R200_SE_VAP_CNTL_STATUS" }, + { 0, 1, "R200_SE_VTX_STATE_CNTL" }, + { 0, 1, "R200_RE_POINTSIZE" }, + { 0, 4, "R200_SE_TCL_INPUT_VTX_VECTOR_ADDR_0" }, + { 0, 1, "R200_PP_CUBIC_FACES_0" }, /* 61 */ + { 0, 5, "R200_PP_CUBIC_OFFSET_F1_0" }, /* 62 */ + { 0, 1, "R200_PP_CUBIC_FACES_1" }, + { 0, 5, "R200_PP_CUBIC_OFFSET_F1_1" }, + { 0, 1, "R200_PP_CUBIC_FACES_2" }, + { 0, 5, "R200_PP_CUBIC_OFFSET_F1_2" }, + { 0, 1, "R200_PP_CUBIC_FACES_3" }, + { 0, 5, "R200_PP_CUBIC_OFFSET_F1_3" }, + { 0, 1, "R200_PP_CUBIC_FACES_4" }, + { 0, 5, "R200_PP_CUBIC_OFFSET_F1_4" }, + { 0, 1, "R200_PP_CUBIC_FACES_5" }, + { 0, 5, "R200_PP_CUBIC_OFFSET_F1_5" }, + { RADEON_PP_TEX_SIZE_0, 2, "RADEON_PP_TEX_SIZE_0" }, + { RADEON_PP_TEX_SIZE_1, 2, "RADEON_PP_TEX_SIZE_1" }, + { RADEON_PP_TEX_SIZE_2, 2, "RADEON_PP_TEX_SIZE_1" }, +}; + +struct reg_names { + int idx; + const char *name; +}; + +static struct reg_names reg_names[] = { + { RADEON_PP_MISC, "RADEON_PP_MISC" }, + { RADEON_PP_FOG_COLOR, "RADEON_PP_FOG_COLOR" }, + { RADEON_RE_SOLID_COLOR, "RADEON_RE_SOLID_COLOR" }, + { RADEON_RB3D_BLENDCNTL, "RADEON_RB3D_BLENDCNTL" }, + { RADEON_RB3D_DEPTHOFFSET, "RADEON_RB3D_DEPTHOFFSET" }, + { RADEON_RB3D_DEPTHPITCH, "RADEON_RB3D_DEPTHPITCH" }, + { RADEON_RB3D_ZSTENCILCNTL, "RADEON_RB3D_ZSTENCILCNTL" }, + { RADEON_PP_CNTL, "RADEON_PP_CNTL" }, + { RADEON_RB3D_CNTL, "RADEON_RB3D_CNTL" }, + { RADEON_RB3D_COLOROFFSET, "RADEON_RB3D_COLOROFFSET" }, + { RADEON_RB3D_COLORPITCH, "RADEON_RB3D_COLORPITCH" }, + { RADEON_SE_CNTL, "RADEON_SE_CNTL" }, + { RADEON_SE_COORD_FMT, "RADEON_SE_COORDFMT" }, + { RADEON_SE_CNTL_STATUS, "RADEON_SE_CNTL_STATUS" }, + { RADEON_RE_LINE_PATTERN, "RADEON_RE_LINE_PATTERN" }, + { RADEON_RE_LINE_STATE, "RADEON_RE_LINE_STATE" }, + { RADEON_SE_LINE_WIDTH, "RADEON_SE_LINE_WIDTH" }, + { RADEON_RB3D_STENCILREFMASK, "RADEON_RB3D_STENCILREFMASK" }, + { RADEON_RB3D_ROPCNTL, "RADEON_RB3D_ROPCNTL" }, + { RADEON_RB3D_PLANEMASK, "RADEON_RB3D_PLANEMASK" }, + { RADEON_SE_VPORT_XSCALE, "RADEON_SE_VPORT_XSCALE" }, + { RADEON_SE_VPORT_XOFFSET, "RADEON_SE_VPORT_XOFFSET" }, + { RADEON_SE_VPORT_YSCALE, "RADEON_SE_VPORT_YSCALE" }, + { RADEON_SE_VPORT_YOFFSET, "RADEON_SE_VPORT_YOFFSET" }, + { RADEON_SE_VPORT_ZSCALE, "RADEON_SE_VPORT_ZSCALE" }, + { RADEON_SE_VPORT_ZOFFSET, "RADEON_SE_VPORT_ZOFFSET" }, + { RADEON_RE_MISC, "RADEON_RE_MISC" }, + { RADEON_PP_TXFILTER_0, "RADEON_PP_TXFILTER_0" }, + { RADEON_PP_TXFILTER_1, "RADEON_PP_TXFILTER_1" }, + { RADEON_PP_TXFILTER_2, "RADEON_PP_TXFILTER_2" }, + { RADEON_PP_TXFORMAT_0, "RADEON_PP_TXFORMAT_0" }, + { RADEON_PP_TXFORMAT_1, "RADEON_PP_TXFORMAT_1" }, + { RADEON_PP_TXFORMAT_2, "RADEON_PP_TXFORMAT_3" }, + { RADEON_PP_TXOFFSET_0, "RADEON_PP_TXOFFSET_0" }, + { RADEON_PP_TXOFFSET_1, "RADEON_PP_TXOFFSET_1" }, + { RADEON_PP_TXOFFSET_2, "RADEON_PP_TXOFFSET_3" }, + { RADEON_PP_TXCBLEND_0, "RADEON_PP_TXCBLEND_0" }, + { RADEON_PP_TXCBLEND_1, "RADEON_PP_TXCBLEND_1" }, + { RADEON_PP_TXCBLEND_2, "RADEON_PP_TXCBLEND_3" }, + { RADEON_PP_TXABLEND_0, "RADEON_PP_TXABLEND_0" }, + { RADEON_PP_TXABLEND_1, "RADEON_PP_TXABLEND_1" }, + { RADEON_PP_TXABLEND_2, "RADEON_PP_TXABLEND_3" }, + { RADEON_PP_TFACTOR_0, "RADEON_PP_TFACTOR_0" }, + { RADEON_PP_TFACTOR_1, "RADEON_PP_TFACTOR_1" }, + { RADEON_PP_TFACTOR_2, "RADEON_PP_TFACTOR_3" }, + { RADEON_PP_BORDER_COLOR_0, "RADEON_PP_BORDER_COLOR_0" }, + { RADEON_PP_BORDER_COLOR_1, "RADEON_PP_BORDER_COLOR_1" }, + { RADEON_PP_BORDER_COLOR_2, "RADEON_PP_BORDER_COLOR_3" }, + { RADEON_SE_ZBIAS_FACTOR, "RADEON_SE_ZBIAS_FACTOR" }, + { RADEON_SE_ZBIAS_CONSTANT, "RADEON_SE_ZBIAS_CONSTANT" }, + { RADEON_SE_TCL_OUTPUT_VTX_FMT, "RADEON_SE_TCL_OUTPUT_VTXFMT" }, + { RADEON_SE_TCL_OUTPUT_VTX_SEL, "RADEON_SE_TCL_OUTPUT_VTXSEL" }, + { RADEON_SE_TCL_MATRIX_SELECT_0, "RADEON_SE_TCL_MATRIX_SELECT_0" }, + { RADEON_SE_TCL_MATRIX_SELECT_1, "RADEON_SE_TCL_MATRIX_SELECT_1" }, + { RADEON_SE_TCL_UCP_VERT_BLEND_CTL, "RADEON_SE_TCL_UCP_VERT_BLEND_CTL" }, + { RADEON_SE_TCL_TEXTURE_PROC_CTL, "RADEON_SE_TCL_TEXTURE_PROC_CTL" }, + { RADEON_SE_TCL_LIGHT_MODEL_CTL, "RADEON_SE_TCL_LIGHT_MODEL_CTL" }, + { RADEON_SE_TCL_PER_LIGHT_CTL_0, "RADEON_SE_TCL_PER_LIGHT_CTL_0" }, + { RADEON_SE_TCL_PER_LIGHT_CTL_1, "RADEON_SE_TCL_PER_LIGHT_CTL_1" }, + { RADEON_SE_TCL_PER_LIGHT_CTL_2, "RADEON_SE_TCL_PER_LIGHT_CTL_2" }, + { RADEON_SE_TCL_PER_LIGHT_CTL_3, "RADEON_SE_TCL_PER_LIGHT_CTL_3" }, + { RADEON_SE_TCL_MATERIAL_EMMISSIVE_RED, "RADEON_SE_TCL_EMMISSIVE_RED" }, + { RADEON_SE_TCL_MATERIAL_EMMISSIVE_GREEN, "RADEON_SE_TCL_EMMISSIVE_GREEN" }, + { RADEON_SE_TCL_MATERIAL_EMMISSIVE_BLUE, "RADEON_SE_TCL_EMMISSIVE_BLUE" }, + { RADEON_SE_TCL_MATERIAL_EMMISSIVE_ALPHA, "RADEON_SE_TCL_EMMISSIVE_ALPHA" }, + { RADEON_SE_TCL_MATERIAL_AMBIENT_RED, "RADEON_SE_TCL_AMBIENT_RED" }, + { RADEON_SE_TCL_MATERIAL_AMBIENT_GREEN, "RADEON_SE_TCL_AMBIENT_GREEN" }, + { RADEON_SE_TCL_MATERIAL_AMBIENT_BLUE, "RADEON_SE_TCL_AMBIENT_BLUE" }, + { RADEON_SE_TCL_MATERIAL_AMBIENT_ALPHA, "RADEON_SE_TCL_AMBIENT_ALPHA" }, + { RADEON_SE_TCL_MATERIAL_DIFFUSE_RED, "RADEON_SE_TCL_DIFFUSE_RED" }, + { RADEON_SE_TCL_MATERIAL_DIFFUSE_GREEN, "RADEON_SE_TCL_DIFFUSE_GREEN" }, + { RADEON_SE_TCL_MATERIAL_DIFFUSE_BLUE, "RADEON_SE_TCL_DIFFUSE_BLUE" }, + { RADEON_SE_TCL_MATERIAL_DIFFUSE_ALPHA, "RADEON_SE_TCL_DIFFUSE_ALPHA" }, + { RADEON_SE_TCL_MATERIAL_SPECULAR_RED, "RADEON_SE_TCL_SPECULAR_RED" }, + { RADEON_SE_TCL_MATERIAL_SPECULAR_GREEN, "RADEON_SE_TCL_SPECULAR_GREEN" }, + { RADEON_SE_TCL_MATERIAL_SPECULAR_BLUE, "RADEON_SE_TCL_SPECULAR_BLUE" }, + { RADEON_SE_TCL_MATERIAL_SPECULAR_ALPHA, "RADEON_SE_TCL_SPECULAR_ALPHA" }, + { RADEON_SE_TCL_SHININESS, "RADEON_SE_TCL_SHININESS" }, + { RADEON_SE_COORD_FMT, "RADEON_SE_COORD_FMT" }, + { RADEON_PP_TEX_SIZE_0, "RADEON_PP_TEX_SIZE_0" }, + { RADEON_PP_TEX_SIZE_1, "RADEON_PP_TEX_SIZE_1" }, + { RADEON_PP_TEX_SIZE_2, "RADEON_PP_TEX_SIZE_2" }, + { RADEON_PP_TEX_SIZE_0+4, "RADEON_PP_TEX_PITCH_0" }, + { RADEON_PP_TEX_SIZE_1+4, "RADEON_PP_TEX_PITCH_1" }, + { RADEON_PP_TEX_SIZE_2+4, "RADEON_PP_TEX_PITCH_2" }, +}; + +static struct reg_names scalar_names[] = { + { RADEON_SS_LIGHT_DCD_ADDR, "LIGHT_DCD" }, + { RADEON_SS_LIGHT_SPOT_EXPONENT_ADDR, "LIGHT_SPOT_EXPONENT" }, + { RADEON_SS_LIGHT_SPOT_CUTOFF_ADDR, "LIGHT_SPOT_CUTOFF" }, + { RADEON_SS_LIGHT_SPECULAR_THRESH_ADDR, "LIGHT_SPECULAR_THRESH" }, + { RADEON_SS_LIGHT_RANGE_CUTOFF_ADDR, "LIGHT_RANGE_CUTOFF" }, + { RADEON_SS_VERT_GUARD_CLIP_ADJ_ADDR, "VERT_GUARD_CLIP" }, + { RADEON_SS_VERT_GUARD_DISCARD_ADJ_ADDR, "VERT_GUARD_DISCARD" }, + { RADEON_SS_HORZ_GUARD_CLIP_ADJ_ADDR, "HORZ_GUARD_CLIP" }, + { RADEON_SS_HORZ_GUARD_DISCARD_ADJ_ADDR, "HORZ_GUARD_DISCARD" }, + { RADEON_SS_SHININESS, "SHININESS" }, + { 1000, "" }, +}; + +/* Puff these out to make them look like normal (dword) registers. + */ +static struct reg_names vector_names[] = { + { RADEON_VS_MATRIX_0_ADDR * 4, "MATRIX_0" }, + { RADEON_VS_MATRIX_1_ADDR * 4, "MATRIX_1" }, + { RADEON_VS_MATRIX_2_ADDR * 4, "MATRIX_2" }, + { RADEON_VS_MATRIX_3_ADDR * 4, "MATRIX_3" }, + { RADEON_VS_MATRIX_4_ADDR * 4, "MATRIX_4" }, + { RADEON_VS_MATRIX_5_ADDR * 4, "MATRIX_5" }, + { RADEON_VS_MATRIX_6_ADDR * 4, "MATRIX_6" }, + { RADEON_VS_MATRIX_7_ADDR * 4, "MATRIX_7" }, + { RADEON_VS_MATRIX_8_ADDR * 4, "MATRIX_8" }, + { RADEON_VS_MATRIX_9_ADDR * 4, "MATRIX_9" }, + { RADEON_VS_MATRIX_10_ADDR * 4, "MATRIX_10" }, + { RADEON_VS_MATRIX_11_ADDR * 4, "MATRIX_11" }, + { RADEON_VS_MATRIX_12_ADDR * 4, "MATRIX_12" }, + { RADEON_VS_MATRIX_13_ADDR * 4, "MATRIX_13" }, + { RADEON_VS_MATRIX_14_ADDR * 4, "MATRIX_14" }, + { RADEON_VS_MATRIX_15_ADDR * 4, "MATRIX_15" }, + { RADEON_VS_LIGHT_AMBIENT_ADDR * 4, "LIGHT_AMBIENT" }, + { RADEON_VS_LIGHT_DIFFUSE_ADDR * 4, "LIGHT_DIFFUSE" }, + { RADEON_VS_LIGHT_SPECULAR_ADDR * 4, "LIGHT_SPECULAR" }, + { RADEON_VS_LIGHT_DIRPOS_ADDR * 4, "LIGHT_DIRPOS" }, + { RADEON_VS_LIGHT_HWVSPOT_ADDR * 4, "LIGHT_HWVSPOT" }, + { RADEON_VS_LIGHT_ATTENUATION_ADDR * 4, "LIGHT_ATTENUATION" }, + { RADEON_VS_MATRIX_EYE2CLIP_ADDR * 4, "MATRIX_EYE2CLIP" }, + { RADEON_VS_UCP_ADDR * 4, "UCP" }, + { RADEON_VS_GLOBAL_AMBIENT_ADDR * 4, "GLOBAL_AMBIENT" }, + { RADEON_VS_FOG_PARAM_ADDR * 4, "FOG_PARAM" }, + { RADEON_VS_EYE_VECTOR_ADDR * 4, "EYE_VECTOR" }, + { 1000, "" }, +}; + +union fi { float f; int i; }; + +#define ISVEC 1 +#define ISFLOAT 2 +#define TOUCHED 4 + +struct reg { + int idx; + struct reg_names *closest; + int flags; + union fi current; + union fi *values; + int nvalues; + int nalloc; + float vmin, vmax; +}; + + +static struct reg regs[Elements(reg_names)+1]; +static struct reg scalars[512+1]; +static struct reg vectors[512*4+1]; + +static int total, total_changed, bufs; + +static void init_regs( void ) +{ + struct reg_names *tmp; + int i; + + for (i = 0 ; i < Elements(regs) ; i++) { + regs[i].idx = reg_names[i].idx; + regs[i].closest = ®_names[i]; + regs[i].flags = 0; + } + + for (i = 0, tmp = scalar_names ; i < Elements(scalars) ; i++) { + if (tmp[1].idx == i) tmp++; + scalars[i].idx = i; + scalars[i].closest = tmp; + scalars[i].flags = ISFLOAT; + } + + for (i = 0, tmp = vector_names ; i < Elements(vectors) ; i++) { + if (tmp[1].idx*4 == i) tmp++; + vectors[i].idx = i; + vectors[i].closest = tmp; + vectors[i].flags = ISFLOAT|ISVEC; + } + + regs[Elements(regs)-1].idx = -1; + scalars[Elements(scalars)-1].idx = -1; + vectors[Elements(vectors)-1].idx = -1; +} + +static int find_or_add_value( struct reg *reg, int val ) +{ + int j; + + for ( j = 0 ; j < reg->nvalues ; j++) + if ( val == reg->values[j].i ) + return 1; + + if (j == reg->nalloc) { + reg->nalloc += 5; + reg->nalloc *= 2; + reg->values = (union fi *) realloc( reg->values, + reg->nalloc * sizeof(union fi) ); + } + + reg->values[reg->nvalues++].i = val; + return 0; +} + +static struct reg *lookup_reg( struct reg *tab, int reg ) +{ + int i; + + for (i = 0 ; tab[i].idx != -1 ; i++) { + if (tab[i].idx == reg) + return &tab[i]; + } + + fprintf(stderr, "*** unknown reg 0x%x\n", reg); + return 0; +} + + +static const char *get_reg_name( struct reg *reg ) +{ + static char tmp[80]; + + if (reg->idx == reg->closest->idx) + return reg->closest->name; + + + if (reg->flags & ISVEC) { + if (reg->idx/4 != reg->closest->idx) + sprintf(tmp, "%s+%d[%d]", + reg->closest->name, + (reg->idx/4) - reg->closest->idx, + reg->idx%4); + else + sprintf(tmp, "%s[%d]", reg->closest->name, reg->idx%4); + } + else { + if (reg->idx != reg->closest->idx) + sprintf(tmp, "%s+%d", reg->closest->name, reg->idx - reg->closest->idx); + else + sprintf(tmp, "%s", reg->closest->name); + } + + return tmp; +} + +static int print_int_reg_assignment( struct reg *reg, int data ) +{ + int changed = (reg->current.i != data); + int ever_seen = find_or_add_value( reg, data ); + + if (VERBOSE || (NORMAL && (changed || !ever_seen))) + fprintf(stderr, " %s <-- 0x%x", get_reg_name(reg), data); + + if (NORMAL) { + if (!ever_seen) + fprintf(stderr, " *** BRAND NEW VALUE"); + else if (changed) + fprintf(stderr, " *** CHANGED"); + } + + reg->current.i = data; + + if (VERBOSE || (NORMAL && (changed || !ever_seen))) + fprintf(stderr, "\n"); + + return changed; +} + + +static int print_float_reg_assignment( struct reg *reg, float data ) +{ + int changed = (reg->current.f != data); + int newmin = (data < reg->vmin); + int newmax = (data > reg->vmax); + + if (VERBOSE || (NORMAL && (newmin || newmax || changed))) + fprintf(stderr, " %s <-- %.3f", get_reg_name(reg), data); + + if (NORMAL) { + if (newmin) { + fprintf(stderr, " *** NEW MIN (prev %.3f)", reg->vmin); + reg->vmin = data; + } + else if (newmax) { + fprintf(stderr, " *** NEW MAX (prev %.3f)", reg->vmax); + reg->vmax = data; + } + else if (changed) { + fprintf(stderr, " *** CHANGED"); + } + } + + reg->current.f = data; + + if (VERBOSE || (NORMAL && (newmin || newmax || changed))) + fprintf(stderr, "\n"); + + return changed; +} + +static int print_reg_assignment( struct reg *reg, int data ) +{ + reg->flags |= TOUCHED; + if (reg->flags & ISFLOAT) + return print_float_reg_assignment( reg, *(float *)&data ); + else + return print_int_reg_assignment( reg, data ); +} + +static void print_reg( struct reg *reg ) +{ + if (reg->flags & TOUCHED) { + if (reg->flags & ISFLOAT) { + fprintf(stderr, " %s == %f\n", get_reg_name(reg), reg->current.f); + } else { + fprintf(stderr, " %s == 0x%x\n", get_reg_name(reg), reg->current.i); + } + } +} + + +static void dump_state( void ) +{ + int i; + + for (i = 0 ; i < Elements(regs) ; i++) + print_reg( ®s[i] ); + + for (i = 0 ; i < Elements(scalars) ; i++) + print_reg( &scalars[i] ); + + for (i = 0 ; i < Elements(vectors) ; i++) + print_reg( &vectors[i] ); +} + + + +static int radeon_emit_packets( + drmRadeonCmdHeader header, + drmRadeonCmdBuffer *cmdbuf ) +{ + int id = (int)header.packet.packet_id; + int sz = packet[id].len; + int *data = (int *)cmdbuf->buf; + int i; + + if (sz * sizeof(int) > cmdbuf->bufsz) { + fprintf(stderr, "Packet overflows cmdbuf\n"); + return -EINVAL; + } + + if (!packet[id].name) { + fprintf(stderr, "*** Unknown packet 0 nr %d\n", id ); + return -EINVAL; + } + + + if (VERBOSE) + fprintf(stderr, "Packet 0 reg %s nr %d\n", packet[id].name, sz ); + + for ( i = 0 ; i < sz ; i++) { + struct reg *reg = lookup_reg( regs, packet[id].start + i*4 ); + if (print_reg_assignment( reg, data[i] )) + total_changed++; + total++; + } + + cmdbuf->buf += sz * sizeof(int); + cmdbuf->bufsz -= sz * sizeof(int); + return 0; +} + + +static int radeon_emit_scalars( + drmRadeonCmdHeader header, + drmRadeonCmdBuffer *cmdbuf ) +{ + int sz = header.scalars.count; + int *data = (int *)cmdbuf->buf; + int start = header.scalars.offset; + int stride = header.scalars.stride; + int i; + + if (VERBOSE) + fprintf(stderr, "emit scalars, start %d stride %d nr %d (end %d)\n", + start, stride, sz, start + stride * sz); + + + for (i = 0 ; i < sz ; i++, start += stride) { + struct reg *reg = lookup_reg( scalars, start ); + if (print_reg_assignment( reg, data[i] )) + total_changed++; + total++; + } + + cmdbuf->buf += sz * sizeof(int); + cmdbuf->bufsz -= sz * sizeof(int); + return 0; +} + + +static int radeon_emit_scalars2( + drmRadeonCmdHeader header, + drmRadeonCmdBuffer *cmdbuf ) +{ + int sz = header.scalars.count; + int *data = (int *)cmdbuf->buf; + int start = header.scalars.offset + 0x100; + int stride = header.scalars.stride; + int i; + + if (VERBOSE) + fprintf(stderr, "emit scalars2, start %d stride %d nr %d (end %d)\n", + start, stride, sz, start + stride * sz); + + if (start + stride * sz > 257) { + fprintf(stderr, "emit scalars OVERFLOW %d/%d/%d\n", start, stride, sz); + return -1; + } + + for (i = 0 ; i < sz ; i++, start += stride) { + struct reg *reg = lookup_reg( scalars, start ); + if (print_reg_assignment( reg, data[i] )) + total_changed++; + total++; + } + + cmdbuf->buf += sz * sizeof(int); + cmdbuf->bufsz -= sz * sizeof(int); + return 0; +} + +/* Check: inf/nan/extreme-size? + * Check: table start, end, nr, etc. + */ +static int radeon_emit_vectors( + drmRadeonCmdHeader header, + drmRadeonCmdBuffer *cmdbuf ) +{ + int sz = header.vectors.count; + int *data = (int *)cmdbuf->buf; + int start = header.vectors.offset; + int stride = header.vectors.stride; + int i,j; + + if (VERBOSE) + fprintf(stderr, "emit vectors, start %d stride %d nr %d (end %d) (0x%x)\n", + start, stride, sz, start + stride * sz, header.i); + +/* if (start + stride * (sz/4) > 128) { */ +/* fprintf(stderr, "emit vectors OVERFLOW %d/%d/%d\n", start, stride, sz); */ +/* return -1; */ +/* } */ + + for (i = 0 ; i < sz ; start += stride) { + int changed = 0; + for (j = 0 ; j < 4 ; i++,j++) { + struct reg *reg = lookup_reg( vectors, start*4+j ); + if (print_reg_assignment( reg, data[i] )) + changed = 1; + } + if (changed) + total_changed += 4; + total += 4; + } + + + cmdbuf->buf += sz * sizeof(int); + cmdbuf->bufsz -= sz * sizeof(int); + return 0; +} + + +static int print_vertex_format( int vfmt ) +{ + if (NORMAL) { + fprintf(stderr, " %s(%x): %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s", + "vertex format", + vfmt, + "xy,", + (vfmt & RADEON_CP_VC_FRMT_Z) ? "z," : "", + (vfmt & RADEON_CP_VC_FRMT_W0) ? "w0," : "", + (vfmt & RADEON_CP_VC_FRMT_FPCOLOR) ? "fpcolor," : "", + (vfmt & RADEON_CP_VC_FRMT_FPALPHA) ? "fpalpha," : "", + (vfmt & RADEON_CP_VC_FRMT_PKCOLOR) ? "pkcolor," : "", + (vfmt & RADEON_CP_VC_FRMT_FPSPEC) ? "fpspec," : "", + (vfmt & RADEON_CP_VC_FRMT_FPFOG) ? "fpfog," : "", + (vfmt & RADEON_CP_VC_FRMT_PKSPEC) ? "pkspec," : "", + (vfmt & RADEON_CP_VC_FRMT_ST0) ? "st0," : "", + (vfmt & RADEON_CP_VC_FRMT_ST1) ? "st1," : "", + (vfmt & RADEON_CP_VC_FRMT_Q1) ? "q1," : "", + (vfmt & RADEON_CP_VC_FRMT_ST2) ? "st2," : "", + (vfmt & RADEON_CP_VC_FRMT_Q2) ? "q2," : "", + (vfmt & RADEON_CP_VC_FRMT_ST3) ? "st3," : "", + (vfmt & RADEON_CP_VC_FRMT_Q3) ? "q3," : "", + (vfmt & RADEON_CP_VC_FRMT_Q0) ? "q0," : "", + (vfmt & RADEON_CP_VC_FRMT_N0) ? "n0," : "", + (vfmt & RADEON_CP_VC_FRMT_XY1) ? "xy1," : "", + (vfmt & RADEON_CP_VC_FRMT_Z1) ? "z1," : "", + (vfmt & RADEON_CP_VC_FRMT_W1) ? "w1," : "", + (vfmt & RADEON_CP_VC_FRMT_N1) ? "n1," : ""); + + +/* if (!find_or_add_value( &others[V_VTXFMT], vfmt )) */ +/* fprintf(stderr, " *** NEW VALUE"); */ + + fprintf(stderr, "\n"); + } + + return 0; +} + +static char *primname[0xf] = { + "NONE", + "POINTS", + "LINES", + "LINE_STRIP", + "TRIANGLES", + "TRIANGLE_FAN", + "TRIANGLE_STRIP", + "TRI_TYPE_2", + "RECT_LIST", + "3VRT_POINTS", + "3VRT_LINES", +}; + +static int print_prim_and_flags( int prim ) +{ + int numverts; + + if (NORMAL) + fprintf(stderr, " %s(%x): %s%s%s%s%s%s%s\n", + "prim flags", + prim, + ((prim & 0x30) == RADEON_CP_VC_CNTL_PRIM_WALK_IND) ? "IND," : "", + ((prim & 0x30) == RADEON_CP_VC_CNTL_PRIM_WALK_LIST) ? "LIST," : "", + ((prim & 0x30) == RADEON_CP_VC_CNTL_PRIM_WALK_RING) ? "RING," : "", + (prim & RADEON_CP_VC_CNTL_COLOR_ORDER_RGBA) ? "RGBA," : "BGRA, ", + (prim & RADEON_CP_VC_CNTL_MAOS_ENABLE) ? "MAOS," : "", + (prim & RADEON_CP_VC_CNTL_VTX_FMT_RADEON_MODE) ? "RADEON," : "", + (prim & RADEON_CP_VC_CNTL_TCL_ENABLE) ? "TCL," : ""); + + if ((prim & 0xf) > RADEON_CP_VC_CNTL_PRIM_TYPE_3VRT_LINE_LIST) { + fprintf(stderr, " *** Bad primitive: %x\n", prim & 0xf); + return -1; + } + + numverts = prim>>16; + + if (NORMAL) + fprintf(stderr, " prim: %s numverts %d\n", primname[prim&0xf], numverts); + + switch (prim & 0xf) { + case RADEON_CP_VC_CNTL_PRIM_TYPE_NONE: + case RADEON_CP_VC_CNTL_PRIM_TYPE_POINT: + if (numverts < 1) { + fprintf(stderr, "Bad nr verts for line %d\n", numverts); + return -1; + } + break; + case RADEON_CP_VC_CNTL_PRIM_TYPE_LINE: + if ((numverts & 1) || numverts == 0) { + fprintf(stderr, "Bad nr verts for line %d\n", numverts); + return -1; + } + break; + case RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP: + if (numverts < 2) { + fprintf(stderr, "Bad nr verts for line_strip %d\n", numverts); + return -1; + } + break; + case RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST: + case RADEON_CP_VC_CNTL_PRIM_TYPE_3VRT_POINT_LIST: + case RADEON_CP_VC_CNTL_PRIM_TYPE_3VRT_LINE_LIST: + case RADEON_CP_VC_CNTL_PRIM_TYPE_RECT_LIST: + if (numverts % 3 || numverts == 0) { + fprintf(stderr, "Bad nr verts for tri %d\n", numverts); + return -1; + } + break; + case RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN: + case RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP: + if (numverts < 3) { + fprintf(stderr, "Bad nr verts for strip/fan %d\n", numverts); + return -1; + } + break; + default: + fprintf(stderr, "Bad primitive\n"); + return -1; + } + return 0; +} + +/* build in knowledge about each packet type + */ +static int radeon_emit_packet3( drmRadeonCmdBuffer *cmdbuf ) +{ + int cmdsz; + int *cmd = (int *)cmdbuf->buf; + int *tmp; + int i, stride, size, start; + + cmdsz = 2 + ((cmd[0] & RADEON_CP_PACKET_COUNT_MASK) >> 16); + + if ((cmd[0] & RADEON_CP_PACKET_MASK) != RADEON_CP_PACKET3 || + cmdsz * 4 > cmdbuf->bufsz || + cmdsz > RADEON_CP_PACKET_MAX_DWORDS) { + fprintf(stderr, "Bad packet\n"); + return -EINVAL; + } + + switch( cmd[0] & ~RADEON_CP_PACKET_COUNT_MASK ) { + case RADEON_CP_PACKET3_NOP: + if (NORMAL) + fprintf(stderr, "PACKET3_NOP, %d dwords\n", cmdsz); + break; + case RADEON_CP_PACKET3_NEXT_CHAR: + if (NORMAL) + fprintf(stderr, "PACKET3_NEXT_CHAR, %d dwords\n", cmdsz); + break; + case RADEON_CP_PACKET3_PLY_NEXTSCAN: + if (NORMAL) + fprintf(stderr, "PACKET3_PLY_NEXTSCAN, %d dwords\n", cmdsz); + break; + case RADEON_CP_PACKET3_SET_SCISSORS: + if (NORMAL) + fprintf(stderr, "PACKET3_SET_SCISSORS, %d dwords\n", cmdsz); + break; + case RADEON_CP_PACKET3_3D_RNDR_GEN_INDX_PRIM: + if (NORMAL) + fprintf(stderr, "PACKET3_3D_RNDR_GEN_INDX_PRIM, %d dwords\n", + cmdsz); + break; + case RADEON_CP_PACKET3_LOAD_MICROCODE: + if (NORMAL) + fprintf(stderr, "PACKET3_LOAD_MICROCODE, %d dwords\n", cmdsz); + break; + case RADEON_CP_PACKET3_WAIT_FOR_IDLE: + if (NORMAL) + fprintf(stderr, "PACKET3_WAIT_FOR_IDLE, %d dwords\n", cmdsz); + break; + + case RADEON_CP_PACKET3_3D_DRAW_VBUF: + if (NORMAL) + fprintf(stderr, "PACKET3_3D_DRAW_VBUF, %d dwords\n", cmdsz); + print_vertex_format(cmd[1]); + print_prim_and_flags(cmd[2]); + break; + + case RADEON_CP_PACKET3_3D_DRAW_IMMD: + if (NORMAL) + fprintf(stderr, "PACKET3_3D_DRAW_IMMD, %d dwords\n", cmdsz); + break; + case RADEON_CP_PACKET3_3D_DRAW_INDX: { + int neltdwords; + if (NORMAL) + fprintf(stderr, "PACKET3_3D_DRAW_INDX, %d dwords\n", cmdsz); + print_vertex_format(cmd[1]); + print_prim_and_flags(cmd[2]); + neltdwords = cmd[2]>>16; + neltdwords += neltdwords & 1; + neltdwords /= 2; + if (neltdwords + 3 != cmdsz) + fprintf(stderr, "Mismatch in DRAW_INDX, %d vs cmdsz %d\n", + neltdwords, cmdsz); + break; + } + case RADEON_CP_PACKET3_LOAD_PALETTE: + if (NORMAL) + fprintf(stderr, "PACKET3_LOAD_PALETTE, %d dwords\n", cmdsz); + break; + case RADEON_CP_PACKET3_3D_LOAD_VBPNTR: + if (NORMAL) { + fprintf(stderr, "PACKET3_3D_LOAD_VBPNTR, %d dwords\n", cmdsz); + fprintf(stderr, " nr arrays: %d\n", cmd[1]); + } + + if (cmd[1]/2 + cmd[1]%2 != cmdsz - 3) { + fprintf(stderr, " ****** MISMATCH %d/%d *******\n", + cmd[1]/2 + cmd[1]%2 + 3, cmdsz); + return -EINVAL; + } + + if (NORMAL) { + tmp = cmd+2; + for (i = 0 ; i < cmd[1] ; i++) { + if (i & 1) { + stride = (tmp[0]>>24) & 0xff; + size = (tmp[0]>>16) & 0xff; + start = tmp[2]; + tmp += 3; + } + else { + stride = (tmp[0]>>8) & 0xff; + size = (tmp[0]) & 0xff; + start = tmp[1]; + } + fprintf(stderr, " array %d: start 0x%x vsize %d vstride %d\n", + i, start, size, stride ); + } + } + break; + case RADEON_CP_PACKET3_CNTL_PAINT: + if (NORMAL) + fprintf(stderr, "PACKET3_CNTL_PAINT, %d dwords\n", cmdsz); + break; + case RADEON_CP_PACKET3_CNTL_BITBLT: + if (NORMAL) + fprintf(stderr, "PACKET3_CNTL_BITBLT, %d dwords\n", cmdsz); + break; + case RADEON_CP_PACKET3_CNTL_SMALLTEXT: + if (NORMAL) + fprintf(stderr, "PACKET3_CNTL_SMALLTEXT, %d dwords\n", cmdsz); + break; + case RADEON_CP_PACKET3_CNTL_HOSTDATA_BLT: + if (NORMAL) + fprintf(stderr, "PACKET3_CNTL_HOSTDATA_BLT, %d dwords\n", + cmdsz); + break; + case RADEON_CP_PACKET3_CNTL_POLYLINE: + if (NORMAL) + fprintf(stderr, "PACKET3_CNTL_POLYLINE, %d dwords\n", cmdsz); + break; + case RADEON_CP_PACKET3_CNTL_POLYSCANLINES: + if (NORMAL) + fprintf(stderr, "PACKET3_CNTL_POLYSCANLINES, %d dwords\n", + cmdsz); + break; + case RADEON_CP_PACKET3_CNTL_PAINT_MULTI: + if (NORMAL) + fprintf(stderr, "PACKET3_CNTL_PAINT_MULTI, %d dwords\n", + cmdsz); + break; + case RADEON_CP_PACKET3_CNTL_BITBLT_MULTI: + if (NORMAL) + fprintf(stderr, "PACKET3_CNTL_BITBLT_MULTI, %d dwords\n", + cmdsz); + break; + case RADEON_CP_PACKET3_CNTL_TRANS_BITBLT: + if (NORMAL) + fprintf(stderr, "PACKET3_CNTL_TRANS_BITBLT, %d dwords\n", + cmdsz); + break; + default: + fprintf(stderr, "UNKNOWN PACKET, %d dwords\n", cmdsz); + break; + } + + cmdbuf->buf += cmdsz * 4; + cmdbuf->bufsz -= cmdsz * 4; + return 0; +} + + +/* Check cliprects for bounds, then pass on to above: + */ +static int radeon_emit_packet3_cliprect( drmRadeonCmdBuffer *cmdbuf ) +{ + XF86DRIClipRectRec *boxes = (XF86DRIClipRectRec *)cmdbuf->boxes; + int i = 0; + + if (VERBOSE && total_changed) { + dump_state(); + total_changed = 0; + } + else fprintf(stderr, "total_changed zero\n"); + + if (NORMAL) { + do { + if ( i < cmdbuf->nbox ) { + fprintf(stderr, "Emit box %d/%d %d,%d %d,%d\n", + i, cmdbuf->nbox, + boxes[i].x1, boxes[i].y1, boxes[i].x2, boxes[i].y2); + } + } while ( ++i < cmdbuf->nbox ); + } + + if (cmdbuf->nbox == 1) + cmdbuf->nbox = 0; + + return radeon_emit_packet3( cmdbuf ); +} + + +int radeonSanityCmdBuffer( radeonContextPtr rmesa, + int nbox, + XF86DRIClipRectRec *boxes ) +{ + int idx; + drmRadeonCmdBuffer cmdbuf; + drmRadeonCmdHeader header; + static int inited = 0; + + if (!inited) { + init_regs(); + inited = 1; + } + + cmdbuf.buf = rmesa->store.cmd_buf; + cmdbuf.bufsz = rmesa->store.cmd_used; + cmdbuf.boxes = (drmClipRect *)boxes; + cmdbuf.nbox = nbox; + + while ( cmdbuf.bufsz >= sizeof(header) ) { + + header.i = *(int *)cmdbuf.buf; + cmdbuf.buf += sizeof(header); + cmdbuf.bufsz -= sizeof(header); + + switch (header.header.cmd_type) { + case RADEON_CMD_PACKET: + if (radeon_emit_packets( header, &cmdbuf )) { + fprintf(stderr,"radeon_emit_packets failed\n"); + return -EINVAL; + } + break; + + case RADEON_CMD_SCALARS: + if (radeon_emit_scalars( header, &cmdbuf )) { + fprintf(stderr,"radeon_emit_scalars failed\n"); + return -EINVAL; + } + break; + + case RADEON_CMD_SCALARS2: + if (radeon_emit_scalars2( header, &cmdbuf )) { + fprintf(stderr,"radeon_emit_scalars failed\n"); + return -EINVAL; + } + break; + + case RADEON_CMD_VECTORS: + if (radeon_emit_vectors( header, &cmdbuf )) { + fprintf(stderr,"radeon_emit_vectors failed\n"); + return -EINVAL; + } + break; + + case RADEON_CMD_DMA_DISCARD: + idx = header.dma.buf_idx; + if (NORMAL) + fprintf(stderr, "RADEON_CMD_DMA_DISCARD buf %d\n", idx); + bufs++; + break; + + case RADEON_CMD_PACKET3: + if (radeon_emit_packet3( &cmdbuf )) { + fprintf(stderr,"radeon_emit_packet3 failed\n"); + return -EINVAL; + } + break; + + case RADEON_CMD_PACKET3_CLIP: + if (radeon_emit_packet3_cliprect( &cmdbuf )) { + fprintf(stderr,"radeon_emit_packet3_clip failed\n"); + return -EINVAL; + } + break; + + case RADEON_CMD_WAIT: + break; + + default: + fprintf(stderr,"bad cmd_type %d at %p\n", + header.header.cmd_type, + cmdbuf.buf - sizeof(header)); + return -EINVAL; + } + } + + if (0) + { + static int n = 0; + n++; + if (n == 10) { + fprintf(stderr, "Bufs %d Total emitted %d real changes %d (%.2f%%)\n", + bufs, + total, total_changed, + ((float)total_changed/(float)total*100.0)); + fprintf(stderr, "Total emitted per buf: %.2f\n", + (float)total/(float)bufs); + fprintf(stderr, "Real changes per buf: %.2f\n", + (float)total_changed/(float)bufs); + + bufs = n = total = total_changed = 0; + } + } + + return 0; +} diff --git a/src/mesa/drivers/dri/radeon/radeon_sanity.h b/src/mesa/drivers/dri/radeon/radeon_sanity.h new file mode 100644 index 0000000000..58e8335dd6 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_sanity.h @@ -0,0 +1,8 @@ +#ifndef RADEON_SANITY_H +#define RADEON_SANITY_H + +extern int radeonSanityCmdBuffer( radeonContextPtr rmesa, + int nbox, + XF86DRIClipRectRec *boxes ); + +#endif diff --git a/src/mesa/drivers/dri/radeon/radeon_screen.c b/src/mesa/drivers/dri/radeon/radeon_screen.c new file mode 100644 index 0000000000..ec8ed42d64 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_screen.c @@ -0,0 +1,421 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_screen.c,v 1.6 2002/12/16 16:18:58 dawes Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#include "glheader.h" +#include "imports.h" + +#include "radeon_context.h" +#include "radeon_screen.h" +#include "radeon_macros.h" + +#include "utils.h" +#include "context.h" +#include "vblank.h" + +#ifndef _SOLO +#include "glxextensions.h" +#endif + +#if 1 +/* Including xf86PciInfo.h introduces a bunch of errors... + */ +#define PCI_CHIP_RADEON_QD 0x5144 +#define PCI_CHIP_RADEON_QE 0x5145 +#define PCI_CHIP_RADEON_QF 0x5146 +#define PCI_CHIP_RADEON_QG 0x5147 + +#define PCI_CHIP_RADEON_QY 0x5159 +#define PCI_CHIP_RADEON_QZ 0x515A + +#define PCI_CHIP_RADEON_LW 0x4C57 /* mobility 7 - has tcl */ + +#define PCI_CHIP_RADEON_LY 0x4C59 +#define PCI_CHIP_RADEON_LZ 0x4C5A + +#define PCI_CHIP_RV200_QW 0x5157 /* Radeon 7500 - not an R200 at all */ +#endif + +static int getSwapInfo( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo ); + +/* Create the device specific screen private data struct. + */ +radeonScreenPtr radeonCreateScreen( __DRIscreenPrivate *sPriv ) +{ + radeonScreenPtr screen; + RADEONDRIPtr dri_priv = (RADEONDRIPtr)sPriv->pDevPriv; + + if ( ! driCheckDriDdxDrmVersions( sPriv, "Radeon", 4, 0, 4, 0, 1, 3 ) ) + return NULL; + + /* Allocate the private area */ + screen = (radeonScreenPtr) CALLOC( sizeof(*screen) ); + if ( !screen ) { + __driUtilMessage("%s: Could not allocate memory for screen structure", + __FUNCTION__); + return NULL; + } + + if ( sPriv->drmMinor < 3 || + getenv("RADEON_COMPAT")) { + fprintf( stderr, "Radeon DRI driver:\n\t" + "Compatibility mode for DRM driver version %d.%d.%d\n\t" + "TCL will be disabled, expect reduced performance\n\t" + "(prefer DRM radeon.o 1.3.x or newer)\n\t", + sPriv->drmMajor, sPriv->drmMinor, sPriv->drmPatch ); + } + + + /* This is first since which regions we map depends on whether or + * not we are using a PCI card. + */ + screen->IsPCI = dri_priv->IsPCI; + + if (sPriv->drmMinor >= 3) { + int ret; + drmRadeonGetParam gp; + + gp.param = RADEON_PARAM_AGP_BUFFER_OFFSET; + gp.value = &screen->agp_buffer_offset; + + ret = drmCommandWriteRead( sPriv->fd, DRM_RADEON_GETPARAM, + &gp, sizeof(gp)); + if (ret) { + fprintf(stderr, "drmRadeonGetParam (RADEON_PARAM_AGP_BUFFER_OFFSET): %d\n", ret); + return NULL; + } + + if (sPriv->drmMinor >= 6) { + gp.param = RADEON_PARAM_IRQ_NR; + gp.value = &screen->irq; + + ret = drmCommandWriteRead( sPriv->fd, DRM_RADEON_GETPARAM, + &gp, sizeof(gp)); + if (ret) { + FREE( screen ); + fprintf(stderr, "drmRadeonGetParam (RADEON_PARAM_IRQ_NR): %d\n", ret); + return NULL; + } + } + } + + screen->mmio.handle = dri_priv->registerHandle; + screen->mmio.size = dri_priv->registerSize; + if ( drmMap( sPriv->fd, + screen->mmio.handle, + screen->mmio.size, + &screen->mmio.map ) ) { + FREE( screen ); + __driUtilMessage("%s: drmMap failed\n", __FUNCTION__ ); + return NULL; + } + + screen->status.handle = dri_priv->statusHandle; + screen->status.size = dri_priv->statusSize; + if ( drmMap( sPriv->fd, + screen->status.handle, + screen->status.size, + &screen->status.map ) ) { + drmUnmap( screen->mmio.map, screen->mmio.size ); + FREE( screen ); + __driUtilMessage("%s: drmMap (2) failed\n", __FUNCTION__ ); + return NULL; + } + screen->scratch = (__volatile__ CARD32 *) + ((GLubyte *)screen->status.map + RADEON_SCRATCH_REG_OFFSET); + + screen->buffers = drmMapBufs( sPriv->fd ); + if ( !screen->buffers ) { + drmUnmap( screen->status.map, screen->status.size ); + drmUnmap( screen->mmio.map, screen->mmio.size ); + FREE( screen ); + __driUtilMessage("%s: drmMapBufs failed\n", __FUNCTION__ ); + return NULL; + } + + if ( !screen->IsPCI ) { + screen->agpTextures.handle = dri_priv->agpTexHandle; + screen->agpTextures.size = dri_priv->agpTexMapSize; + if ( drmMap( sPriv->fd, + screen->agpTextures.handle, + screen->agpTextures.size, + (drmAddressPtr)&screen->agpTextures.map ) ) { + drmUnmapBufs( screen->buffers ); + drmUnmap( screen->status.map, screen->status.size ); + drmUnmap( screen->mmio.map, screen->mmio.size ); + FREE( screen ); + __driUtilMessage("%s: IsPCI failed\n", __FUNCTION__); + return NULL; + } + } + + screen->chipset = 0; + switch ( dri_priv->deviceID ) { + default: + fprintf(stderr, "unknown chip id, assuming full radeon support\n"); + case PCI_CHIP_RADEON_QD: + case PCI_CHIP_RADEON_QE: + case PCI_CHIP_RADEON_QF: + case PCI_CHIP_RADEON_QG: + case PCI_CHIP_RV200_QW: + case PCI_CHIP_RADEON_LW: + screen->chipset |= RADEON_CHIPSET_TCL; + case PCI_CHIP_RADEON_QY: + case PCI_CHIP_RADEON_QZ: + case PCI_CHIP_RADEON_LY: + case PCI_CHIP_RADEON_LZ: + break; + } + + screen->cpp = dri_priv->bpp / 8; + screen->AGPMode = dri_priv->AGPMode; + + screen->frontOffset = dri_priv->frontOffset; + screen->frontPitch = dri_priv->frontPitch; + screen->backOffset = dri_priv->backOffset; + screen->backPitch = dri_priv->backPitch; + screen->depthOffset = dri_priv->depthOffset; + screen->depthPitch = dri_priv->depthPitch; + + screen->texOffset[RADEON_CARD_HEAP] = dri_priv->textureOffset; + screen->texSize[RADEON_CARD_HEAP] = dri_priv->textureSize; + screen->logTexGranularity[RADEON_CARD_HEAP] = + dri_priv->log2TexGran; + + if ( screen->IsPCI + || getenv( "RADEON_AGPTEXTURING_FORCE_DISABLE" ) ) { + screen->numTexHeaps = RADEON_NR_TEX_HEAPS - 1; + screen->texOffset[RADEON_AGP_HEAP] = 0; + screen->texSize[RADEON_AGP_HEAP] = 0; + screen->logTexGranularity[RADEON_AGP_HEAP] = 0; + } else { + screen->numTexHeaps = RADEON_NR_TEX_HEAPS; + screen->texOffset[RADEON_AGP_HEAP] = + dri_priv->agpTexOffset + RADEON_AGP_TEX_OFFSET; + screen->texSize[RADEON_AGP_HEAP] = dri_priv->agpTexMapSize; + screen->logTexGranularity[RADEON_AGP_HEAP] = + dri_priv->log2AGPTexGran; + } + + screen->driScreen = sPriv; + screen->sarea_priv_offset = dri_priv->sarea_priv_offset; + return screen; +} + +/* Destroy the device specific screen private data struct. + */ +void radeonDestroyScreen( __DRIscreenPrivate *sPriv ) +{ + radeonScreenPtr screen = (radeonScreenPtr)sPriv->private; + + if (!screen) + return; + + if ( !screen->IsPCI ) { + drmUnmap( screen->agpTextures.map, + screen->agpTextures.size ); + } + drmUnmapBufs( screen->buffers ); + drmUnmap( screen->status.map, screen->status.size ); + drmUnmap( screen->mmio.map, screen->mmio.size ); + + FREE( screen ); + sPriv->private = NULL; +} + + +/* Initialize the driver specific screen private data. + */ +static GLboolean +radeonInitDriver( __DRIscreenPrivate *sPriv ) +{ + sPriv->private = (void *) radeonCreateScreen( sPriv ); + if ( !sPriv->private ) { + radeonDestroyScreen( sPriv ); + return GL_FALSE; + } + + return GL_TRUE; +} + + + +/* Create and initialize the Mesa and driver specific pixmap buffer + * data. + */ +static GLboolean +radeonCreateBuffer( __DRIscreenPrivate *driScrnPriv, + __DRIdrawablePrivate *driDrawPriv, + const __GLcontextModes *mesaVis, + GLboolean isPixmap ) +{ + if (isPixmap) { + return GL_FALSE; /* not implemented */ + } + else { + const GLboolean swDepth = GL_FALSE; + const GLboolean swAlpha = GL_FALSE; + const GLboolean swAccum = mesaVis->accumRedBits > 0; + const GLboolean swStencil = mesaVis->stencilBits > 0 && + mesaVis->depthBits != 24; + driDrawPriv->driverPrivate = (void *) + _mesa_create_framebuffer( mesaVis, + swDepth, + swStencil, + swAccum, + swAlpha ); + return (driDrawPriv->driverPrivate != NULL); + } +} + + +static void +radeonDestroyBuffer(__DRIdrawablePrivate *driDrawPriv) +{ + _mesa_destroy_framebuffer((GLframebuffer *) (driDrawPriv->driverPrivate)); +} + + + + +/* Fullscreen mode isn't used for much -- could be a way to shrink + * front/back buffers & get more texture memory if the client has + * changed the video resolution. + * + * Pageflipping is now done automatically whenever there is a single + * 3d client. + */ +static GLboolean +radeonOpenCloseFullScreen( __DRIcontextPrivate *driContextPriv ) +{ + return GL_TRUE; +} + +static struct __DriverAPIRec radeonAPI = { + .InitDriver = radeonInitDriver, + .DestroyScreen = radeonDestroyScreen, + .CreateContext = radeonCreateContext, + .DestroyContext = radeonDestroyContext, + .CreateBuffer = radeonCreateBuffer, + .DestroyBuffer = radeonDestroyBuffer, + .SwapBuffers = radeonSwapBuffers, + .MakeCurrent = radeonMakeCurrent, + .UnbindContext = radeonUnbindContext, + .OpenFullScreen = radeonOpenCloseFullScreen, + .CloseFullScreen = radeonOpenCloseFullScreen, + .GetSwapInfo = getSwapInfo, + .GetMSC = driGetMSC32, + .WaitForMSC = driWaitForMSC32, + .WaitForSBC = NULL, + .SwapBuffersMSC = NULL +}; + + + +/* + * This is the bootstrap function for the driver. + * The __driCreateScreen name is the symbol that libGL.so fetches. + * Return: pointer to a __DRIscreenPrivate. + */ +#ifndef _SOLO +void *__driCreateScreen(Display *dpy, int scrn, __DRIscreen *psc, + int numConfigs, __GLXvisualConfig *config) +{ + __DRIscreenPrivate *psp; + psp = __driUtilCreateScreen(dpy, scrn, psc, numConfigs, config, &radeonAPI); + return (void *) psp; +} +#else +void *__driCreateScreen(struct DRIDriverRec *driver, + struct DRIDriverContextRec *driverContext) +{ + __DRIscreenPrivate *psp; + psp = __driUtilCreateScreen(driver, driverContext, &radeonAPI); + return (void *) psp; +} +#endif + + +#ifndef _SOLO +/* This function is called by libGL.so as soon as libGL.so is loaded. + * This is where we'd register new extension functions with the dispatcher. + */ +void +__driRegisterExtensions( void ) +{ + PFNGLXENABLEEXTENSIONPROC glx_enable_extension; + + + if ( driCompareGLXAPIVersion( 20030317 ) >= 0 ) { + glx_enable_extension = (PFNGLXENABLEEXTENSIONPROC) + glXGetProcAddress( "__glXEnableExtension" ); + + if ( glx_enable_extension != NULL ) { + glx_enable_extension( "GLX_SGI_swap_control", GL_FALSE ); + glx_enable_extension( "GLX_SGI_video_sync", GL_FALSE ); + glx_enable_extension( "GLX_MESA_swap_control", GL_FALSE ); + glx_enable_extension( "GLX_MESA_swap_frame_usage", GL_FALSE ); + } + } +} +#endif + + +/** + * Get information about previous buffer swaps. + */ +static int +getSwapInfo( __DRIdrawablePrivate *dPriv, __DRIswapInfo * sInfo ) +{ + radeonContextPtr rmesa; + + if ( (dPriv == NULL) || (dPriv->driContextPriv == NULL) + || (dPriv->driContextPriv->driverPrivate == NULL) + || (sInfo == NULL) ) { + return -1; + } + + rmesa = (radeonContextPtr) dPriv->driContextPriv->driverPrivate; + sInfo->swap_count = rmesa->swap_count; + sInfo->swap_ust = rmesa->swap_ust; + sInfo->swap_missed_count = rmesa->swap_missed_count; + + sInfo->swap_missed_usage = (sInfo->swap_missed_count != 0) + ? driCalculateSwapUsage( dPriv, 0, rmesa->swap_missed_ust ) + : 0.0; + + return 0; +} diff --git a/src/mesa/drivers/dri/radeon/radeon_screen.h b/src/mesa/drivers/dri/radeon/radeon_screen.h new file mode 100644 index 0000000000..2c69d8657a --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_screen.h @@ -0,0 +1,101 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_screen.h,v 1.5 2002/12/16 16:18:58 dawes Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + */ + +#ifndef __RADEON_SCREEN_H__ +#define __RADEON_SCREEN_H__ + +#ifdef GLX_DIRECT_RENDERING + +/* + * IMPORTS: these headers contain all the DRI, X and kernel-related + * definitions that we need. + */ +#include "dri_util.h" +#include "radeon_common.h" +#include "radeon_dri.h" +#include "radeon_reg.h" +#include "radeon_sarea.h" + + +typedef struct { + drmHandle handle; /* Handle to the DRM region */ + drmSize size; /* Size of the DRM region */ + drmAddress map; /* Mapping of the DRM region */ +} radeonRegionRec, *radeonRegionPtr; + +/* chipset features */ +#define RADEON_CHIPSET_TCL (1 << 0) + +typedef struct { + + int chipset; + int cpp; + int IsPCI; /* Current card is a PCI card */ + int AGPMode; + unsigned int irq; /* IRQ number (0 means none) */ + + unsigned int frontOffset; + unsigned int frontPitch; + unsigned int backOffset; + unsigned int backPitch; + + unsigned int depthOffset; + unsigned int depthPitch; + + /* Shared texture data */ + int numTexHeaps; + int texOffset[RADEON_NR_TEX_HEAPS]; + int texSize[RADEON_NR_TEX_HEAPS]; + int logTexGranularity[RADEON_NR_TEX_HEAPS]; + + radeonRegionRec mmio; + radeonRegionRec status; + radeonRegionRec agpTextures; + + drmBufMapPtr buffers; + + __volatile__ CARD32 *scratch; + + __DRIscreenPrivate *driScreen; + unsigned int sarea_priv_offset; + unsigned int agp_buffer_offset; /* offset in card memory space */ +} radeonScreenRec, *radeonScreenPtr; + +extern radeonScreenPtr radeonCreateScreen( __DRIscreenPrivate *sPriv ); +extern void radeonDestroyScreen( __DRIscreenPrivate *sPriv ); + +#endif +#endif /* __RADEON_SCREEN_H__ */ diff --git a/src/mesa/drivers/dri/radeon/radeon_span.c b/src/mesa/drivers/dri/radeon/radeon_span.c new file mode 100644 index 0000000000..029d7cd8ee --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_span.c @@ -0,0 +1,415 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_span.c,v 1.6 2002/10/30 12:51:56 alanh Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * Keith Whitwell <keith@tungstengraphics.com> + * + */ + +#include "glheader.h" +#include "swrast/swrast.h" + +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_state.h" +#include "radeon_span.h" +#include "radeon_tex.h" + +#define DBG 0 + +#define LOCAL_VARS \ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \ + radeonScreenPtr radeonScreen = rmesa->radeonScreen; \ + __DRIscreenPrivate *sPriv = rmesa->dri.screen; \ + __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; \ + GLuint pitch = radeonScreen->frontPitch * radeonScreen->cpp; \ + GLuint height = dPriv->h; \ + char *buf = (char *)(sPriv->pFB + \ + rmesa->state.color.drawOffset + \ + (dPriv->x * radeonScreen->cpp) + \ + (dPriv->y * pitch)); \ + char *read_buf = (char *)(sPriv->pFB + \ + rmesa->state.pixel.readOffset + \ + (dPriv->x * radeonScreen->cpp) + \ + (dPriv->y * pitch)); \ + GLuint p; \ + (void) read_buf; (void) buf; (void) p + +#define LOCAL_DEPTH_VARS \ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \ + radeonScreenPtr radeonScreen = rmesa->radeonScreen; \ + __DRIscreenPrivate *sPriv = rmesa->dri.screen; \ + __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; \ + GLuint height = dPriv->h; \ + GLuint xo = dPriv->x; \ + GLuint yo = dPriv->y; \ + char *buf = (char *)(sPriv->pFB + radeonScreen->depthOffset); \ + (void) buf + +#define LOCAL_STENCIL_VARS LOCAL_DEPTH_VARS + + +#define CLIPPIXEL( _x, _y ) \ + ((_x >= minx) && (_x < maxx) && (_y >= miny) && (_y < maxy)) + + +#define CLIPSPAN( _x, _y, _n, _x1, _n1, _i ) \ + if ( _y < miny || _y >= maxy ) { \ + _n1 = 0, _x1 = x; \ + } else { \ + _n1 = _n; \ + _x1 = _x; \ + if ( _x1 < minx ) _i += (minx-_x1), n1 -= (minx-_x1), _x1 = minx; \ + if ( _x1 + _n1 >= maxx ) n1 -= (_x1 + n1 - maxx); \ + } + +#define Y_FLIP( _y ) (height - _y - 1) + + +#define HW_LOCK() + +#define HW_CLIPLOOP() \ + do { \ + __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; \ + int _nc = dPriv->numClipRects; \ + \ + while ( _nc-- ) { \ + int minx = dPriv->pClipRects[_nc].x1 - dPriv->x; \ + int miny = dPriv->pClipRects[_nc].y1 - dPriv->y; \ + int maxx = dPriv->pClipRects[_nc].x2 - dPriv->x; \ + int maxy = dPriv->pClipRects[_nc].y2 - dPriv->y; + +#define HW_ENDCLIPLOOP() \ + } \ + } while (0) + +#define HW_UNLOCK() + + + +/* ================================================================ + * Color buffer + */ + +/* 16 bit, RGB565 color spanline and pixel functions + */ +#define INIT_MONO_PIXEL(p, color) \ + p = PACK_COLOR_565( color[0], color[1], color[2] ) + +#define WRITE_RGBA( _x, _y, r, g, b, a ) \ + *(GLushort *)(buf + _x*2 + _y*pitch) = ((((int)r & 0xf8) << 8) | \ + (((int)g & 0xfc) << 3) | \ + (((int)b & 0xf8) >> 3)) + +#define WRITE_PIXEL( _x, _y, p ) \ + *(GLushort *)(buf + _x*2 + _y*pitch) = p + +#define READ_RGBA( rgba, _x, _y ) \ + do { \ + GLushort p = *(GLushort *)(read_buf + _x*2 + _y*pitch); \ + rgba[0] = ((p >> 8) & 0xf8) * 255 / 0xf8; \ + rgba[1] = ((p >> 3) & 0xfc) * 255 / 0xfc; \ + rgba[2] = ((p << 3) & 0xf8) * 255 / 0xf8; \ + rgba[3] = 0xff; \ + } while (0) + +#define TAG(x) radeon##x##_RGB565 +#include "spantmp.h" + +/* 32 bit, ARGB8888 color spanline and pixel functions + */ +#undef INIT_MONO_PIXEL +#define INIT_MONO_PIXEL(p, color) \ + p = PACK_COLOR_8888( color[3], color[0], color[1], color[2] ) + +#define WRITE_RGBA( _x, _y, r, g, b, a ) \ +do { \ + *(GLuint *)(buf + _x*4 + _y*pitch) = ((b << 0) | \ + (g << 8) | \ + (r << 16) | \ + (a << 24) ); \ +} while (0) + +#define WRITE_PIXEL( _x, _y, p ) \ +do { \ + *(GLuint *)(buf + _x*4 + _y*pitch) = p; \ +} while (0) + +#define READ_RGBA( rgba, _x, _y ) \ +do { \ + volatile GLuint *ptr = (volatile GLuint *)(read_buf + _x*4 + _y*pitch); \ + GLuint p = *ptr; \ + rgba[0] = (p >> 16) & 0xff; \ + rgba[1] = (p >> 8) & 0xff; \ + rgba[2] = (p >> 0) & 0xff; \ + rgba[3] = (p >> 24) & 0xff; \ +} while (0) + +#define TAG(x) radeon##x##_ARGB8888 +#include "spantmp.h" + + + +/* ================================================================ + * Depth buffer + */ + +/* The Radeon family has depth tiling on all the time, so we have to convert + * the x,y coordinates into the memory bus address (mba) in the same + * manner as the engine. In each case, the linear block address (ba) + * is calculated, and then wired with x and y to produce the final + * memory address. + */ + +static GLuint radeon_mba_z32( radeonContextPtr rmesa, + GLint x, GLint y ) +{ + GLuint pitch = rmesa->radeonScreen->frontPitch; + GLuint ba, address = 0; /* a[0..1] = 0 */ + + ba = (y / 16) * (pitch / 16) + (x / 16); + + address |= (x & 0x7) << 2; /* a[2..4] = x[0..2] */ + address |= (y & 0x3) << 5; /* a[5..6] = y[0..1] */ + address |= + (((x & 0x10) >> 2) ^ (y & 0x4)) << 5; /* a[7] = x[4] ^ y[2] */ + address |= (ba & 0x3) << 8; /* a[8..9] = ba[0..1] */ + + address |= (y & 0x8) << 7; /* a[10] = y[3] */ + address |= + (((x & 0x8) << 1) ^ (y & 0x10)) << 7; /* a[11] = x[3] ^ y[4] */ + address |= (ba & ~0x3) << 10; /* a[12..] = ba[2..] */ + + return address; +} + +static __inline GLuint radeon_mba_z16( radeonContextPtr rmesa, GLint x, GLint y ) +{ + GLuint pitch = rmesa->radeonScreen->frontPitch; + GLuint ba, address = 0; /* a[0] = 0 */ + + ba = (y / 16) * (pitch / 32) + (x / 32); + + address |= (x & 0x7) << 1; /* a[1..3] = x[0..2] */ + address |= (y & 0x7) << 4; /* a[4..6] = y[0..2] */ + address |= (x & 0x8) << 4; /* a[7] = x[3] */ + address |= (ba & 0x3) << 8; /* a[8..9] = ba[0..1] */ + address |= (y & 0x8) << 7; /* a[10] = y[3] */ + address |= ((x & 0x10) ^ (y & 0x10)) << 7; /* a[11] = x[4] ^ y[4] */ + address |= (ba & ~0x3) << 10; /* a[12..] = ba[2..] */ + + return address; +} + + +/* 16-bit depth buffer functions + */ +#define WRITE_DEPTH( _x, _y, d ) \ + *(GLushort *)(buf + radeon_mba_z16( rmesa, _x + xo, _y + yo )) = d; + +#define READ_DEPTH( d, _x, _y ) \ + d = *(GLushort *)(buf + radeon_mba_z16( rmesa, _x + xo, _y + yo )); + +#define TAG(x) radeon##x##_16 +#include "depthtmp.h" + +/* 24 bit depth, 8 bit stencil depthbuffer functions + */ +#define WRITE_DEPTH( _x, _y, d ) \ +do { \ + GLuint offset = radeon_mba_z32( rmesa, _x + xo, _y + yo ); \ + GLuint tmp = *(GLuint *)(buf + offset); \ + tmp &= 0xff000000; \ + tmp |= ((d) & 0x00ffffff); \ + *(GLuint *)(buf + offset) = tmp; \ +} while (0) + +#define READ_DEPTH( d, _x, _y ) \ + d = *(GLuint *)(buf + radeon_mba_z32( rmesa, _x + xo, \ + _y + yo )) & 0x00ffffff; + +#define TAG(x) radeon##x##_24_8 +#include "depthtmp.h" + + +/* ================================================================ + * Stencil buffer + */ + +/* 24 bit depth, 8 bit stencil depthbuffer functions + */ +#define WRITE_STENCIL( _x, _y, d ) \ +do { \ + GLuint offset = radeon_mba_z32( rmesa, _x + xo, _y + yo ); \ + GLuint tmp = *(GLuint *)(buf + offset); \ + tmp &= 0x00ffffff; \ + tmp |= (((d) & 0xff) << 24); \ + *(GLuint *)(buf + offset) = tmp; \ +} while (0) + +#define READ_STENCIL( d, _x, _y ) \ +do { \ + GLuint offset = radeon_mba_z32( rmesa, _x + xo, _y + yo ); \ + GLuint tmp = *(GLuint *)(buf + offset); \ + tmp &= 0xff000000; \ + d = tmp >> 24; \ +} while (0) + +#define TAG(x) radeon##x##_24_8 +#include "stenciltmp.h" + + +/* + * This function is called to specify which buffer to read and write + * for software rasterization (swrast) fallbacks. This doesn't necessarily + * correspond to glDrawBuffer() or glReadBuffer() calls. + */ +static void radeonSetBuffer( GLcontext *ctx, + GLframebuffer *colorBuffer, + GLuint bufferBit ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + switch ( bufferBit ) { + case FRONT_LEFT_BIT: + if ( rmesa->sarea->pfCurrentPage == 1 ) { + rmesa->state.pixel.readOffset = rmesa->radeonScreen->backOffset; + rmesa->state.pixel.readPitch = rmesa->radeonScreen->backPitch; + rmesa->state.color.drawOffset = rmesa->radeonScreen->backOffset; + rmesa->state.color.drawPitch = rmesa->radeonScreen->backPitch; + } else { + rmesa->state.pixel.readOffset = rmesa->radeonScreen->frontOffset; + rmesa->state.pixel.readPitch = rmesa->radeonScreen->frontPitch; + rmesa->state.color.drawOffset = rmesa->radeonScreen->frontOffset; + rmesa->state.color.drawPitch = rmesa->radeonScreen->frontPitch; + } + break; + case BACK_LEFT_BIT: + if ( rmesa->sarea->pfCurrentPage == 1 ) { + rmesa->state.pixel.readOffset = rmesa->radeonScreen->frontOffset; + rmesa->state.pixel.readPitch = rmesa->radeonScreen->frontPitch; + rmesa->state.color.drawOffset = rmesa->radeonScreen->frontOffset; + rmesa->state.color.drawPitch = rmesa->radeonScreen->frontPitch; + } else { + rmesa->state.pixel.readOffset = rmesa->radeonScreen->backOffset; + rmesa->state.pixel.readPitch = rmesa->radeonScreen->backPitch; + rmesa->state.color.drawOffset = rmesa->radeonScreen->backOffset; + rmesa->state.color.drawPitch = rmesa->radeonScreen->backPitch; + } + break; + default: + assert(0); + break; + } +} + +/* Move locking out to get reasonable span performance (10x better + * than doing this in HW_LOCK above). WaitForIdle() is the main + * culprit. + */ + +static void radeonSpanRenderStart( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + + RADEON_FIREVERTICES( rmesa ); + LOCK_HARDWARE( rmesa ); + radeonWaitForIdleLocked( rmesa ); +} + +static void radeonSpanRenderFinish( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + _swrast_flush( ctx ); + UNLOCK_HARDWARE( rmesa ); +} + +void radeonInitSpanFuncs( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct swrast_device_driver *swdd = _swrast_GetDeviceDriverReference(ctx); + + swdd->SetBuffer = radeonSetBuffer; + + switch ( rmesa->radeonScreen->cpp ) { + case 2: + swdd->WriteRGBASpan = radeonWriteRGBASpan_RGB565; + swdd->WriteRGBSpan = radeonWriteRGBSpan_RGB565; + swdd->WriteMonoRGBASpan = radeonWriteMonoRGBASpan_RGB565; + swdd->WriteRGBAPixels = radeonWriteRGBAPixels_RGB565; + swdd->WriteMonoRGBAPixels = radeonWriteMonoRGBAPixels_RGB565; + swdd->ReadRGBASpan = radeonReadRGBASpan_RGB565; + swdd->ReadRGBAPixels = radeonReadRGBAPixels_RGB565; + break; + + case 4: + swdd->WriteRGBASpan = radeonWriteRGBASpan_ARGB8888; + swdd->WriteRGBSpan = radeonWriteRGBSpan_ARGB8888; + swdd->WriteMonoRGBASpan = radeonWriteMonoRGBASpan_ARGB8888; + swdd->WriteRGBAPixels = radeonWriteRGBAPixels_ARGB8888; + swdd->WriteMonoRGBAPixels = radeonWriteMonoRGBAPixels_ARGB8888; + swdd->ReadRGBASpan = radeonReadRGBASpan_ARGB8888; + swdd->ReadRGBAPixels = radeonReadRGBAPixels_ARGB8888; + break; + + default: + break; + } + + switch ( rmesa->glCtx->Visual.depthBits ) { + case 16: + swdd->ReadDepthSpan = radeonReadDepthSpan_16; + swdd->WriteDepthSpan = radeonWriteDepthSpan_16; + swdd->ReadDepthPixels = radeonReadDepthPixels_16; + swdd->WriteDepthPixels = radeonWriteDepthPixels_16; + break; + + case 24: + swdd->ReadDepthSpan = radeonReadDepthSpan_24_8; + swdd->WriteDepthSpan = radeonWriteDepthSpan_24_8; + swdd->ReadDepthPixels = radeonReadDepthPixels_24_8; + swdd->WriteDepthPixels = radeonWriteDepthPixels_24_8; + + swdd->ReadStencilSpan = radeonReadStencilSpan_24_8; + swdd->WriteStencilSpan = radeonWriteStencilSpan_24_8; + swdd->ReadStencilPixels = radeonReadStencilPixels_24_8; + swdd->WriteStencilPixels = radeonWriteStencilPixels_24_8; + break; + + default: + break; + } + + swdd->SpanRenderStart = radeonSpanRenderStart; + swdd->SpanRenderFinish = radeonSpanRenderFinish; +} diff --git a/src/mesa/drivers/dri/radeon/radeon_span.h b/src/mesa/drivers/dri/radeon/radeon_span.h new file mode 100644 index 0000000000..011e8eff57 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_span.h @@ -0,0 +1,45 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_span.h,v 1.2 2002/02/22 21:45:01 dawes Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + */ + +#ifndef __RADEON_SPAN_H__ +#define __RADEON_SPAN_H__ + +#ifdef GLX_DIRECT_RENDERING + +extern void radeonInitSpanFuncs( GLcontext *ctx ); + +#endif +#endif diff --git a/src/mesa/drivers/dri/radeon/radeon_state.c b/src/mesa/drivers/dri/radeon/radeon_state.c new file mode 100644 index 0000000000..7b1bbe75fd --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_state.c @@ -0,0 +1,2211 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_state.c,v 1.8 2002/12/16 16:18:58 dawes Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 VA Linux Systems Inc., Fremont, California. + +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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "glheader.h" +#include "imports.h" +#include "api_arrayelt.h" +#include "enums.h" +#include "colormac.h" +#include "state.h" + +#include "swrast/swrast.h" +#include "array_cache/acache.h" +#include "tnl/tnl.h" +#include "tnl/t_pipeline.h" +#include "main/light.h" +#include "swrast_setup/swrast_setup.h" + +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_state.h" +#include "radeon_tcl.h" +#include "radeon_tex.h" +#include "radeon_swtcl.h" +#include "radeon_vtxfmt.h" + +/* ============================================================= + * Alpha blending + */ + +static void radeonAlphaFunc( GLcontext *ctx, GLenum func, GLfloat ref ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + int pp_misc = rmesa->hw.ctx.cmd[CTX_PP_MISC]; + GLubyte refByte; + + CLAMPED_FLOAT_TO_UBYTE(refByte, ref); + + RADEON_STATECHANGE( rmesa, ctx ); + + pp_misc &= ~(RADEON_ALPHA_TEST_OP_MASK | RADEON_REF_ALPHA_MASK); + pp_misc |= (refByte & RADEON_REF_ALPHA_MASK); + + switch ( func ) { + case GL_NEVER: + pp_misc |= RADEON_ALPHA_TEST_FAIL; + break; + case GL_LESS: + pp_misc |= RADEON_ALPHA_TEST_LESS; + break; + case GL_EQUAL: + pp_misc |= RADEON_ALPHA_TEST_EQUAL; + break; + case GL_LEQUAL: + pp_misc |= RADEON_ALPHA_TEST_LEQUAL; + break; + case GL_GREATER: + pp_misc |= RADEON_ALPHA_TEST_GREATER; + break; + case GL_NOTEQUAL: + pp_misc |= RADEON_ALPHA_TEST_NEQUAL; + break; + case GL_GEQUAL: + pp_misc |= RADEON_ALPHA_TEST_GEQUAL; + break; + case GL_ALWAYS: + pp_misc |= RADEON_ALPHA_TEST_PASS; + break; + } + + rmesa->hw.ctx.cmd[CTX_PP_MISC] = pp_misc; +} + +static void radeonBlendEquation( GLcontext *ctx, GLenum mode ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint b = rmesa->hw.ctx.cmd[CTX_RB3D_BLENDCNTL] & ~RADEON_COMB_FCN_MASK; + GLboolean fallback = GL_FALSE; + + switch ( mode ) { + case GL_FUNC_ADD: + case GL_LOGIC_OP: + b |= RADEON_COMB_FCN_ADD_CLAMP; + break; + + case GL_FUNC_SUBTRACT: + b |= RADEON_COMB_FCN_SUB_CLAMP; + break; + + default: + if (ctx->Color.BlendEnabled) + fallback = GL_TRUE; + else + b |= RADEON_COMB_FCN_ADD_CLAMP; + break; + } + + FALLBACK( rmesa, RADEON_FALLBACK_BLEND_EQ, fallback ); + if ( !fallback ) { + RADEON_STATECHANGE( rmesa, ctx ); + rmesa->hw.ctx.cmd[CTX_RB3D_BLENDCNTL] = b; + if ( ctx->Color.ColorLogicOpEnabled ) { + rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_ROP_ENABLE; + } else { + rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_ROP_ENABLE; + } + } +} + +static void radeonBlendFunc( GLcontext *ctx, GLenum sfactor, GLenum dfactor ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint b = rmesa->hw.ctx.cmd[CTX_RB3D_BLENDCNTL] & + ~(RADEON_SRC_BLEND_MASK | RADEON_DST_BLEND_MASK); + GLboolean fallback = GL_FALSE; + + switch ( ctx->Color.BlendSrcRGB ) { + case GL_ZERO: + b |= RADEON_SRC_BLEND_GL_ZERO; + break; + case GL_ONE: + b |= RADEON_SRC_BLEND_GL_ONE; + break; + case GL_DST_COLOR: + b |= RADEON_SRC_BLEND_GL_DST_COLOR; + break; + case GL_ONE_MINUS_DST_COLOR: + b |= RADEON_SRC_BLEND_GL_ONE_MINUS_DST_COLOR; + break; + case GL_SRC_COLOR: + b |= RADEON_SRC_BLEND_GL_SRC_COLOR; + break; + case GL_ONE_MINUS_SRC_COLOR: + b |= RADEON_SRC_BLEND_GL_ONE_MINUS_SRC_COLOR; + break; + case GL_SRC_ALPHA: + b |= RADEON_SRC_BLEND_GL_SRC_ALPHA; + break; + case GL_ONE_MINUS_SRC_ALPHA: + b |= RADEON_SRC_BLEND_GL_ONE_MINUS_SRC_ALPHA; + break; + case GL_DST_ALPHA: + b |= RADEON_SRC_BLEND_GL_DST_ALPHA; + break; + case GL_ONE_MINUS_DST_ALPHA: + b |= RADEON_SRC_BLEND_GL_ONE_MINUS_DST_ALPHA; + break; + case GL_SRC_ALPHA_SATURATE: + b |= RADEON_SRC_BLEND_GL_SRC_ALPHA_SATURATE; + break; + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + if (ctx->Color.BlendEnabled) + fallback = GL_TRUE; + else + b |= RADEON_SRC_BLEND_GL_ONE; + break; + default: + break; + } + + switch ( ctx->Color.BlendDstRGB ) { + case GL_ZERO: + b |= RADEON_DST_BLEND_GL_ZERO; + break; + case GL_ONE: + b |= RADEON_DST_BLEND_GL_ONE; + break; + case GL_SRC_COLOR: + b |= RADEON_DST_BLEND_GL_SRC_COLOR; + break; + case GL_ONE_MINUS_SRC_COLOR: + b |= RADEON_DST_BLEND_GL_ONE_MINUS_SRC_COLOR; + break; + case GL_SRC_ALPHA: + b |= RADEON_DST_BLEND_GL_SRC_ALPHA; + break; + case GL_ONE_MINUS_SRC_ALPHA: + b |= RADEON_DST_BLEND_GL_ONE_MINUS_SRC_ALPHA; + break; + case GL_DST_COLOR: + b |= RADEON_DST_BLEND_GL_DST_COLOR; + break; + case GL_ONE_MINUS_DST_COLOR: + b |= RADEON_DST_BLEND_GL_ONE_MINUS_DST_COLOR; + break; + case GL_DST_ALPHA: + b |= RADEON_DST_BLEND_GL_DST_ALPHA; + break; + case GL_ONE_MINUS_DST_ALPHA: + b |= RADEON_DST_BLEND_GL_ONE_MINUS_DST_ALPHA; + break; + case GL_CONSTANT_COLOR: + case GL_ONE_MINUS_CONSTANT_COLOR: + case GL_CONSTANT_ALPHA: + case GL_ONE_MINUS_CONSTANT_ALPHA: + if (ctx->Color.BlendEnabled) + fallback = GL_TRUE; + else + b |= RADEON_DST_BLEND_GL_ZERO; + break; + default: + break; + } + + FALLBACK( rmesa, RADEON_FALLBACK_BLEND_FUNC, fallback ); + if ( !fallback ) { + RADEON_STATECHANGE( rmesa, ctx ); + rmesa->hw.ctx.cmd[CTX_RB3D_BLENDCNTL] = b; + } +} + +static void radeonBlendFuncSeparate( GLcontext *ctx, + GLenum sfactorRGB, GLenum dfactorRGB, + GLenum sfactorA, GLenum dfactorA ) +{ + radeonBlendFunc( ctx, sfactorRGB, dfactorRGB ); +} + + +/* ============================================================= + * Depth testing + */ + +static void radeonDepthFunc( GLcontext *ctx, GLenum func ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + RADEON_STATECHANGE( rmesa, ctx ); + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] &= ~RADEON_Z_TEST_MASK; + + switch ( ctx->Depth.Func ) { + case GL_NEVER: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_NEVER; + break; + case GL_LESS: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_LESS; + break; + case GL_EQUAL: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_EQUAL; + break; + case GL_LEQUAL: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_LEQUAL; + break; + case GL_GREATER: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_GREATER; + break; + case GL_NOTEQUAL: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_NEQUAL; + break; + case GL_GEQUAL: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_GEQUAL; + break; + case GL_ALWAYS: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_TEST_ALWAYS; + break; + } +} + + +static void radeonDepthMask( GLcontext *ctx, GLboolean flag ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + RADEON_STATECHANGE( rmesa, ctx ); + + if ( ctx->Depth.Mask ) { + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_Z_WRITE_ENABLE; + } else { + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] &= ~RADEON_Z_WRITE_ENABLE; + } +} + +static void radeonClearDepth( GLcontext *ctx, GLclampd d ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint format = (rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] & + RADEON_DEPTH_FORMAT_MASK); + + switch ( format ) { + case RADEON_DEPTH_FORMAT_16BIT_INT_Z: + rmesa->state.depth.clear = d * 0x0000ffff; + break; + case RADEON_DEPTH_FORMAT_24BIT_INT_Z: + rmesa->state.depth.clear = d * 0x00ffffff; + break; + } +} + + +/* ============================================================= + * Fog + */ + + +static void radeonFogfv( GLcontext *ctx, GLenum pname, const GLfloat *param ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + union { int i; float f; } c, d; + GLchan col[4]; + + c.i = rmesa->hw.fog.cmd[FOG_C]; + d.i = rmesa->hw.fog.cmd[FOG_D]; + + switch (pname) { + case GL_FOG_MODE: + if (!ctx->Fog.Enabled) + return; + RADEON_STATECHANGE(rmesa, tcl); + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~RADEON_TCL_FOG_MASK; + switch (ctx->Fog.Mode) { + case GL_LINEAR: + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_TCL_FOG_LINEAR; + if (ctx->Fog.Start == ctx->Fog.End) { + c.f = 1.0F; + d.f = 1.0F; + } + else { + c.f = ctx->Fog.End/(ctx->Fog.End-ctx->Fog.Start); + d.f = 1.0/(ctx->Fog.End-ctx->Fog.Start); + } + break; + case GL_EXP: + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_TCL_FOG_EXP; + c.f = 0.0; + d.f = ctx->Fog.Density; + break; + case GL_EXP2: + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_TCL_FOG_EXP2; + c.f = 0.0; + d.f = -(ctx->Fog.Density * ctx->Fog.Density); + break; + default: + return; + } + break; + case GL_FOG_DENSITY: + switch (ctx->Fog.Mode) { + case GL_EXP: + c.f = 0.0; + d.f = ctx->Fog.Density; + break; + case GL_EXP2: + c.f = 0.0; + d.f = -(ctx->Fog.Density * ctx->Fog.Density); + break; + default: + break; + } + break; + case GL_FOG_START: + case GL_FOG_END: + if (ctx->Fog.Mode == GL_LINEAR) { + if (ctx->Fog.Start == ctx->Fog.End) { + c.f = 1.0F; + d.f = 1.0F; + } else { + c.f = ctx->Fog.End/(ctx->Fog.End-ctx->Fog.Start); + d.f = 1.0/(ctx->Fog.End-ctx->Fog.Start); + } + } + break; + case GL_FOG_COLOR: + RADEON_STATECHANGE( rmesa, ctx ); + UNCLAMPED_FLOAT_TO_RGB_CHAN( col, ctx->Fog.Color ); + rmesa->hw.ctx.cmd[CTX_PP_FOG_COLOR] = + radeonPackColor( 4, col[0], col[1], col[2], 0 ); + break; + case GL_FOG_COORDINATE_SOURCE_EXT: + /* What to do? + */ + break; + default: + return; + } + + if (c.i != rmesa->hw.fog.cmd[FOG_C] || d.i != rmesa->hw.fog.cmd[FOG_D]) { + RADEON_STATECHANGE( rmesa, fog ); + rmesa->hw.fog.cmd[FOG_C] = c.i; + rmesa->hw.fog.cmd[FOG_D] = d.i; + } +} + + +/* ============================================================= + * Scissoring + */ + + +static GLboolean intersect_rect( XF86DRIClipRectPtr out, + XF86DRIClipRectPtr a, + XF86DRIClipRectPtr b ) +{ + *out = *a; + if ( b->x1 > out->x1 ) out->x1 = b->x1; + if ( b->y1 > out->y1 ) out->y1 = b->y1; + if ( b->x2 < out->x2 ) out->x2 = b->x2; + if ( b->y2 < out->y2 ) out->y2 = b->y2; + if ( out->x1 >= out->x2 ) return GL_FALSE; + if ( out->y1 >= out->y2 ) return GL_FALSE; + return GL_TRUE; +} + + +void radeonRecalcScissorRects( radeonContextPtr rmesa ) +{ + XF86DRIClipRectPtr out; + int i; + + /* Grow cliprect store? + */ + if (rmesa->state.scissor.numAllocedClipRects < rmesa->numClipRects) { + while (rmesa->state.scissor.numAllocedClipRects < rmesa->numClipRects) { + rmesa->state.scissor.numAllocedClipRects += 1; /* zero case */ + rmesa->state.scissor.numAllocedClipRects *= 2; + } + + if (rmesa->state.scissor.pClipRects) + FREE(rmesa->state.scissor.pClipRects); + + rmesa->state.scissor.pClipRects = + MALLOC( rmesa->state.scissor.numAllocedClipRects * + sizeof(XF86DRIClipRectRec) ); + + if ( rmesa->state.scissor.pClipRects == NULL ) { + rmesa->state.scissor.numAllocedClipRects = 0; + return; + } + } + + out = rmesa->state.scissor.pClipRects; + rmesa->state.scissor.numClipRects = 0; + + for ( i = 0 ; i < rmesa->numClipRects ; i++ ) { + if ( intersect_rect( out, + &rmesa->pClipRects[i], + &rmesa->state.scissor.rect ) ) { + rmesa->state.scissor.numClipRects++; + out++; + } + } +} + + +static void radeonUpdateScissor( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if ( rmesa->dri.drawable ) { + __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; + + int x = ctx->Scissor.X; + int y = dPriv->h - ctx->Scissor.Y - ctx->Scissor.Height; + int w = ctx->Scissor.X + ctx->Scissor.Width - 1; + int h = dPriv->h - ctx->Scissor.Y - 1; + + rmesa->state.scissor.rect.x1 = x + dPriv->x; + rmesa->state.scissor.rect.y1 = y + dPriv->y; + rmesa->state.scissor.rect.x2 = w + dPriv->x + 1; + rmesa->state.scissor.rect.y2 = h + dPriv->y + 1; + + radeonRecalcScissorRects( rmesa ); + } +} + + +static void radeonScissor( GLcontext *ctx, + GLint x, GLint y, GLsizei w, GLsizei h ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if ( ctx->Scissor.Enabled ) { + RADEON_FIREVERTICES( rmesa ); /* don't pipeline cliprect changes */ + radeonUpdateScissor( ctx ); + } + +} + + +/* ============================================================= + * Culling + */ + +static void radeonCullFace( GLcontext *ctx, GLenum unused ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint s = rmesa->hw.set.cmd[SET_SE_CNTL]; + GLuint t = rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL]; + + s |= RADEON_FFACE_SOLID | RADEON_BFACE_SOLID; + t &= ~(RADEON_CULL_FRONT | RADEON_CULL_BACK); + + if ( ctx->Polygon.CullFlag ) { + switch ( ctx->Polygon.CullFaceMode ) { + case GL_FRONT: + s &= ~RADEON_FFACE_SOLID; + t |= RADEON_CULL_FRONT; + break; + case GL_BACK: + s &= ~RADEON_BFACE_SOLID; + t |= RADEON_CULL_BACK; + break; + case GL_FRONT_AND_BACK: + s &= ~(RADEON_FFACE_SOLID | RADEON_BFACE_SOLID); + t |= (RADEON_CULL_FRONT | RADEON_CULL_BACK); + break; + } + } + + if ( rmesa->hw.set.cmd[SET_SE_CNTL] != s ) { + RADEON_STATECHANGE(rmesa, set ); + rmesa->hw.set.cmd[SET_SE_CNTL] = s; + } + + if ( rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] != t ) { + RADEON_STATECHANGE(rmesa, tcl ); + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] = t; + } +} + +static void radeonFrontFace( GLcontext *ctx, GLenum mode ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + RADEON_STATECHANGE( rmesa, set ); + rmesa->hw.set.cmd[SET_SE_CNTL] &= ~RADEON_FFACE_CULL_DIR_MASK; + + RADEON_STATECHANGE( rmesa, tcl ); + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~RADEON_CULL_FRONT_IS_CCW; + + switch ( mode ) { + case GL_CW: + rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_FFACE_CULL_CW; + break; + case GL_CCW: + rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_FFACE_CULL_CCW; + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_CULL_FRONT_IS_CCW; + break; + } +} + + +/* ============================================================= + * Line state + */ +static void radeonLineWidth( GLcontext *ctx, GLfloat widthf ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + RADEON_STATECHANGE( rmesa, lin ); + RADEON_STATECHANGE( rmesa, set ); + + /* Line width is stored in U6.4 format. + */ + rmesa->hw.lin.cmd[LIN_SE_LINE_WIDTH] = (GLuint)(widthf * 16.0); + if ( widthf > 1.0 ) { + rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_WIDELINE_ENABLE; + } else { + rmesa->hw.set.cmd[SET_SE_CNTL] &= ~RADEON_WIDELINE_ENABLE; + } +} + +static void radeonLineStipple( GLcontext *ctx, GLint factor, GLushort pattern ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + RADEON_STATECHANGE( rmesa, lin ); + rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] = + ((((GLuint)factor & 0xff) << 16) | ((GLuint)pattern)); +} + + +/* ============================================================= + * Masks + */ +static void radeonColorMask( GLcontext *ctx, + GLboolean r, GLboolean g, + GLboolean b, GLboolean a ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint mask = radeonPackColor( rmesa->radeonScreen->cpp, + ctx->Color.ColorMask[RCOMP], + ctx->Color.ColorMask[GCOMP], + ctx->Color.ColorMask[BCOMP], + ctx->Color.ColorMask[ACOMP] ); + + if ( rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK] != mask ) { + RADEON_STATECHANGE( rmesa, msk ); + rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK] = mask; + } +} + + +/* ============================================================= + * Polygon state + */ + +static void radeonPolygonOffset( GLcontext *ctx, + GLfloat factor, GLfloat units ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat constant = units * rmesa->state.depth.scale; + + RADEON_STATECHANGE( rmesa, zbs ); + rmesa->hw.zbs.cmd[ZBS_SE_ZBIAS_FACTOR] = *(GLuint *)&factor; + rmesa->hw.zbs.cmd[ZBS_SE_ZBIAS_CONSTANT] = *(GLuint *)&constant; +} + +static void radeonPolygonStipple( GLcontext *ctx, const GLubyte *mask ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint i; + drmRadeonStipple stipple; + + /* Must flip pattern upside down. + */ + for ( i = 0 ; i < 32 ; i++ ) { + rmesa->state.stipple.mask[31 - i] = ((GLuint *) mask)[i]; + } + + /* TODO: push this into cmd mechanism + */ + RADEON_FIREVERTICES( rmesa ); + LOCK_HARDWARE( rmesa ); + + /* FIXME: Use window x,y offsets into stipple RAM. + */ + stipple.mask = rmesa->state.stipple.mask; + drmCommandWrite( rmesa->dri.fd, DRM_RADEON_STIPPLE, + &stipple, sizeof(drmRadeonStipple) ); + UNLOCK_HARDWARE( rmesa ); +} + +static void radeonPolygonMode( GLcontext *ctx, GLenum face, GLenum mode ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLboolean flag = (ctx->_TriangleCaps & DD_TRI_UNFILLED) != 0; + + /* Can't generally do unfilled via tcl, but some good special + * cases work. + */ + TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_UNFILLED, flag); + if (rmesa->TclFallback) { + radeonChooseRenderState( ctx ); + radeonChooseVertexState( ctx ); + } +} + + +/* ============================================================= + * Rendering attributes + * + * We really don't want to recalculate all this every time we bind a + * texture. These things shouldn't change all that often, so it makes + * sense to break them out of the core texture state update routines. + */ + +/* Examine lighting and texture state to determine if separate specular + * should be enabled. + */ +static void radeonUpdateSpecular( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + CARD32 p = rmesa->hw.ctx.cmd[CTX_PP_CNTL]; + + RADEON_STATECHANGE( rmesa, tcl ); + + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_SPECULAR; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] &= ~RADEON_TCL_COMPUTE_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~RADEON_TCL_VTX_PK_SPEC; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~RADEON_TCL_VTX_PK_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_LIGHTING_ENABLE; + + p &= ~RADEON_SPECULAR_ENABLE; + + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_DIFFUSE_SPECULAR_COMBINE; + + + if (ctx->Light.Enabled && + ctx->Light.Model.ColorControl == GL_SEPARATE_SPECULAR_COLOR) { + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_SPECULAR; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE; + p |= RADEON_SPECULAR_ENABLE; + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= + ~RADEON_DIFFUSE_SPECULAR_COMBINE; + } + else if (ctx->Light.Enabled) { + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE; + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE; + } else if (ctx->Fog.ColorSumEnabled ) { + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE; + p |= RADEON_SPECULAR_ENABLE; + } else { + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_DIFFUSE; + } + + if (ctx->Fog.Enabled) { + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] |= RADEON_TCL_COMPUTE_SPECULAR; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_PK_SPEC; + + /* Bizzare: have to leave lighting enabled to get fog. + */ + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LIGHTING_ENABLE; + } + + if ( ctx->_TriangleCaps & DD_SEPARATE_SPECULAR ) { + assert( (p & RADEON_SPECULAR_ENABLE) != 0 ); + } else { + assert( (p & RADEON_SPECULAR_ENABLE) == 0 ); + } + + if ( rmesa->hw.ctx.cmd[CTX_PP_CNTL] != p ) { + RADEON_STATECHANGE( rmesa, ctx ); + rmesa->hw.ctx.cmd[CTX_PP_CNTL] = p; + } + + /* Update vertex/render formats + */ + if (rmesa->TclFallback) { + radeonChooseRenderState( ctx ); + radeonChooseVertexState( ctx ); + } +} + + +/* ============================================================= + * Materials + */ + + +/* Update on colormaterial, material emmissive/ambient, + * lightmodel.globalambient + */ +static void update_global_ambient( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + float *fcmd = (float *)RADEON_DB_STATE( glt ); + + /* Need to do more if both emmissive & ambient are PREMULT: + */ + if ((rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] & + ((3 << RADEON_EMISSIVE_SOURCE_SHIFT) | + (3 << RADEON_AMBIENT_SOURCE_SHIFT))) == 0) + { + COPY_3V( &fcmd[GLT_RED], + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_EMISSION]); + ACC_SCALE_3V( &fcmd[GLT_RED], + ctx->Light.Model.Ambient, + ctx->Light.Material.Attrib[MAT_ATTRIB_FRONT_AMBIENT]); + } + else + { + COPY_3V( &fcmd[GLT_RED], ctx->Light.Model.Ambient ); + } + + RADEON_DB_STATECHANGE(rmesa, &rmesa->hw.glt); +} + +/* Update on change to + * - light[p].colors + * - light[p].enabled + * - material, + * - colormaterial enabled + * - colormaterial bitmask + */ +static void update_light_colors( GLcontext *ctx, GLuint p ) +{ + struct gl_light *l = &ctx->Light.Light[p]; + +/* fprintf(stderr, "%s\n", __FUNCTION__); */ + + if (l->Enabled) { + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + float *fcmd = (float *)RADEON_DB_STATE( lit[p] ); + GLuint bitmask = ctx->Light.ColorMaterialBitmask; + GLfloat (*mat)[4] = ctx->Light.Material.Attrib; + + COPY_4V( &fcmd[LIT_AMBIENT_RED], l->Ambient ); + COPY_4V( &fcmd[LIT_DIFFUSE_RED], l->Diffuse ); + COPY_4V( &fcmd[LIT_SPECULAR_RED], l->Specular ); + + if (!ctx->Light.ColorMaterialEnabled) + bitmask = 0; + + if ((bitmask & MAT_BIT_FRONT_AMBIENT) == 0) + SELF_SCALE_3V( &fcmd[LIT_AMBIENT_RED], mat[MAT_ATTRIB_FRONT_AMBIENT] ); + + if ((bitmask & MAT_BIT_FRONT_DIFFUSE) == 0) + SELF_SCALE_3V( &fcmd[LIT_DIFFUSE_RED], mat[MAT_ATTRIB_FRONT_DIFFUSE] ); + + if ((bitmask & MAT_BIT_FRONT_SPECULAR) == 0) + SELF_SCALE_3V( &fcmd[LIT_SPECULAR_RED], mat[MAT_ATTRIB_FRONT_SPECULAR] ); + + RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.lit[p] ); + } +} + +/* Also fallback for asym colormaterial mode in twoside lighting... + */ +static void check_twoside_fallback( GLcontext *ctx ) +{ + GLboolean fallback = GL_FALSE; + GLint i; + + if (ctx->Light.Enabled && ctx->Light.Model.TwoSide) { + if (ctx->Light.ColorMaterialEnabled && + (ctx->Light.ColorMaterialBitmask & BACK_MATERIAL_BITS) != + ((ctx->Light.ColorMaterialBitmask & FRONT_MATERIAL_BITS)<<1)) + fallback = GL_TRUE; + else { + for (i = MAT_ATTRIB_FRONT_AMBIENT; i < MAT_ATTRIB_FRONT_INDEXES; i+=2) + if (memcmp( ctx->Light.Material.Attrib[i], + ctx->Light.Material.Attrib[i+1], + sizeof(GLfloat)*4) != 0) { + fallback = GL_TRUE; + break; + } + } + } + + TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_LIGHT_TWOSIDE, fallback ); +} + + +static void radeonColorMaterial( GLcontext *ctx, GLenum face, GLenum mode ) +{ + if (ctx->Light.ColorMaterialEnabled) { + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint light_model_ctl1 = rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]; + GLuint mask = ctx->Light.ColorMaterialBitmask; + + /* Default to PREMULT: + */ + light_model_ctl1 &= ~((0xf << RADEON_EMISSIVE_SOURCE_SHIFT) | + (0xf << RADEON_AMBIENT_SOURCE_SHIFT) | + (0xf << RADEON_DIFFUSE_SOURCE_SHIFT) | + (0xf << RADEON_SPECULAR_SOURCE_SHIFT)); + + if (mask & MAT_BIT_FRONT_EMISSION) { + light_model_ctl1 |= (3 << + RADEON_EMISSIVE_SOURCE_SHIFT); + } + + if (mask & MAT_BIT_FRONT_AMBIENT) { + light_model_ctl1 |= (3 << + RADEON_AMBIENT_SOURCE_SHIFT); + } + + if (mask & MAT_BIT_FRONT_DIFFUSE) { + light_model_ctl1 |= (3 << + RADEON_DIFFUSE_SOURCE_SHIFT); + } + + if (mask & MAT_BIT_FRONT_SPECULAR) { + light_model_ctl1 |= (3 << + RADEON_SPECULAR_SOURCE_SHIFT); + } + + if (light_model_ctl1 != rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]) { + GLuint p; + + RADEON_STATECHANGE( rmesa, tcl ); + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] = light_model_ctl1; + + for (p = 0 ; p < MAX_LIGHTS; p++) + update_light_colors( ctx, p ); + update_global_ambient( ctx ); + } + } + + check_twoside_fallback( ctx ); +} + +void radeonUpdateMaterial( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat (*mat)[4] = ctx->Light.Material.Attrib; + GLfloat *fcmd = (GLfloat *)RADEON_DB_STATE( mtl ); + GLuint p; + GLuint mask = ~0; + + if (ctx->Light.ColorMaterialEnabled) + mask &= ~ctx->Light.ColorMaterialBitmask; + + if (RADEON_DEBUG & DEBUG_STATE) + fprintf(stderr, "%s\n", __FUNCTION__); + + + if (mask & MAT_BIT_FRONT_EMISSION) { + fcmd[MTL_EMMISSIVE_RED] = mat[MAT_ATTRIB_FRONT_EMISSION][0]; + fcmd[MTL_EMMISSIVE_GREEN] = mat[MAT_ATTRIB_FRONT_EMISSION][1]; + fcmd[MTL_EMMISSIVE_BLUE] = mat[MAT_ATTRIB_FRONT_EMISSION][2]; + fcmd[MTL_EMMISSIVE_ALPHA] = mat[MAT_ATTRIB_FRONT_EMISSION][3]; + } + if (mask & MAT_BIT_FRONT_AMBIENT) { + fcmd[MTL_AMBIENT_RED] = mat[MAT_ATTRIB_FRONT_AMBIENT][0]; + fcmd[MTL_AMBIENT_GREEN] = mat[MAT_ATTRIB_FRONT_AMBIENT][1]; + fcmd[MTL_AMBIENT_BLUE] = mat[MAT_ATTRIB_FRONT_AMBIENT][2]; + fcmd[MTL_AMBIENT_ALPHA] = mat[MAT_ATTRIB_FRONT_AMBIENT][3]; + } + if (mask & MAT_BIT_FRONT_DIFFUSE) { + fcmd[MTL_DIFFUSE_RED] = mat[MAT_ATTRIB_FRONT_DIFFUSE][0]; + fcmd[MTL_DIFFUSE_GREEN] = mat[MAT_ATTRIB_FRONT_DIFFUSE][1]; + fcmd[MTL_DIFFUSE_BLUE] = mat[MAT_ATTRIB_FRONT_DIFFUSE][2]; + fcmd[MTL_DIFFUSE_ALPHA] = mat[MAT_ATTRIB_FRONT_DIFFUSE][3]; + } + if (mask & MAT_BIT_FRONT_SPECULAR) { + fcmd[MTL_SPECULAR_RED] = mat[MAT_ATTRIB_FRONT_SPECULAR][0]; + fcmd[MTL_SPECULAR_GREEN] = mat[MAT_ATTRIB_FRONT_SPECULAR][1]; + fcmd[MTL_SPECULAR_BLUE] = mat[MAT_ATTRIB_FRONT_SPECULAR][2]; + fcmd[MTL_SPECULAR_ALPHA] = mat[MAT_ATTRIB_FRONT_SPECULAR][3]; + } + if (mask & MAT_BIT_FRONT_SHININESS) { + fcmd[MTL_SHININESS] = mat[MAT_ATTRIB_FRONT_SHININESS][0]; + } + + if (RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.mtl )) { + for (p = 0 ; p < MAX_LIGHTS; p++) + update_light_colors( ctx, p ); + + check_twoside_fallback( ctx ); + update_global_ambient( ctx ); + } + else if (RADEON_DEBUG & (DEBUG_PRIMS|DEBUG_STATE)) + fprintf(stderr, "%s: Elided noop material call\n", __FUNCTION__); +} + +/* _NEW_LIGHT + * _NEW_MODELVIEW + * _MESA_NEW_NEED_EYE_COORDS + * + * Uses derived state from mesa: + * _VP_inf_norm + * _h_inf_norm + * _Position + * _NormDirection + * _ModelViewInvScale + * _NeedEyeCoords + * _EyeZDir + * + * which are calculated in light.c and are correct for the current + * lighting space (model or eye), hence dependencies on _NEW_MODELVIEW + * and _MESA_NEW_NEED_EYE_COORDS. + */ +static void update_light( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + /* Have to check these, or have an automatic shortcircuit mechanism + * to remove noop statechanges. (Or just do a better job on the + * front end). + */ + { + GLuint tmp = rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]; + + if (ctx->_NeedEyeCoords) + tmp &= ~RADEON_LIGHT_IN_MODELSPACE; + else + tmp |= RADEON_LIGHT_IN_MODELSPACE; + + + /* Leave this test disabled: (unexplained q3 lockup) (even with + new packets) + */ + if (tmp != rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]) + { + RADEON_STATECHANGE( rmesa, tcl ); + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] = tmp; + } + } + + { + GLfloat *fcmd = (GLfloat *)RADEON_DB_STATE( eye ); + fcmd[EYE_X] = ctx->_EyeZDir[0]; + fcmd[EYE_Y] = ctx->_EyeZDir[1]; + fcmd[EYE_Z] = - ctx->_EyeZDir[2]; + fcmd[EYE_RESCALE_FACTOR] = ctx->_ModelViewInvScale; + RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.eye ); + } + + + + if (ctx->Light.Enabled) { + GLint p; + for (p = 0 ; p < MAX_LIGHTS; p++) { + if (ctx->Light.Light[p].Enabled) { + struct gl_light *l = &ctx->Light.Light[p]; + GLfloat *fcmd = (GLfloat *)RADEON_DB_STATE( lit[p] ); + + if (l->EyePosition[3] == 0.0) { + COPY_3FV( &fcmd[LIT_POSITION_X], l->_VP_inf_norm ); + COPY_3FV( &fcmd[LIT_DIRECTION_X], l->_h_inf_norm ); + fcmd[LIT_POSITION_W] = 0; + fcmd[LIT_DIRECTION_W] = 0; + } else { + COPY_4V( &fcmd[LIT_POSITION_X], l->_Position ); + fcmd[LIT_DIRECTION_X] = -l->_NormDirection[0]; + fcmd[LIT_DIRECTION_Y] = -l->_NormDirection[1]; + fcmd[LIT_DIRECTION_Z] = -l->_NormDirection[2]; + fcmd[LIT_DIRECTION_W] = 0; + } + + RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.lit[p] ); + } + } + } +} + +static void radeonLightfv( GLcontext *ctx, GLenum light, + GLenum pname, const GLfloat *params ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLint p = light - GL_LIGHT0; + struct gl_light *l = &ctx->Light.Light[p]; + GLfloat *fcmd = (GLfloat *)rmesa->hw.lit[p].cmd; + + + switch (pname) { + case GL_AMBIENT: + case GL_DIFFUSE: + case GL_SPECULAR: + update_light_colors( ctx, p ); + break; + + case GL_SPOT_DIRECTION: + /* picked up in update_light */ + break; + + case GL_POSITION: { + /* positions picked up in update_light, but can do flag here */ + GLuint flag; + GLuint idx = TCL_PER_LIGHT_CTL_0 + p/2; + + /* FIXME: Set RANGE_ATTEN only when needed */ + if (p&1) + flag = RADEON_LIGHT_1_IS_LOCAL; + else + flag = RADEON_LIGHT_0_IS_LOCAL; + + RADEON_STATECHANGE(rmesa, tcl); + if (l->EyePosition[3] != 0.0F) + rmesa->hw.tcl.cmd[idx] |= flag; + else + rmesa->hw.tcl.cmd[idx] &= ~flag; + break; + } + + case GL_SPOT_EXPONENT: + RADEON_STATECHANGE(rmesa, lit[p]); + fcmd[LIT_SPOT_EXPONENT] = params[0]; + break; + + case GL_SPOT_CUTOFF: { + GLuint flag = (p&1) ? RADEON_LIGHT_1_IS_SPOT : RADEON_LIGHT_0_IS_SPOT; + GLuint idx = TCL_PER_LIGHT_CTL_0 + p/2; + + RADEON_STATECHANGE(rmesa, lit[p]); + fcmd[LIT_SPOT_CUTOFF] = l->_CosCutoff; + + RADEON_STATECHANGE(rmesa, tcl); + if (l->SpotCutoff != 180.0F) + rmesa->hw.tcl.cmd[idx] |= flag; + else + rmesa->hw.tcl.cmd[idx] &= ~flag; + + break; + } + + case GL_CONSTANT_ATTENUATION: + RADEON_STATECHANGE(rmesa, lit[p]); + fcmd[LIT_ATTEN_CONST] = params[0]; + break; + case GL_LINEAR_ATTENUATION: + RADEON_STATECHANGE(rmesa, lit[p]); + fcmd[LIT_ATTEN_LINEAR] = params[0]; + break; + case GL_QUADRATIC_ATTENUATION: + RADEON_STATECHANGE(rmesa, lit[p]); + fcmd[LIT_ATTEN_QUADRATIC] = params[0]; + break; + default: + return; + } + + /* Set RANGE_ATTEN only when needed */ + switch (pname) { + case GL_POSITION: + case GL_LINEAR_ATTENUATION: + case GL_QUADRATIC_ATTENUATION: + { + GLuint flag; + GLuint idx = TCL_PER_LIGHT_CTL_0 + p/2; + + if (p&1) + flag = RADEON_LIGHT_1_ENABLE_RANGE_ATTEN; + else + flag = RADEON_LIGHT_0_ENABLE_RANGE_ATTEN; + + RADEON_STATECHANGE(rmesa, tcl); + if (l->EyePosition[3] != 0.0F && + (l->LinearAttenuation != 0.0F || l->QuadraticAttenuation != 0.0F)) + rmesa->hw.tcl.cmd[idx] |= flag; + else + rmesa->hw.tcl.cmd[idx] &= ~flag; + break; + } + default: + break; + } +} + + + + +static void radeonLightModelfv( GLcontext *ctx, GLenum pname, + const GLfloat *param ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + switch (pname) { + case GL_LIGHT_MODEL_AMBIENT: + update_global_ambient( ctx ); + break; + + case GL_LIGHT_MODEL_LOCAL_VIEWER: + RADEON_STATECHANGE( rmesa, tcl ); + if (ctx->Light.Model.LocalViewer) + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_LOCAL_VIEWER; + else + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_LOCAL_VIEWER; + break; + + case GL_LIGHT_MODEL_TWO_SIDE: + RADEON_STATECHANGE( rmesa, tcl ); + if (ctx->Light.Model.TwoSide) + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= RADEON_LIGHT_TWOSIDE; + else + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~RADEON_LIGHT_TWOSIDE; + + check_twoside_fallback( ctx ); + + if (rmesa->TclFallback) { + radeonChooseRenderState( ctx ); + radeonChooseVertexState( ctx ); + } + break; + + case GL_LIGHT_MODEL_COLOR_CONTROL: + radeonUpdateSpecular(ctx); + break; + + default: + break; + } +} + +static void radeonShadeModel( GLcontext *ctx, GLenum mode ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint s = rmesa->hw.set.cmd[SET_SE_CNTL]; + + s &= ~(RADEON_DIFFUSE_SHADE_MASK | + RADEON_ALPHA_SHADE_MASK | + RADEON_SPECULAR_SHADE_MASK | + RADEON_FOG_SHADE_MASK); + + switch ( mode ) { + case GL_FLAT: + s |= (RADEON_DIFFUSE_SHADE_FLAT | + RADEON_ALPHA_SHADE_FLAT | + RADEON_SPECULAR_SHADE_FLAT | + RADEON_FOG_SHADE_FLAT); + break; + case GL_SMOOTH: + s |= (RADEON_DIFFUSE_SHADE_GOURAUD | + RADEON_ALPHA_SHADE_GOURAUD | + RADEON_SPECULAR_SHADE_GOURAUD | + RADEON_FOG_SHADE_GOURAUD); + break; + default: + return; + } + + if ( rmesa->hw.set.cmd[SET_SE_CNTL] != s ) { + RADEON_STATECHANGE( rmesa, set ); + rmesa->hw.set.cmd[SET_SE_CNTL] = s; + } +} + + +/* ============================================================= + * User clip planes + */ + +static void radeonClipPlane( GLcontext *ctx, GLenum plane, const GLfloat *eq ) +{ + GLint p = (GLint) plane - (GLint) GL_CLIP_PLANE0; + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLint *ip = (GLint *)ctx->Transform._ClipUserPlane[p]; + + RADEON_STATECHANGE( rmesa, ucp[p] ); + rmesa->hw.ucp[p].cmd[UCP_X] = ip[0]; + rmesa->hw.ucp[p].cmd[UCP_Y] = ip[1]; + rmesa->hw.ucp[p].cmd[UCP_Z] = ip[2]; + rmesa->hw.ucp[p].cmd[UCP_W] = ip[3]; +} + +static void radeonUpdateClipPlanes( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint p; + + for (p = 0; p < ctx->Const.MaxClipPlanes; p++) { + if (ctx->Transform.ClipPlanesEnabled & (1 << p)) { + GLint *ip = (GLint *)ctx->Transform._ClipUserPlane[p]; + + RADEON_STATECHANGE( rmesa, ucp[p] ); + rmesa->hw.ucp[p].cmd[UCP_X] = ip[0]; + rmesa->hw.ucp[p].cmd[UCP_Y] = ip[1]; + rmesa->hw.ucp[p].cmd[UCP_Z] = ip[2]; + rmesa->hw.ucp[p].cmd[UCP_W] = ip[3]; + } + } +} + + +/* ============================================================= + * Stencil + */ + +static void radeonStencilFunc( GLcontext *ctx, GLenum func, + GLint ref, GLuint mask ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint refmask = ((ctx->Stencil.Ref[0] << RADEON_STENCIL_REF_SHIFT) | + (ctx->Stencil.ValueMask[0] << RADEON_STENCIL_MASK_SHIFT)); + + RADEON_STATECHANGE( rmesa, ctx ); + RADEON_STATECHANGE( rmesa, msk ); + + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] &= ~RADEON_STENCIL_TEST_MASK; + rmesa->hw.msk.cmd[MSK_RB3D_STENCILREFMASK] &= ~(RADEON_STENCIL_REF_MASK| + RADEON_STENCIL_VALUE_MASK); + + switch ( ctx->Stencil.Function[0] ) { + case GL_NEVER: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_NEVER; + break; + case GL_LESS: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_LESS; + break; + case GL_EQUAL: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_EQUAL; + break; + case GL_LEQUAL: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_LEQUAL; + break; + case GL_GREATER: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_GREATER; + break; + case GL_NOTEQUAL: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_NEQUAL; + break; + case GL_GEQUAL: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_GEQUAL; + break; + case GL_ALWAYS: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_TEST_ALWAYS; + break; + } + + rmesa->hw.msk.cmd[MSK_RB3D_STENCILREFMASK] |= refmask; +} + +static void radeonStencilMask( GLcontext *ctx, GLuint mask ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + RADEON_STATECHANGE( rmesa, msk ); + rmesa->hw.msk.cmd[MSK_RB3D_STENCILREFMASK] &= ~RADEON_STENCIL_WRITE_MASK; + rmesa->hw.msk.cmd[MSK_RB3D_STENCILREFMASK] |= + (ctx->Stencil.WriteMask[0] << RADEON_STENCIL_WRITEMASK_SHIFT); +} + +static void radeonStencilOp( GLcontext *ctx, GLenum fail, + GLenum zfail, GLenum zpass ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + RADEON_STATECHANGE( rmesa, ctx ); + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] &= ~(RADEON_STENCIL_FAIL_MASK | + RADEON_STENCIL_ZFAIL_MASK | + RADEON_STENCIL_ZPASS_MASK); + + switch ( ctx->Stencil.FailFunc[0] ) { + case GL_KEEP: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_KEEP; + break; + case GL_ZERO: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_ZERO; + break; + case GL_REPLACE: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_REPLACE; + break; + case GL_INCR: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_INC; + break; + case GL_DECR: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_DEC; + break; + case GL_INVERT: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_FAIL_INVERT; + break; + } + + switch ( ctx->Stencil.ZFailFunc[0] ) { + case GL_KEEP: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_KEEP; + break; + case GL_ZERO: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_ZERO; + break; + case GL_REPLACE: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_REPLACE; + break; + case GL_INCR: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_INC; + break; + case GL_DECR: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_DEC; + break; + case GL_INVERT: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZFAIL_INVERT; + break; + } + + switch ( ctx->Stencil.ZPassFunc[0] ) { + case GL_KEEP: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_KEEP; + break; + case GL_ZERO: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_ZERO; + break; + case GL_REPLACE: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_REPLACE; + break; + case GL_INCR: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_INC; + break; + case GL_DECR: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_DEC; + break; + case GL_INVERT: + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] |= RADEON_STENCIL_ZPASS_INVERT; + break; + } +} + +static void radeonClearStencil( GLcontext *ctx, GLint s ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + rmesa->state.stencil.clear = + ((GLuint) ctx->Stencil.Clear | + (0xff << RADEON_STENCIL_MASK_SHIFT) | + (ctx->Stencil.WriteMask[0] << RADEON_STENCIL_WRITEMASK_SHIFT)); +} + + +/* ============================================================= + * Window position and viewport transformation + */ + +/* + * To correctly position primitives: + */ +#define SUBPIXEL_X 0.125 +#define SUBPIXEL_Y 0.125 + +void radeonUpdateWindow( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; + GLfloat xoffset = (GLfloat)dPriv->x; + GLfloat yoffset = (GLfloat)dPriv->y + dPriv->h; + const GLfloat *v = ctx->Viewport._WindowMap.m; + + GLfloat sx = v[MAT_SX]; + GLfloat tx = v[MAT_TX] + xoffset + SUBPIXEL_X; + GLfloat sy = - v[MAT_SY]; + GLfloat ty = (- v[MAT_TY]) + yoffset + SUBPIXEL_Y; + GLfloat sz = v[MAT_SZ] * rmesa->state.depth.scale; + GLfloat tz = v[MAT_TZ] * rmesa->state.depth.scale; + RADEON_FIREVERTICES( rmesa ); + RADEON_STATECHANGE( rmesa, vpt ); + + rmesa->hw.vpt.cmd[VPT_SE_VPORT_XSCALE] = *(GLuint *)&sx; + rmesa->hw.vpt.cmd[VPT_SE_VPORT_XOFFSET] = *(GLuint *)&tx; + rmesa->hw.vpt.cmd[VPT_SE_VPORT_YSCALE] = *(GLuint *)&sy; + rmesa->hw.vpt.cmd[VPT_SE_VPORT_YOFFSET] = *(GLuint *)&ty; + rmesa->hw.vpt.cmd[VPT_SE_VPORT_ZSCALE] = *(GLuint *)&sz; + rmesa->hw.vpt.cmd[VPT_SE_VPORT_ZOFFSET] = *(GLuint *)&tz; +} + + + +static void radeonViewport( GLcontext *ctx, GLint x, GLint y, + GLsizei width, GLsizei height ) +{ + /* Don't pipeline viewport changes, conflict with window offset + * setting below. Could apply deltas to rescue pipelined viewport + * values, or keep the originals hanging around. + */ + RADEON_FIREVERTICES( RADEON_CONTEXT(ctx) ); + radeonUpdateWindow( ctx ); +} + +static void radeonDepthRange( GLcontext *ctx, GLclampd nearval, + GLclampd farval ) +{ + radeonUpdateWindow( ctx ); +} + +void radeonUpdateViewportOffset( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; + GLfloat xoffset = (GLfloat)dPriv->x; + GLfloat yoffset = (GLfloat)dPriv->y + dPriv->h; + const GLfloat *v = ctx->Viewport._WindowMap.m; + + GLfloat tx = v[MAT_TX] + xoffset; + GLfloat ty = (- v[MAT_TY]) + yoffset; + + if ( rmesa->hw.vpt.cmd[VPT_SE_VPORT_XOFFSET] != *(GLuint *)&tx || + rmesa->hw.vpt.cmd[VPT_SE_VPORT_YOFFSET] != *(GLuint *)&ty ) + { + /* Note: this should also modify whatever data the context reset + * code uses... + */ + rmesa->hw.vpt.cmd[VPT_SE_VPORT_XOFFSET] = *(GLuint *)&tx; + rmesa->hw.vpt.cmd[VPT_SE_VPORT_YOFFSET] = *(GLuint *)&ty; + + /* update polygon stipple x/y screen offset */ + { + GLuint stx, sty; + GLuint m = rmesa->hw.msc.cmd[MSC_RE_MISC]; + + m &= ~(RADEON_STIPPLE_X_OFFSET_MASK | + RADEON_STIPPLE_Y_OFFSET_MASK); + + /* add magic offsets, then invert */ + stx = 31 - ((rmesa->dri.drawable->x - 1) & RADEON_STIPPLE_COORD_MASK); + sty = 31 - ((rmesa->dri.drawable->y + rmesa->dri.drawable->h - 1) + & RADEON_STIPPLE_COORD_MASK); + + m |= ((stx << RADEON_STIPPLE_X_OFFSET_SHIFT) | + (sty << RADEON_STIPPLE_Y_OFFSET_SHIFT)); + + if ( rmesa->hw.msc.cmd[MSC_RE_MISC] != m ) { + RADEON_STATECHANGE( rmesa, msc ); + rmesa->hw.msc.cmd[MSC_RE_MISC] = m; + } + } + } + + radeonUpdateScissor( ctx ); +} + + + +/* ============================================================= + * Miscellaneous + */ + +static void radeonClearColor( GLcontext *ctx, const GLfloat color[4] ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLubyte c[4]; + CLAMPED_FLOAT_TO_UBYTE(c[0], color[0]); + CLAMPED_FLOAT_TO_UBYTE(c[1], color[1]); + CLAMPED_FLOAT_TO_UBYTE(c[2], color[2]); + CLAMPED_FLOAT_TO_UBYTE(c[3], color[3]); + rmesa->state.color.clear = radeonPackColor( rmesa->radeonScreen->cpp, + c[0], c[1], c[2], c[3] ); +} + + +static void radeonRenderMode( GLcontext *ctx, GLenum mode ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + FALLBACK( rmesa, RADEON_FALLBACK_RENDER_MODE, (mode != GL_RENDER) ); +} + + +static GLuint radeon_rop_tab[] = { + RADEON_ROP_CLEAR, + RADEON_ROP_AND, + RADEON_ROP_AND_REVERSE, + RADEON_ROP_COPY, + RADEON_ROP_AND_INVERTED, + RADEON_ROP_NOOP, + RADEON_ROP_XOR, + RADEON_ROP_OR, + RADEON_ROP_NOR, + RADEON_ROP_EQUIV, + RADEON_ROP_INVERT, + RADEON_ROP_OR_REVERSE, + RADEON_ROP_COPY_INVERTED, + RADEON_ROP_OR_INVERTED, + RADEON_ROP_NAND, + RADEON_ROP_SET, +}; + +static void radeonLogicOpCode( GLcontext *ctx, GLenum opcode ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint rop = (GLuint)opcode - GL_CLEAR; + + ASSERT( rop < 16 ); + + RADEON_STATECHANGE( rmesa, msk ); + rmesa->hw.msk.cmd[MSK_RB3D_ROPCNTL] = radeon_rop_tab[rop]; +} + + +void radeonSetCliprects( radeonContextPtr rmesa, GLenum mode ) +{ + __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; + + switch ( mode ) { + case GL_FRONT_LEFT: + rmesa->numClipRects = dPriv->numClipRects; + rmesa->pClipRects = (XF86DRIClipRectPtr)dPriv->pClipRects; + break; + case GL_BACK_LEFT: + /* Can't ignore 2d windows if we are page flipping. + */ + if ( dPriv->numBackClipRects == 0 || rmesa->doPageFlip ) { + rmesa->numClipRects = dPriv->numClipRects; + rmesa->pClipRects = (XF86DRIClipRectPtr)dPriv->pClipRects; + } + else { + rmesa->numClipRects = dPriv->numBackClipRects; + rmesa->pClipRects = (XF86DRIClipRectPtr)dPriv->pBackClipRects; + } + break; + default: + fprintf(stderr, "bad mode in radeonSetCliprects\n"); + return; + } + + if (rmesa->state.scissor.enabled) + radeonRecalcScissorRects( rmesa ); +} + + +static void radeonDrawBuffer( GLcontext *ctx, GLenum mode ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if (RADEON_DEBUG & DEBUG_DRI) + fprintf(stderr, "%s %s\n", __FUNCTION__, + _mesa_lookup_enum_by_nr( mode )); + + RADEON_FIREVERTICES(rmesa); /* don't pipeline cliprect changes */ + + /* + * _DrawDestMask is easier to cope with than <mode>. + */ + switch ( ctx->Color._DrawDestMask ) { + case FRONT_LEFT_BIT: + FALLBACK( rmesa, RADEON_FALLBACK_DRAW_BUFFER, GL_FALSE ); + radeonSetCliprects( rmesa, GL_FRONT_LEFT ); + break; + case BACK_LEFT_BIT: + FALLBACK( rmesa, RADEON_FALLBACK_DRAW_BUFFER, GL_FALSE ); + radeonSetCliprects( rmesa, GL_BACK_LEFT ); + break; + default: + /* GL_NONE or GL_FRONT_AND_BACK or stereo left&right, etc */ + FALLBACK( rmesa, RADEON_FALLBACK_DRAW_BUFFER, GL_TRUE ); + return; + } + + /* We want to update the s/w rast state too so that r200SetBuffer() + * gets called. + */ + _swrast_DrawBuffer(ctx, mode); + + RADEON_STATECHANGE( rmesa, ctx ); + rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = (rmesa->state.color.drawOffset & + RADEON_COLOROFFSET_MASK); + rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = rmesa->state.color.drawPitch; +} + +static void radeonReadBuffer( GLcontext *ctx, GLenum mode ) +{ + /* nothing, until we implement h/w glRead/CopyPixels or CopyTexImage */ +} + + +/* ============================================================= + * State enable/disable + */ + +static void radeonEnable( GLcontext *ctx, GLenum cap, GLboolean state ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint p, flag; + + if ( RADEON_DEBUG & DEBUG_STATE ) + fprintf( stderr, "%s( %s = %s )\n", __FUNCTION__, + _mesa_lookup_enum_by_nr( cap ), + state ? "GL_TRUE" : "GL_FALSE" ); + + switch ( cap ) { + /* Fast track this one... + */ + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + case GL_TEXTURE_3D: + break; + + case GL_ALPHA_TEST: + RADEON_STATECHANGE( rmesa, ctx ); + if (state) { + rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_ALPHA_TEST_ENABLE; + } else { + rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_ALPHA_TEST_ENABLE; + } + break; + + case GL_BLEND: + RADEON_STATECHANGE( rmesa, ctx ); + if (state) { + rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_ALPHA_BLEND_ENABLE; + } else { + rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_ALPHA_BLEND_ENABLE; + } + if ( ctx->Color.ColorLogicOpEnabled ) { + rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_ROP_ENABLE; + } else { + rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_ROP_ENABLE; + } + + /* Catch a possible fallback: + */ + if (state) { + ctx->Driver.BlendEquation( ctx, ctx->Color.BlendEquation ); + ctx->Driver.BlendFunc( ctx, ctx->Color.BlendSrcRGB, + ctx->Color.BlendDstRGB ); + } + else { + FALLBACK( rmesa, RADEON_FALLBACK_BLEND_FUNC, GL_FALSE ); + FALLBACK( rmesa, RADEON_FALLBACK_BLEND_EQ, GL_FALSE ); + } + break; + + case GL_CLIP_PLANE0: + case GL_CLIP_PLANE1: + case GL_CLIP_PLANE2: + case GL_CLIP_PLANE3: + case GL_CLIP_PLANE4: + case GL_CLIP_PLANE5: + p = cap-GL_CLIP_PLANE0; + RADEON_STATECHANGE( rmesa, tcl ); + if (state) { + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] |= (RADEON_UCP_ENABLE_0<<p); + radeonClipPlane( ctx, cap, NULL ); + } + else { + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~(RADEON_UCP_ENABLE_0<<p); + } + break; + + case GL_COLOR_MATERIAL: + radeonColorMaterial( ctx, 0, 0 ); + if (!state) + radeonUpdateMaterial( ctx ); + break; + + case GL_CULL_FACE: + radeonCullFace( ctx, 0 ); + break; + + case GL_DEPTH_TEST: + RADEON_STATECHANGE(rmesa, ctx ); + if ( state ) { + rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_Z_ENABLE; + } else { + rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_Z_ENABLE; + } + break; + + case GL_DITHER: + RADEON_STATECHANGE(rmesa, ctx ); + if ( state ) { + rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_DITHER_ENABLE; + } else { + rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_DITHER_ENABLE; + } + break; + + case GL_FOG: + RADEON_STATECHANGE(rmesa, ctx ); + if ( state ) { + rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_FOG_ENABLE; + radeonFogfv( ctx, GL_FOG_MODE, 0 ); + } else { + rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_FOG_ENABLE; + RADEON_STATECHANGE(rmesa, tcl); + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] &= ~RADEON_TCL_FOG_MASK; + } + radeonUpdateSpecular( ctx ); /* for PK_SPEC */ + if (rmesa->TclFallback) + radeonChooseVertexState( ctx ); + _mesa_allow_light_in_model( ctx, !state ); + break; + + case GL_LIGHT0: + case GL_LIGHT1: + case GL_LIGHT2: + case GL_LIGHT3: + case GL_LIGHT4: + case GL_LIGHT5: + case GL_LIGHT6: + case GL_LIGHT7: + RADEON_STATECHANGE(rmesa, tcl); + p = cap - GL_LIGHT0; + if (p&1) + flag = (RADEON_LIGHT_1_ENABLE | + RADEON_LIGHT_1_ENABLE_AMBIENT | + RADEON_LIGHT_1_ENABLE_SPECULAR); + else + flag = (RADEON_LIGHT_0_ENABLE | + RADEON_LIGHT_0_ENABLE_AMBIENT | + RADEON_LIGHT_0_ENABLE_SPECULAR); + + if (state) + rmesa->hw.tcl.cmd[p/2 + TCL_PER_LIGHT_CTL_0] |= flag; + else + rmesa->hw.tcl.cmd[p/2 + TCL_PER_LIGHT_CTL_0] &= ~flag; + + /* + */ + update_light_colors( ctx, p ); + break; + + case GL_LIGHTING: + RADEON_STATECHANGE(rmesa, tcl); + radeonUpdateSpecular(ctx); + check_twoside_fallback( ctx ); + break; + + case GL_LINE_SMOOTH: + RADEON_STATECHANGE( rmesa, ctx ); + if ( state ) { + rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_ANTI_ALIAS_LINE; + } else { + rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_ANTI_ALIAS_LINE; + } + break; + + case GL_LINE_STIPPLE: + RADEON_STATECHANGE( rmesa, ctx ); + if ( state ) { + rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_PATTERN_ENABLE; + } else { + rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_PATTERN_ENABLE; + } + break; + + case GL_COLOR_LOGIC_OP: + RADEON_STATECHANGE( rmesa, ctx ); + if ( state ) { + rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_ROP_ENABLE; + } else { + rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_ROP_ENABLE; + } + break; + + case GL_NORMALIZE: + RADEON_STATECHANGE( rmesa, tcl ); + if ( state ) { + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_NORMALIZE_NORMALS; + } else { + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_NORMALIZE_NORMALS; + } + break; + + case GL_POLYGON_OFFSET_POINT: + if (rmesa->dri.drmMinor == 1) { + radeonChooseRenderState( ctx ); + } + else { + RADEON_STATECHANGE( rmesa, set ); + if ( state ) { + rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_ZBIAS_ENABLE_POINT; + } else { + rmesa->hw.set.cmd[SET_SE_CNTL] &= ~RADEON_ZBIAS_ENABLE_POINT; + } + } + break; + + case GL_POLYGON_OFFSET_LINE: + if (rmesa->dri.drmMinor == 1) { + radeonChooseRenderState( ctx ); + } + else { + RADEON_STATECHANGE( rmesa, set ); + if ( state ) { + rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_ZBIAS_ENABLE_LINE; + } else { + rmesa->hw.set.cmd[SET_SE_CNTL] &= ~RADEON_ZBIAS_ENABLE_LINE; + } + } + break; + + case GL_POLYGON_OFFSET_FILL: + if (rmesa->dri.drmMinor == 1) { + radeonChooseRenderState( ctx ); + } + else { + RADEON_STATECHANGE( rmesa, set ); + if ( state ) { + rmesa->hw.set.cmd[SET_SE_CNTL] |= RADEON_ZBIAS_ENABLE_TRI; + } else { + rmesa->hw.set.cmd[SET_SE_CNTL] &= ~RADEON_ZBIAS_ENABLE_TRI; + } + } + break; + + case GL_POLYGON_SMOOTH: + RADEON_STATECHANGE( rmesa, ctx ); + if ( state ) { + rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_ANTI_ALIAS_POLY; + } else { + rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_ANTI_ALIAS_POLY; + } + break; + + case GL_POLYGON_STIPPLE: + RADEON_STATECHANGE(rmesa, ctx ); + if ( state ) { + rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= RADEON_STIPPLE_ENABLE; + } else { + rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= ~RADEON_STIPPLE_ENABLE; + } + break; + + case GL_RESCALE_NORMAL_EXT: { + GLboolean tmp = ctx->_NeedEyeCoords ? state : !state; + RADEON_STATECHANGE( rmesa, tcl ); + if ( tmp ) { + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_RESCALE_NORMALS; + } else { + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_RESCALE_NORMALS; + } + break; + } + + case GL_SCISSOR_TEST: + RADEON_FIREVERTICES( rmesa ); + rmesa->state.scissor.enabled = state; + radeonUpdateScissor( ctx ); + break; + + case GL_STENCIL_TEST: + if ( rmesa->state.stencil.hwBuffer ) { + RADEON_STATECHANGE( rmesa, ctx ); + if ( state ) { + rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_STENCIL_ENABLE; + } else { + rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] &= ~RADEON_STENCIL_ENABLE; + } + } else { + FALLBACK( rmesa, RADEON_FALLBACK_STENCIL, state ); + } + break; + + case GL_TEXTURE_GEN_Q: + case GL_TEXTURE_GEN_R: + case GL_TEXTURE_GEN_S: + case GL_TEXTURE_GEN_T: + /* Picked up in radeonUpdateTextureState. + */ + rmesa->recheck_texgen[ctx->Texture.CurrentUnit] = GL_TRUE; + break; + + case GL_COLOR_SUM_EXT: + radeonUpdateSpecular ( ctx ); + break; + + default: + return; + } +} + + +static void radeonLightingSpaceChange( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLboolean tmp; + RADEON_STATECHANGE( rmesa, tcl ); + + if (RADEON_DEBUG & DEBUG_STATE) + fprintf(stderr, "%s %d BEFORE %x\n", __FUNCTION__, ctx->_NeedEyeCoords, + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]); + + if (ctx->_NeedEyeCoords) + tmp = ctx->Transform.RescaleNormals; + else + tmp = !ctx->Transform.RescaleNormals; + + if ( tmp ) { + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] |= RADEON_RESCALE_NORMALS; + } else { + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] &= ~RADEON_RESCALE_NORMALS; + } + + if (RADEON_DEBUG & DEBUG_STATE) + fprintf(stderr, "%s %d AFTER %x\n", __FUNCTION__, ctx->_NeedEyeCoords, + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL]); +} + +/* ============================================================= + * Deferred state management - matrices, textures, other? + */ + + + + +static void upload_matrix( radeonContextPtr rmesa, GLfloat *src, int idx ) +{ + float *dest = ((float *)RADEON_DB_STATE( mat[idx] ))+MAT_ELT_0; + int i; + + + for (i = 0 ; i < 4 ; i++) { + *dest++ = src[i]; + *dest++ = src[i+4]; + *dest++ = src[i+8]; + *dest++ = src[i+12]; + } + + RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.mat[idx] ); +} + +static void upload_matrix_t( radeonContextPtr rmesa, GLfloat *src, int idx ) +{ + float *dest = ((float *)RADEON_DB_STATE( mat[idx] ))+MAT_ELT_0; + memcpy(dest, src, 16*sizeof(float)); + RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.mat[idx] ); +} + + +static void update_texturematrix( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + GLuint tpc = rmesa->hw.tcl.cmd[TCL_TEXTURE_PROC_CTL]; + GLuint vs = rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL]; + int unit; + + rmesa->TexMatEnabled = 0; + + for (unit = 0 ; unit < 2; unit++) { + if (!ctx->Texture.Unit[unit]._ReallyEnabled) { + } + else if (ctx->TextureMatrixStack[unit].Top->type != MATRIX_IDENTITY) { + GLuint inputshift = RADEON_TEXGEN_0_INPUT_SHIFT + unit*4; + + rmesa->TexMatEnabled |= (RADEON_TEXGEN_TEXMAT_0_ENABLE| + RADEON_TEXMAT_0_ENABLE) << unit; + + if (rmesa->TexGenEnabled & (RADEON_TEXMAT_0_ENABLE << unit)) { + /* Need to preconcatenate any active texgen + * obj/eyeplane matrices: + */ + _math_matrix_mul_matrix( &rmesa->tmpmat, + &rmesa->TexGenMatrix[unit], + ctx->TextureMatrixStack[unit].Top ); + upload_matrix( rmesa, rmesa->tmpmat.m, TEXMAT_0+unit ); + } + else { + rmesa->TexMatEnabled |= + (RADEON_TEXGEN_INPUT_TEXCOORD_0+unit) << inputshift; + upload_matrix( rmesa, ctx->TextureMatrixStack[unit].Top->m, + TEXMAT_0+unit ); + } + } + else if (rmesa->TexGenEnabled & (RADEON_TEXMAT_0_ENABLE << unit)) { + upload_matrix( rmesa, rmesa->TexGenMatrix[unit].m, + TEXMAT_0+unit ); + } + } + + + tpc = (rmesa->TexMatEnabled | rmesa->TexGenEnabled); + + vs &= ~((0xf << RADEON_TCL_TEX_0_OUTPUT_SHIFT) | + (0xf << RADEON_TCL_TEX_1_OUTPUT_SHIFT)); + + if (tpc & RADEON_TEXGEN_TEXMAT_0_ENABLE) + vs |= RADEON_TCL_TEX_COMPUTED_TEX_0 << RADEON_TCL_TEX_0_OUTPUT_SHIFT; + else + vs |= RADEON_TCL_TEX_INPUT_TEX_0 << RADEON_TCL_TEX_0_OUTPUT_SHIFT; + + if (tpc & RADEON_TEXGEN_TEXMAT_1_ENABLE) + vs |= RADEON_TCL_TEX_COMPUTED_TEX_1 << RADEON_TCL_TEX_1_OUTPUT_SHIFT; + else + vs |= RADEON_TCL_TEX_INPUT_TEX_1 << RADEON_TCL_TEX_1_OUTPUT_SHIFT; + + if (tpc != rmesa->hw.tcl.cmd[TCL_TEXTURE_PROC_CTL] || + vs != rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL]) { + + RADEON_STATECHANGE(rmesa, tcl); + rmesa->hw.tcl.cmd[TCL_TEXTURE_PROC_CTL] = tpc; + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] = vs; + } +} + + + +void radeonValidateState( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint new_state = rmesa->NewGLState; + + if (new_state & _NEW_TEXTURE) { + radeonUpdateTextureState( ctx ); + new_state |= rmesa->NewGLState; /* may add TEXTURE_MATRIX */ + } + + /* Need an event driven matrix update? + */ + if (new_state & (_NEW_MODELVIEW|_NEW_PROJECTION)) + upload_matrix( rmesa, ctx->_ModelProjectMatrix.m, MODEL_PROJ ); + + /* Need these for lighting (shouldn't upload otherwise) + */ + if (new_state & (_NEW_MODELVIEW)) { + upload_matrix( rmesa, ctx->ModelviewMatrixStack.Top->m, MODEL ); + upload_matrix_t( rmesa, ctx->ModelviewMatrixStack.Top->inv, MODEL_IT ); + } + + /* Does this need to be triggered on eg. modelview for + * texgen-derived objplane/eyeplane matrices? + */ + if (new_state & _NEW_TEXTURE_MATRIX) { + update_texturematrix( ctx ); + } + + if (new_state & (_NEW_LIGHT|_NEW_MODELVIEW|_MESA_NEW_NEED_EYE_COORDS)) { + update_light( ctx ); + } + + /* emit all active clip planes if projection matrix changes. + */ + if (new_state & (_NEW_PROJECTION)) { + if (ctx->Transform.ClipPlanesEnabled) + radeonUpdateClipPlanes( ctx ); + } + + + rmesa->NewGLState = 0; +} + + +static void radeonInvalidateState( 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 ); + _ae_invalidate_state( ctx, new_state ); + RADEON_CONTEXT(ctx)->NewGLState |= new_state; + radeonVtxfmtInvalidate( ctx ); +} + +static void radeonWrapRunPipeline( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + TNLcontext *tnl = TNL_CONTEXT(ctx); + + if (0) + fprintf(stderr, "%s, newstate: %x\n", __FUNCTION__, rmesa->NewGLState); + + /* Validate state: + */ + if (rmesa->NewGLState) + radeonValidateState( ctx ); + + if (tnl->vb.Material) { + TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_MATERIAL, GL_TRUE ); + } + + /* Run the pipeline. + */ + _tnl_run_pipeline( ctx ); + + if (tnl->vb.Material) { + TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_MATERIAL, GL_FALSE ); + radeonUpdateMaterial( ctx ); /* not needed any more? */ + } +} + + +/* Initialize the driver's state functions. + */ +void radeonInitStateFuncs( GLcontext *ctx ) +{ + ctx->Driver.UpdateState = radeonInvalidateState; + ctx->Driver.LightingSpaceChange = radeonLightingSpaceChange; + + ctx->Driver.DrawBuffer = radeonDrawBuffer; + ctx->Driver.ReadBuffer = radeonReadBuffer; + + ctx->Driver.AlphaFunc = radeonAlphaFunc; + ctx->Driver.BlendEquation = radeonBlendEquation; + ctx->Driver.BlendFunc = radeonBlendFunc; + ctx->Driver.BlendFuncSeparate = radeonBlendFuncSeparate; + ctx->Driver.ClearColor = radeonClearColor; + ctx->Driver.ClearDepth = radeonClearDepth; + ctx->Driver.ClearIndex = NULL; + ctx->Driver.ClearStencil = radeonClearStencil; + ctx->Driver.ClipPlane = radeonClipPlane; + ctx->Driver.ColorMask = radeonColorMask; + ctx->Driver.CullFace = radeonCullFace; + ctx->Driver.DepthFunc = radeonDepthFunc; + ctx->Driver.DepthMask = radeonDepthMask; + ctx->Driver.DepthRange = radeonDepthRange; + ctx->Driver.Enable = radeonEnable; + ctx->Driver.Fogfv = radeonFogfv; + ctx->Driver.FrontFace = radeonFrontFace; + ctx->Driver.Hint = NULL; + ctx->Driver.IndexMask = NULL; + ctx->Driver.LightModelfv = radeonLightModelfv; + ctx->Driver.Lightfv = radeonLightfv; + ctx->Driver.LineStipple = radeonLineStipple; + ctx->Driver.LineWidth = radeonLineWidth; + ctx->Driver.LogicOpcode = radeonLogicOpCode; + ctx->Driver.PolygonMode = radeonPolygonMode; + + if (RADEON_CONTEXT(ctx)->dri.drmMinor > 1) + ctx->Driver.PolygonOffset = radeonPolygonOffset; + + ctx->Driver.PolygonStipple = radeonPolygonStipple; + ctx->Driver.RenderMode = radeonRenderMode; + ctx->Driver.Scissor = radeonScissor; + ctx->Driver.ShadeModel = radeonShadeModel; + ctx->Driver.StencilFunc = radeonStencilFunc; + ctx->Driver.StencilMask = radeonStencilMask; + ctx->Driver.StencilOp = radeonStencilOp; + ctx->Driver.Viewport = radeonViewport; + + /* Pixel path fallbacks + */ + ctx->Driver.Accum = _swrast_Accum; + ctx->Driver.Bitmap = _swrast_Bitmap; + ctx->Driver.CopyPixels = _swrast_CopyPixels; + ctx->Driver.DrawPixels = _swrast_DrawPixels; + ctx->Driver.ReadPixels = _swrast_ReadPixels; + + /* Swrast hooks for imaging extensions: + */ + ctx->Driver.CopyColorTable = _swrast_CopyColorTable; + ctx->Driver.CopyColorSubTable = _swrast_CopyColorSubTable; + ctx->Driver.CopyConvolutionFilter1D = _swrast_CopyConvolutionFilter1D; + ctx->Driver.CopyConvolutionFilter2D = _swrast_CopyConvolutionFilter2D; + + TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange = radeonUpdateMaterial; + TNL_CONTEXT(ctx)->Driver.RunPipeline = radeonWrapRunPipeline; +} diff --git a/src/mesa/drivers/dri/radeon/radeon_state.h b/src/mesa/drivers/dri/radeon/radeon_state.h new file mode 100644 index 0000000000..a181d427e6 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_state.h @@ -0,0 +1,77 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_state.h,v 1.5 2002/11/05 17:46:09 tsi Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __RADEON_STATE_H__ +#define __RADEON_STATE_H__ + +#ifdef GLX_DIRECT_RENDERING + +#include "radeon_context.h" + +extern void radeonInitState( radeonContextPtr rmesa ); +extern void radeonInitStateFuncs( GLcontext *ctx ); + +extern void radeonUpdateMaterial( GLcontext *ctx ); + +extern void radeonSetCliprects( radeonContextPtr rmesa, GLenum mode ); +extern void radeonRecalcScissorRects( radeonContextPtr rmesa ); +extern void radeonUpdateViewportOffset( GLcontext *ctx ); +extern void radeonUpdateWindow( GLcontext *ctx ); + +extern void radeonValidateState( GLcontext *ctx ); + +extern void radeonPrintDirty( radeonContextPtr rmesa, + const char *msg ); + + +extern void radeonFallback( GLcontext *ctx, GLuint bit, GLboolean mode ); +#define FALLBACK( rmesa, bit, mode ) do { \ + if ( 0 ) fprintf( stderr, "FALLBACK in %s: #%d=%d\n", \ + __FUNCTION__, bit, mode ); \ + radeonFallback( rmesa->glCtx, bit, mode ); \ +} while (0) + + +#define MODEL_PROJ 0 +#define MODEL 1 +#define MODEL_IT 2 +#define TEXMAT_0 3 +#define TEXMAT_1 4 +#define TEXMAT_2 5 + +#endif +#endif diff --git a/src/mesa/drivers/dri/radeon/radeon_state_init.c b/src/mesa/drivers/dri/radeon/radeon_state_init.c new file mode 100644 index 0000000000..971ea699ea --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_state_init.c @@ -0,0 +1,531 @@ +/* $XFree86$ */ +/* + * Copyright 2000, 2001 VA Linux Systems Inc., Fremont, California. + * + * 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 + * VA LINUX SYSTEMS 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. + * + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "glheader.h" +#include "imports.h" +#include "api_arrayelt.h" + +#include "swrast/swrast.h" +#include "array_cache/acache.h" +#include "tnl/tnl.h" +#include "tnl/t_pipeline.h" +#include "swrast_setup/swrast_setup.h" + +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_state.h" +#include "radeon_tcl.h" +#include "radeon_tex.h" +#include "radeon_swtcl.h" +#include "radeon_vtxfmt.h" + +/* ============================================================= + * State initialization + */ + +void radeonPrintDirty( radeonContextPtr rmesa, const char *msg ) +{ + struct radeon_state_atom *l; + + fprintf(stderr, msg); + fprintf(stderr, ": "); + + foreach(l, &(rmesa->hw.dirty)) { + fprintf(stderr, "%s, ", l->name); + } + + fprintf(stderr, "\n"); +} + +static int cmdpkt( int id ) +{ + drmRadeonCmdHeader h; + h.i = 0; + h.packet.cmd_type = RADEON_CMD_PACKET; + h.packet.packet_id = id; + return h.i; +} + +static int cmdvec( int offset, int stride, int count ) +{ + drmRadeonCmdHeader h; + h.i = 0; + h.vectors.cmd_type = RADEON_CMD_VECTORS; + h.vectors.offset = offset; + h.vectors.stride = stride; + h.vectors.count = count; + return h.i; +} + +static int cmdscl( int offset, int stride, int count ) +{ + drmRadeonCmdHeader h; + h.i = 0; + h.scalars.cmd_type = RADEON_CMD_SCALARS; + h.scalars.offset = offset; + h.scalars.stride = stride; + h.scalars.count = count; + return h.i; +} + +#define CHECK( NM, FLAG ) \ +static GLboolean check_##NM( GLcontext *ctx ) \ +{ \ + return FLAG; \ +} + +#define TCL_CHECK( NM, FLAG ) \ +static GLboolean check_##NM( GLcontext *ctx ) \ +{ \ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \ + return !rmesa->TclFallback && (FLAG); \ +} + + +CHECK( always, GL_TRUE ) +CHECK( tex0, ctx->Texture.Unit[0]._ReallyEnabled ) +CHECK( tex1, ctx->Texture.Unit[1]._ReallyEnabled ) +CHECK( fog, ctx->Fog.Enabled ) +TCL_CHECK( tcl, GL_TRUE ) +TCL_CHECK( tcl_tex0, ctx->Texture.Unit[0]._ReallyEnabled ) +TCL_CHECK( tcl_tex1, ctx->Texture.Unit[1]._ReallyEnabled ) +TCL_CHECK( tcl_lighting, ctx->Light.Enabled ) +TCL_CHECK( tcl_eyespace_or_lighting, ctx->_NeedEyeCoords || ctx->Light.Enabled ) +TCL_CHECK( tcl_lit0, ctx->Light.Enabled && ctx->Light.Light[0].Enabled ) +TCL_CHECK( tcl_lit1, ctx->Light.Enabled && ctx->Light.Light[1].Enabled ) +TCL_CHECK( tcl_lit2, ctx->Light.Enabled && ctx->Light.Light[2].Enabled ) +TCL_CHECK( tcl_lit3, ctx->Light.Enabled && ctx->Light.Light[3].Enabled ) +TCL_CHECK( tcl_lit4, ctx->Light.Enabled && ctx->Light.Light[4].Enabled ) +TCL_CHECK( tcl_lit5, ctx->Light.Enabled && ctx->Light.Light[5].Enabled ) +TCL_CHECK( tcl_lit6, ctx->Light.Enabled && ctx->Light.Light[6].Enabled ) +TCL_CHECK( tcl_lit7, ctx->Light.Enabled && ctx->Light.Light[7].Enabled ) +TCL_CHECK( tcl_ucp0, (ctx->Transform.ClipPlanesEnabled & 0x1) ) +TCL_CHECK( tcl_ucp1, (ctx->Transform.ClipPlanesEnabled & 0x2) ) +TCL_CHECK( tcl_ucp2, (ctx->Transform.ClipPlanesEnabled & 0x4) ) +TCL_CHECK( tcl_ucp3, (ctx->Transform.ClipPlanesEnabled & 0x8) ) +TCL_CHECK( tcl_ucp4, (ctx->Transform.ClipPlanesEnabled & 0x10) ) +TCL_CHECK( tcl_ucp5, (ctx->Transform.ClipPlanesEnabled & 0x20) ) +TCL_CHECK( tcl_eyespace_or_fog, ctx->_NeedEyeCoords || ctx->Fog.Enabled ) + +CHECK( txr0, (ctx->Texture.Unit[0]._ReallyEnabled & TEXTURE_RECT_BIT)) +CHECK( txr1, (ctx->Texture.Unit[1]._ReallyEnabled & TEXTURE_RECT_BIT)) + + + +/* Initialize the context's hardware state. + */ +void radeonInitState( radeonContextPtr rmesa ) +{ + GLcontext *ctx = rmesa->glCtx; + GLuint color_fmt, depth_fmt, i; + + switch ( rmesa->radeonScreen->cpp ) { + case 2: + color_fmt = RADEON_COLOR_FORMAT_RGB565; + break; + case 4: + color_fmt = RADEON_COLOR_FORMAT_ARGB8888; + break; + default: + fprintf( stderr, "Error: Unsupported pixel depth... exiting\n" ); + exit( -1 ); + } + + rmesa->state.color.clear = 0x00000000; + + switch ( ctx->Visual.depthBits ) { + case 16: + rmesa->state.depth.clear = 0x0000ffff; + rmesa->state.depth.scale = 1.0 / (GLfloat)0xffff; + depth_fmt = RADEON_DEPTH_FORMAT_16BIT_INT_Z; + rmesa->state.stencil.clear = 0x00000000; + break; + case 24: + rmesa->state.depth.clear = 0x00ffffff; + rmesa->state.depth.scale = 1.0 / (GLfloat)0xffffff; + depth_fmt = RADEON_DEPTH_FORMAT_24BIT_INT_Z; + rmesa->state.stencil.clear = 0xff000000; + break; + default: + fprintf( stderr, "Error: Unsupported depth %d... exiting\n", + ctx->Visual.depthBits ); + exit( -1 ); + } + + /* Only have hw stencil when depth buffer is 24 bits deep */ + rmesa->state.stencil.hwBuffer = ( ctx->Visual.stencilBits > 0 && + ctx->Visual.depthBits == 24 ); + + rmesa->Fallback = 0; + + if ( ctx->Visual.doubleBufferMode && rmesa->sarea->pfCurrentPage == 0 ) { + rmesa->state.color.drawOffset = rmesa->radeonScreen->backOffset; + rmesa->state.color.drawPitch = rmesa->radeonScreen->backPitch; + } else { + rmesa->state.color.drawOffset = rmesa->radeonScreen->frontOffset; + rmesa->state.color.drawPitch = rmesa->radeonScreen->frontPitch; + } + rmesa->state.pixel.readOffset = rmesa->state.color.drawOffset; + rmesa->state.pixel.readPitch = rmesa->state.color.drawPitch; + + /* Initialize lists: + */ + make_empty_list(&(rmesa->hw.dirty)); + make_empty_list(&(rmesa->hw.clean)); + + +#define ALLOC_STATE( ATOM, CHK, SZ, NM, FLAG ) \ + do { \ + rmesa->hw.ATOM.cmd_size = SZ; \ + rmesa->hw.ATOM.cmd = (int *)CALLOC(SZ * sizeof(int)); \ + rmesa->hw.ATOM.lastcmd = (int *)CALLOC(SZ * sizeof(int)); \ + rmesa->hw.ATOM.name = NM; \ + rmesa->hw.ATOM.is_tcl = FLAG; \ + rmesa->hw.ATOM.check = check_##CHK; \ + insert_at_head(&(rmesa->hw.dirty), &(rmesa->hw.ATOM)); \ + } while (0) + + + /* Allocate state buffers: + */ + ALLOC_STATE( ctx, always, CTX_STATE_SIZE, "CTX/context", 0 ); + ALLOC_STATE( lin, always, LIN_STATE_SIZE, "LIN/line", 0 ); + ALLOC_STATE( msk, always, MSK_STATE_SIZE, "MSK/mask", 0 ); + ALLOC_STATE( vpt, always, VPT_STATE_SIZE, "VPT/viewport", 0 ); + ALLOC_STATE( set, always, SET_STATE_SIZE, "SET/setup", 0 ); + ALLOC_STATE( msc, always, MSC_STATE_SIZE, "MSC/misc", 0 ); + ALLOC_STATE( zbs, always, ZBS_STATE_SIZE, "ZBS/zbias", 0 ); + ALLOC_STATE( tcl, always, TCL_STATE_SIZE, "TCL/tcl", 1 ); + ALLOC_STATE( mtl, tcl_lighting, MTL_STATE_SIZE, "MTL/material", 1 ); + ALLOC_STATE( grd, always, GRD_STATE_SIZE, "GRD/guard-band", 1 ); + ALLOC_STATE( fog, fog, FOG_STATE_SIZE, "FOG/fog", 1 ); + ALLOC_STATE( glt, tcl_lighting, GLT_STATE_SIZE, "GLT/light-global", 1 ); + ALLOC_STATE( eye, tcl_lighting, EYE_STATE_SIZE, "EYE/eye-vector", 1 ); + ALLOC_STATE( tex[0], tex0, TEX_STATE_SIZE, "TEX/tex-0", 0 ); + ALLOC_STATE( tex[1], tex1, TEX_STATE_SIZE, "TEX/tex-1", 0 ); + ALLOC_STATE( mat[0], tcl, MAT_STATE_SIZE, "MAT/modelproject", 1 ); + ALLOC_STATE( mat[1], tcl_eyespace_or_fog, MAT_STATE_SIZE, "MAT/modelview", 1 ); + ALLOC_STATE( mat[2], tcl_eyespace_or_lighting, MAT_STATE_SIZE, "MAT/it-modelview", 1 ); + ALLOC_STATE( mat[3], tcl_tex0, MAT_STATE_SIZE, "MAT/texmat0", 1 ); + ALLOC_STATE( mat[4], tcl_tex1, MAT_STATE_SIZE, "MAT/texmat1", 1 ); + ALLOC_STATE( ucp[0], tcl_ucp0, UCP_STATE_SIZE, "UCP/userclip-0", 1 ); + ALLOC_STATE( ucp[1], tcl_ucp1, UCP_STATE_SIZE, "UCP/userclip-1", 1 ); + ALLOC_STATE( ucp[2], tcl_ucp2, UCP_STATE_SIZE, "UCP/userclip-2", 1 ); + ALLOC_STATE( ucp[3], tcl_ucp3, UCP_STATE_SIZE, "UCP/userclip-3", 1 ); + ALLOC_STATE( ucp[4], tcl_ucp4, UCP_STATE_SIZE, "UCP/userclip-4", 1 ); + ALLOC_STATE( ucp[5], tcl_ucp5, UCP_STATE_SIZE, "UCP/userclip-5", 1 ); + ALLOC_STATE( lit[0], tcl_lit0, LIT_STATE_SIZE, "LIT/light-0", 1 ); + ALLOC_STATE( lit[1], tcl_lit1, LIT_STATE_SIZE, "LIT/light-1", 1 ); + ALLOC_STATE( lit[2], tcl_lit2, LIT_STATE_SIZE, "LIT/light-2", 1 ); + ALLOC_STATE( lit[3], tcl_lit3, LIT_STATE_SIZE, "LIT/light-3", 1 ); + ALLOC_STATE( lit[4], tcl_lit4, LIT_STATE_SIZE, "LIT/light-4", 1 ); + ALLOC_STATE( lit[5], tcl_lit5, LIT_STATE_SIZE, "LIT/light-5", 1 ); + ALLOC_STATE( lit[6], tcl_lit6, LIT_STATE_SIZE, "LIT/light-6", 1 ); + ALLOC_STATE( lit[7], tcl_lit7, LIT_STATE_SIZE, "LIT/light-7", 1 ); + ALLOC_STATE( txr[0], txr0, TXR_STATE_SIZE, "TXR/txr-0", 0 ); + ALLOC_STATE( txr[1], txr1, TXR_STATE_SIZE, "TXR/txr-1", 0 ); + + + /* Fill in the packet headers: + */ + rmesa->hw.ctx.cmd[CTX_CMD_0] = cmdpkt(RADEON_EMIT_PP_MISC); + rmesa->hw.ctx.cmd[CTX_CMD_1] = cmdpkt(RADEON_EMIT_PP_CNTL); + rmesa->hw.ctx.cmd[CTX_CMD_2] = cmdpkt(RADEON_EMIT_RB3D_COLORPITCH); + rmesa->hw.lin.cmd[LIN_CMD_0] = cmdpkt(RADEON_EMIT_RE_LINE_PATTERN); + rmesa->hw.lin.cmd[LIN_CMD_1] = cmdpkt(RADEON_EMIT_SE_LINE_WIDTH); + rmesa->hw.msk.cmd[MSK_CMD_0] = cmdpkt(RADEON_EMIT_RB3D_STENCILREFMASK); + rmesa->hw.vpt.cmd[VPT_CMD_0] = cmdpkt(RADEON_EMIT_SE_VPORT_XSCALE); + rmesa->hw.set.cmd[SET_CMD_0] = cmdpkt(RADEON_EMIT_SE_CNTL); + rmesa->hw.set.cmd[SET_CMD_1] = cmdpkt(RADEON_EMIT_SE_CNTL_STATUS); + rmesa->hw.msc.cmd[MSC_CMD_0] = cmdpkt(RADEON_EMIT_RE_MISC); + rmesa->hw.tex[0].cmd[TEX_CMD_0] = cmdpkt(RADEON_EMIT_PP_TXFILTER_0); + rmesa->hw.tex[0].cmd[TEX_CMD_1] = cmdpkt(RADEON_EMIT_PP_BORDER_COLOR_0); + rmesa->hw.tex[1].cmd[TEX_CMD_0] = cmdpkt(RADEON_EMIT_PP_TXFILTER_1); + rmesa->hw.tex[1].cmd[TEX_CMD_1] = cmdpkt(RADEON_EMIT_PP_BORDER_COLOR_1); + rmesa->hw.zbs.cmd[ZBS_CMD_0] = cmdpkt(RADEON_EMIT_SE_ZBIAS_FACTOR); + rmesa->hw.tcl.cmd[TCL_CMD_0] = cmdpkt(RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT); + rmesa->hw.mtl.cmd[MTL_CMD_0] = + cmdpkt(RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED); + rmesa->hw.txr[0].cmd[TXR_CMD_0] = cmdpkt(RADEON_EMIT_PP_TEX_SIZE_0); + rmesa->hw.txr[1].cmd[TXR_CMD_0] = cmdpkt(RADEON_EMIT_PP_TEX_SIZE_1); + rmesa->hw.grd.cmd[GRD_CMD_0] = + cmdscl( RADEON_SS_VERT_GUARD_CLIP_ADJ_ADDR, 1, 4 ); + rmesa->hw.fog.cmd[FOG_CMD_0] = + cmdvec( RADEON_VS_FOG_PARAM_ADDR, 1, 4 ); + rmesa->hw.glt.cmd[GLT_CMD_0] = + cmdvec( RADEON_VS_GLOBAL_AMBIENT_ADDR, 1, 4 ); + rmesa->hw.eye.cmd[EYE_CMD_0] = + cmdvec( RADEON_VS_EYE_VECTOR_ADDR, 1, 4 ); + + for (i = 0 ; i < 5; i++) { + rmesa->hw.mat[i].cmd[MAT_CMD_0] = + cmdvec( RADEON_VS_MATRIX_0_ADDR + i*4, 1, 16); + } + + for (i = 0 ; i < 8; i++) { + rmesa->hw.lit[i].cmd[LIT_CMD_0] = + cmdvec( RADEON_VS_LIGHT_AMBIENT_ADDR + i, 8, 24 ); + rmesa->hw.lit[i].cmd[LIT_CMD_1] = + cmdscl( RADEON_SS_LIGHT_DCD_ADDR + i, 8, 6 ); + } + + for (i = 0 ; i < 6; i++) { + rmesa->hw.ucp[i].cmd[UCP_CMD_0] = + cmdvec( RADEON_VS_UCP_ADDR + i, 1, 4 ); + } + + rmesa->last_ReallyEnabled = -1; + + /* Initial Harware state: + */ + rmesa->hw.ctx.cmd[CTX_PP_MISC] = (RADEON_ALPHA_TEST_PASS | + RADEON_CHROMA_FUNC_FAIL | + RADEON_CHROMA_KEY_NEAREST | + RADEON_SHADOW_FUNC_EQUAL | + RADEON_SHADOW_PASS_1 | + RADEON_RIGHT_HAND_CUBE_OGL); + + rmesa->hw.ctx.cmd[CTX_PP_FOG_COLOR] = (RADEON_FOG_VERTEX | + RADEON_FOG_USE_DEPTH); + + rmesa->hw.ctx.cmd[CTX_RE_SOLID_COLOR] = 0x00000000; + + rmesa->hw.ctx.cmd[CTX_RB3D_BLENDCNTL] = (RADEON_COMB_FCN_ADD_CLAMP | + RADEON_SRC_BLEND_GL_ONE | + RADEON_DST_BLEND_GL_ZERO ); + + rmesa->hw.ctx.cmd[CTX_RB3D_DEPTHOFFSET] = + rmesa->radeonScreen->depthOffset; + + rmesa->hw.ctx.cmd[CTX_RB3D_DEPTHPITCH] = + ((rmesa->radeonScreen->depthPitch & + RADEON_DEPTHPITCH_MASK) | + RADEON_DEPTH_ENDIAN_NO_SWAP); + + rmesa->hw.ctx.cmd[CTX_RB3D_ZSTENCILCNTL] = (depth_fmt | + RADEON_Z_TEST_LESS | + RADEON_STENCIL_TEST_ALWAYS | + RADEON_STENCIL_FAIL_KEEP | + RADEON_STENCIL_ZPASS_KEEP | + RADEON_STENCIL_ZFAIL_KEEP | + RADEON_Z_WRITE_ENABLE); + + rmesa->hw.ctx.cmd[CTX_PP_CNTL] = (RADEON_SCISSOR_ENABLE | + RADEON_ANTI_ALIAS_NONE); + + rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] = (RADEON_PLANE_MASK_ENABLE | + color_fmt | + (1<<15)); + + rmesa->hw.ctx.cmd[CTX_RB3D_CNTL] |= RADEON_DITHER_ENABLE; + + rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] = (rmesa->state.color.drawOffset & + RADEON_COLOROFFSET_MASK); + + rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = ((rmesa->state.color.drawPitch & + RADEON_COLORPITCH_MASK) | + RADEON_COLOR_ENDIAN_NO_SWAP); + + rmesa->hw.set.cmd[SET_SE_CNTL] = (RADEON_FFACE_CULL_CCW | + RADEON_BFACE_SOLID | + RADEON_FFACE_SOLID | +/* RADEON_BADVTX_CULL_DISABLE | */ + RADEON_FLAT_SHADE_VTX_LAST | + RADEON_DIFFUSE_SHADE_GOURAUD | + RADEON_ALPHA_SHADE_GOURAUD | + RADEON_SPECULAR_SHADE_GOURAUD | + RADEON_FOG_SHADE_GOURAUD | + RADEON_VPORT_XY_XFORM_ENABLE | + RADEON_VPORT_Z_XFORM_ENABLE | + RADEON_VTX_PIX_CENTER_OGL | + RADEON_ROUND_MODE_TRUNC | + RADEON_ROUND_PREC_8TH_PIX); + + rmesa->hw.set.cmd[SET_SE_CNTL_STATUS] = +#ifdef MESA_BIG_ENDIAN + RADEON_VC_32BIT_SWAP; +#else + RADEON_VC_NO_SWAP; +#endif + + if (!(rmesa->radeonScreen->chipset & RADEON_CHIPSET_TCL)) { + rmesa->hw.set.cmd[SET_SE_CNTL_STATUS] |= RADEON_TCL_BYPASS; + } + + rmesa->hw.set.cmd[SET_SE_COORDFMT] = ( + RADEON_VTX_W0_IS_NOT_1_OVER_W0 | + RADEON_TEX1_W_ROUTING_USE_Q1); + + + rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] = ((1 << 16) | 0xffff); + + rmesa->hw.lin.cmd[LIN_RE_LINE_STATE] = + ((0 << RADEON_LINE_CURRENT_PTR_SHIFT) | + (1 << RADEON_LINE_CURRENT_COUNT_SHIFT)); + + rmesa->hw.lin.cmd[LIN_SE_LINE_WIDTH] = (1 << 4); + + rmesa->hw.msk.cmd[MSK_RB3D_STENCILREFMASK] = + ((0x00 << RADEON_STENCIL_REF_SHIFT) | + (0xff << RADEON_STENCIL_MASK_SHIFT) | + (0xff << RADEON_STENCIL_WRITEMASK_SHIFT)); + + rmesa->hw.msk.cmd[MSK_RB3D_ROPCNTL] = RADEON_ROP_COPY; + rmesa->hw.msk.cmd[MSK_RB3D_PLANEMASK] = 0xffffffff; + + rmesa->hw.msc.cmd[MSC_RE_MISC] = + ((0 << RADEON_STIPPLE_X_OFFSET_SHIFT) | + (0 << RADEON_STIPPLE_Y_OFFSET_SHIFT) | + RADEON_STIPPLE_BIG_BIT_ORDER); + + rmesa->hw.vpt.cmd[VPT_SE_VPORT_XSCALE] = 0x00000000; + rmesa->hw.vpt.cmd[VPT_SE_VPORT_XOFFSET] = 0x00000000; + rmesa->hw.vpt.cmd[VPT_SE_VPORT_YSCALE] = 0x00000000; + rmesa->hw.vpt.cmd[VPT_SE_VPORT_YOFFSET] = 0x00000000; + rmesa->hw.vpt.cmd[VPT_SE_VPORT_ZSCALE] = 0x00000000; + rmesa->hw.vpt.cmd[VPT_SE_VPORT_ZOFFSET] = 0x00000000; + + for ( i = 0 ; i < ctx->Const.MaxTextureUnits ; i++ ) { + rmesa->hw.tex[i].cmd[TEX_PP_TXFILTER] = RADEON_BORDER_MODE_OGL; + rmesa->hw.tex[i].cmd[TEX_PP_TXFORMAT] = + (RADEON_TXFORMAT_ENDIAN_NO_SWAP | + RADEON_TXFORMAT_PERSPECTIVE_ENABLE | + (i << 24) | /* This is one of RADEON_TXFORMAT_ST_ROUTE_STQ[012] */ + (2 << RADEON_TXFORMAT_WIDTH_SHIFT) | + (2 << RADEON_TXFORMAT_HEIGHT_SHIFT)); + + /* FIXME: What is this magic value? */ + rmesa->hw.tex[i].cmd[TEX_PP_TXOFFSET] = 0x2000 << (2 * i); + + rmesa->hw.tex[i].cmd[TEX_PP_BORDER_COLOR] = 0; + rmesa->hw.tex[i].cmd[TEX_PP_TXCBLEND] = + (RADEON_COLOR_ARG_A_ZERO | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_CURRENT_COLOR | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX); + rmesa->hw.tex[i].cmd[TEX_PP_TXABLEND] = + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_CURRENT_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX); + rmesa->hw.tex[i].cmd[TEX_PP_TFACTOR] = 0; + } + + /* Can only add ST1 at the time of doing some multitex but can keep + * it after that. Errors if DIFFUSE is missing. + */ + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] = + (RADEON_TCL_VTX_Z0 | + RADEON_TCL_VTX_W0 | + RADEON_TCL_VTX_PK_DIFFUSE + ); /* need to keep this uptodate */ + + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXSEL] = + ( RADEON_TCL_COMPUTE_XYZW | + (RADEON_TCL_TEX_INPUT_TEX_0 << RADEON_TCL_TEX_0_OUTPUT_SHIFT) | + (RADEON_TCL_TEX_INPUT_TEX_1 << RADEON_TCL_TEX_1_OUTPUT_SHIFT) | + (RADEON_TCL_TEX_INPUT_TEX_2 << RADEON_TCL_TEX_2_OUTPUT_SHIFT)); + + + /* XXX */ + rmesa->hw.tcl.cmd[TCL_MATRIX_SELECT_0] = + ((MODEL << RADEON_MODELVIEW_0_SHIFT) | + (MODEL_IT << RADEON_IT_MODELVIEW_0_SHIFT)); + + rmesa->hw.tcl.cmd[TCL_MATRIX_SELECT_1] = + ((MODEL_PROJ << RADEON_MODELPROJECT_0_SHIFT) | + (TEXMAT_0 << RADEON_TEXMAT_0_SHIFT) | + (TEXMAT_1 << RADEON_TEXMAT_1_SHIFT)); + + rmesa->hw.tcl.cmd[TCL_UCP_VERT_BLEND_CTL] = + (RADEON_UCP_IN_CLIP_SPACE | + RADEON_CULL_FRONT_IS_CCW); + + rmesa->hw.tcl.cmd[TCL_TEXTURE_PROC_CTL] = 0; + + rmesa->hw.tcl.cmd[TCL_LIGHT_MODEL_CTL] = + (RADEON_SPECULAR_LIGHTS | + RADEON_DIFFUSE_SPECULAR_COMBINE | + RADEON_LOCAL_LIGHT_VEC_GL | + (RADEON_LM_SOURCE_STATE_PREMULT << RADEON_EMISSIVE_SOURCE_SHIFT) | + (RADEON_LM_SOURCE_STATE_PREMULT << RADEON_AMBIENT_SOURCE_SHIFT) | + (RADEON_LM_SOURCE_STATE_PREMULT << RADEON_DIFFUSE_SOURCE_SHIFT) | + (RADEON_LM_SOURCE_STATE_PREMULT << RADEON_SPECULAR_SOURCE_SHIFT)); + + for (i = 0 ; i < 8; i++) { + struct gl_light *l = &ctx->Light.Light[i]; + GLenum p = GL_LIGHT0 + i; + *(float *)&(rmesa->hw.lit[i].cmd[LIT_RANGE_CUTOFF]) = FLT_MAX; + + ctx->Driver.Lightfv( ctx, p, GL_AMBIENT, l->Ambient ); + ctx->Driver.Lightfv( ctx, p, GL_DIFFUSE, l->Diffuse ); + ctx->Driver.Lightfv( ctx, p, GL_SPECULAR, l->Specular ); + ctx->Driver.Lightfv( ctx, p, GL_POSITION, 0 ); + ctx->Driver.Lightfv( ctx, p, GL_SPOT_DIRECTION, 0 ); + ctx->Driver.Lightfv( ctx, p, GL_SPOT_EXPONENT, &l->SpotExponent ); + ctx->Driver.Lightfv( ctx, p, GL_SPOT_CUTOFF, &l->SpotCutoff ); + ctx->Driver.Lightfv( ctx, p, GL_CONSTANT_ATTENUATION, + &l->ConstantAttenuation ); + ctx->Driver.Lightfv( ctx, p, GL_LINEAR_ATTENUATION, + &l->LinearAttenuation ); + ctx->Driver.Lightfv( ctx, p, GL_QUADRATIC_ATTENUATION, + &l->QuadraticAttenuation ); + } + + ctx->Driver.LightModelfv( ctx, GL_LIGHT_MODEL_AMBIENT, + ctx->Light.Model.Ambient ); + + TNL_CONTEXT(ctx)->Driver.NotifyMaterialChange( ctx ); + + for (i = 0 ; i < 6; i++) { + ctx->Driver.ClipPlane( ctx, GL_CLIP_PLANE0 + i, NULL ); + } + + 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.Fogfv( ctx, GL_FOG_COLOR, ctx->Fog.Color ); + ctx->Driver.Fogfv( ctx, GL_FOG_COORDINATE_SOURCE_EXT, 0 ); + + rmesa->hw.grd.cmd[GRD_VERT_GUARD_CLIP_ADJ] = IEEE_ONE; + rmesa->hw.grd.cmd[GRD_VERT_GUARD_DISCARD_ADJ] = IEEE_ONE; + rmesa->hw.grd.cmd[GRD_HORZ_GUARD_CLIP_ADJ] = IEEE_ONE; + rmesa->hw.grd.cmd[GRD_HORZ_GUARD_DISCARD_ADJ] = IEEE_ONE; + + rmesa->hw.eye.cmd[EYE_X] = 0; + rmesa->hw.eye.cmd[EYE_Y] = 0; + rmesa->hw.eye.cmd[EYE_Z] = IEEE_ONE; + rmesa->hw.eye.cmd[EYE_RESCALE_FACTOR] = IEEE_ONE; +} diff --git a/src/mesa/drivers/dri/radeon/radeon_subset.h b/src/mesa/drivers/dri/radeon/radeon_subset.h new file mode 100644 index 0000000000..1b6e7bd432 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_subset.h @@ -0,0 +1,75 @@ +/** + * \file radeon_subset.h + * \brief Radeon subset driver declarations. + * + * \author Keith Whitwell <keith@tungstengraphics.com> + */ + +/* + * Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + * Tungsten Grahpics Inc., Austin, 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, TUNGSTEN GRAHPICS 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$ */ + +#ifndef __RADEON_SUBSET_H__ +#define __RADEON_SUBSET_H__ + +extern void radeonPointsBitmap( GLsizei width, GLsizei height, + GLfloat xorig, GLfloat yorig, + GLfloat xmove, GLfloat ymove, + const GLubyte *bitmap ); + +extern void radeonReadPixels( GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + GLvoid *pixels ); + +extern void radeon_select_Install( GLcontext *ctx ); + +extern void radeonInitSelect( GLcontext *ctx ); + +extern void radeonVtxfmtDestroy( GLcontext *ctx ); + +extern void radeonVtxfmtMakeCurrent( GLcontext *ctx ); + +extern void radeonVtxfmtUnbindContext( GLcontext *ctx ); + +extern void radeonVtxfmtInit( GLcontext *ctx ); + +extern void radeonTclFallback( GLcontext *ctx, GLuint bit, GLboolean mode ); + +extern void radeonVtxfmtInvalidate( GLcontext *ctx ); + +extern void radeonSubsetVtxEnableTCL( radeonContextPtr rmesa, GLboolean flag ); + +extern void radeonUpdateTextureState( GLcontext *ctx ); + +extern void radeonInitTextureFuncs( GLcontext *ctx ); + +extern void radeonAgeTextures( radeonContextPtr rmesa, int heap ); + +extern void radeonDestroyTexObj( radeonContextPtr rmesa, radeonTexObjPtr t ); + +#endif diff --git a/src/mesa/drivers/dri/radeon/radeon_subset_bitmap.c b/src/mesa/drivers/dri/radeon/radeon_subset_bitmap.c new file mode 100644 index 0000000000..cb4a514221 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_subset_bitmap.c @@ -0,0 +1,197 @@ +/** + * \file radeon_subset_bitmap.c + * \brief Bitmap drawing. + * + * \author Keith Whitwell <keith@tungstengraphics.com> + */ + +/* + * Copyright 2003 ATI Technologies Inc., Ontario, Canada, and + * 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, TUNGSTEN GRAPHICS 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$ */ + +#include "glheader.h" +#include "mtypes.h" +#include "colormac.h" +#include "context.h" +#include "enums.h" +#include "imports.h" +#include "image.h" +/*#include "mmath.h"*/ +#include "macros.h" +#include "state.h" + +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_state.h" +#include "radeon_subset.h" + +/** + * \brief Cope with depth operations by drawing individual pixels as points + * + * \param xorig x coordinate of the bitmap corner. + * \param yorig y coordinate of the bitmap corner. + * \param xmove increment to the final x coordinate. + * \param ymove increment to the final y coordinate. + * \param width bitmap width. + * \param height bitmap height. + * \param bitmap bitmap pointer. + * + * Clips the bitmap coordinates and adjusts for windows coordinates. Draws the + * bitmap with glPoints(), turning off TCL and hardware viewport transformation + * to emit raw pixel coordinates. Finally fires any outstanding vertices and + * restores TCL, viewport, texture and color states. + */ +void +radeonPointsBitmap( GLsizei width, GLsizei height, + GLfloat xorig, GLfloat yorig, + GLfloat xmove, GLfloat ymove, + const GLubyte *bitmap ) +{ + GET_CURRENT_CONTEXT(ctx); + GLsizei bmwidth = width, bmheight = height; + GLint px, py; + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat saved_color[4], saved_tex0[2]; + GLint row, col; + GLuint orig_se_cntl; + GLuint w, h; + const struct gl_pixelstore_attrib *unpack = &ctx->Unpack; + + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + if (width < 0 || height < 0) { + _mesa_error( ctx, GL_INVALID_VALUE, "glBitmap(width or height < 0)" ); + return; + } + + if (!ctx->Current.RasterPosValid) + return; + + if (ctx->NewState) + _mesa_update_state(ctx); + + + if (ctx->_RotateMode) { + width = bmheight; height = bmwidth; + + px = IFLOOR(ctx->Current.RasterPos[0] + yorig); + py = IFLOOR(ctx->Current.RasterPos[1] + xorig); + + ctx->Current.RasterPos[0] += ymove; + ctx->Current.RasterPos[1] += xmove; + } + else { + px = IFLOOR(ctx->Current.RasterPos[0] - xorig); + py = IFLOOR(ctx->Current.RasterPos[1] - yorig); + + ctx->Current.RasterPos[0] += xmove; + ctx->Current.RasterPos[1] += ymove; + } + + + + /* Turn off tcl and the hw viewport transformation so that we can + * emit raw pixel coordinates: + */ + radeonSubsetVtxEnableTCL( rmesa, GL_FALSE ); + RADEON_STATECHANGE( rmesa, set ); + orig_se_cntl = rmesa->hw.set.cmd[SET_SE_CNTL]; + rmesa->hw.set.cmd[SET_SE_CNTL] &= ~(RADEON_VPORT_XY_XFORM_ENABLE | + RADEON_VPORT_Z_XFORM_ENABLE); + + + /* Adjust for window coordinates, flip y values: + */ + h = rmesa->dri.drawable->h + rmesa->dri.drawable->y - 1; + w = rmesa->dri.drawable->w; + px += rmesa->dri.drawable->x; + + /* Save current color, texcoord to restore later: + */ + COPY_4V( saved_color, ctx->Current.Attrib[VERT_ATTRIB_COLOR0] ); + COPY_2V( saved_tex0, ctx->Current.Attrib[VERT_ATTRIB_TEX0] ); + + /* Just use the GL entrypoints to talk to radeon_subset_vtx.c: + */ + glBegin( GL_POINTS ); + glColor4fv( ctx->Current.RasterColor ); + glTexCoord2fv( ctx->Current.RasterTexCoords[0] ); + + + if (ctx->_RotateMode) { + for (col=0; col<width; col++) { + const GLubyte *src = (const GLubyte *) + _mesa_image_address( unpack, bitmap, height, width, + GL_COLOR_INDEX, GL_BITMAP, 0, col, 0 ); + + /* Msb first */ + GLubyte mask = 128U >> (unpack->SkipPixels & 0x7); + for (row=0; row<height; row++) { + if (*src & mask) { + glVertex2f( px-col, h - (py + row) ); + } + src += mask & 1; + mask = ((mask << 7) & 0xff) | (mask >> 1); + } + /* get ready for next row */ + if (mask != 128) + src++; + } + } + else { + for (row=0; row<height; row++) { + const GLubyte *src = (const GLubyte *) + _mesa_image_address( unpack, bitmap, width, height, + GL_COLOR_INDEX, GL_BITMAP, 0, row, 0 ); + + /* Msb first */ + GLubyte mask = 128U >> (unpack->SkipPixels & 0x7); + for (col=0; col<width; col++) { + if (*src & mask) { + glVertex2f( px+col, h - (py + row) ); + } + src += mask & 1; + mask = ((mask << 7) & 0xff) | (mask >> 1); + } + /* get ready for next row */ + if (mask != 128) + src++; + } + } + + glEnd(); + glColor4fv( saved_color ); + glTexCoord2fv( saved_tex0 ); + + /* Fire outstanding vertices, restore state + */ + RADEON_STATECHANGE( rmesa, set ); + rmesa->hw.set.cmd[SET_SE_CNTL] = orig_se_cntl; + radeonSubsetVtxEnableTCL( rmesa, GL_TRUE ); +} + diff --git a/src/mesa/drivers/dri/radeon/radeon_subset_readpix.c b/src/mesa/drivers/dri/radeon/radeon_subset_readpix.c new file mode 100644 index 0000000000..f72d3b8472 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_subset_readpix.c @@ -0,0 +1,246 @@ +/** + * \file radeon_subset_readpix.c + * \brief Pixel reading. + * + * \author Keith Whitwell <keith@tungstengraphics.com> + * \author Brian Paul <brian@tungstengraphics.com> + */ + +/* + * Copyright 2003 ATI Technologies Inc., Ontario, Canada, and + * 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, TUNGSTEN GRAPHICS 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$ */ + +#include "glheader.h" +#include "mtypes.h" +#include "colormac.h" +#include "context.h" +#include "enums.h" +#include "imports.h" +/*#include "mmath.h" */ +#include "macros.h" +#include "state.h" + +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_state.h" +#include "radeon_subset.h" + +/** + * \brief Read pixel in RGBA format on a Radeon 16bpp frame buffer. + * + * \param rgba destination pointer. + * \param ptr pointer to the pixel in the frame buffer. + */ +#define READ_RGBA_16( rgba, ptr ) \ +do { \ + GLushort p = *(GLushort *)ptr; \ + rgba[0] = ((p >> 8) & 0xf8) * 255 / 0xf8; \ + rgba[1] = ((p >> 3) & 0xfc) * 255 / 0xfc; \ + rgba[2] = ((p << 3) & 0xf8) * 255 / 0xf8; \ + rgba[3] = 0xff; \ +} while (0) + +/** + * \brief Read pixel in RGBA format on a Radeon 32bpp frame buffer. + * + * \param rgba destination pointer. + * \param ptr pointer to the pixel in the frame buffer. + */ +#define READ_RGBA_32( rgba, ptr ) \ +do { \ + GLuint p = *(GLuint *)ptr; \ + rgba[0] = (p >> 16) & 0xff; \ + rgba[1] = (p >> 8) & 0xff; \ + rgba[2] = (p >> 0) & 0xff; \ + rgba[3] = (p >> 24) & 0xff; \ +} while (0) + +/** + * \brief Read a span in RGBA format. + * + * \param ctx GL context. + * \param n number of pixels in the span. + * \param x x position of the span start. + * \param y y position of the span. + * \param rgba destination buffer. + * + * Calculates the pointer to the span start in the frame buffer and uses either + * #READ_RGBA_16 or #READ_RGBA_32 macros to copy the values. + */ +static void ReadRGBASpan( const GLcontext *ctx, + GLuint n, GLint x, GLint y, + GLubyte rgba[][4]) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeonScreenPtr radeonScreen = rmesa->radeonScreen; + __DRIdrawablePrivate *dPriv = rmesa->dri.drawable; + GLuint cpp = radeonScreen->cpp; + GLuint pitch = radeonScreen->frontPitch * cpp; + GLint i; + + if (ctx->_RotateMode) { + char *ptr = (char *)(rmesa->dri.screen->pFB + + rmesa->state.pixel.readOffset + + ((dPriv->x + (dPriv->w - y - 1)) * cpp) + + ((dPriv->y + (dPriv->h - x - 1)) * pitch)); + + if (cpp == 4) + for (i = 0; i < n; i++, ptr -= pitch) + READ_RGBA_32( rgba[i], ptr ); + else + for (i = 0; i < n; i++, ptr -= pitch) + READ_RGBA_16( rgba[i], ptr ); + } + else { + char *ptr = (char *)(rmesa->dri.screen->pFB + + rmesa->state.pixel.readOffset + + ((dPriv->x + x) * cpp) + + ((dPriv->y + (dPriv->h - y - 1)) * pitch)); + + if (cpp == 4) + for (i = 0; i < n; i++, ptr += cpp) + READ_RGBA_32( rgba[i], ptr ); + else + for (i = 0; i < n; i++, ptr += cpp) + READ_RGBA_16( rgba[i], ptr ); + } +} + + +/** + * \brief Optimized glReadPixels(). + * + * To be used with particular pixel formats GL_UNSIGNED_BYTE and GL_RGBA, when pixel + * scaling, biasing and mapping are disabled. + * + * \param x x start position of the reading rectangle. + * \param y y start position of the reading rectangle. + * \param width width of the reading rectangle. + * \param height height of the reading rectangle. + * \param format pixel format. Must be GL_RGBA. + * \param type pixel type. Must be GL_UNSIGNED_BYTE. + * \param pixels pixel data. + * + * After asserting the above conditions, compensates for clipping and calls + * ReadRGBASpan() to read each row. + */ +void radeonReadPixels( GLint x, GLint y, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + GLvoid *pixels ) +{ + GET_CURRENT_CONTEXT(ctx); + GLint srcX = x; + GLint srcY = y; + GLint readWidth = width; /* actual width read */ + GLint readHeight = height; /* actual height read */ + const struct gl_pixelstore_attrib *packing = &ctx->Pack; + GLint skipRows = packing->SkipRows; + GLint skipPixels = packing->SkipPixels; + GLint rowLength; + ASSERT_OUTSIDE_BEGIN_END_AND_FLUSH(ctx); + + { + GLint tmp, tmps; + tmp = x; x = y; y = tmp; + tmps = width; width = height; height = tmps; + } + + if (width < 0 || height < 0) { + _mesa_error( ctx, GL_INVALID_VALUE, + "glReadPixels(width=%d height=%d)", width, height ); + return; + } + + if (!pixels) { + _mesa_error( ctx, GL_INVALID_VALUE, "glReadPixels(pixels)" ); + return; + } + + if (ctx->NewState) + _mesa_update_state(ctx); + + + /* can't do scale, bias, mapping, etc */ + assert(!ctx->_ImageTransferState); + + /* can't do fancy pixel packing */ + assert (packing->Alignment == 1 && + !packing->SwapBytes && + !packing->LsbFirst); + + + if (packing->RowLength > 0) + rowLength = packing->RowLength; + else + rowLength = width; + + /* horizontal clipping */ + if (srcX < 0) { + skipPixels -= srcX; + readWidth += srcX; + srcX = 0; + } + if (srcX + readWidth > (GLint) ctx->ReadBuffer->Width) + readWidth -= (srcX + readWidth - (GLint) ctx->ReadBuffer->Width); + if (readWidth <= 0) + return; + + /* vertical clipping */ + if (srcY < 0) { + skipRows -= srcY; + readHeight += srcY; + srcY = 0; + } + if (srcY + readHeight > (GLint) ctx->ReadBuffer->Height) + readHeight -= (srcY + readHeight - (GLint) ctx->ReadBuffer->Height); + if (readHeight <= 0) + return; + + /* + * Ready to read! + * The window region at (destX, destY) of size (readWidth, readHeight) + * will be read back. + * We'll write pixel data to buffer pointed to by "pixels" but we'll + * skip "skipRows" rows and skip "skipPixels" pixels/row. + */ + if (format == GL_RGBA && type == GL_UNSIGNED_BYTE) { + GLchan *dest = (GLchan *) pixels + + (skipRows * rowLength + skipPixels) * 4; + GLint row; + + for (row=0; row<readHeight; row++) { + ReadRGBASpan(ctx, readWidth, srcX, srcY, (GLchan (*)[4]) dest); + dest += rowLength * 4; + srcY++; + } + } + else { + /* can't do this format/type combination */ + assert(0); + } +} diff --git a/src/mesa/drivers/dri/radeon/radeon_subset_select.c b/src/mesa/drivers/dri/radeon/radeon_subset_select.c new file mode 100644 index 0000000000..bd5003ffe5 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_subset_select.c @@ -0,0 +1,998 @@ +/** + * \file radeon_subset_select.c + * \brief Selection. + */ + +/* + * Mesa 3-D graphics library + * Version: 4.1 + * + * Copyright (C) 1999-2002 Brian Paul 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, sublicense, + * 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 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 NONINFRINGEMENT. IN NO EVENT SHALL + * BRIAN PAUL 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. + */ + +/* $Id: radeon_subset_select.c,v 1.2 2003/08/22 20:11:45 brianp Exp $ */ + + +#include "glheader.h" +#include "imports.h" +#include "context.h" +/*#include "mmath.h"*/ +#include "mtypes.h" +#include "enums.h" +#include "glapi.h" +#include "feedback.h" + +#include "radeon_context.h" +#include "radeon_subset.h" + +/** + * \brief Vertex. + */ +typedef struct { + struct { GLfloat x, y, z, w; } pos; /**< \brief position */ + struct { GLfloat x, y, z, w; } eyePos; /**< \brief position, eye coordinates */ + struct { GLfloat x, y, z, w; } clipPos; /**< \brief clipped coordinates */ + struct { GLfloat x, y, z, w; } winPos; /**< \brief position, windows coordinates */ + struct { GLfloat s, t; } texCoord; /**< \brief texture coordinates */ + struct { GLfloat r, g, b, a; } color; /**< \brief color */ +} vertex; + + +/** + * \brief Vertex buffer. + */ +static struct select_vb_t { + GLuint vCount; /**< \brief vertex count */ + vertex vBuffer[4]; /**< \brief vertex buffer */ + GLboolean lineReset; + GLboolean partialLineLoop; /**< \brief whether we are in a middle of a line loop */ +} vb; + + + + +/**********************************************************************/ +/** \name Vertex Transformation and Clipping */ +/**********************************************************************/ +/*@{*/ + +/** + * \brief Transform a point (column vector) by a matrix: Q = M * P. + * + * \param Q destination point. + * \param P source point. + * \param M transformation matrix. + */ +#define TRANSFORM_POINT( Q, M, P ) \ + Q.x = M[0] * P.x + M[4] * P.y + M[8] * P.z + M[12] * P.w; \ + Q.y = M[1] * P.x + M[5] * P.y + M[9] * P.z + M[13] * P.w; \ + Q.z = M[2] * P.x + M[6] * P.y + M[10] * P.z + M[14] * P.w; \ + Q.w = M[3] * P.x + M[7] * P.y + M[11] * P.z + M[15] * P.w; + +/** + * \brief Clip coord to window coord mapping. + * + * \param Q destination point. + * \param P source point. + * \param VP view port. + */ +#define MAP_POINT( Q, P, VP ) \ + Q.x = (GLfloat) (((P.x / P.w) + 1.0) * VP.Width / 2.0 + VP.X); \ + Q.y = (GLfloat) (((P.y / P.w) + 1.0) * VP.Height / 2.0 + VP.Y); \ + Q.z = (GLfloat) (((P.z / P.w) + 1.0) * (VP.Far - VP.Near) / 2.0 + VP.Near);\ + Q.w = (GLfloat) P.w; + + +/** + * \brief Linear interpolation: (1 - T) * A + T * B. + * + * \param T interpolation factor. + * \param A first value. + * \param B second value. + * \result interpolated value. + */ +#define INTERPOLATE(T, A, B) ((A) + ((B) - (A)) * (T)) + + + +/** + * \brief Interpolate vertex position, color, texcoords, etc. + * + * \param t interpolation factor. + * \param v0 first vertex. + * \param v1 second vertex. + * \param vOut output vertex. + * + * Uses the #INTERPOLATE macro for all the interpolation of all elements. + */ +static void +interpolate_vertex(GLfloat t, const vertex *v0, const vertex *v1, + vertex *vOut) +{ + vOut->eyePos.x = INTERPOLATE(t, v0->eyePos.x, v1->eyePos.x); + vOut->eyePos.y = INTERPOLATE(t, v0->eyePos.y, v1->eyePos.y); + vOut->eyePos.z = INTERPOLATE(t, v0->eyePos.z, v1->eyePos.z); + vOut->eyePos.w = INTERPOLATE(t, v0->eyePos.w, v1->eyePos.w); + + vOut->clipPos.x = INTERPOLATE(t, v0->clipPos.x, v1->clipPos.x); + vOut->clipPos.y = INTERPOLATE(t, v0->clipPos.y, v1->clipPos.y); + vOut->clipPos.z = INTERPOLATE(t, v0->clipPos.z, v1->clipPos.z); + vOut->clipPos.w = INTERPOLATE(t, v0->clipPos.w, v1->clipPos.w); + + vOut->color.r = INTERPOLATE(t, v0->color.r, v1->color.r); + vOut->color.g = INTERPOLATE(t, v0->color.g, v1->color.g); + vOut->color.b = INTERPOLATE(t, v0->color.b, v1->color.b); + vOut->color.a = INTERPOLATE(t, v0->color.a, v1->color.a); + + vOut->texCoord.s = INTERPOLATE(t, v0->texCoord.s, v1->texCoord.s); + vOut->texCoord.t = INTERPOLATE(t, v0->texCoord.t, v1->texCoord.t); +} + + + + +/* + * Clip bit codes + */ +#define CLIP_LEFT 1 +#define CLIP_RIGHT 2 +#define CLIP_BOTTOM 4 +#define CLIP_TOP 8 +#define CLIP_NEAR 16 +#define CLIP_FAR 32 + + +/** + * \brief Apply view volume clip testing to a point. + * + * \param v point to test. + * \return zero if visible, or the clip code mask, i.e., binary OR of a + * combination of the #CLIP_LEFT, #CLIP_RIGHT, #CLIP_BOTTOM, #CLIP_TOP, #CLIP_NEAR, + * #CLIP_FAR clip bit codes. + */ +static GLuint +clip_point(const vertex *v) +{ + GLuint mask = 0; + if (v->clipPos.x > v->clipPos.w) mask |= CLIP_RIGHT; + if (v->clipPos.x < -v->clipPos.w) mask |= CLIP_LEFT; + if (v->clipPos.y > v->clipPos.w) mask |= CLIP_TOP; + if (v->clipPos.y < -v->clipPos.w) mask |= CLIP_BOTTOM; + if (v->clipPos.z > v->clipPos.w) mask |= CLIP_FAR; + if (v->clipPos.z < -v->clipPos.w) mask |= CLIP_NEAR; + return mask; +} + + +/** + * \def GENERAL_CLIP + * \brief Clipping utility macro. + * + * We use 6 instances of this code in each of the clip_line() and + * clip_polygon() to clip against the 6 planes. For each plane, we define the + * #OUTSIDE and #COMPUTE_INTERSECTION macros appropriately. + */ + + +/** + * \brief Apply clipping to a line segment. + * + * \param v0in input start vertex + * \param v1in input end vertesx + * \param v0new output start vertex + * \param v1new output end vertex + * + * \return GL_TRUE if the line segment is visible, or GL_FALSE if it is totally + * clipped. + * + * \sa #GENERAL_CLIP. + */ +static GLboolean +clip_line(const vertex *v0in, const vertex *v1in, + vertex *v0new, vertex *v1new) +{ + vertex v0, v1, vNew; + GLfloat dx, dy, dz, dw, t; + GLuint code0, code1; + + code0 = clip_point(v0in); + code1 = clip_point(v1in); + if (code0 & code1) + return GL_FALSE; /* totally clipped */ + + *v0new = *v0in; + *v1new = *v1in; + if (code0 == 0 && code1 == 0) + return GL_TRUE; /* no clipping needed */ + + v0 = *v0in; + v1 = *v1in; + + +#define GENERAL_CLIP \ + if (OUTSIDE(v0)) { \ + if (OUTSIDE(v1)) { \ + /* both verts are outside ==> return 0 */ \ + return 0; \ + } \ + else { \ + /* v0 is outside, v1 is inside ==> clip */ \ + COMPUTE_INTERSECTION( v1, v0, vNew ) \ + interpolate_vertex(t, &v1, &v0, &vNew); \ + v0 = vNew; \ + } \ + } \ + else { \ + if (OUTSIDE(v1)) { \ + /* v0 is inside, v1 is outside ==> clip */ \ + COMPUTE_INTERSECTION( v0, v1, vNew ) \ + interpolate_vertex(t, &v0, &v1, &vNew); \ + v1 = vNew; \ + } \ + /* else both verts are inside ==> do nothing */ \ + } + + /* Clip against +X side */ +#define OUTSIDE(V) (V.clipPos.x > V.clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dx = OUT.clipPos.x - IN.clipPos.x; \ + dw = OUT.clipPos.w - IN.clipPos.w; \ + t = (IN.clipPos.x - IN.clipPos.w) / (dw-dx); + GENERAL_CLIP +#undef OUTSIDE +#undef COMPUTE_INTERSECTION + + /* Clip against -X side */ +#define OUTSIDE(V) (V.clipPos.x < -(V.clipPos.w)) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dx = OUT.clipPos.x - IN.clipPos.x; \ + dw = OUT.clipPos.w - IN.clipPos.w; \ + t = -(IN.clipPos.x + IN.clipPos.w) / (dw+dx); + GENERAL_CLIP +#undef OUTSIDE +#undef COMPUTE_INTERSECTION + + /* Clip against +Y side */ +#define OUTSIDE(V) (V.clipPos.y > V.clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dy = OUT.clipPos.y - IN.clipPos.y; \ + dw = OUT.clipPos.w - IN.clipPos.w; \ + t = (IN.clipPos.y - IN.clipPos.w) / (dw-dy); + GENERAL_CLIP +#undef OUTSIDE +#undef COMPUTE_INTERSECTION + + /* Clip against -Y side */ +#define OUTSIDE(V) (V.clipPos.y < -(V.clipPos.w)) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dy = OUT.clipPos.y - IN.clipPos.y; \ + dw = OUT.clipPos.w - IN.clipPos.w; \ + t = -(IN.clipPos.y + IN.clipPos.w) / (dw+dy); + GENERAL_CLIP +#undef OUTSIDE +#undef COMPUTE_INTERSECTION + + /* Clip against +Z side */ +#define OUTSIDE(V) (V.clipPos.z > V.clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dz = OUT.clipPos.z - IN.clipPos.z; \ + dw = OUT.clipPos.w - IN.clipPos.w; \ + t = (IN.clipPos.z - IN.clipPos.w) / (dw-dz); + GENERAL_CLIP +#undef OUTSIDE +#undef COMPUTE_INTERSECTION + + /* Clip against -Z side */ +#define OUTSIDE(V) (V.clipPos.z < -(V.clipPos.w)) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dz = OUT.clipPos.z - IN.clipPos.z; \ + dw = OUT.clipPos.w - IN.clipPos.w; \ + t = -(IN.clipPos.z + IN.clipPos.w) / (dw+dz); + GENERAL_CLIP +#undef OUTSIDE +#undef COMPUTE_INTERSECTION + +#undef GENERAL_CLIP + + *v0new = v0; + *v1new = v1; + return GL_TRUE; +} + + + +/** + * \brief Apply clipping to a polygon. + * + * \param vIn array of input vertices. + * \param inCount number of input vertices + * \param vOut array of output vertices. + * + * \return number of vertices in \p vOut. + * + * \sa #GENERAL_CLIP. + */ +static GLuint +clip_polygon(const vertex *vIn, unsigned int inCount, vertex *vOut) +{ + vertex inlist[20], outlist[20]; + GLfloat dx, dy, dz, dw, t; + GLuint incount, outcount, previ, curri, result; + const vertex *currVert, *prevVert; + vertex *newVert; + + +#define GENERAL_CLIP(INCOUNT, INLIST, OUTCOUNT, OUTLIST) \ + if (INCOUNT < 3) \ + return GL_FALSE; \ + previ = INCOUNT - 1; /* let previous = last vertex */ \ + prevVert = INLIST + previ; \ + OUTCOUNT = 0; \ + for (curri = 0; curri < INCOUNT; curri++) { \ + currVert = INLIST + curri; \ + if (INSIDE(currVert)) { \ + if (INSIDE(prevVert)) { \ + /* both verts are inside ==> copy current to outlist */ \ + OUTLIST[OUTCOUNT] = *currVert; \ + OUTCOUNT++; \ + } \ + else { \ + newVert = OUTLIST + OUTCOUNT; \ + /* current is inside and previous is outside ==> clip */ \ + COMPUTE_INTERSECTION( currVert, prevVert, newVert ) \ + OUTCOUNT++; \ + /* Output current */ \ + OUTLIST[OUTCOUNT] = *currVert; \ + OUTCOUNT++; \ + } \ + } \ + else { \ + if (INSIDE(prevVert)) { \ + newVert = OUTLIST + OUTCOUNT; \ + /* current is outside and previous is inside ==> clip */ \ + COMPUTE_INTERSECTION( prevVert, currVert, newVert ); \ + OUTLIST[OUTCOUNT] = *newVert; \ + OUTCOUNT++; \ + } \ + /* else both verts are outside ==> do nothing */ \ + } \ + /* let previous = current */ \ + previ = curri; \ + prevVert = currVert; \ + } + +/* + * Clip against +X + */ +#define INSIDE(V) (V->clipPos.x <= V->clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dx = OUT->clipPos.x - IN->clipPos.x; \ + dw = OUT->clipPos.w - IN->clipPos.w; \ + t = (IN->clipPos.x - IN->clipPos.w) / (dw - dx); \ + interpolate_vertex(t, IN, OUT, NEW ); + + GENERAL_CLIP(inCount, vIn, outcount, outlist) + +#undef INSIDE +#undef COMPUTE_INTERSECTION + +/* + * Clip against -X + */ +#define INSIDE(V) (V->clipPos.x >= -V->clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dx = OUT->clipPos.x - IN->clipPos.x; \ + dw = OUT->clipPos.w - IN->clipPos.w; \ + t = -(IN->clipPos.x + IN->clipPos.w) / (dw + dx); \ + interpolate_vertex(t, IN, OUT, NEW ); + + GENERAL_CLIP(outcount, outlist, incount, inlist) + +#undef INSIDE +#undef COMPUTE_INTERSECTION + +/* + * Clip against +Y + */ +#define INSIDE(V) (V->clipPos.y <= V->clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dy = OUT->clipPos.y - IN->clipPos.y; \ + dw = OUT->clipPos.w - IN->clipPos.w; \ + t = (IN->clipPos.y - IN->clipPos.w) / (dw - dy); \ + interpolate_vertex(t, IN, OUT, NEW ); + + GENERAL_CLIP(incount, inlist, outcount, outlist) + +#undef INSIDE +#undef COMPUTE_INTERSECTION + +/* + * Clip against -Y + */ +#define INSIDE(V) (V->clipPos.y >= -V->clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dy = OUT->clipPos.y - IN->clipPos.y; \ + dw = OUT->clipPos.w - IN->clipPos.w; \ + t = -(IN->clipPos.y + IN->clipPos.w) / (dw + dy); \ + interpolate_vertex(t, IN, OUT, NEW ); + + GENERAL_CLIP(outcount, outlist, incount, inlist) + +#undef INSIDE +#undef COMPUTE_INTERSECTION + +/* + * Clip against +Z + */ +#define INSIDE(V) (V->clipPos.z <= V->clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dz = OUT->clipPos.z - IN->clipPos.z; \ + dw = OUT->clipPos.w - IN->clipPos.w; \ + t = (IN->clipPos.z - IN->clipPos.w) / (dw - dz); \ + interpolate_vertex(t, IN, OUT, NEW ); + + GENERAL_CLIP(incount, inlist, outcount, outlist) + +#undef INSIDE +#undef COMPUTE_INTERSECTION + +/* + * Clip against -Z + */ +#define INSIDE(V) (V->clipPos.z >= -V->clipPos.w) +#define COMPUTE_INTERSECTION( IN, OUT, NEW ) \ + dz = OUT->clipPos.z - IN->clipPos.z; \ + dw = OUT->clipPos.w - IN->clipPos.w; \ + t = -(IN->clipPos.z + IN->clipPos.w) / (dw + dz); \ + interpolate_vertex(t, IN, OUT, NEW ); + + GENERAL_CLIP(outcount, outlist, result, vOut) + +#undef INSIDE +#undef COMPUTE_INTERSECTION + +#undef GENERAL_CLIP + + return result; +} + +/*@}*/ + + + +/**********************************************************************/ +/** \name Selection */ +/**********************************************************************/ +/*@{*/ + +/** + * \brief Select point. + * + * \param v vertex. + * + * If the clipped point is visible then maps the vertex into window coordinates + * and calls _mesa_update_hitflag(). + */ +static void +select_point(const vertex *v) +{ + GET_CURRENT_CONTEXT(ctx); + if (clip_point(v) == 0) + { + vertex c = *v; + MAP_POINT(c.winPos, c.clipPos, ctx->Viewport); + _mesa_update_hitflag(ctx, c.winPos.z); + } +} + +/** + * \brief Select line. + * + * \param v0 first vertex. + * \param v1 second vertex. + * + * If the clipped line is visible then maps the vertices into window coordinates + * and calls _mesa_update_hitflag(). + */ +static void +select_line(const vertex *v0, const vertex *v1) +{ + GET_CURRENT_CONTEXT(ctx); + vertex c0, c1; + if (clip_line(v0, v1, &c0, &c1)) + { + MAP_POINT(c0.winPos, c0.clipPos, ctx->Viewport); + MAP_POINT(c1.winPos, c1.clipPos, ctx->Viewport); + _mesa_update_hitflag(ctx, c0.winPos.z); + _mesa_update_hitflag(ctx, c1.winPos.z); + } +} + +/** + * \brief Select line. + * + * \param v0 first vertex. + * \param v1 second vertex. + * \param v2 third vertex. + * + * If the clipped polygon is visible then maps the vertices into window + * coordinates and calls _mesa_update_hitflag(). + */ +static void +select_triangle(const vertex *v0, + const vertex *v1, + const vertex *v2) +{ + GET_CURRENT_CONTEXT(ctx); + vertex vlist[3], vclipped[8]; + GLuint i, n; + + vlist[0] = *v0; + vlist[1] = *v1; + vlist[2] = *v2; + n = clip_polygon(vlist, 3, vclipped); + for (i = 0; i < n; i++) { + MAP_POINT(vclipped[i].winPos, vclipped[i].clipPos, ctx->Viewport); + _mesa_update_hitflag(ctx, vclipped[i].winPos.z); + } +} + +/** + * \brief Set current vertex coordinates. + * + * \param x x vertex coordinate. + * \param y y vertex coordinate. + * \param z z vertex coordinate. + * \param w homogeneous coordinate. + * + * Stores the vertex and current attributes in ::vb, transforms it into eye space and then clip space. + * + * If a sufficient number of vertices is stored calls one of select_point(), + * select_line() or select_triangle(), according to the current primitive. + */ +static void +radeon_select_Vertex4f(GLfloat x, GLfloat y, GLfloat z, GLfloat w) +{ + GET_CURRENT_CONTEXT(ctx); + struct gl_polygon_attrib *p = &(ctx->Polygon); + vertex *v = vb.vBuffer + vb.vCount; + + /* store the vertex */ + v->pos.x = x; + v->pos.y = y; + v->pos.z = z; + v->pos.w = w; + v->color.r = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0]; + v->color.g = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1]; + v->color.b = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2]; + v->color.a = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3]; + v->texCoord.s = ctx->Current.Attrib[VERT_ATTRIB_TEX0][0]; + v->texCoord.t = ctx->Current.Attrib[VERT_ATTRIB_TEX0][1]; + + /* transform to eye space, then clip space */ + TRANSFORM_POINT(v->eyePos, ctx->ModelviewMatrixStack.Top->m, v->pos); + TRANSFORM_POINT(v->clipPos, ctx->ProjectionMatrixStack.Top->m, v->eyePos); + + switch (ctx->Driver.CurrentExecPrimitive) { + case GL_POINTS: + assert(vb.vCount == 0); + select_point(v); + break; + case GL_LINES: + if (vb.vCount == 0) + { + vb.vCount = 1; + } + else + { + assert(vb.vCount == 1); + select_line(vb.vBuffer + 0, vb.vBuffer + 1); + vb.vCount = 0; + } + break; + case GL_LINE_STRIP: + if (vb.vCount == 0) + { + vb.vCount = 1; + } + else + { + assert(vb.vCount == 1); + select_line(vb.vBuffer + 0, vb.vBuffer + 1); + vb.vBuffer[0] = vb.vBuffer[1]; + /* leave vb.vCount at 1 */ + } + break; + case GL_LINE_LOOP: + if (vb.vCount == 0) + { + vb.vCount = 1; + vb.partialLineLoop = GL_FALSE; + } + else if (vb.vCount == 1) + { + select_line(vb.vBuffer + 0, vb.vBuffer + 1); + vb.partialLineLoop = GL_TRUE; + vb.vCount = 2; + } + else + { + assert(vb.vCount == 2); + vb.partialLineLoop = GL_FALSE; + select_line(vb.vBuffer + 1, vb.vBuffer + 2); + vb.vBuffer[1] = vb.vBuffer[2]; + /* leave vb.vCount at 2 */ + } + break; + case GL_TRIANGLES: + if (vb.vCount == 0 || vb.vCount == 1) + { + vb.vCount++; + } + else + { + assert(vb.vCount == 2); + select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2); + vb.vCount = 0; + } + break; + case GL_TRIANGLE_STRIP: + if (vb.vCount == 0 || vb.vCount == 1) + { + vb.vCount++; + } + else if (vb.vCount == 2) + { + select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2); + vb.vCount = 3; + } + else + { + assert(vb.vCount == 3); + select_triangle(vb.vBuffer + 1, vb.vBuffer + 3, vb.vBuffer + 2); + vb.vBuffer[0] = vb.vBuffer[2]; + vb.vBuffer[1] = vb.vBuffer[3]; + vb.vCount = 2; + } + break; + case GL_TRIANGLE_FAN: + if (vb.vCount == 0 || vb.vCount == 1) + { + vb.vCount++; + } + else + { + assert(vb.vCount == 2); + select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2); + vb.vBuffer[1] = vb.vBuffer[2]; + /* leave vb.vCount = 2 */ + } + break; + case GL_QUADS: + if (vb.vCount < 3) + { + vb.vCount++; + } + else + { + assert(vb.vCount == 3); + select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2); + select_triangle(vb.vBuffer + 0, vb.vBuffer + 2, vb.vBuffer + 3); + vb.vCount = 0; + } + break; + case GL_QUAD_STRIP: + if (vb.vCount < 3) + { + vb.vCount++; + } + else + { + assert(vb.vCount == 3); + select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2); + select_triangle(vb.vBuffer + 1, vb.vBuffer + 3, vb.vBuffer + 2); + vb.vBuffer[0] = vb.vBuffer[2]; + vb.vBuffer[1] = vb.vBuffer[3]; + vb.vCount = 2; + } + break; + case GL_POLYGON: + switch (p->FrontMode) { + case GL_POINT: + assert(vb.vCount == 0); + select_point(v); + break; + case GL_LINE: + if (vb.vCount == 0) + { + vb.vCount = 1; + vb.partialLineLoop = GL_FALSE; + } + else if (vb.vCount == 1) + { + select_line(vb.vBuffer + 0, vb.vBuffer + 1); + vb.partialLineLoop = GL_TRUE; + vb.vCount = 2; + } + else + { + assert(vb.vCount == 2); + vb.partialLineLoop = GL_FALSE; + select_line(vb.vBuffer + 1, vb.vBuffer + 2); + vb.vBuffer[1] = vb.vBuffer[2]; + /* leave vb.vCount at 2 */ + } + break; + case GL_FILL: + /* draw as a tri-fan */ + if (vb.vCount == 0 || vb.vCount == 1) + { + vb.vCount++; + } + else + { + assert(vb.vCount == 2); + select_triangle(vb.vBuffer + 0, vb.vBuffer + 1, vb.vBuffer + 2); + vb.vBuffer[1] = vb.vBuffer[2]; + /* leave vb.vCount = 2 */ + } + break; + default: + ; /* impossible */ + } + break; + default: + ; /* outside begin/end -- no action required */ + } +} + +/** + * \brief Calls radeon_select_Vertex4f(). + */ +static void radeon_select_Vertex2f(GLfloat x, GLfloat y) +{ + radeon_select_Vertex4f(x, y, 0.0, 1.0); +} + +/** + * \brief Calls radeon_select_Vertex4f(). + */ +static void radeon_select_Vertex2fv(const GLfloat * v) +{ + radeon_select_Vertex4f(v[0], v[1], 0.0, 1.0); +} + +/** + * \brief Calls radeon_select_Vertex4f(). + */ +static void radeon_select_Vertex3f(GLfloat x, GLfloat y, GLfloat z) +{ + radeon_select_Vertex4f(x, y, z, 1.0); +} + +/** + * \brief Calls radeon_select_Vertex4f(). + */ +static void radeon_select_Vertex3fv(const GLfloat * v) +{ + radeon_select_Vertex4f(v[0], v[1], v[2], 1.0); +} + + +/** + * \brief Set current vertex color. + * + * \param r red color component. + * \param g gree color component. + * \param b blue color component. + * \param a alpha color component. + * + * Updates the GL context's current vertex color. + */ +static void radeon_select_Color4f( GLfloat r, GLfloat g, + GLfloat b, GLfloat a ) +{ + GET_CURRENT_CONTEXT(ctx); + GLfloat *dest = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; + dest[0] = r; + dest[1] = g; + dest[2] = b; + dest[3] = a; +} + +/** + * \brief Calls radeon_select_Color4f(). + */ +static void radeon_select_Color4fv( const GLfloat *v ) +{ + radeon_select_Color4f( v[0], v[1], v[2], v[3] ); +} + +/** + * \brief Calls radeon_select_Color4f(). + */ +static void radeon_select_Color3f( GLfloat r, GLfloat g, GLfloat b ) +{ + radeon_select_Color4f( r, g, b, 1.0 ); +} + +/** + * \brief Calls radeon_select_Color4f(). + */ +static void radeon_select_Color3fv( const GLfloat *v ) +{ + radeon_select_Color4f( v[0], v[1], v[2], 1.0 ); +} + +/** + * \brief Set current vertex texture coordinates. + * + * \param s texture coordinate. + * \param t texture coordinate. + * + * Updates the GL context's current vertex texture coordinates. + */ +static __inline__ void radeon_select_TexCoord2f( GLfloat s, GLfloat t ) +{ + GET_CURRENT_CONTEXT(ctx); + GLfloat *dest = ctx->Current.Attrib[VERT_ATTRIB_TEX0]; + dest[0] = s; + dest[1] = t; +} + +/** + * \brief Calls radeon_select_TexCoord2f(). + */ +static void radeon_select_TexCoord2fv( const GLfloat *v ) +{ + radeon_select_TexCoord2f( v[0], v[1] ); +} + + +/** + * \brief Process glBegin(). + * + * \param mode primitive. + */ +static void radeon_select_Begin(GLenum mode) +{ + GET_CURRENT_CONTEXT(ctx); + + if (mode > GL_POLYGON) { + _mesa_error( ctx, GL_INVALID_ENUM, "glBegin" ); + return; + } + + if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) { + _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" ); + return; + } + + ctx->Driver.CurrentExecPrimitive = mode; + + vb.vCount = 0; + vb.lineReset = GL_TRUE; + vb.partialLineLoop = GL_FALSE; +} + +/** + * \brief Process glEnd(). + */ +static void radeon_select_End(void) +{ + GET_CURRENT_CONTEXT(ctx); + + if ( (ctx->Driver.CurrentExecPrimitive == GL_LINE_LOOP || + (ctx->Driver.CurrentExecPrimitive == GL_POLYGON && + ctx->Polygon.FrontMode == GL_LINE)) + && vb.vCount == 2 ) + { + /* draw the last line segment */ + if (vb.partialLineLoop) + select_line(vb.vBuffer + 1, vb.vBuffer + 0); + else + select_line(vb.vBuffer + 2, vb.vBuffer + 0); + } + + ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1; +} + + +/** + * \brief Flush vertices. + * + * \param ctx GL context. + * \param flags not used. + * + * Nothing much to do here, besides marking the vertices as flushed, as we + * don't buffer anything. + */ +static void radeonSelectFlushVertices( GLcontext *ctx, GLuint flags ) +{ + ctx->Driver.NeedFlush = 0; +} + +/** + * \brief Install the select callbacks. + * + * \param ctx GL context. + * + * Installs the glBegin()/glEnd() associated select callbacks into the glapi + * table. + */ +void radeon_select_Install( GLcontext *ctx ) +{ + struct _glapi_table *exec = ctx->Exec; + + exec->Color3f = radeon_select_Color3f; + exec->Color3fv = radeon_select_Color3fv; + exec->Color4f = radeon_select_Color4f; + exec->Color4fv = radeon_select_Color4fv; + exec->TexCoord2f = radeon_select_TexCoord2f; + exec->TexCoord2fv = radeon_select_TexCoord2fv; + exec->Vertex2f = radeon_select_Vertex2f; + exec->Vertex2fv = radeon_select_Vertex2fv; + exec->Vertex3f = radeon_select_Vertex3f; + exec->Vertex3fv = radeon_select_Vertex3fv; + exec->Begin = radeon_select_Begin; + exec->End = radeon_select_End; + + ctx->Driver.FlushVertices = radeonSelectFlushVertices; +} +/*@}*/ + + + +/** + * \brief Set rasterization mode. + * + * \param ctx GL context. + * \param mode rasterization mode. Supports GL_RENDER or + * + * If mode is GL_RENDER, calls either radeonVtxfmtInit() or + * radeon_noop_Install depending on whether the application has focus + * (i.e., a fullscreen-cliprect) or not. If mode is GL_SELECT, calls + * radeon_select_Install(). + */ +static void radeonRenderMode( GLcontext *ctx, GLenum mode ) +{ + switch (mode) { + case GL_RENDER: + radeonVtxfmtInit( ctx ); + break; + case GL_SELECT: + radeon_select_Install( ctx ); + break; + default: + break; + } +} + +/** + * \brief Setup the GL context driver callbacks. + * + * \param ctx GL context. + * + * \sa Called by radeonCreateContext(). + */ +void radeonInitSelect( GLcontext *ctx ) +{ + ctx->Driver.RenderMode = radeonRenderMode; +} diff --git a/src/mesa/drivers/dri/radeon/radeon_subset_tex.c b/src/mesa/drivers/dri/radeon/radeon_subset_tex.c new file mode 100644 index 0000000000..e401779513 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_subset_tex.c @@ -0,0 +1,1018 @@ +/** + * \file radeon_subset_tex.c + * \brief Texturing. + * + * \author Gareth Hughes <gareth@valinux.com> + * \author Brian Paul <brianp@valinux.com> + */ + +/* + * Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + * VA Linux Systems Inc., Fremont, California. + * + * 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/lib/GL/mesa/src/drv/radeon/radeon_tex.c,v 1.6 2002/09/16 18:05:20 eich Exp $ */ + +#include "glheader.h" +#include "imports.h" +#include "colormac.h" +#include "context.h" +#include "enums.h" +#include "image.h" +#include "simple_list.h" +#include "texformat.h" +#include "texstore.h" + +#include "radeon_context.h" +#include "radeon_state.h" +#include "radeon_ioctl.h" +#include "radeon_subset.h" + +#include <errno.h> +#include <stdio.h> + + +/** + * \brief Destroy hardware state associated with a texture. + * + * \param rmesa Radeon context. + * \param t Radeon texture object to be destroyed. + * + * Frees the memory associated with the texture and if the texture is bound to + * a texture unit cleans the associated hardware state. + */ +void radeonDestroyTexObj( radeonContextPtr rmesa, radeonTexObjPtr t ) +{ + if ( t->memBlock ) { + mmFreeMem( t->memBlock ); + t->memBlock = NULL; + } + + if ( t->tObj ) + t->tObj->DriverData = NULL; + + if ( rmesa ) { + if ( t == rmesa->state.texture.unit[0].texobj ) { + rmesa->state.texture.unit[0].texobj = NULL; + remove_from_list( &rmesa->hw.tex[0] ); + make_empty_list( &rmesa->hw.tex[0] ); + } + } + + remove_from_list( t ); + FREE( t ); +} + + +/** + * \brief Keep track of swapped out texture objects. + * + * \param rmesa Radeon context. + * \param t Radeon texture object. + * + * Frees the memory associated with the texture, marks all mipmap images in + * the texture as dirty and add it to the radeon_texture::swapped list. + */ +static void radeonSwapOutTexObj( radeonContextPtr rmesa, radeonTexObjPtr t ) +{ + if ( t->memBlock ) { + mmFreeMem( t->memBlock ); + t->memBlock = NULL; + } + + t->dirty_images = ~0; + move_to_tail( &rmesa->texture.swapped, t ); +} + + +/** + * Texture space has been invalidated. + * + * \param rmesa Radeon context. + * \param heap texture heap number. + * + * Swaps out every texture in the specified heap. + */ +void radeonAgeTextures( radeonContextPtr rmesa, int heap ) +{ + radeonTexObjPtr t, tmp; + + foreach_s ( t, tmp, &rmesa->texture.objects[heap] ) + radeonSwapOutTexObj( rmesa, t ); +} + + +/***************************************************************/ +/** \name Texture image conversions + */ +/*@{*/ + +/** + * \brief Upload texture image. + * + * \param rmesa Radeon context. + * \param t Radeon texture object. + * \param level level of the image to take the sub-image. + * \param x sub-image abscissa. + * \param y sub-image ordinate. + * \param width sub-image width. + * \param height sub-image height. + * + * Fills in a drmRadeonTexture and drmRadeonTexImage structures and uploads the + * texture via the DRM_RADEON_TEXTURE ioctl, aborting in case of failure. + */ +static void radeonUploadSubImage( radeonContextPtr rmesa, + radeonTexObjPtr t, GLint level, + GLint x, GLint y, GLint width, GLint height ) +{ + struct gl_texture_image *texImage; + GLint ret; + drmRadeonTexture tex; + drmRadeonTexImage tmp; + + level += t->firstLevel; + texImage = t->tObj->Image[level]; + + if ( !texImage || !texImage->Data ) + return; + + t->image[level].data = texImage->Data; + + tex.offset = t->bufAddr; + tex.pitch = (t->image[0].width * texImage->TexFormat->TexelBytes) / 64; + tex.format = t->pp_txformat & RADEON_TXFORMAT_FORMAT_MASK; + tex.width = texImage->Width; + tex.height = texImage->Height; + tex.image = &tmp; + + memcpy( &tmp, &t->image[level], sizeof(drmRadeonTexImage) ); + + do { + ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_TEXTURE, + &tex, sizeof(drmRadeonTexture) ); + } while ( ret && errno == EAGAIN ); + + if ( ret ) { + UNLOCK_HARDWARE( rmesa ); + fprintf( stderr, "DRM_RADEON_TEXTURE: return = %d\n", ret ); + exit( 1 ); + } +} + +/** + * \brief Upload texture images. + * + * This might require removing our own and/or other client's texture objects to + * make room for these images. + * + * \param rmesa Radeon context. + * \param tObj texture object to upload. + * + * Sets the matching hardware texture format. Calculates which mipmap levels to + * send, depending of the base image size, GL_TEXTURE_MIN_LOD, + * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL and the + * Radeon offset rules. Kicks out textures until the requested texture fits, + * sets the texture hardware state and, while holding the hardware lock, + * uploads any images that are new. + */ +static void radeonSetTexImages( radeonContextPtr rmesa, + struct gl_texture_object *tObj ) +{ + radeonTexObjPtr t = (radeonTexObjPtr)tObj->DriverData; + const struct gl_texture_image *baseImage = tObj->Image[tObj->BaseLevel]; + GLint totalSize; + GLint texelsPerDword = 0, blitWidth = 0, blitPitch = 0; + GLint x, y, width, height; + GLint i; + GLint firstLevel, lastLevel, numLevels; + GLint log2Width, log2Height; + GLuint txformat = 0; + + /* This code cannot be reached once we have lost focus + */ + assert(rmesa->radeonScreen->buffers); + + /* Set the hardware texture format + */ + switch (baseImage->TexFormat->MesaFormat) { + case MESA_FORMAT_I8: + txformat = RADEON_TXFORMAT_I8; + texelsPerDword = 4; + blitPitch = 64; + break; + case MESA_FORMAT_RGBA8888: + txformat = RADEON_TXFORMAT_RGBA8888 | RADEON_TXFORMAT_ALPHA_IN_MAP; + texelsPerDword = 1; + blitPitch = 16; + break; + case MESA_FORMAT_RGB565: + txformat = RADEON_TXFORMAT_RGB565; + texelsPerDword = 2; + blitPitch = 32; + break; + default: + _mesa_problem(NULL, "unexpected texture format in radeonTexImage2D"); + return; + } + + t->pp_txformat &= ~(RADEON_TXFORMAT_FORMAT_MASK | + RADEON_TXFORMAT_ALPHA_IN_MAP); + t->pp_txformat |= txformat; + + + /* Select the larger of the two widths for our global texture image + * coordinate space. As the Radeon has very strict offset rules, we + * can't upload mipmaps directly and have to reference their location + * from the aligned start of the whole image. + */ + blitWidth = MAX2( baseImage->Width, blitPitch ); + + /* Calculate mipmap offsets and dimensions. + */ + totalSize = 0; + x = 0; + y = 0; + + /* Compute which mipmap levels we really want to send to the hardware. + * This depends on the base image size, GL_TEXTURE_MIN_LOD, + * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL. + * Yes, this looks overly complicated, but it's all needed. + */ + 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 */ + + /* save these values */ + t->firstLevel = firstLevel; + t->lastLevel = lastLevel; + + numLevels = lastLevel - firstLevel + 1; + + log2Width = tObj->Image[firstLevel]->WidthLog2; + log2Height = tObj->Image[firstLevel]->HeightLog2; + + for ( i = 0 ; i < numLevels ; i++ ) { + const struct gl_texture_image *texImage = tObj->Image[i + firstLevel]; + if ( !texImage ) + break; + + width = texImage->Width; + height = texImage->Height; + + /* Texture images have a minimum pitch of 32 bytes (half of the + * 64-byte minimum pitch for blits). For images that have a + * width smaller than this, we must pad each texture image + * scanline out to this amount. + */ + if ( width < blitPitch / 2 ) { + width = blitPitch / 2; + } + + totalSize += width * height * baseImage->TexFormat->TexelBytes; + ASSERT( (totalSize & 31) == 0 ); + + while ( width < blitWidth && height > 1 ) { + width *= 2; + height /= 2; + } + + ASSERT(i < RADEON_MAX_TEXTURE_LEVELS); + t->image[i].x = x; + t->image[i].y = y; + t->image[i].width = width; + t->image[i].height = height; + + /* While blits must have a pitch of at least 64 bytes, mipmaps + * must be aligned on a 32-byte boundary (just like each texture + * image scanline). + */ + if ( width >= blitWidth ) { + y += height; + } else { + x += width; + if ( x >= blitWidth ) { + x = 0; + y++; + } + } + } + + /* Align the total size of texture memory block. + */ + t->totalSize = (totalSize + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK; + + /* Hardware state: + */ + t->pp_txfilter &= ~RADEON_MAX_MIP_LEVEL_MASK; + t->pp_txfilter |= (numLevels - 1) << RADEON_MAX_MIP_LEVEL_SHIFT; + + t->pp_txformat &= ~(RADEON_TXFORMAT_WIDTH_MASK | + RADEON_TXFORMAT_HEIGHT_MASK); + t->pp_txformat |= ((log2Width << RADEON_TXFORMAT_WIDTH_SHIFT) | + (log2Height << RADEON_TXFORMAT_HEIGHT_SHIFT)); + t->dirty_state = TEX_ALL; + + /* Update the local texture LRU. + */ + move_to_head( &rmesa->texture.objects[0], t ); + + LOCK_HARDWARE( rmesa ); + + /* Kick out textures until the requested texture fits */ + while ( !t->memBlock ) { + t->memBlock = mmAllocMem( rmesa->texture.heap[0], t->totalSize, 12, 0); + + if (!t->memBlock) + radeonSwapOutTexObj( rmesa, rmesa->texture.objects[0].prev ); + + } + + /* Set the base offset of the texture image */ + t->bufAddr = rmesa->radeonScreen->texOffset[0] + t->memBlock->ofs; + t->pp_txoffset = t->bufAddr; + + /* Upload any images that are new + */ + for ( i = 0 ; i < numLevels ; i++ ) { + if ( t->dirty_images & (1 << i) ) { + radeonUploadSubImage( rmesa, t, i, 0, 0, + t->image[i].width, t->image[i].height ); + } + } + + rmesa->texture.age[0] = ++rmesa->sarea->texAge[0]; + UNLOCK_HARDWARE( rmesa ); + t->dirty_images = 0; +} + +/*@}*/ + + +/******************************************************************/ +/** \name Texture combine functions + */ +/*@{*/ + +enum { + RADEON_DISABLE = 0, /**< \brief disabled */ + RADEON_REPLACE = 1, /**< \brief replace function */ + RADEON_MODULATE = 2, /**< \brief modulate function */ + RADEON_DECAL = 3, /**< \brief decal function */ + RADEON_BLEND = 4, /**< \brief blend function */ + RADEON_MAX_COMBFUNC = 5 /**< \brief max number of combine functions */ +} ; + + +/** + * \brief Color combine function hardware state table. + */ +static GLuint radeon_color_combine[][RADEON_MAX_COMBFUNC] = +{ + /* Unit 0: + */ + { + /* Disable combiner stage + */ + (RADEON_COLOR_ARG_A_ZERO | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_CURRENT_COLOR | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_REPLACE = 0x00802800 + */ + (RADEON_COLOR_ARG_A_ZERO | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_T0_COLOR | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_MODULATE = 0x00800142 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_T0_COLOR | + RADEON_COLOR_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_DECAL = 0x008c2d42 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_T0_COLOR | + RADEON_COLOR_ARG_C_T0_ALPHA | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_BLEND = 0x008c2902 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_TFACTOR_COLOR | + RADEON_COLOR_ARG_C_T0_COLOR | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + }, + +}; + +/** + * \brief Alpha combine function hardware state table. + */ +static GLuint radeon_alpha_combine[][RADEON_MAX_COMBFUNC] = +{ + /* Unit 0: + */ + { + /* Disable combiner stage + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_CURRENT_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_REPLACE = 0x00800500 + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_T0_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_MODULATE = 0x00800051 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_T0_ALPHA | + RADEON_ALPHA_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_DECAL = 0x00800100 + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_CURRENT_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_BLEND = 0x00800051 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_TFACTOR_ALPHA | + RADEON_ALPHA_ARG_C_T0_ALPHA | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + }, + +}; + +/*@}*/ + + +/******************************************************************/ +/** \name Texture unit state management + */ +/*@{*/ + +/** + * \brief Update the texture environment. + * + * \param ctx GL context + * \param unit texture unit to update. + * + * Sets the state of the RADEON_TEX_PP_TXCBLEND and RADEON_TEX_PP_TXABLEND + * registers using the ::radeon_color_combine and ::radeon_alpha_combine tables, + * and informs of the state change. + */ +static void radeonUpdateTextureEnv( GLcontext *ctx, int unit ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + const struct gl_texture_object *tObj = texUnit->_Current; + const GLenum format = tObj->Image[tObj->BaseLevel]->Format; + GLuint color_combine = radeon_color_combine[unit][RADEON_DISABLE]; + GLuint alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE]; + + + /* Set the texture environment state. Isn't this nice and clean? + * The Radeon will automagically set the texture alpha to 0xff when + * the texture format does not include an alpha component. This + * reduces the amount of special-casing we have to do, alpha-only + * textures being a notable exception. + */ + switch ( texUnit->EnvMode ) { + case GL_REPLACE: + switch ( format ) { + case GL_RGBA: + case GL_INTENSITY: + color_combine = radeon_color_combine[unit][RADEON_REPLACE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_REPLACE]; + break; + case GL_RGB: + color_combine = radeon_color_combine[unit][RADEON_REPLACE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE]; + break; + default: + break; + } + break; + + case GL_MODULATE: + switch ( format ) { + case GL_RGBA: + case GL_INTENSITY: + color_combine = radeon_color_combine[unit][RADEON_MODULATE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE]; + break; + case GL_RGB: + color_combine = radeon_color_combine[unit][RADEON_MODULATE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE]; + break; + default: + break; + } + break; + + case GL_DECAL: + switch ( format ) { + case GL_RGBA: + case GL_RGB: + color_combine = radeon_color_combine[unit][RADEON_DECAL]; + alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE]; + break; + case GL_INTENSITY: + color_combine = radeon_color_combine[unit][RADEON_DISABLE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE]; + break; + default: + break; + } + break; + + case GL_BLEND: + switch ( format ) { + case GL_RGBA: + case GL_RGB: + color_combine = radeon_color_combine[unit][RADEON_BLEND]; + alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE]; + break; + case GL_INTENSITY: + color_combine = radeon_color_combine[unit][RADEON_BLEND]; + alpha_combine = radeon_alpha_combine[unit][RADEON_BLEND]; + break; + default: + break; + } + break; + + default: + break; + } + + if ( rmesa->hw.tex[unit].cmd[TEX_PP_TXCBLEND] != color_combine || + rmesa->hw.tex[unit].cmd[TEX_PP_TXABLEND] != alpha_combine ) { + RADEON_STATECHANGE( rmesa, tex[unit] ); + rmesa->hw.tex[unit].cmd[TEX_PP_TXCBLEND] = color_combine; + rmesa->hw.tex[unit].cmd[TEX_PP_TXABLEND] = alpha_combine; + } +} + + +#define TEXOBJ_TXFILTER_MASK (RADEON_MAX_MIP_LEVEL_MASK | \ + RADEON_MIN_FILTER_MASK | \ + RADEON_MAG_FILTER_MASK | \ + RADEON_MAX_ANISO_MASK | \ + RADEON_CLAMP_S_MASK | \ + RADEON_CLAMP_T_MASK) + +#define TEXOBJ_TXFORMAT_MASK (RADEON_TXFORMAT_WIDTH_MASK | \ + RADEON_TXFORMAT_HEIGHT_MASK | \ + RADEON_TXFORMAT_FORMAT_MASK | \ + RADEON_TXFORMAT_ALPHA_IN_MAP) + + + +void radeonUpdateTextureState( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[0]; + + if ( texUnit->_ReallyEnabled & (TEXTURE_1D_BIT | TEXTURE_2D_BIT) ) { + struct gl_texture_object *tObj = texUnit->_Current; + radeonTexObjPtr t = (radeonTexObjPtr) tObj->DriverData; + + /* Upload teximages (not pipelined) + */ + if ( t->dirty_images ) { + RADEON_FIREVERTICES( rmesa ); + radeonSetTexImages( rmesa, tObj ); + } + + /* Update state if this is a different texture object to last + * time. + */ + if ( rmesa->state.texture.unit[0].texobj != t ) { + rmesa->state.texture.unit[0].texobj = t; + t->dirty_state |= 1<<0; + move_to_head( &rmesa->texture.objects[0], t ); + } + + if (t->dirty_state) { + GLuint *cmd = RADEON_DB_STATE( tex[0] ); + + cmd[TEX_PP_TXFILTER] &= ~TEXOBJ_TXFILTER_MASK; + cmd[TEX_PP_TXFORMAT] &= ~TEXOBJ_TXFORMAT_MASK; + cmd[TEX_PP_TXFILTER] |= t->pp_txfilter & TEXOBJ_TXFILTER_MASK; + cmd[TEX_PP_TXFORMAT] |= t->pp_txformat & TEXOBJ_TXFORMAT_MASK; + cmd[TEX_PP_TXOFFSET] = t->pp_txoffset; + cmd[TEX_PP_BORDER_COLOR] = t->pp_border_color; + + RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.tex[0] ); + t->dirty_state = 0; + } + + /* Newly enabled? + */ + if (!(rmesa->hw.ctx.cmd[CTX_PP_CNTL] & RADEON_TEX_0_ENABLE)) { + RADEON_STATECHANGE( rmesa, ctx ); + rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= (RADEON_TEX_0_ENABLE | + RADEON_TEX_BLEND_0_ENABLE); + + RADEON_STATECHANGE( rmesa, tcl ); + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_ST0; + } + + radeonUpdateTextureEnv( ctx, 0 ); + } + else if (rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (RADEON_TEX_0_ENABLE<<0)) { + /* Texture unit disabled */ + rmesa->state.texture.unit[0].texobj = 0; + RADEON_STATECHANGE( rmesa, ctx ); + rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= + ~((RADEON_TEX_0_ENABLE | RADEON_TEX_BLEND_0_ENABLE) << 0); + + RADEON_STATECHANGE( rmesa, tcl ); + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~(RADEON_TCL_VTX_ST0 | + RADEON_TCL_VTX_Q0); + } +} + + + +/** + * \brief Choose texture format. + * + * \param ctx GL context. + * \param internalFormat texture internal format. + * \param format pixel format. Not used. + * \param type pixel data type. Not used. + * + * \return pointer to chosen texture format. + * + * Returns a pointer to one of the Mesa texture formats which is supported by + * Radeon and matches the internal format. + */ +static const struct gl_texture_format * +radeonChooseTextureFormat( GLcontext *ctx, GLint internalFormat, + GLenum format, GLenum type ) +{ + switch ( internalFormat ) { + case GL_RGBA: + case GL_RGBA8: + return &_mesa_texformat_rgba8888; + + case GL_RGB: + case GL_RGB5: + return &_mesa_texformat_rgb565; + + case GL_INTENSITY: + case GL_INTENSITY8: + return &_mesa_texformat_i8; + + default: + _mesa_problem(ctx, "unexpected texture format in radeonChoosTexFormat"); + return NULL; + } +} + +/** + * \brief Allocate a Radeon texture object. + * + * \param texObj texture object. + * + * \return pointer to the device specific texture object on success, or NULL on failure. + * + * Allocates and initializes a radeon_tex_obj structure to connect it to the + * driver private data pointer in \p texObj. + */ +static radeonTexObjPtr radeonAllocTexObj( struct gl_texture_object *texObj ) +{ + radeonTexObjPtr t; + + t = CALLOC_STRUCT( radeon_tex_obj ); + if (!t) + return NULL; + + t->tObj = texObj; + texObj->DriverData = t; + make_empty_list( t ); + t->dirty_images = ~0; + return t; +} + + +/** + * \brief Load a texture image. + * + * \param ctx GL context. + * \param texObj texture object + * \param target target texture. + * \param level level of detail number. + * \param internalFormat internal format. + * \param width texture image width. + * \param height texture image height. + * \param border border width. + * \param format pixel format. + * \param type pixel data type. + * \param pixels image data. + * \param packing passed to _mesa_store_teximage2d() unchanged. + * \param texImage passed to _mesa_store_teximage2d() unchanged. + * + * If there is a device specific texture object associated with the given + * texture object then swaps that texture out. Calls _mesa_store_teximage2d() + * with all other parameters unchanged. + */ +static void radeonTexImage2D( GLcontext *ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint border, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeonTexObjPtr t = (radeonTexObjPtr)texObj->DriverData; + + if ( t ) + radeonSwapOutTexObj( rmesa, t ); + + /* Note, this will call radeonChooseTextureFormat */ + _mesa_store_teximage2d(ctx, target, level, internalFormat, + width, height, border, format, type, pixels, + &ctx->Unpack, texObj, texImage); +} + +/** + * \brief Set texture environment parameters. + * + * \param ctx GL context. + * \param target texture environment. + * \param pname texture parameter. Accepted value is GL_TEXTURE_ENV_COLOR. + * \param param parameter value. + * + * Updates the current unit's RADEON_TEX_PP_TFACTOR register and informs of the + * state change. + */ +static void radeonTexEnv( GLcontext *ctx, GLenum target, + GLenum pname, const GLfloat *param ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint unit = ctx->Texture.CurrentUnit; + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + + switch ( pname ) { + case GL_TEXTURE_ENV_COLOR: { + GLubyte c[4]; + GLuint envColor; + UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor ); + envColor = radeonPackColor( 4, c[0], c[1], c[2], c[3] ); + if ( rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] != envColor ) { + RADEON_STATECHANGE( rmesa, tex[unit] ); + rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] = envColor; + } + break; + } + + default: + return; + } +} + +/** + * \brief Set texture parameter. + * + * \param ctx GL context. + * \param target target texture. + * \param texObj texture object. + * \param pname texture parameter. + * \param params parameter value. + * + * Allocates the device specific texture object data if it doesn't exist + * already. + * + * Updates the texture object radeon_tex_obj::pp_txfilter register and marks + * the texture state (radeon_tex_obj::dirty_state) as dirty. + */ +static void radeonTexParameter( GLcontext *ctx, GLenum target, + struct gl_texture_object *texObj, + GLenum pname, const GLfloat *params ) +{ + radeonTexObjPtr t = (radeonTexObjPtr) texObj->DriverData; + + if (!t) + t = radeonAllocTexObj( texObj ); + + switch ( pname ) { + case GL_TEXTURE_MIN_FILTER: + t->pp_txfilter &= ~RADEON_MIN_FILTER_MASK; + switch ( texObj->MinFilter ) { + case GL_NEAREST: + t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST; + break; + case GL_LINEAR: + t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR; + break; + case GL_NEAREST_MIPMAP_NEAREST: + t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_NEAREST; + break; + case GL_NEAREST_MIPMAP_LINEAR: + t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_NEAREST; + break; + case GL_LINEAR_MIPMAP_NEAREST: + t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_LINEAR; + break; + case GL_LINEAR_MIPMAP_LINEAR: + t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_LINEAR; + break; + } + break; + + case GL_TEXTURE_MAG_FILTER: + t->pp_txfilter &= ~RADEON_MAG_FILTER_MASK; + switch ( texObj->MagFilter ) { + case GL_NEAREST: + t->pp_txfilter |= RADEON_MAG_FILTER_NEAREST; + break; + case GL_LINEAR: + t->pp_txfilter |= RADEON_MAG_FILTER_LINEAR; + break; + } + break; + + case GL_TEXTURE_WRAP_S: + t->pp_txfilter &= ~RADEON_CLAMP_S_MASK; + switch ( texObj->WrapS ) { + case GL_REPEAT: + t->pp_txfilter |= RADEON_CLAMP_S_WRAP; + break; + case GL_CLAMP_TO_EDGE: + t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_LAST; + break; + } + break; + + case GL_TEXTURE_WRAP_T: + t->pp_txfilter &= ~RADEON_CLAMP_T_MASK; + switch ( texObj->WrapT ) { + case GL_REPEAT: + t->pp_txfilter |= RADEON_CLAMP_T_WRAP; + break; + case GL_CLAMP_TO_EDGE: + t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_LAST; + break; + } + break; + + default: + return; + } + + /* Mark this texobj as dirty (one bit per tex unit) + */ + t->dirty_state = TEX_ALL; +} + +/** + * \brief Bind texture. + * + * \param ctx GL context. + * \param target not used. + * \param texObj texture object. + * + * Allocates the device specific texture data if it doesn't exist already. + */ +static void radeonBindTexture( GLcontext *ctx, GLenum target, + struct gl_texture_object *texObj ) +{ + if ( !texObj->DriverData ) + radeonAllocTexObj( texObj ); +} + +/** + * \brief Delete texture. + * + * \param ctx GL context. + * \param texObj texture object. + * + * Fires any outstanding vertices and destroy the device specific texture + * object. + */ +static void radeonDeleteTexture( GLcontext *ctx, + struct gl_texture_object *texObj ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeonTexObjPtr t = (radeonTexObjPtr) texObj->DriverData; + + if ( t ) { + if ( rmesa ) + RADEON_FIREVERTICES( rmesa ); + radeonDestroyTexObj( rmesa, t ); + } +} + +/** + * \brief Initialize context texture object data. + * + * \param ctx GL context. + * + * Called by radeonInitTextureFuncs() to setup the context initial texture + * objects. + */ +static void radeonInitTextureObjects( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct gl_texture_object *texObj; + GLuint tmp = ctx->Texture.CurrentUnit; + + ctx->Texture.CurrentUnit = 0; + + texObj = ctx->Texture.Unit[0].Current2D; + radeonBindTexture( ctx, GL_TEXTURE_2D, texObj ); + move_to_tail( &rmesa->texture.swapped, + (radeonTexObjPtr)texObj->DriverData ); + + + ctx->Texture.CurrentUnit = tmp; +} + +/** + * \brief Setup the GL context driver callbacks. + * + * \param ctx GL context. + * + * \sa Called by radeonCreateContext(). + */ +void radeonInitTextureFuncs( GLcontext *ctx ) +{ + ctx->Driver.ChooseTextureFormat = radeonChooseTextureFormat; + ctx->Driver.TexImage2D = radeonTexImage2D; + + ctx->Driver.BindTexture = radeonBindTexture; + ctx->Driver.CreateTexture = NULL; /* FIXME: Is this used??? */ + ctx->Driver.DeleteTexture = radeonDeleteTexture; + ctx->Driver.PrioritizeTexture = NULL; + ctx->Driver.ActiveTexture = NULL; + ctx->Driver.UpdateTexturePalette = NULL; + + ctx->Driver.TexEnv = radeonTexEnv; + ctx->Driver.TexParameter = radeonTexParameter; + + radeonInitTextureObjects( ctx ); +} + +/*@}*/ diff --git a/src/mesa/drivers/dri/radeon/radeon_subset_vtx.c b/src/mesa/drivers/dri/radeon/radeon_subset_vtx.c new file mode 100644 index 0000000000..aa6ec73d5b --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_subset_vtx.c @@ -0,0 +1,989 @@ +/** + * \file radeon_subset_vtx.c + * \brief Vertex buffering. + * + * \author Keith Whitwell <keith@tungstengraphics.com> + */ + +/* + * Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + * 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, TUNGSTEN GRAPHICS 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$ */ + +#include "glheader.h" +#include "imports.h" +#include "api_noop.h" +#include "context.h" +/*#include "mmath.h" */ +#include "mtypes.h" +#include "enums.h" +#include "glapi.h" +#include "colormac.h" +#include "state.h" + +#include "radeon_context.h" +#include "radeon_state.h" +#include "radeon_ioctl.h" +#include "radeon_subset.h" + +/** + * \brief Union for vertex data. + */ +union vertex_dword { + float f; /**< \brief floating point value */ + int i; /**< \brief integer point value */ +}; + + +/** + * \brief Maximum number of dwords per vertex. + * + * Defined as 10 to hold: \code xyzw rgba st \endcode + */ +#define MAX_VERTEX_DWORDS 10 + + +/** + * \brief Global vertex buffer data. + */ +static struct vb_t { + /** + * \brief Notification mechanism. + * + * These are treated as a stack to allow us to do things like build quads in + * temporary storage and then emit them as triangles. + */ + struct { + GLint vertspace; /**< \brief free vertices count */ + GLint initial_vertspace; /**< \brief total vertices count */ + GLint *dmaptr; /**< \brief */ + void (*notify)( void ); /**< \brief notification callback */ + } stack[2]; + + /** + * \brief Storage for current vertex. + */ + union vertex_dword vertex[MAX_VERTEX_DWORDS]; + + /** + * \brief Temporary storage for quads, etc. + */ + union vertex_dword vertex_store[MAX_VERTEX_DWORDS * 4]; + + /** + * \name Color/texture + * + * Pointers to either vertex or ctx->Current.Attrib, depending on whether + * color/texture participates in the current vertex. + */ + /*@{*/ + GLfloat *floatcolorptr; /**< \brief color */ + GLfloat *texcoordptr; /**< \brief texture */ + /*@}*/ + + /** + * \brief Pointer to the GL context. + */ + GLcontext *context; + + /** + * \brief Active primitive. + * + * \note May differ from ctx->Driver.CurrentExecPrimitive. + */ + /*@{*/ + GLenum prim; /**< \brief primitive */ + GLuint vertex_format; /**< \brief vertex format */ + GLint vertex_size; /**< \brief vertex size */ + GLboolean recheck; /**< \brief set if it's needed to validate this information */ + /*@}*/ +} vb; + + +static void radeonFlushVertices( GLcontext *, GLuint ); + + +/** + * \brief Primitive information table. + */ +static struct prims_t { + int start, /**< \brief vertex count for the starting primitive */ + incr, /**< \brief vertex increment for a further primitive */ + hwprim; /**< \brief hardware primitive */ +} prims[10] = { + { 1, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_POINT }, + { 2, 2, RADEON_CP_VC_CNTL_PRIM_TYPE_LINE }, + { 2, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP }, + { 2, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP }, + { 3, 3, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST }, + { 3, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP }, + { 3, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN }, + { 4, 4, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST }, + { 4, 2, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP }, + { 3, 1, RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN }, +}; + + +/** + * \brief Finish the primitive in the vertex buffer. + * + * \param rmesa Radeon context. + * + * Truncates any redundant vertices off the end of the buffer, emit the + * remaining vertices and advances the current DMA region. + */ +static void finish_prim( radeonContextPtr rmesa ) +{ + GLuint prim_end = vb.stack[0].initial_vertspace - vb.stack[0].vertspace; + + /* Too few vertices? (eg: 2 vertices for a triangles prim?) + */ + if (prim_end < prims[vb.prim].start) + return; + + /* Drop redundant vertices off end of primitive. (eg: 5 vertices + * for triangles prim?) + */ + prim_end -= (prim_end - prims[vb.prim].start) % prims[vb.prim].incr; + + radeonEmitVertexAOS( rmesa, vb.vertex_size, GET_START(&rmesa->dma.current) ); + + radeonEmitVbufPrim( rmesa, vb.vertex_format, + prims[vb.prim].hwprim | rmesa->tcl.tcl_flag, + prim_end ); + + rmesa->dma.current.ptr = + rmesa->dma.current.start += prim_end * vb.vertex_size * 4; +} + + +/** + * \brief Copy a vertex from the current DMA region + * + * \param rmesa Radeon context. + * \param n vertex index relative to the current DMA region. + * \param dst destination pointer. + * + * Used internally by copy_dma_verts(). + */ +static void copy_vertex( radeonContextPtr rmesa, GLuint n, GLfloat *dst ) +{ + GLuint i; + GLfloat *src = (GLfloat *)(rmesa->dma.current.address + + rmesa->dma.current.ptr + + n * vb.vertex_size * 4); + + for (i = 0 ; i < vb.vertex_size; i++) + dst[i] = src[i]; +} + + +/** + * \brief Copy last vertices from the current DMA buffer to resume in a new buffer. + * + * \param rmesa Radeon context. + * \param tmp destination buffer. + * + * Takes from the current DMA buffer the last vertices necessary to resume in a + * new buffer, according to the current primitive. Uses internally + * copy_vertex() for the vertex copying. + * + */ +static GLuint copy_dma_verts( radeonContextPtr rmesa, + GLfloat (*tmp)[MAX_VERTEX_DWORDS] ) +{ + GLuint ovf, i; + GLuint nr = vb.stack[0].initial_vertspace - vb.stack[0].vertspace; + + switch( vb.prim ) + { + case GL_POINTS: + return 0; + case GL_LINES: + ovf = nr&1; + for (i = 0 ; i < ovf ; i++) + copy_vertex( rmesa, nr-ovf+i, tmp[i] ); + return i; + case GL_LINE_STRIP: + if (nr == 0) + return 0; + copy_vertex( rmesa, nr-1, tmp[0] ); + return 1; + case GL_LINE_LOOP: + case GL_TRIANGLE_FAN: + case GL_POLYGON: + if (nr == 0) + return 0; + else if (nr == 1) { + copy_vertex( rmesa, 0, tmp[0] ); + return 1; + } else { + copy_vertex( rmesa, 0, tmp[0] ); + copy_vertex( rmesa, nr-1, tmp[1] ); + return 2; + } + case GL_TRIANGLES: + ovf = nr % 3; + for (i = 0 ; i < ovf ; i++) + copy_vertex( rmesa, nr-ovf+i, tmp[i] ); + return i; + case GL_QUADS: + ovf = nr % 4; + for (i = 0 ; i < ovf ; i++) + copy_vertex( rmesa, nr-ovf+i, tmp[i] ); + return i; + case GL_TRIANGLE_STRIP: + case GL_QUAD_STRIP: + ovf = MIN2(nr, 2); + for (i = 0 ; i < ovf ; i++) + copy_vertex( rmesa, nr-ovf+i, tmp[i] ); + return i; + default: + return 0; + } +} + +static void notify_wrap_buffer( void ); + +/** + * \brief Resets the vertex buffer notification mechanism. + * + * Fills in vb_t::stack with the values from the current DMA region in + * radeon_dma::current and sets the notification callback to + * notify_wrap_buffer(). + */ +static void reset_notify( void ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( vb.context ); + + vb.stack[0].dmaptr = (int *)(rmesa->dma.current.address + + rmesa->dma.current.ptr); + vb.stack[0].vertspace = ((rmesa->dma.current.end - rmesa->dma.current.ptr) / + (vb.vertex_size * 4)); + vb.stack[0].vertspace &= ~1; /* even numbers only -- avoid tristrip parity */ + vb.stack[0].initial_vertspace = vb.stack[0].vertspace; + vb.stack[0].notify = notify_wrap_buffer; +} + +/** + * \brief Full buffer notification callback. + * + * Makes a copy of the necessary vertices of the current buffer via + * copy_dma_verts(), gets and resets new buffer via radeon and re-emits the + * saved vertices. + */ +static void notify_wrap_buffer( void ) +{ + GLcontext *ctx = vb.context; + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat tmp[3][MAX_VERTEX_DWORDS]; + GLuint i, nrverts = 0; + + /* Copy vertices out of dma: + */ + nrverts = copy_dma_verts( rmesa, tmp ); + finish_prim( rmesa ); + + /* Get new buffer + */ + radeonRefillCurrentDmaRegion( rmesa ); + + /* Reset vertspace[0], dmaptr + */ + reset_notify(); + + /* Reemit saved vertices + */ + for (i = 0 ; i < nrverts; i++) { + memcpy( vb.stack[0].dmaptr, tmp[i], vb.vertex_size * 4 ); + vb.stack[0].dmaptr += vb.vertex_size; + vb.stack[0].vertspace--; + } +} + + +static void notify_noop( void ) +{ + vb.stack[0].dmaptr = (int *)vb.vertex; + vb.stack[0].notify = notify_noop; + vb.stack[0].vertspace = 1; +} + +/** + * \brief Pop the notification mechanism stack. + * + * Simply copy the second stack array element into the first. + * + * \sa vb_t::stack and push_notify(). + */ +static void pop_notify( void ) +{ + vb.stack[0] = vb.stack[1]; +} + +/** + * \brief Push the notification mechanism stack. + * + * \param notify new notify callback for the stack head. + * \param space space available for vertices in \p store. + * \param store buffer where to store the vertices. + * + * Copy the second stack array element into the first and makes the stack head + * use the given resources. + * + * \sa vb_t::stack and pop_notify(). + */ +static void push_notify( void (*notify)( void ), int space, + union vertex_dword *store ) +{ + vb.stack[1] = vb.stack[0]; + vb.stack[0].notify = notify; + vb.stack[0].initial_vertspace = space; + vb.stack[0].vertspace = space; + vb.stack[0].dmaptr = (int *)store; +} + + +/** + * \brief Emit a stored vertex (in vb_t::vertex_store) to DMA. + * + * \param v vertex index. + * + * Adds the vertex into the current vertex buffer and calls the notification + * callback vb_t::notify(). + */ +static void emit_vertex( int v ) +{ + int i, *tmp = (int *)vb.vertex_store + v * vb.vertex_size; + + for (i = 0 ; i < vb.vertex_size ; i++) + *vb.stack[0].dmaptr++ = *tmp++; + + if (--vb.stack[0].vertspace == 0) + vb.stack[0].notify(); +} + + +/** + * \brief Emit a quad (in vb_t::vertex_store) to DMA as two triangles. + * + * \param v0 first vertex index. + * \param v1 second vertex index. + * \param v2 third vertex index. + * \param v3 fourth vertex index. + * + * Calls emit_vertex() to emit the triangles' vertices. + */ +static void emit_quad( int v0, int v1, int v2, int v3 ) +{ + emit_vertex( v0 ); emit_vertex( v1 ); emit_vertex( v3 ); + emit_vertex( v1 ); emit_vertex( v2 ); emit_vertex( v3 ); +} + +/** + * \brief Every fourth vertex in a quad primitive, this is called to emit it. + * + * Pops the notification stack, calls emit_quad() and pushes the notification + * stack again, with itself and the vb_t::vertex_store to process another four + * vertices. + */ +static void notify_quad( void ) +{ + pop_notify(); + emit_quad( 0, 1, 2, 3 ); + push_notify( notify_quad, 4, vb.vertex_store ); +} + +static void notify_qstrip1( void ); + +/** + * \brief After the 4th vertex, emit either a quad or a flipped quad each two + * vertices. + * + * Pops the notification stack, calls emit_quad() with the flipped vertices and + * pushes the notification stack again, with notify_qstrip1() and the + * vb_t::vertex_store to process another two vertices. + * + * \sa notify_qstrip1(). + */ +static void notify_qstrip0( void ) +{ + pop_notify(); + emit_quad( 0, 1, 3, 2 ); + push_notify( notify_qstrip1, 2, vb.vertex_store ); +} + +/** + * \brief After the 4th vertex, emit either a quad or a flipped quad each two + * vertices. + * + * Pops the notification stack, calls emit_quad() with the straight vertices + * and pushes the notification stack again, with notify_qstrip0() and the + * vb_t::vertex_store to process another two vertices. + * + * \sa notify_qstrip0(). + */ +static void notify_qstrip1( void ) +{ + pop_notify(); + emit_quad( 2, 3, 1, 0 ); + push_notify( notify_qstrip0, 2, vb.vertex_store + 2*vb.vertex_size ); +} + +/** + * \brief Emit the saved vertex (but hang on to it for later). + * + * Continue processing this primitive as a linestrip. + * + * Pops the notification stack and calls emit_quad with the first vertex. + */ +static void notify_lineloop0( void ) +{ + pop_notify(); + emit_vertex(0); +} + +/** + * \brief Invalidate the current vertex format. + * + * \param ctx GL context. + * + * Sets the vb_t::recheck flag. + */ +void radeonVtxfmtInvalidate( GLcontext *ctx ) +{ + vb.recheck = GL_TRUE; +} + + +/** + * \brief Validate the vertex format from the context. + * + * \param ctx GL context. + * + * Signals a new primitive and determines the appropriate vertex format and + * size. Points vb_t::floatcolorptr and vb_t::texcoordptr to the current vertex + * and sets them to the current color and texture attributes. + * + * Clears the vb_t::recheck flag on exit. + */ +static void radeonVtxfmtValidate( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + GLuint ind = (RADEON_CP_VC_FRMT_Z | + RADEON_CP_VC_FRMT_FPCOLOR | + RADEON_CP_VC_FRMT_FPALPHA); + + if (ctx->Driver.NeedFlush) + ctx->Driver.FlushVertices( ctx, ctx->Driver.NeedFlush ); + + if (ctx->Texture.Unit[0]._ReallyEnabled) + ind |= RADEON_CP_VC_FRMT_ST0; + + RADEON_NEWPRIM(rmesa); + vb.vertex_format = ind; + vb.vertex_size = 3; + + /* Would prefer to use ubyte floats in the vertex: + */ + vb.floatcolorptr = &vb.vertex[vb.vertex_size].f; + vb.vertex_size += 4; + vb.floatcolorptr[0] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0]; + vb.floatcolorptr[1] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1]; + vb.floatcolorptr[2] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2]; + vb.floatcolorptr[3] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3]; + + if (ind & RADEON_CP_VC_FRMT_ST0) { + vb.texcoordptr = &vb.vertex[vb.vertex_size].f; + vb.vertex_size += 2; + vb.texcoordptr[0] = ctx->Current.Attrib[VERT_ATTRIB_TEX0][0]; + vb.texcoordptr[1] = ctx->Current.Attrib[VERT_ATTRIB_TEX0][1]; + } + else + vb.texcoordptr = ctx->Current.Attrib[VERT_ATTRIB_TEX0]; + + vb.recheck = GL_FALSE; + ctx->Driver.NeedFlush = FLUSH_UPDATE_CURRENT; +} + + +#define RESET_STIPPLE() do { \ + RADEON_STATECHANGE( rmesa, lin ); \ + radeonEmitState( rmesa ); \ +} while (0) + +#define AUTO_STIPPLE( mode ) do { \ + RADEON_STATECHANGE( rmesa, lin ); \ + if (mode) \ + rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] |= \ + RADEON_LINE_PATTERN_AUTO_RESET; \ + else \ + rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] &= \ + ~RADEON_LINE_PATTERN_AUTO_RESET; \ + radeonEmitState( rmesa ); \ +} while (0) + + +/** + * \brief Process glBegin(). + * + * \param mode primitive. + */ +static void radeon_Begin( GLenum mode ) +{ + GLcontext *ctx = vb.context; + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint se_cntl; + + if (mode > GL_POLYGON) { + _mesa_error( ctx, GL_INVALID_ENUM, "glBegin" ); + return; + } + + if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) { + _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" ); + return; + } + + if (ctx->NewState) + _mesa_update_state( ctx ); + + if (rmesa->NewGLState) + radeonValidateState( ctx ); + + if (vb.recheck) + radeonVtxfmtValidate( ctx ); + + /* Do we need to grab a new DMA region for the vertices? + */ + if (rmesa->dma.current.ptr + 12*vb.vertex_size*4 > rmesa->dma.current.end) { + RADEON_NEWPRIM( rmesa ); + radeonRefillCurrentDmaRegion( rmesa ); + } + + reset_notify(); + vb.prim = ctx->Driver.CurrentExecPrimitive = mode; + se_cntl = rmesa->hw.set.cmd[SET_SE_CNTL] | RADEON_FLAT_SHADE_VTX_LAST; + + if (ctx->Line.StippleFlag && + (mode == GL_LINES || + mode == GL_LINE_LOOP || + mode == GL_LINE_STRIP)) + RESET_STIPPLE(); + + switch( mode ) { + case GL_LINES: + if (ctx->Line.StippleFlag) + AUTO_STIPPLE( GL_TRUE ); + break; + case GL_LINE_LOOP: + vb.prim = GL_LINE_STRIP; + push_notify( notify_lineloop0, 1, vb.vertex_store ); + break; + case GL_QUADS: + vb.prim = GL_TRIANGLES; + push_notify( notify_quad, 4, vb.vertex_store ); + break; + case GL_QUAD_STRIP: + if (ctx->_TriangleCaps & DD_FLATSHADE) { + vb.prim = GL_TRIANGLES; + push_notify( notify_qstrip0, 4, vb.vertex_store ); + } + break; + case GL_POLYGON: + if (ctx->_TriangleCaps & DD_FLATSHADE) + se_cntl &= ~RADEON_FLAT_SHADE_VTX_LAST; + break; + default: + break; + } + + if (se_cntl != rmesa->hw.set.cmd[SET_SE_CNTL]) { + RADEON_STATECHANGE( rmesa, set ); + rmesa->hw.set.cmd[SET_SE_CNTL] = se_cntl; + } +} + + +/** + * \brief Process glEnd(). + * + */ +static void radeon_End( void ) +{ + GLcontext *ctx = vb.context; + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if (ctx->Driver.CurrentExecPrimitive == GL_POLYGON+1) { + _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" ); + return; + } + + /* Need to finish a line loop? + */ + if (ctx->Driver.CurrentExecPrimitive == GL_LINE_LOOP) + emit_vertex( 0 ); + + /* Need to pop off quads/quadstrip/etc notification? + */ + if (vb.stack[0].notify != notify_wrap_buffer) + pop_notify(); + + finish_prim( rmesa ); + + if (ctx->Driver.CurrentExecPrimitive == GL_LINES && ctx->Line.StippleFlag) + AUTO_STIPPLE( GL_FALSE ); + + ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1; + notify_noop(); +} + + + +/** + * \brief Flush vertices. + * + * \param ctx GL context. + * \param flags flags. + * + * If FLUSH_UPDATE_CURRENT is et in \p flags then the current vertex attributes + * in the GL context is updated from vb_t::floatcolorptr and vb_t::texcoordptr. + */ +static void radeonFlushVertices( GLcontext *ctx, GLuint flags ) +{ + if (flags & FLUSH_UPDATE_CURRENT) { + ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0] = vb.floatcolorptr[0]; + ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1] = vb.floatcolorptr[1]; + ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2] = vb.floatcolorptr[2]; + ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = vb.floatcolorptr[3]; + + if (vb.vertex_format & RADEON_CP_VC_FRMT_ST0) { + ctx->Current.Attrib[VERT_ATTRIB_TEX0][0] = vb.texcoordptr[0]; + ctx->Current.Attrib[VERT_ATTRIB_TEX0][1] = vb.texcoordptr[1]; + ctx->Current.Attrib[VERT_ATTRIB_TEX0][2] = 0.0F; + ctx->Current.Attrib[VERT_ATTRIB_TEX0][3] = 1.0F; + } + } + + ctx->Driver.NeedFlush &= ~FLUSH_STORED_VERTICES; +} + + +/** + * \brief Set current vertex coordinates. + * + * \param x x vertex coordinate. + * \param y y vertex coordinate. + * \param z z vertex coordinate. + * + * Set the current vertex coordinates. If run out of space in this buffer call + * the notification callback. + */ +static __inline__ void radeon_Vertex3f( GLfloat x, GLfloat y, GLfloat z ) +{ + int i; + + *vb.stack[0].dmaptr++ = *(int *)&x; + *vb.stack[0].dmaptr++ = *(int *)&y; + *vb.stack[0].dmaptr++ = *(int *)&z; + + for (i = 3; i < vb.vertex_size; i++) + *vb.stack[0].dmaptr++ = vb.vertex[i].i; + + if (--vb.stack[0].vertspace == 0) + vb.stack[0].notify(); +} + +/** + * \brief Set current vertex color. + * + * \param r red color component. + * \param g gree color component. + * \param b blue color component. + * \param a alpha color component. + * + * Sets the current vertex color via vb_t::floatcolorptr. + */ +static __inline__ void radeon_Color4f( GLfloat r, GLfloat g, + GLfloat b, GLfloat a ) +{ + GLfloat *dest = vb.floatcolorptr; + dest[0] = r; + dest[1] = g; + dest[2] = b; + dest[3] = a; +} + +/** + * \brief Set current vertex texture coordinates. + * + * \param s texture coordinate. + * \param t texture coordinate. + * + * Sets the current vertex color via vb_t::texcoordptr. + */ +static __inline__ void radeon_TexCoord2f( GLfloat s, GLfloat t ) +{ + GLfloat *dest = vb.texcoordptr; + dest[0] = s; + dest[1] = t; +} + +/** + * Calls radeon_Vertex3f(), which is expanded inline by the compiler to be + * efficient. + */ +static void radeon_Vertex3fv( const GLfloat *v ) +{ + radeon_Vertex3f( v[0], v[1], v[2] ); +} + +/** + * Calls radeon_Vertex3f(), which is expanded inline by the compiler to be + * efficient. + */ +static void radeon_Vertex2f( GLfloat x, GLfloat y ) +{ + radeon_Vertex3f( x, y, 0 ); +} + +/** + * Calls radeon_Vertex3f(), which is expanded inline by the compiler to be + * efficient. + */ +static void radeon_Vertex2fv( const GLfloat *v ) +{ + radeon_Vertex3f( v[0], v[1], 0 ); +} + +/** + * Calls radeon_Vertex3f(), which is expanded inline by the compiler to be + * efficient. + */ +static void radeon_Color4fv( const GLfloat *v ) +{ + radeon_Color4f( v[0], v[1], v[2], v[3] ); +} + +/** + * Calls radeon_Color4f(), which is expanded inline by the compiler to be + * efficient. + */ +static void radeon_Color3f( GLfloat r, GLfloat g, GLfloat b ) +{ + radeon_Color4f( r, g, b, 1.0 ); +} + +/** + * Calls radeon_Color4f(), which is expanded inline by the compiler to be + * efficient. + */ +static void radeon_Color3fv( const GLfloat *v ) +{ + radeon_Color4f( v[0], v[1], v[2], 1.0 ); +} + +/** + * Calls radeon_TexCoord2f(), which is expanded inline by the compiler to be + * efficient. + */ +static void radeon_TexCoord2fv( const GLfloat *v ) +{ + radeon_TexCoord2f( v[0], v[1] ); +} + + +/** + * No-op. + */ +void radeonVtxfmtUnbindContext( GLcontext *ctx ) +{ +} + +/** + * No-op. + */ +void radeonVtxfmtMakeCurrent( GLcontext *ctx ) +{ +} + +/** + * No-op. + */ +void radeonVtxfmtDestroy( GLcontext *ctx ) +{ +} + +/** + * \brief Software rendering fallback. + * + * \param ctx GL context. + * \param bit fallback bitmask. + * \param mode enable or disable. + * + * Does nothing except display a warning message if \p mode is set. + */ +void radeonFallback( GLcontext *ctx, GLuint bit, GLboolean mode ) +{ + if (mode) + fprintf(stderr, "Warning: hit nonexistant fallback path!\n"); +} + +/** + * \brief Software TCL fallback. + * + * \param ctx GL context. + * \param bit fallback bitmask. + * \param mode enable or disable. + * + * Does nothing except display a warning message if \p mode is set. + */ +void radeonTclFallback( GLcontext *ctx, GLuint bit, GLboolean mode ) +{ + if (mode) + fprintf(stderr, "Warning: hit nonexistant fallback path!\n"); +} + +/** + * \brief Called by radeonPointsBitmap() to disable TCL. + * + * \param rmesa Radeon context. + * \param flag whether to enable or disable TCL. + * + * Updates radeon_tcl_info::tcl_flag. + */ +void radeonSubsetVtxEnableTCL( radeonContextPtr rmesa, GLboolean flag ) +{ + rmesa->tcl.tcl_flag = flag ? RADEON_CP_VC_CNTL_TCL_ENABLE : 0; +} + + + +/**********************************************************************/ +/** \name Noop mode for operation without focus */ +/**********************************************************************/ +/*@{*/ + + +/** + * \brief Process glBegin(). + * + * \param mode primitive. + */ +static void radeon_noop_Begin(GLenum mode) +{ + GET_CURRENT_CONTEXT(ctx); + + if (mode > GL_POLYGON) { + _mesa_error( ctx, GL_INVALID_ENUM, "glBegin" ); + return; + } + + if (ctx->Driver.CurrentExecPrimitive != GL_POLYGON+1) { + _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" ); + return; + } + + ctx->Driver.CurrentExecPrimitive = mode; +} + +/** + * \brief Process glEnd(). + */ +static void radeon_noop_End(void) +{ + GET_CURRENT_CONTEXT(ctx); + ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1; +} + + +/** + * \brief Install the noop callbacks. + * + * \param ctx GL context. + * + * Installs the noop callbacks into the glapi table. These functions + * will not attempt to emit any DMA vertices, but will keep internal + * GL state updated. Borrows heavily from the select code. + */ +static void radeon_noop_Install( GLcontext *ctx ) +{ + ctx->Exec->Begin = radeon_noop_Begin; + ctx->Exec->End = radeon_noop_End; + + vb.texcoordptr = ctx->Current.Attrib[VERT_ATTRIB_TEX0]; + vb.floatcolorptr = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; + + notify_noop(); +} + + +/** + * \brief Setup the GL context callbacks. + * + * \param ctx GL context. + * + * Setups the GL context callbacks and links _glapi_table entries related to + * the glBegin()/glEnd() pairs to the functions in this module. + * + * Called by radeonCreateContext() and radeonRenderMode(). + */ +void radeonVtxfmtInit( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct _glapi_table *exec = ctx->Exec; + + exec->Color3f = radeon_Color3f; + exec->Color3fv = radeon_Color3fv; + exec->Color4f = radeon_Color4f; + exec->Color4fv = radeon_Color4fv; + exec->TexCoord2f = radeon_TexCoord2f; + exec->TexCoord2fv = radeon_TexCoord2fv; + exec->Vertex2f = radeon_Vertex2f; + exec->Vertex2fv = radeon_Vertex2fv; + exec->Vertex3f = radeon_Vertex3f; + exec->Vertex3fv = radeon_Vertex3fv; + exec->Begin = radeon_Begin; + exec->End = radeon_End; + + vb.context = ctx; + + ctx->Driver.FlushVertices = radeonFlushVertices; + ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1; + + if (rmesa->radeonScreen->buffers) { + radeonVtxfmtValidate( ctx ); + notify_noop(); + } + else + radeon_noop_Install( ctx ); +} + + +/*@}*/ + + diff --git a/src/mesa/drivers/dri/radeon/radeon_swtcl.c b/src/mesa/drivers/dri/radeon/radeon_swtcl.c new file mode 100644 index 0000000000..926b1523d6 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_swtcl.c @@ -0,0 +1,1332 @@ +/* $XFree86$ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "glheader.h" +#include "mtypes.h" +#include "colormac.h" +#include "enums.h" +#include "imports.h" +#include "macros.h" + +#include "swrast_setup/swrast_setup.h" +#include "math/m_translate.h" +#include "tnl/tnl.h" +#include "tnl/t_context.h" +#include "tnl/t_imm_exec.h" +#include "tnl/t_pipeline.h" + +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_state.h" +#include "radeon_swtcl.h" +#include "radeon_tcl.h" + +/*********************************************************************** + * Build render functions from dd templates * + ***********************************************************************/ + + +#define RADEON_XYZW_BIT 0x01 +#define RADEON_RGBA_BIT 0x02 +#define RADEON_SPEC_BIT 0x04 +#define RADEON_TEX0_BIT 0x08 +#define RADEON_TEX1_BIT 0x10 +#define RADEON_PTEX_BIT 0x20 +#define RADEON_MAX_SETUP 0x40 + +static void flush_last_swtcl_prim( radeonContextPtr rmesa ); +static void flush_last_swtcl_prim_compat( radeonContextPtr rmesa ); + +static struct { + void (*emit)( GLcontext *, GLuint, GLuint, void *, GLuint ); + interp_func interp; + copy_pv_func copy_pv; + GLboolean (*check_tex_sizes)( GLcontext *ctx ); + GLuint vertex_size; + GLuint vertex_stride_shift; + GLuint vertex_format; +} setup_tab[RADEON_MAX_SETUP]; + + +#define TINY_VERTEX_FORMAT (RADEON_CP_VC_FRMT_XY | \ + RADEON_CP_VC_FRMT_Z | \ + RADEON_CP_VC_FRMT_PKCOLOR) + +#define NOTEX_VERTEX_FORMAT (RADEON_CP_VC_FRMT_XY | \ + RADEON_CP_VC_FRMT_Z | \ + RADEON_CP_VC_FRMT_W0 | \ + RADEON_CP_VC_FRMT_PKCOLOR | \ + RADEON_CP_VC_FRMT_PKSPEC) + +#define TEX0_VERTEX_FORMAT (RADEON_CP_VC_FRMT_XY | \ + RADEON_CP_VC_FRMT_Z | \ + RADEON_CP_VC_FRMT_W0 | \ + RADEON_CP_VC_FRMT_PKCOLOR | \ + RADEON_CP_VC_FRMT_PKSPEC | \ + RADEON_CP_VC_FRMT_ST0) + +#define TEX1_VERTEX_FORMAT (RADEON_CP_VC_FRMT_XY | \ + RADEON_CP_VC_FRMT_Z | \ + RADEON_CP_VC_FRMT_W0 | \ + RADEON_CP_VC_FRMT_PKCOLOR | \ + RADEON_CP_VC_FRMT_PKSPEC | \ + RADEON_CP_VC_FRMT_ST0 | \ + RADEON_CP_VC_FRMT_ST1) + +#define PROJ_TEX1_VERTEX_FORMAT (RADEON_CP_VC_FRMT_XY | \ + RADEON_CP_VC_FRMT_Z | \ + RADEON_CP_VC_FRMT_W0 | \ + RADEON_CP_VC_FRMT_PKCOLOR | \ + RADEON_CP_VC_FRMT_PKSPEC | \ + RADEON_CP_VC_FRMT_ST0 | \ + RADEON_CP_VC_FRMT_Q0 | \ + RADEON_CP_VC_FRMT_ST1 | \ + RADEON_CP_VC_FRMT_Q1) + +#define TEX2_VERTEX_FORMAT 0 +#define TEX3_VERTEX_FORMAT 0 +#define PROJ_TEX3_VERTEX_FORMAT 0 + +#define DO_XYZW (IND & RADEON_XYZW_BIT) +#define DO_RGBA (IND & RADEON_RGBA_BIT) +#define DO_SPEC (IND & RADEON_SPEC_BIT) +#define DO_FOG (IND & RADEON_SPEC_BIT) +#define DO_TEX0 (IND & RADEON_TEX0_BIT) +#define DO_TEX1 (IND & RADEON_TEX1_BIT) +#define DO_TEX2 0 +#define DO_TEX3 0 +#define DO_PTEX (IND & RADEON_PTEX_BIT) + +#define VERTEX radeonVertex +#define VERTEX_COLOR radeon_color_t +#define GET_VIEWPORT_MAT() 0 +#define GET_TEXSOURCE(n) n +#define GET_VERTEX_FORMAT() RADEON_CONTEXT(ctx)->swtcl.vertex_format +#define GET_VERTEX_STORE() RADEON_CONTEXT(ctx)->swtcl.verts +#define GET_VERTEX_STRIDE_SHIFT() RADEON_CONTEXT(ctx)->swtcl.vertex_stride_shift +#define GET_UBYTE_COLOR_STORE() &RADEON_CONTEXT(ctx)->UbyteColor +#define GET_UBYTE_SPEC_COLOR_STORE() &RADEON_CONTEXT(ctx)->UbyteSecondaryColor + +#define HAVE_HW_VIEWPORT 1 +/* Tiny vertices don't seem to work atm - haven't looked into why. + */ +#define HAVE_HW_DIVIDE (IND & ~(RADEON_XYZW_BIT|RADEON_RGBA_BIT)) +#define HAVE_TINY_VERTICES 1 +#define HAVE_RGBA_COLOR 1 +#define HAVE_NOTEX_VERTICES 1 +#define HAVE_TEX0_VERTICES 1 +#define HAVE_TEX1_VERTICES 1 +#define HAVE_TEX2_VERTICES 0 +#define HAVE_TEX3_VERTICES 0 +#define HAVE_PTEX_VERTICES 1 + +#define CHECK_HW_DIVIDE (!(ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE| \ + DD_TRI_UNFILLED))) + +#define IMPORT_QUALIFIER +#define IMPORT_FLOAT_COLORS radeon_import_float_colors +#define IMPORT_FLOAT_SPEC_COLORS radeon_import_float_spec_colors + +#define INTERP_VERTEX setup_tab[RADEON_CONTEXT(ctx)->swtcl.SetupIndex].interp +#define COPY_PV_VERTEX setup_tab[RADEON_CONTEXT(ctx)->swtcl.SetupIndex].copy_pv + + +/*********************************************************************** + * Generate pv-copying and translation functions * + ***********************************************************************/ + +#define TAG(x) radeon_##x +#define IND ~0 +#include "tnl_dd/t_dd_vb.c" +#undef IND + + +/*********************************************************************** + * Generate vertex emit and interp functions * + ***********************************************************************/ + +#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT) +#define TAG(x) x##_wg +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_TEX0_BIT) +#define TAG(x) x##_wgt0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_TEX0_BIT|RADEON_PTEX_BIT) +#define TAG(x) x##_wgpt0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_TEX0_BIT|RADEON_TEX1_BIT) +#define TAG(x) x##_wgt0t1 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_TEX0_BIT|RADEON_TEX1_BIT|\ + RADEON_PTEX_BIT) +#define TAG(x) x##_wgpt0t1 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_SPEC_BIT) +#define TAG(x) x##_wgfs +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_SPEC_BIT|\ + RADEON_TEX0_BIT) +#define TAG(x) x##_wgfst0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_SPEC_BIT|\ + RADEON_TEX0_BIT|RADEON_PTEX_BIT) +#define TAG(x) x##_wgfspt0 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_SPEC_BIT|\ + RADEON_TEX0_BIT|RADEON_TEX1_BIT) +#define TAG(x) x##_wgfst0t1 +#include "tnl_dd/t_dd_vbtmp.h" + +#define IND (RADEON_XYZW_BIT|RADEON_RGBA_BIT|RADEON_SPEC_BIT|\ + RADEON_TEX0_BIT|RADEON_TEX1_BIT|RADEON_PTEX_BIT) +#define TAG(x) x##_wgfspt0t1 +#include "tnl_dd/t_dd_vbtmp.h" + + +/*********************************************************************** + * Initialization + ***********************************************************************/ + +static void init_setup_tab( void ) +{ + init_wg(); + init_wgt0(); + init_wgpt0(); + init_wgt0t1(); + init_wgpt0t1(); + init_wgfs(); + init_wgfst0(); + init_wgfspt0(); + init_wgfst0t1(); + init_wgfspt0t1(); +} + + + +void radeonPrintSetupFlags(char *msg, GLuint flags ) +{ + fprintf(stderr, "%s(%x): %s%s%s%s%s%s\n", + msg, + (int)flags, + (flags & RADEON_XYZW_BIT) ? " xyzw," : "", + (flags & RADEON_RGBA_BIT) ? " rgba," : "", + (flags & RADEON_SPEC_BIT) ? " spec/fog," : "", + (flags & RADEON_TEX0_BIT) ? " tex-0," : "", + (flags & RADEON_TEX1_BIT) ? " tex-1," : "", + (flags & RADEON_PTEX_BIT) ? " proj-tex," : ""); +} + + +static void radeonRenderStart( GLcontext *ctx ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + + if (!setup_tab[rmesa->swtcl.SetupIndex].check_tex_sizes(ctx)) { + GLuint ind = rmesa->swtcl.SetupIndex |= (RADEON_PTEX_BIT|RADEON_RGBA_BIT); + + /* Projective textures are handled nicely; just have to change + * up to the new vertex format. + */ + if (setup_tab[ind].vertex_format != rmesa->swtcl.vertex_format) { + RADEON_NEWPRIM(rmesa); + rmesa->swtcl.vertex_format = setup_tab[ind].vertex_format; + rmesa->swtcl.vertex_size = setup_tab[ind].vertex_size; + rmesa->swtcl.vertex_stride_shift = setup_tab[ind].vertex_stride_shift; + } + + if (!(ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED))) { + tnl->Driver.Render.Interp = setup_tab[rmesa->swtcl.SetupIndex].interp; + tnl->Driver.Render.CopyPV = setup_tab[rmesa->swtcl.SetupIndex].copy_pv; + } + } + + if (rmesa->dma.flush != 0 && + rmesa->dma.flush != flush_last_swtcl_prim_compat && + rmesa->dma.flush != flush_last_swtcl_prim) + rmesa->dma.flush( rmesa ); +} + + +void radeonBuildVertices( GLcontext *ctx, GLuint start, GLuint count, + GLuint newinputs ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + GLubyte *v = ((GLubyte *)rmesa->swtcl.verts + + (start << rmesa->swtcl.vertex_stride_shift)); + GLuint stride = 1 << rmesa->swtcl.vertex_stride_shift; + + newinputs |= rmesa->swtcl.SetupNewInputs; + rmesa->swtcl.SetupNewInputs = 0; + + if (!newinputs) + return; + + setup_tab[rmesa->swtcl.SetupIndex].emit( ctx, start, count, v, stride ); +} + +void radeonChooseVertexState( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + TNLcontext *tnl = TNL_CONTEXT(ctx); + GLuint ind = (RADEON_XYZW_BIT | RADEON_RGBA_BIT); + + if (!rmesa->TclFallback || rmesa->Fallback) + return; + + if (ctx->Fog.Enabled || (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR)) + ind |= RADEON_SPEC_BIT; + + if (ctx->Texture._EnabledUnits & 0x2) + /* unit 1 enabled */ + ind |= RADEON_TEX0_BIT|RADEON_TEX1_BIT; + else if (ctx->Texture._EnabledUnits & 0x1) + /* unit 0 enabled */ + ind |= RADEON_TEX0_BIT; + + rmesa->swtcl.SetupIndex = ind; + + if (ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED)) { + tnl->Driver.Render.Interp = radeon_interp_extras; + tnl->Driver.Render.CopyPV = radeon_copy_pv_extras; + } + else { + tnl->Driver.Render.Interp = setup_tab[ind].interp; + tnl->Driver.Render.CopyPV = setup_tab[ind].copy_pv; + } + + if (setup_tab[ind].vertex_format != rmesa->swtcl.vertex_format) { + RADEON_NEWPRIM(rmesa); + rmesa->swtcl.vertex_format = setup_tab[ind].vertex_format; + rmesa->swtcl.vertex_size = setup_tab[ind].vertex_size; + rmesa->swtcl.vertex_stride_shift = setup_tab[ind].vertex_stride_shift; + } + + { + GLuint se_coord_fmt, needproj; + + /* HW perspective divide is a win, but tiny vertex formats are a + * bigger one. + */ + if (setup_tab[ind].vertex_format == TINY_VERTEX_FORMAT || + (ctx->_TriangleCaps & (DD_TRI_LIGHT_TWOSIDE|DD_TRI_UNFILLED))) { + needproj = GL_TRUE; + se_coord_fmt = (RADEON_VTX_XY_PRE_MULT_1_OVER_W0 | + RADEON_VTX_Z_PRE_MULT_1_OVER_W0 | + RADEON_TEX1_W_ROUTING_USE_Q1); + } + else { + needproj = GL_FALSE; + se_coord_fmt = (RADEON_VTX_W0_IS_NOT_1_OVER_W0 | + RADEON_TEX1_W_ROUTING_USE_Q1); + } + + if ( se_coord_fmt != rmesa->hw.set.cmd[SET_SE_COORDFMT] ) { + RADEON_STATECHANGE( rmesa, set ); + rmesa->hw.set.cmd[SET_SE_COORDFMT] = se_coord_fmt; + } + _tnl_need_projected_coords( ctx, needproj ); + } +} + + +/* Flush vertices in the current dma region. + */ +static void flush_last_swtcl_prim( radeonContextPtr rmesa ) +{ + if (RADEON_DEBUG & DEBUG_IOCTL) + fprintf(stderr, "%s\n", __FUNCTION__); + + rmesa->dma.flush = 0; + + if (rmesa->dma.current.buf) { + struct radeon_dma_region *current = &rmesa->dma.current; + GLuint current_offset = (rmesa->radeonScreen->agp_buffer_offset + + current->buf->buf->idx * RADEON_BUFFER_SIZE + + current->start); + + assert (!(rmesa->swtcl.hw_primitive & RADEON_CP_VC_CNTL_PRIM_WALK_IND)); + + assert (current->start + + rmesa->swtcl.numverts * rmesa->swtcl.vertex_size * 4 == + current->ptr); + + if (rmesa->dma.current.start != rmesa->dma.current.ptr) { + radeonEmitVertexAOS( rmesa, + rmesa->swtcl.vertex_size, + current_offset); + + radeonEmitVbufPrim( rmesa, + rmesa->swtcl.vertex_format, + rmesa->swtcl.hw_primitive, + rmesa->swtcl.numverts); + } + + rmesa->swtcl.numverts = 0; + current->start = current->ptr; + } +} + + +static void flush_last_swtcl_prim_compat( radeonContextPtr rmesa ) +{ + struct radeon_dma_region *current = &rmesa->dma.current; + + if (RADEON_DEBUG & DEBUG_IOCTL) + fprintf(stderr, "%s buf %p start %d ptr %d\n", + __FUNCTION__, + current->buf, + current->start, + current->ptr); + + assert (!(rmesa->swtcl.hw_primitive & RADEON_CP_VC_CNTL_PRIM_WALK_IND)); + assert (current->start + + rmesa->swtcl.numverts * rmesa->swtcl.vertex_size * 4 == + current->ptr); + assert (current->start == 0); + + rmesa->dma.flush = 0; + + if (current->ptr && current->buf) { + assert (current->buf->refcount == 1); + + radeonCompatEmitPrimitive( rmesa, + rmesa->swtcl.vertex_format, + rmesa->swtcl.hw_primitive, + rmesa->swtcl.numverts); + + /* The buffer has been released: + */ + FREE(current->buf); + current->buf = 0; + current->start = 0; + current->ptr = current->end; + + } + + rmesa->swtcl.numverts = 0; +} + + +/* Alloc space in the current dma region. + */ +static __inline void *radeonAllocDmaLowVerts( radeonContextPtr rmesa, + int nverts, int vsize ) +{ + GLuint bytes = vsize * nverts; + + if ( rmesa->dma.current.ptr + bytes > rmesa->dma.current.end ) + radeonRefillCurrentDmaRegion( rmesa ); + + if (!rmesa->dma.flush) { + rmesa->glCtx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; + if (rmesa->dri.drmMinor == 1) + rmesa->dma.flush = flush_last_swtcl_prim_compat; + else + rmesa->dma.flush = flush_last_swtcl_prim; + } + + assert( vsize == rmesa->swtcl.vertex_size * 4 ); + assert( rmesa->dma.flush == flush_last_swtcl_prim || + rmesa->dma.flush == flush_last_swtcl_prim_compat); + assert (rmesa->dma.current.start + + rmesa->swtcl.numverts * rmesa->swtcl.vertex_size * 4 == + rmesa->dma.current.ptr); + + + { + char *head = rmesa->dma.current.address + rmesa->dma.current.ptr; + rmesa->dma.current.ptr += bytes; + rmesa->swtcl.numverts += nverts; + return head; + } + +} + + + + +void radeon_emit_contiguous_verts( GLcontext *ctx, GLuint start, GLuint count ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint vertex_size = rmesa->swtcl.vertex_size * 4; + CARD32 *dest = radeonAllocDmaLowVerts( rmesa, count-start, vertex_size ); + setup_tab[rmesa->swtcl.SetupIndex].emit( ctx, start, count, dest, + vertex_size ); +} + + + +void radeon_emit_indexed_verts( GLcontext *ctx, GLuint start, GLuint count ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + radeonAllocDmaRegionVerts( rmesa, + &rmesa->swtcl.indexed_verts, + count - start, + rmesa->swtcl.vertex_size * 4, + 64); + + setup_tab[rmesa->swtcl.SetupIndex].emit( + ctx, start, count, + rmesa->swtcl.indexed_verts.address + rmesa->swtcl.indexed_verts.start, + rmesa->swtcl.vertex_size * 4 ); +} + + +/* + * 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 1 +#define HAVE_LINES 1 +#define HAVE_LINE_STRIPS 1 +#define HAVE_TRIANGLES 1 +#define HAVE_TRI_STRIPS 1 +#define HAVE_TRI_STRIP_1 0 +#define HAVE_TRI_FANS 1 +#define HAVE_QUADS 0 +#define HAVE_QUAD_STRIPS 0 +#define HAVE_POLYGONS 0 +#define HAVE_ELTS 1 + +static const GLuint hw_prim[GL_POLYGON+1] = { + RADEON_CP_VC_CNTL_PRIM_TYPE_POINT, + RADEON_CP_VC_CNTL_PRIM_TYPE_LINE, + 0, + RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP, + RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST, + RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP, + RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN, + 0, + 0, + 0 +}; + +static __inline void radeonDmaPrimitive( radeonContextPtr rmesa, GLenum prim ) +{ + RADEON_NEWPRIM( rmesa ); + rmesa->swtcl.hw_primitive = hw_prim[prim]; + assert(rmesa->dma.current.ptr == rmesa->dma.current.start); +} + +static __inline void radeonEltPrimitive( radeonContextPtr rmesa, GLenum prim ) +{ + RADEON_NEWPRIM( rmesa ); + rmesa->swtcl.hw_primitive = hw_prim[prim] | RADEON_CP_VC_CNTL_PRIM_WALK_IND; +} + + +static void VERT_FALLBACK( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint flags ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + tnl->Driver.Render.PrimitiveNotify( ctx, flags & PRIM_MODE_MASK ); + tnl->Driver.Render.BuildVertices( ctx, start, count, ~0 ); + tnl->Driver.Render.PrimTabVerts[flags&PRIM_MODE_MASK]( ctx, start, count, flags ); + RADEON_CONTEXT(ctx)->swtcl.SetupNewInputs = VERT_BIT_CLIP; +} + +static void ELT_FALLBACK( GLcontext *ctx, + GLuint start, + GLuint count, + GLuint flags ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + tnl->Driver.Render.PrimitiveNotify( ctx, flags & PRIM_MODE_MASK ); + tnl->Driver.Render.BuildVertices( ctx, start, count, ~0 ); + tnl->Driver.Render.PrimTabElts[flags&PRIM_MODE_MASK]( ctx, start, count, flags ); + RADEON_CONTEXT(ctx)->swtcl.SetupNewInputs = VERT_BIT_CLIP; +} + + +#define LOCAL_VARS radeonContextPtr rmesa = RADEON_CONTEXT(ctx) +#define ELTS_VARS GLushort *dest +#define INIT( prim ) radeonDmaPrimitive( rmesa, prim ) +#define ELT_INIT(prim) radeonEltPrimitive( rmesa, prim ) +#define NEW_PRIMITIVE() RADEON_NEWPRIM( rmesa ) +#define NEW_BUFFER() radeonRefillCurrentDmaRegion( rmesa ) +#define GET_CURRENT_VB_MAX_VERTS() \ + (((int)rmesa->dma.current.end - (int)rmesa->dma.current.ptr) / (rmesa->swtcl.vertex_size*4)) +#define GET_SUBSEQUENT_VB_MAX_VERTS() \ + ((RADEON_BUFFER_SIZE) / (rmesa->swtcl.vertex_size*4)) + +#if RADEON_OLD_PACKETS +# define GET_CURRENT_VB_MAX_ELTS() \ + ((RADEON_CMD_BUF_SZ - (rmesa->store.cmd_used + 24)) / 2) +#else +# define GET_CURRENT_VB_MAX_ELTS() \ + ((RADEON_CMD_BUF_SZ - (rmesa->store.cmd_used + 16)) / 2) +#endif +#define GET_SUBSEQUENT_VB_MAX_ELTS() \ + ((RADEON_CMD_BUF_SZ - 1024) / 2) + + + +/* How do you extend an existing primitive? + */ +#define ALLOC_ELTS(nr) \ +do { \ + if (rmesa->dma.flush == radeonFlushElts && \ + rmesa->store.cmd_used + nr*2 < RADEON_CMD_BUF_SZ) { \ + \ + dest = (GLushort *)(rmesa->store.cmd_buf + \ + rmesa->store.cmd_used); \ + rmesa->store.cmd_used += nr*2; \ + } \ + else { \ + if (rmesa->dma.flush) { \ + rmesa->dma.flush( rmesa ); \ + } \ + \ + radeonEmitVertexAOS( rmesa, \ + rmesa->swtcl.vertex_size, \ + (rmesa->radeonScreen->agp_buffer_offset + \ + rmesa->swtcl.indexed_verts.buf->buf->idx * \ + RADEON_BUFFER_SIZE + \ + rmesa->swtcl.indexed_verts.start)); \ + \ + dest = radeonAllocEltsOpenEnded( rmesa, \ + rmesa->swtcl.vertex_format, \ + rmesa->swtcl.hw_primitive, \ + nr ); \ + } \ +} while (0) + +#define ALLOC_ELTS_NEW_PRIMITIVE(nr) ALLOC_ELTS( nr ) + +#ifdef MESA_BIG_ENDIAN +/* We could do without (most of) this ugliness if dest was always 32 bit word aligned... */ +#define EMIT_ELT(offset, x) do { \ + int off = offset + ( ( (GLuint)dest & 0x2 ) >> 1 ); \ + GLushort *des = (GLushort *)( (GLuint)dest & ~0x2 ); \ + (des)[ off + 1 - 2 * ( off & 1 ) ] = (GLushort)(x); } while (0) +#else +#define EMIT_ELT(offset, x) (dest)[offset] = (GLushort) (x) +#endif +#define EMIT_TWO_ELTS(offset, x, y) *(GLuint *)(dest+offset) = ((y)<<16)|(x); +#define INCR_ELTS( nr ) dest += nr +#define RELEASE_ELT_VERTS() \ + radeonReleaseDmaRegion( rmesa, &rmesa->swtcl.indexed_verts, __FUNCTION__ ) +#define EMIT_VERTS( ctx, j, nr ) \ + radeon_emit_contiguous_verts(ctx, j, (j)+(nr)) +#define EMIT_INDEXED_VERTS( ctx, start, count ) \ + radeon_emit_indexed_verts( ctx, start, count ) + + +#define TAG(x) radeon_dma_##x +#include "tnl_dd/t_dd_dmatmp.h" + + +/**********************************************************************/ +/* Render pipeline stage */ +/**********************************************************************/ + + +static GLboolean radeon_run_render( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_buffer *VB = &tnl->vb; + GLuint i, length, flags = 0; + render_func *tab = TAG(render_tab_verts); + + if (rmesa->swtcl.indexed_verts.buf && (!VB->Elts || stage->changed_inputs)) + RELEASE_ELT_VERTS(); + + if (VB->ClipOrMask || /* No clipping */ + rmesa->swtcl.RenderIndex != 0 || /* No per-vertex manipulations */ + ctx->Line.StippleFlag) /* GH: THIS IS A HACK!!! */ + return GL_TRUE; + + if (rmesa->dri.drmMinor < 3) { + /* drm 1.1 doesn't support vertex primitives starting in the + * middle of a buffer. It doesn't support sane indexed vertices + * either. drm 1.2 fixes both of these problems, but we don't have a + * compatibility layer to that version yet. + */ + return GL_TRUE; + } + + tnl->Driver.Render.Start( ctx ); + + if (VB->Elts) { + tab = TAG(render_tab_elts); + if (!rmesa->swtcl.indexed_verts.buf) + if (!TAG(emit_elt_verts)(ctx, 0, VB->Count)) + return GL_TRUE; /* too many vertices */ + } + + for (i = 0 ; !(flags & PRIM_LAST) ; i += length) + { + flags = VB->Primitive[i]; + length = VB->PrimitiveLength[i]; + + if (RADEON_DEBUG & DEBUG_PRIMS) + fprintf(stderr, "radeon_render.c: prim %s %d..%d\n", + _mesa_lookup_enum_by_nr(flags & PRIM_MODE_MASK), + i, i+length); + + if (length) + tab[flags & PRIM_MODE_MASK]( ctx, i, i + length, flags ); + } + + tnl->Driver.Render.Finish( ctx ); + + return GL_FALSE; /* finished the pipe */ +} + + + +static void radeon_check_render( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + GLuint inputs = VERT_BIT_POS | VERT_BIT_CLIP | VERT_BIT_COLOR0; + + if (ctx->RenderMode == GL_RENDER) { + if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) + inputs |= VERT_BIT_COLOR1; + + if (ctx->Texture.Unit[0]._ReallyEnabled) + inputs |= VERT_BIT_TEX0; + + if (ctx->Texture.Unit[1]._ReallyEnabled) + inputs |= VERT_BIT_TEX1; + + if (ctx->Fog.Enabled) + inputs |= VERT_BIT_FOG; + } + + stage->inputs = inputs; +} + + +static void dtr( struct gl_pipeline_stage *stage ) +{ + (void)stage; +} + + +const struct gl_pipeline_stage _radeon_render_stage = +{ + "radeon render", + (_DD_NEW_SEPARATE_SPECULAR | + _NEW_TEXTURE| + _NEW_FOG| + _NEW_RENDERMODE), /* re-check (new inputs) */ + 0, /* re-run (always runs) */ + GL_TRUE, /* active */ + 0, 0, /* inputs (set in check_render), outputs */ + 0, 0, /* changed_inputs, private */ + dtr, /* destructor */ + radeon_check_render, /* check - initially set to alloc data */ + radeon_run_render /* run */ +}; + + +/**************************************************************************/ + +/* Radeon texture rectangle expects coords in 0..1 range, not 0..dimension + * as in the extension spec. Need to translate here. + * + * Note that swrast expects 0..dimension, so if a fallback is active, + * don't do anything. (Maybe need to configure swrast to match hw) + */ +struct texrect_stage_data { + GLvector4f texcoord[MAX_TEXTURE_UNITS]; +}; + +#define TEXRECT_STAGE_DATA(stage) ((struct texrect_stage_data *)stage->privatePtr) + + +static GLboolean run_texrect_stage( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + struct texrect_stage_data *store = TEXRECT_STAGE_DATA(stage); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_buffer *VB = &tnl->vb; + GLuint i; + + if (rmesa->Fallback) + return GL_TRUE; + + for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) { + if (!(ctx->Texture.Unit[i]._ReallyEnabled & TEXTURE_RECT_BIT)) + continue; + + if (stage->changed_inputs & VERT_BIT_TEX(i)) { + struct gl_texture_object *texObj = ctx->Texture.Unit[i].CurrentRect; + struct gl_texture_image *texImage = texObj->Image[texObj->BaseLevel]; + const GLfloat iw = 1.0/texImage->Width; + const GLfloat ih = 1.0/texImage->Height; + GLfloat *in = (GLfloat *)VB->TexCoordPtr[i]->data; + GLint instride = VB->TexCoordPtr[i]->stride; + GLfloat (*out)[4] = store->texcoord[i].data; + GLint j; + + for (j = 0 ; j < VB->Count ; j++) { + out[j][0] = in[0] * iw; + out[j][1] = in[1] * ih; + in = (GLfloat *)((GLubyte *)in + instride); + } + } + + VB->TexCoordPtr[i] = &store->texcoord[i]; + } + + return GL_TRUE; +} + + +/* Called the first time stage->run() is invoked. + */ +static GLboolean alloc_texrect_data( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + struct vertex_buffer *VB = &TNL_CONTEXT(ctx)->vb; + struct texrect_stage_data *store; + GLuint i; + + stage->privatePtr = CALLOC(sizeof(*store)); + store = TEXRECT_STAGE_DATA(stage); + if (!store) + return GL_FALSE; + + for (i = 0 ; i < ctx->Const.MaxTextureUnits ; i++) + _mesa_vector4f_alloc( &store->texcoord[i], 0, VB->Size, 32 ); + + /* Now run the stage. + */ + stage->run = run_texrect_stage; + return stage->run( ctx, stage ); +} + + +static void check_texrect( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + GLuint flags = 0; + + if (ctx->Texture.Unit[0]._ReallyEnabled & TEXTURE_RECT_BIT) + flags |= VERT_BIT_TEX0; + + if (ctx->Texture.Unit[1]._ReallyEnabled & TEXTURE_RECT_BIT) + flags |= VERT_BIT_TEX1; + + stage->inputs = flags; + stage->outputs = flags; + stage->active = (flags != 0); +} + + +static void free_texrect_data( struct gl_pipeline_stage *stage ) +{ + struct texrect_stage_data *store = TEXRECT_STAGE_DATA(stage); + GLuint i; + + if (store) { + for (i = 0 ; i < MAX_TEXTURE_UNITS ; i++) + if (store->texcoord[i].data) + _mesa_vector4f_free( &store->texcoord[i] ); + FREE( store ); + stage->privatePtr = 0; + } +} + + +const struct gl_pipeline_stage _radeon_texrect_stage = +{ + "radeon texrect stage", /* name */ + _NEW_TEXTURE, /* check_state */ + _NEW_TEXTURE, /* run_state */ + GL_TRUE, /* active? */ + 0, /* inputs */ + 0, /* outputs */ + 0, /* changed_inputs */ + NULL, /* private data */ + free_texrect_data, /* destructor */ + check_texrect, /* check */ + alloc_texrect_data, /* run -- initially set to init */ +}; + + +/**************************************************************************/ + + +static const GLuint reduced_hw_prim[GL_POLYGON+1] = { + RADEON_CP_VC_CNTL_PRIM_TYPE_POINT, + RADEON_CP_VC_CNTL_PRIM_TYPE_LINE, + RADEON_CP_VC_CNTL_PRIM_TYPE_LINE, + RADEON_CP_VC_CNTL_PRIM_TYPE_LINE, + RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST, + RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST, + RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST, + RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST, + RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST, + RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST +}; + +static void radeonRasterPrimitive( GLcontext *ctx, GLuint hwprim ); +static void radeonRenderPrimitive( GLcontext *ctx, GLenum prim ); +static void radeonResetLineStipple( GLcontext *ctx ); + + +/*********************************************************************** + * Emit primitives as inline vertices * + ***********************************************************************/ + +#undef LOCAL_VARS +#define CTX_ARG radeonContextPtr rmesa +#define CTX_ARG2 rmesa +#define GET_VERTEX_DWORDS() rmesa->swtcl.vertex_size +#define ALLOC_VERTS( n, size ) radeonAllocDmaLowVerts( rmesa, n, size * 4 ) +#undef LOCAL_VARS +#define LOCAL_VARS \ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \ + const GLuint shift = rmesa->swtcl.vertex_stride_shift; \ + const char *radeonverts = (char *)rmesa->swtcl.verts; +#define VERT(x) (radeonVertex *)(radeonverts + (x << shift)) +#define VERTEX radeonVertex +#undef TAG +#define TAG(x) radeon_##x +#include "tnl_dd/t_dd_triemit.h" + + +/*********************************************************************** + * Macros for t_dd_tritmp.h to draw basic primitives * + ***********************************************************************/ + +#define QUAD( a, b, c, d ) radeon_quad( rmesa, a, b, c, d ) +#define TRI( a, b, c ) radeon_triangle( rmesa, a, b, c ) +#define LINE( a, b ) radeon_line( rmesa, a, b ) +#define POINT( a ) radeon_point( rmesa, a ) + +/*********************************************************************** + * Build render functions from dd templates * + ***********************************************************************/ + +#define RADEON_TWOSIDE_BIT 0x01 +#define RADEON_UNFILLED_BIT 0x02 +#define RADEON_OFFSET_BIT 0x04 /* drmMinor == 1 */ +#define RADEON_MAX_TRIFUNC 0x08 + + +static struct { + points_func points; + line_func line; + triangle_func triangle; + quad_func quad; +} rast_tab[RADEON_MAX_TRIFUNC]; + + +#define DO_FALLBACK 0 +#define DO_OFFSET (IND & RADEON_OFFSET_BIT) +#define DO_UNFILLED (IND & RADEON_UNFILLED_BIT) +#define DO_TWOSIDE (IND & RADEON_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_INDEX 0 +#define HAVE_BACK_COLORS 0 +#define HAVE_HW_FLATSHADE 1 +#define TAB rast_tab + +#define DEPTH_SCALE 1.0 +#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) (rmesa->swtcl.verts + (e<<rmesa->swtcl.vertex_stride_shift)) + +#define VERT_SET_RGBA( v, c ) v->ui[coloroffset] = LE32_TO_CPU(*(GLuint *)c) +#define VERT_COPY_RGBA( v0, v1 ) v0->ui[coloroffset] = v1->ui[coloroffset] +#define VERT_SAVE_RGBA( idx ) color[idx] = CPU_TO_LE32(v[idx]->ui[coloroffset]) +#define VERT_RESTORE_RGBA( idx ) v[idx]->ui[coloroffset] = LE32_TO_CPU(color[idx]) + +#define VERT_SET_SPEC( v0, c ) if (havespec) { \ + v0->v.specular.red = (c)[0]; \ + v0->v.specular.green = (c)[1]; \ + v0->v.specular.blue = (c)[2]; } +#define VERT_COPY_SPEC( v0, v1 ) if (havespec) { \ + v0->v.specular.red = v1->v.specular.red; \ + v0->v.specular.green = v1->v.specular.green; \ + v0->v.specular.blue = v1->v.specular.blue; } +#define VERT_SAVE_SPEC( idx ) if (havespec) spec[idx] = CPU_TO_LE32(v[idx]->ui[5]) +#define VERT_RESTORE_SPEC( idx ) if (havespec) v[idx]->ui[5] = LE32_TO_CPU(spec[idx]) + +#undef LOCAL_VARS +#undef TAG +#undef INIT + +#define LOCAL_VARS(n) \ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \ + GLuint color[n], spec[n]; \ + GLuint coloroffset = (rmesa->swtcl.vertex_size == 4 ? 3 : 4); \ + GLboolean havespec = (rmesa->swtcl.vertex_size > 4); \ + (void) color; (void) spec; (void) coloroffset; (void) havespec; + +/*********************************************************************** + * Helpers for rendering unfilled primitives * + ***********************************************************************/ + +#define RASTERIZE(x) radeonRasterPrimitive( ctx, reduced_hw_prim[x] ) +#define RENDER_PRIMITIVE rmesa->swtcl.render_primitive +#undef TAG +#define TAG(x) x +#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 (RADEON_TWOSIDE_BIT) +#define TAG(x) x##_twoside +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (RADEON_UNFILLED_BIT) +#define TAG(x) x##_unfilled +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (RADEON_TWOSIDE_BIT|RADEON_UNFILLED_BIT) +#define TAG(x) x##_twoside_unfilled +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (RADEON_OFFSET_BIT) +#define TAG(x) x##_offset +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (RADEON_TWOSIDE_BIT|RADEON_OFFSET_BIT) +#define TAG(x) x##_twoside_offset +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (RADEON_UNFILLED_BIT|RADEON_OFFSET_BIT) +#define TAG(x) x##_unfilled_offset +#include "tnl_dd/t_dd_tritmp.h" + +#define IND (RADEON_TWOSIDE_BIT|RADEON_UNFILLED_BIT|RADEON_OFFSET_BIT) +#define TAG(x) x##_twoside_unfilled_offset +#include "tnl_dd/t_dd_tritmp.h" + + +static void init_rast_tab( void ) +{ + init(); + init_twoside(); + init_unfilled(); + init_twoside_unfilled(); + init_offset(); + init_twoside_offset(); + init_unfilled_offset(); + init_twoside_unfilled_offset(); +} + +/**********************************************************************/ +/* Render unclipped begin/end objects */ +/**********************************************************************/ + +#define VERT(x) (radeonVertex *)(radeonverts + (x << shift)) +#define RENDER_POINTS( start, count ) \ + for ( ; start < count ; start++) \ + radeon_point( rmesa, VERT(start) ) +#define RENDER_LINE( v0, v1 ) \ + radeon_line( rmesa, VERT(v0), VERT(v1) ) +#define RENDER_TRI( v0, v1, v2 ) \ + radeon_triangle( rmesa, VERT(v0), VERT(v1), VERT(v2) ) +#define RENDER_QUAD( v0, v1, v2, v3 ) \ + radeon_quad( rmesa, VERT(v0), VERT(v1), VERT(v2), VERT(v3) ) +#undef INIT +#define INIT(x) do { \ + radeonRenderPrimitive( ctx, x ); \ +} while (0) +#undef LOCAL_VARS +#define LOCAL_VARS \ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \ + const GLuint shift = rmesa->swtcl.vertex_stride_shift; \ + const char *radeonverts = (char *)rmesa->swtcl.verts; \ + const GLuint * const elt = TNL_CONTEXT(ctx)->vb.Elts; \ + const GLboolean stipple = ctx->Line.StippleFlag; \ + (void) elt; (void) stipple; +#define RESET_STIPPLE if ( stipple ) radeonResetLineStipple( ctx ); +#define RESET_OCCLUSION +#define PRESERVE_VB_DEFS +#define ELT(x) (x) +#define TAG(x) radeon_##x##_verts +#include "tnl/t_vb_rendertmp.h" +#undef ELT +#undef TAG +#define TAG(x) radeon_##x##_elts +#define ELT(x) elt[x] +#include "tnl/t_vb_rendertmp.h" + + + +/**********************************************************************/ +/* Choose render functions */ +/**********************************************************************/ + +void radeonChooseRenderState( GLcontext *ctx ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint index = 0; + GLuint flags = ctx->_TriangleCaps; + + if (!rmesa->TclFallback || rmesa->Fallback) + return; + + if (flags & DD_TRI_LIGHT_TWOSIDE) index |= RADEON_TWOSIDE_BIT; + if (flags & DD_TRI_UNFILLED) index |= RADEON_UNFILLED_BIT; + if ((flags & DD_TRI_OFFSET) && + rmesa->dri.drmMinor == 1) index |= RADEON_OFFSET_BIT; + + if (index != rmesa->swtcl.RenderIndex) { + tnl->Driver.Render.Points = rast_tab[index].points; + tnl->Driver.Render.Line = rast_tab[index].line; + tnl->Driver.Render.ClippedLine = 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 = radeon_render_tab_verts; + tnl->Driver.Render.PrimTabElts = radeon_render_tab_elts; + tnl->Driver.Render.ClippedPolygon = radeon_fast_clipped_poly; + } else { + tnl->Driver.Render.PrimTabVerts = _tnl_render_tab_verts; + tnl->Driver.Render.PrimTabElts = _tnl_render_tab_elts; + tnl->Driver.Render.ClippedPolygon = _tnl_RenderClippedPolygon; + } + + rmesa->swtcl.RenderIndex = index; + } +} + + +/**********************************************************************/ +/* High level hooks for t_vb_render.c */ +/**********************************************************************/ + + +static void radeonRasterPrimitive( GLcontext *ctx, GLuint hwprim ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if (rmesa->swtcl.hw_primitive != hwprim) { + RADEON_NEWPRIM( rmesa ); + rmesa->swtcl.hw_primitive = hwprim; + } +} + +static void radeonRenderPrimitive( GLcontext *ctx, GLenum prim ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + rmesa->swtcl.render_primitive = prim; + if (prim < GL_TRIANGLES || !(ctx->_TriangleCaps & DD_TRI_UNFILLED)) + radeonRasterPrimitive( ctx, reduced_hw_prim[prim] ); +} + +static void radeonRenderFinish( GLcontext *ctx ) +{ +} + +static void radeonResetLineStipple( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + RADEON_STATECHANGE( rmesa, lin ); +} + + +/**********************************************************************/ +/* Transition to/from hardware rasterization. */ +/**********************************************************************/ + +static const char * const fallbackStrings[] = { + "Texture mode", + "glDrawBuffer(GL_FRONT_AND_BACK)", + "glEnable(GL_STENCIL) without hw stencil buffer", + "glRenderMode(selection or feedback)", + "glBlendEquation", + "glBlendFunc", + "RADEON_NO_RAST", + "Mixing GL_CLAMP_TO_BORDER and GL_CLAMP (or GL_MIRROR_CLAMP_ATI)" +}; + + +static const char *getFallbackString(GLuint bit) +{ + int i = 0; + while (bit > 1) { + i++; + bit >>= 1; + } + return fallbackStrings[i]; +} + + +void radeonFallback( GLcontext *ctx, GLuint bit, GLboolean mode ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + TNLcontext *tnl = TNL_CONTEXT(ctx); + GLuint oldfallback = rmesa->Fallback; + + if (mode) { + rmesa->Fallback |= bit; + if (oldfallback == 0) { + RADEON_FIREVERTICES( rmesa ); + TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_RASTER, GL_TRUE ); + _swsetup_Wakeup( ctx ); + _tnl_need_projected_coords( ctx, GL_TRUE ); + rmesa->swtcl.RenderIndex = ~0; + if (RADEON_DEBUG & DEBUG_FALLBACKS) { + fprintf(stderr, "Radeon begin rasterization fallback: 0x%x %s\n", + bit, getFallbackString(bit)); + } + } + } + else { + rmesa->Fallback &= ~bit; + if (oldfallback == bit) { + _swrast_flush( ctx ); + tnl->Driver.Render.Start = radeonRenderStart; + tnl->Driver.Render.PrimitiveNotify = radeonRenderPrimitive; + tnl->Driver.Render.Finish = radeonRenderFinish; + tnl->Driver.Render.BuildVertices = radeonBuildVertices; + tnl->Driver.Render.ResetLineStipple = radeonResetLineStipple; + TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_RASTER, GL_FALSE ); + if (rmesa->TclFallback) { + /* These are already done if rmesa->TclFallback goes to + * zero above. But not if it doesn't (RADEON_NO_TCL for + * example?) + */ + radeonChooseVertexState( ctx ); + radeonChooseRenderState( ctx ); + } + if (RADEON_DEBUG & DEBUG_FALLBACKS) { + fprintf(stderr, "Radeon end rasterization fallback: 0x%x %s\n", + bit, getFallbackString(bit)); + } + } + } +} + + +void radeonFlushVertices( GLcontext *ctx, GLuint flags ) +{ + _tnl_flush_vertices( ctx, flags ); + + if (flags & FLUSH_STORED_VERTICES) + RADEON_NEWPRIM( RADEON_CONTEXT( ctx ) ); +} + +/**********************************************************************/ +/* Initialization. */ +/**********************************************************************/ + +void radeonInitSwtcl( GLcontext *ctx ) +{ + TNLcontext *tnl = TNL_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint size = TNL_CONTEXT(ctx)->vb.Size; + static int firsttime = 1; + + if (firsttime) { + init_rast_tab(); + init_setup_tab(); + firsttime = 0; + } + + tnl->Driver.Render.Start = radeonRenderStart; + tnl->Driver.Render.Finish = radeonRenderFinish; + tnl->Driver.Render.PrimitiveNotify = radeonRenderPrimitive; + tnl->Driver.Render.ResetLineStipple = radeonResetLineStipple; + tnl->Driver.Render.BuildVertices = radeonBuildVertices; + + rmesa->swtcl.verts = ALIGN_MALLOC( size * 16 * 4, 32 ); + rmesa->swtcl.RenderIndex = ~0; + rmesa->swtcl.render_primitive = GL_TRIANGLES; + rmesa->swtcl.hw_primitive = 0; +} + + +void radeonDestroySwtcl( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if (rmesa->swtcl.indexed_verts.buf) + radeonReleaseDmaRegion( rmesa, &rmesa->swtcl.indexed_verts, + __FUNCTION__ ); + + if (rmesa->swtcl.verts) { + ALIGN_FREE(rmesa->swtcl.verts); + rmesa->swtcl.verts = 0; + } + + if (rmesa->UbyteSecondaryColor.Ptr) { + ALIGN_FREE(rmesa->UbyteSecondaryColor.Ptr); + rmesa->UbyteSecondaryColor.Ptr = 0; + } + + if (rmesa->UbyteColor.Ptr) { + ALIGN_FREE(rmesa->UbyteColor.Ptr); + rmesa->UbyteColor.Ptr = 0; + } +} diff --git a/src/mesa/drivers/dri/radeon/radeon_swtcl.h b/src/mesa/drivers/dri/radeon/radeon_swtcl.h new file mode 100644 index 0000000000..c45e711c0b --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_swtcl.h @@ -0,0 +1,77 @@ +/* $XFree86$ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * + */ + +#ifndef __RADEON_TRIS_H__ +#define __RADEON_TRIS_H__ + +#include "mtypes.h" +#include "swrast/swrast.h" +#include "radeon_context.h" + +extern void radeonInitSwtcl( GLcontext *ctx ); +extern void radeonDestroySwtcl( GLcontext *ctx ); + +extern void radeonFlushVertices( GLcontext *ctx, GLuint flags ); +extern void radeonChooseRenderState( GLcontext *ctx ); +extern void radeonChooseVertexState( GLcontext *ctx ); + +extern void radeonCheckTexSizes( GLcontext *ctx ); + +extern void radeonBuildVertices( GLcontext *ctx, GLuint start, GLuint count, + GLuint newinputs ); + +extern void radeonPrintSetupFlags(char *msg, GLuint flags ); + + +extern void radeon_emit_contiguous_verts( GLcontext *ctx, + GLuint start, + GLuint count ); + +extern void radeon_emit_indexed_verts( GLcontext *ctx, + GLuint start, + GLuint count ); + +extern void radeon_translate_vertex( GLcontext *ctx, + const radeonVertex *src, + SWvertex *dst ); + +extern void radeon_print_vertex( GLcontext *ctx, const radeonVertex *v ); + +extern void radeon_import_float_colors( GLcontext *ctx ); +extern void radeon_import_float_spec_colors( GLcontext *ctx ); + + + +#endif diff --git a/src/mesa/drivers/dri/radeon/radeon_tcl.c b/src/mesa/drivers/dri/radeon/radeon_tcl.c new file mode 100644 index 0000000000..651194a804 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_tcl.c @@ -0,0 +1,527 @@ +/* $XFree86$ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + Tungsten Graphics Inc., Austin, 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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "glheader.h" +#include "imports.h" +#include "light.h" +#include "mtypes.h" +#include "enums.h" + +#include "array_cache/acache.h" +#include "tnl/tnl.h" +#include "tnl/t_pipeline.h" + +#include "radeon_context.h" +#include "radeon_state.h" +#include "radeon_ioctl.h" +#include "radeon_tex.h" +#include "radeon_tcl.h" +#include "radeon_swtcl.h" +#include "radeon_maos.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 1 +#define HAVE_LINES 1 +#define HAVE_LINE_LOOP 0 +#define HAVE_LINE_STRIPS 1 +#define HAVE_TRIANGLES 1 +#define HAVE_TRI_STRIPS 1 +#define HAVE_TRI_STRIP_1 0 +#define HAVE_TRI_FANS 1 +#define HAVE_QUADS 0 +#define HAVE_QUAD_STRIPS 0 +#define HAVE_POLYGONS 1 +#define HAVE_ELTS 1 + + +#define HW_POINTS RADEON_CP_VC_CNTL_PRIM_TYPE_POINT +#define HW_LINES RADEON_CP_VC_CNTL_PRIM_TYPE_LINE +#define HW_LINE_LOOP 0 +#define HW_LINE_STRIP RADEON_CP_VC_CNTL_PRIM_TYPE_LINE_STRIP +#define HW_TRIANGLES RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_LIST +#define HW_TRIANGLE_STRIP_0 RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_STRIP +#define HW_TRIANGLE_STRIP_1 0 +#define HW_TRIANGLE_FAN RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN +#define HW_QUADS 0 +#define HW_QUAD_STRIP 0 +#define HW_POLYGON RADEON_CP_VC_CNTL_PRIM_TYPE_TRI_FAN + + +static GLboolean discrete_prim[0x10] = { + 0, /* 0 none */ + 1, /* 1 points */ + 1, /* 2 lines */ + 0, /* 3 line_strip */ + 1, /* 4 tri_list */ + 0, /* 5 tri_fan */ + 0, /* 6 tri_type2 */ + 1, /* 7 rect list (unused) */ + 1, /* 8 3vert point */ + 1, /* 9 3vert line */ + 0, + 0, + 0, + 0, + 0, + 0, +}; + + +#define LOCAL_VARS radeonContextPtr rmesa = RADEON_CONTEXT(ctx) +#define ELT_TYPE GLushort + +#define ELT_INIT(prim, hw_prim) \ + radeonTclPrimitive( ctx, prim, hw_prim | RADEON_CP_VC_CNTL_PRIM_WALK_IND ) + +#define GET_MESA_ELTS() rmesa->tcl.Elts + + +/* Don't really know how many elts will fit in what's left of cmdbuf, + * as there is state to emit, etc: + */ + +/* Testing on isosurf shows a maximum around here. Don't know if it's + * the card or driver or kernel module that is causing the behaviour. + */ +#define GET_MAX_HW_ELTS() 300 + + +#define RESET_STIPPLE() do { \ + RADEON_STATECHANGE( rmesa, lin ); \ + radeonEmitState( rmesa ); \ +} while (0) + +#define AUTO_STIPPLE( mode ) do { \ + RADEON_STATECHANGE( rmesa, lin ); \ + if (mode) \ + rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] |= \ + RADEON_LINE_PATTERN_AUTO_RESET; \ + else \ + rmesa->hw.lin.cmd[LIN_RE_LINE_PATTERN] &= \ + ~RADEON_LINE_PATTERN_AUTO_RESET; \ + radeonEmitState( rmesa ); \ +} while (0) + + + +#define ALLOC_ELTS(nr) radeonAllocElts( rmesa, nr ) + +static GLushort *radeonAllocElts( radeonContextPtr rmesa, GLuint nr ) +{ + if (rmesa->dma.flush) + rmesa->dma.flush( rmesa ); + + radeonEmitAOS( rmesa, + rmesa->tcl.aos_components, + rmesa->tcl.nr_aos_components, 0 ); + + return radeonAllocEltsOpenEnded( rmesa, + rmesa->tcl.vertex_format, + rmesa->tcl.hw_primitive, nr ); +} + +#define CLOSE_ELTS() RADEON_NEWPRIM( rmesa ) + + + +/* TODO: Try to extend existing primitive if both are identical, + * discrete and there are no intervening state changes. (Somewhat + * duplicates changes to DrawArrays code) + */ +static void EMIT_PRIM( GLcontext *ctx, + GLenum prim, + GLuint hwprim, + GLuint start, + GLuint count) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + radeonTclPrimitive( ctx, prim, hwprim ); + + radeonEmitAOS( rmesa, + rmesa->tcl.aos_components, + rmesa->tcl.nr_aos_components, + start ); + + /* Why couldn't this packet have taken an offset param? + */ + radeonEmitVbufPrim( rmesa, + rmesa->tcl.vertex_format, + rmesa->tcl.hw_primitive, + count - start ); +} + + + +/* Try & join small primitives + */ +#if 0 +#define PREFER_DISCRETE_ELT_PRIM( NR, PRIM ) 0 +#else +#define PREFER_DISCRETE_ELT_PRIM( NR, PRIM ) \ + ((NR) < 20 || \ + ((NR) < 40 && \ + rmesa->tcl.hw_primitive == (PRIM| \ + RADEON_CP_VC_CNTL_PRIM_WALK_IND| \ + RADEON_CP_VC_CNTL_TCL_ENABLE))) +#endif + +#ifdef MESA_BIG_ENDIAN +/* We could do without (most of) this ugliness if dest was always 32 bit word aligned... */ +#define EMIT_ELT(dest, offset, x) do { \ + int off = offset + ( ( (GLuint)dest & 0x2 ) >> 1 ); \ + GLushort *des = (GLushort *)( (GLuint)dest & ~0x2 ); \ + (des)[ off + 1 - 2 * ( off & 1 ) ] = (GLushort)(x); } while (0) +#else +#define EMIT_ELT(dest, offset, x) (dest)[offset] = (GLushort) (x) +#endif + +#define EMIT_TWO_ELTS(dest, offset, x, y) *(GLuint *)(dest+offset) = ((y)<<16)|(x); + + + +#define TAG(x) tcl_##x +#include "tnl_dd/t_dd_dmatmp2.h" + +/**********************************************************************/ +/* External entrypoints */ +/**********************************************************************/ + +void radeonEmitPrimitive( GLcontext *ctx, + GLuint first, + GLuint last, + GLuint flags ) +{ + tcl_render_tab_verts[flags&PRIM_MODE_MASK]( ctx, first, last, flags ); +} + +void radeonEmitEltPrimitive( GLcontext *ctx, + GLuint first, + GLuint last, + GLuint flags ) +{ + tcl_render_tab_elts[flags&PRIM_MODE_MASK]( ctx, first, last, flags ); +} + +void radeonTclPrimitive( GLcontext *ctx, + GLenum prim, + int hw_prim ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint se_cntl; + GLuint newprim = hw_prim | RADEON_CP_VC_CNTL_TCL_ENABLE; + + if (newprim != rmesa->tcl.hw_primitive || + !discrete_prim[hw_prim&0xf]) { + RADEON_NEWPRIM( rmesa ); + rmesa->tcl.hw_primitive = newprim; + } + + se_cntl = rmesa->hw.set.cmd[SET_SE_CNTL]; + se_cntl &= ~RADEON_FLAT_SHADE_VTX_LAST; + + if (prim == GL_POLYGON && (ctx->_TriangleCaps & DD_FLATSHADE)) + se_cntl |= RADEON_FLAT_SHADE_VTX_0; + else + se_cntl |= RADEON_FLAT_SHADE_VTX_LAST; + + if (se_cntl != rmesa->hw.set.cmd[SET_SE_CNTL]) { + RADEON_STATECHANGE( rmesa, set ); + rmesa->hw.set.cmd[SET_SE_CNTL] = se_cntl; + } +} + + +/**********************************************************************/ +/* Render pipeline stage */ +/**********************************************************************/ + + +/* TCL render. + */ +static GLboolean radeon_run_tcl_render( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + TNLcontext *tnl = TNL_CONTEXT(ctx); + struct vertex_buffer *VB = &tnl->vb; + GLuint i,flags = 0,length; + + /* TODO: separate this from the swtnl pipeline + */ + if (rmesa->TclFallback) + return GL_TRUE; /* fallback to software t&l */ + + if (VB->Count == 0) + return GL_FALSE; + + radeonReleaseArrays( ctx, stage->changed_inputs ); + radeonEmitArrays( ctx, stage->inputs ); + + rmesa->tcl.Elts = VB->Elts; + + for (i = VB->FirstPrimitive ; !(flags & PRIM_LAST) ; i += length) + { + flags = VB->Primitive[i]; + length = VB->PrimitiveLength[i]; + + if (RADEON_DEBUG & DEBUG_PRIMS) + fprintf(stderr, "%s: prim %s %d..%d\n", + __FUNCTION__, + _mesa_lookup_enum_by_nr(flags & PRIM_MODE_MASK), + i, i+length); + + if (!length) + continue; + + if (rmesa->tcl.Elts) + radeonEmitEltPrimitive( ctx, i, i+length, flags ); + else + radeonEmitPrimitive( ctx, i, i+length, flags ); + } + + return GL_FALSE; /* finished the pipe */ +} + + + +static void radeon_check_tcl_render( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint inputs = VERT_BIT_POS; + + if (ctx->RenderMode == GL_RENDER) { + /* Make all this event-driven: + */ + if (ctx->Light.Enabled) { + inputs |= VERT_BIT_NORMAL; + + if (1 || ctx->Light.ColorMaterialEnabled) { + inputs |= VERT_BIT_COLOR0; + } + } + else { + inputs |= VERT_BIT_COLOR0; + + if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) { + inputs |= VERT_BIT_COLOR1; + } + } + + if (ctx->Texture.Unit[0]._ReallyEnabled) { + if (ctx->Texture.Unit[0].TexGenEnabled) { + if (rmesa->TexGenNeedNormals[0]) { + inputs |= VERT_BIT_NORMAL; + } + } else { + inputs |= VERT_BIT_TEX0; + } + } + + if (ctx->Texture.Unit[1]._ReallyEnabled) { + if (ctx->Texture.Unit[1].TexGenEnabled) { + if (rmesa->TexGenNeedNormals[1]) { + inputs |= VERT_BIT_NORMAL; + } + } else { + inputs |= VERT_BIT_TEX1; + } + } + + stage->inputs = inputs; + stage->active = 1; + } + else + stage->active = 0; +} + +static void radeon_init_tcl_render( GLcontext *ctx, + struct gl_pipeline_stage *stage ) +{ + stage->check = radeon_check_tcl_render; + stage->check( ctx, stage ); +} + +static void dtr( struct gl_pipeline_stage *stage ) +{ + (void)stage; +} + + +/* Initial state for tcl stage. + */ +const struct gl_pipeline_stage _radeon_tcl_stage = +{ + "radeon render", + (_DD_NEW_SEPARATE_SPECULAR | + _NEW_LIGHT| + _NEW_TEXTURE| + _NEW_FOG| + _NEW_RENDERMODE), /* re-check (new inputs) */ + 0, /* re-run (always runs) */ + GL_TRUE, /* active */ + 0, 0, /* inputs (set in check_render), outputs */ + 0, 0, /* changed_inputs, private */ + dtr, /* destructor */ + radeon_init_tcl_render, /* check - initially set to alloc data */ + radeon_run_tcl_render /* run */ +}; + + + +/**********************************************************************/ +/* Validate state at pipeline start */ +/**********************************************************************/ + + +/*----------------------------------------------------------------------- + * Manage TCL fallbacks + */ + + +static void transition_to_swtnl( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + TNLcontext *tnl = TNL_CONTEXT(ctx); + GLuint se_cntl; + + RADEON_NEWPRIM( rmesa ); + rmesa->swtcl.vertex_format = 0; + + radeonChooseVertexState( ctx ); + radeonChooseRenderState( ctx ); + + _mesa_validate_all_lighting_tables( ctx ); + + tnl->Driver.NotifyMaterialChange = + _mesa_validate_all_lighting_tables; + + radeonReleaseArrays( ctx, ~0 ); + + se_cntl = rmesa->hw.set.cmd[SET_SE_CNTL]; + se_cntl |= RADEON_FLAT_SHADE_VTX_LAST; + + if (se_cntl != rmesa->hw.set.cmd[SET_SE_CNTL]) { + RADEON_STATECHANGE( rmesa, set ); + rmesa->hw.set.cmd[SET_SE_CNTL] = se_cntl; + } +} + + +static void transition_to_hwtnl( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + TNLcontext *tnl = TNL_CONTEXT(ctx); + GLuint se_coord_fmt = (RADEON_VTX_W0_IS_NOT_1_OVER_W0 | + RADEON_TEX1_W_ROUTING_USE_Q1); + + if ( se_coord_fmt != rmesa->hw.set.cmd[SET_SE_COORDFMT] ) { + RADEON_STATECHANGE( rmesa, set ); + rmesa->hw.set.cmd[SET_SE_COORDFMT] = se_coord_fmt; + _tnl_need_projected_coords( ctx, GL_FALSE ); + } + + radeonUpdateMaterial( ctx ); + + tnl->Driver.NotifyMaterialChange = radeonUpdateMaterial; + + if ( rmesa->dma.flush ) + rmesa->dma.flush( rmesa ); + + rmesa->dma.flush = 0; + rmesa->swtcl.vertex_format = 0; + + if (rmesa->swtcl.indexed_verts.buf) + radeonReleaseDmaRegion( rmesa, &rmesa->swtcl.indexed_verts, + __FUNCTION__ ); + + if (RADEON_DEBUG & DEBUG_FALLBACKS) + fprintf(stderr, "Radeon end tcl fallback\n"); +} + +static char *fallbackStrings[] = { + "Rasterization fallback", + "Unfilled triangles", + "Twosided lighting, differing materials", + "Materials in VB (maybe between begin/end)", + "Texgen unit 0", + "Texgen unit 1", + "Texgen unit 2", + "User disable" +}; + + +static char *getFallbackString(GLuint bit) +{ + int i = 0; + while (bit > 1) { + i++; + bit >>= 1; + } + return fallbackStrings[i]; +} + + + +void radeonTclFallback( GLcontext *ctx, GLuint bit, GLboolean mode ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint oldfallback = rmesa->TclFallback; + + if (mode) { + rmesa->TclFallback |= bit; + if (oldfallback == 0) { + if (RADEON_DEBUG & DEBUG_FALLBACKS) + fprintf(stderr, "Radeon begin tcl fallback %s\n", + getFallbackString( bit )); + transition_to_swtnl( ctx ); + } + } + else { + rmesa->TclFallback &= ~bit; + if (oldfallback == bit) { + if (RADEON_DEBUG & DEBUG_FALLBACKS) + fprintf(stderr, "Radeon end tcl fallback %s\n", + getFallbackString( bit )); + transition_to_hwtnl( ctx ); + } + } +} diff --git a/src/mesa/drivers/dri/radeon/radeon_tcl.h b/src/mesa/drivers/dri/radeon/radeon_tcl.h new file mode 100644 index 0000000000..1e97d32148 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_tcl.h @@ -0,0 +1,70 @@ +/* $XFree86$ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + Tungsten Grahpics Inc., Austin, 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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + * + */ + +#ifndef __RADEON_TCL_H__ +#define __RADEON_TCL_H__ + +#ifdef GLX_DIRECT_RENDERING + +#include "radeon_context.h" + +extern void radeonTclPrimitive( GLcontext *ctx, GLenum prim, int hw_prim ); +extern void radeonEmitEltPrimitive( GLcontext *ctx, GLuint first, GLuint last, + GLuint flags ); +extern void radeonEmitPrimitive( GLcontext *ctx, GLuint first, GLuint last, + GLuint flags ); + +extern void radeonTclFallback( GLcontext *ctx, GLuint bit, GLboolean mode ); + +#define RADEON_TCL_FALLBACK_RASTER 0x1 /* rasterization */ +#define RADEON_TCL_FALLBACK_UNFILLED 0x2 /* unfilled tris */ +#define RADEON_TCL_FALLBACK_LIGHT_TWOSIDE 0x4 /* twoside tris */ +#define RADEON_TCL_FALLBACK_MATERIAL 0x8 /* material in vb */ +#define RADEON_TCL_FALLBACK_TEXGEN_0 0x10 /* texgen, unit 0 */ +#define RADEON_TCL_FALLBACK_TEXGEN_1 0x20 /* texgen, unit 1 */ +#define RADEON_TCL_FALLBACK_TEXGEN_2 0x40 /* texgen, unit 2 */ +#define RADEON_TCL_FALLBACK_TCL_DISABLE 0x80 /* user disable */ +#define RADEON_TCL_FALLBACK_TEXRECT_0 0x100 /* texture rectangle */ +#define RADEON_TCL_FALLBACK_TEXRECT_1 0x200 /* texture rectangle */ +#define RADEON_TCL_FALLBACK_TEXRECT_2 0x400 /* texture rectangle */ + +#define RADEON_MAX_TCL_VERTSIZE (15*4) + +#define TCL_FALLBACK( ctx, bit, mode ) radeonTclFallback( ctx, bit, mode ) + + +#endif +#endif diff --git a/src/mesa/drivers/dri/radeon/radeon_tex.c b/src/mesa/drivers/dri/radeon/radeon_tex.c new file mode 100644 index 0000000000..e068202c5e --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_tex.c @@ -0,0 +1,733 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_tex.c,v 1.6 2002/09/16 18:05:20 eich Exp $ */ +/* +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. +*/ + +/* + * Authors: + * Gareth Hughes <gareth@valinux.com> + * Brian Paul <brianp@valinux.com> + */ + +#include "glheader.h" +#include "imports.h" +#include "colormac.h" +#include "context.h" +#include "enums.h" +#include "image.h" +#include "simple_list.h" +#include "texformat.h" +#include "texstore.h" +#include "teximage.h" + + +#include "radeon_context.h" +#include "radeon_state.h" +#include "radeon_ioctl.h" +#include "radeon_swtcl.h" +#include "radeon_tex.h" + + + +/** + * Set the texture wrap modes. + * + * \param t Texture object whose wrap modes are to be set + * \param swrap Wrap mode for the \a s texture coordinate + * \param twrap Wrap mode for the \a t texture coordinate + */ + +static void radeonSetTexWrap( radeonTexObjPtr t, GLenum swrap, GLenum twrap ) +{ + GLboolean is_clamp = GL_FALSE; + GLboolean is_clamp_to_border = GL_FALSE; + + t->pp_txfilter &= ~(RADEON_CLAMP_S_MASK | RADEON_CLAMP_T_MASK | RADEON_BORDER_MODE_D3D); + + switch ( swrap ) { + case GL_REPEAT: + t->pp_txfilter |= RADEON_CLAMP_S_WRAP; + break; + case GL_CLAMP: + t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_GL; + is_clamp = GL_TRUE; + break; + case GL_CLAMP_TO_EDGE: + t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_LAST; + break; + case GL_CLAMP_TO_BORDER: + t->pp_txfilter |= RADEON_CLAMP_S_CLAMP_GL; + is_clamp_to_border = GL_TRUE; + break; + case GL_MIRRORED_REPEAT: + t->pp_txfilter |= RADEON_CLAMP_S_MIRROR; + break; + case GL_MIRROR_CLAMP_ATI: + t->pp_txfilter |= RADEON_CLAMP_S_MIRROR_CLAMP_GL; + is_clamp = GL_TRUE; + break; + case GL_MIRROR_CLAMP_TO_EDGE_ATI: + t->pp_txfilter |= RADEON_CLAMP_S_MIRROR_CLAMP_LAST; + break; + default: + _mesa_problem(NULL, "bad S wrap mode in %s", __FUNCTION__); + } + + switch ( twrap ) { + case GL_REPEAT: + t->pp_txfilter |= RADEON_CLAMP_T_WRAP; + break; + case GL_CLAMP: + t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_GL; + is_clamp = GL_TRUE; + break; + case GL_CLAMP_TO_EDGE: + t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_LAST; + break; + case GL_CLAMP_TO_BORDER: + t->pp_txfilter |= RADEON_CLAMP_T_CLAMP_GL; + is_clamp_to_border = GL_TRUE; + break; + case GL_MIRRORED_REPEAT: + t->pp_txfilter |= RADEON_CLAMP_T_MIRROR; + break; + case GL_MIRROR_CLAMP_ATI: + t->pp_txfilter |= RADEON_CLAMP_T_MIRROR_CLAMP_GL; + is_clamp = GL_TRUE; + break; + case GL_MIRROR_CLAMP_TO_EDGE_ATI: + t->pp_txfilter |= RADEON_CLAMP_T_MIRROR_CLAMP_LAST; + break; + default: + _mesa_problem(NULL, "bad T wrap mode in %s", __FUNCTION__); + } + + if ( is_clamp_to_border ) { + t->pp_txfilter |= RADEON_BORDER_MODE_D3D; + } + + t->border_fallback = (is_clamp && is_clamp_to_border); +} + +static void radeonSetTexMaxAnisotropy( radeonTexObjPtr t, GLfloat max ) +{ + t->pp_txfilter &= ~RADEON_MAX_ANISO_MASK; + + if ( max == 1.0 ) { + t->pp_txfilter |= RADEON_MAX_ANISO_1_TO_1; + } else if ( max <= 2.0 ) { + t->pp_txfilter |= RADEON_MAX_ANISO_2_TO_1; + } else if ( max <= 4.0 ) { + t->pp_txfilter |= RADEON_MAX_ANISO_4_TO_1; + } else if ( max <= 8.0 ) { + t->pp_txfilter |= RADEON_MAX_ANISO_8_TO_1; + } else { + t->pp_txfilter |= RADEON_MAX_ANISO_16_TO_1; + } +} + +/** + * Set the texture magnification and minification modes. + * + * \param t Texture whose filter modes are to be set + * \param minf Texture minification mode + * \param magf Texture magnification mode + */ + +static void radeonSetTexFilter( radeonTexObjPtr t, GLenum minf, GLenum magf ) +{ + GLuint anisotropy = (t->pp_txfilter & RADEON_MAX_ANISO_MASK); + + t->pp_txfilter &= ~(RADEON_MIN_FILTER_MASK | RADEON_MAG_FILTER_MASK); + + if ( anisotropy == RADEON_MAX_ANISO_1_TO_1 ) { + switch ( minf ) { + case GL_NEAREST: + t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST; + break; + case GL_LINEAR: + t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR; + break; + case GL_NEAREST_MIPMAP_NEAREST: + t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_NEAREST; + break; + case GL_NEAREST_MIPMAP_LINEAR: + t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_NEAREST; + break; + case GL_LINEAR_MIPMAP_NEAREST: + t->pp_txfilter |= RADEON_MIN_FILTER_NEAREST_MIP_LINEAR; + break; + case GL_LINEAR_MIPMAP_LINEAR: + t->pp_txfilter |= RADEON_MIN_FILTER_LINEAR_MIP_LINEAR; + break; + } + } else { + switch ( minf ) { + case GL_NEAREST: + t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST; + break; + case GL_LINEAR: + t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_LINEAR; + break; + case GL_NEAREST_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_NEAREST: + t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST_MIP_NEAREST; + break; + case GL_NEAREST_MIPMAP_LINEAR: + case GL_LINEAR_MIPMAP_LINEAR: + t->pp_txfilter |= RADEON_MIN_FILTER_ANISO_NEAREST_MIP_LINEAR; + break; + } + } + + switch ( magf ) { + case GL_NEAREST: + t->pp_txfilter |= RADEON_MAG_FILTER_NEAREST; + break; + case GL_LINEAR: + t->pp_txfilter |= RADEON_MAG_FILTER_LINEAR; + break; + } +} + +static void radeonSetTexBorderColor( radeonTexObjPtr t, GLubyte c[4] ) +{ + t->pp_border_color = radeonPackColor( 4, c[0], c[1], c[2], c[3] ); +} + + +/** + * Allocate space for and load the mesa images into the texture memory block. + * This will happen before drawing with a new texture, or drawing with a + * texture after it was swapped out or teximaged again. + */ + +static radeonTexObjPtr radeonAllocTexObj( struct gl_texture_object *texObj ) +{ + radeonTexObjPtr t; + + t = CALLOC_STRUCT( radeon_tex_obj ); + texObj->DriverData = t; + if ( t != NULL ) { + if ( RADEON_DEBUG & DEBUG_TEXTURE ) { + fprintf( stderr, "%s( %p, %p )\n", __FUNCTION__, texObj, t ); + } + + /* Initialize non-image-dependent parts of the state: + */ + t->base.tObj = texObj; + t->border_fallback = GL_FALSE; + + t->pp_txfilter = RADEON_BORDER_MODE_OGL; + t->pp_txformat = (RADEON_TXFORMAT_ENDIAN_NO_SWAP | + RADEON_TXFORMAT_PERSPECTIVE_ENABLE); + + make_empty_list( & t->base ); + + radeonSetTexWrap( t, texObj->WrapS, texObj->WrapT ); + radeonSetTexMaxAnisotropy( t, texObj->MaxAnisotropy ); + radeonSetTexFilter( t, texObj->MinFilter, texObj->MagFilter ); + radeonSetTexBorderColor( t, texObj->_BorderChan ); + } + + return t; +} + + +static const struct gl_texture_format * +radeonChooseTextureFormat( GLcontext *ctx, GLint internalFormat, + GLenum format, GLenum type ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + const GLboolean do32bpt = ( rmesa->radeonScreen->cpp == 4 ); + + switch ( internalFormat ) { + case 4: + case GL_RGBA: + case GL_COMPRESSED_RGBA: + if ( format == GL_BGRA ) { + if ( type == GL_UNSIGNED_INT_8_8_8_8_REV ) { + return &_mesa_texformat_argb8888; + } + else if ( type == GL_UNSIGNED_SHORT_4_4_4_4_REV ) { + return &_mesa_texformat_argb4444; + } + else if ( type == GL_UNSIGNED_SHORT_1_5_5_5_REV ) { + return &_mesa_texformat_argb1555; + } + } + return do32bpt ? &_mesa_texformat_rgba8888 : &_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_rgba8888 : &_mesa_texformat_rgb565; + + case GL_RGBA8: + case GL_RGB10_A2: + case GL_RGBA12: + case GL_RGBA16: + return do32bpt ? &_mesa_texformat_rgba8888 : &_mesa_texformat_argb4444; + + case GL_RGBA4: + case GL_RGBA2: + return &_mesa_texformat_argb4444; + + case GL_RGB5_A1: + return &_mesa_texformat_argb1555; + + case GL_RGB8: + case GL_RGB10: + case GL_RGB12: + case GL_RGB16: + return do32bpt ? &_mesa_texformat_rgba8888 : &_mesa_texformat_rgb565; + + case GL_RGB5: + case GL_RGB4: + case GL_R3_G3_B2: + return &_mesa_texformat_rgb565; + + case GL_ALPHA: + case GL_ALPHA4: + case GL_ALPHA8: + case GL_ALPHA12: + case GL_ALPHA16: + case GL_COMPRESSED_ALPHA: + return &_mesa_texformat_al88; + + case 1: + case GL_LUMINANCE: + case GL_LUMINANCE4: + case GL_LUMINANCE8: + case GL_LUMINANCE12: + case GL_LUMINANCE16: + case GL_COMPRESSED_LUMINANCE: + return &_mesa_texformat_al88; + + 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_APPLE || + type == GL_UNSIGNED_BYTE) + return &_mesa_texformat_ycbcr; + else + return &_mesa_texformat_ycbcr_rev; + + default: + _mesa_problem(ctx, "unexpected texture format in %s", __FUNCTION__); + return NULL; + } + + return NULL; /* never get here */ +} + + +static void radeonTexImage1D( GLcontext *ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint border, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + if ( t ) { + driSwapOutTextureObject( t ); + } + else { + t = (driTextureObject *) radeonAllocTexObj( texObj ); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage1D"); + return; + } + } + + /* Note, this will call ChooseTextureFormat */ + _mesa_store_teximage1d(ctx, target, level, internalFormat, + width, border, format, type, pixels, + &ctx->Unpack, texObj, texImage); + + t->dirty_images[0] |= (1 << level); +} + + +static void radeonTexSubImage1D( GLcontext *ctx, GLenum target, GLint level, + GLint xoffset, + GLsizei width, + GLenum format, GLenum type, + const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + assert( t ); /* this _should_ be true */ + if ( t ) { + driSwapOutTextureObject( t ); + } + else { + t = (driTextureObject *) radeonAllocTexObj( texObj ); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage1D"); + return; + } + } + + _mesa_store_texsubimage1d(ctx, target, level, xoffset, width, + format, type, pixels, packing, texObj, + texImage); + + t->dirty_images[0] |= (1 << level); +} + + +static void radeonTexImage2D( GLcontext *ctx, GLenum target, GLint level, + GLint internalFormat, + GLint width, GLint height, GLint border, + GLenum format, GLenum type, const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + GLuint face; + + /* which cube face or ordinary 2D image */ + switch (target) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; + ASSERT(face < 6); + break; + default: + face = 0; + } + + if ( t != NULL ) { + driSwapOutTextureObject( t ); + } + else { + t = (driTextureObject *) radeonAllocTexObj( texObj ); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexImage2D"); + return; + } + } + + /* Note, this will call ChooseTextureFormat */ + _mesa_store_teximage2d(ctx, target, level, internalFormat, + width, height, border, format, type, pixels, + &ctx->Unpack, texObj, texImage); + + t->dirty_images[face] |= (1 << level); +} + + +static void radeonTexSubImage2D( GLcontext *ctx, GLenum target, GLint level, + GLint xoffset, GLint yoffset, + GLsizei width, GLsizei height, + GLenum format, GLenum type, + const GLvoid *pixels, + const struct gl_pixelstore_attrib *packing, + struct gl_texture_object *texObj, + struct gl_texture_image *texImage ) +{ + driTextureObject * t = (driTextureObject *) texObj->DriverData; + GLuint face; + + + /* which cube face or ordinary 2D image */ + switch (target) { + case GL_TEXTURE_CUBE_MAP_POSITIVE_X: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_X: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Y: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Y: + case GL_TEXTURE_CUBE_MAP_POSITIVE_Z: + case GL_TEXTURE_CUBE_MAP_NEGATIVE_Z: + face = (GLuint) target - (GLuint) GL_TEXTURE_CUBE_MAP_POSITIVE_X; + ASSERT(face < 6); + break; + default: + face = 0; + } + + assert( t ); /* this _should_ be true */ + if ( t ) { + driSwapOutTextureObject( t ); + } + else { + t = (driTextureObject *) radeonAllocTexObj( texObj ); + if (!t) { + _mesa_error(ctx, GL_OUT_OF_MEMORY, "glTexSubImage2D"); + return; + } + } + + _mesa_store_texsubimage2d(ctx, target, level, xoffset, yoffset, width, + height, format, type, pixels, packing, texObj, + texImage); + + t->dirty_images[face] |= (1 << level); +} + + + +#define SCALED_FLOAT_TO_BYTE( x, scale ) \ + (((GLuint)((255.0F / scale) * (x))) / 2) + +static void radeonTexEnv( GLcontext *ctx, GLenum target, + GLenum pname, const GLfloat *param ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint unit = ctx->Texture.CurrentUnit; + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + + if ( RADEON_DEBUG & DEBUG_STATE ) { + fprintf( stderr, "%s( %s )\n", + __FUNCTION__, _mesa_lookup_enum_by_nr( pname ) ); + } + + switch ( pname ) { + case GL_TEXTURE_ENV_COLOR: { + GLubyte c[4]; + GLuint envColor; + UNCLAMPED_FLOAT_TO_RGBA_CHAN( c, texUnit->EnvColor ); + envColor = radeonPackColor( 4, c[0], c[1], c[2], c[3] ); + if ( rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] != envColor ) { + RADEON_STATECHANGE( rmesa, tex[unit] ); + rmesa->hw.tex[unit].cmd[TEX_PP_TFACTOR] = envColor; + } + break; + } + + case GL_TEXTURE_LOD_BIAS_EXT: { + GLfloat bias; + GLuint b; + + /* The Radeon's LOD bias is a signed 2's complement value with a + * range of -1.0 <= bias < 4.0. We break this into two linear + * functions, one mapping [-1.0,0.0] to [-128,0] and one mapping + * [0.0,4.0] to [0,127]. + */ + bias = CLAMP( *param, -1.0, 4.0 ); + if ( bias == 0 ) { + b = 0; + } else if ( bias > 0 ) { + b = ((GLuint)SCALED_FLOAT_TO_BYTE( bias, 4.0 )) << RADEON_LOD_BIAS_SHIFT; + } else { + b = ((GLuint)SCALED_FLOAT_TO_BYTE( bias, 1.0 )) << RADEON_LOD_BIAS_SHIFT; + } + if ( (rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] & RADEON_LOD_BIAS_MASK) != b ) { + RADEON_STATECHANGE( rmesa, tex[unit] ); + rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] &= ~RADEON_LOD_BIAS_MASK; + rmesa->hw.tex[unit].cmd[TEX_PP_TXFILTER] |= (b & RADEON_LOD_BIAS_MASK); + } + break; + } + + default: + return; + } +} + + +/** + * Changes variables and flags for a state update, which will happen at the + * next UpdateTextureState + */ + +static void radeonTexParameter( GLcontext *ctx, GLenum target, + struct gl_texture_object *texObj, + GLenum pname, const GLfloat *params ) +{ + radeonTexObjPtr t = (radeonTexObjPtr) texObj->DriverData; + + if ( RADEON_DEBUG & (DEBUG_STATE|DEBUG_TEXTURE) ) { + fprintf( stderr, "%s( %s )\n", __FUNCTION__, + _mesa_lookup_enum_by_nr( pname ) ); + } + + if ( ( target != GL_TEXTURE_2D ) && + ( target != GL_TEXTURE_1D ) ) + return; + + switch ( pname ) { + case GL_TEXTURE_MIN_FILTER: + case GL_TEXTURE_MAG_FILTER: + case GL_TEXTURE_MAX_ANISOTROPY_EXT: + radeonSetTexMaxAnisotropy( t, texObj->MaxAnisotropy ); + radeonSetTexFilter( t, texObj->MinFilter, texObj->MagFilter ); + break; + + case GL_TEXTURE_WRAP_S: + case GL_TEXTURE_WRAP_T: + radeonSetTexWrap( t, texObj->WrapS, texObj->WrapT ); + break; + + case GL_TEXTURE_BORDER_COLOR: + radeonSetTexBorderColor( t, texObj->_BorderChan ); + break; + + case GL_TEXTURE_BASE_LEVEL: + case GL_TEXTURE_MAX_LEVEL: + case GL_TEXTURE_MIN_LOD: + case GL_TEXTURE_MAX_LOD: + /* This isn't the most efficient solution but there doesn't appear to + * be a nice alternative. Since there's no LOD clamping, + * we just have to rely on loading the right subset of mipmap levels + * to simulate a clamped LOD. + */ + driSwapOutTextureObject( (driTextureObject *) t ); + break; + + default: + return; + } + + /* Mark this texobj as dirty (one bit per tex unit) + */ + t->dirty_state = TEX_ALL; +} + + + +static void radeonBindTexture( GLcontext *ctx, GLenum target, + struct gl_texture_object *texObj ) +{ + if ( RADEON_DEBUG & (DEBUG_STATE|DEBUG_TEXTURE) ) { + fprintf( stderr, "%s( %p ) unit=%d\n", __FUNCTION__, texObj, + ctx->Texture.CurrentUnit ); + } + + if ( target == GL_TEXTURE_2D || target == GL_TEXTURE_1D ) { + if ( texObj->DriverData == NULL ) { + radeonAllocTexObj( texObj ); + } + } +} + +static void radeonDeleteTexture( GLcontext *ctx, + struct gl_texture_object *texObj ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + driTextureObject * t = (driTextureObject *) texObj->DriverData; + + if ( RADEON_DEBUG & (DEBUG_STATE|DEBUG_TEXTURE) ) { + fprintf( stderr, "%s( %p (target = %s) )\n", __FUNCTION__, texObj, + _mesa_lookup_enum_by_nr( texObj->Target ) ); + } + + if ( t != NULL ) { + if ( rmesa ) { + RADEON_FIREVERTICES( rmesa ); + } + + driDestroyTextureObject( t ); + } +} + +/* Need: + * - Same GEN_MODE for all active bits + * - Same EyePlane/ObjPlane for all active bits when using Eye/Obj + * - STRQ presumably all supported (matrix means incoming R values + * can end up in STQ, this has implications for vertex support, + * presumably ok if maos is used, though?) + * + * Basically impossible to do this on the fly - just collect some + * basic info & do the checks from ValidateState(). + */ +static void radeonTexGen( GLcontext *ctx, + GLenum coord, + GLenum pname, + const GLfloat *params ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint unit = ctx->Texture.CurrentUnit; + rmesa->recheck_texgen[unit] = GL_TRUE; +} + + +void radeonInitTextureFuncs( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + + ctx->Driver.ChooseTextureFormat = radeonChooseTextureFormat; + ctx->Driver.TexImage1D = radeonTexImage1D; + ctx->Driver.TexImage2D = radeonTexImage2D; + ctx->Driver.TexImage3D = _mesa_store_teximage3d; + ctx->Driver.TexSubImage1D = radeonTexSubImage1D; + ctx->Driver.TexSubImage2D = radeonTexSubImage2D; + ctx->Driver.TexSubImage3D = _mesa_store_texsubimage3d; + ctx->Driver.CopyTexImage1D = _swrast_copy_teximage1d; + ctx->Driver.CopyTexImage2D = _swrast_copy_teximage2d; + ctx->Driver.CopyTexSubImage1D = _swrast_copy_texsubimage1d; + ctx->Driver.CopyTexSubImage2D = _swrast_copy_texsubimage2d; + ctx->Driver.CopyTexSubImage3D = _swrast_copy_texsubimage3d; + ctx->Driver.TestProxyTexImage = _mesa_test_proxy_teximage; + + ctx->Driver.BindTexture = radeonBindTexture; + ctx->Driver.CreateTexture = NULL; /* FIXME: Is this used??? */ + ctx->Driver.DeleteTexture = radeonDeleteTexture; + ctx->Driver.IsTextureResident = driIsTextureResident; + ctx->Driver.PrioritizeTexture = NULL; + ctx->Driver.ActiveTexture = NULL; + ctx->Driver.UpdateTexturePalette = NULL; + + ctx->Driver.TexEnv = radeonTexEnv; + ctx->Driver.TexParameter = radeonTexParameter; + ctx->Driver.TexGen = radeonTexGen; + + driInitTextureObjects( ctx, & rmesa->swapped, + DRI_TEXMGR_DO_TEXTURE_1D + | DRI_TEXMGR_DO_TEXTURE_2D ); +} diff --git a/src/mesa/drivers/dri/radeon/radeon_tex.h b/src/mesa/drivers/dri/radeon/radeon_tex.h new file mode 100644 index 0000000000..ce079baec2 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_tex.h @@ -0,0 +1,53 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_tex.h,v 1.3 2002/02/22 21:45:01 dawes Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ + +#ifndef __RADEON_TEX_H__ +#define __RADEON_TEX_H__ + +#ifdef GLX_DIRECT_RENDERING + +extern void radeonUpdateTextureState( GLcontext *ctx ); + +extern int radeonUploadTexImages( radeonContextPtr rmesa, radeonTexObjPtr t, + GLuint face ); + +extern void radeonDestroyTexObj( radeonContextPtr rmesa, radeonTexObjPtr t ); + +extern void radeonInitTextureFuncs( GLcontext *ctx ); + +#endif +#endif /* __RADEON_TEX_H__ */ diff --git a/src/mesa/drivers/dri/radeon/radeon_texmem.c b/src/mesa/drivers/dri/radeon/radeon_texmem.c new file mode 100644 index 0000000000..3adc2a951c --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_texmem.c @@ -0,0 +1,378 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_texmem.c,v 1.7 2002/12/16 16:18:59 dawes Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + * + */ +#include <errno.h> + +#include "glheader.h" +#include "imports.h" +#include "context.h" +#include "macros.h" +#include "simple_list.h" + +#include "radeon_context.h" +#include "radeon_ioctl.h" +#include "radeon_tex.h" + + +/** + * Destroy any device-dependent state associated with the texture. This may + * include NULLing out hardware state that points to the texture. + */ +void +radeonDestroyTexObj( radeonContextPtr rmesa, radeonTexObjPtr t ) +{ + if ( RADEON_DEBUG & DEBUG_TEXTURE ) { + fprintf( stderr, "%s( %p, %p )\n", __FUNCTION__, t, t->base.tObj ); + } + + if ( rmesa != NULL ) { + unsigned i; + + + for ( i = 0 ; i < rmesa->glCtx->Const.MaxTextureUnits ; i++ ) { + if ( t == rmesa->state.texture.unit[i].texobj ) { + rmesa->state.texture.unit[i].texobj = NULL; + remove_from_list( &rmesa->hw.tex[i] ); + make_empty_list( &rmesa->hw.tex[i] ); + } + } + } +} + + +/* ------------------------------------------------------------ + * Texture image conversions + */ + + +static void radeonUploadRectSubImage( radeonContextPtr rmesa, + radeonTexObjPtr t, + struct gl_texture_image *texImage, + GLint x, GLint y, + GLint width, GLint height ) +{ + const struct gl_texture_format *texFormat = texImage->TexFormat; + int blit_format, dstPitch, done; + + switch ( texFormat->TexelBytes ) { + case 1: + blit_format = RADEON_GMC_DST_8BPP_CI; + break; + case 2: + blit_format = RADEON_GMC_DST_16BPP; + break; + case 4: + blit_format = RADEON_GMC_DST_32BPP; + break; + default: + fprintf( stderr, "radeonUploadRectSubImage: unknown blit_format (texelbytes=%d)\n", + texFormat->TexelBytes); + return; + } + + t->image[0][0].data = texImage->Data; + + /* Currently don't need to cope with small pitches. + */ + width = texImage->Width; + height = texImage->Height; + dstPitch = t->pp_txpitch + 32; + + { /* FIXME: prefer AGP-texturing if possible */ + /* Data not in agp memory, or bad pitch. + */ + for (done = 0; done < height ; ) { + struct radeon_dma_region region; + int lines = MIN2( height - done, RADEON_BUFFER_SIZE / dstPitch ); + int src_pitch; + char *tex; + + src_pitch = texImage->RowStride * texFormat->TexelBytes; + + tex = (char *)texImage->Data + done * src_pitch; + + memset(®ion, 0, sizeof(region)); + radeonAllocDmaRegion( rmesa, ®ion, lines * dstPitch, 1024 ); + + /* Copy texdata to dma: + */ + if (0) + fprintf(stderr, "%s: src_pitch %d dst_pitch %d\n", + __FUNCTION__, src_pitch, dstPitch); + + if (src_pitch == dstPitch) { + memcpy( region.address, tex, lines * src_pitch ); + } + else { + char *buf = region.address; + int i; + for (i = 0 ; i < lines ; i++) { + memcpy( buf, tex, src_pitch ); + buf += dstPitch; + tex += src_pitch; + } + } + + radeonEmitWait( rmesa, RADEON_WAIT_3D ); + + + + /* Blit to framebuffer + */ + radeonEmitBlit( rmesa, + blit_format, + dstPitch, GET_START( ®ion ), + dstPitch, t->bufAddr, + 0, 0, + 0, done, + width, lines ); + + radeonEmitWait( rmesa, RADEON_WAIT_2D ); + + radeonReleaseDmaRegion( rmesa, ®ion, __FUNCTION__ ); + done += lines; + } + } +} + + +/** + * Upload the texture image associated with texture \a t at the specified + * level at the address relative to \a start. + */ +static void uploadSubImage( radeonContextPtr rmesa, radeonTexObjPtr t, + GLint hwlevel, + GLint x, GLint y, GLint width, GLint height, + GLuint face ) +{ + struct gl_texture_image *texImage = NULL; + GLuint offset; + GLint imageWidth, imageHeight; + GLint ret; + drmRadeonTexture tex; + drmRadeonTexImage tmp; + const int level = hwlevel + t->base.firstLevel; + + if ( RADEON_DEBUG & DEBUG_TEXTURE ) { + fprintf( stderr, "%s( %p, %p ) level/width/height/face = %d/%d/%d/%u\n", + __FUNCTION__, t, t->base.tObj, level, width, height, face ); + } + + ASSERT(face < 6); + + /* Ensure we have a valid texture to upload */ + if ( ( hwlevel < 0 ) || ( hwlevel >= RADEON_MAX_TEXTURE_LEVELS ) ) { + _mesa_problem(NULL, "bad texture level in %s", __FUNCTION__); + return; + } + + switch (face) { + case 0: + texImage = t->base.tObj->Image[level]; + break; + case 1: + texImage = t->base.tObj->NegX[level]; + break; + case 2: + texImage = t->base.tObj->PosY[level]; + break; + case 3: + texImage = t->base.tObj->NegY[level]; + break; + case 4: + texImage = t->base.tObj->PosZ[level]; + break; + case 5: + texImage = t->base.tObj->NegZ[level]; + break; + } + + if ( !texImage ) { + if ( RADEON_DEBUG & DEBUG_TEXTURE ) + fprintf( stderr, "%s: texImage %d is NULL!\n", __FUNCTION__, level ); + return; + } + if ( !texImage->Data ) { + if ( RADEON_DEBUG & DEBUG_TEXTURE ) + fprintf( stderr, "%s: image data is NULL!\n", __FUNCTION__ ); + return; + } + + + if (t->base.tObj->Target == GL_TEXTURE_RECTANGLE_NV) { + assert(level == 0); + assert(hwlevel == 0); + if ( RADEON_DEBUG & DEBUG_TEXTURE ) + fprintf( stderr, "%s: image data is rectangular\n", __FUNCTION__); + radeonUploadRectSubImage( rmesa, t, texImage, x, y, width, height ); + return; + } + + imageWidth = texImage->Width; + imageHeight = texImage->Height; + + offset = t->bufAddr; + + if ( RADEON_DEBUG & (DEBUG_TEXTURE|DEBUG_IOCTL) ) { + GLint imageX = 0; + GLint imageY = 0; + GLint blitX = t->image[face][hwlevel].x; + GLint blitY = t->image[face][hwlevel].y; + GLint blitWidth = t->image[face][hwlevel].width; + GLint blitHeight = t->image[face][hwlevel].height; + fprintf( stderr, " upload image: %d,%d at %d,%d\n", + imageWidth, imageHeight, imageX, imageY ); + fprintf( stderr, " upload blit: %d,%d at %d,%d\n", + blitWidth, blitHeight, blitX, blitY ); + fprintf( stderr, " blit ofs: 0x%07x level: %d/%d\n", + (GLuint)offset, hwlevel, level ); + } + + t->image[face][hwlevel].data = texImage->Data; + + /* Init the DRM_RADEON_TEXTURE command / drmRadeonTexture struct. + * NOTE: we're always use a 1KB-wide blit and I8 texture format. + * We used to use 1, 2 and 4-byte texels and used to use the texture + * width to dictate the blit width - but that won't work for compressed + * textures. (Brian) + */ + tex.offset = offset; + tex.pitch = BLIT_WIDTH_BYTES / 64; + tex.format = RADEON_TXFORMAT_I8; /* any 1-byte texel format */ + if (texImage->TexFormat->TexelBytes) { + tex.width = imageWidth * texImage->TexFormat->TexelBytes; /* in bytes */ + tex.height = imageHeight; + } + else { + tex.width = imageWidth; /* compressed */ + tex.height = imageHeight; + if (tex.height < 4) + tex.height = 4; + } + tex.image = &tmp; + + /* copy (x,y,width,height,data) */ + memcpy( &tmp, &t->image[face][hwlevel], sizeof(drmRadeonTexImage) ); + + LOCK_HARDWARE( rmesa ); + do { + ret = drmCommandWriteRead( rmesa->dri.fd, DRM_RADEON_TEXTURE, + &tex, sizeof(drmRadeonTexture) ); + } while ( ret && errno == EAGAIN ); + + UNLOCK_HARDWARE( rmesa ); + + if ( ret ) { + fprintf( stderr, "DRM_RADEON_TEXTURE: return = %d\n", ret ); + fprintf( stderr, " offset=0x%08x\n", + offset ); + fprintf( stderr, " image width=%d height=%d\n", + imageWidth, imageHeight ); + fprintf( stderr, " blit width=%d height=%d data=%p\n", + t->image[face][hwlevel].width, t->image[face][hwlevel].height, + t->image[face][hwlevel].data ); + exit( 1 ); + } +} + + +/** + * Upload the texture images associated with texture \a t. This might + * require the allocation of texture memory. + * + * \param rmesa Context pointer + * \param t Texture to be uploaded + * \param face Cube map face to be uploaded. Zero for non-cube maps. + */ + +int radeonUploadTexImages( radeonContextPtr rmesa, radeonTexObjPtr t, GLuint face ) +{ + const int numLevels = t->base.lastLevel - t->base.firstLevel + 1; + + if ( RADEON_DEBUG & (DEBUG_TEXTURE|DEBUG_IOCTL) ) { + fprintf( stderr, "%s( %p, %p ) sz=%d lvls=%d-%d\n", __FUNCTION__, + rmesa->glCtx, t->base.tObj, t->base.totalSize, + t->base.firstLevel, t->base.lastLevel ); + } + + if ( !t || t->base.totalSize == 0 ) + return 0; + + LOCK_HARDWARE( rmesa ); + + if ( t->base.memBlock == NULL ) { + int heap; + + heap = driAllocateTexture( rmesa->texture_heaps, rmesa->nr_heaps, + (driTextureObject *) t ); + if ( heap == -1 ) { + UNLOCK_HARDWARE( rmesa ); + return -1; + } + + /* Set the base offset of the texture image */ + t->bufAddr = rmesa->radeonScreen->texOffset[heap] + + t->base.memBlock->ofs; + t->pp_txoffset = t->bufAddr; + + + /* Mark this texobj as dirty on all units: + */ + t->dirty_state = TEX_ALL; + } + + + /* Let the world know we've used this memory recently. + */ + driUpdateTextureLRU( (driTextureObject *) t ); + UNLOCK_HARDWARE( rmesa ); + + + /* Upload any images that are new */ + if (t->base.dirty_images[face]) { + int i; + for ( i = 0 ; i < numLevels ; i++ ) { + if ( (t->base.dirty_images[face] & (1 << (i+t->base.firstLevel))) != 0 ) { + uploadSubImage( rmesa, t, i, 0, 0, t->image[face][i].width, + t->image[face][i].height, face ); + } + } + t->base.dirty_images[face] = 0; + } + + return 0; +} diff --git a/src/mesa/drivers/dri/radeon/radeon_texstate.c b/src/mesa/drivers/dri/radeon/radeon_texstate.c new file mode 100644 index 0000000000..6dccd31180 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_texstate.c @@ -0,0 +1,1628 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_texstate.c,v 1.6 2002/12/16 16:18:59 dawes Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + VA Linux Systems Inc., Fremont, California. + +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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Kevin E. Martin <martin@valinux.com> + * Gareth Hughes <gareth@valinux.com> + */ + +#include "glheader.h" +#include "imports.h" +#include "colormac.h" +#include "context.h" +#include "macros.h" +#include "texformat.h" +#include "enums.h" + +#include "radeon_context.h" +#include "radeon_state.h" +#include "radeon_ioctl.h" +#include "radeon_swtcl.h" +#include "radeon_tex.h" +#include "radeon_tcl.h" + + +#define RADEON_TXFORMAT_AL88 RADEON_TXFORMAT_AI88 +#define RADEON_TXFORMAT_YCBCR RADEON_TXFORMAT_YVYU422 +#define RADEON_TXFORMAT_YCBCR_REV RADEON_TXFORMAT_VYUY422 + +#define _COLOR(f) \ + [ MESA_FORMAT_ ## f ] = { RADEON_TXFORMAT_ ## f, 0 } +#define _ALPHA(f) \ + [ MESA_FORMAT_ ## f ] = { RADEON_TXFORMAT_ ## f | RADEON_TXFORMAT_ALPHA_IN_MAP, 0 } +#define _YUV(f) \ + [ MESA_FORMAT_ ## f ] = { RADEON_TXFORMAT_ ## f, RADEON_YUV_TO_RGB } +#define _INVALID(f) \ + [ MESA_FORMAT_ ## f ] = { 0xffffffff, 0 } +#define VALID_FORMAT(f) ( ((f) <= MESA_FORMAT_YCBCR_REV) \ + && (tx_table[f].format != 0xffffffff) ) + +static const struct { + GLuint format, filter; +} +tx_table[] = +{ + _ALPHA(RGBA8888), + _ALPHA(ARGB8888), + _INVALID(RGB888), + _COLOR(RGB565), + _ALPHA(ARGB4444), + _ALPHA(ARGB1555), + _ALPHA(AL88), + _INVALID(A8), + _INVALID(L8), + _COLOR(I8), + _INVALID(CI8), + _YUV(YCBCR), + _YUV(YCBCR_REV), +}; + +#undef _COLOR +#undef _ALPHA +#undef _INVALID + +/** + * This function computes the number of bytes of storage needed for + * the given texture object (all mipmap levels, all cube faces). + * The \c image[face][level].x/y/width/height parameters for upload/blitting + * are computed here. \c pp_txfilter, \c pp_txformat, etc. will be set here + * too. + * + * \param rmesa Context pointer + * \param tObj GL texture object whose images are to be posted to + * hardware state. + */ +static void radeonSetTexImages( radeonContextPtr rmesa, + struct gl_texture_object *tObj ) +{ + radeonTexObjPtr t = (radeonTexObjPtr)tObj->DriverData; + const struct gl_texture_image *baseImage = tObj->Image[tObj->BaseLevel]; + GLint curOffset; + GLint i; + GLint firstLevel=0, lastLevel=0, numLevels; + GLint log2Width, log2Height, log2Depth; + + /* Set the hardware texture format + */ + + t->pp_txformat &= ~(RADEON_TXFORMAT_FORMAT_MASK | + RADEON_TXFORMAT_ALPHA_IN_MAP); + t->pp_txfilter &= ~RADEON_YUV_TO_RGB; + + if ( VALID_FORMAT( baseImage->TexFormat->MesaFormat ) ) { + t->pp_txformat |= tx_table[ baseImage->TexFormat->MesaFormat ].format; + t->pp_txfilter |= tx_table[ baseImage->TexFormat->MesaFormat ].filter; + } + else { + _mesa_problem(NULL, "unexpected texture format in %s", __FUNCTION__); + return; + } + + + + /* Compute which mipmap levels we really want to send to the hardware. + * This depends on the base image size, GL_TEXTURE_MIN_LOD, + * GL_TEXTURE_MAX_LOD, GL_TEXTURE_BASE_LEVEL, and GL_TEXTURE_MAX_LEVEL. + * Yes, this looks overly complicated, but it's all needed. + */ + switch (tObj->Target) { + case GL_TEXTURE_1D: + case GL_TEXTURE_2D: + 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 */ + log2Width = tObj->Image[firstLevel]->WidthLog2; + log2Height = tObj->Image[firstLevel]->HeightLog2; + log2Depth = 0; + break; + case GL_TEXTURE_RECTANGLE_NV: + firstLevel = lastLevel = 0; + log2Width = log2Height = 1; /* ? */ + log2Depth = 0; + break; + default: + return; + } + + /* save these values */ + t->base.firstLevel = firstLevel; + t->base.lastLevel = lastLevel; + + numLevels = lastLevel - firstLevel + 1; + + assert(numLevels <= RADEON_MAX_TEXTURE_LEVELS); + + /* Calculate mipmap offsets and dimensions for blitting (uploading) + * The idea is that we lay out the mipmap levels within a block of + * memory organized as a rectangle of width BLIT_WIDTH_BYTES. + */ + curOffset = 0; + + for (i = 0; i < numLevels; i++) { + const struct gl_texture_image *texImage; + GLuint size; + + texImage = tObj->Image[i + firstLevel]; + if ( !texImage ) + break; + + /* find image size in bytes */ + if (texImage->IsCompressed) { + size = texImage->CompressedSize; + } + else if (tObj->Target == GL_TEXTURE_RECTANGLE_NV) { + size = ((texImage->Width * texImage->TexFormat->TexelBytes + 63) + & ~63) * texImage->Height; + } + else { + int w = texImage->Width * texImage->TexFormat->TexelBytes; + if (w < 32) + w = 32; + size = w * texImage->Height * texImage->Depth; + } + assert(size > 0); + + if (curOffset & 0x1f) { + /* align to 32-byte offset */ + curOffset = (curOffset + 0x1f) & ~0x1f; + } + + t->image[0][i].x = curOffset % BLIT_WIDTH_BYTES; + t->image[0][i].y = curOffset / BLIT_WIDTH_BYTES; + t->image[0][i].width = MIN2(size, BLIT_WIDTH_BYTES); + t->image[0][i].height = size / t->image[0][i].width; + +#if 0 + /* for debugging only and only applicable to non-rectangle targets */ + assert(size % t->image[0][i].width == 0); + assert(t->image[0][i].x == 0 + || (size < BLIT_WIDTH_BYTES && t->image[0][i].height == 1)); +#endif + + if (0) + fprintf(stderr, + "level %d: %dx%d x=%d y=%d w=%d h=%d size=%d at %d\n", + i, texImage->Width, texImage->Height, + t->image[0][i].x, t->image[0][i].y, + t->image[0][i].width, t->image[0][i].height, size, curOffset); + + curOffset += size; + + } + + /* Align the total size of texture memory block. + */ + t->base.totalSize = (curOffset + RADEON_OFFSET_MASK) & ~RADEON_OFFSET_MASK; + + /* Hardware state: + */ + t->pp_txfilter &= ~RADEON_MAX_MIP_LEVEL_MASK; + t->pp_txfilter |= (numLevels - 1) << RADEON_MAX_MIP_LEVEL_SHIFT; + + t->pp_txformat &= ~(RADEON_TXFORMAT_WIDTH_MASK | + RADEON_TXFORMAT_HEIGHT_MASK | + RADEON_TXFORMAT_CUBIC_MAP_ENABLE); + t->pp_txformat |= ((log2Width << RADEON_TXFORMAT_WIDTH_SHIFT) | + (log2Height << RADEON_TXFORMAT_HEIGHT_SHIFT)); + + t->pp_txsize = (((tObj->Image[firstLevel]->Width - 1) << 0) | + ((tObj->Image[firstLevel]->Height - 1) << 16)); + + /* Only need to round to nearest 32 for textures, but the blitter + * requires 64-byte aligned pitches, and we may/may not need the + * blitter. NPOT only! + */ + if (baseImage->IsCompressed) + t->pp_txpitch = (tObj->Image[firstLevel]->Width + 63) & ~(63); + else + t->pp_txpitch = ((tObj->Image[firstLevel]->Width * baseImage->TexFormat->TexelBytes) + 63) & ~(63); + t->pp_txpitch -= 32; + + t->dirty_state = TEX_ALL; + + /* FYI: radeonUploadTexImages( rmesa, t ); used to be called here */ +} + + + +/* ================================================================ + * Texture combine functions + */ + +#define RADEON_DISABLE 0 +#define RADEON_REPLACE 1 +#define RADEON_MODULATE 2 +#define RADEON_DECAL 3 +#define RADEON_BLEND 4 +#define RADEON_ADD 5 +#define RADEON_MAX_COMBFUNC 6 + +static GLuint radeon_color_combine[][RADEON_MAX_COMBFUNC] = +{ + /* Unit 0: + */ + { + /* Disable combiner stage + */ + (RADEON_COLOR_ARG_A_ZERO | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_CURRENT_COLOR | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_REPLACE = 0x00802800 + */ + (RADEON_COLOR_ARG_A_ZERO | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_T0_COLOR | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_MODULATE = 0x00800142 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_T0_COLOR | + RADEON_COLOR_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_DECAL = 0x008c2d42 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_T0_COLOR | + RADEON_COLOR_ARG_C_T0_ALPHA | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_BLEND = 0x008c2902 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_TFACTOR_COLOR | + RADEON_COLOR_ARG_C_T0_COLOR | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_ADD = 0x00812802 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_T0_COLOR | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + }, + + /* Unit 1: + */ + { + /* Disable combiner stage + */ + (RADEON_COLOR_ARG_A_ZERO | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_CURRENT_COLOR | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_REPLACE = 0x00803000 + */ + (RADEON_COLOR_ARG_A_ZERO | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_T1_COLOR | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_MODULATE = 0x00800182 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_T1_COLOR | + RADEON_COLOR_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_DECAL = 0x008c3582 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_T1_COLOR | + RADEON_COLOR_ARG_C_T1_ALPHA | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_BLEND = 0x008c3102 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_TFACTOR_COLOR | + RADEON_COLOR_ARG_C_T1_COLOR | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_ADD = 0x00813002 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_T1_COLOR | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + }, + + /* Unit 2: + */ + { + /* Disable combiner stage + */ + (RADEON_COLOR_ARG_A_ZERO | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_CURRENT_COLOR | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_REPLACE = 0x00803800 + */ + (RADEON_COLOR_ARG_A_ZERO | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_T2_COLOR | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_MODULATE = 0x008001c2 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_T2_COLOR | + RADEON_COLOR_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_DECAL = 0x008c3dc2 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_T2_COLOR | + RADEON_COLOR_ARG_C_T2_ALPHA | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_BLEND = 0x008c3902 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_TFACTOR_COLOR | + RADEON_COLOR_ARG_C_T2_COLOR | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_ADD = 0x00813802 + */ + (RADEON_COLOR_ARG_A_CURRENT_COLOR | + RADEON_COLOR_ARG_B_ZERO | + RADEON_COLOR_ARG_C_T2_COLOR | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + } +}; + +static GLuint radeon_alpha_combine[][RADEON_MAX_COMBFUNC] = +{ + /* Unit 0: + */ + { + /* Disable combiner stage + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_CURRENT_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_REPLACE = 0x00800500 + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_T0_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_MODULATE = 0x00800051 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_T0_ALPHA | + RADEON_ALPHA_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_DECAL = 0x00800100 + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_CURRENT_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_BLEND = 0x00800051 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_TFACTOR_ALPHA | + RADEON_ALPHA_ARG_C_T0_ALPHA | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_ADD = 0x00800051 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_T0_ALPHA | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + }, + + /* Unit 1: + */ + { + /* Disable combiner stage + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_CURRENT_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_REPLACE = 0x00800600 + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_T1_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_MODULATE = 0x00800061 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_T1_ALPHA | + RADEON_ALPHA_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_DECAL = 0x00800100 + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_CURRENT_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_BLEND = 0x00800061 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_TFACTOR_ALPHA | + RADEON_ALPHA_ARG_C_T1_ALPHA | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_ADD = 0x00800061 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_T1_ALPHA | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + }, + + /* Unit 2: + */ + { + /* Disable combiner stage + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_CURRENT_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_REPLACE = 0x00800700 + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_T2_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_MODULATE = 0x00800071 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_T2_ALPHA | + RADEON_ALPHA_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_DECAL = 0x00800100 + */ + (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_CURRENT_ALPHA | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_BLEND = 0x00800071 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_TFACTOR_ALPHA | + RADEON_ALPHA_ARG_C_T2_ALPHA | + RADEON_BLEND_CTL_BLEND | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + + /* GL_ADD = 0x00800021 + */ + (RADEON_ALPHA_ARG_A_CURRENT_ALPHA | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_ALPHA_ARG_C_T2_ALPHA | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADD | + RADEON_SCALE_1X | + RADEON_CLAMP_TX), + } +}; + + +/* GL_ARB_texture_env_combine support + */ + +/* The color tables have combine functions for GL_SRC_COLOR, + * GL_ONE_MINUS_SRC_COLOR, GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA. + */ +static GLuint radeon_texture_color[][RADEON_MAX_TEXTURE_UNITS] = +{ + { + RADEON_COLOR_ARG_A_T0_COLOR, + RADEON_COLOR_ARG_A_T1_COLOR, + RADEON_COLOR_ARG_A_T2_COLOR + }, + { + RADEON_COLOR_ARG_A_T0_COLOR | RADEON_COMP_ARG_A, + RADEON_COLOR_ARG_A_T1_COLOR | RADEON_COMP_ARG_A, + RADEON_COLOR_ARG_A_T2_COLOR | RADEON_COMP_ARG_A + }, + { + RADEON_COLOR_ARG_A_T0_ALPHA, + RADEON_COLOR_ARG_A_T1_ALPHA, + RADEON_COLOR_ARG_A_T2_ALPHA + }, + { + RADEON_COLOR_ARG_A_T0_ALPHA | RADEON_COMP_ARG_A, + RADEON_COLOR_ARG_A_T1_ALPHA | RADEON_COMP_ARG_A, + RADEON_COLOR_ARG_A_T2_ALPHA | RADEON_COMP_ARG_A + }, +}; + +static GLuint radeon_tfactor_color[] = +{ + RADEON_COLOR_ARG_A_TFACTOR_COLOR, + RADEON_COLOR_ARG_A_TFACTOR_COLOR | RADEON_COMP_ARG_A, + RADEON_COLOR_ARG_A_TFACTOR_ALPHA, + RADEON_COLOR_ARG_A_TFACTOR_ALPHA | RADEON_COMP_ARG_A +}; + +static GLuint radeon_primary_color[] = +{ + RADEON_COLOR_ARG_A_DIFFUSE_COLOR, + RADEON_COLOR_ARG_A_DIFFUSE_COLOR | RADEON_COMP_ARG_A, + RADEON_COLOR_ARG_A_DIFFUSE_ALPHA, + RADEON_COLOR_ARG_A_DIFFUSE_ALPHA | RADEON_COMP_ARG_A +}; + +static GLuint radeon_previous_color[] = +{ + RADEON_COLOR_ARG_A_CURRENT_COLOR, + RADEON_COLOR_ARG_A_CURRENT_COLOR | RADEON_COMP_ARG_A, + RADEON_COLOR_ARG_A_CURRENT_ALPHA, + RADEON_COLOR_ARG_A_CURRENT_ALPHA | RADEON_COMP_ARG_A +}; + +/* GL_ZERO table - indices 0-3 + * GL_ONE table - indices 1-4 + */ +static GLuint radeon_zero_color[] = +{ + RADEON_COLOR_ARG_A_ZERO, + RADEON_COLOR_ARG_A_ZERO | RADEON_COMP_ARG_A, + RADEON_COLOR_ARG_A_ZERO, + RADEON_COLOR_ARG_A_ZERO | RADEON_COMP_ARG_A, + RADEON_COLOR_ARG_A_ZERO +}; + + +/* The alpha tables only have GL_SRC_ALPHA and GL_ONE_MINUS_SRC_ALPHA. + */ +static GLuint radeon_texture_alpha[][RADEON_MAX_TEXTURE_UNITS] = +{ + { + RADEON_ALPHA_ARG_A_T0_ALPHA, + RADEON_ALPHA_ARG_A_T1_ALPHA, + RADEON_ALPHA_ARG_A_T2_ALPHA + }, + { + RADEON_ALPHA_ARG_A_T0_ALPHA | RADEON_COMP_ARG_A, + RADEON_ALPHA_ARG_A_T1_ALPHA | RADEON_COMP_ARG_A, + RADEON_ALPHA_ARG_A_T2_ALPHA | RADEON_COMP_ARG_A + }, +}; + +static GLuint radeon_tfactor_alpha[] = +{ + RADEON_ALPHA_ARG_A_TFACTOR_ALPHA, + RADEON_ALPHA_ARG_A_TFACTOR_ALPHA | RADEON_COMP_ARG_A +}; + +static GLuint radeon_primary_alpha[] = +{ + RADEON_ALPHA_ARG_A_DIFFUSE_ALPHA, + RADEON_ALPHA_ARG_A_DIFFUSE_ALPHA | RADEON_COMP_ARG_A +}; + +static GLuint radeon_previous_alpha[] = +{ + RADEON_ALPHA_ARG_A_CURRENT_ALPHA, + RADEON_ALPHA_ARG_A_CURRENT_ALPHA | RADEON_COMP_ARG_A +}; + +/* GL_ZERO table - indices 0-1 + * GL_ONE table - indices 1-2 + */ +static GLuint radeon_zero_alpha[] = +{ + RADEON_ALPHA_ARG_A_ZERO, + RADEON_ALPHA_ARG_A_ZERO | RADEON_COMP_ARG_A, + RADEON_ALPHA_ARG_A_ZERO +}; + + +/* Extract the arg from slot A, shift it into the correct argument slot + * and set the corresponding complement bit. + */ +#define RADEON_COLOR_ARG( n, arg ) \ +do { \ + color_combine |= \ + ((color_arg[n] & RADEON_COLOR_ARG_MASK) \ + << RADEON_COLOR_ARG_##arg##_SHIFT); \ + color_combine |= \ + ((color_arg[n] >> RADEON_COMP_ARG_SHIFT) \ + << RADEON_COMP_ARG_##arg##_SHIFT); \ +} while (0) + +#define RADEON_ALPHA_ARG( n, arg ) \ +do { \ + alpha_combine |= \ + ((alpha_arg[n] & RADEON_ALPHA_ARG_MASK) \ + << RADEON_ALPHA_ARG_##arg##_SHIFT); \ + alpha_combine |= \ + ((alpha_arg[n] >> RADEON_COMP_ARG_SHIFT) \ + << RADEON_COMP_ARG_##arg##_SHIFT); \ +} while (0) + + +/* ================================================================ + * Texture unit state management + */ + +static GLboolean radeonUpdateTextureEnv( GLcontext *ctx, int unit ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + const struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + GLuint color_combine, alpha_combine; + + /* texUnit->_Current can be NULL if and only if the texture unit is + * not actually enabled. + */ + assert( (texUnit->_ReallyEnabled == 0) + || (texUnit->_Current != NULL) ); + + if ( RADEON_DEBUG & DEBUG_TEXTURE ) { + fprintf( stderr, "%s( %p, %d )\n", __FUNCTION__, ctx, unit ); + } + + /* Set the texture environment state. Isn't this nice and clean? + * The chip will automagically set the texture alpha to 0xff when + * the texture format does not include an alpha component. This + * reduces the amount of special-casing we have to do, alpha-only + * textures being a notable exception. + */ + if ( !texUnit->_ReallyEnabled ) { + /* Don't cache these results. + */ + rmesa->state.texture.unit[unit].format = 0; + rmesa->state.texture.unit[unit].envMode = 0; + color_combine = radeon_color_combine[unit][RADEON_DISABLE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE]; + } + else { + const struct gl_texture_object *tObj = texUnit->_Current; + const GLenum format = tObj->Image[tObj->BaseLevel]->Format; + GLuint color_arg[3], alpha_arg[3]; + GLuint i, numColorArgs = 0, numAlphaArgs = 0; + GLuint RGBshift = texUnit->CombineScaleShiftRGB; + GLuint Ashift = texUnit->CombineScaleShiftA; + + switch ( texUnit->EnvMode ) { + case GL_REPLACE: + switch ( format ) { + case GL_RGBA: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + color_combine = radeon_color_combine[unit][RADEON_REPLACE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_REPLACE]; + break; + case GL_ALPHA: + color_combine = radeon_color_combine[unit][RADEON_DISABLE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_REPLACE]; + break; + case GL_LUMINANCE: + case GL_RGB: + case GL_YCBCR_MESA: + color_combine = radeon_color_combine[unit][RADEON_REPLACE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE]; + break; + case GL_COLOR_INDEX: + default: + return GL_FALSE; + } + break; + + case GL_MODULATE: + switch ( format ) { + case GL_RGBA: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + color_combine = radeon_color_combine[unit][RADEON_MODULATE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE]; + break; + case GL_ALPHA: + color_combine = radeon_color_combine[unit][RADEON_DISABLE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE]; + break; + case GL_RGB: + case GL_LUMINANCE: + case GL_YCBCR_MESA: + color_combine = radeon_color_combine[unit][RADEON_MODULATE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE]; + break; + case GL_COLOR_INDEX: + default: + return GL_FALSE; + } + break; + + case GL_DECAL: + switch ( format ) { + case GL_RGBA: + case GL_RGB: + case GL_YCBCR_MESA: + color_combine = radeon_color_combine[unit][RADEON_DECAL]; + alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE]; + break; + case GL_ALPHA: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_INTENSITY: + color_combine = radeon_color_combine[unit][RADEON_DISABLE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_DISABLE]; + break; + case GL_COLOR_INDEX: + default: + return GL_FALSE; + } + break; + + case GL_BLEND: + switch ( format ) { + case GL_RGBA: + case GL_RGB: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_YCBCR_MESA: + color_combine = radeon_color_combine[unit][RADEON_BLEND]; + alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE]; + break; + case GL_ALPHA: + color_combine = radeon_color_combine[unit][RADEON_DISABLE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE]; + break; + case GL_INTENSITY: + color_combine = radeon_color_combine[unit][RADEON_BLEND]; + alpha_combine = radeon_alpha_combine[unit][RADEON_BLEND]; + break; + case GL_COLOR_INDEX: + default: + return GL_FALSE; + } + break; + + case GL_ADD: + switch ( format ) { + case GL_RGBA: + case GL_RGB: + case GL_LUMINANCE: + case GL_LUMINANCE_ALPHA: + case GL_YCBCR_MESA: + color_combine = radeon_color_combine[unit][RADEON_ADD]; + alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE]; + break; + case GL_ALPHA: + color_combine = radeon_color_combine[unit][RADEON_DISABLE]; + alpha_combine = radeon_alpha_combine[unit][RADEON_MODULATE]; + break; + case GL_INTENSITY: + color_combine = radeon_color_combine[unit][RADEON_ADD]; + alpha_combine = radeon_alpha_combine[unit][RADEON_ADD]; + break; + case GL_COLOR_INDEX: + default: + return GL_FALSE; + } + break; + + case GL_COMBINE: + /* Don't cache these results. + */ + rmesa->state.texture.unit[unit].format = 0; + rmesa->state.texture.unit[unit].envMode = 0; + + /* Step 0: + * Calculate how many arguments we need to process. + */ + switch ( texUnit->CombineModeRGB ) { + case GL_REPLACE: + numColorArgs = 1; + break; + case GL_MODULATE: + case GL_ADD: + case GL_ADD_SIGNED: + case GL_SUBTRACT: + case GL_DOT3_RGB: + case GL_DOT3_RGBA: + case GL_DOT3_RGB_EXT: + case GL_DOT3_RGBA_EXT: + numColorArgs = 2; + break; + case GL_INTERPOLATE: + case GL_MODULATE_ADD_ATI: + case GL_MODULATE_SIGNED_ADD_ATI: + case GL_MODULATE_SUBTRACT_ATI: + numColorArgs = 3; + break; + default: + return GL_FALSE; + } + + switch ( texUnit->CombineModeA ) { + case GL_REPLACE: + numAlphaArgs = 1; + break; + case GL_MODULATE: + case GL_ADD: + case GL_ADD_SIGNED: + case GL_SUBTRACT: + numAlphaArgs = 2; + break; + case GL_INTERPOLATE: + case GL_MODULATE_ADD_ATI: + case GL_MODULATE_SIGNED_ADD_ATI: + case GL_MODULATE_SUBTRACT_ATI: + numAlphaArgs = 3; + break; + default: + return GL_FALSE; + } + + /* Step 1: + * Extract the color and alpha combine function arguments. + */ + for ( i = 0 ; i < numColorArgs ; i++ ) { + const GLuint op = texUnit->CombineOperandRGB[i] - GL_SRC_COLOR; + assert(op >= 0); + assert(op <= 3); + switch ( texUnit->CombineSourceRGB[i] ) { + case GL_TEXTURE: + color_arg[i] = radeon_texture_color[op][unit]; + break; + case GL_CONSTANT: + color_arg[i] = radeon_tfactor_color[op]; + break; + case GL_PRIMARY_COLOR: + color_arg[i] = radeon_primary_color[op]; + break; + case GL_PREVIOUS: + color_arg[i] = radeon_previous_color[op]; + break; + case GL_ZERO: + color_arg[i] = radeon_zero_color[op]; + break; + case GL_ONE: + color_arg[i] = radeon_zero_color[op+1]; + break; + default: + return GL_FALSE; + } + } + + for ( i = 0 ; i < numAlphaArgs ; i++ ) { + const GLuint op = texUnit->CombineOperandA[i] - GL_SRC_ALPHA; + assert(op >= 0); + assert(op <= 1); + switch ( texUnit->CombineSourceA[i] ) { + case GL_TEXTURE: + alpha_arg[i] = radeon_texture_alpha[op][unit]; + break; + case GL_CONSTANT: + alpha_arg[i] = radeon_tfactor_alpha[op]; + break; + case GL_PRIMARY_COLOR: + alpha_arg[i] = radeon_primary_alpha[op]; + break; + case GL_PREVIOUS: + alpha_arg[i] = radeon_previous_alpha[op]; + break; + case GL_ZERO: + alpha_arg[i] = radeon_zero_alpha[op]; + break; + case GL_ONE: + alpha_arg[i] = radeon_zero_alpha[op+1]; + break; + default: + return GL_FALSE; + } + } + + /* Step 2: + * Build up the color and alpha combine functions. + */ + switch ( texUnit->CombineModeRGB ) { + case GL_REPLACE: + color_combine = (RADEON_COLOR_ARG_A_ZERO | + RADEON_COLOR_ARG_B_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_CLAMP_TX); + RADEON_COLOR_ARG( 0, C ); + break; + case GL_MODULATE: + color_combine = (RADEON_COLOR_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_CLAMP_TX); + RADEON_COLOR_ARG( 0, A ); + RADEON_COLOR_ARG( 1, B ); + break; + case GL_ADD: + color_combine = (RADEON_COLOR_ARG_B_ZERO | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADD | + RADEON_CLAMP_TX); + RADEON_COLOR_ARG( 0, A ); + RADEON_COLOR_ARG( 1, C ); + break; + case GL_ADD_SIGNED: + color_combine = (RADEON_COLOR_ARG_B_ZERO | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADDSIGNED | + RADEON_CLAMP_TX); + RADEON_COLOR_ARG( 0, A ); + RADEON_COLOR_ARG( 1, C ); + break; + case GL_SUBTRACT: + color_combine = (RADEON_COLOR_ARG_B_ZERO | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_SUBTRACT | + RADEON_CLAMP_TX); + RADEON_COLOR_ARG( 0, A ); + RADEON_COLOR_ARG( 1, C ); + break; + case GL_INTERPOLATE: + color_combine = (RADEON_BLEND_CTL_BLEND | + RADEON_CLAMP_TX); + RADEON_COLOR_ARG( 0, B ); + RADEON_COLOR_ARG( 1, A ); + RADEON_COLOR_ARG( 2, C ); + break; + + case GL_DOT3_RGB_EXT: + case GL_DOT3_RGBA_EXT: + /* 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. + */ + RGBshift = 0; + Ashift = 0; + /* FALLTHROUGH */ + + case GL_DOT3_RGB: + case GL_DOT3_RGBA: + /* The R100 / RV200 only support a 1X multiplier in hardware + * w/the ARB version. + */ + if ( RGBshift != (RADEON_SCALE_1X >> RADEON_SCALE_SHIFT) ) { + return GL_FALSE; + } + + RGBshift += 2; + Ashift = RGBshift; + + color_combine = (RADEON_COLOR_ARG_C_ZERO | + RADEON_BLEND_CTL_DOT3 | + RADEON_CLAMP_TX); + RADEON_COLOR_ARG( 0, A ); + RADEON_COLOR_ARG( 1, B ); + break; + + case GL_MODULATE_ADD_ATI: + color_combine = (RADEON_BLEND_CTL_ADD | + RADEON_CLAMP_TX); + RADEON_COLOR_ARG( 0, A ); + RADEON_COLOR_ARG( 1, C ); + RADEON_COLOR_ARG( 2, B ); + break; + case GL_MODULATE_SIGNED_ADD_ATI: + color_combine = (RADEON_BLEND_CTL_ADDSIGNED | + RADEON_CLAMP_TX); + RADEON_COLOR_ARG( 0, A ); + RADEON_COLOR_ARG( 1, C ); + RADEON_COLOR_ARG( 2, B ); + break; + case GL_MODULATE_SUBTRACT_ATI: + color_combine = (RADEON_BLEND_CTL_SUBTRACT | + RADEON_CLAMP_TX); + RADEON_COLOR_ARG( 0, A ); + RADEON_COLOR_ARG( 1, C ); + RADEON_COLOR_ARG( 2, B ); + break; + default: + return GL_FALSE; + } + + switch ( texUnit->CombineModeA ) { + case GL_REPLACE: + alpha_combine = (RADEON_ALPHA_ARG_A_ZERO | + RADEON_ALPHA_ARG_B_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_CLAMP_TX); + RADEON_ALPHA_ARG( 0, C ); + break; + case GL_MODULATE: + alpha_combine = (RADEON_ALPHA_ARG_C_ZERO | + RADEON_BLEND_CTL_ADD | + RADEON_CLAMP_TX); + RADEON_ALPHA_ARG( 0, A ); + RADEON_ALPHA_ARG( 1, B ); + break; + case GL_ADD: + alpha_combine = (RADEON_ALPHA_ARG_B_ZERO | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADD | + RADEON_CLAMP_TX); + RADEON_ALPHA_ARG( 0, A ); + RADEON_ALPHA_ARG( 1, C ); + break; + case GL_ADD_SIGNED: + alpha_combine = (RADEON_ALPHA_ARG_B_ZERO | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_ADDSIGNED | + RADEON_CLAMP_TX); + RADEON_ALPHA_ARG( 0, A ); + RADEON_ALPHA_ARG( 1, C ); + break; + case GL_SUBTRACT: + alpha_combine = (RADEON_COLOR_ARG_B_ZERO | + RADEON_COMP_ARG_B | + RADEON_BLEND_CTL_SUBTRACT | + RADEON_CLAMP_TX); + RADEON_ALPHA_ARG( 0, A ); + RADEON_ALPHA_ARG( 1, C ); + break; + case GL_INTERPOLATE: + alpha_combine = (RADEON_BLEND_CTL_BLEND | + RADEON_CLAMP_TX); + RADEON_ALPHA_ARG( 0, B ); + RADEON_ALPHA_ARG( 1, A ); + RADEON_ALPHA_ARG( 2, C ); + break; + + case GL_MODULATE_ADD_ATI: + alpha_combine = (RADEON_BLEND_CTL_ADD | + RADEON_CLAMP_TX); + RADEON_ALPHA_ARG( 0, A ); + RADEON_ALPHA_ARG( 1, C ); + RADEON_ALPHA_ARG( 2, B ); + break; + case GL_MODULATE_SIGNED_ADD_ATI: + alpha_combine = (RADEON_BLEND_CTL_ADDSIGNED | + RADEON_CLAMP_TX); + RADEON_ALPHA_ARG( 0, A ); + RADEON_ALPHA_ARG( 1, C ); + RADEON_ALPHA_ARG( 2, B ); + break; + case GL_MODULATE_SUBTRACT_ATI: + alpha_combine = (RADEON_BLEND_CTL_SUBTRACT | + RADEON_CLAMP_TX); + RADEON_ALPHA_ARG( 0, A ); + RADEON_ALPHA_ARG( 1, C ); + RADEON_ALPHA_ARG( 2, B ); + break; + default: + return GL_FALSE; + } + + if ( (texUnit->CombineModeRGB == GL_DOT3_RGB_EXT) + || (texUnit->CombineModeRGB == GL_DOT3_RGB) ) { + alpha_combine |= RADEON_DOT_ALPHA_DONT_REPLICATE; + } + + /* Step 3: + * Apply the scale factor. + */ + color_combine |= (RGBshift << RADEON_SCALE_SHIFT); + alpha_combine |= (Ashift << RADEON_SCALE_SHIFT); + + /* All done! + */ + break; + + default: + return GL_FALSE; + } + } + + if ( rmesa->hw.tex[unit].cmd[TEX_PP_TXCBLEND] != color_combine || + rmesa->hw.tex[unit].cmd[TEX_PP_TXABLEND] != alpha_combine ) { + RADEON_STATECHANGE( rmesa, tex[unit] ); + rmesa->hw.tex[unit].cmd[TEX_PP_TXCBLEND] = color_combine; + rmesa->hw.tex[unit].cmd[TEX_PP_TXABLEND] = alpha_combine; + } + + return GL_TRUE; +} + +#define TEXOBJ_TXFILTER_MASK (RADEON_MAX_MIP_LEVEL_MASK | \ + RADEON_MIN_FILTER_MASK | \ + RADEON_MAG_FILTER_MASK | \ + RADEON_MAX_ANISO_MASK | \ + RADEON_YUV_TO_RGB | \ + RADEON_YUV_TEMPERATURE_MASK | \ + RADEON_CLAMP_S_MASK | \ + RADEON_CLAMP_T_MASK | \ + RADEON_BORDER_MODE_D3D ) + +#define TEXOBJ_TXFORMAT_MASK (RADEON_TXFORMAT_WIDTH_MASK | \ + RADEON_TXFORMAT_HEIGHT_MASK | \ + RADEON_TXFORMAT_FORMAT_MASK | \ + RADEON_TXFORMAT_F5_WIDTH_MASK | \ + RADEON_TXFORMAT_F5_HEIGHT_MASK | \ + RADEON_TXFORMAT_ALPHA_IN_MAP | \ + RADEON_TXFORMAT_CUBIC_MAP_ENABLE | \ + RADEON_TXFORMAT_NON_POWER2) + + +static void import_tex_obj_state( radeonContextPtr rmesa, + int unit, + radeonTexObjPtr texobj ) +{ + GLuint *cmd = RADEON_DB_STATE( tex[unit] ); + + cmd[TEX_PP_TXFILTER] &= ~TEXOBJ_TXFILTER_MASK; + cmd[TEX_PP_TXFILTER] |= texobj->pp_txfilter & TEXOBJ_TXFILTER_MASK; + cmd[TEX_PP_TXFORMAT] &= ~TEXOBJ_TXFORMAT_MASK; + cmd[TEX_PP_TXFORMAT] |= texobj->pp_txformat & TEXOBJ_TXFORMAT_MASK; + cmd[TEX_PP_TXOFFSET] = texobj->pp_txoffset; + cmd[TEX_PP_BORDER_COLOR] = texobj->pp_border_color; + RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.tex[unit] ); + + if (texobj->base.tObj->Target == GL_TEXTURE_RECTANGLE_NV) { + GLuint *txr_cmd = RADEON_DB_STATE( txr[unit] ); + txr_cmd[TXR_PP_TEX_SIZE] = texobj->pp_txsize; /* NPOT only! */ + txr_cmd[TXR_PP_TEX_PITCH] = texobj->pp_txpitch; /* NPOT only! */ + RADEON_DB_STATECHANGE( rmesa, &rmesa->hw.txr[unit] ); + } + + texobj->dirty_state &= ~(1<<unit); +} + + + + +static void set_texgen_matrix( radeonContextPtr rmesa, + GLuint unit, + const GLfloat *s_plane, + const GLfloat *t_plane ) +{ + static const GLfloat scale_identity[4] = { 1,1,1,1 }; + + if (!TEST_EQ_4V( s_plane, scale_identity) || + !TEST_EQ_4V( t_plane, scale_identity)) { + rmesa->TexGenEnabled |= RADEON_TEXMAT_0_ENABLE<<unit; + rmesa->TexGenMatrix[unit].m[0] = s_plane[0]; + rmesa->TexGenMatrix[unit].m[4] = s_plane[1]; + rmesa->TexGenMatrix[unit].m[8] = s_plane[2]; + rmesa->TexGenMatrix[unit].m[12] = s_plane[3]; + + rmesa->TexGenMatrix[unit].m[1] = t_plane[0]; + rmesa->TexGenMatrix[unit].m[5] = t_plane[1]; + rmesa->TexGenMatrix[unit].m[9] = t_plane[2]; + rmesa->TexGenMatrix[unit].m[13] = t_plane[3]; + rmesa->NewGLState |= _NEW_TEXTURE_MATRIX; + } +} + +/* Ignoring the Q texcoord for now. + * + * Returns GL_FALSE if fallback required. + */ +static GLboolean radeon_validate_texgen( GLcontext *ctx, GLuint unit ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + GLuint inputshift = RADEON_TEXGEN_0_INPUT_SHIFT + unit*4; + GLuint tmp = rmesa->TexGenEnabled; + + rmesa->TexGenEnabled &= ~(RADEON_TEXGEN_TEXMAT_0_ENABLE<<unit); + rmesa->TexGenEnabled &= ~(RADEON_TEXMAT_0_ENABLE<<unit); + rmesa->TexGenEnabled &= ~(RADEON_TEXGEN_INPUT_MASK<<inputshift); + rmesa->TexGenNeedNormals[unit] = 0; + + if ((texUnit->TexGenEnabled & (S_BIT|T_BIT)) == 0) { + /* Disabled, no fallback: + */ + rmesa->TexGenEnabled |= + (RADEON_TEXGEN_INPUT_TEXCOORD_0+unit) << inputshift; + return GL_TRUE; + } + else if (texUnit->TexGenEnabled & Q_BIT) { + /* Very easy to do this, in fact would remove a fallback case + * elsewhere, but I haven't done it yet... Fallback: + */ + fprintf(stderr, "fallback Q_BIT\n"); + return GL_FALSE; + } + else if ((texUnit->TexGenEnabled & (S_BIT|T_BIT)) != (S_BIT|T_BIT) || + texUnit->GenModeS != texUnit->GenModeT) { + /* Mixed modes, fallback: + */ + /* fprintf(stderr, "fallback mixed texgen\n"); */ + return GL_FALSE; + } + else + rmesa->TexGenEnabled |= RADEON_TEXGEN_TEXMAT_0_ENABLE << unit; + + switch (texUnit->GenModeS) { + case GL_OBJECT_LINEAR: + rmesa->TexGenEnabled |= RADEON_TEXGEN_INPUT_OBJ << inputshift; + set_texgen_matrix( rmesa, unit, + texUnit->ObjectPlaneS, + texUnit->ObjectPlaneT); + break; + + case GL_EYE_LINEAR: + rmesa->TexGenEnabled |= RADEON_TEXGEN_INPUT_EYE << inputshift; + set_texgen_matrix( rmesa, unit, + texUnit->EyePlaneS, + texUnit->EyePlaneT); + break; + + case GL_REFLECTION_MAP_NV: + rmesa->TexGenNeedNormals[unit] = GL_TRUE; + rmesa->TexGenEnabled |= RADEON_TEXGEN_INPUT_EYE_REFLECT<<inputshift; + break; + + case GL_NORMAL_MAP_NV: + rmesa->TexGenNeedNormals[unit] = GL_TRUE; + rmesa->TexGenEnabled |= RADEON_TEXGEN_INPUT_EYE_NORMAL<<inputshift; + break; + + case GL_SPHERE_MAP: + default: + /* Unsupported mode, fallback: + */ + /* fprintf(stderr, "fallback unsupported texgen\n"); */ + return GL_FALSE; + } + + if (tmp != rmesa->TexGenEnabled) { + rmesa->NewGLState |= _NEW_TEXTURE_MATRIX; + } + + return GL_TRUE; +} + + +static void disable_tex( GLcontext *ctx, int unit ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if (rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (RADEON_TEX_0_ENABLE<<unit)) { + /* Texture unit disabled */ + if ( rmesa->state.texture.unit[unit].texobj != NULL ) { + /* The old texture is no longer bound to this texture unit. + * Mark it as such. + */ + + rmesa->state.texture.unit[unit].texobj->base.bound &= ~(1UL << unit); + rmesa->state.texture.unit[unit].texobj = NULL; + } + + RADEON_STATECHANGE( rmesa, ctx ); + rmesa->hw.ctx.cmd[CTX_PP_CNTL] &= + ~((RADEON_TEX_0_ENABLE | RADEON_TEX_BLEND_0_ENABLE) << unit); + + RADEON_STATECHANGE( rmesa, tcl ); + switch (unit) { + case 0: + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~(RADEON_TCL_VTX_ST0 | + RADEON_TCL_VTX_Q0); + break; + case 1: + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] &= ~(RADEON_TCL_VTX_ST1 | + RADEON_TCL_VTX_Q1); + break; + default: + break; + } + + + if (rmesa->TclFallback & (RADEON_TCL_FALLBACK_TEXGEN_0<<unit)) { + TCL_FALLBACK( ctx, (RADEON_TCL_FALLBACK_TEXGEN_0<<unit), GL_FALSE); + rmesa->recheck_texgen[unit] = GL_TRUE; + } + + + + { + GLuint inputshift = RADEON_TEXGEN_0_INPUT_SHIFT + unit*4; + GLuint tmp = rmesa->TexGenEnabled; + + rmesa->TexGenEnabled &= ~(RADEON_TEXGEN_TEXMAT_0_ENABLE<<unit); + rmesa->TexGenEnabled &= ~(RADEON_TEXMAT_0_ENABLE<<unit); + rmesa->TexGenEnabled &= ~(RADEON_TEXGEN_INPUT_MASK<<inputshift); + rmesa->TexGenNeedNormals[unit] = 0; + rmesa->TexGenEnabled |= + (RADEON_TEXGEN_INPUT_TEXCOORD_0+unit) << inputshift; + + if (tmp != rmesa->TexGenEnabled) { + rmesa->recheck_texgen[unit] = GL_TRUE; + rmesa->NewGLState |= _NEW_TEXTURE_MATRIX; + } + } + } +} + +static GLboolean enable_tex_2d( GLcontext *ctx, int unit ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + radeonTexObjPtr t = (radeonTexObjPtr) tObj->DriverData; + + /* Need to load the 2d images associated with this unit. + */ + if (t->pp_txformat & RADEON_TXFORMAT_NON_POWER2) { + t->pp_txformat &= ~RADEON_TXFORMAT_NON_POWER2; + t->base.dirty_images[0] = ~0; + } + + ASSERT(tObj->Target == GL_TEXTURE_2D || tObj->Target == GL_TEXTURE_1D); + + if ( t->base.dirty_images[0] ) { + RADEON_FIREVERTICES( rmesa ); + radeonSetTexImages( rmesa, tObj ); + radeonUploadTexImages( rmesa, (radeonTexObjPtr) tObj->DriverData, 0 ); + if ( !t->base.memBlock ) + return GL_FALSE; + } + + return GL_TRUE; +} + +static GLboolean enable_tex_rect( GLcontext *ctx, int unit ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + radeonTexObjPtr t = (radeonTexObjPtr) tObj->DriverData; + + if (!(t->pp_txformat & RADEON_TXFORMAT_NON_POWER2)) { + t->pp_txformat |= RADEON_TXFORMAT_NON_POWER2; + t->base.dirty_images[0] = ~0; + } + + ASSERT(tObj->Target == GL_TEXTURE_RECTANGLE_NV); + + if ( t->base.dirty_images[0] ) { + RADEON_FIREVERTICES( rmesa ); + radeonSetTexImages( rmesa, tObj ); + radeonUploadTexImages( rmesa, (radeonTexObjPtr) tObj->DriverData, 0 ); + if ( !t->base.memBlock /* && !rmesa->prefer_agp_client_texturing FIXME */ ) { + fprintf(stderr, "%s: upload failed\n", __FUNCTION__); + return GL_FALSE; + } + } + + return GL_TRUE; +} + + +static GLboolean update_tex_common( GLcontext *ctx, int unit ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + struct gl_texture_object *tObj = texUnit->_Current; + radeonTexObjPtr t = (radeonTexObjPtr) tObj->DriverData; + GLenum format; + + /* Fallback if there's a texture border */ + if ( tObj->Image[tObj->BaseLevel]->Border > 0 ) { + fprintf(stderr, "%s: border\n", __FUNCTION__); + return GL_FALSE; + } + + /* Update state if this is a different texture object to last + * time. + */ + if ( rmesa->state.texture.unit[unit].texobj != t ) { + if ( rmesa->state.texture.unit[unit].texobj != NULL ) { + /* The old texture is no longer bound to this texture unit. + * Mark it as such. + */ + + rmesa->state.texture.unit[unit].texobj->base.bound &= + ~(1UL << unit); + } + + rmesa->state.texture.unit[unit].texobj = t; + t->base.bound |= (1UL << unit); + t->dirty_state |= 1<<unit; + driUpdateTextureLRU( (driTextureObject *) t ); /* XXX: should be locked! */ + } + + + /* Newly enabled? + */ + if ( !(rmesa->hw.ctx.cmd[CTX_PP_CNTL] & (RADEON_TEX_0_ENABLE<<unit))) { + RADEON_STATECHANGE( rmesa, ctx ); + rmesa->hw.ctx.cmd[CTX_PP_CNTL] |= + (RADEON_TEX_0_ENABLE | RADEON_TEX_BLEND_0_ENABLE) << unit; + + RADEON_STATECHANGE( rmesa, tcl ); + + if (unit == 0) + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_ST0; + else + rmesa->hw.tcl.cmd[TCL_OUTPUT_VTXFMT] |= RADEON_TCL_VTX_ST1; + + rmesa->recheck_texgen[unit] = GL_TRUE; + } + + if (t->dirty_state & (1<<unit)) { + import_tex_obj_state( rmesa, unit, t ); + } + + if (rmesa->recheck_texgen[unit]) { + GLboolean fallback = !radeon_validate_texgen( ctx, unit ); + TCL_FALLBACK( ctx, (RADEON_TCL_FALLBACK_TEXGEN_0<<unit), fallback); + rmesa->recheck_texgen[unit] = 0; + rmesa->NewGLState |= _NEW_TEXTURE_MATRIX; + } + + format = tObj->Image[tObj->BaseLevel]->Format; + if ( rmesa->state.texture.unit[unit].format != format || + rmesa->state.texture.unit[unit].envMode != texUnit->EnvMode ) { + rmesa->state.texture.unit[unit].format = format; + rmesa->state.texture.unit[unit].envMode = texUnit->EnvMode; + if ( ! radeonUpdateTextureEnv( ctx, unit ) ) { + return GL_FALSE; + } + } + + FALLBACK( rmesa, RADEON_FALLBACK_BORDER_MODE, t->border_fallback ); + return !t->border_fallback; +} + + + +static GLboolean radeonUpdateTextureUnit( GLcontext *ctx, int unit ) +{ + struct gl_texture_unit *texUnit = &ctx->Texture.Unit[unit]; + + TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_TEXRECT_0 << unit, 0 ); + + if ( texUnit->_ReallyEnabled & (TEXTURE_RECT_BIT) ) { + TCL_FALLBACK( ctx, RADEON_TCL_FALLBACK_TEXRECT_0 << unit, 1 ); + + return (enable_tex_rect( ctx, unit ) && + update_tex_common( ctx, unit )); + } + else if ( texUnit->_ReallyEnabled & (TEXTURE_1D_BIT | TEXTURE_2D_BIT) ) { + return (enable_tex_2d( ctx, unit ) && + update_tex_common( ctx, unit )); + } + else if ( texUnit->_ReallyEnabled ) { + return GL_FALSE; + } + else { + disable_tex( ctx, unit ); + return GL_TRUE; + } +} + +void radeonUpdateTextureState( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLboolean ok; + + ok = (radeonUpdateTextureUnit( ctx, 0 ) && + radeonUpdateTextureUnit( ctx, 1 )); + + FALLBACK( rmesa, RADEON_FALLBACK_TEXTURE, !ok ); + + if (rmesa->TclFallback) + radeonChooseVertexState( ctx ); +} diff --git a/src/mesa/drivers/dri/radeon/radeon_vtxfmt.c b/src/mesa/drivers/dri/radeon/radeon_vtxfmt.c new file mode 100644 index 0000000000..b613e9eb43 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_vtxfmt.c @@ -0,0 +1,1089 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_vtxfmt.c,v 1.5 2002/12/16 16:18:59 dawes Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ +#include "glheader.h" +#include "imports.h" +#include "api_noop.h" +#include "api_arrayelt.h" +#include "context.h" +#include "mtypes.h" +#include "enums.h" +#include "glapi.h" +#include "colormac.h" +#include "light.h" +#include "state.h" +#include "vtxfmt.h" + +#include "tnl/tnl.h" +#include "tnl/t_context.h" +#include "tnl/t_array_api.h" + +#include "radeon_context.h" +#include "radeon_state.h" +#include "radeon_ioctl.h" +#include "radeon_tex.h" +#include "radeon_tcl.h" +#include "radeon_swtcl.h" +#include "radeon_vtxfmt.h" + +static void radeonVtxfmtFlushVertices( GLcontext *, GLuint ); + +static void count_func( const char *name, struct dynfn *l ) +{ + int i = 0; + struct dynfn *f; + foreach (f, l) i++; + if (i) fprintf(stderr, "%s: %d\n", name, i ); +} + +static void count_funcs( radeonContextPtr rmesa ) +{ + count_func( "Vertex2f", &rmesa->vb.dfn_cache.Vertex2f ); + count_func( "Vertex2fv", &rmesa->vb.dfn_cache.Vertex2fv ); + count_func( "Vertex3f", &rmesa->vb.dfn_cache.Vertex3f ); + count_func( "Vertex3fv", &rmesa->vb.dfn_cache.Vertex3fv ); + count_func( "Color4ub", &rmesa->vb.dfn_cache.Color4ub ); + count_func( "Color4ubv", &rmesa->vb.dfn_cache.Color4ubv ); + count_func( "Color3ub", &rmesa->vb.dfn_cache.Color3ub ); + count_func( "Color3ubv", &rmesa->vb.dfn_cache.Color3ubv ); + count_func( "Color4f", &rmesa->vb.dfn_cache.Color4f ); + count_func( "Color4fv", &rmesa->vb.dfn_cache.Color4fv ); + count_func( "Color3f", &rmesa->vb.dfn_cache.Color3f ); + count_func( "Color3fv", &rmesa->vb.dfn_cache.Color3fv ); + count_func( "SecondaryColor3f", &rmesa->vb.dfn_cache.SecondaryColor3fEXT ); + count_func( "SecondaryColor3fv", &rmesa->vb.dfn_cache.SecondaryColor3fvEXT ); + count_func( "SecondaryColor3ub", &rmesa->vb.dfn_cache.SecondaryColor3ubEXT ); + count_func( "SecondaryColor3ubv", &rmesa->vb.dfn_cache.SecondaryColor3ubvEXT ); + count_func( "Normal3f", &rmesa->vb.dfn_cache.Normal3f ); + count_func( "Normal3fv", &rmesa->vb.dfn_cache.Normal3fv ); + count_func( "TexCoord2f", &rmesa->vb.dfn_cache.TexCoord2f ); + count_func( "TexCoord2fv", &rmesa->vb.dfn_cache.TexCoord2fv ); + count_func( "TexCoord1f", &rmesa->vb.dfn_cache.TexCoord1f ); + count_func( "TexCoord1fv", &rmesa->vb.dfn_cache.TexCoord1fv ); + count_func( "MultiTexCoord2fARB", &rmesa->vb.dfn_cache.MultiTexCoord2fARB ); + count_func( "MultiTexCoord2fvARB", &rmesa->vb.dfn_cache.MultiTexCoord2fvARB ); + count_func( "MultiTexCoord1fARB", &rmesa->vb.dfn_cache.MultiTexCoord1fARB ); + count_func( "MultiTexCoord1fvARB", &rmesa->vb.dfn_cache.MultiTexCoord1fvARB ); +} + + +void radeon_copy_to_current( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + assert(ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT); + + if (rmesa->vb.vertex_format & RADEON_CP_VC_FRMT_N0) { + ctx->Current.Attrib[VERT_ATTRIB_NORMAL][0] = rmesa->vb.normalptr[0]; + ctx->Current.Attrib[VERT_ATTRIB_NORMAL][1] = rmesa->vb.normalptr[1]; + ctx->Current.Attrib[VERT_ATTRIB_NORMAL][2] = rmesa->vb.normalptr[2]; + } + + if (rmesa->vb.vertex_format & RADEON_CP_VC_FRMT_PKCOLOR) { + ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0] = UBYTE_TO_FLOAT( rmesa->vb.colorptr->red ); + ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1] = UBYTE_TO_FLOAT( rmesa->vb.colorptr->green ); + ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2] = UBYTE_TO_FLOAT( rmesa->vb.colorptr->blue ); + ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = UBYTE_TO_FLOAT( rmesa->vb.colorptr->alpha ); + } + + if (rmesa->vb.vertex_format & RADEON_CP_VC_FRMT_FPCOLOR) { + ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0] = rmesa->vb.floatcolorptr[0]; + ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1] = rmesa->vb.floatcolorptr[1]; + ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2] = rmesa->vb.floatcolorptr[2]; + } + + if (rmesa->vb.vertex_format & RADEON_CP_VC_FRMT_FPALPHA) + ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = rmesa->vb.floatcolorptr[3]; + + if (rmesa->vb.vertex_format & RADEON_CP_VC_FRMT_PKSPEC) { + ctx->Current.Attrib[VERT_ATTRIB_COLOR1][0] = UBYTE_TO_FLOAT( rmesa->vb.specptr->red ); + ctx->Current.Attrib[VERT_ATTRIB_COLOR1][1] = UBYTE_TO_FLOAT( rmesa->vb.specptr->green ); + ctx->Current.Attrib[VERT_ATTRIB_COLOR1][2] = UBYTE_TO_FLOAT( rmesa->vb.specptr->blue ); + } + + if (rmesa->vb.vertex_format & RADEON_CP_VC_FRMT_ST0) { + ctx->Current.Attrib[VERT_ATTRIB_TEX0][0] = rmesa->vb.texcoordptr[0][0]; + ctx->Current.Attrib[VERT_ATTRIB_TEX0][1] = rmesa->vb.texcoordptr[0][1]; + ctx->Current.Attrib[VERT_ATTRIB_TEX0][2] = 0.0F; + ctx->Current.Attrib[VERT_ATTRIB_TEX0][3] = 1.0F; + } + + if (rmesa->vb.vertex_format & RADEON_CP_VC_FRMT_ST1) { + ctx->Current.Attrib[VERT_ATTRIB_TEX1][0] = rmesa->vb.texcoordptr[1][0]; + ctx->Current.Attrib[VERT_ATTRIB_TEX1][1] = rmesa->vb.texcoordptr[1][1]; + ctx->Current.Attrib[VERT_ATTRIB_TEX1][2] = 0.0F; + ctx->Current.Attrib[VERT_ATTRIB_TEX1][3] = 1.0F; + } + + ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT; +} + +static GLboolean discreet_gl_prim[GL_POLYGON+1] = { + 1, /* 0 points */ + 1, /* 1 lines */ + 0, /* 2 line_strip */ + 0, /* 3 line_loop */ + 1, /* 4 tris */ + 0, /* 5 tri_fan */ + 0, /* 6 tri_strip */ + 1, /* 7 quads */ + 0, /* 8 quadstrip */ + 0, /* 9 poly */ +}; + +static void flush_prims( radeonContextPtr rmesa ) +{ + int i,j; + struct radeon_dma_region tmp = rmesa->dma.current; + + tmp.buf->refcount++; + tmp.aos_size = rmesa->vb.vertex_size; + tmp.aos_stride = rmesa->vb.vertex_size; + tmp.aos_start = GET_START(&tmp); + + rmesa->dma.current.ptr = rmesa->dma.current.start += + (rmesa->vb.initial_counter - rmesa->vb.counter) * rmesa->vb.vertex_size * 4; + + rmesa->tcl.vertex_format = rmesa->vb.vertex_format; + rmesa->tcl.aos_components[0] = &tmp; + rmesa->tcl.nr_aos_components = 1; + rmesa->dma.flush = 0; + + /* Optimize the primitive list: + */ + if (rmesa->vb.nrprims > 1) { + for (j = 0, i = 1 ; i < rmesa->vb.nrprims; i++) { + int pj = rmesa->vb.primlist[j].prim & 0xf; + int pi = rmesa->vb.primlist[i].prim & 0xf; + + if (pj == pi && discreet_gl_prim[pj] && + rmesa->vb.primlist[i].start == rmesa->vb.primlist[j].end) { + rmesa->vb.primlist[j].end = rmesa->vb.primlist[i].end; + } + else { + j++; + if (j != i) rmesa->vb.primlist[j] = rmesa->vb.primlist[i]; + } + } + rmesa->vb.nrprims = j+1; + } + + for (i = 0 ; i < rmesa->vb.nrprims; i++) { + if (RADEON_DEBUG & DEBUG_PRIMS) + fprintf(stderr, "vtxfmt prim %d: %s %d..%d\n", i, + _mesa_lookup_enum_by_nr( rmesa->vb.primlist[i].prim & + PRIM_MODE_MASK ), + rmesa->vb.primlist[i].start, + rmesa->vb.primlist[i].end); + + radeonEmitPrimitive( rmesa->glCtx, + rmesa->vb.primlist[i].start, + rmesa->vb.primlist[i].end, + rmesa->vb.primlist[i].prim ); + } + + rmesa->vb.nrprims = 0; + radeonReleaseDmaRegion( rmesa, &tmp, __FUNCTION__ ); +} + + +static void start_prim( radeonContextPtr rmesa, GLuint mode ) +{ + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "%s %d\n", __FUNCTION__, rmesa->vb.initial_counter - rmesa->vb.counter); + + rmesa->vb.primlist[rmesa->vb.nrprims].start = rmesa->vb.initial_counter - rmesa->vb.counter; + rmesa->vb.primlist[rmesa->vb.nrprims].prim = mode; +} + +static void note_last_prim( radeonContextPtr rmesa, GLuint flags ) +{ + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "%s %d\n", __FUNCTION__, rmesa->vb.initial_counter - rmesa->vb.counter); + + if (rmesa->vb.prim[0] != GL_POLYGON+1) { + rmesa->vb.primlist[rmesa->vb.nrprims].prim |= flags; + rmesa->vb.primlist[rmesa->vb.nrprims].end = rmesa->vb.initial_counter - rmesa->vb.counter; + + if (++(rmesa->vb.nrprims) == RADEON_MAX_PRIMS) + flush_prims( rmesa ); + } +} + + +static void copy_vertex( radeonContextPtr rmesa, GLuint n, GLfloat *dst ) +{ + GLuint i; + GLfloat *src = (GLfloat *)(rmesa->dma.current.address + + rmesa->dma.current.ptr + + (rmesa->vb.primlist[rmesa->vb.nrprims].start + n) * + rmesa->vb.vertex_size * 4); + + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "copy_vertex %d\n", rmesa->vb.primlist[rmesa->vb.nrprims].start + n); + + for (i = 0 ; i < rmesa->vb.vertex_size; i++) { + dst[i] = src[i]; + } +} + +/* NOTE: This actually reads the copied vertices back from uncached + * memory. Could also use the counter/notify mechanism to populate + * tmp on the fly as vertices are generated. + */ +static GLuint copy_dma_verts( radeonContextPtr rmesa, GLfloat (*tmp)[15] ) +{ + GLuint ovf, i; + GLuint nr = (rmesa->vb.initial_counter - rmesa->vb.counter) - rmesa->vb.primlist[rmesa->vb.nrprims].start; + + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "%s %d verts\n", __FUNCTION__, nr); + + switch( rmesa->vb.prim[0] ) + { + case GL_POINTS: + return 0; + case GL_LINES: + ovf = nr&1; + for (i = 0 ; i < ovf ; i++) + copy_vertex( rmesa, nr-ovf+i, tmp[i] ); + return i; + case GL_TRIANGLES: + ovf = nr%3; + for (i = 0 ; i < ovf ; i++) + copy_vertex( rmesa, nr-ovf+i, tmp[i] ); + return i; + case GL_QUADS: + ovf = nr&3; + for (i = 0 ; i < ovf ; i++) + copy_vertex( rmesa, nr-ovf+i, tmp[i] ); + return i; + case GL_LINE_STRIP: + if (nr == 0) + return 0; + copy_vertex( rmesa, nr-1, tmp[0] ); + return 1; + case GL_LINE_LOOP: + case GL_TRIANGLE_FAN: + case GL_POLYGON: + if (nr == 0) + return 0; + else if (nr == 1) { + copy_vertex( rmesa, 0, tmp[0] ); + return 1; + } else { + copy_vertex( rmesa, 0, tmp[0] ); + copy_vertex( rmesa, nr-1, tmp[1] ); + return 2; + } + case GL_TRIANGLE_STRIP: + ovf = MIN2(nr, 2); + for (i = 0 ; i < ovf ; i++) + copy_vertex( rmesa, nr-ovf+i, tmp[i] ); + return i; + case GL_QUAD_STRIP: + switch (nr) { + case 0: ovf = 0; break; + case 1: ovf = 1; break; + default: ovf = 2 + (nr&1); break; + } + for (i = 0 ; i < ovf ; i++) + copy_vertex( rmesa, nr-ovf+i, tmp[i] ); + return i; + default: + assert(0); + return 0; + } +} + +static void VFMT_FALLBACK_OUTSIDE_BEGIN_END( const char *caller ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if (RADEON_DEBUG & (DEBUG_VFMT|DEBUG_FALLBACKS)) + fprintf(stderr, "%s from %s\n", __FUNCTION__, caller); + + if (ctx->Driver.NeedFlush) + radeonVtxfmtFlushVertices( ctx, ctx->Driver.NeedFlush ); + + if (ctx->NewState) + _mesa_update_state( ctx ); /* clear state so fell_back sticks */ + + _tnl_wakeup_exec( ctx ); + ctx->Driver.FlushVertices = radeonFlushVertices; + + assert( rmesa->dma.flush == 0 ); + rmesa->vb.fell_back = GL_TRUE; + rmesa->vb.installed = GL_FALSE; +} + + +static void VFMT_FALLBACK( const char *caller ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat tmp[3][15]; + GLuint i, prim; + GLuint ind = rmesa->vb.vertex_format; + GLuint nrverts; + GLfloat alpha = 1.0; + + if (RADEON_DEBUG & (DEBUG_FALLBACKS|DEBUG_VFMT)) + fprintf(stderr, "%s from %s\n", __FUNCTION__, caller); + + if (rmesa->vb.prim[0] == GL_POLYGON+1) { + VFMT_FALLBACK_OUTSIDE_BEGIN_END( __FUNCTION__ ); + return; + } + + /* Copy vertices out of dma: + */ + nrverts = copy_dma_verts( rmesa, tmp ); + + /* Finish the prim at this point: + */ + note_last_prim( rmesa, 0 ); + flush_prims( rmesa ); + + /* Update ctx->Driver.CurrentExecPrimitive and swap in swtnl. + */ + prim = rmesa->vb.prim[0]; + ctx->Driver.CurrentExecPrimitive = GL_POLYGON+1; + _tnl_wakeup_exec( ctx ); + ctx->Driver.FlushVertices = radeonFlushVertices; + + assert(rmesa->dma.flush == 0); + rmesa->vb.fell_back = GL_TRUE; + rmesa->vb.installed = GL_FALSE; + glBegin( prim ); + + if (rmesa->vb.installed_color_3f_sz == 4) + alpha = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3]; + + /* Replay saved vertices + */ + for (i = 0 ; i < nrverts; i++) { + GLuint offset = 3; + if (ind & RADEON_CP_VC_FRMT_N0) { + glNormal3fv( &tmp[i][offset] ); + offset += 3; + } + + if (ind & RADEON_CP_VC_FRMT_PKCOLOR) { + radeon_color_t *col = (radeon_color_t *)&tmp[i][offset]; + glColor4ub( col->red, col->green, col->blue, col->alpha ); + offset++; + } + else if (ind & RADEON_CP_VC_FRMT_FPALPHA) { + glColor4fv( &tmp[i][offset] ); + offset+=4; + } + else if (ind & RADEON_CP_VC_FRMT_FPCOLOR) { + glColor3fv( &tmp[i][offset] ); + offset+=3; + } + + if (ind & RADEON_CP_VC_FRMT_PKSPEC) { + radeon_color_t *spec = (radeon_color_t *)&tmp[i][offset]; + _glapi_Dispatch->SecondaryColor3ubEXT( spec->red, spec->green, spec->blue ); + offset++; + } + + if (ind & RADEON_CP_VC_FRMT_ST0) { + glTexCoord2fv( &tmp[i][offset] ); + offset += 2; + } + + if (ind & RADEON_CP_VC_FRMT_ST1) { + glMultiTexCoord2fvARB( GL_TEXTURE1_ARB, &tmp[i][offset] ); + offset += 2; + } + glVertex3fv( &tmp[i][0] ); + } + + /* Replay current vertex + */ + if (ind & RADEON_CP_VC_FRMT_N0) + glNormal3fv( rmesa->vb.normalptr ); + + if (ind & RADEON_CP_VC_FRMT_PKCOLOR) + glColor4ub( rmesa->vb.colorptr->red, rmesa->vb.colorptr->green, rmesa->vb.colorptr->blue, rmesa->vb.colorptr->alpha ); + else if (ind & RADEON_CP_VC_FRMT_FPALPHA) + glColor4fv( rmesa->vb.floatcolorptr ); + else if (ind & RADEON_CP_VC_FRMT_FPCOLOR) { + if (rmesa->vb.installed_color_3f_sz == 4 && alpha != 1.0) + glColor4f( rmesa->vb.floatcolorptr[0], + rmesa->vb.floatcolorptr[1], + rmesa->vb.floatcolorptr[2], + alpha ); + else + glColor3fv( rmesa->vb.floatcolorptr ); + } + + if (ind & RADEON_CP_VC_FRMT_PKSPEC) + _glapi_Dispatch->SecondaryColor3ubEXT( rmesa->vb.specptr->red, rmesa->vb.specptr->green, rmesa->vb.specptr->blue ); + + if (ind & RADEON_CP_VC_FRMT_ST0) + glTexCoord2fv( rmesa->vb.texcoordptr[0] ); + + if (ind & RADEON_CP_VC_FRMT_ST1) + glMultiTexCoord2fvARB( GL_TEXTURE1_ARB, rmesa->vb.texcoordptr[1] ); +} + + + +static void wrap_buffer( void ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat tmp[3][15]; + GLuint i, nrverts; + + if (RADEON_DEBUG & (DEBUG_VFMT|DEBUG_PRIMS)) + fprintf(stderr, "%s %d\n", __FUNCTION__, rmesa->vb.initial_counter - rmesa->vb.counter); + + /* Don't deal with parity. + */ + if ((((rmesa->vb.initial_counter - rmesa->vb.counter) - + rmesa->vb.primlist[rmesa->vb.nrprims].start) & 1)) { + rmesa->vb.counter++; + rmesa->vb.initial_counter++; + return; + } + + /* Copy vertices out of dma: + */ + if (rmesa->vb.prim[0] == GL_POLYGON+1) + nrverts = 0; + else { + nrverts = copy_dma_verts( rmesa, tmp ); + + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "%d vertices to copy\n", nrverts); + + /* Finish the prim at this point: + */ + note_last_prim( rmesa, 0 ); + } + + /* Fire any buffered primitives + */ + flush_prims( rmesa ); + + /* Get new buffer + */ + radeonRefillCurrentDmaRegion( rmesa ); + + /* Reset counter, dmaptr + */ + rmesa->vb.dmaptr = (int *)(rmesa->dma.current.ptr + rmesa->dma.current.address); + rmesa->vb.counter = (rmesa->dma.current.end - rmesa->dma.current.ptr) / + (rmesa->vb.vertex_size * 4); + rmesa->vb.counter--; + rmesa->vb.initial_counter = rmesa->vb.counter; + rmesa->vb.notify = wrap_buffer; + + rmesa->dma.flush = flush_prims; + + /* Restart wrapped primitive: + */ + if (rmesa->vb.prim[0] != GL_POLYGON+1) + start_prim( rmesa, rmesa->vb.prim[0] ); + + /* Reemit saved vertices + */ + for (i = 0 ; i < nrverts; i++) { + if (RADEON_DEBUG & DEBUG_VERTS) { + int j; + fprintf(stderr, "re-emit vertex %d to %p\n", i, rmesa->vb.dmaptr); + if (RADEON_DEBUG & DEBUG_VERBOSE) + for (j = 0 ; j < rmesa->vb.vertex_size; j++) + fprintf(stderr, "\t%08x/%f\n", *(int*)&tmp[i][j], tmp[i][j]); + } + + memcpy( rmesa->vb.dmaptr, tmp[i], rmesa->vb.vertex_size * 4 ); + rmesa->vb.dmaptr += rmesa->vb.vertex_size; + rmesa->vb.counter--; + } +} + + + +static GLboolean check_vtx_fmt( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLuint ind = RADEON_CP_VC_FRMT_Z; + + if (rmesa->TclFallback || rmesa->vb.fell_back || ctx->CompileFlag) + return GL_FALSE; + + if (ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) + ctx->Driver.FlushVertices( ctx, FLUSH_UPDATE_CURRENT ); + + /* Make all this event-driven: + */ + if (ctx->Light.Enabled) { + ind |= RADEON_CP_VC_FRMT_N0; + + /* TODO: make this data driven: If we receive only ubytes, send + * color as ubytes. Also check if converting (with free + * checking for overflow) is cheaper than sending floats + * directly. + */ + if (ctx->Light.ColorMaterialEnabled) { + ind |= (RADEON_CP_VC_FRMT_FPCOLOR | + RADEON_CP_VC_FRMT_FPALPHA); + } + else + ind |= RADEON_CP_VC_FRMT_PKCOLOR; /* for alpha? */ + } + else { + /* TODO: make this data driven? + */ + ind |= RADEON_CP_VC_FRMT_PKCOLOR; + + if (ctx->_TriangleCaps & DD_SEPARATE_SPECULAR) { + ind |= RADEON_CP_VC_FRMT_PKSPEC; + } + } + + if (ctx->Texture.Unit[0]._ReallyEnabled) { + if (ctx->Texture.Unit[0].TexGenEnabled) { + if (rmesa->TexGenNeedNormals[0]) { + ind |= RADEON_CP_VC_FRMT_N0; + } + } else { + if (ctx->Current.Attrib[VERT_ATTRIB_TEX0][2] != 0.0F || + ctx->Current.Attrib[VERT_ATTRIB_TEX0][3] != 1.0) { + if (RADEON_DEBUG & (DEBUG_VFMT|DEBUG_FALLBACKS)) + fprintf(stderr, "%s: rq0\n", __FUNCTION__); + return GL_FALSE; + } + ind |= RADEON_CP_VC_FRMT_ST0; + } + } + + if (ctx->Texture.Unit[1]._ReallyEnabled) { + if (ctx->Texture.Unit[1].TexGenEnabled) { + if (rmesa->TexGenNeedNormals[1]) { + ind |= RADEON_CP_VC_FRMT_N0; + } + } else { + if (ctx->Current.Attrib[VERT_ATTRIB_TEX1][2] != 0.0F || + ctx->Current.Attrib[VERT_ATTRIB_TEX1][3] != 1.0) { + if (RADEON_DEBUG & (DEBUG_VFMT|DEBUG_FALLBACKS)) + fprintf(stderr, "%s: rq1\n", __FUNCTION__); + return GL_FALSE; + } + ind |= RADEON_CP_VC_FRMT_ST1; + } + } + + if (RADEON_DEBUG & (DEBUG_VFMT|DEBUG_STATE)) + fprintf(stderr, "%s: format: 0x%x\n", __FUNCTION__, ind ); + + RADEON_NEWPRIM(rmesa); + rmesa->vb.vertex_format = ind; + rmesa->vb.vertex_size = 3; + rmesa->vb.prim = &ctx->Driver.CurrentExecPrimitive; + + rmesa->vb.normalptr = ctx->Current.Attrib[VERT_ATTRIB_NORMAL]; + rmesa->vb.colorptr = NULL; + rmesa->vb.floatcolorptr = ctx->Current.Attrib[VERT_ATTRIB_COLOR0]; + rmesa->vb.specptr = NULL; + rmesa->vb.floatspecptr = ctx->Current.Attrib[VERT_ATTRIB_COLOR1]; + rmesa->vb.texcoordptr[0] = ctx->Current.Attrib[VERT_ATTRIB_TEX0]; + rmesa->vb.texcoordptr[1] = ctx->Current.Attrib[VERT_ATTRIB_TEX1]; + + /* Run through and initialize the vertex components in the order + * the hardware understands: + */ + if (ind & RADEON_CP_VC_FRMT_N0) { + rmesa->vb.normalptr = &rmesa->vb.vertex[rmesa->vb.vertex_size].f; + rmesa->vb.vertex_size += 3; + rmesa->vb.normalptr[0] = ctx->Current.Attrib[VERT_ATTRIB_NORMAL][0]; + rmesa->vb.normalptr[1] = ctx->Current.Attrib[VERT_ATTRIB_NORMAL][1]; + rmesa->vb.normalptr[2] = ctx->Current.Attrib[VERT_ATTRIB_NORMAL][2]; + } + + if (ind & RADEON_CP_VC_FRMT_PKCOLOR) { + rmesa->vb.colorptr = &rmesa->vb.vertex[rmesa->vb.vertex_size].color; + rmesa->vb.vertex_size += 1; + UNCLAMPED_FLOAT_TO_CHAN( rmesa->vb.colorptr->red, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0] ); + UNCLAMPED_FLOAT_TO_CHAN( rmesa->vb.colorptr->green, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1] ); + UNCLAMPED_FLOAT_TO_CHAN( rmesa->vb.colorptr->blue, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2] ); + UNCLAMPED_FLOAT_TO_CHAN( rmesa->vb.colorptr->alpha, ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] ); + } + + if (ind & RADEON_CP_VC_FRMT_FPCOLOR) { + assert(!(ind & RADEON_CP_VC_FRMT_PKCOLOR)); + rmesa->vb.floatcolorptr = &rmesa->vb.vertex[rmesa->vb.vertex_size].f; + rmesa->vb.vertex_size += 3; + rmesa->vb.floatcolorptr[0] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][0]; + rmesa->vb.floatcolorptr[1] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][1]; + rmesa->vb.floatcolorptr[2] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][2]; + + if (ind & RADEON_CP_VC_FRMT_FPALPHA) { + rmesa->vb.vertex_size += 1; + rmesa->vb.floatcolorptr[3] = ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3]; + } + } + + if (ind & RADEON_CP_VC_FRMT_PKSPEC) { + rmesa->vb.specptr = &rmesa->vb.vertex[rmesa->vb.vertex_size].color; + rmesa->vb.vertex_size += 1; + UNCLAMPED_FLOAT_TO_CHAN( rmesa->vb.specptr->red, ctx->Current.Attrib[VERT_ATTRIB_COLOR1][0] ); + UNCLAMPED_FLOAT_TO_CHAN( rmesa->vb.specptr->green, ctx->Current.Attrib[VERT_ATTRIB_COLOR1][1] ); + UNCLAMPED_FLOAT_TO_CHAN( rmesa->vb.specptr->blue, ctx->Current.Attrib[VERT_ATTRIB_COLOR1][2] ); + } + + if (ind & RADEON_CP_VC_FRMT_ST0) { + rmesa->vb.texcoordptr[0] = &rmesa->vb.vertex[rmesa->vb.vertex_size].f; + rmesa->vb.vertex_size += 2; + rmesa->vb.texcoordptr[0][0] = ctx->Current.Attrib[VERT_ATTRIB_TEX0][0]; + rmesa->vb.texcoordptr[0][1] = ctx->Current.Attrib[VERT_ATTRIB_TEX0][1]; + } + + if (ind & RADEON_CP_VC_FRMT_ST1) { + rmesa->vb.texcoordptr[1] = &rmesa->vb.vertex[rmesa->vb.vertex_size].f; + rmesa->vb.vertex_size += 2; + rmesa->vb.texcoordptr[1][0] = ctx->Current.Attrib[VERT_ATTRIB_TEX1][0]; + rmesa->vb.texcoordptr[1][1] = ctx->Current.Attrib[VERT_ATTRIB_TEX1][1]; + } + + if (rmesa->vb.installed_vertex_format != rmesa->vb.vertex_format) { + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "reinstall on vertex_format change\n"); + _mesa_install_exec_vtxfmt( ctx, &rmesa->vb.vtxfmt ); + rmesa->vb.installed_vertex_format = rmesa->vb.vertex_format; + } + + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "%s -- success\n", __FUNCTION__); + + return GL_TRUE; +} + +void radeonVtxfmtInvalidate( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + + rmesa->vb.recheck = GL_TRUE; + rmesa->vb.fell_back = GL_FALSE; +} + + +static void radeonNewList( GLcontext *ctx, GLuint list, GLenum mode ) +{ + VFMT_FALLBACK_OUTSIDE_BEGIN_END( __FUNCTION__ ); +} + + +static void radeonVtxfmtValidate( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "%s\n", __FUNCTION__); + + if (ctx->Driver.NeedFlush) + ctx->Driver.FlushVertices( ctx, ctx->Driver.NeedFlush ); + + rmesa->vb.recheck = GL_FALSE; + + if (check_vtx_fmt( ctx )) { + if (!rmesa->vb.installed) { + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "reinstall (new install)\n"); + + _mesa_install_exec_vtxfmt( ctx, &rmesa->vb.vtxfmt ); + ctx->Driver.FlushVertices = radeonVtxfmtFlushVertices; + ctx->Driver.NewList = radeonNewList; + rmesa->vb.installed = GL_TRUE; + } + else if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "%s: already installed", __FUNCTION__); + } + else { + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "%s: failed\n", __FUNCTION__); + + if (rmesa->vb.installed) { + if (rmesa->dma.flush) + rmesa->dma.flush( rmesa ); + _tnl_wakeup_exec( ctx ); + ctx->Driver.FlushVertices = radeonFlushVertices; + rmesa->vb.installed = GL_FALSE; + } + } +} + + + +/* Materials: + */ +static void radeon_Materialfv( GLenum face, GLenum pname, + const GLfloat *params ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "%s\n", __FUNCTION__); + + if (rmesa->vb.prim[0] != GL_POLYGON+1) { + VFMT_FALLBACK( __FUNCTION__ ); + glMaterialfv( face, pname, params ); + return; + } + _mesa_noop_Materialfv( face, pname, params ); + radeonUpdateMaterial( ctx ); +} + + +/* Begin/End + */ +static void radeon_Begin( GLenum mode ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "%s( %s )\n", __FUNCTION__, + _mesa_lookup_enum_by_nr( mode )); + + if (mode > GL_POLYGON) { + _mesa_error( ctx, GL_INVALID_ENUM, "glBegin" ); + return; + } + + if (rmesa->vb.prim[0] != GL_POLYGON+1) { + _mesa_error( ctx, GL_INVALID_OPERATION, "glBegin" ); + return; + } + + if (ctx->NewState) + _mesa_update_state( ctx ); + + if (rmesa->NewGLState) + radeonValidateState( ctx ); + + if (rmesa->vb.recheck) + radeonVtxfmtValidate( ctx ); + + if (!rmesa->vb.installed) { + glBegin( mode ); + return; + } + + + if (rmesa->dma.flush && rmesa->vb.counter < 12) { + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "%s: flush almost-empty buffers\n", __FUNCTION__); + flush_prims( rmesa ); + } + + /* Need to arrange to save vertices here? Or always copy from dma (yuk)? + */ + if (!rmesa->dma.flush) { + if (rmesa->dma.current.ptr + 12*rmesa->vb.vertex_size*4 > + rmesa->dma.current.end) { + RADEON_NEWPRIM( rmesa ); + radeonRefillCurrentDmaRegion( rmesa ); + } + + rmesa->vb.dmaptr = (int *)(rmesa->dma.current.address + rmesa->dma.current.ptr); + rmesa->vb.counter = (rmesa->dma.current.end - rmesa->dma.current.ptr) / + (rmesa->vb.vertex_size * 4); + rmesa->vb.counter--; + rmesa->vb.initial_counter = rmesa->vb.counter; + rmesa->vb.notify = wrap_buffer; + rmesa->dma.flush = flush_prims; + ctx->Driver.NeedFlush |= FLUSH_STORED_VERTICES; + } + + + rmesa->vb.prim[0] = mode; + start_prim( rmesa, mode | PRIM_BEGIN ); +} + + + +static void radeon_End( void ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "%s\n", __FUNCTION__); + + if (rmesa->vb.prim[0] == GL_POLYGON+1) { + _mesa_error( ctx, GL_INVALID_OPERATION, "glEnd" ); + return; + } + + note_last_prim( rmesa, PRIM_END ); + rmesa->vb.prim[0] = GL_POLYGON+1; +} + + +/* Fallback on difficult entrypoints: + */ +#define PRE_LOOPBACK( FUNC ) \ +do { \ + if (RADEON_DEBUG & DEBUG_VFMT) \ + fprintf(stderr, "%s\n", __FUNCTION__); \ + VFMT_FALLBACK( __FUNCTION__ ); \ +} while (0) +#define TAG(x) radeon_fallback_##x +#include "vtxfmt_tmp.h" + + + +static GLboolean radeonNotifyBegin( GLcontext *ctx, GLenum p ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "%s\n", __FUNCTION__); + + assert(!rmesa->vb.installed); + + if (ctx->NewState) + _mesa_update_state( ctx ); + + if (rmesa->NewGLState) + radeonValidateState( ctx ); + + if (ctx->Driver.NeedFlush) + ctx->Driver.FlushVertices( ctx, ctx->Driver.NeedFlush ); + + if (rmesa->vb.recheck) + radeonVtxfmtValidate( ctx ); + + if (!rmesa->vb.installed) { + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "%s -- failed\n", __FUNCTION__); + return GL_FALSE; + } + + radeon_Begin( p ); + return GL_TRUE; +} + +static void radeonVtxfmtFlushVertices( GLcontext *ctx, GLuint flags ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "%s\n", __FUNCTION__); + + assert(rmesa->vb.installed); + + if (flags & FLUSH_UPDATE_CURRENT) { + radeon_copy_to_current( ctx ); + if (RADEON_DEBUG & DEBUG_VFMT) + fprintf(stderr, "reinstall on update_current\n"); + _mesa_install_exec_vtxfmt( ctx, &rmesa->vb.vtxfmt ); + ctx->Driver.NeedFlush &= ~FLUSH_UPDATE_CURRENT; + } + + if (flags & FLUSH_STORED_VERTICES) { + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + assert (rmesa->dma.flush == 0 || + rmesa->dma.flush == flush_prims); + if (rmesa->dma.flush == flush_prims) + flush_prims( RADEON_CONTEXT( ctx ) ); + ctx->Driver.NeedFlush &= ~FLUSH_STORED_VERTICES; + } +} + + + +/* At this point, don't expect very many versions of each function to + * be generated, so not concerned about freeing them? + */ + + +void radeonVtxfmtInit( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + GLvertexformat *vfmt = &(rmesa->vb.vtxfmt); + + MEMSET( vfmt, 0, sizeof(GLvertexformat) ); + + /* Hook in chooser functions for codegen, etc: + */ + radeonVtxfmtInitChoosers( vfmt ); + + /* Handled fully in supported states, but no codegen: + */ + vfmt->Materialfv = radeon_Materialfv; + vfmt->ArrayElement = _ae_loopback_array_elt; /* generic helper */ + vfmt->Rectf = _mesa_noop_Rectf; /* generic helper */ + vfmt->Begin = radeon_Begin; + vfmt->End = radeon_End; + + /* Fallback for performance reasons: (Fix with cva/elt path here and + * dmatmp2.h style primitive-merging) + * + * These should call NotifyBegin(), as should _tnl_EvalMesh, to allow + * a driver-hook. + */ + vfmt->DrawArrays = radeon_fallback_DrawArrays; + vfmt->DrawElements = radeon_fallback_DrawElements; + vfmt->DrawRangeElements = radeon_fallback_DrawRangeElements; + + + /* Not active in supported states; just keep ctx->Current uptodate: + */ + vfmt->FogCoordfvEXT = _mesa_noop_FogCoordfvEXT; + vfmt->FogCoordfEXT = _mesa_noop_FogCoordfEXT; + vfmt->EdgeFlag = _mesa_noop_EdgeFlag; + vfmt->EdgeFlagv = _mesa_noop_EdgeFlagv; + vfmt->Indexi = _mesa_noop_Indexi; + vfmt->Indexiv = _mesa_noop_Indexiv; + + + /* Active but unsupported -- fallback if we receive these: + */ + vfmt->CallList = radeon_fallback_CallList; + vfmt->EvalCoord1f = radeon_fallback_EvalCoord1f; + vfmt->EvalCoord1fv = radeon_fallback_EvalCoord1fv; + vfmt->EvalCoord2f = radeon_fallback_EvalCoord2f; + vfmt->EvalCoord2fv = radeon_fallback_EvalCoord2fv; + vfmt->EvalMesh1 = radeon_fallback_EvalMesh1; + vfmt->EvalMesh2 = radeon_fallback_EvalMesh2; + vfmt->EvalPoint1 = radeon_fallback_EvalPoint1; + vfmt->EvalPoint2 = radeon_fallback_EvalPoint2; + vfmt->TexCoord3f = radeon_fallback_TexCoord3f; + vfmt->TexCoord3fv = radeon_fallback_TexCoord3fv; + vfmt->TexCoord4f = radeon_fallback_TexCoord4f; + vfmt->TexCoord4fv = radeon_fallback_TexCoord4fv; + vfmt->MultiTexCoord3fARB = radeon_fallback_MultiTexCoord3fARB; + vfmt->MultiTexCoord3fvARB = radeon_fallback_MultiTexCoord3fvARB; + vfmt->MultiTexCoord4fARB = radeon_fallback_MultiTexCoord4fARB; + vfmt->MultiTexCoord4fvARB = radeon_fallback_MultiTexCoord4fvARB; + vfmt->Vertex4f = radeon_fallback_Vertex4f; + vfmt->Vertex4fv = radeon_fallback_Vertex4fv; + + (void)radeon_fallback_vtxfmt; + + TNL_CONTEXT(ctx)->Driver.NotifyBegin = radeonNotifyBegin; + + rmesa->vb.enabled = 1; + rmesa->vb.prim = &ctx->Driver.CurrentExecPrimitive; + rmesa->vb.primflags = 0; + + make_empty_list( &rmesa->vb.dfn_cache.Vertex2f ); + make_empty_list( &rmesa->vb.dfn_cache.Vertex2fv ); + make_empty_list( &rmesa->vb.dfn_cache.Vertex3f ); + make_empty_list( &rmesa->vb.dfn_cache.Vertex3fv ); + make_empty_list( &rmesa->vb.dfn_cache.Color4ub ); + make_empty_list( &rmesa->vb.dfn_cache.Color4ubv ); + make_empty_list( &rmesa->vb.dfn_cache.Color3ub ); + make_empty_list( &rmesa->vb.dfn_cache.Color3ubv ); + make_empty_list( &rmesa->vb.dfn_cache.Color4f ); + make_empty_list( &rmesa->vb.dfn_cache.Color4fv ); + make_empty_list( &rmesa->vb.dfn_cache.Color3f ); + make_empty_list( &rmesa->vb.dfn_cache.Color3fv ); + make_empty_list( &rmesa->vb.dfn_cache.SecondaryColor3fEXT ); + make_empty_list( &rmesa->vb.dfn_cache.SecondaryColor3fvEXT ); + make_empty_list( &rmesa->vb.dfn_cache.SecondaryColor3ubEXT ); + make_empty_list( &rmesa->vb.dfn_cache.SecondaryColor3ubvEXT ); + make_empty_list( &rmesa->vb.dfn_cache.Normal3f ); + make_empty_list( &rmesa->vb.dfn_cache.Normal3fv ); + make_empty_list( &rmesa->vb.dfn_cache.TexCoord2f ); + make_empty_list( &rmesa->vb.dfn_cache.TexCoord2fv ); + make_empty_list( &rmesa->vb.dfn_cache.TexCoord1f ); + make_empty_list( &rmesa->vb.dfn_cache.TexCoord1fv ); + make_empty_list( &rmesa->vb.dfn_cache.MultiTexCoord2fARB ); + make_empty_list( &rmesa->vb.dfn_cache.MultiTexCoord2fvARB ); + make_empty_list( &rmesa->vb.dfn_cache.MultiTexCoord1fARB ); + make_empty_list( &rmesa->vb.dfn_cache.MultiTexCoord1fvARB ); + + radeonInitCodegen( &rmesa->vb.codegen ); +} + +static void free_funcs( struct dynfn *l ) +{ + struct dynfn *f, *tmp; + foreach_s (f, tmp, l) { + remove_from_list( f ); + ALIGN_FREE( f->code ); + FREE( f ); + } +} + + + +void radeonVtxfmtMakeCurrent( GLcontext *ctx ) +{ +} + + +void radeonVtxfmtDestroy( GLcontext *ctx ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT( ctx ); + + count_funcs( rmesa ); + free_funcs( &rmesa->vb.dfn_cache.Vertex2f ); + free_funcs( &rmesa->vb.dfn_cache.Vertex2fv ); + free_funcs( &rmesa->vb.dfn_cache.Vertex3f ); + free_funcs( &rmesa->vb.dfn_cache.Vertex3fv ); + free_funcs( &rmesa->vb.dfn_cache.Color4ub ); + free_funcs( &rmesa->vb.dfn_cache.Color4ubv ); + free_funcs( &rmesa->vb.dfn_cache.Color3ub ); + free_funcs( &rmesa->vb.dfn_cache.Color3ubv ); + free_funcs( &rmesa->vb.dfn_cache.Color4f ); + free_funcs( &rmesa->vb.dfn_cache.Color4fv ); + free_funcs( &rmesa->vb.dfn_cache.Color3f ); + free_funcs( &rmesa->vb.dfn_cache.Color3fv ); + free_funcs( &rmesa->vb.dfn_cache.SecondaryColor3ubEXT ); + free_funcs( &rmesa->vb.dfn_cache.SecondaryColor3ubvEXT ); + free_funcs( &rmesa->vb.dfn_cache.SecondaryColor3fEXT ); + free_funcs( &rmesa->vb.dfn_cache.SecondaryColor3fvEXT ); + free_funcs( &rmesa->vb.dfn_cache.Normal3f ); + free_funcs( &rmesa->vb.dfn_cache.Normal3fv ); + free_funcs( &rmesa->vb.dfn_cache.TexCoord2f ); + free_funcs( &rmesa->vb.dfn_cache.TexCoord2fv ); + free_funcs( &rmesa->vb.dfn_cache.TexCoord1f ); + free_funcs( &rmesa->vb.dfn_cache.TexCoord1fv ); + free_funcs( &rmesa->vb.dfn_cache.MultiTexCoord2fARB ); + free_funcs( &rmesa->vb.dfn_cache.MultiTexCoord2fvARB ); + free_funcs( &rmesa->vb.dfn_cache.MultiTexCoord1fARB ); + free_funcs( &rmesa->vb.dfn_cache.MultiTexCoord1fvARB ); +} + diff --git a/src/mesa/drivers/dri/radeon/radeon_vtxfmt.h b/src/mesa/drivers/dri/radeon/radeon_vtxfmt.h new file mode 100644 index 0000000000..9792fcbb78 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_vtxfmt.h @@ -0,0 +1,124 @@ +/* $XFree86: xc/lib/GL/mesa/src/drv/radeon/radeon_vtxfmt.h,v 1.3 2002/12/21 17:02:16 dawes Exp $ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#ifndef __RADEON_VTXFMT_H__ +#define __RADEON_VTXFMT_H__ + +#ifdef GLX_DIRECT_RENDERING + +#include "radeon_context.h" + + +extern void radeonVtxfmtUpdate( GLcontext *ctx ); +extern void radeonVtxfmtInit( GLcontext *ctx ); +extern void radeonVtxfmtInvalidate( GLcontext *ctx ); +extern void radeonVtxfmtDestroy( GLcontext *ctx ); +extern void radeonVtxfmtInitChoosers( GLvertexformat *vfmt ); + +extern void radeonVtxfmtMakeCurrent( GLcontext *ctx ); +extern void radeonVtxfmtUnbindContext( GLcontext *ctx ); + +extern void radeon_copy_to_current( GLcontext *ctx ); + +#define DFN( FUNC, CACHE) \ +do { \ + char *start = (char *)&FUNC; \ + char *end = (char *)&FUNC##_end; \ + insert_at_head( &CACHE, dfn ); \ + dfn->key = key; \ + dfn->code = ALIGN_MALLOC( end - start, 16 ); \ + memcpy (dfn->code, start, end - start); \ +} \ +while ( 0 ) + +#define FIXUP( CODE, OFFSET, CHECKVAL, NEWVAL ) \ +do { \ + int *icode = (int *)(CODE+OFFSET); \ + assert (*icode == CHECKVAL); \ + *icode = (int)NEWVAL; \ +} while (0) + + +/* Useful for figuring out the offsets: + */ +#define FIXUP2( CODE, OFFSET, CHECKVAL, NEWVAL ) \ +do { \ + while (*(int *)(CODE+OFFSET) != CHECKVAL) OFFSET++; \ + fprintf(stderr, "%s/%d CVAL %x OFFSET %d VAL %x\n", __FUNCTION__, \ + __LINE__, CHECKVAL, OFFSET, (int)(NEWVAL)); \ + *(int *)(CODE+OFFSET) = (int)(NEWVAL); \ + OFFSET += 4; \ +} while (0) + +/* + */ +void radeonInitCodegen( struct dfn_generators *gen ); +void radeonInitX86Codegen( struct dfn_generators *gen ); +void radeonInitSSECodegen( struct dfn_generators *gen ); + + + +/* Defined in radeon_vtxfmt_x86.c + */ +struct dynfn *radeon_makeX86Vertex2f( GLcontext *, int ); +struct dynfn *radeon_makeX86Vertex2fv( GLcontext *, int ); +struct dynfn *radeon_makeX86Vertex3f( GLcontext *, int ); +struct dynfn *radeon_makeX86Vertex3fv( GLcontext *, int ); +struct dynfn *radeon_makeX86Color4ub( GLcontext *, int ); +struct dynfn *radeon_makeX86Color4ubv( GLcontext *, int ); +struct dynfn *radeon_makeX86Color3ub( GLcontext *, int ); +struct dynfn *radeon_makeX86Color3ubv( GLcontext *, int ); +struct dynfn *radeon_makeX86Color4f( GLcontext *, int ); +struct dynfn *radeon_makeX86Color4fv( GLcontext *, int ); +struct dynfn *radeon_makeX86Color3f( GLcontext *, int ); +struct dynfn *radeon_makeX86Color3fv( GLcontext *, int ); +struct dynfn *radeon_makeX86SecondaryColor3ubEXT( GLcontext *, int ); +struct dynfn *radeon_makeX86SecondaryColor3ubvEXT( GLcontext *, int ); +struct dynfn *radeon_makeX86SecondaryColor3fEXT( GLcontext *, int ); +struct dynfn *radeon_makeX86SecondaryColor3fvEXT( GLcontext *, int ); +struct dynfn *radeon_makeX86Normal3f( GLcontext *, int ); +struct dynfn *radeon_makeX86Normal3fv( GLcontext *, int ); +struct dynfn *radeon_makeX86TexCoord2f( GLcontext *, int ); +struct dynfn *radeon_makeX86TexCoord2fv( GLcontext *, int ); +struct dynfn *radeon_makeX86TexCoord1f( GLcontext *, int ); +struct dynfn *radeon_makeX86TexCoord1fv( GLcontext *, int ); +struct dynfn *radeon_makeX86MultiTexCoord2fARB( GLcontext *, int ); +struct dynfn *radeon_makeX86MultiTexCoord2fvARB( GLcontext *, int ); +struct dynfn *radeon_makeX86MultiTexCoord1fARB( GLcontext *, int ); +struct dynfn *radeon_makeX86MultiTexCoord1fvARB( GLcontext *, int ); + + +#endif +#endif diff --git a/src/mesa/drivers/dri/radeon/radeon_vtxfmt_c.c b/src/mesa/drivers/dri/radeon/radeon_vtxfmt_c.c new file mode 100644 index 0000000000..188e34a420 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_vtxfmt_c.c @@ -0,0 +1,905 @@ +/* $XFree86$ */ +/************************************************************************** + +Copyright 2002 ATI Technologies Inc., Ontario, Canada, and + 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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ +#include "glheader.h" +#include "mtypes.h" +#include "colormac.h" +#include "simple_list.h" +#include "api_noop.h" +#include "vtxfmt.h" + +#include "radeon_vtxfmt.h" + +/* Fallback versions of all the entrypoints for situations where + * codegen isn't available. This is still a lot faster than the + * vb/pipeline implementation in Mesa. + */ +static void radeon_Vertex3f( GLfloat x, GLfloat y, GLfloat z ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + int i; + + *rmesa->vb.dmaptr++ = *(int *)&x; + *rmesa->vb.dmaptr++ = *(int *)&y; + *rmesa->vb.dmaptr++ = *(int *)&z; + + for (i = 3; i < rmesa->vb.vertex_size; i++) + *rmesa->vb.dmaptr++ = rmesa->vb.vertex[i].i; + + if (--rmesa->vb.counter == 0) + rmesa->vb.notify(); +} + + +static void radeon_Vertex3fv( const GLfloat *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + int i; + + *rmesa->vb.dmaptr++ = *(int *)&v[0]; + *rmesa->vb.dmaptr++ = *(int *)&v[1]; + *rmesa->vb.dmaptr++ = *(int *)&v[2]; + + for (i = 3; i < rmesa->vb.vertex_size; i++) + *rmesa->vb.dmaptr++ = rmesa->vb.vertex[i].i; + + if (--rmesa->vb.counter == 0) + rmesa->vb.notify(); +} + + +static void radeon_Vertex2f( GLfloat x, GLfloat y ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + int i; + + *rmesa->vb.dmaptr++ = *(int *)&x; + *rmesa->vb.dmaptr++ = *(int *)&y; + *rmesa->vb.dmaptr++ = 0; + + for (i = 3; i < rmesa->vb.vertex_size; i++) + *rmesa->vb.dmaptr++ = *(int *)&rmesa->vb.vertex[i]; + + if (--rmesa->vb.counter == 0) + rmesa->vb.notify(); +} + + +static void radeon_Vertex2fv( const GLfloat *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + int i; + + *rmesa->vb.dmaptr++ = *(int *)&v[0]; + *rmesa->vb.dmaptr++ = *(int *)&v[1]; + *rmesa->vb.dmaptr++ = 0; + + for (i = 3; i < rmesa->vb.vertex_size; i++) + *rmesa->vb.dmaptr++ = rmesa->vb.vertex[i].i; + + if (--rmesa->vb.counter == 0) + rmesa->vb.notify(); +} + + + +/* Color for ubyte (packed) color formats: + */ +static void radeon_Color3ub_ub( GLubyte r, GLubyte g, GLubyte b ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeon_color_t *dest = rmesa->vb.colorptr; + dest->red = r; + dest->green = g; + dest->blue = b; + dest->alpha = 0xff; +} + +static void radeon_Color3ubv_ub( const GLubyte *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeon_color_t *dest = rmesa->vb.colorptr; + dest->red = v[0]; + dest->green = v[1]; + dest->blue = v[2]; + dest->alpha = 0xff; +} + +static void radeon_Color4ub_ub( GLubyte r, GLubyte g, GLubyte b, GLubyte a ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeon_color_t *dest = rmesa->vb.colorptr; + dest->red = r; + dest->green = g; + dest->blue = b; + dest->alpha = a; +} + +static void radeon_Color4ubv_ub( const GLubyte *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + *(GLuint *)rmesa->vb.colorptr = LE32_TO_CPU(*(GLuint *)v); +} + + +static void radeon_Color3f_ub( GLfloat r, GLfloat g, GLfloat b ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeon_color_t *dest = rmesa->vb.colorptr; + UNCLAMPED_FLOAT_TO_UBYTE( dest->red, r ); + UNCLAMPED_FLOAT_TO_UBYTE( dest->green, g ); + UNCLAMPED_FLOAT_TO_UBYTE( dest->blue, b ); + dest->alpha = 255; +} + +static void radeon_Color3fv_ub( const GLfloat *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeon_color_t *dest = rmesa->vb.colorptr; + UNCLAMPED_FLOAT_TO_UBYTE( dest->red, v[0] ); + UNCLAMPED_FLOAT_TO_UBYTE( dest->green, v[1] ); + UNCLAMPED_FLOAT_TO_UBYTE( dest->blue, v[2] ); + dest->alpha = 255; +} + +static void radeon_Color4f_ub( GLfloat r, GLfloat g, GLfloat b, GLfloat a ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeon_color_t *dest = rmesa->vb.colorptr; + UNCLAMPED_FLOAT_TO_UBYTE( dest->red, r ); + UNCLAMPED_FLOAT_TO_UBYTE( dest->green, g ); + UNCLAMPED_FLOAT_TO_UBYTE( dest->blue, b ); + UNCLAMPED_FLOAT_TO_UBYTE( dest->alpha, a ); +} + +static void radeon_Color4fv_ub( const GLfloat *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeon_color_t *dest = rmesa->vb.colorptr; + UNCLAMPED_FLOAT_TO_UBYTE( dest->red, v[0] ); + UNCLAMPED_FLOAT_TO_UBYTE( dest->green, v[1] ); + UNCLAMPED_FLOAT_TO_UBYTE( dest->blue, v[2] ); + UNCLAMPED_FLOAT_TO_UBYTE( dest->alpha, v[3] ); +} + + +/* Color for float color+alpha formats: + */ +static void radeon_Color3ub_4f( GLubyte r, GLubyte g, GLubyte b ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatcolorptr; + dest[0] = UBYTE_TO_FLOAT(r); + dest[1] = UBYTE_TO_FLOAT(g); + dest[2] = UBYTE_TO_FLOAT(b); + dest[3] = 1.0; +} + +static void radeon_Color3ubv_4f( const GLubyte *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatcolorptr; + dest[0] = UBYTE_TO_FLOAT(v[0]); + dest[1] = UBYTE_TO_FLOAT(v[1]); + dest[2] = UBYTE_TO_FLOAT(v[2]); + dest[3] = 1.0; +} + +static void radeon_Color4ub_4f( GLubyte r, GLubyte g, GLubyte b, GLubyte a ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatcolorptr; + dest[0] = UBYTE_TO_FLOAT(r); + dest[1] = UBYTE_TO_FLOAT(g); + dest[2] = UBYTE_TO_FLOAT(b); + dest[3] = UBYTE_TO_FLOAT(a); +} + +static void radeon_Color4ubv_4f( const GLubyte *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatcolorptr; + dest[0] = UBYTE_TO_FLOAT(v[0]); + dest[1] = UBYTE_TO_FLOAT(v[1]); + dest[2] = UBYTE_TO_FLOAT(v[2]); + dest[3] = UBYTE_TO_FLOAT(v[3]); +} + + +static void radeon_Color3f_4f( GLfloat r, GLfloat g, GLfloat b ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatcolorptr; + dest[0] = r; + dest[1] = g; + dest[2] = b; + dest[3] = 1.0; +} + +static void radeon_Color3fv_4f( const GLfloat *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatcolorptr; + dest[0] = v[0]; + dest[1] = v[1]; + dest[2] = v[2]; + dest[3] = 1.0; +} + +static void radeon_Color4f_4f( GLfloat r, GLfloat g, GLfloat b, GLfloat a ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatcolorptr; + dest[0] = r; + dest[1] = g; + dest[2] = b; + dest[3] = a; +} + +static void radeon_Color4fv_4f( const GLfloat *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatcolorptr; + dest[0] = v[0]; + dest[1] = v[1]; + dest[2] = v[2]; + dest[3] = v[3]; +} + + +/* Color for float color formats: + */ +static void radeon_Color3ub_3f( GLubyte r, GLubyte g, GLubyte b ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatcolorptr; + dest[0] = UBYTE_TO_FLOAT(r); + dest[1] = UBYTE_TO_FLOAT(g); + dest[2] = UBYTE_TO_FLOAT(b); +} + +static void radeon_Color3ubv_3f( const GLubyte *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatcolorptr; + dest[0] = UBYTE_TO_FLOAT(v[0]); + dest[1] = UBYTE_TO_FLOAT(v[1]); + dest[2] = UBYTE_TO_FLOAT(v[2]); +} + +static void radeon_Color4ub_3f( GLubyte r, GLubyte g, GLubyte b, GLubyte a ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatcolorptr; + dest[0] = UBYTE_TO_FLOAT(r); + dest[1] = UBYTE_TO_FLOAT(g); + dest[2] = UBYTE_TO_FLOAT(b); + ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = UBYTE_TO_FLOAT(a); +} + +static void radeon_Color4ubv_3f( const GLubyte *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatcolorptr; + dest[0] = UBYTE_TO_FLOAT(v[0]); + dest[1] = UBYTE_TO_FLOAT(v[1]); + dest[2] = UBYTE_TO_FLOAT(v[2]); + ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = UBYTE_TO_FLOAT(v[3]); +} + + +static void radeon_Color3f_3f( GLfloat r, GLfloat g, GLfloat b ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatcolorptr; + dest[0] = r; + dest[1] = g; + dest[2] = b; +} + +static void radeon_Color3fv_3f( const GLfloat *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatcolorptr; + dest[0] = v[0]; + dest[1] = v[1]; + dest[2] = v[2]; +} + +static void radeon_Color4f_3f( GLfloat r, GLfloat g, GLfloat b, GLfloat a ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatcolorptr; + dest[0] = r; + dest[1] = g; + dest[2] = b; + ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = a; +} + +static void radeon_Color4fv_3f( const GLfloat *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatcolorptr; + dest[0] = v[0]; + dest[1] = v[1]; + dest[2] = v[2]; + ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = v[3]; +} + + +/* Secondary Color: + */ +static void radeon_SecondaryColor3ubEXT_ub( GLubyte r, GLubyte g, GLubyte b ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeon_color_t *dest = rmesa->vb.specptr; + dest->red = r; + dest->green = g; + dest->blue = b; + dest->alpha = 0xff; +} + +static void radeon_SecondaryColor3ubvEXT_ub( const GLubyte *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeon_color_t *dest = rmesa->vb.specptr; + dest->red = v[0]; + dest->green = v[1]; + dest->blue = v[2]; + dest->alpha = 0xff; +} + +static void radeon_SecondaryColor3fEXT_ub( GLfloat r, GLfloat g, GLfloat b ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeon_color_t *dest = rmesa->vb.specptr; + UNCLAMPED_FLOAT_TO_UBYTE( dest->red, r ); + UNCLAMPED_FLOAT_TO_UBYTE( dest->green, g ); + UNCLAMPED_FLOAT_TO_UBYTE( dest->blue, b ); + dest->alpha = 255; +} + +static void radeon_SecondaryColor3fvEXT_ub( const GLfloat *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + radeon_color_t *dest = rmesa->vb.specptr; + UNCLAMPED_FLOAT_TO_UBYTE( dest->red, v[0] ); + UNCLAMPED_FLOAT_TO_UBYTE( dest->green, v[1] ); + UNCLAMPED_FLOAT_TO_UBYTE( dest->blue, v[2] ); + dest->alpha = 255; +} + +static void radeon_SecondaryColor3ubEXT_3f( GLubyte r, GLubyte g, GLubyte b ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatspecptr; + dest[0] = UBYTE_TO_FLOAT(r); + dest[1] = UBYTE_TO_FLOAT(g); + dest[2] = UBYTE_TO_FLOAT(b); + dest[3] = 1.0; +} + +static void radeon_SecondaryColor3ubvEXT_3f( const GLubyte *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatspecptr; + dest[0] = UBYTE_TO_FLOAT(v[0]); + dest[1] = UBYTE_TO_FLOAT(v[1]); + dest[2] = UBYTE_TO_FLOAT(v[2]); + dest[3] = 1.0; +} + +static void radeon_SecondaryColor3fEXT_3f( GLfloat r, GLfloat g, GLfloat b ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatspecptr; + dest[0] = r; + dest[1] = g; + dest[2] = b; + dest[3] = 1.0; +} + +static void radeon_SecondaryColor3fvEXT_3f( const GLfloat *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.floatspecptr; + dest[0] = v[0]; + dest[1] = v[1]; + dest[2] = v[2]; + dest[3] = 1.0; +} + + +/* Normal + */ +static void radeon_Normal3f( GLfloat n0, GLfloat n1, GLfloat n2 ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.normalptr; + dest[0] = n0; + dest[1] = n1; + dest[2] = n2; +} + +static void radeon_Normal3fv( const GLfloat *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.normalptr; + dest[0] = v[0]; + dest[1] = v[1]; + dest[2] = v[2]; +} + + +/* TexCoord + */ +static void radeon_TexCoord1f( GLfloat s ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.texcoordptr[0]; + dest[0] = s; + dest[1] = 0; +} + +static void radeon_TexCoord1fv( const GLfloat *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.texcoordptr[0]; + dest[0] = v[0]; + dest[1] = 0; +} + +static void radeon_TexCoord2f( GLfloat s, GLfloat t ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.texcoordptr[0]; + dest[0] = s; + dest[1] = t; +} + +static void radeon_TexCoord2fv( const GLfloat *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.texcoordptr[0]; + dest[0] = v[0]; + dest[1] = v[1]; +} + + +/* MultiTexcoord + * + * Technically speaking, these functions should subtract GL_TEXTURE0 from + * \c target before masking and using it. The value of GL_TEXTURE0 is 0x84C0, + * which has the low-order 5 bits 0. For all possible valid values of + * \c target. Subtracting GL_TEXTURE0 has the net effect of masking \c target + * with 0x1F. Masking with 0x1F and then masking with 0x01 is redundant, so + * the subtraction has been omitted. + */ + +static void radeon_MultiTexCoord1fARB( GLenum target, GLfloat s ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.texcoordptr[target & 1]; + dest[0] = s; + dest[1] = 0; +} + +static void radeon_MultiTexCoord1fvARB( GLenum target, const GLfloat *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.texcoordptr[target & 1]; + dest[0] = v[0]; + dest[1] = 0; +} + +static void radeon_MultiTexCoord2fARB( GLenum target, GLfloat s, GLfloat t ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.texcoordptr[target & 1]; + dest[0] = s; + dest[1] = t; +} + +static void radeon_MultiTexCoord2fvARB( GLenum target, const GLfloat *v ) +{ + GET_CURRENT_CONTEXT(ctx); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + GLfloat *dest = rmesa->vb.texcoordptr[target & 1]; + dest[0] = v[0]; + dest[1] = v[1]; +} + +static struct dynfn *lookup( struct dynfn *l, int key ) +{ + struct dynfn *f; + + foreach( f, l ) { + if (f->key == key) + return f; + } + + return 0; +} + +/* Can't use the loopback template for this: + */ + +#define CHOOSE(FN, FNTYPE, MASK, ACTIVE, ARGS1, ARGS2 ) \ +static void choose_##FN ARGS1 \ +{ \ + GET_CURRENT_CONTEXT(ctx); \ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \ + int key = rmesa->vb.vertex_format & (MASK|ACTIVE); \ + struct dynfn *dfn; \ + \ + dfn = lookup( &rmesa->vb.dfn_cache.FN, key ); \ + if (dfn == 0) \ + dfn = rmesa->vb.codegen.FN( ctx, key ); \ + else if (RADEON_DEBUG & DEBUG_CODEGEN) \ + fprintf(stderr, "%s -- cached codegen\n", __FUNCTION__ ); \ + \ + if (dfn) \ + ctx->Exec->FN = (FNTYPE)(dfn->code); \ + else { \ + if (RADEON_DEBUG & DEBUG_CODEGEN) \ + fprintf(stderr, "%s -- generic version\n", __FUNCTION__ ); \ + ctx->Exec->FN = radeon_##FN; \ + } \ + \ + ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \ + ctx->Exec->FN ARGS2; \ +} + + + +/* For the _3f case, only allow one color function to be hooked in at + * a time. Eventually, use a similar mechanism to allow selecting the + * color component of the vertex format based on client behaviour. + * + * Note: Perform these actions even if there is a codegen or cached + * codegen version of the chosen function. + */ +#define CHOOSE_COLOR(FN, FNTYPE, NR, MASK, ACTIVE, ARGS1, ARGS2 ) \ +static void choose_##FN ARGS1 \ +{ \ + GET_CURRENT_CONTEXT(ctx); \ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \ + int key = rmesa->vb.vertex_format & (MASK|ACTIVE); \ + struct dynfn *dfn; \ + \ + if (rmesa->vb.vertex_format & ACTIVE_PKCOLOR) { \ + ctx->Exec->FN = radeon_##FN##_ub; \ + } \ + else if ((rmesa->vb.vertex_format & \ + (ACTIVE_FPCOLOR|ACTIVE_FPALPHA)) == ACTIVE_FPCOLOR) { \ + \ + if (rmesa->vb.installed_color_3f_sz != NR) { \ + rmesa->vb.installed_color_3f_sz = NR; \ + if (NR == 3) ctx->Current.Attrib[VERT_ATTRIB_COLOR0][3] = 1.0; \ + if (ctx->Driver.NeedFlush & FLUSH_UPDATE_CURRENT) { \ + radeon_copy_to_current( ctx ); \ + _mesa_install_exec_vtxfmt( ctx, &rmesa->vb.vtxfmt ); \ + ctx->Exec->FN ARGS2; \ + return; \ + } \ + } \ + \ + ctx->Exec->FN = radeon_##FN##_3f; \ + } \ + else { \ + ctx->Exec->FN = radeon_##FN##_4f; \ + } \ + \ + \ + dfn = lookup( &rmesa->vb.dfn_cache.FN, key ); \ + if (!dfn) dfn = rmesa->vb.codegen.FN( ctx, key ); \ + \ + if (dfn) { \ + if (RADEON_DEBUG & DEBUG_CODEGEN) \ + fprintf(stderr, "%s -- codegen version\n", __FUNCTION__ ); \ + ctx->Exec->FN = (FNTYPE)dfn->code; \ + } \ + else if (RADEON_DEBUG & DEBUG_CODEGEN) \ + fprintf(stderr, "%s -- 'c' version\n", __FUNCTION__ ); \ + \ + ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \ + ctx->Exec->FN ARGS2; \ +} + + + +/* Right now there are both _ub and _3f versions of the secondary color + * functions. Currently, we only set-up the hardware to use the _ub versions. + * The _3f versions are needed for the cases where secondary color isn't used + * in the vertex format, but it still needs to be stored in the context + * state vector. + */ +#define CHOOSE_SECONDARY_COLOR(FN, FNTYPE, MASK, ACTIVE, ARGS1, ARGS2 ) \ +static void choose_##FN ARGS1 \ +{ \ + GET_CURRENT_CONTEXT(ctx); \ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); \ + int key = rmesa->vb.vertex_format & (MASK|ACTIVE); \ + struct dynfn *dfn = lookup( &rmesa->vb.dfn_cache.FN, key ); \ + \ + if (dfn == 0) \ + dfn = rmesa->vb.codegen.FN( ctx, key ); \ + else if (RADEON_DEBUG & DEBUG_CODEGEN) \ + fprintf(stderr, "%s -- cached version\n", __FUNCTION__ ); \ + \ + if (dfn) \ + ctx->Exec->FN = (FNTYPE)(dfn->code); \ + else { \ + if (RADEON_DEBUG & DEBUG_CODEGEN) \ + fprintf(stderr, "%s -- generic version\n", __FUNCTION__ ); \ + ctx->Exec->FN = ((rmesa->vb.vertex_format & ACTIVE_PKSPEC) != 0) \ + ? radeon_##FN##_ub : radeon_##FN##_3f; \ + } \ + \ + ctx->Driver.NeedFlush |= FLUSH_UPDATE_CURRENT; \ + ctx->Exec->FN ARGS2; \ +} + + + + + +/* Shorthands + */ +#define ACTIVE_XYZW (RADEON_CP_VC_FRMT_W0|RADEON_CP_VC_FRMT_Z) +#define ACTIVE_NORM RADEON_CP_VC_FRMT_N0 + +#define ACTIVE_PKCOLOR RADEON_CP_VC_FRMT_PKCOLOR +#define ACTIVE_FPCOLOR RADEON_CP_VC_FRMT_FPCOLOR +#define ACTIVE_FPALPHA RADEON_CP_VC_FRMT_FPALPHA +#define ACTIVE_COLOR (ACTIVE_FPCOLOR|ACTIVE_PKCOLOR) + +#define ACTIVE_PKSPEC RADEON_CP_VC_FRMT_PKSPEC +#define ACTIVE_FPSPEC RADEON_CP_VC_FRMT_FPSPEC +#define ACTIVE_SPEC (ACTIVE_FPSPEC|ACTIVE_PKSPEC) + +#define ACTIVE_ST0 RADEON_CP_VC_FRMT_ST0 +#define ACTIVE_ST1 RADEON_CP_VC_FRMT_ST1 +#define ACTIVE_ST_ALL (RADEON_CP_VC_FRMT_ST1|RADEON_CP_VC_FRMT_ST0) + +/* Each codegen function should be able to be fully specified by a + * subsetted version of rmesa->vb.vertex_format. + */ +#define MASK_NORM (ACTIVE_XYZW) +#define MASK_COLOR (MASK_NORM|ACTIVE_NORM) +#define MASK_SPEC (MASK_COLOR|ACTIVE_COLOR) +#define MASK_ST0 (MASK_SPEC|ACTIVE_SPEC) +#define MASK_ST1 (MASK_ST0|ACTIVE_ST0) +#define MASK_ST_ALL (MASK_ST1|ACTIVE_ST1) +#define MASK_VERTEX (MASK_ST_ALL|ACTIVE_FPALPHA) + + +typedef void (*p4f)( GLfloat, GLfloat, GLfloat, GLfloat ); +typedef void (*p3f)( GLfloat, GLfloat, GLfloat ); +typedef void (*p2f)( GLfloat, GLfloat ); +typedef void (*p1f)( GLfloat ); +typedef void (*pe2f)( GLenum, GLfloat, GLfloat ); +typedef void (*pe1f)( GLenum, GLfloat ); +typedef void (*p4ub)( GLubyte, GLubyte, GLubyte, GLubyte ); +typedef void (*p3ub)( GLubyte, GLubyte, GLubyte ); +typedef void (*pfv)( const GLfloat * ); +typedef void (*pefv)( GLenum, const GLfloat * ); +typedef void (*pubv)( const GLubyte * ); + + +CHOOSE(Normal3f, p3f, MASK_NORM, ACTIVE_NORM, + (GLfloat a,GLfloat b,GLfloat c), (a,b,c)) +CHOOSE(Normal3fv, pfv, MASK_NORM, ACTIVE_NORM, + (const GLfloat *v), (v)) + +CHOOSE_COLOR(Color4ub, p4ub, 4, MASK_COLOR, ACTIVE_COLOR, + (GLubyte a,GLubyte b, GLubyte c, GLubyte d), (a,b,c,d)) +CHOOSE_COLOR(Color4ubv, pubv, 4, MASK_COLOR, ACTIVE_COLOR, + (const GLubyte *v), (v)) +CHOOSE_COLOR(Color3ub, p3ub, 3, MASK_COLOR, ACTIVE_COLOR, + (GLubyte a,GLubyte b, GLubyte c), (a,b,c)) +CHOOSE_COLOR(Color3ubv, pubv, 3, MASK_COLOR, ACTIVE_COLOR, + (const GLubyte *v), (v)) + +CHOOSE_COLOR(Color4f, p4f, 4, MASK_COLOR, ACTIVE_COLOR, + (GLfloat a,GLfloat b, GLfloat c, GLfloat d), (a,b,c,d)) +CHOOSE_COLOR(Color4fv, pfv, 4, MASK_COLOR, ACTIVE_COLOR, + (const GLfloat *v), (v)) +CHOOSE_COLOR(Color3f, p3f, 3, MASK_COLOR, ACTIVE_COLOR, + (GLfloat a,GLfloat b, GLfloat c), (a,b,c)) +CHOOSE_COLOR(Color3fv, pfv, 3, MASK_COLOR, ACTIVE_COLOR, + (const GLfloat *v), (v)) + + +CHOOSE_SECONDARY_COLOR(SecondaryColor3ubEXT, p3ub, MASK_SPEC, ACTIVE_SPEC, + (GLubyte a,GLubyte b, GLubyte c), (a,b,c)) +CHOOSE_SECONDARY_COLOR(SecondaryColor3ubvEXT, pubv, MASK_SPEC, ACTIVE_SPEC, + (const GLubyte *v), (v)) +CHOOSE_SECONDARY_COLOR(SecondaryColor3fEXT, p3f, MASK_SPEC, ACTIVE_SPEC, + (GLfloat a,GLfloat b, GLfloat c), (a,b,c)) +CHOOSE_SECONDARY_COLOR(SecondaryColor3fvEXT, pfv, MASK_SPEC, ACTIVE_SPEC, + (const GLfloat *v), (v)) + +CHOOSE(TexCoord2f, p2f, MASK_ST0, ACTIVE_ST0, + (GLfloat a,GLfloat b), (a,b)) +CHOOSE(TexCoord2fv, pfv, MASK_ST0, ACTIVE_ST0, + (const GLfloat *v), (v)) +CHOOSE(TexCoord1f, p1f, MASK_ST0, ACTIVE_ST0, + (GLfloat a), (a)) +CHOOSE(TexCoord1fv, pfv, MASK_ST0, ACTIVE_ST0, + (const GLfloat *v), (v)) + +CHOOSE(MultiTexCoord2fARB, pe2f, MASK_ST_ALL, ACTIVE_ST_ALL, + (GLenum u,GLfloat a,GLfloat b), (u,a,b)) +CHOOSE(MultiTexCoord2fvARB, pefv, MASK_ST_ALL, ACTIVE_ST_ALL, + (GLenum u,const GLfloat *v), (u,v)) +CHOOSE(MultiTexCoord1fARB, pe1f, MASK_ST_ALL, ACTIVE_ST_ALL, + (GLenum u,GLfloat a), (u,a)) +CHOOSE(MultiTexCoord1fvARB, pefv, MASK_ST_ALL, ACTIVE_ST_ALL, + (GLenum u,const GLfloat *v), (u,v)) + +CHOOSE(Vertex3f, p3f, MASK_VERTEX, MASK_VERTEX, + (GLfloat a,GLfloat b,GLfloat c), (a,b,c)) +CHOOSE(Vertex3fv, pfv, MASK_VERTEX, MASK_VERTEX, + (const GLfloat *v), (v)) +CHOOSE(Vertex2f, p2f, MASK_VERTEX, MASK_VERTEX, + (GLfloat a,GLfloat b), (a,b)) +CHOOSE(Vertex2fv, pfv, MASK_VERTEX, MASK_VERTEX, + (const GLfloat *v), (v)) + + + + + +void radeonVtxfmtInitChoosers( GLvertexformat *vfmt ) +{ + vfmt->Color3f = choose_Color3f; + vfmt->Color3fv = choose_Color3fv; + vfmt->Color3ub = choose_Color3ub; + vfmt->Color3ubv = choose_Color3ubv; + vfmt->Color4f = choose_Color4f; + vfmt->Color4fv = choose_Color4fv; + vfmt->Color4ub = choose_Color4ub; + vfmt->Color4ubv = choose_Color4ubv; + vfmt->SecondaryColor3fEXT = choose_SecondaryColor3fEXT; + vfmt->SecondaryColor3fvEXT = choose_SecondaryColor3fvEXT; + vfmt->SecondaryColor3ubEXT = choose_SecondaryColor3ubEXT; + vfmt->SecondaryColor3ubvEXT = choose_SecondaryColor3ubvEXT; + vfmt->MultiTexCoord1fARB = choose_MultiTexCoord1fARB; + vfmt->MultiTexCoord1fvARB = choose_MultiTexCoord1fvARB; + vfmt->MultiTexCoord2fARB = choose_MultiTexCoord2fARB; + vfmt->MultiTexCoord2fvARB = choose_MultiTexCoord2fvARB; + vfmt->Normal3f = choose_Normal3f; + vfmt->Normal3fv = choose_Normal3fv; + vfmt->TexCoord1f = choose_TexCoord1f; + vfmt->TexCoord1fv = choose_TexCoord1fv; + vfmt->TexCoord2f = choose_TexCoord2f; + vfmt->TexCoord2fv = choose_TexCoord2fv; + vfmt->Vertex2f = choose_Vertex2f; + vfmt->Vertex2fv = choose_Vertex2fv; + vfmt->Vertex3f = choose_Vertex3f; + vfmt->Vertex3fv = choose_Vertex3fv; +} + + +static struct dynfn *codegen_noop( GLcontext *ctx, int key ) +{ + (void) ctx; (void) key; + return 0; +} + +void radeonInitCodegen( struct dfn_generators *gen ) +{ + gen->Vertex3f = codegen_noop; + gen->Vertex3fv = codegen_noop; + gen->Color4ub = codegen_noop; + gen->Color4ubv = codegen_noop; + gen->Normal3f = codegen_noop; + gen->Normal3fv = codegen_noop; + gen->TexCoord2f = codegen_noop; + gen->TexCoord2fv = codegen_noop; + gen->MultiTexCoord2fARB = codegen_noop; + gen->MultiTexCoord2fvARB = codegen_noop; + gen->Vertex2f = codegen_noop; + gen->Vertex2fv = codegen_noop; + gen->Color3ub = codegen_noop; + gen->Color3ubv = codegen_noop; + gen->Color4f = codegen_noop; + gen->Color4fv = codegen_noop; + gen->Color3f = codegen_noop; + gen->Color3fv = codegen_noop; + gen->SecondaryColor3fEXT = codegen_noop; + gen->SecondaryColor3fvEXT = codegen_noop; + gen->SecondaryColor3ubEXT = codegen_noop; + gen->SecondaryColor3ubvEXT = codegen_noop; + gen->TexCoord1f = codegen_noop; + gen->TexCoord1fv = codegen_noop; + gen->MultiTexCoord1fARB = codegen_noop; + gen->MultiTexCoord1fvARB = codegen_noop; + + if (!getenv("RADEON_NO_CODEGEN")) { +#if defined(USE_X86_ASM) + radeonInitX86Codegen( gen ); +#endif + +#if defined(USE_SSE_ASM) + radeonInitSSECodegen( gen ); +#endif + } +} diff --git a/src/mesa/drivers/dri/radeon/radeon_vtxfmt_sse.c b/src/mesa/drivers/dri/radeon/radeon_vtxfmt_sse.c new file mode 100644 index 0000000000..0f2c82bd87 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_vtxfmt_sse.c @@ -0,0 +1,232 @@ +/* $XFree86$ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "glheader.h" +#include "imports.h" +#include "simple_list.h" +#include "radeon_vtxfmt.h" + +#if defined(USE_SSE_ASM) +#include "X86/common_x86_asm.h" + +#define EXTERN( FUNC ) \ +extern const char *FUNC; \ +extern const char *FUNC##_end + +EXTERN( _sse_Attribute2fv ); +EXTERN( _sse_Attribute2f ); +EXTERN( _sse_Attribute3fv ); +EXTERN( _sse_Attribute3f ); +EXTERN( _sse_MultiTexCoord2fv ); +EXTERN( _sse_MultiTexCoord2f ); +EXTERN( _sse_MultiTexCoord2fv_2 ); +EXTERN( _sse_MultiTexCoord2f_2 ); + +/* Build specialized versions of the immediate calls on the fly for + * the current state. + */ + +static struct dynfn *radeon_makeSSEAttribute2fv( struct dynfn * cache, int key, + const char * name, void * dest) +{ + struct dynfn *dfn = MALLOC_STRUCT( dynfn ); + + if (RADEON_DEBUG & DEBUG_CODEGEN) + fprintf(stderr, "%s 0x%08x\n", name, key ); + + DFN ( _sse_Attribute2fv, (*cache) ); + FIXUP(dfn->code, 10, 0x0, (int)dest); + return dfn; +} + +static struct dynfn *radeon_makeSSEAttribute2f( struct dynfn * cache, int key, + const char * name, void * dest ) +{ + struct dynfn *dfn = MALLOC_STRUCT( dynfn ); + + if (RADEON_DEBUG & DEBUG_CODEGEN) + fprintf(stderr, "%s 0x%08x\n", name, key ); + + DFN ( _sse_Attribute2f, (*cache) ); + FIXUP(dfn->code, 8, 0x0, (int)dest); + return dfn; +} + +static struct dynfn *radeon_makeSSEAttribute3fv( struct dynfn * cache, int key, + const char * name, void * dest) +{ + struct dynfn *dfn = MALLOC_STRUCT( dynfn ); + + if (RADEON_DEBUG & DEBUG_CODEGEN) + fprintf(stderr, "%s 0x%08x\n", name, key ); + + DFN ( _sse_Attribute3fv, (*cache) ); + FIXUP(dfn->code, 13, 0x0, (int)dest); + FIXUP(dfn->code, 18, 0x8, 8+(int)dest); + return dfn; +} + +static struct dynfn *radeon_makeSSEAttribute3f( struct dynfn * cache, int key, + const char * name, void * dest ) +{ + struct dynfn *dfn = MALLOC_STRUCT( dynfn ); + + if (RADEON_DEBUG & DEBUG_CODEGEN) + fprintf(stderr, "%s 0x%08x\n", name, key ); + + DFN ( _sse_Attribute3f, (*cache) ); + FIXUP(dfn->code, 12, 0x0, (int)dest); + FIXUP(dfn->code, 17, 0x8, 8+(int)dest); + return dfn; +} + +static struct dynfn * radeon_makeSSENormal3fv( GLcontext *ctx, int key ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + return radeon_makeSSEAttribute3fv( & rmesa->vb.dfn_cache.Normal3fv, key, + __FUNCTION__, rmesa->vb.normalptr ); +} + +static struct dynfn *radeon_makeSSENormal3f( GLcontext *ctx, int key ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + return radeon_makeSSEAttribute3f( & rmesa->vb.dfn_cache.Normal3f, key, + __FUNCTION__, rmesa->vb.normalptr ); +} + +static struct dynfn *radeon_makeSSEColor3fv( GLcontext *ctx, int key ) +{ + if (key & (RADEON_CP_VC_FRMT_PKCOLOR|RADEON_CP_VC_FRMT_FPALPHA)) + return 0; + else + { + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + return radeon_makeSSEAttribute3fv( & rmesa->vb.dfn_cache.Color3fv, key, + __FUNCTION__, rmesa->vb.floatcolorptr ); + } +} + +static struct dynfn *radeon_makeSSEColor3f( GLcontext *ctx, int key ) +{ + if (key & (RADEON_CP_VC_FRMT_PKCOLOR|RADEON_CP_VC_FRMT_FPALPHA)) + return 0; + else + { + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + return radeon_makeSSEAttribute3f( & rmesa->vb.dfn_cache.Color3f, key, + __FUNCTION__, rmesa->vb.floatcolorptr ); + } +} + +static struct dynfn *radeon_makeSSETexCoord2fv( GLcontext *ctx, int key ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + return radeon_makeSSEAttribute2fv( & rmesa->vb.dfn_cache.TexCoord2fv, key, + __FUNCTION__, rmesa->vb.texcoordptr[0] ); +} + +static struct dynfn *radeon_makeSSETexCoord2f( GLcontext *ctx, int key ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + return radeon_makeSSEAttribute2f( & rmesa->vb.dfn_cache.TexCoord2f, key, + __FUNCTION__, rmesa->vb.texcoordptr[0] ); +} + +static struct dynfn *radeon_makeSSEMultiTexCoord2fv( GLcontext *ctx, int key ) +{ + struct dynfn *dfn = MALLOC_STRUCT( dynfn ); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if (RADEON_DEBUG & DEBUG_CODEGEN) + fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key ); + + if ((key & (RADEON_CP_VC_FRMT_ST0|RADEON_CP_VC_FRMT_ST1)) == + (RADEON_CP_VC_FRMT_ST0|RADEON_CP_VC_FRMT_ST1)) { + DFN ( _sse_MultiTexCoord2fv, rmesa->vb.dfn_cache.MultiTexCoord2fvARB ); + FIXUP(dfn->code, 18, 0xdeadbeef, (int)rmesa->vb.texcoordptr[0]); + } else { + DFN ( _sse_MultiTexCoord2fv_2, rmesa->vb.dfn_cache.MultiTexCoord2fvARB ); + FIXUP(dfn->code, 14, 0x0, (int)rmesa->vb.texcoordptr); + } + return dfn; +} + +static struct dynfn *radeon_makeSSEMultiTexCoord2f( GLcontext *ctx, int key ) +{ + struct dynfn *dfn = MALLOC_STRUCT( dynfn ); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if (RADEON_DEBUG & DEBUG_CODEGEN) + fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key ); + + if ((key & (RADEON_CP_VC_FRMT_ST0|RADEON_CP_VC_FRMT_ST1)) == + (RADEON_CP_VC_FRMT_ST0|RADEON_CP_VC_FRMT_ST1)) { + DFN ( _sse_MultiTexCoord2f, rmesa->vb.dfn_cache.MultiTexCoord2fARB ); + FIXUP(dfn->code, 16, 0xdeadbeef, (int)rmesa->vb.texcoordptr[0]); + } else { + DFN ( _sse_MultiTexCoord2f_2, rmesa->vb.dfn_cache.MultiTexCoord2fARB ); + FIXUP(dfn->code, 15, 0x0, (int)rmesa->vb.texcoordptr); + } + return dfn; +} + +void radeonInitSSECodegen( struct dfn_generators *gen ) +{ + if ( cpu_has_xmm ) { + gen->Normal3fv = (void *) radeon_makeSSENormal3fv; + gen->Normal3f = (void *) radeon_makeSSENormal3f; + gen->Color3fv = (void *) radeon_makeSSEColor3fv; + gen->Color3f = (void *) radeon_makeSSEColor3f; + gen->TexCoord2fv = (void *) radeon_makeSSETexCoord2fv; + gen->TexCoord2f = (void *) radeon_makeSSETexCoord2f; + gen->MultiTexCoord2fvARB = (void *) radeon_makeSSEMultiTexCoord2fv; + gen->MultiTexCoord2fARB = (void *) radeon_makeSSEMultiTexCoord2f; + } +} + +#else + +void radeonInitSSECodegen( struct dfn_generators *gen ) +{ + (void) gen; +} + +#endif diff --git a/src/mesa/drivers/dri/radeon/radeon_vtxfmt_x86.c b/src/mesa/drivers/dri/radeon/radeon_vtxfmt_x86.c new file mode 100644 index 0000000000..92941ca5f8 --- /dev/null +++ b/src/mesa/drivers/dri/radeon/radeon_vtxfmt_x86.c @@ -0,0 +1,437 @@ +/* $XFree86$ */ +/************************************************************************** + +Copyright 2000, 2001 ATI Technologies Inc., Ontario, Canada, and + 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, sublicense, 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 NONINFRINGEMENT. +IN NO EVENT SHALL THE COPYRIGHT OWNER(S) 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. + +**************************************************************************/ + +/* + * Authors: + * Keith Whitwell <keith@tungstengraphics.com> + */ + +#include "glheader.h" +#include "imports.h" +#include "simple_list.h" +#include "radeon_vtxfmt.h" + +#if defined(USE_X86_ASM) + +#define EXTERN( FUNC ) \ +extern const char *FUNC; \ +extern const char *FUNC##_end + +EXTERN ( _x86_Attribute2fv ); +EXTERN ( _x86_Attribute2f ); +EXTERN ( _x86_Attribute3fv ); +EXTERN ( _x86_Attribute3f ); +EXTERN ( _x86_Vertex3fv_6 ); +EXTERN ( _x86_Vertex3fv_8 ); +EXTERN ( _x86_Vertex3fv ); +EXTERN ( _x86_Vertex3f_4 ); +EXTERN ( _x86_Vertex3f_6 ); +EXTERN ( _x86_Vertex3f ); +EXTERN ( _x86_Color4ubv_ub ); +EXTERN ( _x86_Color4ubv_4f ); +EXTERN ( _x86_Color4ub_ub ); +EXTERN ( _x86_MultiTexCoord2fv ); +EXTERN ( _x86_MultiTexCoord2fv_2 ); +EXTERN ( _x86_MultiTexCoord2f ); +EXTERN ( _x86_MultiTexCoord2f_2 ); + + +/* Build specialized versions of the immediate calls on the fly for + * the current state. Generic x86 versions. + */ + +struct dynfn *radeon_makeX86Vertex3f( GLcontext *ctx, int key ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct dynfn *dfn = MALLOC_STRUCT( dynfn ); + + if (RADEON_DEBUG & DEBUG_CODEGEN) + fprintf(stderr, "%s 0x%08x %d\n", __FUNCTION__, key, rmesa->vb.vertex_size ); + + switch (rmesa->vb.vertex_size) { + case 4: { + + DFN ( _x86_Vertex3f_4, rmesa->vb.dfn_cache.Vertex3f ); + FIXUP(dfn->code, 2, 0x0, (int)&rmesa->vb.dmaptr); + FIXUP(dfn->code, 25, 0x0, (int)&rmesa->vb.vertex[3]); + FIXUP(dfn->code, 36, 0x0, (int)&rmesa->vb.counter); + FIXUP(dfn->code, 46, 0x0, (int)&rmesa->vb.dmaptr); + FIXUP(dfn->code, 51, 0x0, (int)&rmesa->vb.counter); + FIXUP(dfn->code, 60, 0x0, (int)&rmesa->vb.notify); + break; + } + case 6: { + + DFN ( _x86_Vertex3f_6, rmesa->vb.dfn_cache.Vertex3f ); + FIXUP(dfn->code, 3, 0x0, (int)&rmesa->vb.dmaptr); + FIXUP(dfn->code, 28, 0x0, (int)&rmesa->vb.vertex[3]); + FIXUP(dfn->code, 34, 0x0, (int)&rmesa->vb.vertex[4]); + FIXUP(dfn->code, 40, 0x0, (int)&rmesa->vb.vertex[5]); + FIXUP(dfn->code, 57, 0x0, (int)&rmesa->vb.counter); + FIXUP(dfn->code, 63, 0x0, (int)&rmesa->vb.dmaptr); + FIXUP(dfn->code, 70, 0x0, (int)&rmesa->vb.counter); + FIXUP(dfn->code, 79, 0x0, (int)&rmesa->vb.notify); + break; + } + default: { + + DFN ( _x86_Vertex3f, rmesa->vb.dfn_cache.Vertex3f ); + FIXUP(dfn->code, 3, 0x0, (int)&rmesa->vb.vertex[3]); + FIXUP(dfn->code, 9, 0x0, (int)&rmesa->vb.dmaptr); + FIXUP(dfn->code, 37, 0x0, rmesa->vb.vertex_size-3); + FIXUP(dfn->code, 44, 0x0, (int)&rmesa->vb.counter); + FIXUP(dfn->code, 50, 0x0, (int)&rmesa->vb.dmaptr); + FIXUP(dfn->code, 56, 0x0, (int)&rmesa->vb.counter); + FIXUP(dfn->code, 67, 0x0, (int)&rmesa->vb.notify); + break; + } + } + + return dfn; +} + + + +struct dynfn *radeon_makeX86Vertex3fv( GLcontext *ctx, int key ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + struct dynfn *dfn = MALLOC_STRUCT( dynfn ); + + if (RADEON_DEBUG & DEBUG_CODEGEN) + fprintf(stderr, "%s 0x%08x %d\n", __FUNCTION__, key, rmesa->vb.vertex_size ); + + switch (rmesa->vb.vertex_size) { + case 6: { + + DFN ( _x86_Vertex3fv_6, rmesa->vb.dfn_cache.Vertex3fv ); + FIXUP(dfn->code, 1, 0x00000000, (int)&rmesa->vb.dmaptr); + FIXUP(dfn->code, 27, 0x0000001c, (int)&rmesa->vb.vertex[3]); + FIXUP(dfn->code, 33, 0x00000020, (int)&rmesa->vb.vertex[4]); + FIXUP(dfn->code, 45, 0x00000024, (int)&rmesa->vb.vertex[5]); + FIXUP(dfn->code, 56, 0x00000000, (int)&rmesa->vb.dmaptr); + FIXUP(dfn->code, 61, 0x00000004, (int)&rmesa->vb.counter); + FIXUP(dfn->code, 67, 0x00000004, (int)&rmesa->vb.counter); + FIXUP(dfn->code, 76, 0x00000008, (int)&rmesa->vb.notify); + break; + } + + + case 8: { + + DFN ( _x86_Vertex3fv_8, rmesa->vb.dfn_cache.Vertex3fv ); + FIXUP(dfn->code, 1, 0x00000000, (int)&rmesa->vb.dmaptr); + FIXUP(dfn->code, 27, 0x0000001c, (int)&rmesa->vb.vertex[3]); + FIXUP(dfn->code, 33, 0x00000020, (int)&rmesa->vb.vertex[4]); + FIXUP(dfn->code, 45, 0x0000001c, (int)&rmesa->vb.vertex[5]); + FIXUP(dfn->code, 51, 0x00000020, (int)&rmesa->vb.vertex[6]); + FIXUP(dfn->code, 63, 0x00000024, (int)&rmesa->vb.vertex[7]); + FIXUP(dfn->code, 74, 0x00000000, (int)&rmesa->vb.dmaptr); + FIXUP(dfn->code, 79, 0x00000004, (int)&rmesa->vb.counter); + FIXUP(dfn->code, 85, 0x00000004, (int)&rmesa->vb.counter); + FIXUP(dfn->code, 94, 0x00000008, (int)&rmesa->vb.notify); + break; + } + + + + default: { + + DFN ( _x86_Vertex3fv, rmesa->vb.dfn_cache.Vertex3fv ); + FIXUP(dfn->code, 8, 0x01010101, (int)&rmesa->vb.dmaptr); + FIXUP(dfn->code, 32, 0x00000006, rmesa->vb.vertex_size-3); + FIXUP(dfn->code, 37, 0x00000058, (int)&rmesa->vb.vertex[3]); + FIXUP(dfn->code, 45, 0x01010101, (int)&rmesa->vb.dmaptr); + FIXUP(dfn->code, 50, 0x02020202, (int)&rmesa->vb.counter); + FIXUP(dfn->code, 58, 0x02020202, (int)&rmesa->vb.counter); + FIXUP(dfn->code, 67, 0x0, (int)&rmesa->vb.notify); + break; + } + } + + return dfn; +} + +static struct dynfn * +radeon_makeX86Attribute2fv( struct dynfn * cache, int key, + const char * name, void * dest ) +{ + struct dynfn *dfn = MALLOC_STRUCT( dynfn ); + + if (RADEON_DEBUG & DEBUG_CODEGEN) + fprintf(stderr, "%s 0x%08x\n", name, key ); + + DFN ( _x86_Attribute2fv, (*cache) ); + FIXUP(dfn->code, 11, 0x0, (int)dest); + FIXUP(dfn->code, 16, 0x4, 4+(int)dest); + + return dfn; +} + +static struct dynfn * +radeon_makeX86Attribute2f( struct dynfn * cache, int key, + const char * name, void * dest ) +{ + struct dynfn *dfn = MALLOC_STRUCT( dynfn ); + + if (RADEON_DEBUG & DEBUG_CODEGEN) + fprintf(stderr, "%s 0x%08x\n", name, key ); + + DFN ( _x86_Attribute2f, (*cache) ); + FIXUP(dfn->code, 1, 0x0, (int)dest); + + return dfn; +} + + +static struct dynfn * +radeon_makeX86Attribute3fv( struct dynfn * cache, int key, + const char * name, void * dest ) +{ + struct dynfn *dfn = MALLOC_STRUCT( dynfn ); + + if (RADEON_DEBUG & DEBUG_CODEGEN) + fprintf(stderr, "%s 0x%08x\n", name, key ); + + DFN ( _x86_Attribute3fv, (*cache) ); + FIXUP(dfn->code, 14, 0x0, (int)dest); + FIXUP(dfn->code, 20, 0x4, 4+(int)dest); + FIXUP(dfn->code, 25, 0x8, 8+(int)dest); + + return dfn; +} + +static struct dynfn * +radeon_makeX86Attribute3f( struct dynfn * cache, int key, + const char * name, void * dest ) +{ + struct dynfn *dfn = MALLOC_STRUCT( dynfn ); + + if (RADEON_DEBUG & DEBUG_CODEGEN) + fprintf(stderr, "%s 0x%08x\n", name, key ); + + DFN ( _x86_Attribute3f, (*cache) ); + FIXUP(dfn->code, 14, 0x0, (int)dest); + FIXUP(dfn->code, 20, 0x4, 4+(int)dest); + FIXUP(dfn->code, 25, 0x8, 8+(int)dest); + + return dfn; +} + +struct dynfn *radeon_makeX86Normal3fv( GLcontext *ctx, int key ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + return radeon_makeX86Attribute3fv( & rmesa->vb.dfn_cache.Normal3fv, key, + __FUNCTION__, rmesa->vb.normalptr ); +} + +struct dynfn *radeon_makeX86Normal3f( GLcontext *ctx, int key ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + return radeon_makeX86Attribute3f( & rmesa->vb.dfn_cache.Normal3f, key, + __FUNCTION__, rmesa->vb.normalptr ); +} + +struct dynfn *radeon_makeX86Color4ubv( GLcontext *ctx, int key ) +{ + struct dynfn *dfn = MALLOC_STRUCT( dynfn ); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + + if (RADEON_DEBUG & DEBUG_CODEGEN) + fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key ); + + if (key & RADEON_CP_VC_FRMT_PKCOLOR) { + DFN ( _x86_Color4ubv_ub, rmesa->vb.dfn_cache.Color4ubv); + FIXUP(dfn->code, 5, 0x12345678, (int)rmesa->vb.colorptr); + return dfn; + } + else { + + DFN ( _x86_Color4ubv_4f, rmesa->vb.dfn_cache.Color4ubv); + FIXUP(dfn->code, 2, 0x00000000, (int)_mesa_ubyte_to_float_color_tab); + FIXUP(dfn->code, 27, 0xdeadbeaf, (int)rmesa->vb.floatcolorptr); + FIXUP(dfn->code, 33, 0xdeadbeaf, (int)rmesa->vb.floatcolorptr+4); + FIXUP(dfn->code, 55, 0xdeadbeaf, (int)rmesa->vb.floatcolorptr+8); + FIXUP(dfn->code, 61, 0xdeadbeaf, (int)rmesa->vb.floatcolorptr+12); + return dfn; + } +} + +struct dynfn *radeon_makeX86Color4ub( GLcontext *ctx, int key ) +{ + if (RADEON_DEBUG & DEBUG_CODEGEN) + fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key ); + + if (key & RADEON_CP_VC_FRMT_PKCOLOR) { + struct dynfn *dfn = MALLOC_STRUCT( dynfn ); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + DFN ( _x86_Color4ub_ub, rmesa->vb.dfn_cache.Color4ub ); + FIXUP(dfn->code, 18, 0x0, (int)rmesa->vb.colorptr); + FIXUP(dfn->code, 24, 0x0, (int)rmesa->vb.colorptr+1); + FIXUP(dfn->code, 30, 0x0, (int)rmesa->vb.colorptr+2); + FIXUP(dfn->code, 36, 0x0, (int)rmesa->vb.colorptr+3); + return dfn; + } + else + return 0; +} + + +struct dynfn *radeon_makeX86Color3fv( GLcontext *ctx, int key ) +{ + if (key & (RADEON_CP_VC_FRMT_PKCOLOR|RADEON_CP_VC_FRMT_FPALPHA)) + return 0; + else + { + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + return radeon_makeX86Attribute3fv( & rmesa->vb.dfn_cache.Color3fv, key, + __FUNCTION__, rmesa->vb.floatcolorptr ); + } +} + +struct dynfn *radeon_makeX86Color3f( GLcontext *ctx, int key ) +{ + if (key & (RADEON_CP_VC_FRMT_PKCOLOR|RADEON_CP_VC_FRMT_FPALPHA)) + return 0; + else + { + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + return radeon_makeX86Attribute3f( & rmesa->vb.dfn_cache.Color3f, key, + __FUNCTION__, rmesa->vb.floatcolorptr ); + } +} + + + +struct dynfn *radeon_makeX86TexCoord2fv( GLcontext *ctx, int key ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + return radeon_makeX86Attribute2fv( & rmesa->vb.dfn_cache.TexCoord2fv, key, + __FUNCTION__, rmesa->vb.texcoordptr[0] ); +} + +struct dynfn *radeon_makeX86TexCoord2f( GLcontext *ctx, int key ) +{ + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + return radeon_makeX86Attribute2f( & rmesa->vb.dfn_cache.TexCoord2f, key, + __FUNCTION__, rmesa->vb.texcoordptr[0] ); +} + +struct dynfn *radeon_makeX86MultiTexCoord2fvARB( GLcontext *ctx, int key ) +{ + struct dynfn *dfn = MALLOC_STRUCT( dynfn ); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if (RADEON_DEBUG & DEBUG_CODEGEN) + fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key ); + + if ((key & (RADEON_CP_VC_FRMT_ST0|RADEON_CP_VC_FRMT_ST1)) == + (RADEON_CP_VC_FRMT_ST0|RADEON_CP_VC_FRMT_ST1)) { + DFN ( _x86_MultiTexCoord2fv, rmesa->vb.dfn_cache.MultiTexCoord2fvARB ); + FIXUP(dfn->code, 21, 0xdeadbeef, (int)rmesa->vb.texcoordptr[0]); + FIXUP(dfn->code, 27, 0xdeadbeef, (int)rmesa->vb.texcoordptr[0]+4); + } else { + DFN ( _x86_MultiTexCoord2fv_2, rmesa->vb.dfn_cache.MultiTexCoord2fvARB ); + FIXUP(dfn->code, 14, 0x0, (int)rmesa->vb.texcoordptr); + } + return dfn; +} + +struct dynfn *radeon_makeX86MultiTexCoord2fARB( GLcontext *ctx, + int key ) +{ + struct dynfn *dfn = MALLOC_STRUCT( dynfn ); + radeonContextPtr rmesa = RADEON_CONTEXT(ctx); + + if (RADEON_DEBUG & DEBUG_CODEGEN) + fprintf(stderr, "%s 0x%08x\n", __FUNCTION__, key ); + + if ((key & (RADEON_CP_VC_FRMT_ST0|RADEON_CP_VC_FRMT_ST1)) == + (RADEON_CP_VC_FRMT_ST0|RADEON_CP_VC_FRMT_ST1)) { + DFN ( _x86_MultiTexCoord2f, rmesa->vb.dfn_cache.MultiTexCoord2fARB ); + FIXUP(dfn->code, 20, 0xdeadbeef, (int)rmesa->vb.texcoordptr[0]); + FIXUP(dfn->code, 26, 0xdeadbeef, (int)rmesa->vb.texcoordptr[0]+4); + } + else { + /* Note: this might get generated multiple times, even though the + * actual emitted code is the same. + */ + DFN ( _x86_MultiTexCoord2f_2, rmesa->vb.dfn_cache.MultiTexCoord2fARB ); + FIXUP(dfn->code, 18, 0x0, (int)rmesa->vb.texcoordptr); + } + return dfn; +} + + +void radeonInitX86Codegen( struct dfn_generators *gen ) +{ + gen->Vertex3f = radeon_makeX86Vertex3f; + gen->Vertex3fv = radeon_makeX86Vertex3fv; + gen->Color4ub = radeon_makeX86Color4ub; /* PKCOLOR only */ + gen->Color4ubv = radeon_makeX86Color4ubv; /* PKCOLOR only */ + gen->Normal3f = radeon_makeX86Normal3f; + gen->Normal3fv = radeon_makeX86Normal3fv; + gen->TexCoord2f = radeon_makeX86TexCoord2f; + gen->TexCoord2fv = radeon_makeX86TexCoord2fv; + gen->MultiTexCoord2fARB = radeon_makeX86MultiTexCoord2fARB; + gen->MultiTexCoord2fvARB = radeon_makeX86MultiTexCoord2fvARB; + gen->Color3f = radeon_makeX86Color3f; + gen->Color3fv = radeon_makeX86Color3fv; + + /* Not done: + */ +/* gen->Vertex2f = radeon_makeX86Vertex2f; */ +/* gen->Vertex2fv = radeon_makeX86Vertex2fv; */ +/* gen->Color3ub = radeon_makeX86Color3ub; */ +/* gen->Color3ubv = radeon_makeX86Color3ubv; */ +/* gen->Color4f = radeon_makeX86Color4f; */ +/* gen->Color4fv = radeon_makeX86Color4fv; */ +/* gen->TexCoord1f = radeon_makeX86TexCoord1f; */ +/* gen->TexCoord1fv = radeon_makeX86TexCoord1fv; */ +/* gen->MultiTexCoord1fARB = radeon_makeX86MultiTexCoord1fARB; */ +/* gen->MultiTexCoord1fvARB = radeon_makeX86MultiTexCoord1fvARB; */ +} + + +#else + +void radeonInitX86Codegen( struct dfn_generators *gen ) +{ + (void) gen; +} + +#endif diff --git a/src/mesa/drivers/dri/radeon/server/radeon_common.h b/src/mesa/drivers/dri/radeon/server/radeon_common.h index c26ccd3cc2..0792b5c2e0 100644 --- a/src/mesa/drivers/dri/radeon/server/radeon_common.h +++ b/src/mesa/drivers/dri/radeon/server/radeon_common.h @@ -1,19 +1,5 @@ -/** - * \file server/radeon_common.h - * \brief Common header definitions for Radeon 2D/3D/DRM driver suite. +/* radeon_common.h -- common header definitions for Radeon 2D/3D/DRM suite * - * \note Some of these structures are meant for backward compatibility and - * aren't used by the subset driver. - * - * \author Gareth Hughes <gareth@valinux.com> - * \author Kevin E. Martin <martin@valinux.com> - * \author Keith Whitwell <keith@tungstengraphics.com> - * - * \author Converted to common header format by - * Jens Owen <jens@tungstengraphics.com> - */ - -/* * Copyright 2000 VA Linux Systems, Inc., Fremont, California. * Copyright 2002 Tungsten Graphics, Inc., Cedar Park, Texas. * All Rights Reserved. @@ -36,10 +22,19 @@ * 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. + * + * Author: + * Gareth Hughes <gareth@valinux.com> + * Kevin E. Martin <martin@valinux.com> + * Keith Whitwell <keith@tungstengraphics.com> + * + * Converted to common header format: + * Jens Owen <jens@tungstengraphics.com> + * + * $XFree86: xc/programs/Xserver/hw/xfree86/os-support/xf86drmRadeon.h,v 1.6 2001/04/16 15:02:13 tsi Exp $ + * */ -/* $XFree86: xc/programs/Xserver/hw/xfree86/os-support/xf86drmRadeon.h,v 1.6 2001/04/16 15:02:13 tsi Exp $ */ - #ifndef _RADEON_COMMON_H_ #define _RADEON_COMMON_H_ @@ -90,42 +85,33 @@ #define RADEON_CLEAR_DEPTH 4 -/** - * \brief DRM_RADEON_CP_INIT ioctl argument type. - */ typedef struct { enum { - DRM_RADEON_INIT_CP = 0x01, /**< \brief initialize CP */ - DRM_RADEON_CLEANUP_CP = 0x02, /**< \brief clean up CP */ - DRM_RADEON_INIT_R200_CP = 0x03 /**< \brief initialize R200 CP */ - } func; /**< \brief request */ - unsigned long sarea_priv_offset; /**< \brief SAREA private offset */ - int is_pci; /**< \brief is current card a PCI card? */ - int cp_mode; /**< \brief CP mode */ - int agp_size; /**< \brief AGP space size */ - int ring_size; /**< \brief CP ring buffer size */ - int usec_timeout; /**< \brief timeout for DRM operations in usecs */ - - unsigned int fb_bpp; - unsigned int front_offset; /**< \brief front color buffer offset */ - unsigned int front_pitch; /**< \brief front color buffer pitch */ - unsigned int back_offset; /**< \brief back color buffer offset */ - unsigned int back_pitch; /**< \brief back color buffer pitch*/ - unsigned int depth_bpp; /**< \brief depth buffer bits-per-pixel */ - unsigned int depth_offset; /**< \brief depth buffer offset */ - unsigned int depth_pitch; /**< \brief depth buffer pitch */ - - unsigned long fb_offset; /**< \brief framebuffer offset */ - unsigned long mmio_offset; /**< \brief MMIO register offset */ - unsigned long ring_offset; /**< \brief CP ring buffer offset */ - unsigned long ring_rptr_offset; /**< \brief CP ring buffer read pointer offset */ - unsigned long buffers_offset; /**< \brief vertex buffers offset */ - unsigned long agp_textures_offset; /**< \brief AGP textures offset */ + DRM_RADEON_INIT_CP = 0x01, + DRM_RADEON_CLEANUP_CP = 0x02, + DRM_RADEON_INIT_R200_CP = 0x03 + } func; + unsigned long sarea_priv_offset; + int is_pci; + int cp_mode; + int agp_size; + int ring_size; + int usec_timeout; + + unsigned int fb_bpp; + unsigned int front_offset, front_pitch; + unsigned int back_offset, back_pitch; + unsigned int depth_bpp; + unsigned int depth_offset, depth_pitch; + + unsigned long fb_offset; + unsigned long mmio_offset; + unsigned long ring_offset; + unsigned long ring_rptr_offset; + unsigned long buffers_offset; + unsigned long agp_textures_offset; } drmRadeonInit; -/** - * \brief DRM_RADEON_CP_STOP ioctl argument type. - */ typedef struct { int flush; int idle; @@ -143,17 +129,13 @@ typedef union drmRadeonClearR { unsigned int ui[5]; } drmRadeonClearRect; -/** - * \brief DRM_RADEON_CLEAR ioctl argument type. - */ typedef struct drmRadeonClearT { - unsigned int flags; /**< \brief bitmask of the planes to clear */ - unsigned int clear_color; /**< \brief color buffer clear value */ - unsigned int clear_depth; /**< \brief depth buffer clear value */ - unsigned int color_mask; /**< \brief color buffer clear mask */ - unsigned int depth_mask; /**< \brief stencil buffer clear value - * \todo Misnamed field. */ - drmRadeonClearRect *depth_boxes; /**< \brief depth buffer cliprects */ + unsigned int flags; + unsigned int clear_color; + unsigned int clear_depth; + unsigned int color_mask; + unsigned int depth_mask; /* misnamed field: should be stencil */ + drmRadeonClearRect *depth_boxes; } drmRadeonClearType; typedef struct drmRadeonFullscreenT { @@ -163,16 +145,10 @@ typedef struct drmRadeonFullscreenT { } func; } drmRadeonFullscreenType; -/** - * \brief DRM_RADEON_STIPPLE ioctl argument type. - */ typedef struct { unsigned int *mask; } drmRadeonStipple; -/** - * \brief Texture image for drmRadeonTexture. - */ typedef struct { unsigned int x; unsigned int y; @@ -181,22 +157,18 @@ typedef struct { const void *data; } drmRadeonTexImage; -/** - * \brief DRM_RADEON_TEXTURE ioctl argument type. - */ typedef struct { - int offset; /**< \brief texture offset */ - int pitch; /**< \brief texture pitch */ - int format; /**< \brief pixel format */ - int width; /**< \brief texture width */ - int height; /**< \brief texture height */ - drmRadeonTexImage *image; /**< \brief image */ + int offset; + int pitch; + int format; + int width; /* Texture image coordinates */ + int height; + drmRadeonTexImage *image; } drmRadeonTexture; #define RADEON_MAX_TEXTURE_UNITS 3 - /* Layout matches drm_radeon_state_t in linux drm_radeon.h. */ typedef struct { @@ -266,16 +238,13 @@ typedef struct { unsigned int dirty; } drmRadeonState; -/** - * \brief DRM 1.1 vertex ioctl. - * - * Used in compatibility modes. +/* 1.1 vertex ioctl. Used in compatibility modes. */ typedef struct { - int prim; /**< \brief Primitive number */ - int idx; /**< \brief Index of vertex buffer */ - int count; /**< \brief Number of vertices in buffer */ - int discard; /**< \brief Client finished with buffer? */ + int prim; + int idx; /* Index of vertex buffer */ + int count; /* Number of vertices in buffer */ + int discard; /* Client finished with buffer? */ } drmRadeonVertex; typedef struct { @@ -283,13 +252,13 @@ typedef struct { unsigned int finish; unsigned int prim:8; unsigned int stateidx:8; - unsigned int numverts:16; /**< overloaded as offset/64 for elt prims */ + unsigned int numverts:16; /* overloaded as offset/64 for elt prims */ unsigned int vc_format; } drmRadeonPrim; typedef struct { - int idx; /**< \brief Index of vertex buffer */ - int discard; /**< \brief Client finished with buffer? */ + int idx; /* Index of vertex buffer */ + int discard; /* Client finished with buffer? */ int nr_states; drmRadeonState *state; int nr_prims; @@ -299,156 +268,127 @@ typedef struct { #define RADEON_MAX_STATES 16 #define RADEON_MAX_PRIMS 64 - -/** - * \brief Command buffer. - * - * \todo Replace with true DMA stream? +/* Command buffer. Replace with true dma stream? */ typedef struct { - int bufsz; /**< \brief buffer size */ - char *buf; /**< \brief buffer */ - int nbox; /**< \brief number of cliprects */ - drmClipRect *boxes; /**< \brief cliprects */ + int bufsz; + char *buf; + int nbox; + drmClipRect *boxes; } drmRadeonCmdBuffer; - -/** - * \brief Per-packet identifiers for use with the ::RADEON_CMD_PACKET command - * in the DRM_RADEON_CMDBUF ioctl. - * - * \note Comments relate new packets to old state bits and the packet size. +/* New style per-packet identifiers for use in cmd_buffer ioctl with + * the RADEON_EMIT_PACKET command. Comments relate new packets to old + * state bits and the packet size: */ -enum drmRadeonCmdPkt { - RADEON_EMIT_PP_MISC = 0, /* context/7 */ - RADEON_EMIT_PP_CNTL = 1, /* context/3 */ - RADEON_EMIT_RB3D_COLORPITCH = 2, /* context/1 */ - RADEON_EMIT_RE_LINE_PATTERN = 3, /* line/2 */ - RADEON_EMIT_SE_LINE_WIDTH = 4, /* line/1 */ - RADEON_EMIT_PP_LUM_MATRIX = 5, /* bumpmap/1 */ - RADEON_EMIT_PP_ROT_MATRIX_0 = 6, /* bumpmap/2 */ - RADEON_EMIT_RB3D_STENCILREFMASK = 7, /* masks/3 */ - RADEON_EMIT_SE_VPORT_XSCALE = 8, /* viewport/6 */ - RADEON_EMIT_SE_CNTL = 9, /* setup/2 */ - RADEON_EMIT_SE_CNTL_STATUS = 10, /* setup/1 */ - RADEON_EMIT_RE_MISC = 11, /* misc/1 */ - RADEON_EMIT_PP_TXFILTER_0 = 12, /* tex0/6 */ - RADEON_EMIT_PP_BORDER_COLOR_0 = 13, /* tex0/1 */ - RADEON_EMIT_PP_TXFILTER_1 = 14, /* tex1/6 */ - RADEON_EMIT_PP_BORDER_COLOR_1 = 15, /* tex1/1 */ - RADEON_EMIT_PP_TXFILTER_2 = 16, /* tex2/6 */ - RADEON_EMIT_PP_BORDER_COLOR_2 = 17, /* tex2/1 */ - RADEON_EMIT_SE_ZBIAS_FACTOR = 18, /* zbias/2 */ - RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT = 19, /* tcl/11 */ - RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED = 20, /* material/17 */ - R200_EMIT_PP_TXCBLEND_0 = 21, /* tex0/4 */ - R200_EMIT_PP_TXCBLEND_1 = 22, /* tex1/4 */ - R200_EMIT_PP_TXCBLEND_2 = 23, /* tex2/4 */ - R200_EMIT_PP_TXCBLEND_3 = 24, /* tex3/4 */ - R200_EMIT_PP_TXCBLEND_4 = 25, /* tex4/4 */ - R200_EMIT_PP_TXCBLEND_5 = 26, /* tex5/4 */ - R200_EMIT_PP_TXCBLEND_6 = 27, /* /4 */ - R200_EMIT_PP_TXCBLEND_7 = 28, /* /4 */ - R200_EMIT_TCL_LIGHT_MODEL_CTL_0 = 29, /* tcl/6 */ - R200_EMIT_TFACTOR_0 = 30, /* tf/6 */ - R200_EMIT_VTX_FMT_0 = 31, /* vtx/4 */ - R200_EMIT_VAP_CTL = 32, /* vap/1 */ - R200_EMIT_MATRIX_SELECT_0 = 33, /* msl/5 */ - R200_EMIT_TEX_PROC_CTL_2 = 34, /* tcg/5 */ - R200_EMIT_TCL_UCP_VERT_BLEND_CTL = 35, /* tcl/1 */ - R200_EMIT_PP_TXFILTER_0 = 36, /* tex0/6 */ - R200_EMIT_PP_TXFILTER_1 = 37, /* tex1/6 */ - R200_EMIT_PP_TXFILTER_2 = 38, /* tex2/6 */ - R200_EMIT_PP_TXFILTER_3 = 39, /* tex3/6 */ - R200_EMIT_PP_TXFILTER_4 = 40, /* tex4/6 */ - R200_EMIT_PP_TXFILTER_5 = 41, /* tex5/6 */ - R200_EMIT_PP_TXOFFSET_0 = 42, /* tex0/1 */ - R200_EMIT_PP_TXOFFSET_1 = 43, /* tex1/1 */ - R200_EMIT_PP_TXOFFSET_2 = 44, /* tex2/1 */ - R200_EMIT_PP_TXOFFSET_3 = 45, /* tex3/1 */ - R200_EMIT_PP_TXOFFSET_4 = 46, /* tex4/1 */ - R200_EMIT_PP_TXOFFSET_5 = 47, /* tex5/1 */ - R200_EMIT_VTE_CNTL = 48, /* vte/1 */ - R200_EMIT_OUTPUT_VTX_COMP_SEL = 49, /* vtx/1 */ - R200_EMIT_PP_TAM_DEBUG3 = 50, /* tam/1 */ - R200_EMIT_PP_CNTL_X = 51, /* cst/1 */ - R200_EMIT_RB3D_DEPTHXY_OFFSET = 52, /* cst/1 */ - R200_EMIT_RE_AUX_SCISSOR_CNTL = 53, /* cst/1 */ - R200_EMIT_RE_SCISSOR_TL_0 = 54, /* cst/2 */ - R200_EMIT_RE_SCISSOR_TL_1 = 55, /* cst/2 */ - R200_EMIT_RE_SCISSOR_TL_2 = 56, /* cst/2 */ - R200_EMIT_SE_VAP_CNTL_STATUS = 57, /* cst/1 */ - R200_EMIT_SE_VTX_STATE_CNTL = 58, /* cst/1 */ - R200_EMIT_RE_POINTSIZE = 59, /* cst/1 */ - R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0 = 60, /* cst/4 */ - R200_EMIT_PP_CUBIC_FACES_0 = 61, - R200_EMIT_PP_CUBIC_OFFSETS_0 = 62, - R200_EMIT_PP_CUBIC_FACES_1 = 63, - R200_EMIT_PP_CUBIC_OFFSETS_1 = 64, - R200_EMIT_PP_CUBIC_FACES_2 = 65, - R200_EMIT_PP_CUBIC_OFFSETS_2 = 66, - R200_EMIT_PP_CUBIC_FACES_3 = 67, - R200_EMIT_PP_CUBIC_OFFSETS_3 = 68, - R200_EMIT_PP_CUBIC_FACES_4 = 69, - R200_EMIT_PP_CUBIC_OFFSETS_4 = 70, - R200_EMIT_PP_CUBIC_FACES_5 = 71, - R200_EMIT_PP_CUBIC_OFFSETS_5 = 72, - RADEON_MAX_STATE_PACKETS = 73 -} ; - - -/** - * \brief Command types understood by the DRM_RADEON_CMDBUF ioctl. - * - * More can be added but obviously these can't be removed or changed. - * - * \sa drmRadeonCmdHeader. - */ -enum drmRadeonCmdType { - RADEON_CMD_PACKET = 1, /**< \brief emit one of the ::drmRadeonCmdPkt register packets */ - RADEON_CMD_SCALARS = 2, /**< \brief emit scalar data */ - RADEON_CMD_VECTORS = 3, /**< \brief emit vector data */ - RADEON_CMD_DMA_DISCARD = 4, /**< \brief discard current DMA buffer */ - RADEON_CMD_PACKET3 = 5, /**< \brief emit hardware packet */ - RADEON_CMD_PACKET3_CLIP = 6, /**< \brief emit hardware packet wrapped in cliprects */ - RADEON_CMD_SCALARS2 = 7, /**< \brief R200 stopgap */ - RADEON_CMD_WAIT = 8 /**< \brief synchronization */ -} ; - -/** - * \brief Command packet headers understood by the DRM_RADEON_CMDBUF ioctl. - * - * \sa drmRadeonCmdType. +#define RADEON_EMIT_PP_MISC 0 /* context/7 */ +#define RADEON_EMIT_PP_CNTL 1 /* context/3 */ +#define RADEON_EMIT_RB3D_COLORPITCH 2 /* context/1 */ +#define RADEON_EMIT_RE_LINE_PATTERN 3 /* line/2 */ +#define RADEON_EMIT_SE_LINE_WIDTH 4 /* line/1 */ +#define RADEON_EMIT_PP_LUM_MATRIX 5 /* bumpmap/1 */ +#define RADEON_EMIT_PP_ROT_MATRIX_0 6 /* bumpmap/2 */ +#define RADEON_EMIT_RB3D_STENCILREFMASK 7 /* masks/3 */ +#define RADEON_EMIT_SE_VPORT_XSCALE 8 /* viewport/6 */ +#define RADEON_EMIT_SE_CNTL 9 /* setup/2 */ +#define RADEON_EMIT_SE_CNTL_STATUS 10 /* setup/1 */ +#define RADEON_EMIT_RE_MISC 11 /* misc/1 */ +#define RADEON_EMIT_PP_TXFILTER_0 12 /* tex0/6 */ +#define RADEON_EMIT_PP_BORDER_COLOR_0 13 /* tex0/1 */ +#define RADEON_EMIT_PP_TXFILTER_1 14 /* tex1/6 */ +#define RADEON_EMIT_PP_BORDER_COLOR_1 15 /* tex1/1 */ +#define RADEON_EMIT_PP_TXFILTER_2 16 /* tex2/6 */ +#define RADEON_EMIT_PP_BORDER_COLOR_2 17 /* tex2/1 */ +#define RADEON_EMIT_SE_ZBIAS_FACTOR 18 /* zbias/2 */ +#define RADEON_EMIT_SE_TCL_OUTPUT_VTX_FMT 19 /* tcl/11 */ +#define RADEON_EMIT_SE_TCL_MATERIAL_EMMISSIVE_RED 20 /* material/17 */ +#define R200_EMIT_PP_TXCBLEND_0 21 /* tex0/4 */ +#define R200_EMIT_PP_TXCBLEND_1 22 /* tex1/4 */ +#define R200_EMIT_PP_TXCBLEND_2 23 /* tex2/4 */ +#define R200_EMIT_PP_TXCBLEND_3 24 /* tex3/4 */ +#define R200_EMIT_PP_TXCBLEND_4 25 /* tex4/4 */ +#define R200_EMIT_PP_TXCBLEND_5 26 /* tex5/4 */ +#define R200_EMIT_PP_TXCBLEND_6 27 /* /4 */ +#define R200_EMIT_PP_TXCBLEND_7 28 /* /4 */ +#define R200_EMIT_TCL_LIGHT_MODEL_CTL_0 29 /* tcl/6 */ +#define R200_EMIT_TFACTOR_0 30 /* tf/6 */ +#define R200_EMIT_VTX_FMT_0 31 /* vtx/4 */ +#define R200_EMIT_VAP_CTL 32 /* vap/1 */ +#define R200_EMIT_MATRIX_SELECT_0 33 /* msl/5 */ +#define R200_EMIT_TEX_PROC_CTL_2 34 /* tcg/5 */ +#define R200_EMIT_TCL_UCP_VERT_BLEND_CTL 35 /* tcl/1 */ +#define R200_EMIT_PP_TXFILTER_0 36 /* tex0/6 */ +#define R200_EMIT_PP_TXFILTER_1 37 /* tex1/6 */ +#define R200_EMIT_PP_TXFILTER_2 38 /* tex2/6 */ +#define R200_EMIT_PP_TXFILTER_3 39 /* tex3/6 */ +#define R200_EMIT_PP_TXFILTER_4 40 /* tex4/6 */ +#define R200_EMIT_PP_TXFILTER_5 41 /* tex5/6 */ +#define R200_EMIT_PP_TXOFFSET_0 42 /* tex0/1 */ +#define R200_EMIT_PP_TXOFFSET_1 43 /* tex1/1 */ +#define R200_EMIT_PP_TXOFFSET_2 44 /* tex2/1 */ +#define R200_EMIT_PP_TXOFFSET_3 45 /* tex3/1 */ +#define R200_EMIT_PP_TXOFFSET_4 46 /* tex4/1 */ +#define R200_EMIT_PP_TXOFFSET_5 47 /* tex5/1 */ +#define R200_EMIT_VTE_CNTL 48 /* vte/1 */ +#define R200_EMIT_OUTPUT_VTX_COMP_SEL 49 /* vtx/1 */ +#define R200_EMIT_PP_TAM_DEBUG3 50 /* tam/1 */ +#define R200_EMIT_PP_CNTL_X 51 /* cst/1 */ +#define R200_EMIT_RB3D_DEPTHXY_OFFSET 52 /* cst/1 */ +#define R200_EMIT_RE_AUX_SCISSOR_CNTL 53 /* cst/1 */ +#define R200_EMIT_RE_SCISSOR_TL_0 54 /* cst/2 */ +#define R200_EMIT_RE_SCISSOR_TL_1 55 /* cst/2 */ +#define R200_EMIT_RE_SCISSOR_TL_2 56 /* cst/2 */ +#define R200_EMIT_SE_VAP_CNTL_STATUS 57 /* cst/1 */ +#define R200_EMIT_SE_VTX_STATE_CNTL 58 /* cst/1 */ +#define R200_EMIT_RE_POINTSIZE 59 /* cst/1 */ +#define R200_EMIT_TCL_INPUT_VTX_VECTOR_ADDR_0 60 /* cst/4 */ +#define R200_EMIT_PP_CUBIC_FACES_0 61 +#define R200_EMIT_PP_CUBIC_OFFSETS_0 62 +#define R200_EMIT_PP_CUBIC_FACES_1 63 +#define R200_EMIT_PP_CUBIC_OFFSETS_1 64 +#define R200_EMIT_PP_CUBIC_FACES_2 65 +#define R200_EMIT_PP_CUBIC_OFFSETS_2 66 +#define R200_EMIT_PP_CUBIC_FACES_3 67 +#define R200_EMIT_PP_CUBIC_OFFSETS_3 68 +#define R200_EMIT_PP_CUBIC_FACES_4 69 +#define R200_EMIT_PP_CUBIC_OFFSETS_4 70 +#define R200_EMIT_PP_CUBIC_FACES_5 71 +#define R200_EMIT_PP_CUBIC_OFFSETS_5 72 +#define RADEON_EMIT_PP_TEX_SIZE_0 73 +#define RADEON_EMIT_PP_TEX_SIZE_1 74 +#define RADEON_EMIT_PP_TEX_SIZE_2 75 +#define RADEON_MAX_STATE_PACKETS 76 + + +/* Commands understood by cmd_buffer ioctl. More can be added but + * obviously these can't be removed or changed: */ +#define RADEON_CMD_PACKET 1 /* emit one of the register packets above */ +#define RADEON_CMD_SCALARS 2 /* emit scalar data */ +#define RADEON_CMD_VECTORS 3 /* emit vector data */ +#define RADEON_CMD_DMA_DISCARD 4 /* discard current dma buf */ +#define RADEON_CMD_PACKET3 5 /* emit hw packet */ +#define RADEON_CMD_PACKET3_CLIP 6 /* emit hw packet wrapped in cliprects */ +#define RADEON_CMD_SCALARS2 7 /* R200 stopgap */ +#define RADEON_CMD_WAIT 8 /* synchronization */ + typedef union { - /** \brief integer equivalent */ int i; - struct { unsigned char cmd_type, pad0, pad1, pad2; } header; - - /** \brief emit a register packet */ struct { unsigned char cmd_type, packet_id, pad0, pad1; } packet; - - /** \brief scalar data */ struct { unsigned char cmd_type, offset, stride, count; } scalars; - - /** \brief vector data */ struct { unsigned char cmd_type, offset, stride, count; } vectors; - - /** \brief discard current DMA buffer */ struct { unsigned char cmd_type, buf_idx, pad0, pad1; } dma; - - /** \brief synchronization */ struct { unsigned char cmd_type, flags, pad0, pad1; } wait; @@ -458,12 +398,10 @@ typedef union { #define RADEON_WAIT_2D 0x1 #define RADEON_WAIT_3D 0x2 -/** - * \brief DRM_RADEON_GETPARAM ioctl argument type. - */ + typedef struct drm_radeon_getparam { - int param; /**< \brief parameter number */ - int *value; /**< \brief parameter value */ + int param; + void *value; } drmRadeonGetParam; #define RADEON_PARAM_AGP_BUFFER_OFFSET 1 @@ -472,10 +410,6 @@ typedef struct drm_radeon_getparam { #define RADEON_PARAM_LAST_CLEAR 4 #define RADEON_PARAM_IRQ_NR 5 #define RADEON_PARAM_AGP_BASE 6 -#define RADEON_PARAM_REGISTER_HANDLE 7 -#define RADEON_PARAM_STATUS_HANDLE 8 -#define RADEON_PARAM_SAREA_HANDLE 9 -#define RADEON_PARAM_AGP_TEX_HANDLE 10 #define RADEON_MEM_REGION_AGP 1 @@ -493,29 +427,18 @@ typedef struct drm_radeon_mem_free { int region_offset; } drmRadeonMemFree; -/** - * \brief DRM_RADEON_INIT_HEAP argument type. - */ typedef struct drm_radeon_mem_init_heap { - int region; /**< \brief region type */ - int size; /**< \brief region size */ - int start; /**< \brief region start offset */ + int region; + int size; + int start; } drmRadeonMemInitHeap; -/** - * \brief DRM_RADEON_IRQ_EMIT ioctl argument type. - * - * New in DRM 1.6: userspace can request and wait on IRQ's. +/* 1.6: Userspace can request & wait on irq's: */ typedef struct drm_radeon_irq_emit { int *irq_seq; } drmRadeonIrqEmit; -/** - * \brief DRM_RADEON_IRQ_WAIT ioctl argument type. - * - * New in DRM 1.6: userspace can request and wait on IRQ's. - */ typedef struct drm_radeon_irq_wait { int irq_seq; } drmRadeonIrqWait; diff --git a/src/mesa/drivers/dri/radeon/server/radeon_dri.c b/src/mesa/drivers/dri/radeon/server/radeon_dri.c index f14bd13a95..4271aa7da2 100644 --- a/src/mesa/drivers/dri/radeon/server/radeon_dri.c +++ b/src/mesa/drivers/dri/radeon/server/radeon_dri.c @@ -12,6 +12,7 @@ #include <stdlib.h> #include <string.h> #include <errno.h> +#include <unistd.h> #include "driver.h" #include "drm.h" @@ -23,9 +24,6 @@ #include "radeon_sarea.h" #include "sarea.h" -#include <unistd.h> - - /* HACK - for now, put this here... */ /* Alpha - this may need to be a variable to handle UP1x00 vs TITAN */ @@ -735,7 +733,7 @@ static int RADEONMemoryInit( const DRIDriverContext *ctx, RADEONInfoPtr info ) * Setups a RADEONDRIRec structure to be passed to radeon_dri.so for its * initialization. */ -static int RADEONScreenInit( DRIDriverContext *ctx, RADEONInfoPtr info ) +static int RADEONScreenInit( const DRIDriverContext *ctx, RADEONInfoPtr info ) { RADEONDRIPtr pRADEONDRI; int err; diff --git a/src/mesa/drivers/dri/radeon/server/radeon_reg.h b/src/mesa/drivers/dri/radeon/server/radeon_reg.h index 2cd9dbe094..5570a43945 100644 --- a/src/mesa/drivers/dri/radeon/server/radeon_reg.h +++ b/src/mesa/drivers/dri/radeon/server/radeon_reg.h @@ -1,24 +1,4 @@ -/** - * \file server/radeon_reg.h - * \brief Registers and register definitions for the Radeon. - * - * \authors Kevin E. Martin <martin@xfree86.org> - * \authors Rickard E. Faith <faith@valinux.com> - * \authors Alan Hourihane <alanh@fairlite.demon.co.uk> - * - * \par References - * - * - RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical - * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April - * 1999. - * - RAGE 128 Software Development Manual (Technical Reference Manual P/N - * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. - * - * \note !!!! FIXME !!!! THIS FILE HAS BEEN CONVERTED FROM r128_reg.h - * AND CONTAINS REGISTERS AND REGISTER DEFINITIONS THAT ARE NOT CORRECT - * ON THE RADEON. A FULL AUDIT OF THIS CODE IS NEEDED! - */ - +/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_reg.h,v 1.25 2003/02/07 18:08:59 martin Exp $ */ /* * Copyright 2000 ATI Technologies Inc., Markham, Ontario, and * VA Linux Systems Inc., Fremont, California. @@ -47,7 +27,28 @@ * DEALINGS IN THE SOFTWARE. */ -/* $XFree86: xc/programs/Xserver/hw/xfree86/drivers/ati/radeon_reg.h,v 1.20 2002/10/12 01:38:07 martin Exp $ */ +/* + * Authors: + * Kevin E. Martin <martin@xfree86.org> + * Rickard E. Faith <faith@valinux.com> + * Alan Hourihane <alanh@fairlite.demon.co.uk> + * + * References: + * + * !!!! FIXME !!!! + * RAGE 128 VR/ RAGE 128 GL Register Reference Manual (Technical + * Reference Manual P/N RRG-G04100-C Rev. 0.04), ATI Technologies: April + * 1999. + * + * !!!! FIXME !!!! + * RAGE 128 Software Development Manual (Technical Reference Manual P/N + * SDK-G04000 Rev. 0.01), ATI Technologies: June 1999. + * + */ + +/* !!!! FIXME !!!! NOTE: THIS FILE HAS BEEN CONVERTED FROM r128_reg.h + * AND CONTAINS REGISTERS AND REGISTER DEFINITIONS THAT ARE NOT CORRECT + * ON THE RADEON. A FULL AUDIT OF THIS CODE IS NEEDED! */ #ifndef _RADEON_REG_H_ #define _RADEON_REG_H_ @@ -216,6 +217,10 @@ #define RADEON_CONFIG_APER_SIZE 0x0108 #define RADEON_CONFIG_BONDS 0x00e8 #define RADEON_CONFIG_CNTL 0x00e0 +# define RADEON_CFG_ATI_REV_A11 (0 << 16) +# define RADEON_CFG_ATI_REV_A12 (1 << 16) +# define RADEON_CFG_ATI_REV_A13 (2 << 16) +# define RADEON_CFG_ATI_REV_ID_MASK (0xf << 16) #define RADEON_CONFIG_MEMSIZE 0x00f8 #define RADEON_CONFIG_MEMSIZE_EMBEDDED 0x0114 #define RADEON_CONFIG_REG_1_BASE 0x010c @@ -302,6 +307,10 @@ #define RADEON_CRTC2_PITCH 0x032c #define RADEON_CRTC_STATUS 0x005c # define RADEON_CRTC_VBLANK_SAVE (1 << 1) +# define RADEON_CRTC_VBLANK_SAVE_CLEAR (1 << 1) +#define RADEON_CRTC2_STATUS 0x03fc +# define RADEON_CRTC2_VBLANK_SAVE (1 << 1) +# define RADEON_CRTC2_VBLANK_SAVE_CLEAR (1 << 1) #define RADEON_CRTC_V_SYNC_STRT_WID 0x020c # define RADEON_CRTC_V_SYNC_STRT (0x7ff << 0) # define RADEON_CRTC_V_SYNC_STRT_SHIFT 0 @@ -492,6 +501,7 @@ #define RADEON_DST_LINE_START 0x1600 #define RADEON_DST_LINE_END 0x1604 #define RADEON_DST_LINE_PATCOUNT 0x1608 +# define RADEON_BRES_CNTL_SHIFT 8 #define RADEON_DST_OFFSET 0x1404 #define RADEON_DST_PITCH 0x1408 #define RADEON_DST_PITCH_OFFSET 0x142c @@ -554,6 +564,7 @@ #define RADEON_FP_GEN_CNTL 0x0284 # define RADEON_FP_FPON (1 << 0) # define RADEON_FP_TMDS_EN (1 << 2) +# define RADEON_FP_PANEL_FORMAT (1 << 3) # define RADEON_FP_EN_TMDS (1 << 7) # define RADEON_FP_DETECT_SENSE (1 << 8) # define RADEON_FP_SEL_CRTC2 (1 << 13) @@ -612,6 +623,8 @@ #define RADEON_GEN_INT_STATUS 0x0044 # define RADEON_VSYNC_INT_AK (1 << 2) # define RADEON_VSYNC_INT (1 << 2) +# define RADEON_VSYNC2_INT_AK (1 << 6) +# define RADEON_VSYNC2_INT (1 << 6) #define RADEON_GENENB 0x03c3 /* VGA */ #define RADEON_GENFC_RD 0x03ca /* VGA */ #define RADEON_GENFC_WT 0x03da /* VGA, 0x03ba */ @@ -708,6 +721,9 @@ #define RADEON_MM_DATA 0x0004 #define RADEON_MM_INDEX 0x0000 #define RADEON_MPLL_CNTL 0x000e /* PLL */ +#define RADEON_MPP_TB_CONFIG 0x01c0 /* ? */ +#define RADEON_MPP_GP_CONFIG 0x01c8 /* ? */ + #define RADEON_N_VIF_COUNT 0x0248 @@ -863,6 +879,8 @@ # define RADEON_P2PLL_REF_DIV_MASK 0x03ff # define RADEON_P2PLL_ATOMIC_UPDATE_R (1 << 15) /* same as _W */ # define RADEON_P2PLL_ATOMIC_UPDATE_W (1 << 15) /* same as _R */ +# define R300_PPLL_REF_DIV_ACC_MASK (0x3ff < 18) +# define R300_PPLL_REF_DIV_ACC_SHIFT 18 #define RADEON_PALETTE_DATA 0x00b4 #define RADEON_PALETTE_30_DATA 0x00b8 #define RADEON_PALETTE_INDEX 0x00b0 @@ -1122,6 +1140,10 @@ # define RADEON_LOD_BIAS_SHIFT 8 # define RADEON_MAX_MIP_LEVEL_MASK (0x0f << 16) # define RADEON_MAX_MIP_LEVEL_SHIFT 16 +# define RADEON_YUV_TO_RGB (1 << 20) +# define RADEON_YUV_TEMPERATURE_COOL (0 << 21) +# define RADEON_YUV_TEMPERATURE_HOT (1 << 21) +# define RADEON_YUV_TEMPERATURE_MASK (1 << 21) # define RADEON_WRAPEN_S (1 << 22) # define RADEON_CLAMP_S_WRAP (0 << 23) # define RADEON_CLAMP_S_MIRROR (1 << 23) @@ -1129,6 +1151,8 @@ # define RADEON_CLAMP_S_MIRROR_CLAMP_LAST (3 << 23) # define RADEON_CLAMP_S_CLAMP_BORDER (4 << 23) # define RADEON_CLAMP_S_MIRROR_CLAMP_BORDER (5 << 23) +# define RADEON_CLAMP_S_CLAMP_GL (6 << 23) +# define RADEON_CLAMP_S_MIRROR_CLAMP_GL (7 << 23) # define RADEON_CLAMP_S_MASK (7 << 23) # define RADEON_WRAPEN_T (1 << 26) # define RADEON_CLAMP_T_WRAP (0 << 27) @@ -1137,6 +1161,8 @@ # define RADEON_CLAMP_T_MIRROR_CLAMP_LAST (3 << 27) # define RADEON_CLAMP_T_CLAMP_BORDER (4 << 27) # define RADEON_CLAMP_T_MIRROR_CLAMP_BORDER (5 << 27) +# define RADEON_CLAMP_T_CLAMP_GL (6 << 27) +# define RADEON_CLAMP_T_MIRROR_CLAMP_GL (7 << 27) # define RADEON_CLAMP_T_MASK (7 << 27) # define RADEON_BORDER_MODE_OGL (0 << 31) # define RADEON_BORDER_MODE_D3D (1 << 31) @@ -1152,6 +1178,11 @@ # define RADEON_TXFORMAT_ARGB8888 (6 << 0) # define RADEON_TXFORMAT_RGBA8888 (7 << 0) # define RADEON_TXFORMAT_Y8 (8 << 0) +# define RADEON_TXFORMAT_VYUY422 (10 << 0) +# define RADEON_TXFORMAT_YVYU422 (11 << 0) +# define RADEON_TXFORMAT_DXT1 (12 << 0) +# define RADEON_TXFORMAT_DXT23 (14 << 0) +# define RADEON_TXFORMAT_DXT45 (15 << 0) # define RADEON_TXFORMAT_FORMAT_MASK (31 << 0) # define RADEON_TXFORMAT_FORMAT_SHIFT 0 # define RADEON_TXFORMAT_APPLE_YUV_MODE (1 << 5) @@ -1161,6 +1192,10 @@ # define RADEON_TXFORMAT_WIDTH_SHIFT 8 # define RADEON_TXFORMAT_HEIGHT_MASK (15 << 12) # define RADEON_TXFORMAT_HEIGHT_SHIFT 12 +# define RADEON_TXFORMAT_F5_WIDTH_MASK (15 << 16) +# define RADEON_TXFORMAT_F5_WIDTH_SHIFT 16 +# define RADEON_TXFORMAT_F5_HEIGHT_MASK (15 << 20) +# define RADEON_TXFORMAT_F5_HEIGHT_SHIFT 20 # define RADEON_TXFORMAT_ST_ROUTE_STQ0 (0 << 24) # define RADEON_TXFORMAT_ST_ROUTE_MASK (3 << 24) # define RADEON_TXFORMAT_ST_ROUTE_STQ1 (1 << 24) @@ -1173,6 +1208,26 @@ # define RADEON_TXFORMAT_CHROMA_KEY_ENABLE (1 << 29) # define RADEON_TXFORMAT_CUBIC_MAP_ENABLE (1 << 30) # define RADEON_TXFORMAT_PERSPECTIVE_ENABLE (1 << 31) +#define RADEON_PP_CUBIC_FACES_0 0x1d24 +#define RADEON_PP_CUBIC_FACES_1 0x1d28 +#define RADEON_PP_CUBIC_FACES_2 0x1d2c +# define RADEON_FACE_WIDTH_1_SHIFT 0 +# define RADEON_FACE_HEIGHT_1_SHIFT 4 +# define RADEON_FACE_WIDTH_1_MASK (0xf << 0) +# define RADEON_FACE_HEIGHT_1_MASK (0xf << 4) +# define RADEON_FACE_WIDTH_2_SHIFT 8 +# define RADEON_FACE_HEIGHT_2_SHIFT 12 +# define RADEON_FACE_WIDTH_2_MASK (0xf << 8) +# define RADEON_FACE_HEIGHT_2_MASK (0xf << 12) +# define RADEON_FACE_WIDTH_3_SHIFT 16 +# define RADEON_FACE_HEIGHT_3_SHIFT 20 +# define RADEON_FACE_WIDTH_3_MASK (0xf << 16) +# define RADEON_FACE_HEIGHT_3_MASK (0xf << 20) +# define RADEON_FACE_WIDTH_4_SHIFT 24 +# define RADEON_FACE_HEIGHT_4_SHIFT 28 +# define RADEON_FACE_WIDTH_4_MASK (0xf << 24) +# define RADEON_FACE_HEIGHT_4_MASK (0xf << 28) + #define RADEON_PP_TXOFFSET_0 0x1c5c #define RADEON_PP_TXOFFSET_1 0x1c74 #define RADEON_PP_TXOFFSET_2 0x1c8c @@ -1187,6 +1242,39 @@ # define RADEON_TXO_MICRO_TILE_OPT (2 << 3) # define RADEON_TXO_OFFSET_MASK 0xffffffe0 # define RADEON_TXO_OFFSET_SHIFT 5 + +#define RADEON_PP_CUBIC_OFFSET_T0_0 0x1dd0 /* bits [31:5] */ +#define RADEON_PP_CUBIC_OFFSET_T0_1 0x1dd4 +#define RADEON_PP_CUBIC_OFFSET_T0_2 0x1dd8 +#define RADEON_PP_CUBIC_OFFSET_T0_3 0x1ddc +#define RADEON_PP_CUBIC_OFFSET_T0_4 0x1de0 +#define RADEON_PP_CUBIC_OFFSET_T1_0 0x1e00 +#define RADEON_PP_CUBIC_OFFSET_T1_1 0x1e04 +#define RADEON_PP_CUBIC_OFFSET_T1_2 0x1e08 +#define RADEON_PP_CUBIC_OFFSET_T1_3 0x1e0c +#define RADEON_PP_CUBIC_OFFSET_T1_4 0x1e10 +#define RADEON_PP_CUBIC_OFFSET_T2_0 0x1e14 +#define RADEON_PP_CUBIC_OFFSET_T2_1 0x1e18 +#define RADEON_PP_CUBIC_OFFSET_T2_2 0x1e1c +#define RADEON_PP_CUBIC_OFFSET_T2_3 0x1e20 +#define RADEON_PP_CUBIC_OFFSET_T2_4 0x1e24 + +#define RADEON_PP_TEX_SIZE_0 0x1d04 /* NPOT */ +#define RADEON_PP_TEX_SIZE_1 0x1d0c +#define RADEON_PP_TEX_SIZE_2 0x1d14 +# define RADEON_TEX_USIZE_MASK (0x7ff << 0) +# define RADEON_TEX_USIZE_SHIFT 0 +# define RADEON_TEX_VSIZE_MASK (0x7ff << 16) +# define RADEON_TEX_VSIZE_SHIFT 16 +# define RADEON_SIGNED_RGB_MASK (1 << 30) +# define RADEON_SIGNED_RGB_SHIFT 30 +# define RADEON_SIGNED_ALPHA_MASK (1 << 31) +# define RADEON_SIGNED_ALPHA_SHIFT 31 +#define RADEON_PP_TEX_PITCH_0 0x1d08 /* NPOT */ +#define RADEON_PP_TEX_PITCH_1 0x1d10 /* NPOT */ +#define RADEON_PP_TEX_PITCH_2 0x1d18 /* NPOT */ +/* note: bits 13-5: 32 byte aligned stride of texture map */ + #define RADEON_PP_TXCBLEND_0 0x1c60 #define RADEON_PP_TXCBLEND_1 0x1c78 #define RADEON_PP_TXCBLEND_2 0x1c90 diff --git a/src/mesa/drivers/dri/radeon/server/radeon_sarea.h b/src/mesa/drivers/dri/radeon/server/radeon_sarea.h index f682bb6b6a..81e4325d7a 100644 --- a/src/mesa/drivers/dri/radeon/server/radeon_sarea.h +++ b/src/mesa/drivers/dri/radeon/server/radeon_sarea.h @@ -296,9 +296,9 @@ typedef struct { /** \brief Texture regions. * Last element is sentinal */ - radeon_tex_region_t texList[RADEON_NR_TEX_HEAPS][RADEON_NR_TEX_REGIONS+1]; + drmTextureRegion texList[RADEON_NR_TEX_HEAPS][RADEON_NR_TEX_REGIONS+1]; /** \brief last time texture was uploaded */ - int texAge[RADEON_NR_TEX_HEAPS]; + unsigned int texAge[RADEON_NR_TEX_HEAPS]; /*@}*/ int ctxOwner; /**< \brief last context to upload state */ |