Multiple OpenGL windows on Windows, sharing context - windows

I'm trying to setup multiple OpenGL (3.3) windows on the same program. I've created 2 windows, with the second one having the shared context of the first one (using hglrc[i] = wglCreateContextAttribsARB(hdc[n_windows], hglrc[0], ctxattribs) while the first one has 0 instead of hglrc[0]), with a simple loop like:
for(unsigned i = 0; i < n_windows; ++i)
{
wglMakeCurrent(hdc[i], hglrc[i]);
glClearColor((float)rand() / RAND_MAX, (float)rand() / RAND_MAX, (float)rand() / RAND_MAX, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
SwapBuffers(hdc[i]);
}
However only one window renders, and when I move a window to another screen, the Window that wasn't rendering now renders, and the other one stops rendering.
It's the first time I'm trying to open several OpenGL windows on the same application, with a shared context, so I might be doing something wrong. My code works perfectly with one window, and my old faithful gDEBugger doesn't show any error. Any idea on what I might be doing wrong?

Related

DirectX11 Swapchain and window losing fullscreen status

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

GTK Window Cover Entire Screen

I'm working on a small educational piece of work, I create a window and its supposed to cover the entire monitor. However "special" areas are not being covered as seen in the screnshot at bottom. My window is a solid red with no menu bar scroll bar etc, is there anyway to make this cover the top menu bar and the dock. In my screenshot I am testing on Ubuntu and Mint, this is consistent behavior on Gtk OS's I need to be ablve ot set my window so it covers all things is this possible?
I tried gdk_window_fullscreen but it's not doing anything, not even fullscreen, do you think its because I'm running this function from another thread? How would I know if this function needs to be run from the main thread?
Incomplete coverage on Ubuntu:
Incomplete coverage on Mint:
Code Tried
A frameless window is opened using Firefox code from main thread:
var aEditorDOMWindow = Services.ww.openWindow(null, core.addon.path.content + 'panel.xul', '_blank', 'chrome,width=1,height=1,screenX=0,screenY=0', null);
Now after load of it completes then the GdkWindow* of this window is obtained on the main thread and passed to another thread as a string
The thread now takes the string to GdkWindow* then that to GtkWindow*
var gdkWinPtr = ostypes.TYPE.GdkWindow.ptr(ctypes.UInt64(aHwndStr));
var gtkWinPtr = ostypes.HELPER.gdkWinPtrToGtkWinPtr(gdkWinPtr);
The thread then executes gtk_window_set_keep_above because if there was another app was focused it will focus this guy, and it will keep him on top of existing full screen windows
var rez_topIt = ostypes.API('gtk_window_set_keep_above')(gtkWinPtr, true);
The thread used to then run gtk_window_present but I removed it as I noticed it would crash the app, this was the code:
var rez_focus = ostypes.API('gtk_window_present')(gtkWinPtr);
EXPERIMENTAL STUFF I tried but it didnt work to make the window cover the special UI:
ostypes.API('gdk_window_set_type_hint')(gdkWinPtr, ostypes.CONST.WINDOW_TYPE_HINT_SPLASHSCREEN);
ostypes.API('gtk_window_set_position')(gtkWinPtr, ostypes.CONST.GTK_WIN_POS_NONE);
var geom = ostypes.TYPE.GdkGeometry();
geom.max_width = aOptions.fullWidth;
geom.max_height = aOptions.fullHeight;
var rez_geo = ostypes.API('gtk_window_set_geometry_hints')(gtkWinPtr, null, geom.address(), ostypes.CONST.GDK_HINT_MAX_SIZE);
Now the thread work is done and it goes to main thread. Now the main thread uses firefox javascript to move the window to top left most origin (which i calculated earlier with Gdk calls) and also sets the width and height of this window to that calculated of all the monitors (i did this earlier with other gdk calls)
aEditorDOMWindow.moveTo(collCanMonInfos[0].xTopLeft, collCanMonInfos[0].yTopLeft);
aEditorDOMWindow.resizeTo(collCanMonInfos[0].nWidth, collCanMonInfos[0].nHeight);
This results in the window SOMETIMES covering all monitors, other times just the one it opened on. And it never covers special UI like the taskbar/dock/menubars.
If you can please advise on how to acheive a window that fully covers everything that would be very appreciated, I'm trying to teach some people some stuff and I ran into a mess.
Here is a youtube video of the addon I am making: https://www.youtube.com/watch?v=aJM5NQK67N4
I discontinued using gdk_fullscreen because when it worked intermittently it would not allow the window to expand outside the one monitor.
Panels are usually implemented with struts, and window managers can decide never to allow windows to cover them; that's one of the reasons why the whole idea of "full screen window" was introduced: it gives the window manager a hint that the window that requested to be full screen should cover all other windows; have no decorations; and also cover all eventual "system" components, like panels.

Firemonkey how to implement app drawer-style tab control

I'm going around in circles trying to solve this.
Basically I have a tab control on my Firemonkey android app and can swipe left or right to change tabs and it works fine.
I would like to enhance the swiping so it behaves more like the android app drawer. What I mean by that is if you longtap and slowly slide your finger left or right the screen contents moves left/right with your finger as opposed to what I have now where it only moves a whole screen at a time and not slowly underneath your finger.
A THorzScrollBox is close to the effect I want but it doesn't "snap" onto a single screen but instead can leave your screen half and half on two pages.
Am I making sense here?
I'm using XE8 but I couldn't get it working on earlier versions either!
Many thanks,
Ian.
If someone is interested i just created a new TTabcontrol who enhance the swiping
you can see the code source here
(svn) https://svn.code.sf.net/p/alcinoe/code/
and the demo is here :
(svn) https://svn.code.sf.net/p/alcinoe/code/demos/ALFmxControls
any remark will be welcome :)
i continue also my logic: create a suite of firemonkey control who are very fast to draw, independant of OpenGL and that don't work with the style (i find the style in firemonkey very inefficient and horribly complicated to maintain), so i create this tabcontrol as a descendant of Tcontrol and not as a descendant of TStyleControl.
i think it much (much) more simple to create the title (ie: button) of the tab myself with basic component like trectangle + ttext than updating the so complicated Stylebook for each plateform (ioe, android, windows, macos, etc)
if you compare the unit of my Tabcontrol (ALFmxTabControl.pas) with the unit of the delphi TabControl (Fmx.TabControl.pas) then you will see that i use 3.5x less line of code (1018 vs 3550), and less line of code = always better
please vote for this feature request here :
https://quality.embarcadero.com/browse/RSP-15576
Trying the THorzScrollBox.AniCalculations.SetTargets(...).
eg.
1.Open FMX.HorizontalScroll Sample : CPP\Mobile Snippets\HorizontalScroll
2.Add Form Event : OnResize
3.Write the code :
#include <FMX.InertialMovement.hpp>
void __fastcall THorizontalScrollForm::FormResize(TObject *Sender)
{
TAniCalculations::TTarget target[4];
// Set ths size and position of your slides.
Image1->SetBounds(0, 0, HorzScrollBox1->Width, HorzScrollBox1->Height);
Image2->SetBounds(HorzScrollBox1->Width, 0, HorzScrollBox1->Width, HorzScrollBox1->Height);
Image3->SetBounds(HorzScrollBox1->Width*2, 0, HorzScrollBox1->Width, HorzScrollBox1->Height);
Image4->SetBounds(HorzScrollBox1->Width*3, 0, HorzScrollBox1->Width, HorzScrollBox1->Height);
// Assign the check point(your slides' top-left conner).
target[0].TargetType = TAniCalculations::TTargetType::Other;
target[0].Point = TPointD(1, 0);
target[1].TargetType = TAniCalculations::TTargetType::Other;
target[1].Point = TPointD(HorzScrollBox1->Width, 0);
target[2].TargetType = TAniCalculations::TTargetType::Other;
target[2].Point = TPointD(HorzScrollBox1->Width*2, 0);
target[3].TargetType = TAniCalculations::TTargetType::Other;
target[3].Point = TPointD(HorzScrollBox1->Width*3, 0);
HorzScrollBox1->AniCalculations->SetTargets(target, 3);
}

Refresh a NSOpenGLView within a loop without letting go of the main runloop in Cocoa

I am building an Cocoa/OpenGL app, for periods of about 2 second at a time, I need to control every video frame as well as writing to a digital IO device.
If after I make the openGL calls I let go of the main thread (like if I make the openGL calls inside a timer fire-method with an interval of like 0.01 Sec) openGLview is refreshed with every call to glFinish().
But If I instead keep the main thread busy like in a 2 second long while loop, openGl calls won't work (surprisingly the first call to glFinish() would work but the rest won't).
The documentation says that glFinish should block the thread until the gl commands are executed.
Can anybody please help me understand what is going on here or provide a solution to this problem.
To make it clear, I want to present 200 frames one after another without missing a frame and marking each frame refresh by writing to a digital IO port (I don't have a problem with this) all on Snow Leopard.
This is not quite my department - pretty vanilla NSOpenGLView user myself - but from the Mac OpenGL docs it looks like you might want to use a CVDisplayLink (Q&A1385) for this. Even if that won't do it, the other stuff there should probably help.
EDIT
I've only done some basic testing on this, but it looks like you can do what you want as long as you first set the correct OpenGL context and then swap buffers after each frame (assuming you're using a double buffered context):
// inside an NSOpenGLView subclass, somewhere outside the usual drawing loop
- (void) drawMultipleFrames
{
// it might be advisable to also do a [self lockFocus] here,
// although it seems to work without that in my simple tests
[[self openGLContext] makeCurrentContext];
// ... set up common OpenGL state ...
for ( i = 0; i < LOTS_OF_FRAMES; ++i )
{
// ... draw your frame ...
glFinish();
glSwapAPPLE();
}
// unlockFocus here if locked earlier
}
I previously tried using [[self openGLContext] flushBuffer] at the end of each frame instead -- that doesn't need glSwapAPPLE but doesn't block like glFinish so you might get frames trampling over one another. This seems to work OK with other apps, runs in the background etc, but of course YMMV.

Is it possible to have a QWidget without a display?

I have a console-only win32 application (which can be launched as a windows service) where I want to create QWidget objects and interact with them.
These QWidget will not be rendered locally (because there is no display) but I need to access painting operations (to create screenshot of them for example) and I need to intercept mouse and keyboard operations.
The aim of the service is to provide a display of the widget to a remote application. So the image, mouse and keyboard are meant to be redirected over the network.
Is it possible to have QWidget objects in a console application? What is the preferred method to intercept painting, mouse and keyboard operations in that case?
If this is possible, is it still possible with QAxWidget objects?
Have a peek at Qt for embedded Linux.. Qt is designed so you can do this, but it is non-trivial.
I do suspect you're not on the right track, though, if you have a console-mode service that needs a keyboard, mouse and a graphical UI. The need to interact with a user tells me that it should not be a service, and the need for a mouse suggests that it shouldn't be a console app either.
You can create a QApplication without a Gui using one of the provided constructors:
QApplication::QApplication(int&, char**, bool GuiEnabled)
In order to do GUI operations you'll still need a GUI available. For example, on Linux it will still require that X be running and available. I believe there are certain restrictions on what can and can't happen but can't find the blog post on http://labs.qt.nokia.com that provides details.
At the moment i myself am trying to do something similar. The approach i have taken is creating subclass of QGraphicsScene and overriding QGraphicsScene::sceneChanged event. Then it goes as follows (pseudocode):
QApplication app;
MyGraphicsScene* mgs = new MyGraphicsScene();
MyWidget* mw = new MyWidget();
mgs->addWidget(mw);
Now each time change happens your sceneChanged will be invoked. There you can get snapshot of scene as QImage. In my case i move pixel data to texture and render it as overlay of my game:
void QEOverlay::sceneChanged(QList<QRectF> list)
{
//loop through all screen areas that changed
foreach(QRectF rect, list)
{
//generate a rectangle that is a while number, and fits withing the screen
if(rect.x() < 0) rect.setX(0);
if(rect.y() < 0) rect.setY(0);
if(rect.right() > _width) rect.setRight(_width);
if(rect.bottom() > _height) rect.setRight(_height);
rect = QRectF(Round(rect.x()),Round(rect.y()),Round(rect.width()),Round(rect.height()));
//Create an image, create a qpainter, fill the image with transparent color, and then render a part of the scene to it
QImage image(rect.width(),rect.height(),QImage::Format_ARGB32);
QPainter p(&image);
image.fill(0);
render(&p,image.rect(),rect);
if(tex.lock())
{
for (u32 y = 0; y < image.height(); y++)
{
for (u32 x = 0; x < image.width(); x++)
{
QRgb pix = image.pixel(x, y);
tex.color(x + rect.left(), y + rect.top(), Color(qRed(pix), qGreen(pix), qBlue(pix), qAlpha(pix)));
}
}
tex.unlock();
}
}
}
There is issue with this approach. You still need to redirect keyboard and mouse input events to your subclass. That does not work out for me very well, there are certain issues like mouse click not focusing QLineEdit or elements in QWebView.

Resources