summaryrefslogtreecommitdiff
path: root/src/i915_3d.h
diff options
context:
space:
mode:
authorEric Anholt <anholt@FreeBSD.org>2006-07-18 16:18:18 -0400
committerEric Anholt <anholt@FreeBSD.org>2006-07-18 18:24:28 -0400
commit5176d62ba58c100c87f75a4f333d00129d780c99 (patch)
tree7cad790a132b9fdc697a89ccc14a82d91fe61f18 /src/i915_3d.h
parent148ef9bdd9e0ef3e7ac86b56a8662b53a3ea9168 (diff)
Add an API for programming i915 fragment programs.
Diffstat (limited to 'src/i915_3d.h')
-rw-r--r--src/i915_3d.h431
1 files changed, 431 insertions, 0 deletions
diff --git a/src/i915_3d.h b/src/i915_3d.h
new file mode 100644
index 00000000..fc4ca603
--- /dev/null
+++ b/src/i915_3d.h
@@ -0,0 +1,431 @@
+/* -*- 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);