Monday 30 November 2015

Piping Doxygen output to Github Pages for automatic navigation

Github Pages is a wonderful system for building a website. It works using Git. You edit your files locally, push them to Github, and the site automatically updates. docs.simul.co uses it for Simul's documentation. One great thing about gh-pages is that because you edit it locally, you can use something like Sublime Text to edit the files, which still, in 2015, is so much more responsive than editing online with all the latency that entails.

Gh-pages uses a system called Jekyll, which is also great. While the site can take straight-up html files and reproduce them on the site, it also understands Markdown syntax. While html is a text format, it's hard to write - you often want to use a specialized editor - but these end up filling your file with unnecessary cruft - repeated format tags and so on. Markdown is much simpler - it's plain text with a few conventions, for instance:

Heading
--------

when compiled to html by Jekyll, becomes:

Heading

So if you put a file in your repo called test.md, that becomes a page on your website called test.html. It will only be used if it has Jekyll Front Matter at the top, like so:

---
title: Introduction
layout: reference
url: Introduction
---

Jekyll will format it, and apply a theme if you have one. The sites it generates are generally good-looking.

So that's all great

but most of my interesting stuff comes from the Simul source code - I use Doxygen to generate documentation from source. Based on formatted comments, Doxygen creates html (and various other formats if desired) docs.

So what I wanted was to pipe the doxygen output into my Jekyll site, but keep the Jekyll formatting, and generate a consistent nav bar that looked the same whether you were in the Doxygen-created automatic docs, or the static markdown-based site.

Now Doxygen can't generate markdown. It can use markdown as an input - and create html from it just as Jekyll does. Fortunately, Jekyll doesn't insist on having markdown as an input. If you put a plain html file in a Jekyll site, it will be ignored, but if you add some Jekyll front matter to the top of your html as plain text, it will be included in the Jekyll site. The front matter makes it a wrong html file, so it will only work properly within Jekyll.

So the first step to get the Doxygen content into the Pages site was to create a special jekyll_header.html that Doxygen would use, which has the front matter at the top, like so:

---
title: $title
layout: reference
---
<!-- HTML header for doxygen 1.8.9.1-->
... more typical doxygen stuff here...

Doxygen replaces $title with the page title. We specify "reference" as the layout so that we can create a special Jekyll layout if needed for the docs.

So now Doxygen will build html files which, if copied into the Pages repository, will appear in the website with Jekyll styling.

The whole point of this is automation. We use Jenkins, with a project set up to run doxygen on the source code. It's arranged to that the Doxygen configuration file has these settings, which read environment variables:

HTML_OUTPUT            =$(HTML_OUTPUT)
HTML_HEADER            =$(HTML_HEADER)
HTML_FOOTER            =$(HTML_FOOTER)

Then we call doxygen twice with output to two different folders - once to generate the standard compiled html (chm) help file, and once with the jekyll header to prepare the docs for Pages.

A separate Jenkins project then copies the output into the "reference" directory in the Pages repo. Before this, we delete the entire contents of this directory, because any files that were not regenerated by Doxygen should be removed from the folder - otherwise they'll still show up on the site. Then we git commit, git push, and the site should update.

This much will get the generated docs into Jekyll, and the Jekyll styling will be applied, if you've created the "reference" layout (any good Jekyll tutorial can help you with this).

Doxygen is probably the best docs-generator of its kind, but there's a lack of control. The html generated can have a navigation tree on the side, but the generated tree uses frames, a relic of the 90's which doesn't play well with modern site design, much less with the mobile web. Jekyll on the other hand, can render very nicely on mobile, and with a bit of work, can display a nice modern html navigation bar.

So the next step was to try to fix up the left-hand-side navigation tree for the Doxygen content.

Our existing method relies on the directory structure of the website: each folder is a level of the tree, with the filename being the bottom level. That doesn't work for Doxygen content because Doxygen doesn't generate a directory tree structure, but a single flat directory, full of files with names like "classsimul_1_1base_1_1EnvironmentVariables.html".

In the Jekyll _includes directory, create an html file called something like "ref_sidebar.html", and fill it with:
<div class="sidebar">
  <div class="container sidebar-sticky">
    <div class="sidebar-about">
      <h1>
        <a href="{{ site.baseurl }}">
          {{ site.title }}
        </a>
      </h1>
      <p class="lead">{{ site.description }}</p>
    </div>
    <nav class="sidebar-nav">
    </nav>
  </div>
</div>


Now inside the "sidebar-nav", we will put the Jekyll/liquid code.
{% assign sorted_pages = site.pages | sort: "url" %}

This is the first step - we create a sorted list of all the url's in the site. It's pretty fast. I don't know if it's possible to create an array of structs in Liquid, so we create some blank arrays that we'll fill up with properties of the various pages.

{% assign this_path = "" %}

{% assign pages = site.array %}
{% assign paths = site.array %}
{% assign titles = site.array %}
{% assign path_sizes = site.array %}

Then we're going to go through all the pages (again, not slow), and from the url's we will create a "path" for each page with "/" as a separator. For example, the page
{% for node in sorted_pages %} {% assign path = node.url | remove: "/index.html" %}
So the path is formed initially from the url, knocking off the trailing "/index.html" that Jekyll may have generated. This is so that the main page of any tree branch will look like the root of the branch. Then we discard some pages that we don't want:

{% if path contains "/dir_" or path contains "/struct" or path contains "/functions" or path contains "/namespacemembers" or path contains "graph_legend" or path contains "google" %} {% continue %} {% endif %}
If a page refers to a source file, doxygen gives it a filename ending in _source.html, for example, "ChunkInputOutput_8h_source.html" would be the page generated for the source file "ChunkInputOutput.h" . In this case, if it's in the "reference" folder, we make it a child of "/source/", so all the source pages get grouped together.

{% if path contains "_source.html" %} {% assign path = path | replace: "reference/","reference/source/" %} {% endif %}

Similarly, the page generated for the class simul::base::BaseProfilingInterface would be called "classsimul_1_1base_1_1BaseProfilingInterface.html". We want this to be listed under the page "classes.html", which is doxygen's class list. But we also want it to be in a tree structure, so its full path should read "reference/classes/simul/base/BaseProfilingInterface". The following code achieves this. It replaces "_1_1" (which represents "::") with "/". It replaces "reference/class" with "reference/classes", so that the class definitions will be children of "classes". But that would turn the actual "classes.html" into "classeses.html". So we fix that too. We remove any ".html" extension so that tree parents are properly recognized. Various other functions are performed: "_8" goes back to ".".
Note also that we replace "_ooo" with "/". I've chosen "_ooo" as a separator in doxygen source filenames (not source code, just text documents that doxygen should interpret). This is so we can get proper parent-child relationships in such documents.
{% assign path = path | replace: "reference/class","reference/classes/" | replace: "reference/classeses","reference/classes" | remove: ".html" | replace: "_1_1","/" | replace: "_01"," " | replace: "_8","." | remove_first: "/" | replace: "_ooo","/" %}

Now we'll store some useful information: how many parts (separated by "/") are in the path?

{% assign psz = path | size %} {% assign path_parts = path | split: '/' %} {% assign path_parts_size = path_parts | size %}
And we're ready to push our path onto the list.
{% assign paths = paths | push: path %} {% assign pages = pages | push: node %} {% assign path_sizes = path_sizes | push: path_parts_size %} We fix up the title to look friendlier. We're going to use this in the nav tree.
{% assign title = node.title | remove: " Source File" | remove: " Class Reference" %} {% assign titles = titles | push: title %}
And finally we check if this is the current page.
{% if node.url == page.url %} {% assign this_path = path %} {% assign this_node = node %} {% assign this_index = forloop.index0 %} {% endif %} {% endfor %}

Having prepared

all that, we can now construct the nav tree using nested <ul> and <li> tags:
<ul>
{% assign menu_level = 0 %}

We iterate through the list "pages" that we've just created. The forloop index corresponds for "pages", "paths", "titles" and so on. Remember to use forloop.index0. Just "index" would start from 1 and give you the wrong page.

{% for node in pages %} {% assign node_path = paths[forloop.index0] %} {% assign node_title = titles[forloop.index0] %} {% assign node_path_parts = node_path | split: '/' %} {% assign node_path_parts_size = path_sizes[forloop.index0] %} {% if node_title == "404" %} {% continue %} {% endif %}

At the first level of the nav tree, we only want single-part paths:

{% unless node_path_parts_size == 1 %} {% continue %} {% endunless %} <li> <a class="sidebar-nav-item{% if page.url == node.url %} active{% endif %} sidebar-1" href="{{ node.url }}">{{ node_title }}</a></li>

NOW,

if the path of the page you're viewing contains the path of the page in the list, we'll expand its children!
{% if this_path contains node_path %}

We'll build new lists containing only the children of this parent:
{% assign pages2 = site.array %} {% assign titles2 = site.array %} {% for node2 in pages %}

and only two-level paths at this stage:

{% unless path_sizes[forloop.index0] == 2 %} {% continue %} {% endunless %} {% assign path2 = paths[forloop.index0] %} {% if path2 contains node_path and node2.url != node.url %} {% assign pages2 = pages2 | push: node2 %} {% assign titles2 = titles2 | push: titles[forloop.index0] %} {% endif %} {% endfor %}
{% if pages2.size > 0 %} {% assign menu_level = 1 %} <ul> {% for node2 in pages2 %} <li><a class="sidebar-nav-item{% if page.url == node2.url %} active{% endif %} sidebar-2" href='{{node2.url}}'>{{ titles2[forloop.index0] }}</a></li> {% endfor %}

Now this is the point where you might want to add more levels to the tree. Otherwise, close out the <ul> and the rest is just tidy-up.

</ul> {% endif%}
{% endif %}
{% endfor %} <<!-- node in pages -->
{% for num in (1...menu_level) %} </ul> {% endfor %} </ul>


Tuesday 27 October 2015

Generating mipmaps for 3D textures

Mip-mapping is very useful, and sometimes we want to generate the mips of a texture in a shader. In DirectX 11 hlsl this is tricky because you can't read from the resource that you're writing to.

For example, you might have a 3D texture that you've filled in with a compute shader. You then want to generate its mipmaps from the original texture. But the ShaderResourceView you created can't be read while you're writing to. It will silently fail - unless you have Direct3D debug output enabled, in which case you'll get a warning.

You probably created the SRV like this:

  D3D11_SHADER_RESOURCE_VIEW_DESC srv_desc;
  ZeroMemory(&srv_desc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
  srv_desc.Format                     = f;
  srv_desc.ViewDimension              = D3D11_SRV_DIMENSION_TEXTURE3D;
  srv_desc.Texture3D.MipLevels        = m;
  srv_desc.Texture3D.MostDetailedMip  = 0;
  d3D11Device->CreateShaderResourceView(texture, &srv_desc,&shaderResourceView);

which means that when you pass it to the hlsl shader, it contains all of the mips from 0 to m-1. What you want instead (or rather, as well), is a SRV for each individual mip:

D3D11_SHADER_RESOURCE_VIEW_DESC mip_srv_desc;
ZeroMemory(&mip_srv_desc, sizeof(D3D11_SHADER_RESOURCE_VIEW_DESC));
mip_srv_desc.Format                    = f;
mip_srv_desc.ViewDimension             = D3D11_SRV_DIMENSION_TEXTURE3D;
mip_srv_desc.Texture3D.MipLevels       = 1;
mip_srv_desc.Texture3D.MostDetailedMip = i;
d3D11Device->CreateShaderResourceView(texture, &mip_srv_desc, &mipShaderResourceViews[i]);
Then use these as input to the compute shader.

Thursday 22 October 2015

Unity fails to open a project, spuriously reports that it is open in another instance

Unity refuses to open the same project in two instances - this much is sensible. But when Unity crashes, sometimes it leaves behind a "Temp" folder in the project, and if this exists, you won't be able to reopen the project. So delete "Temp", and problem solved.

Wednesday 30 September 2015

Automatically Generated Nav Bar for Jekyll and Github pages

Github pages, which I use for the Simul documentation, uses Jekyll, which is great for building static websites and blogs.

I wanted to create an automatic two-level nav bar for my site, and after much searching, I found this approach, using the url's of the pages. The implementation didn't quite work for me, and I wanted multi-level navigation, so this is what I came up with:
      
      {% assign url_parts = page.url | split: '/' %}
      {% assign url_parts_size = url_parts | size %}
      {% if url_parts_size != 0 %}
        {% assign rm = url_parts | last %}
        {% assign base_url = page.url | replace: rm %}
      {% else %}
        {% assign base_url = page.url %}
      {% endif %}
      <ul>
      {% for node in site.pages %}
        {% assign node_url_parts = node.url | split: '/' %}
        {% assign node_url_parts_size = node_url_parts | size %}
        {% assign filename = node_url_parts | last %}
       
        {% if node_url_parts_size == 2  %}
            <li>
            <a class="sidebar-nav-item{% if page.url == node.url %} active{% endif %}" href="{{ node.url }}">{{ node.title }}</a></li>
            {% if page.url contains node.url %}
              <ul>
              {% for node2 in site.pages %}
                {% if node2.url contains node.url %}
                  <li><a href='{{node2.url}}'>{{node2.title}}</a></li>
                {% endif %}
              {% endfor %}
              </ul>
            {% endif %}
        {% endif %}
      {% endfor %}
      {% for num in (1...menu_level) %}
        </ul>
      {% endfor %}
      </ul>
      
I think this works. It just looks at all the site's pages, and prints up links for those with two parts to the URL: these are the first sub-level. If that URL is part of the URL of the current page, it does another loop, to find the current page's siblings.

UPDATE:

You could add further nav levels by putting extra inner for loops. Here's a more complete example from my site, that goes to three levels. (See also http://dbgdiary.blogspot.com/2015/11/piping-doxygen-output-to-github-pages.html Done)

{% assign sorted_pages = site.pages | sort: "url" %}

    {% assign this_path = "" %}

    {% assign pages = site.array %}
    {% assign paths = site.array %}
    {% assign titles = site.array %}
    {% assign path_sizes = site.array %}
    {% assign this_index = 100000000 %}


We've initialized some empty arrays here using site.array, which is defined in _config.yml at the site root as:

array: []


Next we build the arrays from the page list, tweaking Doxygen's filenames to produce a tree-like structure (doxygen's file structure is flat, but we want a tree of URI's):


    {% for node in sorted_pages %}
        {% assign path = node.url | remove: "/index.html" %}
        {% if path contains "/dir_" or path contains "/struct" or path contains "/functions" or path contains "/namespacemembers" or path contains "graph_legend" or path contains "google" or path contains "-members.html" or path contains "/classes.html" %}
          {% continue %}
        {% endif %}
        {% if path contains "_source.html" %}
          {% assign path = path | replace: "reference/","reference/source/" %}
        {% endif %}
        {% assign path = path | replace: "reference/class","reference/classes/" | replace: "reference/classes/es","reference/classes" | replace: "reference/namespaces","reference/classes" | remove: ".html" | replace: "_1_1","/" | replace: "_01"," " | replace: "_8","." | remove_first: "/" | replace: "_ooo","/" %}
        {% assign psz = path | size %}

        {% assign title = node.title | replace "Namespace List","Reference" | remove: "Files (x86)/Jenkins/jobs/Simul Installers/workspace/Simul/PRODUCTS/TrueSky/Help/" | remove: " Source File" | remove: " Class Reference" %}
        {% if title == "404" or path contains "search-results" %}
          {% continue %}
        {% endif %}
        {% assign path_parts = path | split: '/' %}
        {% assign path_parts_size = path_parts | size %}

        {% assign paths = paths | push: path %}
        {% assign pages = pages | push: node %}
        {% assign path_sizes = path_sizes | push: path_parts_size %}

        {% assign titles = titles | push: title %}
        {% if node.url == page.url %}
          {% assign this_path = path %}
          {% assign this_node = node %}
          {% assign this_index = forloop.index0 %}
        {% endif %}
      {% endfor %}

Having build the arrays, we now iterate through the page URI's from the outermost level to as many levels as we want. The first loop:
      {% assign menu_level = 0 %}
      {% for node in pages %}
        {% assign node_path = paths[forloop.index0] %}
        {% assign node_title = titles[forloop.index0] %}
        {% assign node_path_parts = node_path | split: '/' %}
        {% assign node_path_parts_size = path_sizes[forloop.index0] %}
        {% unless node_path_parts_size == 1 %}
          {% continue %}
        {% endunless %}
<li>
            <a class="sidebar-nav-item{% if page.url == node.url %} active{% endif %} sidebar-1" href="https://www.blogger.com/%7B%7B%20node.url%20%7D%7D">{{ node_title }}</a></li>
{% if this_path contains node_path %}
              {% assign paths2 = site.array %}
              {% assign pages2 = site.array %}
              {% assign titles2 = site.array %}

For the second loop we will iterate through all the pages, but only pick out the ones with two elements in the path, and only the ones that contain the path to the current parent in loop 1. First we build the array, pages2:
{% for node2 in pages %} {% unless path_sizes[forloop.index0] == 2 %} {% continue %} {% endunless %} {% assign path2 = paths[forloop.index0] %} {% if path2 contains node_path and node2.url != node.url %} {% assign paths2 = paths2 | push: path2 %} {% assign pages2 = pages2 | push: node2 %} {% assign titles2 = titles2 | push: titles[forloop.index0] %} {% endif %} {% endfor %}

Now iterate through pages2:

              {% if pages2.size > 0 %}
                {% assign menu_level = 1 %}
                <ul>
                {% for node2 in pages2 %}
<li><a class="sidebar-nav-item{% if page.url == node2.url %} active{% endif %} sidebar-2" href="https://www.blogger.com/%7B%7Bnode2.url%7D%7D">{{ titles2[forloop.index0] }}</a></li>
{% assign path2 = paths2[forloop.index0] %}

                  {% if this_path contains path2 %}
Now the same process for pages3, build the array:
                    {% assign pages3 = site.array %}
                    {% assign titles3 = site.array %}
                    {% for node3 in pages %}
                      {% unless path_sizes[forloop.index0] == 3 %}
                        {% continue %}
                      {% endunless %}
                      {% assign path3 = paths[forloop.index0] %}
                      {% if path3 contains path2 and node3.url != node.url  %}
                        {% assign paths3 = paths3 | push: path3 %}
                        {% assign pages3 = pages3 | push: node3 %}
                        {% assign titles3 = titles3 | push: titles[forloop.index0] %}
                      {% endif %}
                    {% endfor %}

And iterate through the array for the third level:
{% if pages3.size > 0 %} {% assign menu_level = 1 %} <ul> {% for node3 in pages3 %} <li><a class="sidebar-nav-item{% if page.url == node3.url %} active{% endif %} sidebar-3" href="https://www.blogger.com/%7B%7Bnode3.url%7D%7D">{{ titles3[forloop.index0] }}</a></li> {% endfor %} </ul> {% endif%} {% endif %} {% endfor %} </ul> {% endif%} {% endif %} {% endfor %}
That's it for a set of Doxygen html pages - if your output is not from Doxygen the process may be simpler.

Saturday 29 August 2015

Building icu statically for linkage to Qt

It's bad enough having to link to all the Qt dll's without having to distribute its various dependencies as well - OpenSSL and  ICU chiefly among them. Then if you write a dll that plugs into someone else's exe you need to watch out that you could be trying to load a different version of a dependency dll that's used elsewhere in the exe.

So using static libs of the dependencies to link when you build Qt should help a lot. OpenSSL has some nice well-maintained static windows binaries (https://www.openssl.org/related/binaries.html), but icu does not.

There is this: http://www.npcglib.org/~stathis/blog/precompiled-icu/

But it uses static runtimes. So if you want a static build with dynamic (MD) runtimes, you're out of luck.

Building with Visual Studio

The Visual Studio solution all_in_one.sln that comes with ICU only builds dynamic libs. So you can modify the projects in the solution to link statically. Make sure that the output debug libraries have a suffix 'd' to their filenames, because they'll be built in the same directory as the release libraries.

Building with make

The recipe to build static ICU with MSVC is:

cd "%WORKSPACE%\source\"
set PATH=C:\cygwin\bin;%PATH%
call "C:\Program Files (x86)\Microsoft Visual Studio 11.0\VC\vcvarsall.bat" x86
dos2unix -f *
dos2unix -f configure
dos2unix -f mkinstalldirs

bash runConfigureICU Cygwin/MSVC -prefix=/cygdrive/d/Jarvis/icu_static/dist -enable-static -disable-shared
dos2unix -f install-sh

make && make install


Dos2unix prevents errors of the form '\r unknown command' in the make script.

Path order is crucial. If you call vcvarsall.bat before adding cygwin\bin to the path, you'll get something like:

icupkg: unable to open input file
/cygdrive/d/icu/win32-x86/data/out/build/icudt55l\coll\root.res"

But if you add cygwin/bin after %PATH%, you'll get something like:

link.exe is not a valid executable.

So only the above order works.

Output

You'll get these files in lib (for Win32) or lib64 (for x64):

icudt.lib icuin.lib
icuio.lib
icule.lib
iculx.lib
icutest.lib
icutu.lib
icuuc.lib
testplug.lib

and for debug:
icudtd.lib icuind.lib
icuiod.lib
iculed.lib
iculxd.lib icutestd.lib
icutud.lib
icuucd.lib testplugd.lib

When you come to build Qt, set an ICU environment variable to the parent icu directory, and in the Qt make command add the options:

-icu -I "%ICU%\include" -L "%ICU%\%LIB_OR_LIB64%"

where LIB_OR_LIB64 is "lib" or "lib64" depending on the platform.

Thursday 20 August 2015

Help Qt Designer to find plugins

Qt Designer can't find plugins without QT_PLUGIN_PATH being set. You should also set QT_QPA_PLATFORM_PLUGIN_PATH for the Qt gui applications. If you're writing your own Qt exe, you can set these paths internally.
set QTDIR=C:/Qt/qt5_msvc2012_x64_build/qtbase
set QT_PLUGIN_PATH=%QTDIR%/plugins
set QT_QPA_PLATFORM_PLUGIN_PATH=%QTDIR%/plugins/platforms
Note also that Qt Designer will only load plugins built with the same libraries. And when you do a debug build of Qt, although it appends "d.dll" to its dll's, it does not append "d" to its executables. So a debug build of Qt Designer, in the same Qt distribution as release, will overwrite the release build, thus preventing your plugins from loading! So always build debug first, then release.

Cygwin connecting by ssh to remote Linux

If ssh can't add your server to its list of known hosts, you may need to create a "passwd" file in C:\cygwin\etc. Use:

mkpasswd -l -p "$(cygpath -H)" > /etc/passwd

Thursday 6 August 2015

Using Sublime Text Search+Replace to clean Visual Studio Projects

The find-in-files functionality of Sublime Text can be used to find end remove bad settings from Visual Studio project files - handy if you have a lot of projects.

Search for: <ShowProgress>LinkVerboseLib</ShowProgress>\n
and replace it with nothing. That hides a lot of unneeded output.

Replace:

<LinkLibraryDependencies>true</LinkLibraryDependencies>

with
<LinkLibraryDependencies>false</LinkLibraryDependencies>

To stop MSBuild from linking stuff you don't want lunk.

Sunday 19 July 2015

Windows keyboard stops working

If your keyboard in Windows ever just stops working, but it's clearly not a hardware problem as you can still log-in - it just doesn't work once you have - look for an icon in the bottom-right (the notification area) called FilterKeys.

Double-click the icon, turn off all its nonsense, and the keyboard should start working again.

Wednesday 15 July 2015

Visual Studio to English translation

In Visual Studio, if you get an error that reads:

"This project doesn't contain the Configuration and Platform combination of Debug|Win32"

and you're not even building Debug or Win32, what Visual Studio is actually trying to tell you is:

"This project has a dependency project that isn't loaded in the current solution."


Monday 13 July 2015

Jenkins CI on Windows - Git can't access remote submodules - even public ones.

I'm setting up Jenkins on a windows machines, looks great. But after setting up all the credentials, projects with Git submodules cause a problem - we get git authentication errors.

These errors go away if you set the environment variable HOME to the parent of your .ssh directory. There's also a JENKINS_HOME variable. Possibly setting this and copying the .ssh directory to Program Files (x86)/Jenkins might have the same effect, but I've not tested that yet.

Multi-platform CMake

The latest CMake 3.3 allows you to separately specify the generator (i.e. what compiler to make projects for) and the platform, using the -G and -A command line parameters respectively. That's especially good for Visual Studio, as you can do something like this:

cmake -G "Visual Studio 11 2012" -A x64 -D CMAKE_MAKE_PROGRAM=C:\Windows\Microsoft.NET\Framework\v4.0.30319\MSBuild.exe "C:workspace\source_dir"

 Even better, the -A switch recognizes "x64" as a platform, even though the generator is officially called "Visual Studio 11 2012 Win64". So that will play nicely with environment variables, e.g.
SET PLATFORM=x64

Thursday 2 July 2015

Subtle problems linking dll's built with different compilers

You should generally try to link DLL's and exe's built with the same compiler. I recently had an issue where I redirected C++ std::cout and cerr in my exe, but got no apparent output from these functions in my linked DLL.

Turns out, the exe, being new, was built with the Visual Studio 2013 (v120) toolset, while my DLL's, for backward compatibility, were using v110_xp - the Visual Studio 2012/Windows XP-compatible toolset. And because they used the MD dynamically linked runtimes, they were silently, and happily, loading two different versions of the runtime libraries.

Therefore, my redirects (std::cout.rdbuf() etc) were working on the exe's copy of the runtime, and of course, not on the DLL's, entirely different, runtime library.

Monday 29 June 2015

The Windows 8 SDK version of DirectX Compute shaders in hlsl seems to be broken:

void ComputeShader(uint3 sub_pos: SV_DispatchThreadID)

results in sub_pos=(0,0,0) every time.

Therefore, replace the input with:

void ComputeShader(uint3 g:SV_GroupID,uint3 t:SV_GroupThreadID)

and then:

uint3 sub_pos = g * BLOCK_SIZE + t;

Wednesday 10 June 2015

Compiling HLSL effect files for OpenGL: Part 2 - translating HLSL syntax to GLSL

I'll talk here about some of the approaches used to enable HLSL syntax parsing for GLSL. The best resource I know for Flex/Bison parser generators is "Flex and Bison" by John Levine.

After the initial implementation of the effect parser for GLSL, I had a set of about 20 effect files (I use the .sfx extension) which use another 40-ish include files (.sl files) for shared definitions. At the top of each .sfx we had:

#include "shader_platform.sl"

- and "shader_platform.sl" was different for each API, containing #defines that allowed the same code to be compiled for HLSL and GLSL. For read-writeable texture load and store (as opposed to sampling) we had for GL:

 #define IMAGE_LOAD(tex,pos) imageLoad(tex,int2(pos))
 #define IMAGE_LOAD_3D(tex,pos) imageLoad(tex,int3(pos))
 #define IMAGE_STORE(tex,pos,value) imageStore(tex,int2(pos),value)
 #define IMAGE_STORE_3D(tex,pos,value) imageStore(tex,int3(pos),value)


whereas for HLSL, we had:

 #define IMAGE_LOAD(tex,pos) tex[pos]
 #define IMAGE_LOAD_3D(tex,pos) tex[pos]
 #define IMAGE_STORE(tex,pos,value) tex[pos]=value;
 #define IMAGE_STORE_3D(tex,pos,value) tex[pos]=value;


I didn't want to force users to include a special file to get standard HLSL shaders to work, and I didn't want to force them to use these ugly macros where the HLSL syntax is usually more elegant. So - delving into the Bison .ypp file where I'd added the C grammar, I put something like this:

postfix_exp '[' expression ']'
{
 $$.varName=$1.text;
 $$.index=$3.text;
// Is it actually a texture we're indexing?
 GLTextureType glTextureType=GetTextureType(buildFunction,$$.varName);
 if(glTextureType==0)
 {
    $$.text=($$.varName+"["+)+$$.index+"]";
 }
 else
 {
 ostringstream str;
  bool rw=IsRWTexture(glTextureType);
  if(rw)
   str<<"imageLoad(";
  else
   str<<"texelFetch(";
  }
  str<<$$.varName<<",ivec"<<GetTextureDimension(glTextureType)<<"("<<$$.index<<")"<<(rw?"":",0")<<")";
$$.text=str.str();
  }
}
This looks at any expression of the form A[B] and tries to see if A is a texture or image (as GLSL calls read-write textures), and replaces the expression with an imageLoad or a texelFetch. But postfix_exp '[' expression ']' actually recognizes A[B] even if it's on the right-hand-side. So,

outputTexture[pos]=result

would then become:

imageLoad(outputTexture,ivec2(pos))=result

- which is wrong. But that's fine as long as further up the line we match:

unary_exp '=' assignment_exp
   
- where unary_exp matches the A[B] expression, and assignment_exp matches the RHS. In this case the imageLoad is replaced with an imageStore, and the whole thing becomes:

imageStore(outputTexture,ivec2(pos),result)

Which is correct GLSL. Note: we wrap pos in ivec2() to convert it - just in case it's an unsigned int vector (a uvec2). Many GLSL compilers will complain about implicit conversion, whereas HLSL just steams through - so adding the explicit conversion gives us HLSL-style behaviour. If it's already an ivec, the conversion should optimize out at the GLSL-compile stage.

Texture Dimensions

For obtaining texture sizes in GL, we had:

#define GET_DIMENSIONS(tex,X,Y) {ivec2 iv=textureSize(tex,0); X=iv.x;Y=iv.y;}
#define GET_DIMENSIONS_3D(tex,X,Y,Z) {ivec3 iv=textureSize(tex,0); X=iv.x;Y=iv.y;Z=iv.z;}



While for HLSL, we had definitions like this:

#define GET_DIMENSIONS(tex,x,y) tex.GetDimensions(x,y)
#define GET_DIMENSIONS_3D(tex,x,y,z) tex.GetDimensions(x,y,z)



You can see that we've been forced to use two separate macros for 2D and 3D, in order to know whether we're using an ivec2 or an ivec3 in GLSL. In this case, the bare GLSL textureSize() functions are more succinct than HLSL's oddball approach of multiple individual output parameters. But the goal here (for now) is to support the HLSL syntax so that forces the complex macros you see above.

We do this by matching GetDimensions as a token in the lexer:

<in_shader>"GetDimensions" {          stdReturn(GET_DIMS);

and  in the parser:

get_dims_exp: postfix_exp '.' GET_DIMS
{
 string texture=$1.text;
 string command=$3.text;
}



So when we match:

 get_dims_exp '(' assignment_exp ',' assignment_exp ')'


...we have sufficient information to construct an expression of the form:

{ivec2 iv=textureSize(tex,0); X=iv.x;Y=iv.y;}


where in this case X and Y are the two assignment_exps.

The first part of this series is here; the code is at github.

Thursday 4 June 2015

Compiling HLSL effect files for OpenGL: Part 1



The images above were rendered in different API's - the left image is DirectX 11, the right OpenGL. They were rendered with the same code in C++ - a wrapper class interprets my high-level rendering API to DX or GL interchangeably; this is not so unusual.

What's interesting here is that as well as the same C++ code, these two images were rendered with the same shaders. And that those shaders are pretty much standard HLSL .fx files. For example, here's the file to render text:

//  Copyright (c) 2015 Simul Software Ltd. All rights reserved.
#include "shader_platform.sl"
#include "../../CrossPlatform/SL/common.sl"
#include "../../CrossPlatform/SL/render_states.sl"
#include "../../CrossPlatform/SL/states.sl"
#include "../../CrossPlatform/SL/text_constants.sl"
uniform Texture2D fontTexture;

shader posTexVertexOutput FontVertexShader(idOnly IN)
{
 posTexVertexOutput OUT =VS_ScreenQuad(IN,rect);
 OUT.texCoords  =vec4(texc.xy+texc.zw*OUT.texCoords.xy,0.0,1.0).xy;
 return OUT;
}

shader vec4 FontPixelShader(posTexVertexOutput IN) : SV_TARGET
{
 vec2 tc  =IN.texCoords;
 tc.y  =1.0-tc.y;
 vec4 lookup =fontTexture.SampleLevel(samplerStateNearest,tc,0);
 lookup.a =lookup.r;
 lookup  *=colour;
 return lookup;
}

VertexShader vs = CompileShader(vs_4_0, FontVertexShader());

technique text
{
    pass p0
    {
 SetRasterizerState( RenderNoCull );
 SetDepthStencilState( DisableDepth, 0 );
 SetBlendState(AlphaBlend,vec4( 0.0, 0.0, 0.0, 0.0), 0xFFFFFFFF );
        SetGeometryShader(NULL);
 SetVertexShader(vs);
 SetPixelShader(CompileShader(ps_4_0,FontPixelShader()));
    }
}

A few things to notice: we include "shader_platform.sl" at the top; that's different for each API. For GL for example, it defines float2 as vec2, float3 as vec3, and so on. For DX, it defines out "uniform" so that's ignored. There are many aspects to the shader language differences that can be papered over with #defines. But when we get to something like:

           fontTexture.SampleLevel(samplerStateNearest,tc,0);

That's quite different syntax from the GLSL, which doesn't support separate texture and sampler objects.

We use "shader" to declare functions that will be used as shaders to distinguish them from utility functions. The DX11-style "CompileShader" commands create a compiled shader object for later use in technique definitions.

In techniques, we define passes, and in passes we can set render state: culling, depth test, blending - all that can be taken out of C++, leading to much cleaner-looking rendercode.

Quite aside from the cross-platform advantage, this is much easier to work with than standard GLSL, which would require a separate file for the vertex and fragment (pixel) shader, doesn't support #include, and has no concept of "Effect files" - which contain techniques, passes and state information: we would have to do all that setup in C++.

How's it done? I started off with glfx, an open-source project to allow Effect files for GLSL. Glfx passes-through most of the file, stopping to parse the parts that plain GLSL compilers don't understand. Glfx converts a source effect file into a set of individual shader texts (not files - it doesn't need to save them) - that can then be compiled with your local OpenGL.

 GLint effect=glfxGenEffect();
 glfxParseEffectFromFile(effect, "filename.glfx");

Having branched glfx to our own repo, it became apparent that it might actually be possible to adapt it to something that would, rather than adding Effect functionality to GLSL, simply understand DirectX 11-class HLSL fx files. To do this, rather than passing over the function/shader contents, it would be necessary to parse them completely. Glfx uses Flex and Bison, the GNU parser-generation tools. As GLSL and HLSL are C-based languages, I took the Bison-style Backus-Naur Form of C and added it to Glfx, so that

           fontTexture.SampleLevel(samplerStateNearest,tc,0);

can be automatically rewritten, not as

           textureLod(fontTexture,0);

but as:
textureLod(fontTexture_samplerStateNearest,0);

.. which in turn requires changing the sampler and texture definitions: we do all this automagically. Essentially, we've built separate samplers and textures as a feature into GLSL where it didn't exist before - we can set samplers like so:

glfxSetEffectSamplerState(effect,"samplerStateNearest", (GLuint)sampler);

or just define them in the effect files or headers, just like in HLSL:

SamplerState samplerStateNearest :register(s11)
{
 Filter = MIN_MAG_MIP_POINT;
 AddressU = Clamp;
 AddressV = Clamp;
 AddressW = Clamp;
};

It's conceivable that what we now have should really not be called glfx any more - it's quite different to the original project and I'm mainly concerned with cross-API compatibility, rather than specifically adding functionality to GLSL. The new library supports Pixel, Vertex, Geometry and Compute shaders, constant buffers and structured buffers, technique groups, multiple render targets, passing structures as shader input/output - most of the nice things that HLSL provides.

But more than any of that, it means I only need to write my shaders once.

In Part 2, I'll delve into how the translation is implemented using Flex and Bison parser generators.

Thursday 14 May 2015

Gfx.waitForPresent in Unity

Gfx.waitForPresent taking a lot of CPU time in Unity? That means the CPU is waiting for the GPU - so ignore the CPU times and profile the GPU.
http://forum.unity3d.com/threads/gfx-waitforpresent.211166/

Sunday 10 May 2015

GLSL constant buffers - alignment problems

Uniform buffers in GLSL - arrays of mats seem to destroy the alignment of the values afterwards.

layout(std140) uniform ConstantB
{

uniform mat4 views[6]; 

uniform float texCoord;  <-- this doesn't work.
uniform float gamma;
uniform float interp;
uniform float brightness;
}


Monday 20 April 2015

So I'm working hard on make OpenGL work like DirectX 11, and come to the problem of depth.

GL expects you to use a projection matrix that transforms near z to -1.0, and far z to 1.0, which is a horrible use of numerical precision. Behind the scenes, GL will then map from [-1.0,1.0] to [0.0,1.0] to give you a nonzero depth in your buffer.

DirectX expects you to use a projection matrix that transforms near to 0 and far to 1. It doesn't need to map to [0.0,1.0] because you've already given it the range it's expecting. You can also have far as 1 and near as 0, which is actually much better for numerical precision reasons.

So if you use the same projection matrix, in the "same" vertex shader, in GL and DX, you'll get different depths. What comes out as z=0.0 in DirectX, will come out as z=0.5 in OpenGL.

glDepthRange to the rescue! This function controls the mapping from the values you actually send to GL to the values it puts in the depth buffer. If you leave it as the default, or pass glDepthRange(0.0,1.0), it will map [-1,1] to [0,1]. So if we want to leave the numbers untouched, we just pass glDepthRange(-1.0,1.0), right?

Wrong! Because as the GL spec states,
depth values are treated as though they range from 0 through 1 (like color components). Thus, the values accepted by glDepthRange are both clamped to this range before they are accepted.
Yes, another boneheaded OpenGL spec snafu means that however much you may want to map [0,1] to [0,1], OpenGL won't let you. If you pass glDepthRange(-1.0,1.0), GL will clamp the -1.0 back up to zero, and the mapping will still go [-1,1] -> [0,1].

The solution? For NVIDIA hardware, you can use their extension glDepthRangedNV, which is not nerfed like the standard function. For AMD.... ?

Saturday 28 February 2015

Font Awesome is awesome unless you want your icon anywhere but the left-hand side

Use "right", or "pull-right" to fix that.

<i class="fa fontawesome-icon right pull-right fa-times-circle size-medium medium circle-" style="color:#dd3333"></i>

Sunday 18 January 2015

Resource file access in Qt

Qt resources in qrc files have a Prefix and a Path (which is the file path relative to the qrc file).

To access a resource as if it were a file, you need to use both, with a colon at the start to indicate that it's a resource, not an object on disk:

QFile::exists(":/Prefix/rel_Path/file.ext")

ostringstream is the perfect C++ replacement for sprintf, except...

ostringstream is the perfect C++ replacement for sprintf, except for trying to debug its contents in Visual Studio.
Add this to Microsoft Visual Studio 12.0\Common7\Packages\Debugger\Visualizers\stl.natvis:

<Type Name="std::basic_ostringstream&lt;char,*&gt;">
<DisplayString>{_Mystrbuf->_Gfirst},s</DisplayString>
<StringView>_Mystrbuf->_Gfirst,s</StringView>
<Expand>
<Item Name="[state]">_Mystate</Item>
<ExpandedItem>_Mystrbuf->_Gfirst</ExpandedItem>
</Expand>
</Type>