|
|
@@ -40,7 +40,21 @@ use std::{
|
|
|
|
|
|
pub mod anim;
|
|
|
use anim::{Frame as AnimFrame, GfxSeqAnim};
|
|
|
+mod api;
|
|
|
+pub use api::{
|
|
|
+ EpochIndex, GraphicsMethod, ManagedBuffer, ManagedBufferPtr, ManagedSeqAnim, ManagedSeqAnimPtr,
|
|
|
+ ManagedTexture, ManagedTexturePtr, RenderApi,
|
|
|
+};
|
|
|
+mod ev;
|
|
|
+pub use ev::{
|
|
|
+ GraphicsEventCharSub, GraphicsEventKeyDownSub, GraphicsEventKeyUpSub,
|
|
|
+ GraphicsEventMouseButtonDownSub, GraphicsEventMouseButtonUpSub, GraphicsEventMouseMoveSub,
|
|
|
+ GraphicsEventMouseWheelSub, GraphicsEventPublisher, GraphicsEventPublisherPtr,
|
|
|
+ GraphicsEventResizeSub, GraphicsEventTouchSub,
|
|
|
+};
|
|
|
mod favico;
|
|
|
+mod prune;
|
|
|
+use prune::PruneMethodHeap;
|
|
|
mod linalg;
|
|
|
pub use linalg::{Dimension, Point, Rectangle};
|
|
|
mod shader;
|
|
|
@@ -106,257 +120,6 @@ static NEXT_BUFFER_ID: AtomicU32 = AtomicU32::new(0);
|
|
|
static NEXT_TEXTURE_ID: AtomicU32 = AtomicU32::new(0);
|
|
|
static NEXT_ANIM_ID: AtomicU32 = AtomicU32::new(0);
|
|
|
|
|
|
-pub type ManagedTexturePtr = Arc<ManagedTexture>;
|
|
|
-
|
|
|
-/// Auto-deletes texture on drop
|
|
|
-pub struct ManagedTexture {
|
|
|
- id: TextureId,
|
|
|
- epoch: u32,
|
|
|
- render_api: RenderApi,
|
|
|
- tag: DebugTag,
|
|
|
-}
|
|
|
-
|
|
|
-impl Drop for ManagedTexture {
|
|
|
- fn drop(&mut self) {
|
|
|
- self.render_api.delete_unmanaged_texture(self.id, self.epoch, self.tag);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl std::fmt::Debug for ManagedTexture {
|
|
|
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
- f.debug_struct("ManagedTexture").field("id", &self.id).finish()
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-pub type ManagedBufferPtr = Arc<ManagedBuffer>;
|
|
|
-
|
|
|
-/// Auto-deletes buffer on drop
|
|
|
-pub struct ManagedBuffer {
|
|
|
- id: BufferId,
|
|
|
- epoch: u32,
|
|
|
- render_api: RenderApi,
|
|
|
- tag: DebugTag,
|
|
|
- buftype: u8,
|
|
|
-}
|
|
|
-
|
|
|
-impl Drop for ManagedBuffer {
|
|
|
- fn drop(&mut self) {
|
|
|
- self.render_api.delete_unmanaged_buffer(self.id, self.epoch, self.tag, self.buftype);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl std::fmt::Debug for ManagedBuffer {
|
|
|
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
- f.debug_struct("ManagedBuffer").field("id", &self.id).finish()
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-pub type ManagedSeqAnimPtr = Arc<ManagedSeqAnim>;
|
|
|
-
|
|
|
-pub struct ManagedSeqAnim {
|
|
|
- frames_len: usize,
|
|
|
- pub id: AnimId,
|
|
|
- epoch: u32,
|
|
|
- render_api: RenderApi,
|
|
|
- tag: DebugTag,
|
|
|
-}
|
|
|
-
|
|
|
-impl ManagedSeqAnim {
|
|
|
- pub fn update(&self, frame_idx: usize, frame: AnimFrame) {
|
|
|
- assert!(frame_idx < self.frames_len);
|
|
|
- self.render_api.update_unmanaged_anim(self.id, frame_idx, frame, self.epoch, self.tag);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl Drop for ManagedSeqAnim {
|
|
|
- fn drop(&mut self) {
|
|
|
- self.render_api.delete_unmanaged_anim(self.id, self.epoch, self.tag);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl std::fmt::Debug for ManagedSeqAnim {
|
|
|
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
- f.debug_struct("ManagedSeqAnim").field("id", &self.id).finish()
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-pub type EpochIndex = u32;
|
|
|
-
|
|
|
-#[derive(Clone)]
|
|
|
-pub struct RenderApi {
|
|
|
- /// We are abusing async_channel since it's cloneable whereas std::sync::mpsc is shit.
|
|
|
- method_send: async_channel::Sender<(EpochIndex, GraphicsMethod)>,
|
|
|
- /// Keep track of the current UI epoch
|
|
|
- epoch: Arc<AtomicU32>,
|
|
|
-}
|
|
|
-
|
|
|
-impl RenderApi {
|
|
|
- pub fn new(method_send: async_channel::Sender<(EpochIndex, GraphicsMethod)>) -> Self {
|
|
|
- Self { method_send, epoch: Arc::new(AtomicU32::new(0)) }
|
|
|
- }
|
|
|
-
|
|
|
- fn next_epoch(&self) -> EpochIndex {
|
|
|
- self.epoch.fetch_add(1, Ordering::Relaxed) + 1
|
|
|
- }
|
|
|
-
|
|
|
- fn send(&self, method: GraphicsMethod) -> EpochIndex {
|
|
|
- let epoch = self.epoch.load(Ordering::Relaxed);
|
|
|
- self.send_with_epoch(method, epoch);
|
|
|
- epoch
|
|
|
- }
|
|
|
- fn send_with_epoch(&self, method: GraphicsMethod, epoch: EpochIndex) {
|
|
|
- let _ = self.method_send.try_send((epoch, method)).unwrap();
|
|
|
- }
|
|
|
-
|
|
|
- fn new_unmanaged_texture(
|
|
|
- &self,
|
|
|
- width: u16,
|
|
|
- height: u16,
|
|
|
- data: Vec<u8>,
|
|
|
- fmt: TextureFormat,
|
|
|
- tag: DebugTag,
|
|
|
- ) -> (TextureId, EpochIndex) {
|
|
|
- let gfx_texture_id = NEXT_TEXTURE_ID.fetch_add(1, Ordering::Relaxed);
|
|
|
-
|
|
|
- let method = GraphicsMethod::NewTexture((width, height, data, fmt, gfx_texture_id, tag));
|
|
|
- let epoch = self.send(method);
|
|
|
-
|
|
|
- (gfx_texture_id, epoch)
|
|
|
- }
|
|
|
-
|
|
|
- pub fn new_texture(
|
|
|
- &self,
|
|
|
- width: u16,
|
|
|
- height: u16,
|
|
|
- data: Vec<u8>,
|
|
|
- fmt: TextureFormat,
|
|
|
- tag: DebugTag,
|
|
|
- ) -> ManagedTexturePtr {
|
|
|
- let (id, epoch) = self.new_unmanaged_texture(width, height, data, fmt, tag);
|
|
|
- Arc::new(ManagedTexture { id, epoch, render_api: self.clone(), tag })
|
|
|
- }
|
|
|
-
|
|
|
- fn delete_unmanaged_texture(&self, texture: TextureId, epoch: EpochIndex, tag: DebugTag) {
|
|
|
- let method = GraphicsMethod::DeleteTexture((texture, tag));
|
|
|
- self.send_with_epoch(method, epoch);
|
|
|
- }
|
|
|
-
|
|
|
- fn new_unmanaged_vertex_buffer(
|
|
|
- &self,
|
|
|
- verts: Vec<Vertex>,
|
|
|
- tag: DebugTag,
|
|
|
- ) -> (BufferId, EpochIndex) {
|
|
|
- let gfx_buffer_id = NEXT_BUFFER_ID.fetch_add(1, Ordering::Relaxed);
|
|
|
-
|
|
|
- let method = GraphicsMethod::NewVertexBuffer((verts, gfx_buffer_id, tag));
|
|
|
- let epoch = self.send(method);
|
|
|
-
|
|
|
- (gfx_buffer_id, epoch)
|
|
|
- }
|
|
|
-
|
|
|
- fn new_unmanaged_index_buffer(
|
|
|
- &self,
|
|
|
- indices: Vec<u16>,
|
|
|
- tag: DebugTag,
|
|
|
- ) -> (BufferId, EpochIndex) {
|
|
|
- let gfx_buffer_id = NEXT_BUFFER_ID.fetch_add(1, Ordering::Relaxed);
|
|
|
-
|
|
|
- let method = GraphicsMethod::NewIndexBuffer((indices, gfx_buffer_id, tag));
|
|
|
- let epoch = self.send(method);
|
|
|
-
|
|
|
- (gfx_buffer_id, epoch)
|
|
|
- }
|
|
|
-
|
|
|
- pub fn new_vertex_buffer(&self, verts: Vec<Vertex>, tag: DebugTag) -> ManagedBufferPtr {
|
|
|
- let (id, epoch) = self.new_unmanaged_vertex_buffer(verts, tag);
|
|
|
- Arc::new(ManagedBuffer { id, epoch, render_api: self.clone(), tag, buftype: 0 })
|
|
|
- }
|
|
|
- pub fn new_index_buffer(&self, indices: Vec<u16>, tag: DebugTag) -> ManagedBufferPtr {
|
|
|
- let (id, epoch) = self.new_unmanaged_index_buffer(indices, tag);
|
|
|
- Arc::new(ManagedBuffer { id, epoch, render_api: self.clone(), tag, buftype: 1 })
|
|
|
- }
|
|
|
-
|
|
|
- fn delete_unmanaged_buffer(
|
|
|
- &self,
|
|
|
- buffer: BufferId,
|
|
|
- epoch: EpochIndex,
|
|
|
- tag: DebugTag,
|
|
|
- buftype: u8,
|
|
|
- ) {
|
|
|
- let method = GraphicsMethod::DeleteBuffer((buffer, tag, buftype));
|
|
|
- self.send_with_epoch(method, epoch);
|
|
|
- }
|
|
|
-
|
|
|
- fn new_unmanaged_anim(
|
|
|
- &self,
|
|
|
- frames_len: usize,
|
|
|
- oneshot: bool,
|
|
|
- tag: DebugTag,
|
|
|
- ) -> (AnimId, EpochIndex) {
|
|
|
- let gfx_anim_id = NEXT_ANIM_ID.fetch_add(1, Ordering::Relaxed);
|
|
|
-
|
|
|
- let method = GraphicsMethod::NewSeqAnim { id: gfx_anim_id, frames_len, oneshot, tag };
|
|
|
- let epoch = self.send(method);
|
|
|
-
|
|
|
- (gfx_anim_id, epoch)
|
|
|
- }
|
|
|
-
|
|
|
- pub fn new_anim(&self, frames_len: usize, oneshot: bool, tag: DebugTag) -> ManagedSeqAnimPtr {
|
|
|
- let (id, epoch) = self.new_unmanaged_anim(frames_len, oneshot, tag);
|
|
|
- Arc::new(ManagedSeqAnim { frames_len, id, epoch, render_api: self.clone(), tag })
|
|
|
- }
|
|
|
-
|
|
|
- pub fn update_unmanaged_anim(
|
|
|
- &self,
|
|
|
- anim: AnimId,
|
|
|
- frame_idx: usize,
|
|
|
- frame: AnimFrame,
|
|
|
- epoch: EpochIndex,
|
|
|
- tag: DebugTag,
|
|
|
- ) {
|
|
|
- let method = GraphicsMethod::UpdateSeqAnim { id: anim, frame_idx, frame, tag };
|
|
|
- self.send_with_epoch(method, epoch);
|
|
|
- }
|
|
|
-
|
|
|
- fn delete_unmanaged_anim(&self, anim: AnimId, epoch: EpochIndex, tag: DebugTag) {
|
|
|
- let method = GraphicsMethod::DeleteSeqAnim((anim, tag));
|
|
|
- self.send_with_epoch(method, epoch);
|
|
|
- }
|
|
|
-
|
|
|
- pub fn replace_draw_calls(&self, batch_id: BatchGuardId, dcs: Vec<(DcId, DrawCall)>) {
|
|
|
- let method = GraphicsMethod::ReplaceGfxDrawCalls { batch_id, dcs };
|
|
|
- self.send(method);
|
|
|
-
|
|
|
- // I'm not sure whether we need this. Anyway its not fully reliable either since
|
|
|
- // we have no guarantee that when `Stage::update()` whether this method is ready
|
|
|
- // in the receiver.
|
|
|
- #[cfg(target_os = "android")]
|
|
|
- miniquad::window::schedule_update();
|
|
|
- }
|
|
|
-
|
|
|
- fn start_batch(&self, batch_id: BatchGuardId, tag: DebugTag) {
|
|
|
- let method = GraphicsMethod::StartBatch { batch_id, tag };
|
|
|
- self.send(method);
|
|
|
- }
|
|
|
- fn end_batch(&self, batch_id: BatchGuardId) {
|
|
|
- let timest = unixtime();
|
|
|
- let method = GraphicsMethod::EndBatch { batch_id, timest };
|
|
|
- self.send(method);
|
|
|
-
|
|
|
- // Force an update
|
|
|
- #[cfg(target_os = "android")]
|
|
|
- miniquad::window::schedule_update();
|
|
|
- }
|
|
|
-
|
|
|
- pub fn make_guard(&self, debug_str: Option<&'static str>) -> PropertyAtomicGuard {
|
|
|
- let r = self.clone();
|
|
|
- let start_batch = Box::new(move |bid| r.start_batch(bid, debug_str));
|
|
|
- let r = self.clone();
|
|
|
- let end_batch = Box::new(move |bid| r.end_batch(bid));
|
|
|
- PropertyAtomicGuard::new(start_batch, end_batch)
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
#[derive(Clone, Debug)]
|
|
|
pub struct DrawMesh {
|
|
|
pub vertex_buffer: ManagedBufferPtr,
|
|
|
@@ -844,172 +607,6 @@ impl<'a> RenderContext<'a> {
|
|
|
type Timestamp = u64;
|
|
|
type DcId = u64;
|
|
|
|
|
|
-#[derive(Clone)]
|
|
|
-pub enum GraphicsMethod {
|
|
|
- NewTexture((u16, u16, Vec<u8>, TextureFormat, TextureId, DebugTag)),
|
|
|
- DeleteTexture((TextureId, DebugTag)),
|
|
|
- NewVertexBuffer((Vec<Vertex>, BufferId, DebugTag)),
|
|
|
- NewIndexBuffer((Vec<u16>, BufferId, DebugTag)),
|
|
|
- DeleteBuffer((BufferId, DebugTag, u8)),
|
|
|
- NewSeqAnim { id: AnimId, frames_len: usize, oneshot: bool, tag: DebugTag },
|
|
|
- UpdateSeqAnim { id: AnimId, frame_idx: usize, frame: AnimFrame, tag: DebugTag },
|
|
|
- DeleteSeqAnim((AnimId, DebugTag)),
|
|
|
- ReplaceGfxDrawCalls { batch_id: BatchGuardId, dcs: Vec<(DcId, DrawCall)> },
|
|
|
- StartBatch { batch_id: BatchGuardId, tag: DebugTag },
|
|
|
- EndBatch { batch_id: BatchGuardId, timest: Timestamp },
|
|
|
- Noop,
|
|
|
-}
|
|
|
-
|
|
|
-impl std::fmt::Debug for GraphicsMethod {
|
|
|
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
|
- match self {
|
|
|
- Self::NewTexture(_) => write!(f, "NewTexture"),
|
|
|
- Self::DeleteTexture(_) => write!(f, "DeleteTexture"),
|
|
|
- Self::NewVertexBuffer(_) => write!(f, "NewVertexBuffer"),
|
|
|
- Self::NewIndexBuffer(_) => write!(f, "NewIndexBuffer"),
|
|
|
- Self::DeleteBuffer(_) => write!(f, "DeleteBuffer"),
|
|
|
- Self::NewSeqAnim { .. } => write!(f, "NewSeqAnim"),
|
|
|
- Self::UpdateSeqAnim { .. } => write!(f, "UpdateSeqAnim"),
|
|
|
- Self::DeleteSeqAnim(_) => write!(f, "DeleteSeqAnim"),
|
|
|
- Self::ReplaceGfxDrawCalls { batch_id: bid, dcs: _ } => {
|
|
|
- write!(f, "ReplaceGfxDrawCalls({bid})")
|
|
|
- }
|
|
|
- Self::StartBatch { batch_id, tag } => write!(f, "StartBatch({batch_id}, {tag:?})"),
|
|
|
- Self::EndBatch { batch_id, timest } => write!(f, "EndBatch({batch_id}, {timest})"),
|
|
|
- Self::Noop => write!(f, "Noop"),
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-impl Default for GraphicsMethod {
|
|
|
- fn default() -> Self {
|
|
|
- GraphicsMethod::Noop
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-struct EventChannel<T> {
|
|
|
- sender: async_channel::Sender<T>,
|
|
|
- recvr: async_channel::Receiver<T>,
|
|
|
-}
|
|
|
-
|
|
|
-impl<T> EventChannel<T> {
|
|
|
- fn new() -> Self {
|
|
|
- let (sender, recvr) = async_channel::unbounded();
|
|
|
- Self { sender, recvr }
|
|
|
- }
|
|
|
-
|
|
|
- fn notify(&self, ev: T) {
|
|
|
- self.sender.try_send(ev).unwrap();
|
|
|
- }
|
|
|
-
|
|
|
- fn clone_recvr(&self) -> async_channel::Receiver<T> {
|
|
|
- self.recvr.clone()
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-pub type GraphicsEventPublisherPtr = Arc<GraphicsEventPublisher>;
|
|
|
-
|
|
|
-pub struct GraphicsEventPublisher {
|
|
|
- resize: EventChannel<Dimension>,
|
|
|
- key_down: EventChannel<(KeyCode, KeyMods, bool)>,
|
|
|
- key_up: EventChannel<(KeyCode, KeyMods)>,
|
|
|
- chr: EventChannel<(char, KeyMods, bool)>,
|
|
|
- mouse_btn_down: EventChannel<(MouseButton, Point)>,
|
|
|
- mouse_btn_up: EventChannel<(MouseButton, Point)>,
|
|
|
- mouse_move: EventChannel<Point>,
|
|
|
- mouse_wheel: EventChannel<Point>,
|
|
|
- touch: EventChannel<(TouchPhase, u64, Point)>,
|
|
|
-}
|
|
|
-
|
|
|
-pub type GraphicsEventResizeSub = async_channel::Receiver<Dimension>;
|
|
|
-pub type GraphicsEventKeyDownSub = async_channel::Receiver<(KeyCode, KeyMods, bool)>;
|
|
|
-pub type GraphicsEventKeyUpSub = async_channel::Receiver<(KeyCode, KeyMods)>;
|
|
|
-pub type GraphicsEventCharSub = async_channel::Receiver<(char, KeyMods, bool)>;
|
|
|
-pub type GraphicsEventMouseButtonDownSub = async_channel::Receiver<(MouseButton, Point)>;
|
|
|
-pub type GraphicsEventMouseButtonUpSub = async_channel::Receiver<(MouseButton, Point)>;
|
|
|
-pub type GraphicsEventMouseMoveSub = async_channel::Receiver<Point>;
|
|
|
-pub type GraphicsEventMouseWheelSub = async_channel::Receiver<Point>;
|
|
|
-pub type GraphicsEventTouchSub = async_channel::Receiver<(TouchPhase, u64, Point)>;
|
|
|
-
|
|
|
-impl GraphicsEventPublisher {
|
|
|
- pub fn new() -> Arc<Self> {
|
|
|
- Arc::new(Self {
|
|
|
- resize: EventChannel::new(),
|
|
|
- key_down: EventChannel::new(),
|
|
|
- key_up: EventChannel::new(),
|
|
|
- chr: EventChannel::new(),
|
|
|
- mouse_btn_down: EventChannel::new(),
|
|
|
- mouse_btn_up: EventChannel::new(),
|
|
|
- mouse_move: EventChannel::new(),
|
|
|
- mouse_wheel: EventChannel::new(),
|
|
|
- touch: EventChannel::new(),
|
|
|
- })
|
|
|
- }
|
|
|
-
|
|
|
- fn notify_resize(&self, screen_size: Dimension) {
|
|
|
- self.resize.notify(screen_size);
|
|
|
- }
|
|
|
- fn notify_key_down(&self, key: KeyCode, mods: KeyMods, repeat: bool) {
|
|
|
- let ev = (key, mods, repeat);
|
|
|
- self.key_down.notify(ev);
|
|
|
- }
|
|
|
- fn notify_key_up(&self, key: KeyCode, mods: KeyMods) {
|
|
|
- let ev = (key, mods);
|
|
|
- self.key_up.notify(ev);
|
|
|
- }
|
|
|
- fn notify_char(&self, chr: char, mods: KeyMods, repeat: bool) {
|
|
|
- let ev = (chr, mods, repeat);
|
|
|
- self.chr.notify(ev);
|
|
|
- }
|
|
|
- fn notify_mouse_btn_down(&self, button: MouseButton, mouse_pos: Point) {
|
|
|
- let ev = (button, mouse_pos);
|
|
|
- self.mouse_btn_down.notify(ev);
|
|
|
- }
|
|
|
- fn notify_mouse_btn_up(&self, button: MouseButton, mouse_pos: Point) {
|
|
|
- let ev = (button, mouse_pos);
|
|
|
- self.mouse_btn_up.notify(ev);
|
|
|
- }
|
|
|
-
|
|
|
- fn notify_mouse_move(&self, mouse_pos: Point) {
|
|
|
- self.mouse_move.notify(mouse_pos);
|
|
|
- }
|
|
|
- fn notify_mouse_wheel(&self, wheel_pos: Point) {
|
|
|
- self.mouse_wheel.notify(wheel_pos);
|
|
|
- }
|
|
|
- fn notify_touch(&self, phase: TouchPhase, id: u64, touch_pos: Point) {
|
|
|
- let ev = (phase, id, touch_pos);
|
|
|
- self.touch.notify(ev);
|
|
|
- }
|
|
|
-
|
|
|
- pub fn subscribe_resize(&self) -> GraphicsEventResizeSub {
|
|
|
- self.resize.clone_recvr()
|
|
|
- }
|
|
|
- pub fn subscribe_key_down(&self) -> GraphicsEventKeyDownSub {
|
|
|
- self.key_down.clone_recvr()
|
|
|
- }
|
|
|
- pub fn subscribe_key_up(&self) -> GraphicsEventKeyUpSub {
|
|
|
- self.key_up.clone_recvr()
|
|
|
- }
|
|
|
- pub fn subscribe_char(&self) -> GraphicsEventCharSub {
|
|
|
- self.chr.clone_recvr()
|
|
|
- }
|
|
|
- pub fn subscribe_mouse_btn_down(&self) -> GraphicsEventMouseButtonDownSub {
|
|
|
- self.mouse_btn_down.clone_recvr()
|
|
|
- }
|
|
|
- pub fn subscribe_mouse_btn_up(&self) -> GraphicsEventMouseButtonUpSub {
|
|
|
- self.mouse_btn_up.clone_recvr()
|
|
|
- }
|
|
|
- pub fn subscribe_mouse_move(&self) -> GraphicsEventMouseMoveSub {
|
|
|
- self.mouse_move.clone_recvr()
|
|
|
- }
|
|
|
- pub fn subscribe_mouse_wheel(&self) -> GraphicsEventMouseWheelSub {
|
|
|
- self.mouse_wheel.clone_recvr()
|
|
|
- }
|
|
|
- pub fn subscribe_touch(&self) -> GraphicsEventTouchSub {
|
|
|
- self.touch.clone_recvr()
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
struct Stage {
|
|
|
ctx: Box<dyn RenderingBackend>,
|
|
|
#[cfg(target_os = "android")]
|
|
|
@@ -1486,246 +1083,6 @@ impl Stage {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-struct PendingAnim {
|
|
|
- new_method: GraphicsMethod,
|
|
|
- updates: HashMap<usize, GraphicsMethod>,
|
|
|
-}
|
|
|
-
|
|
|
-/// This is used to process the method queue while the screen is off to avoid the queue
|
|
|
-/// becoming congested and using up all the memory.
|
|
|
-/// Will drop alloc/delete pairs, and merge draw calls together.
|
|
|
-struct PruneMethodHeap {
|
|
|
- /// Newly allocated buffers while screen was off
|
|
|
- new_buf: HashMap<BufferId, GraphicsMethod>,
|
|
|
- /// Newly allocated textures while screen was off
|
|
|
- new_tex: HashMap<TextureId, GraphicsMethod>,
|
|
|
- /// Deleted objects
|
|
|
- del: Vec<GraphicsMethod>,
|
|
|
-
|
|
|
- new_anim: HashMap<AnimId, PendingAnim>,
|
|
|
- /// Existing anim updates
|
|
|
- anim_updates: HashMap<AnimId, HashMap<usize, GraphicsMethod>>,
|
|
|
- /// Existing anim deletes
|
|
|
- anim_deletes: HashSet<AnimId>,
|
|
|
-
|
|
|
- epoch: EpochIndex,
|
|
|
-
|
|
|
- textures: *const HashMap<TextureId, miniquad::TextureId>,
|
|
|
- buffers: *const HashMap<BufferId, miniquad::BufferId>,
|
|
|
- anims: *const HashMap<AnimId, GfxSeqAnim>,
|
|
|
- dropped_batches: *mut HashSet<BatchGuardId>,
|
|
|
-}
|
|
|
-
|
|
|
-impl PruneMethodHeap {
|
|
|
- fn new(epoch: EpochIndex) -> Self {
|
|
|
- Self {
|
|
|
- new_buf: HashMap::new(),
|
|
|
- new_tex: HashMap::new(),
|
|
|
- del: vec![],
|
|
|
- new_anim: HashMap::new(),
|
|
|
- anim_updates: HashMap::new(),
|
|
|
- anim_deletes: HashSet::new(),
|
|
|
- epoch,
|
|
|
- textures: std::ptr::null(),
|
|
|
- buffers: std::ptr::null(),
|
|
|
- anims: std::ptr::null(),
|
|
|
- dropped_batches: std::ptr::null_mut(),
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- #[instrument(skip_all, target = "gfx::pruner")]
|
|
|
- fn drain(&mut self, method_recv: &async_channel::Receiver<(EpochIndex, GraphicsMethod)>) {
|
|
|
- // Process as many methods as we can
|
|
|
- while let Ok((epoch, method)) = method_recv.try_recv() {
|
|
|
- if epoch < self.epoch {
|
|
|
- // Discard old rubbish
|
|
|
- t!(
|
|
|
- "Discard method with old epoch: {epoch} curr: {} [method={method:?}]",
|
|
|
- self.epoch
|
|
|
- );
|
|
|
- continue
|
|
|
- }
|
|
|
- assert_eq!(epoch, self.epoch);
|
|
|
- self.process_method(method);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn process_method(&mut self, mut method: GraphicsMethod) {
|
|
|
- match &method {
|
|
|
- GraphicsMethod::NewTexture((_, _, _, _, gtex_id, _)) => {
|
|
|
- if DEBUG_GFXAPI {
|
|
|
- t!("Prune method: new_texture(..., {gtex_id})");
|
|
|
- }
|
|
|
- self.new_tex.insert(*gtex_id, std::mem::take(&mut method));
|
|
|
- }
|
|
|
- GraphicsMethod::DeleteTexture((gtex_id, _)) => {
|
|
|
- if DEBUG_GFXAPI {
|
|
|
- t!("Prune method: delete_texture(..., {gtex_id})");
|
|
|
- }
|
|
|
- if self.new_tex.remove(>ex_id).is_none() {
|
|
|
- if !self.textures().contains_key(>ex_id) {
|
|
|
- panic!("delete_texture missing ID {gtex_id} in pruner")
|
|
|
- }
|
|
|
- let method = std::mem::take(&mut method);
|
|
|
- self.del.push(method);
|
|
|
- } else if DEBUG_GFXAPI {
|
|
|
- t!("Discard ellided texture {gtex_id}");
|
|
|
- }
|
|
|
- }
|
|
|
- GraphicsMethod::NewVertexBuffer((_, gbuff_id, _)) => {
|
|
|
- if DEBUG_GFXAPI {
|
|
|
- t!("Prune method: new_vertex_buffer(..., {gbuff_id})");
|
|
|
- }
|
|
|
- self.new_buf.insert(*gbuff_id, std::mem::take(&mut method));
|
|
|
- }
|
|
|
- GraphicsMethod::NewIndexBuffer((_, gbuff_id, _)) => {
|
|
|
- if DEBUG_GFXAPI {
|
|
|
- t!("Prune method: new_index_buffer(..., {gbuff_id})");
|
|
|
- }
|
|
|
- self.new_buf.insert(*gbuff_id, std::mem::take(&mut method));
|
|
|
- }
|
|
|
- GraphicsMethod::DeleteBuffer((gbuff_id, _, _)) => {
|
|
|
- if DEBUG_GFXAPI {
|
|
|
- t!("Prune method: delete_buffer(..., {gbuff_id})");
|
|
|
- }
|
|
|
- if self.new_buf.remove(&gbuff_id).is_none() {
|
|
|
- if !self.buffers().contains_key(&gbuff_id) {
|
|
|
- panic!("delete_buffer missing ID {gbuff_id} in pruner")
|
|
|
- }
|
|
|
- let method = std::mem::take(&mut method);
|
|
|
- self.del.push(method);
|
|
|
- } else if DEBUG_GFXAPI {
|
|
|
- t!("Discard ellided buffer {gbuff_id}");
|
|
|
- }
|
|
|
- }
|
|
|
- GraphicsMethod::NewSeqAnim { id, .. } => {
|
|
|
- self.new_anim.insert(
|
|
|
- *id,
|
|
|
- PendingAnim {
|
|
|
- updates: HashMap::new(),
|
|
|
- new_method: std::mem::take(&mut method),
|
|
|
- },
|
|
|
- );
|
|
|
- }
|
|
|
-
|
|
|
- GraphicsMethod::UpdateSeqAnim { id, frame_idx, .. } => {
|
|
|
- if let Some(pending) = self.new_anim.get_mut(id) {
|
|
|
- pending.updates.insert(*frame_idx, method);
|
|
|
- } else if self.anims().contains_key(id) {
|
|
|
- self.anim_updates.entry(*id).or_default().insert(*frame_idx, method);
|
|
|
- } else {
|
|
|
- panic!("UpdateSeqAnim for unknown anim {id}");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- GraphicsMethod::DeleteSeqAnim((id, _)) => {
|
|
|
- if self.new_anim.remove(id).is_some() {
|
|
|
- } else if self.anims().contains_key(id) {
|
|
|
- self.anim_deletes.insert(*id);
|
|
|
- self.anim_updates.remove(id);
|
|
|
- } else {
|
|
|
- panic!("DeleteSeqAnim for unknown anim {id}");
|
|
|
- }
|
|
|
- }
|
|
|
- GraphicsMethod::ReplaceGfxDrawCalls { .. } => {}
|
|
|
- // Discard batches since we will apply everything all at once anyway
|
|
|
- // once the screen is switched on.
|
|
|
- GraphicsMethod::StartBatch { batch_id, tag } => {
|
|
|
- t!("Pruner drop start batch {batch_id} debug={tag:?}");
|
|
|
- if !self.dropped_batches().insert(*batch_id) {
|
|
|
- panic!("dropped batch {batch_id} already exits!");
|
|
|
- }
|
|
|
- }
|
|
|
- GraphicsMethod::EndBatch { batch_id, timest: _ } => {
|
|
|
- t!("Pruner drop end batch {batch_id}");
|
|
|
- // Should have already been dropped previously
|
|
|
- assert!(self.dropped_batches().contains(batch_id));
|
|
|
- }
|
|
|
- GraphicsMethod::Noop => panic!("noop"),
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn textures(&self) -> &HashMap<TextureId, miniquad::TextureId> {
|
|
|
- assert!(!self.textures.is_null());
|
|
|
- unsafe { &*self.textures }
|
|
|
- }
|
|
|
- fn buffers(&self) -> &HashMap<BufferId, miniquad::BufferId> {
|
|
|
- assert!(!self.buffers.is_null());
|
|
|
- unsafe { &*self.buffers }
|
|
|
- }
|
|
|
- fn anims(&self) -> &HashMap<AnimId, GfxSeqAnim> {
|
|
|
- assert!(!self.anims.is_null());
|
|
|
- unsafe { &*self.anims }
|
|
|
- }
|
|
|
- fn dropped_batches(&mut self) -> &mut HashSet<BatchGuardId> {
|
|
|
- assert!(!self.dropped_batches.is_null());
|
|
|
- unsafe { &mut *self.dropped_batches }
|
|
|
- }
|
|
|
-
|
|
|
- /// Collect everything now the screen is on
|
|
|
- fn recv_all(&mut self) -> Vec<GraphicsMethod> {
|
|
|
- // Inhale that smoke deep
|
|
|
- let mut meth = Vec::with_capacity(
|
|
|
- self.new_buf.len() +
|
|
|
- self.new_tex.len() +
|
|
|
- self.del.len() +
|
|
|
- self.new_anim.len() +
|
|
|
- self.anim_updates.len() +
|
|
|
- self.anim_deletes.len(),
|
|
|
- );
|
|
|
-
|
|
|
- self.drain_resources(&mut meth);
|
|
|
- self.drain_anims(&mut meth);
|
|
|
-
|
|
|
- meth
|
|
|
- }
|
|
|
-
|
|
|
- fn drain_resources(&mut self, meth: &mut Vec<GraphicsMethod>) {
|
|
|
- let new_buf = std::mem::take(&mut self.new_buf);
|
|
|
- let new_tex = std::mem::take(&mut self.new_tex);
|
|
|
- meth.extend(new_buf.into_values());
|
|
|
- meth.extend(new_tex.into_values());
|
|
|
- meth.append(&mut self.del);
|
|
|
- }
|
|
|
-
|
|
|
- fn drain_anims(&mut self, meth: &mut Vec<GraphicsMethod>) {
|
|
|
- self.drain_pending_anims(meth);
|
|
|
- self.drain_live_anims(meth);
|
|
|
- }
|
|
|
-
|
|
|
- fn drain_pending_anims(&mut self, meth: &mut Vec<GraphicsMethod>) {
|
|
|
- for (_id, pending) in std::mem::take(&mut self.new_anim) {
|
|
|
- meth.push(pending.new_method);
|
|
|
-
|
|
|
- let mut updates: Vec<_> = pending.updates.into_iter().collect();
|
|
|
- updates.sort_by_key(|(idx, _)| *idx);
|
|
|
- for (_, update) in updates {
|
|
|
- meth.push(update);
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- fn drain_live_anims(&mut self, meth: &mut Vec<GraphicsMethod>) {
|
|
|
- let mut updates: Vec<_> = self
|
|
|
- .anim_updates
|
|
|
- .drain()
|
|
|
- .flat_map(|(anim_id, frame_updates)| {
|
|
|
- let mut sorted: Vec<_> = frame_updates.into_iter().collect();
|
|
|
- sorted.sort_by_key(|(idx, _)| *idx);
|
|
|
- sorted.into_iter().map(move |(idx, update)| (anim_id, idx, update))
|
|
|
- })
|
|
|
- .collect();
|
|
|
- updates.sort_by_key(|(anim_id, idx, _)| (*anim_id, *idx));
|
|
|
- for (_, _, update) in updates {
|
|
|
- meth.push(update);
|
|
|
- }
|
|
|
-
|
|
|
- for id in std::mem::take(&mut self.anim_deletes) {
|
|
|
- meth.push(GraphicsMethod::DeleteSeqAnim((id, None)));
|
|
|
- }
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
#[derive(Copy, Clone, Debug, PartialEq)]
|
|
|
enum ScreenState {
|
|
|
// Screen is on as normal
|