【问题标题】:Setting SharpDX.Windows.RenderForm.IsFullscreen before RenderLoop.Run corrupts window在 RenderLoop.Run 损坏窗口之前设置 SharpDX.Windows.RenderForm.IsFullscreen
【发布时间】:2015-02-16 14:43:41
【问题描述】:

在实现全屏和分辨率切换代码时,我在 SharpDX 中观察到了一个奇怪且错误的行为。每当我在调用RenderLoop.Run() 之前将RenderForm.IsFullscreen 设置为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 错误还是我做错了什么?在调用 RenderLoop.Run() 之前,我没有找到不应将 IsFullscreen 设置为 true 的信息。

【问题讨论】:

    标签: c# fullscreen directx-11 sharpdx


    【解决方案1】:

    分析窗口样式集,损坏的窗口缺少 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);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-28
      • 1970-01-01
      相关资源
      最近更新 更多