xenocara/driver/xf86-video-intel/src/i915_3d.h
2006-11-26 20:06:13 +00:00

432 lines
12 KiB
C

/* -*- c-basic-offset: 4 -*- */
/*
* Copyright © 2006 Intel Corporation
*
* 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 AUTHORS OR COPYRIGHT HOLDERS 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:
* Eric Anholt <eric@anholt.net>
*
*/
/* MASK_* are the unshifted bitmasks of the destination mask in arithmetic
* operations
*/
#define MASK_X 0x1
#define MASK_Y 0x2
#define MASK_Z 0x4
#define MASK_W 0x8
#define MASK_XYZ (MASK_X | MASK_Y | MASK_W)
#define MASK_XYZW (MASK_XYZ | MASK_W)
#define MASK_SATURATE 0x10
/* Temporary, undeclared regs. Preserved between phases */
#define FS_R0 ((REG_TYPE_R << 8) | 0)
#define FS_R1 ((REG_TYPE_R << 8) | 1)
#define FS_R2 ((REG_TYPE_R << 8) | 2)
#define FS_R3 ((REG_TYPE_R << 8) | 3)
/* Texture coordinate regs. Must be declared. */
#define FS_T0 ((REG_TYPE_T << 8) | 0)
#define FS_T1 ((REG_TYPE_T << 8) | 1)
#define FS_T2 ((REG_TYPE_T << 8) | 2)
#define FS_T3 ((REG_TYPE_T << 8) | 3)
#define FS_T4 ((REG_TYPE_T << 8) | 4)
#define FS_T5 ((REG_TYPE_T << 8) | 5)
#define FS_T6 ((REG_TYPE_T << 8) | 6)
#define FS_T7 ((REG_TYPE_T << 8) | 7)
#define FS_T8 ((REG_TYPE_T << 8) | 8)
#define FS_T9 ((REG_TYPE_T << 8) | 9)
#define FS_T10 ((REG_TYPE_T << 8) | 10)
/* Constant values */
#define FS_C0 ((REG_TYPE_CONST << 8) | 0)
#define FS_C1 ((REG_TYPE_CONST << 8) | 1)
#define FS_C2 ((REG_TYPE_CONST << 8) | 2)
#define FS_C3 ((REG_TYPE_CONST << 8) | 3)
/* Sampler regs */
#define FS_S0 ((REG_TYPE_S << 8) | 0)
#define FS_S1 ((REG_TYPE_S << 8) | 1)
#define FS_S2 ((REG_TYPE_S << 8) | 2)
#define FS_S3 ((REG_TYPE_S << 8) | 3)
/* Output color */
#define FS_OC ((REG_TYPE_OC << 8) | 0)
/* Output depth */
#define FS_OD ((REG_TYPE_OD << 8) | 0)
/* Unpreserved temporary regs */
#define FS_U0 ((REG_TYPE_U << 8) | 0)
#define FS_U1 ((REG_TYPE_U << 8) | 1)
#define FS_U2 ((REG_TYPE_U << 8) | 2)
#define FS_U3 ((REG_TYPE_U << 8) | 3)
#define REG_TYPE(reg) ((reg) >> 8)
#define REG_NR(reg) ((reg) & 0xff)
struct i915_fs_op {
CARD32 ui[3];
};
#define X_CHANNEL_VAL 1
#define Y_CHANNEL_VAL 2
#define Z_CHANNEL_VAL 3
#define W_CHANNEL_VAL 4
#define ZERO_CHANNEL_VAL 5
#define ONE_CHANNEL_VAL 6
/**
* This structure represents the contents of an operand to an i915 fragment
* shader.
*
* It is not a hardware representation, though closely related.
*/
struct i915_fs_operand {
/**< REG_TYPE_* register type */
int reg;
/**< *_CHANNEL_VAL swizzle value, with optional negation */
int x;
/**< *_CHANNEL_VAL swizzle value, with optional negation */
int y;
/**< *_CHANNEL_VAL swizzle value, with optional negation */
int z;
/**< *_CHANNEL_VAL swizzle value, with optional negation */
int w;
};
/**
* Construct an operand description for the fragment shader.
*
* \param regtype FS_* register used as the source value for X/Y/Z/W sources.
* \param x *_CHANNEL_VAL swizzle value prefix for operand X channel, with
* optional negation.
* \param y *_CHANNEL_VAL swizzle value prefix for operand Y channel, with
* optional negation.
* \param z *_CHANNEL_VAL swizzle value prefix for operand Z channel, with
* optional negation.
* \param w *_CHANNEL_VAL swizzle value prefix for operand W channel, with
* optional negation.
*/
#define i915_fs_operand(reg, x, y, z, w) \
_i915_fs_operand(reg, \
x##_CHANNEL_VAL, y##_CHANNEL_VAL, \
z##_CHANNEL_VAL, w##_CHANNEL_VAL)
/**
* Construct an oeprand description for using a register with no swizzling
*/
#define i915_fs_operand_reg(reg) \
i915_fs_operand(reg, X, Y, Z, W)
static inline struct i915_fs_operand
_i915_fs_operand(int reg, int x, int y, int z, int w)
{
struct i915_fs_operand operand;
operand.reg = reg;
operand.x = x;
operand.y = y;
operand.z = z;
operand.w = w;
return operand;
}
/**
* Returns an operand containing (0.0, 0.0, 0.0, 0.0).
*/
static inline struct i915_fs_operand
i915_fs_operand_zero(void)
{
return i915_fs_operand(FS_R0, ZERO, ZERO, ZERO, ZERO);
}
/**
* Returns an unused operand
*/
#define i915_fs_operand_none() i915_fs_operand_zero()
/**
* Returns an operand containing (1.0, 1.0, 1.0, 1.0).
*/
static inline struct i915_fs_operand
i915_fs_operand_one(void)
{
return i915_fs_operand(FS_R0, ONE, ONE, ONE, ONE);
}
static inline int
i915_get_hardware_channel_val(int channel_val)
{
if (channel_val < 0)
channel_val = -channel_val;
switch (channel_val) {
case X_CHANNEL_VAL:
return SRC_X;
case Y_CHANNEL_VAL:
return SRC_Y;
case Z_CHANNEL_VAL:
return SRC_Z;
case W_CHANNEL_VAL:
return SRC_W;
case ZERO_CHANNEL_VAL:
return SRC_ZERO;
case ONE_CHANNEL_VAL:
return SRC_ONE;
}
FatalError("Bad channel value %d\n", channel_val);
}
/**
* Outputs a fragment shader command to declare a sampler or texture register.
*/
#define i915_fs_dcl(reg) \
do { \
FS_OUT(_i915_fs_dcl(reg)); \
} while (0)
/**
* Constructs a fragment shader command to declare a sampler or texture
* register.
*/
static inline struct i915_fs_op
_i915_fs_dcl(int reg)
{
struct i915_fs_op op;
op.ui[0] = D0_DCL | (REG_TYPE(reg) << D0_TYPE_SHIFT) |
(REG_NR(reg) << D0_NR_SHIFT);
op.ui[1] = 0;
op.ui[2] = 0;
if (REG_TYPE(reg) != REG_TYPE_S)
op.ui[0] |= D0_CHANNEL_ALL;
return op;
}
/**
* Constructs a fragment shader command to load from a texture sampler.
*/
#define i915_fs_texld(dest_reg, sampler_reg, address_reg) \
do { \
FS_OUT(_i915_fs_texld(T0_TEXLD, dest_reg, sampler_reg, address_reg)); \
} while (0)
static inline struct i915_fs_op
_i915_fs_texld(int load_op, int dest_reg, int sampler_reg, int address_reg)
{
struct i915_fs_op op;
op.ui[0] = 0;
op.ui[1] = 0;
op.ui[2] = 0;
if (REG_TYPE(sampler_reg) != REG_TYPE_S)
FatalError("Bad sampler reg type\n");
op.ui[0] |= load_op;
op.ui[0] |= REG_TYPE(dest_reg) << T0_DEST_TYPE_SHIFT;
op.ui[0] |= REG_NR(dest_reg) << T0_DEST_NR_SHIFT;
op.ui[0] |= REG_NR(sampler_reg) << T0_SAMPLER_NR_SHIFT;
op.ui[1] |= REG_TYPE(address_reg) << T1_ADDRESS_REG_TYPE_SHIFT;
op.ui[1] |= REG_NR(address_reg) << T1_ADDRESS_REG_NR_SHIFT;
return op;
}
#define i915_fs_arith(op, dest_reg, operand0, operand1, operand2) \
_i915_fs_arith(A0_##op, dest_reg, operand0, operand1, operand2)
static inline struct i915_fs_op
_i915_fs_arith(int cmd, int dest_reg,
struct i915_fs_operand operand0,
struct i915_fs_operand operand1,
struct i915_fs_operand operand2)
{
struct i915_fs_op op;
op.ui[0] = 0;
op.ui[1] = 0;
op.ui[2] = 0;
/* Set up destination register and write mask */
op.ui[0] |= cmd;
op.ui[0] |= REG_TYPE(dest_reg) << A0_DEST_TYPE_SHIFT;
op.ui[0] |= REG_NR(dest_reg) << A0_DEST_NR_SHIFT;
op.ui[0] |= A0_DEST_CHANNEL_ALL;
/* Set up operand 0 */
op.ui[0] |= REG_TYPE(operand0.reg) << A0_SRC0_TYPE_SHIFT;
op.ui[0] |= REG_NR(operand0.reg) << A0_SRC0_NR_SHIFT;
op.ui[1] |= i915_get_hardware_channel_val(operand0.x) <<
A1_SRC0_CHANNEL_X_SHIFT;
if (operand0.x < 0)
op.ui[1] |= A1_SRC0_CHANNEL_X_NEGATE;
op.ui[1] |= i915_get_hardware_channel_val(operand0.y) <<
A1_SRC0_CHANNEL_Y_SHIFT;
if (operand0.y < 0)
op.ui[1] |= A1_SRC0_CHANNEL_Y_NEGATE;
op.ui[1] |= i915_get_hardware_channel_val(operand0.z) <<
A1_SRC0_CHANNEL_Z_SHIFT;
if (operand0.z < 0)
op.ui[1] |= A1_SRC0_CHANNEL_Z_NEGATE;
op.ui[1] |= i915_get_hardware_channel_val(operand0.w) <<
A1_SRC0_CHANNEL_W_SHIFT;
if (operand0.w < 0)
op.ui[1] |= A1_SRC0_CHANNEL_W_NEGATE;
/* Set up operand 1 */
op.ui[1] |= REG_TYPE(operand1.reg) << A1_SRC1_TYPE_SHIFT;
op.ui[1] |= REG_NR(operand1.reg) << A1_SRC1_NR_SHIFT;
op.ui[1] |= i915_get_hardware_channel_val(operand1.x) <<
A1_SRC1_CHANNEL_X_SHIFT;
if (operand1.x < 0)
op.ui[1] |= A1_SRC1_CHANNEL_X_NEGATE;
op.ui[1] |= i915_get_hardware_channel_val(operand1.y) <<
A1_SRC1_CHANNEL_Y_SHIFT;
if (operand1.y < 0)
op.ui[1] |= A1_SRC1_CHANNEL_Y_NEGATE;
op.ui[2] |= i915_get_hardware_channel_val(operand1.z) <<
A2_SRC1_CHANNEL_Z_SHIFT;
if (operand1.z < 0)
op.ui[2] |= A2_SRC1_CHANNEL_Z_NEGATE;
op.ui[2] |= i915_get_hardware_channel_val(operand1.w) <<
A2_SRC1_CHANNEL_W_SHIFT;
if (operand1.w < 0)
op.ui[2] |= A2_SRC1_CHANNEL_W_NEGATE;
/* Set up operand 2 */
op.ui[2] |= REG_TYPE(operand2.reg) << A2_SRC2_TYPE_SHIFT;
op.ui[2] |= REG_NR(operand2.reg) << A2_SRC2_NR_SHIFT;
op.ui[2] |= i915_get_hardware_channel_val(operand2.x) <<
A2_SRC2_CHANNEL_X_SHIFT;
if (operand2.x < 0)
op.ui[2] |= A2_SRC2_CHANNEL_X_NEGATE;
op.ui[2] |= i915_get_hardware_channel_val(operand2.y) <<
A2_SRC2_CHANNEL_Y_SHIFT;
if (operand2.y < 0)
op.ui[2] |= A2_SRC2_CHANNEL_Y_NEGATE;
op.ui[2] |= i915_get_hardware_channel_val(operand2.z) <<
A2_SRC2_CHANNEL_Z_SHIFT;
if (operand2.z < 0)
op.ui[2] |= A2_SRC2_CHANNEL_Z_NEGATE;
op.ui[2] |= i915_get_hardware_channel_val(operand2.w) <<
A2_SRC2_CHANNEL_W_SHIFT;
if (operand2.w < 0)
op.ui[2] |= A2_SRC2_CHANNEL_W_NEGATE;
return op;
}
/**
* Move the values in operand0 to the dest reg with the masking/saturation
* specified.
*/
#define i915_fs_mov_masked(dest_reg, dest_mask, operand0) \
do { \
struct i915_fs_op op; \
\
op = i915_fs_arith(MOV, dest_reg, operand0, i915_fs_operand_none(), \
i915_fs_operand_none()); \
op.ui[0] &= ~A0_DEST_CHANNEL_ALL; \
op.ui[0] |= ((dest_mask) & ~MASK_SATURATE) << A0_DEST_CHANNEL_SHIFT; \
if ((dest_mask) & MASK_SATURATE) \
op.ui[0] |= A0_DEST_SATURATE; \
\
FS_OUT(op); \
} while (0)
/** Add operand0 and operand1 and put the result in dest_reg */
#define i915_fs_add(dest_reg, operand0, operand1) \
do { \
FS_OUT(i915_fs_arith(ADD, dest_reg, operand0, operand1, \
i915_fs_operand_none())); \
} while (0)
/**
* Perform a 3-component dot-product of operand0 and operand1 and put the
* resulting scalar in the channels of dest_reg specified by the dest_mask.
*/
#define i915_fs_dp3_masked(dest_reg, dest_mask, operand0, operand1) \
do { \
struct i915_fs_op op; \
\
op = i915_fs_arith(DP3, dest_reg, operand0, i915_fs_operand_none(), \
i915_fs_operand_none()); \
op.ui[0] &= ~A0_DEST_CHANNEL_ALL; \
op.ui[0] |= ((dest_mask) & ~MASK_SATURATE) << A0_DEST_CHANNEL_SHIFT; \
if ((dest_mask) & MASK_SATURATE) \
op.ui[0] |= A0_DEST_SATURATE; \
\
FS_OUT(op); \
} while (0)
/**
* Sets up local state for accumulating a fragment shader buffer.
*
* \param x maximum number of shader commands that may be used between
* a FS_START and FS_END
*/
#define FS_LOCALS(x) \
CARD32 _shader_buf[(x) * 3]; \
int _max_shader_commands = x; \
int _cur_shader_commands
#define FS_BEGIN() \
do { \
_cur_shader_commands = 0; \
} while (0)
#define FS_OUT(_shaderop) \
do { \
_shader_buf[_cur_shader_commands * 3 + 0] = _shaderop.ui[0]; \
_shader_buf[_cur_shader_commands * 3 + 1] = _shaderop.ui[1]; \
_shader_buf[_cur_shader_commands * 3 + 2] = _shaderop.ui[2]; \
if (++_cur_shader_commands > _max_shader_commands) \
FatalError("fragment shader command buffer exceeded (%d)\n", \
_cur_shader_commands); \
} while (0)
#define FS_END() \
do { \
int _i; \
BEGIN_LP_RING(_cur_shader_commands * 3 + 1); \
OUT_RING(_3DSTATE_PIXEL_SHADER_PROGRAM | \
(_cur_shader_commands * 3 - 1)); \
for (_i = 0; _i < _cur_shader_commands * 3; _i++) \
OUT_RING(_shader_buf[_i]); \
ADVANCE_LP_RING(); \
} while (0);