【问题标题】:Integer type to display 10-bits RGB for display整数类型显示 10 位 RGB 用于显示
【发布时间】:2018-11-04 10:33:19
【问题描述】:

我很难找到任何有关如何在 C 中为显示器实现 10 位 RGB 输出的开发人员文档,主要用于 Linux 上的 Xorg/Wayland 并尽可能与 Windows 兼容。

目前,我正在处理的应用程序(暗表)正在使用uint8_t 输出 RGB 值。 10 位 uint 的类型是什么?有没有办法从代码中检查 GPU/编解码器的 10 位支持?

【问题讨论】:

  • 您的显示器字面意思是否每像素使用 10 位,或者 - 与 15 位 RGB 一样 - 它是否有许多未使用的位?
  • 它必须有未使用的位。问题是这三种颜色是如何表示的。
  • X11、Wayland 和 Windows 是三个截然不同的野兽。甚至在一个问题中谈论 tgem 也没有多大意义。话虽如此,您在使用什么 API 时遇到了问题?
  • 好的,这些就是你的 API。 Cairo 表面可以使用 CAIRO_FORMAT_RGB30,它将红色、绿色和蓝色分量以连续的 10 位数量存储在一个 32 位字中,按照从低位到高位的顺序,最高 2 位未使用。见cairographics.org/manual/…。 AFAIK gdk pixbufs 不公开其内部格式,它们读取和写入 xpm(不太适合大型高彩图像)或“真实”图像格式(如 JPEG),因此不太清楚到底是什么问题他们。
  • 请参阅stackoverflow.com/questions/7704670/… 了解 gdk pixbufs 支持的格式列表。

标签: c xorg


【解决方案1】:

我在 Google 上搜索了一下,以澄清 10 位 RGB 的含义。

在维基百科Color Depth – Deep color (30/36/48-bit)我发现:

一些早期的系统将三个 10 位通道放在一个 32 位字中,其中 2 位未使用(或用作 4 级 alpha 通道)。

这似乎是我最合理的。

随之而来的是,红色有 10 位,绿色有 10 位,蓝色有 10 位,+ 2 位未使用(或为 Alpha 保留)。

这留下了两个问题:

  1. 它存储的是 RGBa 还是 BGRa 还是 aRGB? (我相信我在过去见过所有这些变化。)

  2. 组合值是存储小端还是大端?

当我在实际工作中遇到这种情况时,我基于一个假设进行了实现,渲染了一些测试模式,检查它是否看起来像预期的那样,如果没有交换相应的。实施中的部分。没什么,我很自豪,但是恕我直言,我以最少的努力得到了预期的结果。

因此,假设我将颜色存储为 RGB 三元组,其分量值在 [0, 1] 范围内,以下函数将其转换为 aRGB:

uint32_t makeRGB30(float r, float g, float b)
{
  const uint32_t mask = (1u << 10u) - 1u;
  /* convert float -> uint */
  uint32_t rU = r * mask, gU = g * mask, bU = b * mask;
  /* combine and return color components */
  return ((rU & mask) << 20) | ((gU & mask) << 10) | (bU & mask);
}

这会产生具有以下位布局的值:

aaRRRRRR.RRRRGGGG.GGGGGGBB.BBBBBBBB

演示的小样本:

#include <stdint.h>
#include <stdio.h>

uint32_t makeRGB30(float r, float g, float b)
{
  const uint32_t mask = (1u << 10u) - 1u;
  /* convert float -> uint */
  uint32_t rU = r * mask, gU = g * mask, bU = b * mask;
  /* combine and return color components */
  return ((rU & mask) << 20) | ((gU & mask) << 10) | (bU & mask);
}

int main(void)
{
  /* samples */
  const float colors[][3] = {
    { 0.0f, 0.0f, 0.0f }, /* black */
    { 1.0f, 0.0f, 0.0f }, /* red */
    { 0.0f, 1.0f, 0.0f }, /* green */
    { 0.0f, 0.0f, 1.0f }, /* blue */
    { 1.0f, 1.0f, 0.0f }, /* yellow */
    { 1.0f, 0.0f, 1.0f }, /* magenta */
    { 0.0f, 1.0f, 1.0f }, /* cyan */
    { 1.0f, 1.0f, 1.0f } /* white */
  };
  const size_t n = sizeof colors / sizeof *colors;
  for (size_t i = 0; i < n; ++i) {
    float *color = colors[i];
    uint32_t rgb = makeRGB30(color[0], color[1], color[2]);
    printf("(%f, %f, %f): %08x\n", color[0], color[1], color[2], rgb);
  }
  /* done */
  return 0;
}

输出:

(0.000000, 0.000000, 0.000000): 00000000
(1.000000, 0.000000, 0.000000): 3ff00000
(0.000000, 1.000000, 0.000000): 000ffc00
(0.000000, 0.000000, 1.000000): 000003ff
(1.000000, 1.000000, 0.000000): 3ffffc00
(1.000000, 0.000000, 1.000000): 3ff003ff
(0.000000, 1.000000, 1.000000): 000fffff
(1.000000, 1.000000, 1.000000): 3fffffff

Live Demo on ideone

【讨论】:

  • 您假设太多:tge 未使用的位是最重要的位,然后依次是红色、绿色和蓝色分量。这实际上是所有硬件相关的(并且与字节序没有任何关系)。 X11 有 API 来确定从不同通道组成像素所需的掩码和 tge 移位。
  • @n.m.这不是我上面提到的字节序吗?
  • 同样,这与字节序无关。字节序是关于一个单词中字节的顺序。您根本不处理字节,而仅处理 32 位位掩码。即使您的位掩码恰好都是 8 位宽并且从 8 的倍数开始,您也不会处理字节。字节是一个 可寻址 单元。除非你有例如char*int* 指向 same 单词,字节序完全无关。
  • @n.m.我对这样的硬件问题不太熟悉。那么,我可以确定图形硬件的字节序始终与 CPU 的字节序相同吗? OP 提到将颜色值作为字节传递(即uint8_t)。因此,我认为字节序值得一提。
  • Classical X11 是采用有线协议的客户端-服务器系统。该协议可以使用大端或小端格式,具体取决于客户端在连接开始时选择的内容。如果服务器具有不同的字节序,它将负责反转字节顺序。现代直接渲染 API 可能需要客户端反转字节(我对 X11 的这一部分不太熟悉)。这仍然与某些 2 位和 10 位宽掩码的正确顺序无关。
【解决方案2】:

颜色通道的确切排列方式取决于 API。它很可能是平面的(即每个通道一个单色图像),它可能是打包的(即将几个通道打包成一个数据字),它可能是交错的(对每个通道使用不同的表示)。

但是有一点是肯定的:对于任何不完全适合“原生”类型的频道格式,都必须进行一些操作才能访问它。

要了解该字段的巨大,只需查看 Vulkan API 的第一个版本指定的图像格式:https://vulkan.lunarg.com/doc/view/1.0.30.0/linux/vkspec.chunked/ch31s03.html - 该文档还描述了位是为每种格式排列的。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-10-30
    • 2013-01-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-12-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多