aboutsummaryrefslogtreecommitdiff
path: root/nx-X11/extras/Mesa/src/mesa/drivers/dri/r300/r300_state.c
diff options
context:
space:
mode:
Diffstat (limited to 'nx-X11/extras/Mesa/src/mesa/drivers/dri/r300/r300_state.c')
-rw-r--r--nx-X11/extras/Mesa/src/mesa/drivers/dri/r300/r300_state.c2321
1 files changed, 2321 insertions, 0 deletions
diff --git a/nx-X11/extras/Mesa/src/mesa/drivers/dri/r300/r300_state.c b/nx-X11/extras/Mesa/src/mesa/drivers/dri/r300/r300_state.c
new file mode 100644
index 000000000..b6a03a227
--- /dev/null
+++ b/nx-X11/extras/Mesa/src/mesa/drivers/dri/r300/r300_state.c
@@ -0,0 +1,2321 @@
+/*
+Copyright (C) The Weather Channel, Inc. 2002.
+Copyright (C) 2004 Nicolai Haehnle.
+All Rights Reserved.
+
+The Weather Channel (TM) funded Tungsten Graphics to develop the
+initial release of the Radeon 8500 driver under the XFree86 license.
+This notice must be preserved.
+
+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:
+ * Nicolai Haehnle <prefect_@gmx.net>
+ */
+
+#include "glheader.h"
+#include "state.h"
+#include "imports.h"
+#include "enums.h"
+#include "macros.h"
+#include "context.h"
+#include "dd.h"
+#include "simple_list.h"
+
+#include "api_arrayelt.h"
+#include "swrast/swrast.h"
+#include "swrast_setup/swrast_setup.h"
+#include "array_cache/acache.h"
+#include "tnl/tnl.h"
+#include "texformat.h"
+
+#include "radeon_ioctl.h"
+#include "radeon_state.h"
+#include "r300_context.h"
+#include "r300_ioctl.h"
+#include "r300_state.h"
+#include "r300_reg.h"
+#include "r300_program.h"
+#include "r300_emit.h"
+#if USE_ARB_F_P == 1
+#include "r300_fragprog.h"
+#else
+#include "r300_fixed_pipelines.h"
+#include "r300_texprog.h"
+#endif
+#include "r300_tex.h"
+#include "r300_maos.h"
+
+static void r300AlphaFunc(GLcontext * ctx, GLenum func, GLfloat ref)
+{
+ r300ContextPtr rmesa = R300_CONTEXT(ctx);
+ int pp_misc = rmesa->hw.at.cmd[R300_AT_ALPHA_TEST];
+ GLubyte refByte;
+
+ CLAMPED_FLOAT_TO_UBYTE(refByte, ref);
+
+ R300_STATECHANGE(rmesa, at);
+
+ pp_misc &= ~(R300_ALPHA_TEST_OP_MASK | R300_REF_ALPHA_MASK);
+ pp_misc |= (refByte & R300_REF_ALPHA_MASK);
+
+ switch (func) {
+ case GL_NEVER:
+ pp_misc |= R300_ALPHA_TEST_FAIL;
+ break;
+ case GL_LESS:
+ pp_misc |= R300_ALPHA_TEST_LESS;
+ break;
+ case GL_EQUAL:
+ pp_misc |= R300_ALPHA_TEST_EQUAL;
+ break;
+ case GL_LEQUAL:
+ pp_misc |= R300_ALPHA_TEST_LEQUAL;
+ break;
+ case GL_GREATER:
+ pp_misc |= R300_ALPHA_TEST_GREATER;
+ break;
+ case GL_NOTEQUAL:
+ pp_misc |= R300_ALPHA_TEST_NEQUAL;
+ break;
+ case GL_GEQUAL:
+ pp_misc |= R300_ALPHA_TEST_GEQUAL;
+ break;
+ case GL_ALWAYS:
+ pp_misc |= R300_ALPHA_TEST_PASS;
+ //pp_misc &= ~R300_ALPHA_TEST_ENABLE;
+ break;
+ }
+
+ rmesa->hw.at.cmd[R300_AT_ALPHA_TEST] = pp_misc;
+}
+
+static void r300BlendColor(GLcontext * ctx, const GLfloat cf[4])
+{
+ GLubyte color[4];
+ r300ContextPtr rmesa = R300_CONTEXT(ctx);
+
+ R300_STATECHANGE(rmesa, unk4E10);
+
+ /* Ordering might be wrong */
+ CLAMPED_FLOAT_TO_UBYTE(color[0], cf[0]);
+ CLAMPED_FLOAT_TO_UBYTE(color[1], cf[1]);
+ CLAMPED_FLOAT_TO_UBYTE(color[2], cf[2]);
+ CLAMPED_FLOAT_TO_UBYTE(color[3], cf[3]);
+
+ rmesa->hw.unk4E10.cmd[1]=r300PackColor(4, color[0], color[1], color[2], color[3]);
+}
+
+/**
+ * Calculate the hardware blend factor setting. This same function is used
+ * for source and destination of both alpha and RGB.
+ *
+ * \returns
+ * The hardware register value for the specified blend factor. This value
+ * will need to be shifted into the correct position for either source or
+ * destination factor.
+ *
+ * \todo
+ * Since the two cases where source and destination are handled differently
+ * are essentially error cases, they should never happen. Determine if these
+ * cases can be removed.
+ */
+static int blend_factor(GLenum factor, GLboolean is_src)
+{
+ int func;
+
+ switch (factor) {
+ case GL_ZERO:
+ func = R200_BLEND_GL_ZERO;
+ break;
+ case GL_ONE:
+ func = R200_BLEND_GL_ONE;
+ break;
+ case GL_DST_COLOR:
+ func = R200_BLEND_GL_DST_COLOR;
+ break;
+ case GL_ONE_MINUS_DST_COLOR:
+ func = R200_BLEND_GL_ONE_MINUS_DST_COLOR;
+ break;
+ case GL_SRC_COLOR:
+ func = R200_BLEND_GL_SRC_COLOR;
+ break;
+ case GL_ONE_MINUS_SRC_COLOR:
+ func = R200_BLEND_GL_ONE_MINUS_SRC_COLOR;
+ break;
+ case GL_SRC_ALPHA:
+ func = R200_BLEND_GL_SRC_ALPHA;
+ break;
+ case GL_ONE_MINUS_SRC_ALPHA:
+ func = R200_BLEND_GL_ONE_MINUS_SRC_ALPHA;
+ break;
+ case GL_DST_ALPHA:
+ func = R200_BLEND_GL_DST_ALPHA;
+ break;
+ case GL_ONE_MINUS_DST_ALPHA:
+ func = R200_BLEND_GL_ONE_MINUS_DST_ALPHA;
+ break;
+ case GL_SRC_ALPHA_SATURATE:
+ func =
+ (is_src) ? R200_BLEND_GL_SRC_ALPHA_SATURATE :
+ R200_BLEND_GL_ZERO;
+ break;
+ case GL_CONSTANT_COLOR:
+ func = R200_BLEND_GL_CONST_COLOR;
+ break;
+ case GL_ONE_MINUS_CONSTANT_COLOR:
+ func = R200_BLEND_GL_ONE_MINUS_CONST_COLOR;
+ break;
+ case GL_CONSTANT_ALPHA:
+ func = R200_BLEND_GL_CONST_ALPHA;
+ break;
+ case GL_ONE_MINUS_CONSTANT_ALPHA:
+ func = R200_BLEND_GL_ONE_MINUS_CONST_ALPHA;
+ break;
+ default:
+ func = (is_src) ? R200_BLEND_GL_ONE : R200_BLEND_GL_ZERO;
+ }
+ return func;
+}
+
+/**
+ * Sets both the blend equation and the blend function.
+ * This is done in a single
+ * function because some blend equations (i.e., \c GL_MIN and \c GL_MAX)
+ * change the interpretation of the blend function.
+ * Also, make sure that blend function and blend equation are set to their default
+ * value if color blending is not enabled, since at least blend equations GL_MIN
+ * and GL_FUNC_REVERSE_SUBTRACT will cause wrong results otherwise for
+ * unknown reasons.
+ */
+
+/* helper function */
+static void r300_set_blend_cntl(r300ContextPtr r300, int func, int eqn, int cbits, int funcA, int eqnA)
+{
+ GLuint new_ablend, new_cblend;
+
+#if 0
+ fprintf(stderr, "eqnA=%08x funcA=%08x eqn=%08x func=%08x cbits=%08x\n", eqnA, funcA, eqn, func, cbits);
+#endif
+ new_ablend = eqnA | funcA;
+ new_cblend = eqn | func;
+
+ /* Some blend factor combinations don't seem to work when the
+ * BLEND_NO_SEPARATE bit is set.
+ *
+ * Especially problematic candidates are the ONE_MINUS_* flags,
+ * but I can't see a real pattern.
+ */
+#if 0
+ if (new_ablend == new_cblend) {
+ new_cblend |= R300_BLEND_NO_SEPARATE;
+ }
+#endif
+ new_cblend |= cbits;
+
+ if((new_ablend != r300->hw.bld.cmd[R300_BLD_ABLEND]) ||
+ (new_cblend != r300->hw.bld.cmd[R300_BLD_CBLEND])) {
+ R300_STATECHANGE(r300, bld);
+ r300->hw.bld.cmd[R300_BLD_ABLEND]=new_ablend;
+ r300->hw.bld.cmd[R300_BLD_CBLEND]=new_cblend;
+ }
+}
+
+
+static void r300_set_blend_state(GLcontext * ctx)
+{
+ r300ContextPtr r300 = R300_CONTEXT(ctx);
+ int func = (R200_BLEND_GL_ONE << R200_SRC_BLEND_SHIFT) |
+ (R200_BLEND_GL_ZERO << R200_DST_BLEND_SHIFT);
+ int eqn = R200_COMB_FCN_ADD_CLAMP;
+ int funcA = (R200_BLEND_GL_ONE << R200_SRC_BLEND_SHIFT) |
+ (R200_BLEND_GL_ZERO << R200_DST_BLEND_SHIFT);
+ int eqnA = R200_COMB_FCN_ADD_CLAMP;
+
+ if (ctx->Color._LogicOpEnabled || !ctx->Color.BlendEnabled) {
+ r300_set_blend_cntl(r300,
+ func, eqn, 0,
+ func, eqn);
+ return;
+ }
+
+ func = (blend_factor(ctx->Color.BlendSrcRGB, GL_TRUE) << R200_SRC_BLEND_SHIFT) |
+ (blend_factor(ctx->Color.BlendDstRGB, GL_FALSE) << R200_DST_BLEND_SHIFT);
+
+ switch (ctx->Color.BlendEquationRGB) {
+ case GL_FUNC_ADD:
+ eqn = R300_COMB_FCN_ADD_CLAMP;
+ break;
+
+ case GL_FUNC_SUBTRACT:
+ eqn = R300_COMB_FCN_SUB_CLAMP;
+ break;
+
+ case GL_FUNC_REVERSE_SUBTRACT:
+ eqn = R200_COMB_FCN_RSUB_CLAMP;
+ break;
+
+ case GL_MIN:
+ eqn = R200_COMB_FCN_MIN;
+ func = (R200_BLEND_GL_ONE << R200_SRC_BLEND_SHIFT) |
+ (R200_BLEND_GL_ONE << R200_DST_BLEND_SHIFT);
+ break;
+
+ case GL_MAX:
+ eqn = R200_COMB_FCN_MAX;
+ func = (R200_BLEND_GL_ONE << R200_SRC_BLEND_SHIFT) |
+ (R200_BLEND_GL_ONE << R200_DST_BLEND_SHIFT);
+ break;
+
+ default:
+ fprintf(stderr,
+ "[%s:%u] Invalid RGB blend equation (0x%04x).\n",
+ __func__, __LINE__, ctx->Color.BlendEquationRGB);
+ return;
+ }
+
+
+ funcA = (blend_factor(ctx->Color.BlendSrcA, GL_TRUE) << R200_SRC_BLEND_SHIFT) |
+ (blend_factor(ctx->Color.BlendDstA, GL_FALSE) << R200_DST_BLEND_SHIFT);
+
+ switch (ctx->Color.BlendEquationA) {
+ case GL_FUNC_ADD:
+ eqnA = R300_COMB_FCN_ADD_CLAMP;
+ break;
+
+ case GL_FUNC_SUBTRACT:
+ eqnA = R300_COMB_FCN_SUB_CLAMP;
+ break;
+
+ case GL_FUNC_REVERSE_SUBTRACT:
+ eqnA = R200_COMB_FCN_RSUB_CLAMP;
+ break;
+
+ case GL_MIN:
+ eqnA = R200_COMB_FCN_MIN;
+ funcA = (R200_BLEND_GL_ONE << R200_SRC_BLEND_SHIFT) |
+ (R200_BLEND_GL_ONE << R200_DST_BLEND_SHIFT);
+ break;
+
+ case GL_MAX:
+ eqnA = R200_COMB_FCN_MAX;
+ funcA = (R200_BLEND_GL_ONE << R200_SRC_BLEND_SHIFT) |
+ (R200_BLEND_GL_ONE << R200_DST_BLEND_SHIFT);
+ break;
+
+ default:
+ fprintf(stderr, "[%s:%u] Invalid A blend equation (0x%04x).\n",
+ __func__, __LINE__, ctx->Color.BlendEquationA);
+ return;
+ }
+
+ r300_set_blend_cntl(r300,
+ func, eqn, R300_BLEND_UNKNOWN | R300_BLEND_ENABLE,
+ funcA, eqnA);
+}
+
+static void r300BlendEquationSeparate(GLcontext * ctx,
+ GLenum modeRGB, GLenum modeA)
+{
+ r300_set_blend_state(ctx);
+}
+
+static void r300BlendFuncSeparate(GLcontext * ctx,
+ GLenum sfactorRGB, GLenum dfactorRGB,
+ GLenum sfactorA, GLenum dfactorA)
+{
+ r300_set_blend_state(ctx);
+}
+
+/**
+ * Update our tracked culling state based on Mesa's state.
+ */
+static void r300UpdateCulling(GLcontext* ctx)
+{
+ r300ContextPtr r300 = R300_CONTEXT(ctx);
+ uint32_t val = 0;
+
+ R300_STATECHANGE(r300, cul);
+ if (ctx->Polygon.CullFlag) {
+ if (ctx->Polygon.CullFaceMode == GL_FRONT_AND_BACK)
+ val = R300_CULL_FRONT|R300_CULL_BACK;
+ else if (ctx->Polygon.CullFaceMode == GL_FRONT)
+ val = R300_CULL_FRONT;
+ else
+ val = R300_CULL_BACK;
+
+ if (ctx->Polygon.FrontFace == GL_CW)
+ val |= R300_FRONT_FACE_CW;
+ else
+ val |= R300_FRONT_FACE_CCW;
+ }
+ r300->hw.cul.cmd[R300_CUL_CULL] = val;
+}
+
+static void update_early_z(GLcontext* ctx)
+{
+ /* updates register 0x4f14
+ if depth test is not enabled it should be 0x00000000
+ if depth is enabled and alpha not it should be 0x00000001
+ if depth and alpha is enabled it should be 0x00000000
+ */
+ r300ContextPtr r300 = R300_CONTEXT(ctx);
+
+ R300_STATECHANGE(r300, unk4F10);
+ if (ctx->Color.AlphaEnabled)
+ /* disable early Z */
+ r300->hw.unk4F10.cmd[2] = 0x00000000;
+ else {
+ if (ctx->Depth.Test)
+ /* enable early Z */
+ r300->hw.unk4F10.cmd[2] = 0x00000001;
+ else
+ /* disable early Z */
+ r300->hw.unk4F10.cmd[2] = 0x00000000;
+ }
+}
+
+/**
+ * Handle glEnable()/glDisable().
+ *
+ * \note Mesa already filters redundant calls to glEnable/glDisable.
+ */
+static void r300Enable(GLcontext* ctx, GLenum cap, GLboolean state)
+{
+ r300ContextPtr r300 = R300_CONTEXT(ctx);
+ uint32_t newval;
+
+ 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:
+ R300_STATECHANGE(r300, at);
+ if (state) {
+ r300->hw.at.cmd[R300_AT_ALPHA_TEST] |=
+ R300_ALPHA_TEST_ENABLE;
+ } else {
+ r300->hw.at.cmd[R300_AT_ALPHA_TEST] &=
+ ~R300_ALPHA_TEST_ENABLE;
+ }
+ update_early_z(ctx);
+ break;
+
+ case GL_BLEND:
+ case GL_COLOR_LOGIC_OP:
+ r300_set_blend_state(ctx);
+ break;
+
+ case GL_DEPTH_TEST:
+ R300_STATECHANGE(r300, zs);
+
+ if (state) {
+ if (ctx->Depth.Mask)
+ newval = R300_RB3D_Z_TEST_AND_WRITE;
+ else
+ newval = R300_RB3D_Z_TEST;
+ } else
+ newval = R300_RB3D_Z_DISABLED_1;
+
+ r300->hw.zs.cmd[R300_ZS_CNTL_0] &= R300_RB3D_STENCIL_ENABLE;
+ r300->hw.zs.cmd[R300_ZS_CNTL_0] |= newval;
+ update_early_z(ctx);
+ break;
+
+ case GL_STENCIL_TEST:
+ WARN_ONCE("TODO - double side stencil !\n");
+ if (r300->state.stencil.hw_stencil) {
+ R300_STATECHANGE(r300, zs);
+ if (state) {
+ r300->hw.zs.cmd[R300_ZS_CNTL_0] |=
+ R300_RB3D_STENCIL_ENABLE;
+ } else {
+ r300->hw.zs.cmd[R300_ZS_CNTL_0] &=
+ ~R300_RB3D_STENCIL_ENABLE;
+ }
+ } else {
+#if R200_MERGED
+ FALLBACK(&r300->radeon, RADEON_FALLBACK_STENCIL, state);
+#endif
+ }
+ break;
+
+ case GL_CULL_FACE:
+ r300UpdateCulling(ctx);
+ break;
+
+ case GL_POLYGON_OFFSET_POINT:
+ case GL_POLYGON_OFFSET_LINE:
+ break;
+
+ case GL_POLYGON_OFFSET_FILL:
+ R300_STATECHANGE(r300, unk42B4);
+ if(state){
+ r300->hw.unk42B4.cmd[1] |= (3<<0);
+ } else {
+ r300->hw.unk42B4.cmd[1] &= ~(3<<0);
+ }
+ break;
+ default:
+ radeonEnable(ctx, cap, state);
+ return;
+ }
+}
+
+
+static void r300UpdatePolygonMode(GLcontext *ctx)
+{
+ r300ContextPtr r300 = R300_CONTEXT(ctx);
+ uint32_t hw_mode=0;
+
+ if (ctx->Polygon.FrontMode != GL_FILL ||
+ ctx->Polygon.BackMode != GL_FILL) {
+ GLenum f, b;
+
+ if (ctx->Polygon.FrontFace == GL_CCW) {
+ f = ctx->Polygon.FrontMode;
+ b = ctx->Polygon.BackMode;
+ } else {
+ f = ctx->Polygon.BackMode;
+ b = ctx->Polygon.FrontMode;
+ }
+
+ hw_mode |= R300_PM_ENABLED;
+
+ switch (f) {
+ case GL_LINE:
+ hw_mode |= R300_PM_FRONT_LINE;
+ break;
+ case GL_POINT: /* noop */
+ hw_mode |= R300_PM_FRONT_POINT;
+ break;
+ case GL_FILL:
+ hw_mode |= R300_PM_FRONT_FILL;
+ break;
+ }
+
+ switch (b) {
+ case GL_LINE:
+ hw_mode |= R300_PM_BACK_LINE;
+ break;
+ case GL_POINT: /* noop */
+ hw_mode |= R300_PM_BACK_POINT;
+ break;
+ case GL_FILL:
+ hw_mode |= R300_PM_BACK_FILL;
+ break;
+ }
+ }
+
+ if (r300->hw.unk4288.cmd[1] != hw_mode) {
+ R300_STATECHANGE(r300, unk4288);
+ r300->hw.unk4288.cmd[1] = hw_mode;
+ }
+}
+
+/**
+ * Change the culling mode.
+ *
+ * \note Mesa already filters redundant calls to this function.
+ */
+static void r300CullFace(GLcontext* ctx, GLenum mode)
+{
+ (void)mode;
+
+ r300UpdateCulling(ctx);
+}
+
+
+/**
+ * Change the polygon orientation.
+ *
+ * \note Mesa already filters redundant calls to this function.
+ */
+static void r300FrontFace(GLcontext* ctx, GLenum mode)
+{
+ (void)mode;
+
+ r300UpdateCulling(ctx);
+ r300UpdatePolygonMode(ctx);
+}
+
+
+/**
+ * Change the depth testing function.
+ *
+ * \note Mesa already filters redundant calls to this function.
+ */
+static void r300DepthFunc(GLcontext* ctx, GLenum func)
+{
+ r300ContextPtr r300 = R300_CONTEXT(ctx);
+
+ R300_STATECHANGE(r300, zs);
+
+ r300->hw.zs.cmd[R300_ZS_CNTL_1] &= ~(R300_ZS_MASK << R300_RB3D_ZS1_DEPTH_FUNC_SHIFT);
+
+ switch(func) {
+ case GL_NEVER:
+ r300->hw.zs.cmd[R300_ZS_CNTL_1] |= R300_ZS_NEVER << R300_RB3D_ZS1_DEPTH_FUNC_SHIFT;
+ break;
+ case GL_LESS:
+ r300->hw.zs.cmd[R300_ZS_CNTL_1] |= R300_ZS_LESS << R300_RB3D_ZS1_DEPTH_FUNC_SHIFT;
+ break;
+ case GL_EQUAL:
+ r300->hw.zs.cmd[R300_ZS_CNTL_1] |= R300_ZS_EQUAL << R300_RB3D_ZS1_DEPTH_FUNC_SHIFT;
+ break;
+ case GL_LEQUAL:
+ r300->hw.zs.cmd[R300_ZS_CNTL_1] |= R300_ZS_LEQUAL << R300_RB3D_ZS1_DEPTH_FUNC_SHIFT;
+ break;
+ case GL_GREATER:
+ r300->hw.zs.cmd[R300_ZS_CNTL_1] |= R300_ZS_GREATER << R300_RB3D_ZS1_DEPTH_FUNC_SHIFT;
+ break;
+ case GL_NOTEQUAL:
+ r300->hw.zs.cmd[R300_ZS_CNTL_1] |= R300_ZS_NOTEQUAL << R300_RB3D_ZS1_DEPTH_FUNC_SHIFT;
+ break;
+ case GL_GEQUAL:
+ r300->hw.zs.cmd[R300_ZS_CNTL_1] |= R300_ZS_GEQUAL << R300_RB3D_ZS1_DEPTH_FUNC_SHIFT;
+ break;
+ case GL_ALWAYS:
+ r300->hw.zs.cmd[R300_ZS_CNTL_1] |= R300_ZS_ALWAYS << R300_RB3D_ZS1_DEPTH_FUNC_SHIFT;
+ break;
+ }
+}
+
+
+/**
+ * Enable/Disable depth writing.
+ *
+ * \note Mesa already filters redundant calls to this function.
+ */
+static void r300DepthMask(GLcontext* ctx, GLboolean mask)
+{
+ r300ContextPtr r300 = R300_CONTEXT(ctx);
+
+ if (!ctx->Depth.Test)
+ return;
+
+ R300_STATECHANGE(r300, zs);
+ r300->hw.zs.cmd[R300_ZS_CNTL_0] &= R300_RB3D_STENCIL_ENABLE;
+ r300->hw.zs.cmd[R300_ZS_CNTL_0] |= mask
+ ? R300_RB3D_Z_TEST_AND_WRITE : R300_RB3D_Z_TEST;
+}
+
+
+/**
+ * Handle glColorMask()
+ */
+static void r300ColorMask(GLcontext* ctx,
+ GLboolean r, GLboolean g, GLboolean b, GLboolean a)
+{
+ r300ContextPtr r300 = R300_CONTEXT(ctx);
+ int mask = (r ? R300_COLORMASK0_R : 0) |
+ (g ? R300_COLORMASK0_G : 0) |
+ (b ? R300_COLORMASK0_B : 0) |
+ (a ? R300_COLORMASK0_A : 0);
+
+ if (mask != r300->hw.cmk.cmd[R300_CMK_COLORMASK]) {
+ R300_STATECHANGE(r300, cmk);
+ r300->hw.cmk.cmd[R300_CMK_COLORMASK] = mask;
+ }
+}
+
+/* =============================================================
+ * Point state
+ */
+static void r300PointSize(GLcontext * ctx, GLfloat size)
+{
+ r300ContextPtr r300 = R300_CONTEXT(ctx);
+
+ size = ctx->Point._Size;
+
+ R300_STATECHANGE(r300, ps);
+ r300->hw.ps.cmd[R300_PS_POINTSIZE] =
+ ((int)(size * 6) << R300_POINTSIZE_X_SHIFT) |
+ ((int)(size * 6) << R300_POINTSIZE_Y_SHIFT);
+}
+
+/* =============================================================
+ * Line state
+ */
+static void r300LineWidth(GLcontext *ctx, GLfloat widthf)
+{
+ r300ContextPtr r300 = R300_CONTEXT(ctx);
+
+ widthf = ctx->Line._Width;
+
+ R300_STATECHANGE(r300, lcntl);
+ r300->hw.lcntl.cmd[1] = (int)(widthf * 6.0);
+ r300->hw.lcntl.cmd[1] |= R300_LINE_CNT_VE;
+}
+
+static void r300PolygonMode(GLcontext *ctx, GLenum face, GLenum mode)
+{
+ (void)face;
+ (void)mode;
+
+ r300UpdatePolygonMode(ctx);
+}
+
+/* =============================================================
+ * Stencil
+ */
+
+static int translate_stencil_func(int func)
+{
+ switch (func) {
+ case GL_NEVER:
+ return R300_ZS_NEVER;
+ case GL_LESS:
+ return R300_ZS_LESS;
+ case GL_EQUAL:
+ return R300_ZS_EQUAL;
+ case GL_LEQUAL:
+ return R300_ZS_LEQUAL;
+ case GL_GREATER:
+ return R300_ZS_GREATER;
+ case GL_NOTEQUAL:
+ return R300_ZS_NOTEQUAL;
+ case GL_GEQUAL:
+ return R300_ZS_GEQUAL;
+ case GL_ALWAYS:
+ return R300_ZS_ALWAYS;
+ }
+ return 0;
+}
+
+static int translate_stencil_op(int op)
+{
+ switch (op) {
+ case GL_KEEP:
+ return R300_ZS_KEEP;
+ case GL_ZERO:
+ return R300_ZS_ZERO;
+ case GL_REPLACE:
+ return R300_ZS_REPLACE;
+ case GL_INCR:
+ return R300_ZS_INCR;
+ case GL_DECR:
+ return R300_ZS_DECR;
+ case GL_INCR_WRAP_EXT:
+ return R300_ZS_INCR_WRAP;
+ case GL_DECR_WRAP_EXT:
+ return R300_ZS_DECR_WRAP;
+ case GL_INVERT:
+ return R300_ZS_INVERT;
+ default:
+ WARN_ONCE("Do not know how to translate stencil op");
+ return R300_ZS_KEEP;
+ }
+ return 0;
+}
+
+static void r300ShadeModel(GLcontext * ctx, GLenum mode)
+{
+ r300ContextPtr rmesa = R300_CONTEXT(ctx);
+
+ R300_STATECHANGE(rmesa, unk4274);
+ switch (mode) {
+ case GL_FLAT:
+ rmesa->hw.unk4274.cmd[2] = R300_RE_SHADE_MODEL_FLAT;
+ break;
+ case GL_SMOOTH:
+ rmesa->hw.unk4274.cmd[2] = R300_RE_SHADE_MODEL_SMOOTH;
+ break;
+ default:
+ return;
+ }
+}
+
+static void r300StencilFunc(GLcontext * ctx, GLenum func,
+ GLint ref, GLuint mask)
+{
+ r300ContextPtr rmesa = R300_CONTEXT(ctx);
+ GLuint refmask = ((ctx->Stencil.Ref[0] << R300_RB3D_ZS2_STENCIL_REF_SHIFT) |
+ (ctx->Stencil.ValueMask[0] << R300_RB3D_ZS2_STENCIL_MASK_SHIFT));
+
+ GLuint flag;
+
+ R300_STATECHANGE(rmesa, zs);
+
+ rmesa->hw.zs.cmd[R300_ZS_CNTL_1] &= ~(
+ (R300_ZS_MASK << R300_RB3D_ZS1_FRONT_FUNC_SHIFT)
+ | (R300_ZS_MASK << R300_RB3D_ZS1_BACK_FUNC_SHIFT));
+
+ rmesa->hw.zs.cmd[R300_ZS_CNTL_2] &= ~((R300_RB3D_ZS2_STENCIL_MASK << R300_RB3D_ZS2_STENCIL_REF_SHIFT) |
+ (R300_RB3D_ZS2_STENCIL_MASK << R300_RB3D_ZS2_STENCIL_MASK_SHIFT));
+
+ flag = translate_stencil_func(ctx->Stencil.Function[0]);
+
+ rmesa->hw.zs.cmd[R300_ZS_CNTL_1] |= (flag << R300_RB3D_ZS1_FRONT_FUNC_SHIFT)
+ | (flag << R300_RB3D_ZS1_BACK_FUNC_SHIFT);
+ rmesa->hw.zs.cmd[R300_ZS_CNTL_2] |= refmask;
+}
+
+static void r300StencilMask(GLcontext * ctx, GLuint mask)
+{
+ r300ContextPtr rmesa = R300_CONTEXT(ctx);
+
+ R300_STATECHANGE(rmesa, zs);
+ rmesa->hw.zs.cmd[R300_ZS_CNTL_2] &= ~(R300_RB3D_ZS2_STENCIL_MASK << R300_RB3D_ZS2_STENCIL_WRITE_MASK_SHIFT);
+ rmesa->hw.zs.cmd[R300_ZS_CNTL_2] |= ctx->Stencil.WriteMask[0] << R300_RB3D_ZS2_STENCIL_WRITE_MASK_SHIFT;
+}
+
+
+static void r300StencilOp(GLcontext * ctx, GLenum fail,
+ GLenum zfail, GLenum zpass)
+{
+ r300ContextPtr rmesa = R300_CONTEXT(ctx);
+
+ R300_STATECHANGE(rmesa, zs);
+ /* It is easier to mask what's left.. */
+ rmesa->hw.zs.cmd[R300_ZS_CNTL_1] &=
+ (R300_ZS_MASK << R300_RB3D_ZS1_DEPTH_FUNC_SHIFT) |
+ (R300_ZS_MASK << R300_RB3D_ZS1_FRONT_FUNC_SHIFT) |
+ (R300_ZS_MASK << R300_RB3D_ZS1_BACK_FUNC_SHIFT);
+
+ rmesa->hw.zs.cmd[R300_ZS_CNTL_1] |=
+ (translate_stencil_op(ctx->Stencil.FailFunc[0]) << R300_RB3D_ZS1_FRONT_FAIL_OP_SHIFT)
+ |(translate_stencil_op(ctx->Stencil.ZFailFunc[0]) << R300_RB3D_ZS1_FRONT_ZFAIL_OP_SHIFT)
+ |(translate_stencil_op(ctx->Stencil.ZPassFunc[0]) << R300_RB3D_ZS1_FRONT_ZPASS_OP_SHIFT)
+ |(translate_stencil_op(ctx->Stencil.FailFunc[0]) << R300_RB3D_ZS1_BACK_FAIL_OP_SHIFT)
+ |(translate_stencil_op(ctx->Stencil.ZFailFunc[0]) << R300_RB3D_ZS1_BACK_ZFAIL_OP_SHIFT)
+ |(translate_stencil_op(ctx->Stencil.ZPassFunc[0]) << R300_RB3D_ZS1_BACK_ZPASS_OP_SHIFT);
+}
+
+static void r300ClearStencil(GLcontext * ctx, GLint s)
+{
+ r300ContextPtr rmesa = R300_CONTEXT(ctx);
+
+ rmesa->state.stencil.clear =
+ ((GLuint) ctx->Stencil.Clear |
+ (R300_RB3D_ZS2_STENCIL_MASK << R300_RB3D_ZS2_STENCIL_MASK_SHIFT) |
+ (ctx->Stencil.WriteMask[0] << R300_RB3D_ZS2_STENCIL_WRITE_MASK_SHIFT));
+}
+
+/* =============================================================
+ * Window position and viewport transformation
+ */
+
+/*
+ * To correctly position primitives:
+ */
+#define SUBPIXEL_X 0.125
+#define SUBPIXEL_Y 0.125
+
+static void r300UpdateWindow(GLcontext * ctx)
+{
+ r300ContextPtr rmesa = R300_CONTEXT(ctx);
+ __DRIdrawablePrivate *dPriv = rmesa->radeon.dri.drawable;
+ GLfloat xoffset = dPriv ? (GLfloat) dPriv->x : 0;
+ GLfloat yoffset = dPriv ? (GLfloat) dPriv->y + dPriv->h : 0;
+ 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;
+
+ R300_FIREVERTICES(rmesa);
+ R300_STATECHANGE(rmesa, vpt);
+
+ rmesa->hw.vpt.cmd[R300_VPT_XSCALE] = r300PackFloat32(sx);
+ rmesa->hw.vpt.cmd[R300_VPT_XOFFSET] = r300PackFloat32(tx);
+ rmesa->hw.vpt.cmd[R300_VPT_YSCALE] = r300PackFloat32(sy);
+ rmesa->hw.vpt.cmd[R300_VPT_YOFFSET] = r300PackFloat32(ty);
+ rmesa->hw.vpt.cmd[R300_VPT_ZSCALE] = r300PackFloat32(sz);
+ rmesa->hw.vpt.cmd[R300_VPT_ZOFFSET] = r300PackFloat32(tz);
+}
+
+static void r300Viewport(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.
+ */
+ R300_FIREVERTICES(R300_CONTEXT(ctx));
+ r300UpdateWindow(ctx);
+}
+
+static void r300DepthRange(GLcontext * ctx, GLclampd nearval, GLclampd farval)
+{
+ r300UpdateWindow(ctx);
+}
+
+/* =============================================================
+ * Polygon state
+ */
+static void r300PolygonOffset(GLcontext * ctx, GLfloat factor, GLfloat units)
+{
+ r300ContextPtr rmesa = R300_CONTEXT(ctx);
+ GLfloat constant = units;
+
+ switch (ctx->Visual.depthBits) {
+ case 16:
+ constant *= 4.0;
+ break;
+ case 24:
+ constant *= 2.0;
+ break;
+ }
+
+ factor *= 12.0;
+
+/* fprintf(stderr, "%s f:%f u:%f\n", __FUNCTION__, factor, constant); */
+
+ R300_STATECHANGE(rmesa, zbs);
+ rmesa->hw.zbs.cmd[R300_ZBS_T_FACTOR] = r300PackFloat32(factor);
+ rmesa->hw.zbs.cmd[R300_ZBS_T_CONSTANT] = r300PackFloat32(constant);
+ rmesa->hw.zbs.cmd[R300_ZBS_W_FACTOR] = r300PackFloat32(factor);
+ rmesa->hw.zbs.cmd[R300_ZBS_W_CONSTANT] = r300PackFloat32(constant);
+}
+
+/* Routing and texture-related */
+
+static r300TexObj default_tex_obj={
+ filter:R300_TX_MAG_FILTER_LINEAR | R300_TX_MIN_FILTER_LINEAR,
+ pitch: 0x8000,
+ size: (0xff << R300_TX_WIDTHMASK_SHIFT)
+ | (0xff << R300_TX_HEIGHTMASK_SHIFT)
+ | (0x8 << R300_TX_SIZE_SHIFT),
+ format: 0x88a0c,
+ offset: 0x0,
+ unknown4: 0x0,
+ unknown5: 0x0
+ };
+
+ /* there is probably a system to these value, but, for now,
+ we just try by hand */
+
+static int inline translate_src(int src)
+{
+ switch (src) {
+ case GL_TEXTURE:
+ return 1;
+ break;
+ case GL_CONSTANT:
+ return 2;
+ break;
+ case GL_PRIMARY_COLOR:
+ return 3;
+ break;
+ case GL_PREVIOUS:
+ return 4;
+ break;
+ case GL_ZERO:
+ return 5;
+ break;
+ case GL_ONE:
+ return 6;
+ break;
+ default:
+ return 0;
+ }
+}
+
+/* r300 doesnt handle GL_CLAMP and GL_MIRROR_CLAMP_EXT correctly when filter is NEAREST.
+ * Since texwrap produces same results for GL_CLAMP and GL_CLAMP_TO_EDGE we use them instead.
+ * We need to recalculate wrap modes whenever filter mode is changed because someone might do:
+ * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ * glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ * Since r300 completely ignores R300_TX_CLAMP when either min or mag is nearest it cant handle
+ * combinations where only one of them is nearest.
+ */
+static unsigned long gen_fixed_filter(unsigned long f)
+{
+ unsigned long mag, min, needs_fixing=0;
+ //return f;
+
+ /* We ignore MIRROR bit so we dont have to do everything twice */
+ if((f & ((7-1) << R300_TX_WRAP_S_SHIFT)) == (R300_TX_CLAMP << R300_TX_WRAP_S_SHIFT)){
+ needs_fixing |= 1;
+ }
+ if((f & ((7-1) << R300_TX_WRAP_T_SHIFT)) == (R300_TX_CLAMP << R300_TX_WRAP_T_SHIFT)){
+ needs_fixing |= 2;
+ }
+ if((f & ((7-1) << R300_TX_WRAP_Q_SHIFT)) == (R300_TX_CLAMP << R300_TX_WRAP_Q_SHIFT)){
+ needs_fixing |= 4;
+ }
+
+ if(!needs_fixing)
+ return f;
+
+ mag=f & R300_TX_MAG_FILTER_MASK;
+ min=f & R300_TX_MIN_FILTER_MASK;
+
+ /* TODO: Check for anisto filters too */
+ if((mag != R300_TX_MAG_FILTER_NEAREST) && (min != R300_TX_MIN_FILTER_NEAREST))
+ return f;
+
+ /* r300 cant handle these modes hence we force nearest to linear */
+ if((mag == R300_TX_MAG_FILTER_NEAREST) && (min != R300_TX_MIN_FILTER_NEAREST)){
+ f &= ~R300_TX_MAG_FILTER_NEAREST;
+ f |= R300_TX_MAG_FILTER_LINEAR;
+ return f;
+ }
+
+ if((min == R300_TX_MIN_FILTER_NEAREST) && (mag != R300_TX_MAG_FILTER_NEAREST)){
+ f &= ~R300_TX_MIN_FILTER_NEAREST;
+ f |= R300_TX_MIN_FILTER_LINEAR;
+ return f;
+ }
+
+ /* Both are nearest */
+ if(needs_fixing & 1){
+ f &= ~((7-1) << R300_TX_WRAP_S_SHIFT);
+ f |= R300_TX_CLAMP_TO_EDGE << R300_TX_WRAP_S_SHIFT;
+ }
+ if(needs_fixing & 2){
+ f &= ~((7-1) << R300_TX_WRAP_T_SHIFT);
+ f |= R300_TX_CLAMP_TO_EDGE << R300_TX_WRAP_T_SHIFT;
+ }
+ if(needs_fixing & 4){
+ f &= ~((7-1) << R300_TX_WRAP_Q_SHIFT);
+ f |= R300_TX_CLAMP_TO_EDGE << R300_TX_WRAP_Q_SHIFT;
+ }
+ return f;
+}
+
+void r300_setup_textures(GLcontext *ctx)
+{
+ int i, mtu;
+ struct r300_tex_obj *t;
+ r300ContextPtr r300 = R300_CONTEXT(ctx);
+ int max_texture_unit=-1; /* -1 translates into no setup costs for fields */
+ struct gl_texture_unit *texUnit;
+ GLuint OutputsWritten;
+
+ if(hw_tcl_on)
+ OutputsWritten = CURRENT_VERTEX_SHADER(ctx)->OutputsWritten;
+
+ R300_STATECHANGE(r300, txe);
+ R300_STATECHANGE(r300, tex.filter);
+ R300_STATECHANGE(r300, tex.unknown1);
+ R300_STATECHANGE(r300, tex.size);
+ R300_STATECHANGE(r300, tex.format);
+ R300_STATECHANGE(r300, tex.offset);
+ R300_STATECHANGE(r300, tex.unknown4);
+ R300_STATECHANGE(r300, tex.border_color);
+
+ r300->hw.txe.cmd[R300_TXE_ENABLE]=0x0;
+
+ mtu = r300->radeon.glCtx->Const.MaxTextureUnits;
+ if (RADEON_DEBUG & DEBUG_STATE)
+ fprintf(stderr, "mtu=%d\n", mtu);
+
+ if(mtu > R300_MAX_TEXTURE_UNITS) {
+ fprintf(stderr, "Aiiee ! mtu=%d is greater than R300_MAX_TEXTURE_UNITS=%d\n",
+ mtu, R300_MAX_TEXTURE_UNITS);
+ exit(-1);
+ }
+
+ for(i=0; i < mtu; i++) {
+ /*if( ((r300->state.render_inputs & (_TNL_BIT_TEX0<<i))!=0) != ((ctx->Texture.Unit[i].Enabled)!=0) ) {
+ WARN_ONCE("Mismatch between render_inputs and ctx->Texture.Unit[i].Enabled value(%d vs %d).\n",
+ ((r300->state.render_inputs & (_TNL_BIT_TEX0<<i))!=0), ((ctx->Texture.Unit[i].Enabled)!=0));
+ }*/
+
+ if(TMU_ENABLED(ctx, i)) {
+ t=r300->state.texture.unit[i].texobj;
+ //fprintf(stderr, "format=%08x\n", r300->state.texture.unit[i].format);
+
+ if(t == NULL){
+ fprintf(stderr, "Texture unit %d enabled, but corresponding texobj is NULL, using default object.\n", i);
+ //exit(-1);
+ t=&default_tex_obj;
+ }
+
+ //fprintf(stderr, "t->format=%08x\n", t->format);
+ if((t->format & 0xffffff00)==0xffffff00) {
+ WARN_ONCE("unknown texture format (entry %x) encountered. Help me !\n", t->format & 0xff);
+ //fprintf(stderr, "t->format=%08x\n", t->format);
+ }
+
+ if (RADEON_DEBUG & DEBUG_STATE)
+ fprintf(stderr, "Activating texture unit %d\n", i);
+ max_texture_unit=i;
+ r300->hw.txe.cmd[R300_TXE_ENABLE]|=(1<<i);
+
+ r300->hw.tex.filter.cmd[R300_TEX_VALUE_0+i]=gen_fixed_filter(t->filter) | (i << 28);
+ //r300->hw.tex.unknown1.cmd[R300_TEX_VALUE_0+i]=0x0; /* move lod bias here? */
+
+ /* No idea why linear filtered textures shake when puting random data */
+ /*r300->hw.tex.unknown1.cmd[R300_TEX_VALUE_0+i]=(rand()%0xffffffff) & (~0x1fff);*/
+ r300->hw.tex.size.cmd[R300_TEX_VALUE_0+i]=t->size;
+ r300->hw.tex.format.cmd[R300_TEX_VALUE_0+i]=t->format;
+ //fprintf(stderr, "t->format=%08x\n", t->format);
+ r300->hw.tex.offset.cmd[R300_TEX_VALUE_0+i]=t->offset;
+ r300->hw.tex.unknown4.cmd[R300_TEX_VALUE_0+i]=0x0;
+ r300->hw.tex.border_color.cmd[R300_TEX_VALUE_0+i]=t->pp_border_color;
+ }
+ }
+
+ ((drm_r300_cmd_header_t*)r300->hw.tex.filter.cmd)->packet0.count = max_texture_unit+1;
+ ((drm_r300_cmd_header_t*)r300->hw.tex.unknown1.cmd)->packet0.count = max_texture_unit+1;
+ ((drm_r300_cmd_header_t*)r300->hw.tex.size.cmd)->packet0.count = max_texture_unit+1;
+ ((drm_r300_cmd_header_t*)r300->hw.tex.format.cmd)->packet0.count = max_texture_unit+1;
+ ((drm_r300_cmd_header_t*)r300->hw.tex.offset.cmd)->packet0.count = max_texture_unit+1;
+ ((drm_r300_cmd_header_t*)r300->hw.tex.unknown4.cmd)->packet0.count = max_texture_unit+1;
+ ((drm_r300_cmd_header_t*)r300->hw.tex.border_color.cmd)->packet0.count = max_texture_unit+1;
+
+ if (RADEON_DEBUG & DEBUG_STATE)
+ fprintf(stderr, "TX_ENABLE: %08x max_texture_unit=%d\n", r300->hw.txe.cmd[R300_TXE_ENABLE], max_texture_unit);
+}
+
+#if USE_ARB_F_P == 1
+void r300_setup_rs_unit(GLcontext *ctx)
+{
+ r300ContextPtr r300 = R300_CONTEXT(ctx);
+ /* I'm still unsure if these are needed */
+ GLuint interp_magic[8] = {
+ 0x00,
+ 0x40,
+ 0x80,
+ 0xC0,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ };
+ GLuint OutputsWritten;
+ GLuint InputsRead;
+ int vp_reg, fp_reg, high_rr;
+ int in_texcoords, col_interp_nr;
+ int i;
+
+ if(hw_tcl_on)
+ OutputsWritten = CURRENT_VERTEX_SHADER(ctx)->OutputsWritten;
+ else
+ OutputsWritten = r300->state.render_inputs;
+
+ if (ctx->FragmentProgram._Current)
+ InputsRead = ctx->FragmentProgram._Current->InputsRead;
+ else {
+ fprintf(stderr, "No ctx->FragmentProgram._Current!!\n");
+ return; /* This should only ever happen once.. */
+ }
+
+ R300_STATECHANGE(r300, ri);
+ R300_STATECHANGE(r300, rc);
+ R300_STATECHANGE(r300, rr);
+
+ vp_reg = fp_reg = in_texcoords = col_interp_nr = high_rr = 0;
+ r300->hw.rr.cmd[R300_RR_ROUTE_0] = 0;
+ r300->hw.rr.cmd[R300_RR_ROUTE_1] = 0;
+
+ for (i=0;i<ctx->Const.MaxTextureUnits;i++) {
+ if (OutputsWritten & (hw_tcl_on ? (1 << (VERT_RESULT_TEX0+i)) : (_TNL_BIT_TEX0<<i)))
+ in_texcoords++;
+
+ r300->hw.ri.cmd[R300_RI_INTERP_0+i] = 0
+ | R300_RS_INTERP_USED
+ | (vp_reg << R300_RS_INTERP_SRC_SHIFT)
+ | interp_magic[i];
+
+ if (InputsRead & (FRAG_BIT_TEX0<<i)) {
+ //assert(r300->state.texture.tc_count != 0);
+ r300->hw.rr.cmd[R300_RR_ROUTE_0 + fp_reg] = 0
+ | R300_RS_ROUTE_ENABLE
+ | i /* source INTERP */
+ | (fp_reg << R300_RS_ROUTE_DEST_SHIFT);
+ high_rr = fp_reg;
+
+ if (OutputsWritten & (hw_tcl_on ? (1 << (VERT_RESULT_TEX0+i)) : (_TNL_BIT_TEX0<<i))) {
+ vp_reg++;
+ } else {
+ /* Unsure of how to handle this situation, for now print errors and
+ * the program will just recieve bogus data
+ */
+ fprintf(stderr, "fragprog wants coords for tex%d, vp doesn't provide them!\n", i);
+ }
+ InputsRead &= ~(FRAG_BIT_TEX0<<i);
+ fp_reg++;
+ }
+ }
+
+ if (InputsRead & FRAG_BIT_COL0) {
+ if (!(OutputsWritten & (hw_tcl_on ? (1<<VERT_RESULT_COL0) : _TNL_BIT_COLOR0)))
+ fprintf(stderr, "fragprog wants col0, vp doesn't provide it\n");
+
+ r300->hw.rr.cmd[R300_RR_ROUTE_0] |= 0
+ | R300_RS_ROUTE_0_COLOR
+ | (fp_reg++ << R300_RS_ROUTE_0_COLOR_DEST_SHIFT);
+ InputsRead &= ~FRAG_BIT_COL0;
+ col_interp_nr++;
+ }
+
+ if (InputsRead & FRAG_BIT_COL1) {
+ if (!(OutputsWritten & (hw_tcl_on ? (1<<VERT_RESULT_COL1) : _TNL_BIT_COLOR1)))
+ fprintf(stderr, "fragprog wants col1, vp doesn't provide it\n");
+
+ r300->hw.rr.cmd[R300_RR_ROUTE_1] |= R300_RS_ROUTE_1_UNKNOWN11
+ | R300_RS_ROUTE_1_COLOR1
+ | (fp_reg++ << R300_RS_ROUTE_1_COLOR1_DEST_SHIFT);
+ InputsRead &= ~FRAG_BIT_COL1;
+ if (high_rr < 1) high_rr = 1;
+ col_interp_nr++;
+ }
+
+ r300->hw.rc.cmd[1] = 0
+ | (in_texcoords << R300_RS_CNTL_TC_CNT_SHIFT)
+ | (col_interp_nr << R300_RS_CNTL_CI_CNT_SHIFT)
+ | R300_RS_CNTL_0_UNKNOWN_18;
+
+ assert(high_rr >= 0);
+ r300->hw.rr.cmd[R300_RR_CMD_0] = cmdpacket0(R300_RS_ROUTE_0, high_rr+1);
+ r300->hw.rc.cmd[2] = 0xC0 | high_rr;
+
+ if (InputsRead)
+ WARN_ONCE("Don't know how to satisfy InputsRead=0x%08x\n", InputsRead);
+}
+#else
+void r300_setup_rs_unit(GLcontext *ctx)
+{
+ r300ContextPtr r300 = R300_CONTEXT(ctx);
+ int i, cur_reg;
+ /* I'm still unsure if these are needed */
+ GLuint interp_magic[8] = {
+ 0x00,
+ 0x40,
+ 0x80,
+ 0xC0,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ };
+ GLuint OutputsWritten;
+
+ if(hw_tcl_on)
+ OutputsWritten = CURRENT_VERTEX_SHADER(ctx)->OutputsWritten;
+
+ /* This needs to be rewritten - it is a hack at best */
+
+ R300_STATECHANGE(r300, ri);
+ R300_STATECHANGE(r300, rc);
+ R300_STATECHANGE(r300, rr);
+
+ cur_reg = 0;
+ r300->hw.rr.cmd[R300_RR_ROUTE_0] = 0;
+
+ for (i=0;i<ctx->Const.MaxTextureUnits;i++) {
+ r300->hw.ri.cmd[R300_RI_INTERP_0+i] = 0
+ | R300_RS_INTERP_USED
+ | (cur_reg << R300_RS_INTERP_SRC_SHIFT)
+ | interp_magic[i];
+// fprintf(stderr, "RS_INTERP[%d] = 0x%x\n", i, r300->hw.ri.cmd[R300_RI_INTERP_0+i]);
+
+ if (TMU_ENABLED(ctx, i)) {
+ assert(r300->state.texture.tc_count != 0);
+ r300->hw.rr.cmd[R300_RR_ROUTE_0 + cur_reg] = 0
+ | R300_RS_ROUTE_ENABLE
+ | i /* source INTERP */
+ | (cur_reg << R300_RS_ROUTE_DEST_SHIFT);
+// fprintf(stderr, "RS_ROUTE[%d] = 0x%x\n", cur_reg, r300->hw.rr.cmd[R300_RR_ROUTE_0 + cur_reg]);
+ cur_reg++;
+ }
+ }
+ if (hw_tcl_on ? OutputsWritten & (1<<VERT_RESULT_COL0) : r300->state.render_inputs & _TNL_BIT_COLOR0)
+ r300->hw.rr.cmd[R300_RR_ROUTE_0] |= 0
+ | R300_RS_ROUTE_0_COLOR
+ | (cur_reg << R300_RS_ROUTE_0_COLOR_DEST_SHIFT);
+
+// fprintf(stderr, "ADJ_RR0 = 0x%x\n", r300->hw.rr.cmd[R300_RR_ROUTE_0]);
+
+ r300->hw.rc.cmd[1] = 0
+ | (cur_reg /* count */ << R300_RS_CNTL_TC_CNT_SHIFT)
+ | R300_RS_CNTL_0_UNKNOWN_7
+ | R300_RS_CNTL_0_UNKNOWN_18;
+
+ if (r300->state.texture.tc_count > 0) {
+ r300->hw.rr.cmd[R300_RR_CMD_0] = cmdpacket0(R300_RS_ROUTE_0, cur_reg);
+ r300->hw.rc.cmd[2] = 0xC0 | (cur_reg-1); /* index of highest */
+ } else {
+ r300->hw.rr.cmd[R300_RR_CMD_0] = cmdpacket0(R300_RS_ROUTE_0, 1);
+ r300->hw.rc.cmd[2] = 0x0;
+ }
+
+
+// fprintf(stderr, "rendering with %d texture co-ordinate sets\n", cur_reg);
+}
+#endif // USE_ARB_F_P
+
+#define vpucount(ptr) (((drm_r300_cmd_header_t*)(ptr))->vpu.count)
+
+#define bump_vpu_count(ptr, new_count) do{\
+ drm_r300_cmd_header_t* _p=((drm_r300_cmd_header_t*)(ptr));\
+ int _nc=(new_count)/4; \
+ if(_nc>_p->vpu.count)_p->vpu.count=_nc;\
+ }while(0)
+
+void static inline setup_vertex_shader_fragment(r300ContextPtr r300, int dest, struct r300_vertex_shader_fragment *vsf)
+{
+ int i;
+
+ if(vsf->length==0)return;
+
+ if(vsf->length & 0x3){
+ fprintf(stderr,"VERTEX_SHADER_FRAGMENT must have length divisible by 4\n");
+ exit(-1);
+ }
+
+ switch((dest>>8) & 0xf){
+ case 0:
+ R300_STATECHANGE(r300, vpi);
+ for(i=0;i<vsf->length;i++)
+ r300->hw.vpi.cmd[R300_VPI_INSTR_0+i+4*(dest & 0xff)]=(vsf->body.d[i]);
+ bump_vpu_count(r300->hw.vpi.cmd, vsf->length+4*(dest & 0xff));
+ break;
+
+ case 2:
+ R300_STATECHANGE(r300, vpp);
+ for(i=0;i<vsf->length;i++)
+ r300->hw.vpp.cmd[R300_VPP_PARAM_0+i+4*(dest & 0xff)]=(vsf->body.d[i]);
+ bump_vpu_count(r300->hw.vpp.cmd, vsf->length+4*(dest & 0xff));
+ break;
+ case 4:
+ R300_STATECHANGE(r300, vps);
+ for(i=0;i<vsf->length;i++)
+ r300->hw.vps.cmd[1+i+4*(dest & 0xff)]=(vsf->body.d[i]);
+ bump_vpu_count(r300->hw.vps.cmd, vsf->length+4*(dest & 0xff));
+ break;
+ default:
+ fprintf(stderr, "%s:%s don't know how to handle dest %04x\n", __FILE__, __FUNCTION__, dest);
+ exit(-1);
+ }
+}
+
+void r300SetupVertexProgram(r300ContextPtr rmesa);
+
+/* just a skeleton for now.. */
+
+/* Generate a vertex shader that simply transforms vertex and texture coordinates,
+ while leaving colors intact. Nothing fancy (like lights)
+
+ If implementing lights make a copy first, so it is easy to switch between the two versions */
+static void r300GenerateSimpleVertexShader(r300ContextPtr r300)
+{
+ int i;
+ GLuint o_reg = 0;
+
+ /* Allocate parameters */
+ r300->state.vap_param.transform_offset=0x0; /* transform matrix */
+ r300->state.vertex_shader.param_offset=0x0;
+ r300->state.vertex_shader.param_count=0x4; /* 4 vector values - 4x4 matrix */
+
+ r300->state.vertex_shader.program_start=0x0;
+ r300->state.vertex_shader.unknown_ptr1=0x4; /* magic value ? */
+ r300->state.vertex_shader.program_end=0x0;
+
+ r300->state.vertex_shader.unknown_ptr2=0x0; /* magic value */
+ r300->state.vertex_shader.unknown_ptr3=0x4; /* magic value */
+
+ /* Initialize matrix and vector parameters.. these should really be restructured */
+ /* TODO: fix vertex_shader structure */
+ r300->state.vertex_shader.matrix[0].length=16;
+ r300->state.vertex_shader.matrix[1].length=0;
+ r300->state.vertex_shader.matrix[2].length=0;
+ r300->state.vertex_shader.vector[0].length=0;
+ r300->state.vertex_shader.vector[1].length=0;
+ r300->state.vertex_shader.unknown1.length=0;
+ r300->state.vertex_shader.unknown2.length=0;
+
+#define WRITE_OP(oper,source1,source2,source3) {\
+ r300->state.vertex_shader.program.body.i[r300->state.vertex_shader.program_end].op=(oper); \
+ r300->state.vertex_shader.program.body.i[r300->state.vertex_shader.program_end].src1=(source1); \
+ r300->state.vertex_shader.program.body.i[r300->state.vertex_shader.program_end].src2=(source2); \
+ r300->state.vertex_shader.program.body.i[r300->state.vertex_shader.program_end].src3=(source3); \
+ r300->state.vertex_shader.program_end++; \
+ }
+
+ /* Multiply vertex coordinates with transform matrix */
+
+ WRITE_OP(
+ EASY_VSF_OP(MUL, 0, ALL, TMP),
+ VSF_PARAM(3),
+ VSF_ATTR_W(0),
+ EASY_VSF_SOURCE(0, W, W, W, W, NONE, NONE)
+ )
+
+ WRITE_OP(
+ EASY_VSF_OP(MUL, 1, ALL, RESULT),
+ VSF_REG(1),
+ VSF_ATTR_UNITY(1),
+ VSF_UNITY(1)
+ )
+
+ WRITE_OP(
+ EASY_VSF_OP(MAD, 0, ALL, TMP),
+ VSF_PARAM(2),
+ VSF_ATTR_Z(0),
+ VSF_TMP(0)
+ )
+
+ WRITE_OP(
+ EASY_VSF_OP(MAD, 0, ALL, TMP),
+ VSF_PARAM(1),
+ VSF_ATTR_Y(0),
+ VSF_TMP(0)
+ )
+
+ WRITE_OP(
+ EASY_VSF_OP(MAD, 0, ALL, RESULT),
+ VSF_PARAM(0),
+ VSF_ATTR_X(0),
+ VSF_TMP(0)
+ )
+ o_reg += 2;
+
+ if (r300->state.render_inputs & _TNL_BIT_COLOR1) {
+ WRITE_OP(
+ EASY_VSF_OP(MUL, o_reg++, ALL, RESULT),
+ VSF_REG(r300->state.vap_reg.i_color[1]),
+ VSF_ATTR_UNITY(r300->state.vap_reg.i_color[1]),
+ VSF_UNITY(r300->state.vap_reg.i_color[1])
+ )
+ }
+
+ /* Pass through texture coordinates, if any */
+ for(i=0;i < r300->radeon.glCtx->Const.MaxTextureUnits;i++)
+ if(r300->state.render_inputs & (_TNL_BIT_TEX0<<i)){
+ // fprintf(stderr, "i_tex[%d]=%d\n", i, r300->state.vap_reg.i_tex[i]);
+ WRITE_OP(
+ EASY_VSF_OP(MUL, o_reg++ /* 2+i */, ALL, RESULT),
+ VSF_REG(r300->state.vap_reg.i_tex[i]),
+ VSF_ATTR_UNITY(r300->state.vap_reg.i_tex[i]),
+ VSF_UNITY(r300->state.vap_reg.i_tex[i])
+ )
+ }
+
+ r300->state.vertex_shader.program_end--; /* r300 wants program length to be one more - no idea why */
+ r300->state.vertex_shader.program.length=(r300->state.vertex_shader.program_end+1)*4;
+
+ r300->state.vertex_shader.unknown_ptr1=r300->state.vertex_shader.program_end; /* magic value ? */
+ r300->state.vertex_shader.unknown_ptr2=r300->state.vertex_shader.program_end; /* magic value ? */
+ r300->state.vertex_shader.unknown_ptr3=r300->state.vertex_shader.program_end; /* magic value ? */
+
+}
+
+
+void r300SetupVertexShader(r300ContextPtr rmesa)
+{
+ GLcontext* ctx = rmesa->radeon.glCtx;
+ struct r300_vertex_shader_fragment unk4={
+ length: 4,
+ body: { f: {
+ /*0.0*/(rand()%100)/10.0,
+ /*0.0*/(rand()%100)/10.0,
+ /*1.0*/(rand()%100)/10.0,
+ /*0.0*/(rand()%100)/10.0
+ } }
+ };
+ LOCAL_VARS
+
+ /* Reset state, in case we don't use something */
+ ((drm_r300_cmd_header_t*)rmesa->hw.vpp.cmd)->vpu.count = 0;
+ ((drm_r300_cmd_header_t*)rmesa->hw.vpi.cmd)->vpu.count = 0;
+ ((drm_r300_cmd_header_t*)rmesa->hw.vps.cmd)->vpu.count = 0;
+
+ /* Not sure why this doesnt work...
+ 0x400 area might have something to do with pixel shaders as it appears right after pfs programming.
+ 0x406 is set to { 0.0, 0.0, 1.0, 0.0 } most of the time but should change with smooth points and in other rare cases. */
+ //setup_vertex_shader_fragment(rmesa, 0x406, &unk4);
+ if(hw_tcl_on && ((struct r300_vertex_program *)CURRENT_VERTEX_SHADER(ctx))->translated){
+ r300SetupVertexProgram(rmesa);
+ return ;
+ }
+
+/* This needs to be replaced by vertex shader generation code */
+
+
+#if 0
+ /* textures enabled ? */
+ if(rmesa->state.texture.tc_count>0){
+ rmesa->state.vertex_shader=SINGLE_TEXTURE_VERTEX_SHADER;
+ } else {
+ rmesa->state.vertex_shader=FLAT_COLOR_VERTEX_SHADER;
+ }
+#endif
+
+ r300GenerateSimpleVertexShader(rmesa);
+
+ rmesa->state.vertex_shader.matrix[0].length=16;
+ memcpy(rmesa->state.vertex_shader.matrix[0].body.f, ctx->_ModelProjectMatrix.m, 16*4);
+
+ setup_vertex_shader_fragment(rmesa, VSF_DEST_PROGRAM, &(rmesa->state.vertex_shader.program));
+
+ setup_vertex_shader_fragment(rmesa, VSF_DEST_MATRIX0, &(rmesa->state.vertex_shader.matrix[0]));
+#if 0
+ setup_vertex_shader_fragment(rmesa, VSF_DEST_MATRIX1, &(rmesa->state.vertex_shader.matrix[0]));
+ setup_vertex_shader_fragment(rmesa, VSF_DEST_MATRIX2, &(rmesa->state.vertex_shader.matrix[0]));
+
+ setup_vertex_shader_fragment(rmesa, VSF_DEST_VECTOR0, &(rmesa->state.vertex_shader.vector[0]));
+ setup_vertex_shader_fragment(rmesa, VSF_DEST_VECTOR1, &(rmesa->state.vertex_shader.vector[1]));
+#endif
+
+#if 0
+ setup_vertex_shader_fragment(rmesa, VSF_DEST_UNKNOWN1, &(rmesa->state.vertex_shader.unknown1));
+ setup_vertex_shader_fragment(rmesa, VSF_DEST_UNKNOWN2, &(rmesa->state.vertex_shader.unknown2));
+#endif
+
+ R300_STATECHANGE(rmesa, pvs);
+ rmesa->hw.pvs.cmd[R300_PVS_CNTL_1]=(rmesa->state.vertex_shader.program_start << R300_PVS_CNTL_1_PROGRAM_START_SHIFT)
+ | (rmesa->state.vertex_shader.unknown_ptr1 << R300_PVS_CNTL_1_POS_END_SHIFT)
+ | (rmesa->state.vertex_shader.program_end << R300_PVS_CNTL_1_PROGRAM_END_SHIFT);
+ rmesa->hw.pvs.cmd[R300_PVS_CNTL_2]=(rmesa->state.vertex_shader.param_offset << R300_PVS_CNTL_2_PARAM_OFFSET_SHIFT)
+ | (rmesa->state.vertex_shader.param_count << R300_PVS_CNTL_2_PARAM_COUNT_SHIFT);
+ rmesa->hw.pvs.cmd[R300_PVS_CNTL_3]=(rmesa->state.vertex_shader.unknown_ptr2 << R300_PVS_CNTL_3_PROGRAM_UNKNOWN_SHIFT)
+ | (rmesa->state.vertex_shader.unknown_ptr3 << 0);
+
+ /* This is done for vertex shader fragments, but also needs to be done for vap_pvs,
+ so I leave it as a reminder */
+#if 0
+ reg_start(R300_VAP_PVS_WAITIDLE,0);
+ e32(0x00000000);
+#endif
+}
+
+void r300SetupVertexProgram(r300ContextPtr rmesa)
+{
+ GLcontext* ctx = rmesa->radeon.glCtx;
+ int inst_count;
+ int param_count;
+ LOCAL_VARS
+ struct r300_vertex_program *prog=(struct r300_vertex_program *)CURRENT_VERTEX_SHADER(ctx);
+
+
+ /* Reset state, in case we don't use something */
+ ((drm_r300_cmd_header_t*)rmesa->hw.vpp.cmd)->vpu.count = 0;
+ ((drm_r300_cmd_header_t*)rmesa->hw.vpi.cmd)->vpu.count = 0;
+ ((drm_r300_cmd_header_t*)rmesa->hw.vps.cmd)->vpu.count = 0;
+
+ r300VertexProgUpdateParams(ctx, prog);
+
+ setup_vertex_shader_fragment(rmesa, VSF_DEST_PROGRAM, &(prog->program));
+
+ setup_vertex_shader_fragment(rmesa, VSF_DEST_MATRIX0, &(prog->params));
+
+#if 0
+ setup_vertex_shader_fragment(rmesa, VSF_DEST_UNKNOWN1, &(rmesa->state.vertex_shader.unknown1));
+ setup_vertex_shader_fragment(rmesa, VSF_DEST_UNKNOWN2, &(rmesa->state.vertex_shader.unknown2));
+#endif
+
+ inst_count=prog->program.length/4 - 1;
+ param_count=prog->params.length/4;
+
+ R300_STATECHANGE(rmesa, pvs);
+ rmesa->hw.pvs.cmd[R300_PVS_CNTL_1]=(0 << R300_PVS_CNTL_1_PROGRAM_START_SHIFT)
+ | (inst_count/*pos_end*/ << R300_PVS_CNTL_1_POS_END_SHIFT)
+ | (inst_count << R300_PVS_CNTL_1_PROGRAM_END_SHIFT);
+ rmesa->hw.pvs.cmd[R300_PVS_CNTL_2]=(0 << R300_PVS_CNTL_2_PARAM_OFFSET_SHIFT)
+ | (param_count << R300_PVS_CNTL_2_PARAM_COUNT_SHIFT);
+ rmesa->hw.pvs.cmd[R300_PVS_CNTL_3]=(0/*rmesa->state.vertex_shader.unknown_ptr2*/ << R300_PVS_CNTL_3_PROGRAM_UNKNOWN_SHIFT)
+ | (inst_count /*rmesa->state.vertex_shader.unknown_ptr3*/ << 0);
+
+ /* This is done for vertex shader fragments, but also needs to be done for vap_pvs,
+ so I leave it as a reminder */
+#if 0
+ reg_start(R300_VAP_PVS_WAITIDLE,0);
+ e32(0x00000000);
+#endif
+}
+
+/* This is probably wrong for some values, I need to test this
+ * some more. Range checking would be a good idea also..
+ *
+ * But it works for most things. I'll fix it later if someone
+ * else with a better clue doesn't
+ */
+static unsigned int r300PackFloat24(float f)
+{
+ float mantissa;
+ int exponent;
+ unsigned int float24 = 0;
+
+ if (f == 0.0) return 0;
+
+ mantissa = frexpf(f, &exponent);
+
+ /* Handle -ve */
+ if (mantissa < 0) {
+ float24 |= (1<<23);
+ mantissa = mantissa * -1.0;
+ }
+ /* Handle exponent, bias of 63 */
+ exponent += 62;
+ float24 |= (exponent << 16);
+ /* Kill 7 LSB of mantissa */
+ float24 |= (r300PackFloat32(mantissa) & 0x7FFFFF) >> 7;
+
+ return float24;
+}
+
+#if USE_ARB_F_P == 1
+void r300SetupPixelShader(r300ContextPtr rmesa)
+{
+ GLcontext *ctx = rmesa->radeon.glCtx;
+ struct r300_fragment_program *rp =
+ (struct r300_fragment_program *)ctx->FragmentProgram._Current;
+ int i,k;
+
+ if (!rp) /* should only happenen once, just after context is created */
+ return;
+
+ translate_fragment_shader(rp);
+ if (!rp->translated) {
+ fprintf(stderr, "%s: No valid fragment shader, exiting\n", __func__);
+ exit(-1);
+ }
+
+ R300_STATECHANGE(rmesa, fpt);
+ for(i=0;i<rp->tex.length;i++)
+ rmesa->hw.fpt.cmd[R300_FPT_INSTR_0+i]=rp->tex.inst[i];
+ rmesa->hw.fpt.cmd[R300_FPT_CMD_0]=cmdpacket0(R300_PFS_TEXI_0, rp->tex.length);
+
+#define OUTPUT_FIELD(st, reg, field) \
+ R300_STATECHANGE(rmesa, st); \
+ for(i=0;i<=rp->alu_end;i++) \
+ rmesa->hw.st.cmd[R300_FPI_INSTR_0+i]=rp->alu.inst[i].field;\
+ rmesa->hw.st.cmd[R300_FPI_CMD_0]=cmdpacket0(reg, rp->alu_end+1);
+
+ OUTPUT_FIELD(fpi[0], R300_PFS_INSTR0_0, inst0);
+ OUTPUT_FIELD(fpi[1], R300_PFS_INSTR1_0, inst1);
+ OUTPUT_FIELD(fpi[2], R300_PFS_INSTR2_0, inst2);
+ OUTPUT_FIELD(fpi[3], R300_PFS_INSTR3_0, inst3);
+#undef OUTPUT_FIELD
+
+ R300_STATECHANGE(rmesa, fp);
+ /* I just want to say, the way these nodes are stored.. weird.. */
+ for (i=0,k=(4-(rp->cur_node+1));i<4;i++,k++) {
+ if (i<(rp->cur_node+1)) {
+ rmesa->hw.fp.cmd[R300_FP_NODE0+k]=
+ (rp->node[i].alu_offset << R300_PFS_NODE_ALU_OFFSET_SHIFT)
+ | (rp->node[i].alu_end << R300_PFS_NODE_ALU_END_SHIFT)
+ | (rp->node[i].tex_offset << R300_PFS_NODE_TEX_OFFSET_SHIFT)
+ | (rp->node[i].tex_end << R300_PFS_NODE_TEX_END_SHIFT)
+ | ( (k==3) ? R300_PFS_NODE_LAST_NODE : 0);
+ } else {
+ rmesa->hw.fp.cmd[R300_FP_NODE0+(3-i)] = 0;
+ }
+ }
+
+ /* PFS_CNTL_0 */
+ rmesa->hw.fp.cmd[R300_FP_CNTL0]=
+ rp->cur_node
+ | (rp->first_node_has_tex<<3);
+ /* PFS_CNTL_1 */
+ rmesa->hw.fp.cmd[R300_FP_CNTL1]=rp->max_temp_idx;
+ /* PFS_CNTL_2 */
+ rmesa->hw.fp.cmd[R300_FP_CNTL2]=
+ (rp->alu_offset << R300_PFS_CNTL_ALU_OFFSET_SHIFT)
+ | (rp->alu_end << R300_PFS_CNTL_ALU_END_SHIFT)
+ | (rp->tex_offset << R300_PFS_CNTL_TEX_OFFSET_SHIFT)
+ | (rp->tex_end << R300_PFS_CNTL_TEX_END_SHIFT);
+
+ R300_STATECHANGE(rmesa, fpp);
+ for(i=0;i<rp->const_nr;i++){
+ rmesa->hw.fpp.cmd[R300_FPP_PARAM_0+4*i+0]=r300PackFloat24(rp->constant[i][0]);
+ rmesa->hw.fpp.cmd[R300_FPP_PARAM_0+4*i+1]=r300PackFloat24(rp->constant[i][1]);
+ rmesa->hw.fpp.cmd[R300_FPP_PARAM_0+4*i+2]=r300PackFloat24(rp->constant[i][2]);
+ rmesa->hw.fpp.cmd[R300_FPP_PARAM_0+4*i+3]=r300PackFloat24(rp->constant[i][3]);
+ }
+ rmesa->hw.fpp.cmd[R300_FPP_CMD_0]=cmdpacket0(R300_PFS_PARAM_0_X, rp->const_nr*4);
+}
+#else
+/* just a skeleton for now.. */
+void r300GenerateTexturePixelShader(r300ContextPtr r300)
+{
+ int i, mtu;
+ mtu = r300->radeon.glCtx->Const.MaxTextureUnits;
+ GLenum envMode;
+ GLuint OutputsWritten = CURRENT_VERTEX_SHADER(r300->radeon.glCtx)->OutputsWritten;
+
+ int tex_inst=0, alu_inst=0;
+
+ for(i=0;i<mtu;i++){
+ /* No need to proliferate {} */
+ if(!TMU_ENABLED(r300->radeon.glCtx, i))continue;
+
+ envMode = r300->radeon.glCtx->Texture.Unit[i].EnvMode;
+ //fprintf(stderr, "envMode=%s\n", _mesa_lookup_enum_by_nr(envMode));
+
+ /* Fetch textured pixel */
+
+ r300->state.pixel_shader.program.tex.inst[tex_inst]=0x00018000;
+ tex_inst++;
+
+ switch(r300->radeon.glCtx->Texture.Unit[i]._CurrentCombine->ModeRGB){
+ case GL_REPLACE:
+ WARN_ONCE("ModeA==GL_REPLACE is possibly broken.\n");
+ r300->state.pixel_shader.program.alu.inst[alu_inst].inst0=
+ EASY_PFS_INSTR0(MAD, SRC0C_XYZ, ONE, ZERO);
+
+ r300->state.pixel_shader.program.alu.inst[alu_inst].inst1=
+ EASY_PFS_INSTR1(0, 0, 0 | PFS_FLAG_CONST, 0 | PFS_FLAG_CONST, NONE, ALL);
+ break;
+ case GL_MODULATE:
+ WARN_ONCE("ModeRGB==GL_MODULATE is possibly broken.\n");
+ r300->state.pixel_shader.program.alu.inst[alu_inst].inst0=
+ EASY_PFS_INSTR0(MAD, SRC0C_XYZ, SRC1C_XYZ, ZERO);
+
+ r300->state.pixel_shader.program.alu.inst[alu_inst].inst1=
+ EASY_PFS_INSTR1(0, 0, 1, 0 | PFS_FLAG_CONST, NONE, ALL);
+
+ break;
+ default:
+ WARN_ONCE("ModeRGB=%s is not implemented yet !\n",
+ _mesa_lookup_enum_by_nr(r300->radeon.glCtx->Texture.Unit[i]._CurrentCombine->ModeRGB));
+ /* PFS_NOP */
+ r300->state.pixel_shader.program.alu.inst[alu_inst].inst0=
+ EASY_PFS_INSTR0(MAD, SRC0C_XYZ, ONE, ZERO);
+
+ r300->state.pixel_shader.program.alu.inst[alu_inst].inst1=
+ EASY_PFS_INSTR1(0, 0, 0 | PFS_FLAG_CONST, 0 | PFS_FLAG_CONST, NONE, ALL);
+ }
+ switch(r300->radeon.glCtx->Texture.Unit[i]._CurrentCombine->ModeA){
+ case GL_REPLACE:
+ WARN_ONCE("ModeA==GL_REPLACE is possibly broken.\n");
+ r300->state.pixel_shader.program.alu.inst[alu_inst].inst2=
+ EASY_PFS_INSTR2(MAD, SRC0A, ONE, ZERO);
+
+ r300->state.pixel_shader.program.alu.inst[alu_inst].inst3=
+ EASY_PFS_INSTR3(0, 0, 0| PFS_FLAG_CONST, 0 | PFS_FLAG_CONST, OUTPUT);
+
+#if 0
+ fprintf(stderr, "numArgsA=%d sourceA[0]=%s op=%d\n",
+ r300->radeon.glCtx->Texture.Unit[i]._CurrentCombine->_NumArgsA,
+ _mesa_lookup_enum_by_nr(r300->radeon.glCtx->Texture.Unit[i]._CurrentCombine->SourceA[0]),
+ r300->radeon.glCtx->Texture.Unit[i]._CurrentCombine->OperandA[0]-GL_SRC_ALPHA);
+#endif
+ break;
+ case GL_MODULATE:
+ WARN_ONCE("ModeA==GL_MODULATE is possibly broken.\n");
+
+ r300->state.pixel_shader.program.alu.inst[alu_inst].inst2=
+ EASY_PFS_INSTR2(MAD, SRC0A, SRC1A, ZERO);
+
+ r300->state.pixel_shader.program.alu.inst[alu_inst].inst3=
+ EASY_PFS_INSTR3(0, 0, 1, 0 | PFS_FLAG_CONST, OUTPUT);
+
+ break;
+ default:
+ WARN_ONCE("ModeA=%s is not implemented yet !\n",
+ _mesa_lookup_enum_by_nr(r300->radeon.glCtx->Texture.Unit[i]._CurrentCombine->ModeA));
+ /* PFS_NOP */
+ r300->state.pixel_shader.program.alu.inst[alu_inst].inst2=
+ EASY_PFS_INSTR2(MAD, SRC0A, ONE, ZERO);
+
+ r300->state.pixel_shader.program.alu.inst[alu_inst].inst3=
+ EASY_PFS_INSTR3(0, 0, 0 | PFS_FLAG_CONST, 0 | PFS_FLAG_CONST, OUTPUT);
+
+ }
+
+ alu_inst++;
+ }
+
+ r300->state.pixel_shader.program.tex.length=tex_inst;
+ r300->state.pixel_shader.program.tex_offset=0;
+ r300->state.pixel_shader.program.tex_end=tex_inst-1;
+
+#if 0
+ /* saturate last instruction, like i915 driver does */
+ r300->state.pixel_shader.program.alu.inst[alu_inst-1].inst0|=R300_FPI0_OUTC_SAT;
+ r300->state.pixel_shader.program.alu.inst[alu_inst-1].inst2|=R300_FPI2_OUTA_SAT;
+#endif
+
+ r300->state.pixel_shader.program.alu.length=alu_inst;
+ r300->state.pixel_shader.program.alu_offset=0;
+ r300->state.pixel_shader.program.alu_end=alu_inst-1;
+}
+
+void r300SetupPixelShader(r300ContextPtr rmesa)
+{
+int i,k;
+
+ /* This needs to be replaced by pixel shader generation code */
+
+ /* textures enabled ? */
+ if(rmesa->state.texture.tc_count>0){
+#if 1
+ r300GenerateTextureFragmentShader(rmesa);
+#else
+ rmesa->state.pixel_shader=SINGLE_TEXTURE_PIXEL_SHADER;
+ r300GenerateTexturePixelShader(rmesa);
+#endif
+ } else {
+ rmesa->state.pixel_shader=FLAT_COLOR_PIXEL_SHADER;
+ }
+
+ R300_STATECHANGE(rmesa, fpt);
+ for(i=0;i<rmesa->state.pixel_shader.program.tex.length;i++)
+ rmesa->hw.fpt.cmd[R300_FPT_INSTR_0+i]=rmesa->state.pixel_shader.program.tex.inst[i];
+ rmesa->hw.fpt.cmd[R300_FPT_CMD_0]=cmdpacket0(R300_PFS_TEXI_0, rmesa->state.pixel_shader.program.tex.length);
+
+#define OUTPUT_FIELD(st, reg, field) \
+ R300_STATECHANGE(rmesa, st); \
+ for(i=0;i<rmesa->state.pixel_shader.program.alu.length;i++) \
+ rmesa->hw.st.cmd[R300_FPI_INSTR_0+i]=rmesa->state.pixel_shader.program.alu.inst[i].field;\
+ rmesa->hw.st.cmd[R300_FPI_CMD_0]=cmdpacket0(reg, rmesa->state.pixel_shader.program.alu.length);
+
+ OUTPUT_FIELD(fpi[0], R300_PFS_INSTR0_0, inst0);
+ OUTPUT_FIELD(fpi[1], R300_PFS_INSTR1_0, inst1);
+ OUTPUT_FIELD(fpi[2], R300_PFS_INSTR2_0, inst2);
+ OUTPUT_FIELD(fpi[3], R300_PFS_INSTR3_0, inst3);
+#undef OUTPUT_FIELD
+
+ R300_STATECHANGE(rmesa, fp);
+ for(i=0;i<4;i++){
+ rmesa->hw.fp.cmd[R300_FP_NODE0+i]=
+ (rmesa->state.pixel_shader.program.node[i].alu_offset << R300_PFS_NODE_ALU_OFFSET_SHIFT)
+ | (rmesa->state.pixel_shader.program.node[i].alu_end << R300_PFS_NODE_ALU_END_SHIFT)
+ | (rmesa->state.pixel_shader.program.node[i].tex_offset << R300_PFS_NODE_TEX_OFFSET_SHIFT)
+ | (rmesa->state.pixel_shader.program.node[i].tex_end << R300_PFS_NODE_TEX_END_SHIFT)
+ | ( (i==3) ? R300_PFS_NODE_LAST_NODE : 0);
+ }
+
+ /* PFS_CNTL_0 */
+ rmesa->hw.fp.cmd[R300_FP_CNTL0]=
+ (rmesa->state.pixel_shader.program.active_nodes-1)
+ | (rmesa->state.pixel_shader.program.first_node_has_tex<<3);
+ /* PFS_CNTL_1 */
+ rmesa->hw.fp.cmd[R300_FP_CNTL1]=rmesa->state.pixel_shader.program.temp_register_count;
+ /* PFS_CNTL_2 */
+ rmesa->hw.fp.cmd[R300_FP_CNTL2]=
+ (rmesa->state.pixel_shader.program.alu_offset << R300_PFS_CNTL_ALU_OFFSET_SHIFT)
+ | (rmesa->state.pixel_shader.program.alu_end << R300_PFS_CNTL_ALU_END_SHIFT)
+ | (rmesa->state.pixel_shader.program.tex_offset << R300_PFS_CNTL_TEX_OFFSET_SHIFT)
+ | (rmesa->state.pixel_shader.program.tex_end << R300_PFS_CNTL_TEX_END_SHIFT);
+
+ R300_STATECHANGE(rmesa, fpp);
+ for(i=0;i<rmesa->state.pixel_shader.param_length;i++){
+ rmesa->hw.fpp.cmd[R300_FPP_PARAM_0+4*i+0]=r300PackFloat32(rmesa->state.pixel_shader.param[i].x);
+ rmesa->hw.fpp.cmd[R300_FPP_PARAM_0+4*i+1]=r300PackFloat32(rmesa->state.pixel_shader.param[i].y);
+ rmesa->hw.fpp.cmd[R300_FPP_PARAM_0+4*i+2]=r300PackFloat32(rmesa->state.pixel_shader.param[i].z);
+ rmesa->hw.fpp.cmd[R300_FPP_PARAM_0+4*i+3]=r300PackFloat32(rmesa->state.pixel_shader.param[i].w);
+ }
+ rmesa->hw.fpp.cmd[R300_FPP_CMD_0]=cmdpacket0(R300_PFS_PARAM_0_X, rmesa->state.pixel_shader.param_length);
+
+}
+#endif
+
+/**
+ * Called by Mesa after an internal state update.
+ */
+static void r300InvalidateState(GLcontext * ctx, GLuint new_state)
+{
+ r300ContextPtr r300 = R300_CONTEXT(ctx);
+
+ _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);
+
+ /* Go inefficiency! */
+ r300ResetHwState(r300);
+}
+
+/* Checks that r300ResetHwState actually modifies all states.
+ Should probably be burried in somewhere else as this file is getting longish. */
+static void verify_r300ResetHwState(r300ContextPtr r300, int stage)
+{
+ struct r300_state_atom* atom;
+ int i;
+ drm_r300_cmd_header_t cmd;
+
+ if(stage){ /* mess around with states */
+ unsigned long fp1, cb1;
+
+ fp1=r300->hw.fp.cmd[R300_FP_CMD_1]; /* some special cases... */
+ cb1=r300->hw.cb.cmd[R300_CB_CMD_1];
+
+ fprintf(stderr, "verify begin:\n");
+
+ foreach(atom, &r300->hw.atomlist) {
+ for(i=1; i < (*atom->check)(r300, atom); i++)
+ atom->cmd[i]=0xdeadbeef;
+ }
+ r300->hw.fp.cmd[R300_FP_CMD_1]=fp1;
+ r300->hw.cb.cmd[R300_CB_CMD_1]=cb1;
+
+ foreach(atom, &r300->hw.atomlist) {
+ cmd.u=atom->cmd[0];
+ switch(cmd.header.cmd_type){
+ case R300_CMD_PACKET0:
+ case R300_CMD_VPU:
+ case R300_CMD_PACKET3:
+ case R300_CMD_END3D:
+ case R300_CMD_CP_DELAY:
+ case R300_CMD_DMA_DISCARD:
+ break;
+ default: fprintf(stderr, "unknown cmd_type %d in atom %s\n",
+ cmd.header.cmd_type, atom->name);
+ }
+
+ }
+ } else { /* check that they were set */
+ foreach(atom, &r300->hw.atomlist) {
+ for(i=1; i < (*atom->check)(r300, atom); i++)
+ if(atom->cmd[i]==0xdeadbeef)
+ fprintf(stderr, "atom %s is untouched\n", atom->name);
+ }
+ }
+}
+
+/**
+ * Completely recalculates hardware state based on the Mesa state.
+ */
+void r300ResetHwState(r300ContextPtr r300)
+{
+ GLcontext* ctx = r300->radeon.glCtx;
+ int i;
+
+ if (RADEON_DEBUG & DEBUG_STATE)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
+ //verify_r300ResetHwState(r300, 1);
+
+ /* This is a place to initialize registers which
+ have bitfields accessed by different functions
+ and not all bits are used */
+#if 0
+ /* initialize similiar to r200 */
+ r300->hw.zs.cmd[R300_ZS_CNTL_0] = 0;
+ r300->hw.zs.cmd[R300_ZS_CNTL_1] =
+ (R300_ZS_ALWAYS << R300_RB3D_ZS1_FRONT_FUNC_SHIFT) |
+ (R300_ZS_KEEP << R300_RB3D_ZS1_FRONT_FAIL_OP_SHIFT) |
+ (R300_ZS_KEEP << R300_RB3D_ZS1_FRONT_ZPASS_OP_SHIFT) |
+ (R300_ZS_KEEP << R300_RB3D_ZS1_FRONT_ZFAIL_OP_SHIFT) |
+ (R300_ZS_ALWAYS << R300_RB3D_ZS1_BACK_FUNC_SHIFT) |
+ (R300_ZS_KEEP << R300_RB3D_ZS1_BACK_FAIL_OP_SHIFT) |
+ (R300_ZS_KEEP << R300_RB3D_ZS1_BACK_ZPASS_OP_SHIFT) |
+ (R300_ZS_KEEP << R300_RB3D_ZS1_BACK_ZFAIL_OP_SHIFT);
+ r300->hw.zs.cmd[R300_ZS_CNTL_2] = 0x00ffff00;
+#endif
+
+ /* go and compute register values from GL state */
+
+ r300UpdateWindow(ctx);
+
+ r300ColorMask(ctx,
+ ctx->Color.ColorMask[RCOMP],
+ ctx->Color.ColorMask[GCOMP],
+ ctx->Color.ColorMask[BCOMP],
+ ctx->Color.ColorMask[ACOMP]);
+
+ r300Enable(ctx, GL_DEPTH_TEST, ctx->Depth.Test);
+ r300DepthMask(ctx, ctx->Depth.Mask);
+ r300DepthFunc(ctx, ctx->Depth.Func);
+
+ /* stencil */
+ r300Enable(ctx, GL_STENCIL_TEST, ctx->Stencil.Enabled);
+ r300StencilMask(ctx, ctx->Stencil.WriteMask[0]);
+ r300StencilFunc(ctx, ctx->Stencil.Function[0], ctx->Stencil.Ref[0], ctx->Stencil.ValueMask[0]);
+ r300StencilOp(ctx, ctx->Stencil.FailFunc[0], ctx->Stencil.ZFailFunc[0], ctx->Stencil.ZPassFunc[0]);
+
+ r300UpdateCulling(ctx);
+
+ r300UpdateTextureState(ctx);
+
+// r300_setup_routing(ctx, GL_TRUE);
+ if(hw_tcl_on == GL_FALSE){
+ r300EmitArrays(ctx, GL_TRUE); /* Just do the routing */
+ r300_setup_textures(ctx);
+ r300_setup_rs_unit(ctx);
+
+ r300SetupVertexShader(r300);
+ r300SetupPixelShader(r300);
+ }
+
+ r300_set_blend_state(ctx);
+
+ r300AlphaFunc(ctx, ctx->Color.AlphaFunc, ctx->Color.AlphaRef);
+ r300Enable(ctx, GL_ALPHA_TEST, ctx->Color.AlphaEnabled);
+
+ /* Initialize magic registers
+ TODO : learn what they really do, or get rid of
+ those we don't have to touch */
+ r300->hw.unk2080.cmd[1] = 0x0030045A; /* Dangerous */
+
+ r300->hw.vte.cmd[1] = R300_VPORT_X_SCALE_ENA
+ | R300_VPORT_X_OFFSET_ENA
+ | R300_VPORT_Y_SCALE_ENA
+ | R300_VPORT_Y_OFFSET_ENA
+ | R300_VPORT_Z_SCALE_ENA
+ | R300_VPORT_Z_OFFSET_ENA
+ | R300_VTX_W0_FMT;
+ r300->hw.vte.cmd[2] = 0x00000008;
+
+ r300->hw.unk2134.cmd[1] = 0x00FFFFFF;
+ r300->hw.unk2134.cmd[2] = 0x00000000;
+#ifdef MESA_BIG_ENDIAN
+ r300->hw.unk2140.cmd[1] = 0x00000002;
+#else
+ r300->hw.unk2140.cmd[1] = 0x00000000;
+#endif
+
+#if 0 /* Done in setup routing */
+ ((drm_r300_cmd_header_t*)r300->hw.vir[0].cmd)->packet0.count = 1;
+ r300->hw.vir[0].cmd[1] = 0x21030003;
+
+ ((drm_r300_cmd_header_t*)r300->hw.vir[1].cmd)->packet0.count = 1;
+ r300->hw.vir[1].cmd[1] = 0xF688F688;
+
+ r300->hw.vic.cmd[R300_VIR_CNTL_0] = 0x00000001;
+ r300->hw.vic.cmd[R300_VIR_CNTL_1] = 0x00000405;
+#endif
+
+ r300->hw.unk21DC.cmd[1] = 0xAAAAAAAA;
+
+ r300->hw.unk221C.cmd[1] = R300_221C_NORMAL;
+
+ r300->hw.unk2220.cmd[1] = r300PackFloat32(1.0);
+ r300->hw.unk2220.cmd[2] = r300PackFloat32(1.0);
+ r300->hw.unk2220.cmd[3] = r300PackFloat32(1.0);
+ r300->hw.unk2220.cmd[4] = r300PackFloat32(1.0);
+
+ if (GET_CHIP(r300->radeon.radeonScreen) == RADEON_CHIP_R300)
+ r300->hw.unk2288.cmd[1] = R300_2288_R300;
+ else
+ r300->hw.unk2288.cmd[1] = R300_2288_RV350;
+
+#if 0
+ r300->hw.vof.cmd[R300_VOF_CNTL_0] = R300_VAP_OUTPUT_VTX_FMT_0__POS_PRESENT
+ | R300_VAP_OUTPUT_VTX_FMT_0__COLOR_PRESENT;
+ r300->hw.vof.cmd[R300_VOF_CNTL_1] = 0; /* no textures */
+
+
+ r300->hw.pvs.cmd[R300_PVS_CNTL_1] = 0;
+ r300->hw.pvs.cmd[R300_PVS_CNTL_2] = 0;
+ r300->hw.pvs.cmd[R300_PVS_CNTL_3] = 0;
+#endif
+
+ r300->hw.gb_enable.cmd[1] = R300_GB_POINT_STUFF_ENABLE
+ | R300_GB_LINE_STUFF_ENABLE
+ | R300_GB_TRIANGLE_STUFF_ENABLE /*| R300_GB_UNK30*/;
+
+ r300->hw.gb_misc.cmd[R300_GB_MISC_MSPOS_0] = 0x66666666;
+ r300->hw.gb_misc.cmd[R300_GB_MISC_MSPOS_1] = 0x06666666;
+ if (GET_CHIP(r300->radeon.radeonScreen) == RADEON_CHIP_R300)
+ r300->hw.gb_misc.cmd[R300_GB_MISC_TILE_CONFIG] = R300_GB_TILE_ENABLE
+ | R300_GB_TILE_PIPE_COUNT_R300
+ | R300_GB_TILE_SIZE_16;
+ else if (GET_CHIP(r300->radeon.radeonScreen) == RADEON_CHIP_R420)
+ r300->hw.gb_misc.cmd[R300_GB_MISC_TILE_CONFIG] = R300_GB_TILE_ENABLE
+ | R300_GB_TILE_PIPE_COUNT_R420
+ | R300_GB_TILE_SIZE_16;
+ else
+ r300->hw.gb_misc.cmd[R300_GB_MISC_TILE_CONFIG] = R300_GB_TILE_ENABLE
+ | R300_GB_TILE_PIPE_COUNT_RV300
+ | R300_GB_TILE_SIZE_16;
+ r300->hw.gb_misc.cmd[R300_GB_MISC_SELECT] = 0x00000000;
+ r300->hw.gb_misc.cmd[R300_GB_MISC_AA_CONFIG] = 0x00000000; /* No antialiasing */
+
+ //r300->hw.txe.cmd[R300_TXE_ENABLE] = 0;
+
+ r300->hw.unk4200.cmd[1] = r300PackFloat32(0.0);
+ r300->hw.unk4200.cmd[2] = r300PackFloat32(0.0);
+ r300->hw.unk4200.cmd[3] = r300PackFloat32(1.0);
+ r300->hw.unk4200.cmd[4] = r300PackFloat32(1.0);
+
+ r300->hw.unk4214.cmd[1] = 0x00050005;
+
+ r300PointSize(ctx, 0.0);
+#if 0
+ r300->hw.ps.cmd[R300_PS_POINTSIZE] = (6 << R300_POINTSIZE_X_SHIFT) |
+ (6 << R300_POINTSIZE_Y_SHIFT);
+#endif
+
+ r300->hw.unk4230.cmd[1] = 0x01800000;//18000006;
+ r300->hw.unk4230.cmd[2] = 0x00020006;
+ r300->hw.unk4230.cmd[3] = r300PackFloat32(1.0 / 192.0);
+
+ r300LineWidth(ctx, 0.0);
+
+ r300->hw.unk4260.cmd[1] = 0;
+ r300->hw.unk4260.cmd[2] = r300PackFloat32(0.0);
+ r300->hw.unk4260.cmd[3] = r300PackFloat32(1.0);
+
+ r300->hw.unk4274.cmd[1] = 0x00000002;
+ r300ShadeModel(ctx, ctx->Light.ShadeModel);
+ r300->hw.unk4274.cmd[3] = 0x00000000;
+ r300->hw.unk4274.cmd[4] = 0x00000000;
+
+ r300PolygonMode(ctx, GL_FRONT, ctx->Polygon.FrontMode);
+ r300PolygonMode(ctx, GL_BACK, ctx->Polygon.BackMode);
+ r300->hw.unk4288.cmd[2] = 0x00000001;
+ r300->hw.unk4288.cmd[3] = 0x00000000;
+ r300->hw.unk4288.cmd[4] = 0x00000000;
+ r300->hw.unk4288.cmd[5] = 0x00000000;
+
+ r300->hw.unk42A0.cmd[1] = 0x00000000;
+
+ r300PolygonOffset(ctx, ctx->Polygon.OffsetFactor, ctx->Polygon.OffsetUnits);
+ r300Enable(ctx, GL_POLYGON_OFFSET_FILL, ctx->Polygon.OffsetFill);
+
+ r300->hw.unk42C0.cmd[1] = 0x4B7FFFFF;
+ r300->hw.unk42C0.cmd[2] = 0x00000000;
+
+
+ r300->hw.unk43A4.cmd[1] = 0x0000001C;
+ r300->hw.unk43A4.cmd[2] = 0x2DA49525;
+
+ r300->hw.unk43E8.cmd[1] = 0x00FFFFFF;
+
+#if 0
+ r300->hw.fp.cmd[R300_FP_CNTL0] = 0;
+ r300->hw.fp.cmd[R300_FP_CNTL1] = 0;
+ r300->hw.fp.cmd[R300_FP_CNTL2] = 0;
+ r300->hw.fp.cmd[R300_FP_NODE0] = 0;
+ r300->hw.fp.cmd[R300_FP_NODE1] = 0;
+ r300->hw.fp.cmd[R300_FP_NODE2] = 0;
+ r300->hw.fp.cmd[R300_FP_NODE3] = 0;
+#endif
+
+ r300->hw.unk46A4.cmd[1] = 0x00001B01;
+ r300->hw.unk46A4.cmd[2] = 0x00001B0F;
+ r300->hw.unk46A4.cmd[3] = 0x00001B0F;
+ r300->hw.unk46A4.cmd[4] = 0x00001B0F;
+ r300->hw.unk46A4.cmd[5] = 0x00000001;
+
+#if 0
+ for(i = 1; i <= 64; ++i) {
+ /* create NOP instructions */
+ r300->hw.fpi[0].cmd[i] = FP_INSTRC(MAD, FP_ARGC(SRC0C_XYZ), FP_ARGC(ONE), FP_ARGC(ZERO));
+ r300->hw.fpi[1].cmd[i] = FP_SELC(0,XYZ,NO,FP_TMP(0),0,0);
+ r300->hw.fpi[2].cmd[i] = FP_INSTRA(MAD, FP_ARGA(SRC0A), FP_ARGA(ONE), FP_ARGA(ZERO));
+ r300->hw.fpi[3].cmd[i] = FP_SELA(0,W,NO,FP_TMP(0),0,0);
+ }
+#endif
+
+ r300->hw.unk4BC0.cmd[1] = 0;
+
+ r300->hw.unk4BC8.cmd[1] = 0;
+ r300->hw.unk4BC8.cmd[2] = 0;
+ r300->hw.unk4BC8.cmd[3] = 0;
+
+
+ r300->hw.at.cmd[R300_AT_UNKNOWN] = 0;
+ r300->hw.unk4BD8.cmd[1] = 0;
+
+ r300->hw.unk4E00.cmd[1] = 0;
+
+#if 0
+ r300->hw.bld.cmd[R300_BLD_CBLEND] = 0;
+ r300->hw.bld.cmd[R300_BLD_ABLEND] = 0;
+#endif
+
+ r300BlendColor(ctx, ctx->Color.BlendColor);
+ r300->hw.unk4E10.cmd[2] = 0;
+ r300->hw.unk4E10.cmd[3] = 0;
+
+ /* Again, r300ClearBuffer uses this */
+ r300->hw.cb.cmd[R300_CB_OFFSET] = r300->radeon.state.color.drawOffset +
+ r300->radeon.radeonScreen->fbLocation;
+ r300->hw.cb.cmd[R300_CB_PITCH] = r300->radeon.state.color.drawPitch;
+
+ if (r300->radeon.radeonScreen->cpp == 4)
+ r300->hw.cb.cmd[R300_CB_PITCH] |= R300_COLOR_FORMAT_ARGB8888;
+ else
+ r300->hw.cb.cmd[R300_CB_PITCH] |= R300_COLOR_FORMAT_RGB565;
+
+ if (r300->radeon.sarea->tiling_enabled)
+ r300->hw.cb.cmd[R300_CB_PITCH] |= R300_COLOR_TILE_ENABLE;
+
+ r300->hw.unk4E50.cmd[1] = 0;
+ r300->hw.unk4E50.cmd[2] = 0;
+ r300->hw.unk4E50.cmd[3] = 0;
+ r300->hw.unk4E50.cmd[4] = 0;
+ r300->hw.unk4E50.cmd[5] = 0;
+ r300->hw.unk4E50.cmd[6] = 0;
+ r300->hw.unk4E50.cmd[7] = 0;
+ r300->hw.unk4E50.cmd[8] = 0;
+ r300->hw.unk4E50.cmd[9] = 0;
+
+ r300->hw.unk4E88.cmd[1] = 0;
+
+ r300->hw.unk4EA0.cmd[1] = 0x00000000;
+ r300->hw.unk4EA0.cmd[2] = 0xffffffff;
+
+ switch (ctx->Visual.depthBits) {
+ case 16:
+ r300->hw.unk4F10.cmd[1] = R300_DEPTH_FORMAT_16BIT_INT_Z;
+ break;
+ case 24:
+ r300->hw.unk4F10.cmd[1] = R300_DEPTH_FORMAT_24BIT_INT_Z;
+ break;
+ default:
+ fprintf(stderr, "Error: Unsupported depth %d... exiting\n",
+ ctx->Visual.depthBits);
+ exit(-1);
+
+ }
+ r300->hw.unk4F10.cmd[3] = 0x00000003;
+ r300->hw.unk4F10.cmd[4] = 0x00000000;
+
+ r300->hw.zb.cmd[R300_ZB_OFFSET] =
+ r300->radeon.radeonScreen->depthOffset +
+ r300->radeon.radeonScreen->fbLocation;
+ r300->hw.zb.cmd[R300_ZB_PITCH] = r300->radeon.radeonScreen->depthPitch;
+
+ if (r300->radeon.sarea->tiling_enabled) {
+ /* Turn off when clearing buffers ? */
+ r300->hw.zb.cmd[R300_ZB_PITCH] |= R300_DEPTH_TILE_ENABLE;
+
+ if (ctx->Visual.depthBits == 24)
+ r300->hw.zb.cmd[R300_ZB_PITCH] |= R300_DEPTH_MICROTILE_ENABLE;
+ }
+
+ r300->hw.unk4F28.cmd[1] = 0;
+
+ r300->hw.unk4F30.cmd[1] = 0;
+ r300->hw.unk4F30.cmd[2] = 0;
+
+ r300->hw.unk4F44.cmd[1] = 0;
+
+ r300->hw.unk4F54.cmd[1] = 0;
+
+#if 0
+ ((drm_r300_cmd_header_t*)r300->hw.vpi.cmd)->vpu.count = 0;
+ for(i = 1; i < R300_VPI_CMDSIZE; i += 4) {
+ /* MOV t0, t0 */
+ r300->hw.vpi.cmd[i+0] = VP_OUT(ADD,TMP,0,XYZW);
+ r300->hw.vpi.cmd[i+1] = VP_IN(TMP,0);
+ r300->hw.vpi.cmd[i+2] = VP_ZERO();
+ r300->hw.vpi.cmd[i+3] = VP_ZERO();
+ }
+
+ ((drm_r300_cmd_header_t*)r300->hw.vpp.cmd)->vpu.count = 0;
+ for(i = 1; i < R300_VPP_CMDSIZE; ++i)
+ r300->hw.vpp.cmd[i] = 0;
+#endif
+
+ r300->hw.vps.cmd[R300_VPS_ZERO_0] = 0;
+ r300->hw.vps.cmd[R300_VPS_ZERO_1] = 0;
+ r300->hw.vps.cmd[R300_VPS_POINTSIZE] = r300PackFloat32(1.0);
+ r300->hw.vps.cmd[R300_VPS_ZERO_3] = 0;
+
+//END: TODO
+ //verify_r300ResetHwState(r300, 0);
+ r300->hw.all_dirty = GL_TRUE;
+}
+
+
+
+/**
+ * Calculate initial hardware state and register state functions.
+ * Assumes that the command buffer and state atoms have been
+ * initialized already.
+ */
+void r300InitState(r300ContextPtr r300)
+{
+ GLcontext *ctx = r300->radeon.glCtx;
+ GLuint depth_fmt;
+
+ radeonInitState(&r300->radeon);
+
+ switch (ctx->Visual.depthBits) {
+ case 16:
+ r300->state.depth.scale = 1.0 / (GLfloat) 0xffff;
+ depth_fmt = R200_DEPTH_FORMAT_16BIT_INT_Z;
+ r300->state.stencil.clear = 0x00000000;
+ break;
+ case 24:
+ r300->state.depth.scale = 1.0 / (GLfloat) 0xffffff;
+ depth_fmt = R200_DEPTH_FORMAT_24BIT_INT_Z;
+ r300->state.stencil.clear = 0x00ff0000;
+ 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 */
+ r300->state.stencil.hw_stencil = (ctx->Visual.stencilBits > 0 &&
+ ctx->Visual.depthBits == 24);
+
+ memset(&(r300->state.texture), 0, sizeof(r300->state.texture));
+
+ r300ResetHwState(r300);
+}
+
+static void r300RenderMode( GLcontext *ctx, GLenum mode )
+{
+ r300ContextPtr rmesa = R300_CONTEXT(ctx);
+ WARN_ONCE("TODO: fallback properly when rendering mode is not GL_RENDER\n"
+ "\tThe way things are now neither selection nor feedback modes work\n")
+// FALLBACK( rmesa, R300_FALLBACK_RENDER_MODE, (mode != GL_RENDER) );
+}
+
+/**
+ * Initialize driver's state callback functions
+ */
+void r300InitStateFuncs(struct dd_function_table* functions)
+{
+ radeonInitStateFuncs(functions);
+
+ functions->UpdateState = r300InvalidateState;
+ functions->AlphaFunc = r300AlphaFunc;
+ functions->BlendColor = r300BlendColor;
+ functions->BlendEquationSeparate = r300BlendEquationSeparate;
+ functions->BlendFuncSeparate = r300BlendFuncSeparate;
+ functions->Enable = r300Enable;
+ functions->ColorMask = r300ColorMask;
+ functions->DepthFunc = r300DepthFunc;
+ functions->DepthMask = r300DepthMask;
+ functions->CullFace = r300CullFace;
+ functions->FrontFace = r300FrontFace;
+ functions->ShadeModel = r300ShadeModel;
+
+ /* Stencil related */
+ functions->ClearStencil = r300ClearStencil;
+ functions->StencilFunc = r300StencilFunc;
+ functions->StencilMask = r300StencilMask;
+ functions->StencilOp = r300StencilOp;
+
+ /* Viewport related */
+ functions->Viewport = r300Viewport;
+ functions->DepthRange = r300DepthRange;
+ functions->PointSize = r300PointSize;
+ functions->LineWidth = r300LineWidth;
+
+ functions->PolygonOffset = r300PolygonOffset;
+ functions->PolygonMode = r300PolygonMode;
+
+ functions->RenderMode = r300RenderMode;
+}
+