1use crate::backend::Facade;
2use crate::context::Context;
3use crate::context::CommandContext;
4use crate::ContextExt;
5use crate::DrawError;
6use crate::ToGlEnum;
7use crate::GlObject;
8use crate::QueryExt;
9
10use std::cell::Cell;
11use std::fmt;
12use std::rc::Rc;
13use std::error::Error;
14
15use crate::buffer::Buffer;
16use crate::buffer::BufferSlice;
17use crate::BufferExt;
18use crate::BufferSliceExt;
19
20use crate::gl;
21use crate::version::Api;
22use crate::version::Version;
23
24pub struct RawQuery {
25 context: Rc<Context>,
26 id: gl::types::GLuint,
27 ty: QueryType,
28
29 has_been_used: Cell<bool>,
32}
33
34pub enum QueryType {
35 SamplesPassed,
36 AnySamplesPassed,
37 AnySamplesPassedConservative,
38 TimeElapsed,
39 Timestamp,
40 PrimitivesGenerated,
41 TransformFeedbackPrimitivesWritten,
42}
43
44impl ToGlEnum for QueryType {
45 #[inline]
46 fn to_glenum(&self) -> gl::types::GLenum {
47 match *self {
48 QueryType::SamplesPassed => gl::SAMPLES_PASSED,
49 QueryType::AnySamplesPassed => gl::ANY_SAMPLES_PASSED,
50 QueryType::AnySamplesPassedConservative => gl::ANY_SAMPLES_PASSED_CONSERVATIVE,
51 QueryType::TimeElapsed => gl::TIME_ELAPSED,
52 QueryType::Timestamp => gl::TIMESTAMP,
53 QueryType::PrimitivesGenerated => gl::PRIMITIVES_GENERATED,
54 QueryType::TransformFeedbackPrimitivesWritten => {
55 gl::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN
56 },
57 }
58 }
59}
60
61#[derive(Copy, Clone, Debug)]
63pub enum QueryCreationError {
64 NotSupported,
66}
67
68impl fmt::Display for QueryCreationError {
69 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
70 use self::QueryCreationError::*;
71 let desc = match *self {
72 NotSupported => "The given query type is not supported",
73 };
74 fmt.write_str(desc)
75 }
76}
77
78impl Error for QueryCreationError {}
79
80#[derive(Copy, Clone, Debug)]
82pub enum ToBufferError {
83 NotSupported,
85}
86
87impl fmt::Display for ToBufferError {
88 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
89 use self::ToBufferError::*;
90 let desc = match *self {
91 NotSupported => "Writing the result to a buffer is not supported",
92 };
93 fmt.write_str(desc)
94 }
95}
96
97impl Error for ToBufferError {}
98
99impl RawQuery {
100 pub fn new<F: ?Sized>(facade: &F, ty: QueryType) -> Result<RawQuery, QueryCreationError>
102 where F: Facade
103 {
104 let context = facade.get_context().clone();
105 let ctxt = facade.get_context().make_current();
106
107 let id = unsafe {
110 let mut id = 0;
111
112 if ctxt.version >= &Version(Api::Gl, 3, 3) {
113 match ty {
114 QueryType::AnySamplesPassed | QueryType::SamplesPassed |
115 QueryType::PrimitivesGenerated | QueryType::TimeElapsed |
116 QueryType::TransformFeedbackPrimitivesWritten => (),
117 QueryType::AnySamplesPassedConservative if
118 ctxt.extensions.gl_arb_es3_compatibility ||
119 ctxt.version >= &Version(Api:: Gl, 4, 3) => (),
120 _ => return Err(QueryCreationError::NotSupported)
121 };
122
123 if ctxt.version >= &Version(Api:: Gl, 4, 5) ||
124 ctxt.extensions.gl_arb_direct_state_access
125 {
126 ctxt.gl.CreateQueries(ty.to_glenum(), 1, &mut id);
127 } else {
128 ctxt.gl.GenQueries(1, &mut id);
129 }
130
131 } else if ctxt.version >= &Version(Api::Gl, 3, 0) {
132 match ty {
133 QueryType::SamplesPassed | QueryType::PrimitivesGenerated |
134 QueryType::TransformFeedbackPrimitivesWritten => (),
135 QueryType::AnySamplesPassed if ctxt.extensions.gl_arb_occlusion_query2 => (),
136 QueryType::AnySamplesPassedConservative if ctxt.extensions.gl_arb_es3_compatibility => (),
137 QueryType::TimeElapsed if ctxt.extensions.gl_arb_timer_query => (),
138
139 _ => return Err(QueryCreationError::NotSupported)
140 };
141
142 ctxt.gl.GenQueries(1, &mut id);
143
144 } else if ctxt.version >= &Version(Api::Gl, 1, 5) || ctxt.extensions.gl_arb_occlusion_query {
145 match ty {
146 QueryType::SamplesPassed => (),
147 QueryType::AnySamplesPassed if ctxt.extensions.gl_arb_occlusion_query2 => (),
148 QueryType::AnySamplesPassedConservative if ctxt.extensions.gl_arb_es3_compatibility => (),
149 QueryType::PrimitivesGenerated if ctxt.extensions.gl_ext_transform_feedback => (),
150 QueryType::TransformFeedbackPrimitivesWritten if ctxt.extensions.gl_ext_transform_feedback => (),
151 QueryType::TimeElapsed if ctxt.extensions.gl_arb_timer_query => (),
152 _ => return Err(QueryCreationError::NotSupported)
153 };
154
155 if ctxt.version >= &Version(Api::Gl, 1, 5) {
156 ctxt.gl.GenQueries(1, &mut id);
157 } else if ctxt.extensions.gl_arb_occlusion_query {
158 ctxt.gl.GenQueriesARB(1, &mut id);
159 } else {
160 unreachable!();
161 }
162
163 } else if ctxt.version >= &Version(Api::GlEs, 3, 0) {
164 match ty {
165 QueryType::AnySamplesPassed | QueryType::AnySamplesPassedConservative |
166 QueryType::TransformFeedbackPrimitivesWritten => (),
167 _ => return Err(QueryCreationError::NotSupported)
168 };
169
170 ctxt.gl.GenQueries(1, &mut id);
171
172 } else if ctxt.extensions.gl_ext_occlusion_query_boolean {
173 match ty {
174 QueryType::AnySamplesPassed | QueryType::AnySamplesPassedConservative => (),
175 _ => return Err(QueryCreationError::NotSupported)
176 };
177
178 ctxt.gl.GenQueriesEXT(1, &mut id);
179
180 } else {
181 return Err(QueryCreationError::NotSupported);
182 }
183
184 id
185 };
186
187 Ok(RawQuery {
188 context,
189 id,
190 ty,
191 has_been_used: Cell::new(false),
192 })
193 }
194
195 pub fn is_ready(&self) -> bool {
197 let mut ctxt = self.context.make_current();
198 self.deactivate(&mut ctxt);
199
200 if !self.has_been_used.get() {
201 return false;
202 }
203
204 Buffer::<u8>::unbind_query(&mut ctxt);
205
206 unsafe {
207 let mut value = 0;
208
209 if ctxt.version >= &Version(Api::Gl, 1, 5) ||
210 ctxt.version >= &Version(Api::GlEs, 3, 0)
211 {
212 ctxt.gl.GetQueryObjectuiv(self.id, gl::QUERY_RESULT_AVAILABLE, &mut value);
213
214 } else if ctxt.extensions.gl_arb_occlusion_query {
215 ctxt.gl.GetQueryObjectuivARB(self.id, gl::QUERY_RESULT_AVAILABLE, &mut value);
216
217 } else if ctxt.extensions.gl_ext_occlusion_query_boolean {
218 ctxt.gl.GetQueryObjectuivEXT(self.id, gl::QUERY_RESULT_AVAILABLE, &mut value);
219
220 } else {
221 unreachable!();
224 }
225
226 value != 0
227 }
228 }
229
230 pub fn get_u32(&self) -> u32 {
234 let mut ctxt = self.context.make_current();
235 self.deactivate(&mut ctxt);
236
237 if !self.has_been_used.get() {
238 return 0;
239 }
240
241 Buffer::<u8>::unbind_query(&mut ctxt);
242
243 unsafe {
244 let mut value = 0;
245 self.raw_get_u32(&mut ctxt, &mut value);
246 value
247 }
248 }
249
250 pub fn write_u32_to_buffer(&self, target: BufferSlice<'_, u32>) -> Result<(), ToBufferError> {
252 let mut ctxt = self.context.make_current();
253
254 if !(ctxt.version >= &Version(Api::Gl, 4, 4) || ctxt.extensions.gl_arb_query_buffer_object ||
255 ctxt.extensions.gl_amd_query_buffer_object)
256 {
257 return Err(ToBufferError::NotSupported);
258 }
259
260 self.deactivate(&mut ctxt);
261
262 if !self.has_been_used.get() {
263 panic!();
264 }
265
266 assert!(target.get_offset_bytes() % 4 == 0);
267
268 target.prepare_and_bind_for_query(&mut ctxt);
269 unsafe { self.raw_get_u32(&mut ctxt, target.get_offset_bytes() as *mut _); }
270
271 if let Some(fence) = target.add_fence() {
272 fence.insert(&mut ctxt);
273 }
274
275 Ok(())
276 }
277
278 unsafe fn raw_get_u32(&self, ctxt: &mut CommandContext<'_>, target: *mut gl::types::GLuint) {
279 if ctxt.version >= &Version(Api::Gl, 1, 5) || ctxt.version >= &Version(Api::GlEs, 3, 0) {
280 ctxt.gl.GetQueryObjectuiv(self.id, gl::QUERY_RESULT, target);
281
282 } else if ctxt.extensions.gl_arb_occlusion_query {
283 ctxt.gl.GetQueryObjectuivARB(self.id, gl::QUERY_RESULT, target);
284
285 } else if ctxt.extensions.gl_ext_occlusion_query_boolean {
286 ctxt.gl.GetQueryObjectuivEXT(self.id, gl::QUERY_RESULT, target);
287
288 } else {
289 unreachable!();
292 }
293 }
294
295 pub fn get_u64(&self) -> u64 {
299 let mut ctxt = self.context.make_current();
300 self.deactivate(&mut ctxt);
301
302 if !self.has_been_used.get() {
303 return 0;
304 }
305
306 Buffer::<u8>::unbind_query(&mut ctxt);
307
308 unsafe {
309 let mut value = 0;
310 if self.raw_get_u64(&mut ctxt, &mut value).is_ok() {
311 return value;
312 }
313
314 let mut value = 0;
315 self.raw_get_u32(&mut ctxt, &mut value);
316 value as u64
317 }
318 }
319
320 unsafe fn raw_get_u64(&self, ctxt: &mut CommandContext<'_>, target: *mut gl::types::GLuint64)
321 -> Result<(), ()>
322 {
323 if ctxt.version >= &Version(Api::Gl, 3, 3) {
324 ctxt.gl.GetQueryObjectui64v(self.id, gl::QUERY_RESULT, target);
325 Ok(())
326
327 } else {
328 Err(())
329 }
330 }
331
332 #[inline]
336 pub fn get_bool(&self) -> bool {
337 self.get_u32() != 0
338 }
339
340 fn deactivate(&self, ctxt: &mut CommandContext<'_>) {
342 if ctxt.state.samples_passed_query == self.id {
343 unsafe { raw_end_query(ctxt, gl::SAMPLES_PASSED) };
344 ctxt.state.samples_passed_query = 0;
345 }
346
347 if ctxt.state.any_samples_passed_query == self.id {
348 unsafe { raw_end_query(ctxt, gl::ANY_SAMPLES_PASSED) };
349 ctxt.state.any_samples_passed_query = 0;
350 }
351
352 if ctxt.state.any_samples_passed_conservative_query == self.id {
353 unsafe { raw_end_query(ctxt, gl::ANY_SAMPLES_PASSED_CONSERVATIVE) };
354 ctxt.state.any_samples_passed_conservative_query = 0;
355 }
356
357 if ctxt.state.primitives_generated_query == self.id {
358 unsafe { raw_end_query(ctxt, gl::PRIMITIVES_GENERATED) };
359 ctxt.state.primitives_generated_query = 0;
360 }
361
362 if ctxt.state.transform_feedback_primitives_written_query == self.id {
363 unsafe { raw_end_query(ctxt, gl::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN) };
364 ctxt.state.transform_feedback_primitives_written_query = 0;
365 }
366
367 if ctxt.state.time_elapsed_query == self.id {
368 unsafe { raw_end_query(ctxt, gl::TIME_ELAPSED) };
369 ctxt.state.time_elapsed_query = 0;
370 }
371 }
372}
373
374impl Drop for RawQuery {
375 fn drop(&mut self) {
376 let mut ctxt = self.context.make_current();
377 self.deactivate(&mut ctxt);
378
379 if let Some((id, _)) = ctxt.state.conditional_render {
380 if id == self.id {
381 RawQuery::end_conditional_render(&mut ctxt);
382 }
383 }
384
385 unsafe {
386 if ctxt.version >= &Version(Api::Gl, 1, 5) ||
387 ctxt.version >= &Version(Api::GlEs, 3, 0)
388 {
389 ctxt.gl.DeleteQueries(1, [self.id].as_ptr());
390
391 } else if ctxt.extensions.gl_arb_occlusion_query {
392 ctxt.gl.DeleteQueriesARB(1, [self.id].as_ptr());
393
394 } else if ctxt.extensions.gl_ext_occlusion_query_boolean {
395 ctxt.gl.DeleteQueriesEXT(1, [self.id].as_ptr());
396
397 } else {
398 unreachable!();
399 }
400 }
401 }
402}
403
404impl QueryExt for RawQuery {
405 fn begin_query(&self, ctxt: &mut CommandContext<'_>) -> Result<(), DrawError> {
406 match self.ty {
407 QueryType::SamplesPassed => {
408 if ctxt.state.any_samples_passed_query != 0 {
409 ctxt.state.any_samples_passed_query = 0;
410 unsafe { raw_end_query(ctxt, gl::ANY_SAMPLES_PASSED); }
411 }
412
413 if ctxt.state.any_samples_passed_conservative_query != 0 {
414 ctxt.state.any_samples_passed_conservative_query = 0;
415 unsafe { raw_end_query(ctxt, gl::ANY_SAMPLES_PASSED_CONSERVATIVE); }
416 }
417
418 if ctxt.state.samples_passed_query != self.id {
419 if self.has_been_used.get() {
420 return Err(DrawError::WrongQueryOperation);
421 }
422
423 unsafe {
424 if ctxt.state.samples_passed_query != 0 {
425 raw_end_query(ctxt, gl::SAMPLES_PASSED);
426 }
427 raw_begin_query(ctxt, gl::SAMPLES_PASSED, self.id);
428 }
429
430 self.has_been_used.set(true);
431 ctxt.state.samples_passed_query = self.id;
432 }
433 },
434
435 QueryType::AnySamplesPassed => {
436 if ctxt.state.samples_passed_query != 0 {
437 ctxt.state.samples_passed_query = 0;
438 unsafe { raw_end_query(ctxt, gl::SAMPLES_PASSED); }
439 }
440
441 if ctxt.state.any_samples_passed_conservative_query != 0 {
442 ctxt.state.any_samples_passed_conservative_query = 0;
443 unsafe { raw_end_query(ctxt, gl::ANY_SAMPLES_PASSED_CONSERVATIVE); }
444 }
445
446 if ctxt.state.any_samples_passed_query != self.id {
447 if self.has_been_used.get() {
448 return Err(DrawError::WrongQueryOperation);
449 }
450
451 unsafe {
452 if ctxt.state.any_samples_passed_query != 0 {
453 raw_end_query(ctxt, gl::ANY_SAMPLES_PASSED);
454 }
455 raw_begin_query(ctxt, gl::ANY_SAMPLES_PASSED, self.id);
456 }
457
458 self.has_been_used.set(true);
459 ctxt.state.any_samples_passed_query = self.id;
460 }
461 },
462
463 QueryType::AnySamplesPassedConservative => {
464 if ctxt.state.samples_passed_query != 0 {
465 ctxt.state.samples_passed_query = 0;
466 unsafe { raw_end_query(ctxt, gl::SAMPLES_PASSED); }
467 }
468
469 if ctxt.state.any_samples_passed_query != 0 {
470 ctxt.state.any_samples_passed_query = 0;
471 unsafe { raw_end_query(ctxt, gl::ANY_SAMPLES_PASSED); }
472 }
473
474 if ctxt.state.any_samples_passed_conservative_query != self.id {
475 if self.has_been_used.get() {
476 return Err(DrawError::WrongQueryOperation);
477 }
478
479 unsafe {
480 if ctxt.state.any_samples_passed_conservative_query != 0 {
481 raw_end_query(ctxt, gl::ANY_SAMPLES_PASSED_CONSERVATIVE);
482 }
483 raw_begin_query(ctxt, gl::ANY_SAMPLES_PASSED_CONSERVATIVE, self.id);
484 }
485
486 self.has_been_used.set(true);
487 ctxt.state.any_samples_passed_conservative_query = self.id;
488 }
489 },
490
491 QueryType::TimeElapsed => {
492 if ctxt.state.time_elapsed_query != self.id {
493 if self.has_been_used.get() {
494 return Err(DrawError::WrongQueryOperation);
495 }
496
497 unsafe {
498 if ctxt.state.time_elapsed_query != 0 {
499 raw_end_query(ctxt, gl::TIME_ELAPSED);
500 }
501 raw_begin_query(ctxt, gl::TIME_ELAPSED, self.id);
502 }
503
504 self.has_been_used.set(true);
505 ctxt.state.time_elapsed_query = self.id;
506 }
507 },
508
509 QueryType::Timestamp => panic!(),
510
511 QueryType::PrimitivesGenerated => {
512 if ctxt.state.primitives_generated_query != self.id {
513 if self.has_been_used.get() {
514 return Err(DrawError::WrongQueryOperation);
515 }
516
517 unsafe {
518 if ctxt.state.primitives_generated_query != 0 {
519 raw_end_query(ctxt, gl::PRIMITIVES_GENERATED);
520 }
521 raw_begin_query(ctxt, gl::PRIMITIVES_GENERATED, self.id);
522 }
523
524 self.has_been_used.set(true);
525 ctxt.state.primitives_generated_query = self.id;
526 }
527 },
528
529 QueryType::TransformFeedbackPrimitivesWritten => {
530 if ctxt.state.transform_feedback_primitives_written_query != self.id {
531 if self.has_been_used.get() {
532 return Err(DrawError::WrongQueryOperation);
533 }
534
535 unsafe {
536 if ctxt.state.transform_feedback_primitives_written_query != 0 {
537 raw_end_query(ctxt, gl::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN);
538 }
539 raw_begin_query(ctxt, gl::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN, self.id);
540 }
541
542 self.has_been_used.set(true);
543 ctxt.state.transform_feedback_primitives_written_query = self.id;
544 }
545 },
546 };
547
548 Ok(())
549 }
550
551 fn end_samples_passed_query(ctxt: &mut CommandContext<'_>) {
552 if ctxt.state.samples_passed_query != 0 {
553 ctxt.state.samples_passed_query = 0;
554 unsafe { raw_end_query(ctxt, gl::SAMPLES_PASSED); }
555 }
556
557 if ctxt.state.any_samples_passed_query != 0 {
558 ctxt.state.any_samples_passed_query = 0;
559 unsafe { raw_end_query(ctxt, gl::ANY_SAMPLES_PASSED); }
560 }
561
562 if ctxt.state.any_samples_passed_conservative_query != 0 {
563 ctxt.state.any_samples_passed_conservative_query = 0;
564 unsafe { raw_end_query(ctxt, gl::ANY_SAMPLES_PASSED_CONSERVATIVE); }
565 }
566 }
567
568 #[inline]
569 fn end_time_elapsed_query(ctxt: &mut CommandContext<'_>) {
570 if ctxt.state.time_elapsed_query != 0 {
571 ctxt.state.time_elapsed_query = 0;
572 unsafe { raw_end_query(ctxt, gl::TIME_ELAPSED); }
573 }
574 }
575
576 #[inline]
577 fn end_primitives_generated_query(ctxt: &mut CommandContext<'_>) {
578 if ctxt.state.primitives_generated_query != 0 {
579 ctxt.state.primitives_generated_query = 0;
580 unsafe { raw_end_query(ctxt, gl::PRIMITIVES_GENERATED); }
581 }
582 }
583
584 #[inline]
585 fn end_transform_feedback_primitives_written_query(ctxt: &mut CommandContext<'_>) {
586 if ctxt.state.transform_feedback_primitives_written_query != 0 {
587 ctxt.state.transform_feedback_primitives_written_query = 0;
588 unsafe { raw_end_query(ctxt, gl::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN); }
589 }
590 }
591
592 fn begin_conditional_render(&self, ctxt: &mut CommandContext<'_>, wait: bool, per_region: bool) {
593 let new_mode = match (wait, per_region) {
594 (true, true) => gl::QUERY_BY_REGION_WAIT,
595 (true, false) => gl::QUERY_WAIT,
596 (false, true) => gl::QUERY_BY_REGION_NO_WAIT,
597 (false, false) => gl::QUERY_NO_WAIT,
598 };
599
600 if let Some((old_id, old_mode)) = ctxt.state.conditional_render {
602 if old_id == self.id {
603 match (new_mode, old_mode) {
606 (a, b) if a == b => return,
607 (gl::QUERY_NO_WAIT, gl::QUERY_WAIT) => return,
608 (gl::QUERY_BY_REGION_NO_WAIT, gl::QUERY_BY_REGION_WAIT) => return,
609 _ => (),
610 }
611 }
612 }
613
614 if ctxt.state.conditional_render.is_some() {
616 RawQuery::end_conditional_render(ctxt);
617 }
618
619 self.deactivate(ctxt);
621
622 if ctxt.version >= &Version(Api::Gl, 3, 0) {
624 unsafe { ctxt.gl.BeginConditionalRender(self.id, new_mode) };
625 } else if ctxt.extensions.gl_nv_conditional_render {
626 unsafe { ctxt.gl.BeginConditionalRenderNV(self.id, new_mode) };
627 } else {
628 unreachable!();
629 }
630
631 ctxt.state.conditional_render = Some((self.id, new_mode));
632 }
633
634 fn end_conditional_render(ctxt: &mut CommandContext<'_>) {
635 if ctxt.state.conditional_render.is_none() {
636 return;
637 }
638
639 if ctxt.version >= &Version(Api::Gl, 3, 0) {
640 unsafe { ctxt.gl.EndConditionalRender(); }
641 } else if ctxt.extensions.gl_nv_conditional_render {
642 unsafe { ctxt.gl.EndConditionalRenderNV(); }
643 } else {
644 unreachable!();
645 }
646
647 ctxt.state.conditional_render = None;
648 }
649
650 fn is_unused(&self) -> bool {
651 !self.has_been_used.get()
652 }
653}
654
655impl fmt::Debug for RawQuery {
656 #[inline]
657 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
658 write!(fmt, "Query object #{}", self.id)
659 }
660}
661
662impl GlObject for RawQuery {
663 type Id = gl::types::GLuint;
664
665 #[inline]
666 fn get_id(&self) -> gl::types::GLuint {
667 self.id
668 }
669}
670
671unsafe fn raw_begin_query(ctxt: &mut CommandContext<'_>, ty: gl::types::GLenum, id: gl::types::GLuint) {
679 if ctxt.version >= &Version(Api::Gl, 1, 5) ||
680 ctxt.version >= &Version(Api::GlEs, 3, 0)
681 {
682 ctxt.gl.BeginQuery(ty, id);
683
684 } else if ctxt.extensions.gl_arb_occlusion_query {
685 ctxt.gl.BeginQueryARB(ty, id);
686
687 } else if ctxt.extensions.gl_ext_occlusion_query_boolean {
688 ctxt.gl.BeginQueryEXT(ty, id);
689
690 } else {
691 unreachable!();
692 }
693}
694
695unsafe fn raw_end_query(ctxt: &mut CommandContext<'_>, ty: gl::types::GLenum) {
701 if ctxt.version >= &Version(Api::Gl, 1, 5) ||
702 ctxt.version >= &Version(Api::GlEs, 3, 0)
703 {
704 ctxt.gl.EndQuery(ty);
705
706 } else if ctxt.extensions.gl_arb_occlusion_query {
707 ctxt.gl.EndQueryARB(ty);
708
709 } else if ctxt.extensions.gl_ext_occlusion_query_boolean {
710 ctxt.gl.EndQueryEXT(ty);
711
712 } else {
713 unreachable!();
714 }
715}
716
717macro_rules! impl_helper {
718 ($name:ident, $ret:ty, $get_fn:ident) => {
719 impl $name {
720 #[inline]
722 pub fn is_ready(&self) -> bool {
723 self.query.is_ready()
724 }
725
726 #[inline]
736 pub fn get(self) -> $ret {
737 self.query.$get_fn()
738 }
739
740 #[inline]
747 pub fn to_buffer_u32(&self, target: BufferSlice<'_, u32>)
748 -> Result<(), ToBufferError>
749 {
750 self.query.write_u32_to_buffer(target)
751 }
752 }
753
754 impl GlObject for $name {
755 type Id = gl::types::GLuint;
756
757 #[inline]
758 fn get_id(&self) -> gl::types::GLuint {
759 self.query.get_id()
760 }
761 }
762
763 impl QueryExt for $name {
764 #[inline]
765 fn begin_query(&self, ctxt: &mut CommandContext<'_>) -> Result<(), DrawError> {
766 self.query.begin_query(ctxt)
767 }
768
769 #[inline]
770 fn end_samples_passed_query(ctxt: &mut CommandContext<'_>) {
771 RawQuery::end_samples_passed_query(ctxt)
772 }
773
774 #[inline]
775 fn end_time_elapsed_query(ctxt: &mut CommandContext<'_>) {
776 RawQuery::end_time_elapsed_query(ctxt)
777 }
778
779 #[inline]
780 fn end_primitives_generated_query(ctxt: &mut CommandContext<'_>) {
781 RawQuery::end_primitives_generated_query(ctxt)
782 }
783
784 #[inline]
785 fn end_transform_feedback_primitives_written_query(ctxt: &mut CommandContext<'_>) {
786 RawQuery::end_transform_feedback_primitives_written_query(ctxt)
787 }
788
789 #[inline]
790 fn begin_conditional_render(&self, ctxt: &mut CommandContext<'_>, wait: bool, per_region: bool) {
791 self.query.begin_conditional_render(ctxt, wait, per_region)
792 }
793
794 #[inline]
795 fn end_conditional_render(ctxt: &mut CommandContext<'_>) {
796 RawQuery::end_conditional_render(ctxt)
797 }
798
799 #[inline]
800 fn is_unused(&self) -> bool {
801 self.query.is_unused()
802 }
803 }
804 };
805}
806
807#[derive(Debug)]
813pub struct SamplesPassedQuery {
814 query: RawQuery,
815}
816
817impl SamplesPassedQuery {
818 #[inline]
820 pub fn new<F: ?Sized>(facade: &F) -> Result<SamplesPassedQuery, QueryCreationError> where F: Facade {
821 RawQuery::new(facade, QueryType::SamplesPassed).map(|q| SamplesPassedQuery { query: q })
822 }
823}
824
825impl_helper!(SamplesPassedQuery, u32, get_u32);
826
827#[derive(Debug)]
832pub struct TimeElapsedQuery {
833 query: RawQuery,
834}
835
836impl TimeElapsedQuery {
837 #[inline]
839 pub fn new<F: ?Sized>(facade: &F) -> Result<TimeElapsedQuery, QueryCreationError> where F: Facade {
840 RawQuery::new(facade, QueryType::TimeElapsed).map(|q| TimeElapsedQuery { query: q })
841 }
842}
843
844impl_helper!(TimeElapsedQuery, u32, get_u32);
845
846#[derive(Debug)]
858pub struct AnySamplesPassedQuery {
859 query: RawQuery,
860}
861
862impl AnySamplesPassedQuery {
863 pub fn new<F: ?Sized>(facade: &F, conservative: bool)
868 -> Result<AnySamplesPassedQuery, QueryCreationError>
869 where F: Facade
870 {
871 if conservative {
872 if let Ok(q) = RawQuery::new(facade, QueryType::AnySamplesPassedConservative) {
873 return Ok(AnySamplesPassedQuery { query: q });
874 }
875 }
876
877 if let Ok(q) = RawQuery::new(facade, QueryType::AnySamplesPassed) {
878 Ok(AnySamplesPassedQuery { query: q })
879 } else if let Ok(q) = RawQuery::new(facade, QueryType::SamplesPassed) {
880 Ok(AnySamplesPassedQuery { query: q })
881 } else {
882 Err(QueryCreationError::NotSupported)
883 }
884 }
885}
886
887impl_helper!(AnySamplesPassedQuery, bool, get_bool);
888
889#[derive(Debug)]
892pub struct PrimitivesGeneratedQuery {
893 query: RawQuery,
894}
895
896impl PrimitivesGeneratedQuery {
897 #[inline]
899 pub fn new<F: ?Sized>(facade: &F) -> Result<PrimitivesGeneratedQuery, QueryCreationError>
900 where F: Facade
901 {
902 RawQuery::new(facade, QueryType::PrimitivesGenerated)
903 .map(|q| PrimitivesGeneratedQuery { query: q })
904 }
905}
906
907impl_helper!(PrimitivesGeneratedQuery, u32, get_u32);
908
909#[derive(Debug)]
911pub struct TransformFeedbackPrimitivesWrittenQuery {
912 query: RawQuery,
913}
914
915impl TransformFeedbackPrimitivesWrittenQuery {
916 #[inline]
918 pub fn new<F: ?Sized>(facade: &F) -> Result<TransformFeedbackPrimitivesWrittenQuery, QueryCreationError>
919 where F: Facade
920 {
921 RawQuery::new(facade, QueryType::TransformFeedbackPrimitivesWritten)
922 .map(|q| TransformFeedbackPrimitivesWrittenQuery { query: q })
923 }
924}
925
926impl_helper!(TransformFeedbackPrimitivesWrittenQuery, u32, get_u32);