1fa225cbcSrjs/* -*- c-basic-offset: 4 -*- */
2fa225cbcSrjs/*
3fa225cbcSrjs * Copyright © 2006 Intel Corporation
4fa225cbcSrjs *
5fa225cbcSrjs * Permission is hereby granted, free of charge, to any person obtaining a
6fa225cbcSrjs * copy of this software and associated documentation files (the "Software"),
7fa225cbcSrjs * to deal in the Software without restriction, including without limitation
8fa225cbcSrjs * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9fa225cbcSrjs * and/or sell copies of the Software, and to permit persons to whom the
10fa225cbcSrjs * Software is furnished to do so, subject to the following conditions:
11fa225cbcSrjs *
12fa225cbcSrjs * The above copyright notice and this permission notice (including the next
13fa225cbcSrjs * paragraph) shall be included in all copies or substantial portions of the
14fa225cbcSrjs * Software.
15fa225cbcSrjs *
16fa225cbcSrjs * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17fa225cbcSrjs * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18fa225cbcSrjs * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19fa225cbcSrjs * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20fa225cbcSrjs * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21fa225cbcSrjs * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22fa225cbcSrjs * SOFTWARE.
23fa225cbcSrjs *
24fa225cbcSrjs * Authors:
25fa225cbcSrjs *    Eric Anholt <eric@anholt.net>
26fa225cbcSrjs *
27fa225cbcSrjs */
28fa225cbcSrjs
29fa225cbcSrjs/* MASK_* are the unshifted bitmasks of the destination mask in arithmetic
30fa225cbcSrjs * operations
31fa225cbcSrjs */
32fa225cbcSrjs#define MASK_X			0x1
33fa225cbcSrjs#define MASK_Y			0x2
34fa225cbcSrjs#define MASK_Z			0x4
35fa225cbcSrjs#define MASK_W			0x8
36fa225cbcSrjs#define MASK_XYZ		(MASK_X | MASK_Y | MASK_Z)
37fa225cbcSrjs#define MASK_XYZW		(MASK_XYZ | MASK_W)
38fa225cbcSrjs#define MASK_SATURATE		0x10
39fa225cbcSrjs
40fa225cbcSrjs/* Temporary, undeclared regs. Preserved between phases */
41fa225cbcSrjs#define FS_R0			((REG_TYPE_R << 8) | 0)
42fa225cbcSrjs#define FS_R1			((REG_TYPE_R << 8) | 1)
43fa225cbcSrjs#define FS_R2			((REG_TYPE_R << 8) | 2)
44fa225cbcSrjs#define FS_R3			((REG_TYPE_R << 8) | 3)
45fa225cbcSrjs
46fa225cbcSrjs/* Texture coordinate regs.  Must be declared. */
47fa225cbcSrjs#define FS_T0			((REG_TYPE_T << 8) | 0)
48fa225cbcSrjs#define FS_T1			((REG_TYPE_T << 8) | 1)
49fa225cbcSrjs#define FS_T2			((REG_TYPE_T << 8) | 2)
50fa225cbcSrjs#define FS_T3			((REG_TYPE_T << 8) | 3)
51fa225cbcSrjs#define FS_T4			((REG_TYPE_T << 8) | 4)
52fa225cbcSrjs#define FS_T5			((REG_TYPE_T << 8) | 5)
53fa225cbcSrjs#define FS_T6			((REG_TYPE_T << 8) | 6)
54fa225cbcSrjs#define FS_T7			((REG_TYPE_T << 8) | 7)
55fa225cbcSrjs#define FS_T8			((REG_TYPE_T << 8) | 8)
56fa225cbcSrjs#define FS_T9			((REG_TYPE_T << 8) | 9)
57fa225cbcSrjs#define FS_T10			((REG_TYPE_T << 8) | 10)
58fa225cbcSrjs
59fa225cbcSrjs/* Constant values */
60fa225cbcSrjs#define FS_C0			((REG_TYPE_CONST << 8) | 0)
61fa225cbcSrjs#define FS_C1			((REG_TYPE_CONST << 8) | 1)
62fa225cbcSrjs#define FS_C2			((REG_TYPE_CONST << 8) | 2)
63fa225cbcSrjs#define FS_C3			((REG_TYPE_CONST << 8) | 3)
64fa225cbcSrjs#define FS_C4			((REG_TYPE_CONST << 8) | 4)
65fa225cbcSrjs#define FS_C5			((REG_TYPE_CONST << 8) | 5)
66fa225cbcSrjs#define FS_C6			((REG_TYPE_CONST << 8) | 6)
67fa225cbcSrjs#define FS_C7			((REG_TYPE_CONST << 8) | 7)
68fa225cbcSrjs
69fa225cbcSrjs/* Sampler regs */
70fa225cbcSrjs#define FS_S0			((REG_TYPE_S << 8) | 0)
71fa225cbcSrjs#define FS_S1			((REG_TYPE_S << 8) | 1)
72fa225cbcSrjs#define FS_S2			((REG_TYPE_S << 8) | 2)
73fa225cbcSrjs#define FS_S3			((REG_TYPE_S << 8) | 3)
74fa225cbcSrjs
75fa225cbcSrjs/* Output color */
76fa225cbcSrjs#define FS_OC			((REG_TYPE_OC << 8) | 0)
77fa225cbcSrjs
78fa225cbcSrjs/* Output depth */
79fa225cbcSrjs#define FS_OD			((REG_TYPE_OD << 8) | 0)
80fa225cbcSrjs
81fa225cbcSrjs/* Unpreserved temporary regs */
82fa225cbcSrjs#define FS_U0			((REG_TYPE_U << 8) | 0)
83fa225cbcSrjs#define FS_U1			((REG_TYPE_U << 8) | 1)
84fa225cbcSrjs#define FS_U2			((REG_TYPE_U << 8) | 2)
85fa225cbcSrjs#define FS_U3			((REG_TYPE_U << 8) | 3)
86fa225cbcSrjs
87fa225cbcSrjs#define REG_TYPE(reg)		((reg) >> 8)
88fa225cbcSrjs#define REG_NR(reg)		((reg) & 0xff)
89fa225cbcSrjs
90fa225cbcSrjsstruct i915_fs_op {
91fa225cbcSrjs    uint32_t ui[3];
92fa225cbcSrjs};
93fa225cbcSrjs
94fa225cbcSrjs#define X_CHANNEL_VAL		1
95fa225cbcSrjs#define Y_CHANNEL_VAL		2
96fa225cbcSrjs#define Z_CHANNEL_VAL		3
97fa225cbcSrjs#define W_CHANNEL_VAL		4
98fa225cbcSrjs#define ZERO_CHANNEL_VAL	5
99fa225cbcSrjs#define ONE_CHANNEL_VAL		6
100fa225cbcSrjs
101fa225cbcSrjs/**
102fa225cbcSrjs * This structure represents the contents of an operand to an i915 fragment
103fa225cbcSrjs * shader.
104fa225cbcSrjs *
105fa225cbcSrjs * It is not a hardware representation, though closely related.
106fa225cbcSrjs */
107fa225cbcSrjsstruct i915_fs_operand {
108fa225cbcSrjs    /**< REG_TYPE_* register type */
109fa225cbcSrjs    int reg;
110fa225cbcSrjs    /**< *_CHANNEL_VAL swizzle value, with optional negation */
111fa225cbcSrjs    int x;
112fa225cbcSrjs    /**< *_CHANNEL_VAL swizzle value, with optional negation */
113fa225cbcSrjs    int y;
114fa225cbcSrjs    /**< *_CHANNEL_VAL swizzle value, with optional negation */
115fa225cbcSrjs    int z;
116fa225cbcSrjs    /**< *_CHANNEL_VAL swizzle value, with optional negation */
117fa225cbcSrjs    int w;
118fa225cbcSrjs};
119fa225cbcSrjs
120fa225cbcSrjs/**
121fa225cbcSrjs * Construct an operand description for the fragment shader.
122fa225cbcSrjs *
123fa225cbcSrjs * \param regtype FS_* register used as the source value for X/Y/Z/W sources.
124fa225cbcSrjs * \param x *_CHANNEL_VAL swizzle value prefix for operand X channel, with
125fa225cbcSrjs *          optional negation.
126fa225cbcSrjs * \param y *_CHANNEL_VAL swizzle value prefix for operand Y channel, with
127fa225cbcSrjs *          optional negation.
128fa225cbcSrjs * \param z *_CHANNEL_VAL swizzle value prefix for operand Z channel, with
129fa225cbcSrjs *          optional negation.
130fa225cbcSrjs * \param w *_CHANNEL_VAL swizzle value prefix for operand W channel, with
131fa225cbcSrjs *          optional negation.
132fa225cbcSrjs */
133fa225cbcSrjs#define i915_fs_operand(reg, x, y, z, w)				\
134fa225cbcSrjs    _i915_fs_operand(reg,						\
135fa225cbcSrjs		     x##_CHANNEL_VAL, y##_CHANNEL_VAL,			\
136fa225cbcSrjs		     z##_CHANNEL_VAL, w##_CHANNEL_VAL)
137fa225cbcSrjs
138fa225cbcSrjs/**
139fa225cbcSrjs * Construct an oeprand description for using a register with no swizzling
140fa225cbcSrjs */
141fa225cbcSrjs#define i915_fs_operand_reg(reg)					\
142fa225cbcSrjs    i915_fs_operand(reg, X, Y, Z, W)
143fa225cbcSrjs
144fa225cbcSrjsstatic inline struct i915_fs_operand
145fa225cbcSrjs_i915_fs_operand(int reg, int x, int y, int z, int w)
146fa225cbcSrjs{
147fa225cbcSrjs    struct i915_fs_operand operand;
148fa225cbcSrjs
149fa225cbcSrjs    operand.reg = reg;
150fa225cbcSrjs    operand.x = x;
151fa225cbcSrjs    operand.y = y;
152fa225cbcSrjs    operand.z = z;
153fa225cbcSrjs    operand.w = w;
154fa225cbcSrjs
155fa225cbcSrjs    return operand;
156fa225cbcSrjs}
157fa225cbcSrjs
158fa225cbcSrjs/**
159fa225cbcSrjs * Returns an operand containing (0.0, 0.0, 0.0, 0.0).
160fa225cbcSrjs */
161fa225cbcSrjsstatic inline struct i915_fs_operand
162fa225cbcSrjsi915_fs_operand_zero(void)
163fa225cbcSrjs{
164fa225cbcSrjs    return i915_fs_operand(FS_R0, ZERO, ZERO, ZERO, ZERO);
165fa225cbcSrjs}
166fa225cbcSrjs
167fa225cbcSrjs/**
168fa225cbcSrjs * Returns an unused operand
169fa225cbcSrjs */
170fa225cbcSrjs#define i915_fs_operand_none() i915_fs_operand_zero()
171fa225cbcSrjs
172fa225cbcSrjs/**
173fa225cbcSrjs * Returns an operand containing (1.0, 1.0, 1.0, 1.0).
174fa225cbcSrjs */
175fa225cbcSrjsstatic inline struct i915_fs_operand
176fa225cbcSrjsi915_fs_operand_one(void)
177fa225cbcSrjs{
178fa225cbcSrjs    return i915_fs_operand(FS_R0, ONE, ONE, ONE, ONE);
179fa225cbcSrjs}
180fa225cbcSrjs
181fa225cbcSrjsstatic inline int
182fa225cbcSrjsi915_get_hardware_channel_val(int channel_val)
183fa225cbcSrjs{
184fa225cbcSrjs    if (channel_val < 0)
185fa225cbcSrjs	channel_val = -channel_val;
186fa225cbcSrjs
187fa225cbcSrjs    switch (channel_val) {
188fa225cbcSrjs    case X_CHANNEL_VAL:
189fa225cbcSrjs	return SRC_X;
190fa225cbcSrjs    case Y_CHANNEL_VAL:
191fa225cbcSrjs	return SRC_Y;
192fa225cbcSrjs    case Z_CHANNEL_VAL:
193fa225cbcSrjs	return SRC_Z;
194fa225cbcSrjs    case W_CHANNEL_VAL:
195fa225cbcSrjs	return SRC_W;
196fa225cbcSrjs    case ZERO_CHANNEL_VAL:
197fa225cbcSrjs	return SRC_ZERO;
198fa225cbcSrjs    case ONE_CHANNEL_VAL:
199fa225cbcSrjs	return SRC_ONE;
200fa225cbcSrjs    }
201fa225cbcSrjs    FatalError("Bad channel value %d\n", channel_val);
202fa225cbcSrjs}
203fa225cbcSrjs
204fa225cbcSrjs/**
205fa225cbcSrjs * Outputs a fragment shader command to declare a sampler or texture register.
206fa225cbcSrjs */
207fa225cbcSrjs#define i915_fs_dcl(reg)						\
208fa225cbcSrjsdo {									\
209fa225cbcSrjs    FS_OUT(_i915_fs_dcl(reg));						\
210fa225cbcSrjs} while (0)
211fa225cbcSrjs
212fa225cbcSrjs/**
213fa225cbcSrjs * Constructs a fragment shader command to declare a sampler or texture
214fa225cbcSrjs * register.
215fa225cbcSrjs */
216fa225cbcSrjsstatic inline struct i915_fs_op
217fa225cbcSrjs_i915_fs_dcl(int reg)
218fa225cbcSrjs{
219fa225cbcSrjs    struct i915_fs_op op;
220fa225cbcSrjs
221fa225cbcSrjs    op.ui[0] = D0_DCL | (REG_TYPE(reg) << D0_TYPE_SHIFT) |
222fa225cbcSrjs	(REG_NR(reg) << D0_NR_SHIFT);
223fa225cbcSrjs    op.ui[1] = 0;
224fa225cbcSrjs    op.ui[2] = 0;
225fa225cbcSrjs    if (REG_TYPE(reg) != REG_TYPE_S)
226fa225cbcSrjs	op.ui[0] |= D0_CHANNEL_ALL;
227fa225cbcSrjs
228fa225cbcSrjs    return op;
229fa225cbcSrjs}
230fa225cbcSrjs
231fa225cbcSrjs/**
232fa225cbcSrjs * Constructs a fragment shader command to load from a texture sampler.
233fa225cbcSrjs */
234fa225cbcSrjs#define i915_fs_texld(dest_reg, sampler_reg, address_reg)		\
235fa225cbcSrjsdo {									\
236fa225cbcSrjs     FS_OUT(_i915_fs_texld(T0_TEXLD, dest_reg, sampler_reg, address_reg)); \
237fa225cbcSrjs} while (0)
238fa225cbcSrjs
239fa225cbcSrjs#define i915_fs_texldp(dest_reg, sampler_reg, address_reg)		\
240fa225cbcSrjsdo {									\
241fa225cbcSrjs     FS_OUT(_i915_fs_texld(T0_TEXLDP, dest_reg, sampler_reg, address_reg)); \
242fa225cbcSrjs} while (0)
243fa225cbcSrjs
244fa225cbcSrjsstatic inline struct i915_fs_op
245fa225cbcSrjs_i915_fs_texld(int load_op, int dest_reg, int sampler_reg, int address_reg)
246fa225cbcSrjs{
247fa225cbcSrjs    struct i915_fs_op op;
248fa225cbcSrjs
249fa225cbcSrjs    op.ui[0] = 0;
250fa225cbcSrjs    op.ui[1] = 0;
251fa225cbcSrjs    op.ui[2] = 0;
252fa225cbcSrjs
253fa225cbcSrjs    if (REG_TYPE(sampler_reg) != REG_TYPE_S)
254fa225cbcSrjs	FatalError("Bad sampler reg type\n");
255fa225cbcSrjs
256fa225cbcSrjs    op.ui[0] |= load_op;
257fa225cbcSrjs    op.ui[0] |= REG_TYPE(dest_reg) << T0_DEST_TYPE_SHIFT;
258fa225cbcSrjs    op.ui[0] |= REG_NR(dest_reg) << T0_DEST_NR_SHIFT;
259fa225cbcSrjs    op.ui[0] |= REG_NR(sampler_reg) << T0_SAMPLER_NR_SHIFT;
260fa225cbcSrjs    op.ui[1] |= REG_TYPE(address_reg) << T1_ADDRESS_REG_TYPE_SHIFT;
261fa225cbcSrjs    op.ui[1] |= REG_NR(address_reg) << T1_ADDRESS_REG_NR_SHIFT;
262fa225cbcSrjs
263fa225cbcSrjs    return op;
264fa225cbcSrjs}
265fa225cbcSrjs
266fa225cbcSrjs#define i915_fs_arith(op, dest_reg, operand0, operand1, operand2)	\
267fa225cbcSrjs    _i915_fs_arith(A0_##op, dest_reg, operand0, operand1, operand2)
268fa225cbcSrjs
269fa225cbcSrjsstatic inline struct i915_fs_op
270fa225cbcSrjs_i915_fs_arith(int cmd, int dest_reg,
271fa225cbcSrjs	       struct i915_fs_operand operand0,
272fa225cbcSrjs	       struct i915_fs_operand operand1,
273fa225cbcSrjs	       struct i915_fs_operand operand2)
274fa225cbcSrjs{
275fa225cbcSrjs    struct i915_fs_op op;
276fa225cbcSrjs
277fa225cbcSrjs    op.ui[0] = 0;
278fa225cbcSrjs    op.ui[1] = 0;
279fa225cbcSrjs    op.ui[2] = 0;
280fa225cbcSrjs
281fa225cbcSrjs    /* Set up destination register and write mask */
282fa225cbcSrjs    op.ui[0] |= cmd;
283fa225cbcSrjs    op.ui[0] |= REG_TYPE(dest_reg) << A0_DEST_TYPE_SHIFT;
284fa225cbcSrjs    op.ui[0] |= REG_NR(dest_reg) << A0_DEST_NR_SHIFT;
285fa225cbcSrjs    op.ui[0] |= A0_DEST_CHANNEL_ALL;
286fa225cbcSrjs
287fa225cbcSrjs    /* Set up operand 0 */
288fa225cbcSrjs    op.ui[0] |= REG_TYPE(operand0.reg) << A0_SRC0_TYPE_SHIFT;
289fa225cbcSrjs    op.ui[0] |= REG_NR(operand0.reg) << A0_SRC0_NR_SHIFT;
290fa225cbcSrjs
291fa225cbcSrjs    op.ui[1] |= i915_get_hardware_channel_val(operand0.x) <<
292fa225cbcSrjs	A1_SRC0_CHANNEL_X_SHIFT;
293fa225cbcSrjs    if (operand0.x < 0)
294fa225cbcSrjs	op.ui[1] |= A1_SRC0_CHANNEL_X_NEGATE;
295fa225cbcSrjs
296fa225cbcSrjs    op.ui[1] |= i915_get_hardware_channel_val(operand0.y) <<
297fa225cbcSrjs	A1_SRC0_CHANNEL_Y_SHIFT;
298fa225cbcSrjs    if (operand0.y < 0)
299fa225cbcSrjs	op.ui[1] |= A1_SRC0_CHANNEL_Y_NEGATE;
300fa225cbcSrjs
301fa225cbcSrjs    op.ui[1] |= i915_get_hardware_channel_val(operand0.z) <<
302fa225cbcSrjs	A1_SRC0_CHANNEL_Z_SHIFT;
303fa225cbcSrjs    if (operand0.z < 0)
304fa225cbcSrjs	op.ui[1] |= A1_SRC0_CHANNEL_Z_NEGATE;
305fa225cbcSrjs
306fa225cbcSrjs    op.ui[1] |= i915_get_hardware_channel_val(operand0.w) <<
307fa225cbcSrjs	A1_SRC0_CHANNEL_W_SHIFT;
308fa225cbcSrjs    if (operand0.w < 0)
309fa225cbcSrjs	op.ui[1] |= A1_SRC0_CHANNEL_W_NEGATE;
310fa225cbcSrjs
311fa225cbcSrjs    /* Set up operand 1 */
312fa225cbcSrjs    op.ui[1] |= REG_TYPE(operand1.reg) << A1_SRC1_TYPE_SHIFT;
313fa225cbcSrjs    op.ui[1] |= REG_NR(operand1.reg) << A1_SRC1_NR_SHIFT;
314fa225cbcSrjs
315fa225cbcSrjs    op.ui[1] |= i915_get_hardware_channel_val(operand1.x) <<
316fa225cbcSrjs	A1_SRC1_CHANNEL_X_SHIFT;
317fa225cbcSrjs    if (operand1.x < 0)
318fa225cbcSrjs	op.ui[1] |= A1_SRC1_CHANNEL_X_NEGATE;
319fa225cbcSrjs
320fa225cbcSrjs    op.ui[1] |= i915_get_hardware_channel_val(operand1.y) <<
321fa225cbcSrjs	A1_SRC1_CHANNEL_Y_SHIFT;
322fa225cbcSrjs    if (operand1.y < 0)
323fa225cbcSrjs	op.ui[1] |= A1_SRC1_CHANNEL_Y_NEGATE;
324fa225cbcSrjs
325fa225cbcSrjs    op.ui[2] |= i915_get_hardware_channel_val(operand1.z) <<
326fa225cbcSrjs	A2_SRC1_CHANNEL_Z_SHIFT;
327fa225cbcSrjs    if (operand1.z < 0)
328fa225cbcSrjs	op.ui[2] |= A2_SRC1_CHANNEL_Z_NEGATE;
329fa225cbcSrjs
330fa225cbcSrjs    op.ui[2] |= i915_get_hardware_channel_val(operand1.w) <<
331fa225cbcSrjs	A2_SRC1_CHANNEL_W_SHIFT;
332fa225cbcSrjs    if (operand1.w < 0)
333fa225cbcSrjs	op.ui[2] |= A2_SRC1_CHANNEL_W_NEGATE;
334fa225cbcSrjs
335fa225cbcSrjs    /* Set up operand 2 */
336fa225cbcSrjs    op.ui[2] |= REG_TYPE(operand2.reg) << A2_SRC2_TYPE_SHIFT;
337fa225cbcSrjs    op.ui[2] |= REG_NR(operand2.reg) << A2_SRC2_NR_SHIFT;
338fa225cbcSrjs
339fa225cbcSrjs    op.ui[2] |= i915_get_hardware_channel_val(operand2.x) <<
340fa225cbcSrjs	A2_SRC2_CHANNEL_X_SHIFT;
341fa225cbcSrjs    if (operand2.x < 0)
342fa225cbcSrjs	op.ui[2] |= A2_SRC2_CHANNEL_X_NEGATE;
343fa225cbcSrjs
344fa225cbcSrjs    op.ui[2] |= i915_get_hardware_channel_val(operand2.y) <<
345fa225cbcSrjs	A2_SRC2_CHANNEL_Y_SHIFT;
346fa225cbcSrjs    if (operand2.y < 0)
347fa225cbcSrjs	op.ui[2] |= A2_SRC2_CHANNEL_Y_NEGATE;
348fa225cbcSrjs
349fa225cbcSrjs    op.ui[2] |= i915_get_hardware_channel_val(operand2.z) <<
350fa225cbcSrjs	A2_SRC2_CHANNEL_Z_SHIFT;
351fa225cbcSrjs    if (operand2.z < 0)
352fa225cbcSrjs	op.ui[2] |= A2_SRC2_CHANNEL_Z_NEGATE;
353fa225cbcSrjs
354fa225cbcSrjs    op.ui[2] |= i915_get_hardware_channel_val(operand2.w) <<
355fa225cbcSrjs	A2_SRC2_CHANNEL_W_SHIFT;
356fa225cbcSrjs    if (operand2.w < 0)
357fa225cbcSrjs	op.ui[2] |= A2_SRC2_CHANNEL_W_NEGATE;
358fa225cbcSrjs
359fa225cbcSrjs    return op;
360fa225cbcSrjs}
361fa225cbcSrjs
362fa225cbcSrjs/** Move operand0 to dest_reg */
363fa225cbcSrjs#define i915_fs_mov(dest_reg, operand0)					\
364fa225cbcSrjsdo {									\
365fa225cbcSrjs    FS_OUT(i915_fs_arith(MOV, dest_reg, operand0,			\
366fa225cbcSrjs			 i915_fs_operand_none(),			\
367fa225cbcSrjs			 i915_fs_operand_none()));			\
368fa225cbcSrjs} while (0)
369fa225cbcSrjs
370fa225cbcSrjs/**
371fa225cbcSrjs * Move the value in operand0 to the dest reg with the masking/saturation
372fa225cbcSrjs * specified.
373fa225cbcSrjs */
374fa225cbcSrjs#define i915_fs_mov_masked(dest_reg, dest_mask, operand0)		\
375fa225cbcSrjsdo {									\
376fa225cbcSrjs    struct i915_fs_op op;						\
377fa225cbcSrjs									\
378fa225cbcSrjs    op = i915_fs_arith(MOV, dest_reg, operand0, i915_fs_operand_none(),	\
379fa225cbcSrjs		       i915_fs_operand_none());				\
380fa225cbcSrjs    op.ui[0] &= ~A0_DEST_CHANNEL_ALL;					\
381fa225cbcSrjs    op.ui[0] |= ((dest_mask) & ~MASK_SATURATE) << A0_DEST_CHANNEL_SHIFT; \
382fa225cbcSrjs    if ((dest_mask) & MASK_SATURATE)					\
383fa225cbcSrjs	op.ui[0] |= A0_DEST_SATURATE;					\
384fa225cbcSrjs									\
385fa225cbcSrjs    FS_OUT(op);								\
386fa225cbcSrjs} while (0)
387fa225cbcSrjs
388fa225cbcSrjs/** Add operand0 and operand1 and put the result in dest_reg */
389fa225cbcSrjs#define i915_fs_add(dest_reg, operand0, operand1)			\
390fa225cbcSrjsdo {									\
391fa225cbcSrjs    FS_OUT(i915_fs_arith(ADD, dest_reg, operand0, operand1,		\
392fa225cbcSrjs			 i915_fs_operand_none()));			\
393fa225cbcSrjs} while (0)
394fa225cbcSrjs
395fa225cbcSrjs/** Add operand0 and operand1 and put the result in dest_reg */
396fa225cbcSrjs#define i915_fs_mul(dest_reg, operand0, operand1)			\
397fa225cbcSrjsdo {									\
398fa225cbcSrjs    FS_OUT(i915_fs_arith(MUL, dest_reg, operand0, operand1,		\
399fa225cbcSrjs			 i915_fs_operand_none()));			\
400fa225cbcSrjs} while (0)
401fa225cbcSrjs
402fa225cbcSrjs/**
403fa225cbcSrjs * Perform a 3-component dot-product of operand0 and operand1 and put the
404fa225cbcSrjs * resulting scalar in the channels of dest_reg specified by the dest_mask.
405fa225cbcSrjs */
406fa225cbcSrjs#define i915_fs_dp3_masked(dest_reg, dest_mask, operand0, operand1)	\
407fa225cbcSrjsdo {									\
408fa225cbcSrjs    struct i915_fs_op op;						\
409fa225cbcSrjs									\
410fa225cbcSrjs    op = i915_fs_arith(DP3, dest_reg, operand0, operand1,		\
411fa225cbcSrjs		       i915_fs_operand_none());				\
412fa225cbcSrjs    op.ui[0] &= ~A0_DEST_CHANNEL_ALL;					\
413fa225cbcSrjs    op.ui[0] |= ((dest_mask) & ~MASK_SATURATE) << A0_DEST_CHANNEL_SHIFT; \
414fa225cbcSrjs    if ((dest_mask) & MASK_SATURATE)					\
415fa225cbcSrjs	op.ui[0] |= A0_DEST_SATURATE;					\
416fa225cbcSrjs									\
417fa225cbcSrjs    FS_OUT(op);								\
418fa225cbcSrjs} while (0)
419fa225cbcSrjs
420fa225cbcSrjs/**
421fa225cbcSrjs * Sets up local state for accumulating a fragment shader buffer.
422fa225cbcSrjs *
423fa225cbcSrjs * \param x maximum number of shader commands that may be used between
424fa225cbcSrjs *        a FS_START and FS_END
425fa225cbcSrjs */
426fa225cbcSrjs#define FS_LOCALS(x)							\
427fa225cbcSrjs    uint32_t _shader_buf[(x) * 3];					\
428fa225cbcSrjs    int _max_shader_commands = x;					\
429fa225cbcSrjs    int _cur_shader_commands
430fa225cbcSrjs
431fa225cbcSrjs#define FS_BEGIN()							\
432fa225cbcSrjsdo {									\
433fa225cbcSrjs    _cur_shader_commands = 0;						\
434fa225cbcSrjs} while (0)
435fa225cbcSrjs
436fa225cbcSrjs#define FS_OUT(_shaderop)						\
437fa225cbcSrjsdo {									\
438fa225cbcSrjs    _shader_buf[_cur_shader_commands * 3 + 0] = _shaderop.ui[0];	\
439fa225cbcSrjs    _shader_buf[_cur_shader_commands * 3 + 1] = _shaderop.ui[1];	\
440fa225cbcSrjs    _shader_buf[_cur_shader_commands * 3 + 2] = _shaderop.ui[2];	\
441fa225cbcSrjs    if (++_cur_shader_commands > _max_shader_commands)			\
442fa225cbcSrjs	 FatalError("fragment shader command buffer exceeded (%d)\n",	\
443fa225cbcSrjs		    _cur_shader_commands);				\
444fa225cbcSrjs} while (0)
445fa225cbcSrjs
446fa225cbcSrjs#define FS_END()							\
447fa225cbcSrjsdo {									\
448fa225cbcSrjs    int _i, _pad = (_cur_shader_commands & 0x1) ? 0 : 1;		\
449fa225cbcSrjs    BEGIN_BATCH(_cur_shader_commands * 3 + 1 + _pad);			\
450fa225cbcSrjs    OUT_BATCH(_3DSTATE_PIXEL_SHADER_PROGRAM |				\
451fa225cbcSrjs	     (_cur_shader_commands * 3 - 1));				\
452fa225cbcSrjs    for (_i = 0; _i < _cur_shader_commands * 3; _i++)			\
453fa225cbcSrjs	OUT_BATCH(_shader_buf[_i]);					\
454fa225cbcSrjs    if (_pad != 0)							\
455fa225cbcSrjs	OUT_BATCH(MI_NOOP);						\
456fa225cbcSrjs    ADVANCE_BATCH();							\
457fa225cbcSrjs} while (0);
458