Repository navigation
gpui: draw externally owned native GPU surfaces on Windows, and keep Core Video resources alive until command-buffer completion #64849
Haoxincode
started this conversation in
Zed GPUI
Replies: 3 comments 7 replies
|
Surface work released in bite-gpui v1.23 version. So far, vulkan/linux/dma-buf + va-api path is implemented. After that, upstreaming work could start. The issue is that I don't have access to all the platforms, so I'd have to rely on virtual machines and/or CI. |
0 replies
But why? Why not directly take a MTLTexture, since that's the texture that the macOS backend will be rendering? |
7 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment

Uh oh!
There was an error while loading. Please reload this page.
Context
This follows longbridge/gpui-kit#3168. GPUI Kit consumes unmodified
gpui-presnapshots of this repository and does not carry renderer patches, so that report was redirected here. Once the behavior is in Zed, their snapshot job can pick it up.I embed camera frames that a platform decoder has already produced as GPU resources. Copying each frame through the CPU sprite atlas is the wrong path: it adds a readback, inserts frames into an atlas that will never reuse them, and cannot keep up with a live preview.
surface()/PaintSurfaceis already the primitive for this. On currentmainit is not usable for the case below.This is narrower than #60572. That proposal is a backend-neutral compositor for externally rendered wgpu textures. These frames are not wgpu textures. They are a
CVPixelBuffer, or a D3D11 BGRA shader-resource view that already belongs to the window device. I would like to extend the existing surface primitive rather than add a second one.What
maindoes todaymacOS.
gpui::surface()/Window::paint_surfacetakes aCVPixelBuffer, andgpui_applesamples it indraw_surfaces. Two gaps:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange. Any other format aborts the process, including release builds, because the check isassert_eq!. Single-plane BGRA is already proposed separately in #61291. This discussion does not need to absorb that change.CVMetalTexturevalues returned byCVMetalTextureCacheCreateTextureFromImageare locals in the encode loop. They drop when the iteration ends, before the command buffer completes. Core Video requires both the sourceCVPixelBufferand eachCVMetalTextureto stay alive until the GPU is done reading. Keeping only theMTLTextureis not sufficient: the cache may recycle the underlying IOSurface while the command buffer is still in flight. A caller with a smallCVPixelBufferPoolthen either stalls or samples a recycled allocation.Windows.
PaintSurface::image_bufferexists only undercfg(target_os = "macos"),surface()is macOS-only, andDirectXRenderer::draw_surfacesreturns without drawing:There is no way to submit an externally owned D3D11 texture. The other image path uploads CPU BGRA into the atlas.
wgpu. Surfaces are skipped. That belongs in #60572, not here.
Contract
Same
surface()element andPaintSurfaceprimitive on each platform. No CPU pixels cross the boundary. The renderer only enqueues a read.CVPixelBuffer. While encoding, retain that buffer and everyCVMetalTexturederived from it with the command buffer, and release them from the buffer's completed handler. Aftercommit, theScenemay drop its clone. The underlying pool allocation must remain unique until that handler runs. A regression test is a pool withkCVPixelBufferPoolAllocationThresholdKey = 1: create one buffer, paint it, drop the scene, flush the texture cache, and assert that a secondcreate_pixel_bufferstill returnskCVReturnWouldExceedAllocationThresholdwhile the command buffer is blocked. Unblocking the queue must then allow the allocation. The same lease has to cover whatever formatsdraw_surfacesaccepts, so it still holds if gpui: Support single-plane BGRA CVPixelBuffers in surface rendering #61291 adds a single BGRA plane.ID3D11ShaderResourceViewthat already belongs to the renderer'sID3D11Device(one mip,TEXTURE2D, opaque full-range). Draw it with the existing sprite geometry, bounds, and content mask, and do not allocate an atlas tile. Unbind the SRV before returning so a later primitive cannot sample it. The caller imports across devices and holds the resource until its own GPU reads complete. GPUI should not grow a second completion scheduler. If the view is busy, on the wrong device, or in the wrong format, skip that surface and continue the frame. One unavailable video frame must not stop unrelated UI from painting.I have this behavior working against the
gpui-pre 0.3.6snapshot (zed@bcf6582), with a WARP test that the Windows path samples BGRA, respects the clip, and unbinds the SRV, and with the Metal pool test above. I can open a PR againstmainonce this shape is acceptable.Non-goals
gpui.All reactions