xref: /reactos/dll/directx/wine/d3d9/shader.c (revision 19b18ce2)
1 /*
2  * Copyright 2002-2003 Jason Edmeades
3  *                     Raphael Junqueira
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18  */
19 
20 #include "config.h"
21 #include "d3d9_private.h"
22 
23 WINE_DEFAULT_DEBUG_CHANNEL(d3d9);
24 
25 static inline struct d3d9_vertexshader *impl_from_IDirect3DVertexShader9(IDirect3DVertexShader9 *iface)
26 {
27     return CONTAINING_RECORD(iface, struct d3d9_vertexshader, IDirect3DVertexShader9_iface);
28 }
29 
30 static HRESULT WINAPI d3d9_vertexshader_QueryInterface(IDirect3DVertexShader9 *iface, REFIID riid, void **out)
31 {
32     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
33 
34     if (IsEqualGUID(riid, &IID_IDirect3DVertexShader9)
35             || IsEqualGUID(riid, &IID_IUnknown))
36     {
37         IDirect3DVertexShader9_AddRef(iface);
38         *out = iface;
39         return S_OK;
40     }
41 
42     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
43 
44     *out = NULL;
45     return E_NOINTERFACE;
46 }
47 
48 static ULONG WINAPI d3d9_vertexshader_AddRef(IDirect3DVertexShader9 *iface)
49 {
50     struct d3d9_vertexshader *shader = impl_from_IDirect3DVertexShader9(iface);
51     ULONG refcount = InterlockedIncrement(&shader->refcount);
52 
53     TRACE("%p increasing refcount to %u.\n", iface, refcount);
54 
55     if (refcount == 1)
56     {
57         IDirect3DDevice9Ex_AddRef(shader->parent_device);
58         wined3d_mutex_lock();
59         wined3d_shader_incref(shader->wined3d_shader);
60         wined3d_mutex_unlock();
61     }
62 
63     return refcount;
64 }
65 
66 static ULONG WINAPI d3d9_vertexshader_Release(IDirect3DVertexShader9 *iface)
67 {
68     struct d3d9_vertexshader *shader = impl_from_IDirect3DVertexShader9(iface);
69     ULONG refcount = InterlockedDecrement(&shader->refcount);
70 
71     TRACE("%p decreasing refcount to %u.\n", iface, refcount);
72 
73     if (!refcount)
74     {
75         IDirect3DDevice9Ex *device = shader->parent_device;
76 
77         wined3d_mutex_lock();
78         wined3d_shader_decref(shader->wined3d_shader);
79         wined3d_mutex_unlock();
80 
81         /* Release the device last, as it may cause the device to be destroyed. */
82         IDirect3DDevice9Ex_Release(device);
83     }
84 
85     return refcount;
86 }
87 
88 static HRESULT WINAPI d3d9_vertexshader_GetDevice(IDirect3DVertexShader9 *iface, IDirect3DDevice9 **device)
89 {
90     struct d3d9_vertexshader *shader = impl_from_IDirect3DVertexShader9(iface);
91 
92     TRACE("iface %p, device %p.\n", iface, device);
93 
94     *device = (IDirect3DDevice9 *)shader->parent_device;
95     IDirect3DDevice9_AddRef(*device);
96 
97     TRACE("Returning device %p.\n", *device);
98 
99     return D3D_OK;
100 }
101 
102 static HRESULT WINAPI d3d9_vertexshader_GetFunction(IDirect3DVertexShader9 *iface, void *data, UINT *data_size)
103 {
104     struct d3d9_vertexshader *shader = impl_from_IDirect3DVertexShader9(iface);
105     HRESULT hr;
106 
107     TRACE("iface %p, data %p, data_size %p.\n", iface, data, data_size);
108 
109     wined3d_mutex_lock();
110     hr = wined3d_shader_get_byte_code(shader->wined3d_shader, data, data_size);
111     wined3d_mutex_unlock();
112 
113     return hr;
114 }
115 
116 static const IDirect3DVertexShader9Vtbl d3d9_vertexshader_vtbl =
117 {
118     /* IUnknown */
119     d3d9_vertexshader_QueryInterface,
120     d3d9_vertexshader_AddRef,
121     d3d9_vertexshader_Release,
122     /* IDirect3DVertexShader9 */
123     d3d9_vertexshader_GetDevice,
124     d3d9_vertexshader_GetFunction,
125 };
126 
127 static void STDMETHODCALLTYPE d3d9_vertexshader_wined3d_object_destroyed(void *parent)
128 {
129     heap_free(parent);
130 }
131 
132 static const struct wined3d_parent_ops d3d9_vertexshader_wined3d_parent_ops =
133 {
134     d3d9_vertexshader_wined3d_object_destroyed,
135 };
136 
137 HRESULT vertexshader_init(struct d3d9_vertexshader *shader, struct d3d9_device *device, const DWORD *byte_code)
138 {
139     struct wined3d_shader_desc desc;
140     HRESULT hr;
141 
142     shader->refcount = 1;
143     shader->IDirect3DVertexShader9_iface.lpVtbl = &d3d9_vertexshader_vtbl;
144 
145     desc.byte_code = byte_code;
146     desc.byte_code_size = ~(size_t)0;
147     desc.format = WINED3D_SHADER_BYTE_CODE_FORMAT_SM1;
148     desc.input_signature.element_count = 0;
149     desc.output_signature.element_count = 0;
150     desc.patch_constant_signature.element_count = 0;
151     desc.max_version = 3;
152 
153     wined3d_mutex_lock();
154     hr = wined3d_shader_create_vs(device->wined3d_device, &desc, shader,
155             &d3d9_vertexshader_wined3d_parent_ops, &shader->wined3d_shader);
156     wined3d_mutex_unlock();
157     if (FAILED(hr))
158     {
159         WARN("Failed to create wined3d vertex shader, hr %#x.\n", hr);
160         return hr;
161     }
162 
163     shader->parent_device = &device->IDirect3DDevice9Ex_iface;
164     IDirect3DDevice9Ex_AddRef(shader->parent_device);
165 
166     return D3D_OK;
167 }
168 
169 struct d3d9_vertexshader *unsafe_impl_from_IDirect3DVertexShader9(IDirect3DVertexShader9 *iface)
170 {
171     if (!iface)
172         return NULL;
173     if (iface->lpVtbl != &d3d9_vertexshader_vtbl)
174         WARN("Vertex shader %p with the wrong vtbl %p\n", iface, iface->lpVtbl);
175 
176     return impl_from_IDirect3DVertexShader9(iface);
177 }
178 
179 static inline struct d3d9_pixelshader *impl_from_IDirect3DPixelShader9(IDirect3DPixelShader9 *iface)
180 {
181     return CONTAINING_RECORD(iface, struct d3d9_pixelshader, IDirect3DPixelShader9_iface);
182 }
183 
184 static HRESULT WINAPI d3d9_pixelshader_QueryInterface(IDirect3DPixelShader9 *iface, REFIID riid, void **out)
185 {
186     TRACE("iface %p, riid %s, out %p.\n", iface, debugstr_guid(riid), out);
187 
188     if (IsEqualGUID(riid, &IID_IDirect3DPixelShader9)
189             || IsEqualGUID(riid, &IID_IUnknown))
190     {
191         IDirect3DPixelShader9_AddRef(iface);
192         *out = iface;
193         return S_OK;
194     }
195 
196     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
197 
198     *out = NULL;
199     return E_NOINTERFACE;
200 }
201 
202 static ULONG WINAPI d3d9_pixelshader_AddRef(IDirect3DPixelShader9 *iface)
203 {
204     struct d3d9_pixelshader *shader = impl_from_IDirect3DPixelShader9(iface);
205     ULONG refcount = InterlockedIncrement(&shader->refcount);
206 
207     TRACE("%p increasing refcount to %u.\n", iface, refcount);
208 
209     if (refcount == 1)
210     {
211         IDirect3DDevice9Ex_AddRef(shader->parent_device);
212         wined3d_mutex_lock();
213         wined3d_shader_incref(shader->wined3d_shader);
214         wined3d_mutex_unlock();
215     }
216 
217     return refcount;
218 }
219 
220 static ULONG WINAPI d3d9_pixelshader_Release(IDirect3DPixelShader9 *iface)
221 {
222     struct d3d9_pixelshader *shader = impl_from_IDirect3DPixelShader9(iface);
223     ULONG refcount = InterlockedDecrement(&shader->refcount);
224 
225     TRACE("%p decreasing refcount to %u.\n", iface, refcount);
226 
227     if (!refcount)
228     {
229         IDirect3DDevice9Ex *device = shader->parent_device;
230 
231         wined3d_mutex_lock();
232         wined3d_shader_decref(shader->wined3d_shader);
233         wined3d_mutex_unlock();
234 
235         /* Release the device last, as it may cause the device to be destroyed. */
236         IDirect3DDevice9Ex_Release(device);
237     }
238 
239     return refcount;
240 }
241 
242 static HRESULT WINAPI d3d9_pixelshader_GetDevice(IDirect3DPixelShader9 *iface, IDirect3DDevice9 **device)
243 {
244     struct d3d9_pixelshader *shader = impl_from_IDirect3DPixelShader9(iface);
245 
246     TRACE("iface %p, device %p.\n", iface, device);
247 
248     *device = (IDirect3DDevice9 *)shader->parent_device;
249     IDirect3DDevice9_AddRef(*device);
250 
251     TRACE("Returning device %p.\n", *device);
252 
253     return D3D_OK;
254 }
255 
256 static HRESULT WINAPI d3d9_pixelshader_GetFunction(IDirect3DPixelShader9 *iface, void *data, UINT *data_size)
257 {
258     struct d3d9_pixelshader *shader = impl_from_IDirect3DPixelShader9(iface);
259     HRESULT hr;
260 
261     TRACE("iface %p, data %p, data_size %p.\n", iface, data, data_size);
262 
263     wined3d_mutex_lock();
264     hr = wined3d_shader_get_byte_code(shader->wined3d_shader, data, data_size);
265     wined3d_mutex_unlock();
266 
267     return hr;
268 }
269 
270 static const IDirect3DPixelShader9Vtbl d3d9_pixelshader_vtbl =
271 {
272     /* IUnknown */
273     d3d9_pixelshader_QueryInterface,
274     d3d9_pixelshader_AddRef,
275     d3d9_pixelshader_Release,
276     /* IDirect3DPixelShader9 */
277     d3d9_pixelshader_GetDevice,
278     d3d9_pixelshader_GetFunction,
279 };
280 
281 static void STDMETHODCALLTYPE d3d9_pixelshader_wined3d_object_destroyed(void *parent)
282 {
283     heap_free(parent);
284 }
285 
286 static const struct wined3d_parent_ops d3d9_pixelshader_wined3d_parent_ops =
287 {
288     d3d9_pixelshader_wined3d_object_destroyed,
289 };
290 
291 HRESULT pixelshader_init(struct d3d9_pixelshader *shader, struct d3d9_device *device, const DWORD *byte_code)
292 {
293     struct wined3d_shader_desc desc;
294     HRESULT hr;
295 
296     shader->refcount = 1;
297     shader->IDirect3DPixelShader9_iface.lpVtbl = &d3d9_pixelshader_vtbl;
298 
299     desc.byte_code = byte_code;
300     desc.byte_code_size = ~(size_t)0;
301     desc.format = WINED3D_SHADER_BYTE_CODE_FORMAT_SM1;
302     desc.input_signature.element_count = 0;
303     desc.output_signature.element_count = 0;
304     desc.patch_constant_signature.element_count = 0;
305     desc.max_version = 3;
306 
307     wined3d_mutex_lock();
308     hr = wined3d_shader_create_ps(device->wined3d_device, &desc, shader,
309             &d3d9_pixelshader_wined3d_parent_ops, &shader->wined3d_shader);
310     wined3d_mutex_unlock();
311     if (FAILED(hr))
312     {
313         WARN("Failed to created wined3d pixel shader, hr %#x.\n", hr);
314         return hr;
315     }
316 
317     shader->parent_device = &device->IDirect3DDevice9Ex_iface;
318     IDirect3DDevice9Ex_AddRef(shader->parent_device);
319 
320     return D3D_OK;
321 }
322 
323 struct d3d9_pixelshader *unsafe_impl_from_IDirect3DPixelShader9(IDirect3DPixelShader9 *iface)
324 {
325     if (!iface)
326         return NULL;
327     if (iface->lpVtbl != &d3d9_pixelshader_vtbl)
328         WARN("Pixel shader %p with the wrong vtbl %p\n", iface, iface->lpVtbl);
329 
330     return impl_from_IDirect3DPixelShader9(iface);
331 }
332