1/**************************************************************************
2 *
3 * Copyright 2008 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/**
29 * Polygon stipple stage:  implement polygon stipple with texture map and
30 * fragment program.  The fragment program samples the texture using the
31 * fragment window coordinate register and does a fragment kill for the
32 * stipple-failing fragments.
33 *
34 * Authors:  Brian Paul
35 */
36
37
38#include "pipe/p_context.h"
39#include "pipe/p_defines.h"
40#include "pipe/p_shader_tokens.h"
41#include "util/u_inlines.h"
42
43#include "util/format/u_format.h"
44#include "util/u_math.h"
45#include "util/u_memory.h"
46#include "util/u_pstipple.h"
47#include "util/u_sampler.h"
48
49#include "tgsi/tgsi_transform.h"
50
51#include "draw_context.h"
52#include "draw_pipe.h"
53
54#include "nir.h"
55#include "nir/nir_draw_helpers.h"
56
57/** Approx number of new tokens for instructions in pstip_transform_inst() */
58#define NUM_NEW_TOKENS 53
59
60
61/**
62 * Subclass of pipe_shader_state to carry extra fragment shader info.
63 */
64struct pstip_fragment_shader
65{
66   struct pipe_shader_state state;
67   void *driver_fs;
68   void *pstip_fs;
69   uint sampler_unit;
70};
71
72
73/**
74 * Subclass of draw_stage
75 */
76struct pstip_stage
77{
78   struct draw_stage stage;
79
80   void *sampler_cso;
81   struct pipe_resource *texture;
82   struct pipe_sampler_view *sampler_view;
83   uint num_samplers;
84   uint num_sampler_views;
85
86   /*
87    * Currently bound state
88    */
89   struct pstip_fragment_shader *fs;
90   struct {
91      void *samplers[PIPE_MAX_SAMPLERS];
92      struct pipe_sampler_view *sampler_views[PIPE_MAX_SHADER_SAMPLER_VIEWS];
93      const struct pipe_poly_stipple *stipple;
94   } state;
95
96   /*
97    * Driver interface/override functions
98    */
99   void * (*driver_create_fs_state)(struct pipe_context *,
100                                    const struct pipe_shader_state *);
101   void (*driver_bind_fs_state)(struct pipe_context *, void *);
102   void (*driver_delete_fs_state)(struct pipe_context *, void *);
103
104   void (*driver_bind_sampler_states)(struct pipe_context *,
105                                      enum pipe_shader_type,
106                                      unsigned, unsigned, void **);
107
108   void (*driver_set_sampler_views)(struct pipe_context *,
109                                    enum pipe_shader_type shader,
110                                    unsigned start, unsigned count,
111                                    unsigned unbind_num_trailing_slots,
112                                    bool take_ownership,
113                                    struct pipe_sampler_view **);
114
115   void (*driver_set_polygon_stipple)(struct pipe_context *,
116                                      const struct pipe_poly_stipple *);
117
118   struct pipe_context *pipe;
119};
120
121
122/**
123 * Generate the frag shader we'll use for doing polygon stipple.
124 * This will be the user's shader prefixed with a TEX and KIL instruction.
125 */
126static boolean
127generate_pstip_fs(struct pstip_stage *pstip)
128{
129   struct pipe_context *pipe = pstip->pipe;
130   struct pipe_screen *screen = pipe->screen;
131   const struct pipe_shader_state *orig_fs = &pstip->fs->state;
132   /*struct draw_context *draw = pstip->stage.draw;*/
133   struct pipe_shader_state pstip_fs;
134   enum tgsi_file_type wincoord_file;
135
136   wincoord_file = screen->get_param(screen, PIPE_CAP_TGSI_FS_POSITION_IS_SYSVAL) ?
137                   TGSI_FILE_SYSTEM_VALUE : TGSI_FILE_INPUT;
138
139   pstip_fs = *orig_fs; /* copy to init */
140   if (orig_fs->type == PIPE_SHADER_IR_TGSI) {
141      pstip_fs.tokens = util_pstipple_create_fragment_shader(orig_fs->tokens,
142                                                             &pstip->fs->sampler_unit,
143                                                             0,
144                                                             wincoord_file);
145      if (pstip_fs.tokens == NULL)
146         return FALSE;
147   } else {
148      pstip_fs.ir.nir = nir_shader_clone(NULL, orig_fs->ir.nir);
149      nir_lower_pstipple_fs(pstip_fs.ir.nir,
150                            &pstip->fs->sampler_unit, 0, wincoord_file == TGSI_FILE_SYSTEM_VALUE);
151   }
152
153   assert(pstip->fs->sampler_unit < PIPE_MAX_SAMPLERS);
154
155   pstip->fs->pstip_fs = pstip->driver_create_fs_state(pipe, &pstip_fs);
156
157   FREE((void *)pstip_fs.tokens);
158
159   if (!pstip->fs->pstip_fs)
160      return FALSE;
161
162   return TRUE;
163}
164
165
166/**
167 * When we're about to draw our first stipple polygon in a batch, this function
168 * is called to tell the driver to bind our modified fragment shader.
169 */
170static boolean
171bind_pstip_fragment_shader(struct pstip_stage *pstip)
172{
173   struct draw_context *draw = pstip->stage.draw;
174   if (!pstip->fs->pstip_fs &&
175       !generate_pstip_fs(pstip))
176      return FALSE;
177
178   draw->suspend_flushing = TRUE;
179   pstip->driver_bind_fs_state(pstip->pipe, pstip->fs->pstip_fs);
180   draw->suspend_flushing = FALSE;
181   return TRUE;
182}
183
184
185static inline struct pstip_stage *
186pstip_stage( struct draw_stage *stage )
187{
188   return (struct pstip_stage *) stage;
189}
190
191
192static void
193pstip_first_tri(struct draw_stage *stage, struct prim_header *header)
194{
195   struct pstip_stage *pstip = pstip_stage(stage);
196   struct pipe_context *pipe = pstip->pipe;
197   struct draw_context *draw = stage->draw;
198   uint num_samplers;
199   uint num_sampler_views;
200
201   assert(stage->draw->rasterizer->poly_stipple_enable);
202
203   /* bind our fragprog */
204   if (!bind_pstip_fragment_shader(pstip)) {
205      stage->tri = draw_pipe_passthrough_tri;
206      stage->tri(stage, header);
207      return;
208   }
209
210   /* how many samplers? */
211   /* we'll use sampler/texture[pstip->sampler_unit] for the stipple */
212   num_samplers = MAX2(pstip->num_samplers, pstip->fs->sampler_unit + 1);
213   num_sampler_views = MAX2(pstip->num_sampler_views, num_samplers);
214
215   /* plug in our sampler, texture */
216   pstip->state.samplers[pstip->fs->sampler_unit] = pstip->sampler_cso;
217   pipe_sampler_view_reference(&pstip->state.sampler_views[pstip->fs->sampler_unit],
218                               pstip->sampler_view);
219
220   assert(num_samplers <= PIPE_MAX_SAMPLERS);
221
222   draw->suspend_flushing = TRUE;
223
224   pstip->driver_bind_sampler_states(pipe, PIPE_SHADER_FRAGMENT, 0,
225                                     num_samplers, pstip->state.samplers);
226
227   pstip->driver_set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0,
228                                   num_sampler_views, 0, false,
229                                   pstip->state.sampler_views);
230
231   draw->suspend_flushing = FALSE;
232
233   /* now really draw first triangle */
234   stage->tri = draw_pipe_passthrough_tri;
235   stage->tri(stage, header);
236}
237
238
239static void
240pstip_flush(struct draw_stage *stage, unsigned flags)
241{
242   struct draw_context *draw = stage->draw;
243   struct pstip_stage *pstip = pstip_stage(stage);
244   struct pipe_context *pipe = pstip->pipe;
245
246   stage->tri = pstip_first_tri;
247   stage->next->flush( stage->next, flags );
248
249   /* restore original frag shader, texture, sampler state */
250   draw->suspend_flushing = TRUE;
251   pstip->driver_bind_fs_state(pipe, pstip->fs ? pstip->fs->driver_fs : NULL);
252
253   pstip->driver_bind_sampler_states(pipe, PIPE_SHADER_FRAGMENT, 0,
254                                     pstip->num_samplers,
255                                     pstip->state.samplers);
256
257   pstip->driver_set_sampler_views(pipe, PIPE_SHADER_FRAGMENT, 0,
258                                   pstip->num_sampler_views, 0, false,
259                                   pstip->state.sampler_views);
260
261   draw->suspend_flushing = FALSE;
262}
263
264
265static void
266pstip_reset_stipple_counter(struct draw_stage *stage)
267{
268   stage->next->reset_stipple_counter( stage->next );
269}
270
271
272static void
273pstip_destroy(struct draw_stage *stage)
274{
275   struct pstip_stage *pstip = pstip_stage(stage);
276   uint i;
277
278   for (i = 0; i < PIPE_MAX_SHADER_SAMPLER_VIEWS; i++) {
279      pipe_sampler_view_reference(&pstip->state.sampler_views[i], NULL);
280   }
281
282   pstip->pipe->delete_sampler_state(pstip->pipe, pstip->sampler_cso);
283
284   pipe_resource_reference(&pstip->texture, NULL);
285
286   if (pstip->sampler_view) {
287      pipe_sampler_view_reference(&pstip->sampler_view, NULL);
288   }
289
290   draw_free_temp_verts( stage );
291   FREE( stage );
292}
293
294
295/** Create a new polygon stipple drawing stage object */
296static struct pstip_stage *
297draw_pstip_stage(struct draw_context *draw, struct pipe_context *pipe)
298{
299   struct pstip_stage *pstip = CALLOC_STRUCT(pstip_stage);
300   if (!pstip)
301      goto fail;
302
303   pstip->pipe = pipe;
304
305   pstip->stage.draw = draw;
306   pstip->stage.name = "pstip";
307   pstip->stage.next = NULL;
308   pstip->stage.point = draw_pipe_passthrough_point;
309   pstip->stage.line = draw_pipe_passthrough_line;
310   pstip->stage.tri = pstip_first_tri;
311   pstip->stage.flush = pstip_flush;
312   pstip->stage.reset_stipple_counter = pstip_reset_stipple_counter;
313   pstip->stage.destroy = pstip_destroy;
314
315   if (!draw_alloc_temp_verts( &pstip->stage, 8 ))
316      goto fail;
317
318   return pstip;
319
320fail:
321   if (pstip)
322      pstip->stage.destroy( &pstip->stage );
323
324   return NULL;
325}
326
327
328static struct pstip_stage *
329pstip_stage_from_pipe(struct pipe_context *pipe)
330{
331   struct draw_context *draw = (struct draw_context *) pipe->draw;
332   return pstip_stage(draw->pipeline.pstipple);
333}
334
335
336/**
337 * This function overrides the driver's create_fs_state() function and
338 * will typically be called by the gallium frontend.
339 */
340static void *
341pstip_create_fs_state(struct pipe_context *pipe,
342                       const struct pipe_shader_state *fs)
343{
344   struct pstip_stage *pstip = pstip_stage_from_pipe(pipe);
345   struct pstip_fragment_shader *pstipfs = CALLOC_STRUCT(pstip_fragment_shader);
346
347   if (pstipfs) {
348      pstipfs->state.type = fs->type;
349      if (fs->type == PIPE_SHADER_IR_TGSI)
350         pstipfs->state.tokens = tgsi_dup_tokens(fs->tokens);
351      else
352         pstipfs->state.ir.nir = nir_shader_clone(NULL, fs->ir.nir);
353
354      /* pass-through */
355      pstipfs->driver_fs = pstip->driver_create_fs_state(pstip->pipe, fs);
356   }
357
358   return pstipfs;
359}
360
361
362static void
363pstip_bind_fs_state(struct pipe_context *pipe, void *fs)
364{
365   struct pstip_stage *pstip = pstip_stage_from_pipe(pipe);
366   struct pstip_fragment_shader *pstipfs = (struct pstip_fragment_shader *) fs;
367   /* save current */
368   pstip->fs = pstipfs;
369   /* pass-through */
370   pstip->driver_bind_fs_state(pstip->pipe,
371                               (pstipfs ? pstipfs->driver_fs : NULL));
372}
373
374
375static void
376pstip_delete_fs_state(struct pipe_context *pipe, void *fs)
377{
378   struct pstip_stage *pstip = pstip_stage_from_pipe(pipe);
379   struct pstip_fragment_shader *pstipfs = (struct pstip_fragment_shader *) fs;
380   /* pass-through */
381   pstip->driver_delete_fs_state(pstip->pipe, pstipfs->driver_fs);
382
383   if (pstipfs->pstip_fs)
384      pstip->driver_delete_fs_state(pstip->pipe, pstipfs->pstip_fs);
385
386   if (pstipfs->state.type == PIPE_SHADER_IR_TGSI)
387      FREE((void*)pstipfs->state.tokens);
388   else
389      ralloc_free(pstipfs->state.ir.nir);
390   FREE(pstipfs);
391}
392
393
394static void
395pstip_bind_sampler_states(struct pipe_context *pipe,
396                          enum pipe_shader_type shader,
397                          unsigned start, unsigned num, void **sampler)
398{
399   struct pstip_stage *pstip = pstip_stage_from_pipe(pipe);
400   uint i;
401
402   assert(start == 0);
403
404   if (shader == PIPE_SHADER_FRAGMENT) {
405      /* save current */
406      memcpy(pstip->state.samplers, sampler, num * sizeof(void *));
407      for (i = num; i < PIPE_MAX_SAMPLERS; i++) {
408         pstip->state.samplers[i] = NULL;
409      }
410      pstip->num_samplers = num;
411   }
412
413   /* pass-through */
414   pstip->driver_bind_sampler_states(pstip->pipe, shader, start, num, sampler);
415}
416
417
418static void
419pstip_set_sampler_views(struct pipe_context *pipe,
420                        enum pipe_shader_type shader,
421                        unsigned start, unsigned num,
422                        unsigned unbind_num_trailing_slots,
423                        bool take_ownership,
424                        struct pipe_sampler_view **views)
425{
426   struct pstip_stage *pstip = pstip_stage_from_pipe(pipe);
427   uint i;
428
429   if (shader == PIPE_SHADER_FRAGMENT) {
430      /* save current */
431      for (i = 0; i < num; i++) {
432         pipe_sampler_view_reference(&pstip->state.sampler_views[start + i],
433                                     views[i]);
434      }
435      for (; i < num + unbind_num_trailing_slots; i++) {
436         pipe_sampler_view_reference(&pstip->state.sampler_views[start + i],
437                                     NULL);
438      }
439      pstip->num_sampler_views = num;
440   }
441
442   /* pass-through */
443   pstip->driver_set_sampler_views(pstip->pipe, shader, start, num,
444                                   unbind_num_trailing_slots, take_ownership, views);
445}
446
447
448static void
449pstip_set_polygon_stipple(struct pipe_context *pipe,
450                          const struct pipe_poly_stipple *stipple)
451{
452   struct pstip_stage *pstip = pstip_stage_from_pipe(pipe);
453
454   /* save current */
455   pstip->state.stipple = stipple;
456
457   /* pass-through */
458   pstip->driver_set_polygon_stipple(pstip->pipe, stipple);
459
460   util_pstipple_update_stipple_texture(pstip->pipe, pstip->texture,
461                                        pstip->state.stipple->stipple);
462}
463
464
465/**
466 * Called by drivers that want to install this polygon stipple stage
467 * into the draw module's pipeline.  This will not be used if the
468 * hardware has native support for polygon stipple.
469 */
470boolean
471draw_install_pstipple_stage(struct draw_context *draw,
472                            struct pipe_context *pipe)
473{
474   struct pstip_stage *pstip;
475
476   pipe->draw = (void *) draw;
477
478   /*
479    * Create / install pgon stipple drawing / prim stage
480    */
481   pstip = draw_pstip_stage( draw, pipe );
482   if (!pstip)
483      goto fail;
484
485   draw->pipeline.pstipple = &pstip->stage;
486
487   /* save original driver functions */
488   pstip->driver_create_fs_state = pipe->create_fs_state;
489   pstip->driver_bind_fs_state = pipe->bind_fs_state;
490   pstip->driver_delete_fs_state = pipe->delete_fs_state;
491
492   pstip->driver_bind_sampler_states = pipe->bind_sampler_states;
493   pstip->driver_set_sampler_views = pipe->set_sampler_views;
494   pstip->driver_set_polygon_stipple = pipe->set_polygon_stipple;
495
496   /* create special texture, sampler state */
497   pstip->texture = util_pstipple_create_stipple_texture(pipe, NULL);
498   if (!pstip->texture)
499      goto fail;
500
501   pstip->sampler_view = util_pstipple_create_sampler_view(pipe,
502                                                           pstip->texture);
503   if (!pstip->sampler_view)
504      goto fail;
505
506   pstip->sampler_cso = util_pstipple_create_sampler(pipe);
507   if (!pstip->sampler_cso)
508      goto fail;
509
510   /* override the driver's functions */
511   pipe->create_fs_state = pstip_create_fs_state;
512   pipe->bind_fs_state = pstip_bind_fs_state;
513   pipe->delete_fs_state = pstip_delete_fs_state;
514
515   pipe->bind_sampler_states = pstip_bind_sampler_states;
516   pipe->set_sampler_views = pstip_set_sampler_views;
517   pipe->set_polygon_stipple = pstip_set_polygon_stipple;
518
519   return TRUE;
520
521 fail:
522   if (pstip)
523      pstip->stage.destroy( &pstip->stage );
524
525   return FALSE;
526}
527