Multiple windows and views - help me understand Direct3D11 a little better?

Started by
7 comments, last by NathanRidley 9 years, 6 months ago

I'm learning Direct3D11 by diving in the deep end. I've done some basic stuff, like rendering some animated cubes and so forth, but I'm trying to build a simple game engine that (a) I can use for further learning projects and simple games and (b) to help me understand Direct3D and related topics a little better. For what it's worth, I'm doing this with C# and SharpDX. System architecture and design is not new to me, as I'm coming from a long history of business and web app development, but in the context of game development, I have a lot to learn.

The task I've set for myself is to learn how to abstract my rendering in such a way that I could hypothetically have more than one window open, each with its own independent renderer, and for each window, have multiple "views", so that hypothetically I could layer several rendered scenes over the top of each other (think of a tabbed, tiled or cascaded set of views within the same parent window), and each view could have either2D or 3D information (or both?) Examples of 2D information would be 2D HUD information or a text console for inputting commands. Also, I'd like to be able to take any of my views and render them as a texture in an underlying 3D scene (such as on a CCTV screen or computer terminal).

The questions I have are:

* Do I need a separate device per view that I'm rendering? Or only per window? Or do I only need one device for all windows? (I'm guessing: one device in total)

* Do I need a separate swap chain per view? (I'm guessing I need one per view because each represents a flat rendered end result)

* If I only need one device, should I still be creating one device context per view?
* What is the relationship between the device context and the swap chain?

* Should I be rendering each view to a texture and then arranging the views in a "flat" 3D scene that simply defines the positions of each view?

One semi-unrelated question: is there any reason not to use Direct2D for views containing only 2D content, so that I can easily draw 2D shapes and use DirectWrite to write text onto the screen? I ask because I see a lot of tutorials using spites for drawing text and it seems an inferior way to render text.

EDIT:

I'm going to augment my questions above with a sample scenario:

  • I have two separate windows/forms.
  • The first window has a rotating 3D model and a bit of 2D UI at the bottom for displaying info about the model and changing some simple options about how it is displayed.
  • The second window has the following:
    • A 3D scene which includes the model in the first window and a model of computer on which is displayed a live rendering of a CCTV camera at a different location in the world.
    • A variety of 2D user interface elements, including:
      • A small console and chat message window
      • Some information about current incomplete objectives
      • A small live-updating orthographically-projected 3D map of the area
      • A small view showing a 3D model of the player's head
      • A rectangular view showing a camera view of a small drone which scouts the area ahead of the player

All in all I count a need for the following render targets maybe:

  • One for the first window
  • One for the 3D scene in the second window
  • One for the CCTV image on the computer terminal model
  • One for the player's head view in the HUD
  • One for the orthographic map view in the HUD
  • One for the drone camera view in the HUD
  • One for the additional 2D elements (console/objectives) in the HUD
  • One to layer all of the elements in the second window together

I just made all of that up to try and describe a scenario which would give me everything I need to understand the building blocks I need for my purposes. How many of each thing do I need? What DirectX objects need to be shared and rendered to independently and in what order? What owns what? Is my assumed approach correct? Or is it overcomplicated?

I can kind of fudge through this and sort of figure it out myself, but having no mentors or colleagues from whom I can extract some expert knowledge, I will have no idea if I'm doing things correctly or if my understanding of what I am doing is correct. Any help from you fine people is most appreciated :)

Advertisement

* Do I need a separate device per view that I'm rendering? Or only per window? Or do I only need one device for all windows? (I'm guessing: one device in total)

I've never used multiple windows, but I think you can use the same device for all windows. However you need to create a separate swap chain for each window. More info here

* Do I need a separate swap chain per view? (I'm guessing I need one per view because each represents a flat rendered end result)

You only need one swap chain per window (multiple views inside the same window share the same swap chain)


* If I only need one device, should I still be creating one device context per view?

Not necessarily. Multiple device contexts are used to generate command lists, etc.


* What is the relationship between the device context and the swap chain?

From the docs:

A device context contains the circumstance or setting in which a device is used. More specifically, a device context is used to set pipeline state and generate rendering commands using the resources owned by a device.

So I don't think there is any special relationship.


* Should I be rendering each view to a texture and then arranging the views in a "flat" 3D scene that simply defines the positions of each view?

Unless you're doing some special composition, you can draw directly to each swap chain back buffer (render target), and use multiple viewports to arrange the views.

Overview:

-Create a device (and immediate context).

-Create one swap chain for each window (using the appropriate descs)

-For each window:

-Set window's swap chain's backbuffer as render target

-For each view inside window:

-Set the viewport desc

-Render view contents

If you need to do a composition of the views more complex than simple viewports then create offscreen render targets and render to those instead, and then render them to the backbuffer.

@TiagoCosta thanks for the info, that's helpful.

TiagoCosta outlines a good approach. I'm not familiar with SharpDX so this may be bogus advice. But, with regard to a console (text with I/O), perhaps a better way to incorporate that (for a beginner) is to start the project as a console app, and then create your D3D11 device/contexts/swapchains. You can use std::cout and std::cin (or printf, etc.) for simple formatted text I/O.

Please don't PM me with questions. Post them in the forums for everyone's benefit, and I can embarrass myself publicly.

You don't forget how to play when you grow old; you grow old when you forget how to play.

If you want to check out a sample program that demonstrates using multiple windows, you can check out the 'ViewFromTheWindow' sample in Hieroglyph 3. It renders the scene to a single off screen render target, then renders sub areas of the window to each swap chain of many Win32 windows. If you have any questions about how something is done in particular, I would be happy to answer them!

@Jason Z - thanks, I'll check it out!

Jason, on the Hieroglyph main page, there is a screenshot of a single window with three different views of the same grey cube. Which demo is that screenshot from?

That is from the MFC sample. You have to open a separate solution file for the MFC stuff... try out Hieroglyph3_Desktop_MFC.sln. That should get you what you are looking for (although it requires one of the paid version of Visual Studio to compile MFC related projects).

Thanks. I have VS2013 Pro, so all good.

This topic is closed to new replies.

Advertisement