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