wined3d: Don't record dirty areas in a readonly lock.
[wine] / dlls / d3d8 / vertexshader.c
1 /*
2  * IDirect3DVertexShader8 implementation
3  *
4  * Copyright 2002-2003 Jason Edmeades
5  *                     Raphael Junqueira
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include "config.h"
23 #include "d3d8_private.h"
24
25 WINE_DEFAULT_DEBUG_CHANNEL(d3d8);
26
27 /* IDirect3DVertexShader8 IUnknown parts follow: */
28 static HRESULT WINAPI IDirect3DVertexShader8Impl_QueryInterface(IDirect3DVertexShader8 *iface, REFIID riid, LPVOID* ppobj) {
29     IDirect3DVertexShader8Impl *This = (IDirect3DVertexShader8Impl *)iface;
30
31     TRACE("iface %p, riid %s, object %p.\n", iface, debugstr_guid(riid), ppobj);
32
33     if (IsEqualGUID(riid, &IID_IUnknown)
34         || IsEqualGUID(riid, &IID_IDirect3DVertexShader8)) {
35         IUnknown_AddRef(iface);
36         *ppobj = This;
37         return S_OK;
38     }
39
40     WARN("(%p)->(%s,%p),not found\n", This, debugstr_guid(riid), ppobj);
41     *ppobj = NULL;
42     return E_NOINTERFACE;
43 }
44
45 static ULONG WINAPI IDirect3DVertexShader8Impl_AddRef(IDirect3DVertexShader8 *iface) {
46     IDirect3DVertexShader8Impl *This = (IDirect3DVertexShader8Impl *)iface;
47     ULONG ref = InterlockedIncrement(&This->ref);
48
49     TRACE("%p increasing refcount to %u.\n", iface, ref);
50
51     if (ref == 1 && This->wineD3DVertexShader)
52     {
53         wined3d_mutex_lock();
54         IWineD3DVertexShader_AddRef(This->wineD3DVertexShader);
55         wined3d_mutex_unlock();
56     }
57
58     return ref;
59 }
60
61 static void STDMETHODCALLTYPE d3d8_vertexshader_wined3d_object_destroyed(void *parent)
62 {
63     IDirect3DVertexShader8Impl *shader = parent;
64     IDirect3DVertexDeclaration8_Release(shader->vertex_declaration);
65     HeapFree(GetProcessHeap(), 0, shader);
66 }
67
68 static ULONG WINAPI IDirect3DVertexShader8Impl_Release(IDirect3DVertexShader8 *iface) {
69     IDirect3DVertexShader8Impl *This = (IDirect3DVertexShader8Impl *)iface;
70     ULONG ref = InterlockedDecrement(&This->ref);
71
72     TRACE("%p decreasing refcount to %u.\n", iface, ref);
73
74     if (ref == 0) {
75         if (This->wineD3DVertexShader)
76         {
77             wined3d_mutex_lock();
78             IWineD3DVertexShader_Release(This->wineD3DVertexShader);
79             wined3d_mutex_unlock();
80         }
81         else
82         {
83             d3d8_vertexshader_wined3d_object_destroyed(This);
84         }
85     }
86     return ref;
87 }
88
89 static const IDirect3DVertexShader8Vtbl Direct3DVertexShader8_Vtbl =
90 {
91     /* IUnknown */
92     IDirect3DVertexShader8Impl_QueryInterface,
93     IDirect3DVertexShader8Impl_AddRef,
94     IDirect3DVertexShader8Impl_Release,
95 };
96
97 static const struct wined3d_parent_ops d3d8_vertexshader_wined3d_parent_ops =
98 {
99     d3d8_vertexshader_wined3d_object_destroyed,
100 };
101
102 static HRESULT vertexshader_create_vertexdeclaration(IDirect3DDevice8Impl *device,
103         const DWORD *declaration, DWORD shader_handle, IDirect3DVertexDeclaration8 **decl_ptr)
104 {
105     IDirect3DVertexDeclaration8Impl *object;
106     HRESULT hr;
107
108     TRACE("device %p, declaration %p, shader_handle %#x, decl_ptr %p.\n",
109             device, declaration, shader_handle, decl_ptr);
110
111     object = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*object));
112     if (!object) {
113         ERR("Memory allocation failed\n");
114         *decl_ptr = NULL;
115         return D3DERR_OUTOFVIDEOMEMORY;
116     }
117
118     hr = vertexdeclaration_init(object, device, declaration, shader_handle);
119     if (FAILED(hr))
120     {
121         WARN("Failed to initialize vertex declaration, hr %#x.\n", hr);
122         HeapFree(GetProcessHeap(), 0, object);
123         return hr;
124     }
125
126     TRACE("Created vertex declaration %p.\n", object);
127     *decl_ptr = (IDirect3DVertexDeclaration8 *)object;
128
129     return D3D_OK;
130 }
131
132 HRESULT vertexshader_init(IDirect3DVertexShader8Impl *shader, IDirect3DDevice8Impl *device,
133         const DWORD *declaration, const DWORD *byte_code, DWORD shader_handle, DWORD usage)
134 {
135     const DWORD *token = declaration;
136     HRESULT hr;
137
138     /* Test if the vertex declaration is valid */
139     while (D3DVSD_END() != *token)
140     {
141         D3DVSD_TOKENTYPE token_type = ((*token & D3DVSD_TOKENTYPEMASK) >> D3DVSD_TOKENTYPESHIFT);
142
143         if (token_type == D3DVSD_TOKEN_STREAMDATA && !(token_type & 0x10000000))
144         {
145             DWORD type = ((*token & D3DVSD_DATATYPEMASK) >> D3DVSD_DATATYPESHIFT);
146             DWORD reg  = ((*token & D3DVSD_VERTEXREGMASK) >> D3DVSD_VERTEXREGSHIFT);
147
148             if (reg == D3DVSDE_NORMAL && type != D3DVSDT_FLOAT3 && !byte_code)
149             {
150                 WARN("Attempt to use a non-FLOAT3 normal with the fixed function function\n");
151                 return D3DERR_INVALIDCALL;
152             }
153         }
154         token += parse_token(token);
155     }
156
157     shader->ref = 1;
158     shader->lpVtbl = &Direct3DVertexShader8_Vtbl;
159
160     hr = vertexshader_create_vertexdeclaration(device, declaration, shader_handle, &shader->vertex_declaration);
161     if (FAILED(hr))
162     {
163         WARN("Failed to create vertex declaration, hr %#x.\n", hr);
164         return hr;
165     }
166
167     if (byte_code)
168     {
169         if (usage) FIXME("Usage %#x not implemented.\n", usage);
170
171         wined3d_mutex_lock();
172         hr = IWineD3DDevice_CreateVertexShader(device->WineD3DDevice, byte_code,
173                 NULL /* output signature */, &shader->wineD3DVertexShader,
174                 (IUnknown *)shader, &d3d8_vertexshader_wined3d_parent_ops);
175         wined3d_mutex_unlock();
176         if (FAILED(hr))
177         {
178             WARN("Failed to create wined3d vertex shader, hr %#x.\n", hr);
179             IDirect3DVertexDeclaration8_Release(shader->vertex_declaration);
180             return hr;
181         }
182
183         load_local_constants(declaration, shader->wineD3DVertexShader);
184     }
185
186     return D3D_OK;
187 }