diff --git a/MonoGame.Framework/Platform/Graphics/BufferResource.OpenGL.cs b/MonoGame.Framework/Platform/Graphics/BufferResource.OpenGL.cs index 89ded9206f0..718ddbeb88f 100644 --- a/MonoGame.Framework/Platform/Graphics/BufferResource.OpenGL.cs +++ b/MonoGame.Framework/Platform/Graphics/BufferResource.OpenGL.cs @@ -25,8 +25,7 @@ private void PlatformGraphicsDeviceResetting() BufferTarget GetBufferTarget() { - switch (BufferType) - { + switch (BufferType) { case BufferType.StructuredBuffer: return BufferTarget.ShaderStorageBuffer; case BufferType.VertexBuffer: @@ -44,20 +43,18 @@ BufferTarget GetBufferTarget() /// void GenerateIfRequired() { - if (buffer == 0 && ElementStride != 0) - { + if (buffer == 0 && ElementStride != 0) { GL.GenBuffers(1, out this.buffer); GraphicsExtensions.CheckGLError(); GL.BindBuffer(GetBufferTarget(), this.buffer); GraphicsExtensions.CheckGLError(); GL.BufferData(GetBufferTarget(), - new IntPtr(ElementStride * ElementCount), IntPtr.Zero, - _isDynamic ? BufferUsageHint.StreamDraw : BufferUsageHint.StaticDraw); + new IntPtr(ElementStride * ElementCount), IntPtr.Zero, + _isDynamic ? BufferUsageHint.StreamDraw : BufferUsageHint.StaticDraw); GraphicsExtensions.CheckGLError(); } - if (counterBuffer == 0 && StructuredBufferType != StructuredBufferType.Basic) - { + if (counterBuffer == 0 && StructuredBufferType != StructuredBufferType.Basic) { GL.GenBuffers(1, out this.counterBuffer); GraphicsExtensions.CheckGLError(); GL.BindBuffer(BufferTarget.ShaderStorageBuffer, this.counterBuffer); @@ -69,40 +66,34 @@ void GenerateIfRequired() } } - internal void PlatformGetData(int offsetInBytes, T[] data, int startIndex, int elementCount, int vertexStride) + internal void PlatformGetData(int offsetInBytes, T[] data, int startIndex, int elementCount, + int vertexStride) where T : struct { -#if GLES - // Buffers are write-only on OpenGL ES 1.1 and 2.0. See the GL_OES_mapbuffer extension for more information. - // http://www.khronos.org/registry/gles/extensions/OES/OES_mapbuffer.txt - throw new NotSupportedException("Vertex buffers are write-only on OpenGL ES platforms"); -#else Threading.BlockOnUIThread(() => GetBufferData(offsetInBytes, data, startIndex, elementCount, vertexStride)); -#endif } -#if !GLES private void GetBufferData(int offsetInBytes, T[] data, int startIndex, int elementCount, int elementStride) where T : struct { GL.BindBuffer(GetBufferTarget(), buffer); + GraphicsExtensions.CheckGLError(); // Pointer to the start of data in the vertex buffer - var ptr = GL.MapBuffer(GetBufferTarget(), BufferAccess.ReadOnly); + // Use relative modern glMapBufferRange from + var ptr = GL.MapBufferRange(GetBufferTarget(), 0, elementCount * elementStride, AccessFlags.GlMapReadBit); GraphicsExtensions.CheckGLError(); - ptr = (IntPtr)(ptr.ToInt64() + offsetInBytes); + ptr = (IntPtr) (ptr.ToInt64() + offsetInBytes); - if (typeof(T) == typeof(byte) && elementStride == 1) - { + if (typeof(T) == typeof(byte) && elementStride == 1) { // If data is already a byte[] and stride is 1 we can skip the temporary buffer var buffer = data as byte[]; Marshal.Copy(ptr, buffer, startIndex * elementStride, elementCount * elementStride); } - else - { + else { // Temporary buffer to store the copied section of data var tmp = new byte[elementCount * elementStride]; // Copy from the vertex buffer to the temporary buffer @@ -110,17 +101,14 @@ private void GetBufferData(int offsetInBytes, T[] data, int startIndex, int e // Copy from the temporary buffer to the destination array var tmpHandle = GCHandle.Alloc(tmp, GCHandleType.Pinned); - try - { + try { var tmpPtr = tmpHandle.AddrOfPinnedObject(); - for (var i = 0; i < elementCount; i++) - { - data[startIndex + i] = (T)Marshal.PtrToStructure(tmpPtr, typeof(T)); - tmpPtr = (IntPtr)(tmpPtr.ToInt64() + elementStride); + for (var i = 0; i < elementCount; i++) { + data[startIndex + i] = (T) Marshal.PtrToStructure(tmpPtr, typeof(T)); + tmpPtr = (IntPtr) (tmpPtr.ToInt64() + elementStride); } } - finally - { + finally { tmpHandle.Free(); } } @@ -129,10 +117,9 @@ private void GetBufferData(int offsetInBytes, T[] data, int startIndex, int e GraphicsExtensions.CheckGLError(); } -#endif - internal void PlatformSetData( - int offsetInBytes, T[] data, int startIndex, int elementCount, int elementStride, SetDataOptions options, int bufferSize, int elementSizeInBytes) + int offsetInBytes, T[] data, int startIndex, int elementCount, int elementStride, SetDataOptions options, + int bufferSize, int elementSizeInBytes) where T : struct { Threading.BlockOnUIThread(SetDataState.Action, new SetDataState @@ -150,7 +137,8 @@ internal void PlatformSetData( } private void PlatformSetDataBody( - int offsetInBytes, T[] data, int startIndex, int elementCount, int elementStride, SetDataOptions options, int bufferSize, int elementSizeInBytes) + int offsetInBytes, T[] data, int startIndex, int elementCount, int elementStride, SetDataOptions options, + int bufferSize, int elementSizeInBytes) where T : struct { GenerateIfRequired(); @@ -158,55 +146,49 @@ private void PlatformSetDataBody( GL.BindBuffer(GetBufferTarget(), buffer); GraphicsExtensions.CheckGLError(); - if (options == SetDataOptions.Discard) - { + if (options == SetDataOptions.Discard) { // By assigning NULL data to the buffer this gives a hint // to the device to discard the previous content. GL.BufferData( GetBufferTarget(), - (IntPtr)bufferSize, + (IntPtr) bufferSize, IntPtr.Zero, _isDynamic ? BufferUsageHint.StreamDraw : BufferUsageHint.StaticDraw); GraphicsExtensions.CheckGLError(); } var elementSizeInByte = Marshal.SizeOf(); - if (elementSizeInByte == elementStride || elementSizeInByte % elementStride == 0) - { + if (elementSizeInByte == elementStride || elementSizeInByte % elementStride == 0) { // there are no gaps so we can copy in one go var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); - try - { - var dataPtr = (IntPtr)(dataHandle.AddrOfPinnedObject().ToInt64() + startIndex * elementSizeInBytes); + try { + var dataPtr = + (IntPtr) (dataHandle.AddrOfPinnedObject().ToInt64() + startIndex * elementSizeInBytes); - GL.BufferSubData(GetBufferTarget(), (IntPtr)offsetInBytes, (IntPtr)(elementSizeInBytes * elementCount), dataPtr); + GL.BufferSubData(GetBufferTarget(), (IntPtr) offsetInBytes, + (IntPtr) (elementSizeInBytes * elementCount), dataPtr); GraphicsExtensions.CheckGLError(); } - finally - { + finally { dataHandle.Free(); } } - else - { + else { // else we must copy each element separately var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned); - try - { + try { int dstOffset = offsetInBytes; - var dataPtr = (IntPtr)(dataHandle.AddrOfPinnedObject().ToInt64() + startIndex * elementSizeInByte); + var dataPtr = (IntPtr) (dataHandle.AddrOfPinnedObject().ToInt64() + startIndex * elementSizeInByte); - for (int i = 0; i < elementCount; i++) - { - GL.BufferSubData(GetBufferTarget(), (IntPtr)dstOffset, (IntPtr)elementSizeInByte, dataPtr); + for (int i = 0; i < elementCount; i++) { + GL.BufferSubData(GetBufferTarget(), (IntPtr) dstOffset, (IntPtr) elementSizeInByte, dataPtr); GraphicsExtensions.CheckGLError(); dstOffset += elementStride; - dataPtr = (IntPtr)(dataPtr.ToInt64() + elementSizeInByte); + dataPtr = (IntPtr) (dataPtr.ToInt64() + elementSizeInByte); } } - finally - { + finally { dataHandle.Free(); } } @@ -217,35 +199,34 @@ private void SetCounterBufferValue(int val) GL.BindBuffer(BufferTarget.ShaderStorageBuffer, counterBuffer); GraphicsExtensions.CheckGLError(); - unsafe - { + unsafe { int* data = stackalloc int[1]; data[0] = val; - GL.BufferSubData(BufferTarget.ShaderStorageBuffer, IntPtr.Zero, new IntPtr(4), (IntPtr)data); + GL.BufferSubData(BufferTarget.ShaderStorageBuffer, IntPtr.Zero, new IntPtr(4), (IntPtr) data); GraphicsExtensions.CheckGLError(); } } - internal override void PlatformApply(GraphicsDevice device, ShaderProgram program, ref ResourceBinding resourceBinding, bool writeAcess) + internal override void PlatformApply(GraphicsDevice device, ShaderProgram program, + ref ResourceBinding resourceBinding, bool writeAcess) { GL.BindBufferBase(BufferTarget.ShaderStorageBuffer, resourceBinding.bindingSlot, buffer); GraphicsExtensions.CheckGLError(); - - if (counterBuffer > 0) - { + + if (counterBuffer > 0) { if (CounterBufferResetValue != -1) SetCounterBufferValue(CounterBufferResetValue); - GL.BindBufferBase(BufferTarget.ShaderStorageBuffer, resourceBinding.bindingSlotForCounter, counterBuffer); + GL.BindBufferBase(BufferTarget.ShaderStorageBuffer, resourceBinding.bindingSlotForCounter, + counterBuffer); GraphicsExtensions.CheckGLError(); } } protected override void Dispose(bool disposing) { - if (!IsDisposed) - { + if (!IsDisposed) { if (GraphicsDevice != null) GraphicsDevice.DisposeBuffer(buffer); } @@ -268,7 +249,8 @@ struct SetDataState public static Action> Action = (s) => { s.buffer.PlatformSetDataBody( - s.offsetInBytes, s.data, s.startIndex, s.elementCount, s.elementStride, s.options, s.bufferSize, s.elementSizeInBytes); + s.offsetInBytes, s.data, s.startIndex, s.elementCount, s.elementStride, s.options, s.bufferSize, + s.elementSizeInBytes); }; } } diff --git a/MonoGame.Framework/Platform/Graphics/GraphicsDevice.OpenGL.cs b/MonoGame.Framework/Platform/Graphics/GraphicsDevice.OpenGL.cs index aa955611909..18604cc000a 100644 --- a/MonoGame.Framework/Platform/Graphics/GraphicsDevice.OpenGL.cs +++ b/MonoGame.Framework/Platform/Graphics/GraphicsDevice.OpenGL.cs @@ -227,7 +227,7 @@ private void ApplyAttribs(Shader shader, int baseVertex) (IntPtr)(offset.ToInt64() + element.Offset)); // only set the divisor if instancing is supported - if (GraphicsCapabilities.SupportsInstancing) + if (GraphicsCapabilities.SupportsInstancing) GL.VertexAttribDivisor(element.AttributeLocation, vertexBufferBinding.InstanceFrequency); GraphicsExtensions.CheckGLError(); @@ -348,7 +348,7 @@ private void PlatformInitialize() // Ensure the vertex attributes are reset _enabledVertexAttributes.Clear(); - // Free all the cached shader programs. + // Free all the cached shader programs. _programCache.Clear(); _shaderProgram = null; @@ -362,8 +362,20 @@ private void PlatformInitialize() _bufferBindingInfos = new BufferBindingInfo[_maxVertexBufferSlots]; for (int i = 0; i < _bufferBindingInfos.Length; i++) _bufferBindingInfos[i] = new BufferBindingInfo(null, IntPtr.Zero, 0, -1); + + // Create VAO + // Indirect drawing does not work without VAO on some platforms (Android for instance) + // Check if function exist + if (GL.GenVertexArrays != null && GL.BindVertexArray != null) { + // (for some reason this does not work for a scalar, works only for an array) + var a = new uint[1]; + var dataPtr = GCHandle.Alloc(a, GCHandleType.Pinned); + var vao = (UIntPtr) dataPtr.AddrOfPinnedObject(); + GL.GenVertexArrays(1, vao); + GL.BindVertexArray(a[0]); + } } - + private DepthStencilState clearDepthStencilState = new DepthStencilState { StencilEnable = true }; private void PlatformClear(ClearOptions options, Vector4 color, float depth, int stencil) @@ -386,7 +398,7 @@ private void PlatformClear(ClearOptions options, Vector4 color, float depth, int var prevDepthStencilState = DepthStencilState; var prevBlendState = BlendState; ScissorRectangle = _viewport.Bounds; - // DepthStencilState.Default has the Stencil Test disabled; + // DepthStencilState.Default has the Stencil Test disabled; // make sure stencil test is enabled before we clear since // some drivers won't clear with stencil test disabled DepthStencilState = this.clearDepthStencilState; @@ -415,7 +427,7 @@ private void PlatformClear(ClearOptions options, Vector4 color, float depth, int bufferMask = bufferMask | ClearBufferMask.StencilBufferBit; } - if ((options & ClearOptions.DepthBuffer) == ClearOptions.DepthBuffer) + if ((options & ClearOptions.DepthBuffer) == ClearOptions.DepthBuffer) { if (depth != _lastClearDepth) { @@ -435,7 +447,7 @@ private void PlatformClear(ClearOptions options, Vector4 color, float depth, int #if MONOMAC || IOS } #endif - + // Restore the previous render state. ScissorRectangle = prevScissorRect; DepthStencilState = prevDepthStencilState; @@ -572,7 +584,7 @@ private void PlatformSetViewport(ref Viewport value) GL.DepthRange(value.MinDepth, value.MaxDepth); GraphicsExtensions.LogGLError("GraphicsDevice.Viewport_set() GL.DepthRange"); - + // In OpenGL we have to re-apply the special "posFixup" // vertex shader uniform if the viewport changes. _vertexShaderDirty = true; @@ -649,7 +661,7 @@ internal void PlatformCreateRenderTarget(IRenderTarget renderTarget, int width, var color = 0; var depth = 0; var stencil = 0; - + if (preferredMultiSampleCount > 0 && this.framebufferHelper.SupportsBlitFramebuffer) { this.framebufferHelper.GenRenderbuffer(out color); @@ -663,7 +675,7 @@ internal void PlatformCreateRenderTarget(IRenderTarget renderTarget, int width, var stencilInternalFormat = (RenderbufferStorage)0; switch (preferredDepthFormat) { - case DepthFormat.Depth16: + case DepthFormat.Depth16: depthInternalFormat = RenderbufferStorage.DepthComponent16; break; #if GLES @@ -947,7 +959,7 @@ private static GLPrimitiveType PrimitiveTypeGL(PrimitiveType primitiveType) } /// - /// Activates the Current Vertex/Pixel shader pair into a program. + /// Activates the Current Vertex/Pixel shader pair into a program. /// private unsafe void ActivateShaderProgram() { @@ -1129,7 +1141,7 @@ internal void PlatformApplyState(bool applyShaders) _geometryConstantBuffers.SetConstantBuffers(this, _shaderProgram); GeometryShaderResources.PlatformApplyAllResourcesToDevice(this, _shaderProgram); GeometrySamplerStates.PlatformSetSamplers(this, _geometryShader, GeometryShaderResources); - } + } } private void PlatformDrawIndexedPrimitives(PrimitiveType primitiveType, int baseVertex, int startIndex, int primitiveCount) @@ -1198,7 +1210,7 @@ private void PlatformDrawUserPrimitives( private void PlatformDrawPrimitives(PrimitiveType primitiveType, int vertexStart, int vertexCount) { - ApplyState(true); + ApplyState(true); ApplyAttribs(_vertexShader, 0); @@ -1348,16 +1360,20 @@ private void PlatformDrawInstancedPrimitives(PrimitiveType primitiveType, int ba GraphicsExtensions.CheckGLError(); } - + private void PlatformDrawInstancedPrimitivesIndirect(PrimitiveType primitiveType, IndirectDrawBuffer indirectDrawBuffer, int alignedByteOffsetForArgs) { if (!GraphicsCapabilities.SupportsInstancing) throw new PlatformNotSupportedException("Instanced geometry drawing requires at least OpenGL 3.2 or GLES 3.2. Try upgrading your graphics card drivers."); + GraphicsExtensions.CheckGLError(); + ApplyState(true); ApplyAttribs(_vertexShader, 0); + + // Set vertex count for tesselation patch var primitiveTypeGL = PrimitiveTypeGL(primitiveType); if (primitiveTypeGL == GLPrimitiveType.Patches) @@ -1413,7 +1429,7 @@ private void PlatformDispatchCompute(int threadGroupCountX, int threadGroupCount GraphicsExtensions.CheckGLError(); // The memory barrier will ensure that data written by the compute shader will be visible when other shaders read that data later. - // Better performance can probably be achievable by using only the required bits, and only when it's actually neccessary. + // Better performance can probably be achievable by using only the required bits, and only when it's actually neccessary. GL.MemoryBarrier(MemoryBarrierBits.All); GraphicsExtensions.CheckGLError(); } @@ -1429,7 +1445,7 @@ private void PlatformDispatchComputeIndirect(IndirectDrawBuffer indirectDrawBuff GraphicsExtensions.CheckGLError(); // The memory barrier will ensure that data written by the compute shader will be visible when other shaders read that data later. - // Better performance can probably be achievable by using only the required bits, and only when it's actually neccessary. + // Better performance can probably be achievable by using only the required bits, and only when it's actually neccessary. GL.MemoryBarrier(MemoryBarrierBits.All); GraphicsExtensions.CheckGLError(); } @@ -1510,7 +1526,7 @@ private static Rectangle PlatformGetTitleSafeArea(int x, int y, int width, int h { return new Rectangle(x, y, width, height); } - + internal void PlatformSetMultiSamplingToMaximum(PresentationParameters presentationParameters, out int quality) { presentationParameters.MultiSampleCount = 4; @@ -1569,7 +1585,7 @@ private void GetDisplayResolution(out int width, out int height) height = mode.Height; } #endif - + } } diff --git a/MonoGame.Framework/Platform/Graphics/OpenGL.cs b/MonoGame.Framework/Platform/Graphics/OpenGL.cs index 78b09714632..34d80765c5d 100644 --- a/MonoGame.Framework/Platform/Graphics/OpenGL.cs +++ b/MonoGame.Framework/Platform/Graphics/OpenGL.cs @@ -441,7 +441,7 @@ internal enum PixelInternalFormat Rgba16f = 0x881A, R16f = 0x822D, Rg32f = 0x8230, - Rgba32f = 0x8814, + Rgba32f = 0x8814, R8ui = 0x8232, R8i = 0x8231, R16ui = 0x8234, @@ -506,9 +506,9 @@ internal enum PixelType Float = 0x1406, HalfFloat = 0x140B, HalfFloatOES = 0x8D61, - Byte = 0x1400, - Short = 0x1402, - Int = 0x1404, + Byte = 0x1400, + Short = 0x1402, + Int = 0x1404, UnsignedShort = 0x1403, UnsignedInt = 0x1405, UnsignedInt1010102 = 0x8036, @@ -609,6 +609,11 @@ internal enum MemoryBarrierBits : uint All = 0xFFFFFFFF, } + internal enum AccessFlags : uint + { + GlMapReadBit = 0x1, + } + internal partial class ColorFormat { internal ColorFormat (int r, int g, int b, int a) @@ -1401,6 +1406,12 @@ internal delegate void TexSubImage3DDelegate(TextureTarget target, int level, internal delegate IntPtr MapBufferDelegate(BufferTarget target, BufferAccess access); internal static MapBufferDelegate MapBuffer; + [System.Security.SuppressUnmanagedCodeSecurity()] + [UnmanagedFunctionPointer(callingConvention)] + [MonoNativeFunctionWrapper] + internal delegate IntPtr MapBufferRangeDelegate(BufferTarget target, IntPtr offset, IntPtr size, AccessFlags access); + internal static MapBufferRangeDelegate MapBufferRange; + [System.Security.SuppressUnmanagedCodeSecurity()] [UnmanagedFunctionPointer(callingConvention)] [MonoNativeFunctionWrapper] @@ -1464,6 +1475,23 @@ internal delegate void DrawElementsInstancedBaseInstanceDelegate(GLPrimitiveType internal delegate void MemoryBarrierDelegate(MemoryBarrierBits barriers); internal static MemoryBarrierDelegate MemoryBarrier; + /**********************************************************************************/ + + [System.Security.SuppressUnmanagedCodeSecurity()] + [UnmanagedFunctionPointer(callingConvention)] + [MonoNativeFunctionWrapper] + internal delegate void GenVertexArraysDelegate(int n, UIntPtr size); + internal static GenVertexArraysDelegate GenVertexArrays; + + [System.Security.SuppressUnmanagedCodeSecurity()] + [UnmanagedFunctionPointer(callingConvention)] + [MonoNativeFunctionWrapper] + internal delegate void BindVertexArrayDelegate(UIntPtr vao); + internal static BindVertexArrayDelegate BindVertexArray; + + /**********************************************************************************/ + + #if DEBUG [UnmanagedFunctionPointer (CallingConvention.StdCall)] delegate void DebugMessageCallbackProc (int source, int type, int id, int severity, int length, IntPtr message, IntPtr userParam); @@ -1543,10 +1571,10 @@ internal static void LoadEntryPoints () UniformMatrix4fv = LoadFunction ("glUniformMatrix4fv"); UniformMatrix2x3fv = LoadFunction ("glUniformMatrix2x3fv"); UniformMatrix2x4fv = LoadFunction ("glUniformMatrix2x4fv"); - UniformMatrix3x2fv = LoadFunction ("glUniformMatrix3x2fv"); + UniformMatrix3x2fv = LoadFunction ("glUniformMatrix3x2fv"); UniformMatrix3x4fv = LoadFunction ("glUniformMatrix3x4fv"); UniformMatrix4x2fv = LoadFunction ("glUniformMatrix4x2fv"); - UniformMatrix4x3fv = LoadFunction ("glUniformMatrix4x3fv"); + UniformMatrix4x3fv = LoadFunction ("glUniformMatrix4x3fv"); ReadPixelsInternal = LoadFunction ("glReadPixels"); @@ -1629,10 +1657,14 @@ internal static void LoadEntryPoints () GenBuffers = LoadFunction ("glGenBuffers"); BufferData = LoadFunction ("glBufferData"); MapBuffer = LoadFunction ("glMapBuffer"); + MapBufferRange = LoadFunction ("glMapBufferRange"); UnmapBuffer = LoadFunction ("glUnmapBuffer"); BufferSubData = LoadFunction ("glBufferSubData"); DeleteBuffers = LoadFunction ("glDeleteBuffers"); + GenVertexArrays = LoadFunction ("glGenVertexArrays"); + BindVertexArray = LoadFunction ("glBindVertexArray"); + VertexAttribPointer = LoadFunction ("glVertexAttribPointer"); PatchParameteri = LoadFunction("glPatchParameteri"); @@ -1701,7 +1733,7 @@ internal static void LoadExtensions() GL.LoadFrameBufferObjectEXTEntryPoints(); } if (GL.RenderbufferStorageMultisample == null) - { + { if (Extensions.Contains("GL_APPLE_framebuffer_multisample")) { GL.RenderbufferStorageMultisample = LoadFunction("glRenderbufferStorageMultisampleAPPLE");