OpenGL查询对象 Query Objects

查询对象和异步查询(Query Objects and Asynchronous Queries)

Query Objects(查询对象)是OpenGL中的一种机制,用于获取有关一系列GL命令处理过程的信息。这些信息可以包括:

  1. 绘图命令处理的图元数量。
  2. 写入变换反馈缓冲区的图元数量。
  3. 在片段处理期间通过深度测试的样本数量。
  4. 处理命令所需的时间量。

通过使用查询对象,OpenGL应用程序可以动态地获取有关图形渲染过程的各种性能指标和统计信息。这些信息对于性能优化、调试和分析应用程序的渲染流程非常有用。

使用查询对象的一般步骤如下:

  1. 创建查询对象:通过调用OpenGL的API函数,可以创建一个查询对象,并指定要查询的信息类型。
  2. 开始查询:在需要获取信息的地方,通过调用OpenGL的API函数,开始一个查询操作。
  3. 执行一系列GL命令:在开始查询和结束查询之间,执行一系列的GL命令,这些命令可以是绘图命令、变换反馈命令、深度测试命令等。
  4. 结束查询:在执行完一系列GL命令后,通过调用OpenGL的API函数,结束查询操作。
  5. 获取查询结果:通过调用OpenGL的API函数,可以获取查询对象的结果,这些结果包含了在查询期间收集的有关图形处理过程的信息,比如处理的图元数量、通过的样本数量等。

使用查询对象可以帮助开发人员更好地了解和优化他们的OpenGL应用程序的性能特征,从而提高图形渲染的效率和质量。

查询类型

OpenGL 支持的查询类型包括:

  1. 图元生成查询:目标为 PRIMITIVES_GENERATED,用于返回通过 OpenGL 处理的图元数量。同时激活的此类查询最多可达 MAX_VERTEX_STREAMS 个。

  2. 变换反馈写入的图元查询:目标为 TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN,用于统计被写入一个或多个缓冲对象中的图元数量。同时激活的此类查询同样不得超过 MAX_VERTEX_STREAMS 个。

  3. 变换反馈溢出查询:目标为 TRANSFORM_FEEDBACK_OVERFLOWTRANSFORM_FEEDBACK_STREAM_OVERFLOW,用于报告一个或多个流是否存在变换反馈溢出情况。

  4. 遮挡查询:目标为 SAMPLES_PASSEDANY_SAMPLES_PASSEDANY_SAMPLES_PASSED_CONSERVATIVE,用于计数通过深度测试的片段或样本数量,或者设置布尔值以表示是否至少有一个片段或样本通过了深度测试。同时只能激活一个此类查询。

  5. 时间流逝查询:目标为 TIME_ELAPSED,记录完成一系列命令所需的完整时间。同时只能激活一个此类查询。

  6. 时间戳查询:目标为 TIMESTAMP,记录当前 OpenGL 的时间。同时只能激活一个此类查询。

  7. 提交查询:目标为 VERTICES_SUBMITTEDPRIMITIVES_SUBMITTED 分别返回传输到 OpenGL 的顶点数量和图元数量信息。

  8. 顶点着色器查询:目标为 VERTEX_SHADER_INVOCATIONS,返回顶点着色器被调用的次数。

  9. 曲面细分着色器查询:目标为 TESS_CONTROL_SHADER_PATCHESTESS_EVALUATION_SHADER_INVOCATIONS,分别返回曲面细分控制着色器处理的补丁数量和曲面细分评估着色器被调用的次数。

  10. 几何着色器查询:目标为 GEOMETRY_SHADER_INVOCATIONSGEOMETRY_SHADER_PRIMITIVES_EMITTED,分别返回几何着色器被调用的次数以及它发射的图元数量。

  11. 图元裁剪查询:目标为 CLIPPING_INPUT_PRIMITIVESCLIPPING_OUTPUT_PRIMITIVES,分别返回在图元裁剪阶段处理的图元数量和由图元裁剪阶段输出并进一步被光栅化阶段处理的图元数量。

  12. 片段着色器查询:目标为 FRAGMENT_SHADER_INVOCATIONS,返回片段着色器被调用的次数。

  13. 计算着色器查询:目标为 COMPUTE_SHADER_INVOCATIONS,返回计算着色器被调用的次数。

查询对象创建和激活

异步查询的结果不会在集合中的最后一个命令完成后立即由GL返回;在查询结果完全就绪之前,可以处理后续命令。一旦可用,查询结果将存储在相关联的查询对象中。第4.2.3节描述的命令提供了确定查询结果何时可用并返回查询的实际结果的机制。查询对象的名称空间是无符号整数,其中零被GL保留。

void glGenQueries( sizei n, uint *ids )

命令在ids中返回n个先前未使用的查询对象名称。这些名称被标记为已使用,仅用于GenQueries,但在它们首次被BeginQuery、BeginQueryIndexed或QueryCounter使用之前,它们不与任何对象关联。

void glCreateQueries( enum target, sizei n, uint *ids )

glCreateQueries在ids中返回n个先前未使用的查询对象名称,每个名称表示具有指定目标的新查询对象。目标必须是 **查询类型** 中描述的查询对象目标之一。生成的查询对象的初始状态是结果已标记为可用(查询对象的QUERY_RESULT_AVAILABLE的值为TRUE),并且结果值(QUERY_RESULT的值)为零。

void glDeleteQueries( sizei n, const uint *ids )

ids包含要删除的n个查询对象的名称。删除查询对象后,其名称再次变为未使用。如果删除了活动查询对象,则其名称立即变为未使用,但底层对象直到不再处于活动状态(参见第5.1节)才会被删除。对于GenQueries目的而标记为已使用的ids中的未使用名称将再次标记为未使用。未使用的ids中的名称将被静默忽略,零值也将被静默忽略。

在OpenGL中,除TIMESTAMP类型的计时器查询外,对于支持的每种查询类型,针对每个可能激活的查询,都有一个对应的活动查询对象名称。如果这个活动查询对象名称非零,则表示OpenGL当前正在追踪相关的信息,并且查询结果会被记录到该查询对象内。

反之,如果活动查询对象名称为零,则意味着未追踪此类信息。

创建并激活查询对象可以使用以下命令:

void glBeginQueryIndexed( enum target, uint index, uint id )

  • target 参数指定了要执行的查询类型,后续章节将详细介绍其有效值。
  • 如果id是一个未使用的查询对象名称,则该名称会被标记为已使用,并与指定目标类型的新的查询对象关联起来。否则,id必须是现有且同类型查询对象的名称。请注意,通过ANY_SAMPLES_PASSED或ANY_SAMPLES_PASSED_CONSERVATIVE两种目标指定的遮挡查询对象,在未来的查询中可以重用于这两种目标中的任何一种。而由SAMPLES_PASSED目标指定的对象只能重用于该目标。
  • index 参数是查询的索引,其值必须在0和目标特定的最大值之间。
  • 无论id是否为新创建的查询对象,其状态都将被设置为结果不可用(查询对象的QUERY_RESULT_AVAILABLE值为FALSE),并且结果值(QUERY_RESULT)初始化为零。
  • 对于给定的targetindex,其对应的活动查询对象名称会被设置为id

void glBeginQuery( enum target, uint id )

  • 等价于 glBeginQueryIndexed(target, 0, id);

void glEndQueryIndexed( enum target, uint index )

  • 标记了由target和index指定的活动查询要跟踪的命令序列的结束。target和index的含义与BeginQueryIndexed中相同。

  • 相应的活动查询对象被更新以指示查询结果不可用,并且target和index的活动查询对象名称被重置为零。当在EndQueryIndexed调用时发出的命令完成并且最终查询结果可用时,被调用时活动的查询对象被更新以包含查询结果,并指示查询结果可用。

void glEndQuery( enum target )

  • 等价于 glEndQueryIndexed(target, 0);

查询对象包含两部分状态信息:

  1. 一个单比特位,用于指示查询结果是否可用。
  2. 一个整数,用于存储查询结果的值。这个表示查询结果所使用的比特位数量(n)是实现依赖的,并且可以按照4.2.3节中描述的方式确定。
查询对象的初始状态取决于它是通过`CreateQueries`还是`BeginQueryIndexed`创建的,如上所述。如果查询结果发生溢出(即超过2^n - 1的值),其值将变为未定义。尽管不是必需的,但建议实现能够通过在达到2^n - 1时饱和并停止增加的方式来处理这种溢出情况。对于每个可能的活动查询目标和索引,都需要维护的状态包括:一个无符号整数,用于保存活动查询对象名称(如果没有活动查询对象,则为零);以及任何保持正在进行的异步查询当前结果所需的状态。同一时间内只允许一种遮挡查询类型处于活动状态,因此遮挡查询所需的必要状态会被共享。

boolean glIsQuery( uint id )

用于检查给定的ID(id)是否为一个查询对象的名称。

void glGetQueryIndexediv( enum target, uint index, enum pname, int *params )

查询有关活动查询对象的信息

  • targetindex 指定了要查询的活动查询,其含义与 BeginQueryIndexed 中相同。

  • 如果 pname 设置为 CURRENT_QUERY,则当前为 targetindex 指定的活动查询对象名称(如果有活动查询的话),将被放置在 params 指向的内存中。若目标为 TIMESTAMP,则始终返回0。

  • pname 设为 QUERY_COUNTER_BITS,则忽略 index 参数,并将在 params 中放置目标查询类型的实现依赖的查询结果所使用的比特位数。查询计数器的比特位数量可能为0,这意味着计数器不包含有用信息。

对于不同类型的查询对象,如果对应的比特位数非零,则它们至少应具备以下最低位数要求:

  • 基本图元查询(PRIMITIVES_GENERATED和TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN):至少32位。
  • 变换反馈溢出查询(TRANSFORM_FEEDBACK_OVERFLOW和TRANSFORM_FEEDBACK_STREAM_OVERFLOW):至少1位。
  • 遮挡查询(ANY_SAMPLES_PASSED或ANY_SAMPLES_PASSED_CONSERVATIVE):至少1位。针对SAMPLES_PASSED目标的遮挡查询,至少需要32位。
  • 计时器查询(TIME_ELAPSED和TIMESTAMP):至少30位,确保至少能测量一秒的时间。
  • 管道统计查询(VERTICES_SUBMITTED、PRIMITIVES_SUBMITTED、VERTEX_SHADER_INVOCATIONS、TESS_CONTROL_SHADER_PATCHES、TESS_EVALUATION_SHADER_INVOCATIONS、GEOMETRY_SHADER_INVOCATIONS、FRAGMENT_SHADER_INVOCATIONS、COMPUTE_SHADER_INVOCATIONS、GEOMETRY_SHADER_PRIMITIVES_EMITTED、CLIPPING_INPUT_PRIMITIVES和CLIPPING_OUTPUT_PRIMITIVES):至少32位。

void glGetQueryiv( enum target, enum pname, int *params )

等价于 glGetQueryIndexediv(target, 0, pname, params);


查询对象的状态可以通过以下命令进行查询

void GetQueryObjectiv( uint id, enum pname, int *params );
void GetQueryObjectuiv( uint id, enum pname, uint *params );
void GetQueryObjecti64v( uint id, enum pname, int64 *params );
void GetQueryObjectui64v( uint id, enum pname, uint64 *params );
void GetQueryBufferObjectiv( uint id, uint buffer, enum pname, intptr offset );
void GetQueryBufferObjectuiv( uint id, uint buffer, enum pname, intptr offset );
void GetQueryBufferObjecti64v( uint id, uint buffer, enum pname, intptr offset );
void GetQueryBufferObjectui64v( uint id, uint buffer, enum pname, intptr offset );

其中:

  • id 是一个查询对象的名称。
  • 对于 GetQueryBufferObject* 函数,buffer 是缓冲区对象的名称,而 offset 是缓冲区内写入查询值的偏移量。
  • 对于 GetQueryObject* 函数,查询值可以被返回到客户端内存中,也可以写入到缓冲区对象中。如果当前绑定到查询结果缓冲区绑定点(见第6.1节中的 QUERY_RESULT)的是零,则 params 被视为指向客户端内存的一个指针,在该位置写入查询值;否则,params 将被视为查询结果缓冲对象内的一个偏移量。

对于查询对象的结果值,可能需要一定时间才能变得可用。如果 pname 设置为 QUERY_RESULT_AVAILABLE,则在需要等待时函数将返回 FALSE;否则返回 TRUE。必须保证,若任何查询对象返回的结果可用性为 TRUE,那么在此之前所有相同类型的所有查询也必须返回 TRUE。对任一查询对象反复查询 QUERY_RESULT_AVAILABLE 保证最终会返回 TRUE

  • pnameQUERY_TARGET,则返回查询对象的目标类型作为一个整数值。
  • pnameQUERY_RESULT,则返回查询对象的结果值作为单个整数。如果结果值的大小过大以至于无法用请求的类型表示,则返回最接近的可表示值。如果目标类型的查询计数器位数为零,则结果将以整数值0的形式返回。查询 QUERY_RESULT 会使给定查询对象在有限时间内完成其计算过程。
  • pnameQUERY_RESULT_NO_WAIT,则仅当结果在执行状态查询时已可用时,才以单个整数形式返回查询对象的结果值。若结果不可用,则不写入查询返回值。

如果在调用上述查询命令之前,使用同一对象名称发起了多个查询操作,则返回的结果和可用性信息始终来自最后发起的那个查询。在开始针对同一目标和ID的新查询之前,如果不先检索先前查询的结果,这些结果将会丢失。

时间查询(Time Queries)

查询对象还可用于追踪完成一组OpenGL命令所需的时间(时间流逝查询),或确定当前的OpenGL时间(计时器查询)。

当使用目标 TIME_ELAPSED 调用 BeginQueryEndQuery 时,OpenGL将准备启动和停止用于时间流逝查询的计时器。计时器会在所有先前命令对OpenGL客户端、服务器状态以及帧缓冲区的影响完全实现后开始或停止。BeginQueryEndQuery 命令可能在计时器实际开始或停止之前返回。

当时间流逝查询的计时器最终停止时,流逝的时间(以纳秒为单位)会被写入到相应的查询对象作为查询结果值,并标记该对象的查询结果为可用。

可以通过以下命令创建计时器查询对象:

void QueryCounter( uint id, enum target );

其中 target 必须是 TIMESTAMP。如果 id 是未使用的查询对象名称,则该名称会被标记为已使用并与新的类型为 TIMESTAMP 的查询对象关联。否则,id 必须是现有同类型查询对象的名称。

另外,也可以通过调用 CreateQueries 并将 target 设置为 TIMESTAMP 来创建 TIMESTAMP 类型的查询对象。

当调用 QueryCounter 时,OpenGL会记录下当前时间并将其存入对应的查询对象中。这个时间是在所有先前命令对OpenGL客户端、服务器状态及帧缓冲区的影响完全实现之后记录的。一旦时间被记录,该对象的查询结果就会被标记为可用。计时器查询可以在目标为 TIME_ELAPSEDBeginQuery / EndQuery 块内部使用,且不会影响该查询对象的结果。

通过调用 GetIntegervGetInteger64v 并传入符号常量 TIMESTAMP,可以查询当前的OpenGL时间。这将返回所有先前命令到达OpenGL服务器但不一定执行完毕后的GL时间。通过结合这种同步获取命令和异步时间戳查询对象目标,应用程序可以测量命令从到达OpenGL服务器到在帧缓冲区实现之间的延迟。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/660335.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小黄鸭聊电脑(4)硬盘分区

小黄鸭聊电脑(4)硬盘分区 夜深人静,万籁俱寂,老郭趴在电脑桌上打盹,桌子上的小黄鸭和桌子旁的冰箱又开始窃窃私语…… 小黄鸭:冰箱大哥,上次你说的那个“分区”和“格式化”是什么意思? 冰箱:…

洛夫克拉夫特与文学中的超自然恐怖:前哥特时代

洛夫克拉夫特与文学中的超自然恐怖:前哥特时代 ![ 洛夫克拉夫特是美国恐怖、科幻与奇幻小说作家,尤以其怪奇小说著称,他在自己的一系列小说中开发出了克苏鲁神话体系。他的创作对后世恐怖小说创造影响深远,我们可以在许多当代文…

[leetcode] 21. 合并两个有序链表

文章目录 题目描述解题方法双指针遍历java代码 题目描述 将两个升序链表合并为一个新的 升序 链表并返回。新链表是通过拼接给定的两个链表的所有节点组成的。 示例 1: 输入:l1 [1,2,4], l2 [1,3,4] 输出:[1,1,2,3,4,4]示例 2&#xff…

自动驾驶:Apollo如何塑造人类的未来出行

前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家:https://www.captainbed.cn/z ChatGPT体验地址 文章目录 前言1. 什么是自定义指令?2. Apollo中的自定义指令2.1 查询中的自定…

sqlalchemy——@listens_for

问:sqlalchemy如何实现:表中指定数据更新时,其time字段自动更新?答:使用listens_for 装饰器来注册事件监听器,确保在项目数据更新时触发相应的处理逻辑。 示例代码如下: # coding: utf-8 impo…

Vue2组件注册:全局组件和局部组件

在Vue 2 中,你可以使用全局注册和局部注册两种方式注册组件。以下是两种方式的示例: • 全局注册 全局注册的组件可以在整个应用中使用,适用于高频的通用组件。 // 在 main.js 或者入口文件中 import Vue from vue import App from ./App.v…

鸿蒙HarmonyOS——AVSession开发指导

AVSession开发指导 说明: AVSession的所有接口均为系统接口,其功能仅提供给系统应用使用。 会话接入端开发指导 基本概念 会话元数据AVMetadata: 媒体数据相关属性,包含标识当前媒体的ID(assetId),上一首媒体的ID(previousAsset…

17. Spring Boot Actuator

17. Spring Boot Actuator Spring Boot执行器(Actuator)提供安全端点,用于监视和管理Spring Boot应用程序。 默认情况下,所有执行器端点都是安全的。 在本章中,将详细了解如何为应用程序启用Spring Boot执行器。 启用Spring Boot Actuator …

光纤熔接-热熔

实验教学日的及具体要求 目的 1.掌握室外光缆、皮线光缆的开剥方法。 2.掌握应用光纤切割刀制作光纤端面的方法 3.掌握光纤熔接的基本知识。 4.掌握光纤熔接机的使用方法及接续步骤。 任务 1.完成2芯光缆在终端盒内与尾纤的熔接 2.用激光笔完成光纤熔接检测。 …

如何使用mock.js实现接口测试的自动化?

Mock.js 基础用法介绍 Mock.js是一个常用于生成随机数据和拦截Ajax请求的JavaScript库。本文将介绍Mock.js的用法,包括安装和基础用法,在开始前我们可以看下看:了解 Mock.js 的语法规范。 安装 可以通过npm安装Mock.js: npm i…

Debezium发布历史94

原文地址: https://debezium.io/blog/2020/09/16/debezium-1-3-beta2-released/ 欢迎关注留言,我是收集整理小能手,工具翻译,仅供参考,笔芯笔芯. Debezium 1.3.0.Beta2 发布 2020 年 9 月 16 日 作者: Gu…

敏捷认证大热:PMI-ACP

你是否在寻找一个能让你在不断变化的职场环境中脱颖而出的认证?PMI-ACP正是你需要的!这个由美国项目管理协会PMI颁发的认证,是全球敏捷项目管理领域的权威代表。无论你是希望转型到项目管理领域,还是想提升现有项目管理技能&#…

代码随想录算法训练营第二十三天|669.修剪二叉搜索树、108.将有序数组转换为二叉搜索树、538.把二叉搜索树转换为累加树

669.修剪二叉搜索树 public class Solution {public TreeNode TrimBST(TreeNode root, int low, int high) {if(rootnull){return null;}if(root.val<low){var rightTrimBST(root.right,low,high);return right;}if(root.val>high){var leftTrimBST(root.left,low,high)…

Kafka下载安装及基本使用

目录 Kafka介绍 消息队列的作用 消息队列的优势 应用解耦 异步提速 削峰填谷 为什么要用Kafka Kafka下载安装 Kafka快速上手&#xff08;单机体验&#xff09; 1. 启动zookeeper服务 2. 启动kafka服务 3. 简单收发消息 Kakfa的消息传递机制 Kafka介绍 Apache Kafka…

数据库面试题汇总

如何定位慢查询SQL慢语句执行的很慢&#xff0c;如何分析&#xff1f;索引概念及索引底层数据结构&#xff1f;聚簇索引和非聚簇索引、回表查询&#xff1f;覆盖索引、超大分页优化索引创建的原则什么情况下索引会失效谈一谈你对SQL优化的经验事务的特性并发事务问题、隔离级别…

联邦学习公式推导--为何只需要发送模型参数而不是模型梯度?

参考文献&#xff1a;https://arxiv.org/pdf/1602.05629v4.pdf 对于一个机器学习应用来说&#xff0c;我们需要找到一个目标函数&#xff0c;使其最小化 f ( w ) 1 n ∑ i 1 n f i ( w ) f(w) \frac{1}{n}\sum_{i1}^{n}f_i(w) f(w)n1​i1∑n​fi​(w) 上面等式中&#xff…

Vue3中的watch函数使用

Vue2和Vue3中的watch函数作用是一样的&#xff0c;用来监测数据的变化并在数据变化时触发对应的回调函数&#xff0c;但Vue2和Vue3中的watch在使用的细节上有所不同&#xff0c;Vue3中的watch在监测reactive定义的响应式数据时&#xff0c;oldValue&#xff08;旧的值&#xff…

模拟实现哈希表 - HashMap(Java版本)

目录 1. 概念 2. 冲突-概念 3. 冲突-避免 4. 冲突-避免-哈希函数设计 5. 冲突-避免-负载因子调节 ⭐⭐⭐⭐⭐ 6. 冲突-解决 6.1 冲突-解决-闭散列 6.2 冲突-解决-开散列/哈希桶 ⭐⭐⭐⭐⭐ 7. 冲突严重时的解决办法 8. 模拟实现 1. 概念 顺序结构以及平衡树中&#…

揭开时间序列的神秘面纱:特征工程的力量

目录 写在开头1. 什么是特征工程?1.1 特征工程的定义和基本概念1.2 特征工程在传统机器学习中的应用1.3 时间序列领域中特征工程的独特挑战和需求3. 时间序列数据的特征工程技术2.1 数据清洗和预处理2.1.1 缺失值处理2.1.2 异常值检测与处理2.2 时间特征的提取2.2.1 时间戳解析…

MySQL基础(三)-学习笔记

一.innodb引擎&#xff1a; 1). 表空间&#xff1a;表空间是InnoDB存储引擎逻辑结构的最高层&#xff0c;启用了参数 innodb_file_per_table(在 8.0版本中默认开启) &#xff0c;则每张表都会有一个表空间&#xff08;xxx.ibd&#xff09;&#xff0c;一个mysql实例可以对应多个…