Two Instances of the same App class
As title implies: I'm trying to create two instances of the same app from one executable.
Basically i want 2 separate windows with the same view and put them on 2 monitors respectively.
The following code runs ok, but when uncommenting T.Start(), the error pops up: "An Application was already created"
I also changed the App class from examples as:
Basically i want 2 separate windows with the same view and put them on 2 monitors respectively.
The following code runs ok, but when uncommenting T.Start(), the error pops up: "An Application was already created"
Code: Select all
class Apper
{
static Thread T = null;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
T = new Thread(new ThreadStart(SecondWindow));
// T.Start();
App app = new App();
app.Run();
}
static void SecondWindow()
{
App app = new App(2);
app.Run();
}
}
Code: Select all
public partial class App : Application
{
public App()
{
Uri = "App.xaml";
}
public App(int WindowNumber)
{
Uri = "App.xaml";
}
protected override Display CreateDisplay()
{
return new Win32Display();
}
protected override RenderContext CreateRenderContext()
{
return new RenderContextD3D11();
}
protected override bool VSync => true;
}
Re: Two Instances of the same App class
It doesn't make sense to have two App classes for the same executable. What you probably need is one App class and several Window instances. That scenario should be supported although our examples do not use it, so probably minor changes may be needed.
Re: Two Instances of the same App class
I thought, cus of the App class seems to be the starting point of the application and the overriden function.
Is there an quick sample on how to do this?
I tried Creating 2 MainWindows, but the Display property is only Get.
Then furthermore i think i also should create an render context? or is this all handles internaly.
Currently im trying to get the openGL integration to work with just pure noesis classes.
This is what i got so far:
All i see is a black window, and with msi afterburner i see 2 "stat" overlays. but not the xaml....
Is there an quick sample on how to do this?
I tried Creating 2 MainWindows, but the Display property is only Get.
Then furthermore i think i also should create an render context? or is this all handles internaly.
Currently im trying to get the openGL integration to work with just pure noesis classes.
This is what i got so far:
Code: Select all
namespace HelloWorld
{
public class Apper
{
static TimeSpan start = TimeSpan.FromTicks(DateTime.Now.Ticks);
static View _view = null;
static RenderContextD3D11 context = null;
[STAThread]
static void Main()
{
//App app = new App();
// app.Uri = "App.xaml";
// app.Run();
Noesis.Log.SetLogCallback((level, channel, message) =>
{
if (channel == "")
{
// [TRACE] [DEBUG] [INFO] [WARNING] [ERROR]
string[] prefixes = new string[] { "T", "D", "I", "W", "E" };
string prefix = (int)level < prefixes.Length ? prefixes[(int)level] : " ";
Console.WriteLine("[NOESIS/" + prefix + "] " + message);
}
});
Noesis.GUI.Init();
Win32Display disp = new Win32Display();
context = new RenderContextD3D11();
// context.SetWindow(disp.NativeWindow);
context.Init(disp.NativeHandle, disp.NativeWindow, 1, false, false);
// window.Init(disp, context, 1, false);
_view = GUI.CreateView((Noesis.Grid)Noesis.GUI.ParseXaml(@"
<Grid xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation"">
<Grid.Background>
<LinearGradientBrush StartPoint=""0,0"" EndPoint=""0,1"">
<GradientStop Offset=""0"" Color=""#FF123F61""/>
<GradientStop Offset=""0.6"" Color=""#FF0E4B79""/>
<GradientStop Offset=""0.7"" Color=""#FF106097""/>
</LinearGradientBrush>
</Grid.Background>
<Viewbox>
<StackPanel Margin=""50"">
<Button Content=""Hello World!"" Margin=""0,30,0,0""/>
<Rectangle Height=""5"" Margin=""-10,20,-10,0"">
<Rectangle.Fill>
<RadialGradientBrush>
<GradientStop Offset=""0"" Color=""#40000000""/>
<GradientStop Offset=""1"" Color=""#00000000""/>
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>
</StackPanel>
</Viewbox>
</Grid>"));
_view.Renderer.Init(context.Device);
_view.SetSize(1920, 1080);
_view.Activate();
disp.Show();
disp.Render += new RenderEventHandler(Rndr);
disp.EnterMessageLoop(false);
}
private static void Rndr(Display disp)
{
double time = TimeSpan.FromTicks(DateTime.Now.Ticks).TotalSeconds - start.TotalSeconds;
context.BeginRender();
_view.Update(TimeSpan.FromTicks(DateTime.Now.Ticks).TotalSeconds);
_view.Renderer.UpdateRenderTree();
_view.Renderer.RenderOffscreen();
_view.Renderer.Render();
context.EndRender();
context.Swap();
}
}
}
Re: Two Instances of the same App class
Our application layer is just he minimum code for our samples. We tried to be as simple as possible to improve readability of this layer.
My recommendation, avoid the App layer and just create everything on top of the Core layer as we are doing in the GLUT sample.
Even if you are using two windows, you want the same rendercontext. I will find time later to give you a better explanation.
My recommendation, avoid the App layer and just create everything on top of the Core layer as we are doing in the GLUT sample.
Even if you are using two windows, you want the same rendercontext. I will find time later to give you a better explanation.
-
sfernandez
Site Admin
- Posts: 3154
- Joined:
Re: Two Instances of the same App class
You can only have 1 application, but you don't need more. Your own application class can handle multiple windows (base Application class only provides you the MainWindow) by having a List of opened windows.
If you use our application framework you will need a Display and a RenderContext for each Window, and they have to run in separate threads to have their own message/update loop.
But if you have your own windowing system (as you can see in our integration sample, not using the application framework) you can handle everything in a single thread with a single RenderDevice that will be shared across all the Views (one or more for each window).
If you use our application framework you will need a Display and a RenderContext for each Window, and they have to run in separate threads to have their own message/update loop.
But if you have your own windowing system (as you can see in our integration sample, not using the application framework) you can handle everything in a single thread with a single RenderDevice that will be shared across all the Views (one or more for each window).
-
sfernandez
Site Admin
- Posts: 3154
- Joined:
Re: Two Instances of the same App class
Some pseudo code:
Code: Select all
namespace MultiWindow
{
internal static class Program
{
[STAThread]
private static void Main()
{
Noesis.GUI.Init();
// ... create SO windows (window1, window2)
// ... create device context
Noesis.RenderDeviceD3D11 device = new Noesis.RenderDeviceD3D11(context.NativePointer);
Noesis.UserControl xaml1 = Noesis.GUI.LoadXaml("Window1.xaml");
Noesis.View view1 = Noesis.GUI.CreateView(xaml1);
view1.Renderer.Init(device);
view1.SetSize(window1.Width, window1.Height);
Noesis.UserControl xaml2 = Noesis.GUI.LoadXaml("Window2.xaml");
Noesis.View view2 = Noesis.GUI.CreateView(xaml2);
view2.Renderer.Init(device);
view2.SetSize(window2.Width, window2.Height);
//...
// Render loop
while (running)
{
view1.Update(totalSeconds);
view2.Update(totalSeconds);
view1.Renderer.UpdateRenderTree();
view2.Renderer.UpdateRenderTree();
view1.Renderer.RenderOffscreen();
view2.Renderer.RenderOffscreen();
// Set render buffers and clear each window...
view1.Renderer.Render();
view2.Renderer.Render();
// Swap each window...
}
}
}
}
Re: Two Instances of the same App class
So have been fiddling around and went for the:
And use it like this:
I get a lot of errors reading like:
Cus im creating separate instances of MainWindow wich loads .xaml using: GUI.LoadComponent(this, "MainWindow.xaml");
Wich should return an new instance of that file?....
If you want i can make a small compilable example to check out?
way like this:If you use our application framework you will need a Display and a RenderContext for each Window, and they have to run in separate threads to have their own message/update loop.
Code: Select all
public class AppDisplay
{
DateTime start = DateTime.Now;
Display _display = null;
Window _window = null;
RenderContext _context = null;
Thread RenderThread = null;
public AppDisplay()
{
}
public AppDisplay(Display display, Window window, RenderContext context)
{
_window = window;
_display = display;
_display.SetResizeMode(ResizeMode.CanResize);
_context = context;
_context.Init(_display.NativeHandle, _display.NativeWindow, 1, true, false);
_window.Init(display, context, 1, true);
_display.Show();
RenderThread = new Thread(new ThreadStart(RenderFunction));
RenderThread.Start();
_display.EnterMessageLoop(false);
RenderThread.Abort();
RenderThread.Join();
}
private void RenderFunction()
{
while (true)
{
_window.Render((DateTime.Now - start).TotalSeconds);
}
}
}
Code: Select all
static void Main()
{
GUI.Init();
GUI.SetXamlProvider(new EmbeddedXamlProvider(System.Reflection.Assembly.GetCallingAssembly(),"Slidecrew"));
Thread T = new Thread(new ParameterizedThreadStart(SecondWindow));
T.Start();
AppDisplay WindowOne = new AppDisplay(new Win32Display(), new MainWindow(), new RenderContextD3D11());
T.Join();
}
static void SecondWindow(object sender)
{
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
AppDisplay WindowTwo = new AppDisplay(new Win32Display(),new MainWindow(), new RenderContextD3D11());
}
Obviously its an threading issue, but why?The calling thread (17724) cannot access this object (.?AVView@Noesis@@) because a different thread owns it (14176)
Cus im creating separate instances of MainWindow wich loads .xaml using: GUI.LoadComponent(this, "MainWindow.xaml");
Wich should return an new instance of that file?....
If you want i can make a small compilable example to check out?
-
sfernandez
Site Admin
- Posts: 3154
- Joined:
Re: Two Instances of the same App class
Those threading errors are because you are creating the Window in one thread and updating it in another thread.
You should do all the creation code inside the thread that will update the window:
You should do all the creation code inside the thread that will update the window:
Code: Select all
RenderThread = new Thread(new ThreadStart(WindowProc));
RenderThread.Start();
...
private void WindowProc()
{
_display = new Win32Display();
_display.SetResizeMode(ResizeMode.CanResize);
_context = new RenderContextD3D11();
_context.Init(_display.NativeHandle, _display.NativeWindow, 1, true, false);
_window = new MainWindow();
_window.Init(display, context, 1, true);
DateTime startTime = DateTime.Now;
_display.Render += (d) =>
{
_window.Render((DateTime.Now - startTime).TotalSeconds);
};
_display.Show();
_display.EnterMessageLoop(false);
}
Re: Two Instances of the same App class
Alright, so i've set it up like you said.
and in Main()
This runs ok when only one thread is fired.
When the second thread is called into the mix, it crashed all over the place.
Sometimes it crashes at start-up, other times only one window is rendered, some other time i get an MemoryAccessViolation at:
So i opened an example, Application tutorial to be exact.
Implemented the change i did in my own project and got the same results.
I understand the threading issue in the Render call.
But since we basically, or so seems it, create a new instance on MainWindow in every thread for every window i don't know why it crashes even in the example project.
Here is a link to my dropbox with the project i edited.
https://www.dropbox.com/s/z87argdm2td82 ... l.rar?dl=0
Code: Select all
static void FirstWindow()
{
Window _window = new MainWindow();
Display _display = new Win32Display();
_display.SetResizeMode(ResizeMode.CanResize);
RenderContext _context = new RenderContextD3D11();
_context.Init(_display.NativeHandle, _display.NativeWindow, 1, true, false);
_window.Init(_display, _context, 1, true);
DateTime start = DateTime.Now;
_display.Render += (s) =>
{
_window.Render((DateTime.Now - start).TotalSeconds);
};
_display.Show();
_display.EnterMessageLoop(false);
}
Code: Select all
GUI.Init();
GUI.SetXamlProvider(new EmbeddedXamlProvider(System.Reflection.Assembly.GetExecutingAssembly(), "RssReader"));
Thread T = new Thread(new ThreadStart(FirstWindow));
T.Start();
// Thread T2 = new Thread(new ThreadStart(FirstWindow));
// T2.Start();
T.Join();
// T2.Join();
When the second thread is called into the mix, it crashed all over the place.
Sometimes it crashes at start-up, other times only one window is rendered, some other time i get an MemoryAccessViolation at:
Code: Select all
protected override bool ConnectEvent(object source, string eventName, string handlerName)
{
if (eventName == "Click" && handlerName == "OnPrevClicked")
{
((Button)source).Click += OnPrevClicked;
return true;
}
if (eventName == "Click" && handlerName == "OnNextClicked")
{
((Button)source).Click += OnNextClicked;
return true;
}
return false;
}
Implemented the change i did in my own project and got the same results.
I understand the threading issue in the Render call.
But since we basically, or so seems it, create a new instance on MainWindow in every thread for every window i don't know why it crashes even in the example project.
Here is a link to my dropbox with the project i edited.
https://www.dropbox.com/s/z87argdm2td82 ... l.rar?dl=0
-
sfernandez
Site Admin
- Posts: 3154
- Joined:
Re: Two Instances of the same App class
Could you please open a ticket in our bugtracker, it seems there are some parts in our code that are not thread-safe and are causing those crashes.
While that is being addressed, have you tried the other approach I suggested, by using a single RenderDevice shared among several Views (in the same thread)?
While that is being addressed, have you tried the other approach I suggested, by using a single RenderDevice shared among several Views (in the same thread)?
Who is online
Users browsing this forum: Bing [Bot] and 1 guest