1

我在一个窗口中的 SlimDX 中设置了 Direct3D11 场景。渲染在单独的线程中完成。

有没有办法让渲染器在绘制到调整大小的控件时不拉伸图像?我试过ModeDescription.Scaling = DisplayModeScaling.Centered了,好像没什么效果。有什么我想念的吗?

(我已经在更新渲染目标大小。我问这个的原因是,当我调整控件大小时,它会拉伸图像以在渲染目标更新为新大小之前填充控件一瞬间。结果是当我调整它的大小时,它会严重闪烁。如果我可以稍微快一点地重置渲染目标,它可能会消除闪烁。将图像保持在角落而不缩放它是非常好的,因为最终它根本不会缩放。 )

解决方法 1: 可以将渲染目标放在控件中。当窗口调整大小时,仅通过一种特殊方法调整控件的大小,该方法首先停止渲染,然后更新缓冲区并再次开始渲染。不过,这有点骇人听闻。我必须等待渲染周期完成,然后阻止它,然后调整大小,然后解除阻止。

解决方法 2:类似的解决方法是检查渲染循环中的调整大小标志,而不是中断它。渲染器应该能够直接绘制而无需缩放。这在性能方面更容易接受。但是,必须对 UI 线程进行阻塞调用才能执行实际的调整大小。

解决方法 3:与其完全调整控件的大小,不如将其设置为尽可能大,但会被裁剪(在窗口内)。无需调整大小,但必须以与上述解决方法类似的方式维护剪刀矩形,除非您不介意渲染大量屏幕外像素。渲染 20 左右额外的像素行和列确实具有在窗口重新变大时在边缘提供即时图像的有利效果。

理想情况下,调整大小应该直接从 UI 线程完成(不要鬼混延迟它并从渲染线程重新进入 UI 线程)。这不是渲染线程的责任,它会减慢它的速度。同样,缓冲区调整大小应该在渲染线程中完成以获得最佳性能(不要胡乱等待/阻塞/调整大小/解除阻塞)。这不起作用的唯一原因是如果在调整缓冲区大小之前完成调整大小,则渲染线程会缩放。

所以我的问题仍然存在:有没有一种方法可以在不缩放的情况下进行渲染?

4

2 回答 2

1

我将根据所涉及的原始 Win32 API 来回答这个问题,这可能需要一些技巧才能转换为托管的 .NET 环境和 SlimDX。

当您拖动或调整窗口大小时,窗口基本上会劫持您的消息泵并创建一个专门设计用于有效执行调整大小逻辑的新消息泵。在完成之前,此操作或多或少是模态的。在调整大小或拖动完成之前,您通常会收到许多消息被完全屏蔽。在应用程序条款中,当此行为开始时,您将获得 WM_ENTERSIZEMOVE,而当此行为结束时,您将获得 WM_EXITSIZEMOVE 或 WM_CAPTURECHANGED。您需要检查这两条消息,因为在拖动时使用 alt-tabing 会发送 WM_CAPTURECHANGED 而不会发送 WM_EXITSIZEMOVE!

这一切意味着当你得到一个 WM_ENTERSIZEMOVE 时,你可以设置一个标志,并且知道之后出现的所有 WM_SIZE 和 WM_MOVE 消息都是针对拖动操作的。通常,调整渲染目标的大小以及跟踪和取消分配所有默认池资源是一个非常缓慢的操作,非常值得推迟到拖动/调整大小完成。这具有使窗口拉伸的副作用,这与您在此处描述的问题完全相同,并且您想解决该问题。

应该可以在 WM_SIZE、WM_MOVE 或 WM_SIZING 和 WM_MOVING 中添加特殊处理程序,当它们发生时通过 SendMessage(而不是 PostMessage)强制同步渲染和重绘,但您需要确保仅在内部执行此操作WM_ENTERSIZEMOVE 拥有的模态循环。

于 2011-07-06T08:16:31.507 回答
0

我建议要么将窗口强制为固定大小(这似乎很常见),要么在更改完成之前不重绘 D3D 控件(或者只是将其清除为黑色)。

似乎有一种方法可以做你想做的事,因为我已经看到游戏能够在没有闪烁的情况下改变大小,但不幸的是,我不知道这是怎么做到的。锁定窗口大小并提供菜单是旧的解决方案。

于 2011-07-05T21:03:14.737 回答