script/dom/webgl/
webglsync.rs1use std::cell::Cell;
6
7use dom_struct::dom_struct;
8use script_bindings::reflector::reflect_dom_object;
9use script_bindings::weakref::WeakRef;
10use servo_canvas_traits::webgl::{WebGLCommand, WebGLSyncId, 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;
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 DroppableWebGLSync {
23 context: WeakRef<WebGLRenderingContext>,
24 #[no_trace]
25 sync_id: WebGLSyncId,
26 marked_for_deletion: Cell<bool>,
27}
28
29impl DroppableWebGLSync {
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.is_valid() {
41 self.marked_for_deletion.set(true);
42 self.send_with_fallibility(
43 WebGLCommand::DeleteSync(self.sync_id),
44 operation_fallibility,
45 );
46 }
47 }
48
49 fn is_valid(&self) -> bool {
50 !self.marked_for_deletion.get()
51 }
52}
53
54impl Drop for DroppableWebGLSync {
55 fn drop(&mut self) {
56 self.delete(Operation::Fallible);
57 }
58}
59
60#[dom_struct(associated_memory)]
61pub(crate) struct WebGLSync {
62 webgl_object: WebGLObject,
63 client_wait_status: Cell<Option<u32>>,
64 sync_status: Cell<Option<u32>>,
65 droppable: DroppableWebGLSync,
66}
67
68impl WebGLSync {
69 fn new_inherited(context: &WebGLRenderingContext, sync_id: WebGLSyncId) -> Self {
70 Self {
71 webgl_object: WebGLObject::new_inherited(context),
72 client_wait_status: Cell::new(None),
73 sync_status: Cell::new(None),
74 droppable: DroppableWebGLSync {
75 context: WeakRef::new(context),
76 sync_id,
77 marked_for_deletion: Cell::new(false),
78 },
79 }
80 }
81
82 pub(crate) fn new(context: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<Self> {
83 let (sender, receiver) = webgl_channel().unwrap();
84 context.send_command(WebGLCommand::FenceSync(sender));
85 let sync_id = receiver.recv().unwrap();
86
87 reflect_dom_object(
88 Box::new(WebGLSync::new_inherited(context, sync_id)),
89 &*context.global(),
90 can_gc,
91 )
92 }
93}
94
95impl WebGLSync {
96 pub(crate) fn client_wait_sync(
97 &self,
98 context: &WebGLRenderingContext,
99 flags: u32,
100 timeout: u64,
101 ) -> Option<u32> {
102 match self.client_wait_status.get() {
103 Some(constants::TIMEOUT_EXPIRED) | Some(constants::WAIT_FAILED) | None => {
104 let this = Trusted::new(self);
105 let context = Trusted::new(context);
106 let task = task!(request_client_wait_status: move || {
107 let this = this.root();
108 let context = context.root();
109 let (sender, receiver) = webgl_channel().unwrap();
110 context.send_command(WebGLCommand::ClientWaitSync(
111 this.id(),
112 flags,
113 timeout,
114 sender,
115 ));
116 this.client_wait_status.set(Some(receiver.recv().unwrap()));
117 });
118 self.global()
119 .task_manager()
120 .dom_manipulation_task_source()
121 .queue(task);
122 },
123 _ => {},
124 }
125 self.client_wait_status.get()
126 }
127
128 pub(crate) fn delete(&self, operation_fallibility: Operation) {
129 self.droppable.delete(operation_fallibility);
130 }
131
132 pub(crate) fn get_sync_status(
133 &self,
134 pname: u32,
135 context: &WebGLRenderingContext,
136 ) -> Option<u32> {
137 match self.sync_status.get() {
138 Some(constants::UNSIGNALED) | None => {
139 let this = Trusted::new(self);
140 let context = Trusted::new(context);
141 let task = task!(request_sync_status: move || {
142 let this = this.root();
143 let context = context.root();
144 let (sender, receiver) = webgl_channel().unwrap();
145 context.send_command(WebGLCommand::GetSyncParameter(this.id(), pname, sender));
146 this.sync_status.set(Some(receiver.recv().unwrap()));
147 });
148 self.global()
149 .task_manager()
150 .dom_manipulation_task_source()
151 .queue(task);
152 },
153 _ => {},
154 }
155 self.sync_status.get()
156 }
157
158 pub(crate) fn is_valid(&self) -> bool {
159 self.droppable.is_valid()
160 }
161
162 pub(crate) fn id(&self) -> WebGLSyncId {
163 self.droppable.sync_id
164 }
165}