Sign in to follow this  
Quat

SlimDX and UserControl

Recommended Posts

Quat    568
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;

Share this post


Link to post
Share on other sites
Quat    568
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.

Share this post


Link to post
Share on other sites
Quat    568
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".

Share this post


Link to post
Share on other sites
Quat    568
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.

Share this post


Link to post
Share on other sites
ragnarsun    133
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)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this