rust-windowing / winit

Window handling library in pure Rust
https://docs.rs/winit/
Apache License 2.0
4.88k stars 911 forks source link

RenderPass ops_load Clear(TRANSPARENT) renders a black window. #3918

Closed laycookie closed 2 months ago

laycookie commented 2 months ago

Description

When setting ops_load to transparent, it renders it as black. I use Hyprland as my Window Compositor.

Code:

use std::fs::read_to_string;
use std::path::PathBuf;
use winit::{
    application::ApplicationHandler,
    event::WindowEvent,
    event_loop::{ActiveEventLoop, EventLoop},
    window::{Window, WindowId},
};

pub mod backend;

struct App<'a> {
    instance: wgpu::Instance,
    adapter: wgpu::Adapter,
    device: wgpu::Device,
    queue: wgpu::Queue,
    surface: Option<wgpu::Surface<'a>>,
}

impl<'a> ApplicationHandler for App<'a> {
    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
        let window = event_loop
            .create_window(Window::default_attributes())
            .unwrap();

        let surface = self.instance.create_surface(window).unwrap();
        let config = surface.get_default_config(&self.adapter, 500, 500).unwrap();
        surface.configure(&self.device, &config);

        self.surface = Some(surface);
    }

    fn window_event(&mut self, event_loop: &ActiveEventLoop, id: WindowId, event: WindowEvent) {
        match event {
            WindowEvent::CloseRequested => {
                println!("The close button was pressed; stopping");
                event_loop.exit();
            }
            WindowEvent::RedrawRequested => {
                if let Some(s) = &self.surface {
                    let frame = s.get_current_texture().unwrap();
                    let view = frame
                        .texture
                        .create_view(&wgpu::TextureViewDescriptor::default());
                    let mut encoder = self
                        .device
                        .create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });

                    {
                        let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
                            label: None,
                            color_attachments: &[Some(wgpu::RenderPassColorAttachment {
                                view: &view,
                                resolve_target: None,
                                ops: wgpu::Operations {
                                    load: wgpu::LoadOp::Clear(wgpu::Color::TRANSPARENT),
                                    store: wgpu::StoreOp::Store,
                                },
                            })],
                            depth_stencil_attachment: None,
                            timestamp_writes: None,
                            occlusion_query_set: None,
                        });
                        // rpass.draw(0..3, 0..1);
                    }

                    println!("{:#?}", frame.texture.format());

                    self.queue.submit(Some(encoder.finish()));
                    frame.present();
                }
                println!("redraw");
                // self.window.as_ref().unwrap().request_redraw();
            }
            _ => (),
        }
    }
}

#[tokio::main]
async fn main() {
    let instance = wgpu::Instance::default();
    let adapter = instance
        .request_adapter(&wgpu::RequestAdapterOptions::default())
        .await
        .unwrap();

    let (device, queue) = adapter
        .request_device(
            &wgpu::DeviceDescriptor {
                label: None,
                required_features: wgpu::Features::empty(),
                // Make sure we use the texture resolution limits from the adapter, so we can support images the size of the swapchain.
                required_limits: wgpu::Limits::downlevel_webgl2_defaults()
                    .using_resolution(adapter.limits()),
                memory_hints: wgpu::MemoryHints::MemoryUsage,
            },
            None,
        )
        .await
        .expect("Failed to create device");
    // Create an event loop
    let event_loop = EventLoop::new().unwrap();
    // Create a window
    let mut app = App {
        instance,
        adapter,
        device,
        queue,
        surface: None,
    };
    event_loop.run_app(&mut app).unwrap();
}

Debugging output

No response

Window isn't shown unless you draw

Winit version

0.30.5

Koranir commented 2 months ago

Your winit::Window must be created with the transparent flag enabled, and your wgpu::Surface must have its configuration's alpha mode set to one that supports transparency.

laycookie commented 2 months ago

Your winit::Window must be created with the transparent flag enabled, and your wgpu::Surface must have its configuration's alpha mode set to one that supports transparency.

Thank you, CompositeAlpha was set to Auto which was then setting it to opaque. Setting it to PostMultiplied, or Inherit caused the application to crash meanwhile setting it to PreMultiplied caused transparency to work properly. Setting 'with_transperacny' in my case wasn't necessary tho. In the description of CompositeAlphaMode::Inherit it is saying that by default it will apply platform specific default for blending, so what is the reason it might possibly be just crashing, when set to that or did I miss interpreted it?

Koranir commented 2 months ago

In the description of CompositeAlphaMode::Inherit it is saying that by default it will apply platform specific default for blending, so what is the reason it might possibly be just crashing, when set to that or did I miss interpreted it?

It probably crashed because your gpu does not support post-multiplied alpha modes. You can check what modes are supported with the Surface::get_capabilities function.