~ubuntu-branches/ubuntu/quantal/mesa/quantal

« back to all changes in this revision

Viewing changes to src/mesa/drivers/dri/i915tex/i915_fragprog.c

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2007-02-21 12:44:07 UTC
  • mfrom: (1.2.1 upstream)
  • mto: This revision was merged to the branch mainline in revision 22.
  • Revision ID: james.westby@ubuntu.com-20070221124407-rgcacs32mycrtadl
ImportĀ upstreamĀ versionĀ 6.5.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/**************************************************************************
 
2
 * 
 
3
 * Copyright 2003 Tungsten Graphics, Inc., Cedar Park, Texas.
 
4
 * All Rights Reserved.
 
5
 * 
 
6
 * Permission is hereby granted, free of charge, to any person obtaining a
 
7
 * copy of this software and associated documentation files (the
 
8
 * "Software"), to deal in the Software without restriction, including
 
9
 * without limitation the rights to use, copy, modify, merge, publish,
 
10
 * distribute, sub license, and/or sell copies of the Software, and to
 
11
 * permit persons to whom the Software is furnished to do so, subject to
 
12
 * the following conditions:
 
13
 * 
 
14
 * The above copyright notice and this permission notice (including the
 
15
 * next paragraph) shall be included in all copies or substantial portions
 
16
 * of the Software.
 
17
 * 
 
18
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 
19
 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 
20
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
 
21
 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
 
22
 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 
23
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
 
24
 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
25
 * 
 
26
 **************************************************************************/
 
27
 
 
28
#include "glheader.h"
 
29
#include "macros.h"
 
30
#include "enums.h"
 
31
 
 
32
#include "tnl/tnl.h"
 
33
#include "tnl/t_context.h"
 
34
#include "intel_batchbuffer.h"
 
35
 
 
36
#include "i915_reg.h"
 
37
#include "i915_context.h"
 
38
#include "i915_program.h"
 
39
 
 
40
#include "program_instruction.h"
 
41
#include "program.h"
 
42
#include "programopt.h"
 
43
 
 
44
 
 
45
 
 
46
/* 1, -1/3!, 1/5!, -1/7! */
 
47
static const GLfloat sin_constants[4] = { 1.0,
 
48
   -1.0 / (3 * 2 * 1),
 
49
   1.0 / (5 * 4 * 3 * 2 * 1),
 
50
   -1.0 / (7 * 6 * 5 * 4 * 3 * 2 * 1)
 
51
};
 
52
 
 
53
/* 1, -1/2!, 1/4!, -1/6! */
 
54
static const GLfloat cos_constants[4] = { 1.0,
 
55
   -1.0 / (2 * 1),
 
56
   1.0 / (4 * 3 * 2 * 1),
 
57
   -1.0 / (6 * 5 * 4 * 3 * 2 * 1)
 
58
};
 
59
 
 
60
/**
 
61
 * Retrieve a ureg for the given source register.  Will emit
 
62
 * constants, apply swizzling and negation as needed.
 
63
 */
 
64
static GLuint
 
65
src_vector(struct i915_fragment_program *p,
 
66
           const struct prog_src_register *source,
 
67
           const struct gl_fragment_program *program)
 
68
{
 
69
   GLuint src;
 
70
 
 
71
   switch (source->File) {
 
72
 
 
73
      /* Registers:
 
74
       */
 
75
   case PROGRAM_TEMPORARY:
 
76
      if (source->Index >= I915_MAX_TEMPORARY) {
 
77
         i915_program_error(p, "Exceeded max temporary reg");
 
78
         return 0;
 
79
      }
 
80
      src = UREG(REG_TYPE_R, source->Index);
 
81
      break;
 
82
   case PROGRAM_INPUT:
 
83
      switch (source->Index) {
 
84
      case FRAG_ATTRIB_WPOS:
 
85
         src = i915_emit_decl(p, REG_TYPE_T, p->wpos_tex, D0_CHANNEL_ALL);
 
86
         break;
 
87
      case FRAG_ATTRIB_COL0:
 
88
         src = i915_emit_decl(p, REG_TYPE_T, T_DIFFUSE, D0_CHANNEL_ALL);
 
89
         break;
 
90
      case FRAG_ATTRIB_COL1:
 
91
         src = i915_emit_decl(p, REG_TYPE_T, T_SPECULAR, D0_CHANNEL_XYZ);
 
92
         src = swizzle(src, X, Y, Z, ONE);
 
93
         break;
 
94
      case FRAG_ATTRIB_FOGC:
 
95
         src = i915_emit_decl(p, REG_TYPE_T, T_FOG_W, D0_CHANNEL_W);
 
96
         src = swizzle(src, W, W, W, W);
 
97
         break;
 
98
      case FRAG_ATTRIB_TEX0:
 
99
      case FRAG_ATTRIB_TEX1:
 
100
      case FRAG_ATTRIB_TEX2:
 
101
      case FRAG_ATTRIB_TEX3:
 
102
      case FRAG_ATTRIB_TEX4:
 
103
      case FRAG_ATTRIB_TEX5:
 
104
      case FRAG_ATTRIB_TEX6:
 
105
      case FRAG_ATTRIB_TEX7:
 
106
         src = i915_emit_decl(p, REG_TYPE_T,
 
107
                              T_TEX0 + (source->Index - FRAG_ATTRIB_TEX0),
 
108
                              D0_CHANNEL_ALL);
 
109
         break;
 
110
 
 
111
      default:
 
112
         i915_program_error(p, "Bad source->Index");
 
113
         return 0;
 
114
      }
 
115
      break;
 
116
 
 
117
      /* Various paramters and env values.  All emitted to
 
118
       * hardware as program constants.
 
119
       */
 
120
   case PROGRAM_LOCAL_PARAM:
 
121
      src = i915_emit_param4fv(p, program->Base.LocalParams[source->Index]);
 
122
      break;
 
123
 
 
124
   case PROGRAM_ENV_PARAM:
 
125
      src =
 
126
         i915_emit_param4fv(p,
 
127
                            p->ctx->FragmentProgram.Parameters[source->
 
128
                                                               Index]);
 
129
      break;
 
130
 
 
131
   case PROGRAM_CONSTANT:
 
132
   case PROGRAM_STATE_VAR:
 
133
   case PROGRAM_NAMED_PARAM:
 
134
      src =
 
135
         i915_emit_param4fv(p,
 
136
                            program->Base.Parameters->ParameterValues[source->
 
137
                                                                      Index]);
 
138
      break;
 
139
 
 
140
   default:
 
141
      i915_program_error(p, "Bad source->File");
 
142
      return 0;
 
143
   }
 
144
 
 
145
   src = swizzle(src,
 
146
                 GET_SWZ(source->Swizzle, 0),
 
147
                 GET_SWZ(source->Swizzle, 1),
 
148
                 GET_SWZ(source->Swizzle, 2), GET_SWZ(source->Swizzle, 3));
 
149
 
 
150
   if (source->NegateBase)
 
151
      src = negate(src,
 
152
                   GET_BIT(source->NegateBase, 0),
 
153
                   GET_BIT(source->NegateBase, 1),
 
154
                   GET_BIT(source->NegateBase, 2),
 
155
                   GET_BIT(source->NegateBase, 3));
 
156
 
 
157
   return src;
 
158
}
 
159
 
 
160
 
 
161
static GLuint
 
162
get_result_vector(struct i915_fragment_program *p,
 
163
                  const struct prog_instruction *inst)
 
164
{
 
165
   switch (inst->DstReg.File) {
 
166
   case PROGRAM_OUTPUT:
 
167
      switch (inst->DstReg.Index) {
 
168
      case FRAG_RESULT_COLR:
 
169
         return UREG(REG_TYPE_OC, 0);
 
170
      case FRAG_RESULT_DEPR:
 
171
         p->depth_written = 1;
 
172
         return UREG(REG_TYPE_OD, 0);
 
173
      default:
 
174
         i915_program_error(p, "Bad inst->DstReg.Index");
 
175
         return 0;
 
176
      }
 
177
   case PROGRAM_TEMPORARY:
 
178
      return UREG(REG_TYPE_R, inst->DstReg.Index);
 
179
   default:
 
180
      i915_program_error(p, "Bad inst->DstReg.File");
 
181
      return 0;
 
182
   }
 
183
}
 
184
 
 
185
static GLuint
 
186
get_result_flags(const struct prog_instruction *inst)
 
187
{
 
188
   GLuint flags = 0;
 
189
 
 
190
   if (inst->SaturateMode == SATURATE_ZERO_ONE)
 
191
      flags |= A0_DEST_SATURATE;
 
192
   if (inst->DstReg.WriteMask & WRITEMASK_X)
 
193
      flags |= A0_DEST_CHANNEL_X;
 
194
   if (inst->DstReg.WriteMask & WRITEMASK_Y)
 
195
      flags |= A0_DEST_CHANNEL_Y;
 
196
   if (inst->DstReg.WriteMask & WRITEMASK_Z)
 
197
      flags |= A0_DEST_CHANNEL_Z;
 
198
   if (inst->DstReg.WriteMask & WRITEMASK_W)
 
199
      flags |= A0_DEST_CHANNEL_W;
 
200
 
 
201
   return flags;
 
202
}
 
203
 
 
204
static GLuint
 
205
translate_tex_src_target(struct i915_fragment_program *p, GLubyte bit)
 
206
{
 
207
   switch (bit) {
 
208
   case TEXTURE_1D_INDEX:
 
209
      return D0_SAMPLE_TYPE_2D;
 
210
   case TEXTURE_2D_INDEX:
 
211
      return D0_SAMPLE_TYPE_2D;
 
212
   case TEXTURE_RECT_INDEX:
 
213
      return D0_SAMPLE_TYPE_2D;
 
214
   case TEXTURE_3D_INDEX:
 
215
      return D0_SAMPLE_TYPE_VOLUME;
 
216
   case TEXTURE_CUBE_INDEX:
 
217
      return D0_SAMPLE_TYPE_CUBE;
 
218
   default:
 
219
      i915_program_error(p, "TexSrcBit");
 
220
      return 0;
 
221
   }
 
222
}
 
223
 
 
224
#define EMIT_TEX( OP )                                          \
 
225
do {                                                            \
 
226
   GLuint dim = translate_tex_src_target( p, inst->TexSrcTarget );      \
 
227
   GLuint sampler = i915_emit_decl(p, REG_TYPE_S,               \
 
228
                                  inst->TexSrcUnit, dim);       \
 
229
   GLuint coord = src_vector( p, &inst->SrcReg[0], program);    \
 
230
   /* Texel lookup */                                           \
 
231
                                                                \
 
232
   i915_emit_texld( p,                                          \
 
233
               get_result_vector( p, inst ),                    \
 
234
               get_result_flags( inst ),                        \
 
235
               sampler,                                         \
 
236
               coord,                                           \
 
237
               OP);                                             \
 
238
} while (0)
 
239
 
 
240
#define EMIT_ARITH( OP, N )                                             \
 
241
do {                                                                    \
 
242
   i915_emit_arith( p,                                                  \
 
243
               OP,                                                      \
 
244
               get_result_vector( p, inst ),                            \
 
245
               get_result_flags( inst ), 0,                     \
 
246
               (N<1)?0:src_vector( p, &inst->SrcReg[0], program),       \
 
247
               (N<2)?0:src_vector( p, &inst->SrcReg[1], program),       \
 
248
               (N<3)?0:src_vector( p, &inst->SrcReg[2], program));      \
 
249
} while (0)
 
250
 
 
251
#define EMIT_1ARG_ARITH( OP ) EMIT_ARITH( OP, 1 )
 
252
#define EMIT_2ARG_ARITH( OP ) EMIT_ARITH( OP, 2 )
 
253
#define EMIT_3ARG_ARITH( OP ) EMIT_ARITH( OP, 3 )
 
254
 
 
255
 
 
256
/* Possible concerns:
 
257
 *
 
258
 * SIN, COS -- could use another taylor step?
 
259
 * LIT      -- results seem a little different to sw mesa
 
260
 * LOG      -- different to mesa on negative numbers, but this is conformant.
 
261
 * 
 
262
 * Parse failures -- Mesa doesn't currently give a good indication
 
263
 * internally whether a particular program string parsed or not.  This
 
264
 * can lead to confusion -- hopefully we cope with it ok now.
 
265
 *
 
266
 */
 
267
static void
 
268
upload_program(struct i915_fragment_program *p)
 
269
{
 
270
   const struct gl_fragment_program *program =
 
271
      p->ctx->FragmentProgram._Current;
 
272
   const struct prog_instruction *inst = program->Base.Instructions;
 
273
 
 
274
/*    _mesa_debug_fp_inst(program->Base.NumInstructions, inst); */
 
275
 
 
276
   /* Is this a parse-failed program?  Ensure a valid program is
 
277
    * loaded, as the flagging of an error isn't sufficient to stop
 
278
    * this being uploaded to hardware.
 
279
    */
 
280
   if (inst[0].Opcode == OPCODE_END) {
 
281
      GLuint tmp = i915_get_utemp(p);
 
282
      i915_emit_arith(p,
 
283
                      A0_MOV,
 
284
                      UREG(REG_TYPE_OC, 0),
 
285
                      A0_DEST_CHANNEL_ALL, 0,
 
286
                      swizzle(tmp, ONE, ZERO, ONE, ONE), 0, 0);
 
287
      return;
 
288
   }
 
289
 
 
290
   while (1) {
 
291
      GLuint src0, src1, src2, flags;
 
292
      GLuint tmp = 0;
 
293
 
 
294
      switch (inst->Opcode) {
 
295
      case OPCODE_ABS:
 
296
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
297
         i915_emit_arith(p,
 
298
                         A0_MAX,
 
299
                         get_result_vector(p, inst),
 
300
                         get_result_flags(inst), 0,
 
301
                         src0, negate(src0, 1, 1, 1, 1), 0);
 
302
         break;
 
303
 
 
304
      case OPCODE_ADD:
 
305
         EMIT_2ARG_ARITH(A0_ADD);
 
306
         break;
 
307
 
 
308
      case OPCODE_CMP:
 
309
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
310
         src1 = src_vector(p, &inst->SrcReg[1], program);
 
311
         src2 = src_vector(p, &inst->SrcReg[2], program);
 
312
         i915_emit_arith(p, A0_CMP, get_result_vector(p, inst), get_result_flags(inst), 0, src0, src2, src1);   /* NOTE: order of src2, src1 */
 
313
         break;
 
314
 
 
315
      case OPCODE_COS:
 
316
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
317
         tmp = i915_get_utemp(p);
 
318
 
 
319
         i915_emit_arith(p,
 
320
                         A0_MUL,
 
321
                         tmp, A0_DEST_CHANNEL_X, 0,
 
322
                         src0, i915_emit_const1f(p, 1.0 / (M_PI * 2)), 0);
 
323
 
 
324
         i915_emit_arith(p, A0_MOD, tmp, A0_DEST_CHANNEL_X, 0, tmp, 0, 0);
 
325
 
 
326
         /* By choosing different taylor constants, could get rid of this mul:
 
327
          */
 
328
         i915_emit_arith(p,
 
329
                         A0_MUL,
 
330
                         tmp, A0_DEST_CHANNEL_X, 0,
 
331
                         tmp, i915_emit_const1f(p, (M_PI * 2)), 0);
 
332
 
 
333
         /* 
 
334
          * t0.xy = MUL x.xx11, x.x1111  ; x^2, x, 1, 1
 
335
          * t0 = MUL t0.xyxy t0.xx11 ; x^4, x^3, x^2, 1
 
336
          * t0 = MUL t0.xxz1 t0.z111    ; x^6 x^4 x^2 1
 
337
          * result = DP4 t0, cos_constants
 
338
          */
 
339
         i915_emit_arith(p,
 
340
                         A0_MUL,
 
341
                         tmp, A0_DEST_CHANNEL_XY, 0,
 
342
                         swizzle(tmp, X, X, ONE, ONE),
 
343
                         swizzle(tmp, X, ONE, ONE, ONE), 0);
 
344
 
 
345
         i915_emit_arith(p,
 
346
                         A0_MUL,
 
347
                         tmp, A0_DEST_CHANNEL_XYZ, 0,
 
348
                         swizzle(tmp, X, Y, X, ONE),
 
349
                         swizzle(tmp, X, X, ONE, ONE), 0);
 
350
 
 
351
         i915_emit_arith(p,
 
352
                         A0_MUL,
 
353
                         tmp, A0_DEST_CHANNEL_XYZ, 0,
 
354
                         swizzle(tmp, X, X, Z, ONE),
 
355
                         swizzle(tmp, Z, ONE, ONE, ONE), 0);
 
356
 
 
357
         i915_emit_arith(p,
 
358
                         A0_DP4,
 
359
                         get_result_vector(p, inst),
 
360
                         get_result_flags(inst), 0,
 
361
                         swizzle(tmp, ONE, Z, Y, X),
 
362
                         i915_emit_const4fv(p, cos_constants), 0);
 
363
 
 
364
         break;
 
365
 
 
366
      case OPCODE_DP3:
 
367
         EMIT_2ARG_ARITH(A0_DP3);
 
368
         break;
 
369
 
 
370
      case OPCODE_DP4:
 
371
         EMIT_2ARG_ARITH(A0_DP4);
 
372
         break;
 
373
 
 
374
      case OPCODE_DPH:
 
375
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
376
         src1 = src_vector(p, &inst->SrcReg[1], program);
 
377
 
 
378
         i915_emit_arith(p,
 
379
                         A0_DP4,
 
380
                         get_result_vector(p, inst),
 
381
                         get_result_flags(inst), 0,
 
382
                         swizzle(src0, X, Y, Z, ONE), src1, 0);
 
383
         break;
 
384
 
 
385
      case OPCODE_DST:
 
386
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
387
         src1 = src_vector(p, &inst->SrcReg[1], program);
 
388
 
 
389
         /* result[0] = 1    * 1;
 
390
          * result[1] = a[1] * b[1];
 
391
          * result[2] = a[2] * 1;
 
392
          * result[3] = 1    * b[3];
 
393
          */
 
394
         i915_emit_arith(p,
 
395
                         A0_MUL,
 
396
                         get_result_vector(p, inst),
 
397
                         get_result_flags(inst), 0,
 
398
                         swizzle(src0, ONE, Y, Z, ONE),
 
399
                         swizzle(src1, ONE, Y, ONE, W), 0);
 
400
         break;
 
401
 
 
402
      case OPCODE_EX2:
 
403
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
404
 
 
405
         i915_emit_arith(p,
 
406
                         A0_EXP,
 
407
                         get_result_vector(p, inst),
 
408
                         get_result_flags(inst), 0,
 
409
                         swizzle(src0, X, X, X, X), 0, 0);
 
410
         break;
 
411
 
 
412
      case OPCODE_FLR:
 
413
         EMIT_1ARG_ARITH(A0_FLR);
 
414
         break;
 
415
 
 
416
      case OPCODE_FRC:
 
417
         EMIT_1ARG_ARITH(A0_FRC);
 
418
         break;
 
419
 
 
420
      case OPCODE_KIL:
 
421
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
422
         tmp = i915_get_utemp(p);
 
423
 
 
424
         i915_emit_texld(p, tmp, A0_DEST_CHANNEL_ALL,   /* use a dummy dest reg */
 
425
                         0, src0, T0_TEXKILL);
 
426
         break;
 
427
 
 
428
      case OPCODE_LG2:
 
429
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
430
 
 
431
         i915_emit_arith(p,
 
432
                         A0_LOG,
 
433
                         get_result_vector(p, inst),
 
434
                         get_result_flags(inst), 0,
 
435
                         swizzle(src0, X, X, X, X), 0, 0);
 
436
         break;
 
437
 
 
438
      case OPCODE_LIT:
 
439
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
440
         tmp = i915_get_utemp(p);
 
441
 
 
442
         /* tmp = max( a.xyzw, a.00zw )
 
443
          * XXX: Clamp tmp.w to -128..128
 
444
          * tmp.y = log(tmp.y)
 
445
          * tmp.y = tmp.w * tmp.y
 
446
          * tmp.y = exp(tmp.y)
 
447
          * result = cmp (a.11-x1, a.1x01, a.1xy1 )
 
448
          */
 
449
         i915_emit_arith(p, A0_MAX, tmp, A0_DEST_CHANNEL_ALL, 0,
 
450
                         src0, swizzle(src0, ZERO, ZERO, Z, W), 0);
 
451
 
 
452
         i915_emit_arith(p, A0_LOG, tmp, A0_DEST_CHANNEL_Y, 0,
 
453
                         swizzle(tmp, Y, Y, Y, Y), 0, 0);
 
454
 
 
455
         i915_emit_arith(p, A0_MUL, tmp, A0_DEST_CHANNEL_Y, 0,
 
456
                         swizzle(tmp, ZERO, Y, ZERO, ZERO),
 
457
                         swizzle(tmp, ZERO, W, ZERO, ZERO), 0);
 
458
 
 
459
         i915_emit_arith(p, A0_EXP, tmp, A0_DEST_CHANNEL_Y, 0,
 
460
                         swizzle(tmp, Y, Y, Y, Y), 0, 0);
 
461
 
 
462
         i915_emit_arith(p, A0_CMP,
 
463
                         get_result_vector(p, inst),
 
464
                         get_result_flags(inst), 0,
 
465
                         negate(swizzle(tmp, ONE, ONE, X, ONE), 0, 0, 1, 0),
 
466
                         swizzle(tmp, ONE, X, ZERO, ONE),
 
467
                         swizzle(tmp, ONE, X, Y, ONE));
 
468
 
 
469
         break;
 
470
 
 
471
      case OPCODE_LRP:
 
472
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
473
         src1 = src_vector(p, &inst->SrcReg[1], program);
 
474
         src2 = src_vector(p, &inst->SrcReg[2], program);
 
475
         flags = get_result_flags(inst);
 
476
         tmp = i915_get_utemp(p);
 
477
 
 
478
         /* b*a + c*(1-a)
 
479
          *
 
480
          * b*a + c - ca 
 
481
          *
 
482
          * tmp = b*a + c, 
 
483
          * result = (-c)*a + tmp 
 
484
          */
 
485
         i915_emit_arith(p, A0_MAD, tmp,
 
486
                         flags & A0_DEST_CHANNEL_ALL, 0, src1, src0, src2);
 
487
 
 
488
         i915_emit_arith(p, A0_MAD,
 
489
                         get_result_vector(p, inst),
 
490
                         flags, 0, negate(src2, 1, 1, 1, 1), src0, tmp);
 
491
         break;
 
492
 
 
493
      case OPCODE_MAD:
 
494
         EMIT_3ARG_ARITH(A0_MAD);
 
495
         break;
 
496
 
 
497
      case OPCODE_MAX:
 
498
         EMIT_2ARG_ARITH(A0_MAX);
 
499
         break;
 
500
 
 
501
      case OPCODE_MIN:
 
502
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
503
         src1 = src_vector(p, &inst->SrcReg[1], program);
 
504
         tmp = i915_get_utemp(p);
 
505
         flags = get_result_flags(inst);
 
506
 
 
507
         i915_emit_arith(p,
 
508
                         A0_MAX,
 
509
                         tmp, flags & A0_DEST_CHANNEL_ALL, 0,
 
510
                         negate(src0, 1, 1, 1, 1),
 
511
                         negate(src1, 1, 1, 1, 1), 0);
 
512
 
 
513
         i915_emit_arith(p,
 
514
                         A0_MOV,
 
515
                         get_result_vector(p, inst),
 
516
                         flags, 0, negate(tmp, 1, 1, 1, 1), 0, 0);
 
517
         break;
 
518
 
 
519
      case OPCODE_MOV:
 
520
         EMIT_1ARG_ARITH(A0_MOV);
 
521
         break;
 
522
 
 
523
      case OPCODE_MUL:
 
524
         EMIT_2ARG_ARITH(A0_MUL);
 
525
         break;
 
526
 
 
527
      case OPCODE_POW:
 
528
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
529
         src1 = src_vector(p, &inst->SrcReg[1], program);
 
530
         tmp = i915_get_utemp(p);
 
531
         flags = get_result_flags(inst);
 
532
 
 
533
         /* XXX: masking on intermediate values, here and elsewhere.
 
534
          */
 
535
         i915_emit_arith(p,
 
536
                         A0_LOG,
 
537
                         tmp, A0_DEST_CHANNEL_X, 0,
 
538
                         swizzle(src0, X, X, X, X), 0, 0);
 
539
 
 
540
         i915_emit_arith(p, A0_MUL, tmp, A0_DEST_CHANNEL_X, 0, tmp, src1, 0);
 
541
 
 
542
 
 
543
         i915_emit_arith(p,
 
544
                         A0_EXP,
 
545
                         get_result_vector(p, inst),
 
546
                         flags, 0, swizzle(tmp, X, X, X, X), 0, 0);
 
547
 
 
548
         break;
 
549
 
 
550
      case OPCODE_RCP:
 
551
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
552
 
 
553
         i915_emit_arith(p,
 
554
                         A0_RCP,
 
555
                         get_result_vector(p, inst),
 
556
                         get_result_flags(inst), 0,
 
557
                         swizzle(src0, X, X, X, X), 0, 0);
 
558
         break;
 
559
 
 
560
      case OPCODE_RSQ:
 
561
 
 
562
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
563
 
 
564
         i915_emit_arith(p,
 
565
                         A0_RSQ,
 
566
                         get_result_vector(p, inst),
 
567
                         get_result_flags(inst), 0,
 
568
                         swizzle(src0, X, X, X, X), 0, 0);
 
569
         break;
 
570
 
 
571
      case OPCODE_SCS:
 
572
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
573
         tmp = i915_get_utemp(p);
 
574
 
 
575
         /* 
 
576
          * t0.xy = MUL x.xx11, x.x1111  ; x^2, x, 1, 1
 
577
          * t0 = MUL t0.xyxy t0.xx11 ; x^4, x^3, x^2, x
 
578
          * t1 = MUL t0.xyyw t0.yz11    ; x^7 x^5 x^3 x
 
579
          * scs.x = DP4 t1, sin_constants
 
580
          * t1 = MUL t0.xxz1 t0.z111    ; x^6 x^4 x^2 1
 
581
          * scs.y = DP4 t1, cos_constants
 
582
          */
 
583
         i915_emit_arith(p,
 
584
                         A0_MUL,
 
585
                         tmp, A0_DEST_CHANNEL_XY, 0,
 
586
                         swizzle(src0, X, X, ONE, ONE),
 
587
                         swizzle(src0, X, ONE, ONE, ONE), 0);
 
588
 
 
589
         i915_emit_arith(p,
 
590
                         A0_MUL,
 
591
                         tmp, A0_DEST_CHANNEL_ALL, 0,
 
592
                         swizzle(tmp, X, Y, X, Y),
 
593
                         swizzle(tmp, X, X, ONE, ONE), 0);
 
594
 
 
595
         if (inst->DstReg.WriteMask & WRITEMASK_Y) {
 
596
            GLuint tmp1;
 
597
 
 
598
            if (inst->DstReg.WriteMask & WRITEMASK_X)
 
599
               tmp1 = i915_get_utemp(p);
 
600
            else
 
601
               tmp1 = tmp;
 
602
 
 
603
            i915_emit_arith(p,
 
604
                            A0_MUL,
 
605
                            tmp1, A0_DEST_CHANNEL_ALL, 0,
 
606
                            swizzle(tmp, X, Y, Y, W),
 
607
                            swizzle(tmp, X, Z, ONE, ONE), 0);
 
608
 
 
609
            i915_emit_arith(p,
 
610
                            A0_DP4,
 
611
                            get_result_vector(p, inst),
 
612
                            A0_DEST_CHANNEL_Y, 0,
 
613
                            swizzle(tmp1, W, Z, Y, X),
 
614
                            i915_emit_const4fv(p, sin_constants), 0);
 
615
         }
 
616
 
 
617
         if (inst->DstReg.WriteMask & WRITEMASK_X) {
 
618
            i915_emit_arith(p,
 
619
                            A0_MUL,
 
620
                            tmp, A0_DEST_CHANNEL_XYZ, 0,
 
621
                            swizzle(tmp, X, X, Z, ONE),
 
622
                            swizzle(tmp, Z, ONE, ONE, ONE), 0);
 
623
 
 
624
            i915_emit_arith(p,
 
625
                            A0_DP4,
 
626
                            get_result_vector(p, inst),
 
627
                            A0_DEST_CHANNEL_X, 0,
 
628
                            swizzle(tmp, ONE, Z, Y, X),
 
629
                            i915_emit_const4fv(p, cos_constants), 0);
 
630
         }
 
631
         break;
 
632
 
 
633
      case OPCODE_SGE:
 
634
         EMIT_2ARG_ARITH(A0_SGE);
 
635
         break;
 
636
 
 
637
      case OPCODE_SIN:
 
638
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
639
         tmp = i915_get_utemp(p);
 
640
 
 
641
         i915_emit_arith(p,
 
642
                         A0_MUL,
 
643
                         tmp, A0_DEST_CHANNEL_X, 0,
 
644
                         src0, i915_emit_const1f(p, 1.0 / (M_PI * 2)), 0);
 
645
 
 
646
         i915_emit_arith(p, A0_MOD, tmp, A0_DEST_CHANNEL_X, 0, tmp, 0, 0);
 
647
 
 
648
         /* By choosing different taylor constants, could get rid of this mul:
 
649
          */
 
650
         i915_emit_arith(p,
 
651
                         A0_MUL,
 
652
                         tmp, A0_DEST_CHANNEL_X, 0,
 
653
                         tmp, i915_emit_const1f(p, (M_PI * 2)), 0);
 
654
 
 
655
         /* 
 
656
          * t0.xy = MUL x.xx11, x.x1111  ; x^2, x, 1, 1
 
657
          * t0 = MUL t0.xyxy t0.xx11 ; x^4, x^3, x^2, x
 
658
          * t1 = MUL t0.xyyw t0.yz11    ; x^7 x^5 x^3 x
 
659
          * result = DP4 t1.wzyx, sin_constants
 
660
          */
 
661
         i915_emit_arith(p,
 
662
                         A0_MUL,
 
663
                         tmp, A0_DEST_CHANNEL_XY, 0,
 
664
                         swizzle(tmp, X, X, ONE, ONE),
 
665
                         swizzle(tmp, X, ONE, ONE, ONE), 0);
 
666
 
 
667
         i915_emit_arith(p,
 
668
                         A0_MUL,
 
669
                         tmp, A0_DEST_CHANNEL_ALL, 0,
 
670
                         swizzle(tmp, X, Y, X, Y),
 
671
                         swizzle(tmp, X, X, ONE, ONE), 0);
 
672
 
 
673
         i915_emit_arith(p,
 
674
                         A0_MUL,
 
675
                         tmp, A0_DEST_CHANNEL_ALL, 0,
 
676
                         swizzle(tmp, X, Y, Y, W),
 
677
                         swizzle(tmp, X, Z, ONE, ONE), 0);
 
678
 
 
679
         i915_emit_arith(p,
 
680
                         A0_DP4,
 
681
                         get_result_vector(p, inst),
 
682
                         get_result_flags(inst), 0,
 
683
                         swizzle(tmp, W, Z, Y, X),
 
684
                         i915_emit_const4fv(p, sin_constants), 0);
 
685
         break;
 
686
 
 
687
      case OPCODE_SLT:
 
688
         EMIT_2ARG_ARITH(A0_SLT);
 
689
         break;
 
690
 
 
691
      case OPCODE_SUB:
 
692
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
693
         src1 = src_vector(p, &inst->SrcReg[1], program);
 
694
 
 
695
         i915_emit_arith(p,
 
696
                         A0_ADD,
 
697
                         get_result_vector(p, inst),
 
698
                         get_result_flags(inst), 0,
 
699
                         src0, negate(src1, 1, 1, 1, 1), 0);
 
700
         break;
 
701
 
 
702
      case OPCODE_SWZ:
 
703
         EMIT_1ARG_ARITH(A0_MOV);       /* extended swizzle handled natively */
 
704
         break;
 
705
 
 
706
      case OPCODE_TEX:
 
707
         EMIT_TEX(T0_TEXLD);
 
708
         break;
 
709
 
 
710
      case OPCODE_TXB:
 
711
         EMIT_TEX(T0_TEXLDB);
 
712
         break;
 
713
 
 
714
      case OPCODE_TXP:
 
715
         EMIT_TEX(T0_TEXLDP);
 
716
         break;
 
717
 
 
718
      case OPCODE_XPD:
 
719
         /* Cross product:
 
720
          *      result.x = src0.y * src1.z - src0.z * src1.y;
 
721
          *      result.y = src0.z * src1.x - src0.x * src1.z;
 
722
          *      result.z = src0.x * src1.y - src0.y * src1.x;
 
723
          *      result.w = undef;
 
724
          */
 
725
         src0 = src_vector(p, &inst->SrcReg[0], program);
 
726
         src1 = src_vector(p, &inst->SrcReg[1], program);
 
727
         tmp = i915_get_utemp(p);
 
728
 
 
729
         i915_emit_arith(p,
 
730
                         A0_MUL,
 
731
                         tmp, A0_DEST_CHANNEL_ALL, 0,
 
732
                         swizzle(src0, Z, X, Y, ONE),
 
733
                         swizzle(src1, Y, Z, X, ONE), 0);
 
734
 
 
735
         i915_emit_arith(p,
 
736
                         A0_MAD,
 
737
                         get_result_vector(p, inst),
 
738
                         get_result_flags(inst), 0,
 
739
                         swizzle(src0, Y, Z, X, ONE),
 
740
                         swizzle(src1, Z, X, Y, ONE),
 
741
                         negate(tmp, 1, 1, 1, 0));
 
742
         break;
 
743
 
 
744
      case OPCODE_END:
 
745
         return;
 
746
 
 
747
      default:
 
748
         i915_program_error(p, "bad opcode");
 
749
         return;
 
750
      }
 
751
 
 
752
      inst++;
 
753
      i915_release_utemps(p);
 
754
   }
 
755
}
 
756
 
 
757
/* Rather than trying to intercept and jiggle depth writes during
 
758
 * emit, just move the value into its correct position at the end of
 
759
 * the program:
 
760
 */
 
761
static void
 
762
fixup_depth_write(struct i915_fragment_program *p)
 
763
{
 
764
   if (p->depth_written) {
 
765
      GLuint depth = UREG(REG_TYPE_OD, 0);
 
766
 
 
767
      i915_emit_arith(p,
 
768
                      A0_MOV,
 
769
                      depth, A0_DEST_CHANNEL_W, 0,
 
770
                      swizzle(depth, X, Y, Z, Z), 0, 0);
 
771
   }
 
772
}
 
773
 
 
774
 
 
775
#define FRAG_BIT_TEX(n)  (FRAG_BIT_TEX0 << (n))
 
776
 
 
777
 
 
778
static void
 
779
check_wpos(struct i915_fragment_program *p)
 
780
{
 
781
   GLuint inputs = p->FragProg.Base.InputsRead;
 
782
   GLint i;
 
783
 
 
784
   p->wpos_tex = -1;
 
785
 
 
786
   for (i = 0; i < p->ctx->Const.MaxTextureCoordUnits; i++) {
 
787
      if (inputs & FRAG_BIT_TEX(i))
 
788
         continue;
 
789
      else if (inputs & FRAG_BIT_WPOS) {
 
790
         p->wpos_tex = i;
 
791
         inputs &= ~FRAG_BIT_WPOS;
 
792
      }
 
793
   }
 
794
 
 
795
   if (inputs & FRAG_BIT_WPOS) {
 
796
      i915_program_error(p, "No free texcoord for wpos value");
 
797
   }
 
798
}
 
799
 
 
800
 
 
801
static void
 
802
translate_program(struct i915_fragment_program *p)
 
803
{
 
804
   struct i915_context *i915 = I915_CONTEXT(p->ctx);
 
805
 
 
806
   i915_init_program(i915, p);
 
807
   check_wpos(p);
 
808
   upload_program(p);
 
809
   fixup_depth_write(p);
 
810
   i915_fini_program(p);
 
811
 
 
812
   p->translated = 1;
 
813
}
 
814
 
 
815
 
 
816
static void
 
817
track_params(struct i915_fragment_program *p)
 
818
{
 
819
   GLint i;
 
820
 
 
821
   if (p->nr_params)
 
822
      _mesa_load_state_parameters(p->ctx, p->FragProg.Base.Parameters);
 
823
 
 
824
   for (i = 0; i < p->nr_params; i++) {
 
825
      GLint reg = p->param[i].reg;
 
826
      COPY_4V(p->constant[reg], p->param[i].values);
 
827
   }
 
828
 
 
829
   p->params_uptodate = 1;
 
830
   p->on_hardware = 0;          /* overkill */
 
831
}
 
832
 
 
833
 
 
834
static void
 
835
i915BindProgram(GLcontext * ctx, GLenum target, struct gl_program *prog)
 
836
{
 
837
   if (target == GL_FRAGMENT_PROGRAM_ARB) {
 
838
      struct i915_context *i915 = I915_CONTEXT(ctx);
 
839
      struct i915_fragment_program *p = (struct i915_fragment_program *) prog;
 
840
 
 
841
      if (i915->current_program == p)
 
842
         return;
 
843
 
 
844
      if (i915->current_program) {
 
845
         i915->current_program->on_hardware = 0;
 
846
         i915->current_program->params_uptodate = 0;
 
847
      }
 
848
 
 
849
      i915->current_program = p;
 
850
 
 
851
      assert(p->on_hardware == 0);
 
852
      assert(p->params_uptodate == 0);
 
853
 
 
854
      /* Hack: make sure fog is correctly enabled according to this
 
855
       * fragment program's fog options.
 
856
       */
 
857
      ctx->Driver.Enable(ctx, GL_FRAGMENT_PROGRAM_ARB,
 
858
                         ctx->FragmentProgram.Enabled);
 
859
   }
 
860
}
 
861
 
 
862
static struct gl_program *
 
863
i915NewProgram(GLcontext * ctx, GLenum target, GLuint id)
 
864
{
 
865
   switch (target) {
 
866
   case GL_VERTEX_PROGRAM_ARB:
 
867
      return _mesa_init_vertex_program(ctx, CALLOC_STRUCT(gl_vertex_program),
 
868
                                       target, id);
 
869
 
 
870
   case GL_FRAGMENT_PROGRAM_ARB:{
 
871
         struct i915_fragment_program *prog =
 
872
            CALLOC_STRUCT(i915_fragment_program);
 
873
         if (prog) {
 
874
            i915_init_program(I915_CONTEXT(ctx), prog);
 
875
 
 
876
            return _mesa_init_fragment_program(ctx, &prog->FragProg,
 
877
                                               target, id);
 
878
         }
 
879
         else
 
880
            return NULL;
 
881
      }
 
882
 
 
883
   default:
 
884
      /* Just fallback:
 
885
       */
 
886
      return _mesa_new_program(ctx, target, id);
 
887
   }
 
888
}
 
889
 
 
890
static void
 
891
i915DeleteProgram(GLcontext * ctx, struct gl_program *prog)
 
892
{
 
893
   if (prog->Target == GL_FRAGMENT_PROGRAM_ARB) {
 
894
      struct i915_context *i915 = I915_CONTEXT(ctx);
 
895
      struct i915_fragment_program *p = (struct i915_fragment_program *) prog;
 
896
 
 
897
      if (i915->current_program == p)
 
898
         i915->current_program = 0;
 
899
   }
 
900
 
 
901
   _mesa_delete_program(ctx, prog);
 
902
}
 
903
 
 
904
 
 
905
static GLboolean
 
906
i915IsProgramNative(GLcontext * ctx, GLenum target, struct gl_program *prog)
 
907
{
 
908
   if (target == GL_FRAGMENT_PROGRAM_ARB) {
 
909
      struct i915_fragment_program *p = (struct i915_fragment_program *) prog;
 
910
 
 
911
      if (!p->translated)
 
912
         translate_program(p);
 
913
 
 
914
      return !p->error;
 
915
   }
 
916
   else
 
917
      return GL_TRUE;
 
918
}
 
919
 
 
920
static void
 
921
i915ProgramStringNotify(GLcontext * ctx,
 
922
                        GLenum target, struct gl_program *prog)
 
923
{
 
924
   if (target == GL_FRAGMENT_PROGRAM_ARB) {
 
925
      struct i915_fragment_program *p = (struct i915_fragment_program *) prog;
 
926
      p->translated = 0;
 
927
 
 
928
      /* Hack: make sure fog is correctly enabled according to this
 
929
       * fragment program's fog options.
 
930
       */
 
931
      ctx->Driver.Enable(ctx, GL_FRAGMENT_PROGRAM_ARB,
 
932
                         ctx->FragmentProgram.Enabled);
 
933
 
 
934
      if (p->FragProg.FogOption) {
 
935
         /* add extra instructions to do fog, then turn off FogOption field */
 
936
         _mesa_append_fog_code(ctx, &p->FragProg);
 
937
         p->FragProg.FogOption = GL_NONE;
 
938
      }
 
939
   }
 
940
 
 
941
   _tnl_program_string(ctx, target, prog);
 
942
}
 
943
 
 
944
 
 
945
void
 
946
i915ValidateFragmentProgram(struct i915_context *i915)
 
947
{
 
948
   GLcontext *ctx = &i915->intel.ctx;
 
949
   struct intel_context *intel = intel_context(ctx);
 
950
   TNLcontext *tnl = TNL_CONTEXT(ctx);
 
951
   struct vertex_buffer *VB = &tnl->vb;
 
952
 
 
953
   struct i915_fragment_program *p =
 
954
      (struct i915_fragment_program *) ctx->FragmentProgram._Current;
 
955
 
 
956
   const GLuint inputsRead = p->FragProg.Base.InputsRead;
 
957
   GLuint s4 = i915->state.Ctx[I915_CTXREG_LIS4] & ~S4_VFMT_MASK;
 
958
   GLuint s2 = S2_TEXCOORD_NONE;
 
959
   int i, offset = 0;
 
960
 
 
961
   if (i915->current_program != p) {
 
962
      if (i915->current_program) {
 
963
         i915->current_program->on_hardware = 0;
 
964
         i915->current_program->params_uptodate = 0;
 
965
      }
 
966
 
 
967
      i915->current_program = p;
 
968
   }
 
969
 
 
970
 
 
971
   /* Important:
 
972
    */
 
973
   VB->AttribPtr[VERT_ATTRIB_POS] = VB->NdcPtr;
 
974
 
 
975
   if (!p->translated)
 
976
      translate_program(p);
 
977
 
 
978
   intel->vertex_attr_count = 0;
 
979
   intel->wpos_offset = 0;
 
980
   intel->wpos_size = 0;
 
981
   intel->coloroffset = 0;
 
982
   intel->specoffset = 0;
 
983
 
 
984
   if (inputsRead & FRAG_BITS_TEX_ANY) {
 
985
      EMIT_ATTR(_TNL_ATTRIB_POS, EMIT_4F_VIEWPORT, S4_VFMT_XYZW, 16);
 
986
   }
 
987
   else {
 
988
      EMIT_ATTR(_TNL_ATTRIB_POS, EMIT_3F_VIEWPORT, S4_VFMT_XYZ, 12);
 
989
   }
 
990
 
 
991
   if (inputsRead & FRAG_BIT_COL0) {
 
992
      intel->coloroffset = offset / 4;
 
993
      EMIT_ATTR(_TNL_ATTRIB_COLOR0, EMIT_4UB_4F_BGRA, S4_VFMT_COLOR, 4);
 
994
   }
 
995
 
 
996
   if ((inputsRead & (FRAG_BIT_COL1 | FRAG_BIT_FOGC)) ||
 
997
       i915->vertex_fog != I915_FOG_NONE) {
 
998
 
 
999
      if (inputsRead & FRAG_BIT_COL1) {
 
1000
         intel->specoffset = offset / 4;
 
1001
         EMIT_ATTR(_TNL_ATTRIB_COLOR1, EMIT_3UB_3F_BGR, S4_VFMT_SPEC_FOG, 3);
 
1002
      }
 
1003
      else
 
1004
         EMIT_PAD(3);
 
1005
 
 
1006
      if ((inputsRead & FRAG_BIT_FOGC) || i915->vertex_fog != I915_FOG_NONE)
 
1007
         EMIT_ATTR(_TNL_ATTRIB_FOG, EMIT_1UB_1F, S4_VFMT_SPEC_FOG, 1);
 
1008
      else
 
1009
         EMIT_PAD(1);
 
1010
   }
 
1011
 
 
1012
   /* XXX this was disabled, but enabling this code helped fix the Glean
 
1013
    * tfragprog1 fog tests.
 
1014
    */
 
1015
#if 1
 
1016
   if ((inputsRead & FRAG_BIT_FOGC) || i915->vertex_fog != I915_FOG_NONE) {
 
1017
      EMIT_ATTR(_TNL_ATTRIB_FOG, EMIT_1F, S4_VFMT_FOG_PARAM, 4);
 
1018
   }
 
1019
#endif
 
1020
 
 
1021
   for (i = 0; i < p->ctx->Const.MaxTextureCoordUnits; i++) {
 
1022
      if (inputsRead & FRAG_BIT_TEX(i)) {
 
1023
         int sz = VB->TexCoordPtr[i]->size;
 
1024
 
 
1025
         s2 &= ~S2_TEXCOORD_FMT(i, S2_TEXCOORD_FMT0_MASK);
 
1026
         s2 |= S2_TEXCOORD_FMT(i, SZ_TO_HW(sz));
 
1027
 
 
1028
         EMIT_ATTR(_TNL_ATTRIB_TEX0 + i, EMIT_SZ(sz), 0, sz * 4);
 
1029
      }
 
1030
      else if (i == p->wpos_tex) {
 
1031
 
 
1032
         /* If WPOS is required, duplicate the XYZ position data in an
 
1033
          * unused texture coordinate:
 
1034
          */
 
1035
         s2 &= ~S2_TEXCOORD_FMT(i, S2_TEXCOORD_FMT0_MASK);
 
1036
         s2 |= S2_TEXCOORD_FMT(i, SZ_TO_HW(3));
 
1037
 
 
1038
         intel->wpos_offset = offset;
 
1039
         intel->wpos_size = 3 * sizeof(GLuint);
 
1040
 
 
1041
         EMIT_PAD(intel->wpos_size);
 
1042
      }
 
1043
   }
 
1044
 
 
1045
   if (s2 != i915->state.Ctx[I915_CTXREG_LIS2] ||
 
1046
       s4 != i915->state.Ctx[I915_CTXREG_LIS4]) {
 
1047
      int k;
 
1048
 
 
1049
      I915_STATECHANGE(i915, I915_UPLOAD_CTX);
 
1050
 
 
1051
      /* Must do this *after* statechange, so as not to affect
 
1052
       * buffered vertices reliant on the old state:
 
1053
       */
 
1054
      intel->vertex_size = _tnl_install_attrs(&intel->ctx,
 
1055
                                              intel->vertex_attrs,
 
1056
                                              intel->vertex_attr_count,
 
1057
                                              intel->ViewportMatrix.m, 0);
 
1058
 
 
1059
      intel->vertex_size >>= 2;
 
1060
 
 
1061
      i915->state.Ctx[I915_CTXREG_LIS2] = s2;
 
1062
      i915->state.Ctx[I915_CTXREG_LIS4] = s4;
 
1063
 
 
1064
      k = intel->vtbl.check_vertex_size(intel, intel->vertex_size);
 
1065
      assert(k);
 
1066
   }
 
1067
 
 
1068
   if (!p->params_uptodate)
 
1069
      track_params(p);
 
1070
 
 
1071
   if (!p->on_hardware)
 
1072
      i915_upload_program(i915, p);
 
1073
}
 
1074
 
 
1075
void
 
1076
i915InitFragProgFuncs(struct dd_function_table *functions)
 
1077
{
 
1078
   functions->BindProgram = i915BindProgram;
 
1079
   functions->NewProgram = i915NewProgram;
 
1080
   functions->DeleteProgram = i915DeleteProgram;
 
1081
   functions->IsProgramNative = i915IsProgramNative;
 
1082
   functions->ProgramStringNotify = i915ProgramStringNotify;
 
1083
}