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