How do I enumerate and use OpenGL on a headless GPU? - linux

Despite days of research, I can't seem to find a reliable way to programmatically create GL[ES] contexts on secondary GPUs. On my laptop, for example, I have the Intel GPU driving the panel, and a secondary NVIDIA card not connected to anything. optirun and primusrun let me run on the NVIDIA card, but then I can't detect the Intel GPU. I also don't want to require changing xorg.conf to add a dummy display.
I have tried a number of extensions, but none seem to work correctly:
glXEnumerateVideoDevicesNV returns 0 devices.
eglQueryDevicesEXT returns 0 devices.
eglGetPlatformDisplay only works with the main panel and gives me an Intel context
I am fine getting my hands dirty, e.g. rolling my own loader, but I can't seem to find any documentation for where to start. I've looked at the source for optirun but it just seems to do redirection. Obviously something equivalent to Windows' IDXGIFactory::EnumAdapters would be ideal, but I'm fine with anything that works without additional system configuration.

Related

AMD GPU won't work with Blender's "Cycles Render" on Linux

I've been working a lot with Blender and it's "Cycles Render" on Fedora lately. But Blender keeps getting a lot slower while rendering. So I discovered that my Blender is only capable of rendering with my CPU. I tried running Blender from the terminal, so I could see any errors. And if I set "Device" to "GPU Compute" in the rendering settings, I get this output:
DRM_IOCTL_I915_GEM_APERTURE failed: Invalid argument
Assuming 131072kB available aperture size.
May lead to reduced performance or incorrect rendering.
get chip id failed: -1 [2]
param: 4, val: 0
My machine's specifications are:
Operaring system: Fedora GNU/Linux 27
Blender version: 2.79
Graphics card: AMD Radeon RX 480 using "amdgpu" driver (default open-source driver)
So it seems like, Blender's Cycle Render won't work with my AMD GPU...
Any ideas?
As far as I've seen on the release docs, the Blender cycles engine is not yet fully optimized for all AMD graphics cards, currently they only support AMD cards with GCN architecture 2.0 and above. The dev team focuses on NVIDIA cards mostly (also blender is most optimized for windows).
However, you might as well try to change the settings, first you must make sure you are using OpenCL and not CUDA in your User Preferences, under the System tab, Compute Device(s). Then if your card is not supported, enable the experimental features on the render properties of your workspace, which warn you that will make everything go unstable, this usually enables most AMD GPUs to be selectable as a render device. here on the render properties, you will also be selecting the compute device you desire to use for each scene.
Also, Using an official AMD driver would make rendering faster (also this is a requirement by Blender to use AMD cards) but its not available for fedora as far as I know. I suggest changing your distro to Ubuntu.
EDIT: You MUST use an official AMD driver for the desired card, I have checked the card you have is on the list of supported cards, just that it IS a requirement to have the AMD driver and not opensource. this is the list of supported cards https://en.wikipedia.org/wiki/List_of_AMD_graphics_processing_units, according to the blender documentation.
But it must be a driver from this list: https://support.amd.com/en-us/download/linux, according to the blender documentation.
Now if that doesn't solve the issue then it must be a hardware issue or blender bug, although you could try to run it on windows to discard it being a hardware issue, if you are willing to do a dual boot or usb boot test.

Get screenshot of EGL DRM/KMS application

How to get screenshot of graphical application programmatically? Application draw its window using EGL API via DRM/KMS.
I use Ubuntu Server 16.04.3 and graphical application written using Qt 5.9.2 with EGLFS QPA backend. It started from first virtual terminal (if matters), then it switch display to output in full HD graphical mode.
When I use utilities (e.g. fb2png) which operates on /dev/fb?, then only textmode contents of first virtual terminal (Ctrl+Alt+F1) are saved as screenshot.
It is hardly, that there are EGL API to get contents of any buffer from context of another process (it would be insecure), but maybe there are some mechanism (and library) to get access to final output of GPU?
One way would be to get a screenshot from within your application, reading the contents of the back buffer with glReadPixels(). Or use QQuickWindow::grabWindow(), which internally uses glReadPixels() in the correct way. This seems to be not an option for you, as you need to take a screenshot when the Qt app is frozen.
The other way would be to use the DRM API to map the framebuffer and then memcpy the mapped pixels. This is implemented in Chromium OS with Python and can be translated to C easily, see https://chromium-review.googlesource.com/c/chromiumos/platform/factory/+/367611. The DRM API can also be used by another process than the Qt UI process that does the rendering.
This is a very interesting question, and I have fought this problem from several angles.
The problem is quite complex and dependant on platform, you seem to be running on EGL, which means embedded, and there you have few options unless your platform offers them.
The options you have are:
glTexSubImage2D
glTexSubImage2D can copy several kinds of buffers from OpenGL textures to CPU memory. Unfortunatly it is not supported in GLES 2/3, but your embedded provider might support it via an extension. This is nice because you can either render to FBO or get the pixels from the specific texture you need. It also needs minimal code intervertion.
glReadPixels
glReadPixels is the most common way to download all or part of the GPU pixels which are already rendered. Albeit slow, it works on GLES and Desktop. On Desktop with a decent GPU is bearable up to interactive framerates, but beware on embedded it might be really slow as it stops your render thread to get the data (horrible framedrops ensured). You can save code as it can be made to work with minimal code modifications.
Pixel Buffer Objects (PBO's)
Once you start doing real research PBO's appear here and there because they can be made to work asynchronously. They are also generally not supported in embedded but can work really well on desktop even on mediocre GPU's. Also a bit tricky to setup and require specific render modifications.
Framebuffer
On embedded, sometimes you already render to the framebuffer, so go there and fetch the pixels. Also works on desktop. You can enven mmap() the buffer to a file and get partial contents easily. But beware in many embedded systems EGL does not work on the framebuffer but on a different 'overlay' so you might be snapshotting the background of it. Also to note some multimedia applications are run with UI's on the EGL and media players on the framebuffer. So if you only need to capture the video players this might work for you. In other cases there is EGL targeting a texture which is copied to the framebuffer, and it will also work just fine.
As far as I know render to texture and stream to a framebuffer is the way they made the sweet Qt UI you see on the Ableton Push 2
More exotic Dispmanx/OpenWF
On some embedded systems (notably the Raspberry Pi and most Broadcom Videocore's) you have DispmanX. Whichs is really interesting:
This is fun:
The lowest level of accessing the GPU seems to be by an API called Dispmanx[...]
It continues...
Just to give you total lack of encouragement from using Dispmanx there are hardly any examples and no serious documentation.
Basically DispmanX is very near to baremetal. So it is even deeper down than the framebuffer or EGL. Really interesting stuff because you can use vc_dispmanx_snapshot() and really get a snapshot of everything really fast. And by fast I mean I got 30FPS RGBA32 screen capture with no noticeable stutter on screen and about 4~6% of extra CPU overhead on a Rasberry Pi. Night and day because glReadPixels got was producing very noticeable framedrops even for 1x1 pixel capture.
That's pretty much what I've found.

Multiple screen view on laptop display

First I dont know wheather this is right place to ask such question.
My laptop displays multiple screen on booting. I googled about this but I am unable to find the solution. came across this type of dysfunction on many laptops screen.
I cant figure out whether it is a screen problem/ hardware problem/ graphic card problem or its a bios problem.
I would really appreciate if anyone can direct me towards correct solution.
Following steps will help zero down
Enter Safe mode ( F8 in most ) and then see if its there. If it's gone then there's a problem likely with the graphics driver
Try to download the latest Chipset drivers from Intel or AMD Site depending on your Graphics card. Intel has a chipset detect utility that will pull up the latest drivers for all intel h/w on the pc
If you see this just on the desktop ( and not other apps like browser ) - it because the desktop background image is tiled vs Centered / stretched. In that case change it to centered.
Uninstall graphics driver and see if the multiple images disappear. You will not see high res image without driver but it will rule out card failure vs improper driver

Create a Wacom-like Linux uinput device for work with touchscreen and pen

This is a fairly broad question, so I will try to keep it as focused as I can.
I currently own a Lenovo laptop with Ubuntu installed and touchscreen functionality and own a pressure-sensitive Bluetooth pen, and been trying to make the two work together as a cheap Cintiq-like tablet.
The pen has, unfortunately, support for only specific apps for iOS phones and tablets.
So after lots of research, I've managed to interface with the pen and create a uinput device for it, so I can register button clicks and pressure changes on the pen and even see them routed to GIMP when configuring the device through the Input Controllers menu.
The code I have so far for that interface is available here.
The trouble starts when trying to test it out with GIMP.
From what I gather, this is because GIMP assumes Wacom devices report their own position, treats touchscreen touches as mouse movements and only allows input from a single device at a time.
My question is, how can I work around this?
More specifically, how can I create a uinput device that would behave as a Wacom tablet and supersede/block the behavior I described?
Or if there's a different solution, such as patching GIMP or writing a plugin for it.
Update (2014-06-07)
The code mentioned above now works.
I have written a blog post on the process of getting this to work: http://gerev.github.io/laptop-cintiq
As you said, Gimp expects you to provide ABS_X and ABS_Y along with ABS_PRESSURE in your driver - which is not strange, because you are using you virtual device as input, so it wouldn't make much sense to pick ABS_X and ABS_Y coordinates from one device and ABS_PRESSURE from another (although they will always be the same in this case). Maybe you can just read the current coordinates of the mouse and copy them as your own device coordinates.
As an example, the project GfxTablet does something similar to what you are trying, they have an Android application for tablets with pen and use uinput to create virtual device that works like pressure-sensitive pen on Linux. I have used it and it worked like a charm in Gimp and mypaint on my laptop, and I had no problem with having a mouse (or the touchpad) active at the same time as the uinput device (I think that Krita added support for generic pressure-sensitive devices recently). You can take a look at the source code of the driver here (surprinsingly simple, to be fair).
Note that this is not a faulty behavior of Gimp, because this is what is expected from a tablet-like device. Take a look at the event codes kernel documentation page, in the last section (Guidelines), it is said that tablets must report ABS_X and ABS_Y. Moreover, they should use BTN_STYLUS and BTN_STYLUS2 to report the tool buttons and some BTN_TOOL_* (e.g. BTN_TOOL_PEN) to report activity (you can find all the available codes in input.h); however, these last does not seem that important, as GfxTablet does not implement them and worked without problem.

CUDA/PyCUDA: Which GPU is running X11?

In a Linux system with multiple GPUs, how can you determine which GPU is running X11 and which is completely free to run CUDA kernels? In a system that has a low powered GPU to run X11 and a higher powered GPU to run kernels, this can be determined with some heuristics to use the faster card. But on a system with two equal cards, this method cannot be used. Is there a CUDA and/or X11 API to determine this?
UPDATE: The command 'nvidia-smi -a' shows a whether a "display" is connected or not. I have yet to determine if this means physically connected, logically connected (running X11), or both. Running strace on this command shows lots of ioctls being invoked and no calls to X11, so assuming that the card is reporting that a display is physically connected.
There is a device property kernelExecTimeoutEnabled in the cudaDeviceProp structure which will indicate whether the device is subject to a display watchdog timer. That is the best indicator of whether a given CUDA device is running X11 (or the windows/Mac OS equivalent).
In PyCUDA you can query the device status like this:
In [1]: from pycuda import driver as drv
In [2]: drv.init()
In [3]: print drv.Device(0).get_attribute(drv.device_attribute.KERNEL_EXEC_TIMEOUT)
1
In [4]: print drv.Device(1).get_attribute(drv.device_attribute.KERNEL_EXEC_TIMEOUT)
0
Here device 0 has a display attached, and device 1 is a dedicated compute device.
I don't know any library function which could check that. However a one "hack" comes in mind:
X11, or any other system component that manages a connected monitor must consume some of the GPU memory.
So, check if both devices report the same amount of available global memory through 'cudaGetDeviceProperties' and then check the value of 'totalGlobalMem' field.
If it is the same, try allocating that (or only slightly lower) amount of memory on each of the GPU and see which one fails to do that (cudaMalloc returning an error flag).
Some time ago I read somewhere (I don't remember where) that when you increase your monitor resolution, while there is an active CUDA context on the GPU, the context may get invalidated. That hints that the above suggestion might work. Note however that I never actually tried it. It's just my wild guess.
If you manage to confirm that it works, or that it doesn't, let us know!

Resources