环境:VS2017 语言:C++
根据上一次的博文,龙书第四章后面有一些练习题,这边正好做一下。
先附上工程链接:https://github.com/anguangzhihen/Dx11。
1.这边的程序都是以win64运行的;
2.如果没有找到Common脚本,请到工程/属性/VC++目录中添加包含目录“../Common”;
3.如果没有找到libs,请到工程/属性/链接器添加附加库目录“../Common/libs”
4.所有的练习都在工程中,全局搜索“练习4”关键字就能找到,想要运行打开注释即可。
有任何的错误,请大佬们指正。
1.让Alt+Enter方式切换全屏/窗口无效。
答:
// 练习4.1,在CreateSwapChain函数调用后添加
HR(dxgiFactory->MakeWindowAssociation(mhMainWnd, DXGI_MWA_NO_WINDOW_CHANGES));
MakeWindowAssociation第二个参数可以填写三种值:
1)DXGI_MWA_NO_WINDOW_CHANGES,禁用全屏/窗口转换;
2)DXGI_MWA_NO_ALT_ENTER,禁用Alt+Enter的屏幕切换;
3)DXGI_MWA_NO_PRINT_SCREEN,禁用Print Screen键。
2.打印所有显卡的数量。
答:
// 练习4.2
UINT i = 0;
IDXGIAdapter* adapter = 0;
std::vector<IDXGIAdapter*> adapters;
while (dxgiFactory->EnumAdapters(i, &adapter) != DXGI_ERROR_NOT_FOUND)
{
DXGI_ADAPTER_DESC desc;
if (SUCCEEDED(adapter->GetDesc(&desc)))
{
std::wostringstream outs;
outs << mMainWndCaption << L"显卡" << i << " " << desc.Description << L":" << L"\n";
OutputDebugString(outs.str().c_str());
}
adapters.push_back(adapter);
i++;
}
std::wostringstream outs;
outs << mMainWndCaption << L"显卡数量:" << adapters.size()<< L"\n" ;
OutputDebugString(outs.str().c_str());
效果:
关于Microsoft Basic Render Driver是在没有安装显卡驱动的情况下,使用基本通用驱动来运行GPU。
代码实际练习下来,连打Log都不会了,要不要这么难……
3.检查当前显卡是否支持dx11
答:
// 练习4.3,CheckInterfaceSupport方法只能用于检测dx10和vista以上系统,如果需要检测则直接创建接口,创建成功则支持(例如 ID3D11Device::CreateBlendState)
for (size_t i = 0; i < adapters.size(); i++)
{
auto adapter = adapters[i];
LARGE_INTEGER ver;
if (adapter->CheckInterfaceSupport(__uuidof(ID3D10Device), &ver) == S_OK)
{
std::wostringstream outs;
outs << mMainWndCaption << L"显卡" << i << L"支持Dx10\n";
OutputDebugString(outs.str().c_str());
}
else
{
std::wostringstream outs;
outs << mMainWndCaption << L"显卡" << i << L"不支持Dx10\n";
OutputDebugString(outs.str().c_str());
}
// 使用CreateBlendState函数判断是否支持dx11
ID3D11Device* device;
HRESULT hr = D3D11CreateDevice(
adapter, // 使用指定的显卡
D3D_DRIVER_TYPE_UNKNOWN,
0,
createDeviceFlags,
0, 0,
D3D11_SDK_VERSION, // 我们使用Dx11的SDK
&device,0,0);
if (FAILED(hr))
{
MessageBox(0, L"Direct3D Reature Level 11 unsupported.", 0, 0);
continue;
}
ID3D11BlendState* m_BlendState;
D3D11_BLEND_DESC blendDesc = { 0 };
blendDesc.RenderTarget[0].BlendEnable = TRUE;
blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_SRC_ALPHA; // Color_Fsrc
blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_INV_SRC_ALPHA; // Color_Fdst
blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; // Color_Operation
blendDesc.RenderTarget[0].SrcBlendAlpha = D3D11_BLEND_ONE; // Alpha_Fsrc
blendDesc.RenderTarget[0].DestBlendAlpha = D3D11_BLEND_ZERO; // Alpha_Fdst
blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; // Alpha_Operation
blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
if (FAILED(device->CreateBlendState(&blendDesc, &m_BlendState)))
{
std::wostringstream outs;
outs << mMainWndCaption << L"显卡" << i << L"不支持Dx11\n";
OutputDebugString(outs.str().c_str());
}
else
{
std::wostringstream outs;
outs << mMainWndCaption << L"显卡" << i << L"支持Dx11\n";
OutputDebugString(outs.str().c_str());
}
ReleaseCOM(m_BlendState);
ReleaseCOM(device);
}
书上说让我们用CheckInterfaceSupport,但是一查发现不支持dx11,google了一下,发现该方法只能用于dx10,真正有需要的话请用后面的方法吧。
4.输出默认显卡使用的显示器数量。
答:
// 练习4.4
auto adapterDef = adapters[0];
IDXGIOutput* output;
std::vector<IDXGIOutput*> outputs;
UINT index = 0;
while (adapterDef->EnumOutputs(index, &output) != DXGI_ERROR_NOT_FOUND)
{
outputs.push_back(output);
index++;
}
std::wostringstream outs1;
outs1 << mMainWndCaption << L"显示器数量:" << outputs.size() << L"\n";
OutputDebugString(outs1.str().c_str());
跟获取Adapter差不多,这类方法调用已经很熟练了。
每次打Log也蛮烦的,这边还是定义两个宏好了:
#define Log2(x, y){ std::wostringstream outs; outs << x << y << L"\n"; OutputDebugString(outs.str().c_str()); }
#define Log3(x, y, z){ std::wostringstream outs; outs << x << y << z << L"\n"; OutputDebugString(outs.str().c_str()); }
效果:
5.打印当前显示器所支持的分辨率和刷新率
// 练习4.5
for (size_t i = 0; i < outputs.size(); i++)
{
UINT num = 0;
IDXGIOutput* out = outputs[i];
out->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &num, 0);
DXGI_MODE_DESC* pDescs = new DXGI_MODE_DESC[num];
out->GetDisplayModeList(DXGI_FORMAT_R8G8B8A8_UNORM, DXGI_ENUM_MODES_INTERLACED, &num, pDescs);
for (size_t i = 0; i < num; i++)
{
auto desc = pDescs[i];
std::wostringstream outs;
outs << "width:" << desc.Width << " height:" << desc.Height << " Rate:" << desc.RefreshRate.Numerator << "/" << desc.RefreshRate.Denominator << L"\n";
OutputDebugString(outs.str().c_str());
}
}
效果:
6.尝试使用不同的Viewport参数显示游戏。
尝试下来没有发什么不同,看别的博主说需要填充其他东西才能看的出来,到时候再补一张图片吧。
运行Skull Demo的效果: