use super::resource::ManagedWgpuTexture;
use super::*;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) enum ManagedRequestOutcome {
Uploaded(TextureId),
Destroyed,
Superseded,
}
impl WgpuTextureManager {
pub(crate) fn handle_texture_requests(
&mut self,
requests: &[TextureRequest],
request_epoch: u64,
device: &Device,
queue: &Queue,
render_resources: &mut RenderResources,
) -> RendererResult<Vec<TextureFeedback>> {
let mut feedback = Vec::with_capacity(requests.len());
for request in requests {
match self.apply_managed_request_at_epoch(
request.texture(),
request.operation(),
request_epoch,
device,
queue,
render_resources,
)? {
ManagedRequestOutcome::Uploaded(texture_id) => {
feedback.push(request.uploaded(texture_id)?);
}
ManagedRequestOutcome::Destroyed => feedback.push(request.destroyed()?),
ManagedRequestOutcome::Superseded => feedback.push(request.superseded()),
}
}
Ok(feedback)
}
pub(crate) fn apply_managed_request_at_epoch(
&mut self,
id: SnapshotTextureId,
operation: &TextureOp,
request_epoch: u64,
device: &Device,
queue: &Queue,
render_resources: &mut RenderResources,
) -> RendererResult<ManagedRequestOutcome> {
match operation {
TextureOp::Create {
format,
width,
height,
row_pitch,
pixels,
} => {
if self.destroyed_managed_textures.contains_key(&id) {
return Ok(ManagedRequestOutcome::Superseded);
}
if let Some(existing) = self.managed_textures.get(&id)
&& (existing.width != *width || existing.height != *height)
{
return Err(RendererError::ManagedTextureLayoutMismatch {
texture: id,
expected: [existing.width, existing.height],
actual: [*width, *height],
});
}
let (resource, rgba_pixels) = Self::create_managed_texture_resource(
device, queue, *format, *width, *height, *row_pitch, pixels,
)?;
let texture_id = if let Some(existing) = self.managed_textures.get_mut(&id) {
existing.resource = resource;
existing.rgba_pixels = rgba_pixels;
existing.texture_id
} else {
let texture_id = self.allocate_managed_texture_id()?;
self.managed_textures.insert(
id,
ManagedWgpuTexture {
texture_id,
width: *width,
height: *height,
resource,
rgba_pixels,
},
);
self.managed_by_texture_id.insert(texture_id, id);
texture_id
};
render_resources.remove_image_bind_group(texture_id);
Ok(ManagedRequestOutcome::Uploaded(texture_id))
}
TextureOp::Update {
format,
width,
height,
rects,
} => {
if self.destroyed_managed_textures.contains_key(&id) {
return Ok(ManagedRequestOutcome::Superseded);
}
self.update_managed_texture(device, queue, id, *format, [*width, *height], rects)?;
let texture_id = self
.managed_texture_id(id)
.ok_or(RendererError::ManagedTextureMissing(id))?;
render_resources.remove_image_bind_group(texture_id);
Ok(ManagedRequestOutcome::Uploaded(texture_id))
}
TextureOp::Destroy => {
self.destroyed_managed_textures
.entry(id)
.and_modify(|destroy_epoch| {
*destroy_epoch = (*destroy_epoch).max(request_epoch);
})
.or_insert(request_epoch);
if let Some(entry) = self.managed_textures.remove(&id) {
self.managed_by_texture_id.remove(&entry.texture_id);
render_resources.remove_image_bind_group(entry.texture_id);
}
Ok(ManagedRequestOutcome::Destroyed)
}
}
}
#[cfg(test)]
pub(super) fn apply_managed_request(
&mut self,
id: SnapshotTextureId,
operation: &TextureOp,
device: &Device,
queue: &Queue,
render_resources: &mut RenderResources,
) -> RendererResult<ManagedRequestOutcome> {
self.apply_managed_request_at_epoch(id, operation, 0, device, queue, render_resources)
}
}