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