SlimDX and UserControl

Started by
4 comments, last by ragnarsun 14 years, 1 month ago
I have created a new control that derives from UserControl. In that control, I add the D3D device, swapchain, etc, and that control will present a 3D display. I am having some repainting issues in that the control does not seem to like when Invalidate() is called to repaint itself. Inside the repaint I have:

protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);

            if(_d3dDevice != null)
            {
                _d3dDevice.ClearRenderTargetView(_renderTargetView, Color.Blue);
                _d3dDevice.ClearDepthStencilView(_depthStencilView, DepthStencilClearFlags.Depth | DepthStencilClearFlags.Stencil, 1.0f, 0);

                _swapChain.Present(0, PresentFlags.None);
            }
        }
However, on the first paint something is not working because the control is painted gray and not Blue. If I resize the window (not having overridden OnResize, it turns Blue). If I override OnResize, and call Invalidate from it, it turns gray. What is strange is I have copy and paste the same D3D initialization code into a Form, and it works correctly. Anyone know why a UserControl might be throwing it off?

private void InitDirect3D()
        {
            SwapChainDescription sd = new SwapChainDescription();
            sd.ModeDescription = new ModeDescription(Width, Height, new SlimDX.Rational(60, 1), Format.R8G8B8A8_UNorm);
            sd.SampleDescription = new SampleDescription(1, 0);
            sd.Usage = Usage.RenderTargetOutput;
            sd.BufferCount = 1;
            sd.OutputHandle = Handle;
            sd.IsWindowed = true;
            sd.SwapEffect = SwapEffect.Discard;
            sd.Flags = SwapChainFlags.None;

            // Create the device.

            DeviceCreationFlags createDeviceFlags = DeviceCreationFlags.None;
#if DEBUG
            createDeviceFlags |= DeviceCreationFlags.Debug;
#endif

            SlimDX.Direct3D10.Device.CreateWithSwapChain(null, DriverType.Hardware,
                createDeviceFlags, sd, out _d3dDevice, out _swapChain);

            ResizeBackBuffer();
        }

        private void ResizeBackBuffer()
        {
            // Release the old views, as they hold references to the buffers we
            // will be destroying.  Also release the old depth/stencil buffer.

            if(_renderTargetView != null)
                _renderTargetView.Dispose();

            if(_depthStencilView != null)
                _depthStencilView.Dispose();

            if(_depthStencilBuffer != null)
                _depthStencilBuffer.Dispose();


            _swapChain.ResizeBuffers(1, ClientSize.Width, ClientSize.Height, Format.R8G8B8A8_UNorm, SwapChainFlags.None);

            Texture2D backBuffer = Texture2D.FromSwapChain<Texture2D>(_swapChain, 0);
            _renderTargetView = new RenderTargetView(_d3dDevice, backBuffer);
            backBuffer.Dispose();

            // Create the depth/stencil buffer and view.

            Texture2DDescription depthStencilDesc = new Texture2DDescription();
            depthStencilDesc.Width = ClientSize.Width;
            depthStencilDesc.Height = ClientSize.Height;
            depthStencilDesc.MipLevels = 1;
            depthStencilDesc.ArraySize = 1;
            depthStencilDesc.Format = Format.D24_UNorm_S8_UInt;
            depthStencilDesc.SampleDescription = new SampleDescription(1, 0);
            depthStencilDesc.Usage = ResourceUsage.Default;
            depthStencilDesc.BindFlags = BindFlags.DepthStencil;
            depthStencilDesc.CpuAccessFlags = 0;
            depthStencilDesc.OptionFlags = ResourceOptionFlags.None;

            _depthStencilBuffer = new Texture2D(_d3dDevice, depthStencilDesc);
            _depthStencilView = new DepthStencilView(_d3dDevice, _depthStencilBuffer);

            // Bind the render target view and depth/stencil view to the pipeline.

            _d3dDevice.OutputMerger.SetTargets(_depthStencilView, _renderTargetView);


            // Set the viewport transform.

            Viewport vp = new Viewport(0, 0, ClientSize.Width, ClientSize.Height, 0.0f, 1.0f);
            _d3dDevice.Rasterizer.SetViewports(vp);
        }

protected override void OnLoad(EventArgs e)
        {
            base.OnLoad(e);

            if (!DesignMode)
            {
                InitDirect3D();
            }
        }

private SlimDX.Direct3D10.Device _d3dDevice;
        private SwapChain _swapChain;

        private Texture2D _depthStencilBuffer;
        private RenderTargetView _renderTargetView;
        private DepthStencilView _depthStencilView;
-----Quat
Advertisement
You'll want to also override OnPaintBackground and have it do nothing, since by default that method will clear the client area to the control's background color.
Quote:
You'll want to also override OnPaintBackground and have it do nothing, since by default that method will clear the client area to the control's background color.


I tried that already, and still no luck. By the way, I don't think that is needed except to avoid flicker. In the Form version that does work, I added

Quote:
protected override void OnPaintBackground(PaintEventArgs e)
{

}


and it prevents flicker when I resize the window, for example. If I add it to the version that uses the UserControl (form with my UserControl with Fill docking), then I get the situation I originally described but the color is black instead of gray on the first paint.
-----Quat
I am still working on this. Here is the simple code to show the problem.

New UserControl:using System;using System.Collections.Generic;using System.ComponentModel;using System.Drawing;using System.Data;using System.Linq;using System.Text;using System.Windows.Forms;using SlimDX;using SlimDX.Direct3D10;using SlimDX.DXGI;namespace SkyConfig{    public partial class Direct3DControl : UserControl    {        #region Private Fields         private SlimDX.Direct3D10.Device _d3dDevice;        private SwapChain _swapChain;        private Texture2D _depthStencilBuffer;        private RenderTargetView _renderTargetView;        private DepthStencilView _depthStencilView;         #endregion        #region Public Methods        public Direct3DControl()        {            InitializeComponent();         }              #endregion        #region Protected Methods        /// <summary>         /// Clean up any resources being used.        /// </summary>        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>        protected override void Dispose(bool disposing)        {            Effects.DisposeAll();            InputLayouts.DisposeAll();            if( _renderTargetView != null )                _renderTargetView.Dispose();            if (_depthStencilView != null)                _depthStencilView.Dispose();            if (_depthStencilBuffer != null)                _depthStencilBuffer.Dispose();            if (_swapChain != null)                _swapChain.Dispose();            if (_d3dDevice != null)                _d3dDevice.Dispose();            if(disposing && (components != null))            {                components.Dispose();            }            base.Dispose(disposing);        }        protected override void OnLoad(EventArgs e)        {            base.OnLoad(e);            if (!DesignMode)            {                InitDirect3D();            }        }                 protected override void OnResize(EventArgs e)        {            base.OnResize(e);            if( _d3dDevice != null && (Width > 0) && (Height > 0) )	        {                ResizeBackBuffer();                //SetProjection();                // The control is not repainted when we size down, but we need it to.                Invalidate();            }        }        protected override void OnPaint(PaintEventArgs e)        {            base.OnPaint(e);            // Don't use Direct3D in design mode.            if (DesignMode || _d3dDevice == null)            {                e.Graphics.Clear(Color.White);            }            else            {                if (_d3dDevice != null)                {                    _d3dDevice.ClearRenderTargetView(_renderTargetView, Color.Blue);                    _d3dDevice.ClearDepthStencilView(_depthStencilView, DepthStencilClearFlags.Depth | DepthStencilClearFlags.Stencil, 1.0f, 0);                    _swapChain.Present(0, PresentFlags.None);                }            }        }        protected override void OnPaintBackground(PaintEventArgs e)        {        }        #endregion        #region Private Methods        private void InitDirect3D()        {            SwapChainDescription sd = new SwapChainDescription();            sd.ModeDescription = new ModeDescription(Width, Height, new SlimDX.Rational(60, 1), Format.R8G8B8A8_UNorm);            sd.SampleDescription = new SampleDescription(1, 0);            sd.Usage = Usage.RenderTargetOutput;            sd.BufferCount = 1;            sd.OutputHandle = Handle;            sd.IsWindowed = true;            sd.SwapEffect = SwapEffect.Discard;            sd.Flags = SwapChainFlags.None;            // Create the device.            DeviceCreationFlags createDeviceFlags = DeviceCreationFlags.None;#if DEBUG            createDeviceFlags |= DeviceCreationFlags.Debug;#endif            SlimDX.Direct3D10.Device.CreateWithSwapChain(null, DriverType.Hardware,                createDeviceFlags, sd, out _d3dDevice, out _swapChain);            ResizeBackBuffer();        }        private void ResizeBackBuffer()        {            // Release the old views, as they hold references to the buffers we            // will be destroying.  Also release the old depth/stencil buffer.            if(_renderTargetView != null)                _renderTargetView.Dispose();            if(_depthStencilView != null)                _depthStencilView.Dispose();            if(_depthStencilBuffer != null)                _depthStencilBuffer.Dispose();            _swapChain.ResizeBuffers(1, ClientSize.Width, ClientSize.Height, Format.R8G8B8A8_UNorm, SwapChainFlags.None);            Texture2D backBuffer = Texture2D.FromSwapChain<Texture2D>(_swapChain, 0);            _renderTargetView = new RenderTargetView(_d3dDevice, backBuffer);            backBuffer.Dispose();            // Create the depth/stencil buffer and view.            Texture2DDescription depthStencilDesc = new Texture2DDescription();            depthStencilDesc.Width = ClientSize.Width;            depthStencilDesc.Height = ClientSize.Height;            depthStencilDesc.MipLevels = 1;            depthStencilDesc.ArraySize = 1;            depthStencilDesc.Format = Format.D24_UNorm_S8_UInt;            depthStencilDesc.SampleDescription = new SampleDescription(1, 0);            depthStencilDesc.Usage = ResourceUsage.Default;            depthStencilDesc.BindFlags = BindFlags.DepthStencil;            depthStencilDesc.CpuAccessFlags = 0;            depthStencilDesc.OptionFlags = ResourceOptionFlags.None;            _depthStencilBuffer = new Texture2D(_d3dDevice, depthStencilDesc);            _depthStencilView = new DepthStencilView(_d3dDevice, _depthStencilBuffer);            // Bind the render target view and depth/stencil view to the pipeline.            _d3dDevice.OutputMerger.SetTargets(_depthStencilView, _renderTargetView);            // Set the viewport transform.            Viewport vp = new Viewport(0, 0, ClientSize.Width, ClientSize.Height, 0.0f, 1.0f);            _d3dDevice.Rasterizer.SetViewports(vp);        }        #endregion    }}


For the main form, I only do the following. I add a menu strip, I add a panel docked to the right, and I add the Direct3DControl above docked with "Fill".

-----Quat
It seems like a SlimDX issue because I rewrote the UserControl in C++/CLI and dropped it into the C# Form, and it is working as expected. I would like to use SlimDX still, so hopefully someone knows the solution.
-----Quat
Very weird, I copy and paste your code and is working. Also I comment the lines:

Effects.DisposeAll();
InputLayouts.DisposeAll();

Do you have the lastes release? (feb. 2010)

This topic is closed to new replies.

Advertisement