起因:用OpenGL ES的變換反饋(transform feedback)特性,在GPU上實現圖象處理中常用的查表映射功能(LookUp Table Map)。
這是一個工作量在五天以內的小項目(簡單分為三個部分:一、分配頂點數組,二、寫着色器,三、利用變換反饋把結果取回內存。)
本應該自己來做。但是湊巧有個算法移植到CUDA平台的工作在手,於是就拜托公司一位比較熟悉OpenGL ES的實習生來做,先第一部分和第三部分,第二部分可以暫時以一個簡單的着色器來替代,先把整個框架搭起來。
過了三天,自己手頭的事情做好了。就問他做的怎么樣,有沒有遇到什么問題。小伙子說,框架搭好了,但是遇到了一個百思不得其解的問題,傳進去着色器的-1,沒做任何改變,純粹地返回,但是在讀出來的時候總是-1082130432。(其中int類型的數字-1是表中較常出現的數字。)
簡單review了一下,代碼大致沒什么問題。
排查-1變成-1082130432的問題。
用以下代碼測試
float f = -1.0f;
printf("%d\n", *(int*)&f);
得到的輸出結果就是-1082130432。
所以很明顯,在傳入着色器的過程當中,int類型的-1被轉化成了float類型的-1,所以我們在讀取以int類型再去讀取它的時候,就讀出了-1082130432這個數字。
bug定位好了之后,就開始排查數據進入着色器的過程中是否出現了問題。
最后發現,小伙子用了glVertexAttribPointer函數來指定每個頂點的屬性,但是這個函數在normalized屬性被設置為GL_FALSE時,非float類型的數值將被轉換成float類型。於是int類型的-1就被轉換成了float類型。
改用glVertexAttribIPointer函數,bug解決。
OpenGL ES 3中的glVertexAttribPointer與glVertexAttribIPointer的文檔摘錄如下:
For
glVertexAttribPointer
, ifnormalized
is set toGL_TRUE
, it indicates that values stored in an integer format are to be mapped to the range [-1,1] (for signed values) or [0,1] (for unsigned values) when they are accessed and converted to floating point. Otherwise, values will be converted to floats directly without normalization.For
glVertexAttribIPointer
, only the integer typesGL_BYTE
,GL_UNSIGNED_BYTE
,GL_SHORT
,GL_UNSIGNED_SHORT
,GL_INT
,GL_UNSIGNED_INT
are accepted. Values are always left as integer values.