Developing on a Mac with El Capitan and Xcode 7.2:
If I have a project with one Window, that has a SKScene for SpriteKit, then I will get the needed 60 fps and everything works as expected. But as soon as I define a second window with an SKScene in it, then I will have only 30 fps in my first window, even if the second window is not used at all and not even a Referencing Outlet for the second window is defined. The second window only exists in MainMenu.xib and is not used at all.
I need four Sprite Kit Windows with one scene in it for my projects, so I get a very poor updating performance. Programs work fine with Yosemite but as soon as I run them in El Capitan this problem occurs.
I would be very lucky for any suggestions. Problem is the same in older Xcode versions and the newest one (7.2). I have compiled final programs that are a few month old and ones which are new, all have the same issue, so I think it has nothing to do with Xcode but with the El Capitan Mac OS.
When setting the SKView into the "Core Animation Layer", in Xcode "MainMenu.xib", dialog page "View Effects Inspector" and check all the SKViews to set into "Core Animation Layer", then everything is fine for small Animations. As soon as the 60 fps cannot reched, because I have too much objects in the scene, the View is only updated once a second and this looks horrible. With Yosemite, the Scene was updates 30 times a second, which is really enough for my purpose.
Because this does not depend on the Xcode version, it seems that Apple has changed something to "optimize" the screen redrawing and if it is not possible to make 60 fps, then the drawing is not made with 30 fps or whatever is possible, but only with 1 fps. I also tried "Can Draw Concurrently" on the "Attributes Inspector" page but this makes no difference at all. I use a new 8-core Mac Pro with D700 graphic. So this should not be the reason.
I also tried to limit the screen updates with myView.frameInterval = 30 from which I expected that only two updates per second are made. But this command seems to do absolutely nothing. The myView.allowsTransparency = ... produces an exception, regardless if true or false. myView.asynchronous = true makes the updates as smooth as in Yosemite. But it needs 30 seconds or so to pull down a menu (with a big node count, of course) and you cannot work with the program. This is - in the result - not identically to the "Can Draw Concurrently" option in Xcode.
Is it possible to change to the Yosemite rendering, because all described options seem to be not optimal.
Any ideas how to handle a large node-count or restrict the update-rate so that the program can be quit comfortably by menu?
I have now developed a workaround. With some additional lines of code I get the same results in Yosemite and in El Capitan. The Performance in El Capitan is about twice as quick than in Yosemite.
"SKView" must be set into the "Core Animation Layer" in "MainMenu.xib" or you will see no Sprite at all
You can define as much "SKViews" as you want. I will only show one as an example
The Definition of the Views in the AppDelegate Class needs some more code:
class AppDelegate: NSObject, NSApplicationDelegate
{
#IBOutlet var myWindow1: NSWindow!
#IBOutlet var mySKView1: SKView!
// other functions here as needed
func applicationDidFinishLaunching (aNotification: NSNotification)
{
let scene_size = CGSizeMake(1280.0, 800.0) // For example 1280x800 Pixel
let myScene1 = myScene1Class(size: scene_size)
mySKView1.scaleMode = .ResizeFill // works for me better than ".AspectFill"
mySKView1.ignoresSiblingOrder = false
mySKView1.asynchronous = true // This makes the difference in smooth Display-Speed
mySKView1.showsFPS = false
mySKView1.showsNodeCount = false
mySKView1.presentScene(myScene1)
mySKView1.paused = true // This makes the difference in Event-Handling
// Start your Main-Program-Process here
}
}
The "Can Draw Concurrently" Option in "MainMenu.xib" can be set or not, it makes no difference
Screen Updates start automatically when adding Sprites and showing the windows. When I present the scene in "AppDelegate", no sprite is in it. This is done by my automatic initialization for every program.
If you want, you can play with the two options "mySKView1.asynchronous = true" and "mySKView1.paused = true". If you set one to "false", you can see the problems. Note, that you must define much nodes to make this problem visible at all, because if your Mac reaches 60 fps because you have less nodes, than everything seems fine regardless which option you choose. And you will nedd two "SKViews" or more, in one or more Windows.
Tested with 130000 (130k!) nodes, making about 20 fps. Tested with 260000 (260k!) nodes, making about 10 fps. Three other "SKViews" defined with no sprites to test the whole thing.
I just stumbled on this little annoying behavior, while adding full screen support on a sample program.
Creating a full screen window works, but as soon as I move any window (from another application) on the output that contains my fullscreen window, it automatically switches back to windowed.
Is there any way to prevent this behavior (so full screen window do not go back to windowed)?
As a reference, this is a small standalone example (so problem can be replicated easily).
Also if that is useful, I'm running on Windows 8.1.
I already tried to change WindowAssociationFlags and SwapChainFlags, both with no success, same as using FlipSequential instead of Discard
SharpDX.DXGI.Factory2 factory = new SharpDX.DXGI.Factory2();
SharpDX.DXGI.Adapter adapter = factory.GetAdapter(0);
var renderForm1 = new RenderForm("Form 1");
factory.MakeWindowAssociation(renderForm1.Handle, SharpDX.DXGI.WindowAssociationFlags.IgnoreAll);
Device device = new Device(adapter, DeviceCreationFlags.BgraSupport);
SharpDX.DXGI.SwapChainDescription sd = new SharpDX.DXGI.SwapChainDescription()
{
BufferCount = 2,
ModeDescription = new SharpDX.DXGI.ModeDescription(0, 0, new SharpDX.DXGI.Rational(50, 1), SharpDX.DXGI.Format.R8G8B8A8_UNorm),
IsWindowed = true,
OutputHandle = renderForm1.Handle,
SampleDescription = new SharpDX.DXGI.SampleDescription(1,0),
SwapEffect = SharpDX.DXGI.SwapEffect.Discard,
Usage = SharpDX.DXGI.Usage.RenderTargetOutput,
Flags = SharpDX.DXGI.SwapChainFlags.None
};
var swapChain1 = new SharpDX.DXGI.SwapChain(factory, device, sd);
renderForm1.Left = 1922; //Just hardcoded here to move window to second screen
renderForm1.Width = 1920;
renderForm1.Height = 1080;
renderForm1.FormBorderStyle = FormBorderStyle.None;
swapChain1.SetFullscreenState(true, null);
swapChain1.ResizeBuffers(2, 1920, 1080, SharpDX.DXGI.Format.R8G8B8A8_UNorm, SharpDX.DXGI.SwapChainFlags.AllowModeSwitch);
var resource = Texture2D.FromSwapChain<Texture2D>(swapChain1, 0);
var renderView = new RenderTargetView(device, resource);
RenderLoop.Run(renderForm1, () =>
{
device.ImmediateContext.ClearRenderTargetView(renderView, new SharpDX.Color4(1, 0, 0, 1));
swapChain1.Present(1, SharpDX.DXGI.PresentFlags.None);
});
Edit:
I also tried a c++ sample (just taken DirectX11 basic tutorial from Microsoft and added full screen switch), this leads to the same behavior, so this is not a SharpDX specific issue.
I looked at the message loop, and once this occurs, first fullscreen mode is changed back to windowed, and I receive a WM_DISPLAYCHANGE message).
This sounds like expected behavior. If you have a full screen 'exclusive' mode swapchain and the associated window loses focus, the system automatically switches the application out of full screen mode back to windowed mode by design.
With a single monitor, it mostly works as long as you have your applications' window sized to fill the display. Users can't use the mouse to change focus of your window, and it requires something like ALT+TAB to switch focus.
With multiple monitors, it's a real problem. If you click on another window on another display, your app loses focus and the full screen mode is again switched out. There are also limitations that prevent you from setting full screen 'exclusive' mode on more than one monitor.
Furthermore, on Windows Vista or later the notion of 'exclusive' mode is an illusion: the GPU is always shared anyhow. The 'focus' application gets priority whether it is a full screen or a windowed swap chain.
For a Windows desktop apps you have three choices for a full screen style experience:
Use the traditional full screen 'exclusive' mode with a window sized to fill the display, along with setting the display mode which may not be what the user has set for Windows generally. Here you have IsWindowed = false.
You set the window size to fill the full display (i.e. maximized). You can use windows styles to ensure that the window has no frame which results in a full screen style experience (WS_POPUP). Here you have IsWindowed = true, and you should be sure to set DXGI_MWA_NO_ALT_ENTER to avoid allowing DXGI to try to take you to use the 1 case.
You can do the same as 2 with IsWindowed = true and the borderless window sized to match the screen, but you change the display mode to something other than the system default. This is commonly referred to as 'fake full screen'. The display mode gets changed back whenever you exit the application.
1 has all has all the problems with multi-tasking and focus we just described. 2 and 3 allow system notifications and other pop-ups to show up over the game and not force a mode switch. 2 and 3 also work a lot better in multi-monitor setups where you can play your game on one display and use other apps on another display. For multi-tasking most people to prefer a classic window style with a frame border.
Windows Store UWP notions of full screen mode is basically like 2 above. You can't change the display mode with a UWP.
Debugging a full-screen setup is quite challenging. With multiple monitors, 2 and 3 can work with your debugger on the other screen. For true full-screen exclusive mode, really the only option is to use remote debugging from another PC.
Another issue with 1 and 3 is that you can set the display mode to something that won't sync with the display leaving the user with a system with no UI and no way to exit. Ideally with the right driver setup, the DXGI enumeration list does not contain unsupported modes, but it is something to be aware of. For this reason, your UI for selecting a display mode should have a timeout and you should make sure there's a reasonable way to abort the application with the keyboard if the display mode fails to sync at some point in the future. Using the existing display mode as we do in 2 above is always the safest option.
The main reason to use full screen exclusive mode (1) above is to try to get 'flip' rather than 'blit' of the backbuffer/frontbuffer. For most modern systems, this is a negligible performance difference. The other reason to go through the pain of using it is for SLI/Crossfire multi-GPU rendering going to a single display. There are a number of other optimizations required to really make that scenario work, and it's pretty niche. You should seek out the vendor optimization guides for the details.
Most modern games default to using fake full screen rather than full screen 'exclusive' mode. They offer the ability to use a true windowed mode as many users want to be able to multi-task while playing (like looking up hints online, use IM or external voice chat, etc.). AAA Windows desktop games that want to support tuned high-performance gaming for SLI/Crossfire will offer a full screen 'exclusive' mode, but this requires some work to get working fully and entails more work than just some DXGI code.
See DXGI Overview and DirectX Graphics Infrastructure (DXGI): Best Practices
After several attempts and trials, here are the different workarounds I used, none are ideal but all are somehow better than getting a mode change.
1/Force cursor in the middle of the full screen window, with a keyboard shortcut to get control again.
This is not ideal since we can't really do anything while our part is running, but at least prevents accidental "disaster click". It does not prevent keyboard interaction either.
2/Use a DX9 renderer with a shared texture.
DX9 Swapchain can have it's parent window set to desktop, so it does not lose focus when moving to something else.
Having a focused window on top show little borders visible while moving it, but that is a bit more acceptable than losing everything.
Not future proof but guess will stay actual for a while.
3/Stay on Windows 7 and Disable DWM Service:
Doesn't work in Windows 8 anymore, but in my use case since most media companies I work for are still on Windows 7, it stays a valid solution for at least 5 to 10 years.
4/Force the DX11 Window on foreground
Basically continuously call SetForegroundWindow to avoid another window to take focus.
5/Prevent mode switch at presentation level.
Since on my application I got access to when presentation occurs, I use the following routine (before to call Present)
-Get Foreground window handle (using GetForegroundWindow), If Foreground handle is our fullscreen window, just call Present as usual.
If Foreground handle is not our fullscreen window, perform the following. Please note that visibility check is not needed, since even an invisible overlapping window will also cause a full screen loss! (seriously, this is just so bad...)
-Verify if our foreground window overlaps with the monitor:
Call GetWindowRect to get the bounds, and perform intersection with the monitor location.
Alternatively, call Present on the swapchain with the DXGI_PRESENT_TEST flag. If a window is overlapping, the Present call will return DXGI_STATUS_OCCLUDED
If a window overlaps, either Hide it or move it in another monitor (anywhere so it does not overlap):
ShowWindow and SetWindowPos are aperfect fit for this task.
Repeat that Test present call in a loop until it doesn't return the occluded status (this is important, since windows might not have processed the messages immediately); Once occluded flag is gone, call Present as usual.
There is a way to prevent DXGI from automatically leaving fullscreen mode when your process loses focus, though I must warn, it is a bit hackish.
Basically DXGI calls GetForegroundWindow() and checks if the returned window is yours.
If not, it switches off the fullscreen mode.
So if you hook/redirect this function to your own replacement, that always returns your window (regardless of whether it has the focus or not) - that will get the job done.
Here is a simple code that does that. It is for 64-bit mode and assumes that you NEVER need to call the real function, so it simply overwrites its start with a jump instruction to your replacement:
HWND WINAPI get_our_window()
{
return our_window;
}
void disable_automatic_leaving_fullscreen_on_lost_focus()
{
// get the address of GetForegroundWindow
char *p = (char *)GetProcAddress(GetModuleHandleA("user32.dll"), "GetForegroundWindow");
// make the function code writable
DWORD old;
VirtualProtect(p, 12, PAGE_EXECUTE_WRITECOPY, &old);
// overwrite the function start:
// mov rax, <address_of_GetOurWindow>
p[0] = 0x48, p[1] = 0xB8, *(void **)(p + 2) = (void *)get_our_window;
// jmp rax
p[10] = 0xFF, p[11] = 0xE0;
}
This code is only for demonstration.
If you need to retain the ability to call the true function, then you have to hook it in a different, more complicated way, but this is a separate subject
I have a fullscreen xna game that is supposed to run on a secondary screen if available. It all works fine getting it into fullscreen mode on the secondary screen. However, when i focus a window on the primary screen, the fullscreen application on the secondary screen unfocusses. AlwaysOnTop is not an option here, as this is not a form, but a fullscreen application. How would i go around and tackle this problem?
Full screen is usually supposed to only work if it has focus I think. You could always make the application a border less window that is the size of the monitor. So it is still "full screen" without having to have focus. I wrote some code a little while ago to do this and it really isn't that hard to do let me see if i can find it..
WindowPoint = Window.Position;
WindowPoint.X = System.Windows.Forms.Screen.AllScreens[0].WorkingArea.Location.X;
WindowPoint.Y = System.Windows.Forms.Screen.AllScreens[0].WorkingArea.Location.Y;
Window.Position = WindowPoint;
Window.IsBorderless = true;
graphics.PreferredBackBufferWidth = System.Windows.Forms.Screen.AllScreens[0].WorkingArea.Width;
graphics.PreferredBackBufferHeight = System.Windows.Forms.Screen.AllScreens[0].WorkingArea.Height;
graphics.IsFullScreen = false;
graphics.ApplyChanges();
I am sure that there is a better way to do this. I'm still learning myself but this gets the job done. On my computer AllScreens[0] is the second monitor and [1] is the primary monitor. Let me know if this helps. Good luck :)
I am trying to build a nice GUI with some glass effect in the client area.
So I implemented it as described here.
I was successful and have nice frame fully of glass, but only as long the window is not maximized. When I maximize the window it is only black :-(
With some googleing and experimenting I figured out, that when I invalidate the the window in response to a WM_WINDOWPOSCHANGING like this:
case WM_WINDOWPOSCHANGING: {
WINDOWPOS* pWindowPos = (WINDOWPOS*)lParam;
if (pWindowPos->flags & SWP_FRAMECHANGED) {
InvalidateRect(hWnd, NULL, TRUE);
}
}
I get the glass effect also when I maximize the window.
The odd thing now is that this is only working if I double click on the title bar or this the maximize button on the right top corner of the window. But if I move the window to the top of the screen to let it snap there to maximize the window (Aero Snap) the window turns just black.
Does anyone has a idea how this is done right?
(I am developing under Windows 7 64 bit.)
Edit:
I should also mention that I want to remove the standard title bar, I doing so by returning 0 in response to a WM_NCCALCSIZE message. Without this everything is working fine.
Edit:
A test on another system, which is basically the same was successful. The only notable difference is that there is another graphics card, a AMD Radeon HD 4300 instead of a AMD Radeon HD 5870. Could this be a issue with the driver of the graphics card?
My purpose is to size a window to a width/height greater than the size of my physical screen programmatically under Win32. How can I do this?
On my systems it seems the maximum size of a given window is bound by the size of my screen whether programmatically or whether sizing manually by dragging the sizing cursor.
I have tried programmatically with SetWindowPos() and MoveWindow() and both cap the size of the target window. Oddly I know some people do not have this 'cap' so I wonder whether this is perhaps due to some OS setting (registry). Does anyone know something about this? Or perhaps some way to workaround it?
// Edit: new developments
I am testing on Windows XP and Windows 7. The graphics cards I'm using are a NVIDIA Quadro NVS 290 (256MB) and a Geforce 9800GT (1GB). After further investigation it looks like Windows is intercepting the message and fiddling with the parameters. For example, if you call SetWindowPos to make a target 2000x2000 it will only receive a WM_SIZE for the capped x/y.
Implement a message handler for WM_GETMINMAXINFO to stop Windows from applying the sane default behavior:
case WM_GETMINMAXINFO: {
DefWindowProc(hWnd, message, wParam, lParam);
MINMAXINFO* pmmi = (MINMAXINFO*)lParam;
pmmi->ptMaxTrackSize.x = 2000;
pmmi->ptMaxTrackSize.y = 2000;
return 0;
}
Windows with a thick frame (to allow user resize) are restricted from growing larger than the desktop.
Try SetWindowLong() clearing the THICKFRAME (0x40000) flag.
The following should allow programatic sizing, but the user will lose the ability to resize. If you add the Thickframe back after sizing, the user can resize, but when he does so the window will immediately shrink back to the desktop limited size.
The following is from some csharp code that also removes all borders, caption, etc:
WS style = (WS)GetWindowLong(ptr, GWL_STYLE);
style = style & ~WS.BORDER & ~WS.ThickFrame & ~WS.SYSMENU & ~WS.CAPTION | WS.POPUP;
SetWindowLong(ptr, GWL_STYLE, (int)style);
A good tool to play with window settings is uuSpy.
It's like Microsoft Spy++, but allows you to modify settings like THICKFRAME.
Yes, windows can be larger than the screen (or even the sum of all your monitors). Windows can also be positioned off-screen (which some applications do as a hack to hide while remaining active).
Perhaps the Windows 7 desktop manager is kicking in and trying to "dock" those windows to the edges of your screen for you.
You might try using the slightly lower-level API SetWindowPos, which gives you control over notifications, z-order, and other stuff.
You can get a window to be larger in resolution (and even way way larger) than your screen, using the 'Infinte Screen" software:
http://ynea.futureware.at/cgi-bin/infinite_screen.pl
Here's how to use it:
Download it, run it.
In the Oversize tab, choose the Windows you want to enlarge.
Give it the Width and Height you want. Done!
Just in case you need a large screenshot (that's how I ended up here):
If you want to get a screenshot of the window, you've got a screenshot option in the same Oversize tab. (Because screenshots are normally no bigger than the screen size, even if the window is larger). Another (and better) way to screenshot the window is using Greenshot, as you can save them in .tiff and directly watching the window.