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

Last change on this file since 1324 was 1324, checked in by sam, 9 years ago

gpu: fix a memory leak in the VertexBuffer and IndexBuffer classes.

File size: 16.5 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 __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    g_d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, 1);
127    g_d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
128    g_d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
129    if (FAILED(g_d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW)))
130        Abort();
131    switch (type)
132    {
133    case MeshPrimitive::Triangles:
134        if (FAILED(g_d3ddevice->DrawPrimitive(D3DPT_TRIANGLELIST, skip, count)))
135            Abort();
136        break;
137    }
138#else
139#   if defined HAVE_GL_2X && !defined __APPLE__
140    glEnable(GL_ALPHA_TEST);
141    glAlphaFunc(GL_GEQUAL, 0.01f);
142#   endif
143    glEnable(GL_BLEND);
144    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
145
146    switch (type)
147    {
148    case MeshPrimitive::Triangles:
149        glDrawArrays(GL_TRIANGLES, skip * 3, count * 3);
150        break;
151    }
152#endif
153}
154
155void VertexDeclaration::DrawIndexedElements(MeshPrimitive type, int vbase,
156                                            int vskip, int vcount,
157                                            int skip, int count)
158{
159#if defined _XBOX || defined USE_D3D9
160    g_d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, 1);
161    g_d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
162    g_d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
163    g_d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
164    switch (type)
165    {
166    case MeshPrimitive::Triangles:
167        if (FAILED(g_d3ddevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, vbase, vskip, vcount, skip, count)))
168            Abort();
169        break;
170    }
171#else
172#   if defined HAVE_GL_2X && !defined __APPLE__
173    glEnable(GL_ALPHA_TEST);
174    glAlphaFunc(GL_GEQUAL, 0.01f);
175#   endif
176    glEnable(GL_BLEND);
177    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
178
179    switch (type)
180    {
181    case MeshPrimitive::Triangles:
182        /* FIXME: ignores most of the arguments! */
183        glDrawElements(GL_TRIANGLES, count * 3, GL_UNSIGNED_SHORT, 0);
184        break;
185    }
186#endif
187}
188
189void VertexDeclaration::Unbind()
190{
191#if defined _XBOX || defined USE_D3D9
192    int stream = -1;
193    for (int i = 0; i < m_count; i++)
194        if (m_streams[i].index != stream)
195        {
196            stream = m_streams[i].index;
197            if (FAILED(g_d3ddevice->SetStreamSource(stream, 0, 0, 0)))
198                Abort();
199        }
200    if (FAILED(g_d3ddevice->SetVertexDeclaration(NULL)))
201        Abort();
202#else
203    /* FIXME: we need to unbind what we bound */
204    //glDisableVertexAttribArray(m_attrib);
205    /* FIXME: only useful for VAOs */
206    //glBindBuffer(GL_ARRAY_BUFFER, 0);
207    /* Or: */
208    //glDisableVertexAttribArray(m_attrib);
209    /* Or even: */
210    //glDisableClientState(GL_VERTEX_ARRAY);
211#endif
212}
213
214void VertexDeclaration::SetStream(VertexBuffer *vb, ShaderAttrib attr1,
215                                                    ShaderAttrib attr2,
216                                                    ShaderAttrib attr3,
217                                                    ShaderAttrib attr4,
218                                                    ShaderAttrib attr5,
219                                                    ShaderAttrib attr6,
220                                                    ShaderAttrib attr7,
221                                                    ShaderAttrib attr8,
222                                                    ShaderAttrib attr9,
223                                                    ShaderAttrib attr10,
224                                                    ShaderAttrib attr11,
225                                                    ShaderAttrib attr12)
226{
227#if defined _XBOX || defined USE_D3D9
228    /* Only the first item is required to know which stream this
229     * is about; the rest of the information is stored in the
230     * vertex declaration already. */
231    uint32_t usage = (attr1.m_flags >> 16) & 0xffff;
232    uint32_t index = attr1.m_flags & 0xffff;
233
234    /* Find the stream number */
235    int usage_index = 0, stream = -1;
236    for (int i = 0; i < m_count; i++)
237        if (m_streams[i].usage == usage)
238            if (usage_index++ == index)
239            {
240                stream = m_streams[i].index;
241                break;
242            }
243
244    /* Compute this stream's stride */
245    int stride = 0;
246    for (int i = 0; i < m_count; i++)
247        if (stream == m_streams[i].index)
248            stride += m_streams[i].size;
249
250    /* Now we know the stream index and the element stride */
251    /* FIXME: precompute most of the crap above! */
252    if (stream >= 0)
253    {
254        if (FAILED(g_d3ddevice->SetStreamSource(stream, vb->m_data->m_vbo, 0, stride)))
255            Abort();
256    }
257#else
258    glBindBuffer(GL_ARRAY_BUFFER, vb->m_data->m_vbo);
259    ShaderAttrib l[12] = { attr1, attr2, attr3, attr4, attr5, attr6,
260                           attr7, attr8, attr9, attr10, attr11, attr12 };
261    for (int n = 0; n < 12 && l[n].m_flags != (uint64_t)0 - 1; n++)
262    {
263        uint32_t reg = l[n].m_flags >> 32;
264        uint32_t usage = (l[n].m_flags >> 16) & 0xffff;
265        uint32_t index = l[n].m_flags & 0xffff;
266
267#   if !defined __CELLOS_LV2__
268        glEnableVertexAttribArray((GLint)reg);
269#   else
270        switch (usage)
271        {
272        case VertexUsage::Position:
273            glEnableClientState(GL_VERTEX_ARRAY);
274            break;
275        case VertexUsage::Color:
276            glEnableClientState(GL_COLOR_ARRAY);
277            break;
278        }
279#   endif
280
281        /* We need to parse the whole vertex declaration to retrieve
282         * the information. It sucks. */
283
284        int attr_index = 0, usage_index = 0;
285        /* First, find the stream index */
286        for (; attr_index < m_count; attr_index++)
287            if (m_streams[attr_index].usage == usage)
288                if (usage_index++ == index)
289                    break;
290
291        /* Now compute the stride and offset up to this stream index */
292        int stride = 0, offset = 0;
293        for (int i = 0; i < m_count; i++)
294            if (m_streams[i].index == m_streams[attr_index].index)
295            {
296                stride += m_streams[i].size;
297                if (i < attr_index)
298                    offset += m_streams[i].size;
299            }
300
301        /* Finally, we need to retrieve the type of the data */
302#   if !defined GL_DOUBLE
303#       define GL_DOUBLE 0
304#   endif
305        static struct { GLint size; GLenum type; } const tlut[] =
306        {
307            { 0, 0 },
308            { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, /* half */
309            { 1, GL_FLOAT }, { 2, GL_FLOAT }, { 3, GL_FLOAT },
310                { 4, GL_FLOAT }, /* float */
311            { 1, GL_DOUBLE }, { 2, GL_DOUBLE }, { 3, GL_DOUBLE },
312                { 4, GL_DOUBLE }, /* double */
313            { 1, GL_BYTE }, { 2, GL_BYTE }, { 3, GL_BYTE },
314                { 4, GL_BYTE }, /* int8_t */
315            { 1, GL_UNSIGNED_BYTE }, { 2, GL_UNSIGNED_BYTE },
316                { 3, GL_UNSIGNED_BYTE }, { 4, GL_UNSIGNED_BYTE }, /* uint8_t */
317            { 1, GL_SHORT }, { 2, GL_SHORT }, { 3, GL_SHORT },
318                { 4, GL_SHORT }, /* int16_t */
319            { 1, GL_UNSIGNED_SHORT }, { 2, GL_UNSIGNED_SHORT }, { 3,
320                GL_UNSIGNED_SHORT }, { 4, GL_UNSIGNED_SHORT }, /* uint16_t */
321            { 1, GL_INT }, { 2, GL_INT }, { 3, GL_INT },
322                { 4, GL_INT }, /* int32_t */
323            { 1, GL_UNSIGNED_INT }, { 2, GL_UNSIGNED_INT },
324                { 3, GL_UNSIGNED_INT }, { 4, GL_UNSIGNED_INT }, /* uint32_t */
325        };
326
327        int type_index = m_streams[attr_index].stream_type;
328        if (type_index < 0 || type_index >= sizeof(tlut) / sizeof(*tlut))
329            type_index = 0;
330
331        /* Normalize unsigned bytes by default, because it's usually
332         * some color information. */
333        GLboolean normalize = (tlut[type_index].type == GL_UNSIGNED_BYTE)
334                           || (tlut[type_index].type == GL_BYTE);
335
336#   if !defined __CELLOS_LV2__
337        glVertexAttribPointer((GLint)reg, tlut[type_index].size,
338                              tlut[type_index].type, normalize,
339                              stride, (GLvoid const *)(uintptr_t)offset);
340#   else
341        switch (usage)
342        {
343        case VertexUsage::Position:
344            glVertexPointer(tlut[type_index].size, tlut[type_index].type,
345                            stride, (GLvoid const *)(uintptr_t)offset);
346            break;
347        case VertexUsage::Normal:
348            glNormalPointer(tlut[type_index].type,
349                            stride, (GLvoid const *)(uintptr_t)offset);
350            break;
351        case VertexUsage::Color:
352            glColorPointer(tlut[type_index].size, tlut[type_index].type,
353                           stride, (GLvoid const *)(uintptr_t)offset);
354            break;
355        }
356#   endif
357    }
358#endif
359}
360
361void VertexDeclaration::Initialize()
362{
363#if defined _XBOX || defined USE_D3D9
364    static D3DVERTEXELEMENT9 const end_element[] = { D3DDECL_END() };
365    static D3DDECLTYPE const X = D3DDECLTYPE_UNUSED;
366    static D3DDECLTYPE const tlut[] =
367    {
368        D3DDECLTYPE_UNUSED,
369        X, D3DDECLTYPE_FLOAT16_2, X, D3DDECLTYPE_FLOAT16_4, /* half */
370        D3DDECLTYPE_FLOAT1, D3DDECLTYPE_FLOAT2, D3DDECLTYPE_FLOAT3,
371            D3DDECLTYPE_FLOAT4, /* float */
372        X, X, X, X, /* double */
373        X, X, X, X, /* int8_t */
374        X, X, X, D3DDECLTYPE_UBYTE4N, /* uint8_t */
375        X, D3DDECLTYPE_SHORT2N, X, D3DDECLTYPE_SHORT4N, /* int16_t */
376        X, D3DDECLTYPE_USHORT2N, X, D3DDECLTYPE_USHORT4N, /* uint16_t */
377        X, X, X, X, /* int32_t */
378        X, X, X, X, /* uint32_t */
379    };
380    static D3DDECLUSAGE const ulut[] =
381    {
382        D3DDECLUSAGE_POSITION,
383        D3DDECLUSAGE_BLENDWEIGHT,
384        D3DDECLUSAGE_BLENDINDICES,
385        D3DDECLUSAGE_NORMAL,
386        D3DDECLUSAGE_PSIZE,
387        D3DDECLUSAGE_TEXCOORD,
388        D3DDECLUSAGE_TANGENT,
389        D3DDECLUSAGE_BINORMAL,
390        D3DDECLUSAGE_TESSFACTOR,
391#if defined _XBOX
392        D3DDECLUSAGE_TEXCOORD, /* FIXME: nonexistent */
393#else
394        D3DDECLUSAGE_POSITIONT,
395#endif
396        D3DDECLUSAGE_COLOR,
397        D3DDECLUSAGE_FOG,
398        D3DDECLUSAGE_DEPTH,
399        D3DDECLUSAGE_SAMPLE,
400    };
401
402    D3DVERTEXELEMENT9 elements[12 + 1];
403    for (int n = 0; n < m_count; n++)
404    {
405        elements[n].Stream = m_streams[n].index;
406        elements[n].Offset = 0;
407        for (int i = 0; i < n; i++)
408            if (m_streams[i].index == m_streams[n].index)
409                elements[n].Offset += m_streams[i].size;
410
411        if (m_streams[n].stream_type >= 0
412             && m_streams[n].stream_type < sizeof(tlut) / sizeof(*tlut))
413            elements[n].Type = tlut[m_streams[n].stream_type];
414        else
415            elements[n].Type = D3DDECLTYPE_UNUSED;
416
417        elements[n].Method = D3DDECLMETHOD_DEFAULT;
418
419        if (m_streams[n].usage >= 0
420             && m_streams[n].usage < sizeof(ulut) / sizeof(*ulut))
421            elements[n].Usage = ulut[m_streams[n].usage];
422        else
423            elements[n].Usage = D3DDECLUSAGE_POSITION;
424
425        elements[n].UsageIndex = 0;
426        for (int i = 0; i < n; i++)
427            if (elements[i].Stream == elements[n].Stream
428                 && elements[i].Usage == elements[n].Usage)
429                elements[n].UsageIndex++;
430    }
431    elements[m_count] = end_element[0];
432
433#   if defined USE_D3D9
434    IDirect3DVertexDeclaration9 *vdecl;
435#   elif defined _XBOX
436    D3DVertexDeclaration *vdecl;
437#   endif
438
439    if (FAILED(g_d3ddevice->CreateVertexDeclaration(elements, &vdecl)))
440        Abort();
441
442    m_data = vdecl;
443#else
444
445#endif
446}
447
448void VertexDeclaration::AddStream(VertexStreamBase const &s)
449{
450    int index = m_count ? m_streams[m_count - 1].index + 1 : 0;
451
452    for (int i = 0; s.m_streams[i].size; i++)
453    {
454        m_streams[m_count].stream_type = s.m_streams[i].stream_type;
455        m_streams[m_count].usage = s.m_streams[i].usage;
456        m_streams[m_count].size = s.m_streams[i].size;
457        m_streams[m_count].index = index;
458        m_count++;
459    }
460}
461
462//
463// The VertexBuffer class
464// ----------------------
465//
466
467VertexBuffer::VertexBuffer(size_t size)
468  : m_data(new VertexBufferData)
469{
470#if defined USE_D3D9 || defined _XBOX
471    if (FAILED(g_d3ddevice->CreateVertexBuffer(size, D3DUSAGE_WRITEONLY, NULL,
472                                               D3DPOOL_MANAGED, &m_data->m_vbo, NULL)))
473        Abort();
474#elif !defined __CELLOS_LV2__ && !defined __ANDROID__
475    glGenBuffers(1, &m_data->m_vbo);
476    m_data->m_memory = new uint8_t[size];
477    m_data->m_size = size;
478#endif
479}
480
481VertexBuffer::~VertexBuffer()
482{
483#if defined USE_D3D9 || defined _XBOX
484    if (FAILED(m_data->m_vbo->Release()))
485        Abort();
486#elif !defined __CELLOS_LV2__ && !defined __ANDROID__
487    glDeleteBuffers(1, &m_data->m_vbo);
488    delete[] m_data->m_memory;
489#endif
490    delete m_data;
491}
492
493void *VertexBuffer::Lock(size_t offset, size_t size)
494{
495#if defined USE_D3D9 || defined _XBOX
496    void *ret;
497    if (FAILED(m_data->m_vbo->Lock(offset, size, (void **)&ret, 0)))
498        Abort();
499    return ret;
500#elif !defined __CELLOS_LV2__ && !defined __ANDROID__
501    return m_data->m_memory + offset;
502#endif
503}
504
505void VertexBuffer::Unlock()
506{
507#if defined USE_D3D9 || defined _XBOX
508    if (FAILED(m_data->m_vbo->Unlock()))
509        Abort();
510#elif !defined __CELLOS_LV2__ && !defined __ANDROID__
511    glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo);
512    glBufferData(GL_ARRAY_BUFFER, m_data->m_size, m_data->m_memory,
513                 GL_STATIC_DRAW);
514#endif
515}
516
517} /* namespace lol */
518
Note: See TracBrowser for help on using the repository browser.