防止 Direct3D 視口圖像縮放 (SlimDX) (Prevent Direct3D viewport image from scaling (SlimDX))


問題描述

防止 Direct3D 視口圖像縮放 (SlimDX) (Prevent Direct3D viewport image from scaling (SlimDX))

I have a Direct3D11 scene set up in SlimDX in a window.  The rendering is done in a separate thread.

Is there a way to keep the renderer from stretching the image when it draws to the resized control?  I've tried ModeDescription.Scaling = DisplayModeScaling.Centered and it doesn't seem to have any effect.  Is there something I'm missing?

(I already am updating the render target size.  The reason I ask this is that when I resize the control it stretches the image to fill the control for a split second before the render target gets updated with the new size.  This has the result that as I resize it, it flickers terribly.  If I could reset the render target just slightly faster it might get rid the the flicker.  Keeping the image in the corner without scaling it is perfectly fine since ultimately it won't be scaling at all.)

Workaround 1:  One can put the render target inside a control.  When the window resizes only resize the control though a special method that first stops the rendering, then update the buffers and begins rendering again.  It's a bit of hack, though.  I have to wait for the render cycle to complete, then block it, then resize, then unblock.

Workaround 2: A similar workaround is to check for a resize flag in the render loop rather than interrupting it.  The renderer should be able to draw directly without scaling.  This is much more acceptable performancewise.  However, a blocking call to the UI thread must be made to execute the actual resize.

Workaround 3:  Rather than resizing the control at all, one could make it as large as the maximum size it could be, but clipped (inside the window).  No resize is necessary, but a scissor rectangle must be maintained in a similar manner to the workarounds above unless you don't mind rendering a whole lot of offscreen pixels.  Rendering twenty or so extra rows and columns of pixels does have the favorable effect of supplying immediate image at the edge when the window is resized back larger.

Ideally the resize should be done directly from the UI thread (no fooling around with delaying it and reentering the UI thread from the render thread).  It's not the render thread's responsibility and it slows it down.  Likewise, the buffer resize should be done in the render thread for maximum performance (no fooling around with waiting/blocking/resizing/unblocking).  The only reason this does not work is that the render thread scales if the resize is done before the buffers are resized.

So my question still stands: Is there a way to render without scaling?


參考解法

方法 1:

I am going to answer this in terms of the raw Win32 APIs involved, which might require a bit of finesse to translate to a managed .NET environment & SlimDX.

When you are dragging or resizing a window, windows basically hijacks your message pump and creates a new one specifically designed to do the resizing logic efficiently.   This operation is more or less modal until it is completed.  Many messages you would normally get are quite literally blocked until the resize or drag is completed.  In the app terms you get a WM_ENTERSIZEMOVE when this behavior begins, and either WM_EXITSIZEMOVE or WM_CAPTURECHANGED when it ends.  You need to check both of these messages, as alt-tabing out when doing a drag will send WM_CAPTURECHANGED and never a WM_EXITSIZEMOVE!

All this means that when you get a WM_ENTERSIZEMOVE you can set a flag and know that all WM_SIZE and WM_MOVE messages that occur afterwards are for the drag operation.  Typically resizing rendertargets and tracking down and de-allocating all default pool resources is a very slow operation, and well worth defering until the drag/resize has completed.  This has the side effect of making the window stretch which is exactly the same problem you are describing here, and you want to fix that.

It should be possible to add special handlers in WM_SIZE, WM_MOVE, or WM_SIZING, and WM_MOVING that forces a syncronous render and repaint via SendMessage (as opposed to PostMessage) when they occur, but you will need to make sure you only do this when inside the modal loop owned by WM_ENTERSIZEMOVE.

方法 2:

I would recommend either forcing the window to a fixed size (which seems rather common) or not redrawing the D3D control until the changes are done (that or simply clear it black).

There seems to be a way to do what you want, as I have seen games capable of changing size with no flicker, but I've no idea how that's done, unfortunately. Locking the window size and providing a menu was the old solution.

(by jnm2Zonerssube)

參考文件

  1. Prevent Direct3D viewport image from scaling (SlimDX) (CC BY-SA 3.0/4.0)

#slimdx #direct3d #scaling #viewport






相關問題

使用紋理作為渲染目標時的大小限制 (Size limitation when using a texture as a render target)

如何安全地將事件傳遞到線程中。SlimDX / DX9 (How to safely pass events into a thread. SlimDX / DX9)

將directdx轉換為slimdx (Converting directdx to slimdx)

Toán véc tơ nhanh trong .NET - Các tùy chọn là gì? (Fast Vector Math in .NET - What are the options?)

DirectX10/ShapDX 自定義控件 (DirectX10/ShapDX Custom control)

使用 GDI 繪製散點圖太慢 (Drawing scatter plot is too slow with GDI)

防止 Direct3D 視口圖像縮放 (SlimDX) (Prevent Direct3D viewport image from scaling (SlimDX))

如何使用 SlimDX 設置 HLSL 統一變量的值? (How do I set the value of a HLSL uniform variable with SlimDX?)

使用 Direct3D 繪製帶有圓角末端的線條 (Drawing lines with rounded endings with Direct3D)

如何使圖元在 DirectX (2D) 中正確覆蓋精靈 (How to make primitives correctly overlay sprites in DirectX (2D))

多個渲染目標不保存數據 (Multiple Render Targets not saving data)

SlimDX VertexDeclaration 內存洩漏?- 如何避免? (SlimDX VertexDeclaration memory leak? - How to avoid it?)







留言討論