• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "nine_helpers.h"
24 #include "nine_shader.h"
25 
26 #include "pixelshader9.h"
27 
28 #include "device9.h"
29 #include "pipe/p_context.h"
30 
31 #define DBG_CHANNEL DBG_PIXELSHADER
32 
33 HRESULT
NinePixelShader9_ctor(struct NinePixelShader9 * This,struct NineUnknownParams * pParams,const DWORD * pFunction,void * cso)34 NinePixelShader9_ctor( struct NinePixelShader9 *This,
35                        struct NineUnknownParams *pParams,
36                        const DWORD *pFunction, void *cso )
37 {
38     struct NineDevice9 *device;
39     struct nine_shader_info info;
40     struct pipe_context *pipe;
41     HRESULT hr;
42 
43     DBG("This=%p pParams=%p pFunction=%p cso=%p\n", This, pParams, pFunction, cso);
44 
45     hr = NineUnknown_ctor(&This->base, pParams);
46     if (FAILED(hr))
47         return hr;
48 
49     if (cso) {
50         This->ff_cso = cso;
51         return D3D_OK;
52     }
53     device = This->base.device;
54 
55     info.type = PIPE_SHADER_FRAGMENT;
56     info.byte_code = pFunction;
57     info.const_i_base = NINE_CONST_I_BASE(NINE_MAX_CONST_F_PS3) / 16;
58     info.const_b_base = NINE_CONST_B_BASE(NINE_MAX_CONST_F_PS3) / 16;
59     info.sampler_mask_shadow = 0x0;
60     info.fetch4 = 0x0;
61     info.force_color_in_centroid = 0;
62     info.sampler_ps1xtypes = 0x0;
63     info.fog_enable = 0;
64     info.projected = 0;
65     info.alpha_test_emulation = 0;
66     info.color_flatshade = 0;
67     info.add_constants_defs.c_combination = NULL;
68     info.add_constants_defs.int_const_added = NULL;
69     info.add_constants_defs.bool_const_added = NULL;
70     info.process_vertices = false;
71     info.swvp_on = false;
72 
73     pipe = nine_context_get_pipe_acquire(device);
74     hr = nine_translate_shader(device, &info, pipe);
75     nine_context_get_pipe_release(device);
76     if (FAILED(hr))
77         return hr;
78     This->byte_code.version = info.version;
79 
80     This->byte_code.tokens = mem_dup(pFunction, info.byte_size);
81     if (!This->byte_code.tokens)
82         return E_OUTOFMEMORY;
83     This->byte_code.size = info.byte_size;
84 
85     This->variant.cso = info.cso;
86     This->variant.const_ranges = info.const_ranges;
87     This->variant.const_used_size = info.const_used_size;
88     This->last_cso = info.cso;
89     This->last_const_ranges = info.const_ranges;
90     This->last_const_used_size = info.const_used_size;
91     This->last_key = 0;
92 
93     This->sampler_mask = info.sampler_mask;
94     This->rt_mask = info.rt_mask;
95     This->bumpenvmat_needed = info.bumpenvmat_needed;
96 
97     memcpy(This->int_slots_used, info.int_slots_used, sizeof(This->int_slots_used));
98     memcpy(This->bool_slots_used, info.bool_slots_used, sizeof(This->bool_slots_used));
99 
100     This->const_int_slots = info.const_int_slots;
101     This->const_bool_slots = info.const_bool_slots;
102 
103     This->c_combinations = NULL;
104 
105     /* no constant relative addressing for ps */
106     assert(info.lconstf.data == NULL);
107     assert(info.lconstf.ranges == NULL);
108 
109     return D3D_OK;
110 }
111 
112 void
NinePixelShader9_dtor(struct NinePixelShader9 * This)113 NinePixelShader9_dtor( struct NinePixelShader9 *This )
114 {
115     DBG("This=%p\n", This);
116 
117     if (This->base.device) {
118         struct pipe_context *pipe = nine_context_get_pipe_multithread(This->base.device);
119         struct nine_shader_variant *var = &This->variant;
120 
121         do {
122             if (var->cso) {
123                 if (This->base.device->context.cso_shader.ps == var->cso) {
124                     /* unbind because it is illegal to delete something bound */
125                     pipe->bind_fs_state(pipe, NULL);
126                     /* This will rebind cso_shader.ps in case somehow actually
127                      * an identical shader with same cso is bound */
128                     This->base.device->context.commit |= NINE_STATE_COMMIT_PS;
129                 }
130                 pipe->delete_fs_state(pipe, var->cso);
131                 FREE(var->const_ranges);
132             }
133             var = var->next;
134         } while (var);
135 
136         if (This->ff_cso) {
137             if (This->ff_cso == This->base.device->context.cso_shader.ps) {
138                 pipe->bind_fs_state(pipe, NULL);
139                 This->base.device->context.commit |= NINE_STATE_COMMIT_PS;
140             }
141             pipe->delete_fs_state(pipe, This->ff_cso);
142         }
143     }
144     nine_shader_variants_free(&This->variant);
145 
146     nine_shader_constant_combination_free(This->c_combinations);
147 
148     FREE((void *)This->byte_code.tokens); /* const_cast */
149 
150     NineUnknown_dtor(&This->base);
151 }
152 
153 HRESULT NINE_WINAPI
NinePixelShader9_GetFunction(struct NinePixelShader9 * This,void * pData,UINT * pSizeOfData)154 NinePixelShader9_GetFunction( struct NinePixelShader9 *This,
155                               void *pData,
156                               UINT *pSizeOfData )
157 {
158     DBG("This=%p pData=%p pSizeOfData=%p\n", This, pData, pSizeOfData);
159 
160     user_assert(pSizeOfData, D3DERR_INVALIDCALL);
161 
162     if (!pData) {
163         *pSizeOfData = This->byte_code.size;
164         return D3D_OK;
165     }
166     user_assert(*pSizeOfData >= This->byte_code.size, D3DERR_INVALIDCALL);
167 
168     memcpy(pData, This->byte_code.tokens, This->byte_code.size);
169 
170     return D3D_OK;
171 }
172 
173 void *
NinePixelShader9_GetVariant(struct NinePixelShader9 * This,unsigned ** const_ranges,unsigned * const_used_size)174 NinePixelShader9_GetVariant( struct NinePixelShader9 *This,
175                              unsigned **const_ranges,
176                              unsigned *const_used_size )
177 {
178     /* GetVariant is called from nine_context, thus we can
179      * get pipe directly */
180     struct pipe_context *pipe = This->base.device->context.pipe;
181     void *cso;
182     uint64_t key;
183 
184     key = This->next_key;
185     if (key == This->last_key) {
186         *const_ranges = This->last_const_ranges;
187         *const_used_size = This->last_const_used_size;
188         return This->last_cso;
189     }
190 
191     cso = nine_shader_variant_get(&This->variant, const_ranges, const_used_size, key);
192     if (!cso) {
193         struct NineDevice9 *device = This->base.device;
194         struct nine_shader_info info;
195         HRESULT hr;
196 
197         info.type = PIPE_SHADER_FRAGMENT;
198         info.const_i_base = NINE_CONST_I_BASE(NINE_MAX_CONST_F_PS3) / 16;
199         info.const_b_base = NINE_CONST_B_BASE(NINE_MAX_CONST_F_PS3) / 16;
200         info.byte_code = This->byte_code.tokens;
201         info.sampler_mask_shadow = key & 0xffff;
202         /* intended overlap with sampler_mask_shadow */
203         if (unlikely(This->byte_code.version < 0x20)) {
204             if (This->byte_code.version < 0x14) {
205                 info.sampler_ps1xtypes = (key >> 4) & 0xff;
206                 info.projected = (key >> 12) & 0xff;
207             } else {
208                 info.sampler_ps1xtypes = (key >> 6) & 0xfff;
209                 info.projected = 0;
210             }
211         } else {
212             info.sampler_ps1xtypes = 0;
213             info.projected = 0;
214         }
215         info.fog_enable = device->context.rs[D3DRS_FOGENABLE];
216         info.fog_mode = device->context.rs[D3DRS_FOGTABLEMODE];
217         info.zfog = device->context.zfog;
218         info.add_constants_defs.c_combination =
219             nine_shader_constant_combination_get(This->c_combinations, (key >> 24) & 0xff);
220         info.add_constants_defs.int_const_added = &This->int_slots_used;
221         info.add_constants_defs.bool_const_added = &This->bool_slots_used;
222         info.fetch4 = (key >> 32) & 0xffff;
223         info.force_color_in_centroid = (key >> 48) & 1;
224         info.alpha_test_emulation = (key >> 49) & 0x7;
225         info.color_flatshade = (key >> 52) & 1;
226         info.force_color_in_centroid &= !info.color_flatshade; /* centroid doesn't make sense with flatshade */
227         info.process_vertices = false;
228         info.swvp_on = false;
229 
230         hr = nine_translate_shader(This->base.device, &info, pipe);
231         if (FAILED(hr))
232             return NULL;
233         nine_shader_variant_add(&This->variant, key, info.cso,
234                                 info.const_ranges, info.const_used_size);
235         cso = info.cso;
236         *const_ranges = info.const_ranges;
237         *const_used_size = info.const_used_size;
238     }
239 
240     This->last_key = key;
241     This->last_cso = cso;
242     This->last_const_ranges = *const_ranges;
243     This->last_const_used_size = *const_used_size;
244 
245     return cso;
246 }
247 
248 IDirect3DPixelShader9Vtbl NinePixelShader9_vtable = {
249     (void *)NineUnknown_QueryInterface,
250     (void *)NineUnknown_AddRef,
251     (void *)NineUnknown_Release,
252     (void *)NineUnknown_GetDevice,
253     (void *)NinePixelShader9_GetFunction
254 };
255 
256 static const GUID *NinePixelShader9_IIDs[] = {
257     &IID_IDirect3DPixelShader9,
258     &IID_IUnknown,
259     NULL
260 };
261 
262 HRESULT
NinePixelShader9_new(struct NineDevice9 * pDevice,struct NinePixelShader9 ** ppOut,const DWORD * pFunction,void * cso)263 NinePixelShader9_new( struct NineDevice9 *pDevice,
264                       struct NinePixelShader9 **ppOut,
265                       const DWORD *pFunction, void *cso )
266 {
267     if (cso) { /* ff shader. Needs to start with bind count */
268         NINE_DEVICE_CHILD_BIND_NEW(PixelShader9, ppOut, pDevice, pFunction, cso);
269     } else {
270         NINE_DEVICE_CHILD_NEW(PixelShader9, ppOut, pDevice, pFunction, cso);
271     }
272 }
273