我的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值是相同的。
您可以在下面看到,这是在首次上传后使用未初始化内存运行的原始代码:
现在,随着xOffset / yOffset和宽度/高度的翻转,整个纹理上传但是块未对齐(如果以错误的顺序上传块,您会期望什么)
对ASTC有任何限制会导致这种行为吗?有没有其他人碰到类似的东西?一些论坛帖子提到了一些外部状态变化导致上传失败,我还没有找到任何东西(这包括glActiveTexture,未在上面的代码中显示)。为什么交换参数会导致错误消失?
答案 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设备的模式。