protected void CopyTo(BaseResource dest, SubresourceBox srcBox, uint srcSubresourceIndex, uint dstSubresourceIndex, uint dstX, uint dstY, uint dstZ) { Assure.NotNull(dest); Assure.False(this == dest && srcSubresourceIndex == dstSubresourceIndex, "Can not copy to/from same subresource."); dest.ThrowIfCannotBeCopyDestination(); lock (InstanceMutationLock) { if (IsDisposed) { Logger.Warn("Attempted copy manipulation from disposed resource of type: " + GetType().Name); return; } lock (dest.InstanceMutationLock) { if (IsDisposed) { Logger.Warn("Attempted copy manipulation to disposed resource of type: " + GetType().Name); return; } InteropUtils.CallNative( NativeMethods.ResourceFactory_CopySubresourceRegion, RenderingModule.DeviceContext, ResourceHandle, srcSubresourceIndex, (IntPtr)(&srcBox), dest.ResourceHandle, dstSubresourceIndex, dstX, dstY, dstZ ).ThrowOnFailure(); } } }
public void TestWrite() { LosgapSystem.InvokeOnMaster(() => { // Define variables and constants const uint WIDTH_TX = 100U; const uint HEIGHT_TX = 100U; const uint WRITE_OFFSET_U = 30U; const uint WRITE_OFFSET_V = 30U; SubresourceBox writeTarget = new SubresourceBox( WRITE_OFFSET_U, WIDTH_TX, WRITE_OFFSET_V, HEIGHT_TX ); Texture2D <TexelFormat.RGBA8Int> srcTex = TextureFactory.NewTexture2D <TexelFormat.RGBA8Int>() .WithUsage(ResourceUsage.Write) .WithMultisampling(true) .WithWidth(WIDTH_TX) .WithHeight(HEIGHT_TX); // Set up context // Execute srcTex.Write( Enumerable.Range(0, (int)writeTarget.Volume) .Select(i => new TexelFormat.RGBA8Int { R = (sbyte)i, G = (sbyte)(i * 2), B = (sbyte)(i * 3), A = (sbyte)(i * 4) }) .ToArray(), writeTarget ); Texture2D <TexelFormat.RGBA8Int> dstTex = srcTex.Clone() .WithUsage(ResourceUsage.StagingRead) .WithPermittedBindings(GPUBindings.None); srcTex.CopyTo(dstTex); // Assert outcome TexelArray2D <TexelFormat.RGBA8Int> copiedData = dstTex.Read(0U); for (uint v = WRITE_OFFSET_V, value = 0U; v < HEIGHT_TX; ++v) { for (uint u = WRITE_OFFSET_U; u < WIDTH_TX; ++u, ++value) { Assert.AreEqual((sbyte)value, copiedData[(int)u, (int)v].R); Assert.AreEqual((sbyte)(value * 2U), copiedData[(int)u, (int)v].G); Assert.AreEqual((sbyte)(value * 3U), copiedData[(int)u, (int)v].B); Assert.AreEqual((sbyte)(value * 4U), copiedData[(int)u, (int)v].A); } } srcTex.Dispose(); dstTex.Dispose(); }); }
public void CopyTo(Texture2D <TTexel> dest, SubresourceBox srcRegion, uint srcMipIndex = 0U, uint dstMipIndex = 0U, uint destWriteOffsetX = 0U, uint destWriteOffsetY = 0U) { Assure.LessThan( srcMipIndex, NumMips, "Can not copy from mip level " + srcMipIndex + ": Only " + NumMips + " present in source texture." ); Assure.LessThan( dstMipIndex, dest.NumMips, "Can not copy to mip level " + dstMipIndex + ": Only " + dest.NumMips + " present in destination texture." ); Assure.LessThan( srcRegion.Left, MipWidth(srcMipIndex), "Buffer overflow: Please ensure you are not attempting to copy from past the end of the source texture." ); Assure.LessThanOrEqualTo( srcRegion.Right, MipWidth(srcMipIndex), "Buffer overflow: Please ensure you are not attempting to copy from past the end of the source texture." ); Assure.LessThan( srcRegion.Top, MipHeight(srcMipIndex), "Buffer overflow: Please ensure you are not attempting to copy from past the end of the source texture." ); Assure.LessThanOrEqualTo( srcRegion.Bottom, MipHeight(srcMipIndex), "Buffer overflow: Please ensure you are not attempting to copy from past the end of the source texture." ); Assure.LessThanOrEqualTo( srcRegion.Width + destWriteOffsetX, dest.MipWidth(dstMipIndex), "Buffer overflow: Please ensure you are not attempting to copy to past the end of the destination texture." ); Assure.LessThanOrEqualTo( srcRegion.Height + destWriteOffsetY, dest.MipHeight(dstMipIndex), "Buffer overflow: Please ensure you are not attempting to copy to past the end of the destination texture." ); base.CopyTo( dest, srcRegion, GetSubresourceIndex(srcMipIndex), dest.GetSubresourceIndex(dstMipIndex), destWriteOffsetX, destWriteOffsetY, 0U ); }
private void Mutate_UpdateSubresourceRegion(IntPtr data, SubresourceBox updateBox) { lock (InstanceMutationLock) { if (IsDisposed) { Logger.Warn("Attempted write manipulation on disposed resource of type: " + GetType().Name); return; } InteropUtils.CallNative( NativeMethods.ResourceFactory_UpdateSubresourceRegion, RenderingModule.DeviceContext, ResourceHandle, 0U, (IntPtr)(&updateBox), data, (uint)Size, (uint)Size ).ThrowOnFailure(); } }
private void Mutate_MapWrite(GCHandle pinnedDataHandle, SubresourceBox dataDesc, uint mipIndex) { LosgapSystem.InvokeOnMasterAsync(() => { IntPtr dstDataPtr; uint outRowStrideBytes, outSliceStrideBytes; InteropUtils.CallNative( NativeMethods.ResourceFactory_MapSubresource, RenderingModule.DeviceContext, ResourceHandle, GetSubresourceIndex(mipIndex), ResourceMapping.Write, (IntPtr)(&dstDataPtr), (IntPtr)(&outRowStrideBytes), (IntPtr)(&outSliceStrideBytes) ).ThrowOnFailure(); try { IntPtr srcDataPtr = pinnedDataHandle.AddrOfPinnedObject(); for (uint srcSlice = 0U, dstSliceStart = outSliceStrideBytes * dataDesc.Front; srcSlice < dataDesc.Depth; ++srcSlice, dstSliceStart += outSliceStrideBytes) { for (uint srcRow = 0U, dstRowStart = outRowStrideBytes * dataDesc.Top; srcRow < dataDesc.Height; ++srcRow, dstRowStart += outRowStrideBytes) { UnsafeUtils.MemCopy(srcDataPtr + (int)((dataDesc.Width * srcRow + dataDesc.Height * srcSlice) * TexelSizeBytes), dstDataPtr + (int)(dataDesc.Left + dstRowStart + dstSliceStart), dataDesc.Width * TexelSizeBytes); } } } finally { InteropUtils.CallNative( NativeMethods.ResourceFactory_UnmapSubresource, RenderingModule.DeviceContext, ResourceHandle, GetSubresourceIndex(mipIndex) ).ThrowOnFailure(); } }); }
public void TestDerivedProperties() { // Define variables and constants SubresourceBox box1 = new SubresourceBox(10, 30); SubresourceBox box2 = new SubresourceBox(10, 30, 20, 50); SubresourceBox box3 = new SubresourceBox(10, 30, 20, 50, 60, 100); // Set up context // Execute // Assert outcome Assert.AreEqual(20U, box1.Width); Assert.AreEqual(20U, box2.Width); Assert.AreEqual(20U, box3.Width); Assert.AreEqual(30U, box2.Height); Assert.AreEqual(30U, box3.Height); Assert.AreEqual(40U, box3.Depth); Assert.AreEqual(20U, box1.Volume); Assert.AreEqual(600U, box2.Volume); Assert.AreEqual(24000U, box3.Volume); }
public void TestCopyTo() { LosgapSystem.InvokeOnMaster(() => { // Define variables and constants const uint WIDTH_TX = 256U; const uint HEIGHT_TX = 32U; const uint DEPTH_TX = 32U; const uint NUM_TEXELS_TO_COPY_PER_ROW = 25U; const uint FIRST_TEXEL_TO_COPY_IN_ROW = 25U; const uint NUM_ROWS_TO_COPY_PER_SLICE = 5U; const uint FIRST_ROW_TO_COPY_IN_SLICE = 1U; const uint NUM_SLICES_TO_COPY = 10U; const uint FIRST_SLICE_TO_COPY = 4U; const uint SRC_MIP_INDEX = 1U; const uint DST_MIP_INDEX = 1U; const uint DST_WRITE_OFFSET_X = 15U; const uint DST_WRITE_OFFSET_Y = 2U; const uint DST_WRITE_OFFSET_Z = 0U; const float DATA_VALUE_ADDITION_W = (float)(HEIGHT_TX >> 1) * (float)(WIDTH_TX >> 1); const float DATA_VALUE_ADDITION_V = (float)(WIDTH_TX >> 1); const float DATA_VALUE_START_R = WIDTH_TX * HEIGHT_TX * DEPTH_TX + FIRST_TEXEL_TO_COPY_IN_ROW + DATA_VALUE_ADDITION_V * FIRST_ROW_TO_COPY_IN_SLICE + DATA_VALUE_ADDITION_W * FIRST_SLICE_TO_COPY; TexelFormat.RGBA32Float[] initialData = Enumerable.Range(0, (int)TextureUtils.GetSizeTexels(true, WIDTH_TX, HEIGHT_TX, DEPTH_TX)) .Select(i => new TexelFormat.RGBA32Float { R = (float)i, G = (float)i * 2f, B = (float)i * 4f, A = (float)i * 8f }) .ToArray(); Texture3D <TexelFormat.RGBA32Float> srcTex = TextureFactory.NewTexture3D <TexelFormat.RGBA32Float>() .WithDynamicDetail(false) .WithInitialData(initialData) .WithMipAllocation(true) .WithMipGenerationTarget(false) .WithPermittedBindings(GPUBindings.ReadableShaderResource) .WithUsage(ResourceUsage.Immutable) .WithWidth(WIDTH_TX) .WithHeight(HEIGHT_TX) .WithDepth(DEPTH_TX); // Set up context // Execute Texture3D <TexelFormat.RGBA32Float> dstTex = srcTex.Clone() .WithUsage(ResourceUsage.StagingRead) .WithPermittedBindings(GPUBindings.None); SubresourceBox targetBox = new SubresourceBox( FIRST_TEXEL_TO_COPY_IN_ROW, FIRST_TEXEL_TO_COPY_IN_ROW + NUM_TEXELS_TO_COPY_PER_ROW, FIRST_ROW_TO_COPY_IN_SLICE, FIRST_ROW_TO_COPY_IN_SLICE + NUM_ROWS_TO_COPY_PER_SLICE, FIRST_SLICE_TO_COPY, FIRST_SLICE_TO_COPY + NUM_SLICES_TO_COPY ); srcTex.CopyTo( dstTex, targetBox, SRC_MIP_INDEX, DST_MIP_INDEX, DST_WRITE_OFFSET_X, DST_WRITE_OFFSET_Y, DST_WRITE_OFFSET_Z ); // Assert outcome TexelArray3D <TexelFormat.RGBA32Float> copiedData = dstTex.Read(DST_MIP_INDEX); for (int w = 0; w < NUM_SLICES_TO_COPY; ++w) { for (int v = 0; v < NUM_ROWS_TO_COPY_PER_SLICE; ++v) { for (int u = 0; u < NUM_TEXELS_TO_COPY_PER_ROW; ++u) { var thisTexel = copiedData[u + (int)DST_WRITE_OFFSET_X, v + (int)DST_WRITE_OFFSET_Y, w + (int)DST_WRITE_OFFSET_Z]; Assert.AreEqual((float)(DATA_VALUE_START_R + u + v * DATA_VALUE_ADDITION_V + w * DATA_VALUE_ADDITION_W), thisTexel.R); Assert.AreEqual((float)(DATA_VALUE_START_R + u + v * DATA_VALUE_ADDITION_V + w * DATA_VALUE_ADDITION_W) * 2f, thisTexel.G); Assert.AreEqual((float)(DATA_VALUE_START_R + u + v * DATA_VALUE_ADDITION_V + w * DATA_VALUE_ADDITION_W) * 4f, thisTexel.B); Assert.AreEqual((float)(DATA_VALUE_START_R + u + v * DATA_VALUE_ADDITION_V + w * DATA_VALUE_ADDITION_W) * 8f, thisTexel.A); } } } srcTex.Dispose(); dstTex.Dispose(); }); }
/// <summary> /// Performs a <see cref="ResourceUsage.Write"/> on this texture, copying the supplied data to the resource. /// </summary> /// <param name="data">The data to write. /// <see cref="ArraySlice{T}.Length">Length</see> vertices will be copied from the given /// array slice. The copy will start from the specified <see cref="ArraySlice{T}.Offset">Offset</see> in the /// contained array. /// </param> /// <param name="writeOffsetX">The first texel in this texture to start copying the data to.</param> /// <param name="mipIndex">The mip level to write to. Only one mip level may be written to at a time. If this texture /// is not mipmapped, you must supply a value of <c>0U</c>.</param> /// <exception cref="ResourceOperationUnavailableException">Thrown if <see cref="BaseResource.CanDiscardWrite"/> is /// <c>false</c>.</exception> /// <exception cref="AssuranceFailedException">(Debug only) Thrown if the combination of supplied parameters would /// result in writing past the end of the texture in any dimension.</exception> public void Write(ArraySlice <TTexel> data, uint mipIndex = 0U, uint writeOffsetX = 0U) { Assure.LessThan( mipIndex, NumMips, "Can not write to mip level " + mipIndex + ": Only " + NumMips + " present in texture." ); Assure.LessThan( data.Length + writeOffsetX, Width, "Buffer overrun: Please ensure you are not attempting to write past the end of the texture." ); ThrowIfCannotWrite(); lock (InstanceMutationLock) { if (IsDisposed) { Logger.Warn("Attempted write manipulation on disposed resource of type: " + GetType().Name); return; } if (Usage.ShouldUpdateSubresourceRegion()) { GCHandle pinnedDataHandle = GCHandle.Alloc(data.ContainingArray, GCHandleType.Pinned); try { SubresourceBox subBox = new SubresourceBox(writeOffsetX, writeOffsetX + data.Length); InteropUtils.CallNative( NativeMethods.ResourceFactory_UpdateSubresourceRegion, RenderingModule.DeviceContext, ResourceHandle, GetSubresourceIndex(mipIndex), (IntPtr)(&subBox), pinnedDataHandle.AddrOfPinnedObject() + (int)(data.Offset * TexelSizeBytes), (uint)Size, (uint)Size ).ThrowOnFailure(); } finally { pinnedDataHandle.Free(); } } else { LosgapSystem.InvokeOnMasterAsync(() => { IntPtr outDataPtr; uint outRowStrideBytes, outSliceStrideBytes; InteropUtils.CallNative( NativeMethods.ResourceFactory_MapSubresource, RenderingModule.DeviceContext, ResourceHandle, GetSubresourceIndex(mipIndex), ResourceMapping.Write, (IntPtr)(&outDataPtr), (IntPtr)(&outRowStrideBytes), (IntPtr)(&outSliceStrideBytes) ).ThrowOnFailure(); try { UnsafeUtils.CopyGenericArray(data, outDataPtr + (int)(writeOffsetX * TexelSizeBytes), TexelSizeBytes); } finally { InteropUtils.CallNative( NativeMethods.ResourceFactory_UnmapSubresource, RenderingModule.DeviceContext, ResourceHandle, GetSubresourceIndex(mipIndex) ).ThrowOnFailure(); } }); } } }
/// <summary> /// Performs a <see cref="ResourceUsage.Write"/> on this texture, copying the supplied data to the resource. /// </summary> /// <param name="data">The data to write. /// <see cref="ArraySlice{T}.Length">Length</see> vertices will be copied from the given /// array slice. The copy will start from the specified <see cref="ArraySlice{T}.Offset">Offset</see> in the /// contained array. /// </param> /// <param name="dataDesc">The region of the selected <paramref name="mipIndex"/> to write to. The /// <see cref="SubresourceBox.Volume"/> of the box must be equal to the <see cref="ArraySlice{T}.Length">Length</see> /// parameter of the supplied <paramref name="data"/>.</param> /// <param name="mipIndex">The mip level to write to. Only one mip level may be written to at a time. If this texture /// is not mipmapped, you must supply a value of <c>0U</c>.</param> /// <exception cref="ResourceOperationUnavailableException">Thrown if <see cref="BaseResource.CanDiscardWrite"/> is /// <c>false</c>.</exception> /// <exception cref="AssuranceFailedException">(Debug only) Thrown if the combination of supplied parameters would /// result in writing past the end of the texture in any dimension.</exception> public void Write(ArraySlice <TTexel> data, SubresourceBox dataDesc, uint mipIndex = 0U) { Assure.LessThan( mipIndex, NumMips, "Can not write to mip level " + mipIndex + ": Only " + NumMips + " present in texture." ); Assure.Equal( data.Length, dataDesc.Volume, "Invalid parameters: Data length must equal the write target region area." ); Assure.LessThanOrEqualTo( dataDesc.Left, Width, "Buffer overrun: Please ensure you are not attempting to write past the end of the texture." ); Assure.LessThanOrEqualTo( dataDesc.Right, Width, "Buffer overrun: Please ensure you are not attempting to write past the end of the texture." ); Assure.LessThanOrEqualTo( dataDesc.Top, Height, "Buffer overrun: Please ensure you are not attempting to write past the end of the texture." ); Assure.LessThanOrEqualTo( dataDesc.Bottom, Height, "Buffer overrun: Please ensure you are not attempting to write past the end of the texture." ); Assure.LessThanOrEqualTo( dataDesc.Front, Depth, "Buffer overrun: Please ensure you are not attempting to write past the end of the texture." ); Assure.LessThanOrEqualTo( dataDesc.Back, Depth, "Buffer overrun: Please ensure you are not attempting to write past the end of the texture." ); ThrowIfCannotWrite(); lock (InstanceMutationLock) { if (IsDisposed) { Logger.Warn("Attempted write manipulation on disposed resource of type: " + GetType().Name); return; } GCHandle pinnedDataHandle = GCHandle.Alloc(data.ContainingArray, GCHandleType.Pinned); try { if (Usage.ShouldUpdateSubresourceRegion()) { InteropUtils.CallNative( NativeMethods.ResourceFactory_UpdateSubresourceRegion, RenderingModule.DeviceContext, ResourceHandle, GetSubresourceIndex(mipIndex), (IntPtr)(&dataDesc), pinnedDataHandle.AddrOfPinnedObject() + (int)(data.Offset * TexelSizeBytes), dataDesc.Width * TexelSizeBytes, dataDesc.Width * dataDesc.Height * TexelSizeBytes ).ThrowOnFailure(); } else { Mutate_MapWrite(pinnedDataHandle, dataDesc, mipIndex); } } finally { pinnedDataHandle.Free(); } } }