glCompressedTexSubImage2D上的GL_INVALID_VALUE,带有ASTC 8x8纹理

时间:2017-04-11 04:43:12

标签: android c++ opengl-es astc

我的Android手机(Adreno 530 GPU)上glCompressedTexSubImage2D遇到了一个带有ASTC 8x8纹理的奇怪问题。我的设置最初包含一个用于促进异步纹理上传的PBO,但我已经把它减少到最低限度来重现这个问题。请注意,它作为本机插件托管在Unity 5.5.2f1中,因此Unity可能会在我调用glCompressedTexSubImage2D

之间更改某些状态

首先,我正在针对Android平台24进行编译,以便现在可以访问<GLES3/gl32.h>,并使用正确的标志和设置来启用C ++ 11功能。

我定义了这个结构,它存储了通过插件更新的每个纹理的状态:

enum texture_format
{
    ASTC_RGBA_8x8 = 57,
};

struct texture_data
{
    void* ptr;
    bool has_initialized;
    uint32_t width;
    uint32_t height;
    texture_format format;
    std::vector<uint8_t> cpu_buffer;
    std::mutex lock_cpu_buffer;
    uint32_t row;
};

我已经验证Unity中的数据是正确传递的,这是(为了清晰起见)缩短了纹理上传的功能:

data.lock_cpu_buffer.lock();

int bytesPerRow = data.width * 2; //Specific to ASTC 8x8 for now: (width / 8) * 16

int num_rows = data.cpu_buffer.size() / bytesPerRow;
if (num_rows <= 0)
{
    data.lock_cpu_buffer.unlock();
    return;
}

glBindTexture(GL_TEXTURE_2D, (GLuint)data.ptr);

//Just in case Unity is doing something with these
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);

glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, data.row, data.width, 8 * num_rows, GL_COMPRESSED_RGBA_ASTC_8x8, bytesPerRow * num_rows, data.cpu_buffer.data());

GLenum err = glGetError();
if (err != GL_NO_ERROR)
{
#if UNITY_ANDROID
    __android_log_print(ANDROID_LOG_VERBOSE, APPNAME, "glCompressedTexSubImage2D error %u", err);
#endif
}

//prepare buffer for future by copying remainder to beginning of vector and resizing (no allocation should happen here)
data.row += num_rows * 8;
std::copy(data.cpu_buffer.begin() + (bytesPerRow * num_rows), data.cpu_buffer.end(), data.cpu_buffer.begin());
data.cpu_buffer.resize(data.cpu_buffer.size() - (bytesPerRow * num_rows));

glBindTexture(GL_TEXTURE_2D, 0);

data.lock_cpu_buffer.unlock();

总之,我将从Unity中的流中的任意数量的数据推送到本机插件中的缓冲区(代替映射的PBO指针),然后通过{{1一次上载多个行为了使事情变得更简单,我正在跳过流的前16个字节(文件头)并读取4096个字节块(恰好是一行的大小)。所以std :: copy的最后一点实际上并没有真正复制任何数据。我已经通过记录尽可能多的数据来验证这一点,缓冲区每次从4096到0的精确倍数调整大小。

编写的此函数将成功glCompressedTexSubImage2D(根据规范,无论在该调用中上载多少行,8 192或8的任意倍数)。在第一次通话之后,所有其他通话都以yOffset = 0失败。如果我反转Y顺序(GL_INVALID_VALUE的yOffset),那么它是唯一成功的最后一次调用。

使用GL_KHR_debug进一步挖掘,我的实现返回&#34;图像大小对压缩纹理无效&#34;

data.height - (num_rows * 8)

此外,这里的部分让我很困惑,如果我交换xOffset和yOffset,以及宽度和高度,纹理上传没有错误。我的块都在错误的位置,但这个错误永远不会发生。当computing the imageSize from the table in the documentation两个变体具有相同的imageSize值时。记录参数时,我的imageSize值是相同的。

您可以在下面看到,这是在首次上传后使用未初始化内存运行的原始代码:

Screenshot of the original code

现在,随着xOffset / yOffset和宽度/高度的翻转,整个纹理上传但是块未对齐(如果以错误的顺序上传块,您会期望什么)

Values flipped

对ASTC有任何限制会导致这种行为吗?有没有其他人碰到类似的东西?一些论坛帖子提到了一些外部状态变化导致上传失败,我还没有找到任何东西(这包括glActiveTexture,未在上面的代码中显示)。为什么交换参数会导致错误消失?

1 个答案:

答案 0 :(得分:1)

看起来好像这些是OpenGL的特定实现中的错误。我用多个设备看了这个,上面提供的代码自4月以来已经成熟了。

Qualcomm设备似乎希望纹理的大小达到行。也就是说,而不是我期望的ceil(width/8) * ceil(height/8) * 16,公式为ceil(width/8) * ceil((height + yOffset)/8) * 16

在上面的代码中,这将转换为

glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, data.row, data.width, 8 * num_rows, GL_COMPRESSED_RGBA_ASTC_8x8, bytesPerRow * (data.row + num_rows), data.cpu_buffer.data());

Apple设备(imgtec)似乎遵循我对规范的解释,我正在尝试发现Mali设备的模式。