d3d9: Properly retrieve an interface pointer in IDirect3DDevice9Impl_GetStreamSource().
[wine] / dlls / d3d9 / shader.c
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 IDirect3DVertexShader9Impl *impl_from_IDirect3DVertexShader9(IDirect3DVertexShader9 *iface)
26 {
27     return CONTAINING_RECORD(iface, IDirect3DVertexShader9Impl, IDirect3DVertexShader9_iface);
28 }
29
30 static HRESULT WINAPI d3d9_vertexshader_QueryInterface(IDirect3DVertexShader9 *iface, REFIID riid, void **object)
31 {
32     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
33
34     if (IsEqualGUID(riid, &IID_IDirect3DVertexShader9)
35             || IsEqualGUID(riid, &IID_IUnknown))
36     {
37         IDirect3DVertexShader9_AddRef(iface);
38         *object = iface;
39         return S_OK;
40     }
41
42     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
43
44     *object = NULL;
45     return E_NOINTERFACE;
46 }
47
48 static ULONG WINAPI d3d9_vertexshader_AddRef(IDirect3DVertexShader9 *iface)
49 {
50     IDirect3DVertexShader9Impl *shader = impl_from_IDirect3DVertexShader9(iface);
51     ULONG refcount = InterlockedIncrement(&shader->ref);
52
53     TRACE("%p increasing refcount to %u.\n", iface, refcount);
54
55     if (refcount == 1)
56     {
57         IDirect3DDevice9Ex_AddRef(shader->parentDevice);
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     IDirect3DVertexShader9Impl *shader = impl_from_IDirect3DVertexShader9(iface);
69     ULONG refcount = InterlockedDecrement(&shader->ref);
70
71     TRACE("%p decreasing refcount to %u.\n", iface, refcount);
72
73     if (!refcount)
74     {
75         IDirect3DDevice9Ex *device = shader->parentDevice;
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     IDirect3DVertexShader9Impl *shader = impl_from_IDirect3DVertexShader9(iface);
91
92     TRACE("iface %p, device %p.\n", iface, device);
93
94     *device = (IDirect3DDevice9 *)shader->parentDevice;
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,
103         void *data, UINT *data_size)
104 {
105     IDirect3DVertexShader9Impl *shader = impl_from_IDirect3DVertexShader9(iface);
106     HRESULT hr;
107
108     TRACE("iface %p, data %p, data_size %p.\n", iface, data, data_size);
109
110     wined3d_mutex_lock();
111     hr = wined3d_shader_get_byte_code(shader->wined3d_shader, data, data_size);
112     wined3d_mutex_unlock();
113
114     return hr;
115 }
116
117 static const IDirect3DVertexShader9Vtbl d3d9_vertexshader_vtbl =
118 {
119     /* IUnknown */
120     d3d9_vertexshader_QueryInterface,
121     d3d9_vertexshader_AddRef,
122     d3d9_vertexshader_Release,
123     /* IDirect3DVertexShader9 */
124     d3d9_vertexshader_GetDevice,
125     d3d9_vertexshader_GetFunction,
126 };
127
128 static void STDMETHODCALLTYPE d3d9_vertexshader_wined3d_object_destroyed(void *parent)
129 {
130     HeapFree(GetProcessHeap(), 0, parent);
131 }
132
133 static const struct wined3d_parent_ops d3d9_vertexshader_wined3d_parent_ops =
134 {
135     d3d9_vertexshader_wined3d_object_destroyed,
136 };
137
138 HRESULT vertexshader_init(IDirect3DVertexShader9Impl *shader, IDirect3DDevice9Impl *device, const DWORD *byte_code)
139 {
140     HRESULT hr;
141
142     shader->ref = 1;
143     shader->IDirect3DVertexShader9_iface.lpVtbl = &d3d9_vertexshader_vtbl;
144
145     wined3d_mutex_lock();
146     hr = wined3d_shader_create_vs(device->wined3d_device, byte_code, NULL,
147             shader, &d3d9_vertexshader_wined3d_parent_ops, &shader->wined3d_shader, 3);
148     wined3d_mutex_unlock();
149     if (FAILED(hr))
150     {
151         WARN("Failed to create wined3d vertex shader, hr %#x.\n", hr);
152         return hr;
153     }
154
155     shader->parentDevice = &device->IDirect3DDevice9Ex_iface;
156     IDirect3DDevice9Ex_AddRef(shader->parentDevice);
157
158     return D3D_OK;
159 }
160
161 IDirect3DVertexShader9Impl *unsafe_impl_from_IDirect3DVertexShader9(IDirect3DVertexShader9 *iface)
162 {
163     if (!iface)
164         return NULL;
165     assert(iface->lpVtbl == &d3d9_vertexshader_vtbl);
166
167     return impl_from_IDirect3DVertexShader9(iface);
168 }
169
170 static inline IDirect3DPixelShader9Impl *impl_from_IDirect3DPixelShader9(IDirect3DPixelShader9 *iface)
171 {
172     return CONTAINING_RECORD(iface, IDirect3DPixelShader9Impl, IDirect3DPixelShader9_iface);
173 }
174
175 static HRESULT WINAPI d3d9_pixelshader_QueryInterface(IDirect3DPixelShader9 *iface, REFIID riid, void **object)
176 {
177     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object);
178
179     if (IsEqualGUID(riid, &IID_IDirect3DPixelShader9)
180             || IsEqualGUID(riid, &IID_IUnknown))
181     {
182         IDirect3DPixelShader9_AddRef(iface);
183         *object = iface;
184         return S_OK;
185     }
186
187     WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid));
188
189     *object = NULL;
190     return E_NOINTERFACE;
191 }
192
193 static ULONG WINAPI d3d9_pixelshader_AddRef(IDirect3DPixelShader9 *iface)
194 {
195     IDirect3DPixelShader9Impl *shader = impl_from_IDirect3DPixelShader9(iface);
196     ULONG refcount = InterlockedIncrement(&shader->ref);
197
198     TRACE("%p increasing refcount to %u.\n", iface, refcount);
199
200     if (refcount == 1)
201     {
202         IDirect3DDevice9Ex_AddRef(shader->parentDevice);
203         wined3d_mutex_lock();
204         wined3d_shader_incref(shader->wined3d_shader);
205         wined3d_mutex_unlock();
206     }
207
208     return refcount;
209 }
210
211 static ULONG WINAPI d3d9_pixelshader_Release(IDirect3DPixelShader9 *iface)
212 {
213     IDirect3DPixelShader9Impl *shader = impl_from_IDirect3DPixelShader9(iface);
214     ULONG refcount = InterlockedDecrement(&shader->ref);
215
216     TRACE("%p decreasing refcount to %u.\n", iface, refcount);
217
218     if (!refcount)
219     {
220         IDirect3DDevice9Ex *device = shader->parentDevice;
221
222         wined3d_mutex_lock();
223         wined3d_shader_decref(shader->wined3d_shader);
224         wined3d_mutex_unlock();
225
226         /* Release the device last, as it may cause the device to be destroyed. */
227         IDirect3DDevice9Ex_Release(device);
228     }
229
230     return refcount;
231 }
232
233 static HRESULT WINAPI d3d9_pixelshader_GetDevice(IDirect3DPixelShader9 *iface,
234         IDirect3DDevice9 **device)
235 {
236     IDirect3DPixelShader9Impl *shader = impl_from_IDirect3DPixelShader9(iface);
237
238     TRACE("iface %p, device %p.\n", iface, device);
239
240     *device = (IDirect3DDevice9 *)shader->parentDevice;
241     IDirect3DDevice9_AddRef(*device);
242
243     TRACE("Returning device %p.\n", *device);
244
245     return D3D_OK;
246 }
247
248 static HRESULT WINAPI d3d9_pixelshader_GetFunction(IDirect3DPixelShader9 *iface, void *data,
249         UINT *data_size)
250 {
251     IDirect3DPixelShader9Impl *shader = impl_from_IDirect3DPixelShader9(iface);
252     HRESULT hr;
253
254     TRACE("iface %p, data %p, data_size %p.\n", iface, data, data_size);
255
256     wined3d_mutex_lock();
257     hr = wined3d_shader_get_byte_code(shader->wined3d_shader, data, data_size);
258     wined3d_mutex_unlock();
259
260     return hr;
261 }
262
263 static const IDirect3DPixelShader9Vtbl d3d9_pixelshader_vtbl =
264 {
265     /* IUnknown */
266     d3d9_pixelshader_QueryInterface,
267     d3d9_pixelshader_AddRef,
268     d3d9_pixelshader_Release,
269     /* IDirect3DPixelShader9 */
270     d3d9_pixelshader_GetDevice,
271     d3d9_pixelshader_GetFunction,
272 };
273
274 static void STDMETHODCALLTYPE d3d9_pixelshader_wined3d_object_destroyed(void *parent)
275 {
276     HeapFree(GetProcessHeap(), 0, parent);
277 }
278
279 static const struct wined3d_parent_ops d3d9_pixelshader_wined3d_parent_ops =
280 {
281     d3d9_pixelshader_wined3d_object_destroyed,
282 };
283
284 HRESULT pixelshader_init(IDirect3DPixelShader9Impl *shader, IDirect3DDevice9Impl *device, const DWORD *byte_code)
285 {
286     HRESULT hr;
287
288     shader->ref = 1;
289     shader->IDirect3DPixelShader9_iface.lpVtbl = &d3d9_pixelshader_vtbl;
290
291     wined3d_mutex_lock();
292     hr = wined3d_shader_create_ps(device->wined3d_device, byte_code, NULL, shader,
293             &d3d9_pixelshader_wined3d_parent_ops, &shader->wined3d_shader, 3);
294     wined3d_mutex_unlock();
295     if (FAILED(hr))
296     {
297         WARN("Failed to created wined3d pixel shader, hr %#x.\n", hr);
298         return hr;
299     }
300
301     shader->parentDevice = &device->IDirect3DDevice9Ex_iface;
302     IDirect3DDevice9Ex_AddRef(shader->parentDevice);
303
304     return D3D_OK;
305 }
306
307 IDirect3DPixelShader9Impl *unsafe_impl_from_IDirect3DPixelShader9(IDirect3DPixelShader9 *iface)
308 {
309     if (!iface)
310         return NULL;
311     assert(iface->lpVtbl == &d3d9_pixelshader_vtbl);
312
313     return impl_from_IDirect3DPixelShader9(iface);
314 }