现在的位置: 首页 > 综合 > 正文

d3d9查询(Queries Direct3d9)

2013年09月18日 ⁄ 综合 ⁄ 共 4738字 ⁄ 字号 评论关闭

D3D9查询(Queries Direct3d9)


来源:d3d9帮助文档 Queries(Direct3d9)
翻译:游蓝海(http://blog.csdn.net/you_lan_hai
说明:费了好大劲,终于看懂了d3d9 queries,翻译一下跟大家共享。第一次翻译文章,有很多地方不准确,请多多见谅。

概述

       有很多种查询,用来查询资源的状态,这些资源状态包括图形处理单元(GPU)的状态、驱动状态、运行时状态。为了理解不同类型的查询,你需要先理解查询状态。下面的状态流图,说明了每个查询的状态。

查询状态图
    图表列举出了3种状态(Signaled State, Building State, Issued State),分别用圆圈表示。实线表示应用程序驱动事件引发的状态传递,虚线表示资源驱动事件将一个查询从完成状态(Issued State)切换到了就绪状态(Signaled State),每种状态都有不同的用处:
    ·就绪状态(Signaled State):像是一个空闲的状态。查询对象已经生成,等待应用程序来完成此次查询。当查询结束,查询状态转变为就绪状态时,就可以获取到查询结果了。
    ·创建状态(Building State): 像是一个暂存区域。在创建状态,查询已经被发起(通过调用D3DISSUE_BEGIN),但还没有转换到完成状态。当应用程序申明查询结束(通过调用D3DISSUE_END),查询便转换到了完成状态。
    ·完成状态(Issued State): 表示被查询的资源已经接管了查询。当资源完成工作后,会将状态机转换到就绪状态。在完成阶段,应用程序必须检测是否已经转变成就绪状态,如果是就绪状态,那么GetData返回的就是需要的查询结果了。

    一些查询需要开始和结束事件,但是有些仅需要结束事件。仅需要一个结束事件的查询,会在一些暗含的事件发生后自动开始。所有的查询都会返回一个结果,除了事件查询(event query)总是会返回TRUE。


创建查询(Create a query)

    在创建查询之前,你可以检查运行时(runtime)是否支持此查询,调用CreateQuery,并传入一个NULL,如下:
IDirect3DQuery9* pEventQuery;

// Create a device pointer m_pd3dDevice

// Create a query object
HRESULT hr = m_pd3dDevice->CreateQuery(D3DQUERYTYPE_EVENT, NULL);
如果该查询可以被创建,改方法返回成功码;否则,返回一个错误码。一旦CreateQuery调用成功,你可以这样创建一个查询:
IDirect3DQuery9* pEventQuery;
m_pd3dDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQuery);

如果函数调用成功,一个查询对象就创建完成了。查询初始为就绪状态,等待被激活。当查询对象使用完毕之后,像其他d3d对象一样,释放掉它。


发起查询Issue a Query

应用程序通过发起查询来改变一个查询的状态,这里有一个发起查询的例子:

IDirect3DQuery9* pEventQuery;
m_pD3DDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQuery);

// Issue a Begin event
pEventQuery->Issue(D3DISSUE_BEGIN);

or

// Issue an End event
pEventQuery->Issue(D3DISSUE_END);

当发起之后,一个处于就绪状态的查询,将会这样改变:

发起类型 查询变成这样 . . .
D3DISSUE_BEGIN 创建状态(Building state).
D3DISSUE_END 完成状态(Issued state).

发起之后,一个处于创建状态的查询,将会这样改变:

发起类型 查询变成这样 . . .
D3DISSUE_BEGIN (仍然是创建状态,会 重置查询框架 .)
D3DISSUE_END 完成状态.

发起之后,一个处于完成状态的查询,将会这样改变:

发起类型 查询变成这样 . . .
D3DISSUE_BEGIN 创建状态并且重置查询框架。
D3DISSUE_END 放弃已经存在的查询,仍然是完成状态。

检查查询状态以及获得查询结果(Check the Query State and Get the Answer to the Query)

GetData做了两件事情:
1.通过函数返回值,返回查询状态。
2.通过参数pData,返回查询结果。

针对三种查询状态,GetData的返回值如下:

查询状态  GetData 返回值
Signaled S_OK
Building Error code
Issued S_FALSE
例如,当查询处于完成状态时,查询结果不可用,GetData会返回S_FALSE。当资源完成它的工作并且应用程序已经发起过查询结束事件,资源将使查询状态转为就绪状态。在就绪状态中,如果GetData返回S_OK,则表示查询结果已经写入了pData中。举个例子,以下查询事件,返回了一次渲染中绘制的像素个数:
    ·创建查询。
    ·发起查询开始事件。
    ·渲染一些东西。
    ·发起查询结束事件。

下面是该查询的源码:

IDirect3DQuery9* pOcclusionQuery;
DWORD numberOfPixelsDrawn;

m_pD3DDevice->CreateQuery(D3DQUERYTYPE_OCCLUSION, &pOcclusionQuery);

// Add an end marker to the command buffer queue.
pOcclusionQuery->Issue(D3DISSUE_BEGIN);

// API render loop
...
Draw(...)
...

// Add an end marker to the command buffer queue.
pOcclusionQuery->Issue(D3DISSUE_END);

// Force the driver to execute the commands from the command buffer.
// Empty the command buffer and wait until the GPU is idle.
while(S_FALSE == pOcclusionQuery->GetData( &numberOfPixelsDrawn, 
                                  sizeof(DWORD), D3DGETDATA_FLUSH ))
    ;

这些代码做了这些事情:

·调用GetData获取已经绘制的像素个数。
·设定 D3DGETDATA_FLUSH参数,表明允许资源将查询转换成就绪状态。
·不断的检查资源,只要返回S_FALSE,就表示还没有拿到结果。


GetData返回了当前的查询状态。他的返回值可能是S_OK,S_FALSE或者是一个错误码。注意,不要在创建状态调用GetData.
  • S_OK表示资源 (GPU or driver, or runtime)  已经完成了工作,此时查询已经变成了就绪状态,GetData已经返回了查询结果。
  • S_FALSE 表示资源 (GPU or driver, or runtime) 目前还不能返回结果.。这表示GPU还没完成工作或者还没执行到查询。
  • 出现错误,表示查询出现了致命错误,这可能是设备丢失导致的。如果查询已经出现了错误(不是S_FALSE),查询必须要重新创建,然后从就绪状态重新开始。
    除了指定 D3DGETDATA_FLUSH参数外,也可以传入0,进行轻量级的查询状态检测。传入0时,GetData将不会刷新命令缓冲区,因此,需要小心查询陷入死循环。当运行时工作在命令缓冲区时,D3DGETDATA_FLUSH模式将有一次机会刷新缓冲区,将查询转变成就绪状态。


例子: 事件查询

事件查询不支持begin event.

  • 创建查询。
  • 产生一个结束事件。
  • 一直检测,直到GPU完成工作。
  • 产生一个结束事件。
IDirect3DQuery9* pEventQuery = NULL;
m_pD3DDevice->CreateQuery(D3DQUERYTYPE_EVENT, &pEventQuery);

// Add an end marker to the command buffer queue.
pEventQuery->Issue(D3DISSUE_END);

// Empty the command buffer and wait until the GPU is idle.
while(S_FALSE == pEventQuery->GetData( NULL, 0, D3DGETDATA_FLUSH ))
    ;

... // API calls

// Add an end marker to the command buffer queue.
pEventQuery->Issue(D3DISSUE_END);

// Force the driver to execute the commands from the command buffer.
// Empty the command buffer and wait until the GPU is idle.
while(S_FALSE == pEventQuery->GetData( NULL, 0, D3DGETDATA_FLUSH ))
    ;

应用程序需要特别注意刷新命令缓冲区产生的开销,这源于操作系统会切换到内核模式,因此产生了相当大的性能损耗。应用程序也应该意识到等待查询结束时浪费的cpu循环。

    在渲染期间,查询可作为优化来增加性能。花费时间等待查询结束没有益处。取代上面循环的位置,如果查询已经是完成状态,但是应用程序还没有拿到查询结果,优化尝试失败,渲染应该像平常一样继续进行。经典的例子就是隐藏面剔除。如果查询完成,应用程序可以使用查询结果来实现隐藏面剔除;如果查询没有完成,这时跳过隐藏面剔除测试,直接渲染物体,就仿佛是测试不成立,物体没有被裁减。

IDirect3DQuery9* pOcclusionQuery = NULL;
m_pD3DDevice->CreateQuery( D3DQUERYTYPE_OCCLUSION, &pOcclusionQuery );

// Add a begin marker to the command buffer queue.
pOcclusionQuery->Issue( D3DISSUE_BEGIN );

... // API calls

// Add an end marker to the command buffer queue.
pOcclusionQuery->Issue( D3DISSUE_END );

// Avoid flushing and letting the CPU go idle by not using a while loop.
// Check if queries are finished:
DWORD dwOccluded = 0;
if( S_FALSE == pOcclusionQuery->GetData( &dwOccluded, sizeof(DWORD), 0 ) )
{
	// Query is not done yet or object not occluded; avoid flushing/wait by continuing with worst-case scenario
	pSomeComplexMesh->Render();
}
else if( dwOccluded != 0 )
{
	// Query is done and object is not occluded.
	pSomeComplexMesh->Render();
}



抱歉!评论已关闭.