Getting a window's pixel format on GLFW in linux - c++

I want to get a GLFW window's pixel format. I'm using ubuntu so win32 functions are out of the picture. I've stumbled upon this question but there are only win32 answers and there is an answer that uses HDC and PIXELFORMATDESCRIPTOR which I don't have access to (Since I will not be using the function permanently I rather not install a new library for this.)
I want to get the format in the form of YUV420P or RGB24.

Conceptually the closest thing to a pixelformat in X11 is a so called Visual (X11 core) or FBConfig (through GLX extension).
First you need the native window handle. You can retrieve this from GLFW using
Window x11win = glfwGetX11Window(glfwwin);
A window's visual can be queried using XGetWindowAttributes
XWindowAttributs winattr;
XGetWindowAttributes(display, x11win, &winattr);
// winattr->visual
// use it to query a XVisualInfo which can then be
// passed to glXGetConfig
The FBConfig can be queried using glXQueryDrawable
unsigned fbconfigid;
glXQueryDrawable(display, x11win, GLX_FBCONFIG_ID, &fbconfigid);
unsigned n_fbconfigs;
GLXFBConfig glxfbconfigs = glXGetFBConfigs(display, screen, &n_fbconfigs);
if( fbconfigid >= n_fbconfigs ){ raise_error(...); }
int attribute_value;
glXGetFBConfigAttrib(display, glxfbconfigs[fbconfigid], GLX_…, &attribute_value);
XFree(fbconfigs);

That is outside the scope of GLFW as can be read here:
Framebuffer related attributes
GLFW does not expose attributes of the default framebuffer (i.e. the framebuffer attached to the window) as these can be queried directly with either OpenGL, OpenGL ES or Vulkan.
If you are using version 3.0 or later of OpenGL or OpenGL ES, the glGetFramebufferAttachmentParameteriv function can be used to retrieve the number of bits for the red, green, blue, alpha, depth and stencil buffer channels. Otherwise, the glGetIntegerv function can be used.
Hint:
Don't rely on (if you've created the window with the videomode of the specified monitor and didn't tinkered with framebuffers):
GLFWvidmode *vid_mode = glfwGetVideoMode(glfwGetWindowMonitor(win));
vid_mode->redBits;
vid_mode->greenBits;
vid_mode->blueBits;
because in glfwCreateWindow we read the following:
The created window, framebuffer and context may differ from what you requested, as not all parameters and hints are hard constraints. This includes the size of the window, especially for full screen windows. To query the actual attributes of the created window, framebuffer and context, see glfwGetWindowAttrib, glfwGetWindowSize and glfwGetFramebufferSize.

Related

How to Get Unity Context into OpenGL Window

I want to get the unity context into opengl so I can display a unity render texture in an opengl glfw window. I tried using
oldContext = glfwGetCurrentContext(); but the value of oldContext is just null.
I am trying to use the low-level native unity plugin and Texture.GetNativeTexturePtr
Any help would be greatly appreciated!
OpenGL context cannot be queried like OpenGL state related objects via some glGet* API.Context is not part of OpenGL API,it is a part of the system you're running on and it exists to allow you maintaining of OpenGL state and issue command to the driver. You must access a system specific handle that points to the context via system specific API.On Windows (WinGDI)that's would be
HGLRC wglGetCurrentContext();
On linux see related GLX API. You need to find functions to access GLXContext
I did it once in Unity3D (framebuffer readout plugin). But it used Unity's OpenGL or DirectX context to issue API commands only.
Also,I am not sure you can 'inject' or share a context for a window that doesn't own that context. You see, when you (or Unity) init display it creates context and related GL resources,like the default FBO with all required attachments on its own,and that FBO is mapped to some system resource(device) which takes actually care of presenting those pixels on the screen. Therefore, I am not sure display context can be moved from Window to Window in the same manner that a context can be shared between threads.(But I can be wrong on this one)
You can create your plugin Window on some thread,with its own GL context. Then create and share a texture object between those two. Remember, GL textures are shareable. If you copy contents from Unity's screen FBO into that texture,then you can copy it into your plugin's screen FBO from that texture as well.
Btw,look at this SO question .You can see there vendor specific GL extensions which allow copying data into texture from different contexts without requiring shared context,share lists setup.
Regarding why GLFW returns you nullptr. In your example you use GLFW library.
glfwGetCurrentContext()
But if you look at the source code,you see this:
GLFWAPI GLFWwindow* glfwGetCurrentContext(void)
{
_GLFW_REQUIRE_INIT_OR_RETURN(NULL);
return _glfwPlatformGetTls(&_glfw.contextSlot);
}
Which probably means that it retrieves a pointer to GLFWWindow from its own cache and not from the system.And if you didn't create that context via GLFW,you won't get any valid pointer. So try working directly with your system related API as explained above.

OpenGL load texture without or with static device context?

I want to create opengl 2d library, where textures as well as windows are encapsulated as objects. Is it possible to create dummy static DC and make it current when loading textures? All of the windows would have same PIXELFORMATDESCRIPTOR as the static one. This way, users of the library would not have to create window prior to loading textures or passing windows as parameters to textures.
Is it possible to create dummy static DC and make it current when loading textures?
Sort of. As long as the visual formats of the device contexts are compatible with each other, you can bind a OpenGL render context created for this visual format to any of these device contexts.
So you can perfectly fine create a window, with a DC that's never shown on the screen (always kept hidden, size of 0×0) and use that for background OpenGL operations. You can also create a secondary OpenGL context, have it share its namespace with the primary context, make it current on the hidden window on a separate worker thread, so that you can asynchronously perform OpenGL operations (like loading textures) while the main context is used for other things.

How to make an existing X11 window OpenGL ready?

I can't seem to find an example of creating an OpenGL context off of an existing X11 Window. Every example I find creates a window that is already OpenGL ready by providing the necessary visual attributes (via glXChooseVisual or glXChooseFBConfig). What if I already have an existing window (referenced via Display* and Window) and want to change the Colormap and XVisualInfo for the Window for OpenGL rendering? Think ChoosePixelFormat and SetPixelFormat on Windows when creating an OpenGL context. Is this even possible in X11? Do I have to create a Window that's already ready for OpenGL?

how can I create OpenGL context using Windows memory dc (c++)

In my Windows MFC application, in its View class I created an OpenGL context using View's DC:
HANDLE * hdc = GetDC()->m_hdc;
int nPixelFormat;
static PIXELFORMATDESCRIPTOR pfd = {
sizeof(PIXELFORMATDESCRIPTOR), // Size of this structure
1, // Version of this structure
PFD_DRAW_TO_WINDOW | // Draw to window (not bitmap)
PFD_SUPPORT_OPENGL | // Support OpenGL calls
PFD_DOUBLEBUFFER, // Double -buffered mode
PFD_TYPE_RGBA, // RGBA Color mode
24, // Want 24bit color
0,0,0,0,0,0, // Not used to select mode
0,0, // Not used to select mode
0,0,0,0,0, // Not used to select mode
32, // Size of depth buffer
0, // Not used to select mode
0, // Not used to select mode
PFD_MAIN_PLANE, // Draw in main plane
0, // Not used to select mode
0,0,0 }; // Not used to select mode
// Choose a pixel format that best matches that described in pfd
nPixelFormat = ChoosePixelFormat(hdC, &pfd);
// Set the pixel format for the device context
assert(SetPixelFormat(hdC, nPixelFormat, &pfd));
HGLRC m_hrc = wglCreateContext(hdc);
assert(m_hrc);
wglMakeCurrent(m_hdc,m_hrc);
All the code above works all right, and I can do OpenGL drawings as expected.
But , What I need now is to change the DC to memory dc instead of window DC . To be exact, how can I use the 'hmemDC' bellow to create an OpenGL context like the way I did above with window DC:
CRect rct;
GetClientRect(&rct);
HDC hmemDC = CreateCompatibleDC(pDC->m_hDC);
HBITMAP hBmp = CreateCompatibleBitmap(pDC->m_hDC,rct.Width(),rct.Height());
with the same pixel format constructed above, I came across the "Invalid pixel format" error in calling wglCreateContext() , can not success in getting the correct OpenGL context.
I googled a lot , and tryed to change some of the values of pixel format, the result was the same.
Is it possible to create OpenGL context with Windows Memory DC? and if it is how should I do it?
Edit:
This is why I need a bitmap ( or Memory DC ): I created a 2d map rendering library which uses OpenGL. The client want to use this library to render background map, and draw its own symbols on top of it . But, they prefer to use Windows GDI other than OpenGL to draw their symbols. So I thought if I can provide them with a bitmap or a Mmeory DC, they could to what they want. Any better solutions? Am I in the right direction? Or it is a total bad idea to provide such a 2d library in OpenGL backend.
This can't be done in a useful way.
You can in principle render to a bitmap by using the PFD_DRAW_TO_BITMAP flag instead of PFD_DRAW_TO_WINDOW in the PIXELFORMATDESCRIPTOR.
However, doing so will disable all hardware accelearated rendering. This will fall back to Microsofts default OpenGL 1.1 implementation.
If you want hw-accleration and/or modern GL, you either need a window or some offscreen buffer like a pbuffer, which is available via the WGL_ARB_pbuffer extension. However, in modern GL, you are probably better off creating a window which is just never shown, and using a Frambeuffer Object as the offscreen render target.
In either case, you will have to copy the data back to the CPU, if you need it as some bitmap there.
Put in few words: You can't create arbitrary OpenGL contexts for MemDCs. At least no kind of OpenGL context you'd actually want to use.
If your goal is off-screen rendering either create a PBuffer-DC; which requires to create a OpenGL context first which in turn required to create a window and setting its pixel format. Or you can just create a window and a OpenGL context for it and use a framebuffer object.

Improving window resize behaviour, possibly by manually setting bigger framebuffer size

I was considering using glfw in my application, while developing on mac
After successfully writing a very simple program to render a triangle on a colored backround,
I noticed that when resizing the window, it takes quite some time to rerender the scene, as I suspect due to framebuffer resize.
This is not the case when I am repeating the experiment with NSOpenGLView. Is there a way to hint glfw to use bigger framebuffer size on start, to avoid expensive resizes?
I am using GLFW 3.
Could you also help me with enabling High DPI for retina display. Couldn't find something in docs on that, but it supported in version 3.
Obtaining a larger framebuffer
Try to obtain a large initial frame-buffer by calling glfwCreateWindow() with large values for width & height and immediately switching to displaying a smaller window using glfwSetWindowSize() with the actual initial window size desired.
Alternately, register your own framebuffer size callback function using glfwSetFramebufferSizeCallback() and set the framebuffer to a large size according to your requirement as follows :
void custom_fbsize_callback(GLFWwindow* window, int width, int height)
{
/* use system width,height */
/* glViewport(0, 0, width, height); */
/* use custom width,height */
glViewport(0, 0, <CUSTOM_WIDTH>, <CUSTOM_HEIGHT>);
}
UPDATE :
The render pipeline stall seen during the window re-size(and window drag) operation is due to the blocking behavior implemented in the window manager.
To mitigate this in one's app, one needs to install handler functions for the window messages and run the render pipeline in a separate thread independent from the main app(GUI) thread.
High DPI support
The GLFW documentation says :
GLFW now supports high-DPI monitors on both Windows and OS X, giving
windows full resolution framebuffers where other UI elements are
scaled up. To achieve this, glfwGetFramebufferSize() and
glfwSetFramebufferSizeCallback() have been added. These work with
pixels, while the rest of the GLFW API work with screen coordinates.
AFAIK, that seems to be pretty much everything about high-DPI in the documentation.
Going through the code we can see that on Windows, glfw hooks into the SetProcessDPIAware() and calls it during platformInit. Currently i am not able to find any similar code for high-DPI support on mac.