script/dom/webgl/
webglquery.rs1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use script_bindings::weakref::WeakRef;
9use servo_canvas_traits::webgl::WebGLError::*;
10use servo_canvas_traits::webgl::{WebGLCommand, WebGLQueryId, webgl_channel};
11
12use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants;
13use crate::dom::bindings::refcounted::Trusted;
14use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
15use crate::dom::bindings::root::DomRoot;
16use crate::dom::webgl::webglobject::WebGLObject;
17use crate::dom::webgl::webglrenderingcontext::{Operation, WebGLRenderingContext};
18use crate::dom::webglrenderingcontext::capture_webgl_backtrace;
19use crate::script_runtime::CanGc;
20
21#[derive(JSTraceable, MallocSizeOf)]
22struct DroppableWebGLQuery {
23 context: WeakRef<WebGLRenderingContext>,
24 #[no_trace]
25 gl_id: WebGLQueryId,
26 marked_for_deletion: Cell<bool>,
27}
28
29impl DroppableWebGLQuery {
30 fn send_with_fallibility(&self, command: WebGLCommand, fallibility: Operation) {
31 if let Some(root) = self.context.root() {
32 let result = root.sender().send(command, capture_webgl_backtrace());
33 if matches!(fallibility, Operation::Infallible) {
34 result.expect("Operation failed");
35 }
36 }
37 }
38
39 fn delete(&self, operation_fallibility: Operation) {
40 if !self.marked_for_deletion.get() {
41 self.marked_for_deletion.set(true);
42 self.send_with_fallibility(
43 WebGLCommand::DeleteQuery(self.gl_id),
44 operation_fallibility,
45 );
46 }
47 }
48}
49
50impl Drop for DroppableWebGLQuery {
51 fn drop(&mut self) {
52 self.delete(Operation::Fallible);
53 }
54}
55
56#[dom_struct(associated_memory)]
57pub(crate) struct WebGLQuery {
58 webgl_object: WebGLObject,
59 gl_target: Cell<Option<u32>>,
60 query_result_available: Cell<Option<u32>>,
61 query_result: Cell<u32>,
62 droppable: DroppableWebGLQuery,
63}
64
65impl WebGLQuery {
66 fn new_inherited(context: &WebGLRenderingContext, id: WebGLQueryId) -> Self {
67 Self {
68 webgl_object: WebGLObject::new_inherited(context),
69 gl_target: Cell::new(None),
70 query_result_available: Cell::new(None),
71 query_result: Cell::new(0),
72 droppable: DroppableWebGLQuery {
73 context: WeakRef::new(context),
74 gl_id: id,
75 marked_for_deletion: Cell::new(false),
76 },
77 }
78 }
79
80 pub(crate) fn new(context: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<Self> {
81 let (sender, receiver) = webgl_channel().unwrap();
82 context.send_command(WebGLCommand::GenerateQuery(sender));
83 let id = receiver.recv().unwrap();
84
85 reflect_dom_object(
86 Box::new(Self::new_inherited(context, id)),
87 &*context.global(),
88 can_gc,
89 )
90 }
91
92 pub(crate) fn begin(
93 &self,
94 context: &WebGLRenderingContext,
95 target: u32,
96 ) -> Result<(), servo_canvas_traits::webgl::WebGLError> {
97 if self.droppable.marked_for_deletion.get() {
98 return Err(InvalidOperation);
99 }
100 if let Some(current_target) = self.gl_target.get() {
101 if current_target != target {
102 return Err(InvalidOperation);
103 }
104 }
105 match target {
106 constants::ANY_SAMPLES_PASSED |
107 constants::ANY_SAMPLES_PASSED_CONSERVATIVE |
108 constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => (),
109 _ => return Err(InvalidEnum),
110 }
111 self.gl_target.set(Some(target));
112
113 context.send_command(WebGLCommand::BeginQuery(target, self.droppable.gl_id));
114 Ok(())
115 }
116
117 pub(crate) fn end(
118 &self,
119 context: &WebGLRenderingContext,
120 target: u32,
121 ) -> Result<(), servo_canvas_traits::webgl::WebGLError> {
122 if self.droppable.marked_for_deletion.get() {
123 return Err(InvalidOperation);
124 }
125 if let Some(current_target) = self.gl_target.get() {
126 if current_target != target {
127 return Err(InvalidOperation);
128 }
129 }
130 match target {
131 constants::ANY_SAMPLES_PASSED |
132 constants::ANY_SAMPLES_PASSED_CONSERVATIVE |
133 constants::TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN => (),
134 _ => return Err(InvalidEnum),
135 }
136 context.send_command(WebGLCommand::EndQuery(target));
137 Ok(())
138 }
139
140 pub(crate) fn delete(&self, operation_fallibility: Operation) {
141 self.droppable.delete(operation_fallibility);
142 }
143
144 pub(crate) fn is_valid(&self) -> bool {
145 !self.droppable.marked_for_deletion.get() && self.target().is_some()
146 }
147
148 pub(crate) fn target(&self) -> Option<u32> {
149 self.gl_target.get()
150 }
151
152 fn update_results(&self, context: &WebGLRenderingContext) {
153 let (sender, receiver) = webgl_channel().unwrap();
154 context.send_command(WebGLCommand::GetQueryState(
155 sender,
156 self.droppable.gl_id,
157 constants::QUERY_RESULT_AVAILABLE,
158 ));
159 let is_available = receiver.recv().unwrap();
160 if is_available == 0 {
161 self.query_result_available.set(None);
162 return;
163 }
164
165 let (sender, receiver) = webgl_channel().unwrap();
166 context.send_command(WebGLCommand::GetQueryState(
167 sender,
168 self.droppable.gl_id,
169 constants::QUERY_RESULT,
170 ));
171
172 self.query_result.set(receiver.recv().unwrap());
173 self.query_result_available.set(Some(is_available));
174 }
175
176 #[rustfmt::skip]
177 pub(crate) fn get_parameter(
178 &self,
179 context: &WebGLRenderingContext,
180 pname: u32,
181 ) -> Result<u32, servo_canvas_traits::webgl::WebGLError> {
182 if !self.is_valid() {
183 return Err(InvalidOperation);
184 }
185 match pname {
186 constants::QUERY_RESULT |
187 constants::QUERY_RESULT_AVAILABLE => {},
188 _ => return Err(InvalidEnum),
189 }
190
191 if self.query_result_available.get().is_none() {
192 self.query_result_available.set(Some(0));
193
194 let this = Trusted::new(self);
195 let context = Trusted::new(context);
196 let task = task!(request_query_state: move || {
197 let this = this.root();
198 let context = context.root();
199 this.update_results(&context);
200 });
201
202 self.global()
203 .task_manager()
204 .dom_manipulation_task_source()
205 .queue(task);
206 }
207
208 match pname {
209 constants::QUERY_RESULT => Ok(self.query_result.get()),
210 constants::QUERY_RESULT_AVAILABLE => Ok(self.query_result_available.get().unwrap()),
211 _ => unreachable!(),
212 }
213 }
214}