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 /*
29  * Authors:
30  *   Keith Whitwell <keith@tungstengraphics.com>
31  */
32
33#include "main/glheader.h"
34#include "main/macros.h"
35#include "main/enums.h"
36#include "main/shaderapi.h"
37#include "program/prog_instruction.h"
38#include "program/program.h"
39
40#include "cso_cache/cso_context.h"
41#include "draw/draw_context.h"
42
43#include "st_context.h"
44#include "st_program.h"
45#include "st_mesa_to_tgsi.h"
46#include "st_cb_program.h"
47#include "st_glsl_to_tgsi.h"
48
49
50
51/**
52 * Called via ctx->Driver.BindProgram() to bind an ARB vertex or
53 * fragment program.
54 */
55static void
56st_bind_program(struct gl_context *ctx, GLenum target, struct gl_program *prog)
57{
58   struct st_context *st = st_context(ctx);
59
60   switch (target) {
61   case GL_VERTEX_PROGRAM_ARB:
62      st->dirty.st |= ST_NEW_VERTEX_PROGRAM;
63      break;
64   case GL_FRAGMENT_PROGRAM_ARB:
65      st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM;
66      break;
67   case MESA_GEOMETRY_PROGRAM:
68      st->dirty.st |= ST_NEW_GEOMETRY_PROGRAM;
69      break;
70   }
71}
72
73
74/**
75 * Called via ctx->Driver.UseProgram() to bind a linked GLSL program
76 * (vertex shader + fragment shader).
77 */
78static void
79st_use_program(struct gl_context *ctx, struct gl_shader_program *shProg)
80{
81   struct st_context *st = st_context(ctx);
82
83   st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM;
84   st->dirty.st |= ST_NEW_VERTEX_PROGRAM;
85   st->dirty.st |= ST_NEW_GEOMETRY_PROGRAM;
86}
87
88
89/**
90 * Called via ctx->Driver.NewProgram() to allocate a new vertex or
91 * fragment program.
92 */
93static struct gl_program *
94st_new_program(struct gl_context *ctx, GLenum target, GLuint id)
95{
96   switch (target) {
97   case GL_VERTEX_PROGRAM_ARB: {
98      struct st_vertex_program *prog = ST_CALLOC_STRUCT(st_vertex_program);
99      return _mesa_init_vertex_program(ctx, &prog->Base, target, id);
100   }
101
102   case GL_FRAGMENT_PROGRAM_ARB:
103   case GL_FRAGMENT_PROGRAM_NV: {
104      struct st_fragment_program *prog = ST_CALLOC_STRUCT(st_fragment_program);
105      return _mesa_init_fragment_program(ctx, &prog->Base, target, id);
106   }
107
108   case MESA_GEOMETRY_PROGRAM: {
109      struct st_geometry_program *prog = ST_CALLOC_STRUCT(st_geometry_program);
110      return _mesa_init_geometry_program(ctx, &prog->Base, target, id);
111   }
112
113   default:
114      assert(0);
115      return NULL;
116   }
117}
118
119
120/**
121 * Called via ctx->Driver.DeleteProgram()
122 */
123static void
124st_delete_program(struct gl_context *ctx, struct gl_program *prog)
125{
126   struct st_context *st = st_context(ctx);
127
128   switch( prog->Target ) {
129   case GL_VERTEX_PROGRAM_ARB:
130      {
131         struct st_vertex_program *stvp = (struct st_vertex_program *) prog;
132         st_release_vp_variants( st, stvp );
133
134         if (stvp->glsl_to_tgsi)
135            free_glsl_to_tgsi_visitor(stvp->glsl_to_tgsi);
136      }
137      break;
138   case MESA_GEOMETRY_PROGRAM:
139      {
140         struct st_geometry_program *stgp =
141            (struct st_geometry_program *) prog;
142
143         st_release_gp_variants(st, stgp);
144
145         if (stgp->glsl_to_tgsi)
146            free_glsl_to_tgsi_visitor(stgp->glsl_to_tgsi);
147
148         if (stgp->tgsi.tokens) {
149            st_free_tokens((void *) stgp->tgsi.tokens);
150            stgp->tgsi.tokens = NULL;
151         }
152      }
153      break;
154   case GL_FRAGMENT_PROGRAM_ARB:
155      {
156         struct st_fragment_program *stfp =
157            (struct st_fragment_program *) prog;
158
159         st_release_fp_variants(st, stfp);
160
161         if (stfp->glsl_to_tgsi)
162            free_glsl_to_tgsi_visitor(stfp->glsl_to_tgsi);
163      }
164      break;
165   default:
166      assert(0); /* problem */
167   }
168
169   /* delete base class */
170   _mesa_delete_program( ctx, prog );
171}
172
173
174/**
175 * Called via ctx->Driver.IsProgramNative()
176 */
177static GLboolean
178st_is_program_native(struct gl_context *ctx,
179                     GLenum target,
180                     struct gl_program *prog)
181{
182   return GL_TRUE;
183}
184
185
186/**
187 * Called via ctx->Driver.ProgramStringNotify()
188 * Called when the program's text/code is changed.  We have to free
189 * all shader variants and corresponding gallium shaders when this happens.
190 */
191static GLboolean
192st_program_string_notify( struct gl_context *ctx,
193                                           GLenum target,
194                                           struct gl_program *prog )
195{
196   struct st_context *st = st_context(ctx);
197
198   if (target == GL_FRAGMENT_PROGRAM_ARB) {
199      struct st_fragment_program *stfp = (struct st_fragment_program *) prog;
200
201      st_release_fp_variants(st, stfp);
202
203      if (st->fp == stfp)
204	 st->dirty.st |= ST_NEW_FRAGMENT_PROGRAM;
205   }
206   else if (target == MESA_GEOMETRY_PROGRAM) {
207      struct st_geometry_program *stgp = (struct st_geometry_program *) prog;
208
209      st_release_gp_variants(st, stgp);
210
211      if (stgp->tgsi.tokens) {
212         st_free_tokens((void *) stgp->tgsi.tokens);
213         stgp->tgsi.tokens = NULL;
214      }
215
216      if (st->gp == stgp)
217	 st->dirty.st |= ST_NEW_GEOMETRY_PROGRAM;
218   }
219   else if (target == GL_VERTEX_PROGRAM_ARB) {
220      struct st_vertex_program *stvp = (struct st_vertex_program *) prog;
221
222      st_release_vp_variants( st, stvp );
223
224      if (st->vp == stvp)
225	 st->dirty.st |= ST_NEW_VERTEX_PROGRAM;
226   }
227
228   /* XXX check if program is legal, within limits */
229   return GL_TRUE;
230}
231
232
233/**
234 * Plug in the program and shader-related device driver functions.
235 */
236void
237st_init_program_functions(struct dd_function_table *functions)
238{
239   functions->BindProgram = st_bind_program;
240   functions->UseProgram = st_use_program;
241   functions->NewProgram = st_new_program;
242   functions->DeleteProgram = st_delete_program;
243   functions->IsProgramNative = st_is_program_native;
244   functions->ProgramStringNotify = st_program_string_notify;
245
246   functions->NewShader = st_new_shader;
247   functions->NewShaderProgram = st_new_shader_program;
248   functions->LinkShader = st_link_shader;
249}
250