1. 程式人生 > >編譯GDAL支援OpenCL使用GPU加速

編譯GDAL支援OpenCL使用GPU加速

前言

GDAL庫中提供的gdalwarp支援各種高效能的影象重取樣演算法,影象重取樣演算法廣泛應用於影象校正,重投影,裁切,鑲嵌等演算法中,而且對於這些演算法來說,計算座標變換的運算量是相當少的,絕大部分運算量都在影象的重取樣演算法中,尤其是三次卷積取樣以及更高階的重取樣演算法來說,運算量會成倍的增加,所以提升這些演算法的處理效率優先是提高重取樣的效率。由於GPU的多核心使得目前對於GPU的並行處理非常熱,同時也能大幅度的提升處理速度。基於上述原因,GDALWARP也提供了基於OPENCL的GPU加速,之前在GDAL的郵件列表中有人測試發現使用OpenCL加速後,在Telsa的顯示卡上速度可以達到CPU的20~60倍。

GDAL庫一般編譯的時候不會開啟,所以預設的GDAL是不支援GPU並行處理的,本文就是指導大家在Windows平臺上使用Visual Studio系列編譯GDAL時,怎麼使之支援OpenCL並行處理。

所需軟體

-Visual Studio 系列(VS2003以上版本)
-OpenCL庫(AMD或者NVIDIA均可)
-GDAL原始碼

修改nmake.opt檔案

nmake.opt檔案中一共要修改四處地方,其中兩處是新增,兩處是修改。

第一處(增加)

首先在nmake.opt檔案參考其他的引用庫,新增OpenCL的庫目錄。首先在namke.opt找到下面這行:

######
##### END OF STUFF THAT NORMALLY NEEDS TO BE UPDATED ##################

在上面這行程式碼的前面新增如下程式碼(使用的是NVIDIA的CUDA安裝包下面的OpenCL庫):

#include opencl lib
INCLUDE_OPENCL = YES

# Uncomment for OPENCL_AMD support
!IFDEF INCLUDE_OPENCL
OPENCL_DIR="C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v7.0"
OPENCL_CFLAGS
= -I$(OPENCL_DIR)/include -DHAVE_OPENCL OPENCL_LIB = $(OPENCL_DIR)/lib/Win32/OpenCL.lib !ELSE OPENCL_DIR= OPENCL_CFLAGS = -I OPENCL_LIB = !ENDIF

第二處(增加)

然後在上面那行程式碼(END OF STUFF THAT NORMALLY NEEDS TO BE UPDATED)的下面新增下面的程式碼:

# liml
!IFDEF INCLUDE_OPENCL
OPENCL_FLAG = -DHAVE_OPENCL
!ENDIF

第三處(修改)

接下來找到程式碼CFLAGS = 這句程式碼,在這句程式碼的後面加上$(OPENCL_FLAG)

地四處(修改)

找到程式碼EXTERNAL_LIBS =,在最後面加上$(OPENCL_LIB)

修改alg目錄下的makefile.vc檔案

makefile.vc檔案中共需要修改兩處位置,一處增加一處修改。

第一處(增加)

在檔案中OBJ = 的前面新增下面的程式碼,用來設定使用OpenCL的巨集定義。

!IFDEF INCLUDE_OPENCL
EXTRAFLAGS = $(EXTRAFLAGS) $(OPENCL_CFLAGS) -DHAVE_OPENCL
!ENDIF

第二處(修改)

在檔案中OBJ = 的後面新增OpenCL的演算法檔案gdalwarpkernel_opencl.obj。注意新增的時候與其他的obj檔案中間用空格隔開。

編譯

修改完上述檔案之後,使用VS或者命令列編譯,正常的話應該就直接編譯通過了。如果編譯不過提示.h檔案無法開啟啥的,請檢查opencl的庫的路徑設定的是否有問題,如果opencl的路徑中有空格的話,那麼在nmake.opt檔案中,路徑用雙引號括起來,如果最後提示連線錯誤,或者lib檔案找不到,同樣先檢查opencl的庫路徑設定的是否正確,如果路徑中有空格,同樣用雙引號括起來。

注意
如果你還是編譯不過去,根據提示內容,修改gdalwarpkernel_opencl.h和檔案gdalwarpkernel_opencl.c檔案。我就遇到了這個問題,修改的是h檔案,修改前後的程式碼如下(上方的是原來的程式碼,下方是修改後的程式碼):

#if defined(DEBUG_OPENCL) && DEBUG_OPENCL == 1
#define CL_USE_DEPRECATED_OPENCL_1_0_APIS
#endif
#if defined(DEBUG_OPENCL) && DEBUG_OPENCL == 1
#define CL_USE_DEPRECATED_OPENCL_1_0_APIS
#else
#define CL_USE_DEPRECATED_OPENCL_1_1_APIS
#endif

至此,編譯如果沒有問題的話,那麼就可以使用depends之類的檢視dll的依賴關係的軟體來檢視gdal的動態庫,如果gdal的動態庫依賴opencl.dll的話,那麼應該就可以支援了,可以使用gdal自帶的gdalwarp.exe進行測試是否支援opencl。
注意:GDAL庫中的重取樣演算法支援opencl庫的有雙線性插值和三次立方卷積,最鄰近取樣是不支援OpenCL加速的,所以測試的時候請指定重取樣演算法進行測試。

兩個問題

使用GDAL的GPU測試的時候發現下面兩個問題:
1、使用OPENCL進行重取樣時,只能使用第一個裝置進行處理(比如我的筆記本可以獲取到兩個GPU裝置,第一個是Intel的整合顯示卡,第二個才是Nvidia的獨立顯示卡)
2、使用-wm引數設定大於顯示卡視訊記憶體時,處理失敗

第一個問題,我大致修改了下,參考下面的程式碼,第二個暫時沒有。
對於第一個問題的修改,主要就是將預設使用的第一個設定,換成了使用最後一個裝置,等有空了可以設定由使用者指定使用那個裝置進行處理。
修改前的程式碼:

    // Find the GPU CL device, this is what we really want
    // If there is no GPU device is CL capable, fall back to CPU
    err = clGetDeviceIDs(platforms[0], CL_DEVICE_TYPE_GPU, 1, &device, NULL);
    if (err != CL_SUCCESS)
    {
        // Find the CPU CL device, as a fallback
        err = clGetDeviceIDs(platforms[0], CL_DEVICE_TYPE_CPU, 1, &device, NULL);
        if( err != CL_SUCCESS || device == 0 )
            return NULL;
    }

修改後的程式碼

    // Find the GPU CL device, this is what we really want
    // If there is no GPU device is CL capable, fall back to CPU
    err = clGetDeviceIDs(platforms[num_platforms-1], CL_DEVICE_TYPE_GPU, 1, &device, NULL);
    if (err != CL_SUCCESS)
    {
        // Find the CPU CL device, as a fallback
        err = clGetDeviceIDs(platforms[num_platforms-1], CL_DEVICE_TYPE_CPU, 1, &device, NULL);
        if( err != CL_SUCCESS || device == 0 )
            return NULL;
    }