26 using SiliconStudio.Core;
27 using SiliconStudio.Core.ReferenceCounting;
28 using SiliconStudio.Core.Serialization.Contents;
31 namespace SiliconStudio.Paradox.Graphics
88 internal readonly
int RowStride;
93 internal readonly
int DepthStride;
98 internal readonly
Texture ParentTexture;
107 : this(device, parentTexture.Description, viewType, viewArraySlice, viewMipLevel, viewFormat)
109 ParentTexture = parentTexture;
110 ParentTexture.AddReferenceInternal();
115 Description = description;
116 IsBlockCompressed = description.Format.IsCompressed();
117 RowStride = this.Description.Width * description.Format.SizeInBytes();
118 DepthStride = RowStride * this.Description.Height;
119 mipmapDescriptions = Image.CalculateMipMapDescription(description);
121 Width = Math.Max(1, Description.Width >> viewMipLevel);
122 Height = Math.Max(1, Description.Height >> viewMipLevel);
123 Depth = Math.Max(1, Description.Depth >> viewMipLevel);
124 MipLevel = viewMipLevel;
125 ViewFormat = viewFormat == PixelFormat.None ? description.Format : viewFormat;
126 ArraySlice = viewArraySlice;
132 var description = this.Description;
134 description.Usage = GraphicsResourceUsage.Default;
141 if (ParentTexture != null)
143 ParentTexture.ReleaseInternal();
154 public T ToTexture<T>(
ViewType viewType,
int arrayOrDepthSlice,
int mipMapSlice) where T :
Texture
156 return (T)ToTexture(viewType, arrayOrDepthSlice, mipMapSlice);
166 public abstract Texture ToTexture(
ViewType viewType,
int arraySlice,
int mipMapSlice);
170 return ToRenderTarget(
ViewType.Single, 0, 0);
180 return mipmapDescriptions[mipmap];
185 mipLevel = Math.Min(mipLevel, Image.CountMips(width));
186 width = width >> mipLevel;
187 return width > 0 ? width : 1;
198 return arraySlice * Description.MipLevels + mipSlice;
207 public int CalculateWidth<TData>(
int mipLevel = 0) where TData :
struct
209 var widthOnMip = CalculateMipSize((
int)Description.Width, mipLevel);
210 var rowStride = widthOnMip * Description.Format.SizeInBytes();
212 var dataStrideInBytes = Utilities.SizeOf<TData>() * widthOnMip;
213 var width = ((double)rowStride / dataStrideInBytes) * widthOnMip;
214 if (Math.Abs(width - (
int)width) > Double.Epsilon)
215 throw new ArgumentException(
"sizeof(TData) / sizeof(Format) * Width is not an integer");
227 public int CalculatePixelDataCount<TData>(
int mipLevel = 0) where TData :
struct
229 return CalculateWidth<TData>(mipLevel) * CalculateMipSize(Description.Height, mipLevel) * CalculateMipSize(Description.Depth, mipLevel);
241 public abstract Texture Clone();
254 return (T)this.Clone();
268 public TData[] GetData<TData>(
int arraySlice = 0,
int mipSlice = 0) where TData :
struct
270 var toData =
new TData[this.CalculatePixelDataCount<TData>(mipSlice)];
271 GetData(toData, arraySlice, mipSlice);
288 public bool GetData<TData>(TData[] toData,
int arraySlice = 0,
int mipSlice = 0,
bool doNotWait =
false) where TData :
struct
294 return GetData(
this, toData, arraySlice, mipSlice, doNotWait);
299 using (var throughStaging = this.ToStaging())
300 return GetData(throughStaging, toData, arraySlice, mipSlice, doNotWait);
318 public unsafe
bool GetData<TData>(
Texture stagingTexture, TData[] toData,
int arraySlice = 0,
int mipSlice = 0,
bool doNotWait =
false) where TData :
struct
320 return GetData(stagingTexture,
new DataPointer((IntPtr)Interop.Fixed(toData), toData.Length * Utilities.SizeOf<TData>()), arraySlice, mipSlice, doNotWait);
336 public void SetData<TData>(TData[] fromData,
int arraySlice = 0,
int mipSlice = 0,
ResourceRegion? region = null) where TData :
struct
371 public unsafe
void SetData<TData>(
GraphicsDevice device, TData[] fromData,
int arraySlice = 0,
int mipSlice = 0,
ResourceRegion? region = null) where TData :
struct
373 SetData(device,
new DataPointer((IntPtr)Interop.Fixed(fromData), fromData.Length * Utilities.SizeOf<TData>()), arraySlice, mipSlice, region);
391 if (stagingTexture == null)
throw new ArgumentNullException(
"stagingTexture");
396 var mipmap = this.GetMipMapDescription(mipSlice);
399 int height = mipmap.HeightPacked;
400 int depth = mipmap.Depth;
403 int rowStride = mipmap.RowStride;
406 int textureDepthStride = mipmap.DepthStride;
409 int mipMapSize = mipmap.MipmapSize;
412 if (toData.
Size > mipMapSize)
413 throw new ArgumentException(
string.Format(
"Size of toData ({0} bytes) is not compatible expected size ({1} bytes) : Width * Height * Depth * sizeof(PixelFormat) size in bytes", toData.
Size, mipMapSize));
416 if (!ReferenceEquals(
this, stagingTexture))
417 device.Copy(
this, stagingTexture);
420 int subResourceIndex = this.GetSubResourceIndex(arraySlice, mipSlice);
423 var mappedResource = device.MapSubresource(stagingTexture, subResourceIndex, MapMode.Read, doNotWait);
426 var box = mappedResource.DataBox;
433 var boxDepthStride = this.Description.Depth == 1 ? box.SlicePitch : textureDepthStride;
435 var isFlippedTexture = IsFlippedTexture();
438 if (box.RowPitch == rowStride && boxDepthStride == textureDepthStride && !isFlippedTexture)
440 Utilities.CopyMemory(toData.Pointer, box.DataPointer, mipMapSize);
445 var sourcePerDepthPtr = (byte*)box.DataPointer;
446 var destPtr = (byte*)toData.Pointer;
449 for (
int j = 0; j < depth; j++)
451 var sourcePtr = sourcePerDepthPtr;
454 if (isFlippedTexture)
456 sourcePtr = sourcePtr + box.RowPitch * (height - 1);
457 for (
int i = height - 1; i >= 0; i--)
460 Utilities.CopyMemory(
new IntPtr(destPtr),
new IntPtr(sourcePtr), rowStride);
461 sourcePtr -= box.RowPitch;
462 destPtr += rowStride;
467 for (
int i = 0; i < height; i++)
470 Utilities.CopyMemory(
new IntPtr(destPtr),
new IntPtr(sourcePtr), rowStride);
471 sourcePtr += box.RowPitch;
472 destPtr += rowStride;
475 sourcePerDepthPtr += box.SlicePitch;
480 device.UnmapSubresource(mappedResource);
499 if (device == null)
throw new ArgumentNullException(
"device");
501 throw new ArgumentException(
"Region is only supported for textures with ResourceUsage.Default");
504 var mipMapDesc = this.GetMipMapDescription(mipSlice);
506 int width = mipMapDesc.Width;
507 int height = mipMapDesc.Height;
508 int depth = mipMapDesc.Depth;
513 int newWidth = region.Value.Right - region.Value.Left;
514 int newHeight = region.Value.Bottom - region.Value.Top;
515 int newDepth = region.Value.Back - region.Value.Front;
516 if (newWidth > width)
517 throw new ArgumentException(
string.Format(
"Region width [{0}] cannot be greater than mipmap width [{1}]", newWidth, width),
"region");
518 if (newHeight > height)
519 throw new ArgumentException(
string.Format(
"Region height [{0}] cannot be greater than mipmap height [{1}]", newHeight, height),
"region");
520 if (newDepth > depth)
521 throw new ArgumentException(
string.Format(
"Region depth [{0}] cannot be greater than mipmap depth [{1}]", newDepth, depth),
"region");
529 var sizePerElement = Description.Format.SizeInBytes();
535 int textureDepthStride;
538 Image.ComputePitch(this.Description.Format, width, height, out rowStride, out textureDepthStride, out width, out height);
541 int sizeOfTextureData = textureDepthStride * depth;
544 if (fromData.
Size != sizeOfTextureData)
545 throw new ArgumentException(
string.Format(
"Size of toData ({0} bytes) is not compatible expected size ({1} bytes) : Width * Height * Depth * sizeof(PixelFormat) size in bytes", fromData.
Size, sizeOfTextureData));
548 int subResourceIndex = this.GetSubResourceIndex(arraySlice, mipSlice);
556 var regionValue = region.Value;
557 var sourceDataPtr = fromData.Pointer;
561 if (device.NeedWorkAroundForUpdateSubResource)
563 if (IsBlockCompressed)
565 regionValue.Left /= 4;
566 regionValue.Right /= 4;
567 regionValue.Top /= 4;
568 regionValue.Bottom /= 4;
570 sourceDataPtr =
new IntPtr((byte*)sourceDataPtr - (regionValue.Front * textureDepthStride) - (regionValue.Top * rowStride) - (regionValue.Left * sizePerElement));
572 device.UpdateSubresource(
this, subResourceIndex,
new DataBox(sourceDataPtr, rowStride, textureDepthStride), regionValue);
576 device.UpdateSubresource(
this, subResourceIndex,
new DataBox(fromData.
Pointer, rowStride, textureDepthStride));
581 var mappedResource = device.MapSubresource(
this, subResourceIndex, this.Description.Usage == GraphicsResourceUsage.Dynamic ? MapMode.WriteDiscard : MapMode.Write);
582 var box = mappedResource.DataBox;
585 var boxDepthStride = this.Description.Depth == 1 ? box.SlicePitch : textureDepthStride;
588 if (box.RowPitch == rowStride && boxDepthStride == textureDepthStride)
590 Utilities.CopyMemory(box.DataPointer, fromData.Pointer, sizeOfTextureData);
595 var destPerDepthPtr = (byte*)box.DataPointer;
596 var sourcePtr = (byte*)fromData.Pointer;
599 for (
int j = 0; j < depth; j++)
601 var destPtr = destPerDepthPtr;
603 for (
int i = 0; i < height; i++)
605 Utilities.CopyMemory((IntPtr)destPtr, (IntPtr)sourcePtr, rowStride);
606 destPtr += box.RowPitch;
607 sourcePtr += rowStride;
609 destPerDepthPtr += box.SlicePitch;
613 device.UnmapSubresource(mappedResource);
621 public abstract Texture ToStaging();
633 using (var image = Image.Load(stream))
634 return New(device, image, textureFlags, usage);
648 if (device == null)
throw new ArgumentNullException(
"device");
649 if (image == null)
throw new ArgumentNullException(
"image");
652 case TextureDimension.Texture1D:
653 return Texture1D.New(device, image, textureFlags, usage);
654 case TextureDimension.Texture2D:
655 return Texture2D.New(device, image, textureFlags, usage);
656 case TextureDimension.Texture3D:
657 return Texture3D.New(device, image, textureFlags, usage);
658 case TextureDimension.TextureCube:
659 return TextureCube.New(device, image, textureFlags, usage);
662 throw new InvalidOperationException(
"Dimension not supported");
673 if (graphicsDevice == null)
675 throw new ArgumentNullException(
"graphicsDevice");
679 case TextureDimension.Texture1D:
680 return new Texture1D(graphicsDevice, description);
681 case TextureDimension.Texture2D:
682 return new Texture2D(graphicsDevice, description);
683 case TextureDimension.Texture3D:
684 return new Texture3D(graphicsDevice, description);
685 case TextureDimension.TextureCube:
686 return new TextureCube(graphicsDevice, description);
698 if (stream == null)
throw new ArgumentNullException(
"stream");
699 using (var staging = ToStaging())
700 Save(stream, staging, fileType);
708 using (var stagingTexture = ToStaging())
709 return GetDataAsImage(stagingTexture);
719 if (stagingTexture == null)
throw new ArgumentNullException(
"stagingTexture");
721 throw new ArgumentException(
"Invalid texture used as staging. Must have Usage = GraphicsResourceUsage.Staging",
"stagingTexture");
723 var image = Image.New(stagingTexture.Description);
725 for (
int arrayIndex = 0; arrayIndex < image.Description.ArraySize; arrayIndex++)
727 for (
int mipLevel = 0; mipLevel < image.Description.MipLevels; mipLevel++)
729 var pixelBuffer = image.PixelBuffer[arrayIndex, mipLevel];
730 GetData(stagingTexture,
new DataPointer(pixelBuffer.DataPointer, pixelBuffer.BufferStride), arrayIndex, mipLevel);
752 using (var image = GetDataAsImage(stagingTexture))
753 image.Save(stream, fileType);
764 internal static int CalculateMipMapCount(
MipMapCount requestedLevel,
int width,
int height = 0,
int depth = 0)
766 int size = Math.Max(Math.Max(width, height), depth);
767 int maxMipMap = 1 + (int)Math.Ceiling(Math.Log(
size) / Math.Log(2.0));
769 return requestedLevel == 0 ? maxMipMap : Math.Min(requestedLevel, maxMipMap);
772 protected static DataBox GetDataBox<T>(
PixelFormat format,
int width,
int height,
int depth, T[] textureData, IntPtr fixedPointer) where T :
struct
775 if (textureData == null)
throw new ArgumentNullException(
"textureData");
780 Image.ComputePitch(
format, width, height, out rowPitch, out slicePitch, out widthCount, out heightCount);
781 if (
Utilities.SizeOf(textureData) != (slicePitch * depth))
throw new ArgumentException(
"Invalid size for Image");
783 return new DataBox(fixedPointer, rowPitch, slicePitch);
789 desc.Flags = textureFlags;
796 internal void GetViewSliceBounds(
ViewType viewType, ref
int arrayOrDepthIndex, ref
int mipIndex, out
int arrayOrDepthCount, out
int mipCount)
798 int arrayOrDepthSize = this.Description.Depth > 1 ? this.Description.Depth : this.Description.ArraySize;
803 arrayOrDepthIndex = 0;
805 arrayOrDepthCount = arrayOrDepthSize;
806 mipCount = this.Description.MipLevels;
808 case ViewType.Single:
809 arrayOrDepthCount = 1;
812 case ViewType.MipBand:
813 arrayOrDepthCount = arrayOrDepthSize - arrayOrDepthIndex;
816 case ViewType.ArrayBand:
817 arrayOrDepthCount = 1;
818 mipCount = Description.MipLevels - mipIndex;
821 arrayOrDepthCount = 0;
827 internal int GetViewCount()
829 int arrayOrDepthSize = this.Description.Depth > 1 ? this.Description.Depth : this.Description.ArraySize;
830 return GetViewIndex((
ViewType)4, arrayOrDepthSize, this.Description.MipLevels);
833 internal int GetViewIndex(
ViewType viewType,
int arrayOrDepthIndex,
int mipIndex)
835 int arrayOrDepthSize = this.Description.Depth > 1 ? this.Description.Depth : this.Description.ArraySize;
836 return (((
int)viewType) * arrayOrDepthSize + arrayOrDepthIndex) * this.Description.MipLevels + mipIndex;
843 return GraphicsResourceUsage.Default;
Image GetDataAsImage(Texture stagingTexture)
Gets the GPU content of this texture to an Image on the CPU.
Texture(GraphicsDevice device, Texture parentTexture, ViewType viewType, int viewArraySlice, int viewMipLevel, PixelFormat viewFormat=PixelFormat.None)
Texture(GraphicsDevice device, TextureDescription description, ViewType viewType, int viewArraySlice, int viewMipLevel, PixelFormat viewFormat=PixelFormat.None)
readonly PixelFormat ViewFormat
The format of this texture view.
static Texture New(GraphicsDevice graphicsDevice, TextureDescription description)
Creates a new texture with the specified generic texture description.
ImageFileType
Image file format used by Image.Save(string,SiliconStudio.Paradox.Graphics.ImageFileType) ...
A simple wrapper to specify number of mipmaps. Set to true to specify all mipmaps or sets an integer ...
A renderable texture view.
readonly int MipLevel
The miplevel index of this texture view.
static int CalculateMipSize(int width, int mipLevel)
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ DXGI_FORMAT _In_ DWORD flags
Provides method to instantiate an image 1D/2D/3D supporting TextureArray and mipmaps on the CPU or to...
A TextureCube frontend to SharpDX.Direct3D11.Texture2D.
Image GetDataAsImage()
Gets the GPU content of this texture as an Image on the CPU.
GraphicsResourceUsage
Identifies expected resource use during rendering. The usage directly reflects whether a resource is ...
ImageDescription Description
Description of this image.
static Texture New(GraphicsDevice device, Image image, TextureFlags textureFlags=TextureFlags.ShaderResource, GraphicsResourceUsage usage=GraphicsResourceUsage.Immutable)
Loads a texture from a stream.
readonly int Depth
The depth of this texture view.
readonly int ArraySlice
The array index of this texture view.
virtual TextureDescription GetCloneableDescription()
Performs primitive-based rendering, creates resources, handles system-level variables, adjusts gamma ramp levels, and creates shaders. See The+GraphicsDevice+class to learn more about the class.
static Texture Load(GraphicsDevice device, Stream stream, TextureFlags textureFlags=TextureFlags.ShaderResource, GraphicsResourceUsage usage=GraphicsResourceUsage.Immutable)
Loads a texture from a stream.
A Common description for all textures.
TextureDimension Dimension
The dimension of a texture.
int Height
The height of this texture view.
SiliconStudio.Core.Utilities Utilities
GraphicsResourceUsage Usage
unsafe bool GetData(Texture stagingTexture, DataPointer toData, int arraySlice=0, int mipSlice=0, bool doNotWait=false)
Copies the content of this texture from GPU memory to a pointer on CPU memory using a specific stagin...
ViewType
Defines how a view is selected from a resource.
A Texture 3D frontend to SharpDX.Direct3D11.Texture3D.
int Width
The width of this texture view.
A Texture 2D frontend to SharpDX.Direct3D11.Texture2D.
A Texture 1D frontend to SharpDX.Direct3D11.Texture1D.
void Save(Stream stream, ImageFileType fileType)
Saves this texture to a stream with a specified format.
override void Destroy()
Disposes of object resources.
Provides access to data organized in 3D.
RenderTarget ToRenderTarget()
MipMapDescription GetMipMapDescription(int mipmap)
Gets the mipmap description of this instance for the specified mipmap level.
readonly TextureDescription Description
Common description for the original texture.
_In_ size_t _In_ size_t _In_ DXGI_FORMAT format
unsafe void SetData(GraphicsDevice device, DataPointer fromData, int arraySlice=0, int mipSlice=0, ResourceRegion?region=null)
Copies the content an data on CPU memory to this texture into GPU memory.
void Save(Stream stream, Texture stagingTexture, ImageFileType fileType)
Saves this texture to a stream with a specified format.
GraphicsResource abstract class
_In_ size_t _In_ size_t size
PixelFormat
Defines various types of pixel formats.
int GetSubResourceIndex(int arraySlice, int mipSlice)
Gets the absolute sub-resource index from the array and mip slice.
readonly bool IsBlockCompressed
Gets a boolean indicating whether this Texture is a using a block compress format (BC1...
TextureDimension Dimension
The dimension of a texture.
readonly ViewType ViewType
The format of this texture view.
Base class for texture resources.
void SetData(DataPointer fromData, int arraySlice=0, int mipSlice=0, ResourceRegion?region=null)
Copies the content an data on CPU memory to this texture into GPU memory using the specified Graphics...