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

Last change on this file since 1532 was 1532, checked in by sam, 11 years ago

gpu: fix vertex and index buffer behaviour on the PS3.

File size: 18.6 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    size_t m_size;
46
47#if defined USE_D3D9
48    IDirect3DVertexBuffer9 *m_vbo;
49#elif defined _XBOX
50    D3DVertexBuffer *m_vbo;
51#else
52    GLuint m_vbo;
53    uint8_t *m_memory;
54#endif
55};
56
57//
58// The VertexDeclaration class
59// ---------------------------
60//
61
62VertexStreamBase const VertexStreamBase::Empty;
63
64VertexDeclaration::VertexDeclaration(VertexStreamBase const &s1,
65                                     VertexStreamBase const &s2,
66                                     VertexStreamBase const &s3,
67                                     VertexStreamBase const &s4,
68                                     VertexStreamBase const &s5,
69                                     VertexStreamBase const &s6,
70                                     VertexStreamBase const &s7,
71                                     VertexStreamBase const &s8,
72                                     VertexStreamBase const &s9,
73                                     VertexStreamBase const &s10,
74                                     VertexStreamBase const &s11,
75                                     VertexStreamBase const &s12) : m_count(0)
76{
77    if (&s1 != &VertexStreamBase::Empty) AddStream(s1);
78    if (&s2 != &VertexStreamBase::Empty) AddStream(s2);
79    if (&s3 != &VertexStreamBase::Empty) AddStream(s3);
80    if (&s4 != &VertexStreamBase::Empty) AddStream(s4);
81    if (&s5 != &VertexStreamBase::Empty) AddStream(s5);
82    if (&s6 != &VertexStreamBase::Empty) AddStream(s6);
83    if (&s7 != &VertexStreamBase::Empty) AddStream(s7);
84    if (&s8 != &VertexStreamBase::Empty) AddStream(s8);
85    if (&s9 != &VertexStreamBase::Empty) AddStream(s9);
86    if (&s10 != &VertexStreamBase::Empty) AddStream(s10);
87    if (&s11 != &VertexStreamBase::Empty) AddStream(s11);
88    if (&s12 != &VertexStreamBase::Empty) AddStream(s12);
89    Initialize();
90}
91
92VertexDeclaration::~VertexDeclaration()
93{
94#if defined _XBOX || defined USE_D3D9
95#   if defined USE_D3D9
96    IDirect3DVertexDeclaration9 *vdecl = (IDirect3DVertexDeclaration9 *)m_data;
97#   elif defined _XBOX
98    D3DVertexDeclaration *vdecl = (D3DVertexDeclaration *)m_data;
99#   endif
100
101    if (FAILED(vdecl->Release()))
102        Abort();
103#else
104
105#endif
106}
107
108void VertexDeclaration::Bind()
109{
110#if defined _XBOX || defined USE_D3D9
111#   if defined USE_D3D9
112    IDirect3DVertexDeclaration9 *vdecl = (IDirect3DVertexDeclaration9 *)m_data;
113#   elif defined _XBOX
114    D3DVertexDeclaration *vdecl = (D3DVertexDeclaration *)m_data;
115#   endif
116
117    if (FAILED(g_d3ddevice->SetVertexDeclaration(vdecl)))
118        Abort();
119#else
120    /* FIXME: Nothing to do? */
121#endif
122}
123
124void VertexDeclaration::DrawElements(MeshPrimitive type, int skip, int count)
125{
126    if (count <= 0)
127        return;
128
129#if defined _XBOX || defined USE_D3D9
130    g_d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, 1);
131    g_d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
132    g_d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
133    if (FAILED(g_d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW)))
134        Abort();
135    switch (type)
136    {
137    case MeshPrimitive::Triangles:
138        if (FAILED(g_d3ddevice->DrawPrimitive(D3DPT_TRIANGLELIST, skip, count)))
139            Abort();
140        break;
141    case MeshPrimitive::Points:
142        if (FAILED(g_d3ddevice->DrawPrimitive(D3DPT_POINTLIST, skip, count)))
143            Abort();
144        break;
145    }
146#else
147    glFrontFace(GL_CCW);
148    glEnable(GL_CULL_FACE);
149#   if defined HAVE_GL_2X && !defined __APPLE__
150    /* FIXME: this has nothing to do here! */
151    glEnable(GL_ALPHA_TEST);
152    glAlphaFunc(GL_GEQUAL, 0.01f);
153#   endif
154    glEnable(GL_BLEND);
155    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
156
157    switch (type)
158    {
159    case MeshPrimitive::Triangles:
160        glDrawArrays(GL_TRIANGLES, skip * 3, count * 3);
161        break;
162    case MeshPrimitive::Points:
163        glDrawArrays(GL_POINTS, skip, count);
164        break;
165    }
166#   if defined HAVE_GL_2X && !defined __APPLE__
167    /* FIXME: this has nothing to do here! */
168    glDisable(GL_ALPHA_TEST);
169#   endif
170#endif
171}
172
173void VertexDeclaration::DrawIndexedElements(MeshPrimitive type, int vbase,
174                                            int vskip, int vcount,
175                                            int skip, int count)
176{
177    if (count <= 0)
178        return;
179
180#if defined _XBOX || defined USE_D3D9
181    g_d3ddevice->SetRenderState(D3DRS_ALPHABLENDENABLE, 1);
182    g_d3ddevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
183    g_d3ddevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
184    g_d3ddevice->SetRenderState(D3DRS_CULLMODE, D3DCULL_CW);
185    switch (type)
186    {
187    case MeshPrimitive::Triangles:
188        if (FAILED(g_d3ddevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST, vbase, vskip, vcount, skip, count)))
189            Abort();
190        break;
191    case MeshPrimitive::Points:
192        if (FAILED(g_d3ddevice->DrawIndexedPrimitive(D3DPT_POINTLIST, vbase, vskip, vcount, skip, count)))
193            Abort();
194        break;
195    }
196#else
197#   if defined HAVE_GL_2X && !defined __APPLE__
198    /* FIXME: this has nothing to do here! */
199    glEnable(GL_ALPHA_TEST);
200    glAlphaFunc(GL_GEQUAL, 0.01f);
201#   endif
202    glEnable(GL_BLEND);
203    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
204
205    switch (type)
206    {
207    case MeshPrimitive::Triangles:
208        /* FIXME: ignores most of the arguments! */
209        glDrawElements(GL_TRIANGLES, count * 3, GL_UNSIGNED_SHORT, 0);
210        break;
211    case MeshPrimitive::Points:
212        /* FIXME: ignores most of the arguments! */
213        glDrawElements(GL_POINTS, count, GL_UNSIGNED_SHORT, 0);
214        break;
215    }
216#   if defined HAVE_GL_2X && !defined __APPLE__
217    /* FIXME: this has nothing to do here! */
218    glDisable(GL_ALPHA_TEST);
219#   endif
220#endif
221}
222
223void VertexDeclaration::Unbind()
224{
225#if defined _XBOX || defined USE_D3D9
226    int stream = -1;
227    for (int i = 0; i < m_count; i++)
228        if (m_streams[i].index != stream)
229        {
230            stream = m_streams[i].index;
231            if (FAILED(g_d3ddevice->SetStreamSource(stream, 0, 0, 0)))
232                Abort();
233        }
234    if (FAILED(g_d3ddevice->SetVertexDeclaration(NULL)))
235        Abort();
236#elif !defined __CELLOS_LV2__
237    /* FIXME: we need to unbind what we bound */
238    //glDisableVertexAttribArray(m_attrib);
239    /* FIXME: temporary kludge */
240    for (int i = 0; i < 12; i++)
241        glDisableVertexAttribArray(i);
242    glBindBuffer(GL_ARRAY_BUFFER, 0);
243    /* FIXME: only useful for VAOs */
244    //glBindBuffer(GL_ARRAY_BUFFER, 0);
245    /* Or: */
246    //glDisableVertexAttribArray(m_attrib);
247#else
248    /* Or even: */
249    glDisableClientState(GL_VERTEX_ARRAY);
250    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
251    glDisableClientState(GL_NORMAL_ARRAY);
252    glDisableClientState(GL_COLOR_ARRAY);
253#endif
254}
255
256void VertexDeclaration::SetStream(VertexBuffer *vb, ShaderAttrib attr1,
257                                                    ShaderAttrib attr2,
258                                                    ShaderAttrib attr3,
259                                                    ShaderAttrib attr4,
260                                                    ShaderAttrib attr5,
261                                                    ShaderAttrib attr6,
262                                                    ShaderAttrib attr7,
263                                                    ShaderAttrib attr8,
264                                                    ShaderAttrib attr9,
265                                                    ShaderAttrib attr10,
266                                                    ShaderAttrib attr11,
267                                                    ShaderAttrib attr12)
268{
269    if (!vb->m_data->m_size)
270        return;
271
272#if defined _XBOX || defined USE_D3D9
273    /* Only the first item is required to know which stream this
274     * is about; the rest of the information is stored in the
275     * vertex declaration already. */
276    uint32_t usage = (attr1.m_flags >> 16) & 0xffff;
277    uint32_t index = attr1.m_flags & 0xffff;
278
279    /* Find the stream number */
280    int usage_index = 0, stream = -1;
281    for (int i = 0; i < m_count; i++)
282        if (m_streams[i].usage == usage)
283            if (usage_index++ == index)
284            {
285                stream = m_streams[i].index;
286                break;
287            }
288
289    /* Compute this stream's stride */
290    int stride = 0;
291    for (int i = 0; i < m_count; i++)
292        if (stream == m_streams[i].index)
293            stride += m_streams[i].size;
294
295    /* Now we know the stream index and the element stride */
296    /* FIXME: precompute most of the crap above! */
297    if (stream >= 0)
298    {
299        if (FAILED(g_d3ddevice->SetStreamSource(stream, vb->m_data->m_vbo, 0, stride)))
300            Abort();
301    }
302#else
303    glBindBuffer(GL_ARRAY_BUFFER, vb->m_data->m_vbo);
304    ShaderAttrib l[12] = { attr1, attr2, attr3, attr4, attr5, attr6,
305                           attr7, attr8, attr9, attr10, attr11, attr12 };
306    for (int n = 0; n < 12 && l[n].m_flags != (uint64_t)0 - 1; n++)
307    {
308        uint32_t reg = l[n].m_flags >> 32;
309        uint32_t usage = (l[n].m_flags >> 16) & 0xffff;
310        uint32_t index = l[n].m_flags & 0xffff;
311
312#   if !defined __CELLOS_LV2__
313        glEnableVertexAttribArray((GLint)reg);
314#   else
315        switch (usage)
316        {
317        case VertexUsage::Position:
318            glEnableClientState(GL_VERTEX_ARRAY);
319            break;
320        case VertexUsage::TexCoord:
321            glEnableClientState(GL_TEXTURE_COORD_ARRAY);
322            break;
323        case VertexUsage::Normal:
324            glEnableClientState(GL_NORMAL_ARRAY);
325            break;
326        case VertexUsage::Color:
327            glEnableClientState(GL_COLOR_ARRAY);
328            break;
329        }
330#   endif
331
332        /* We need to parse the whole vertex declaration to retrieve
333         * the information. It sucks. */
334
335        int attr_index = 0, usage_index = 0;
336        /* First, find the stream index */
337        for (; attr_index < m_count; attr_index++)
338            if (m_streams[attr_index].usage == usage)
339                if (usage_index++ == index)
340                    break;
341
342        /* Now compute the stride and offset up to this stream index */
343        int stride = 0, offset = 0;
344        for (int i = 0; i < m_count; i++)
345            if (m_streams[i].index == m_streams[attr_index].index)
346            {
347                stride += m_streams[i].size;
348                if (i < attr_index)
349                    offset += m_streams[i].size;
350            }
351
352        /* Finally, we need to retrieve the type of the data */
353#   if !defined GL_DOUBLE
354#       define GL_DOUBLE 0
355#   endif
356        static struct { GLint size; GLenum type; } const tlut[] =
357        {
358            { 0, 0 },
359            { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, /* half */
360            { 1, GL_FLOAT }, { 2, GL_FLOAT }, { 3, GL_FLOAT },
361                { 4, GL_FLOAT }, /* float */
362            { 1, GL_DOUBLE }, { 2, GL_DOUBLE }, { 3, GL_DOUBLE },
363                { 4, GL_DOUBLE }, /* double */
364            { 1, GL_BYTE }, { 2, GL_BYTE }, { 3, GL_BYTE },
365                { 4, GL_BYTE }, /* int8_t */
366            { 1, GL_UNSIGNED_BYTE }, { 2, GL_UNSIGNED_BYTE },
367                { 3, GL_UNSIGNED_BYTE }, { 4, GL_UNSIGNED_BYTE }, /* uint8_t */
368            { 1, GL_SHORT }, { 2, GL_SHORT }, { 3, GL_SHORT },
369                { 4, GL_SHORT }, /* int16_t */
370            { 1, GL_UNSIGNED_SHORT }, { 2, GL_UNSIGNED_SHORT }, { 3,
371                GL_UNSIGNED_SHORT }, { 4, GL_UNSIGNED_SHORT }, /* uint16_t */
372            { 1, GL_INT }, { 2, GL_INT }, { 3, GL_INT },
373                { 4, GL_INT }, /* int32_t */
374            { 1, GL_UNSIGNED_INT }, { 2, GL_UNSIGNED_INT },
375                { 3, GL_UNSIGNED_INT }, { 4, GL_UNSIGNED_INT }, /* uint32_t */
376        };
377
378        int type_index = m_streams[attr_index].stream_type;
379        if (type_index < 0 || type_index >= sizeof(tlut) / sizeof(*tlut))
380            type_index = 0;
381
382
383#   if !defined __CELLOS_LV2__
384        if (tlut[type_index].type == GL_FLOAT
385             || tlut[type_index].type == GL_DOUBLE
386             || tlut[type_index].type == GL_BYTE
387             || tlut[type_index].type == GL_UNSIGNED_BYTE)
388        {
389            /* Normalize unsigned bytes by default, because it's usually
390             * some color information. */
391            GLboolean normalize = (tlut[type_index].type == GL_UNSIGNED_BYTE)
392                               || (tlut[type_index].type == GL_BYTE);
393            glVertexAttribPointer((GLint)reg, tlut[type_index].size,
394                                  tlut[type_index].type, normalize,
395                                  stride, (GLvoid const *)(uintptr_t)offset);
396        }
397#       if defined GL_VERSION_3_0
398        else
399        {
400            glVertexAttribIPointer((GLint)reg, tlut[type_index].size,
401                                   tlut[type_index].type,
402                                   stride, (GLvoid const *)(uintptr_t)offset);
403        }
404#       endif
405#   else
406        switch (usage)
407        {
408        case VertexUsage::Position:
409            glVertexPointer(tlut[type_index].size, tlut[type_index].type,
410                            stride, (GLvoid const *)(uintptr_t)offset);
411            break;
412        case VertexUsage::Normal:
413            glNormalPointer(tlut[type_index].type,
414                            stride, (GLvoid const *)(uintptr_t)offset);
415            break;
416        case VertexUsage::Color:
417            glColorPointer(tlut[type_index].size, tlut[type_index].type,
418                           stride, (GLvoid const *)(uintptr_t)offset);
419            break;
420        }
421#   endif
422    }
423#endif
424}
425
426void VertexDeclaration::Initialize()
427{
428#if defined _XBOX || defined USE_D3D9
429    static D3DVERTEXELEMENT9 const end_element[] = { D3DDECL_END() };
430    static D3DDECLTYPE const X = D3DDECLTYPE_UNUSED;
431    static D3DDECLTYPE const tlut[] =
432    {
433        D3DDECLTYPE_UNUSED,
434        X, D3DDECLTYPE_FLOAT16_2, X, D3DDECLTYPE_FLOAT16_4, /* half */
435        D3DDECLTYPE_FLOAT1, D3DDECLTYPE_FLOAT2, D3DDECLTYPE_FLOAT3,
436            D3DDECLTYPE_FLOAT4, /* float */
437        X, X, X, X, /* double */
438        X, X, X, X, /* int8_t */
439        X, X, X, D3DDECLTYPE_UBYTE4N, /* uint8_t */
440        X, D3DDECLTYPE_SHORT2N, X, D3DDECLTYPE_SHORT4N, /* int16_t */
441        X, D3DDECLTYPE_USHORT2N, X, D3DDECLTYPE_USHORT4N, /* uint16_t */
442        X, X, X, X, /* int32_t */
443        X, X, X, X, /* uint32_t */
444    };
445    static D3DDECLUSAGE const ulut[] =
446    {
447        D3DDECLUSAGE_POSITION,
448        D3DDECLUSAGE_BLENDWEIGHT,
449        D3DDECLUSAGE_BLENDINDICES,
450        D3DDECLUSAGE_NORMAL,
451        D3DDECLUSAGE_PSIZE,
452        D3DDECLUSAGE_TEXCOORD,
453        D3DDECLUSAGE_TANGENT,
454        D3DDECLUSAGE_BINORMAL,
455        D3DDECLUSAGE_TESSFACTOR,
456#if defined _XBOX
457        D3DDECLUSAGE_TEXCOORD, /* FIXME: nonexistent */
458#else
459        D3DDECLUSAGE_POSITIONT,
460#endif
461        D3DDECLUSAGE_COLOR,
462        D3DDECLUSAGE_FOG,
463        D3DDECLUSAGE_DEPTH,
464        D3DDECLUSAGE_SAMPLE,
465    };
466
467    D3DVERTEXELEMENT9 elements[12 + 1];
468    for (int n = 0; n < m_count; n++)
469    {
470        elements[n].Stream = m_streams[n].index;
471        elements[n].Offset = 0;
472        for (int i = 0; i < n; i++)
473            if (m_streams[i].index == m_streams[n].index)
474                elements[n].Offset += m_streams[i].size;
475
476        if (m_streams[n].stream_type >= 0
477             && m_streams[n].stream_type < sizeof(tlut) / sizeof(*tlut))
478            elements[n].Type = tlut[m_streams[n].stream_type];
479        else
480            elements[n].Type = D3DDECLTYPE_UNUSED;
481
482        elements[n].Method = D3DDECLMETHOD_DEFAULT;
483
484        if (m_streams[n].usage >= 0
485             && m_streams[n].usage < sizeof(ulut) / sizeof(*ulut))
486            elements[n].Usage = ulut[m_streams[n].usage];
487        else
488            elements[n].Usage = D3DDECLUSAGE_POSITION;
489
490        elements[n].UsageIndex = 0;
491        for (int i = 0; i < n; i++)
492            if (elements[i].Stream == elements[n].Stream
493                 && elements[i].Usage == elements[n].Usage)
494                elements[n].UsageIndex++;
495    }
496    elements[m_count] = end_element[0];
497
498#   if defined USE_D3D9
499    IDirect3DVertexDeclaration9 *vdecl;
500#   elif defined _XBOX
501    D3DVertexDeclaration *vdecl;
502#   endif
503
504    if (FAILED(g_d3ddevice->CreateVertexDeclaration(elements, &vdecl)))
505        Abort();
506
507    m_data = vdecl;
508#else
509
510#endif
511}
512
513void VertexDeclaration::AddStream(VertexStreamBase const &s)
514{
515    int index = m_count ? m_streams[m_count - 1].index + 1 : 0;
516
517    for (int i = 0; s.m_streams[i].size; i++)
518    {
519        m_streams[m_count].stream_type = s.m_streams[i].stream_type;
520        m_streams[m_count].usage = s.m_streams[i].usage;
521        m_streams[m_count].size = s.m_streams[i].size;
522        m_streams[m_count].index = index;
523        m_count++;
524    }
525}
526
527//
528// The VertexBuffer class
529// ----------------------
530//
531
532VertexBuffer::VertexBuffer(size_t size)
533  : m_data(new VertexBufferData)
534{
535    m_data->m_size = size;
536    if (!size)
537        return;
538#if defined USE_D3D9 || defined _XBOX
539    if (FAILED(g_d3ddevice->CreateVertexBuffer(size, D3DUSAGE_WRITEONLY, NULL,
540                                               D3DPOOL_MANAGED, &m_data->m_vbo, NULL)))
541        Abort();
542#else
543    glGenBuffers(1, &m_data->m_vbo);
544    m_data->m_memory = new uint8_t[size];
545#endif
546}
547
548VertexBuffer::~VertexBuffer()
549{
550    if (m_data->m_size)
551    {
552#if defined USE_D3D9 || defined _XBOX
553        if (FAILED(m_data->m_vbo->Release()))
554            Abort();
555#else
556        glDeleteBuffers(1, &m_data->m_vbo);
557        delete[] m_data->m_memory;
558#endif
559    }
560    delete m_data;
561}
562
563void *VertexBuffer::Lock(size_t offset, size_t size)
564{
565    if (!m_data->m_size)
566        return NULL;
567#if defined USE_D3D9 || defined _XBOX
568    void *ret;
569    if (FAILED(m_data->m_vbo->Lock(offset, size, (void **)&ret, 0)))
570        Abort();
571    return ret;
572#else
573    return m_data->m_memory + offset;
574#endif
575}
576
577void VertexBuffer::Unlock()
578{
579    if (!m_data->m_size)
580        return;
581#if defined USE_D3D9 || defined _XBOX
582    if (FAILED(m_data->m_vbo->Unlock()))
583        Abort();
584#else
585    glBindBuffer(GL_ARRAY_BUFFER, m_data->m_vbo);
586    glBufferData(GL_ARRAY_BUFFER, m_data->m_size, m_data->m_memory,
587                 GL_STATIC_DRAW);
588    glBindBuffer(GL_ARRAY_BUFFER, 0);
589#endif
590}
591
592} /* namespace lol */
593
Note: See TracBrowser for help on using the repository browser.