/// <summary> /// Reads back a lobe texture histogram into an array /// </summary> /// <param name="_texHistogram_CPU"></param> /// <param name="_scatteringOrder"></param> /// <returns></returns> public static double[,] HistogramTexture2Array(Texture2D _texHistogram_CPU, int _scatteringOrder) { int scattMin = _scatteringOrder - 1; // Because scattering order 1 is actually stored in first slice of the texture array int scattMax = scattMin + 1; // To simulate a single scattering order // int scattMax = MAX_SCATTERING_ORDER; // To simulate all scattering orders accumulated int W = _texHistogram_CPU.Width; int H = _texHistogram_CPU.Height; double[,] histogramData = new double[W, H]; for (int scatteringOrder = scattMin; scatteringOrder < scattMax; scatteringOrder++) { PixelsBuffer Content = _texHistogram_CPU.Map(0, scatteringOrder); using (BinaryReader R = Content.OpenStreamRead()) for (int Y = 0; Y < H; Y++) { for (int X = 0; X < W; X++) { histogramData[X, Y] += W * H * R.ReadSingle(); } } Content.CloseStream(); _texHistogram_CPU.UnMap(0, scatteringOrder); } return(histogramData); }
private void FFT_CPUInOut(Complex[,] _input, Complex[,] _output, float _sign) { try { ////////////////////////////////////////////////////////////////////////// // Load initial content PixelsBuffer loadingBuffer = m_texBufferCPU.MapWrite(0, 0); System.IO.BinaryWriter W = loadingBuffer.OpenStreamWrite(); for (int Y = 0; Y < m_size; Y++) { for (int X = 0; X < m_size; X++) { W.Write((float)_input[X, Y].r); W.Write((float)_input[X, Y].i); } } loadingBuffer.CloseStream(); m_texBufferCPU.UnMap(loadingBuffer); m_texBufferIn.CopyFrom(m_texBufferCPU); ////////////////////////////////////////////////////////////////////////// // Apply multiple shader passes FFT_GPUInOut(_sign); ////////////////////////////////////////////////////////////////////////// // Read back content m_texBufferCPU.CopyFrom(m_texBufferOut); PixelsBuffer resultBuffer = m_texBufferCPU.MapRead(0, 0); System.IO.BinaryReader R = resultBuffer.OpenStreamRead(); for (int Y = 0; Y < m_size; Y++) { for (int X = 0; X < m_size; X++) { _output[X, Y].Set(R.ReadSingle(), R.ReadSingle()); } } resultBuffer.CloseStream(); m_texBufferCPU.UnMap(resultBuffer); } catch (Exception _e) { throw new Exception("An error occurred while performing the FFT!", _e); } }
void CheckAgainstFFTW() { if (m_FFTW_2D == null) { m_FFTW_2D = new fftwlib.FFT2D(SIGNAL_SIZE_2D, SIGNAL_SIZE_2D); m_test_CPU = new Texture2D(m_device2D, SIGNAL_SIZE_2D, SIGNAL_SIZE_2D, 1, 1, ImageUtility.PIXEL_FORMAT.RG32F, ImageUtility.COMPONENT_FORMAT.AUTO, true, false, null); m_FFTW2D_Output = new Texture2D(m_device2D, SIGNAL_SIZE_2D, SIGNAL_SIZE_2D, 1, 1, ImageUtility.PIXEL_FORMAT.RG32F, ImageUtility.COMPONENT_FORMAT.AUTO, false, true, null); } // Retrieve input as CPU-accessible m_test_CPU.CopyFrom(m_FFT2D_GPU.Input); PixelsBuffer bufferIn = m_test_CPU.MapRead(0, 0); m_test_CPU.UnMap(bufferIn); float2[,] input_GPU = new float2[SIGNAL_SIZE_2D, SIGNAL_SIZE_2D]; using (System.IO.BinaryReader R = bufferIn.OpenStreamRead()) for (int Y = 0; Y < SIGNAL_SIZE_2D; Y++) { for (int X = 0; X < SIGNAL_SIZE_2D; X++) { input_GPU[X, Y].Set(R.ReadSingle(), R.ReadSingle()); } } bufferIn.Dispose(); // Apply FFT m_FFT2D_GPU.FFT_GPUInOut(-1.0f); // Retrieve output as CPU-accessible m_test_CPU.CopyFrom(m_FFT2D_GPU.Output); PixelsBuffer bufferOut = m_test_CPU.MapRead(0, 0); m_test_CPU.UnMap(bufferOut); float2[,] output_GPU = new float2[SIGNAL_SIZE_2D, SIGNAL_SIZE_2D]; using (System.IO.BinaryReader R = bufferOut.OpenStreamRead()) for (int Y = 0; Y < SIGNAL_SIZE_2D; Y++) { for (int X = 0; X < SIGNAL_SIZE_2D; X++) { output_GPU[X, Y].Set(R.ReadSingle(), R.ReadSingle()); } } bufferOut.Dispose(); // Process input with FFTW m_FFTW_2D.FillInputSpatial((int _x, int _y, out float _r, out float _i) => { _r = input_GPU[_x, _y].x; _i = input_GPU[_x, _y].y; }); m_FFTW_2D.Execute(fftwlib.FFT2D.Normalization.DIMENSIONS_PRODUCT); float2[,] output_FFTW = new float2[SIGNAL_SIZE_2D, SIGNAL_SIZE_2D]; m_FFTW_2D.GetOutput((int _x, int _y, float _r, float _i) => { output_FFTW[_x, _y].Set(_r, _i); }); // Upload FFTW output to GPU bufferOut = m_test_CPU.MapWrite(0, 0); using (System.IO.BinaryWriter W = bufferOut.OpenStreamWrite()) for (int Y = 0; Y < SIGNAL_SIZE_2D; Y++) { for (int X = 0; X < SIGNAL_SIZE_2D; X++) { W.Write(output_FFTW[X, Y].x); W.Write(output_FFTW[X, Y].y); } } m_test_CPU.UnMap(bufferOut); bufferOut.Dispose(); m_FFTW2D_Output.CopyFrom(m_test_CPU); // Compare float sumSqDiffR = 0.0f; float sumSqDiffI = 0.0f; for (int Y = 0; Y < SIGNAL_SIZE_2D; Y++) { for (int X = 0; X < SIGNAL_SIZE_2D; X++) { float2 GPU = output_GPU[X, Y]; float2 FFTW = output_FFTW[X, Y]; float2 diff = GPU - FFTW; sumSqDiffR += diff.x * diff.x; sumSqDiffI += diff.y * diff.y; } } labelDiff2D.Text = "SqDiff = " + sumSqDiffR.ToString("G3") + " , " + sumSqDiffI.ToString("G3"); }
private void Generate() { try { tabControlGenerators.Enabled = false; ////////////////////////////////////////////////////////////////////////// // 1] Apply bilateral filtering to the input texture as a pre-process ApplyBilateralFiltering(m_textureSourceHeightMap, m_textureTarget0, floatTrackbarControlBilateralRadius.Value, floatTrackbarControlBilateralTolerance.Value, checkBoxWrap.Checked); ////////////////////////////////////////////////////////////////////////// // 2] Compute directional occlusion m_textureTarget1.RemoveFromLastAssignedSlots(); // Prepare computation parameters m_textureTarget0.SetCS(0); m_textureTarget1.SetCSUAV(0); m_SB_Rays.SetInput(1); m_CB_Input.m.RaysCount = (UInt32)Math.Min(MAX_THREADS, integerTrackbarControlRaysCount.Value); m_CB_Input.m.MaxStepsCount = (UInt32)integerTrackbarControlMaxStepsCount.Value; m_CB_Input.m.Tile = (uint)(checkBoxWrap.Checked ? 1 : 0); m_CB_Input.m.TexelSize_mm = TextureSize_mm / Math.Max(W, H); m_CB_Input.m.Displacement_mm = TextureHeight_mm; // Start if (!m_CS_GenerateSSBumpMap.Use()) { throw new Exception("Can't generate self-shadowed bump map as compute shader failed to compile!"); } uint h = Math.Max(1, MAX_LINES * 1024 / W); uint callsCount = (uint)Math.Ceiling((float)H / h); for (uint i = 0; i < callsCount; i++) { m_CB_Input.m.Y0 = i * h; m_CB_Input.UpdateData(); m_CS_GenerateSSBumpMap.Dispatch(W, h, 1); m_device.Present(true); progressBar.Value = (int)(0.01f * (BILATERAL_PROGRESS + (100 - BILATERAL_PROGRESS) * (i + 1) / (callsCount)) * progressBar.Maximum); // for ( int a=0; a < 10; a++ ) Application.DoEvents(); } m_textureTarget1.RemoveFromLastAssignedSlotUAV(); // So we can use it as input for next stage progressBar.Value = progressBar.Maximum; // Compute in a single shot (this is madness!) // m_CB_Input.m.y = 0; // m_CB_Input.UpdateData(); // m_CS_GenerateSSBumpMap.Dispatch( W, H, 1 ); ////////////////////////////////////////////////////////////////////////// // 3] Copy target to staging for CPU readback and update the resulting bitmap m_textureTarget_CPU.CopyFrom(m_textureTarget1); if (m_imageResult != null) { m_imageResult.Dispose(); } m_imageResult = null; m_imageResult = new ImageUtility.ImageFile(W, H, ImageUtility.PIXEL_FORMAT.RGBA8, m_linearProfile); float4[] scanline = new float4[W]; PixelsBuffer pixels = m_textureTarget_CPU.MapRead(0, 0); using (System.IO.BinaryReader R = pixels.OpenStreamRead()) for (uint Y = 0; Y < H; Y++) { R.BaseStream.Position = Y * pixels.RowPitch; for (int X = 0; X < W; X++) { scanline[X].Set(R.ReadSingle(), R.ReadSingle(), R.ReadSingle(), R.ReadSingle()); } m_imageResult.WriteScanline(Y, scanline); } m_textureTarget_CPU.UnMap(pixels); // Assign result viewportPanelResult.Image = m_imageResult; } catch (Exception _e) { MessageBox("An error occurred during generation!\r\n\r\nDetails: ", _e); } finally { tabControlGenerators.Enabled = true; } }