Windows在将DirectX后备缓冲区拉伸至窗口时使用点采样。

3

Windows7使用点过滤方法将DirectX9后备缓冲区拉伸到窗口客户区域。 当调整窗口大小时,拉伸产生的伪影非常严重。 通过更改后备缓冲区大小,我们可以避免这种情况,但这需要调用IDirect3DDevice9 :: Reset()方法。 这会导致黑屏和调整大小期间的小延迟。

有没有办法改善Windows使用的过滤方法?或者,有没有办法从不同的DirectX表面,如渲染目标更新窗口?


我正在使用未托管的 C++ DirectX 代码。假设我有一个 1280 x 720 的后台缓冲表面:

D3DPRESENT_PARAMETERS  presentParams;
presentParams.BackBufferWidth  = 1280;
presentParams.BackBufferHeight = 720;
gD3D->CreateDevice(
    0, D3DDEVTYPE_HAL, hWnd,               
    D3DCREATE_HARDWARE_VERTEXPROCESSING,
    &presentParams,
    &pD3D9Device);

但我有一个 1920 x 1080 的窗口:

hWnd = CreateWindowExA(NULL, "WindowClass", winName,
                flags, 0, 0, 1920, 1080,
                NULL, NULL, hInstance, NULL);

当我调用Present()函数时,Windows会将我的DirectX后备缓冲区拉伸到窗口大小。然而,他们的拉伸似乎没有执行任何滤波。
pD3D9Device->Present(NULL, NULL, NULL, NULL);

我可以调整后备缓冲区的大小,但这需要调用Reset(),Reset()会导致视频内存表面丢失。


我删除了windowswindows-7标签,因为它们没有意义。这个问题是关于DirectX9的,显然是特定于Windows的,而且是DirectX在进行采样/渲染,而不是Windows本身(如果是Windows完成,你就不需要DirectX)。 - Ken White
Windows只是在将图像渲染后进行了拉伸blt操作,以适应窗口大小。 - JustinB
1
通常的方法是使后备缓冲区和窗口大小相同 - 如果无法更改缓冲区,则更改窗口。我假设DirectX正在使用最快的方式将图像传输到窗口,这不涉及任何过滤。您可以通过使缓冲区成为窗口大小的整数除法来最小化失真。 - Mark Ransom
是的,这很有道理。在用户调整窗口大小到任意大小的情况下,我们试图优雅而快速地处理它。 - JustinB
3个回答

1

当我尝试在窗口中播放视频并希望调整窗口大小而不需要重置设备时,我遇到了这个问题。

我从mpc-hc源代码中找到了一个解决方案:https://github.com/mpc-hc/mpc-hc/blob/develop/src/filters/renderer/VideoRenderers/SyncRenderer.cpp

1)使后备缓冲区变大(预期窗口最大尺寸)-> 我选择屏幕尺寸

2)仅在大小等于窗口的矩形上绘制

3)使用Device.Present(srcrect, destrect)。 srcrect和destrect是相同的矩形,并且具有窗口大小。

虽然我对DirectX等技术还很陌生,但这个解决方案对我有效。


看起来应该可以工作!我得试一下。 - JustinB

0
你尝试过使用IDirect3DDevice9::SetSamplerState了吗?

http://msdn.microsoft.com/en-us/library/windows/desktop/bb174698(v=vs.85).aspx

其实我在搜寻关于我遇到的类似问题的解决方法。我使用D3D9纹理来渲染一些图像,在Vista系统中,通过SetSamplerState加上线性材质过滤可以帮助大大减少由于调整窗口大小而引起的伪影。但是在Windows 7中情况并非如此。我不确定这两个平台是如何处理这个问题的。

0

如果您能发布一些特定操作的代码片段,那将会很有帮助。但是,如果您正在使用GDI(非托管Win32)StretchBlt函数,则可以通过HALFTONE获得更好的调整大小行为,如此帖子所述:Is StretchBlt HALFTONE == BILINEAR for all scaling?

如果您正在使用GDI+(WinForms/C#),则可以使用g.InterpolationMode = InterpolationMode.Bilinear(查看MSDN以获取所有选项)来获得双线性(或更好)插值。请注意,GDI+通常比GDI(或DX)慢。

(此帖子中有一些相关信息:Bilinear interpolation - DirectX vs. GDI+


谢谢提供信息。然而我并不使用GDI,而是使用DirectX。我只是尝试避免在DirectX中调整我的后备缓冲区大小,但似乎这是唯一的解决方法。 - JustinB

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接