2017-04-11 144 views
1

我的Android手机(Adreno 530 GPU)上有glCompressedTexSubImage2D的ASTC 8x8纹理,遇到了一个奇怪的问题。我的安装程序最初包含一个用于促进异步纹理上传的PBO,但我已将其降低到最低限度以重现此问题。请注意,这是内部的团结5.5.2f1托管作为原生的插件,所以团结可以改变我的电话之间的一些状态glCompressedTexSubImage2DglCompressedTexSubImage2D上具有ASTC 8x8纹理的GL_INVALID_VALUE

要开始我对编译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指针),然后一次上传多行通过glCompressedTexSubImage2D为了使事情更简单,我跳过了流(文件头)的前16个字节并读取了4096个字节块(恰好是一行的大小)。所以std :: copy的最后一位实际上并不实际复制任何数据。我通过记录尽可能多的数据验证了这一点,缓冲区每次都从4096的精确倍数调整为0。

这个函数写成yOffset = 0(无论该调用中有多少行上传,8 192个,或8个倍数,根据规范)。在第一次通话之后,所有其他通话都会失败,并显示GL_INVALID_VALUE。如果我将Y顺序颠倒(yOffset为data.height - (num_rows * 8)),那么这是唯一成功的最后一个呼叫。

与GL_KHR_debug进一步挖掘,我实现返回“图像大小是压缩纹理无效”

04-10 18:35:26.218 24522 24541 V AsyncTexUpload: id=102 glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 1432, 2048, 96, GL_COMPRESSED_RGBA_ASTC_8x8, 49152, ptr) 
04-10 18:35:26.218 24522 24541 V AsyncTexUpload: Logged message 8246, 824C, 7FFFFFFF, 9146, image size is invalid for compressed texture 
04-10 18:35:26.218 24522 24541 V AsyncTexUpload: glCompressedTexSubImage2D error 1281 

此外,这里的是真的糊涂了,如果我换X偏移的一部分, yOffset,以及宽度和高度,纹理上传没有错误。我的块都在不正确的位置,但是这个错误从未发生。当computing the imageSize from the table in the documentation,这两个变体具有相同的图像大小值。将参数记录下来时,我的imageSize值是相同的。

下面你可以看到,这是原来的代码未初始化的内存过去的第一个上传运行:

Screenshot of the original code

而现在,X偏移/ Y偏移和宽度/高度翻转,整个纹理越来越上传但块对齐(你所期望的,如果在上传错误的顺序块)

Values flipped

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

回答

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()); 

苹果设备(imgtec)似乎遵循我的规范的解释,我正在试图发现马里设备的模式。

+0

谢谢你的回答!我面临着同样的问题,你的公式解决了Adreno 430上的错误,你是否设法获得了马里设备的模式? –

+1

还没有,到本周末可能会有东西,只是设法从某人那借用一个设备。请注意,在Adreno上,这仅适用于宽度和高度均为64 texels倍数的纹理。我们刚刚决定暂时不支持这些纹理 –

+0

更新:马里接受与imgtec相同的值,但似乎在具有段错误的最后一块上崩溃。进一步了解这一点 –