1

I'm using the WinAPI to grab a bitmap of your monitor and then add that data to a texture. The problem however is that the GetDIBits function writes its color-data (lpPixels parameter) in BGR-format as opposed to RGB. Thus, assigning this data to a texture, which uses a RGB-formatted byte array, makes the order wrong. One can easily just make a for/while loop and just iterate through the arrays and fix the order, however, this process is extremely slow. You could also just directly assign the BGR-array to the RGB-array but this results in a texture which has the wrong RGB-order! On the other hand, the second method is extremely fast, which is exactly what I am looking for.

I suppose there might be ways to use bitmasks within the WinAPIs BITMAPINFO struct, but I do not know how or even if that would be possible. There might even be a variable of some sort which determines the color-order used by the WinAPI, either way, I haven't been able to find such a variable. Hence, my question: How do I quickly assign a BGR-formatted array to a RGB-formatted one?

Slow way of converting BGR to RGB:

for (size_t i = 0; i < myWidth * myHeight; i++)
    {
        size_t tempIndex = (i * 4);

        // The colors are in BGR-format (windows format)
        // Hence, the order is reversed
        rgbPixels[tempIndex] = bgrPixels[tempIndex + 2]; // r
        rgbPixels[tempIndex + 1] = bgrPixels[tempIndex + 1]; // g
        rgbPixels[tempIndex + 2] = bgrPixels[tempIndex]; // b
        rgbPixels[tempIndex + 3] = 255; // a (always 255)
    }
  • 1
    @RemyLebeau: If one is using `-fno-strict-aliasing`, loading groups of three 8-byte chunks, and then using bit shifts to rearrange their contents, and then writing three 8-byte chunks, may be faster than reading 24 individual bytes and writing 24 individual bytes. Whether it's actually faster will depend upon factors like cache access patterns. – supercat Feb 05 '21 at 18:24
  • Depending on your compiler it might be somewhat faster to read a dword, processs that, then write it out, rather than the several array reads and writes for each pixel that you have now. – 500 - Internal Server Error Feb 05 '21 at 18:27
  • 2
    I am not sure what API you are using for loading the texture map, but generally there is a way to specify BGR instead of RGB. For example, int OpenGL you can specify `GL_BGRA`. A lot of hardware uses this format anyway, – wcochran Feb 05 '21 at 18:27
  • There is possibly a workaround to get RGB instead of BGR by using the BITMAPINFO->bmiHeader->biCompression = BI_BITFIELDS. Also the bmiColors field must be set. Never tried it, but you may want to check this link: https://stackoverflow.com/questions/9606906/saving-bmp-file-using-hbitmap-createdibsection-in-c-win32 – Sven Nilsson Feb 05 '21 at 18:42
  • Isn't this something that SSE's register shuffling can do faster than anything else? Haven't been following CPU technologies closely for decades, so this may no longer be the case. – IInspectable Feb 05 '21 at 18:47
  • @IInspectable no need in SSE, just good old `BSWAP32` and a shift+or – Ruslan Feb 05 '21 at 19:24
  • @rus Isn't `BSWAP` fixed to reverse the bytes in a register? If so, how would you then swap the first and third byte, and keep the second and fourth byte in place? Would that not then require additional shifting and masking? And if so, would it still perform better than an SSE/AVX implementation? – IInspectable Feb 05 '21 at 19:34
  • @IInspectable yeah, you may be right, `pshufb` should be faster. – Ruslan Feb 05 '21 at 19:54
  • Please refer: [Fast vectorized conversion from RGB to BGRA](https://stackoverflow.com/questions/7194452/fast-vectorized-conversion-from-rgb-to-bgra) – Strive Sun Feb 07 '21 at 03:09

0 Answers0