4

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.

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Turgut
  • 711
  • 3
  • 25
  • 4
    pixelformats are a concept of the win32 API, linux simply doesn't have these. For X11, there are visuals and fbconfigs. – derhass Sep 02 '22 at 17:30

2 Answers2

3

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);
datenwolf
  • 159,371
  • 13
  • 185
  • 298
2

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.

Erdal Küçük
  • 4,810
  • 1
  • 6
  • 11
  • 1
    As long as I get the description of the format somehow its ok. Like `planar YUV 4:2:0` or `packed RGB 8:8:8, 24bpp`. You can see my goal more clearly here: https://stackoverflow.com/questions/73580246/what-is-the-glfw-screen-format-for-ffmpeg-encoding – Turgut Sep 03 '22 at 08:21
  • 1
    Also saying `const GLFWvidmode *vid_mode = glfwGetVideoMode(glfwGetWindowMonitor(window));` results in a segfault in which valgrind says `Invalid read of size 8`. – Turgut Sep 03 '22 at 08:37
  • 2
    @Turgut Once you retrieved the pixelformat of the framebuffer, you have to translate it to the corresponding pixelformat of the codec. First you have to query the codec, whether it supports that format and if not, you have to convert the pixels before feeding it to the codec. – Erdal Küçük Sep 03 '22 at 08:54
  • 1
    @Turgut If you get an error, consult the glfw reference why that might happen and debug your program why it did happen. – Erdal Küçük Sep 03 '22 at 08:57
  • 1
    Figured as much. Converting to the corresponding format is exactly what I need. Just wanted to ask if the error is a common one you are aware of. Teşekkürler Erdal bey. – Turgut Sep 03 '22 at 09:09
  • 2
    The converting part is that, what you have to do by hand. Maybe, there are other projects which have done that already. `pixfmt.h` (ffmpeg) has a good documentation of the available pixelformats. And if you look at `glReadPixels`, you have control of how the pixels are transferred into client memory. Rica ederim (you're welcome). – Erdal Küçük Sep 03 '22 at 09:21
  • 3
    Oh, and `sws_scale` (ffmpeg) is your friend either, when it comes to converting the pixels from one format into another. – Erdal Küçük Sep 03 '22 at 09:29
  • 1
    I was already using `sws_scale` before, here is what it looks like (Since the code is really long I did not post it.), I have updated my other question to include the sample code. – Turgut Sep 03 '22 at 09:43
  • @ErdalKüçük: I just noticed that your goal is passing the data obtained with `glReadPixels` to FFmpeg. So here's the thing: *The window's pixelformat then is completely irrelevant to you then, since glReadPixels will perform a conversion to the format you ask it to produce.* – datenwolf Sep 04 '22 at 17:34
  • @datenwolf Yes, you're right. I mentioned in a previous comment, that [`glReadPixels`](https://registry.khronos.org/OpenGL-Refpages/gl4/html/glReadPixels.xhtml) allows to control on how the pixels are transferred into client memory. The orig question was, how to get framebuffer attributes in GLFW (for whatever reason), i think that was answered. But the OP mentioned the YUV color format, for that, we still have to use a converter. – Erdal Küçük Sep 04 '22 at 18:48