1/**************************************************************************
2 *
3 * Copyright 2003 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 "util/u_inlines.h"
29#include "util/u_math.h"
30#include "util/u_memory.h"
31#include "pipe/p_shader_tokens.h"
32#include "draw/draw_context.h"
33#include "draw/draw_vertex.h"
34#include "sp_context.h"
35#include "sp_screen.h"
36#include "sp_state.h"
37#include "sp_texture.h"
38#include "sp_tex_sample.h"
39#include "sp_tex_tile_cache.h"
40
41
42/**
43 * Mark the current vertex layout as "invalid".
44 * We'll validate the vertex layout later, when we start to actually
45 * render a point or line or tri.
46 */
47static void
48invalidate_vertex_layout(struct softpipe_context *softpipe)
49{
50   softpipe->setup_info.valid =  0;
51}
52
53
54/**
55 * The vertex info describes how to convert the post-transformed vertices
56 * (simple float[][4]) used by the 'draw' module into vertices for
57 * rasterization.
58 *
59 * This function validates the vertex layout.
60 */
61static void
62softpipe_compute_vertex_info(struct softpipe_context *softpipe)
63{
64   struct sp_setup_info *sinfo = &softpipe->setup_info;
65
66   if (sinfo->valid == 0) {
67      const struct tgsi_shader_info *fsInfo = &softpipe->fs_variant->info;
68      struct vertex_info *vinfo = &softpipe->vertex_info;
69      uint i;
70      int vs_index;
71      /*
72       * This doesn't quite work right (wrt face injection, prim id,
73       * wide points) - hit a couple assertions, misrenderings plus
74       * memory corruption. Albeit could fix (the former two) by calling
75       * this "more often" (rasterizer changes etc.). (The latter would
76       * need to be included in draw_prepare_shader_outputs, but it looks
77       * like that would potentially allocate quite some unused additional
78       * vertex outputs.)
79       * draw_prepare_shader_outputs(softpipe->draw);
80       */
81
82      /*
83       * Those can't actually be 0 (because pos is always at 0).
84       * But use ints anyway to avoid confusion (in vs outputs, they
85       * can very well be at pos 0).
86       */
87      softpipe->viewport_index_slot = -1;
88      softpipe->layer_slot = -1;
89      softpipe->psize_slot = -1;
90
91      vinfo->num_attribs = 0;
92
93      /*
94       * Put position always first (setup needs it there).
95       */
96      vs_index = draw_find_shader_output(softpipe->draw,
97                                         TGSI_SEMANTIC_POSITION, 0);
98
99      draw_emit_vertex_attr(vinfo, EMIT_4F, vs_index);
100
101      /*
102       * Match FS inputs against VS outputs, emitting the necessary
103       * attributes.
104       */
105      for (i = 0; i < fsInfo->num_inputs; i++) {
106         enum sp_interp_mode interp = SP_INTERP_LINEAR;
107
108         switch (fsInfo->input_interpolate[i]) {
109         case TGSI_INTERPOLATE_CONSTANT:
110            interp = SP_INTERP_CONSTANT;
111            break;
112         case TGSI_INTERPOLATE_LINEAR:
113            interp = SP_INTERP_LINEAR;
114            break;
115         case TGSI_INTERPOLATE_PERSPECTIVE:
116            interp = SP_INTERP_PERSPECTIVE;
117            break;
118         case TGSI_INTERPOLATE_COLOR:
119            assert(fsInfo->input_semantic_name[i] == TGSI_SEMANTIC_COLOR);
120            break;
121         default:
122            assert(0);
123         }
124
125         switch (fsInfo->input_semantic_name[i]) {
126         case TGSI_SEMANTIC_POSITION:
127            interp = SP_INTERP_POS;
128            break;
129
130         case TGSI_SEMANTIC_COLOR:
131            if (fsInfo->input_interpolate[i] == TGSI_INTERPOLATE_COLOR) {
132               if (softpipe->rasterizer->flatshade)
133                  interp = SP_INTERP_CONSTANT;
134               else
135                  interp = SP_INTERP_PERSPECTIVE;
136            }
137            break;
138         }
139
140         /*
141          * Search for each input in current vs output:
142          */
143         vs_index = draw_find_shader_output(softpipe->draw,
144                                            fsInfo->input_semantic_name[i],
145                                            fsInfo->input_semantic_index[i]);
146
147         if (fsInfo->input_semantic_name[i] == TGSI_SEMANTIC_COLOR &&
148             vs_index == -1) {
149            /*
150             * try and find a bcolor.
151             * Note that if there's both front and back color, draw will
152             * have copied back to front color already.
153             */
154            vs_index = draw_find_shader_output(softpipe->draw,
155                                               TGSI_SEMANTIC_BCOLOR,
156                                               fsInfo->input_semantic_index[i]);
157         }
158
159         sinfo->attrib[i].interp = interp;
160         /* extremely pointless index map */
161         sinfo->attrib[i].src_index = i + 1;
162         /*
163          * For vp index and layer, if the fs requires them but the vs doesn't
164          * provide them, draw (vbuf) will give us the required 0 (slot -1).
165          * (This means in this case we'll also use those slots in setup, which
166          * isn't necessary but they'll contain the correct (0) value.)
167          */
168         if (fsInfo->input_semantic_name[i] ==
169                    TGSI_SEMANTIC_VIEWPORT_INDEX) {
170            softpipe->viewport_index_slot = (int)vinfo->num_attribs;
171            draw_emit_vertex_attr(vinfo, EMIT_4F, vs_index);
172         } else if (fsInfo->input_semantic_name[i] == TGSI_SEMANTIC_LAYER) {
173            softpipe->layer_slot = (int)vinfo->num_attribs;
174            draw_emit_vertex_attr(vinfo, EMIT_4F, vs_index);
175            /*
176             * Note that we'd actually want to skip position (as we won't use
177             * the attribute in the fs) but can't. The reason is that we don't
178             * actually have an input/output map for setup (even though it looks
179             * like we do...). Could adjust for this though even without a map.
180             */
181         } else {
182            /*
183             * Note that we'd actually want to skip position (as we won't use
184             * the attribute in the fs) but can't. The reason is that we don't
185             * actually have an input/output map for setup (even though it looks
186             * like we do...). Could adjust for this though even without a map.
187             */
188            draw_emit_vertex_attr(vinfo, EMIT_4F, vs_index);
189         }
190      }
191
192      /* Figure out if we need pointsize as well.
193       */
194      vs_index = draw_find_shader_output(softpipe->draw,
195                                         TGSI_SEMANTIC_PSIZE, 0);
196
197      if (vs_index >= 0) {
198         softpipe->psize_slot = (int)vinfo->num_attribs;
199         draw_emit_vertex_attr(vinfo, EMIT_4F, vs_index);
200      }
201
202      /* Figure out if we need viewport index (if it wasn't already in fs input) */
203      if (softpipe->viewport_index_slot < 0) {
204         vs_index = draw_find_shader_output(softpipe->draw,
205                                            TGSI_SEMANTIC_VIEWPORT_INDEX,
206                                            0);
207         if (vs_index >= 0) {
208            softpipe->viewport_index_slot =(int)vinfo->num_attribs;
209            draw_emit_vertex_attr(vinfo, EMIT_4F, vs_index);
210         }
211      }
212
213      /* Figure out if we need layer (if it wasn't already in fs input) */
214      if (softpipe->layer_slot < 0) {
215         vs_index = draw_find_shader_output(softpipe->draw,
216                                            TGSI_SEMANTIC_LAYER,
217                                            0);
218         if (vs_index >= 0) {
219            softpipe->layer_slot = (int)vinfo->num_attribs;
220            draw_emit_vertex_attr(vinfo, EMIT_4F, vs_index);
221         }
222      }
223
224      draw_compute_vertex_size(vinfo);
225      softpipe->setup_info.valid = 1;
226   }
227   return;
228}
229
230
231/**
232 * Called from vbuf module.
233 *
234 * This will trigger validation of the vertex layout (and also compute
235 * the required information for setup).
236 */
237struct vertex_info *
238softpipe_get_vbuf_vertex_info(struct softpipe_context *softpipe)
239{
240   softpipe_compute_vertex_info(softpipe);
241   return &softpipe->vertex_info;
242}
243
244
245/**
246 * Recompute cliprect from scissor bounds, scissor enable and surface size.
247 */
248static void
249compute_cliprect(struct softpipe_context *sp)
250{
251   unsigned i;
252   /* SP_NEW_FRAMEBUFFER
253    */
254   uint surfWidth = sp->framebuffer.width;
255   uint surfHeight = sp->framebuffer.height;
256
257   for (i = 0; i < PIPE_MAX_VIEWPORTS; i++) {
258      /* SP_NEW_RASTERIZER
259       */
260      if (sp->rasterizer->scissor) {
261
262         /* SP_NEW_SCISSOR
263          *
264          * clip to scissor rect:
265          */
266         sp->cliprect[i].minx = MAX2(sp->scissors[i].minx, 0);
267         sp->cliprect[i].miny = MAX2(sp->scissors[i].miny, 0);
268         sp->cliprect[i].maxx = MIN2(sp->scissors[i].maxx, surfWidth);
269         sp->cliprect[i].maxy = MIN2(sp->scissors[i].maxy, surfHeight);
270      }
271      else {
272         /* clip to surface bounds */
273         sp->cliprect[i].minx = 0;
274         sp->cliprect[i].miny = 0;
275         sp->cliprect[i].maxx = surfWidth;
276         sp->cliprect[i].maxy = surfHeight;
277      }
278   }
279}
280
281
282static void
283set_shader_sampler(struct softpipe_context *softpipe,
284                   enum pipe_shader_type shader,
285                   int max_sampler)
286{
287   int i;
288   for (i = 0; i <= max_sampler; i++) {
289      softpipe->tgsi.sampler[shader]->sp_sampler[i] =
290         (struct sp_sampler *)(softpipe->samplers[shader][i]);
291   }
292}
293
294void
295softpipe_update_compute_samplers(struct softpipe_context *softpipe)
296{
297   set_shader_sampler(softpipe, PIPE_SHADER_COMPUTE, softpipe->cs->max_sampler);
298}
299
300static void
301update_tgsi_samplers( struct softpipe_context *softpipe )
302{
303   unsigned i, sh;
304
305   set_shader_sampler(softpipe, PIPE_SHADER_VERTEX,
306                      softpipe->vs->max_sampler);
307   set_shader_sampler(softpipe, PIPE_SHADER_FRAGMENT,
308                      softpipe->fs_variant->info.file_max[TGSI_FILE_SAMPLER]);
309   if (softpipe->gs) {
310      set_shader_sampler(softpipe, PIPE_SHADER_GEOMETRY,
311                         softpipe->gs->max_sampler);
312   }
313
314   /* XXX is this really necessary here??? */
315   for (sh = 0; sh < ARRAY_SIZE(softpipe->tex_cache); sh++) {
316      for (i = 0; i < PIPE_MAX_SAMPLERS; i++) {
317         struct softpipe_tex_tile_cache *tc = softpipe->tex_cache[sh][i];
318         if (tc && tc->texture) {
319            struct softpipe_resource *spt = softpipe_resource(tc->texture);
320            if (spt->timestamp != tc->timestamp) {
321               sp_tex_tile_cache_validate_texture( tc );
322               /*
323                 _debug_printf("INV %d %d\n", tc->timestamp, spt->timestamp);
324               */
325               tc->timestamp = spt->timestamp;
326            }
327         }
328      }
329   }
330}
331
332
333static void
334update_fragment_shader(struct softpipe_context *softpipe, unsigned prim)
335{
336   struct sp_fragment_shader_variant_key key;
337
338   memset(&key, 0, sizeof(key));
339
340   if (softpipe->fs) {
341      softpipe->fs_variant = softpipe_find_fs_variant(softpipe,
342                                                      softpipe->fs, &key);
343
344      /* prepare the TGSI interpreter for FS execution */
345      softpipe->fs_variant->prepare(softpipe->fs_variant,
346                                    softpipe->fs_machine,
347                                    (struct tgsi_sampler *) softpipe->
348                                    tgsi.sampler[PIPE_SHADER_FRAGMENT],
349                                    (struct tgsi_image *)softpipe->tgsi.image[PIPE_SHADER_FRAGMENT],
350                                    (struct tgsi_buffer *)softpipe->tgsi.buffer[PIPE_SHADER_FRAGMENT]);
351   }
352   else {
353      softpipe->fs_variant = NULL;
354   }
355
356   /* This would be the logical place to pass the fragment shader
357    * to the draw module.  However, doing this here, during state
358    * validation, causes problems with the 'draw' module helpers for
359    * wide/AA/stippled lines.
360    * In principle, the draw's fragment shader should be per-variant
361    * but that doesn't work.  So we use a single draw fragment shader
362    * per fragment shader, not per variant.
363    */
364#if 0
365   if (softpipe->fs_variant) {
366      draw_bind_fragment_shader(softpipe->draw,
367                                softpipe->fs_variant->draw_shader);
368   }
369   else {
370      draw_bind_fragment_shader(softpipe->draw, NULL);
371   }
372#endif
373}
374
375
376/* Hopefully this will remain quite simple, otherwise need to pull in
377 * something like the gallium frontend mechanism.
378 */
379void
380softpipe_update_derived(struct softpipe_context *softpipe, unsigned prim)
381{
382   struct softpipe_screen *sp_screen = softpipe_screen(softpipe->pipe.screen);
383
384   /* Check for updated textures.
385    */
386   if (softpipe->tex_timestamp != sp_screen->timestamp) {
387      softpipe->tex_timestamp = sp_screen->timestamp;
388      softpipe->dirty |= SP_NEW_TEXTURE;
389   }
390
391   if (softpipe->dirty & (SP_NEW_RASTERIZER |
392                          SP_NEW_FS))
393      update_fragment_shader(softpipe, prim);
394
395   /* TODO: this looks suboptimal */
396   if (softpipe->dirty & (SP_NEW_SAMPLER |
397                          SP_NEW_TEXTURE |
398                          SP_NEW_FS |
399                          SP_NEW_VS))
400      update_tgsi_samplers( softpipe );
401
402   if (softpipe->dirty & (SP_NEW_RASTERIZER |
403                          SP_NEW_FS |
404                          SP_NEW_VS))
405      invalidate_vertex_layout( softpipe );
406
407   if (softpipe->dirty & (SP_NEW_SCISSOR |
408                          SP_NEW_RASTERIZER |
409                          SP_NEW_FRAMEBUFFER))
410      compute_cliprect(softpipe);
411
412   if (softpipe->dirty & (SP_NEW_BLEND |
413                          SP_NEW_DEPTH_STENCIL_ALPHA |
414                          SP_NEW_FRAMEBUFFER |
415                          SP_NEW_FS))
416      sp_build_quad_pipeline(softpipe);
417
418   softpipe->dirty = 0;
419}
420