Sign in to follow this  

SlimDX and UserControl

This topic is 2829 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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
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
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
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

This topic is 2829 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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