• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright © 2015 Intel Corporation
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21  * IN THE SOFTWARE.
22  */
23 
24 #include "nir.h"
25 #include "nir_builder.h"
26 
27 /**
28  * @file
29  *
30  * This pass combines clip and cull distance arrays in separate locations and
31  * colocates them both in VARYING_SLOT_CLIP_DIST0.  It does so by maintaining
32  * two arrays but making them compact and using location_frac to stack them on
33  * top of each other.
34  */
35 
36 /**
37  * Get the length of the clip/cull distance array, looking past
38  * any interface block arrays.
39  */
40 static unsigned
get_unwrapped_array_length(nir_shader * nir,nir_variable * var)41 get_unwrapped_array_length(nir_shader *nir, nir_variable *var)
42 {
43    if (!var)
44       return 0;
45 
46    /* Unwrap GS input and TCS input/output interfaces.  We want the
47     * underlying clip/cull distance array length, not the per-vertex
48     * array length.
49     */
50    const struct glsl_type *type = var->type;
51    if (nir_is_arrayed_io(var, nir->info.stage))
52       type = glsl_get_array_element(type);
53 
54    if (var->data.per_view) {
55       assert(glsl_type_is_array(type));
56       type = glsl_get_array_element(type);
57    }
58 
59    assert(glsl_type_is_array(type));
60 
61    return glsl_get_length(type);
62 }
63 
64 static bool
combine_clip_cull(nir_shader * nir,nir_variable_mode mode,bool store_info)65 combine_clip_cull(nir_shader *nir,
66                   nir_variable_mode mode,
67                   bool store_info)
68 {
69    nir_variable *cull = NULL;
70    nir_variable *clip = NULL;
71 
72    nir_foreach_variable_with_modes(var, nir, mode) {
73       if (var->data.location == VARYING_SLOT_CLIP_DIST0)
74          clip = var;
75 
76       if (var->data.location == VARYING_SLOT_CULL_DIST0)
77          cull = var;
78    }
79 
80    if (!cull && !clip) {
81       /* If this is run after optimizations and the variables have been
82        * eliminated, we should update the shader info, because no other
83        * place does that.
84        */
85       if (store_info) {
86          nir->info.clip_distance_array_size = 0;
87          nir->info.cull_distance_array_size = 0;
88       }
89       return false;
90    }
91 
92    if (!cull && clip) {
93       /* The GLSL IR lowering pass must have converted these to vectors */
94       if (!clip->data.compact)
95          return false;
96 
97       /* If this pass has already run, don't repeat.  We would think that
98        * the combined clip/cull distance array was clip-only and mess up.
99        */
100       if (clip->data.how_declared == nir_var_hidden)
101          return false;
102    }
103 
104    const unsigned clip_array_size = get_unwrapped_array_length(nir, clip);
105    const unsigned cull_array_size = get_unwrapped_array_length(nir, cull);
106 
107    if (store_info) {
108       nir->info.clip_distance_array_size = clip_array_size;
109       nir->info.cull_distance_array_size = cull_array_size;
110    }
111 
112    if (clip) {
113       assert(clip->data.compact);
114       clip->data.how_declared = nir_var_hidden;
115    }
116 
117    if (cull) {
118       assert(cull->data.compact);
119       cull->data.how_declared = nir_var_hidden;
120       cull->data.location = VARYING_SLOT_CLIP_DIST0 + clip_array_size / 4;
121       cull->data.location_frac = clip_array_size % 4;
122    }
123 
124    return true;
125 }
126 
127 bool
nir_lower_clip_cull_distance_arrays(nir_shader * nir)128 nir_lower_clip_cull_distance_arrays(nir_shader *nir)
129 {
130    bool progress = false;
131 
132    if (nir->info.stage <= MESA_SHADER_GEOMETRY ||
133        nir->info.stage == MESA_SHADER_MESH)
134       progress |= combine_clip_cull(nir, nir_var_shader_out, true);
135 
136    if (nir->info.stage > MESA_SHADER_VERTEX &&
137        nir->info.stage <= MESA_SHADER_FRAGMENT) {
138       progress |= combine_clip_cull(nir, nir_var_shader_in,
139                                     nir->info.stage == MESA_SHADER_FRAGMENT);
140    }
141 
142    nir_foreach_function(function, nir) {
143       if (!function->impl)
144          continue;
145 
146       if (progress) {
147          nir_metadata_preserve(function->impl,
148                                nir_metadata_block_index |
149                                nir_metadata_dominance |
150                                nir_metadata_live_ssa_defs |
151                                nir_metadata_loop_analysis);
152       } else {
153          nir_metadata_preserve(function->impl, nir_metadata_all);
154       }
155    }
156 
157    return progress;
158 }
159