Exemplo n.º 1
0
        public void DiscardWrite(ArraySlice <TTexel> data, uint mipIndex = 0U,
                                 uint writeOffsetX = 0U, uint writeOffsetY = 0U)
        {
            Assure.LessThan(
                mipIndex, NumMips,
                "Can not write to mip level " + mipIndex + ": Only " + NumMips + " present in texture."
                );
            Assure.LessThanOrEqualTo(
                data.Length + writeOffsetX + (writeOffsetY * Width),
                Width * Height,
                "Buffer overrun: Please ensure you are not attempting to write past the end of the texture."
                );

            ThrowIfCannotDiscardWrite();

            lock (InstanceMutationLock) {
                if (IsDisposed)
                {
                    Logger.Warn("Attempted write manipulation on disposed resource of type: " + GetType().Name);
                    return;
                }

                IntPtr outDataPtr;
                uint   outRowStrideBytes, outSliceStrideBytes;
                InteropUtils.CallNative(
                    NativeMethods.ResourceFactory_MapSubresource,
                    RenderingModule.DeviceContext,
                    ResourceHandle,
                    GetSubresourceIndex(mipIndex),
                    ResourceMapping.WriteDiscard,
                    (IntPtr)(&outDataPtr),
                    (IntPtr)(&outRowStrideBytes),
                    (IntPtr)(&outSliceStrideBytes)
                    ).ThrowOnFailure();

                try {
                    uint srcRowStrideBytes = MipWidth(mipIndex) * TexelSizeBytes;
                    if (srcRowStrideBytes == outRowStrideBytes)                       // If the data is aligned, just fast copy
                    {
                        UnsafeUtils.CopyGenericArray(
                            data,
                            outDataPtr + (int)((writeOffsetX + writeOffsetY * Width) * TexelSizeBytes),
                            TexelSizeBytes
                            );
                    }
                    else                       // Otherwise, copy row-by-row
                    {
                        GCHandle pinnedDataHandle = GCHandle.Alloc(data.ContainingArray, GCHandleType.Pinned);
                        try {
                            IntPtr srcDataPtr        = pinnedDataHandle.AddrOfPinnedObject();
                            uint   firstFullRowIndex = writeOffsetY + 1;                                                     // Inclusive
                            uint   lastFullRowIndex  = firstFullRowIndex + ((data.Length - (Width - writeOffsetX)) / Width); // Exclusive

                            // Write first row
                            UnsafeUtils.MemCopy(srcDataPtr,
                                                outDataPtr + (int)(((firstFullRowIndex - 1) * outRowStrideBytes) + (writeOffsetX * TexelSizeBytes)), (Width - writeOffsetX) * TexelSizeBytes);

                            int srcOffsetAtRowStart = (int)((Width - writeOffsetX) * TexelSizeBytes);
                            int dstOffsetAtRowStart = (int)(firstFullRowIndex * outRowStrideBytes);
                            for (uint r = firstFullRowIndex; r < lastFullRowIndex; ++r)
                            {
                                UnsafeUtils.MemCopy(srcDataPtr + srcOffsetAtRowStart,
                                                    outDataPtr + dstOffsetAtRowStart, srcRowStrideBytes);
                                srcOffsetAtRowStart += (int)srcRowStrideBytes;
                                dstOffsetAtRowStart += (int)outRowStrideBytes;
                            }

                            // Write last row
                            UnsafeUtils.MemCopy(srcDataPtr + srcOffsetAtRowStart,
                                                outDataPtr + dstOffsetAtRowStart, ((data.Length - (Width - writeOffsetX)) % Width) * TexelSizeBytes);
                        }
                        finally {
                            pinnedDataHandle.Free();
                        }
                    }
                }
                finally {
                    InteropUtils.CallNative(
                        NativeMethods.ResourceFactory_UnmapSubresource,
                        RenderingModule.DeviceContext,
                        ResourceHandle,
                        GetSubresourceIndex(mipIndex)
                        ).ThrowOnFailure();
                }
            }
        }
Exemplo n.º 2
0
        /// <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"/> (in this case, synonymous with 'area') 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."
                );

            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,
                            (uint)Size
                            ).ThrowOnFailure();
                    }
                    else
                    {
                        Mutate_MapWrite(pinnedDataHandle, dataDesc, mipIndex);
                    }
                }
                finally {
                    pinnedDataHandle.Free();
                }
            }
        }
        private unsafe Texture1DResourceHandle CreateTexture1D(uint arrayLen, ArraySlice <TTexel>?initialData)
        {
            Assure.True(Usage != ResourceUsage.Immutable || initialData != null, "You must supply initial data to an immutable resource.");
            Assure.False(
                (Usage == ResourceUsage.Immutable || Usage == ResourceUsage.DiscardWrite) && permittedBindings == GPUBindings.None,
                "An immutable or discard-write resource with no permitted bindings is useless."
                );
            Assure.False(
                Usage.GetUsage() == 0x3 && permittedBindings != GPUBindings.None,
                "Staging resources can not be bound to the pipeline."
                );
            Assure.False((Usage == ResourceUsage.DiscardWrite || Usage == ResourceUsage.Immutable) &&
                         ((permittedBindings & GPUBindings.RenderTarget) > 0 ||
                          (permittedBindings & GPUBindings.DepthStencilTarget) > 0 ||
                          (permittedBindings & GPUBindings.WritableShaderResource) > 0),
                         "Can not bind an immutable or discard-write texture as a render target or depth stencil target, or as a GPU-writeable shader resource."
                         );

            Assure.GreaterThan(arrayLen, 0U, "Can not create an array of 0 textures.");

            Assure.GreaterThan(width, 0U, "Please specify a width for the texture.");

            Assure.False(
                mipAllocation && !MathUtils.IsPowerOfTwo(width),
                "Can not create mipmapped texture with any non-power-of-two (NPOT) dimension. Dimensions: " + width + "."
                );
            Assure.False(
                mipAllocation && Usage == ResourceUsage.DiscardWrite,
                "Can not allocate mips on a discard-write texture."
                );
            Assure.False(
                mipGenerationTarget && !mipAllocation,
                "Can not generate mips without allocating space for them."
                );
            Assure.False(
                mipGenerationTarget &&
                ((permittedBindings & GPUBindings.RenderTarget) == 0x0 || (permittedBindings & GPUBindings.ReadableShaderResource) == 0x0),
                "To make a texture a viable mip generation target, it must be created with the RenderTarget and ReadableShaderResource GPU bindings."
                );
            Assure.False(
                mipGenerationTarget && initialData != null,
                "Can not supply initial data to a mip generation target."
                );
            Assure.True(
                initialData == null ||
                (initialData.Value.Length == TextureUtils.GetSizeTexels(mipAllocation, width) * arrayLen),
                "Initial data is of incorrect length (" + (initialData != null ? initialData.Value.Length : 0) + ") for this resource. " +
                "It should have a length of: " + TextureUtils.GetSizeTexels(mipAllocation, width) * arrayLen + "."
                );
            Assure.False(dynamicDetail && Usage.GetUsage() == 0x3, "Can not create a dynamic-detail staging resource.");
            Assure.False(
                (permittedBindings & GPUBindings.DepthStencilTarget) == GPUBindings.DepthStencilTarget &&
                texelFormat != TexelFormat.DSV_FORMAT_CODE,
                "Can not create a depth-stencil target with any texel format other than " + typeof(TexelFormat.DepthStencil).Name + "."
                );

            Texture1DResourceHandle outResourceHandle;
            GCHandle?pinnedInitData   = null;
            GCHandle?pinnedDataHandle = null;
            IntPtr   initialDataPtr   = IntPtr.Zero;

            InitialResourceDataDesc[] dataArr = null;

            if (initialData != null)
            {
                pinnedInitData = GCHandle.Alloc(initialData.Value.ContainingArray, GCHandleType.Pinned);

                dataArr = InitialResourceDataDesc.CreateDataArr(
                    pinnedInitData.Value.AddrOfPinnedObject() + (int)(initialData.Value.Offset * texelSizeBytes),
                    arrayLen,
                    numMips,
                    width,
                    1U,
                    1U,
                    texelSizeBytes
                    );

                pinnedDataHandle = GCHandle.Alloc(dataArr, GCHandleType.Pinned);
                initialDataPtr   = pinnedDataHandle.Value.AddrOfPinnedObject();
            }

            try {
                InteropUtils.CallNative(NativeMethods.ResourceFactory_CreateTexture1DArray,
                                        RenderingModule.Device,
                                        width,
                                        arrayLen,
                                        (InteropBool)mipAllocation,
                                        texelFormat,
                                        Usage.GetUsage(),
                                        Usage.GetCPUUsage(),
                                        (PipelineBindings)permittedBindings,
                                        (InteropBool)mipGenerationTarget,
                                        (InteropBool)dynamicDetail,
                                        initialDataPtr,
                                        dataArr != null ? (uint)dataArr.Length : 0U,
                                        (IntPtr)(&outResourceHandle)
                                        ).ThrowOnFailure();
            }
            finally {
                if (pinnedDataHandle != null)
                {
                    pinnedDataHandle.Value.Free();
                }
                if (pinnedInitData != null)
                {
                    pinnedInitData.Value.Free();
                }
            }

            return(outResourceHandle);
        }