]> git.tdb.fi Git - libs/gl.git/blob - source/backends/opengl/vertexsetup_backend.cpp
Move all OpenGL-specific code to a separate directory
[libs/gl.git] / source / backends / opengl / vertexsetup_backend.cpp
1 #include <algorithm>
2 #include <msp/gl/extensions/arb_direct_state_access.h>
3 #include <msp/gl/extensions/arb_instanced_arrays.h>
4 #include <msp/gl/extensions/arb_vertex_array_object.h>
5 #include <msp/gl/extensions/arb_vertex_attrib_binding.h>
6 #include <msp/gl/extensions/arb_vertex_buffer_object.h>
7 #include <msp/gl/extensions/arb_vertex_shader.h>
8 #include <msp/gl/extensions/ext_gpu_shader4.h>
9 #include <msp/gl/extensions/khr_debug.h>
10 #include "buffer.h"
11 #include "vertexarray.h"
12 #include "vertexformat.h"
13 #include "vertexsetup.h"
14 #include "vertexsetup_backend.h"
15
16 using namespace std;
17
18 namespace Msp {
19 namespace GL {
20
21 OpenGLVertexSetup::OpenGLVertexSetup()
22 {
23         static Require req(ARB_vertex_array_object);
24         if(ARB_direct_state_access)
25                 glCreateVertexArrays(1, &id);
26         else
27                 glGenVertexArrays(1, &id);
28 }
29
30 OpenGLVertexSetup::~OpenGLVertexSetup()
31 {
32         glDeleteVertexArrays(1, &id);
33 }
34
35 void OpenGLVertexSetup::require_format(const VertexFormat &fmt, bool instanced)
36 {
37         if(any_of(fmt.begin(), fmt.end(), is_integer_attribute))
38                 static Require _req(EXT_gpu_shader4);
39         if(instanced)
40                 static Require req(ARB_instanced_arrays);
41 }
42
43 void OpenGLVertexSetup::update(unsigned mask) const
44 {
45         static bool direct = ARB_direct_state_access && ARB_vertex_attrib_binding;
46
47         if(mask&VertexSetup::VERTEX_ARRAY)
48                 update_vertex_array(*static_cast<const VertexSetup *>(this)->vertex_array, 0, 0, direct);
49
50         if(mask&VertexSetup::INSTANCE_ARRAY)
51                 update_vertex_array(*static_cast<const VertexSetup *>(this)->inst_array, 1, 1, direct);
52
53         if(mask&VertexSetup::INDEX_BUFFER)
54         {
55                 unsigned buf_id = static_cast<const VertexSetup *>(this)->index_buffer->id;
56                 if(direct)
57                         glVertexArrayElementBuffer(id, buf_id);
58                 else
59                         glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buf_id);
60         }
61 }
62
63 void OpenGLVertexSetup::update_vertex_array(const VertexArray &array, unsigned binding, unsigned divisor, bool direct) const
64 {
65         if(!direct)
66         {
67                 OpenGLBuffer::unbind_scratch();
68                 glBindBuffer(GL_ARRAY_BUFFER, array.get_buffer()->id);
69         }
70
71         const VertexFormat &fmt = array.get_format();
72         unsigned stride = fmt.stride();
73         if(direct)
74         {
75                 glVertexArrayVertexBuffer(id, binding, array.get_buffer()->id, 0, stride);
76                 glVertexArrayBindingDivisor(id, binding, divisor);
77         }
78
79         unsigned offset = 0;
80         for(VertexAttribute a: fmt)
81         {
82                 unsigned sem = get_attribute_semantic(a);
83                 bool integer = is_integer_attribute(a);
84                 GLenum type = get_gl_type(get_attribute_source_type(a));
85                 unsigned cc = get_attribute_component_count(a);
86                 if(direct)
87                 {
88                         if(integer)
89                                 glVertexArrayAttribIFormat(id, sem, cc, type, offset);
90                         else
91                                 glVertexArrayAttribFormat(id, sem, cc, type, true, offset);
92                         glVertexArrayAttribBinding(id, sem, binding);
93                         glEnableVertexArrayAttrib(id, sem);
94                 }
95                 else
96                 {
97                         if(integer)
98                                 glVertexAttribIPointer(sem, cc, type, stride, reinterpret_cast<void *>(offset));
99                         else
100                                 glVertexAttribPointer(sem, cc, type, true, stride, reinterpret_cast<void *>(offset));
101                         if(ARB_instanced_arrays)
102                                 glVertexAttribDivisor(sem, divisor);
103                         glEnableVertexAttribArray(sem);
104                 }
105                 offset += get_attribute_size(a);
106         }
107
108         if(!direct)
109                 glBindBuffer(GL_ARRAY_BUFFER, 0);
110 }
111
112 void OpenGLVertexSetup::unload()
113 {
114         if(ARB_direct_state_access)
115         {
116                 glVertexArrayVertexBuffer(id, 0, 0, 0, 0);
117                 glVertexArrayVertexBuffer(id, 1, 0, 0, 0);
118                 glVertexArrayElementBuffer(id, 0);
119         }
120         else
121         {
122                 glBindVertexArray(id);
123                 glBindBuffer(GL_ARRAY_BUFFER, 0);
124
125                 for(VertexAttribute a: static_cast<const VertexSetup *>(this)->vertex_format)
126                 {
127                         unsigned sem = get_attribute_semantic(a);
128                         glDisableVertexAttribArray(sem);
129                         glVertexAttribPointer(sem, 1, GL_FLOAT, false, 0, 0);
130                 }
131                 for(VertexAttribute a: static_cast<const VertexSetup *>(this)->inst_format)
132                 {
133                         unsigned sem = get_attribute_semantic(a);
134                         glDisableVertexAttribArray(sem);
135                         glVertexAttribPointer(sem, 1, GL_FLOAT, false, 0, 0);
136                 }
137
138                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
139         }
140 }
141
142 void OpenGLVertexSetup::set_debug_name(const string &name)
143 {
144 #ifdef DEBUG
145         if(KHR_debug)
146                 glObjectLabel(GL_VERTEX_ARRAY, id, name.size(), name.c_str());
147 #else
148         (void)name;
149 #endif
150 }
151
152 } // namespace GL
153 } // namespace Msp