在实施全屏和分辨率切换代码时,我在SharpDX中观察到一种奇怪且错误的行为。每当我在调用RenderForm.IsFullscreen
之前将RenderLoop.Run()
设置为true,并在稍后返回窗口模式时,窗口就会损坏:
注意它是如何丢失一个图标,我的桌面背景和控制台闪耀。另外,我无法点击它,任何点击都会被重定向到底层窗口。即使在RenderLoop仍在运行时,将背景颜色清除为深蓝色,只会填充灰色和太小的区域。 (我可以通过任务栏按钮最大化损坏的窗口,以此作为用户解决此问题。只需调整大小无济于事。)
这是我的完整测试代码:
using System;
using System.Drawing;
using System.Windows.Forms;
using SharpDX;
using SharpDX.Direct3D;
using SharpDX.Direct3D11;
using SharpDX.DXGI;
using SharpDX.Windows;
internal class Program
{
private static RenderForm _window;
private static SharpDX.Direct3D11.Device _device;
private static DeviceContext _deviceContext;
private static SwapChain _swapChain;
private static RenderTargetView _renderTargetView;
private static bool Fullscreen
{
get
{
return _window.IsFullscreen;
}
set
{
// Do not resize multiple times by preventing the resized event.
_window.UserResized -= _window_UserResized;
_window.IsFullscreen = value;
_swapChain.SetFullscreenState(_window.IsFullscreen, null);
// Resize the window when returning to windowed mode to fit the most recent resolution.
if (!_window.IsFullscreen)
{
_window.ClientSize = _resolution;
}
// Allow new resize events.
_window.UserResized += _window_UserResized;
}
}
private static Size _resolution;
private static Size Resolution
{
get
{
return _resolution;
}
set
{
_resolution = value;
Debug.WriteLine("Setting resolution: " + _resolution.ToString());
// Do not resize multiple times by preventing the resized event.
_window.UserResized -= _window_UserResized;
// Resize the window in windowed mode.
if (!_window.IsFullscreen)
{
_window.ClientSize = _resolution;
}
// Dispose existing objects.
Utilities.Dispose(ref _renderTargetView);
// Resize the back buffer.
_swapChain.ResizeBuffers(0, _resolution.Width, _resolution.Height, Format.R8G8B8A8_UNorm, SwapChainFlags.AllowModeSwitch);
// Create the new and resized render target and set it.
using (Texture2D backBuffer = _swapChain.GetBackBuffer<Texture2D>(0))
{
_renderTargetView = new RenderTargetView(_device, backBuffer);
}
_deviceContext.OutputMerger.SetRenderTargets(_renderTargetView);
// Resize the swap chain buffers to set the fullscreen resolution.
ModeDescription bufferDescription = new ModeDescription()
{
Width = _resolution.Width,
Height = _resolution.Height,
RefreshRate = new Rational(60, 1),
Format = Format.R8G8B8A8_UNorm
};
_swapChain.ResizeTarget(ref bufferDescription);
// Allow new resize events.
_window.UserResized += _window_UserResized;
}
}
private static void Main(string[] args)
{
_window = new RenderForm();
_window.KeyDown += _window_KeyDown;
_window.IsFullscreen = true;
// Set default resolution.
_resolution = new Size(800, 600);
// Describe the swap chain buffer mode.
ModeDescription bufferDescription = new ModeDescription()
{
Width = _resolution.Width,
Height = _resolution.Height,
RefreshRate = new Rational(60, 1),
Format = Format.R8G8B8A8_UNorm
};
// Describe the swap chain.
SwapChainDescription swapChainDescription = new SwapChainDescription()
{
ModeDescription = bufferDescription,
SampleDescription = new SampleDescription(1, 0),
Usage = Usage.RenderTargetOutput,
BufferCount = 1,
OutputHandle = _window.Handle,
IsWindowed = !_window.IsFullscreen,
Flags = SwapChainFlags.AllowModeSwitch // Allows other fullscreen resolutions than native one.
};
// Create the device with the swap chain.
SharpDX.Direct3D11.Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.None, swapChainDescription, out _device, out _swapChain);
_deviceContext = _device.ImmediateContext;
// Set the resolution to run the code which resizes the internal buffers.
Resolution = _resolution;
_window.UserResized += _window_UserResized;
RenderLoop.Run(_window, Loop);
}
private static void Loop()
{
_deviceContext.ClearRenderTargetView(_renderTargetView, new Color4(0.4f, 0.5f, 0.6f, 1f));
_swapChain.Present(1, 0);
}
private static void _window_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.F)
{
Fullscreen = !Fullscreen;
}
}
private static void _window_UserResized(object sender, EventArgs e)
{
Resolution = _window.ClientSize;
}
}
我可以重写代码以将全屏设置记住为布尔值而不直接使用_window.IsFullscreen
,然后检查我是否在渲染循环的第一次迭代中并通过检查来设置全屏状态布尔,但那只是尴尬。
当我这样做时,窗口会动画到桌面上,就好像它是新创建的一样。看起来SharpDX在这里混淆了窗口样式。
这是一个SharpDX错误还是我做错了什么?在调用IsFullscreen
之前,我没有找到不应将RenderLoop.Run()
设置为true的信息。
答案 0 :(得分:4)
分析窗口样式集,损坏的窗口缺少WS_VISIBLE。
所以,我只是忘了Show()
渲染表单。事实证明,我必须在分析任何D3D之前做到这一点,否则窗口会再次被破坏。
这是固定的Main()
方法:
private static void Main(string[] args)
{
_window = new RenderForm();
_window.KeyDown += _window_KeyDown;
_window.IsFullscreen = true;
_window.Show(); // Do not forget this or window styles may break
// Set default resolution.
_resolution = new Size(800, 600);
// Describe the swap chain buffer mode.
ModeDescription bufferDescription = new ModeDescription()
{
Width = _resolution.Width,
Height = _resolution.Height,
RefreshRate = new Rational(60, 1),
Format = Format.R8G8B8A8_UNorm
};
// Describe the swap chain.
SwapChainDescription swapChainDescription = new SwapChainDescription()
{
ModeDescription = bufferDescription,
SampleDescription = new SampleDescription(1, 0),
Usage = Usage.RenderTargetOutput,
BufferCount = 1,
OutputHandle = _window.Handle,
IsWindowed = !_fullscreen,
Flags = SwapChainFlags.AllowModeSwitch // Allows other fullscreen resolutions than native one.
};
// Create the device with the swap chain.
SharpDX.Direct3D11.Device.CreateWithSwapChain(DriverType.Hardware, DeviceCreationFlags.None,
swapChainDescription, out _device, out _swapChain);
_deviceContext = _device.ImmediateContext;
// Set the resolution to run the code which resizes the internal buffers.
Resolution = _resolution;
RenderLoop.Run(_window, Loop);
}