2020年2月10日 星期一

把螢幕畫面錄成 GIF 檔的軟體

把螢幕畫面錄成 GIF 檔的軟體

前言

  Windows 的截圖功能很好用,但有的時候需要能動的圖像,而表達能動的圖片看來就只有 GIF 檔能勝認了,於是上網找到 [ www.screentogif.com ] ScreenToGif  這個軟體,用起來相當簡單,在此把學習的過程做個紀錄。

內容

  先到 [ www.screentogif.com ] ScreenToGif  下載軟體,如下圖
下載 ScreenToGif

下載完後解壓,再開啟軟體,可以看到下圖
開啟 ScreenToGif

開啟後按下螢幕錄影,可以看到以下
錄影視窗

錄影視窗的中間是透明的,可以在下方調整錄影視窗的大小,再按下錄影後開始錄影,錄到想要的時間按下停止,可以得到以下
編輯畫面

到了編輯畫面後在左上按下"檔案"的按鍵後,再按下"另存新檔"後,可以得到以下
存檔介面

在存檔介面設定存檔路徑與檔明後按下"儲存"就可以取得結果。

參考資料

[ www.screentogif.com ] ScreenToGif

2020年2月9日 星期日

RX570 驅動程式 Bug

RX570 驅動程式 Bug
內容
  在 Ubuntu 安裝 RX570 驅動程式後,晶片名稱會顯示成 RX470,如下圖
顯示錯誤的晶片名稱


這應該就只是單純的名稱錯誤。

2020年2月3日 星期一

關於逆矩陣的運算

關於逆矩陣的運算

前言

  逆矩陣的計算相當繁瑣,很難記在腦中或用推導的方式取得,所以每次需要時都要重新 google 一次,這篇做個紀錄,方便以後查詢。

內容

  詳細的計算式可以在 [ stackoverflow.com ] inverting a 4x4 matrix 裡找到,這裡複製一下結果如下
bool gluInvertMatrix(const double m[16], double invOut[16])
{
    double inv[16], det;
    int i;

    inv[0] = m[5]  * m[10] * m[15] - 
             m[5]  * m[11] * m[14] - 
             m[9]  * m[6]  * m[15] + 
             m[9]  * m[7]  * m[14] +
             m[13] * m[6]  * m[11] - 
             m[13] * m[7]  * m[10];

    inv[4] = -m[4]  * m[10] * m[15] + 
              m[4]  * m[11] * m[14] + 
              m[8]  * m[6]  * m[15] - 
              m[8]  * m[7]  * m[14] - 
              m[12] * m[6]  * m[11] + 
              m[12] * m[7]  * m[10];

    inv[8] = m[4]  * m[9] * m[15] - 
             m[4]  * m[11] * m[13] - 
             m[8]  * m[5] * m[15] + 
             m[8]  * m[7] * m[13] + 
             m[12] * m[5] * m[11] - 
             m[12] * m[7] * m[9];

    inv[12] = -m[4]  * m[9] * m[14] + 
               m[4]  * m[10] * m[13] +
               m[8]  * m[5] * m[14] - 
               m[8]  * m[6] * m[13] - 
               m[12] * m[5] * m[10] + 
               m[12] * m[6] * m[9];

    inv[1] = -m[1]  * m[10] * m[15] + 
              m[1]  * m[11] * m[14] + 
              m[9]  * m[2] * m[15] - 
              m[9]  * m[3] * m[14] - 
              m[13] * m[2] * m[11] + 
              m[13] * m[3] * m[10];

    inv[5] = m[0]  * m[10] * m[15] - 
             m[0]  * m[11] * m[14] - 
             m[8]  * m[2] * m[15] + 
             m[8]  * m[3] * m[14] + 
             m[12] * m[2] * m[11] - 
             m[12] * m[3] * m[10];

    inv[9] = -m[0]  * m[9] * m[15] + 
              m[0]  * m[11] * m[13] + 
              m[8]  * m[1] * m[15] - 
              m[8]  * m[3] * m[13] - 
              m[12] * m[1] * m[11] + 
              m[12] * m[3] * m[9];

    inv[13] = m[0]  * m[9] * m[14] - 
              m[0]  * m[10] * m[13] - 
              m[8]  * m[1] * m[14] + 
              m[8]  * m[2] * m[13] + 
              m[12] * m[1] * m[10] - 
              m[12] * m[2] * m[9];

    inv[2] = m[1]  * m[6] * m[15] - 
             m[1]  * m[7] * m[14] - 
             m[5]  * m[2] * m[15] + 
             m[5]  * m[3] * m[14] + 
             m[13] * m[2] * m[7] - 
             m[13] * m[3] * m[6];

    inv[6] = -m[0]  * m[6] * m[15] + 
              m[0]  * m[7] * m[14] + 
              m[4]  * m[2] * m[15] - 
              m[4]  * m[3] * m[14] - 
              m[12] * m[2] * m[7] + 
              m[12] * m[3] * m[6];

    inv[10] = m[0]  * m[5] * m[15] - 
              m[0]  * m[7] * m[13] - 
              m[4]  * m[1] * m[15] + 
              m[4]  * m[3] * m[13] + 
              m[12] * m[1] * m[7] - 
              m[12] * m[3] * m[5];

    inv[14] = -m[0]  * m[5] * m[14] + 
               m[0]  * m[6] * m[13] + 
               m[4]  * m[1] * m[14] - 
               m[4]  * m[2] * m[13] - 
               m[12] * m[1] * m[6] + 
               m[12] * m[2] * m[5];

    inv[3] = -m[1] * m[6] * m[11] + 
              m[1] * m[7] * m[10] + 
              m[5] * m[2] * m[11] - 
              m[5] * m[3] * m[10] - 
              m[9] * m[2] * m[7] + 
              m[9] * m[3] * m[6];

    inv[7] = m[0] * m[6] * m[11] - 
             m[0] * m[7] * m[10] - 
             m[4] * m[2] * m[11] + 
             m[4] * m[3] * m[10] + 
             m[8] * m[2] * m[7] - 
             m[8] * m[3] * m[6];

    inv[11] = -m[0] * m[5] * m[11] + 
               m[0] * m[7] * m[9] + 
               m[4] * m[1] * m[11] - 
               m[4] * m[3] * m[9] - 
               m[8] * m[1] * m[7] + 
               m[8] * m[3] * m[5];

    inv[15] = m[0] * m[5] * m[10] - 
              m[0] * m[6] * m[9] - 
              m[4] * m[1] * m[10] + 
              m[4] * m[2] * m[9] + 
              m[8] * m[1] * m[6] - 
              m[8] * m[2] * m[5];

    det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];

    if (det == 0)
        return false;

    det = 1.0 / det;

    for (i = 0; i < 16; i++)
        invOut[i] = inv[i] * det;

    return true;
}

如果需要推導的過程與驗算的話,可以在 [ ncalculators.com ] nxn Inverse Matrix Calculator 。

參考資料

[ stackoverflow.com ] inverting a 4x4 matrix
[ ncalculators.com ] nxn Inverse Matrix Calculator

2020年1月27日 星期一

使用 Map() 與 UpdateSubresource() 更新 Constant buffer 的差異

使用 Map() 與 UpdateSubresource() 更新 Constant buffer 的差異

前言

  在 Direct3D11 裡提供兩種更新 Constant buffer 資料的方法,分別是 Map() 與 UpdateSubresource() ,在 Direct3D11 的官方範例中的入門範例( Direct3D11Tutorials )裡採用的是 UpdateSubresource() ,但其它範例卻用 Map() 來更新,到底兩者的差異在哪?在此把學習的過程做個紀錄。

內容

  Map() 與 UpdateSubresource()  兩者在 Create 的時候有些不一樣, Map() 的 Usage 使用的是 D3D11_USAGE_DYNAMIC ,而 UpdateSubresource() 的 Usage 使用的是 D3D11_USAGE_DEFAULT ,由於 Usage 無法在 Create 後改變,所以在 Create 時其實就確定了更新的方法。就 [ Windows dev center ] D3D11_USAGE enumeration 裡對 D3D11_USAGE_DYNAMIC 的描述非常符合 Constant buffer 的情形(  CPU 寫 GPU 讀  ) ,那 UpdateSubresource() 又是怎麼回事?

  這兩者的差異我並沒有真的去測試差異,但就我所知,GPU讀  D3D11_USAGE_DEFAULT 的速度比 D3D11_USAGE_DYNAMIC 快,但這是在不考慮寫資料的狀況下,如果同時考慮 CPU 寫與 GPU 讀的話,請使用  D3D11_USAGE_DYNAMIC ,但是如果只是偶而更新資料的話就可以使用 D3D11_USAGE_DEFAULT 。可是 Constant buffer 很難保證它不會常常更新,所以適合的更新方法其實是 Map() , UpdateSubresource() 其實是不適合的更新方式,或者是說 UpdateSubresource() 並不適合用在 Constant buffer ,而且之後的 Direct3D12 也是採用 Map() 的方式更新 Constant buffer ,所以全部使用 Map() 的方法是較好的做法,把 UpdateSubresource() 視為優化的方法(確定不常更新)。

參考資料

[ gamedev.net ] Constant buffer UpdateSubResource vs Map
[ Windows dev center ] D3D11_USAGE enumeration

2020年1月20日 星期一

使用 NDK 建置 Shaderc 在 Windows

使用 NDK 建置 Shaderc 在 Windows

前言

  在之前的 建置 glslang 在 Windows 裡建置了 glslang 來當 Shader 的編譯器,但不幸的是 Android 平台並不能使用 glslang 而是由 Google 提供的 Shaderc 專案來當 Shader 的編譯器,並且要自己編譯成 Library 來使用,在此把過程做個紀錄。

內容

  Shaderc 的專案在 [ Github ] Shaderc 裡可以取得最新的版本,但幸運的是 NDK 本身會自帶一份 Shaderc 的專案,可以在以下的位址找到它
(NDK_ROOT)/sources/third_party/shaderc

可以在該資料夾下發現 Android.mk ,接著在使用以下命令來建置
..\..\..\ndk-build NDK_PROJECT_PATH=. APP_BUILD_SCRIPT=Android.mk APP_ABI=all APP_PLATFORM=android-24 APP_STL=c++_static -j8 clean libshaderc_combined

要注意的是命令中的 APP_STL 參數,範例用的是 c++_static ,如果需要別的 APP_STL 請修改此參數,建置完成後會產生 include 與 libs 這兩個資料夾, include 裡會包含所需要的 Header 檔 , libs 則包含對應各種 ABI 的 library 檔( .a 檔),建置到此就完成了。

  建置完成後就是如何加入到 NDK 的  Android.mk 裡來引用,以下是使用範例
#=====shaderc
include $(CLEAR_VARS)

LOCAL_MODULE := Shaderc_prebuild
LOCAL_SRC_FILES := (NDK_ROOT)/sources/third_party/shaderc/libs/$(APP_STL)/$(TARGET_ARCH_ABI)/libshaderc.a

include $(PREBUILT_STATIC_LIBRARY)

#=====
include $(CLEAR_VARS)
#...
LOCAL_C_INCLUDES += (NDK_ROOT)/sources/third_party/shaderc/include
#...
LOCAL_STATIC_LIBRARIES += Shaderc_prebuild

include $(BUILD_SHARED_LIBRARY)

範例先是產生一個 Prbult static library ,接著在需要引用的專案加入 include path ,並在 LOCAL_STATIC_LIBRARIES 加入  Prbult static library  ,加入的時候後要注意用的 Module 名稱來加入,這樣就可以開始使用了。如果需要一個具體的使用範例來參考的話可以使用 [ Github ] GearVRf  這個專案裡有完整使用範例。

  在 NDK 的參數裡的參數 LOCAL_SRC_FILES 是用 ":=" 來給值,由於右方有NDK的變數( APP_STL 與 TARGET_ARCH_ABI ),請不要使用"+="給值,不然會在 Link 的時候得到 Permission denied 錯誤,這個錯誤個人足足找了4天才找到這個錯誤,希望沒有下一個人會踩到這個雷。

參考資料

[ Github ] Shaderc
[ https://developer.android.com ] Vulkan Setup
[ Github ] GearVRf

相關文章

建置 glslang 在 Windows

2020年1月13日 星期一

查詢 GPU 的 Extension

查詢 GPU 的 Extension

前言

  要取得 GPU 的 Extension 的話直接透過繪圖 API ( OpenGL 、 OpenGLES 與 Vulkan )來取得即可,但這個前提是機器必須在身邊,在手機平台的話,難道要把所有的機器的買來取得資料嗎!?幸運的有個網站可以查詢,在此做個紀錄。

內容

  在 [ gpuinfo.org ] gpuinfo.org 可以查詢繪圖API的資訊,進入網站後可以看到以下
gupinfo.org 的網頁

根據要查詢的繪圖API點選,網站會引導到查詢網頁,以下以 Vulkan 為例,會看到以下
查詢 Vulkan 的 Extension

上方的輸入可以用來依據需求來過濾想查詢的 GPU ,接著會以 AMD Radeon RX 570 series 為例,會看到以下
查詢 AMD Radeon RX 570 series 的 Extension

在上方可以發現其實不只可以查詢 Extension ,還包含 Formats 等資訊,用起來相當簡單。

參考資料

[ gpuinfo.org ] gpuinfo.org

2020年1月6日 星期一

在 OpenGL 的 Vertex buffer 裡使用 interger 資料

在 OpenGL 的 Vertex buffer 裡使用 Interger 資料

前言

  最近需要在 Vertex buffer 裡使用 Interger 資料,在 Direct3D 時沒什麼問題,但是變成 OpenGL 就會跑出不正確的答案,在此把研究的過程做個紀錄。

內容

   OpenGL 輸入資料時會透過 glVertexAttribPointer() 來輸入資料,一般輸入的範例如下
glVertexAttribPointer( posLoc , 4 , GL_FLOAT , GL_FALSE , 4*sizeof(float), (GLvoid*)0 );

這樣輸入對應到 GLSL 的型別是 vec4 ,所以如果 GLSL 的型別是 int4 的話可能會像以下這樣輸入
glVertexAttribPointer( posLoc , 4 , GL_INT , GL_FALSE , 4*sizeof(GLint), (GLvoid*)0 );

如果你按照上述輸入的話會是錯的!正確的輸入如下
glVertexAttribIPointer( posLoc , 4 , GL_INT , 4*sizeof(GLint), (GLvoid*)0 );

要輸入 interger 資料的話,要用 glVertexAttribIPointer() 來輸入,glVertexAttribPointer() 用來輸入資料是 float 的時候,參數的部分 glVertexAttribIPointer() 沒有 normalized ,詳細的差異可以在[ docs.gl ]glVertexAttribPointer 裡查詢。

  題外話,在 OpenGL2 或 OpenGLES2 的時候,由於不支援 Integer 型別,所以只能用 float 的型態來輸入,然後在 GLSL 會提供 int() 來轉型,要注意雖有 int() ,但沒有 uint() ,這是早期的規格制定的缺陷。

參考資料

[ docs.gl ]glVertexAttribPointer