script/dom/webgl/
webglsync.rs

1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
5use std::cell::Cell;
6
7use canvas_traits::webgl::{WebGLCommand, WebGLSyncId, webgl_channel};
8use dom_struct::dom_struct;
9
10use crate::dom::bindings::codegen::Bindings::WebGL2RenderingContextBinding::WebGL2RenderingContextConstants as constants;
11use crate::dom::bindings::inheritance::Castable;
12use crate::dom::bindings::refcounted::Trusted;
13use crate::dom::bindings::reflector::{DomGlobal, reflect_dom_object};
14use crate::dom::bindings::root::DomRoot;
15use crate::dom::webgl::webglobject::WebGLObject;
16use crate::dom::webgl::webglrenderingcontext::{Operation, WebGLRenderingContext};
17use crate::script_runtime::CanGc;
18
19#[dom_struct]
20pub(crate) struct WebGLSync {
21    webgl_object: WebGLObject,
22    #[no_trace]
23    sync_id: WebGLSyncId,
24    marked_for_deletion: Cell<bool>,
25    client_wait_status: Cell<Option<u32>>,
26    sync_status: Cell<Option<u32>>,
27}
28
29impl WebGLSync {
30    fn new_inherited(context: &WebGLRenderingContext, sync_id: WebGLSyncId) -> Self {
31        Self {
32            webgl_object: WebGLObject::new_inherited(context),
33            sync_id,
34            marked_for_deletion: Cell::new(false),
35            client_wait_status: Cell::new(None),
36            sync_status: Cell::new(None),
37        }
38    }
39
40    pub(crate) fn new(context: &WebGLRenderingContext, can_gc: CanGc) -> DomRoot<Self> {
41        let (sender, receiver) = webgl_channel().unwrap();
42        context.send_command(WebGLCommand::FenceSync(sender));
43        let sync_id = receiver.recv().unwrap();
44
45        reflect_dom_object(
46            Box::new(WebGLSync::new_inherited(context, sync_id)),
47            &*context.global(),
48            can_gc,
49        )
50    }
51}
52
53impl WebGLSync {
54    pub(crate) fn context(&self) -> &WebGLRenderingContext {
55        self.upcast::<WebGLObject>().context()
56    }
57
58    pub(crate) fn client_wait_sync(
59        &self,
60        context: &WebGLRenderingContext,
61        flags: u32,
62        timeout: u64,
63    ) -> Option<u32> {
64        match self.client_wait_status.get() {
65            Some(constants::TIMEOUT_EXPIRED) | Some(constants::WAIT_FAILED) | None => {
66                let this = Trusted::new(self);
67                let context = Trusted::new(context);
68                let task = task!(request_client_wait_status: move || {
69                    let this = this.root();
70                    let context = context.root();
71                    let (sender, receiver) = webgl_channel().unwrap();
72                    context.send_command(WebGLCommand::ClientWaitSync(
73                        this.sync_id,
74                        flags,
75                        timeout,
76                        sender,
77                    ));
78                    this.client_wait_status.set(Some(receiver.recv().unwrap()));
79                });
80                self.global()
81                    .task_manager()
82                    .dom_manipulation_task_source()
83                    .queue(task);
84            },
85            _ => {},
86        }
87        self.client_wait_status.get()
88    }
89
90    pub(crate) fn delete(&self, operation_fallibility: Operation) {
91        if self.is_valid() {
92            self.marked_for_deletion.set(true);
93            let context = self.upcast::<WebGLObject>().context();
94            let cmd = WebGLCommand::DeleteSync(self.sync_id);
95            match operation_fallibility {
96                Operation::Fallible => context.send_command_ignored(cmd),
97                Operation::Infallible => context.send_command(cmd),
98            }
99        }
100    }
101
102    pub(crate) fn get_sync_status(
103        &self,
104        pname: u32,
105        context: &WebGLRenderingContext,
106    ) -> Option<u32> {
107        match self.sync_status.get() {
108            Some(constants::UNSIGNALED) | None => {
109                let this = Trusted::new(self);
110                let context = Trusted::new(context);
111                let task = task!(request_sync_status: move || {
112                    let this = this.root();
113                    let context = context.root();
114                    let (sender, receiver) = webgl_channel().unwrap();
115                    context.send_command(WebGLCommand::GetSyncParameter(this.sync_id, pname, sender));
116                    this.sync_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.sync_status.get()
126    }
127
128    pub(crate) fn is_valid(&self) -> bool {
129        !self.marked_for_deletion.get()
130    }
131
132    pub(crate) fn id(&self) -> WebGLSyncId {
133        self.sync_id
134    }
135}
136
137impl Drop for WebGLSync {
138    fn drop(&mut self) {
139        self.delete(Operation::Fallible);
140    }
141}