wined3d: Fix ARB_0001 with pixel shaders in arb_get_helper_value().
[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  * Copyright 2009 Henri Verbeet for CodeWeavers
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24
25 #include "config.h"
26 #include "wined3d_private.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(d3d_decl);
29
30 static void dump_wined3dvertexelement(const WINED3DVERTEXELEMENT *element) {
31     TRACE("     format: %s (%#x)\n", debug_d3dformat(element->format), element->format);
32     TRACE(" input_slot: %u\n", element->input_slot);
33     TRACE("     offset: %u\n", element->offset);
34     TRACE("output_slot: %u\n", element->output_slot);
35     TRACE("     method: %s (%#x)\n", debug_d3ddeclmethod(element->method), element->method);
36     TRACE("      usage: %s (%#x)\n", debug_d3ddeclusage(element->usage), element->usage);
37     TRACE("  usage_idx: %u\n", element->usage_idx);
38 }
39
40 ULONG CDECL wined3d_vertex_declaration_incref(struct wined3d_vertex_declaration *declaration)
41 {
42     ULONG refcount = InterlockedIncrement(&declaration->ref);
43
44     TRACE("%p increasing refcount to %u.\n", declaration, refcount);
45
46     return refcount;
47 }
48
49 ULONG CDECL wined3d_vertex_declaration_decref(struct wined3d_vertex_declaration *declaration)
50 {
51     ULONG refcount = InterlockedDecrement(&declaration->ref);
52
53     TRACE("%p decreasing refcount to %u.\n", declaration, refcount);
54
55     if (!refcount)
56     {
57         HeapFree(GetProcessHeap(), 0, declaration->elements);
58         declaration->parent_ops->wined3d_object_destroyed(declaration->parent);
59         HeapFree(GetProcessHeap(), 0, declaration);
60     }
61
62     return refcount;
63 }
64
65 void * CDECL wined3d_vertex_declaration_get_parent(const struct wined3d_vertex_declaration *declaration)
66 {
67     TRACE("declaration %p.\n", declaration);
68
69     return declaration->parent;
70 }
71
72 static BOOL declaration_element_valid_ffp(const WINED3DVERTEXELEMENT *element)
73 {
74     switch(element->usage)
75     {
76         case WINED3DDECLUSAGE_POSITION:
77         case WINED3DDECLUSAGE_POSITIONT:
78             switch(element->format)
79             {
80                 case WINED3DFMT_R32G32_FLOAT:
81                 case WINED3DFMT_R32G32B32_FLOAT:
82                 case WINED3DFMT_R32G32B32A32_FLOAT:
83                 case WINED3DFMT_R16G16_SINT:
84                 case WINED3DFMT_R16G16B16A16_SINT:
85                 case WINED3DFMT_R16G16_FLOAT:
86                 case WINED3DFMT_R16G16B16A16_FLOAT:
87                     return TRUE;
88                 default:
89                     return FALSE;
90             }
91
92         case WINED3DDECLUSAGE_BLENDWEIGHT:
93             switch(element->format)
94             {
95                 case WINED3DFMT_R32_FLOAT:
96                 case WINED3DFMT_R32G32_FLOAT:
97                 case WINED3DFMT_R32G32B32_FLOAT:
98                 case WINED3DFMT_R32G32B32A32_FLOAT:
99                 case WINED3DFMT_B8G8R8A8_UNORM:
100                 case WINED3DFMT_R8G8B8A8_UINT:
101                 case WINED3DFMT_R16G16_SINT:
102                 case WINED3DFMT_R16G16B16A16_SINT:
103                 case WINED3DFMT_R16G16_FLOAT:
104                 case WINED3DFMT_R16G16B16A16_FLOAT:
105                     return TRUE;
106                 default:
107                     return FALSE;
108             }
109
110         case WINED3DDECLUSAGE_NORMAL:
111             switch(element->format)
112             {
113                 case WINED3DFMT_R32G32B32_FLOAT:
114                 case WINED3DFMT_R32G32B32A32_FLOAT:
115                 case WINED3DFMT_R16G16B16A16_SINT:
116                 case WINED3DFMT_R16G16B16A16_FLOAT:
117                     return TRUE;
118                 default:
119                     return FALSE;
120             }
121
122         case WINED3DDECLUSAGE_TEXCOORD:
123             switch(element->format)
124             {
125                 case WINED3DFMT_R32_FLOAT:
126                 case WINED3DFMT_R32G32_FLOAT:
127                 case WINED3DFMT_R32G32B32_FLOAT:
128                 case WINED3DFMT_R32G32B32A32_FLOAT:
129                 case WINED3DFMT_R16G16_SINT:
130                 case WINED3DFMT_R16G16B16A16_SINT:
131                 case WINED3DFMT_R16G16_FLOAT:
132                 case WINED3DFMT_R16G16B16A16_FLOAT:
133                     return TRUE;
134                 default:
135                     return FALSE;
136             }
137
138         case WINED3DDECLUSAGE_COLOR:
139             switch(element->format)
140             {
141                 case WINED3DFMT_R32G32B32_FLOAT:
142                 case WINED3DFMT_R32G32B32A32_FLOAT:
143                 case WINED3DFMT_B8G8R8A8_UNORM:
144                 case WINED3DFMT_R8G8B8A8_UINT:
145                 case WINED3DFMT_R16G16B16A16_SINT:
146                 case WINED3DFMT_R8G8B8A8_UNORM:
147                 case WINED3DFMT_R16G16B16A16_SNORM:
148                 case WINED3DFMT_R16G16B16A16_UNORM:
149                 case WINED3DFMT_R16G16B16A16_FLOAT:
150                     return TRUE;
151                 default:
152                     return FALSE;
153             }
154
155         default:
156             return FALSE;
157     }
158 }
159
160 HRESULT vertexdeclaration_init(struct wined3d_vertex_declaration *declaration, IWineD3DDeviceImpl *device,
161         const WINED3DVERTEXELEMENT *elements, UINT element_count,
162         void *parent, const struct wined3d_parent_ops *parent_ops)
163 {
164     const struct wined3d_gl_info *gl_info = &device->adapter->gl_info;
165     WORD preloaded = 0; /* MAX_STREAMS, 16 */
166     unsigned int i;
167
168     if (TRACE_ON(d3d_decl))
169     {
170         for (i = 0; i < element_count; ++i)
171         {
172             dump_wined3dvertexelement(elements + i);
173         }
174     }
175
176     declaration->ref = 1;
177     declaration->parent = parent;
178     declaration->parent_ops = parent_ops;
179     declaration->device = device;
180     declaration->elements = HeapAlloc(GetProcessHeap(), 0, sizeof(*declaration->elements) * element_count);
181     if (!declaration->elements)
182     {
183         ERR("Failed to allocate elements memory.\n");
184         return E_OUTOFMEMORY;
185     }
186     declaration->element_count = element_count;
187
188     /* Do some static analysis on the elements to make reading the
189      * declaration more comfortable for the drawing code. */
190     for (i = 0; i < element_count; ++i)
191     {
192         struct wined3d_vertex_declaration_element *e = &declaration->elements[i];
193
194         e->format = wined3d_get_format(gl_info, elements[i].format);
195         e->ffp_valid = declaration_element_valid_ffp(&elements[i]);
196         e->input_slot = elements[i].input_slot;
197         e->offset = elements[i].offset;
198         e->output_slot = elements[i].output_slot;
199         e->method = elements[i].method;
200         e->usage = elements[i].usage;
201         e->usage_idx = elements[i].usage_idx;
202
203         if (e->usage == WINED3DDECLUSAGE_POSITIONT) declaration->position_transformed = TRUE;
204
205         /* Find the streams used in the declaration. The vertex buffers have
206          * to be loaded when drawing, but filter tesselation pseudo streams. */
207         if (e->input_slot >= MAX_STREAMS) continue;
208
209         if (!e->format->gl_vtx_format)
210         {
211             FIXME("The application tries to use an unsupported format (%s), returning E_FAIL.\n",
212                     debug_d3dformat(elements[i].format));
213             HeapFree(GetProcessHeap(), 0, declaration->elements);
214             return E_FAIL;
215         }
216
217         if (e->offset & 0x3)
218         {
219             WARN("Declaration element %u is not 4 byte aligned(%u), returning E_FAIL.\n", i, e->offset);
220             HeapFree(GetProcessHeap(), 0, declaration->elements);
221             return E_FAIL;
222         }
223
224         if (!(preloaded & (1 << e->input_slot)))
225         {
226             declaration->streams[declaration->num_streams] = e->input_slot;
227             ++declaration->num_streams;
228             preloaded |= 1 << e->input_slot;
229         }
230
231         if (elements[i].format == WINED3DFMT_R16G16_FLOAT || elements[i].format == WINED3DFMT_R16G16B16A16_FLOAT)
232         {
233             if (!gl_info->supported[ARB_HALF_FLOAT_VERTEX]) declaration->half_float_conv_needed = TRUE;
234         }
235     }
236
237     return WINED3D_OK;
238 }