{"id":415,"date":"2014-09-04T13:43:04","date_gmt":"2014-09-04T11:43:04","guid":{"rendered":"http:\/\/blogs.igalia.com\/itoral\/?p=415"},"modified":"2014-09-04T13:43:14","modified_gmt":"2014-09-04T11:43:14","slug":"driver-loading-and-querying-in-mesa","status":"publish","type":"post","link":"https:\/\/blogs.igalia.com\/itoral\/2014\/09\/04\/driver-loading-and-querying-in-mesa\/","title":{"rendered":"Driver loading and querying in Mesa"},"content":{"rendered":"<p><strong>Recap<\/strong><\/p>\n<p><a href=\"http:\/\/blogs.igalia.com\/itoral\/2014\/08\/08\/diving-into-mesa\/\" title=\"Diving into Mesa\" target=\"_blank\">In my previous post<\/a> I explained that Mesa is a framework for OpenGL driver development. As such, it provides code that can be reused by multiple driver implementations. This code is, of course, hardware agnostic, but frees driver developers from doing a significant part of the work. The framework also provides hooks for developers to add the bits of code that deal with the actual hardware. This design allows multiple drivers to co-exist and share a significant amount of code.<\/p>\n<p>I also explained that among the various drivers that Mesa provides, we can find both hardware drivers that take advantage of a specific GPU and software drivers, that are implemented entirely in software (so they work on the CPU and do not depend on a specific GPU). The latter are obviously slower, but as I discussed, they may come in handy in some scenarios.<\/p>\n<p><strong>Driver selection<\/strong><\/p>\n<p>So, Mesa provides multiple drivers, but how does it select the one that fits the requirements of a specific system?<\/p>\n<p>You have probably noticed that Mesa is deployed in multiple packages. In my Ubuntu system, the one that deploys the DRI drivers is <em>libgl1-mesa-dri:amd64<\/em>. If you check its contents you will see that this package installs OpenGL drivers for various GPUs:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n# dpkg -L libgl1-mesa-dri:amd64 \r\n(...)\r\n\/usr\/lib\/x86_64-linux-gnu\/gallium-pipe\/pipe_radeonsi.so\r\n\/usr\/lib\/x86_64-linux-gnu\/gallium-pipe\/pipe_r600.so\r\n\/usr\/lib\/x86_64-linux-gnu\/gallium-pipe\/pipe_nouveau.so\r\n\/usr\/lib\/x86_64-linux-gnu\/gallium-pipe\/pipe_vmwgfx.so\r\n\/usr\/lib\/x86_64-linux-gnu\/gallium-pipe\/pipe_r300.so\r\n\/usr\/lib\/x86_64-linux-gnu\/gallium-pipe\/pipe_swrast.so\r\n\/usr\/lib\/x86_64-linux-gnu\/dri\/i915_dri.so\r\n\/usr\/lib\/x86_64-linux-gnu\/dri\/i965_dri.so\r\n\/usr\/lib\/x86_64-linux-gnu\/dri\/r200_dri.so\r\n\/usr\/lib\/x86_64-linux-gnu\/dri\/r600_dri.so\r\n\/usr\/lib\/x86_64-linux-gnu\/dri\/radeon_dri.so\r\n\/usr\/lib\/x86_64-linux-gnu\/dri\/r300_dri.so\r\n\/usr\/lib\/x86_64-linux-gnu\/dri\/vmwgfx_dri.so\r\n\/usr\/lib\/x86_64-linux-gnu\/dri\/swrast_dri.so\r\n\/usr\/lib\/x86_64-linux-gnu\/dri\/nouveau_vieux_dri.so\r\n\/usr\/lib\/x86_64-linux-gnu\/dri\/nouveau_dri.so\r\n\/usr\/lib\/x86_64-linux-gnu\/dri\/radeonsi_dri.so\r\n(...)\r\n<\/pre>\n<p>Since I have a relatively recent Intel GPU, the driver I need is the one provided in i965_dri.so. So how do we tell Mesa that this is the one we need? Well, the answer is that we don&#8217;t, Mesa is smart enough to know which driver is the right one for our GPU, and selects it automatically when you load <em>libGL.so<\/em>. The part of Mesa that takes care of this is called the <em>&#8216;loader&#8217;<\/em>.<\/p>\n<p>You can, however, point Mesa to look for suitable drivers in a specific directory other than the default, or force it to use a software driver <a href=\"http:\/\/www.mesa3d.org\/envvars.html\" title=\"Mesa 3D environment variables\" target=\"_blank\">using various environment variables<\/a>.<\/p>\n<p><strong>What driver is Mesa actually loading?<\/strong><\/p>\n<p>If you want to know exactly what driver Mesa is loading, you can instruct it to dump this (and other) information to <em>stderr<\/em> via the <em>LIBGL_DEBUG<\/em> environment variable:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n# LIBGL_DEBUG=verbose glxgears \r\nlibGL: screen 0 does not appear to be DRI3 capable\r\nlibGL: pci id for fd 4: 8086:0126, driver i965\r\nlibGL: OpenDriver: trying \/usr\/lib\/x86_64-linux-gnu\/dri\/tls\/i965_dri.so\r\nlibGL: OpenDriver: trying \/usr\/lib\/x86_64-linux-gnu\/dri\/i965_dri.so\r\n<\/pre>\n<p>So we see that Mesa checks the existing hardware and realizes that the <em>i965<\/em> driver is the one to use, so it first attempts to load the TLS version of that driver and, since I don&#8217;t have the TLS version, falls back to the normal version, which I do have.<\/p>\n<p>The code in <em>src\/loader\/loader.c (loader_get_driver_for_fd)<\/em> is the one responsible for detecting the right driver to use (<em>i965<\/em> in my case). This receives a device fd as input parameter that is acquired previously by calling <em>DRI2Connect()<\/em> as part of the DRI bring up process. Then the actual driver file is loaded in <em>glx\/dri_common.c (driOpenDriver)<\/em>.<\/p>\n<p>We can also obtain a more descriptive indication of the driver we are loading by using the <em>glxinfo<\/em> program that comes with the <em>mesa-utils<\/em> package:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n# glxinfo | grep -i &quot;opengl renderer&quot;\r\nOpenGL renderer string: Mesa DRI Intel(R) Sandybridge Mobile \r\n<\/pre>\n<p>This tells me that I am using the Intel hardware driver, and it also shares information related with the specific Intel GPU I have (<em>SandyBridge<\/em>).<\/p>\n<p><strong>Forcing a software driver<\/strong><\/p>\n<p>I have mentioned that having software drivers available comes in handy at times, but how do we tell the loader to use them? Mesa provides an environment variable that we can set for this purpose, so switching between a hardware driver and a software one is very easy to do:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n# LIBGL_DEBUG=verbose LIBGL_ALWAYS_SOFTWARE=1 glxgears \r\nlibGL: OpenDriver: trying \/usr\/lib\/x86_64-linux-gnu\/dri\/tls\/swrast_dri.so\r\nlibGL: OpenDriver: trying \/usr\/lib\/x86_64-linux-gnu\/dri\/swrast_dri.so\r\n<\/pre>\n<p>As we can see, setting <em>LIBGL_ALWAYS_SOFTWARE<\/em> will make the loader select a software driver (<em>swrast<\/em>).<\/p>\n<p>If I force a software driver and call <em>glxinfo<\/em> like I did before, this is what I get:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n# LIBGL_ALWAYS_SOFTWARE=1 glxinfo | grep -i &quot;opengl renderer&quot;\r\nOpenGL renderer string: Software Rasterizer\r\n<\/pre>\n<p>So it is clear that I am using a software driver in this case.<\/p>\n<p><strong>Querying the driver for OpenGL features<\/strong><\/p>\n<p>The <em>glxinfo<\/em> program also comes in handy to obtain information about the specific OpenGL features implemented by the driver. If you want to check if the Mesa driver for your hardware implements a specific OpenGL extension you can inspect the output of glxinfo and look for that extension:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n# glxinfo | grep GL_ARB_texture_multisample\r\n<\/pre>\n<p>You can also ask glxinfo to include hardware limits for certain OpenGL features including the <em>-l<\/em> switch. For example:<\/p>\n<pre class=\"brush: plain; title: ; notranslate\" title=\"\">\r\n# glxinfo -l | grep GL_MAX_TEXTURE_SIZE\r\nGL_MAX_TEXTURE_SIZE = 8192\r\n<\/pre>\n<p><strong>Coming up next<\/strong><\/p>\n<p>In my next posts I will cover the directory structure of the Mesa repository, identifying its main modules, which should give Mesa newcomers some guidance as to where they should look for when they need to find the code that deals with something specific. We will then discuss how modern 3D hardware has changed the way GPU drivers are developed and explain how a modern 3D graphics pipeline works, which should pave the way to start looking into the real guts of Mesa: the implementation of shaders.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Recap In my previous post I explained that Mesa is a framework for OpenGL driver development. As such, it provides code that can be reused by multiple driver implementations. This code is, of course, hardware agnostic, but frees driver developers from doing a significant part of the work. The framework also provides hooks for developers &hellip; <a href=\"https:\/\/blogs.igalia.com\/itoral\/2014\/09\/04\/driver-loading-and-querying-in-mesa\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Driver loading and querying in Mesa&#8221;<\/span><\/a><\/p>\n","protected":false},"author":16,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[],"class_list":["post-415","post","type-post","status-publish","format-standard","hentry","category-graphics"],"_links":{"self":[{"href":"https:\/\/blogs.igalia.com\/itoral\/wp-json\/wp\/v2\/posts\/415","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.igalia.com\/itoral\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.igalia.com\/itoral\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.igalia.com\/itoral\/wp-json\/wp\/v2\/users\/16"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.igalia.com\/itoral\/wp-json\/wp\/v2\/comments?post=415"}],"version-history":[{"count":4,"href":"https:\/\/blogs.igalia.com\/itoral\/wp-json\/wp\/v2\/posts\/415\/revisions"}],"predecessor-version":[{"id":419,"href":"https:\/\/blogs.igalia.com\/itoral\/wp-json\/wp\/v2\/posts\/415\/revisions\/419"}],"wp:attachment":[{"href":"https:\/\/blogs.igalia.com\/itoral\/wp-json\/wp\/v2\/media?parent=415"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.igalia.com\/itoral\/wp-json\/wp\/v2\/categories?post=415"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.igalia.com\/itoral\/wp-json\/wp\/v2\/tags?post=415"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}