/// <summary> /// Determines number of image array entries and pixel size. /// </summary> /// <param name="imageDesc">Description of the image to create.</param> /// <param name="pitchFlags">Pitch flags.</param> /// <param name="bufferCount">Output number of mipmap.</param> /// <param name="pixelSizeInBytes">Output total size to allocate pixel buffers for all images.</param> private static List<int> CalculateImageArray( ImageDescription imageDesc, PitchFlags pitchFlags, int rowStride, out int bufferCount, out int pixelSizeInBytes) { pixelSizeInBytes = 0; bufferCount = 0; var mipmapToZIndex = new List<int>(); for (int j = 0; j < imageDesc.ArraySize; j++) { int w = imageDesc.Width; int h = imageDesc.Height; int d = imageDesc.Depth; for (int i = 0; i < imageDesc.MipLevels; i++) { int rowPitch, slicePitch; int widthPacked; int heightPacked; ComputePitch(imageDesc.Format, w, h, out rowPitch, out slicePitch, out widthPacked, out heightPacked, pitchFlags); if (rowStride > 0) { // Check that stride is ok if (rowStride < rowPitch) throw new InvalidOperationException(string.Format("Invalid stride [{0}]. Value can't be lower than actual stride [{1}]", rowStride, rowPitch)); if (widthPacked != w || heightPacked != h) throw new InvalidOperationException("Custom strides is not supported with packed PixelFormats"); // Override row pitch rowPitch = rowStride; // Recalculate slice pitch slicePitch = rowStride * h; } // Store the number of z-slicec per miplevels if ( j == 0) mipmapToZIndex.Add(bufferCount); // Keep a trace of indices for the 1st array size, for each mip levels pixelSizeInBytes += d * slicePitch; bufferCount += d; if (h > 1) h >>= 1; if (w > 1) w >>= 1; if (d > 1) d >>= 1; } // For the last mipmaps, store just the number of zbuffers in total if (j == 0) mipmapToZIndex.Add(bufferCount); } return mipmapToZIndex; }
/// <summary> /// Determines number of image array entries and pixel size. /// </summary> /// <param name="imageDesc">Description of the image to create.</param> /// <param name="pitchFlags">Pitch flags.</param> /// <param name="bufferCount">Output number of mipmap.</param> /// <param name="pixelSizeInBytes">Output total size to allocate pixel buffers for all images.</param> private static List <int> CalculateImageArray(ImageDescription imageDesc, PitchFlags pitchFlags, out int bufferCount, out int pixelSizeInBytes) { pixelSizeInBytes = 0; bufferCount = 0; var mipmapToZIndex = new List <int>(); for (int j = 0; j < imageDesc.ArraySize; j++) { int w = imageDesc.Width; int h = imageDesc.Height; int d = imageDesc.Depth; for (int i = 0; i < imageDesc.MipLevels; i++) { int rowPitch, slicePitch; int widthPacked; int heightPacked; ComputePitch(imageDesc.Format, w, h, out rowPitch, out slicePitch, out widthPacked, out heightPacked, pitchFlags); // Store the number of z-slices per miplevel if (j == 0) { mipmapToZIndex.Add(bufferCount); } // Keep a trace of indices for the 1st array size, for each mip levels pixelSizeInBytes += d * slicePitch; bufferCount += d; if (h > 1) { h >>= 1; } if (w > 1) { w >>= 1; } if (d > 1) { d >>= 1; } } // For the last mipmaps, store just the number of zbuffers in total if (j == 0) { mipmapToZIndex.Add(bufferCount); } } return(mipmapToZIndex); }
internal unsafe void Initialize(ImageDescription description, IntPtr dataPointer, int offset, GCHandle?handle, bool bufferIsDisposable, PitchFlags pitchFlags = PitchFlags.None) { if (!FormatHelper.IsValid(description.Format) || FormatHelper.IsVideo(description.Format)) { throw new InvalidOperationException("Unsupported DXGI Format"); } this.handle = handle; switch (description.Dimension) { case TextureDimension.Texture1D: if (description.Width <= 0 || description.Height != 1 || description.Depth != 1 || description.ArraySize == 0) { throw new InvalidOperationException("Invalid Width/Height/Depth/ArraySize for Image 1D"); } // Check that miplevels are fine description.MipLevels = Texture.CalculateMipLevels(description.Width, 1, description.MipLevels); break; case TextureDimension.Texture2D: case TextureDimension.TextureCube: if (description.Width <= 0 || description.Height <= 0 || description.Depth != 1 || description.ArraySize == 0) { throw new InvalidOperationException("Invalid Width/Height/Depth/ArraySize for Image 2D"); } if (description.Dimension == TextureDimension.TextureCube) { if ((description.ArraySize % 6) != 0) { throw new InvalidOperationException("TextureCube must have an arraysize = 6"); } } // Check that miplevels are fine description.MipLevels = Texture.CalculateMipLevels(description.Width, description.Height, description.MipLevels); break; case TextureDimension.Texture3D: if (description.Width <= 0 || description.Height <= 0 || description.Depth <= 0 || description.ArraySize != 1) { throw new InvalidOperationException("Invalid Width/Height/Depth/ArraySize for Image 3D"); } // Check that miplevels are fine description.MipLevels = Texture.CalculateMipLevels(description.Width, description.Height, description.Depth, description.MipLevels); break; } // Calculate mipmaps int pixelBufferCount; this.mipMapToZIndex = CalculateImageArray(description, pitchFlags, out pixelBufferCount, out totalSizeInBytes); this.mipmapDescriptions = CalculateMipMapDescription(description, pitchFlags); zBufferCountPerArraySlice = this.mipMapToZIndex[this.mipMapToZIndex.Count - 1]; // Allocate all pixel buffers pixelBuffers = new PixelBuffer[pixelBufferCount]; pixelBufferArray = new PixelBufferArray(this); // Setup all pointers // only release buffer that is not pinned and is asked to be disposed. this.bufferIsDisposable = !handle.HasValue && bufferIsDisposable; this.buffer = dataPointer; if (dataPointer == IntPtr.Zero) { buffer = Utilities.AllocateMemory(totalSizeInBytes); offset = 0; this.bufferIsDisposable = true; } SetupImageArray((IntPtr)((byte *)buffer + offset), totalSizeInBytes, description, pitchFlags, pixelBuffers); Description = description; // PreCompute databoxes dataBoxArray = ComputeDataBox(); }
/// <summary> /// Initializes a new instance of the <see cref="Image" /> class. /// </summary> /// <param name="description">The image description.</param> /// <param name="dataPointer">The pointer to the data buffer.</param> /// <param name="offset">The offset from the beginning of the data buffer.</param> /// <param name="handle">The handle (optional).</param> /// <param name="bufferIsDisposable">if set to <c>true</c> [buffer is disposable].</param> /// <exception cref="System.InvalidOperationException">If the format is invalid, or width/height/depth/arraysize is invalid with respect to the dimension.</exception> internal unsafe Image(ImageDescription description, IntPtr dataPointer, int offset, GCHandle?handle, bool bufferIsDisposable, PitchFlags pitchFlags = PitchFlags.None) { Initialize(description, dataPointer, offset, handle, bufferIsDisposable, pitchFlags); }
/// <summary> /// Allocates PixelBuffers /// </summary> /// <param name="buffer"></param> /// <param name="pixelSize"></param> /// <param name="imageDesc"></param> /// <param name="pitchFlags"></param> /// <param name="output"></param> private static unsafe void SetupImageArray(IntPtr buffer, int pixelSize, ImageDescription imageDesc, PitchFlags pitchFlags, PixelBuffer[] output) { int index = 0; var pixels = (byte *)buffer; for (uint item = 0; item < imageDesc.ArraySize; ++item) { int w = imageDesc.Width; int h = imageDesc.Height; int d = imageDesc.Depth; for (uint level = 0; level < imageDesc.MipLevels; ++level) { int rowPitch, slicePitch; int widthPacked; int heightPacked; ComputePitch(imageDesc.Format, w, h, out rowPitch, out slicePitch, out widthPacked, out heightPacked, pitchFlags); for (uint zSlice = 0; zSlice < d; ++zSlice) { // We use the same memory organization that Direct3D 11 needs for D3D11_SUBRESOURCE_DATA // with all slices of a given miplevel being continuous in memory output[index] = new PixelBuffer(w, h, imageDesc.Format, rowPitch, slicePitch, (IntPtr)pixels); ++index; pixels += slicePitch; } if (h > 1) { h >>= 1; } if (w > 1) { w >>= 1; } if (d > 1) { d >>= 1; } } } }
/// <summary> /// Function to return pitch information for this format. /// </summary> /// <param name="width">The width of the pixel data.</param> /// <param name="height">The height of the pixel data.</param> /// <param name="flags">Legacy flags for counting the bits per pixel and data alignment.</param> /// <returns>The pitch information for the format.</returns> public GorgonFormatPitch GetPitch(int width, int height, PitchFlags flags) { int rowPitch; // Do calculations for compressed formats. if (IsCompressed) { int bpb; switch (Format) { case BufferFormat.BC1: case BufferFormat.BC1_UIntNormal: case BufferFormat.BC1_UIntNormal_sRGB: case BufferFormat.BC4: case BufferFormat.BC4_IntNormal: case BufferFormat.BC4_UIntNormal: bpb = 8; break; default: bpb = 16; break; } int widthCounter = 1.Max((width + 3) / 4); int heightCounter = 1.Max((height + 3) / 4); rowPitch = widthCounter * bpb; return(new GorgonFormatPitch(widthCounter * bpb, heightCounter * rowPitch, new Size(widthCounter, heightCounter))); } if (IsPacked) { rowPitch = ((width + 1) >> 1) >> 2; return(new GorgonFormatPitch(rowPitch, rowPitch * height, Size.Empty)); } int bitsPerPixel = BitDepth; if ((flags & PitchFlags.BPP24) == PitchFlags.BPP24) { bitsPerPixel = 24; } else if ((flags & PitchFlags.BPP16) == PitchFlags.BPP16) { bitsPerPixel = 16; } else if ((flags & PitchFlags.BPP8) == PitchFlags.BPP8) { bitsPerPixel = 8; } // This is for handling old DirectDraw DDS files that didn't output // properly because of assumptions about pitch alignment. if ((flags & PitchFlags.LegacyDWORD) == PitchFlags.LegacyDWORD) { rowPitch = ((width * bitsPerPixel + 31) / 32) * sizeof(int); } else { rowPitch = ((width * bitsPerPixel + 7) / 8); } return(new GorgonFormatPitch(rowPitch, rowPitch * height, Size.Empty)); }
internal static MipMapDescription[] CalculateMipMapDescription(ImageDescription metadata, PitchFlags cpFlags, out int nImages, out int pixelSize) { pixelSize = 0; nImages = 0; int w = metadata.Width; int h = metadata.Height; int d = metadata.Depth; var mipmaps = new MipMapDescription[metadata.MipLevels]; for (int level = 0; level < metadata.MipLevels; ++level) { int rowPitch, slicePitch; int widthPacked; int heightPacked; ComputePitch(metadata.Format, w, h, out rowPitch, out slicePitch, out widthPacked, out heightPacked, PitchFlags.None); mipmaps[level] = new MipMapDescription( w, h, d, rowPitch, slicePitch, widthPacked, heightPacked ); pixelSize += d * slicePitch; nImages += d; if (h > 1) h >>= 1; if (w > 1) w >>= 1; if (d > 1) d >>= 1; } return mipmaps; }
internal static void ComputePitch(PixelFormat fmt, int width, int height, out int rowPitch, out int slicePitch, out int widthCount, out int heightCount, PitchFlags flags = PitchFlags.None) { widthCount = width; heightCount = height; if (fmt.IsCompressed()) { int minWidth = 1; int minHeight = 1; int bpb = 8; switch (fmt) { case PixelFormat.BC1_Typeless: case PixelFormat.BC1_UNorm: case PixelFormat.BC1_UNorm_SRgb: case PixelFormat.BC4_Typeless: case PixelFormat.BC4_UNorm: case PixelFormat.BC4_SNorm: case PixelFormat.ETC1: bpb = 8; break; case PixelFormat.PVRTC_4bpp_RGB: case PixelFormat.PVRTC_4bpp_RGBA: case PixelFormat.PVRTC_II_4bpp: minWidth = 8; minHeight = 8; break; case PixelFormat.PVRTC_2bpp_RGBA: case PixelFormat.PVRTC_II_2bpp: minWidth = 16; minHeight = 8; bpb = 4; break; default: bpb = 16; break; } widthCount = Math.Max(1, (Math.Max(minWidth, width) + 3)) / 4; heightCount = Math.Max(1, (Math.Max(minHeight, height) + 3)) / 4; rowPitch = widthCount*bpb; slicePitch = rowPitch*heightCount; } else if (fmt.IsPacked()) { rowPitch = ((width + 1) >> 1) * 4; slicePitch = rowPitch * height; } else { int bpp; if ((flags & PitchFlags.Bpp24) != 0) bpp = 24; else if ((flags & PitchFlags.Bpp16) != 0) bpp = 16; else if ((flags & PitchFlags.Bpp8) != 0) bpp = 8; else bpp = fmt.SizeInBits(); if ((flags & PitchFlags.LegacyDword) != 0) { // Special computation for some incorrectly created DDS files based on // legacy DirectDraw assumptions about pitch alignment rowPitch = ((width * bpp + 31) / 32) * sizeof(int); slicePitch = rowPitch * height; } else { rowPitch = (width * bpp + 7) / 8; slicePitch = rowPitch * height; } } }
/// <summary> /// Initializes a new instance of the <see cref="Image" /> class. /// </summary> /// <param name="description">The image description.</param> /// <param name="dataPointer">The pointer to the data buffer.</param> /// <param name="offset">The offset from the beginning of the data buffer.</param> /// <param name="handle">The handle (optionnal).</param> /// <param name="bufferIsDisposable">if set to <c>true</c> [buffer is disposable].</param> /// <exception cref="System.InvalidOperationException">If the format is invalid, or width/height/depth/arraysize is invalid with respect to the dimension.</exception> internal unsafe Image(ImageDescription description, IntPtr dataPointer, int offset, GCHandle? handle, bool bufferIsDisposable, PitchFlags pitchFlags = PitchFlags.None, int rowStride = 0) { Initialize(description, dataPointer, offset, handle, bufferIsDisposable, pitchFlags, rowStride); }
internal static void ComputePitch(Format fmt, int width, int height, out int rowPitch, out int slicePitch, out int widthCount, out int heightCount, PitchFlags flags = PitchFlags.None) { widthCount = width; heightCount = height; if (FormatHelper.IsCompressed(fmt)) { int bpb = (fmt == Format.BC1_Typeless || fmt == Format.BC1_UNorm || fmt == Format.BC1_UNorm_SRgb || fmt == Format.BC4_Typeless || fmt == Format.BC4_UNorm || fmt == Format.BC4_SNorm) ? 8 : 16; widthCount = Math.Max(1, (width + 3) / 4); heightCount = Math.Max(1, (height + 3) / 4); rowPitch = widthCount * bpb; slicePitch = rowPitch * heightCount; } else if (FormatHelper.IsPacked(fmt)) { rowPitch = ((width + 1) >> 1) * 4; slicePitch = rowPitch * height; } else { int bpp; if ((flags & PitchFlags.Bpp24) != 0) bpp = 24; else if ((flags & PitchFlags.Bpp16) != 0) bpp = 16; else if ((flags & PitchFlags.Bpp8) != 0) bpp = 8; else bpp = FormatHelper.SizeOfInBits(fmt); if ((flags & PitchFlags.LegacyDword) != 0) { // Special computation for some incorrectly created DDS files based on // legacy DirectDraw assumptions about pitch alignment rowPitch = ((width * bpp + 31) / 32) * sizeof(int); slicePitch = rowPitch * height; } else { rowPitch = (width * bpp + 7) / 8; slicePitch = rowPitch * height; } } }
/// <summary> /// Allocates PixelBuffers /// </summary> /// <param name="buffer"></param> /// <param name="pixelSize"></param> /// <param name="imageDesc"></param> /// <param name="pitchFlags"></param> /// <param name="output"></param> private static unsafe void SetupImageArray(IntPtr buffer, int pixelSize, ImageDescription imageDesc, PitchFlags pitchFlags, PixelBuffer[] output) { int index = 0; var pixels = (byte*)buffer; for (uint item = 0; item < imageDesc.ArraySize; ++item) { int w = imageDesc.Width; int h = imageDesc.Height; int d = imageDesc.Depth; for (uint level = 0; level < imageDesc.MipLevels; ++level) { int rowPitch, slicePitch; int widthPacked; int heightPacked; ComputePitch(imageDesc.Format, w, h, out rowPitch, out slicePitch, out widthPacked, out heightPacked, pitchFlags); for (uint zSlice = 0; zSlice < d; ++zSlice) { // We use the same memory organization that Direct3D 11 needs for D3D11_SUBRESOURCE_DATA // with all slices of a given miplevel being continuous in memory output[index] = new PixelBuffer(w, h, imageDesc.Format, rowPitch, slicePitch, (IntPtr)pixels); ++index; pixels += slicePitch; } if (h > 1) h >>= 1; if (w > 1) w >>= 1; if (d > 1) d >>= 1; } } }
/// <summary> /// Allocates PixelBuffers /// </summary> /// <param name="buffer"></param> /// <param name="pixelSize"></param> /// <param name="imageDesc"></param> /// <param name="pitchFlags"></param> /// <param name="output"></param> private static unsafe void SetupImageArray(IntPtr buffer, int pixelSize, int rowStride, ImageDescription imageDesc, PitchFlags pitchFlags, PixelBuffer[] output) { int index = 0; var pixels = (byte*)buffer; for (uint item = 0; item < imageDesc.ArraySize; ++item) { int w = imageDesc.Width; int h = imageDesc.Height; int d = imageDesc.Depth; for (uint level = 0; level < imageDesc.MipLevels; ++level) { int rowPitch, slicePitch; int widthPacked; int heightPacked; ComputePitch(imageDesc.Format, w, h, out rowPitch, out slicePitch, out widthPacked, out heightPacked, pitchFlags); if (rowStride > 0) { // Check that stride is ok if (rowStride < rowPitch) throw new InvalidOperationException(string.Format("Invalid stride [{0}]. Value can't be lower than actual stride [{1}]", rowStride, rowPitch)); if (widthPacked != w || heightPacked != h) throw new InvalidOperationException("Custom strides is not supported with packed PixelFormats"); // Override row pitch rowPitch = rowStride; // Recalculate slice pitch slicePitch = rowStride * h; } for (uint zSlice = 0; zSlice < d; ++zSlice) { // We use the same memory organization that Direct3D 11 needs for D3D11_SUBRESOURCE_DATA // with all slices of a given miplevel being continuous in memory output[index] = new PixelBuffer(w, h, imageDesc.Format, rowPitch, slicePitch, (IntPtr)pixels); ++index; pixels += slicePitch; } if (h > 1) h >>= 1; if (w > 1) w >>= 1; if (d > 1) d >>= 1; } } }
public static void ComputePitch(PixelFormats fmt, int width, int height, out int rowPitch, out int slicePitch, out int widthCount, out int heightCount, PitchFlags flags = PitchFlags.None) { widthCount = width; heightCount = height; if (IsCompressedFormat(fmt)) { int bpb = (fmt == PixelFormats.BC1_TYPELESS || fmt == PixelFormats.BC1_UNORM || fmt == PixelFormats.BC1_UNORM_SRGB || fmt == PixelFormats.BC4_TYPELESS || fmt == PixelFormats.BC4_UNORM || fmt == PixelFormats.BC4_SNORM) ? 8 : 16; widthCount = Math.Max(1, (width + 3) / 4); heightCount = Math.Max(1, (height + 3) / 4); rowPitch = widthCount * bpb; slicePitch = rowPitch * heightCount; } else if (IsPacked(fmt)) { rowPitch = ((width + 1) >> 1) * 4; slicePitch = rowPitch * height; } else { int bpp; if ((flags & PitchFlags.Bpp24) != 0) { bpp = 24; } else if ((flags & PitchFlags.Bpp16) != 0) { bpp = 16; } else if ((flags & PitchFlags.Bpp8) != 0) { bpp = 8; } else { bpp = GetBitsPerPixel(fmt); } if ((flags & PitchFlags.LegacyDword) != 0) { // Special computation for some incorrectly created DDS files based on // legacy DirectDraw assumptions about pitch alignment rowPitch = ((width * bpp + 31) / 32) * sizeof(int); slicePitch = rowPitch * height; } else { rowPitch = (width * bpp + 7) / 8; slicePitch = rowPitch * height; } } }
public GorgonPitchLayout GetPitchForFormat(int width, int height, PitchFlags flags = PitchFlags.None) { int rowPitch; // Do calculations for compressed formats. if (IsCompressed) { int bpb; switch (Format) { case BufferFormat.BC1_Typeless: case BufferFormat.BC1_UNorm: case BufferFormat.BC1_UNorm_SRgb: case BufferFormat.BC4_Typeless: case BufferFormat.BC4_SNorm: case BufferFormat.BC4_UNorm: bpb = 8; break; default: bpb = 16; break; } /* * int widthCounter = 1.Max((width + 3) / 4); * int heightCounter = 1.Max((height + 3) / 4); * rowPitch = widthCounter * bpb;*/ long numBlocksWide = 0; if (width > 0) { numBlocksWide = (width + 3) / 4; } long numBlocksHigh = 0; if (height > 0) { numBlocksHigh = (height + 3) / 4; } long rowBytes = numBlocksWide * bpb; long numBytes = rowBytes * numBlocksHigh; return(new GorgonPitchLayout((int)rowBytes, (int)numBytes, (int)numBlocksWide, (int)numBlocksHigh)); } if (IsPacked) { int slicePitch = 0; switch (Format) { case BufferFormat.R8G8_B8G8_UNorm: case BufferFormat.G8R8_G8B8_UNorm: case BufferFormat.YUY2: rowPitch = ((width + 1) >> 1) << 2; slicePitch = rowPitch * height; break; case BufferFormat.Y210: case BufferFormat.Y216: rowPitch = ((width + 1) >> 1) << 4; slicePitch = rowPitch * height; break; case BufferFormat.NV12: case BufferFormat.Opaque420: rowPitch = ((width + 1) >> 1) << 1; slicePitch = rowPitch * (height + ((height + 1) >> 1)); break; case BufferFormat.P010: case BufferFormat.P016: rowPitch = ((width + 1) >> 1) << 2; slicePitch = rowPitch * (height + ((height + 1) >> 1)); break; case BufferFormat.NV11: rowPitch = ((width + 3) >> 2) << 2; slicePitch = (rowPitch * height) << 1; break; default: rowPitch = 0; break; } Debug.Assert(rowPitch != 0, "Format [" + Format + "] is a packed format. Cannot to extract pitch/slice info."); return(new GorgonPitchLayout(rowPitch, slicePitch)); } int bitsPerPixel = BitDepth; if ((flags & PitchFlags.BPP24) == PitchFlags.BPP24) { bitsPerPixel = 24; } else if ((flags & PitchFlags.BPP16) == PitchFlags.BPP16) { bitsPerPixel = 16; } else if ((flags & PitchFlags.BPP8) == PitchFlags.BPP8) { bitsPerPixel = 8; } // This is for handling old DirectDraw DDS files that didn't output // properly because of assumptions about pitch alignment. if ((flags & PitchFlags.LegacyDWORD) == PitchFlags.LegacyDWORD) { rowPitch = (((width * bitsPerPixel) + 31) / 32) * sizeof(int); } else if ((flags & PitchFlags.Align4K) == PitchFlags.Align4K) { rowPitch = (((width * bitsPerPixel) + 32767) / 32768) * 4096; } else if ((flags & PitchFlags.Align64Byte) == PitchFlags.Align64Byte) { rowPitch = (((width * bitsPerPixel) + 511) / 512) * 64; } else if ((flags & PitchFlags.Align32Byte) == PitchFlags.Align32Byte) { rowPitch = (((width * bitsPerPixel) + 255) / 256) * 32; } else if ((flags & PitchFlags.Align16Byte) == PitchFlags.Align16Byte) { rowPitch = (((width * bitsPerPixel) + 127) / 128) * 16; } else { rowPitch = (((width * bitsPerPixel) + 7) / 8); } return(new GorgonPitchLayout(rowPitch, rowPitch * height)); }
internal static void ComputePitch(Format fmt, int width, int height, out int rowPitch, out int slicePitch, out int widthCount, out int heightCount, PitchFlags flags = PitchFlags.None) { widthCount = width; heightCount = height; if (FormatHelper.IsCompressed(fmt)) { int bpb = (fmt == Format.BC1_Typeless || fmt == Format.BC1_UNorm || fmt == Format.BC1_UNorm_SRgb || fmt == Format.BC4_Typeless || fmt == Format.BC4_UNorm || fmt == Format.BC4_SNorm) ? 8 : 16; widthCount = Math.Max(1, (width + 3) / 4); heightCount = Math.Max(1, (height + 3) / 4); rowPitch = widthCount * bpb; slicePitch = rowPitch * heightCount; } else if (FormatHelper.IsPacked(fmt)) { rowPitch = ((width + 1) >> 1) * 4; slicePitch = rowPitch * height; } else { int bpp; if ((flags & PitchFlags.Bpp24) != 0) { bpp = 24; } else if ((flags & PitchFlags.Bpp16) != 0) { bpp = 16; } else if ((flags & PitchFlags.Bpp8) != 0) { bpp = 8; } else { bpp = FormatHelper.SizeOfInBits(fmt); } if ((flags & PitchFlags.LegacyDword) != 0) { // Special computation for some incorrectly created DDS files based on // legacy DirectDraw assumptions about pitch alignment rowPitch = ((width * bpp + 31) / 32) * sizeof(int); slicePitch = rowPitch * height; } else { rowPitch = (width * bpp + 7) / 8; slicePitch = rowPitch * height; } } }
/// <summary> /// Determines number of image array entries and pixel size. /// </summary> /// <param name="imageDesc">Description of the image to create.</param> /// <param name="pitchFlags">Pitch flags.</param> /// <param name="bufferCount">Output number of mipmap.</param> /// <param name="pixelSizeInBytes">Output total size to allocate pixel buffers for all images.</param> private static List<int> CalculateImageArray( ImageDescription imageDesc, PitchFlags pitchFlags, out int bufferCount, out int pixelSizeInBytes) { pixelSizeInBytes = 0; bufferCount = 0; var mipmapToZIndex = new List<int>(); for (int j = 0; j < imageDesc.ArraySize; j++) { int w = imageDesc.Width; int h = imageDesc.Height; int d = imageDesc.Depth; for (int i = 0; i < imageDesc.MipLevels; i++) { int rowPitch, slicePitch; int widthPacked; int heightPacked; ComputePitch(imageDesc.Format, w, h, out rowPitch, out slicePitch, out widthPacked, out heightPacked, pitchFlags); // Store the number of z-slicec per miplevels if ( j == 0) mipmapToZIndex.Add(bufferCount); // Keep a trace of indices for the 1st array size, for each mip levels pixelSizeInBytes += d * slicePitch; bufferCount += d; if (h > 1) h >>= 1; if (w > 1) w >>= 1; if (d > 1) d >>= 1; } // For the last mipmaps, store just the number of zbuffers in total if (j == 0) mipmapToZIndex.Add(bufferCount); } return mipmapToZIndex; }
internal unsafe void Initialize(ImageDescription description, IntPtr dataPointer, int offset, GCHandle? handle, bool bufferIsDisposable, PitchFlags pitchFlags = PitchFlags.None, int rowStride = 0) { if (!description.Format.IsValid() || description.Format.IsVideo()) throw new InvalidOperationException("Unsupported DXGI Format"); if (rowStride > 0 && description.MipLevels != 1) throw new InvalidOperationException("Cannot specify custom stride with mipmaps"); this.handle = handle; switch (description.Dimension) { case TextureDimension.Texture1D: if (description.Width <= 0 || description.Height != 1 || description.Depth != 1 || description.ArraySize == 0) throw new InvalidOperationException("Invalid Width/Height/Depth/ArraySize for Image 1D"); // Check that miplevels are fine description.MipLevels = CalculateMipLevels(description.Width, 1, description.MipLevels); break; case TextureDimension.Texture2D: case TextureDimension.TextureCube: if (description.Width <= 0 || description.Height <= 0 || description.Depth != 1 || description.ArraySize == 0) throw new InvalidOperationException("Invalid Width/Height/Depth/ArraySize for Image 2D"); if (description.Dimension == TextureDimension.TextureCube) { if ((description.ArraySize % 6) != 0) throw new InvalidOperationException("TextureCube must have an arraysize = 6"); } // Check that miplevels are fine description.MipLevels = CalculateMipLevels(description.Width, description.Height, description.MipLevels); break; case TextureDimension.Texture3D: if (description.Width <= 0 || description.Height <= 0 || description.Depth <= 0 || description.ArraySize != 1) throw new InvalidOperationException("Invalid Width/Height/Depth/ArraySize for Image 3D"); // Check that miplevels are fine description.MipLevels = CalculateMipLevels(description.Width, description.Height, description.Depth, description.MipLevels); break; } // Calculate mipmaps int pixelBufferCount; this.mipMapToZIndex = CalculateImageArray(description, pitchFlags, rowStride, out pixelBufferCount, out totalSizeInBytes); this.mipmapDescriptions = CalculateMipMapDescription(description, pitchFlags); zBufferCountPerArraySlice = this.mipMapToZIndex[this.mipMapToZIndex.Count - 1]; // Allocate all pixel buffers pixelBuffers = new PixelBuffer[pixelBufferCount]; pixelBufferArray = new PixelBufferArray(this); // Setup all pointers // only release buffer that is not pinned and is asked to be disposed. this.bufferIsDisposable = !handle.HasValue && bufferIsDisposable; this.buffer = dataPointer; if (dataPointer == IntPtr.Zero) { buffer = Utilities.AllocateMemory(totalSizeInBytes); offset = 0; this.bufferIsDisposable = true; } SetupImageArray((IntPtr)((byte*)buffer + offset), totalSizeInBytes, rowStride, description, pitchFlags, pixelBuffers); Description = description; // PreCompute databoxes dataBoxArray = ComputeDataBox(); }
internal static MipMapDescription[] CalculateMipMapDescription(ImageDescription metadata, PitchFlags cpFlags = PitchFlags.None) { int nImages; int pixelSize; return(CalculateMipMapDescription(metadata, cpFlags, out nImages, out pixelSize)); }
internal static MipMapDescription[] CalculateMipMapDescription(ImageDescription metadata, PitchFlags cpFlags = PitchFlags.None) { int nImages; int pixelSize; return CalculateMipMapDescription(metadata, cpFlags, out nImages, out pixelSize); }
internal static MipMapDescription[] CalculateMipMapDescription(ImageDescription metadata, PitchFlags cpFlags, out int nImages, out int pixelSize) { pixelSize = 0; nImages = 0; int w = metadata.Width; int h = metadata.Height; int d = metadata.Depth; var mipmaps = new MipMapDescription[metadata.MipLevels]; for (int level = 0; level < metadata.MipLevels; ++level) { int rowPitch, slicePitch; int widthPacked; int heightPacked; ComputePitch(metadata.Format, w, h, out rowPitch, out slicePitch, out widthPacked, out heightPacked, PitchFlags.None); mipmaps[level] = new MipMapDescription( w, h, d, rowPitch, slicePitch, widthPacked, heightPacked ); pixelSize += d * slicePitch; nImages += d; if (h > 1) { h >>= 1; } if (w > 1) { w >>= 1; } if (d > 1) { d >>= 1; } } return(mipmaps); }
public static void ComputePitch(PixelFormats fmt, int width, int height, out int rowPitch, out int slicePitch, out int widthCount, out int heightCount, PitchFlags flags = PitchFlags.None) { widthCount = width; heightCount = height; if (IsCompressedFormat(fmt)) { int bpb = (fmt == PixelFormats.BC1_TYPELESS || fmt == PixelFormats.BC1_UNORM || fmt == PixelFormats.BC1_UNORM_SRGB || fmt == PixelFormats.BC4_TYPELESS || fmt == PixelFormats.BC4_UNORM || fmt == PixelFormats.BC4_SNORM) ? 8 : 16; widthCount = Math.Max(1, (width + 3)/4); heightCount = Math.Max(1, (height + 3)/4); rowPitch = widthCount*bpb; slicePitch = rowPitch*heightCount; } else if (IsPacked(fmt)) { rowPitch = ((width + 1) >> 1)*4; slicePitch = rowPitch*height; } else { int bpp; if ((flags & PitchFlags.Bpp24) != 0) bpp = 24; else if ((flags & PitchFlags.Bpp16) != 0) bpp = 16; else if ((flags & PitchFlags.Bpp8) != 0) bpp = 8; else bpp = GetBitsPerPixel(fmt); if ((flags & PitchFlags.LegacyDword) != 0) { // Special computation for some incorrectly created DDS files based on // legacy DirectDraw assumptions about pitch alignment rowPitch = ((width*bpp + 31)/32)*sizeof (int); slicePitch = rowPitch*height; } else { rowPitch = (width*bpp + 7)/8; slicePitch = rowPitch*height; } } }