diff --git a/MonoGame.Framework/Graphics/GraphicsCapabilities.DirectX.cs b/MonoGame.Framework/Graphics/GraphicsCapabilities.DirectX.cs index 4fa17cffd7e..a1378b5b5cc 100644 --- a/MonoGame.Framework/Graphics/GraphicsCapabilities.DirectX.cs +++ b/MonoGame.Framework/Graphics/GraphicsCapabilities.DirectX.cs @@ -25,6 +25,9 @@ private void PlatformInitialize(GraphicsDevice device) SupportsTextureArrays = device.GraphicsProfile == GraphicsProfile.HiDef; SupportsDepthClamp = device.GraphicsProfile == GraphicsProfile.HiDef; SupportsVertexTextures = device.GraphicsProfile == GraphicsProfile.HiDef; + SupportsFloatTextures = true; + SupportsHalfFloatTextures = true; + SupportsNormalized = true; SupportsInstancing = true; diff --git a/MonoGame.Framework/Graphics/GraphicsCapabilities.OpenGL.cs b/MonoGame.Framework/Graphics/GraphicsCapabilities.OpenGL.cs index d76d20fa702..b21ef766eb1 100644 --- a/MonoGame.Framework/Graphics/GraphicsCapabilities.OpenGL.cs +++ b/MonoGame.Framework/Graphics/GraphicsCapabilities.OpenGL.cs @@ -92,8 +92,14 @@ private void PlatformInitialize(GraphicsDevice device) // sRGB #if GLES SupportsSRgb = GL.Extensions.Contains("GL_EXT_sRGB"); + SupportsFloatTextures = GL.BoundApi == GL.RenderApi.ES && (device.glMajorVersion >= 3 || GL.Extensions.Contains("GL_EXT_color_buffer_float")); + SupportsHalfFloatTextures = GL.BoundApi == GL.RenderApi.ES && (device.glMajorVersion >= 3 || GL.Extensions.Contains("GL_EXT_color_buffer_half_float")); + SupportsNormalized = GL.BoundApi == GL.RenderApi.ES && (device.glMajorVersion >= 3 && GL.Extensions.Contains("GL_EXT_texture_norm16")); #else SupportsSRgb = GL.Extensions.Contains("GL_EXT_texture_sRGB") && GL.Extensions.Contains("GL_EXT_framebuffer_sRGB"); + SupportsFloatTextures = GL.BoundApi == GL.RenderApi.GL && (device.glMajorVersion >= 3 || GL.Extensions.Contains("GL_ARB_texture_float")); + SupportsHalfFloatTextures = GL.BoundApi == GL.RenderApi.GL && (device.glMajorVersion >= 3 || GL.Extensions.Contains("GL_ARB_half_float_pixel"));; + SupportsNormalized = GL.BoundApi == GL.RenderApi.GL && (device.glMajorVersion >= 3 || GL.Extensions.Contains("GL_EXT_texture_norm16"));; #endif // TODO: Implement OpenGL support for texture arrays @@ -107,11 +113,7 @@ private void PlatformInitialize(GraphicsDevice device) GL.GetInteger((GetPName)GetParamName.MaxSamples, out _maxMultiSampleCount); -#if GLES - SupportsInstancing = false; -#else SupportsInstancing = GL.VertexAttribDivisor != null; -#endif } } diff --git a/MonoGame.Framework/Graphics/GraphicsCapabilities.cs b/MonoGame.Framework/Graphics/GraphicsCapabilities.cs index 59a9dd23c74..9996c234bed 100644 --- a/MonoGame.Framework/Graphics/GraphicsCapabilities.cs +++ b/MonoGame.Framework/Graphics/GraphicsCapabilities.cs @@ -30,11 +30,11 @@ internal void Initialize(GraphicsDevice device) /// internal bool SupportsTextureFilterAnisotropic { get; private set; } - internal bool SupportsDepth24 { get; private set; } + internal bool SupportsDepth24 { get; private set; } - internal bool SupportsPackedDepthStencil { get; private set; } + internal bool SupportsPackedDepthStencil { get; private set; } - internal bool SupportsDepthNonLinear { get; private set; } + internal bool SupportsDepthNonLinear { get; private set; } /// /// Gets the support for DXT1 @@ -69,13 +69,35 @@ internal void Initialize(GraphicsDevice device) /// and texture sRGB are supported. /// internal bool SupportsSRgb { get; private set; } - + internal bool SupportsTextureArrays { get; private set; } internal bool SupportsDepthClamp { get; private set; } internal bool SupportsVertexTextures { get; private set; } + /// + /// True, if the underlying platform supports floating point textures. + /// For Direct3D platforms this is always true. + /// For OpenGL Desktop platforms it is always true. + /// For OpenGL Mobile platforms it requires `GL_EXT_color_buffer_float`. + /// If the requested format is not supported an NotSupportedException + /// will be thrown. + /// + internal bool SupportsFloatTextures { get; private set; } + + /// + /// True, if the underlying platform supports half floating point textures. + /// For Direct3D platforms this is always true. + /// For OpenGL Desktop platforms it is always true. + /// For OpenGL Mobile platforms it requires `GL_EXT_color_buffer_half_float`. + /// If the requested format is not supported an NotSupportedException + /// will be thrown. + /// + internal bool SupportsHalfFloatTextures { get; private set; } + + internal bool SupportsNormalized { get; private set; } + /// /// Gets the max texture anisotropy. This value typically lies /// between 0 and 16, where 0 means anisotropic filtering is not diff --git a/MonoGame.Framework/Graphics/GraphicsDevice.OpenGL.cs b/MonoGame.Framework/Graphics/GraphicsDevice.OpenGL.cs index 9b6827190ec..d25a40f92c8 100644 --- a/MonoGame.Framework/Graphics/GraphicsDevice.OpenGL.cs +++ b/MonoGame.Framework/Graphics/GraphicsDevice.OpenGL.cs @@ -200,7 +200,7 @@ private void ApplyAttribs(Shader shader, int baseVertex) // If instancing is not supported, but InstanceFrequency of the buffer is not zero, throw an exception if (!GraphicsCapabilities.SupportsInstancing && vertexBufferBinding.InstanceFrequency > 0) - throw new PlatformNotSupportedException("Instanced geometry drawing requires at least OpenGL 3.2. Try upgrading your graphics drivers."); + throw new PlatformNotSupportedException("Instanced geometry drawing requires at least OpenGL 3.2 or GLES 3.2. Try upgrading your graphics drivers."); foreach (var element in attrInfo.Elements) { @@ -211,11 +211,9 @@ private void ApplyAttribs(Shader shader, int baseVertex) vertexStride, (IntPtr)(offset.ToInt64() + element.Offset)); -#if !(GLES || MONOMAC) // only set the divisor if instancing is supported if (GraphicsCapabilities.SupportsInstancing) GL.VertexAttribDivisor(element.AttributeLocation, vertexBufferBinding.InstanceFrequency); -#endif GraphicsExtensions.CheckGLError(); } @@ -1173,11 +1171,8 @@ private void PlatformDrawUserIndexedPrimitives(PrimitiveType primitiveType, T private void PlatformDrawInstancedPrimitives(PrimitiveType primitiveType, int baseVertex, int startIndex, int primitiveCount, int instanceCount) { -#if GLES || MONOMAC - throw new PlatformNotSupportedException("Instanced geometry drawing is not supported yet for GLES or MONOMAC."); -#else if (!GraphicsCapabilities.SupportsInstancing) - throw new PlatformNotSupportedException("Instanced geometry drawing requires at least OpenGL 3.2. Try upgrading your graphics card drivers."); + throw new PlatformNotSupportedException("Instanced geometry drawing requires at least OpenGL 3.2 or GLES 3.2. Try upgrading your graphics card drivers."); ApplyState(true); var shortIndices = _indexBuffer.IndexElementSize == IndexElementSize.SixteenBits; @@ -1196,7 +1191,6 @@ private void PlatformDrawInstancedPrimitives(PrimitiveType primitiveType, int ba indexOffsetInBytes, instanceCount); GraphicsExtensions.CheckGLError(); -#endif } private void PlatformGetBackBufferData(Rectangle? rectangle, T[] data, int startIndex, int count) where T : struct diff --git a/MonoGame.Framework/Graphics/GraphicsExtensions.cs b/MonoGame.Framework/Graphics/GraphicsExtensions.cs index 2973042013f..16bb9a1de77 100644 --- a/MonoGame.Framework/Graphics/GraphicsExtensions.cs +++ b/MonoGame.Framework/Graphics/GraphicsExtensions.cs @@ -495,8 +495,8 @@ internal static int GetSwapInterval(this PresentInterval interval) } } #endif - - + + const SurfaceFormat InvalidFormat = (SurfaceFormat)int.MaxValue; internal static void GetGLFormat (this SurfaceFormat format, GraphicsDevice graphicsDevice, out PixelInternalFormat glInternalFormat, @@ -508,7 +508,15 @@ internal static void GetGLFormat (this SurfaceFormat format, glType = PixelType.UnsignedByte; var supportsSRgb = graphicsDevice.GraphicsCapabilities.SupportsSRgb; - + var supportsS3tc = graphicsDevice.GraphicsCapabilities.SupportsS3tc; + var supportsPvrtc = graphicsDevice.GraphicsCapabilities.SupportsPvrtc; + var supportsEtc1 = graphicsDevice.GraphicsCapabilities.SupportsEtc1; + var supportsAtitc = graphicsDevice.GraphicsCapabilities.SupportsAtitc; + var supportsFloat = graphicsDevice.GraphicsCapabilities.SupportsFloatTextures; + var supportsHalfFloat = graphicsDevice.GraphicsCapabilities.SupportsHalfFloatTextures; + var supportsNormalized = graphicsDevice.GraphicsCapabilities.SupportsNormalized; + var isGLES2 = GL.BoundApi == GL.RenderApi.ES && graphicsDevice.glMajorVersion == 2; + switch (format) { case SurfaceFormat.Color: glInternalFormat = PixelInternalFormat.Rgba; @@ -518,7 +526,7 @@ internal static void GetGLFormat (this SurfaceFormat format, case SurfaceFormat.ColorSRgb: if (!supportsSRgb) goto case SurfaceFormat.Color; - glInternalFormat = (PixelInternalFormat) 0x8C40; // PixelInternalFormat.Srgb; + glInternalFormat = PixelInternalFormat.Srgb; glFormat = PixelFormat.Rgba; glType = PixelType.UnsignedByte; break; @@ -546,8 +554,9 @@ internal static void GetGLFormat (this SurfaceFormat format, glFormat = PixelFormat.Luminance; glType = PixelType.UnsignedByte; break; -#if !IOS && !ANDROID && !ANGLE case SurfaceFormat.Dxt1: + if (!supportsS3tc) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.CompressedRgbS3tcDxt1Ext; glFormat = (PixelFormat)GLPixelFormat.CompressedTextureFormats; break; @@ -558,10 +567,14 @@ internal static void GetGLFormat (this SurfaceFormat format, glFormat = (PixelFormat)GLPixelFormat.CompressedTextureFormats; break; case SurfaceFormat.Dxt1a: + if (!supportsS3tc) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt1Ext; glFormat = (PixelFormat)GLPixelFormat.CompressedTextureFormats; break; case SurfaceFormat.Dxt3: + if (!supportsS3tc) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt3Ext; glFormat = (PixelFormat)GLPixelFormat.CompressedTextureFormats; break; @@ -572,6 +585,8 @@ internal static void GetGLFormat (this SurfaceFormat format, glFormat = (PixelFormat)GLPixelFormat.CompressedTextureFormats; break; case SurfaceFormat.Dxt5: + if (!supportsS3tc) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.CompressedRgbaS3tcDxt5Ext; glFormat = (PixelFormat)GLPixelFormat.CompressedTextureFormats; break; @@ -581,14 +596,24 @@ internal static void GetGLFormat (this SurfaceFormat format, glInternalFormat = PixelInternalFormat.CompressedSrgbAlphaS3tcDxt5Ext; glFormat = (PixelFormat)GLPixelFormat.CompressedTextureFormats; break; - - case SurfaceFormat.Single: - glInternalFormat = PixelInternalFormat.R32f; - glFormat = PixelFormat.Red; - glType = PixelType.Float; - break; +#if !IOS && !ANDROID && !ANGLE + case SurfaceFormat.Rgba1010102: + glInternalFormat = PixelInternalFormat.Rgb10A2ui; + glFormat = PixelFormat.Rgba; + glType = PixelType.UnsignedInt1010102; + break; +#endif + case SurfaceFormat.Single: + if (!supportsFloat) + goto case InvalidFormat; + glInternalFormat = PixelInternalFormat.R32f; + glFormat = PixelFormat.Red; + glType = PixelType.Float; + break; case SurfaceFormat.HalfVector2: + if (!supportsHalfFloat) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.Rg16f; glFormat = PixelFormat.Rg; glType = PixelType.HalfFloat; @@ -597,131 +622,113 @@ internal static void GetGLFormat (this SurfaceFormat format, // HdrBlendable implemented as HalfVector4 (see http://blogs.msdn.com/b/shawnhar/archive/2010/07/09/surfaceformat-hdrblendable.aspx) case SurfaceFormat.HdrBlendable: case SurfaceFormat.HalfVector4: + if (!supportsHalfFloat) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.Rgba16f; glFormat = PixelFormat.Rgba; glType = PixelType.HalfFloat; break; case SurfaceFormat.HalfSingle: + if (!supportsHalfFloat) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.R16f; glFormat = PixelFormat.Red; - glType = PixelType.HalfFloat; + glType = isGLES2 ? PixelType.HalfFloatOES : PixelType.HalfFloat; break; case SurfaceFormat.Vector2: + if (!supportsFloat) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.Rg32f; glFormat = PixelFormat.Rg; glType = PixelType.Float; break; case SurfaceFormat.Vector4: + if (!supportsFloat) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.Rgba32f; glFormat = PixelFormat.Rgba; glType = PixelType.Float; break; case SurfaceFormat.NormalizedByte2: + if (!supportsNormalized) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.Rg8i; glFormat = PixelFormat.Rg; glType = PixelType.Byte; break; case SurfaceFormat.NormalizedByte4: + if (!supportsNormalized) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.Rgba8i; glFormat = PixelFormat.Rgba; glType = PixelType.Byte; break; case SurfaceFormat.Rg32: + if (!supportsNormalized) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.Rg16ui; glFormat = PixelFormat.Rg; glType = PixelType.UnsignedShort; break; case SurfaceFormat.Rgba64: + if (!supportsNormalized) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.Rgba16; glFormat = PixelFormat.Rgba; glType = PixelType.UnsignedShort; break; - - case SurfaceFormat.Rgba1010102: - glInternalFormat = PixelInternalFormat.Rgb10A2ui; - glFormat = PixelFormat.Rgba; - glType = PixelType.UnsignedInt1010102; - break; -#endif - -#if ANDROID - case SurfaceFormat.Dxt1: - // 0x83F0 is the RGB version, 0x83F1 is the RGBA version (1-bit alpha) - // XNA uses the RGB version. - glInternalFormat = (PixelInternalFormat)0x83F0; - glFormat = PixelFormat.CompressedTextureFormats; - break; - case SurfaceFormat.Dxt1SRgb: - if (!supportsSRgb) - goto case SurfaceFormat.Dxt1; - glInternalFormat = (PixelInternalFormat)0x8C4C; - glFormat = PixelFormat.CompressedTextureFormats; - break; - case SurfaceFormat.Dxt1a: - // 0x83F0 is the RGB version, 0x83F1 is the RGBA version (1-bit alpha) - glInternalFormat = (PixelInternalFormat)0x83F1; - glFormat = PixelFormat.CompressedTextureFormats; - break; - case SurfaceFormat.Dxt3: - glInternalFormat = (PixelInternalFormat)0x83F2; - glFormat = PixelFormat.CompressedTextureFormats; - break; - case SurfaceFormat.Dxt3SRgb: - if (!supportsSRgb) - goto case SurfaceFormat.Dxt3; - glInternalFormat = (PixelInternalFormat)0x8C4E; - glFormat = PixelFormat.CompressedTextureFormats; - break; - case SurfaceFormat.Dxt5: - glInternalFormat = (PixelInternalFormat)0x83F3; - glFormat = PixelFormat.CompressedTextureFormats; - break; - case SurfaceFormat.Dxt5SRgb: - if (!supportsSRgb) - goto case SurfaceFormat.Dxt5; - glInternalFormat = (PixelInternalFormat)0x8C4F; - glFormat = PixelFormat.CompressedTextureFormats; - break; case SurfaceFormat.RgbaAtcExplicitAlpha: + if (!supportsAtitc) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.AtcRgbaExplicitAlphaAmd; glFormat = PixelFormat.CompressedTextureFormats; break; case SurfaceFormat.RgbaAtcInterpolatedAlpha: + if (!supportsAtitc) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.AtcRgbaInterpolatedAlphaAmd; glFormat = PixelFormat.CompressedTextureFormats; break; case SurfaceFormat.RgbEtc1: - glInternalFormat = (PixelInternalFormat)0x8D64; // GL_ETC1_RGB8_OES + if (!supportsEtc1) + goto case InvalidFormat; + glInternalFormat = PixelInternalFormat.Etc1; // GL_ETC1_RGB8_OES glFormat = PixelFormat.CompressedTextureFormats; break; -#endif -#if IOS || ANDROID case SurfaceFormat.RgbPvrtc2Bpp: + if (!supportsPvrtc) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.CompressedRgbPvrtc2Bppv1Img; glFormat = PixelFormat.CompressedTextureFormats; break; case SurfaceFormat.RgbPvrtc4Bpp: + if (!supportsPvrtc) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.CompressedRgbPvrtc4Bppv1Img; glFormat = PixelFormat.CompressedTextureFormats; break; case SurfaceFormat.RgbaPvrtc2Bpp: + if (!supportsPvrtc) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.CompressedRgbaPvrtc2Bppv1Img; glFormat = PixelFormat.CompressedTextureFormats; break; case SurfaceFormat.RgbaPvrtc4Bpp: + if (!supportsPvrtc) + goto case InvalidFormat; glInternalFormat = PixelInternalFormat.CompressedRgbaPvrtc4Bppv1Img; glFormat = PixelFormat.CompressedTextureFormats; break; -#endif + case InvalidFormat: default: - throw new NotSupportedException(); + throw new NotSupportedException(string.Format("The requested SurfaceFormat `{0}` is not supported.", format)); } } diff --git a/MonoGame.Framework/Graphics/OpenGL.cs b/MonoGame.Framework/Graphics/OpenGL.cs index ebae11b04b9..a929c749225 100644 --- a/MonoGame.Framework/Graphics/OpenGL.cs +++ b/MonoGame.Framework/Graphics/OpenGL.cs @@ -411,7 +411,9 @@ internal enum PixelInternalFormat // ATITC AtcRgbaExplicitAlphaAmd = 0x8C93, AtcRgbaInterpolatedAlphaAmd = 0x87EE, - // DXT + // ETC1 + Etc1 = 0x8D64, + Srgb = 0x8C40, } @@ -433,6 +435,7 @@ internal enum PixelType UnsignedShort5551 = 0x8034, Float = 0x1406, HalfFloat = 0x140B, + HalfFloatOES = 0x8D61, Byte = 0x1400, UnsignedShort = 0x1403, UnsignedInt1010102 = 0x8036,