|  | /* | 
|  | * Copyright 2002-2003 Jason Edmeades | 
|  | *                     Raphael Junqueira | 
|  | * | 
|  | * This library is free software; you can redistribute it and/or | 
|  | * modify it under the terms of the GNU Lesser General Public | 
|  | * License as published by the Free Software Foundation; either | 
|  | * version 2.1 of the License, or (at your option) any later version. | 
|  | * | 
|  | * This library is distributed in the hope that it will be useful, | 
|  | * but WITHOUT ANY WARRANTY; without even the implied warranty of | 
|  | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|  | * Lesser General Public License for more details. | 
|  | * | 
|  | * You should have received a copy of the GNU Lesser General Public | 
|  | * License along with this library; if not, write to the Free Software | 
|  | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include <assert.h> | 
|  | #include "d3d9_private.h" | 
|  |  | 
|  | WINE_DEFAULT_DEBUG_CHANNEL(d3d9); | 
|  |  | 
|  | static inline IDirect3DVertexShader9Impl *impl_from_IDirect3DVertexShader9(IDirect3DVertexShader9 *iface) | 
|  | { | 
|  | return CONTAINING_RECORD(iface, IDirect3DVertexShader9Impl, IDirect3DVertexShader9_iface); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI d3d9_vertexshader_QueryInterface(IDirect3DVertexShader9 *iface, REFIID riid, void **object) | 
|  | { | 
|  | TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object); | 
|  |  | 
|  | if (IsEqualGUID(riid, &IID_IDirect3DVertexShader9) | 
|  | || IsEqualGUID(riid, &IID_IUnknown)) | 
|  | { | 
|  | IDirect3DVertexShader9_AddRef(iface); | 
|  | *object = iface; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); | 
|  |  | 
|  | *object = NULL; | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI d3d9_vertexshader_AddRef(IDirect3DVertexShader9 *iface) | 
|  | { | 
|  | IDirect3DVertexShader9Impl *shader = impl_from_IDirect3DVertexShader9(iface); | 
|  | ULONG refcount = InterlockedIncrement(&shader->ref); | 
|  |  | 
|  | TRACE("%p increasing refcount to %u.\n", iface, refcount); | 
|  |  | 
|  | if (refcount == 1) | 
|  | { | 
|  | IDirect3DDevice9Ex_AddRef(shader->parentDevice); | 
|  | wined3d_mutex_lock(); | 
|  | wined3d_shader_incref(shader->wined3d_shader); | 
|  | wined3d_mutex_unlock(); | 
|  | } | 
|  |  | 
|  | return refcount; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI d3d9_vertexshader_Release(IDirect3DVertexShader9 *iface) | 
|  | { | 
|  | IDirect3DVertexShader9Impl *shader = impl_from_IDirect3DVertexShader9(iface); | 
|  | ULONG refcount = InterlockedDecrement(&shader->ref); | 
|  |  | 
|  | TRACE("%p decreasing refcount to %u.\n", iface, refcount); | 
|  |  | 
|  | if (!refcount) | 
|  | { | 
|  | IDirect3DDevice9Ex *device = shader->parentDevice; | 
|  |  | 
|  | wined3d_mutex_lock(); | 
|  | wined3d_shader_decref(shader->wined3d_shader); | 
|  | wined3d_mutex_unlock(); | 
|  |  | 
|  | /* Release the device last, as it may cause the device to be destroyed. */ | 
|  | IDirect3DDevice9Ex_Release(device); | 
|  | } | 
|  |  | 
|  | return refcount; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI d3d9_vertexshader_GetDevice(IDirect3DVertexShader9 *iface, IDirect3DDevice9 **device) | 
|  | { | 
|  | IDirect3DVertexShader9Impl *shader = impl_from_IDirect3DVertexShader9(iface); | 
|  |  | 
|  | TRACE("iface %p, device %p.\n", iface, device); | 
|  |  | 
|  | *device = (IDirect3DDevice9 *)shader->parentDevice; | 
|  | IDirect3DDevice9_AddRef(*device); | 
|  |  | 
|  | TRACE("Returning device %p.\n", *device); | 
|  |  | 
|  | return D3D_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI d3d9_vertexshader_GetFunction(IDirect3DVertexShader9 *iface, | 
|  | void *data, UINT *data_size) | 
|  | { | 
|  | IDirect3DVertexShader9Impl *shader = impl_from_IDirect3DVertexShader9(iface); | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("iface %p, data %p, data_size %p.\n", iface, data, data_size); | 
|  |  | 
|  | wined3d_mutex_lock(); | 
|  | hr = wined3d_shader_get_byte_code(shader->wined3d_shader, data, data_size); | 
|  | wined3d_mutex_unlock(); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static const IDirect3DVertexShader9Vtbl d3d9_vertexshader_vtbl = | 
|  | { | 
|  | /* IUnknown */ | 
|  | d3d9_vertexshader_QueryInterface, | 
|  | d3d9_vertexshader_AddRef, | 
|  | d3d9_vertexshader_Release, | 
|  | /* IDirect3DVertexShader9 */ | 
|  | d3d9_vertexshader_GetDevice, | 
|  | d3d9_vertexshader_GetFunction, | 
|  | }; | 
|  |  | 
|  | static void STDMETHODCALLTYPE d3d9_vertexshader_wined3d_object_destroyed(void *parent) | 
|  | { | 
|  | HeapFree(GetProcessHeap(), 0, parent); | 
|  | } | 
|  |  | 
|  | static const struct wined3d_parent_ops d3d9_vertexshader_wined3d_parent_ops = | 
|  | { | 
|  | d3d9_vertexshader_wined3d_object_destroyed, | 
|  | }; | 
|  |  | 
|  | HRESULT vertexshader_init(IDirect3DVertexShader9Impl *shader, IDirect3DDevice9Impl *device, const DWORD *byte_code) | 
|  | { | 
|  | HRESULT hr; | 
|  |  | 
|  | shader->ref = 1; | 
|  | shader->IDirect3DVertexShader9_iface.lpVtbl = &d3d9_vertexshader_vtbl; | 
|  |  | 
|  | wined3d_mutex_lock(); | 
|  | hr = wined3d_shader_create_vs(device->wined3d_device, byte_code, NULL, | 
|  | shader, &d3d9_vertexshader_wined3d_parent_ops, &shader->wined3d_shader); | 
|  | wined3d_mutex_unlock(); | 
|  | if (FAILED(hr)) | 
|  | { | 
|  | WARN("Failed to create wined3d vertex shader, hr %#x.\n", hr); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | shader->parentDevice = &device->IDirect3DDevice9Ex_iface; | 
|  | IDirect3DDevice9Ex_AddRef(shader->parentDevice); | 
|  |  | 
|  | return D3D_OK; | 
|  | } | 
|  |  | 
|  | IDirect3DVertexShader9Impl *unsafe_impl_from_IDirect3DVertexShader9(IDirect3DVertexShader9 *iface) | 
|  | { | 
|  | if (!iface) | 
|  | return NULL; | 
|  | assert(iface->lpVtbl == &d3d9_vertexshader_vtbl); | 
|  |  | 
|  | return impl_from_IDirect3DVertexShader9(iface); | 
|  | } | 
|  |  | 
|  | static inline IDirect3DPixelShader9Impl *impl_from_IDirect3DPixelShader9(IDirect3DPixelShader9 *iface) | 
|  | { | 
|  | return CONTAINING_RECORD(iface, IDirect3DPixelShader9Impl, IDirect3DPixelShader9_iface); | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI d3d9_pixelshader_QueryInterface(IDirect3DPixelShader9 *iface, REFIID riid, void **object) | 
|  | { | 
|  | TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), object); | 
|  |  | 
|  | if (IsEqualGUID(riid, &IID_IDirect3DPixelShader9) | 
|  | || IsEqualGUID(riid, &IID_IUnknown)) | 
|  | { | 
|  | IDirect3DPixelShader9_AddRef(iface); | 
|  | *object = iface; | 
|  | return S_OK; | 
|  | } | 
|  |  | 
|  | WARN("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(riid)); | 
|  |  | 
|  | *object = NULL; | 
|  | return E_NOINTERFACE; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI d3d9_pixelshader_AddRef(IDirect3DPixelShader9 *iface) | 
|  | { | 
|  | IDirect3DPixelShader9Impl *shader = impl_from_IDirect3DPixelShader9(iface); | 
|  | ULONG refcount = InterlockedIncrement(&shader->ref); | 
|  |  | 
|  | TRACE("%p increasing refcount to %u.\n", iface, refcount); | 
|  |  | 
|  | if (refcount == 1) | 
|  | { | 
|  | IDirect3DDevice9Ex_AddRef(shader->parentDevice); | 
|  | wined3d_mutex_lock(); | 
|  | wined3d_shader_incref(shader->wined3d_shader); | 
|  | wined3d_mutex_unlock(); | 
|  | } | 
|  |  | 
|  | return refcount; | 
|  | } | 
|  |  | 
|  | static ULONG WINAPI d3d9_pixelshader_Release(IDirect3DPixelShader9 *iface) | 
|  | { | 
|  | IDirect3DPixelShader9Impl *shader = impl_from_IDirect3DPixelShader9(iface); | 
|  | ULONG refcount = InterlockedDecrement(&shader->ref); | 
|  |  | 
|  | TRACE("%p decreasing refcount to %u.\n", iface, refcount); | 
|  |  | 
|  | if (!refcount) | 
|  | { | 
|  | IDirect3DDevice9Ex *device = shader->parentDevice; | 
|  |  | 
|  | wined3d_mutex_lock(); | 
|  | wined3d_shader_decref(shader->wined3d_shader); | 
|  | wined3d_mutex_unlock(); | 
|  |  | 
|  | /* Release the device last, as it may cause the device to be destroyed. */ | 
|  | IDirect3DDevice9Ex_Release(device); | 
|  | } | 
|  |  | 
|  | return refcount; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI d3d9_pixelshader_GetDevice(IDirect3DPixelShader9 *iface, | 
|  | IDirect3DDevice9 **device) | 
|  | { | 
|  | IDirect3DPixelShader9Impl *shader = impl_from_IDirect3DPixelShader9(iface); | 
|  |  | 
|  | TRACE("iface %p, device %p.\n", iface, device); | 
|  |  | 
|  | *device = (IDirect3DDevice9 *)shader->parentDevice; | 
|  | IDirect3DDevice9_AddRef(*device); | 
|  |  | 
|  | TRACE("Returning device %p.\n", *device); | 
|  |  | 
|  | return D3D_OK; | 
|  | } | 
|  |  | 
|  | static HRESULT WINAPI d3d9_pixelshader_GetFunction(IDirect3DPixelShader9 *iface, void *data, | 
|  | UINT *data_size) | 
|  | { | 
|  | IDirect3DPixelShader9Impl *shader = impl_from_IDirect3DPixelShader9(iface); | 
|  | HRESULT hr; | 
|  |  | 
|  | TRACE("iface %p, data %p, data_size %p.\n", iface, data, data_size); | 
|  |  | 
|  | wined3d_mutex_lock(); | 
|  | hr = wined3d_shader_get_byte_code(shader->wined3d_shader, data, data_size); | 
|  | wined3d_mutex_unlock(); | 
|  |  | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | static const IDirect3DPixelShader9Vtbl d3d9_pixelshader_vtbl = | 
|  | { | 
|  | /* IUnknown */ | 
|  | d3d9_pixelshader_QueryInterface, | 
|  | d3d9_pixelshader_AddRef, | 
|  | d3d9_pixelshader_Release, | 
|  | /* IDirect3DPixelShader9 */ | 
|  | d3d9_pixelshader_GetDevice, | 
|  | d3d9_pixelshader_GetFunction, | 
|  | }; | 
|  |  | 
|  | static void STDMETHODCALLTYPE d3d9_pixelshader_wined3d_object_destroyed(void *parent) | 
|  | { | 
|  | HeapFree(GetProcessHeap(), 0, parent); | 
|  | } | 
|  |  | 
|  | static const struct wined3d_parent_ops d3d9_pixelshader_wined3d_parent_ops = | 
|  | { | 
|  | d3d9_pixelshader_wined3d_object_destroyed, | 
|  | }; | 
|  |  | 
|  | HRESULT pixelshader_init(IDirect3DPixelShader9Impl *shader, IDirect3DDevice9Impl *device, const DWORD *byte_code) | 
|  | { | 
|  | HRESULT hr; | 
|  |  | 
|  | shader->ref = 1; | 
|  | shader->IDirect3DPixelShader9_iface.lpVtbl = &d3d9_pixelshader_vtbl; | 
|  |  | 
|  | wined3d_mutex_lock(); | 
|  | hr = wined3d_shader_create_ps(device->wined3d_device, byte_code, NULL, shader, | 
|  | &d3d9_pixelshader_wined3d_parent_ops, &shader->wined3d_shader); | 
|  | wined3d_mutex_unlock(); | 
|  | if (FAILED(hr)) | 
|  | { | 
|  | WARN("Failed to created wined3d pixel shader, hr %#x.\n", hr); | 
|  | return hr; | 
|  | } | 
|  |  | 
|  | shader->parentDevice = &device->IDirect3DDevice9Ex_iface; | 
|  | IDirect3DDevice9Ex_AddRef(shader->parentDevice); | 
|  |  | 
|  | return D3D_OK; | 
|  | } | 
|  |  | 
|  | IDirect3DPixelShader9Impl *unsafe_impl_from_IDirect3DPixelShader9(IDirect3DPixelShader9 *iface) | 
|  | { | 
|  | if (!iface) | 
|  | return NULL; | 
|  | assert(iface->lpVtbl == &d3d9_pixelshader_vtbl); | 
|  |  | 
|  | return impl_from_IDirect3DPixelShader9(iface); | 
|  | } |