GPU渲染时代——2D图形图像中的应用(一)

代码和例子的下载路径:http://pan.baidu.com/s/1ntFPXhv

联系方式:crazycooler@qq.com

随着对硬件渲染的不断开发,DirectX频频发布新的版本,以更好的发挥硬件的性能。但是Windows XP只支持到DirectX 9.0版本,为了软件开发的兼容性,因此不会考虑太高版本的DX。当微软宣告Windows XP退出历史舞台时,可能新的硬件渲染时代将会来临,DX10,DX11,DX12和DX9又有什么重大的区别呢?

可能windows Vista是一个比较糟糕的系统,但它却是一个里程碑,为后面的WIN 7,WIN 8奠定基础。来看下渲染模块的API结构吧:



图1 .Graphics APIs in Windows XP

 

图 2. Graphics APIs in Windows Vista

 

原来各自为营的方式,形成了一个统一的模式。WDDM为后面WIN 7,WIN 8的出现起到非常重要的作用,可能对WDDM会比较陌生,在此摘录官网的一段原话来解释:

Over the years, the power of 3D video cardshas grown dramatically to the point where the vast majority of hardware isdedicated to this function. A new driver model,Windows Display Driver Model (WDDM), brings theGPU and Direct3D to the forefront, allowing the creation of an entirely newexperience, the 3D desktop, that seamlessly blends the 2D world of GDI with thepower of modern programmable GPUs. With WDDM, the video hardware is drivenentirely by Direct3D, and all other graphics interfaces communicate with thevideo hardware via the new Direct3D–centric driver model.


而且DX10之后,发生了巨大变化。首先将2D模块从D3D中分离出来,形成D2D。同样用官网的原话来描述Direct2D:

Direct2D is a hardware-accelerated,immediate-mode, 2-D graphics API that provides high performance andhigh-quality rendering for 2-D geometry, bitmaps, and text. The Direct2D API isdesigned to interoperate well with GDI, GDI+, and Direct3D.


如果需要做二维渲染的话,还少不了Direct2D的好基友,DirectWrite和WIC。

DirectWrite一个文字渲染模块:

DirectWrite supports high-quality textrendering, resolution-independent outline fonts, and full Unicode text and layouts.

 

WIC一个图像模块:

The Windows Imaging Component (WIC) is an extensibleplatform that provides low-level API for digital images.  WIC supports the standard web image formats,high dynamic range images, and raw camera data. WIC also supports additional features.

 

当然还少不了DXGI,和设备打交道的模块。同样也是从D3D分离出来的。

Microsoft DirectX Graphics Infrastructure (DXGI) handles enumeratinggraphics adapters, enumerating display modes, selecting buffer formats, sharingresources between processes (such as, between applications and the DesktopWindow Manager (DWM)), and presenting rendered frames to a window or monitorfor display.

You can use DXGI to present frames to awindow, monitor, or other graphics component for eventual composition anddisplay. You can also use DXGI to read the contents on a monitor.

 

差不多渲染相关的模块就这些了(还有Direct3D太熟悉了,在此就不再介绍。),如何来使用这些新技术呢?


 环境

首先,需要新的操作系统,在此最低要求是WIN 7 SP1,这样加个拓展包就可以使用DX11.1和DXGI1.2(WIN8 系统自带),因为DX11.1中对图像功能的增加还是比较诱人的。


图3. 拓展包的路径

ps:安装vs2012后,会自动安装这个拓展包。

然后,搭建底层架构,将DX的渲染用起来。

 

DX的简易封装

因为DX的初始化还是比较麻烦的,要写一大堆。而且每次都是差不多的工作,因此对其封装以简化DX的使用。

在此封装一个MDxKernel模块,对外导出的接口和类:

class DXKERNEL_DLL MDxKernel
{
public:
	MDxKernel(){}
	virtual ~MDxKernel(){}
public:
	virtual ID2D1Factory1 *GetD2D1Factory()=0;
	virtual IDWriteFactory1 *GetDWriteFactory()=0;
	virtual ID2D1DeviceContext *GetD2D1DevContext()=0;
	virtual IWICImagingFactory *GetWICFactory()=0;

	virtual float GetDpi()=0;
	virtual ID2D1Bitmap1 *GetTargetBitmap()=0;
public:
	virtual void UpdateForWindowSizeChange()=0;
	virtual void Present(CRect *dtRect)=0;
	
};

namespace DX
{
DXKERNEL_DLL MDxKernel *CreateDxKernel(HWND hWnd,float dpi = -1.0f);

DXKERNEL_DLL void ReleaseDxKernel(MDxKernel *&pDxKernel);
}

当然在MDxKernel类中还可以导出更多的接口,只是现在不需要,用到时再添加。


两个在DX namespace中的函数,是类似工厂模式设计的。

功能是创建和释放MDxKernel对象。由于窗口作为输出设备的情况比较多,因此这里也就使用窗口句柄进行传入。


MDxKernel中,最重要的两个操作接口(其他只是些get接口)

UpdateForWindowSizeChange窗口大小改变时调用

Present在绘图完成后,操作交换页,该接口中可以控制渲染的垂直同步。


具体的MDxKernel实现将会在下一篇博文中介绍。


Sample

介绍下封装后MDxKernel的使用:

因为封装的方式是将窗口作为输出设备,所以创建DxKernel对象时需要提供一个窗口句柄。

在类成员中添加成员变量:

MDxKernel *m_pDxKernel;
构造函数中创建:

if(!m_pDxKernel)
		m_pDxKernel = DX::CreateDxKernel(m_hWnd);
析构函数中释放:

if(m_pDxKernel)
		DX::ReleaseDxKernel(m_pDxKernel);

然后在微软的官网上面随便拿了一个例子,做一个简单的输出效果:

HRESULT CDxSampleDlg::OnRender()
{
	HRESULT hr = S_OK;

	//hr = CreateDeviceResources();
	ID2D1DeviceContext *m_pRenderTarget = m_pDxKernel->GetD2D1DevContext();

	ID2D1SolidColorBrush* m_pLightSlateGrayBrush;
	ID2D1SolidColorBrush* m_pCornflowerBlueBrush;
	if (SUCCEEDED(hr))
	{
		// Create a gray brush.
		hr = m_pRenderTarget->CreateSolidColorBrush(
			D2D1::ColorF(D2D1::ColorF::LightSlateGray),
			&m_pLightSlateGrayBrush
			);
	}
	if (SUCCEEDED(hr))
	{
		// Create a blue brush.
		hr = m_pRenderTarget->CreateSolidColorBrush(
			D2D1::ColorF(D2D1::ColorF::CornflowerBlue),
			&m_pCornflowerBlueBrush
			);
	}

	if (SUCCEEDED(hr))
	{
		m_pRenderTarget->BeginDraw();

		m_pRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());

		m_pRenderTarget->Clear(D2D1::ColorF(D2D1::ColorF::White));

		D2D1_SIZE_F rtSize = m_pRenderTarget->GetSize();

		// Draw a grid background.
		int width = static_cast<int>(rtSize.width);
		int height = static_cast<int>(rtSize.height);

		for (int x = 0; x < width; x += 10)
		{
			m_pRenderTarget->DrawLine(
				D2D1::Point2F(static_cast<FLOAT>(x), 0.0f),
				D2D1::Point2F(static_cast<FLOAT>(x), rtSize.height),
				m_pLightSlateGrayBrush,
				0.5f
				);
		}

		for (int y = 0; y < height; y += 10)
		{
			m_pRenderTarget->DrawLine(
				D2D1::Point2F(0.0f, static_cast<FLOAT>(y)),
				D2D1::Point2F(rtSize.width, static_cast<FLOAT>(y)),
				m_pLightSlateGrayBrush,
				0.5f
				);
		}

		// Draw two rectangles.
		D2D1_RECT_F rectangle1 = D2D1::RectF(
			rtSize.width/2 - 50.0f,
			rtSize.height/2 - 50.0f,
			rtSize.width/2 + 50.0f,
			rtSize.height/2 + 50.0f
			);

		D2D1_RECT_F rectangle2 = D2D1::RectF(
			rtSize.width/2 - 100.0f,
			rtSize.height/2 - 100.0f,
			rtSize.width/2 + 100.0f,
			rtSize.height/2 + 100.0f
			);


		// Draw a filled rectangle.
		m_pRenderTarget->FillRectangle(&rectangle1, m_pLightSlateGrayBrush);

		// Draw the outline of a rectangle.
		m_pRenderTarget->DrawRectangle(&rectangle2, m_pCornflowerBlueBrush);

		hr = m_pRenderTarget->EndDraw();
	}



	if (hr == D2DERR_RECREATE_TARGET || hr == S_OK)
	{
		m_pDxKernel->Present(NULL);

		hr = S_OK;
		SafeRelease(&m_pLightSlateGrayBrush);
		SafeRelease(&m_pCornflowerBlueBrush);
	}

	return hr;
}
运行效果:





在下是一个做图形图像渲染的码农

第一次写博客,不知道如何表达,写得不到位的地方请多拍板砖。

其中多处地方参考微软官网和MSDN,在此表示感谢。

代码和例子的下载路径:http://pan.baidu.com/s/1ntFPXhv

联系方式:crazycooler@qq.com







评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值