确实的来说,这是个Debug/Profile的需求,在运行期这个时间毫无意义,有意义的是两帧之间走过了多少时间,而这个,可以用来查询某一个效果所用耗时,废话不多少,进入正题.

    首先要创建查询接口,也就是ID3D11Query* 接口,与查询CPU耗时一样,我们需要三个量,GPU时钟频率,起始时的时间戳,结束时的时间戳.听上去听简单,不过略比CPU的复杂,因为需要通过Begin和End来操作,首先创建三个查询接口:

    使用ID3D11Device::CreateQuery函数,函数声明如下:

        HRESULT CreateQuery(

            [in]   const D3D11_QUERY_DESC *pQueryDesc,

            [out]  ID3D11Query **ppQuery

        );

    我们需要填充一个D3D11_QUERY_DESC结构,来指明查询的内容, D3D11_QUERY_DESC结构如下:

        typedef
							struct D3D11_QUERY_DESC {

            D3D11_QUERY Query;

            UINT MiscFlags;

} D3D11_QUERY_DESC

    简单的,将MiscFlags置为0,查询类型有很多种,只捡我们需要的讲,其中一个就是查询时间戳的 D3D11_QUERY_TIMESTAMP,其他的查询,需要在查询之前调用ID3D11Device::Begin,查询之后使用ID3D11Device::End,但是时间戳很明显的不是"一段时间"的查询,而是一个点,所以我们只需要调用End就行了,首先我们就是要获取起始时间戳,意味着创建完查询后,立即调用End,代码如下:

        D3D11_QUERY_DESC
desc;

desc.Query
=D3D11_QUERY_TIMESTAMP;

desc.MiscFlags
=
0;

        device->CreateQuery(&desc,
& timestampstart;

        context->End(timestampstart);

    这样便获得了起始时间的查询接口,同理,我们还需要创建一个结束时的时间戳查询接口,按照上面的代码再创建一个,然后在结束时调用End,获得数据,所有查询接口的数据通过ID3D11Device::GetData返回,不同的查询接口返回的数据大小不一样,这个函数需要你自己提供一个BUFFER(你得保证有足够的大小),对于D3D11_QUERY_TIMESTAMP,GetData返回的是一个UINT64(windows.h),于是我们需要这样:

            std::uint64_t
starttime
=
0;

            while
(context->GetData(timestampstart,
&starttime,
sizeof(starttime),
0)
!=
S_OK)

                ;

            std::uint64_t
endtime
=
0;

            while
(context->GetData(timestampend,
&endtime,
sizeof(endtime),
0)
!=
S_OK)

                ;

 

    查询不成功可是不断的去循环调用的哦,接下来是查询GPU时钟频率,值得注意的是,这应该不是一个固定值(),使用D3D11_QUERY_TIMESTAMP_DISJOINT  来查询时钟频率,GetData会填充这样一个

        typedef
							struct D3D11_QUERY_DATA_TIMESTAMP_DISJOINT {

              UINT64 Frequency;

              BOOL   Disjoint;

        } D3D11_QUERY_DATA_TIMESTAMP_DISJOINT;

    

结构,很显然,Frequency放的是频率,BOOL变量指示是否有效,如同Disjoint的意思,当其为TRUE的时候,说明时间戳计数因为某些原因而导致了不准确,只有当其为FALSE,查询的两个时间戳之差才是有效的,很显然,加上如下代码:

    desc.Query
=
D3D11_QUERY_TIMESTAMP_DISJOINT;

    desc.MiscFlags
=
0;

    device->CreateQuery(&desc,
&disjoint);

注意这个查询需要遵循Begin,End调用,于是,创建完之后,我们应该调用Begin

    context->Begin(disjoint);

在查询结束时调用timestampend的End和disjoint的End

    context->End(timestampend);

    context->End(disjoint);

然后我们就可以获得经过时间了:

    std::uint64_t
starttime
=
0;

    while
(context->GetData(timestampstart,
&starttime,
sizeof(starttime),
0)
!=
S_OK)

                ;

    std::uint64_t
endtime
=
0;

    while
(context->GetData(timestampend,
&endtime,
sizeof(endtime),
0)
!=
S_OK)

        ;

    D3D11_QUERY_DATA_TIMESTAMP_DISJOINT
disjointdata;

    while
(context->GetData(disjoint,
&disjointdata,
sizeof(disjointdata),
0)
!=
S_OK)

                ;

 

    float
time
=
0.0f;

    if
(!disjointdata.Disjoint)

    {

        std::uint64_t
delta
=
endtime
-
starttime;

        float
frequency
=
static_cast<float>(disjointdata.Frequency);

        time
=
(delta
/
frequency);

    }

 

为了方便查询,我们可以写个block类,在某个子操作之前构造一个block,构造函数建立一个查询,析构函数结束一个查询.这个block将自己注册在一个查询管理类中,大概就想这样子:

    profileblock::profileblock(const
std::wstring&
name)

            :name(name)

        {

            profiler::global_profiler.startprofile(name);

        }

 

    profileblock::~profileblock()

    {

        profiler::global_profiler.endprofile(name);

    }

至于profiler就用一个map,来实现一个字符串对应一个查询

 

具体实现,我是每5帧才进行一次输出的,但没有取平均时间,代码如下:

//头文件

struct
d3d11_timer

        {

            static
const
std::uint64_t
querylatency
=
5;

 

            ID3D11QueryPtr
disjoint[querylatency];

            ID3D11QueryPtr
timestampstart[querylatency];

            ID3D11QueryPtr
timestampend[querylatency];

            bool
started{
false
};

            bool
finished{
false
};

 

            void
start(std::uint64_t currframe,ID3D11Device* device,
ID3D11DeviceContext* context);

            void
end(std::uint64_t currframe,
ID3D11DeviceContext* context);

            float
time(std::uint64_t currframe,
ID3D11DeviceContext* context);

        };

        class
profiler

        {

        public:

            static
profiler
global_profiler;

            

            void
init(ID3D11Device* device,
ID3D11DeviceContext* context);

 

            void
startprofile(const
std::wstring& name);

            void
endprofile(const
std::wstring& name);

 

            void
endframe();

        protected:

            static
const
std::uint64_t
querylatency
=
d3d11_timer::querylatency;

 

            using
profilemap
=
std::map<std::wstring,
d3d11_timer>;

 

            profilemap
profiles;

            std::uint64_t
currframe;

 

            ID3D11DevicePtr
device;

            ID3D11DeviceContextPtr
context;

        };

        class
profileblock

        {

        public:

            profileblock(const
std::wstring& name);

            ~profileblock();

        protected:

            std::wstring
name;

        };

//源文件

void
d3d11_timer::start(std::uint64_t
currframe,
ID3D11Device*
device,
ID3D11DeviceContext*
context)

        {

            assert(!started);

            assert(!finished);

 

            if
(!disjoint[currframe])

            {

                D3D11_QUERY_DESC
desc;

                desc.Query
=
D3D11_QUERY_TIMESTAMP_DISJOINT;

                desc.MiscFlags
=
0;

                //there should checke error and throw exception,but i am not write exception hpp

                device->CreateQuery(&desc,
&disjoint[currframe]);

                desc.Query
=
D3D11_QUERY_TIMESTAMP;

                device->CreateQuery(&desc,
&timestampstart[currframe]);

                device->CreateQuery(&desc,
&timestampend[currframe]);

            }

 

            context->Begin(disjoint[currframe]);

            context->End(timestampstart[currframe]);

 

            started
=
true;

        }

 

        void
d3d11_timer::end(std::uint64_t
currframe,
ID3D11DeviceContext*
context)

        {

            assert(started);

            assert(!finished);

            //this mean insert the timestampend

            //http://msdn.microsoft.com/en-us/library/windows/desktop/ff476191(v=vs.85).aspx

            context->End(timestampend[currframe]);

            context->End(disjoint[currframe]);

 

            started
=
false;

            finished
=
true;

        }

 

        float
d3d11_timer::time(std::uint64_t
currframe,
ID3D11DeviceContext*
context)

        {

            if
(!finished)

                return
0.f;

            finished
=
false;

            if
(!disjoint[currframe])

                return
0.f;

 

            //maybe you can record query time

 

            std::uint64_t
starttime
=
0;

            while
(context->GetData(timestampstart[currframe],
&starttime,
sizeof(starttime),
0)
!=
S_OK)

                ;

            std::uint64_t
endtime
=
0;

            while
(context->GetData(timestampend[currframe],
&endtime,
sizeof(endtime),
0)
!=
S_OK)

                ;

            D3D11_QUERY_DATA_TIMESTAMP_DISJOINT
disjointdata;

            while
(context->GetData(disjoint[currframe],
&disjointdata,
sizeof(disjointdata),
0)
!=
S_OK)

                ;

 

            float
time
=
0.0f;

            if
(!disjointdata.Disjoint)

            {

                std::uint64_t
delta
=
endtime
-
starttime;

                float
frequency
=
static_cast<float>(disjointdata.Frequency);

                time
=
(delta
/
frequency);

            }

            return
time;

        }

 

        profiler
profiler::global_profiler;

 

        void
profiler::init(ID3D11Device*
device,
ID3D11DeviceContext*
context)

        {

            this->device
=
device;

            this->context
=
context;

        }

 

        void
profiler::startprofile(const
std::wstring&
name)

        {

            //Todo : query "game setting"

            auto
&
profile
=
profiles[name];

            profile.start(currframe,
device,
context);

        }

 

        void
profiler::endprofile(const
std::wstring&
name)

        {

            //Todo : query "game setting"

            auto
&
profile
=
profiles[name];

            profile.end(currframe,
context);

        }

        

        void
profiler::endframe()//

        {

            currframe
=
(currframe
+
1)
%
querylatency;

 

            //Todo : query "query time"

 

            for
(auto
iter
=
profiles.begin();
iter
!=
profiles.end();
++iter)

            {

                auto
&
profile
=
(*iter).second;

                

                float
time
=
profile.time(currframe,
context);

 

                if
(time
==
0.f)

                    continue;

                DebugPrintf(L"currframe: %u ",currframe);

                DebugPrintf(L"%s: %f\n",
iter->first.c_str(),
time);

            }

        }

 

        profileblock::profileblock(const
std::wstring&
name)

            :name(name)

        {

            profiler::global_profiler.startprofile(name);

        }

 

        profileblock::~profileblock()

        {

            profiler::global_profiler.endprofile(name);

        }

使用他则是

    Void Render()

    {

        XX();

        ….

        global_profiler.endframe();

    }

在XX里面如下

    {

        Profileblock block("XXX")'

        …….

    }

D3D11 Query查询耗时的更多相关文章

  1. Hibernate 学习之Query查询(HQL查询)

    package com.itcloud.test; import com.itcloud.pojo.Dept; import org.hibernate.Session; import org.hib ...

  2. php mysqli query 查询数据库后读取内容的方法

    php mysqli query 查询数据库后读取内容的方法 <?php$mysqli = new mysqli("localhost", "my_user&quo ...

  3. Spring Data @Query查询注解的使用(六)

    按照上一篇文章 我们知道  我们定义的方法  都要根据它的规范进行定义  不然就没法实用 这篇我们讲@Query 查询注解   我们就可以不需要遵循它的方法规则去编写  咱们讲@Query定义到方法上 ...

  4. 分享知识-快乐自己:Hibernate 中Criteria Query查询详解

    1):Hibernate 中Criteria Query查询详解 当查询数据时,人们往往需要设置查询条件.在SQL或HQL语句中,查询条件常常放在where子句中. 此外,Hibernate还支持Cr ...

  5. Elasticsearch(5) --- Query查询和Filter查询

    Elasticsearch(5) --- Query查询和Filter查询 这篇博客主要分为 :Query查询和Filter查询.有关复合查询.聚合查询也会单独写篇博客. 一.概念 1.概念 一个查询 ...

  6. 20191217-关于JPA @Query查询数据一直为空,直接在数据库里执行SQL则可以查出来

    20191217-关于JPA @Query查询数据一直为空,直接在数据库里执行SQL则可以查出来 前提:数据库中查询,由于在视图中无主键概念,只是在代码中由逻辑主键.结果:数据中作为逻辑主键中有个字段 ...

  7. NHibernate系列文章二十六:NHibernate查询之SQL Query查询(附程序下载)

    摘要 NHibernate在很早的版本就提供了SQL Query(原生SQL查询),对于很复杂的查询,如果使用其他的查询方式实现比较困难的时候,一般使用SQL Query.使用SQL Query是基于 ...

  8. 关于MySql数据库设计表与查询耗时分析

    本地建一张表persons,使用脚本插入了1000万条数据 下面比较几种查询方法的耗时(查询9000000到9000005这中间5条数据) 查询结果: 1: SELECT * FROM test.pe ...

  9. Mongodb query查询

    Query.All("name", "a", "b");//通过多个元素来匹配数组Query.And(Query.EQ("name ...

随机推荐

  1. fedora 16安装ByPass四网口网卡遇到的问题

    这个问题困扰了好几天,今天终于在大谷歌的帮助下,在这个网站http://blog.bwysystems.com/bwysystems/?p=16上找到了答案!还是国外的技术论坛强,在百度上搜遍了也没有 ...

  2. webrtc 的回声抵消(aec、aecm)算法简介(转)

    webrtc 的回声抵消(aec.aecm)算法简介        webrtc 的回声抵消(aec.aecm)算法主要包括以下几个重要模块:1.回声时延估计 2.NLMS(归一化最小均方自适应算法) ...

  3. reentrant可重入函数

    在多任务操作系统环境中,应用程序的各个任务是并发运行的,所以会经常出现多个任务“同时”调用同一个函数的情况.这里之所以在“同时” 这个词上使用了引号,是因为这个歌”同时“的含义与我们平时所说的同时不是 ...

  4. oracle 的行级触发器

    create or replace trigger tri_insertAcceptList after insert on STDOC.DEVELOPER for each row DECLARE ...

  5. Oracle Standby Database 实现方案

    Oracle Standby Database 实现方案  From: http://wanow.blog.hexun.com/4672755_d.html 字号:大 中 小 版本:V20060328 ...

  6. Codeforces 597C. Subsequences (树状数组+dp)

    题目链接:http://codeforces.com/contest/597/problem/C 给你n和数(1~n各不同),问你长为k+1的上升自序列有多少. dp[i][j] 表示末尾数字为i 长 ...

  7. poj1584

    题意:已知一个多边形的n个顶点坐标,然后再给一个钉子,给定钉子的半径和圆心坐标,首先判断多边形是否为凸多边形,若为凸多边形,再判断钉子是否可以放到凸多边形内部. 思路: 1.由于顶点给出的顺序可能为逆 ...

  8. javascript自执行函数为什么要把windows作为参数传进去

    http://segmentfault.com/q/1010000000311686 (function (window, $, undefined) { play=function(){ $(&qu ...

  9. PING的原理以及ICMP协议

    主要内容: 1.ping的原理以及工作过程 2.ICMP协议 3.ICMP的应用:ping,traceroute 1.ping的原理以及工作过程  ping的原理  ping 程序是用来探测主机到主机 ...

  10. Apache实现动态虚拟主机

    经常在开发中为Apache web server添加虚拟主机  方便多个项目的 同时运营,但是每次增加新的项目时都得重新配置增加VirtualHost:虚拟主机    部分,时间久了VirtualHo ...