Commit c0caa658decf
tarball5 files changed+59-9
@@ -16,6 +16,7 @@ pub(crate) enum Op {
1616
},1717
Draw {1818
kind: Kind,19
+ opaque: bool,1920
texture: Option<VulkanTexture>,2021
push: Push,2122
scissors: Vec<vk::Rect2D>,@@ -192,6 +193,10 @@ impl<'frame, 'buffer> VulkanFrame<'frame, 'buffer> {
192193
};193194
self.ops.push(Op::Draw {194195
kind,196
+ opaque: kind == Kind::Texture197
+ && alpha >= 1.0198
+ && self.clip.is_none()199
+ && texture.0.opaque(),195200
texture: Some(texture.clone()),196201
push,197202
scissors,@@ -253,6 +258,7 @@ impl Frame for VulkanFrame<'_, '_> {
253258
};254259
self.ops.push(Op::Draw {255260
kind: Kind::Solid,261
+ opaque: color.a() >= 1.0 && self.clip.is_none(),256262
texture: None,257263
push,258264
scissors,@@ -167,6 +167,11 @@ impl ImageInner {
167167
Ok(Arc::new(inner))168168
}169169
170
+ /// Whether sampling the image always gives alpha one.171
+ pub fn opaque(&self) -> bool {172
+ vk_format(self.fourcc).is_some_and(|f| f.opaque)173
+ }174
+170175
pub fn layout(&self) -> vk::ImageLayout {171176
*self.layout.lock().unwrap_or_else(|e| e.into_inner())172177
}@@ -47,7 +47,7 @@ pub(crate) struct Pipelines {
4747
solid: vk::ShaderModule,4848
texture: vk::ShaderModule,4949
effect: vk::ShaderModule,50
- cache: HashMap<(vk::Format, Kind), vk::Pipeline>,50
+ cache: HashMap<(vk::Format, Kind, bool), vk::Pipeline>,5151
vk_cache: vk::PipelineCache,5252
cache_path: Option<PathBuf>,5353
loaded_len: usize,@@ -135,9 +135,15 @@ impl Pipelines {
135135
let Some(format) = vk_format(fourcc) else {136136
continue;137137
};138
- for kind in [Kind::Solid, Kind::Texture, Kind::Effect] {139
- if let Err(e) = self.get(format.format, kind) {140
- tracing::warn!(?kind, "cannot warm a pipeline: {e}");138
+ for (kind, opaque) in [139
+ (Kind::Solid, false),140
+ (Kind::Solid, true),141
+ (Kind::Texture, false),142
+ (Kind::Texture, true),143
+ (Kind::Effect, false),144
+ ] {145
+ if let Err(e) = self.get(format.format, kind, opaque) {146
+ tracing::warn!(?kind, opaque, "cannot warm a pipeline: {e}");141147
return;142148
}143149
}@@ -180,8 +186,15 @@ impl Pipelines {
180186
}181187
}182188
183
- pub fn get(&mut self, format: vk::Format, kind: Kind) -> Result<vk::Pipeline, Error> {184
- if let Some(&p) = self.cache.get(&(format, kind)) {189
+ /// The pipeline for `kind` into `format`. An `opaque` one replaces the190
+ /// destination instead of blending, for draws known to cover it.191
+ pub fn get(192
+ &mut self,193
+ format: vk::Format,194
+ kind: Kind,195
+ opaque: bool,196
+ ) -> Result<vk::Pipeline, Error> {197
+ if let Some(&p) = self.cache.get(&(format, kind, opaque)) {185198
return Ok(p);186199
}187200
let d = &self.shared.device.device;@@ -213,7 +226,7 @@ impl Pipelines {
213226
let multisample = vk::PipelineMultisampleStateCreateInfo::default()214227
.rasterization_samples(vk::SampleCountFlags::TYPE_1);215228
let attachments = [vk::PipelineColorBlendAttachmentState::default()216
- .blend_enable(true)229
+ .blend_enable(!opaque)217230
.src_color_blend_factor(vk::BlendFactor::ONE)218231
.dst_color_blend_factor(vk::BlendFactor::ONE_MINUS_SRC_ALPHA)219232
.color_blend_op(vk::BlendOp::ADD)@@ -240,7 +253,7 @@ impl Pipelines {
240253
.push_next(&mut rendering);241254
let pipeline = unsafe { d.create_graphics_pipelines(self.vk_cache, &[info], None) }242255
.map_err(|(_, e)| e)?[0];243
- self.cache.insert((format, kind), pipeline);256
+ self.cache.insert((format, kind, opaque), pipeline);244257
Ok(pipeline)245258
}246259
}@@ -429,7 +429,9 @@ impl VulkanRenderer {
429429
let mut pipelines = Vec::with_capacity(ops.len());430430
for op in &ops {431431
pipelines.push(match op {432
- Op::Draw { kind, .. } => Some(self.pipelines.get(image.format, *kind)?),432
+ Op::Draw { kind, opaque, .. } => {433
+ Some(self.pipelines.get(image.format, *kind, *opaque)?)434
+ }433435
Op::Clear { .. } => None,434436
});435437
}@@ -275,3 +275,27 @@ fn queued_uploads_to_one_texture_land_in_order() {
275275
});276276
assert_eq!(at(&s.pixels(), 32, 32), RED);277277
}278
+279
+#[test]280
+fn opaque_format_texture_replaces_what_is_under_it() {281
+ let mut s = Scene::new();282
+ let bytes = [0u8, 255, 0, 0];283
+ let tex = s284
+ .renderer285
+ .import_memory(&bytes, Fourcc::Xbgr8888, (1, 1).into(), false)286
+ .unwrap();287
+ s.draw(Transform::Normal, |f| {288
+ f.clear(rgba(RED), &[full()]).unwrap();289
+ f.render_texture_from_to(290
+ &tex,291
+ Rectangle::from_size((1.0, 1.0).into()),292
+ full(),293
+ &[full()],294
+ &[],295
+ Transform::Normal,296
+ 1.0,297
+ )298
+ .unwrap();299
+ });300
+ assert_eq!(at(&s.pixels(), 32, 32), GREEN);301
+}