Show More
Commit Description:
Fix build errors.
Commit Description:
Fix build errors.
References:
File last commit:
Show/Diff file:
Action:
FNA/src/Graphics/Texture.cs
470 lines | 10.9 KiB | text/x-csharp | CSharpLexer
470 lines | 10.9 KiB | text/x-csharp | CSharpLexer
r0 | #region License | |||
/* FNA - XNA4 Reimplementation for Desktop Platforms | ||||
r690 | * Copyright 2009-2022 Ethan Lee and the MonoGame Team | |||
r0 | * | |||
* Released under the Microsoft Public License. | ||||
* See LICENSE for details. | ||||
*/ | ||||
#endregion | ||||
#region Using Statements | ||||
using System; | ||||
r690 | using System.IO; | |||
r0 | #endregion | |||
namespace Microsoft.Xna.Framework.Graphics | ||||
{ | ||||
public abstract class Texture : GraphicsResource | ||||
{ | ||||
#region Public Properties | ||||
public SurfaceFormat Format | ||||
{ | ||||
get; | ||||
protected set; | ||||
} | ||||
public int LevelCount | ||||
{ | ||||
get; | ||||
protected set; | ||||
} | ||||
#endregion | ||||
r690 | #region Internal FNA3D Variables | |||
r0 | ||||
r690 | internal IntPtr texture; | |||
r0 | ||||
#endregion | ||||
#region Protected Dispose Method | ||||
protected override void Dispose(bool disposing) | ||||
{ | ||||
if (!IsDisposed) | ||||
{ | ||||
r690 | GraphicsDevice.Textures.RemoveDisposedTexture(this); | |||
GraphicsDevice.VertexTextures.RemoveDisposedTexture(this); | ||||
FNA3D.FNA3D_AddDisposeTexture( | ||||
GraphicsDevice.GLDevice, | ||||
texture | ||||
); | ||||
r0 | } | |||
base.Dispose(disposing); | ||||
} | ||||
#endregion | ||||
#region Internal Context Reset Method | ||||
internal protected override void GraphicsDeviceResetting() | ||||
{ | ||||
// FIXME: Do we even want to bother with DeviceResetting for GL? -flibit | ||||
} | ||||
#endregion | ||||
r690 | #region Static SurfaceFormat Size Methods | |||
protected static int GetBlockSizeSquared(SurfaceFormat format) | ||||
{ | ||||
switch (format) | ||||
{ | ||||
case SurfaceFormat.Dxt1: | ||||
case SurfaceFormat.Dxt3: | ||||
case SurfaceFormat.Dxt5: | ||||
case SurfaceFormat.Dxt5SrgbEXT: | ||||
case SurfaceFormat.Bc7EXT: | ||||
case SurfaceFormat.Bc7SrgbEXT: | ||||
return 16; | ||||
case SurfaceFormat.Alpha8: | ||||
case SurfaceFormat.Bgr565: | ||||
case SurfaceFormat.Bgra4444: | ||||
case SurfaceFormat.Bgra5551: | ||||
case SurfaceFormat.HalfSingle: | ||||
case SurfaceFormat.NormalizedByte2: | ||||
case SurfaceFormat.Color: | ||||
case SurfaceFormat.Single: | ||||
case SurfaceFormat.Rg32: | ||||
case SurfaceFormat.HalfVector2: | ||||
case SurfaceFormat.NormalizedByte4: | ||||
case SurfaceFormat.Rgba1010102: | ||||
case SurfaceFormat.ColorBgraEXT: | ||||
case SurfaceFormat.ColorSrgbEXT: | ||||
case SurfaceFormat.HalfVector4: | ||||
case SurfaceFormat.Rgba64: | ||||
case SurfaceFormat.Vector2: | ||||
case SurfaceFormat.HdrBlendable: | ||||
case SurfaceFormat.Vector4: | ||||
return 1; | ||||
default: | ||||
throw new ArgumentException("Should be a value defined in SurfaceFormat", "Format"); | ||||
} | ||||
} | ||||
r0 | ||||
internal static int GetFormatSize(SurfaceFormat format) | ||||
{ | ||||
switch (format) | ||||
{ | ||||
case SurfaceFormat.Dxt1: | ||||
return 8; | ||||
case SurfaceFormat.Dxt3: | ||||
case SurfaceFormat.Dxt5: | ||||
r690 | case SurfaceFormat.Dxt5SrgbEXT: | |||
case SurfaceFormat.Bc7EXT: | ||||
case SurfaceFormat.Bc7SrgbEXT: | ||||
r0 | return 16; | |||
case SurfaceFormat.Alpha8: | ||||
return 1; | ||||
case SurfaceFormat.Bgr565: | ||||
case SurfaceFormat.Bgra4444: | ||||
case SurfaceFormat.Bgra5551: | ||||
case SurfaceFormat.HalfSingle: | ||||
case SurfaceFormat.NormalizedByte2: | ||||
return 2; | ||||
case SurfaceFormat.Color: | ||||
case SurfaceFormat.Single: | ||||
case SurfaceFormat.Rg32: | ||||
case SurfaceFormat.HalfVector2: | ||||
case SurfaceFormat.NormalizedByte4: | ||||
case SurfaceFormat.Rgba1010102: | ||||
case SurfaceFormat.ColorBgraEXT: | ||||
r690 | case SurfaceFormat.ColorSrgbEXT: | |||
r0 | return 4; | |||
case SurfaceFormat.HalfVector4: | ||||
case SurfaceFormat.Rgba64: | ||||
case SurfaceFormat.Vector2: | ||||
r690 | case SurfaceFormat.HdrBlendable: | |||
r0 | return 8; | |||
case SurfaceFormat.Vector4: | ||||
return 16; | ||||
default: | ||||
throw new ArgumentException("Should be a value defined in SurfaceFormat", "Format"); | ||||
} | ||||
} | ||||
r690 | internal static int GetPixelStoreAlignment(SurfaceFormat format) | |||
r0 | { | |||
/* | ||||
* https://github.com/FNA-XNA/FNA/pull/238 | ||||
* https://www.khronos.org/registry/OpenGL/specs/gl/glspec21.pdf | ||||
* OpenGL 2.1 Specification, section 3.6.1, table 3.1 specifies that the pixelstorei alignment cannot exceed 8 | ||||
*/ | ||||
return Math.Min(8, GetFormatSize(format)); | ||||
} | ||||
r690 | internal static void ValidateGetDataFormat( | |||
SurfaceFormat format, | ||||
int elementSizeInBytes | ||||
) { | ||||
if (GetFormatSize(format) % elementSizeInBytes != 0) | ||||
{ | ||||
throw new ArgumentException( | ||||
"The type you are using for T in this" + | ||||
" method is an invalid size for this" + | ||||
" resource" | ||||
); | ||||
} | ||||
} | ||||
r0 | #endregion | |||
#region Static Mipmap Level Calculator | ||||
internal static int CalculateMipLevels( | ||||
int width, | ||||
int height = 0, | ||||
int depth = 0 | ||||
) { | ||||
int levels = 1; | ||||
for ( | ||||
int size = Math.Max(Math.Max(width, height), depth); | ||||
size > 1; | ||||
levels += 1 | ||||
) { | ||||
size /= 2; | ||||
} | ||||
return levels; | ||||
} | ||||
#endregion | ||||
r690 | ||||
#region Static DDS Parser | ||||
internal static int CalculateDDSLevelSize( | ||||
int width, | ||||
int height, | ||||
SurfaceFormat format | ||||
) { | ||||
if (format == SurfaceFormat.ColorBgraEXT) | ||||
{ | ||||
return (((width * 32) + 7) / 8) * height; | ||||
} | ||||
else if (format == SurfaceFormat.HalfVector4) | ||||
{ | ||||
return (((width * 64) + 7) / 8) * height; | ||||
} | ||||
else if (format == SurfaceFormat.Vector4) | ||||
{ | ||||
return (((width * 128) + 7) / 8) * height; | ||||
} | ||||
else | ||||
{ | ||||
int blockSize = 16; | ||||
if (format == SurfaceFormat.Dxt1) | ||||
{ | ||||
blockSize = 8; | ||||
} | ||||
width = Math.Max(width, 1); | ||||
height = Math.Max(height, 1); | ||||
return ( | ||||
((width + 3) / 4) * | ||||
((height + 3) / 4) * | ||||
blockSize | ||||
); | ||||
} | ||||
} | ||||
// DDS loading extension, based on MojoDDS | ||||
internal static void ParseDDS( | ||||
BinaryReader reader, | ||||
out SurfaceFormat format, | ||||
out int width, | ||||
out int height, | ||||
out int levels, | ||||
out bool isCube | ||||
) { | ||||
// A whole bunch of magic numbers, yay DDS! | ||||
const uint DDS_MAGIC = 0x20534444; | ||||
const uint DDS_HEADERSIZE = 124; | ||||
const uint DDS_PIXFMTSIZE = 32; | ||||
const uint DDSD_CAPS = 0x1; | ||||
const uint DDSD_HEIGHT = 0x2; | ||||
const uint DDSD_WIDTH = 0x4; | ||||
const uint DDSD_PITCH = 0x8; | ||||
const uint DDSD_FMT = 0x1000; | ||||
const uint DDSD_LINEARSIZE = 0x80000; | ||||
const uint DDSD_REQ = ( | ||||
DDSD_CAPS | DDSD_HEIGHT | DDSD_WIDTH | DDSD_FMT | ||||
); | ||||
const uint DDSCAPS_MIPMAP = 0x400000; | ||||
const uint DDSCAPS_TEXTURE = 0x1000; | ||||
const uint DDSCAPS2_CUBEMAP = 0x200; | ||||
const uint DDPF_FOURCC = 0x4; | ||||
const uint DDPF_RGB = 0x40; | ||||
const uint FOURCC_DXT1 = 0x31545844; | ||||
const uint FOURCC_DXT3 = 0x33545844; | ||||
const uint FOURCC_DXT5 = 0x35545844; | ||||
const uint FOURCC_DX10 = 0x30315844; | ||||
const uint pitchAndLinear = ( | ||||
DDSD_PITCH | DDSD_LINEARSIZE | ||||
); | ||||
// File should start with 'DDS ' | ||||
if (reader.ReadUInt32() != DDS_MAGIC) | ||||
{ | ||||
throw new NotSupportedException("Not a DDS!"); | ||||
} | ||||
// Texture info | ||||
uint size = reader.ReadUInt32(); | ||||
if (size != DDS_HEADERSIZE) | ||||
{ | ||||
throw new NotSupportedException("Invalid DDS header!"); | ||||
} | ||||
uint flags = reader.ReadUInt32(); | ||||
if ((flags & DDSD_REQ) != DDSD_REQ) | ||||
{ | ||||
throw new NotSupportedException("Invalid DDS flags!"); | ||||
} | ||||
if ((flags & pitchAndLinear) == pitchAndLinear) | ||||
{ | ||||
throw new NotSupportedException("Invalid DDS flags!"); | ||||
} | ||||
height = reader.ReadInt32(); | ||||
width = reader.ReadInt32(); | ||||
reader.ReadUInt32(); // dwPitchOrLinearSize, unused | ||||
reader.ReadUInt32(); // dwDepth, unused | ||||
levels = reader.ReadInt32(); | ||||
// "Reserved" | ||||
reader.ReadBytes(4 * 11); | ||||
// Format info | ||||
uint formatSize = reader.ReadUInt32(); | ||||
if (formatSize != DDS_PIXFMTSIZE) | ||||
{ | ||||
throw new NotSupportedException("Bogus PIXFMTSIZE!"); | ||||
} | ||||
uint formatFlags = reader.ReadUInt32(); | ||||
uint formatFourCC = reader.ReadUInt32(); | ||||
uint formatRGBBitCount = reader.ReadUInt32(); | ||||
uint formatRBitMask = reader.ReadUInt32(); | ||||
uint formatGBitMask = reader.ReadUInt32(); | ||||
uint formatBBitMask = reader.ReadUInt32(); | ||||
uint formatABitMask = reader.ReadUInt32(); | ||||
// dwCaps "stuff" | ||||
uint caps = reader.ReadUInt32(); | ||||
if ((caps & DDSCAPS_TEXTURE) == 0) | ||||
{ | ||||
throw new NotSupportedException("Not a texture!"); | ||||
} | ||||
isCube = false; | ||||
uint caps2 = reader.ReadUInt32(); | ||||
if (caps2 != 0) | ||||
{ | ||||
if ((caps2 & DDSCAPS2_CUBEMAP) == DDSCAPS2_CUBEMAP) | ||||
{ | ||||
isCube = true; | ||||
} | ||||
else | ||||
{ | ||||
throw new NotSupportedException("Invalid caps2!"); | ||||
} | ||||
} | ||||
reader.ReadUInt32(); // dwCaps3, unused | ||||
reader.ReadUInt32(); // dwCaps4, unused | ||||
// "Reserved" | ||||
reader.ReadUInt32(); | ||||
// Mipmap sanity check | ||||
if ((caps & DDSCAPS_MIPMAP) != DDSCAPS_MIPMAP) | ||||
{ | ||||
levels = 1; | ||||
} | ||||
// Determine texture format | ||||
if ((formatFlags & DDPF_FOURCC) == DDPF_FOURCC) | ||||
{ | ||||
switch (formatFourCC) | ||||
{ | ||||
case 0x71: // D3DFMT_A16B16G16R16F | ||||
format = SurfaceFormat.HalfVector4; | ||||
break; | ||||
case 0x74: // D3DFMT_A32B32G32R32F | ||||
format = SurfaceFormat.Vector4; | ||||
break; | ||||
case FOURCC_DXT1: | ||||
format = SurfaceFormat.Dxt1; | ||||
break; | ||||
case FOURCC_DXT3: | ||||
format = SurfaceFormat.Dxt3; | ||||
break; | ||||
case FOURCC_DXT5: | ||||
format = SurfaceFormat.Dxt5; | ||||
break; | ||||
case FOURCC_DX10: | ||||
// If the fourCC is DX10, there is an extra header with additional format information. | ||||
uint dxgiFormat = reader.ReadUInt32(); | ||||
// These values are taken from the DXGI_FORMAT enum. | ||||
switch (dxgiFormat) | ||||
{ | ||||
case 2: | ||||
format = SurfaceFormat.Vector4; | ||||
break; | ||||
case 10: | ||||
format = SurfaceFormat.HalfVector4; | ||||
break; | ||||
case 71: | ||||
format = SurfaceFormat.Dxt1; | ||||
break; | ||||
case 74: | ||||
format = SurfaceFormat.Dxt3; | ||||
break; | ||||
case 77: | ||||
format = SurfaceFormat.Dxt5; | ||||
break; | ||||
case 98: | ||||
format = SurfaceFormat.Bc7EXT; | ||||
break; | ||||
case 99: | ||||
format = SurfaceFormat.Bc7SrgbEXT; | ||||
break; | ||||
default: | ||||
throw new NotSupportedException( | ||||
"Unsupported DDS texture format" | ||||
); | ||||
} | ||||
uint resourceDimension = reader.ReadUInt32(); | ||||
// These values are taken from the D3D10_RESOURCE_DIMENSION enum. | ||||
switch (resourceDimension) | ||||
{ | ||||
case 0: // Unknown | ||||
case 1: // Buffer | ||||
throw new NotSupportedException( | ||||
"Unsupported DDS texture format" | ||||
); | ||||
default: | ||||
break; | ||||
} | ||||
/* | ||||
* This flag seemingly only indicates if the texture is a cube map. | ||||
* This is already determined above. Cool! | ||||
*/ | ||||
reader.ReadUInt32(); | ||||
/* | ||||
* Indicates the number of elements in the texture array. | ||||
* We don't support texture arrays so just throw if it's greater than 1. | ||||
*/ | ||||
uint arraySize = reader.ReadUInt32(); | ||||
if (arraySize > 1) | ||||
{ | ||||
throw new NotSupportedException( | ||||
"Unsupported DDS texture format" | ||||
); | ||||
} | ||||
reader.ReadUInt32(); // reserved | ||||
break; | ||||
default: | ||||
throw new NotSupportedException( | ||||
"Unsupported DDS texture format" | ||||
); | ||||
} | ||||
} | ||||
else if ((formatFlags & DDPF_RGB) == DDPF_RGB) | ||||
{ | ||||
if ( formatRGBBitCount != 32 || | ||||
formatRBitMask != 0x00FF0000 || | ||||
formatGBitMask != 0x0000FF00 || | ||||
formatBBitMask != 0x000000FF || | ||||
formatABitMask != 0xFF000000 ) | ||||
{ | ||||
throw new NotSupportedException( | ||||
"Unsupported DDS texture format" | ||||
); | ||||
} | ||||
format = SurfaceFormat.ColorBgraEXT; | ||||
} | ||||
else | ||||
{ | ||||
throw new NotSupportedException( | ||||
"Unsupported DDS texture format" | ||||
); | ||||
} | ||||
} | ||||
#endregion | ||||
r0 | } | |||
} | ||||