vertexdeclaration.c 10.1 KB
Newer Older
1 2 3 4 5 6
/*
 * vertex declaration implementation
 *
 * Copyright 2002-2005 Raphael Junqueira
 * Copyright 2004 Jason Edmeades
 * Copyright 2004 Christian Costa
7
 * Copyright 2005 Oliver Stieber
8 9 10 11 12 13 14 15 16 17 18 19 20
 *
 * 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
21
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 23 24 25 26 27 28
 */

#include "config.h"
#include "wined3d_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(d3d_decl);

29 30
#define GLINFO_LOCATION This->wineD3DDevice->adapter->gl_info

31
static void dump_wined3dvertexelement(const WINED3DVERTEXELEMENT *element) {
32 33 34 35 36 37 38
    TRACE("     format: %s (%#x)\n", debug_d3dformat(element->format), element->format);
    TRACE(" input_slot: %u\n", element->input_slot);
    TRACE("     offset: %u\n", element->offset);
    TRACE("output_slot: %u\n", element->output_slot);
    TRACE("     method: %s (%#x)\n", debug_d3ddeclmethod(element->method), element->method);
    TRACE("      usage: %s (%#x)\n", debug_d3ddeclusage(element->usage), element->usage);
    TRACE("  usage_idx: %u\n", element->usage_idx);
39 40
}

41 42 43
/* *******************************************
   IWineD3DVertexDeclaration IUnknown parts follow
   ******************************************* */
44
static HRESULT WINAPI IWineD3DVertexDeclarationImpl_QueryInterface(IWineD3DVertexDeclaration *iface, REFIID riid, LPVOID *ppobj)
45 46
{
    IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface;
47 48
    TRACE("(%p)->(%s,%p)\n",This,debugstr_guid(riid),ppobj);
    if (IsEqualGUID(riid, &IID_IUnknown)
49
        || IsEqualGUID(riid, &IID_IWineD3DBase)
50 51 52
        || IsEqualGUID(riid, &IID_IWineD3DVertexDeclaration)){
        IUnknown_AddRef(iface);
        *ppobj = This;
53
        return S_OK;
54
    }
55
    *ppobj = NULL;
56 57 58
    return E_NOINTERFACE;
}

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 63 64
    return InterlockedIncrement(&This->ref);
}

65
static ULONG WINAPI IWineD3DVertexDeclarationImpl_Release(IWineD3DVertexDeclaration *iface) {
66 67
    IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface;
    ULONG ref;
68
    TRACE("(%p) : Releasing from %d\n", This, This->ref);
69 70
    ref = InterlockedDecrement(&This->ref);
    if (ref == 0) {
71 72 73 74 75
        if(iface == This->wineD3DDevice->stateBlock->vertexDecl) {
            /* See comment in PixelShader::Release */
            IWineD3DDeviceImpl_MarkStateDirty(This->wineD3DDevice, STATE_VDECL);
        }

76
        HeapFree(GetProcessHeap(), 0, This->elements);
77
        HeapFree(GetProcessHeap(), 0, This);
78 79 80 81 82 83 84 85
    }
    return ref;
}

/* *******************************************
   IWineD3DVertexDeclaration parts follow
   ******************************************* */

86
static HRESULT WINAPI IWineD3DVertexDeclarationImpl_GetParent(IWineD3DVertexDeclaration *iface, IUnknown** parent){
87 88
    IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface;

89
    *parent= This->parent;
90 91
    IUnknown_AddRef(*parent);
    TRACE("(%p) : returning %p\n", This, *parent);
92
    return WINED3D_OK;
93 94
}

95
static HRESULT WINAPI IWineD3DVertexDeclarationImpl_GetDevice(IWineD3DVertexDeclaration *iface, IWineD3DDevice** ppDevice) {
96 97
    IWineD3DVertexDeclarationImpl *This = (IWineD3DVertexDeclarationImpl *)iface;
    TRACE("(%p) : returning %p\n", This, This->wineD3DDevice);
98

99 100 101
    *ppDevice = (IWineD3DDevice *) This->wineD3DDevice;
    IWineD3DDevice_AddRef(*ppDevice);

102
    return WINED3D_OK;
103 104
}

105 106
static BOOL declaration_element_valid_ffp(const WINED3DVERTEXELEMENT *element)
{
107
    switch(element->usage)
108 109 110
    {
        case WINED3DDECLUSAGE_POSITION:
        case WINED3DDECLUSAGE_POSITIONT:
111
            switch(element->format)
112
            {
113 114 115 116 117 118 119
                case WINED3DFMT_R32G32_FLOAT:
                case WINED3DFMT_R32G32B32_FLOAT:
                case WINED3DFMT_R32G32B32A32_FLOAT:
                case WINED3DFMT_R16G16_SINT:
                case WINED3DFMT_R16G16B16A16_SINT:
                case WINED3DFMT_R16G16_FLOAT:
                case WINED3DFMT_R16G16B16A16_FLOAT:
120 121 122 123 124 125
                    return TRUE;
                default:
                    return FALSE;
            }

        case WINED3DDECLUSAGE_BLENDWEIGHT:
126
            switch(element->format)
127
            {
128 129 130 131 132 133 134 135 136 137
                case WINED3DFMT_R32_FLOAT:
                case WINED3DFMT_R32G32_FLOAT:
                case WINED3DFMT_R32G32B32_FLOAT:
                case WINED3DFMT_R32G32B32A32_FLOAT:
                case WINED3DFMT_A8R8G8B8:
                case WINED3DFMT_R8G8B8A8_UINT:
                case WINED3DFMT_R16G16_SINT:
                case WINED3DFMT_R16G16B16A16_SINT:
                case WINED3DFMT_R16G16_FLOAT:
                case WINED3DFMT_R16G16B16A16_FLOAT:
138 139 140 141 142 143
                    return TRUE;
                default:
                    return FALSE;
            }

        case WINED3DDECLUSAGE_NORMAL:
144
            switch(element->format)
145
            {
146 147 148 149
                case WINED3DFMT_R32G32B32_FLOAT:
                case WINED3DFMT_R32G32B32A32_FLOAT:
                case WINED3DFMT_R16G16B16A16_SINT:
                case WINED3DFMT_R16G16B16A16_FLOAT:
150 151 152 153 154 155
                    return TRUE;
                default:
                    return FALSE;
            }

        case WINED3DDECLUSAGE_TEXCOORD:
156
            switch(element->format)
157
            {
158 159 160 161 162 163 164 165
                case WINED3DFMT_R32_FLOAT:
                case WINED3DFMT_R32G32_FLOAT:
                case WINED3DFMT_R32G32B32_FLOAT:
                case WINED3DFMT_R32G32B32A32_FLOAT:
                case WINED3DFMT_R16G16_SINT:
                case WINED3DFMT_R16G16B16A16_SINT:
                case WINED3DFMT_R16G16_FLOAT:
                case WINED3DFMT_R16G16B16A16_FLOAT:
166 167 168 169 170 171
                    return TRUE;
                default:
                    return FALSE;
            }

        case WINED3DDECLUSAGE_COLOR:
172
            switch(element->format)
173
            {
174 175 176 177 178 179 180 181 182
                case WINED3DFMT_R32G32B32_FLOAT:
                case WINED3DFMT_R32G32B32A32_FLOAT:
                case WINED3DFMT_A8R8G8B8:
                case WINED3DFMT_R8G8B8A8_UINT:
                case WINED3DFMT_R16G16B16A16_SINT:
                case WINED3DFMT_R8G8B8A8_UNORM:
                case WINED3DFMT_R16G16B16A16_SNORM:
                case WINED3DFMT_R16G16B16A16_UNORM:
                case WINED3DFMT_R16G16B16A16_FLOAT:
183 184 185 186 187 188 189 190 191 192
                    return TRUE;
                default:
                    return FALSE;
            }

        default:
            return FALSE;
    }
}

193 194 195
HRESULT vertexdeclaration_init(IWineD3DVertexDeclarationImpl *This,
        const WINED3DVERTEXELEMENT *elements, UINT element_count)
{
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 204 205
    if (TRACE_ON(d3d_decl)) {
        for (i = 0; i < element_count; ++i) {
            dump_wined3dvertexelement(elements+i);
206
        }
207
    }
208

209 210 211 212
    This->element_count = element_count;
    This->elements = HeapAlloc(GetProcessHeap(), 0, sizeof(*This->elements) * element_count);
    if (!This->elements)
    {
213
        ERR("Memory allocation failed\n");
214
        return WINED3DERR_OUTOFVIDEOMEMORY;
215 216
    }

217 218 219 220
    /* Do some static analysis on the elements to make reading the declaration more comfortable
     * for the drawing code
     */
    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 228 229 230 231 232
        e->input_slot = elements[i].input_slot;
        e->offset = elements[i].offset;
        e->output_slot = elements[i].output_slot;
        e->method = elements[i].method;
        e->usage = elements[i].usage;
        e->usage_idx = elements[i].usage_idx;
233 234

        if (e->usage == WINED3DDECLUSAGE_POSITIONT) This->position_transformed = TRUE;
235 236 237 238

        /* Find the Streams used in the declaration. The vertex buffers have to be loaded
         * when drawing, but filter tesselation pseudo streams
         */
239
        if (e->input_slot >= MAX_STREAMS) continue;
240

241
        if (!e->format_desc->gl_vtx_format)
242
        {
243 244
            FIXME("The application tries to use an unsupported format (%s), returning E_FAIL\n",
                    debug_d3dformat(elements[i].format));
245
            /* The caller will release the vdecl, which will free This->elements */
246 247 248
            return E_FAIL;
        }

249 250 251
        if (e->offset & 0x3)
        {
            WARN("Declaration element %u is not 4 byte aligned(%u), returning E_FAIL\n", i, e->offset);
252 253 254
            return E_FAIL;
        }

255 256 257
        if (!isPreLoaded[e->input_slot])
        {
            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 269
    TRACE("Returning\n");
    return hr;
270 271
}

272
const IWineD3DVertexDeclarationVtbl IWineD3DVertexDeclaration_Vtbl =
273
{
274
    /* IUnknown */
275 276 277
    IWineD3DVertexDeclarationImpl_QueryInterface,
    IWineD3DVertexDeclarationImpl_AddRef,
    IWineD3DVertexDeclarationImpl_Release,
278 279
    /* IWineD3DVertexDeclaration */
    IWineD3DVertexDeclarationImpl_GetParent,
280 281
    IWineD3DVertexDeclarationImpl_GetDevice,
};