private void Apply(TextureArray2D src, TextureArray2D dst, int dirX, int dirY) { quad.Bind(false); var dev = Device.Get(); dev.Pixel.Set(shader.Pixel); cbuffer.SetData(new DirSizeData { DirX = dirX, DirY = dirY, SizeX = src.Size.Width, SizeY = src.Size.Height }); dev.Pixel.SetConstantBuffer(0, cbuffer.Handle); dev.SetViewScissors(dst.Size.Width, dst.Size.Height); foreach (var lm in src.LayerMipmap.LayersOfMipmap(0)) { dev.Pixel.SetShaderResource(0, src.GetSrView(lm)); dev.OutputMerger.SetRenderTargets(dst.GetRtView(lm)); dev.DrawQuad(); } dev.Pixel.SetShaderResource(0, null); dev.OutputMerger.SetRenderTargets((RenderTargetView)null); quad.Unbind(); }
/// <summary> /// copies a single mip from one layer of a texture to another layer of a texture. The formats don't have to match /// </summary> /// <param name="src">source texture</param> /// <param name="srcLayer"></param> /// <param name="srcMip"></param> /// <param name="dst">destination texture</param> /// <param name="dstLayer"></param> /// <param name="dstMip"></param> public void CopyLayer(TextureArray2D src, int srcLayer, int srcMip, TextureArray2D dst, int dstLayer, int dstMip) { Debug.Assert(src.Size == dst.Size); var dev = DirectX.Device.Get(); quad.Bind(false); dev.Pixel.Set(convert2D.Pixel); dev.Pixel.SetShaderResource(0, src.View); cbuffer.SetData(new LayerLevelOffsetData { Layer = srcLayer, Level = srcMip, Xoffset = 0, Yoffset = 0, Multiplier = 1.0f }); var dim = dst.Size.GetMip(dstMip); dev.Pixel.SetConstantBuffer(0, cbuffer.Handle); dev.OutputMerger.SetRenderTargets(dst.GetRtView(dstLayer, dstMip)); dev.SetViewScissors(dim.Width, dim.Height); dev.DrawQuad(); // remove bindings dev.Pixel.SetShaderResource(0, null); dev.OutputMerger.SetRenderTargets((RenderTargetView)null); }
/// converts a cubemap texture to a lat long map public TextureArray2D ConvertToLatLong(TextureArray2D cube, int resolution) { Debug.Assert(cube.NumLayers == 6); var dst = new TextureArray2D(LayerMipmapCount.One, new Size3(resolution, Math.Max(resolution / 2, 1)), Format.R32G32B32A32_Float, false); var dev = Device.Get(); quad.Bind(false); dev.Pixel.Set(toLatLong.Pixel); var dim = dst.Size; dev.Pixel.SetShaderResource(0, cube.GetCubeView(0)); dev.Pixel.SetSampler(0, sampler); dev.OutputMerger.SetRenderTargets(dst.GetRtView(LayerMipmapSlice.Mip0)); dev.SetViewScissors(dim.Width, dim.Height); dev.DrawQuad(); dev.Pixel.SetShaderResource(0, null); dev.Pixel.SetSampler(0, null); dev.OutputMerger.SetRenderTargets((RenderTargetView)null); quad.Unbind(); return(dst); }
/// <summary> /// for unit testing purposes. Converts naked srv to TextureArray2D /// </summary> internal TextureArray2D ConvertFromRaw(SharpDX.Direct3D11.ShaderResourceView srv, Size3 size, SharpDX.DXGI.Format dstFormat) { var res = new TextureArray2D(1, 1, size, dstFormat, false); var dev = DirectX.Device.Get(); quad.Bind(false); dev.Pixel.Set(convert2D.Pixel); dev.Pixel.SetShaderResource(0, srv); cbuffer.SetData(new LayerLevelOffsetData { Layer = 0, Level = 0, Xoffset = 0, Yoffset = 0, Multiplier = 1.0f }); dev.Pixel.SetConstantBuffer(0, cbuffer.Handle); dev.OutputMerger.SetRenderTargets(res.GetRtView(0, 0)); dev.SetViewScissors(size.Width, size.Height); dev.DrawQuad(); // remove bindings dev.Pixel.SetShaderResource(0, null); dev.OutputMerger.SetRenderTargets((RenderTargetView)null); quad.Unbind(); return(res); }
private async Task CreateGifAsync(TextureArray2D left, TextureArray2D right, Config cfg, IProgress progress) { // delay in milliseconds var numFrames = cfg.FramesPerSecond * cfg.NumSeconds; try { progressModel.EnableDllProgress = false; var leftView = left.GetSrView(LayerMipmapSlice.Mip0); var rightView = right.GetSrView(LayerMipmapSlice.Mip0); var curProg = progress.CreateSubProgress(0.9f); // create frames using (var dst = IO.CreateImage(new ImageFormat(Format.R8G8B8A8_UNorm_SRgb), left.Size, LayerMipmapCount.One)) { var dstMip = dst.GetMipmap(LayerMipmapSlice.Mip0); var dstPtr = dstMip.Bytes; var dstSize = dstMip.ByteSize; // render frames into texture using (var frame = new TextureArray2D(LayerMipmapCount.One, left.Size, Format.R8G8B8A8_UNorm_SRgb, false)) { var frameView = frame.GetRtView(LayerMipmapSlice.Mip0); for (int i = 0; i < numFrames; ++i) { float t = (float)i / (numFrames); int borderPos = (int)(t * frame.Size.Width); // render frame shader.Run(leftView, rightView, frameView, cfg.SliderWidth, borderPos, frame.Size.Width, frame.Size.Height); // save frame as png frame.CopyPixels(LayerMipmapSlice.Mip0, dstPtr, dstSize); var filename = $"{cfg.TmpFilename}{i:D4}"; await Task.Run(() => IO.SaveImage(dst, filename, "png", GliFormat.RGBA8_SRGB), progress.Token); curProg.Progress = i / (float)numFrames; curProg.What = "creating frames"; } } } // convert video await FFMpeg.ConvertAsync(cfg, progress.CreateSubProgress(1.0f)); } finally { progressModel.EnableDllProgress = true; } }
// converts a lat long texture to a cubemap public TextureArray2D ConvertToCube(TextureArray2D latlong, int resolution) { Debug.Assert(latlong.NumLayers == 1); var dst = new TextureArray2D(new LayerMipmapCount(6, 1), new Size3(resolution, resolution), Format.R32G32B32A32_Float, false); var dev = Device.Get(); quad.Bind(false); dev.Pixel.Set(toCube.Pixel); dev.Pixel.SetShaderResource(0, latlong.GetSrView(LayerMipmapSlice.Mip0)); dev.Pixel.SetSampler(0, sampler); dev.OutputMerger.SetRenderTargets(null, dst.GetRtView(new LayerMipmapSlice(0, 0)), dst.GetRtView(new LayerMipmapSlice(1, 0)), dst.GetRtView(new LayerMipmapSlice(2, 0)), dst.GetRtView(new LayerMipmapSlice(3, 0)), dst.GetRtView(new LayerMipmapSlice(4, 0)), dst.GetRtView(new LayerMipmapSlice(5, 0))); dev.SetViewScissors(resolution, resolution); dev.DrawQuad(); dev.Pixel.SetShaderResource(0, null); dev.Pixel.SetSampler(0, null); dev.OutputMerger.SetRenderTargets((RenderTargetView)null); quad.Unbind(); return(dst); }
public TextureArray2D ConvertToArray(Texture3D src, int fixedAxis1, int fixedAxis2, UploadBuffer cbuffer, int startLayer = 0, int numLayers = -1) { Debug.Assert(fixedAxis1 >= 0 && fixedAxis1 <= 2); Debug.Assert(fixedAxis2 >= 0 && fixedAxis2 <= 2); var dim = src.Size; var layerAxis = 3 - fixedAxis1 - fixedAxis2; if (numLayers < 0) { numLayers = dim[layerAxis] - startLayer; } var dst = new TextureArray2D( new LayerMipmapCount(numLayers, 1), new Size3(dim[fixedAxis1], dim[fixedAxis2]), Format.R32G32B32A32_Float, false ); var data = new LayerBufferData { XAxis = fixedAxis1, YAxis = fixedAxis2 }; var dev = Device.Get(); quad.Bind(false); dev.Pixel.Set(shaderLayer.Pixel); dev.Pixel.SetShaderResource(0, src.GetSrView(0)); dev.SetViewScissors(dst.Size.Width, dst.Size.Height); foreach (var lm in dst.LayerMipmap.Range) { data.ZValue = lm.Layer + startLayer; cbuffer.SetData(data); dev.Pixel.SetConstantBuffer(0, cbuffer.Handle); dev.OutputMerger.SetRenderTargets(dst.GetRtView(lm)); dev.DrawFullscreenTriangle(1); } quad.Unbind(); dev.Pixel.SetShaderResource(0, null); dev.OutputMerger.SetRenderTargets((RenderTargetView)null); return(dst); }
/// <summary> /// for unit testing purposes. Converts naked srv to TextureArray2D /// </summary> internal TextureArray2D ConvertFromRaw(SharpDX.Direct3D11.ShaderResourceView srv, Size3 size, SharpDX.DXGI.Format dstFormat, bool isInteger) { var res = new TextureArray2D(LayerMipmapCount.One, size, dstFormat, false); var dev = DirectX.Device.Get(); quad.Bind(false); if (isInteger) { if (convert2DInt == null) { convert2DInt = new DirectX.Shader(DirectX.Shader.Type.Pixel, GetSource(new ShaderBuilder2D("int4")), "ConvertInt"); } dev.Pixel.Set(convert2DInt.Pixel); } else { dev.Pixel.Set(convert2D.Pixel); } dev.Pixel.SetShaderResource(0, srv); cbuffer.SetData(new LayerLevelOffsetData { Layer = 0, Level = 0, Xoffset = 0, Yoffset = 0, Multiplier = 1.0f, UseOverlay = 0, Scale = 1 }); dev.Pixel.SetConstantBuffer(0, cbuffer.Handle); dev.OutputMerger.SetRenderTargets(res.GetRtView(LayerMipmapSlice.Mip0)); dev.SetViewScissors(size.Width, size.Height); dev.DrawQuad(); // remove bindings dev.Pixel.SetShaderResource(0, null); dev.OutputMerger.SetRenderTargets((RenderTargetView)null); quad.Unbind(); return(res); }
/// <summary> /// creates a thumbnail for one image layer/mipmap /// </summary> /// <param name="size">maximum width/height of the thumbnail</param> /// <param name="texture">source texture</param> /// <param name="dstFormat">destination texture format</param> /// <param name="layer">source layer</param> /// <returns>texture with width, height smaller or equal to size. One layer and one mipmap</returns> public TextureArray2D CreateThumbnail(int size, ITexture texture, SharpDX.DXGI.Format dstFormat, int layer, ScalingModel scaling) { Debug.Assert(ImageFormat.IsSupported(dstFormat)); Debug.Assert(ImageFormat.IsSupported(texture.Format)); // determine dimensions of output texture var width = 0; var height = 0; if (texture.Size.Width > texture.Size.Height) { width = size; height = (texture.Size.Height * size) / texture.Size.Width; } else { height = size; width = (texture.Size.Width * size) / texture.Size.Height; } Debug.Assert(width <= size); Debug.Assert(height <= size); var res = new TextureArray2D(LayerMipmapCount.One, new Size3(width, height), dstFormat, false); // compute which mipmap has the closest fit var mipmap = 0; var curWidth = texture.Size.Width; while (curWidth >= width) { ++mipmap; curWidth /= 2; } // mipmap just jumped over the optimal size mipmap = Math.Max(0, mipmap - 1); var dev = Device.Get(); ITexture tmpTex = null; if (texture.NumMipmaps < mipmap + 1) { // generate new texture with mipmaps tmpTex = texture.CloneWithMipmaps(mipmap + 1); scaling.WriteMipmaps(tmpTex); dev.Pixel.SetShaderResource(0, tmpTex.GetSrView(new LayerMipmapSlice(layer, mipmap))); } else { dev.Pixel.SetShaderResource(0, texture.GetSrView(new LayerMipmapSlice(layer, mipmap))); } quad.Bind(false); if (texture.Is3D) { dev.Pixel.Set(convert3D.Pixel); } else { dev.Pixel.Set(convert2D.Pixel); } dev.Pixel.SetSampler(0, sampler); dev.OutputMerger.SetRenderTargets(res.GetRtView(LayerMipmapSlice.Mip0)); dev.SetViewScissors(width, height); dev.DrawFullscreenTriangle(1); // remove bindings dev.Pixel.SetShaderResource(0, null); dev.OutputMerger.SetRenderTargets((RenderTargetView)null); quad.Unbind(); tmpTex?.Dispose(); return(res); }
private async Task CreateGifAsync(Config cfg, IProgress progress, SharedModel shared) { // delay in milliseconds var numFrames = cfg.FramesPerSecond * cfg.NumSeconds; var left = cfg.Left; var right = cfg.Right; var overlay = cfg.Overlay; // size compatible? bool disposeImages = false; if ((left.Size.Width % 2) != 0 || (left.Size.Height % 2) != 0) { disposeImages = true; var pad = Size3.Zero; pad.X = left.Size.Width % 2; pad.Y = left.Size.Height % 2; left = (TextureArray2D)shared.Padding.Run(left, Size3.Zero, pad, PaddingShader.FillMode.Clamp, null, shared, false); right = (TextureArray2D)shared.Padding.Run(right, Size3.Zero, pad, PaddingShader.FillMode.Clamp, null, shared, false); if (overlay != null) { overlay = (TextureArray2D)shared.Padding.Run(overlay, Size3.Zero, pad, PaddingShader.FillMode.Transparent, null, shared, false); } Debug.Assert(left.Size.Width % 2 == 0 && left.Size.Height % 2 == 0); } try { progressModel.EnableDllProgress = false; var leftView = left.GetSrView(LayerMipmapSlice.Mip0); var rightView = right.GetSrView(LayerMipmapSlice.Mip0); var overlayView = overlay?.GetSrView(LayerMipmapSlice.Mip0); var curProg = progress.CreateSubProgress(0.9f); // prepare parallel processing var numTasks = Environment.ProcessorCount; var tasks = new Task[numTasks]; var images = new DllImageData[numTasks]; for (int i = 0; i < numTasks; ++i) { images[i] = IO.CreateImage(new ImageFormat(Format.R8G8B8A8_UNorm_SRgb), left.Size, LayerMipmapCount.One); } int textSize = left.Size.Y / 18; float padding = textSize / 4.0f; // render frames into texture using (var frame = new TextureArray2D(LayerMipmapCount.One, left.Size, Format.R8G8B8A8_UNorm_SRgb, false)) { var frameView = frame.GetRtView(LayerMipmapSlice.Mip0); using (var d2d = new Direct2D(frame)) { for (int i = 0; i < numFrames; ++i) { float t = (float)i / (numFrames - 1); int borderPos = (int)(t * (frame.Size.Width - 1)); int idx = i % numTasks; // render frame shader.Run(leftView, rightView, overlayView, frameView, cfg.SliderWidth, borderPos, frame.Size.Width, frame.Size.Height, shared.QuadShader, shared.Upload); // add text using (var c = d2d.Begin()) { c.Text(new Float2(padding), new Float2(left.Size.X - padding, left.Size.Y - padding), textSize, Colors.White, cfg.Label1, TextAlignment.Leading); c.Text(new Float2(padding), new Float2(left.Size.X - padding, left.Size.Y - padding), textSize, Colors.White, cfg.Label2, TextAlignment.Trailing); } // copy frame from gpu to cpu var dstMip = images[idx].GetMipmap(LayerMipmapSlice.Mip0); var dstPtr = dstMip.Bytes; var dstSize = dstMip.ByteSize; // wait for previous task to finish before writing it to the file if (tasks[idx] != null) { await tasks[idx]; } frame.CopyPixels(LayerMipmapSlice.Mip0, dstPtr, dstSize); var filename = $"{cfg.TmpFilename}{i:D4}"; // write to file tasks[idx] = Task.Run(() => { try { IO.SaveImage(images[idx], filename, "png", GliFormat.RGBA8_SRGB); } catch (Exception) { // ignored (probably cancelled by user) } }, progress.Token); curProg.Progress = i / (float)numFrames; curProg.What = "creating frames"; progress.Token.ThrowIfCancellationRequested(); } } } // wait for tasks to finish for (var i = 0; i < tasks.Length; i++) { if (tasks[i] != null) { await tasks[i]; } tasks[i] = null; } // convert video await FFMpeg.ConvertAsync(cfg, progress.CreateSubProgress(1.0f)); } finally { progressModel.EnableDllProgress = true; if (disposeImages) { left.Dispose(); right.Dispose(); overlay?.Dispose(); } } }