Skip to content

Commit

Permalink
rendervulkan: Don't reuse textures with PipeWire
Browse files Browse the repository at this point in the history
PipeWire allocates textures on a different thread, and that causes a lot
of race conditions with the compositor thread.
  • Loading branch information
Starsam80 committed Jul 4, 2023
1 parent 1b9b736 commit f13171e
Show file tree
Hide file tree
Showing 4 changed files with 30 additions and 44 deletions.
7 changes: 3 additions & 4 deletions src/pipewire.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,6 @@ static void stream_handle_param_changed(void *data, uint32_t id, const struct sp
uint8_t buf[1024];
struct spa_pod_builder builder = SPA_POD_BUILDER_INIT(buf, sizeof(buf));

int buffers = 4;
int shm_size = state->shm_stride * state->video_info.size.height;
if (state->video_info.format == SPA_VIDEO_FORMAT_NV12) {
shm_size += ((state->video_info.size.height + 1) / 2) * state->shm_stride;
Expand All @@ -358,7 +357,7 @@ static void stream_handle_param_changed(void *data, uint32_t id, const struct sp
const struct spa_pod *buffers_param =
(const struct spa_pod *) spa_pod_builder_add_object(&builder,
SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(buffers, 1, 8),
SPA_PARAM_BUFFERS_buffers, SPA_POD_CHOICE_RANGE_Int(4, 1, 32),
SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1),
SPA_PARAM_BUFFERS_size, SPA_POD_Int(shm_size),
SPA_PARAM_BUFFERS_stride, SPA_POD_Int(state->shm_stride),
Expand Down Expand Up @@ -473,8 +472,8 @@ static void stream_handle_add_buffer(void *user_data, struct pw_buffer *pw_buffe

uint32_t drmFormat = spa_format_to_drm(state->video_info.format);

buffer->texture = vulkan_acquire_screenshot_texture(s_nCaptureWidth, s_nCaptureHeight, is_dmabuf, drmFormat, colorspace);
assert(buffer->texture != nullptr);
buffer->texture = vulkan_create_screenshot_texture(s_nCaptureWidth, s_nCaptureHeight, drmFormat, is_dmabuf);
buffer->texture->setStreamColorspace(colorspace);

if (is_dmabuf) {
const struct wlr_dmabuf_attributes dmabuf = buffer->texture->dmabuf();
Expand Down
54 changes: 24 additions & 30 deletions src/rendervulkan.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ struct VulkanOutput_t

VkFormat outputFormat = VK_FORMAT_UNDEFINED;

std::array<std::shared_ptr<CVulkanTexture>, 8> pScreenshotImages;
std::shared_ptr<CVulkanTexture> pScreenshotImage;

// NIS and FSR
std::shared_ptr<CVulkanTexture> tmpOutput;
Expand Down Expand Up @@ -2967,8 +2967,7 @@ bool vulkan_remake_swapchain( void )
g_device.vk.DestroySwapchainKHR( g_device.device(), pOutput->swapChain, nullptr );

// Delete screenshot image to be remade if needed
for (auto& pScreenshotImage : pOutput->pScreenshotImages)
pScreenshotImage = nullptr;
pOutput->pScreenshotImage = nullptr;

bool bRet = vulkan_make_swapchain( pOutput );
assert( bRet ); // Something has gone horribly wrong!
Expand Down Expand Up @@ -3018,8 +3017,7 @@ bool vulkan_remake_output_images()
pOutput->nOutImage = 0;

// Delete screenshot image to be remade if needed
for (auto& pScreenshotImage : pOutput->pScreenshotImages)
pScreenshotImage = nullptr;
pOutput->pScreenshotImage = nullptr;

bool bRet = vulkan_make_output_images( pOutput );
assert( bRet );
Expand Down Expand Up @@ -3266,37 +3264,33 @@ void vulkan_garbage_collect( void )
g_device.garbageCollect();
}

std::shared_ptr<CVulkanTexture> vulkan_acquire_screenshot_texture(uint32_t width, uint32_t height, bool exportable, uint32_t drmFormat, EStreamColorspace colorspace)
std::shared_ptr<CVulkanTexture> vulkan_create_screenshot_texture(uint32_t width, uint32_t height, uint32_t drmFormat, bool exportable)
{
for (auto& pScreenshotImage : g_output.pScreenshotImages)
{
if (pScreenshotImage == nullptr)
{
pScreenshotImage = std::make_shared<CVulkanTexture>();

CVulkanTexture::createFlags screenshotImageFlags;
screenshotImageFlags.bMappable = true;
screenshotImageFlags.bTransferDst = true;
screenshotImageFlags.bStorage = true;
if (exportable || drmFormat == DRM_FORMAT_NV12) {
screenshotImageFlags.bExportable = true;
screenshotImageFlags.bLinear = true; // TODO: support multi-planar DMA-BUF export via PipeWire
}
std::shared_ptr<CVulkanTexture> pTex = std::make_shared<CVulkanTexture>();

bool bSuccess = pScreenshotImage->BInit( width, height, 1u, drmFormat, screenshotImageFlags );
pScreenshotImage->setStreamColorspace(colorspace);
CVulkanTexture::createFlags flags;
flags.bTransferDst = true;
flags.bStorage = true;
flags.bLinear = true; // TODO: support multi-planar DMA-BUF export via PipeWire
if (exportable) {
flags.bExportable = true;
} else {
flags.bMappable = true;
}

assert( bSuccess );
}
assert( pTex->BInit( width, height, 1u, drmFormat, flags ) );

if (pScreenshotImage.use_count() > 1 || width != pScreenshotImage->width() || height != pScreenshotImage->height())
continue;
return pTex;
}

return pScreenshotImage;
std::shared_ptr<CVulkanTexture> vulkan_acquire_screenshot_texture(uint32_t width, uint32_t height, uint32_t drmFormat)
{
auto& pScreenshotImage = g_output.pScreenshotImage;
if ( pScreenshotImage == nullptr || pScreenshotImage->width() != width || pScreenshotImage->height() != height)
{
pScreenshotImage = vulkan_create_screenshot_texture(width, height, drmFormat);
}

vk_log.errorf("Unable to acquire screenshot texture. Out of textures.");
return nullptr;
return pScreenshotImage;
}

// Internal display's native brightness.
Expand Down
3 changes: 2 additions & 1 deletion src/rendervulkan.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,7 +329,8 @@ std::shared_ptr<CVulkanTexture> vulkan_create_texture_from_wlr_buffer( struct wl

bool vulkan_composite( const struct FrameInfo_t *frameInfo, std::shared_ptr<CVulkanTexture> pScreenshotTexture );
std::shared_ptr<CVulkanTexture> vulkan_get_last_output_image( void );
std::shared_ptr<CVulkanTexture> vulkan_acquire_screenshot_texture(uint32_t width, uint32_t height, bool exportable, uint32_t drmFormat, EStreamColorspace colorspace = k_EStreamColorspace_Unknown);
std::shared_ptr<CVulkanTexture> vulkan_create_screenshot_texture(uint32_t width, uint32_t height, uint32_t drmFormat, bool exportable = false);
std::shared_ptr<CVulkanTexture> vulkan_acquire_screenshot_texture(uint32_t width, uint32_t height, uint32_t drmFormat);

void vulkan_present_to_window( void );
#if HAVE_OPENVR
Expand Down
10 changes: 1 addition & 9 deletions src/steamcompmgr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2555,15 +2555,7 @@ paint_all(bool async)

if ( takeScreenshot )
{
constexpr bool bHackForceNV12DumpScreenshot = false;

uint32_t drmCaptureFormat = bHackForceNV12DumpScreenshot
? DRM_FORMAT_NV12
: DRM_FORMAT_XRGB8888;

std::shared_ptr<CVulkanTexture> pScreenshotTexture = vulkan_acquire_screenshot_texture(g_nOutputWidth, g_nOutputHeight, false, drmCaptureFormat);

assert( pScreenshotTexture != nullptr );
std::shared_ptr<CVulkanTexture> pScreenshotTexture = vulkan_acquire_screenshot_texture(g_nOutputWidth, g_nOutputHeight, DRM_FORMAT_XRGB8888);

// Basically no color mgmt applied for screenshots. (aside from being able to handle HDR content with LUTs)
for ( uint32_t nInputEOTF = 0; nInputEOTF < EOTF_Count; nInputEOTF++ )
Expand Down

0 comments on commit f13171e

Please sign in to comment.