1 /*
2  * Copyright 2011 Joakim Sindholt <opensource@zhasha.com>
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  * on the rights to use, copy, modify, merge, publish, distribute, sub
8  * license, and/or sell copies of the Software, and to permit persons to whom
9  * the 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 NON-INFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHOR(S) AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM,
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
21  * USE OR OTHER DEALINGS IN THE SOFTWARE. */
22 
23 #ifndef _NINE_SHADER_H_
24 #define _NINE_SHADER_H_
25 
26 #include "d3d9types.h"
27 #include "d3d9caps.h"
28 #include "nine_defines.h"
29 #include "nine_helpers.h"
30 #include "nine_state.h"
31 #include "pipe/p_state.h" /* PIPE_MAX_ATTRIBS */
32 #include "util/u_memory.h"
33 
34 struct NineDevice9;
35 struct NineVertexDeclaration9;
36 struct ureg_program;
37 
38 struct nine_lconstf /* NOTE: both pointers should be FREE'd by the user */
39 {
40     struct nine_range *ranges; /* single MALLOC, but next-pointers valid */
41     float *data;
42 };
43 
44 struct nine_shader_constant_combination;
45 
46 struct nine_shader_info
47 {
48     unsigned type; /* in, PIPE_SHADER_x */
49 
50     uint8_t version; /* (major << 4) | minor */
51 
52     const DWORD *byte_code; /* in, pointer to shader tokens */
53     DWORD        byte_size; /* out, size of data at byte_code */
54 
55     void *cso; /* out, pipe cso for bind_vs,fs_state */
56 
57     uint16_t input_map[PIPE_MAX_ATTRIBS]; /* VS input -> NINE_DECLUSAGE_x */
58     uint8_t num_inputs; /* there may be unused inputs (NINE_DECLUSAGE_NONE) */
59 
60     boolean position_t; /* out, true if VP writes pre-transformed position */
61     boolean point_size; /* out, true if VP writes point size */
62     float point_size_min;
63     float point_size_max;
64 
65     uint32_t sampler_ps1xtypes; /* 2 bits per sampler */
66     uint16_t sampler_mask; /* out, which samplers are being used */
67     uint16_t sampler_mask_shadow; /* in, which samplers use depth compare */
68     uint8_t rt_mask; /* out, which render targets are being written */
69 
70     uint8_t fog_enable;
71     uint8_t fog_mode;
72     uint8_t force_color_in_centroid;
73     uint8_t projected; /* ps 1.1 to 1.3 */
74     uint16_t fetch4;
75 
76     unsigned const_i_base; /* in vec4 (16 byte) units */
77     unsigned const_b_base; /* in vec4 (16 byte) units */
78     unsigned const_used_size;
79 
80     boolean int_slots_used[NINE_MAX_CONST_I];
81     boolean bool_slots_used[NINE_MAX_CONST_B];
82 
83     unsigned const_float_slots;
84     unsigned const_int_slots;
85     unsigned const_bool_slots;
86 
87     unsigned *const_ranges;
88 
89     struct nine_lconstf lconstf; /* out, NOTE: members to be free'd by user */
90     uint8_t bumpenvmat_needed;
91 
92     struct {
93         struct nine_shader_constant_combination* c_combination;
94         boolean (*int_const_added)[NINE_MAX_CONST_I];
95         boolean (*bool_const_added)[NINE_MAX_CONST_B];
96     } add_constants_defs;
97 
98     boolean swvp_on;
99 
100     boolean process_vertices;
101     struct NineVertexDeclaration9 *vdecl_out;
102     struct pipe_stream_output_info so;
103 };
104 
105 struct nine_vs_output_info
106 {
107     BYTE output_semantic;
108     int output_semantic_index;
109     int mask;
110     int output_index;
111 };
112 
113 void *
114 nine_create_shader_with_so_and_destroy(struct ureg_program *p,
115                                        struct pipe_context *pipe,
116                                        const struct pipe_stream_output_info *so);
117 
118 HRESULT
119 nine_translate_shader(struct NineDevice9 *device,
120                       struct nine_shader_info *,
121                       struct pipe_context *);
122 
123 
124 struct nine_shader_variant
125 {
126     struct nine_shader_variant *next;
127     void *cso;
128     unsigned *const_ranges;
129     unsigned const_used_size;
130     uint64_t key;
131 };
132 
133 static inline void *
nine_shader_variant_get(struct nine_shader_variant * list,unsigned ** const_ranges,unsigned * const_used_size,uint64_t key)134 nine_shader_variant_get(struct nine_shader_variant *list,
135                         unsigned **const_ranges,
136                         unsigned *const_used_size,
137                         uint64_t key)
138 {
139     while (list->key != key && list->next)
140         list = list->next;
141     if (list->key == key) {
142         *const_ranges = list->const_ranges;
143         *const_used_size = list->const_used_size;
144         return list->cso;
145     }
146     return NULL;
147 }
148 
149 static inline boolean
nine_shader_variant_add(struct nine_shader_variant * list,uint64_t key,void * cso,unsigned * const_ranges,unsigned const_used_size)150 nine_shader_variant_add(struct nine_shader_variant *list,
151                         uint64_t key, void *cso,
152                         unsigned *const_ranges,
153                         unsigned const_used_size)
154 {
155     while (list->next) {
156         assert(list->key != key);
157         list = list->next;
158     }
159     list->next = MALLOC_STRUCT(nine_shader_variant);
160     if (!list->next)
161         return FALSE;
162     list->next->next = NULL;
163     list->next->key = key;
164     list->next->cso = cso;
165     list->next->const_ranges = const_ranges;
166     list->next->const_used_size = const_used_size;
167     return TRUE;
168 }
169 
170 static inline void
nine_shader_variants_free(struct nine_shader_variant * list)171 nine_shader_variants_free(struct nine_shader_variant *list)
172 {
173     while (list->next) {
174         struct nine_shader_variant *ptr = list->next;
175         list->next = ptr->next;
176         FREE(ptr);
177     }
178 }
179 
180 struct nine_shader_variant_so
181 {
182     struct nine_shader_variant_so *next;
183     struct NineVertexDeclaration9 *vdecl;
184     struct pipe_stream_output_info so;
185     void *cso;
186 };
187 
188 static inline void *
nine_shader_variant_so_get(struct nine_shader_variant_so * list,struct NineVertexDeclaration9 * vdecl,struct pipe_stream_output_info * so)189 nine_shader_variant_so_get(struct nine_shader_variant_so *list,
190                            struct NineVertexDeclaration9 *vdecl,
191                            struct pipe_stream_output_info *so)
192 {
193     while (list->vdecl != vdecl && list->next)
194         list = list->next;
195     if (list->vdecl == vdecl) {
196         *so = list->so;
197         return list->cso;
198     }
199     return NULL;
200 }
201 
202 static inline boolean
nine_shader_variant_so_add(struct nine_shader_variant_so * list,struct NineVertexDeclaration9 * vdecl,struct pipe_stream_output_info * so,void * cso)203 nine_shader_variant_so_add(struct nine_shader_variant_so *list,
204                            struct NineVertexDeclaration9 *vdecl,
205                            struct pipe_stream_output_info *so, void *cso)
206 {
207     if (list->vdecl == NULL) { /* first shader */
208         list->next = NULL;
209         nine_bind(&list->vdecl, vdecl);
210         list->so = *so;
211         list->cso = cso;
212         return TRUE;
213     }
214     while (list->next) {
215         assert(list->vdecl != vdecl);
216         list = list->next;
217     }
218     list->next = MALLOC_STRUCT(nine_shader_variant_so);
219     if (!list->next)
220         return FALSE;
221     list->next->next = NULL;
222     nine_bind(&list->vdecl, vdecl);
223     list->next->so = *so;
224     list->next->cso = cso;
225     return TRUE;
226 }
227 
228 static inline void
nine_shader_variants_so_free(struct nine_shader_variant_so * list)229 nine_shader_variants_so_free(struct nine_shader_variant_so *list)
230 {
231     while (list->next) {
232         struct nine_shader_variant_so *ptr = list->next;
233         list->next = ptr->next;
234         nine_bind(&ptr->vdecl, NULL);
235         FREE(ptr);
236     }
237     if (list->vdecl)
238         nine_bind(&list->vdecl, NULL);
239 }
240 
241 struct nine_shader_constant_combination
242 {
243     struct nine_shader_constant_combination *next;
244     int const_i[NINE_MAX_CONST_I][4];
245     BOOL const_b[NINE_MAX_CONST_B];
246 };
247 
248 #define NINE_MAX_CONSTANT_COMBINATION_VARIANTS 32
249 
250 static inline uint8_t
nine_shader_constant_combination_key(struct nine_shader_constant_combination ** list,boolean * int_slots_used,boolean * bool_slots_used,int * const_i,BOOL * const_b)251 nine_shader_constant_combination_key(struct nine_shader_constant_combination **list,
252                                      boolean *int_slots_used,
253                                      boolean *bool_slots_used,
254                                      int *const_i,
255                                      BOOL *const_b)
256 {
257     int i;
258     uint8_t index = 0;
259     boolean match;
260     struct nine_shader_constant_combination **next_allocate = list, *current = *list;
261 
262     assert(int_slots_used);
263     assert(bool_slots_used);
264     assert(const_i);
265     assert(const_b);
266 
267     while (current) {
268         index++; /* start at 1. 0 is for the variant without constant replacement */
269         match = TRUE;
270         for (i = 0; i < NINE_MAX_CONST_I; ++i) {
271             if (int_slots_used[i])
272                 match &= !memcmp(const_i + 4*i, current->const_i[i], sizeof(current->const_i[0]));
273         }
274         for (i = 0; i < NINE_MAX_CONST_B; ++i) {
275             if (bool_slots_used[i])
276                 match &= const_b[i] == current->const_b[i];
277         }
278         if (match)
279             return index;
280         next_allocate = &current->next;
281         current = current->next;
282     }
283 
284     if (index < NINE_MAX_CONSTANT_COMBINATION_VARIANTS) {
285         *next_allocate = MALLOC_STRUCT(nine_shader_constant_combination);
286         current = *next_allocate;
287         index++;
288         current->next = NULL;
289         memcpy(current->const_i, const_i, sizeof(current->const_i));
290         memcpy(current->const_b, const_b, sizeof(current->const_b));
291         return index;
292     }
293 
294     return 0; /* Too many variants, revert to no replacement */
295 }
296 
297 static inline struct nine_shader_constant_combination *
nine_shader_constant_combination_get(struct nine_shader_constant_combination * list,uint8_t index)298 nine_shader_constant_combination_get(struct nine_shader_constant_combination *list, uint8_t index)
299 {
300     if (index == 0)
301         return NULL;
302     while (index) {
303         assert(list != NULL);
304         index--;
305         if (index == 0)
306             return list;
307         list = list->next;
308     }
309     assert(FALSE);
310     return NULL;
311 }
312 
313 static inline void
nine_shader_constant_combination_free(struct nine_shader_constant_combination * list)314 nine_shader_constant_combination_free(struct nine_shader_constant_combination *list)
315 {
316     if (!list)
317         return;
318 
319     while (list->next) {
320         struct nine_shader_constant_combination *ptr = list->next;
321         list->next = ptr->next;
322         FREE(ptr);
323     }
324 
325     FREE(list);
326 }
327 
328 #endif /* _NINE_SHADER_H_ */
329