wined3d: Properly check if an attribute is used in TRACE_STRIDED.
[wine] / dlls / wined3d / vertexdeclaration.c
1 /*
2  * vertex declaration implementation
3  *
4  * Copyright 2002-2005 Raphael Junqueira
5  * Copyright 2004 Jason Edmeades
6  * Copyright 2004 Christian Costa
7  * Copyright 2005 Oliver Stieber
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22  */
23
24 #include "config.h"
25 #include "wined3d_private.h"
26
27 WINE_DEFAULT_DEBUG_CHANNEL(d3d_decl);
28
29 #define GLINFO_LOCATION This->wineD3DDevice->adapter->gl_info
30
31 static void dump_wined3dvertexelement(const WINED3DVERTEXELEMENT *element) {
32     TRACE("     format: %s (%#x)\n", debug_d3dformat(element->format), element->format);
33     TRACE(" input_slot: %u\n", element->input_slot);
34     TRACE("     offset: %u\n", element->offset);
35     TRACE("output_slot: %u\n", element->output_slot);
36     TRACE("     method: %s (%#x)\n", debug_d3ddeclmethod(element->method), element->method);
37     TRACE("      usage: %s (%#x)\n", debug_d3ddeclusage(element->usage), element->usage);
38     TRACE("  usage_idx: %u\n", element->usage_idx);
39 }
40
41 /* *******************************************
42    IWineD3DVertexDeclaration IUnknown parts follow
43    ******************************************* */
44 static HRESULT WINAPI IWineD3DVertexDeclarationImpl_QueryInterface(IWineD3DVertexDeclaration *iface, REFIID riid, LPVOID *ppobj)
45 {
46     IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface;
47     TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
48     if (IsEqualGUID(riid, &IID_IUnknown)
49         || IsEqualGUID(riid, &IID_IWineD3DBase)
50         || IsEqualGUID(riid, &IID_IWineD3DVertexDeclaration)){
51         IUnknown_AddRef(iface);
52         *ppobj = This;
53         return S_OK;
54     }
55     *ppobj = NULL;
56     return E_NOINTERFACE;
57 }
58
59 static ULONG WINAPI IWineD3DVertexDeclarationImpl_AddRef(IWineD3DVertexDeclaration *iface) {
60     IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface;
61     TRACE("(%p) : AddRef increasing from %d\n", This, This->ref);
62     return InterlockedIncrement(&This->ref);
63 }
64
65 static ULONG WINAPI IWineD3DVertexDeclarationImpl_Release(IWineD3DVertexDeclaration *iface) {
66     IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface;
67     ULONG ref;
68     TRACE("(%p) : Releasing from %d\n", This, This->ref);
69     ref = InterlockedDecrement(&This->ref);
70     if (ref == 0) {
71         if(iface == This->wineD3DDevice->stateBlock->vertexDecl) {
72             /* See comment in PixelShader::Release */
73             IWineD3DDeviceImpl_MarkStateDirty(This->wineD3DDevice, STATE_VDECL);
74         }
75
76         HeapFree(GetProcessHeap(), 0, This->elements);
77         HeapFree(GetProcessHeap(), 0, This);
78     }
79     return ref;
80 }
81
82 /* *******************************************
83    IWineD3DVertexDeclaration parts follow
84    ******************************************* */
85
86 static HRESULT WINAPI IWineD3DVertexDeclarationImpl_GetParent(IWineD3DVertexDeclaration *iface, IUnknown** parent){
87     IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface;
88
89     *parent= This->parent;
90     IUnknown_AddRef(*parent);
91     TRACE("(%p) : returning %p\n", This, *parent);
92     return WINED3D_OK;
93 }
94
95 static HRESULT WINAPI IWineD3DVertexDeclarationImpl_GetDevice(IWineD3DVertexDeclaration *iface, IWineD3DDevice** ppDevice) {
96     IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface;
97     TRACE("(%p) : returning %p\n", This, This->wineD3DDevice);
98
99     *ppDevice = (IWineD3DDevice *) This->wineD3DDevice;
100     IWineD3DDevice_AddRef(*ppDevice);
101
102     return WINED3D_OK;
103 }
104
105 static BOOL declaration_element_valid_ffp(const WINED3DVERTEXELEMENT *element)
106 {
107     switch(element->usage)
108     {
109         case WINED3DDECLUSAGE_POSITION:
110         case WINED3DDECLUSAGE_POSITIONT:
111             switch(element->format)
112             {
113                 case WINED3DFMT_R32G32_FLOAT:
114                 case WINED3DFMT_R32G32B32_FLOAT:
115                 case WINED3DFMT_R32G32B32A32_FLOAT:
116                 case WINED3DFMT_R16G16_SINT:
117                 case WINED3DFMT_R16G16B16A16_SINT:
118                 case WINED3DFMT_R16G16_FLOAT:
119                 case WINED3DFMT_R16G16B16A16_FLOAT:
120                     return TRUE;
121                 default:
122                     return FALSE;
123             }
124
125         case WINED3DDECLUSAGE_BLENDWEIGHT:
126             switch(element->format)
127             {
128                 case WINED3DFMT_R32_FLOAT:
129                 case WINED3DFMT_R32G32_FLOAT:
130                 case WINED3DFMT_R32G32B32_FLOAT:
131                 case WINED3DFMT_R32G32B32A32_FLOAT:
132                 case WINED3DFMT_A8R8G8B8:
133                 case WINED3DFMT_R8G8B8A8_UINT:
134                 case WINED3DFMT_R16G16_SINT:
135                 case WINED3DFMT_R16G16B16A16_SINT:
136                 case WINED3DFMT_R16G16_FLOAT:
137                 case WINED3DFMT_R16G16B16A16_FLOAT:
138                     return TRUE;
139                 default:
140                     return FALSE;
141             }
142
143         case WINED3DDECLUSAGE_NORMAL:
144             switch(element->format)
145             {
146                 case WINED3DFMT_R32G32B32_FLOAT:
147                 case WINED3DFMT_R32G32B32A32_FLOAT:
148                 case WINED3DFMT_R16G16B16A16_SINT:
149                 case WINED3DFMT_R16G16B16A16_FLOAT:
150                     return TRUE;
151                 default:
152                     return FALSE;
153             }
154
155         case WINED3DDECLUSAGE_TEXCOORD:
156             switch(element->format)
157             {
158                 case WINED3DFMT_R32_FLOAT:
159                 case WINED3DFMT_R32G32_FLOAT:
160                 case WINED3DFMT_R32G32B32_FLOAT:
161                 case WINED3DFMT_R32G32B32A32_FLOAT:
162                 case WINED3DFMT_R16G16_SINT:
163                 case WINED3DFMT_R16G16B16A16_SINT:
164                 case WINED3DFMT_R16G16_FLOAT:
165                 case WINED3DFMT_R16G16B16A16_FLOAT:
166                     return TRUE;
167                 default:
168                     return FALSE;
169             }
170
171         case WINED3DDECLUSAGE_COLOR:
172             switch(element->format)
173             {
174                 case WINED3DFMT_R32G32B32_FLOAT:
175                 case WINED3DFMT_R32G32B32A32_FLOAT:
176                 case WINED3DFMT_A8R8G8B8:
177                 case WINED3DFMT_R8G8B8A8_UINT:
178                 case WINED3DFMT_R16G16B16A16_SINT:
179                 case WINED3DFMT_R8G8B8A8_UNORM:
180                 case WINED3DFMT_R16G16B16A16_SNORM:
181                 case WINED3DFMT_R16G16B16A16_UNORM:
182                 case WINED3DFMT_R16G16B16A16_FLOAT:
183                     return TRUE;
184                 default:
185                     return FALSE;
186             }
187
188         default:
189             return FALSE;
190     }
191 }
192
193 HRESULT vertexdeclaration_init(IWineD3DVertexDeclarationImpl *This,
194         const WINED3DVERTEXELEMENT *elements, UINT element_count)
195 {
196     HRESULT hr = WINED3D_OK;
197     unsigned int i;
198     char isPreLoaded[MAX_STREAMS];
199
200     TRACE("(%p) : d3d version %d\n", This, ((IWineD3DImpl *)This->wineD3DDevice->wineD3D)->dxVersion);
201     memset(isPreLoaded, 0, sizeof(isPreLoaded));
202
203     if (TRACE_ON(d3d_decl)) {
204         for (i = 0; i < element_count; ++i) {
205             dump_wined3dvertexelement(elements+i);
206         }
207     }
208
209     This->element_count = element_count;
210     This->elements = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->elements) * element_count);
211     if (!This->elements)
212     {
213         ERR("Memory allocation failed\n");
214         return WINED3DERR_OUTOFVIDEOMEMORY;
215     }
216
217     /* Do some static analysis on the elements to make reading the declaration more comfortable
218      * for the drawing code
219      */
220     This->num_streams = 0;
221     This->position_transformed = FALSE;
222     for (i = 0; i < element_count; ++i) {
223         struct wined3d_vertex_declaration_element *e = &This->elements[i];
224
225         e->format_desc = getFormatDescEntry(elements[i].format, &This->wineD3DDevice->adapter->gl_info);
226         e->ffp_valid = declaration_element_valid_ffp(&elements[i]);
227         e->input_slot = elements[i].input_slot;
228         e->offset = elements[i].offset;
229         e->output_slot = elements[i].output_slot;
230         e->method = elements[i].method;
231         e->usage = elements[i].usage;
232         e->usage_idx = elements[i].usage_idx;
233
234         if (e->usage == WINED3DDECLUSAGE_POSITIONT) This->position_transformed = TRUE;
235
236         /* Find the Streams used in the declaration. The vertex buffers have to be loaded
237          * when drawing, but filter tesselation pseudo streams
238          */
239         if (e->input_slot >= MAX_STREAMS) continue;
240
241         if (!e->format_desc->gl_vtx_format)
242         {
243             FIXME("The application tries to use an unsupported format (%s), returning E_FAIL\n",
244                     debug_d3dformat(elements[i].format));
245             /* The caller will release the vdecl, which will free This->elements */
246             return E_FAIL;
247         }
248
249         if (e->offset & 0x3)
250         {
251             WARN("Declaration element %u is not 4 byte aligned(%u), returning E_FAIL\n", i, e->offset);
252             return E_FAIL;
253         }
254
255         if (!isPreLoaded[e->input_slot])
256         {
257             This->streams[This->num_streams] = e->input_slot;
258             This->num_streams++;
259             isPreLoaded[e->input_slot] = 1;
260         }
261
262         if (elements[i].format == WINED3DFMT_R16G16_FLOAT || elements[i].format == WINED3DFMT_R16G16B16A16_FLOAT)
263         {
264             if (!GL_SUPPORT(ARB_HALF_FLOAT_VERTEX)) This->half_float_conv_needed = TRUE;
265         }
266     }
267
268     TRACE("Returning\n");
269     return hr;
270 }
271
272 const IWineD3DVertexDeclarationVtbl IWineD3DVertexDeclaration_Vtbl =
273 {
274     /* IUnknown */
275     IWineD3DVertexDeclarationImpl_QueryInterface,
276     IWineD3DVertexDeclarationImpl_AddRef,
277     IWineD3DVertexDeclarationImpl_Release,
278     /* IWineD3DVertexDeclaration */
279     IWineD3DVertexDeclarationImpl_GetParent,
280     IWineD3DVertexDeclarationImpl_GetDevice,
281 };