【问题标题】:Efficient implementation of bidirectional map between 64bit and 32bit unsigned integers64位和32位无符号整数之间双向映射的高效实现
【发布时间】:2014-01-27 17:06:23
【问题描述】:

假设我们有 2 台机器,名为:Alice 和 Bob。 Alice 支持 64 位无符号整数运算,而 Bob 仅支持 32 位无符号整数运算。

Bob 向 Alice 发送创建任务的请求。对于每个任务,Alice 分配唯一的 ID,该 ID 是随机的但唯一的 64 位无符号整数。 Bob 最多可以创建 2^32 个任务。

我需要为 Bob 添加一个能够按 ID 删除任务的功能。因此,我需要设置一个代理,当消息从 Alice 发送到 Bob 时,将 64 位单元替换为 32 位单元,并在消息方向相反时从 32 位单元恢复 64 位单元。

问题是我需要使转换非常高效,我只有 ~10MB 的 RAM 来执行此操作。
是否有任何容器已经解决了这个问题?

更新

社区要求澄清,澄清的唯一方法是描述现实世界的情况。

所以,我正在开发属于 AOSP 的 OpenGL 转换器库。总之,出于加速原因,它允许将 Android 系统(例如在 VM 内运行)的渲染移动到主机系统。
它是通过将所有 OpenGL 命令(来回)从目标 (Android) 流式传输到主机(即 Win8 64 位)来完成的。

OpenGL 对象表示为类型为GLuintunsigned int 的句柄。因此对象的大小和允许的值取决于系统是 32 位还是 64 位。

由于大多数Android系统是32位,而大多数主机系统是64位,所以出现了问题:在从Android创建OpenGL对象的请求中,Host可以创建值不能表示为32位值的句柄。但是,出于显而易见的原因,Android 不能请求超过 2^32 - 1 的对象。

我想到的唯一解决方案是设置代理,将 64 位句柄映射到 32 位,反之亦然。

产生问题的具体代码:https://android.googlesource.com/platform/sdk/+/master/emulator/opengl/host/libs/Translator/include/GLcommon/GLutils.h 第 47 行。

更新 2

在进一步探索问题后,我发现这不是 GLuint 的问题(如 @KillianDS 所述)。但它仍然是 OpenGL 的问题。

有些函数返回指针,而不是 GLuint 句柄。例如。 eglCreateContext。 我需要找到一种在 64 位主机和 32 位目标之间交换指针的方法。

更新 3

最后我发现这个具体的崩溃与 32 位和 64 位机器之间的句柄转换无关。这是翻译器目标部分中的一个错误,它使用错误的参数调用了错误的函数(glVertexAttribPointerData)。

【问题讨论】:

  • 为什么需要转换。只需确保您使用的是独立于平台的类型,例如 int32_tint64_t,以便数据大小相同。
  • 我建议双方都使用 32 位 ID。或者简单地让 Bob 将两个相邻的 32 位值视为 64 位值。如果出于某种奇怪的原因,这些都不可能,那么您需要一个哈希表来翻译。
  • 如果你没有注意到,没有单射函数{0..2^64-1} -> {0..2^32-1}。使用pidgeonhole principle 很容易证明。那么您到底在寻找什么?
  • @Sean 这个例子完全是人为的,只是为了演示系统的要求。
  • 一个哈希表能够存储 2^32 个元素(条件 1)和适合 10MB 的 RAM(条件 2)?祝你好运。这甚至不适用于位大小的数据类型,并且假设指针的大小为零。

标签: c++ c algorithm opengl containers


【解决方案1】:

根据latest core OpenGL spec 中的table 2.2,OpenGL 中的 uint 应始终为 32 位宽度(ES 的规范大致相同)。据我所知,所有 OpenGL 名称/句柄(你也在你的问题中说)uint's。因此,它在您的主机和目标上都应该是 32 位的。

请注意,正是因为 unsigned int 的实际位宽可能因平台而异,OpenGL 有自己的类型,应该符合规范。

更新

如果剩下的句柄真的只是上下文和其他窗口系统调用,我会保持简单,因为我们不是在谈论频繁的操作,也不是大量的句柄。此类操作通常不会在每个 GPU 的每个 OpenGL 应用程序中执行一次以上,这在任何手机上都可能是 1 次。我认为最简单的解决方案是使用数组。伪代码

class context_creator
{
    std::array<EGLContext, 1000> context_map; //8KB
public:
    context_creator() : context_map{} {}
    uint32_t allocate(...) {
        for(unsigned i = 0; i < context_map.size(); i++) {
            if(!context_map[i]) {
                context_map[i] = eglCreateContext(...);
                return i;
            }
        }
    }
    void deallocate(uint32_t handle) {
        eglDeleteContext(context_map[handle]);
        context_map[handle] = 0;
    }
    //Has to be called in every function where a context is a parameter.
    EGLContext translate(uint32_t handle) const {
        return context_map[handle];
    }
}

请注意,如果0 是上下文的有效名称,这将不起作用。我真的不知道 WGL,但可能不是。这样做的好处是,虽然 allocate 不是有史以来最快的算法,但 translate 是 O(1),这是最有可能最常调用的算法。

当然,变化是存在的:

  • 您可以使用更动态的容器(例如vector)而不是固定大小。
  • 您可以使用哈希表(如std::map),只需为每次调用生成一个唯一索引。这会消耗更多内存,因为您还必须存储索引(它隐含在数组中),但如果 0 是一个有效的上下文名称,它可以解决问题。

【讨论】:

  • 请检查更新 2。
  • @Kentzo 这是一个完全不同的问题,因为这些句柄的数量通常在完全不同的范围内。我用我的想法更新了我的答案。
【解决方案2】:

OpenGL 中的 uint 应该是 4 个字节,即宽度总是 32 位,因此目标和主机上的句柄/名称应该是 32 位

【讨论】:

  • OpenGL 会为您分配数字,您不能自己选择。
猜你喜欢
  • 1970-01-01
  • 2014-06-23
  • 2012-08-30
  • 2013-07-20
  • 2019-03-25
  • 1970-01-01
  • 2015-07-18
  • 1970-01-01
  • 2019-05-21
相关资源
最近更新 更多