Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
VertexArrayObjectInstance.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGL
4 using System;
5 using System.Collections.Generic;
6 using SiliconStudio.Core.Collections;
7 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
8 using OpenTK.Graphics.ES30;
9 #else
10 using OpenTK.Graphics.OpenGL;
11 #endif
12 
13 namespace SiliconStudio.Paradox.Graphics
14 {
15  internal class VertexArrayObjectInstance : IDisposable
16  {
17  private readonly VertexAttrib[] vertexAttribs;
18 
19  private readonly Dictionary<string, int> programAttributes;
20 
21  private readonly uint enabledVertexAttribArrays;
22 
23  private bool hasDynamicStagingVB;
24 
25  private int vaoId;
26 
27  private readonly GraphicsDevice graphicsDevice;
28 
29  private readonly int indexBufferId;
30 
31  public VertexArrayObjectInstance(GraphicsDevice graphicsDevice, EffectInputSignature effectInputSignature, VertexAttrib[] sharedVertexAttribs, int indexBufferId)
32  {
33  this.graphicsDevice = graphicsDevice;
34  this.indexBufferId = indexBufferId;
35  programAttributes = effectInputSignature.Attributes;
36 
37  int vertexAttributeCount = 0;
38  for (int i = 0; i < sharedVertexAttribs.Length; i++)
39  {
40  if (programAttributes.ContainsKey(sharedVertexAttribs[i].AttributeName))
41  {
42  vertexAttributeCount++;
43  }
44  }
45 
46  vertexAttribs = new VertexAttrib[vertexAttributeCount];
47 
48  int j = 0;
49  for (int i = 0; i < sharedVertexAttribs.Length; i++)
50  {
51  AddAttribute(ref j, ref sharedVertexAttribs[i], ref enabledVertexAttribArrays);
52  }
53  }
54 
55  public void Dispose()
56  {
57  if (vaoId != 0)
58  {
59 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
60  if (graphicsDevice.HasVAO)
61  OpenTK.Graphics.ES20.GL.Oes.DeleteVertexArrays(1, ref vaoId);
62 #else
63  GL.DeleteVertexArrays(1, ref vaoId);
64 #endif
65  vaoId = 0;
66  }
67  }
68 
69  private void AddAttribute(ref int index, ref VertexAttrib attrib, ref uint enabledVertexAttribArrays)
70  {
71  int attribIndex;
72  if (programAttributes.TryGetValue(attrib.AttributeName, out attribIndex))
73  {
74  vertexAttribs[index] = attrib;
75  vertexAttribs[index].Index = attribIndex;
76 
77 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
78  hasDynamicStagingVB |= attrib.VertexBufferId == 0;
79 #endif
80 
81  if (attribIndex != -1)
82  enabledVertexAttribArrays |= 1U << attribIndex;
83 
84  index++;
85  }
86  }
87 
88  /// <summary>
89  /// Sets the VAO, creates if necessary
90  /// </summary>
91  internal void Apply(GraphicsDevice graphicsDevice)
92  {
93  if (graphicsDevice.HasVAO)
94  {
95 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
96  if (hasDynamicStagingVB)
97  {
98  OpenTK.Graphics.ES20.GL.Oes.BindVertexArray(0);
99  ApplyAttributes(ref graphicsDevice.enabledVertexAttribArrays);
100  }
101  else
102 #endif
103  if (vaoId == 0)
104  {
105 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
106  OpenTK.Graphics.ES20.GL.Oes.GenVertexArrays(1, out vaoId);
107  OpenTK.Graphics.ES20.GL.Oes.BindVertexArray(vaoId);
108 #else
109  GL.GenVertexArrays(1, out vaoId);
110  GL.BindVertexArray(vaoId);
111 #endif
112 
113  // New VAO starts with no vertex attribs
114  uint currentlyEnabledVertexAttribArrays = 0;
115  ApplyAttributes(ref currentlyEnabledVertexAttribArrays);
116  }
117  else
118  {
119 #if SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
120  OpenTK.Graphics.ES20.GL.Oes.BindVertexArray(vaoId);
121 #else
122  GL.BindVertexArray(vaoId);
123 #endif
124 
125 #if SILICONSTUDIO_PLATFORM_ANDROID
126  // Not sure why, but it seems PowerVR doesn't work well when changing VAO.
127  // This happened on Android 2.3, with a scene having both normal and skinned geometry (skinned geometry is trashed).
128  // Maybe this is related to changing both VAO and Program, something is not refreshed properly?
129  // TODO: Isolate case better: Only PowerVR SGX 540? Does it still happen in Android 4.0?
130  // Is it related to program changing or just a vertex attrib being added/removed compared to previous draw call?
131  if (graphicsDevice.Workaround_VAO_PowerVR_SGX_540)
132  {
133  // Disable unused vertex attribs (ones that are currently enabled and that should not be)
134  var vertexAttribsToReenable = enabledVertexAttribArrays;
135 
136  int currentVertexAttribIndex = 0;
137  while (vertexAttribsToReenable != 0)
138  {
139  if ((vertexAttribsToReenable & 1) == 1)
140  {
141  GL.DisableVertexAttribArray(currentVertexAttribIndex);
142  GL.EnableVertexAttribArray(currentVertexAttribIndex);
143  }
144 
145  currentVertexAttribIndex++;
146  vertexAttribsToReenable >>= 1;
147  }
148  }
149 #endif
150  }
151  }
152  else
153  {
154  ApplyAttributes(ref graphicsDevice.enabledVertexAttribArrays);
155  }
156  }
157 
158  private void ApplyAttributes(ref uint currentlyEnabledVertexAttribArrays)
159  {
160  GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexBufferId);
161 
162  // Disable unused vertex attribs (ones that are currently enabled and that should not be)
163  var vertexAttribsToDisable = currentlyEnabledVertexAttribArrays & ~enabledVertexAttribArrays;
164 
165  int currentVertexAttribIndex = 0;
166  while (vertexAttribsToDisable != 0)
167  {
168  if ((vertexAttribsToDisable & 1) == 1)
169  {
170  GL.DisableVertexAttribArray(currentVertexAttribIndex);
171  }
172 
173  currentVertexAttribIndex++;
174  vertexAttribsToDisable >>= 1;
175  }
176 
177  int vertexBuffer = -1;
178 
179  foreach (var vertexAttrib in vertexAttribs)
180  {
181  if (vertexAttrib.VertexBufferId != vertexBuffer)
182  {
183  GL.BindBuffer(BufferTarget.ArrayBuffer, vertexAttrib.VertexBufferId);
184  vertexBuffer = vertexAttrib.VertexBufferId;
185  }
186  var vertexAttribMask = 1U << vertexAttrib.Index;
187  if ((currentlyEnabledVertexAttribArrays & vertexAttribMask) == 0)
188  {
189  GL.EnableVertexAttribArray(vertexAttrib.Index);
190  }
191 
192 #if !SILICONSTUDIO_PARADOX_GRAPHICS_API_OPENGLES
193  if (vertexAttrib.IsInteger && !vertexAttrib.Normalized)
194  GL.VertexAttribIPointer(vertexAttrib.Index, vertexAttrib.Size, (VertexAttribIPointerType)vertexAttrib.Type, vertexAttrib.Stride, vertexAttrib.Offset);
195  else
196 #endif
197  GL.VertexAttribPointer(vertexAttrib.Index, vertexAttrib.Size, vertexAttrib.Type, vertexAttrib.Normalized, vertexAttrib.Stride, vertexAttrib.Offset);
198  }
199 
200  currentlyEnabledVertexAttribArrays = enabledVertexAttribArrays;
201  }
202  }
203 }
204 #endif