source: trunk/src/gpu/vertexbuffer.cpp @ 1246

Last change on this file since 1246 was 1246, checked in by sam, 10 years ago

gpu: remove old code in VertexBuffer that caused a memory leak.

File size: 13.7 KB
Line 
1//
2// Lol Engine
3//
4// Copyright: (c) 2010-2012 Sam Hocevar <sam@hocevar.net>
5//   This program is free software; you can redistribute it and/or
6//   modify it under the terms of the Do What The Fuck You Want To
7//   Public License, Version 2, as published by Sam Hocevar. See
8//   http://sam.zoy.org/projects/COPYING.WTFPL for more details.
9//
10
11#if defined HAVE_CONFIG_H
12#   include "config.h"
13#endif
14
15#include "core.h"
16#include "lolgl.h"
17
18#if defined _WIN32 && defined USE_D3D9
19#   define FAR
20#   define NEAR
21#   include <d3d9.h>
22#endif
23
24using namespace std;
25
26#if defined USE_D3D9
27extern IDirect3DDevice9 *g_d3ddevice;
28#elif defined _XBOX
29extern D3DDevice *g_d3ddevice;
30#endif
31
32namespace lol
33{
34
35//
36// The VertexBufferData class
37// --------------------------
38//
39
40class VertexBufferData
41{
42    friend class VertexBuffer;
43    friend class VertexDeclaration;
44
45#if defined USE_D3D9
46    IDirect3DVertexBuffer9 *m_vbo;
47#elif defined _XBOX
48    D3DVertexBuffer *m_vbo;
49#elif !defined __CELLOS_LV2__ && !defined __ANDROID__
50    GLuint m_vbo;
51    uint8_t *m_memory;
52    size_t m_size;
53#endif
54};
55
56//
57// The VertexDeclaration class
58// ---------------------------
59//
60
61VertexStreamBase const VertexStreamBase::Empty;
62
63VertexDeclaration::VertexDeclaration(VertexStreamBase const &s1,
64                                     VertexStreamBase const &s2,
65                                     VertexStreamBase const &s3,
66                                     VertexStreamBase const &s4,
67                                     VertexStreamBase const &s5,
68                                     VertexStreamBase const &s6,
69                                     VertexStreamBase const &s7,
70                                     VertexStreamBase const &s8,
71                                     VertexStreamBase const &s9,
72                                     VertexStreamBase const &s10,
73                                     VertexStreamBase const &s11,
74                                     VertexStreamBase const &s12) : m_count(0)
75{
76    if (&s1 != &VertexStreamBase::Empty) AddStream(s1);
77    if (&s2 != &VertexStreamBase::Empty) AddStream(s2);
78    if (&s3 != &VertexStreamBase::Empty) AddStream(s3);
79    if (&s4 != &VertexStreamBase::Empty) AddStream(s4);
80    if (&s5 != &VertexStreamBase::Empty) AddStream(s5);
81    if (&s6 != &VertexStreamBase::Empty) AddStream(s6);
82    if (&s7 != &VertexStreamBase::Empty) AddStream(s7);
83    if (&s8 != &VertexStreamBase::Empty) AddStream(s8);
84    if (&s9 != &VertexStreamBase::Empty) AddStream(s9);
85    if (&s10 != &VertexStreamBase::Empty) AddStream(s10);
86    if (&s11 != &VertexStreamBase::Empty) AddStream(s11);
87    if (&s12 != &VertexStreamBase::Empty) AddStream(s12);
88    Initialize();
89}
90
91VertexDeclaration::~VertexDeclaration()
92{
93#if defined _XBOX || defined USE_D3D9
94#   if defined USE_D3D9
95    IDirect3DVertexDeclaration9 *vdecl = (IDirect3DVertexDeclaration9 *)m_data;
96#   elif defined _XBOX
97    D3DVertexDeclaration *vdecl = (D3DVertexDeclaration *)m_data;
98#   endif
99
100    if (FAILED(vdecl->Release()))
101        Abort();
102#else
103
104#endif
105}
106
107void VertexDeclaration::Bind()
108{
109#if defined _XBOX || defined USE_D3D9
110#   if defined USE_D3D9
111    IDirect3DVertexDeclaration9 *vdecl = (IDirect3DVertexDeclaration9 *)m_data;
112#   elif defined _XBOX
113    D3DVertexDeclaration *vdecl = (D3DVertexDeclaration *)m_data;
114#   endif
115
116    if (FAILED(g_d3ddevice->SetVertexDeclaration(vdecl)))
117        Abort();
118#else
119    /* FIXME: Nothing to do? */
120#endif
121}
122
123void VertexDeclaration::DrawElements(MeshPrimitive type, int skip, int count)
124{
125#if defined _XBOX || defined USE_D3D9
126    if (FAILED(g_d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW)))
127        Abort();
128    switch (type)
129    {
130    case MeshPrimitive::Triangles:
131        if (FAILED(g_d3ddevice->DrawPrimitive(D3DPT_TRIANGLELIST, skip, count)))
132            Abort();
133        break;
134    }
135#else
136    switch (type)
137    {
138    case MeshPrimitive::Triangles:
139        glDrawArrays(GL_TRIANGLES, skip * 3, count * 3);
140        break;
141    }
142#endif
143}
144
145void VertexDeclaration::Unbind()
146{
147#if defined _XBOX || defined USE_D3D9
148    int stream = -1;
149    for (int i = 0; i < m_count; i++)
150        if (m_streams[i].index != stream)
151        {
152            stream = m_streams[i].index;
153            if (FAILED(g_d3ddevice->SetStreamSource(stream, 0, 0, 0)))
154                Abort();
155        }
156    if (FAILED(g_d3ddevice->SetVertexDeclaration(NULL)))
157        Abort();
158#else
159    /* FIXME: we need to unbind what we bound */
160    //glDisableVertexAttribArray(m_attrib);
161    /* FIXME: only useful for VAOs */
162    //glBindBuffer(GL_ARRAY_BUFFER, 0);
163    /* Or: */
164    //glDisableVertexAttribArray(m_attrib);
165    /* Or even: */
166    //glDisableClientState(GL_VERTEX_ARRAY);
167#endif
168}
169
170void VertexDeclaration::SetStream(VertexBuffer *vb, ShaderAttrib attr1,
171                                                    ShaderAttrib attr2,
172                                                    ShaderAttrib attr3,
173                                                    ShaderAttrib attr4,
174                                                    ShaderAttrib attr5,
175                                                    ShaderAttrib attr6,
176                                                    ShaderAttrib attr7,
177                                                    ShaderAttrib attr8,
178                                                    ShaderAttrib attr9,
179                                                    ShaderAttrib attr10,
180                                                    ShaderAttrib attr11,
181                                                    ShaderAttrib attr12)
182{
183#if defined _XBOX || defined USE_D3D9
184    /* Only the first item is required to know which stream this
185     * is about; the rest of the information is stored in the
186     * vertex declaration already. */
187    uint32_t usage = (attr1.m_flags >> 16) & 0xffff;
188    uint32_t index = attr1.m_flags & 0xffff;
189
190    /* Find the stream number */
191    int usage_index = 0, stream = -1;
192    for (int i = 0; i < m_count; i++)
193        if (m_streams[i].usage == usage)
194            if (usage_index++ == index)
195            {
196                stream = m_streams[i].index;
197                break;
198            }
199
200    /* Compute this stream's stride */
201    int stride = 0;
202    for (int i = 0; i < m_count; i++)
203        if (stream == m_streams[i].index)
204            stride += m_streams[i].size;
205
206    /* Now we know the stream index and the element stride */
207    /* FIXME: precompute most of the crap above! */
208    if (stream >= 0)
209    {
210        if (FAILED(g_d3ddevice->SetStreamSource(stream, vb->m_data->m_vbo, 0, stride)))
211            Abort();
212    }
213#else
214    glBindBuffer(GL_ARRAY_BUFFER, vb->m_data->m_vbo);
215    ShaderAttrib l[12] = { attr1, attr2, attr3, attr4, attr5, attr6,
216                           attr7, attr8, attr9, attr10, attr11, attr12 };
217    for (int n = 0; n < 12 && l[n].m_flags != (uint64_t)0 - 1; n++)
218    {
219        uint32_t reg = l[n].m_flags >> 32;
220        uint32_t usage = (l[n].m_flags >> 16) & 0xffff;
221        uint32_t index = l[n].m_flags & 0xffff;
222
223        glEnableVertexAttribArray((GLint)reg);
224
225        /* We need to parse the whole vertex declaration to retrieve
226         * the information. It sucks. */
227
228        int attr_index = 0, usage_index = 0;
229        /* First, find the stream index */
230        for (; attr_index < m_count; attr_index++)
231            if (m_streams[attr_index].usage == usage)
232                if (usage_index++ == index)
233                    break;
234
235        /* Now compute the stride and offset up to this stream index */
236        int stride = 0, offset = 0;
237        for (int i = 0; i < m_count; i++)
238            if (m_streams[i].index == m_streams[attr_index].index)
239            {
240                stride += m_streams[i].size;
241                if (i < attr_index)
242                    offset += m_streams[i].size;
243            }
244
245        /* Finally, we need to retrieve the type of the data */
246        static struct { GLint size; GLenum type; } const tlut[] =
247        {
248            { 0, 0 },
249            { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, /* half */
250            { 1, GL_FLOAT }, { 2, GL_FLOAT }, { 3, GL_FLOAT },
251                { 4, GL_FLOAT }, /* float */
252            { 1, GL_DOUBLE }, { 2, GL_DOUBLE }, { 3, GL_DOUBLE },
253                { 4, GL_DOUBLE }, /* double */
254            { 1, GL_BYTE }, { 2, GL_BYTE }, { 3, GL_BYTE },
255                { 4, GL_BYTE }, /* int8_t */
256            { 1, GL_UNSIGNED_BYTE }, { 2, GL_UNSIGNED_BYTE },
257                { 3, GL_UNSIGNED_BYTE }, { 4, GL_UNSIGNED_BYTE }, /* uint8_t */
258            { 1, GL_SHORT }, { 2, GL_SHORT }, { 3, GL_SHORT },
259                { 4, GL_SHORT }, /* int16_t */
260            { 1, GL_UNSIGNED_SHORT }, { 2, GL_UNSIGNED_SHORT }, { 3,
261                GL_UNSIGNED_SHORT }, { 4, GL_UNSIGNED_SHORT }, /* uint16_t */
262            { 1, GL_INT }, { 2, GL_INT }, { 3, GL_INT },
263                { 4, GL_INT }, /* int32_t */
264            { 1, GL_UNSIGNED_INT }, { 2, GL_UNSIGNED_INT },
265                { 3, GL_UNSIGNED_INT }, { 4, GL_UNSIGNED_INT }, /* uint32_t */
266        };
267
268        int type_index = m_streams[attr_index].stream_type;
269        if (type_index < 0 || type_index >= sizeof(tlut) / sizeof(*tlut))
270            type_index = 0;
271
272        glVertexAttribPointer((GLint)reg, tlut[type_index].size,
273                              tlut[type_index].type, GL_FALSE,
274                              stride, (GLvoid const *)(uintptr_t)offset);
275    }
276#endif
277}
278
279void VertexDeclaration::Initialize()
280{
281#if defined _XBOX || defined USE_D3D9
282    static D3DVERTEXELEMENT9 const end_element[] = { D3DDECL_END() };
283    static D3DDECLTYPE const X = D3DDECLTYPE_UNUSED;
284    static D3DDECLTYPE const tlut[] =
285    {
286        D3DDECLTYPE_UNUSED,
287        X, D3DDECLTYPE_FLOAT16_2, X, D3DDECLTYPE_FLOAT16_4, /* half */
288        D3DDECLTYPE_FLOAT1, D3DDECLTYPE_FLOAT2, D3DDECLTYPE_FLOAT3,
289            D3DDECLTYPE_FLOAT4, /* float */
290        X, X, X, X, /* double */
291        X, X, X, X, /* int8_t */
292        X, X, X, D3DDECLTYPE_UBYTE4, /* uint8_t */
293        X, D3DDECLTYPE_SHORT2N, X, D3DDECLTYPE_SHORT4N, /* int16_t */
294        X, D3DDECLTYPE_USHORT2N, X, D3DDECLTYPE_USHORT4N, /* uint16_t */
295        X, X, X, X, /* int32_t */
296        X, X, X, X, /* int64_t */
297    };
298    static D3DDECLUSAGE const ulut[] =
299    {
300        D3DDECLUSAGE_POSITION,
301        D3DDECLUSAGE_BLENDWEIGHT,
302        D3DDECLUSAGE_BLENDINDICES,
303        D3DDECLUSAGE_NORMAL,
304        D3DDECLUSAGE_PSIZE,
305        D3DDECLUSAGE_TEXCOORD,
306        D3DDECLUSAGE_TANGENT,
307        D3DDECLUSAGE_BINORMAL,
308        D3DDECLUSAGE_TESSFACTOR,
309#if defined _XBOX
310        D3DDECLUSAGE_TEXCOORD, /* FIXME: nonexistent */
311#else
312        D3DDECLUSAGE_POSITIONT,
313#endif
314        D3DDECLUSAGE_COLOR,
315        D3DDECLUSAGE_FOG,
316        D3DDECLUSAGE_DEPTH,
317        D3DDECLUSAGE_SAMPLE,
318    };
319
320    D3DVERTEXELEMENT9 elements[12 + 1];
321    for (int n = 0; n < m_count; n++)
322    {
323        elements[n].Stream = m_streams[n].index;
324        elements[n].Offset = 0;
325        for (int i = 0; i < n; i++)
326            if (m_streams[i].index == m_streams[n].index)
327                elements[n].Offset += m_streams[i].size;
328
329        if (m_streams[n].stream_type >= 0
330             && m_streams[n].stream_type < sizeof(tlut) / sizeof(*tlut))
331            elements[n].Type = tlut[m_streams[n].stream_type];
332        else
333            elements[n].Type = D3DDECLTYPE_UNUSED;
334
335        elements[n].Method = D3DDECLMETHOD_DEFAULT;
336
337        if (m_streams[n].usage >= 0
338             && m_streams[n].usage < sizeof(ulut) / sizeof(*ulut))
339            elements[n].Usage = ulut[m_streams[n].usage];
340        else
341            elements[n].Usage = D3DDECLUSAGE_POSITION;
342
343        elements[n].UsageIndex = 0;
344        for (int i = 0; i < n; i++)
345            if (elements[i].Stream == elements[n].Stream
346                 && elements[i].Usage == elements[n].Usage)
347                elements[n].UsageIndex++;
348    }
349    elements[m_count] = end_element[0];
350
351#   if defined USE_D3D9
352    IDirect3DVertexDeclaration9 *vdecl;
353#   elif defined _XBOX
354    D3DVertexDeclaration *vdecl;
355#   endif
356
357    if (FAILED(g_d3ddevice->CreateVertexDeclaration(elements, &vdecl)))
358        Abort();
359
360    m_data = vdecl;
361#else
362
363#endif
364}
365
366void VertexDeclaration::AddStream(VertexStreamBase const &s)
367{
368    int index = m_count ? m_streams[m_count - 1].index + 1 : 0;
369
370    for (int i = 0; s.m_streams[i].size; i++)
371    {
372        m_streams[m_count].stream_type = s.m_streams[i].stream_type;
373        m_streams[m_count].usage = s.m_streams[i].usage;
374        m_streams[m_count].size = s.m_streams[i].size;
375        m_streams[m_count].index = index;
376        m_count++;
377    }
378}
379
380//
381// The VertexBuffer class
382// ----------------------
383//
384
385VertexBuffer::VertexBuffer(size_t size)
386  : m_data(new VertexBufferData)
387{
388#if defined USE_D3D9 || defined _XBOX
389    if (FAILED(g_d3ddevice->CreateVertexBuffer(size, D3DUSAGE_WRITEONLY, NULL,
390                                               D3DPOOL_MANAGED, &m_data->m_vbo, NULL)))
391        Abort();
392#elif !defined __CELLOS_LV2__ && !defined __ANDROID__
393    glGenBuffers(1, &m_data->m_vbo);
394    m_data->m_memory = new uint8_t[size];
395    m_data->m_size = size;
396#endif
397}
398
399VertexBuffer::~VertexBuffer()
400{
401#if defined USE_D3D9 || defined _XBOX
402    if (FAILED(m_data->m_vbo->Release()))
403        Abort();
404#elif !defined __CELLOS_LV2__ && !defined __ANDROID__
405    glDeleteBuffers(1, &m_data->m_vbo);
406    delete[] m_data->m_memory;
407#endif
408}
409
410void *VertexBuffer::Lock(size_t offset, size_t size)
411{
412#if defined USE_D3D9 || defined _XBOX
413    void *ret;
414    if (FAILED(m_data->m_vbo->Lock(offset, size, (void **)&ret, 0)))
415        Abort();
416    return ret;
417#elif !defined __CELLOS_LV2__ && !defined __ANDROID__
418    return m_data->m_memory + offset;
419#endif
420}
421
422void VertexBuffer::Unlock()
423{
424#if defined USE_D3D9 || defined _XBOX
425    if (FAILED(m_data->m_vbo->Unlock()))
426        Abort();
427#elif !defined __CELLOS_LV2__ && !defined __ANDROID__
428    glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo);
429    glBufferData(GL_ARRAY_BUFFER, m_data->m_size, m_data->m_memory,
430                 GL_STATIC_DRAW);
431#endif
432}
433
434} /* namespace lol */
435
Note: See TracBrowser for help on using the repository browser.