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
34struct NineDevice9;
35struct NineVertexDeclaration9;
36struct ureg_program;
37
38struct 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
44struct nine_shader_constant_combination;
45
46struct 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
105struct nine_vs_output_info
106{
107    BYTE output_semantic;
108    int output_semantic_index;
109    int mask;
110    int output_index;
111};
112
113void *
114nine_create_shader_with_so_and_destroy(struct ureg_program *p,
115                                       struct pipe_context *pipe,
116                                       const struct pipe_stream_output_info *so);
117
118HRESULT
119nine_translate_shader(struct NineDevice9 *device,
120                      struct nine_shader_info *,
121                      struct pipe_context *);
122
123
124struct 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
133static inline void *
134nine_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
149static inline boolean
150nine_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
170static inline void
171nine_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
180struct 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
188static inline void *
189nine_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
202static inline boolean
203nine_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
228static inline void
229nine_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
241struct 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
250static inline uint8_t
251nine_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
297static inline struct nine_shader_constant_combination *
298nine_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
313static inline void
314nine_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