Tizen 2.0 Release
[profile/ivi/osmesa.git] / src / mesa / drivers / dri / i965 / brw_program.c
1 /*
2  Copyright (C) Intel Corp.  2006.  All Rights Reserved.
3  Intel funded Tungsten Graphics (http://www.tungstengraphics.com) to
4  develop this 3D driver.
5  
6  Permission is hereby granted, free of charge, to any person obtaining
7  a 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, sublicense, 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
16  portions of the Software.
17  
18  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21  IN NO EVENT SHALL THE COPYRIGHT OWNER(S) AND/OR ITS SUPPLIERS BE
22  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25  
26  **********************************************************************/
27  /*
28   * Authors:
29   *   Keith Whitwell <keith@tungstengraphics.com>
30   */
31   
32 #include "main/imports.h"
33 #include "main/enums.h"
34 #include "main/shaderobj.h"
35 #include "program/prog_parameter.h"
36 #include "program/program.h"
37 #include "program/programopt.h"
38 #include "tnl/tnl.h"
39 #include "../glsl/ralloc.h"
40
41 #include "brw_context.h"
42 #include "brw_wm.h"
43
44 static void brwBindProgram( struct gl_context *ctx,
45                             GLenum target, 
46                             struct gl_program *prog )
47 {
48    struct brw_context *brw = brw_context(ctx);
49
50    switch (target) {
51    case GL_VERTEX_PROGRAM_ARB: 
52       brw->state.dirty.brw |= BRW_NEW_VERTEX_PROGRAM;
53       break;
54    case GL_FRAGMENT_PROGRAM_ARB:
55       brw->state.dirty.brw |= BRW_NEW_FRAGMENT_PROGRAM;
56       break;
57    }
58 }
59
60 static struct gl_program *brwNewProgram( struct gl_context *ctx,
61                                       GLenum target, 
62                                       GLuint id )
63 {
64    struct brw_context *brw = brw_context(ctx);
65
66    switch (target) {
67    case GL_VERTEX_PROGRAM_ARB: {
68       struct brw_vertex_program *prog = CALLOC_STRUCT(brw_vertex_program);
69       if (prog) {
70          prog->id = brw->program_id++;
71
72          return _mesa_init_vertex_program( ctx, &prog->program,
73                                              target, id );
74       }
75       else
76          return NULL;
77    }
78
79    case GL_FRAGMENT_PROGRAM_ARB: {
80       struct brw_fragment_program *prog = CALLOC_STRUCT(brw_fragment_program);
81       if (prog) {
82          prog->id = brw->program_id++;
83
84          return _mesa_init_fragment_program( ctx, &prog->program,
85                                              target, id );
86       }
87       else
88          return NULL;
89    }
90
91    default:
92       return _mesa_new_program(ctx, target, id);
93    }
94 }
95
96 static void brwDeleteProgram( struct gl_context *ctx,
97                               struct gl_program *prog )
98 {
99    _mesa_delete_program( ctx, prog );
100 }
101
102
103 static GLboolean brwIsProgramNative( struct gl_context *ctx,
104                                      GLenum target, 
105                                      struct gl_program *prog )
106 {
107    return GL_TRUE;
108 }
109
110 static void
111 shader_error(struct gl_context *ctx, struct gl_program *prog, const char *msg)
112 {
113    struct gl_shader_program *shader;
114
115    shader = _mesa_lookup_shader_program(ctx, prog->Id);
116
117    if (shader) {
118       ralloc_strcat(&shader->InfoLog, msg);
119       shader->LinkStatus = GL_FALSE;
120    }
121 }
122
123 static GLboolean brwProgramStringNotify( struct gl_context *ctx,
124                                          GLenum target,
125                                          struct gl_program *prog )
126 {
127    struct brw_context *brw = brw_context(ctx);
128    int i;
129
130    if (target == GL_FRAGMENT_PROGRAM_ARB) {
131       struct gl_fragment_program *fprog = (struct gl_fragment_program *) prog;
132       struct brw_fragment_program *newFP = brw_fragment_program(fprog);
133       const struct brw_fragment_program *curFP =
134          brw_fragment_program_const(brw->fragment_program);
135       struct gl_shader_program *shader_program;
136
137       if (newFP == curFP)
138          brw->state.dirty.brw |= BRW_NEW_FRAGMENT_PROGRAM;
139       newFP->id = brw->program_id++;      
140
141       /* Don't reject fragment shaders for their Mesa IR state when we're
142        * using the new FS backend.
143        */
144       shader_program = _mesa_lookup_shader_program(ctx, prog->Id);
145       if (shader_program
146           && shader_program->_LinkedShaders[MESA_SHADER_FRAGMENT]) {
147          return GL_TRUE;
148       }
149    }
150    else if (target == GL_VERTEX_PROGRAM_ARB) {
151       struct gl_vertex_program *vprog = (struct gl_vertex_program *) prog;
152       struct brw_vertex_program *newVP = brw_vertex_program(vprog);
153       const struct brw_vertex_program *curVP =
154          brw_vertex_program_const(brw->vertex_program);
155
156       if (newVP == curVP)
157          brw->state.dirty.brw |= BRW_NEW_VERTEX_PROGRAM;
158       if (newVP->program.IsPositionInvariant) {
159          _mesa_insert_mvp_code(ctx, &newVP->program);
160       }
161       newVP->id = brw->program_id++;      
162
163       /* Also tell tnl about it:
164        */
165       _tnl_program_string(ctx, target, prog);
166    }
167
168    /* Reject programs with subroutines, which are totally broken at the moment
169     * (all program flows return when any program flow returns, and
170     * the VS also hangs if a function call calls a function.
171     *
172     * See piglit glsl-{vs,fs}-functions-[23] tests.
173     */
174    for (i = 0; i < prog->NumInstructions; i++) {
175       struct prog_instruction *inst = prog->Instructions + i;
176       int r;
177
178       if (prog->Instructions[i].Opcode == OPCODE_CAL) {
179          shader_error(ctx, prog,
180                       "i965 driver doesn't yet support uninlined function "
181                       "calls.  Move to using a single return statement at "
182                       "the end of the function to work around it.\n");
183          return GL_FALSE;
184       }
185
186       if (prog->Instructions[i].Opcode == OPCODE_RET) {
187          shader_error(ctx, prog,
188                       "i965 driver doesn't yet support \"return\" "
189                       "from main().\n");
190          return GL_FALSE;
191       }
192
193       for (r = 0; r < _mesa_num_inst_src_regs(inst->Opcode); r++) {
194          if (prog->Instructions[i].SrcReg[r].RelAddr &&
195              prog->Instructions[i].SrcReg[r].File == PROGRAM_INPUT) {
196             shader_error(ctx, prog,
197                          "Variable indexing of shader inputs unsupported\n");
198             return GL_FALSE;
199          }
200       }
201
202       if (target == GL_FRAGMENT_PROGRAM_ARB &&
203           prog->Instructions[i].DstReg.RelAddr &&
204           prog->Instructions[i].DstReg.File == PROGRAM_OUTPUT) {
205          shader_error(ctx, prog,
206                       "Variable indexing of FS outputs unsupported\n");
207          return GL_FALSE;
208       }
209       if (target == GL_FRAGMENT_PROGRAM_ARB) {
210          if ((prog->Instructions[i].DstReg.RelAddr &&
211               prog->Instructions[i].DstReg.File == PROGRAM_TEMPORARY) ||
212              (prog->Instructions[i].SrcReg[0].RelAddr &&
213               prog->Instructions[i].SrcReg[0].File == PROGRAM_TEMPORARY) ||
214              (prog->Instructions[i].SrcReg[1].RelAddr &&
215               prog->Instructions[i].SrcReg[1].File == PROGRAM_TEMPORARY) ||
216              (prog->Instructions[i].SrcReg[2].RelAddr &&
217               prog->Instructions[i].SrcReg[2].File == PROGRAM_TEMPORARY)) {
218             shader_error(ctx, prog,
219                          "Variable indexing of variable arrays in the FS "
220                          "unsupported\n");
221             return GL_FALSE;
222          }
223       }
224    }
225
226    return GL_TRUE;
227 }
228
229 void brwInitFragProgFuncs( struct dd_function_table *functions )
230 {
231    assert(functions->ProgramStringNotify == _tnl_program_string); 
232
233    functions->BindProgram = brwBindProgram;
234    functions->NewProgram = brwNewProgram;
235    functions->DeleteProgram = brwDeleteProgram;
236    functions->IsProgramNative = brwIsProgramNative;
237    functions->ProgramStringNotify = brwProgramStringNotify;
238
239    functions->NewShader = brw_new_shader;
240    functions->NewShaderProgram = brw_new_shader_program;
241    functions->LinkShader = brw_link_shader;
242 }
243