private void InitializeFromImpl(DataBox[] dataBoxes = null) { if (ParentTexture != null) { NativeDeviceChild = ParentTexture.NativeDeviceChild; } if (NativeDeviceChild == null) { switch (Dimension) { case TextureDimension.Texture1D: NativeDeviceChild = new Texture1D(GraphicsDevice.NativeDevice, ConvertToNativeDescription1D(), ConvertDataBoxes(dataBoxes)); break; case TextureDimension.Texture2D: case TextureDimension.TextureCube: NativeDeviceChild = new Texture2D(GraphicsDevice.NativeDevice, ConvertToNativeDescription2D(), ConvertDataBoxes(dataBoxes)); break; case TextureDimension.Texture3D: NativeDeviceChild = new Texture3D(GraphicsDevice.NativeDevice, ConvertToNativeDescription3D(), ConvertDataBoxes(dataBoxes)); break; } GraphicsDevice.RegisterTextureMemoryUsage(SizeInBytes); } if (NativeShaderResourceView == null) { NativeShaderResourceView = GetShaderResourceView(ViewType, ArraySlice, MipLevel); } NativeUnorderedAccessView = GetUnorderedAccessView(ViewType, ArraySlice, MipLevel); NativeRenderTargetView = GetRenderTargetView(ViewType, ArraySlice, MipLevel); NativeDepthStencilView = GetDepthStencilView(out HasStencil); switch (textureDescription.Options) { case TextureOptions.None: SharedHandle = IntPtr.Zero; break; case TextureOptions.Shared: var sharedResource = NativeDeviceChild.QueryInterface <SharpDX.DXGI.Resource>(); SharedHandle = sharedResource.SharedHandle; break; #if STRIDE_GRAPHICS_API_DIRECT3D11 case TextureOptions.SharedNthandle | TextureOptions.SharedKeyedmutex: var sharedResource1 = NativeDeviceChild.QueryInterface <SharpDX.DXGI.Resource1>(); var uniqueName = "Stride:" + Guid.NewGuid().ToString(); SharedHandle = sharedResource1.CreateSharedHandle(uniqueName, SharpDX.DXGI.SharedResourceFlags.Write); SharedNtHandleName = uniqueName; break; #endif default: throw new ArgumentOutOfRangeException("textureDescription.Options"); } }
protected internal override void OnDestroyed() { // If it was a View, do not release reference if (ParentTexture != null) { NativeDeviceChild = null; } else if (GraphicsDevice != null) { GraphicsDevice.RegisterTextureMemoryUsage(-SizeInBytes); } base.OnDestroyed(); }
protected internal override void OnDestroyed() { // If it was a View, do not release reference if (ParentTexture != null) { NativeDeviceChild = null; } else if (GraphicsDevice != null) { GraphicsDevice.RegisterTextureMemoryUsage(-SizeInBytes); } ReleaseComObject(ref renderTargetView); ReleaseComObject(ref depthStencilView); base.OnDestroyed(); }
private void OnRecreateImpl() { // Dependency: wait for underlying texture to be recreated if (ParentTexture != null && ParentTexture.LifetimeState != GraphicsResourceLifetimeState.Active) { return; } // Render Target / Depth Stencil are considered as "dynamic" if ((Usage == GraphicsResourceUsage.Immutable || Usage == GraphicsResourceUsage.Default) && !IsRenderTarget && !IsDepthStencil) { return; } if (ParentTexture == null && GraphicsDevice != null) { GraphicsDevice.RegisterTextureMemoryUsage(-SizeInBytes); } InitializeFromImpl(); }
/// <inheritdoc/> protected internal override void OnDestroyed() { using (GraphicsDevice.UseOpenGLCreationContext()) { if (TextureId != 0 && ParentTexture == null) { if (IsRenderbuffer) { GL.DeleteRenderbuffers(1, ref TextureId); } else { GL.DeleteTextures(1, ref TextureId); } GraphicsDevice.RegisterTextureMemoryUsage(-SizeInBytes); } if (stencilId != 0) { GL.DeleteRenderbuffers(1, ref stencilId); } if (pixelBufferObjectId != 0) { GL.DeleteBuffers(1, ref pixelBufferObjectId); } } TextureTotalSize = 0; TextureId = 0; stencilId = 0; pixelBufferObjectId = 0; base.OnDestroyed(); }
private void InitializeFromImpl(DataBox[] dataBoxes = null) { bool hasInitData = dataBoxes != null && dataBoxes.Length > 0; if (ParentTexture != null) { ParentResource = ParentTexture; NativeDeviceChild = ParentTexture.NativeDeviceChild; } if (NativeDeviceChild == null) { ClearValue?clearValue = GetClearValue(); ResourceDescription nativeDescription; switch (Dimension) { case TextureDimension.Texture1D: nativeDescription = ConvertToNativeDescription1D(); break; case TextureDimension.Texture2D: case TextureDimension.TextureCube: nativeDescription = ConvertToNativeDescription2D(); break; case TextureDimension.Texture3D: nativeDescription = ConvertToNativeDescription3D(); break; default: throw new ArgumentOutOfRangeException(); } var initialResourceState = ResourceStates.GenericRead; var heapType = HeapType.Default; var currentResourceState = initialResourceState; if (Usage == GraphicsResourceUsage.Staging) { heapType = HeapType.Readback; NativeResourceState = ResourceStates.CopyDestination; int totalSize = ComputeBufferTotalSize(); nativeDescription = ResourceDescription.Buffer(totalSize); // Staging textures on DirectX 12 use buffer internally NativeDeviceChild = GraphicsDevice.NativeDevice.CreateCommittedResource(new HeapProperties(heapType), HeapFlags.None, nativeDescription, NativeResourceState); if (hasInitData) { var commandList = GraphicsDevice.NativeCopyCommandList; commandList.Reset(GraphicsDevice.NativeCopyCommandAllocator, null); Resource uploadResource; int uploadOffset; var uploadMemory = GraphicsDevice.AllocateUploadBuffer(totalSize, out uploadResource, out uploadOffset, TextureSubresourceAlignment); // Copy data to the upload buffer int dataBoxIndex = 0; var uploadMemoryMipStart = uploadMemory; for (int arraySlice = 0; arraySlice < ArraySize; arraySlice++) { for (int mipLevel = 0; mipLevel < MipLevels; mipLevel++) { var databox = dataBoxes[dataBoxIndex++]; var mipHeight = CalculateMipSize(Width, mipLevel); var mipRowPitch = ComputeRowPitch(mipLevel); var uploadMemoryCurrent = uploadMemoryMipStart; var dataPointerCurrent = databox.DataPointer; for (int rowIndex = 0; rowIndex < mipHeight; rowIndex++) { Utilities.CopyMemory(uploadMemoryCurrent, dataPointerCurrent, mipRowPitch); uploadMemoryCurrent += mipRowPitch; dataPointerCurrent += databox.RowPitch; } uploadMemoryMipStart += ComputeSubresourceSize(mipLevel); } } // Copy from upload heap to actual resource commandList.CopyBufferRegion(NativeResource, 0, uploadResource, uploadOffset, totalSize); commandList.Close(); StagingFenceValue = 0; GraphicsDevice.WaitCopyQueue(); } return; } if (hasInitData) { currentResourceState = ResourceStates.CopyDestination; } // TODO D3D12 move that to a global allocator in bigger committed resources NativeDeviceChild = GraphicsDevice.NativeDevice.CreateCommittedResource(new HeapProperties(heapType), HeapFlags.None, nativeDescription, currentResourceState, clearValue); GraphicsDevice.RegisterTextureMemoryUsage(SizeInBytes); if (hasInitData) { // Trigger copy var commandList = GraphicsDevice.NativeCopyCommandList; commandList.Reset(GraphicsDevice.NativeCopyCommandAllocator, null); long textureCopySize; var placedSubresources = new PlacedSubResourceFootprint[dataBoxes.Length]; var rowCounts = new int[dataBoxes.Length]; var rowSizeInBytes = new long[dataBoxes.Length]; GraphicsDevice.NativeDevice.GetCopyableFootprints(ref nativeDescription, 0, dataBoxes.Length, 0, placedSubresources, rowCounts, rowSizeInBytes, out textureCopySize); SharpDX.Direct3D12.Resource uploadResource; int uploadOffset; var uploadMemory = GraphicsDevice.AllocateUploadBuffer((int)textureCopySize, out uploadResource, out uploadOffset, TextureSubresourceAlignment); for (int i = 0; i < dataBoxes.Length; ++i) { var databox = dataBoxes[i]; var dataPointer = databox.DataPointer; var rowCount = rowCounts[i]; var sliceCount = placedSubresources[i].Footprint.Depth; var rowSize = (int)rowSizeInBytes[i]; var destRowPitch = placedSubresources[i].Footprint.RowPitch; // Memcpy data for (int z = 0; z < sliceCount; ++z) { var uploadMemoryCurrent = uploadMemory + (int)placedSubresources[i].Offset + z * destRowPitch * rowCount; var dataPointerCurrent = dataPointer + z * databox.SlicePitch; for (int y = 0; y < rowCount; ++y) { Utilities.CopyMemory(uploadMemoryCurrent, dataPointerCurrent, rowSize); uploadMemoryCurrent += destRowPitch; dataPointerCurrent += databox.RowPitch; } } // Adjust upload offset (circular dependency between GetCopyableFootprints and AllocateUploadBuffer) placedSubresources[i].Offset += uploadOffset; commandList.CopyTextureRegion(new TextureCopyLocation(NativeResource, i), 0, 0, 0, new TextureCopyLocation(uploadResource, placedSubresources[i]), null); } commandList.ResourceBarrierTransition(NativeResource, ResourceStates.CopyDestination, initialResourceState); commandList.Close(); GraphicsDevice.WaitCopyQueue(); } NativeResourceState = initialResourceState; } NativeShaderResourceView = GetShaderResourceView(ViewType, ArraySlice, MipLevel); NativeRenderTargetView = GetRenderTargetView(ViewType, ArraySlice, MipLevel); NativeDepthStencilView = GetDepthStencilView(out HasStencil); NativeUnorderedAccessView = GetUnorderedAccessView(ViewType, ArraySlice, MipLevel); }
private void InitializeFromImpl(DataBox[] dataBoxes = null) { if (ParentTexture != null) { CopyParentAttributes(); } if (TextureId == 0) { TextureTarget = GetTextureTarget(Dimension); bool compressed; OpenGLConvertExtensions.ConvertPixelFormat(GraphicsDevice, ref textureDescription.Format, out TextureInternalFormat, out TextureFormat, out TextureType, out TexturePixelSize, out compressed); DepthPitch = Description.Width * Description.Height * TexturePixelSize; RowPitch = Description.Width * TexturePixelSize; IsDepthBuffer = ((Description.Flags & TextureFlags.DepthStencil) != 0); if (IsDepthBuffer) { HasStencil = InternalHasStencil(Format); } else { HasStencil = false; } if ((Description.Flags & TextureFlagsCustomResourceId) != 0) { return; } using (var openglContext = GraphicsDevice.UseOpenGLCreationContext()) { TextureTotalSize = ComputeBufferTotalSize(); if (Description.Usage == GraphicsResourceUsage.Staging) { InitializeStagingPixelBufferObject(dataBoxes); return; // TODO: This return causes "GraphicsDevice.RegisterTextureMemoryUsage(SizeInBytes);" not to get entered. Is that okay? } // Depth textures are renderbuffers for now // TODO: PERFORMANCE: Why? I think we should change that so we can sample them directly. // TODO: enable switch // TODO: What does this comment even mean? IsRenderbuffer = !Description.IsShaderResource; // Force to renderbuffer if MSAA is on because we don't support MSAA textures ATM (and they don't exist on OpenGL ES). if (Description.IsMultisample) { // TODO: Ideally the caller of this method should be aware of this "force to renderbuffer", // because the caller won't be able to bind it as a texture. IsRenderbuffer = true; } if (IsRenderbuffer) { CreateRenderbuffer(); return; // TODO: This return causes "GraphicsDevice.RegisterTextureMemoryUsage(SizeInBytes);" not to get entered. Is that okay? } GL.GenTextures(1, out TextureId); GL.BindTexture(TextureTarget, TextureId); SetFilterMode(); if (Description.MipLevels == 0) { throw new NotImplementedException(); } var setSize = TextureSetSize(TextureTarget); for (var arrayIndex = 0; arrayIndex < Description.ArraySize; ++arrayIndex) { int offsetArray = arrayIndex * Description.MipLevels; for (int mipLevel = 0; mipLevel < Description.MipLevels; ++mipLevel) { DataBox dataBox; Int3 dimensions = new Int3(CalculateMipSize(Description.Width, mipLevel), CalculateMipSize(Description.Height, mipLevel), CalculateMipSize(Description.Depth, mipLevel)); if (dataBoxes != null && mipLevel < dataBoxes.Length) { if (setSize > 1 && !compressed && dataBoxes[mipLevel].RowPitch != dimensions.X * TexturePixelSize) { throw new NotSupportedException("Can't upload texture with pitch in glTexImage2D/3D."); } // Might be possible, need to check API better. dataBox = dataBoxes[offsetArray + mipLevel]; } else { dataBox = new DataBox(); } switch (TextureTarget) { case TextureTarget.Texture1D: CreateTexture1D(compressed, dimensions.X, mipLevel, dataBox); break; case TextureTarget.Texture2D: case TextureTarget.TextureCubeMap: CreateTexture2D(compressed, dimensions.X, dimensions.Y, mipLevel, arrayIndex, dataBox); break; case TextureTarget.Texture3D: CreateTexture3D(compressed, dimensions.X, dimensions.Y, dimensions.Z, mipLevel, dataBox); break; case TextureTarget.Texture2DArray: CreateTexture2DArray(compressed, dimensions.X, dimensions.Y, mipLevel, arrayIndex, dataBox); break; } } } GL.BindTexture(TextureTarget, 0); // This unbinds the texture. if (openglContext.CommandList != null) { // If we messed up with some states of a command list, mark dirty states openglContext.CommandList.boundShaderResourceViews[openglContext.CommandList.activeTexture] = null; } } GraphicsDevice.RegisterTextureMemoryUsage(SizeInBytes); } }