2017-04-11 241 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相同的值,但似乎在具有段錯誤的最後一塊上崩潰。進一步瞭解這一點 –