/// <summary> /// Our present hook that will grab a copy of the backbuffer when requested. Note: this supports multi-sampling (anti-aliasing) /// </summary> /// <param name="swapChainPtr"></param> /// <param name="syncInterval"></param> /// <param name="flags"></param> /// <returns>The HRESULT of the original method</returns> private int PresentHook(IntPtr swapChainPtr, int syncInterval, PresentFlags flags) { Frame(); var swapChain = (SwapChain)swapChainPtr; { try { #region Screenshot Request if (Request != null) { try { DebugMessage("PresentHook: Request Start"); var startTime = DateTime.Now; using (var texture = Resource.FromSwapChain <Texture2D>(swapChain, 0)) { #region Determine region to capture var regionToCapture = new Rectangle(0, 0, texture.Description.Width, texture.Description.Height); if (Request.RegionToCapture.Width > 0) { regionToCapture = Request.RegionToCapture; } #endregion var theTexture = texture; // If texture is multisampled, then we can use ResolveSubresource to copy it into a non-multisampled texture Texture2D textureResolved = null; if (texture.Description.SampleDescription.Count > 1) { DebugMessage("PresentHook: resolving multi-sampled texture"); // texture is multi-sampled, lets resolve it down to single sample textureResolved = new Texture2D(texture.Device, new Texture2DDescription { CpuAccessFlags = CpuAccessFlags.None, Format = texture.Description.Format, Height = texture.Description.Height, Usage = ResourceUsage.Default, Width = texture.Description.Width, ArraySize = 1, SampleDescription = new SampleDescription(1, 0), // Ensure single sample BindFlags = BindFlags.None, MipLevels = 1, OptionFlags = texture.Description.OptionFlags }); // Resolve into textureResolved texture.Device.ResolveSubresource(texture, 0, textureResolved, 0, texture.Description.Format); // Make "theTexture" be the resolved texture theTexture = textureResolved; } // Create destination texture var textureDest = new Texture2D(texture.Device, new Texture2DDescription { CpuAccessFlags = CpuAccessFlags.None, // CpuAccessFlags.Write | CpuAccessFlags.Read, Format = Format.R8G8B8A8_UNorm, // Supports BMP/PNG Height = regionToCapture.Height, Usage = ResourceUsage.Default, // ResourceUsage.Staging, Width = regionToCapture.Width, ArraySize = 1, //texture.Description.ArraySize, SampleDescription = new SampleDescription(1, 0), // texture.Description.SampleDescription, BindFlags = BindFlags.None, MipLevels = 1, //texture.Description.MipLevels, OptionFlags = texture.Description.OptionFlags }); // Copy the subresource region, we are dealing with a flat 2D texture with no MipMapping, so 0 is the subresource index theTexture.Device.CopySubresourceRegion(theTexture, 0, new ResourceRegion { Top = regionToCapture.Top, Bottom = regionToCapture.Bottom, Left = regionToCapture.Left, Right = regionToCapture.Right, Front = 0, Back = 1 // Must be 1 or only black will be copied }, textureDest, 0, 0, 0, 0); // Note: it would be possible to capture multiple frames and process them in a background thread // Copy to memory and send back to host process on a background thread so that we do not cause any delay in the rendering pipeline var request = Request.Clone(); // this.Request gets set to null, so copy the Request for use in the thread ThreadPool.QueueUserWorkItem(delegate { //FileStream fs = new FileStream(@"c:\temp\temp.bmp", FileMode.Create); //Texture2D.ToStream(testSubResourceCopy, ImageFileFormat.Bmp, fs); var startCopyToSystemMemory = DateTime.Now; using (var ms = new MemoryStream()) { Resource.ToStream(textureDest, ImageFileFormat.Bmp, ms); ms.Position = 0; DebugMessage("PresentHook: Copy to System Memory time: " + (DateTime.Now - startCopyToSystemMemory)); var startSendResponse = DateTime.Now; ProcessCapture(ms, request); DebugMessage("PresentHook: Send response time: " + (DateTime.Now - startSendResponse)); } // Free the textureDest as we no longer need it. textureDest.Dispose(); textureDest = null; DebugMessage("PresentHook: Full Capture time: " + (DateTime.Now - startTime)); }); // Make sure we free up the resolved texture if it was created textureResolved?.Dispose(); } DebugMessage("PresentHook: Copy BackBuffer time: " + (DateTime.Now - startTime)); DebugMessage("PresentHook: Request End"); } finally { // Prevent the request from being processed a second time Request = null; } } #endregion #region Example: Draw overlay (after screenshot so we don't capture overlay as well) if (Config.ShowOverlay) { using var texture = Resource.FromSwapChain <Texture2D>(swapChain, 0); if (Fps.GetFps() >= 1) { var fd = new FontDescription { Height = 16, FaceName = "Arial", Italic = false, Width = 0, MipLevels = 1, CharacterSet = FontCharacterSet.Default, OutputPrecision = FontPrecision.Default, Quality = FontQuality.Antialiased, PitchAndFamily = FontPitchAndFamily.Default | FontPitchAndFamily.DontCare, Weight = FontWeight.Bold }; // TODO: do not create font every frame! using var font = new Font(texture.Device, fd); DrawText(font, new Vector2(5, 5), $"{Fps.GetFps():N0} fps", Color.Red); if (TextDisplay is { Display : true }) { DrawText(font, new Vector2(5, 25), TextDisplay.Text, new Color4(Color.Red.R, Color.Red.G, Color.Red.B, Math.Abs(1.0f - TextDisplay.Remaining))); } } }
public void RunAllTool() { HTuple /*start = null, */ end = null; //帧率统计增加 fps.IncreaseFrameNum(); fpsCount++; if (fpsCount > 10) { fps.UpdateFps(); fpsCount = 0; } RunStatus runStatus = new RunStatus(settingIndex, cameraIndex); runStatus.FpsStr = string.Format("FPS:{0:F1}|帧:{1}|", fps.GetFps(), fps.GetTotalFrameCount()); List <ToolBase> runToolList = ToolsFactory.GetToolList(settingIndex); Tools.CreateImage.CreateImageTool createImageTool = runToolList[0] as Tools.CreateImage.CreateImageTool; HWndCtrl hWndCtrl = cameraShowUnit.HWndUnit.HWndCtrl; try { HTuple toolStart = new HTuple(), toolEnd = new HTuple(); StatusManger statusManger = StatusManger.Instance; statusManger.RuningStatus = RuningStatus.图像检测中; runningResultFlag = false; toolErr = null; //开始运行所有工具 HOperatorSet.CountSeconds(out toolStart); //外部触发处理 if (isExtTrigger || isGrabber) { createImageTool.SettExtTriggerData(ImageData); isGrabber = false; } else { createImageTool.SetExtTriggerDataOff(); } StringBuilder MyStringBuilder = new StringBuilder(); //string yy = MyStringBuilder.ToString(); string datSend = ""; foreach (var item in runToolList) { if (item is IToolRun) { try { item.Run(); string result = item.IsOk ? "OK" : "NG"; Util.Notify(string.Format("{0}_{1} T={2:f2}ms,结果: {3}", item.Name, result, item.ExecutionTime, item.Result)); MyStringBuilder.Append(string.Format("{0}_{1}_T={2:f2}ms\r\n", item.Name, result, item.ExecutionTime)); if (item.IsOutputResults) { string dat = item.GetSendResult(); if (dat != string.Empty) { datSend += dat; datSend += toolDelimiter; } } runStatus.RunStatusList.Add(item.IsOk); } catch (Exception ex) { //Util.WriteLog(this.GetType(), ex); Util.Notify(Level.Err, string.Format("工具{0}运行出现异常{1}", item.Name, ex.Message)); runStatus.RunStatusList.Add(false); } } else { runStatus.RunStatusList.Add(true); } } runStatus.ResultMessage = MyStringBuilder.ToString(); //时间统计 HOperatorSet.CountSeconds(out toolEnd); double toolTime = (toolEnd - toolStart) * 1000.0; //toolStart) * 1000.0; Util.Notify(string.Format("工具组{0}图像处理用时{1:f2}ms", settingIndex, toolTime)); #region 3 查找是否存在运行错误的工具 toolErr = runToolList.Find(x => x.IsOk == false && x is IToolRun); if (toolErr == null && ToolsFactory.ToolsDic.Count > 0) { runningResultFlag = true; ok++; } else { runningResultFlag = false; ng++; Util.Notify(string.Format("工具{0}图像处理检测到异常", toolErr.Name)); } if (runningResultFlag == true) { datSend = Util.TrimEndString(datSend, toolDelimiter); datSend = Util.TrimStartString(datSend, toolDelimiter); } else { datSend = ("Image" + Environment.NewLine + "Done" + Environment.NewLine); } if (isOffLineMode == false) //这个变量与AutoUnit中的isTestMode不是同一个,这里是指AutoUnit的测试模式与离线模式。 { //SerialHelper.Instance.WriteCommdToSerial(datSend); //非相机输出模式下就直接输出文本信息 if (!CommHandle.Instance.CommunicationParam.IsCamIOOutput && datSend != string.Empty) { Util.Notify(string.Format("发送结果: {0}", datSend)); autoUnit.RunCommWriteDataThread.WriteData(datSend); } else { if (StatusManger.Instance.IsInterlocking && CameraManger.CameraDic.ContainsKey(settingIndex) && runningResultFlag == false) { CameraManger.CameraDic[settingIndex].Output(); //结果NG时相机外部输出信号导通。 } } } else { if (runningResultFlag == false) { Util.Notify(string.Format("测试结果:{0}", "NG")); } else { Util.Notify(string.Format("测试结果:{0}", "OK")); } } #endregion #region 4 显示所有的图形 //HTuple showStart; //HOperatorSet.CountSeconds(out showStart); autoUnit.Invoke(new Action <HWndCtrl, List <ToolBase>, bool>((h, l, f) => { ShowResult(h, l, f); }), hWndCtrl, runToolList, runningResultFlag); #endregion HTuple end1; HOperatorSet.CountSeconds(out end1); double time1 = (end1 - toolEnd) * 1000.0; Util.Notify(string.Format("工具组{0}分析显示用时{1:f2}ms", settingIndex, time1)); } catch (Exception) { //Util.WriteLog(this.GetType(), ex); Util.Notify(string.Format("图像处理异常")); } finally { HOperatorSet.CountSeconds(out end); double runTime = 0; runTime = (end - startExTime) * 1000.0; runStatus.OKCount = ok; runStatus.NgCount = ng; runStatus.CylceTime = runTime; RunStatus runStatusTmp = runStatus.DeepClone(); autoUnit.RefreshUI(runStatusTmp); //指示可以来图像处理 Util.Notify(string.Format("---工具组{0}运行完成,用时{1:f2}ms\r\n", settingIndex, runTime)); imageRunFinishSignalFlow.Set(); //离线模式 if (isOffLineMode && createImageTool.OffLineMode == true && createImageTool.AllReadFinish == false) { Task.Run(async delegate { await Task.Delay(1000); if (isOffLineMode) { TrigerRun(this.settingIndex, true); //离线测试模式时,接着触发下次离线测试。 } }); } else { isOffLineMode = false; //将该对象的离线模式标志复位,不再执行离线。 } } }