/// <summary> /// Loads a bitmap from the given texture. Be careful: The texture must have CPU read access and this only matches for staging textures. /// </summary> /// <param name="texture">The texture to be loaded into the bitmap.</param> public static GDI.Bitmap LoadBitmapFromMemoryMappedTexture(MemoryMappedTexture <int> texture) { texture.EnsureNotNullOrDisposed(nameof(texture)); var width = texture.Width; var height = texture.Height; // Create and lock bitmap so it can be accessed for texture loading var resultBitmap = new GDI.Bitmap(width, height); var bitmapData = resultBitmap.LockBits( new GDI.Rectangle(0, 0, resultBitmap.Width, resultBitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); try { SeeingSharpUtil.CopyMemory( texture.Pointer, bitmapData.Scan0, texture.SizeInBytes); } finally { resultBitmap.UnlockBits(bitmapData); } return(resultBitmap); }
/// <summary> /// Upload a texture from the graphics hardware. /// </summary> /// <param name="textureToUpload">The texture to be uploaded.</param> internal MemoryMappedTexture <T> UploadToMemoryMappedTexture <T>(D3D11.ID3D11Texture2D textureToUpload) where T : unmanaged { if (_isDisposed) { throw new ObjectDisposedException(nameof(TextureUploader)); } var result = new MemoryMappedTexture <T>( new Size(_width, _height)); this.UploadToMemoryMappedTexture(textureToUpload, result); return(result); }
/// <summary> /// Upload a texture from the graphics hardware. /// </summary> /// <param name="textureToUpload">The texture to be uploaded.</param> /// <param name="targetFloatBuffer">The target buffer to which to copy all data.</param> internal unsafe void UploadToMemoryMappedTexture <T>(D3D11.ID3D11Texture2D textureToUpload, MemoryMappedTexture <T> targetFloatBuffer) where T : unmanaged { if (_isDisposed) { throw new ObjectDisposedException(nameof(TextureUploader)); } this.EnsureNotNullOrDisposed(nameof(targetFloatBuffer)); // Check input texture var textureDesc = textureToUpload.Description; if (textureDesc.Width != _width) { throw new SeeingSharpGraphicsException($"Invalid texture: Width does not match (given: {textureDesc.Width}, expected: {_width})!"); } if (textureDesc.Height != _height) { throw new SeeingSharpGraphicsException($"Invalid texture: Height does not match (given: {textureDesc.Height}, expected: {_height})!"); } if (textureDesc.Format != _format) { throw new SeeingSharpGraphicsException($"Invalid texture: Format does not match (given: {textureDesc.Format}, expected: {_format})!"); } if (GraphicsHelper.IsMultisampled(textureDesc) != _isMultisampled) { throw new SeeingSharpGraphicsException($"Invalid texture: Multisampling does not match (given: {GraphicsHelper.IsMultisampled(textureDesc)}, expected: {_isMultisampled})!"); } // Check source and destination size var targetPixelSize = targetFloatBuffer.PixelSize; if (targetPixelSize.Width != _width) { throw new SeeingSharpGraphicsException("The width of the textures during texture upload does not match!"); } if (targetPixelSize.Height != _height) { throw new SeeingSharpGraphicsException("The height of the textures during texture upload does not match!"); } // Check format compatibility var textureFormatByteSize = FormatHelper.SizeOfInBytes(_format); if (textureFormatByteSize != sizeof(T)) { throw new SeeingSharpGraphicsException( "Format of the texture to upload and the destination buffer does not match " + $"(source: {_format} / {textureFormatByteSize} bytes, target: {typeof(T).Name} / {sizeof(T)} bytes)!"); } // Upload the texture this.CopyTextureToStagingResource(textureToUpload); // Read the data into the .Net data block var dataBox = _device.DeviceImmediateContextD3D11.Map( _copyHelperTextureStaging, 0, D3D11.MapMode.Read, D3D11.MapFlags.None); try { var rowPitchSource = dataBox.RowPitch; var rowPitchDestination = targetFloatBuffer.Width * sizeof(T); if (rowPitchSource > 0 && rowPitchDestination > 0) { for (var loopY = 0; loopY < _height; loopY++) { SeeingSharpUtil.CopyMemory( dataBox.DataPointer + loopY * rowPitchSource, targetFloatBuffer.Pointer + loopY * rowPitchDestination, (uint)rowPitchDestination); } } else { throw new SeeingSharpGraphicsException($"Invalid row pitch (source: {rowPitchSource}, destination: {rowPitchDestination})!"); } } finally { _device.DeviceImmediateContextD3D11.Unmap(_copyHelperTextureStaging, 0); } }
internal RenderPassDumpEntry(string dumpKey, Size size) { this.Key = dumpKey; _bufferColor = new MemoryMappedTexture <int>(size); }
public static D3D11.ID3D11Texture2D LoadTexture2DFromMappedTexture(EngineDevice device, MemoryMappedTexture <int> mappedTexture, bool generateMiplevels) { // Create the texture var dataRectangle = new D3D11.SubresourceData( mappedTexture.Pointer, mappedTexture.Width * 4); D3D11.ID3D11Texture2D result; if (generateMiplevels) { result = device.DeviceD3D11_1.CreateTexture2D(new D3D11.Texture2DDescription { Width = mappedTexture.Width, Height = mappedTexture.Height, ArraySize = 1, BindFlags = D3D11.BindFlags.ShaderResource | D3D11.BindFlags.RenderTarget, Usage = D3D11.ResourceUsage.Default, CpuAccessFlags = D3D11.CpuAccessFlags.None, Format = DEFAULT_TEXTURE_FORMAT, MipLevels = 0, OptionFlags = D3D11.ResourceOptionFlags.None | D3D11.ResourceOptionFlags.GenerateMips, SampleDescription = new SampleDescription(1, 0) }, new D3D11.SubresourceData[] { dataRectangle, dataRectangle, dataRectangle, dataRectangle, dataRectangle, dataRectangle, dataRectangle, dataRectangle, dataRectangle, dataRectangle, dataRectangle, dataRectangle }); // Auto generate miplevels using (var shaderResourceView = device.DeviceD3D11_1.CreateShaderResourceView(result)) { device.DeviceImmediateContextD3D11.GenerateMips(shaderResourceView); } } else { result = device.DeviceD3D11_1.CreateTexture2D(new D3D11.Texture2DDescription { Width = mappedTexture.Width, Height = mappedTexture.Height, ArraySize = 1, BindFlags = D3D11.BindFlags.ShaderResource, Usage = D3D11.ResourceUsage.Default, CpuAccessFlags = D3D11.CpuAccessFlags.None, Format = DEFAULT_TEXTURE_FORMAT, MipLevels = 1, OptionFlags = D3D11.ResourceOptionFlags.None, SampleDescription = new SampleDescription(1, 0) }, new D3D11.SubresourceData[] { dataRectangle }); } return(result); }
/// <summary> /// Queries for the ObjectId at the given location. /// </summary> /// <param name="texture">The uploaded texture.</param> /// <param name="xPos">The x position where to start.</param> /// <param name="yPos">The y position where to start.</param> public static unsafe float QueryForObjectId(this MemoryMappedTexture <float> texture, int xPos, int yPos) { var pixelSize = texture.PixelSize; if (xPos < 0) { throw new ArgumentException("xPos"); } if (xPos >= pixelSize.Width) { throw new ArgumentException("xPos"); } if (yPos < 0) { throw new ArgumentException("yPos"); } if (yPos >= pixelSize.Height) { throw new ArgumentException("yPos"); } // Loop over more pixels to be sure, that we are directly facing one object // => This is needed because of manipulations done by multisampling (=Antialiasing) var pointerNative = texture.GetNativePointer(); var currentX = xPos; var currentY = yPos; var lastObjId = pointerNative[currentY * pixelSize.Width + currentX]; for (var loopActQueryStep = 0; loopActQueryStep < s_queryObjectIdSteps.Length; loopActQueryStep++) { // Calculate current query location var currentStep = s_queryObjectIdSteps[loopActQueryStep]; currentX += currentStep.X; currentY += currentStep.Y; // Check whether we are still in a valid pixel coordinate if (currentX < 0) { continue; } if (currentX >= pixelSize.Width) { continue; } if (currentY < 0) { continue; } if (currentY >= pixelSize.Height) { continue; } // Read current value and compare with last one // (If equal, than at least two pixels are the same => Return this ObjectId) var currObjId = pointerNative[currentY * pixelSize.Width + currentX]; if (EngineMath.EqualsWithTolerance(currObjId, lastObjId)) { return(currObjId); } // No match found, continue with next one lastObjId = currObjId; } // No clear match found return(0f); }