Rendering multiple game class instances in avalonia form

Hi there,

I am using two instances of a Game class implementation in an Avalonia context.
The way this works is that i manually run Update and Draw methods, and after drawing i copy the backbuffer content to a bitmap that is displayed in Avalonia like so:

GraphicsDevice.GetBackBufferData(bufferData, 0, bitmapBufferLength);
Marshal.Copy(bufferData, 0, bitmapAddress, bitmapBufferLength);

In the Game’s constructor i run the following to setup rendering:

var graphicsManager = new GraphicsDeviceManager(this)
{
    GraphicsProfile = GraphicsProfile.HiDef
};
graphicsManager.ApplyChanges();

This works great for rendering two independent instances side by side.

A problem arises when they are not of the same size.

It seems like the backbuffer that the left game is rendering to, actually has the size of the right one.
The right game is the one that is instantiated last.
GraphicsDevice.Viewport.Bounds.Size is of the correct size for each instance.

Is there a way to fix this?

More info:

When changing / setting the size, this is how i do it.

GraphicsDevice.Viewport = new Viewport(0, 0, newWidth, newHeight);
presentationParameters.BackBufferWidth = newWidth;
presentationParameters.BackBufferHeight = newHeight;
GraphicsDevice.Reset(presentationParameters);

Thanks

It might be worth asking if there’s a reason the two instances should ever be a different size from one another. Also from what I’m reading, GetBackBufferData might be a bit slow for a main rendering method. That being said, you might try out a function like this. I’m not an expert on this so I apologize if it’s irrelevant, but it worked for me when I had a similar resizing issue:

protected override void Initialize() {
	...
	Window.ClientSizeChanged += Window_ClientSizeChanged;
} 
private void Window_ClientSizeChanged(object sender, System.EventArgs e) {
	Window.ClientSizeChanged -= Window_ClientSizeChanged;

	int w = Window.ClientBounds.Width;
	int h = Window.ClientBounds.Height;

	_graphics.PreferredBackBufferWidth = w;
	_graphics.PreferredBackBufferHeight = h;

	var viewportadapter = new BoxingViewportAdapter(Window, GraphicsDevice, w, h);
	_camera = new OrthographicCamera(viewportadapter);

	_graphics.ApplyChanges();
	Window.ClientSizeChanged += Window_ClientSizeChanged;
}

I can’t find the original source for this function, but there’s more information if you search for CliendSizeChanged. I use this in combination with Monogame.Extended BoxingViewportAdapter and OrthographicCamera, but you might not need that.

Good point, some background: It’s an avalonia application (similar to WPF) in which I create and destroy game instances that provide 3D rendering for displaying 3d models. This game controls/widgets are placed throughout the application, some of them have to be large and others small. Sometimes spanning the whole screen and sometimes just like for example a mini-window in the corner.

I am aware of that and agree. Once there is a stable way in Avalonia to provide a GL surface to draw on and me figuring out a way to use that surface in Monogame as render surface I’m planning to switch to that. For now, however it’s not a big issue, as I’m not rendering at a fixed target fps. Meaning I am only rendering “on demand”, for example when rotating a 3d model.

I had partial success in the meantime. With some trial and error I figured out that the backbuffer seems to always have the size of the largest game instance. So in my resize method I resize presentationParameters.BackBufferWidth and Height to a static maximum of all the games. Then, when copying the backbuffer to a bitmap I use a Rect to copy the content:
GraphicsDevice.GetBackBufferData(viewportSizeRect, bufferData, 0, bufferLength);
This almost fixes my problem. Rendering works fine. But since that backbuffer now always has the size of the largest game instance, the instances also render in that size obviously, meaning lots of rendering of unneeded pixels and the center of the viewport is also off.

Now I’m gonna try to render to rendertargets of the correct size and see how that goes.

Update

Managed to solve it.

When setting the size for a game instance, presentationParameters.BackBufferWidth and presentationParameters.BackBufferHeight has to be the largest dimension of all the instances (In case of the screenshot it would be 640,360). After settings the size, call GraphicsDevice.Reset(presentationParameters);

When rendering an instance, I’m setting GraphicsDevice.Viewport to my desired rendering size
(for example 150,350 for bottom left).

After rendering, when copying to bitmap, I copy only the area of the specified viewport.
GraphicsDevice.GetBackBufferData(renderViewportRect, bufferData, 0, bufferLength);

When doing all this, it behaves exactly how i wanted.

1 Like