QT GPU混合使用
2013-10-11 11:23
253 查看
GPU相对CPU,可以更好地并行处理数据,因此可以利用GPU,来进行可以并行的计算,比如图像处理中,若每个像素的处理都独立于其他像素,则就可以使用GPU来加速。
GPGPU的一个比较一般而通用的核心方法就是将待处理的图片或者其他数据转成比如说OpenGL的纹理,然后用OpenGL绘制一个矩形,并使用GLSL、Cg、HLSL等着色语言编写着色程序实现针对每个数据的算法,OpenGL绘制的东西放在用于离屏渲染的帧缓存对象FBO里,每个输入数据对应一组输出,运算完后从FBO中获得结果。
GPGPU的实现方法可以参考如下文章:
http://www.mathematik.uni-dortmund.de/~goeddeke/gpgpu/tutorial.html
翻译版:
http://blog.csdn.net/huawenguang/archive/2007/03/15/1530547.aspx
其中的细节不多说,文章讲得比较详细,也有源码提供。下面我写一下我总结的一些问题
一、硬件支持
要想GPGPU有较好效果,显卡不能太烂……我之前使用一个笔记本的集成显卡,结果综合起来还没有用CPU跑的快。
对于OpenGL的纹理,较烂的显卡只能支持浮点纹理,只有Geforce8以上才能支持整型纹理。虽然似乎显卡处理浮点数速度挺快,但整型纹理的好处是,对于Qt来说,图像像素信息是以整数形式存储的,这样导入导出GPU时不需要转换。
另外,对于N卡和A卡,OpenGL纹理创建的时候的格式是有区别的,虽然也有通用的格式,不过也不是全都覆盖的,还是会有一些型号的显卡无法运行,需要使用更针对性的格式(参考文章中的相关表格)。因此,这里需要识别出当前系统的显卡型号,并以此选择不同的格式。
其他平台我不知道,Windows下,各个硬件的信息都放在了注册表里,因此我们要做的就是找到这个地方,并找到显卡的位置,然后读取相关的信息,并根据信息来设置参数
硬件信息的注册表地址:HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Class
[cpp]
view plaincopy
void SetTextureParams()
{
SP_DEVINFO_DATA DeviceInfoData;
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
char buffer[MAX_PATH];
ZeroMemory(buffer, MAX_PATH);
HKEY hCurKey;
std::string strConstKey;
HKEY hRootKey = HKEY_LOCAL_MACHINE;
OSVERSIONINFO osvi;
BOOL bIsWindowsXPorLater;
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
// 获得操作系统版本
bIsWindowsXPorLater =
( (osvi.dwMajorVersion > 5) ||
( (osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion >= 1) ));
if (bIsWindowsXPorLater)
strConstKey = "SYSTEM//CurrentControlSet//Control//Class//";
else
strConstKey = "SYSTEM//CurrentControlSet//Services//Class//";
HDEVINFO hDevInfo;
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(NULL,
0, // Enumerator
0,
DIGCF_PRESENT | DIGCF_ALLCLASSES );
if (hDevInfo == INVALID_HANDLE_VALUE)
{
// Insert error handling here.
return;
}
char szValueData[100];
DWORD dwVDataSize=100;
for (DWORD i=0;SetupDiEnumDeviceInfo(hDevInfo,i,&DeviceInfoData);i++)
{
SetupDiGetDeviceRegistryPropertyA(hDevInfo, &DeviceInfoData,
SPDRP_DRIVER, NULL, (PBYTE)buffer, MAX_PATH, NULL);
std::string strKey = strConstKey;
strKey.append(buffer);
char dpath[100]={0}, purepath[100]={0};
int strlength=strlen(strKey.c_str());
memcpy(dpath, strKey.c_str(), strlength+1);
if(dpath[strlength-1]!='}'){
int temp=strcspn(dpath, "}");
memcpy(purepath, dpath, temp+1);
}
else{
memcpy(purepath, dpath, strlength+1);
}
if (ERROR_SUCCESS != ::RegOpenKeyExA(hRootKey, (LPCSTR)purepath, 0, KEY_READ, &hCurKey))
{
// TRACE( "%d ", GetLastError());
return;
}
// Get the driver description
DWORD dwType = REG_SZ;
// 根据Class的名称,找到显卡的对应项,即Display
if (ERROR_SUCCESS == ::RegQueryValueExA(hCurKey, (LPCSTR)"Class", NULL, &dwType, (LPBYTE)szValueData, &dwVDataSize)) {
dwVDataSize=100;
if(strcmp((char*)szValueData, "Display")!=0){
continue;
}
if (ERROR_SUCCESS != ::RegOpenKeyExA(hRootKey, (LPCSTR)dpath, 0, KEY_READ, &hCurKey)){
return;
}
// 找到显卡后,我这里是简单地根据厂商,即ProviderName来判断;DriverDesc提供了具体的型号描述,也可发掘其他有用信息
if (ERROR_SUCCESS == ::RegQueryValueExA(hCurKey, (LPCSTR)"ProviderName", NULL, &dwType, (LPBYTE)szValueData, &dwVDataSize)) {
dwVDataSize=100;
if(strcmp((char*)szValueData, "NVIDIA")==0){
// 设置N卡的参数
}
else{
// 设置其他卡的参数
}
return;
}
}
}
}
参考文献:http://topic.csdn.net/t/20051027/13/4353990.html
二、纹理坐标
OpenGL的纹理有两种tex2D和texRect。前者必须是正方形纹理,纹理坐标范围为[0, 1];后者可以是任意形状,纹理坐标范围为[0.5, length-0.5],而不是[0, length-1]。
三、GLSL
GLSL的输出颜色变量:gl_FragColor
这个变量似乎不能读,只能写。如果先对它赋值,然后再读取它,在很多情况下会编译不通过。我之前写了个简单的程序没啥问题。后来程序里加了个循环语句,就死也编译不了了。因此,gl_FragColor最好在程序的最后赋值,如果需要对输出结果反复修改,先放在一个临时变量里。
GPGPU的一个比较一般而通用的核心方法就是将待处理的图片或者其他数据转成比如说OpenGL的纹理,然后用OpenGL绘制一个矩形,并使用GLSL、Cg、HLSL等着色语言编写着色程序实现针对每个数据的算法,OpenGL绘制的东西放在用于离屏渲染的帧缓存对象FBO里,每个输入数据对应一组输出,运算完后从FBO中获得结果。
GPGPU的实现方法可以参考如下文章:
http://www.mathematik.uni-dortmund.de/~goeddeke/gpgpu/tutorial.html
翻译版:
http://blog.csdn.net/huawenguang/archive/2007/03/15/1530547.aspx
其中的细节不多说,文章讲得比较详细,也有源码提供。下面我写一下我总结的一些问题
一、硬件支持
要想GPGPU有较好效果,显卡不能太烂……我之前使用一个笔记本的集成显卡,结果综合起来还没有用CPU跑的快。
对于OpenGL的纹理,较烂的显卡只能支持浮点纹理,只有Geforce8以上才能支持整型纹理。虽然似乎显卡处理浮点数速度挺快,但整型纹理的好处是,对于Qt来说,图像像素信息是以整数形式存储的,这样导入导出GPU时不需要转换。
另外,对于N卡和A卡,OpenGL纹理创建的时候的格式是有区别的,虽然也有通用的格式,不过也不是全都覆盖的,还是会有一些型号的显卡无法运行,需要使用更针对性的格式(参考文章中的相关表格)。因此,这里需要识别出当前系统的显卡型号,并以此选择不同的格式。
其他平台我不知道,Windows下,各个硬件的信息都放在了注册表里,因此我们要做的就是找到这个地方,并找到显卡的位置,然后读取相关的信息,并根据信息来设置参数
硬件信息的注册表地址:HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control/Class
[cpp]
view plaincopy
void SetTextureParams()
{
SP_DEVINFO_DATA DeviceInfoData;
DeviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
char buffer[MAX_PATH];
ZeroMemory(buffer, MAX_PATH);
HKEY hCurKey;
std::string strConstKey;
HKEY hRootKey = HKEY_LOCAL_MACHINE;
OSVERSIONINFO osvi;
BOOL bIsWindowsXPorLater;
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osvi);
// 获得操作系统版本
bIsWindowsXPorLater =
( (osvi.dwMajorVersion > 5) ||
( (osvi.dwMajorVersion == 5) && (osvi.dwMinorVersion >= 1) ));
if (bIsWindowsXPorLater)
strConstKey = "SYSTEM//CurrentControlSet//Control//Class//";
else
strConstKey = "SYSTEM//CurrentControlSet//Services//Class//";
HDEVINFO hDevInfo;
// Create a HDEVINFO with all present devices.
hDevInfo = SetupDiGetClassDevs(NULL,
0, // Enumerator
0,
DIGCF_PRESENT | DIGCF_ALLCLASSES );
if (hDevInfo == INVALID_HANDLE_VALUE)
{
// Insert error handling here.
return;
}
char szValueData[100];
DWORD dwVDataSize=100;
for (DWORD i=0;SetupDiEnumDeviceInfo(hDevInfo,i,&DeviceInfoData);i++)
{
SetupDiGetDeviceRegistryPropertyA(hDevInfo, &DeviceInfoData,
SPDRP_DRIVER, NULL, (PBYTE)buffer, MAX_PATH, NULL);
std::string strKey = strConstKey;
strKey.append(buffer);
char dpath[100]={0}, purepath[100]={0};
int strlength=strlen(strKey.c_str());
memcpy(dpath, strKey.c_str(), strlength+1);
if(dpath[strlength-1]!='}'){
int temp=strcspn(dpath, "}");
memcpy(purepath, dpath, temp+1);
}
else{
memcpy(purepath, dpath, strlength+1);
}
if (ERROR_SUCCESS != ::RegOpenKeyExA(hRootKey, (LPCSTR)purepath, 0, KEY_READ, &hCurKey))
{
// TRACE( "%d ", GetLastError());
return;
}
// Get the driver description
DWORD dwType = REG_SZ;
// 根据Class的名称,找到显卡的对应项,即Display
if (ERROR_SUCCESS == ::RegQueryValueExA(hCurKey, (LPCSTR)"Class", NULL, &dwType, (LPBYTE)szValueData, &dwVDataSize)) {
dwVDataSize=100;
if(strcmp((char*)szValueData, "Display")!=0){
continue;
}
if (ERROR_SUCCESS != ::RegOpenKeyExA(hRootKey, (LPCSTR)dpath, 0, KEY_READ, &hCurKey)){
return;
}
// 找到显卡后,我这里是简单地根据厂商,即ProviderName来判断;DriverDesc提供了具体的型号描述,也可发掘其他有用信息
if (ERROR_SUCCESS == ::RegQueryValueExA(hCurKey, (LPCSTR)"ProviderName", NULL, &dwType, (LPBYTE)szValueData, &dwVDataSize)) {
dwVDataSize=100;
if(strcmp((char*)szValueData, "NVIDIA")==0){
// 设置N卡的参数
}
else{
// 设置其他卡的参数
}
return;
}
}
}
}
参考文献:http://topic.csdn.net/t/20051027/13/4353990.html
二、纹理坐标
OpenGL的纹理有两种tex2D和texRect。前者必须是正方形纹理,纹理坐标范围为[0, 1];后者可以是任意形状,纹理坐标范围为[0.5, length-0.5],而不是[0, length-1]。
三、GLSL
GLSL的输出颜色变量:gl_FragColor
这个变量似乎不能读,只能写。如果先对它赋值,然后再读取它,在很多情况下会编译不通过。我之前写了个简单的程序没啥问题。后来程序里加了个循环语句,就死也编译不了了。因此,gl_FragColor最好在程序的最后赋值,如果需要对输出结果反复修改,先放在一个临时变量里。
相关文章推荐
- Qt4另类使用教程(五)---Qt4使用win32 wgl渲染OpenGL FrameWork + cg language(GPU渲染语言)
- GPUImage混合滤镜的简单使用
- QT中QPainter的使用及矩形、圆形等常见图形的画法
- vs2010 使用QT
- qt中对任务繁忙时QProgressDialog的使用
- 使用QT连接SqlServer数据库
- Qt笔记-3-LineEdit中使用正则表达
- CUDA—使用GPU暴力破解密码
- Qt中使用事件过滤器来处理键盘焦点
- Qt5.5 QFileDialog类的使用方法
- QT样式表,setstylesheet,控件使用图片
- C#中Event和Delegate的混合使用
- qt QDockWidget QStackWidget的简单使用
- Qt中使用QSqlDatabase::removeDatabase()的正确方法
- Qt 学习之路 2(64):使用 QJsonDocument 处理 JSON
- QT学习 第一章:基本对话框--使用标准输入框
- Cell自适应高度及自定义cell混合使用
- qt5 扩展式弹窗的使用例子
- 在 Qt 程序中使用 MPIR
- iOS 开发,工程中混合使用 ARC 和非ARC