#Directx12基本的Graphics概念和Direct3D类型(二)

多重采样(Multisampling)

  • 由于我们的屏幕的像素点不是足够的小,因此在绘制一条直线时候可能出现阶梯形近似的表达一条直线。如下
    这里写图片描述

通过不断的提高屏幕的分辨率可以逐步的消除这种影响。然而当提高分辨率变得不可能时候,我们可以采取一些其他的方法减弱这个影响,其中一种技术是 超级采样(supersampling),其原理是将backbuffer和depthbuffer增大到屏幕分辨率的四倍大小,然后将图像渲染在这个增大的backbuffer上,然后当需要将backbuffer上的内容呈现到屏幕上的时候在将4个像素点的颜色值取平均数,最后映射到屏幕上。这个方法通过软件增大屏幕的分辨率达到效果

然而超级采样的代价是昂贵的,这种做法既要增加像素计算量也会增加内存占用。Direct3D采取一种折中的方法:多重采样(multisampling),这种方法通过共享一些计算结果来减少计算量。例如对于常用的四重采样,同样需要四倍大小的backbuffer和depthbuffer,但是不同于超级采样计算每一个子像素点的颜色,对么一个像素点只计算一次,而且只计算中心店的像素值,对于下一个像素点则根据是否可见共享一些计算结果。

Direct3D中的多重采样

为了使用Direct3D中的多重采样,需要填充一个结构体DXGI_SAMPLE_DESC

typedef struct DXGI_SAMPLE_DESC{
 UINT Cout;//每个采样点的像素数量
 UINT Quality;//采样的质量水平
} DXGI_SAMPLE_DESC

其中的Quality因各个厂商而异,且由纹理格式和采样像素点数量决定。高的采样像素点数量和采样质量意味着更高的代价,因此必须权衡。

  • 我们可以通过**ID3D12Device::CheckFeatureSupport()** 方法查询特定的纹理格式和采样大小下的质量水平,如下
    typedef struct D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS{
    DXGI_FORMAT Foramt; //纹理格式
    UINT SampleCount; //采样大小
    D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG Flags; //采样质量标志位
    UINT NumQulityLevels; //采样水平
    }D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS;
    D3D12_FEATURE_DATA_MULTISAMPLE_QUALITY_LEVELS msQualityLevels;
    msQualityLevels.Format=mBackBufferFormat;
    msQualityLevels.SampleCount=4 ;
    msQualityLevels.Flags=D3D12_MULTISAMPLE_QUALITY_LEVELS_FLAG_NONE;
    msQualityLevels.NumQualityLevels=0;

ThrowIfFailed(md3dDevice->CheckFeatureSupport(
D3D12_FEATURE_MULTISAMPLE_QUALITY_LEVELS, //查询的特性枚举
& msQualityLevels, //既是输入也是查询结果的输出
sizeof(msQualityLevels)));
//查询的结果会填充在msQualityLevels中,合法的采样质量水平是[0,NumQualityLevels-1]的一个值

最大的采样大小是通过 #define D3D11_MAX_MULTYSAMPLE_SAMPLE_COUNT 来定义的。通常我们使用4重或者8重采样,如果不希望使用多重采样,可以通过定义采样大小为1,采样质量水平为0来达到效果。所有的Direct3D 11设备对于所有的渲染目标格式都支持4重采样

特性等级(Feature Levels)

Direct3D 11引入了特性等级概念,这是一个枚举量,其枚举值对应着Directx 9到11版本

eum D3D_FEATURE_LEVEL{
D3D_FEATURE_LEVEL_9_1 =0X9100,
D3D_FEATURE_LEVEL_9_2 =0X9200,
D3D_FEATURE_LEVEL_9_3 =0X9300,
D3D_FEATURE_LEVEL_10_0 =0Xa000,
D3D_FEATURE_LEVEL_10_1 =0Xa100,
D3D_FEATURE_LEVEL_11_0 =0Xb000,
D3D_FEATURE_LEVEL_11_1 =0Xb100,
} D3D_FEATURE_LEVEL;

特性等级的概念方便了开发者进行开发,假设GPU支持某一个等级的特性,例如D3D_FEATURE_LEVEL_11_0 特性,则要求GPU必须支持整个Direct3D 11的所有特性(当然允许某些特性需要根据情况查询,例如多重采样水平,因为允许不同的硬件设备不同)。

如果某个硬件设备不支持一个特定的特性水平,则会按照顺序往下查询直到找到支持的设备特性等级。

DXGI(DirectX Graphics Infrastructure)

-DXGI 是一组基础的Direct3D API。DXGI 的基本思想是很多看似不一样的任务其实使用的是同一套API,因此DXGI处理其他通用的图形功能,例如全屏模式转换,图形枚举系统信息,如显示适配器,显示器和支持的显示模式(分辨率,刷新率,等等);它还定义了各种支持的表面的格式(DXGI_FORMAT)。

  • DXGI中一个重要的接口是IDXGIFactory,这个接口主要用于创建IDXGISwapChain交换链以及枚举显示适配器(display adapters),显示适配器主要用于实现图形化功能。通常显示适配器由硬件提供支持,然而一个系统同样可以拥有一些软件显示适配器,一个适配器使用IDXGIAdapter表示。可以通过以下方法枚举所有的适配器
void D3DApp::LogAdapters()
{
UINT i = 0;
IDXGIAdapter* adapter = nullptr;//定义一个显示适配器指针对象
std::vector<IDXGIAdapter*> adapterList; //保存当前系统的所有适配器
while(mdxgiFactory->EnumAdapters(i, &adapter) !=DXGI_ERROR_NOT_FOUND)
{  //EnumAdapters() 枚举显示适配器
DXGI_ADAPTER_DESC desc;
adapter->GetDesc(&desc);  //获得当前适配器的信息
std::wstring text = L”***Adapter: “;
text += desc.Description;
text += L”\n”;
OutputDebugString(text.c_str());
adapterList.push_back(adapter);
++i;
} 
for(size_t i = 0; i < adapterList.size(); ++i)
{
LogAdapterOutputs(adapterList[i]);
ReleaseCom(adapterList[i]);
}
}

****  一种可能的输出为
*** Adapter: NVIDIA GeForce GTX 760   //硬件适配器
*** Adapter: Microsoft Basic Render Driver  //win8以及以后的系统包含的软件适配器

输出适配器(IDXGIOutput)

  • 一个系统可以包含很多个屏幕,因此一个屏幕就是一个输出适配器的实例,一个输出使用IDXGIOutput表示。一个适配器可以关联一系列的输出,例如一个显示屏多个图形显卡以及一个显卡多个屏幕情况,我们可以使用以下代码枚举出关联到一个适配器的所有输出实例:
void D3DApp::LogAdapterOutputs(IDXGIAdapter* adapter)
{
UINT i = 0;
IDXGIOutput* output = nullptr;
while(adapter->EnumOutputs(i, &output) !=DXGI_ERROR_NOT_FOUND)
{  //枚举所有的输出实例
DXGI_OUTPUT_DESC desc;
output->GetDesc(&desc);
std::wstring text = L”***Output: “;
text += desc.DeviceName;
text += L”\n”;
OutputDebugString(text.c_str());
LogOutputDisplayModes(output,
DXGI_FORMAT_B8G8R8A8_UNORM);
ReleaseCom(output);
++i;
}
}

//注: win自带的软件显示适配器(Microsoft Basic Render Driver)  不包含输出适配器

DXGI_MODE_DESC(显示模式信息)

每一个显示器都有一系列其支持的显示模式,使用DXGI_MODE_DESC 表示显示模式

typedef struct DXGI_MODE_DESC
{
UINT Width; //分辨率 width
UINT Height; // 分辨率height
DXGI_RATIONAL RefreshRate;  //刷新频率
DXGI_FORMAT Format; // 显示格式
DXGI_MODE_SCANLINE_ORDER ScanlineOrdering;//扫描顺序:渐进式  隔行扫描
DXGI_MODE_SCALING Scaling; // 图像拉伸方式
} DXGI_MODE_DESC;

typedef struct DXGI_RATIONAL
{
UINT Numerator;
UINT Denominator;
} DXGI_RATIONAL;

typedef enum DXGI_MODE_SCANLINE_ORDER
{
DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED = 0,
DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE = 1,
DXGI_MODE_SCANLINE_ORDER_UPPER_FIELD_FIRST = 2,
DXGI_MODE_SCANLINE_ORDER_LOWER_FIELD_FIRST = 3
} DXGI_MODE_SCANLINE_ORDER;

typedef enum DXGI_MODE_SCALING
{
DXGI_MODE_SCALING_UNSPECIFIED = 0,
DXGI_MODE_SCALING_CENTERED = 1,
DXGI_MODE_SCALING_STRETCHED = 2
} DXGI_MODE_SCALING;

填充一个显示格式,可以通过以下代码得到一些列支持的显示模式:

void D3DApp::LogOutputDisplayModes(IDXGIOutput*output, DXGI_FORMAT format)
{
UINT count = 0;
UINT flags = 0;
output->GetDisplayModeList(format, flags, &count,nullptr); 
std::vector<DXGI_MODE_DESC> modeList(count);
output->GetDisplayModeList(format, flags, &count,&modeList[0]); //获得支持的显示模式列表
for(auto& x : modeList){
UINT n = x.RefreshRate.Numerator;//获得刷新率的分子
UINT d = x.RefreshRate.Denominator;//获得刷新率的分母
std::wstring text =
L”Width = ” + std::to_wstring(x.Width) + L” ” +
L”Height = ” + std::to_wstring(x.Height) + L” ” +
L”Refresh = ” + std::to_wstring(n) + L”/” +std::to_wstring(d) +L”\n”;
::OutputDebugString(text.c_str());
} }
//一种可能的输出是:
width = 1920 Height = 1080 Refresh = 59950/1000
Width = 1920 Height = 1200 Refresh = 59950/1000

//* 2016/10/5 23:33

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值