防止Direct3D视口图像缩放(SlimDX)

时间:2011-07-05 20:17:08

标签: scaling direct3d viewport slimdx

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

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

(我已经在更新渲染目标大小了。我之所以这样说是因为当我调整控件大小时,它会拉伸图像以在一小段时间内填充控件,然后渲染目标会以新大小进行更新。结果是,当我调整大小时,它会闪烁得非常糟糕。如果我可以稍微快一点地重置渲染目标,它可能会消除闪烁。将图像保留在角落而不缩放它是完全正常的,因为最终它不会缩放完全没有。)

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

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

解决方法3 :根本不需要调整控件的大小,可以使其尽可能大,但可以剪裁(在窗口内)。不需要调整大小,但必须以与上述变通方法类似的方式维护剪刀矩形,除非您不介意渲染大量的屏幕外像素。渲染大约二十个额外的行和列像素 具有在窗口调整大一点时在边缘处提供即时图像的有利效果。

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

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

2 个答案:

答案 0 :(得分:1)

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

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

所有这些意味着当你得到一个WM_ENTERSIZEMOVE时,你可以设置一个标志,并知道之后发生的所有WM_SIZE和WM_MOVE消息都是用于拖动操作。通常,调整rendertargets并跟踪和取消分配所有默认池资源是一个非常慢的操作,非常值得推迟,直到拖动/调整大小完成。这有使窗口伸展的副作用,这与您在此描述的问题完全相同,并且您想要修复它。

应该可以在WM_SIZE,WM_MOVE或WM_SIZING中添加特殊处理程序,以及WM_MOVING强制同步渲染并在发生时通过SendMessage重绘(而不是PostMessage),但是你需要确保只做这在WM_ENTERSIZEMOVE所拥有的模态循环中。

答案 1 :(得分:0)

我建议将窗口强制为固定大小(这似乎相当普遍)或者不要重绘D3D控件直到更改完成(或者简单地将其清除为黑色)。

似乎有办法做你想要的,因为我已经看到游戏能够改变大小而没有闪烁,但遗憾的是我不知道如何做到这一点。锁定窗口大小并提供菜单是旧解决方案。