1/**************************************************************************
2 *
3 * Copyright 2007 VMware, Inc.
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 VMWARE 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 "sp_context.h"
29#include "sp_state.h"
30#include "sp_fs.h"
31#include "sp_texture.h"
32
33#include "pipe/p_defines.h"
34#include "util/u_memory.h"
35#include "util/u_inlines.h"
36#include "util/u_pstipple.h"
37#include "draw/draw_context.h"
38#include "draw/draw_vs.h"
39#include "draw/draw_gs.h"
40#include "tgsi/tgsi_dump.h"
41#include "tgsi/tgsi_scan.h"
42#include "tgsi/tgsi_parse.h"
43
44
45/**
46 * Create a new fragment shader variant.
47 */
48static struct sp_fragment_shader_variant *
49create_fs_variant(struct softpipe_context *softpipe,
50                  struct sp_fragment_shader *fs,
51                  const struct sp_fragment_shader_variant_key *key)
52{
53   struct sp_fragment_shader_variant *var;
54   struct pipe_shader_state *curfs = &fs->shader;
55
56   /* codegen, create variant object */
57   var = softpipe_create_fs_variant_exec(softpipe);
58
59   if (var) {
60      var->key = *key;
61
62#if DO_PSTIPPLE_IN_HELPER_MODULE
63      if (key->polygon_stipple) {
64         /* get new shader that implements polygon stippling */
65         var->tokens =
66            util_pstipple_create_fragment_shader(curfs->tokens,
67                                                 &var->stipple_sampler_unit, 0,
68                                                 TGSI_FILE_INPUT);
69      }
70      else
71#endif
72      {
73         var->tokens = tgsi_dup_tokens(curfs->tokens);
74         var->stipple_sampler_unit = 0;
75      }
76
77      tgsi_scan_shader(var->tokens, &var->info);
78
79      /* See comments elsewhere about draw fragment shaders */
80#if 0
81      /* draw's fs state */
82      var->draw_shader = draw_create_fragment_shader(softpipe->draw,
83                                                     &fs->shader);
84      if (!var->draw_shader) {
85         var->delete(var);
86         FREE((void *) var->tokens);
87         return NULL;
88      }
89#endif
90
91      /* insert variant into linked list */
92      var->next = fs->variants;
93      fs->variants = var;
94   }
95
96   return var;
97}
98
99
100struct sp_fragment_shader_variant *
101softpipe_find_fs_variant(struct softpipe_context *sp,
102                         struct sp_fragment_shader *fs,
103                         const struct sp_fragment_shader_variant_key *key)
104{
105   struct sp_fragment_shader_variant *var;
106
107   for (var = fs->variants; var; var = var->next) {
108      if (memcmp(&var->key, key, sizeof(*key)) == 0) {
109         /* found it */
110         return var;
111      }
112   }
113
114   return create_fs_variant(sp, fs, key);
115}
116
117
118static void *
119softpipe_create_fs_state(struct pipe_context *pipe,
120                         const struct pipe_shader_state *templ)
121{
122   struct softpipe_context *softpipe = softpipe_context(pipe);
123   struct sp_fragment_shader *state = CALLOC_STRUCT(sp_fragment_shader);
124
125   /* debug */
126   if (softpipe->dump_fs)
127      tgsi_dump(templ->tokens, 0);
128
129   /* we need to keep a local copy of the tokens */
130   state->shader.tokens = tgsi_dup_tokens(templ->tokens);
131
132   /* draw's fs state */
133   state->draw_shader = draw_create_fragment_shader(softpipe->draw,
134                                                    &state->shader);
135   if (!state->draw_shader) {
136      tgsi_free_tokens(state->shader.tokens);
137      FREE(state);
138      return NULL;
139   }
140
141   return state;
142}
143
144
145static void
146softpipe_bind_fs_state(struct pipe_context *pipe, void *fs)
147{
148   struct softpipe_context *softpipe = softpipe_context(pipe);
149   struct sp_fragment_shader *state = (struct sp_fragment_shader *) fs;
150
151   if (softpipe->fs == fs)
152      return;
153
154   draw_flush(softpipe->draw);
155
156   softpipe->fs = fs;
157
158   /* This depends on the current fragment shader and must always be
159    * re-validated before use.
160    */
161   softpipe->fs_variant = NULL;
162
163   if (state)
164      draw_bind_fragment_shader(softpipe->draw,
165                                state->draw_shader);
166   else
167      draw_bind_fragment_shader(softpipe->draw, NULL);
168
169   softpipe->dirty |= SP_NEW_FS;
170}
171
172
173static void
174softpipe_delete_fs_state(struct pipe_context *pipe, void *fs)
175{
176   struct softpipe_context *softpipe = softpipe_context(pipe);
177   struct sp_fragment_shader *state = fs;
178   struct sp_fragment_shader_variant *var, *next_var;
179
180   assert(fs != softpipe->fs);
181
182   /* delete variants */
183   for (var = state->variants; var; var = next_var) {
184      next_var = var->next;
185
186      assert(var != softpipe->fs_variant);
187
188      /* See comments elsewhere about draw fragment shaders */
189#if 0
190      draw_delete_fragment_shader(softpipe->draw, var->draw_shader);
191#endif
192
193      var->delete(var, softpipe->fs_machine);
194   }
195
196   draw_delete_fragment_shader(softpipe->draw, state->draw_shader);
197
198   tgsi_free_tokens(state->shader.tokens);
199   FREE(state);
200}
201
202
203static void *
204softpipe_create_vs_state(struct pipe_context *pipe,
205                         const struct pipe_shader_state *templ)
206{
207   struct softpipe_context *softpipe = softpipe_context(pipe);
208   struct sp_vertex_shader *state;
209
210   state = CALLOC_STRUCT(sp_vertex_shader);
211   if (!state)
212      goto fail;
213
214   /* copy shader tokens, the ones passed in will go away.
215    */
216   state->shader.tokens = tgsi_dup_tokens(templ->tokens);
217   if (state->shader.tokens == NULL)
218      goto fail;
219
220   state->draw_data = draw_create_vertex_shader(softpipe->draw, templ);
221   if (state->draw_data == NULL)
222      goto fail;
223
224   state->max_sampler = state->draw_data->info.file_max[TGSI_FILE_SAMPLER];
225
226   return state;
227
228fail:
229   if (state) {
230      tgsi_free_tokens(state->shader.tokens);
231      FREE( state->draw_data );
232      FREE( state );
233   }
234   return NULL;
235}
236
237
238static void
239softpipe_bind_vs_state(struct pipe_context *pipe, void *vs)
240{
241   struct softpipe_context *softpipe = softpipe_context(pipe);
242
243   softpipe->vs = (struct sp_vertex_shader *) vs;
244
245   draw_bind_vertex_shader(softpipe->draw,
246                           (softpipe->vs ? softpipe->vs->draw_data : NULL));
247
248   softpipe->dirty |= SP_NEW_VS;
249}
250
251
252static void
253softpipe_delete_vs_state(struct pipe_context *pipe, void *vs)
254{
255   struct softpipe_context *softpipe = softpipe_context(pipe);
256
257   struct sp_vertex_shader *state = (struct sp_vertex_shader *) vs;
258
259   draw_delete_vertex_shader(softpipe->draw, state->draw_data);
260   tgsi_free_tokens(state->shader.tokens);
261   FREE( state );
262}
263
264
265static void *
266softpipe_create_gs_state(struct pipe_context *pipe,
267                         const struct pipe_shader_state *templ)
268{
269   struct softpipe_context *softpipe = softpipe_context(pipe);
270   struct sp_geometry_shader *state;
271
272   state = CALLOC_STRUCT(sp_geometry_shader);
273   if (!state)
274      goto fail;
275
276   state->shader = *templ;
277
278   if (templ->tokens) {
279      /* debug */
280      if (softpipe->dump_gs)
281         tgsi_dump(templ->tokens, 0);
282
283      /* copy shader tokens, the ones passed in will go away.
284       */
285      state->shader.tokens = tgsi_dup_tokens(templ->tokens);
286      if (state->shader.tokens == NULL)
287         goto fail;
288
289      state->draw_data = draw_create_geometry_shader(softpipe->draw, templ);
290      if (state->draw_data == NULL)
291         goto fail;
292
293      state->max_sampler = state->draw_data->info.file_max[TGSI_FILE_SAMPLER];
294   }
295
296   return state;
297
298fail:
299   if (state) {
300      tgsi_free_tokens(state->shader.tokens);
301      FREE( state->draw_data );
302      FREE( state );
303   }
304   return NULL;
305}
306
307
308static void
309softpipe_bind_gs_state(struct pipe_context *pipe, void *gs)
310{
311   struct softpipe_context *softpipe = softpipe_context(pipe);
312
313   softpipe->gs = (struct sp_geometry_shader *)gs;
314
315   draw_bind_geometry_shader(softpipe->draw,
316                             (softpipe->gs ? softpipe->gs->draw_data : NULL));
317
318   softpipe->dirty |= SP_NEW_GS;
319}
320
321
322static void
323softpipe_delete_gs_state(struct pipe_context *pipe, void *gs)
324{
325   struct softpipe_context *softpipe = softpipe_context(pipe);
326
327   struct sp_geometry_shader *state =
328      (struct sp_geometry_shader *)gs;
329
330   draw_delete_geometry_shader(softpipe->draw,
331                               (state) ? state->draw_data : 0);
332
333   tgsi_free_tokens(state->shader.tokens);
334   FREE(state);
335}
336
337
338static void
339softpipe_set_constant_buffer(struct pipe_context *pipe,
340                             uint shader, uint index,
341                             const struct pipe_constant_buffer *cb)
342{
343   struct softpipe_context *softpipe = softpipe_context(pipe);
344   struct pipe_resource *constants = cb ? cb->buffer : NULL;
345   unsigned size;
346   const void *data;
347
348   assert(shader < PIPE_SHADER_TYPES);
349
350   if (cb && cb->user_buffer) {
351      constants = softpipe_user_buffer_create(pipe->screen,
352                                              (void *) cb->user_buffer,
353                                              cb->buffer_size,
354                                              PIPE_BIND_CONSTANT_BUFFER);
355   }
356
357   size = cb ? cb->buffer_size : 0;
358   data = constants ? softpipe_resource_data(constants) : NULL;
359   if (data)
360      data = (const char *) data + cb->buffer_offset;
361
362   draw_flush(softpipe->draw);
363
364   /* note: reference counting */
365   pipe_resource_reference(&softpipe->constants[shader][index], constants);
366
367   if (shader == PIPE_SHADER_VERTEX || shader == PIPE_SHADER_GEOMETRY) {
368      draw_set_mapped_constant_buffer(softpipe->draw, shader, index, data, size);
369   }
370
371   softpipe->mapped_constants[shader][index] = data;
372   softpipe->const_buffer_size[shader][index] = size;
373
374   softpipe->dirty |= SP_NEW_CONSTANTS;
375
376   if (cb && cb->user_buffer) {
377      pipe_resource_reference(&constants, NULL);
378   }
379}
380
381static void *
382softpipe_create_compute_state(struct pipe_context *pipe,
383                              const struct pipe_compute_state *templ)
384{
385   struct softpipe_context *softpipe = softpipe_context(pipe);
386   const struct tgsi_token *tokens;
387   struct sp_compute_shader *state;
388   if (templ->ir_type != PIPE_SHADER_IR_TGSI)
389      return NULL;
390
391   tokens = templ->prog;
392   /* debug */
393   if (softpipe->dump_cs)
394      tgsi_dump(tokens, 0);
395
396   state = CALLOC_STRUCT(sp_compute_shader);
397
398   state->shader = *templ;
399   state->tokens = tgsi_dup_tokens(tokens);
400   tgsi_scan_shader(state->tokens, &state->info);
401
402   state->max_sampler = state->info.file_max[TGSI_FILE_SAMPLER];
403
404   return state;
405}
406
407static void
408softpipe_bind_compute_state(struct pipe_context *pipe,
409                            void *cs)
410{
411   struct softpipe_context *softpipe = softpipe_context(pipe);
412   struct sp_compute_shader *state = (struct sp_compute_shader *)cs;
413   if (softpipe->cs == state)
414      return;
415
416   softpipe->cs = state;
417}
418
419static void
420softpipe_delete_compute_state(struct pipe_context *pipe,
421                              void *cs)
422{
423   MAYBE_UNUSED struct softpipe_context *softpipe = softpipe_context(pipe);
424   struct sp_compute_shader *state = (struct sp_compute_shader *)cs;
425
426   assert(softpipe->cs != state);
427   tgsi_free_tokens(state->tokens);
428   FREE(state);
429}
430
431void
432softpipe_init_shader_funcs(struct pipe_context *pipe)
433{
434   pipe->create_fs_state = softpipe_create_fs_state;
435   pipe->bind_fs_state   = softpipe_bind_fs_state;
436   pipe->delete_fs_state = softpipe_delete_fs_state;
437
438   pipe->create_vs_state = softpipe_create_vs_state;
439   pipe->bind_vs_state   = softpipe_bind_vs_state;
440   pipe->delete_vs_state = softpipe_delete_vs_state;
441
442   pipe->create_gs_state = softpipe_create_gs_state;
443   pipe->bind_gs_state   = softpipe_bind_gs_state;
444   pipe->delete_gs_state = softpipe_delete_gs_state;
445
446   pipe->set_constant_buffer = softpipe_set_constant_buffer;
447
448   pipe->create_compute_state = softpipe_create_compute_state;
449   pipe->bind_compute_state = softpipe_bind_compute_state;
450   pipe->delete_compute_state = softpipe_delete_compute_state;
451}
452