| /* |
| 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. |
| |
| **************************************************************************/ |
| |
| /** |
| * \file |
| * |
| * \author 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 "shader/prog_parameter.h" |
| #include "shader/prog_statevars.h" |
| #include "vbo/vbo.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_emit.h" |
| #include "r300_fragprog.h" |
| #include "r300_tex.h" |
| |
| #include "drirenderbuffer.h" |
| |
| extern int future_hw_tcl_on; |
| extern void _tnl_UpdateFixedFunctionProgram(GLcontext * ctx); |
| |
| static void r300BlendColor(GLcontext * ctx, const GLfloat cf[4]) |
| { |
| r300ContextPtr rmesa = R300_CONTEXT(ctx); |
| |
| R300_STATECHANGE(rmesa, blend_color); |
| |
| if (rmesa->radeon.radeonScreen->chip_family >= CHIP_FAMILY_RV515) { |
| GLuint r = IROUND(cf[0]*1023.0f); |
| GLuint g = IROUND(cf[1]*1023.0f); |
| GLuint b = IROUND(cf[2]*1023.0f); |
| GLuint a = IROUND(cf[3]*1023.0f); |
| |
| rmesa->hw.blend_color.cmd[1] = r | (a << 16); |
| rmesa->hw.blend_color.cmd[2] = b | (g << 16); |
| } else { |
| GLubyte color[4]; |
| 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.blend_color.cmd[1] = PACK_COLOR_8888(color[3], color[0], |
| color[1], color[2]); |
| } |
| } |
| |
| /** |
| * 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) |
| { |
| switch (factor) { |
| case GL_ZERO: |
| return R300_BLEND_GL_ZERO; |
| break; |
| case GL_ONE: |
| return R300_BLEND_GL_ONE; |
| break; |
| case GL_DST_COLOR: |
| return R300_BLEND_GL_DST_COLOR; |
| break; |
| case GL_ONE_MINUS_DST_COLOR: |
| return R300_BLEND_GL_ONE_MINUS_DST_COLOR; |
| break; |
| case GL_SRC_COLOR: |
| return R300_BLEND_GL_SRC_COLOR; |
| break; |
| case GL_ONE_MINUS_SRC_COLOR: |
| return R300_BLEND_GL_ONE_MINUS_SRC_COLOR; |
| break; |
| case GL_SRC_ALPHA: |
| return R300_BLEND_GL_SRC_ALPHA; |
| break; |
| case GL_ONE_MINUS_SRC_ALPHA: |
| return R300_BLEND_GL_ONE_MINUS_SRC_ALPHA; |
| break; |
| case GL_DST_ALPHA: |
| return R300_BLEND_GL_DST_ALPHA; |
| break; |
| case GL_ONE_MINUS_DST_ALPHA: |
| return R300_BLEND_GL_ONE_MINUS_DST_ALPHA; |
| break; |
| case GL_SRC_ALPHA_SATURATE: |
| return (is_src) ? R300_BLEND_GL_SRC_ALPHA_SATURATE : |
| R300_BLEND_GL_ZERO; |
| break; |
| case GL_CONSTANT_COLOR: |
| return R300_BLEND_GL_CONST_COLOR; |
| break; |
| case GL_ONE_MINUS_CONSTANT_COLOR: |
| return R300_BLEND_GL_ONE_MINUS_CONST_COLOR; |
| break; |
| case GL_CONSTANT_ALPHA: |
| return R300_BLEND_GL_CONST_ALPHA; |
| break; |
| case GL_ONE_MINUS_CONSTANT_ALPHA: |
| return R300_BLEND_GL_ONE_MINUS_CONST_ALPHA; |
| break; |
| default: |
| fprintf(stderr, "unknown blend factor %x\n", factor); |
| return (is_src) ? R300_BLEND_GL_ONE : R300_BLEND_GL_ZERO; |
| break; |
| } |
| } |
| |
| /** |
| * 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 r300SetBlendCntl(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_DISCARD_SRC_PIXELS_SRC_ALPHA_0; |
| } |
| #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 r300SetBlendState(GLcontext * ctx) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| int func = (R300_BLEND_GL_ONE << R300_SRC_BLEND_SHIFT) | |
| (R300_BLEND_GL_ZERO << R300_DST_BLEND_SHIFT); |
| int eqn = R300_COMB_FCN_ADD_CLAMP; |
| int funcA = (R300_BLEND_GL_ONE << R300_SRC_BLEND_SHIFT) | |
| (R300_BLEND_GL_ZERO << R300_DST_BLEND_SHIFT); |
| int eqnA = R300_COMB_FCN_ADD_CLAMP; |
| |
| if (RGBA_LOGICOP_ENABLED(ctx) || !ctx->Color.BlendEnabled) { |
| r300SetBlendCntl(r300, func, eqn, 0, func, eqn); |
| return; |
| } |
| |
| func = |
| (blend_factor(ctx->Color.BlendSrcRGB, GL_TRUE) << |
| R300_SRC_BLEND_SHIFT) | (blend_factor(ctx->Color.BlendDstRGB, |
| GL_FALSE) << |
| R300_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 = R300_COMB_FCN_RSUB_CLAMP; |
| break; |
| |
| case GL_MIN: |
| eqn = R300_COMB_FCN_MIN; |
| func = (R300_BLEND_GL_ONE << R300_SRC_BLEND_SHIFT) | |
| (R300_BLEND_GL_ONE << R300_DST_BLEND_SHIFT); |
| break; |
| |
| case GL_MAX: |
| eqn = R300_COMB_FCN_MAX; |
| func = (R300_BLEND_GL_ONE << R300_SRC_BLEND_SHIFT) | |
| (R300_BLEND_GL_ONE << R300_DST_BLEND_SHIFT); |
| break; |
| |
| default: |
| fprintf(stderr, |
| "[%s:%u] Invalid RGB blend equation (0x%04x).\n", |
| __FUNCTION__, __LINE__, ctx->Color.BlendEquationRGB); |
| return; |
| } |
| |
| funcA = |
| (blend_factor(ctx->Color.BlendSrcA, GL_TRUE) << |
| R300_SRC_BLEND_SHIFT) | (blend_factor(ctx->Color.BlendDstA, |
| GL_FALSE) << |
| R300_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 = R300_COMB_FCN_RSUB_CLAMP; |
| break; |
| |
| case GL_MIN: |
| eqnA = R300_COMB_FCN_MIN; |
| funcA = (R300_BLEND_GL_ONE << R300_SRC_BLEND_SHIFT) | |
| (R300_BLEND_GL_ONE << R300_DST_BLEND_SHIFT); |
| break; |
| |
| case GL_MAX: |
| eqnA = R300_COMB_FCN_MAX; |
| funcA = (R300_BLEND_GL_ONE << R300_SRC_BLEND_SHIFT) | |
| (R300_BLEND_GL_ONE << R300_DST_BLEND_SHIFT); |
| break; |
| |
| default: |
| fprintf(stderr, |
| "[%s:%u] Invalid A blend equation (0x%04x).\n", |
| __FUNCTION__, __LINE__, ctx->Color.BlendEquationA); |
| return; |
| } |
| |
| r300SetBlendCntl(r300, |
| func, eqn, |
| (R300_SEPARATE_ALPHA_ENABLE | |
| R300_READ_ENABLE | |
| R300_ALPHA_BLEND_ENABLE), funcA, eqnA); |
| } |
| |
| static void r300BlendEquationSeparate(GLcontext * ctx, |
| GLenum modeRGB, GLenum modeA) |
| { |
| r300SetBlendState(ctx); |
| } |
| |
| static void r300BlendFuncSeparate(GLcontext * ctx, |
| GLenum sfactorRGB, GLenum dfactorRGB, |
| GLenum sfactorA, GLenum dfactorA) |
| { |
| r300SetBlendState(ctx); |
| } |
| |
| /** |
| * Translate LogicOp enums into hardware representation. |
| * Both use a very logical bit-wise layout, but unfortunately the order |
| * of bits is reversed. |
| */ |
| static GLuint translate_logicop(GLenum logicop) |
| { |
| GLuint bits = logicop - GL_CLEAR; |
| bits = ((bits & 1) << 3) | ((bits & 2) << 1) | ((bits & 4) >> 1) | ((bits & 8) >> 3); |
| return bits << R300_RB3D_ROPCNTL_ROP_SHIFT; |
| } |
| |
| /** |
| * Used internally to update the r300->hw hardware state to match the |
| * current OpenGL state. |
| */ |
| static void r300SetLogicOpState(GLcontext *ctx) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| R300_STATECHANGE(r300, rop); |
| if (RGBA_LOGICOP_ENABLED(ctx)) { |
| r300->hw.rop.cmd[1] = R300_RB3D_ROPCNTL_ROP_ENABLE | |
| translate_logicop(ctx->Color.LogicOp); |
| } else { |
| r300->hw.rop.cmd[1] = 0; |
| } |
| } |
| |
| /** |
| * Called by Mesa when an application program changes the LogicOp state |
| * via glLogicOp. |
| */ |
| static void r300LogicOpcode(GLcontext *ctx, GLenum logicop) |
| { |
| if (RGBA_LOGICOP_ENABLED(ctx)) |
| r300SetLogicOpState(ctx); |
| } |
| |
| static void r300ClipPlane( GLcontext *ctx, GLenum plane, const GLfloat *eq ) |
| { |
| r300ContextPtr rmesa = R300_CONTEXT(ctx); |
| GLint p; |
| GLint *ip; |
| |
| /* no VAP UCP on non-TCL chipsets */ |
| if (!(rmesa->radeon.radeonScreen->chip_flags & RADEON_CHIPSET_TCL)) |
| return; |
| |
| p = (GLint) plane - (GLint) GL_CLIP_PLANE0; |
| ip = (GLint *)ctx->Transform._ClipUserPlane[p]; |
| |
| R300_STATECHANGE( rmesa, vpucp[p] ); |
| rmesa->hw.vpucp[p].cmd[R300_VPUCP_X] = ip[0]; |
| rmesa->hw.vpucp[p].cmd[R300_VPUCP_Y] = ip[1]; |
| rmesa->hw.vpucp[p].cmd[R300_VPUCP_Z] = ip[2]; |
| rmesa->hw.vpucp[p].cmd[R300_VPUCP_W] = ip[3]; |
| } |
| |
| static void r300SetClipPlaneState(GLcontext * ctx, GLenum cap, GLboolean state) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| GLuint p; |
| |
| /* no VAP UCP on non-TCL chipsets */ |
| if (!(r300->radeon.radeonScreen->chip_flags & RADEON_CHIPSET_TCL)) |
| return; |
| |
| p = cap - GL_CLIP_PLANE0; |
| R300_STATECHANGE(r300, vap_clip_cntl); |
| if (state) { |
| r300->hw.vap_clip_cntl.cmd[1] |= (R300_VAP_UCP_ENABLE_0 << p); |
| r300ClipPlane(ctx, cap, NULL); |
| } else { |
| r300->hw.vap_clip_cntl.cmd[1] &= ~(R300_VAP_UCP_ENABLE_0 << p); |
| } |
| } |
| |
| /** |
| * Update our tracked culling state based on Mesa's state. |
| */ |
| static void r300UpdateCulling(GLcontext * ctx) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| uint32_t val = 0; |
| |
| if (ctx->Polygon.CullFlag) { |
| switch (ctx->Polygon.CullFaceMode) { |
| case GL_FRONT: |
| val = R300_CULL_FRONT; |
| break; |
| case GL_BACK: |
| val = R300_CULL_BACK; |
| break; |
| case GL_FRONT_AND_BACK: |
| val = R300_CULL_FRONT | R300_CULL_BACK; |
| break; |
| default: |
| break; |
| } |
| } |
| |
| switch (ctx->Polygon.FrontFace) { |
| case GL_CW: |
| val |= R300_FRONT_FACE_CW; |
| break; |
| case GL_CCW: |
| val |= R300_FRONT_FACE_CCW; |
| break; |
| default: |
| break; |
| } |
| |
| R300_STATECHANGE(r300, cul); |
| r300->hw.cul.cmd[R300_CUL_CULL] = val; |
| } |
| |
| static void r300SetPolygonOffsetState(GLcontext * ctx, GLboolean state) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| |
| R300_STATECHANGE(r300, occlusion_cntl); |
| if (state) { |
| r300->hw.occlusion_cntl.cmd[1] |= (3 << 0); |
| } else { |
| r300->hw.occlusion_cntl.cmd[1] &= ~(3 << 0); |
| } |
| } |
| |
| static GLboolean current_fragment_program_writes_depth(GLcontext* ctx) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| |
| if (r300->radeon.radeonScreen->chip_family < CHIP_FAMILY_RV515) { |
| struct r300_fragment_program *fp = (struct r300_fragment_program *) |
| (char *)ctx->FragmentProgram._Current; |
| return (fp && fp->WritesDepth); |
| } else { |
| struct r500_fragment_program* fp = |
| (struct r500_fragment_program*)(char*) |
| ctx->FragmentProgram._Current; |
| return (fp && fp->writes_depth); |
| } |
| } |
| |
| static void r300SetEarlyZState(GLcontext * ctx) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| GLuint topZ = R300_ZTOP_ENABLE; |
| |
| if (ctx->Color.AlphaEnabled && ctx->Color.AlphaFunc != GL_ALWAYS) |
| topZ = R300_ZTOP_DISABLE; |
| if (current_fragment_program_writes_depth(ctx)) |
| topZ = R300_ZTOP_DISABLE; |
| |
| if (topZ != r300->hw.zstencil_format.cmd[2]) { |
| /* Note: This completely reemits the stencil format. |
| * I have not tested whether this is strictly necessary, |
| * or if emitting a write to ZB_ZTOP is enough. |
| */ |
| R300_STATECHANGE(r300, zstencil_format); |
| r300->hw.zstencil_format.cmd[2] = topZ; |
| } |
| } |
| |
| static void r300SetAlphaState(GLcontext * ctx) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| GLubyte refByte; |
| uint32_t pp_misc = 0x0; |
| GLboolean really_enabled = ctx->Color.AlphaEnabled; |
| |
| CLAMPED_FLOAT_TO_UBYTE(refByte, ctx->Color.AlphaRef); |
| |
| switch (ctx->Color.AlphaFunc) { |
| case GL_NEVER: |
| pp_misc |= R300_FG_ALPHA_FUNC_NEVER; |
| break; |
| case GL_LESS: |
| pp_misc |= R300_FG_ALPHA_FUNC_LESS; |
| break; |
| case GL_EQUAL: |
| pp_misc |= R300_FG_ALPHA_FUNC_EQUAL; |
| break; |
| case GL_LEQUAL: |
| pp_misc |= R300_FG_ALPHA_FUNC_LE; |
| break; |
| case GL_GREATER: |
| pp_misc |= R300_FG_ALPHA_FUNC_GREATER; |
| break; |
| case GL_NOTEQUAL: |
| pp_misc |= R300_FG_ALPHA_FUNC_NOTEQUAL; |
| break; |
| case GL_GEQUAL: |
| pp_misc |= R300_FG_ALPHA_FUNC_GE; |
| break; |
| case GL_ALWAYS: |
| /*pp_misc |= FG_ALPHA_FUNC_ALWAYS; */ |
| really_enabled = GL_FALSE; |
| break; |
| } |
| |
| if (really_enabled) { |
| pp_misc |= R300_FG_ALPHA_FUNC_ENABLE; |
| pp_misc |= R500_FG_ALPHA_FUNC_8BIT; |
| pp_misc |= (refByte & R300_FG_ALPHA_FUNC_VAL_MASK); |
| } else { |
| pp_misc = 0x0; |
| } |
| |
| R300_STATECHANGE(r300, at); |
| r300->hw.at.cmd[R300_AT_ALPHA_TEST] = pp_misc; |
| r300->hw.at.cmd[R300_AT_UNKNOWN] = 0; |
| |
| r300SetEarlyZState(ctx); |
| } |
| |
| static void r300AlphaFunc(GLcontext * ctx, GLenum func, GLfloat ref) |
| { |
| (void)func; |
| (void)ref; |
| r300SetAlphaState(ctx); |
| } |
| |
| static int translate_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 void r300SetDepthState(GLcontext * ctx) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| |
| R300_STATECHANGE(r300, zs); |
| r300->hw.zs.cmd[R300_ZS_CNTL_0] &= R300_STENCIL_ENABLE|R300_STENCIL_FRONT_BACK; |
| r300->hw.zs.cmd[R300_ZS_CNTL_1] &= ~(R300_ZS_MASK << R300_Z_FUNC_SHIFT); |
| |
| if (ctx->Depth.Test) { |
| r300->hw.zs.cmd[R300_ZS_CNTL_0] |= R300_Z_ENABLE; |
| if (ctx->Depth.Mask) |
| r300->hw.zs.cmd[R300_ZS_CNTL_0] |= R300_Z_WRITE_ENABLE; |
| r300->hw.zs.cmd[R300_ZS_CNTL_1] |= |
| translate_func(ctx->Depth.Func) << R300_Z_FUNC_SHIFT; |
| } |
| |
| r300SetEarlyZState(ctx); |
| } |
| |
| static void r300SetStencilState(GLcontext * ctx, GLboolean state) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| |
| if (r300->state.stencil.hw_stencil) { |
| R300_STATECHANGE(r300, zs); |
| if (state) { |
| r300->hw.zs.cmd[R300_ZS_CNTL_0] |= |
| R300_STENCIL_ENABLE; |
| } else { |
| r300->hw.zs.cmd[R300_ZS_CNTL_0] &= |
| ~R300_STENCIL_ENABLE; |
| } |
| } else { |
| #if R200_MERGED |
| FALLBACK(&r300->radeon, RADEON_FALLBACK_STENCIL, state); |
| #endif |
| } |
| } |
| |
| static void r300UpdatePolygonMode(GLcontext * ctx) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| uint32_t hw_mode = R300_GA_POLY_MODE_DISABLE; |
| |
| /* Only do something if a polygon mode is wanted, default is GL_FILL */ |
| if (ctx->Polygon.FrontMode != GL_FILL || |
| ctx->Polygon.BackMode != GL_FILL) { |
| GLenum f, b; |
| |
| /* Handle GL_CW (clock wise and GL_CCW (counter clock wise) |
| * correctly by selecting the correct front and back face |
| */ |
| if (ctx->Polygon.FrontFace == GL_CCW) { |
| f = ctx->Polygon.FrontMode; |
| b = ctx->Polygon.BackMode; |
| } else { |
| f = ctx->Polygon.BackMode; |
| b = ctx->Polygon.FrontMode; |
| } |
| |
| /* Enable polygon mode */ |
| hw_mode |= R300_GA_POLY_MODE_DUAL; |
| |
| switch (f) { |
| case GL_LINE: |
| hw_mode |= R300_GA_POLY_MODE_FRONT_PTYPE_LINE; |
| break; |
| case GL_POINT: |
| hw_mode |= R300_GA_POLY_MODE_FRONT_PTYPE_POINT; |
| break; |
| case GL_FILL: |
| hw_mode |= R300_GA_POLY_MODE_FRONT_PTYPE_TRI; |
| break; |
| } |
| |
| switch (b) { |
| case GL_LINE: |
| hw_mode |= R300_GA_POLY_MODE_BACK_PTYPE_LINE; |
| break; |
| case GL_POINT: |
| hw_mode |= R300_GA_POLY_MODE_BACK_PTYPE_POINT; |
| break; |
| case GL_FILL: |
| hw_mode |= R300_GA_POLY_MODE_BACK_PTYPE_TRI; |
| break; |
| } |
| } |
| |
| if (r300->hw.polygon_mode.cmd[1] != hw_mode) { |
| R300_STATECHANGE(r300, polygon_mode); |
| r300->hw.polygon_mode.cmd[1] = hw_mode; |
| } |
| |
| r300->hw.polygon_mode.cmd[2] = 0x00000001; |
| r300->hw.polygon_mode.cmd[3] = 0x00000000; |
| } |
| |
| /** |
| * 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) |
| { |
| (void)func; |
| r300SetDepthState(ctx); |
| } |
| |
| /** |
| * Enable/Disable depth writing. |
| * |
| * \note Mesa already filters redundant calls to this function. |
| */ |
| static void r300DepthMask(GLcontext * ctx, GLboolean mask) |
| { |
| (void)mask; |
| r300SetDepthState(ctx); |
| } |
| |
| /** |
| * Handle glColorMask() |
| */ |
| static void r300ColorMask(GLcontext * ctx, |
| GLboolean r, GLboolean g, GLboolean b, GLboolean a) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| int mask = (r ? RB3D_COLOR_CHANNEL_MASK_RED_MASK0 : 0) | |
| (g ? RB3D_COLOR_CHANNEL_MASK_GREEN_MASK0 : 0) | |
| (b ? RB3D_COLOR_CHANNEL_MASK_BLUE_MASK0 : 0) | |
| (a ? RB3D_COLOR_CHANNEL_MASK_ALPHA_MASK0 : 0); |
| |
| if (mask != r300->hw.cmk.cmd[R300_CMK_COLORMASK]) { |
| R300_STATECHANGE(r300, cmk); |
| r300->hw.cmk.cmd[R300_CMK_COLORMASK] = mask; |
| } |
| } |
| |
| /* ============================================================= |
| * Fog |
| */ |
| static void r300Fogfv(GLcontext * ctx, GLenum pname, const GLfloat * param) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| union { |
| int i; |
| float f; |
| } fogScale, fogStart; |
| |
| (void)param; |
| |
| fogScale.i = r300->hw.fogp.cmd[R300_FOGP_SCALE]; |
| fogStart.i = r300->hw.fogp.cmd[R300_FOGP_START]; |
| |
| switch (pname) { |
| case GL_FOG_MODE: |
| switch (ctx->Fog.Mode) { |
| case GL_LINEAR: |
| R300_STATECHANGE(r300, fogs); |
| r300->hw.fogs.cmd[R300_FOGS_STATE] = |
| (r300->hw.fogs. |
| cmd[R300_FOGS_STATE] & ~R300_FG_FOG_BLEND_FN_MASK) | |
| R300_FG_FOG_BLEND_FN_LINEAR; |
| |
| if (ctx->Fog.Start == ctx->Fog.End) { |
| fogScale.f = -1.0; |
| fogStart.f = 1.0; |
| } else { |
| fogScale.f = |
| 1.0 / (ctx->Fog.End - ctx->Fog.Start); |
| fogStart.f = |
| -ctx->Fog.Start / (ctx->Fog.End - |
| ctx->Fog.Start); |
| } |
| break; |
| case GL_EXP: |
| R300_STATECHANGE(r300, fogs); |
| r300->hw.fogs.cmd[R300_FOGS_STATE] = |
| (r300->hw.fogs. |
| cmd[R300_FOGS_STATE] & ~R300_FG_FOG_BLEND_FN_MASK) | |
| R300_FG_FOG_BLEND_FN_EXP; |
| fogScale.f = 0.0933 * ctx->Fog.Density; |
| fogStart.f = 0.0; |
| break; |
| case GL_EXP2: |
| R300_STATECHANGE(r300, fogs); |
| r300->hw.fogs.cmd[R300_FOGS_STATE] = |
| (r300->hw.fogs. |
| cmd[R300_FOGS_STATE] & ~R300_FG_FOG_BLEND_FN_MASK) | |
| R300_FG_FOG_BLEND_FN_EXP2; |
| fogScale.f = 0.3 * ctx->Fog.Density; |
| fogStart.f = 0.0; |
| default: |
| return; |
| } |
| break; |
| case GL_FOG_DENSITY: |
| switch (ctx->Fog.Mode) { |
| case GL_EXP: |
| fogScale.f = 0.0933 * ctx->Fog.Density; |
| fogStart.f = 0.0; |
| break; |
| case GL_EXP2: |
| fogScale.f = 0.3 * ctx->Fog.Density; |
| fogStart.f = 0.0; |
| default: |
| break; |
| } |
| break; |
| case GL_FOG_START: |
| case GL_FOG_END: |
| if (ctx->Fog.Mode == GL_LINEAR) { |
| if (ctx->Fog.Start == ctx->Fog.End) { |
| fogScale.f = -1.0; |
| fogStart.f = 1.0; |
| } else { |
| fogScale.f = |
| 1.0 / (ctx->Fog.End - ctx->Fog.Start); |
| fogStart.f = |
| -ctx->Fog.Start / (ctx->Fog.End - |
| ctx->Fog.Start); |
| } |
| } |
| break; |
| case GL_FOG_COLOR: |
| R300_STATECHANGE(r300, fogc); |
| r300->hw.fogc.cmd[R300_FOGC_R] = |
| (GLuint) (ctx->Fog.Color[0] * 1023.0F) & 0x3FF; |
| r300->hw.fogc.cmd[R300_FOGC_G] = |
| (GLuint) (ctx->Fog.Color[1] * 1023.0F) & 0x3FF; |
| r300->hw.fogc.cmd[R300_FOGC_B] = |
| (GLuint) (ctx->Fog.Color[2] * 1023.0F) & 0x3FF; |
| break; |
| case GL_FOG_COORD_SRC: |
| break; |
| default: |
| return; |
| } |
| |
| if (fogScale.i != r300->hw.fogp.cmd[R300_FOGP_SCALE] || |
| fogStart.i != r300->hw.fogp.cmd[R300_FOGP_START]) { |
| R300_STATECHANGE(r300, fogp); |
| r300->hw.fogp.cmd[R300_FOGP_SCALE] = fogScale.i; |
| r300->hw.fogp.cmd[R300_FOGP_START] = fogStart.i; |
| } |
| } |
| |
| static void r300SetFogState(GLcontext * ctx, GLboolean state) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| |
| R300_STATECHANGE(r300, fogs); |
| if (state) { |
| r300->hw.fogs.cmd[R300_FOGS_STATE] |= R300_FG_FOG_BLEND_ENABLE; |
| |
| r300Fogfv(ctx, GL_FOG_MODE, NULL); |
| r300Fogfv(ctx, GL_FOG_DENSITY, &ctx->Fog.Density); |
| r300Fogfv(ctx, GL_FOG_START, &ctx->Fog.Start); |
| r300Fogfv(ctx, GL_FOG_END, &ctx->Fog.End); |
| r300Fogfv(ctx, GL_FOG_COLOR, ctx->Fog.Color); |
| } else { |
| r300->hw.fogs.cmd[R300_FOGS_STATE] &= ~R300_FG_FOG_BLEND_ENABLE; |
| } |
| } |
| |
| /* ============================================================= |
| * Point state |
| */ |
| static void r300PointSize(GLcontext * ctx, GLfloat size) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| /* same size limits for AA, non-AA points */ |
| size = CLAMP(size, ctx->Const.MinPointSize, ctx->Const.MaxPointSize); |
| |
| 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); |
| } |
| |
| static void r300PointParameter(GLcontext * ctx, GLenum pname, const GLfloat * param) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| |
| switch (pname) { |
| case GL_POINT_SIZE_MIN: |
| R300_STATECHANGE(r300, ga_point_minmax); |
| r300->hw.ga_point_minmax.cmd[1] &= ~R300_GA_POINT_MINMAX_MIN_MASK; |
| r300->hw.ga_point_minmax.cmd[1] |= (GLuint)(ctx->Point.MinSize * 6.0); |
| break; |
| case GL_POINT_SIZE_MAX: |
| R300_STATECHANGE(r300, ga_point_minmax); |
| r300->hw.ga_point_minmax.cmd[1] &= ~R300_GA_POINT_MINMAX_MAX_MASK; |
| r300->hw.ga_point_minmax.cmd[1] |= (GLuint)(ctx->Point.MaxSize * 6.0) |
| << R300_GA_POINT_MINMAX_MAX_SHIFT; |
| break; |
| case GL_POINT_DISTANCE_ATTENUATION: |
| break; |
| case GL_POINT_FADE_THRESHOLD_SIZE: |
| break; |
| default: |
| break; |
| } |
| } |
| |
| /* ============================================================= |
| * Line state |
| */ |
| static void r300LineWidth(GLcontext * ctx, GLfloat widthf) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| |
| widthf = CLAMP(widthf, |
| ctx->Const.MinPointSize, |
| ctx->Const.MaxPointSize); |
| R300_STATECHANGE(r300, lcntl); |
| r300->hw.lcntl.cmd[1] = |
| R300_LINE_CNT_HO | R300_LINE_CNT_VE | (int)(widthf * 6.0); |
| } |
| |
| static void r300PolygonMode(GLcontext * ctx, GLenum face, GLenum mode) |
| { |
| (void)face; |
| (void)mode; |
| |
| r300UpdatePolygonMode(ctx); |
| } |
| |
| /* ============================================================= |
| * Stencil |
| */ |
| |
| 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, shade); |
| rmesa->hw.shade.cmd[1] = 0x00000002; |
| switch (mode) { |
| case GL_FLAT: |
| rmesa->hw.shade.cmd[2] = R300_RE_SHADE_MODEL_FLAT; |
| break; |
| case GL_SMOOTH: |
| rmesa->hw.shade.cmd[2] = R300_RE_SHADE_MODEL_SMOOTH; |
| break; |
| default: |
| return; |
| } |
| rmesa->hw.shade.cmd[3] = 0x00000000; |
| rmesa->hw.shade.cmd[4] = 0x00000000; |
| } |
| |
| static void r300StencilFuncSeparate(GLcontext * ctx, GLenum face, |
| GLenum func, GLint ref, GLuint mask) |
| { |
| r300ContextPtr rmesa = R300_CONTEXT(ctx); |
| GLuint refmask = |
| (((ctx->Stencil. |
| Ref[0] & 0xff) << R300_STENCILREF_SHIFT) | ((ctx-> |
| Stencil. |
| ValueMask |
| [0] & |
| 0xff) |
| << |
| R300_STENCILMASK_SHIFT)); |
| |
| GLuint flag; |
| |
| R300_STATECHANGE(rmesa, zs); |
| rmesa->hw.zs.cmd[R300_ZS_CNTL_0] |= R300_STENCIL_FRONT_BACK; |
| rmesa->hw.zs.cmd[R300_ZS_CNTL_1] &= ~((R300_ZS_MASK << |
| R300_S_FRONT_FUNC_SHIFT) |
| | (R300_ZS_MASK << |
| R300_S_BACK_FUNC_SHIFT)); |
| |
| rmesa->hw.zs.cmd[R300_ZS_CNTL_2] &= |
| ~((R300_STENCILREF_MASK << R300_STENCILREF_SHIFT) | |
| (R300_STENCILREF_MASK << R300_STENCILMASK_SHIFT)); |
| |
| flag = translate_func(ctx->Stencil.Function[0]); |
| rmesa->hw.zs.cmd[R300_ZS_CNTL_1] |= |
| (flag << R300_S_FRONT_FUNC_SHIFT); |
| |
| if (ctx->Stencil._TestTwoSide) |
| flag = translate_func(ctx->Stencil.Function[1]); |
| |
| rmesa->hw.zs.cmd[R300_ZS_CNTL_1] |= |
| (flag << R300_S_BACK_FUNC_SHIFT); |
| rmesa->hw.zs.cmd[R300_ZS_CNTL_2] |= refmask; |
| } |
| |
| static void r300StencilMaskSeparate(GLcontext * ctx, GLenum face, GLuint mask) |
| { |
| r300ContextPtr rmesa = R300_CONTEXT(ctx); |
| |
| R300_STATECHANGE(rmesa, zs); |
| rmesa->hw.zs.cmd[R300_ZS_CNTL_2] &= |
| ~(R300_STENCILREF_MASK << |
| R300_STENCILWRITEMASK_SHIFT); |
| rmesa->hw.zs.cmd[R300_ZS_CNTL_2] |= |
| (ctx->Stencil. |
| WriteMask[0] & R300_STENCILREF_MASK) << |
| R300_STENCILWRITEMASK_SHIFT; |
| } |
| |
| static void r300StencilOpSeparate(GLcontext * ctx, GLenum face, |
| 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_Z_FUNC_SHIFT) | |
| (R300_ZS_MASK << R300_S_FRONT_FUNC_SHIFT) | |
| (R300_ZS_MASK << R300_S_BACK_FUNC_SHIFT); |
| |
| rmesa->hw.zs.cmd[R300_ZS_CNTL_1] |= |
| (translate_stencil_op(ctx->Stencil.FailFunc[0]) << |
| R300_S_FRONT_SFAIL_OP_SHIFT) |
| | (translate_stencil_op(ctx->Stencil.ZFailFunc[0]) << |
| R300_S_FRONT_ZFAIL_OP_SHIFT) |
| | (translate_stencil_op(ctx->Stencil.ZPassFunc[0]) << |
| R300_S_FRONT_ZPASS_OP_SHIFT); |
| |
| if (ctx->Stencil._TestTwoSide) { |
| rmesa->hw.zs.cmd[R300_ZS_CNTL_1] |= |
| (translate_stencil_op(ctx->Stencil.FailFunc[1]) << |
| R300_S_BACK_SFAIL_OP_SHIFT) |
| | (translate_stencil_op(ctx->Stencil.ZFailFunc[1]) << |
| R300_S_BACK_ZFAIL_OP_SHIFT) |
| | (translate_stencil_op(ctx->Stencil.ZPassFunc[1]) << |
| R300_S_BACK_ZPASS_OP_SHIFT); |
| } else { |
| rmesa->hw.zs.cmd[R300_ZS_CNTL_1] |= |
| (translate_stencil_op(ctx->Stencil.FailFunc[0]) << |
| R300_S_BACK_SFAIL_OP_SHIFT) |
| | (translate_stencil_op(ctx->Stencil.ZFailFunc[0]) << |
| R300_S_BACK_ZFAIL_OP_SHIFT) |
| | (translate_stencil_op(ctx->Stencil.ZPassFunc[0]) << |
| R300_S_BACK_ZPASS_OP_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. |
| */ |
| r300UpdateWindow(ctx); |
| } |
| |
| static void r300DepthRange(GLcontext * ctx, GLclampd nearval, GLclampd farval) |
| { |
| r300UpdateWindow(ctx); |
| } |
| |
| void r300UpdateViewportOffset(GLcontext * ctx) |
| { |
| r300ContextPtr rmesa = R300_CONTEXT(ctx); |
| __DRIdrawablePrivate *dPriv = ((radeonContextPtr) 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 + SUBPIXEL_X; |
| GLfloat ty = (-v[MAT_TY]) + yoffset + SUBPIXEL_Y; |
| |
| if (rmesa->hw.vpt.cmd[R300_VPT_XOFFSET] != r300PackFloat32(tx) || |
| rmesa->hw.vpt.cmd[R300_VPT_YOFFSET] != r300PackFloat32(ty)) { |
| /* Note: this should also modify whatever data the context reset |
| * code uses... |
| */ |
| R300_STATECHANGE(rmesa, vpt); |
| rmesa->hw.vpt.cmd[R300_VPT_XOFFSET] = r300PackFloat32(tx); |
| rmesa->hw.vpt.cmd[R300_VPT_YOFFSET] = r300PackFloat32(ty); |
| |
| } |
| |
| radeonUpdateScissor(ctx); |
| } |
| |
| /** |
| * Tell the card where to render (offset, pitch). |
| * Effected by glDrawBuffer, etc |
| */ |
| void r300UpdateDrawBuffer(GLcontext * ctx) |
| { |
| r300ContextPtr rmesa = R300_CONTEXT(ctx); |
| r300ContextPtr r300 = rmesa; |
| struct gl_framebuffer *fb = ctx->DrawBuffer; |
| driRenderbuffer *drb; |
| |
| if (fb->_ColorDrawBufferIndexes[0] == BUFFER_FRONT_LEFT) { |
| /* draw to front */ |
| drb = |
| (driRenderbuffer *) fb->Attachment[BUFFER_FRONT_LEFT]. |
| Renderbuffer; |
| } else if (fb->_ColorDrawBufferIndexes[0] == BUFFER_BACK_LEFT) { |
| /* draw to back */ |
| drb = |
| (driRenderbuffer *) fb->Attachment[BUFFER_BACK_LEFT]. |
| Renderbuffer; |
| } else { |
| /* drawing to multiple buffers, or none */ |
| return; |
| } |
| |
| assert(drb); |
| assert(drb->flippedPitch); |
| |
| R300_STATECHANGE(rmesa, cb); |
| |
| r300->hw.cb.cmd[R300_CB_OFFSET] = drb->flippedOffset + //r300->radeon.state.color.drawOffset + |
| r300->radeon.radeonScreen->fbLocation; |
| r300->hw.cb.cmd[R300_CB_PITCH] = drb->flippedPitch; //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; |
| #if 0 |
| R200_STATECHANGE(rmesa, ctx); |
| |
| /* Note: we used the (possibly) page-flipped values */ |
| rmesa->hw.ctx.cmd[CTX_RB3D_COLOROFFSET] |
| = ((drb->flippedOffset + rmesa->r200Screen->fbLocation) |
| & R200_COLOROFFSET_MASK); |
| rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] = drb->flippedPitch; |
| |
| if (rmesa->sarea->tiling_enabled) { |
| rmesa->hw.ctx.cmd[CTX_RB3D_COLORPITCH] |= |
| R200_COLOR_TILE_ENABLE; |
| } |
| #endif |
| } |
| |
| static void |
| r300FetchStateParameter(GLcontext * ctx, |
| const gl_state_index state[STATE_LENGTH], |
| GLfloat * value) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| |
| switch (state[0]) { |
| case STATE_INTERNAL: |
| switch (state[1]) { |
| case STATE_R300_WINDOW_DIMENSION: |
| value[0] = r300->radeon.dri.drawable->w * 0.5f; /* width*0.5 */ |
| value[1] = r300->radeon.dri.drawable->h * 0.5f; /* height*0.5 */ |
| value[2] = 0.5F; /* for moving range [-1 1] -> [0 1] */ |
| value[3] = 1.0F; /* not used */ |
| break; |
| |
| case STATE_R300_TEXRECT_FACTOR:{ |
| struct gl_texture_object *t = |
| ctx->Texture.Unit[state[2]].CurrentRect; |
| |
| if (t && t->Image[0][t->BaseLevel]) { |
| struct gl_texture_image *image = |
| t->Image[0][t->BaseLevel]; |
| value[0] = 1.0 / image->Width2; |
| value[1] = 1.0 / image->Height2; |
| } else { |
| value[0] = 1.0; |
| value[1] = 1.0; |
| } |
| value[2] = 1.0; |
| value[3] = 1.0; |
| break; |
| } |
| |
| default: |
| break; |
| } |
| break; |
| |
| default: |
| break; |
| } |
| } |
| |
| /** |
| * Update R300's own internal state parameters. |
| * For now just STATE_R300_WINDOW_DIMENSION |
| */ |
| void r300UpdateStateParameters(GLcontext * ctx, GLuint new_state) |
| { |
| struct r300_fragment_program *fp; |
| struct gl_program_parameter_list *paramList; |
| GLuint i; |
| |
| if (!(new_state & (_NEW_BUFFERS | _NEW_PROGRAM))) |
| return; |
| |
| fp = (struct r300_fragment_program *)ctx->FragmentProgram._Current; |
| if (!fp) |
| return; |
| |
| paramList = fp->mesa_program.Base.Parameters; |
| |
| if (!paramList) |
| return; |
| |
| for (i = 0; i < paramList->NumParameters; i++) { |
| if (paramList->Parameters[i].Type == PROGRAM_STATE_VAR) { |
| r300FetchStateParameter(ctx, |
| paramList->Parameters[i]. |
| StateIndexes, |
| paramList->ParameterValues[i]); |
| } |
| } |
| } |
| |
| /* ============================================================= |
| * 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 */ |
| |
| /* 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_R_SHIFT)) == |
| (R300_TX_CLAMP << R300_TX_WRAP_R_SHIFT)) { |
| needs_fixing |= 4; |
| } |
| |
| if (!needs_fixing) |
| return f; |
| |
| mag = f & R300_TX_MAG_FILTER_MASK; |
| min = f & (R300_TX_MIN_FILTER_MASK|R300_TX_MIN_FILTER_MIP_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_R_SHIFT); |
| f |= R300_TX_CLAMP_TO_EDGE << R300_TX_WRAP_R_SHIFT; |
| } |
| return f; |
| } |
| |
| static void r300SetupFragmentShaderTextures(GLcontext *ctx, int *tmu_mappings) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| int i; |
| struct r300_fragment_program *fp = (struct r300_fragment_program *) |
| (char *)ctx->FragmentProgram._Current; |
| struct r300_fragment_program_code *code = &fp->code; |
| |
| R300_STATECHANGE(r300, fpt); |
| |
| for (i = 0; i < code->tex.length; i++) { |
| int unit; |
| int opcode; |
| unsigned long val; |
| |
| unit = code->tex.inst[i] >> R300_TEX_ID_SHIFT; |
| unit &= 15; |
| |
| val = code->tex.inst[i]; |
| val &= ~R300_TEX_ID_MASK; |
| |
| opcode = |
| (val & R300_TEX_INST_MASK) >> R300_TEX_INST_SHIFT; |
| if (opcode == R300_TEX_OP_KIL) { |
| r300->hw.fpt.cmd[R300_FPT_INSTR_0 + i] = val; |
| } else { |
| if (tmu_mappings[unit] >= 0) { |
| val |= |
| tmu_mappings[unit] << |
| R300_TEX_ID_SHIFT; |
| r300->hw.fpt.cmd[R300_FPT_INSTR_0 + i] = val; |
| } else { |
| // We get here when the corresponding texture image is incomplete |
| // (e.g. incomplete mipmaps etc.) |
| r300->hw.fpt.cmd[R300_FPT_INSTR_0 + i] = val; |
| } |
| } |
| } |
| |
| r300->hw.fpt.cmd[R300_FPT_CMD_0] = |
| cmdpacket0(R300_US_TEX_INST_0, code->tex.length); |
| } |
| |
| static void r500SetupFragmentShaderTextures(GLcontext *ctx, int *tmu_mappings) |
| { |
| int i; |
| struct r500_fragment_program *fp = (struct r500_fragment_program *) |
| (char *)ctx->FragmentProgram._Current; |
| struct r500_fragment_program_code *code = &fp->code; |
| |
| /* find all the texture instructions and relocate the texture units */ |
| for (i = 0; i < code->inst_end + 1; i++) { |
| if ((code->inst[i].inst0 & 0x3) == R500_INST_TYPE_TEX) { |
| uint32_t val; |
| int unit, opcode, new_unit; |
| |
| val = code->inst[i].inst1; |
| |
| unit = (val >> 16) & 0xf; |
| |
| val &= ~(0xf << 16); |
| |
| opcode = val & (0x7 << 22); |
| if (opcode == R500_TEX_INST_TEXKILL) { |
| new_unit = 0; |
| } else { |
| if (tmu_mappings[unit] >= 0) { |
| new_unit = tmu_mappings[unit]; |
| } else { |
| new_unit = 0; |
| } |
| } |
| val |= R500_TEX_ID(new_unit); |
| code->inst[i].inst1 = val; |
| } |
| } |
| } |
| |
| static GLuint translate_lod_bias(GLfloat bias) |
| { |
| GLint b = (int)(bias*32); |
| if (b >= (1 << 9)) |
| b = (1 << 9)-1; |
| else if (b < -(1 << 9)) |
| b = -(1 << 9); |
| return (((GLuint)b) << R300_LOD_BIAS_SHIFT) & R300_LOD_BIAS_MASK; |
| } |
| |
| static void r300SetupTextures(GLcontext * ctx) |
| { |
| int i, mtu; |
| struct r300_tex_obj *t; |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| int hw_tmu = 0; |
| int last_hw_tmu = -1; /* -1 translates into no setup costs for fields */ |
| int tmu_mappings[R300_MAX_TEXTURE_UNITS] = { -1, }; |
| struct r300_fragment_program *fp = (struct r300_fragment_program *) |
| (char *)ctx->FragmentProgram._Current; |
| |
| R300_STATECHANGE(r300, txe); |
| R300_STATECHANGE(r300, tex.filter); |
| R300_STATECHANGE(r300, tex.filter_1); |
| R300_STATECHANGE(r300, tex.size); |
| R300_STATECHANGE(r300, tex.format); |
| R300_STATECHANGE(r300, tex.pitch); |
| R300_STATECHANGE(r300, tex.offset); |
| R300_STATECHANGE(r300, tex.chroma_key); |
| 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); |
| _mesa_exit(-1); |
| } |
| |
| /* We cannot let disabled tmu offsets pass DRM */ |
| for (i = 0; i < mtu; i++) { |
| if (ctx->Texture.Unit[i]._ReallyEnabled) { |
| |
| #if 0 /* Enables old behaviour */ |
| hw_tmu = i; |
| #endif |
| tmu_mappings[i] = hw_tmu; |
| |
| t = r300->state.texture.unit[i].texobj; |
| /* XXX questionable fix for bug 9170: */ |
| if (!t) |
| continue; |
| |
| if ((t->format & 0xffffff00) == 0xffffff00) { |
| WARN_ONCE |
| ("unknown texture format (entry %x) encountered. Help me !\n", |
| t->format & 0xff); |
| } |
| |
| if (RADEON_DEBUG & DEBUG_STATE) |
| fprintf(stderr, |
| "Activating texture unit %d\n", i); |
| |
| r300->hw.txe.cmd[R300_TXE_ENABLE] |= (1 << hw_tmu); |
| |
| r300->hw.tex.filter.cmd[R300_TEX_VALUE_0 + |
| hw_tmu] = |
| gen_fixed_filter(t->filter) | (hw_tmu << 28); |
| /* Note: There is a LOD bias per texture unit and a LOD bias |
| * per texture object. We add them here to get the correct behaviour. |
| * (The per-texture object LOD bias was introduced in OpenGL 1.4 |
| * and is not present in the EXT_texture_object extension). |
| */ |
| r300->hw.tex.filter_1.cmd[R300_TEX_VALUE_0 + hw_tmu] = |
| t->filter_1 | |
| translate_lod_bias(ctx->Texture.Unit[i].LodBias + t->base.tObj->LodBias); |
| r300->hw.tex.size.cmd[R300_TEX_VALUE_0 + hw_tmu] = |
| t->size; |
| r300->hw.tex.format.cmd[R300_TEX_VALUE_0 + |
| hw_tmu] = t->format; |
| r300->hw.tex.pitch.cmd[R300_TEX_VALUE_0 + hw_tmu] = |
| t->pitch_reg; |
| r300->hw.tex.offset.cmd[R300_TEX_VALUE_0 + |
| hw_tmu] = t->offset; |
| |
| if (t->offset & R300_TXO_MACRO_TILE) { |
| WARN_ONCE("macro tiling enabled!\n"); |
| } |
| |
| if (t->offset & R300_TXO_MICRO_TILE) { |
| WARN_ONCE("micro tiling enabled!\n"); |
| } |
| |
| r300->hw.tex.chroma_key.cmd[R300_TEX_VALUE_0 + |
| hw_tmu] = 0x0; |
| r300->hw.tex.border_color.cmd[R300_TEX_VALUE_0 + |
| hw_tmu] = |
| t->pp_border_color; |
| |
| last_hw_tmu = hw_tmu; |
| |
| hw_tmu++; |
| } |
| } |
| |
| r300->hw.tex.filter.cmd[R300_TEX_CMD_0] = |
| cmdpacket0(R300_TX_FILTER0_0, last_hw_tmu + 1); |
| r300->hw.tex.filter_1.cmd[R300_TEX_CMD_0] = |
| cmdpacket0(R300_TX_FILTER1_0, last_hw_tmu + 1); |
| r300->hw.tex.size.cmd[R300_TEX_CMD_0] = |
| cmdpacket0(R300_TX_SIZE_0, last_hw_tmu + 1); |
| r300->hw.tex.format.cmd[R300_TEX_CMD_0] = |
| cmdpacket0(R300_TX_FORMAT_0, last_hw_tmu + 1); |
| r300->hw.tex.pitch.cmd[R300_TEX_CMD_0] = |
| cmdpacket0(R300_TX_FORMAT2_0, last_hw_tmu + 1); |
| r300->hw.tex.offset.cmd[R300_TEX_CMD_0] = |
| cmdpacket0(R300_TX_OFFSET_0, last_hw_tmu + 1); |
| r300->hw.tex.chroma_key.cmd[R300_TEX_CMD_0] = |
| cmdpacket0(R300_TX_CHROMA_KEY_0, last_hw_tmu + 1); |
| r300->hw.tex.border_color.cmd[R300_TEX_CMD_0] = |
| cmdpacket0(R300_TX_BORDER_COLOR_0, last_hw_tmu + 1); |
| |
| if (!fp) /* should only happenen once, just after context is created */ |
| return; |
| |
| if (r300->radeon.radeonScreen->chip_family < CHIP_FAMILY_RV515) { |
| if (fp->mesa_program.UsesKill && last_hw_tmu < 0) { |
| // The KILL operation requires the first texture unit |
| // to be enabled. |
| r300->hw.txe.cmd[R300_TXE_ENABLE] |= 1; |
| r300->hw.tex.filter.cmd[R300_TEX_VALUE_0] = 0; |
| r300->hw.tex.filter.cmd[R300_TEX_CMD_0] = |
| cmdpacket0(R300_TX_FILTER0_0, 1); |
| } |
| r300SetupFragmentShaderTextures(ctx, tmu_mappings); |
| } else |
| r500SetupFragmentShaderTextures(ctx, tmu_mappings); |
| |
| if (RADEON_DEBUG & DEBUG_STATE) |
| fprintf(stderr, "TX_ENABLE: %08x last_hw_tmu=%d\n", |
| r300->hw.txe.cmd[R300_TXE_ENABLE], last_hw_tmu); |
| } |
| |
| union r300_outputs_written { |
| GLuint vp_outputs; /* hw_tcl_on */ |
| DECLARE_RENDERINPUTS(index_bitset); /* !hw_tcl_on */ |
| }; |
| |
| #define R300_OUTPUTS_WRITTEN_TEST(ow, vp_result, tnl_attrib) \ |
| ((hw_tcl_on) ? (ow).vp_outputs & (1 << (vp_result)) : \ |
| RENDERINPUTS_TEST( (ow.index_bitset), (tnl_attrib) )) |
| |
| static void r300SetupRSUnit(GLcontext * ctx) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| /* I'm still unsure if these are needed */ |
| GLuint interp_col[8]; |
| TNLcontext *tnl = TNL_CONTEXT(ctx); |
| struct vertex_buffer *VB = &tnl->vb; |
| union r300_outputs_written OutputsWritten; |
| GLuint InputsRead; |
| int fp_reg, high_rr; |
| int col_interp_nr; |
| int rs_tex_count = 0, rs_col_count = 0; |
| int i, count; |
| |
| memset(interp_col, 0, sizeof(interp_col)); |
| |
| if (hw_tcl_on) |
| OutputsWritten.vp_outputs = CURRENT_VERTEX_SHADER(ctx)->key.OutputsWritten; |
| else |
| RENDERINPUTS_COPY(OutputsWritten.index_bitset, r300->state.render_inputs_bitset); |
| |
| if (ctx->FragmentProgram._Current) |
| InputsRead = ctx->FragmentProgram._Current->Base.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); |
| |
| fp_reg = col_interp_nr = high_rr = 0; |
| |
| r300->hw.rr.cmd[R300_RR_INST_1] = 0; |
| |
| if (InputsRead & FRAG_BIT_WPOS) { |
| for (i = 0; i < ctx->Const.MaxTextureUnits; i++) |
| if (!(InputsRead & (FRAG_BIT_TEX0 << i))) |
| break; |
| |
| if (i == ctx->Const.MaxTextureUnits) { |
| fprintf(stderr, "\tno free texcoord found...\n"); |
| _mesa_exit(-1); |
| } |
| |
| InputsRead |= (FRAG_BIT_TEX0 << i); |
| InputsRead &= ~FRAG_BIT_WPOS; |
| } |
| |
| if (InputsRead & FRAG_BIT_COL0) { |
| count = VB->AttribPtr[_TNL_ATTRIB_COLOR0]->size; |
| interp_col[0] |= R300_RS_COL_PTR(rs_col_count); |
| if (count == 3) |
| interp_col[0] |= R300_RS_COL_FMT(R300_RS_COL_FMT_RGB1); |
| rs_col_count += count; |
| } |
| else |
| interp_col[0] = R300_RS_COL_FMT(R300_RS_COL_FMT_0001); |
| |
| if (InputsRead & FRAG_BIT_COL1) { |
| count = VB->AttribPtr[_TNL_ATTRIB_COLOR1]->size; |
| if (count == 3) |
| interp_col[1] |= R300_RS_COL_FMT(R300_RS_COL_FMT_RGB0); |
| interp_col[1] |= R300_RS_COL_PTR(1); |
| rs_col_count += count; |
| } |
| |
| |
| for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { |
| int swiz; |
| |
| /* with TCL we always seem to route 4 components */ |
| if (hw_tcl_on) |
| count = 4; |
| else |
| count = VB->AttribPtr[_TNL_ATTRIB_TEX(i)]->size; |
| |
| r300->hw.ri.cmd[R300_RI_INTERP_0 + i] = interp_col[i] | rs_tex_count; |
| switch(count) { |
| case 4: swiz = R300_RS_SEL_S(0) | R300_RS_SEL_T(1) | R300_RS_SEL_R(2) | R300_RS_SEL_Q(3); break; |
| case 3: swiz = R300_RS_SEL_S(0) | R300_RS_SEL_T(1) | R300_RS_SEL_R(2) | R300_RS_SEL_Q(R300_RS_SEL_K1); break; |
| default: |
| case 1: |
| case 2: swiz = R300_RS_SEL_S(0) | R300_RS_SEL_T(1) | R300_RS_SEL_R(R300_RS_SEL_K0) | R300_RS_SEL_Q(R300_RS_SEL_K1); break; |
| }; |
| |
| r300->hw.ri.cmd[R300_RI_INTERP_0 + i] |= swiz; |
| |
| r300->hw.rr.cmd[R300_RR_INST_0 + fp_reg] = 0; |
| if (InputsRead & (FRAG_BIT_TEX0 << i)) { |
| |
| rs_tex_count += count; |
| |
| //assert(r300->state.texture.tc_count != 0); |
| r300->hw.rr.cmd[R300_RR_INST_0 + fp_reg] |= R300_RS_INST_TEX_CN_WRITE | i /* source INTERP */ |
| | (fp_reg << R300_RS_INST_TEX_ADDR_SHIFT); |
| high_rr = fp_reg; |
| |
| /* Passing invalid data here can lock the GPU. */ |
| if (R300_OUTPUTS_WRITTEN_TEST(OutputsWritten, VERT_RESULT_TEX0 + i, _TNL_ATTRIB_TEX(i))) { |
| InputsRead &= ~(FRAG_BIT_TEX0 << i); |
| fp_reg++; |
| } else { |
| WARN_ONCE("fragprog wants coords for tex%d, vp doesn't provide them!\n", i); |
| } |
| } |
| } |
| |
| if (InputsRead & FRAG_BIT_COL0) { |
| if (R300_OUTPUTS_WRITTEN_TEST(OutputsWritten, VERT_RESULT_COL0, _TNL_ATTRIB_COLOR0)) { |
| r300->hw.rr.cmd[R300_RR_INST_0] |= R300_RS_INST_COL_ID(0) | R300_RS_INST_COL_CN_WRITE | (fp_reg++ << R300_RS_INST_COL_ADDR_SHIFT); |
| InputsRead &= ~FRAG_BIT_COL0; |
| col_interp_nr++; |
| } else { |
| WARN_ONCE("fragprog wants col0, vp doesn't provide it\n"); |
| } |
| } |
| |
| if (InputsRead & FRAG_BIT_COL1) { |
| if (R300_OUTPUTS_WRITTEN_TEST(OutputsWritten, VERT_RESULT_COL1, _TNL_ATTRIB_COLOR1)) { |
| r300->hw.rr.cmd[R300_RR_INST_1] |= R300_RS_INST_COL_ID(1) | R300_RS_INST_COL_CN_WRITE | (fp_reg++ << R300_RS_INST_COL_ADDR_SHIFT); |
| InputsRead &= ~FRAG_BIT_COL1; |
| if (high_rr < 1) |
| high_rr = 1; |
| col_interp_nr++; |
| } else { |
| WARN_ONCE("fragprog wants col1, vp doesn't provide it\n"); |
| } |
| } |
| |
| /* Need at least one. This might still lock as the values are undefined... */ |
| if (rs_tex_count == 0 && col_interp_nr == 0) { |
| r300->hw.rr.cmd[R300_RR_INST_0] |= R300_RS_INST_COL_ID(0) | R300_RS_INST_COL_CN_WRITE | (fp_reg++ << R300_RS_INST_COL_ADDR_SHIFT); |
| col_interp_nr++; |
| } |
| |
| r300->hw.rc.cmd[1] = 0 | (rs_tex_count << R300_IT_COUNT_SHIFT) |
| | (col_interp_nr << R300_IC_COUNT_SHIFT) |
| | R300_HIRES_EN; |
| |
| assert(high_rr >= 0); |
| r300->hw.rr.cmd[R300_RR_CMD_0] = cmdpacket0(R300_RS_INST_0, high_rr + 1); |
| r300->hw.rc.cmd[2] = high_rr; |
| |
| if (InputsRead) |
| WARN_ONCE("Don't know how to satisfy InputsRead=0x%08x\n", InputsRead); |
| } |
| |
| static void r500SetupRSUnit(GLcontext * ctx) |
| { |
| r300ContextPtr r300 = R300_CONTEXT(ctx); |
| /* I'm still unsure if these are needed */ |
| GLuint interp_col[8]; |
| union r300_outputs_written OutputsWritten; |
| TNLcontext *tnl = TNL_CONTEXT(ctx); |
| struct vertex_buffer *VB = &tnl->vb; |
| GLuint InputsRead; |
| int fp_reg, high_rr; |
| int rs_col_count = 0; |
| int in_texcoords, col_interp_nr; |
| int i, count; |
| |
| memset(interp_col, 0, sizeof(interp_col)); |
| if (hw_tcl_on) |
| OutputsWritten.vp_outputs = CURRENT_VERTEX_SHADER(ctx)->key.OutputsWritten; |
| else |
| RENDERINPUTS_COPY(OutputsWritten.index_bitset, r300->state.render_inputs_bitset); |
| |
| if (ctx->FragmentProgram._Current) |
| InputsRead = ctx->FragmentProgram._Current->Base.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); |
| |
| fp_reg = col_interp_nr = high_rr = in_texcoords = 0; |
| |
| r300->hw.rr.cmd[R300_RR_INST_1] = 0; |
| |
| if (InputsRead & FRAG_BIT_WPOS) { |
| for (i = 0; i < ctx->Const.MaxTextureUnits; i++) |
| if (!(InputsRead & (FRAG_BIT_TEX0 << i))) |
| break; |
| |
| if (i == ctx->Const.MaxTextureUnits) { |
| fprintf(stderr, "\tno free texcoord found...\n"); |
| _mesa_exit(-1); |
| } |
| |
| InputsRead |= (FRAG_BIT_TEX0 << i); |
| InputsRead &= ~FRAG_BIT_WPOS; |
| } |
| |
| if (InputsRead & FRAG_BIT_COL0) { |
| count = VB->AttribPtr[_TNL_ATTRIB_COLOR0]->size; |
| interp_col[0] |= R500_RS_COL_PTR(rs_col_count); |
| if (count == 3) |
| interp_col[0] |= R500_RS_COL_FMT(R300_RS_COL_FMT_RGB1); |
| rs_col_count += count; |
| } |
| else |
| interp_col[0] = R500_RS_COL_FMT(R300_RS_COL_FMT_0001); |
| |
| if (InputsRead & FRAG_BIT_COL1) { |
| count = VB->AttribPtr[_TNL_ATTRIB_COLOR1]->size; |
| interp_col[1] |= R500_RS_COL_PTR(1); |
| if (count == 3) |
| interp_col[1] |= R500_RS_COL_FMT(R300_RS_COL_FMT_RGB0); |
| rs_col_count += count; |
| } |
| |
| for (i = 0; i < ctx->Const.MaxTextureUnits; i++) { |
| GLuint swiz = 0; |
| |
| /* with TCL we always seem to route 4 components */ |
| if (InputsRead & (FRAG_BIT_TEX0 << i)) { |
| |
| if (hw_tcl_on) |
| count = 4; |
| else |
| count = VB->AttribPtr[_TNL_ATTRIB_TEX(i)]->size; |
| |
| /* always have on texcoord */ |
| swiz |= in_texcoords++ << R500_RS_IP_TEX_PTR_S_SHIFT; |
| if (count >= 2) |
| swiz |= in_texcoords++ << R500_RS_IP_TEX_PTR_T_SHIFT; |
| else |
| swiz |= R500_RS_IP_PTR_K0 << R500_RS_IP_TEX_PTR_T_SHIFT; |
| |
| if (count >= 3) |
| swiz |= in_texcoords++ << R500_RS_IP_TEX_PTR_R_SHIFT; |
| else |
| swiz |= R500_RS_IP_PTR_K0 << R500_RS_IP_TEX_PTR_R_SHIFT; |
| |
| if (count == 4) |
| swiz |= in_texcoords++ << R500_RS_IP_TEX_PTR_Q_SHIFT; |
| else |
| swiz |= R500_RS_IP_PTR_K1 << R500_RS_IP_TEX_PTR_Q_SHIFT; |
| |
| } else |
| swiz = (R500_RS_IP_PTR_K0 << R500_RS_IP_TEX_PTR_S_SHIFT) | |
| (R500_RS_IP_PTR_K0 << R500_RS_IP_TEX_PTR_T_SHIFT) | |
| (R500_RS_IP_PTR_K0 << R500_RS_IP_TEX_PTR_R_SHIFT) | |
| (R500_RS_IP_PTR_K1 << R500_RS_IP_TEX_PTR_Q_SHIFT); |
| |
| r300->hw.ri.cmd[R300_RI_INTERP_0 + i] = interp_col[i] | swiz; |
| |
| r300->hw.rr.cmd[R300_RR_INST_0 + fp_reg] = 0; |
| if (InputsRead & (FRAG_BIT_TEX0 << i)) { |
| //assert(r300->state.texture.tc_count != 0); |
| r300->hw.rr.cmd[R300_RR_INST_0 + fp_reg] |= R500_RS_INST_TEX_CN_WRITE | i /* source INTERP */ |
| | (fp_reg << R500_RS_INST_TEX_ADDR_SHIFT); |
| high_rr = fp_reg; |
| |
| /* Passing invalid data here can lock the GPU. */ |
| if (R300_OUTPUTS_WRITTEN_TEST(OutputsWritten, VERT_RESULT_TEX0 + i, _TNL_ATTRIB_TEX(i))) { |
| InputsRead &= ~(FRAG_BIT_TEX0 << i); |
| fp_reg++; |
| } else { |
| WARN_ONCE("fragprog wants coords for tex%d, vp doesn't provide them!\n", i); |
| } |
| } |
| } |
| |
| if (InputsRead & FRAG_BIT_COL0) { |
| if (R300_OUTPUTS_WRITTEN_TEST(OutputsWritten, VERT_RESULT_COL0, _TNL_ATTRIB_COLOR0)) { |
| r300->hw.rr.cmd[R300_RR_INST_0] |= R500_RS_INST_COL_CN_WRITE | (fp_reg++ << R500_RS_INST_COL_ADDR_SHIFT); |
| InputsRead &= ~FRAG_BIT_COL0; |
| col_interp_nr++; |
| } else { |
| WARN_ONCE("fragprog wants col0, vp doesn't provide it\n"); |
| } |
| } |
| |
| if (InputsRead & FRAG_BIT_COL1) { |
| if (R300_OUTPUTS_WRITTEN_TEST(OutputsWritten, VERT_RESULT_COL1, _TNL_ATTRIB_COLOR1)) { |
| r300->hw.rr.cmd[R300_RR_INST_1] |= (1 << 12) | R500_RS_INST_COL_CN_WRITE | (fp_reg++ << R500_RS_INST_COL_ADDR_SHIFT); |
| InputsRead &= ~FRAG_BIT_COL1; |
| if (high_rr < 1) |
| high_rr = 1; |
| col_interp_nr++; |
| } else { |
| WARN_ONCE("fragprog wants col1, vp doesn't provide it\n"); |
| } |
| } |
| |
| /* Need at least one. This might still lock as the values are undefined... */ |
| if (in_texcoords == 0 && col_interp_nr == 0) { |
| r300->hw.rr.cmd[R300_RR_INST_0] |= 0 | R500_RS_INST_COL_CN_WRITE | (fp_reg++ << R500_RS_INST_COL_ADDR_SHIFT); |
| col_interp_nr++; |
| } |
| |
| r300->hw.rc.cmd[1] = 0 | (in_texcoords << R300_IT_COUNT_SHIFT) |
| | (col_interp_nr << R300_IC_COUNT_SHIFT) |
| | R300_HIRES_EN; |
| |
| assert(high_rr >= 0); |
| r300->hw.rr.cmd[R300_RR_CMD_0] = cmdpacket0(R500_RS_INST_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); |
| } |
| |
| |
| |
| |
| #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; \ |
| assert(_nc < 256); \ |
| if(_nc>_p->vpu.count)_p->vpu.count=_nc;\ |
| }while(0) |
| |
| static INLINE void r300SetupVertexProgramFragment(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"); |
| _mesa_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); |
| _mesa_exit(-1); |
| } |
| } |
| |
| #define MIN3(a, b, c) ((a) < (b) ? MIN2(a, c) : MIN2(b, c)) |
| |
| |
| static void r300VapCntl(r300ContextPtr rmesa, GLuint input_count, |
| GLuint output_count, GLuint temp_count) |
| { |
| int vtx_mem_size; |
| int pvs_num_slots; |
| int pvs_num_cntrls; |
| |
| /* Flush PVS engine before changing PVS_NUM_SLOTS, PVS_NUM_CNTRLS. |
| * See r500 docs 6.5.2 - done in emit */ |
| |
| /* avoid division by zero */ |
| if (input_count == 0) input_count = 1; |
| if (output_count == 0) output_count = 1; |
| if (temp_count == 0) temp_count = 1; |
| |
| if (rmesa->radeon.radeonScreen->chip_family >= CHIP_FAMILY_RV515) |
| vtx_mem_size = 128; |
| else |
| vtx_mem_size = 72; |
| |
| pvs_num_slots = MIN3(10, vtx_mem_size/input_count, vtx_mem_size/output_count); |
| pvs_num_cntrls = MIN2(6, vtx_mem_size/temp_count); |
| |
| R300_STATECHANGE(rmesa, vap_cntl); |
| if (rmesa->radeon.radeonScreen->chip_flags & RADEON_CHIPSET_TCL) { |
| rmesa->hw.vap_cntl.cmd[R300_VAP_CNTL_INSTR] = |
| (pvs_num_slots << R300_PVS_NUM_SLOTS_SHIFT) | |
| (pvs_num_cntrls << R300_PVS_NUM_CNTLRS_SHIFT) | |
| (12 << R300_VF_MAX_VTX_NUM_SHIFT); |
| if (rmesa->radeon.radeonScreen->chip_family >= CHIP_FAMILY_RV515) |
| rmesa->hw.vap_cntl.cmd[R300_VAP_CNTL_INSTR] |= R500_TCL_STATE_OPTIMIZATION; |
| } else |
| /* not sure about non-tcl */ |
| rmesa->hw.vap_cntl.cmd[R300_VAP_CNTL_INSTR] = ((10 << R300_PVS_NUM_SLOTS_SHIFT) | |
| (5 << R300_PVS_NUM_CNTLRS_SHIFT) | |
| (5 << R300_VF_MAX_VTX_NUM_SHIFT)); |
| |
| if (rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_RV515) |
| rmesa->hw.vap_cntl.cmd[R300_VAP_CNTL_INSTR] |= (2 << R300_PVS_NUM_FPUS_SHIFT); |
| else if ((rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_RV530) || |
| (rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_RV560) || |
| (rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_RV570)) |
| rmesa->hw.vap_cntl.cmd[R300_VAP_CNTL_INSTR] |= (5 << R300_PVS_NUM_FPUS_SHIFT); |
| else if ((rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_RV410) || |
| (rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_R420)) |
| rmesa->hw.vap_cntl.cmd[R300_VAP_CNTL_INSTR] |= (6 << R300_PVS_NUM_FPUS_SHIFT); |
| else if ((rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_R520) || |
| (rmesa->radeon.radeonScreen->chip_family == CHIP_FAMILY_R580)) |
| rmesa->hw.vap_cntl.cmd[R300_VAP_CNTL_INSTR] |= (8 << R300_PVS_NUM_FPUS_SHIFT); |
| else |
| rmesa->hw.vap_cntl.cmd[R300_VAP_CNTL_INSTR] |= (4 << R300_PVS_NUM_FPUS_SHIFT); |
| |
| } |
| |
| static void r300SetupDefaultVertexProgram(r300ContextPtr rmesa) |
| { |
| struct r300_vertex_shader_state *prog = &(rmesa->state.vertex_shader); |
| GLuint o_reg = 0; |
| GLuint i_reg = 0; |
| int i; |
| int inst_count = 0; |
| int param_count = 0; |
| int program_end = 0; |
| |
| for (i = VERT_ATTRIB_POS; i < VERT_ATTRIB_MAX; i++) { |
| if (rmesa->state.sw_tcl_inputs[i] != -1) { |
| prog->program.body.i[program_end + 0] = PVS_OP_DST_OPERAND(VE_MULTIPLY, GL_FALSE, GL_FALSE, o_reg++, VSF_FLAG_ALL, PVS_DST_REG_OUT); |
| prog->program.body.i[program_end + 1] = PVS_SRC_OPERAND(rmesa->state.sw_tcl_inputs[i], PVS_SRC_SELECT_X, PVS_SRC_SELECT_Y, PVS_SRC_SELECT_Z, PVS_SRC_SELECT_W, PVS_SRC_REG_INPUT, VSF_FLAG_NONE); |
| prog->program.body.i[program_end + 2] = PVS_SRC_OPERAND(rmesa->state.sw_tcl_inputs[i], PVS_SRC_SELECT_FORCE_1, PVS_SRC_SELECT_FORCE_1, PVS_SRC_SELECT_FORCE_1, PVS_SRC_SELECT_FORCE_1, PVS_SRC_REG_INPUT, VSF_FLAG_NONE); |
| prog->program.body.i[program_end + 3] = PVS_SRC_OPERAND(rmesa->state.sw_tcl_inputs[i], PVS_SRC_SELECT_FORCE_1, PVS_SRC_SELECT_FORCE_1, PVS_SRC_SELECT_FORCE_1, PVS_SRC_SELECT_FORCE_1, PVS_SRC_REG_INPUT, VSF_FLAG_NONE); |
| program_end += 4; |
| i_reg++; |
| } |
| } |
| |
| prog->program.length = program_end; |
| |
| r300SetupVertexProgramFragment(rmesa, R300_PVS_CODE_START, |
| &(prog->program)); |
| inst_count = (prog->program.length / 4) - 1; |
| |
| r300VapCntl(rmesa, i_reg, o_reg, 0); |
| |
| R300_STATECHANGE(rmesa, pvs); |
| rmesa->hw.pvs.cmd[R300_PVS_CNTL_1] = |
| (0 << R300_PVS_FIRST_INST_SHIFT) | |
| (inst_count << R300_PVS_XYZW_VALID_INST_SHIFT) | |
| (inst_count << R300_PVS_LAST_INST_SHIFT); |
| rmesa->hw.pvs.cmd[R300_PVS_CNTL_2] = |
| (0 << R300_PVS_CONST_BASE_OFFSET_SHIFT) | |
| (param_count << R300_PVS_MAX_CONST_ADDR_SHIFT); |
| rmesa->hw.pvs.cmd[R300_PVS_CNTL_3] = |
| (inst_count << R300_PVS_LAST_VTX_SRC_INST_SHIFT); |
| } |
| |
| static int bit_count (int x) |
| { |
| x = ((x & 0xaaaaaaaaU) >> 1) + (x & 0x55555555U); |
| x = ((x & 0xccccccccU) >> 2) + (x & 0x33333333U); |
| x = (x >> 16) + (x & 0xffff); |
| x = ((x & 0xf0f0) >> 4) + (x & 0x0f0f); |
| return (x >> 8) + (x & 0x00ff); |
| } |
| |
| static void r300SetupRealVertexProgram(r300ContextPtr rmesa) |
| { |
| GLcontext *ctx = rmesa->radeon.glCtx; |
| struct r300_vertex_program *prog = (struct r300_vertex_program *)CURRENT_VERTEX_SHADER(ctx); |
| int inst_count = 0; |
| int param_count = 0; |
| |
| /* FIXME: r300SetupVertexProgramFragment */ |
| R300_STATECHANGE(rmesa, vpp); |
| param_count = |
| r300VertexProgUpdateParams(ctx, |
| (struct r300_vertex_program_cont *) |
| ctx->VertexProgram._Current, |
| (float *)&rmesa->hw.vpp. |
| cmd[R300_VPP_PARAM_0]); |
| bump_vpu_count(rmesa->hw.vpp.cmd, param_count); |
| param_count /= 4; |
| |
| r300SetupVertexProgramFragment(rmesa, R300_PVS_CODE_START, &(prog->program)); |
| inst_count = (prog->program.length / 4) - 1; |
| |
| r300VapCntl(rmesa, bit_count(prog->key.InputsRead), |
| bit_count(prog->key.OutputsWritten), prog->num_temporaries); |
| |
| R300_STATECHANGE(rmesa, pvs); |
| rmesa->hw.pvs.cmd[R300_PVS_CNTL_1] = |
| (0 << R300_PVS_FIRST_INST_SHIFT) | |
| (inst_count << R300_PVS_XYZW_VALID_INST_SHIFT) | |
| (inst_count << R300_PVS_LAST_INST_SHIFT); |
| rmesa->hw.pvs.cmd[R300_PVS_CNTL_2] = |
| (0 << R300_PVS_CONST_BASE_OFFSET_SHIFT) | |
| (param_count << R300_PVS_MAX_CONST_ADDR_SHIFT); |
| rmesa->hw.pvs.cmd[R300_PVS_CNTL_3] = |
| (inst_count << R300_PVS_LAST_VTX_SRC_INST_SHIFT); |
| } |
| |
| static void r300SetupVertexProgram(r300ContextPtr rmesa) |
| { |
| GLcontext *ctx = rmesa->radeon.glCtx; |
| |
| /* 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) { |
| r300SetupRealVertexProgram(rmesa); |
| } else { |
| /* FIXME: This needs to be replaced by vertex shader generation code. */ |
| r300SetupDefaultVertexProgram(rmesa); |
| } |
| |
| } |
| |
| /** |
| * Enable/Disable states. |
| * |
| * \note Mesa already filters redundant calls to this function. |
| */ |
| static void r300Enable(GLcontext * ctx, GLenum cap, GLboolean state) |
| { |
| 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) { |
| case GL_TEXTURE_1D: |
| case GL_TEXTURE_2D: |
| case GL_TEXTURE_3D: |
| /* empty */ |
| break; |
| case GL_FOG: |
| r300SetFogState(ctx, state); |
| break; |
| case GL_ALPHA_TEST: |
| r300SetAlphaState(ctx); |
| break; |
| case GL_COLOR_LOGIC_OP: |
| r300SetLogicOpState(ctx); |
| /* fall-through, because logic op overrides blending */ |
| case GL_BLEND: |
| r300SetBlendState(ctx); |
| 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: |
| r300SetClipPlaneState(ctx, cap, state); |
| break; |
| case GL_DEPTH_TEST: |
| r300SetDepthState(ctx); |
| break; |
| case GL_STENCIL_TEST: |
| r300SetStencilState(ctx, state); |
| break; |
| case GL_CULL_FACE: |
| r300UpdateCulling(ctx); |
| break; |
| case GL_POLYGON_OFFSET_POINT: |
| case GL_POLYGON_OFFSET_LINE: |
| case GL_POLYGON_OFFSET_FILL: |
| r300SetPolygonOffsetState(ctx, state); |
| break; |
| default: |
| radeonEnable(ctx, cap, state); |
| break; |
| } |
| } |
| |
| /** |
| * Completely recalculates hardware state based on the Mesa state. |
| */ |
| static void r300ResetHwState(r300ContextPtr r300) |
| { |
| GLcontext *ctx = r300->radeon.glCtx; |
| int has_tcl = 1; |
| |
| if (!(r300->radeon.radeonScreen->chip_flags & RADEON_CHIPSET_TCL)) |
| has_tcl = 0; |
| |
| if (RADEON_DEBUG & DEBUG_STATE) |
| fprintf(stderr, "%s\n", __FUNCTION__); |
| |
| 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); |
| r300StencilMaskSeparate(ctx, 0, ctx->Stencil.WriteMask[0]); |
| r300StencilFuncSeparate(ctx, 0, ctx->Stencil.Function[0], |
| ctx->Stencil.Ref[0], ctx->Stencil.ValueMask[0]); |
| r300StencilOpSeparate(ctx, 0, ctx->Stencil.FailFunc[0], |
| ctx->Stencil.ZFailFunc[0], |
| ctx->Stencil.ZPassFunc[0]); |
| |
| r300UpdateCulling(ctx); |
| |
| r300UpdateTextureState(ctx); |
| |
| r300SetBlendState(ctx); |
| r300SetLogicOpState(ctx); |
| |
| r300AlphaFunc(ctx, ctx->Color.AlphaFunc, ctx->Color.AlphaRef); |
| r300Enable(ctx, GL_ALPHA_TEST, ctx->Color.AlphaEnabled); |
| |
| 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.vap_vf_max_vtx_indx.cmd[1] = 0x00FFFFFF; |
| r300->hw.vap_vf_max_vtx_indx.cmd[2] = 0x00000000; |
| |
| #ifdef MESA_LITTLE_ENDIAN |
| r300->hw.vap_cntl_status.cmd[1] = R300_VC_NO_SWAP; |
| #else |
| r300->hw.vap_cntl_status.cmd[1] = R300_VC_32BIT_SWAP; |
| #endif |
| |
| /* disable VAP/TCL on non-TCL capable chips */ |
| if (!has_tcl) |
| r300->hw.vap_cntl_status.cmd[1] |= R300_VAP_TCL_BYPASS; |
| |
| r300->hw.vap_psc_sgn_norm_cntl.cmd[1] = 0xAAAAAAAA; |
| |
| /* XXX: Other families? */ |
| if (has_tcl) { |
| r300->hw.vap_clip_cntl.cmd[1] = R300_PS_UCP_MODE_DIST_COP; |
| |
| r300->hw.vap_clip.cmd[1] = r300PackFloat32(1.0); /* X */ |
| r300->hw.vap_clip.cmd[2] = r300PackFloat32(1.0); /* X */ |
| r300->hw.vap_clip.cmd[3] = r300PackFloat32(1.0); /* Y */ |
| r300->hw.vap_clip.cmd[4] = r300PackFloat32(1.0); /* Y */ |
| |
| switch (r300->radeon.radeonScreen->chip_family) { |
| case CHIP_FAMILY_R300: |
| r300->hw.vap_pvs_vtx_timeout_reg.cmd[1] = R300_2288_R300; |
| break; |
| default: |
| r300->hw.vap_pvs_vtx_timeout_reg.cmd[1] = R300_2288_RV350; |
| break; |
| } |
| } |
| |
| r300->hw.gb_enable.cmd[1] = R300_GB_POINT_STUFF_ENABLE |
| | R300_GB_LINE_STUFF_ENABLE |
| | R300_GB_TRIANGLE_STUFF_ENABLE; |
| |
| r300->hw.gb_misc.cmd[R300_GB_MISC_MSPOS_0] = 0x66666666; |
| r300->hw.gb_misc.cmd[R300_GB_MISC_MSPOS_1] = 0x06666666; |
| |
| r300->hw.gb_misc.cmd[R300_GB_MISC_TILE_CONFIG] = |
| R300_GB_TILE_ENABLE | R300_GB_TILE_SIZE_16 /*| R300_GB_SUBPIXEL_1_16*/; |
| switch (r300->radeon.radeonScreen->num_gb_pipes) { |
| case 1: |
| default: |
| r300->hw.gb_misc.cmd[R300_GB_MISC_TILE_CONFIG] |= |
| R300_GB_TILE_PIPE_COUNT_RV300; |
| break; |
| case 2: |
| r300->hw.gb_misc.cmd[R300_GB_MISC_TILE_CONFIG] |= |
| R300_GB_TILE_PIPE_COUNT_R300; |
| break; |
| case 3: |
| r300->hw.gb_misc.cmd[R300_GB_MISC_TILE_CONFIG] |= |
| R300_GB_TILE_PIPE_COUNT_R420_3P; |
| break; |
| case 4: |
| r300->hw.gb_misc.cmd[R300_GB_MISC_TILE_CONFIG] |= |
| R300_GB_TILE_PIPE_COUNT_R420; |
| break; |
| } |
| |
| /* XXX: set to 0 when fog is disabled? */ |
| r300->hw.gb_misc.cmd[R300_GB_MISC_SELECT] = R300_GB_FOG_SELECT_1_1_W; |
| |
| /* XXX: Enable anti-aliasing? */ |
| r300->hw.gb_misc.cmd[R300_GB_MISC_AA_CONFIG] = GB_AA_CONFIG_AA_DISABLE; |
| |
| r300->hw.ga_point_s0.cmd[1] = r300PackFloat32(0.0); |
| r300->hw.ga_point_s0.cmd[2] = r300PackFloat32(0.0); |
| r300->hw.ga_point_s0.cmd[3] = r300PackFloat32(1.0); |
| r300->hw.ga_point_s0.cmd[4] = r300PackFloat32(1.0); |
| |
| r300->hw.ga_triangle_stipple.cmd[1] = 0x00050005; |
| |
| r300PointSize(ctx, 1.0); |
| |
| r300->hw.ga_point_minmax.cmd[1] = 0x18000006; |
| r300->hw.ga_point_minmax.cmd[2] = 0x00020006; |
| r300->hw.ga_point_minmax.cmd[3] = r300PackFloat32(1.0 / 192.0); |
| |
| r300LineWidth(ctx, 1.0); |
| |
| r300->hw.ga_line_stipple.cmd[1] = 0; |
| r300->hw.ga_line_stipple.cmd[2] = r300PackFloat32(0.0); |
| r300->hw.ga_line_stipple.cmd[3] = r300PackFloat32(1.0); |
| |
| r300ShadeModel(ctx, ctx->Light.ShadeModel); |
| |
| r300PolygonMode(ctx, GL_FRONT, ctx->Polygon.FrontMode); |
| r300PolygonMode(ctx, GL_BACK, ctx->Polygon.BackMode); |
| r300->hw.zbias_cntl.cmd[1] = 0x00000000; |
| |
| r300PolygonOffset(ctx, ctx->Polygon.OffsetFactor, |
| ctx->Polygon.OffsetUnits); |
| r300Enable(ctx, GL_POLYGON_OFFSET_POINT, ctx->Polygon.OffsetPoint); |
| r300Enable(ctx, GL_POLYGON_OFFSET_LINE, ctx->Polygon.OffsetLine); |
| r300Enable(ctx, GL_POLYGON_OFFSET_FILL, ctx->Polygon.OffsetFill); |
| |
| r300->hw.su_depth_scale.cmd[1] = 0x4B7FFFFF; |
| r300->hw.su_depth_scale.cmd[2] = 0x00000000; |
| |
| r300->hw.sc_hyperz.cmd[1] = 0x0000001C; |
| r300->hw.sc_hyperz.cmd[2] = 0x2DA49525; |
| |
| r300->hw.sc_screendoor.cmd[1] = 0x00FFFFFF; |
| |
| r300->hw.us_out_fmt.cmd[1] = R500_OUT_FMT_C4_8 | |
| R500_C0_SEL_B | R500_C1_SEL_G | R500_C2_SEL_R | R500_C3_SEL_A; |
| r300->hw.us_out_fmt.cmd[2] = R500_OUT_FMT_UNUSED | |
| R500_C0_SEL_B | R500_C1_SEL_G | R500_C2_SEL_R | R500_C3_SEL_A; |
| r300->hw.us_out_fmt.cmd[3] = R500_OUT_FMT_UNUSED | |
| R500_C0_SEL_B | R500_C1_SEL_G | R500_C2_SEL_R | R500_C3_SEL_A; |
| r300->hw.us_out_fmt.cmd[4] = R500_OUT_FMT_UNUSED | |
| R500_C0_SEL_B | R500_C1_SEL_G | R500_C2_SEL_R | R500_C3_SEL_A; |
| r300->hw.us_out_fmt.cmd[5] = R300_W_FMT_W24; |
| |
| r300Enable(ctx, GL_FOG, ctx->Fog.Enabled); |
| r300Fogfv(ctx, GL_FOG_MODE, NULL); |
| r300Fogfv(ctx, GL_FOG_DENSITY, &ctx->Fog.Density); |
| r300Fogfv(ctx, GL_FOG_START, &ctx->Fog.Start); |
| r300Fogfv(ctx, GL_FOG_END, &ctx->Fog.End); |
| r300Fogfv(ctx, GL_FOG_COLOR, ctx->Fog.Color); |
| r300Fogfv(ctx, GL_FOG_COORDINATE_SOURCE_EXT, NULL); |
| |
| r300->hw.fg_depth_src.cmd[1] = 0; |
| |
| r300->hw.rb3d_cctl.cmd[1] = 0; |
| |
| r300BlendColor(ctx, ctx->Color.BlendColor); |
| |
| /* 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.rb3d_dither_ctl.cmd[1] = 0; |
| r300->hw.rb3d_dither_ctl.cmd[2] = 0; |
| r300->hw.rb3d_dither_ctl.cmd[3] = 0; |
| r300->hw.rb3d_dither_ctl.cmd[4] = 0; |
| r300->hw.rb3d_dither_ctl.cmd[5] = 0; |
| r300->hw.rb3d_dither_ctl.cmd[6] = 0; |
| r300->hw.rb3d_dither_ctl.cmd[7] = 0; |
| r300->hw.rb3d_dither_ctl.cmd[8] = 0; |
| r300->hw.rb3d_dither_ctl.cmd[9] = 0; |
| |
| r300->hw.rb3d_aaresolve_ctl.cmd[1] = 0; |
| |
| r300->hw.rb3d_discard_src_pixel_lte_threshold.cmd[1] = 0x00000000; |
| r300->hw.rb3d_discard_src_pixel_lte_threshold.cmd[2] = 0xffffffff; |
| |
| 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) { |
| /* XXX: Turn off when clearing buffers ? */ |
| r300->hw.zb.cmd[R300_ZB_PITCH] |= R300_DEPTHMACROTILE_ENABLE; |
| |
| if (ctx->Visual.depthBits == 24) |
| r300->hw.zb.cmd[R300_ZB_PITCH] |= |
| R300_DEPTHMICROTILE_TILED; |
| } |
| |
| r300->hw.zb_depthclearvalue.cmd[1] = 0; |
| |
| switch (ctx->Visual.depthBits) { |
| case 16: |
| r300->hw.zstencil_format.cmd[1] = R300_DEPTHFORMAT_16BIT_INT_Z; |
| break; |
| case 24: |
| r300->hw.zstencil_format.cmd[1] = R300_DEPTHFORMAT_24BIT_INT_Z_8BIT_STENCIL; |
| break; |
| default: |
| fprintf(stderr, "Error: Unsupported depth %d... exiting\n", ctx->Visual.depthBits); |
| _mesa_exit(-1); |
| } |
| |
| r300->hw.zstencil_format.cmd[2] = R300_ZTOP_DISABLE; |
| r300->hw.zstencil_format.cmd[3] = 0x00000003; |
| r300->hw.zstencil_format.cmd[4] = 0x00000000; |
| r300SetEarlyZState(ctx); |
| |
| r300->hw.unk4F30.cmd[1] = 0; |
| r300->hw.unk4F30.cmd[2] = 0; |
| |
| r300->hw.zb_hiz_offset.cmd[1] = 0; |
| |
| r300->hw.zb_hiz_pitch.cmd[1] = 0; |
| |
| r300VapCntl(r300, 0, 0, 0); |
| if (has_tcl) { |
| 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; |
| } |
| |
| r300->hw.all_dirty = GL_TRUE; |
| } |
| |
| void r300UpdateShaders(r300ContextPtr rmesa) |
| { |
| GLcontext *ctx; |
| struct r300_vertex_program *vp; |
| int i; |
| |
| ctx = rmesa->radeon.glCtx; |
| |
| if (rmesa->NewGLState && hw_tcl_on) { |
| rmesa->NewGLState = 0; |
| |
| for (i = _TNL_FIRST_MAT; i <= _TNL_LAST_MAT; i++) { |
| rmesa->temp_attrib[i] = |
| TNL_CONTEXT(ctx)->vb.AttribPtr[i]; |
| TNL_CONTEXT(ctx)->vb.AttribPtr[i] = |
| &rmesa->dummy_attrib[i]; |
| } |
| |
| _tnl_UpdateFixedFunctionProgram(ctx); |
| |
| for (i = _TNL_FIRST_MAT; i <= _TNL_LAST_MAT; i++) { |
| TNL_CONTEXT(ctx)->vb.AttribPtr[i] = |
| rmesa->temp_attrib[i]; |
| } |
| |
| r300SelectVertexShader(rmesa); |
| vp = (struct r300_vertex_program *) |
| CURRENT_VERTEX_SHADER(ctx); |
| /*if (vp->translated == GL_FALSE) |
| r300TranslateVertexShader(vp); */ |
| if (vp->translated == GL_FALSE) { |
| fprintf(stderr, "Failing back to sw-tcl\n"); |
| hw_tcl_on = future_hw_tcl_on = 0; |
| r300ResetHwState(rmesa); |
| |
| r300UpdateStateParameters(ctx, _NEW_PROGRAM); |
| return; |
| } |
| } |
| r300UpdateStateParameters(ctx, _NEW_PROGRAM); |
| } |
| |
| static const GLfloat *get_fragmentprogram_constant(GLcontext *ctx, |
| struct gl_program *program, struct prog_src_register srcreg) |
| { |
| static const GLfloat dummy[4] = { 0, 0, 0, 0 }; |
| |
| switch(srcreg.File) { |
| case PROGRAM_LOCAL_PARAM: |
| return program->LocalParams[srcreg.Index]; |
| case PROGRAM_ENV_PARAM: |
| return ctx->FragmentProgram.Parameters[srcreg.Index]; |
| case PROGRAM_STATE_VAR: |
| case PROGRAM_NAMED_PARAM: |
| case PROGRAM_CONSTANT: |
| return program->Parameters->ParameterValues[srcreg.Index]; |
| default: |
| _mesa_problem(ctx, "get_fragmentprogram_constant: Unknown\n"); |
| return dummy; |
| } |
| } |
| |
| |
| static void r300SetupPixelShader(r300ContextPtr rmesa) |
| { |
| GLcontext *ctx = rmesa->radeon.glCtx; |
| struct r300_fragment_program *fp = (struct r300_fragment_program *) |
| (char *)ctx->FragmentProgram._Current; |
| struct r300_fragment_program_code *code; |
| int i, k; |
| |
| if (!fp) /* should only happenen once, just after context is created */ |
| return; |
| |
| r300TranslateFragmentShader(rmesa, fp); |
| if (!fp->translated) { |
| fprintf(stderr, "%s: No valid fragment shader, exiting\n", |
| __FUNCTION__); |
| return; |
| } |
| code = &fp->code; |
| |
| r300SetupTextures(ctx); |
| |
| R300_STATECHANGE(rmesa, fpi[0]); |
| R300_STATECHANGE(rmesa, fpi[1]); |
| R300_STATECHANGE(rmesa, fpi[2]); |
| R300_STATECHANGE(rmesa, fpi[3]); |
| rmesa->hw.fpi[0].cmd[R300_FPI_CMD_0] = cmdpacket0(R300_US_ALU_RGB_INST_0, code->alu.length); |
| rmesa->hw.fpi[1].cmd[R300_FPI_CMD_0] = cmdpacket0(R300_US_ALU_RGB_ADDR_0, code->alu.length); |
| rmesa->hw.fpi[2].cmd[R300_FPI_CMD_0] = cmdpacket0(R300_US_ALU_ALPHA_INST_0, code->alu.length); |
| rmesa->hw.fpi[3].cmd[R300_FPI_CMD_0] = cmdpacket0(R300_US_ALU_ALPHA_ADDR_0, code->alu.length); |
| for (i = 0; i < code->alu.length; i++) { |
| rmesa->hw.fpi[0].cmd[R300_FPI_INSTR_0 + i] = code->alu.inst[i].inst0; |
| rmesa->hw.fpi[1].cmd[R300_FPI_INSTR_0 + i] = code->alu.inst[i].inst1; |
| rmesa->hw.fpi[2].cmd[R300_FPI_INSTR_0 + i] = code->alu.inst[i].inst2; |
| rmesa->hw.fpi[3].cmd[R300_FPI_INSTR_0 + i] = code->alu.inst[i].inst3; |
| } |
| |
| R300_STATECHANGE(rmesa, fp); |
| rmesa->hw.fp.cmd[R300_FP_CNTL0] = code->cur_node | (code->first_node_has_tex << 3); |
| rmesa->hw.fp.cmd[R300_FP_CNTL1] = code->max_temp_idx; |
| rmesa->hw.fp.cmd[R300_FP_CNTL2] = |
| (0 << R300_PFS_CNTL_ALU_OFFSET_SHIFT) | |
| ((code->alu.length-1) << R300_PFS_CNTL_ALU_END_SHIFT) | |
| (0 << R300_PFS_CNTL_TEX_OFFSET_SHIFT) | |
| ((code->tex.length ? code->tex.length-1 : 0) << R300_PFS_CNTL_TEX_END_SHIFT); |
| /* I just want to say, the way these nodes are stored.. weird.. */ |
| for (i = 0, k = (4 - (code->cur_node + 1)); i < 4; i++, k++) { |
| if (i < (code->cur_node + 1)) { |
| rmesa->hw.fp.cmd[R300_FP_NODE0 + k] = |
| (code->node[i].alu_offset << R300_ALU_START_SHIFT) | |
| (code->node[i].alu_end << R300_ALU_SIZE_SHIFT) | |
| (code->node[i].tex_offset << R300_TEX_START_SHIFT) | |
| (code->node[i].tex_end << R300_TEX_SIZE_SHIFT) | |
| code->node[i].flags; |
| } else { |
| rmesa->hw.fp.cmd[R300_FP_NODE0 + (3 - i)] = 0; |
| } |
| } |
| |
| R300_STATECHANGE(rmesa, fpp); |
| rmesa->hw.fpp.cmd[R300_FPP_CMD_0] = cmdpacket0(R300_PFS_PARAM_0_X, code->const_nr * 4); |
| for (i = 0; i < code->const_nr; i++) { |
| const GLfloat *constant = get_fragmentprogram_constant(ctx, |
| &fp->mesa_program.Base, code->constant[i]); |
| rmesa->hw.fpp.cmd[R300_FPP_PARAM_0 + 4 * i + 0] = r300PackFloat24(constant[0]); |
| rmesa->hw.fpp.cmd[R300_FPP_PARAM_0 + 4 * i + 1] = r300PackFloat24(constant[1]); |
| rmesa->hw.fpp.cmd[R300_FPP_PARAM_0 + 4 * i + 2] = r300PackFloat24(constant[2]); |
| rmesa->hw.fpp.cmd[R300_FPP_PARAM_0 + 4 * i + 3] = r300PackFloat24(constant[3]); |
| } |
| } |
| |
| #define bump_r500fp_count(ptr, new_count) do{\ |
| drm_r300_cmd_header_t* _p=((drm_r300_cmd_header_t*)(ptr));\ |
| int _nc=(new_count)/6; \ |
| assert(_nc < 256); \ |
| if(_nc>_p->r500fp.count)_p->r500fp.count=_nc;\ |
| } while(0) |
| |
| #define bump_r500fp_const_count(ptr, new_count) do{\ |
| drm_r300_cmd_header_t* _p=((drm_r300_cmd_header_t*)(ptr));\ |
| int _nc=(new_count)/4; \ |
| assert(_nc < 256); \ |
| if(_nc>_p->r500fp.count)_p->r500fp.count=_nc;\ |
| } while(0) |
| |
| static void r500SetupPixelShader(r300ContextPtr rmesa) |
| { |
| GLcontext *ctx = rmesa->radeon.glCtx; |
| struct r500_fragment_program *fp = (struct r500_fragment_program *) |
| (char *)ctx->FragmentProgram._Current; |
| int i; |
| struct r500_fragment_program_code *code; |
| |
| if (!fp) /* should only happenen once, just after context is created */ |
| return; |
| |
| ((drm_r300_cmd_header_t *) rmesa->hw.r500fp.cmd)->r500fp.count = 0; |
| ((drm_r300_cmd_header_t *) rmesa->hw.r500fp_const.cmd)->r500fp.count = 0; |
| |
| r500TranslateFragmentShader(rmesa, fp); |
| if (!fp->translated) { |
| fprintf(stderr, "%s: No valid fragment shader, exiting\n", |
| __FUNCTION__); |
| return; |
| } |
| code = &fp->code; |
| |
| if (fp->mesa_program.FogOption != GL_NONE) { |
| /* Enable HW fog. Try not to squish GL context. |
| * (Anybody sane remembered to set glFog() opts first!) */ |
| r300SetFogState(ctx, GL_TRUE); |
| ctx->Fog.Mode = fp->mesa_program.FogOption; |
| r300Fogfv(ctx, GL_FOG_MODE, NULL); |
| } else |
| /* Make sure HW is matching GL context. */ |
| r300SetFogState(ctx, ctx->Fog.Enabled); |
| |
| r300SetupTextures(ctx); |
| |
| R300_STATECHANGE(rmesa, fp); |
| rmesa->hw.fp.cmd[R500_FP_PIXSIZE] = code->max_temp_idx; |
| |
| rmesa->hw.fp.cmd[R500_FP_CODE_ADDR] = |
| R500_US_CODE_START_ADDR(code->inst_offset) | |
| R500_US_CODE_END_ADDR(code->inst_end); |
| rmesa->hw.fp.cmd[R500_FP_CODE_RANGE] = |
| R500_US_CODE_RANGE_ADDR(code->inst_offset) | |
| R500_US_CODE_RANGE_SIZE(code->inst_end); |
| rmesa->hw.fp.cmd[R500_FP_CODE_OFFSET] = |
| R500_US_CODE_OFFSET_ADDR(0); /* FIXME when we add flow control */ |
| |
| R300_STATECHANGE(rmesa, r500fp); |
| /* Emit our shader... */ |
| for (i = 0; i < code->inst_end+1; i++) { |
| rmesa->hw.r500fp.cmd[i*6+1] = code->inst[i].inst0; |
| rmesa->hw.r500fp.cmd[i*6+2] = code->inst[i].inst1; |
| rmesa->hw.r500fp.cmd[i*6+3] = code->inst[i].inst2; |
| rmesa->hw.r500fp.cmd[i*6+4] = code->inst[i].inst3; |
| rmesa->hw.r500fp.cmd[i*6+5] = code->inst[i].inst4; |
| rmesa->hw.r500fp.cmd[i*6+6] = code->inst[i].inst5; |
| } |
| |
| bump_r500fp_count(rmesa->hw.r500fp.cmd, (code->inst_end + 1) * 6); |
| |
| R300_STATECHANGE(rmesa, r500fp_const); |
| for (i = 0; i < code->const_nr; i++) { |
| const GLfloat *constant = get_fragmentprogram_constant(ctx, |
| &fp->mesa_program.Base, code->constant[i]); |
| rmesa->hw.r500fp_const.cmd[R300_FPP_PARAM_0 + 4 * i + 0] = r300PackFloat32(constant[0]); |
| rmesa->hw.r500fp_const.cmd[R300_FPP_PARAM_0 + 4 * i + 1] = r300PackFloat32(constant[1]); |
| rmesa->hw.r500fp_const.cmd[R300_FPP_PARAM_0 + 4 * i + 2] = r300PackFloat32(constant[2]); |
| rmesa->hw.r500fp_const.cmd[R300_FPP_PARAM_0 + 4 * i + 3] = r300PackFloat32(constant[3]); |
| } |
| bump_r500fp_const_count(rmesa->hw.r500fp_const.cmd, code->const_nr * 4); |
| |
| } |
| |
| void r300UpdateShaderStates(r300ContextPtr rmesa) |
| { |
| GLcontext *ctx; |
| ctx = rmesa->radeon.glCtx; |
| |
| r300UpdateTextureState(ctx); |
| r300SetEarlyZState(ctx); |
| |
| GLuint fgdepthsrc = R300_FG_DEPTH_SRC_SCAN; |
| if (current_fragment_program_writes_depth(ctx)) |
| fgdepthsrc = R300_FG_DEPTH_SRC_SHADER; |
| if (fgdepthsrc != rmesa->hw.fg_depth_src.cmd[1]) { |
| R300_STATECHANGE(rmesa, fg_depth_src); |
| rmesa->hw.fg_depth_src.cmd[1] = fgdepthsrc; |
| } |
| |
| if (rmesa->radeon.radeonScreen->chip_family >= CHIP_FAMILY_RV515) |
| r500SetupPixelShader(rmesa); |
| else |
| r300SetupPixelShader(rmesa); |
| |
| if (rmesa->radeon.radeonScreen->chip_family >= CHIP_FAMILY_RV515) |
| r500SetupRSUnit(ctx); |
| else |
| r300SetupRSUnit(ctx); |
| |
| if ((rmesa->radeon.radeonScreen->chip_flags & RADEON_CHIPSET_TCL)) |
| r300SetupVertexProgram(rmesa); |
| |
| } |
| |
| /** |
| * 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); |
| _vbo_InvalidateState(ctx, new_state); |
| _tnl_InvalidateState(ctx, new_state); |
| _ae_invalidate_state(ctx, new_state); |
| |
| if (new_state & (_NEW_BUFFERS | _NEW_COLOR | _NEW_PIXEL)) { |
| r300UpdateDrawBuffer(ctx); |
| } |
| |
| r300UpdateStateParameters(ctx, new_state); |
| |
| r300->NewGLState |= new_state; |
| } |
| |
| /** |
| * 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 = R300_DEPTHFORMAT_16BIT_INT_Z; |
| break; |
| case 24: |
| r300->state.depth.scale = 1.0 / (GLfloat) 0xffffff; |
| depth_fmt = R300_DEPTHFORMAT_24BIT_INT_Z_8BIT_STENCIL; |
| break; |
| default: |
| fprintf(stderr, "Error: Unsupported depth %d... exiting\n", |
| ctx->Visual.depthBits); |
| _mesa_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); |
| (void)rmesa; |
| (void)mode; |
| } |
| |
| void r300UpdateClipPlanes( GLcontext *ctx ) |
| { |
| r300ContextPtr rmesa = R300_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]; |
| |
| R300_STATECHANGE( rmesa, vpucp[p] ); |
| rmesa->hw.vpucp[p].cmd[R300_VPUCP_X] = ip[0]; |
| rmesa->hw.vpucp[p].cmd[R300_VPUCP_Y] = ip[1]; |
| rmesa->hw.vpucp[p].cmd[R300_VPUCP_Z] = ip[2]; |
| rmesa->hw.vpucp[p].cmd[R300_VPUCP_W] = ip[3]; |
| } |
| } |
| } |
| |
| /** |
| * 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->Fogfv = r300Fogfv; |
| functions->FrontFace = r300FrontFace; |
| functions->ShadeModel = r300ShadeModel; |
| functions->LogicOpcode = r300LogicOpcode; |
| |
| /* ARB_point_parameters */ |
| functions->PointParameterfv = r300PointParameter; |
| |
| /* Stencil related */ |
| functions->StencilFuncSeparate = r300StencilFuncSeparate; |
| functions->StencilMaskSeparate = r300StencilMaskSeparate; |
| functions->StencilOpSeparate = r300StencilOpSeparate; |
| |
| /* Viewport related */ |
| functions->Viewport = r300Viewport; |
| functions->DepthRange = r300DepthRange; |
| functions->PointSize = r300PointSize; |
| functions->LineWidth = r300LineWidth; |
| |
| functions->PolygonOffset = r300PolygonOffset; |
| functions->PolygonMode = r300PolygonMode; |
| |
| functions->RenderMode = r300RenderMode; |
| |
| functions->ClipPlane = r300ClipPlane; |
| } |