Multiple GameWindow support for Windows/DirectX #1465

Merged
merged 17 commits into from May 1, 2013

Conversation

Projects
None yet
6 participants
Contributor

jamesford42 commented Feb 26, 2013

Adding support for multiple GameWindow(s) within a single game.

This is only implemented for WINDOWS && DIRECTX

Non-primary windows do not handle any input and for input events to reach the users game the primary window must be active. This can be improved at a later time when it is a needed feature.

The existing Game / Platform / GraphicsDevice code is largely unchanged and only deals directly with the standard, primary window which it also creates.

Example:

// In Game.Initialize()
window = GameWindow.CreateWindow(this, 640, 480);
window.Title = "Second Game Window";
swapChain = new SwapChainRenderTarget(GraphicsDevice, window.Handle, 640, 480);

// In Game.Draw()
GraphicsDevice.SetRenderTarget(swapChain);
GraphicsDevice.Clear(Color.Red);
GraphicsDevice.Present();
GraphicsDevice.SetRenderTarget(null);

jamesford42 added some commits Feb 23, 2013

@jamesford42 jamesford42 Exposing the ability to create secondary windows via static GameWindo…
…w method.
eb5abd5
@jamesford42 jamesford42 Added new class SwapChainRenderTarget, which is allocated with a wind…
…ow handle and exposes Present. Since it is a RenderTarget it can be set on the GraphicsDevice but Present needs to be called on it.
965305f

This should be internal.

What is a sdx? Don't invent terms that no one else will ever understand. Code is communication and we must communicate to people clearly. Simply use _swapChain.

Just use 'windowHandle' here... there is nothing 'device' about it.

Make GraphicsDevice the first parameter. This matches all other XNA classes.

Remove the 'preferred' here. It confuses what the behavior is.

This requires the lock (_d3dContext) put it in.

As we discussed on Friday. Remove this function... change the original to take PresentInterval instead of PresentationParameters.

Member

mgbot commented Feb 26, 2013

Can one of the admins verify this patch?

jamesford42 referenced this pull request Feb 26, 2013

Closed

Don't pull #1463

Owner

tomspilman commented Feb 26, 2013

@mgbot test

Member

mgbot commented Feb 26, 2013

Build results will soon be (or already are) available at: http://build.monogame.net/job/BuildPR/41/

Owner

tomspilman commented Feb 26, 2013

@mgbot test

Member

mgbot commented Feb 26, 2013

Build results will soon be (or already are) available at: http://build.monogame.net/job/BuildPR/42/

Owner

tomspilman commented Feb 27, 2013

@mgbot test

Member

mgbot commented Feb 27, 2013

Build results will soon be (or already are) available at: http://build.monogame.net/job/BuildPR/44/

Member

mgbot commented Mar 5, 2013

Can one of the admins verify this patch?

Contributor

dellis1972 commented Mar 5, 2013

@mgbot test

On 5 March 2013 22:59, MonoGame Build Bot notifications@github.com wrote:

Can one of the admins verify this patch?

Reply to this email directly or view it on GitHubhttps://github.com/mono/MonoGame/pull/1465#issuecomment-14471385
.

Owner

tomspilman commented Mar 9, 2013

@mgbot test

Member

mgbot commented Mar 9, 2013

Build results will soon be (or already are) available at: http://build.monogame.net/job/BuildPR/88/

Owner

tomspilman commented Mar 9, 2013

Can someone else give this PR a test?

Are there any concerns with adding this feature?

Contributor

xanather commented Mar 9, 2013

I can give this a test later tonight/tomorrow, but how do I function it? create another GameWindow from within the main Game1.cs constructor? then to draw set RenderTarget to that window?

Owner

tomspilman commented Mar 9, 2013

Well first make sure it doesn't break any existing functionality in your game.

If you want to then test the new features just create the second window in Game.Initialize:

_altwindow = GameWindow.CreateWindow(this, 640, 480);
_altwindow.Title = "Second Game Window";

_altSwapChain = new SwapChainRenderTarget( GraphicsDevice, 
                                            _altwindow.Handle,
                                            640,
                                            480,
                                            false,
                                            PresentInterval.Default,
                                            SurfaceFormat.Color,
                                            DepthFormat.Depth24Stencil8,
                                            0,
                                            RenderTargetUsage.DiscardContents);

Then in your Game.Draw do this:

// Set the alt windows/swapcain and render to it.
GraphicsDevice.SetRenderTarget(_altSwapChain);
GraphicsDevice.Clear(Color.Red);
GraphicsDevice.Present();

// Return to the default window/swapchain.
GraphicsDevice.SetRenderTarget(null);

// Do your normal rendering.

base.Draw();

It is pretty simple and you can create as many windows as you need.

Also in theory you could pass a IntPtr handle to a non-GameWindow window as well... but we've not tried that.

Contributor

xanather commented Mar 10, 2013

Well, I can make the other window show. However I cant render to it (its not displaying the correct color from GraphicsDevice.Clear()).

This is my draw method:

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.SetRenderTarget(swapChain);
        GraphicsDevice.Clear(Color.Black);
        GraphicsDevice.Present();
        GraphicsDevice.SetRenderTarget(null);
        GraphicsDevice.Clear(Color.Black);
        base.Draw(gameTime);
    }

The other window just has the default creamy-colored background.

Also can I suggest that SwapChainRenderTarget gets a new constructor that is much more simple and automatically sets all the other settings (default settings)?

new SwapChainRenderTarget(GraphicsDevice, gameWindow.Handle, 1000, 1000);?

If people want the more customizable constructor they can use it aswell

Owner

tomspilman commented Mar 10, 2013

@xanather

However I cant render to it

Are you sure you are building against MonoGame for Windows DX? It does not work under OpenGL yet.

Also can I suggest that SwapChainRenderTarget gets a new constructor

Sure... no problem. I'll add that right now in fact.

Owner

tomspilman commented Mar 10, 2013

Note I came across the old Windows Mobile C# wrapper for DirectX and it too has a SwapChain class:

http://msdn.microsoft.com/en-us/library/microsoft.windowsmobile.directx.direct3d.swapchain_members.aspx

Just noting the precedent for having this class in MonoGame.

@tomspilman tomspilman Added simpler constructor.
Rearraged the construtor parameters to match RenderTarget better.
Resharper cleanups.
Added some TODOs.
Fixed some of the docs.
8caa010
Owner

tomspilman commented Mar 11, 2013

@xanather - Updated with the simpler constructor.

Contributor

xanather commented Mar 11, 2013

It is a windows DirectX project.

Code:

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
namespace MonoGameTest
{
    class Engine : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        GameWindow gameWindow;
        SwapChainRenderTarget swapChain;
        public Engine()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }
        protected override void Initialize()
        {
            gameWindow = GameWindow.Create(this, 640, 480);
            gameWindow.Title = "Second Game Window Test";
            swapChain = new SwapChainRenderTarget(GraphicsDevice, gameWindow.Handle, 640, 480, false, PresentInterval.Default, SurfaceFormat.Color, DepthFormat.Depth24Stencil8, 0, RenderTargetUsage.DiscardContents);
            base.Initialize();
        }
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
        }
        protected override void UnloadContent()
        {
        }
        protected override void Update(GameTime gameTime)
        {
            base.Update(gameTime);
        }
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.SetRenderTarget(swapChain);
            GraphicsDevice.Clear(Color.Black);
            GraphicsDevice.Present();
            GraphicsDevice.SetRenderTarget(null);
            GraphicsDevice.Clear(Color.Black);
            base.Draw(gameTime);
        }
    }
}

Edit: that didnt come out too well : /
Should be still readable though, I can't see anything wrong with it?

Owner

tomspilman commented Mar 11, 2013

@xanather

I edited your post to use code block formatting... take a look.

Maybe try calling base.Initialize(); before everything else in that method?

Contributor

xanather commented Mar 11, 2013

no difference, do you want me to upload the project?

Owner

tomspilman commented Mar 11, 2013

Hum. I have an idea... i'll test it over here first. I think there might be an error if you try to create the swap chain too early. Looking at our use we are creating the swap chain on first GameWindow.ClientSizeChanged event.

Contributor

xanather commented Mar 11, 2013

Oh I see. I just tried after a 1 second timer, still doesn't work.

Contributor

KonajuGames commented Mar 15, 2013

I've been trying to test this, but I get E_FAIL (0x80004005) when trying to create the Direct3D11 device. No idea why.

Owner

tomspilman commented Mar 15, 2013

Hum.... i'll make sure I test a clean pull of this and verify some of the issues brought up here.

Owner

tomspilman commented Apr 5, 2013

@xanather - I went and tested your case... you just misinterpreted how to use the API. You had this:

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.SetRenderTarget(swapChain);
            GraphicsDevice.Clear(Color.Black);
            GraphicsDevice.Present(); // WRONG!

            GraphicsDevice.SetRenderTarget(null);
            GraphicsDevice.Clear(Color.Black);
            base.Draw(gameTime);
        }

... it should have been this...

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.SetRenderTarget(swapChain);
            GraphicsDevice.Clear(Color.Black);
            swapChain.Present(); // Correct!

            GraphicsDevice.SetRenderTarget(null);
            GraphicsDevice.Clear(Color.Black);
            base.Draw(gameTime);
        }

So this it would be good if you can verify, but this PR does work.

Owner

tomspilman commented Apr 5, 2013

@slygamer @dellis1972

Are you guys good with this?

Note that the high level plan is simplify swapchain/framebuffer management code in GraphicsDevice.

I next want to add OpenGL support (not sure if GLES can support it). Also need to add resize support as that is missing right now.

Then we can replace the existing swap chain creation/resizing code which makes up a ton of GraphicsDevice (and scattered about on OpenGL) with this class.

Owner

tomspilman commented Apr 5, 2013

@mgbot test

Member

mgbot commented Apr 5, 2013

Build results will soon be (or already are) available at: http://build.monogame.net/job/PullRequestTester/86/

Contributor

dellis1972 commented Apr 5, 2013

ok by me

On 5 April 2013 19:51, MonoGame Build Bot notifications@github.com wrote:

Build results will soon be (or already are) available at:
http://build.monogame.net/job/PullRequestTester/86/


Reply to this email directly or view it on GitHubhttps://github.com/mono/MonoGame/pull/1465#issuecomment-15973815
.

Contributor

xanather commented Apr 6, 2013

Oh cool, I will verify it soon

Contributor

xanather commented Apr 7, 2013

yep with the change it works :)

xanather referenced this pull request Apr 23, 2013

Closed

Yet to be implemented #1634

KonajuGames merged commit 7da4118 into MonoGame:develop May 1, 2013

1 check passed

default Merged build finished.
Details

This was referenced May 14, 2013

tomspilman deleted the SickheadGames:multiwin branch Jan 20, 2014

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment