steamcompmgr, rendervulkan: Implement deferred partial composition

Use partial composition for overlays when we have too many layers.
This commit is contained in:
Joshua Ashton 2023-06-24 01:27:49 +01:00 committed by Joshie
parent d5aec88630
commit bc3c4bc275
8 changed files with 292 additions and 52 deletions

View file

@ -41,6 +41,7 @@ extern "C" {
struct drm_t g_DRM = {};
uint32_t g_nDRMFormat = DRM_FORMAT_INVALID;
uint32_t g_nDRMFormatOverlay = DRM_FORMAT_INVALID; // for partial composition, we may have more limited formats than base planes + alpha.
bool g_bRotated = false;
bool g_bUseLayers = true;
bool g_bDebugLayers = false;
@ -1357,6 +1358,12 @@ bool init_drm(struct drm_t *drm, int width, int height, int refresh, bool wants_
}
}
// ARGB8888 is the Xformat and AFormat here in this function as we want transparent overlay
g_nDRMFormatOverlay = pick_plane_format(&drm->primary_formats, DRM_FORMAT_ARGB8888, DRM_FORMAT_ARGB8888);
if ( g_nDRMFormatOverlay == DRM_FORMAT_INVALID ) {
drm_log.errorf("Overlay plane doesn't support any formats >= 8888");
}
drm->kms_in_fence_fd = -1;
std::thread flip_handler_thread( flip_handler_thread_run );
@ -2284,11 +2291,6 @@ drm_prepare_liftoff( struct drm_t *drm, const struct FrameInfo_t *frameInfo, boo
liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_TF", 0 );
liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_LUT3D", 0 );
}
if (!g_bDisableBlendTF && !bSinglePlane)
liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_BLEND_TF", drm->pending.output_tf );
else
liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_BLEND_TF", 0 );
}
}
else
@ -2299,6 +2301,23 @@ drm_prepare_liftoff( struct drm_t *drm, const struct FrameInfo_t *frameInfo, boo
liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_LUT", 0 );
liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_SHAPER_TF", 0 );
liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_LUT3D", 0 );
}
}
if ( frameInfo->layers[i].allowBlending )
{
if ( drm_supports_color_mgmt( drm ) )
{
if (!g_bDisableBlendTF && !bSinglePlane)
liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_BLEND_TF", drm->pending.output_tf );
else
liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_BLEND_TF", 0 );
}
}
else
{
if ( drm_supports_color_mgmt( drm ) )
{
liftoff_layer_set_property( drm->lo_layers[ i ], "VALVE1_PLANE_BLEND_TF", DRM_VALVE1_TRANSFER_FUNCTION_DEFAULT );
}
}

View file

@ -269,6 +269,7 @@ struct drm_t {
extern struct drm_t g_DRM;
extern uint32_t g_nDRMFormat;
extern uint32_t g_nDRMFormatOverlay;
extern bool g_bUseLayers;
extern bool g_bRotated;

View file

@ -103,9 +103,13 @@ struct VulkanOutput_t
VkFence acquireFence;
uint32_t nOutImage; // swapchain index in nested mode, or ping/pong between two RTs
uint32_t nOutImagePartial;
uint32_t nOutPresentImagePartial;
std::vector<std::shared_ptr<CVulkanTexture>> outputImages;
std::vector<std::shared_ptr<CVulkanTexture>> outputImagesPartialOverlay;
VkFormat outputFormat = VK_FORMAT_UNDEFINED;
VkFormat outputFormatOverlay = VK_FORMAT_UNDEFINED;
std::array<std::shared_ptr<CVulkanTexture>, 8> pScreenshotImages;
@ -2861,7 +2865,7 @@ std::shared_ptr<CVulkanTexture> vulkan_create_debug_white_texture()
void vulkan_present_to_openvr( void )
{
//static auto texture = vulkan_create_debug_white_texture();
auto texture = vulkan_get_last_output_image();
auto texture = vulkan_get_last_output_image( false );
vr::VRVulkanTextureData_t data =
{
@ -2985,9 +2989,13 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput )
outputImageflags.bSwapchain = BIsVRSession();
pOutput->outputImages.resize(2);
pOutput->outputImagesPartialOverlay.resize(3);
pOutput->outputImages[0] = nullptr;
pOutput->outputImages[1] = nullptr;
pOutput->outputImagesPartialOverlay[0] = nullptr;
pOutput->outputImagesPartialOverlay[1] = nullptr;
pOutput->outputImagesPartialOverlay[2] = nullptr;
VkFormat format = pOutput->outputFormat;
@ -3007,6 +3015,35 @@ static bool vulkan_make_output_images( VulkanOutput_t *pOutput )
return false;
}
if ( pOutput->outputFormatOverlay != VK_FORMAT_UNDEFINED )
{
VkFormat partialFormat = pOutput->outputFormatOverlay;
pOutput->outputImagesPartialOverlay[0] = std::make_shared<CVulkanTexture>();
bool bSuccess = pOutput->outputImagesPartialOverlay[0]->BInit( g_nOutputWidth, g_nOutputHeight, 1u, VulkanFormatToDRM(partialFormat), outputImageflags );
if ( bSuccess != true )
{
vk_log.errorf( "failed to allocate buffer for KMS" );
return false;
}
pOutput->outputImagesPartialOverlay[1] = std::make_shared<CVulkanTexture>();
bSuccess = pOutput->outputImagesPartialOverlay[1]->BInit( g_nOutputWidth, g_nOutputHeight, 1u, VulkanFormatToDRM(partialFormat), outputImageflags );
if ( bSuccess != true )
{
vk_log.errorf( "failed to allocate buffer for KMS" );
return false;
}
pOutput->outputImagesPartialOverlay[2] = std::make_shared<CVulkanTexture>();
bSuccess = pOutput->outputImagesPartialOverlay[2]->BInit( g_nOutputWidth, g_nOutputHeight, 1u, VulkanFormatToDRM(partialFormat), outputImageflags );
if ( bSuccess != true )
{
vk_log.errorf( "failed to allocate buffer for KMS" );
return false;
}
}
return true;
}
@ -3016,6 +3053,8 @@ bool vulkan_remake_output_images()
g_device.waitIdle();
pOutput->nOutImage = 0;
pOutput->nOutImagePartial = 0;
pOutput->nOutPresentImagePartial = 2;
// Delete screenshot image to be remade if needed
for (auto& pScreenshotImage : pOutput->pScreenshotImages)
@ -3094,6 +3133,7 @@ bool vulkan_make_output( VkSurfaceKHR surface )
else
{
pOutput->outputFormat = DRMFormatToVulkan( g_nDRMFormat, false );
pOutput->outputFormatOverlay = DRMFormatToVulkan( g_nDRMFormatOverlay, false );
if ( pOutput->outputFormat == VK_FORMAT_UNDEFINED )
{
@ -3101,6 +3141,12 @@ bool vulkan_make_output( VkSurfaceKHR surface )
return false;
}
if ( pOutput->outputFormatOverlay == VK_FORMAT_UNDEFINED )
{
vk_log.errorf( "failed to find Vulkan format suitable for KMS partial overlays" );
return false;
}
if ( !vulkan_make_output_images( pOutput ) )
return false;
}
@ -3497,9 +3543,23 @@ bool vulkan_screenshot( const struct FrameInfo_t *frameInfo, std::shared_ptr<CVu
return true;
}
bool vulkan_composite( const struct FrameInfo_t *frameInfo, std::shared_ptr<CVulkanTexture> pPipewireTexture )
std::unique_ptr<std::thread> partial_wait_thread;
bool vulkan_composite( const struct FrameInfo_t *frameInfo, std::shared_ptr<CVulkanTexture> pPipewireTexture, bool partial )
{
auto compositeImage = g_output.outputImages[ g_output.nOutImage ];
if ( partial_wait_thread )
{
partial_wait_thread->join();
partial_wait_thread = nullptr;
}
if ( partial )
{
g_output.nOutPresentImagePartial = g_output.nOutImagePartial;
g_output.nOutImagePartial = ( g_output.nOutImagePartial + 1 ) % 3;
}
auto compositeImage = partial ? g_output.outputImagesPartialOverlay[ g_output.nOutImagePartial ] : g_output.outputImages[ g_output.nOutImage ];
auto cmdBuffer = g_device.commandBuffer();
@ -3682,18 +3742,36 @@ bool vulkan_composite( const struct FrameInfo_t *frameInfo, std::shared_ptr<CVul
}
uint64_t sequence = g_device.submit(std::move(cmdBuffer));
g_device.wait(sequence);
if ( !BIsSDLSession() )
if ( partial )
{
g_output.nOutImage = !g_output.nOutImage;
partial_wait_thread = std::make_unique<std::thread>([sequence]
{
g_device.wait(sequence);
});
}
else
{
g_device.wait(sequence);
if ( !BIsSDLSession() )
{
g_output.nOutImage = !g_output.nOutImage;
}
}
return true;
}
std::shared_ptr<CVulkanTexture> vulkan_get_last_output_image( void )
std::shared_ptr<CVulkanTexture> vulkan_get_last_output_image( bool partial )
{
if ( partial )
{
uint32_t nOutImage = g_output.nOutPresentImagePartial;
//vk_log.infof( "Partial overlay frame: %d", nOutImage );
return g_output.outputImagesPartialOverlay[ nOutImage ];
}
return g_output.outputImages[ !g_output.nOutImage ];
}

View file

@ -240,7 +240,7 @@ struct FrameInfo_t
std::shared_ptr<CVulkanTexture> shaperLut[EOTF_Count];
std::shared_ptr<CVulkanTexture> lut3D[EOTF_Count];
bool applyOutputColorMgmt;
bool applyOutputColorMgmt; // drm only
int layerCount;
struct Layer_t
@ -256,7 +256,8 @@ struct FrameInfo_t
bool blackBorder;
bool linearFilter;
bool applyColorMgmt;
bool applyColorMgmt; // drm only
bool allowBlending; // drm only
GamescopeAppTextureColorspace colorspace;
@ -315,6 +316,7 @@ namespace CompositeDebugFlag
static constexpr uint32_t Heatmap = 1u << 2;
static constexpr uint32_t Heatmap_MSWCG = 1u << 3;
static constexpr uint32_t Heatmap_Hard = 1u << 4;
static constexpr uint32_t Markers_Partial = 1u << 5;
static constexpr uint32_t Tonemap_Reinhard = 1u << 7;
};
@ -327,8 +329,8 @@ std::shared_ptr<CVulkanTexture> vulkan_create_texture_from_dmabuf( struct wlr_dm
std::shared_ptr<CVulkanTexture> vulkan_create_texture_from_bits( uint32_t width, uint32_t height, uint32_t contentWidth, uint32_t contentHeight, uint32_t drmFormat, CVulkanTexture::createFlags texCreateFlags, void *bits );
std::shared_ptr<CVulkanTexture> vulkan_create_texture_from_wlr_buffer( struct wlr_buffer *buf );
bool vulkan_composite( const struct FrameInfo_t *frameInfo, std::shared_ptr<CVulkanTexture> pScreenshotTexture );
std::shared_ptr<CVulkanTexture> vulkan_get_last_output_image( void );
bool vulkan_composite( const struct FrameInfo_t *frameInfo, std::shared_ptr<CVulkanTexture> pScreenshotTexture, bool partial );
std::shared_ptr<CVulkanTexture> vulkan_get_last_output_image( bool partial );
std::shared_ptr<CVulkanTexture> vulkan_acquire_screenshot_texture(uint32_t width, uint32_t height, bool exportable, uint32_t drmFormat, EStreamColorspace colorspace = k_EStreamColorspace_Unknown);
void vulkan_present_to_window( void );

View file

@ -14,6 +14,9 @@ void compositing_debug(uvec2 coord) {
if (pos.x >= 40 && pos.x < 120 && pos.y >= 40 && pos.y < 120) {
vec4 value = vec4(1.0f, 1.0f, 1.0f, 1.0f);
if (checkDebugFlag(compositedebug_Markers_Partial)) {
value = vec4(0.0f, 1.0f, 1.0f, 1.0f);
}
if (pos.x >= 48 && pos.x < 112 && pos.y >= 48 && pos.y < 112) {
uint random = pseudo_random(u_frameId.x + (pos.x & ~0x7) + (pos.y & ~0x7) * 50);
vec4 time = round(unpackUnorm4x8(random)).xyzw;

View file

@ -26,13 +26,14 @@ void main() {
return;
vec2 uv = vec2(coord);
vec3 outputValue = vec3(0.0f);
vec4 outputValue = vec4(0.0f);
if (checkDebugFlag(compositedebug_PlaneBorders))
outputValue = vec3(1.0f, 0.0f, 0.0f);
outputValue = vec4(1.0f, 0.0f, 0.0f, 0.0f);
if (c_layerCount > 0)
outputValue = sampleLayer(0, uv).rgb * u_opacity[0];
if (c_layerCount > 0) {
outputValue = sampleLayer(0, uv) * u_opacity[0];
}
for (int i = 1; i < c_layerCount; i++) {
vec4 layerColor = sampleLayer(i, uv);
@ -43,11 +44,11 @@ void main() {
// For the other side of things, we need to multiply by (1.0f - (layerColor.a * opacity))
float opacity = u_opacity[i];
float layerAlpha = opacity * layerColor.a;
outputValue = layerColor.rgb * opacity + outputValue * (1.0f - layerAlpha);
outputValue = layerColor * opacity + outputValue * (1.0f - layerAlpha);
}
outputValue = encodeOutputColor(outputValue);
imageStore(dst, ivec2(coord), vec4(outputValue, 0));
outputValue.rgb = encodeOutputColor(outputValue.rgb);
imageStore(dst, ivec2(coord), outputValue);
// Indicator to quickly tell if we're in the compositing path or not.
if (checkDebugFlag(compositedebug_Markers))

View file

@ -26,6 +26,7 @@ const uint compositedebug_PlaneBorders = 1u << 1;
const uint compositedebug_Heatmap = 1u << 2;
const uint compositedebug_Heatmap_MSWCG = 1u << 3; // If compositedebug_Heatmap is set, use the MS WCG heatmap instead of Lilium
const uint compositedebug_Heatmap_Hard = 1u << 4; // If compositedebug_Heatmap is set, use a heatmap with specialized hard flagging
const uint compositedebug_Markers_Partial = 1u << 5; // If compositedebug_Heatmap is set, use a heatmap with specialized hard flagging
//const uint compositedebug_Tonemap_Reinhard = 1u << 7; // Use Reinhard tonemapping instead of Uncharted.
bool checkDebugFlag(uint flag) {

View file

@ -1858,6 +1858,7 @@ void MouseCursor::paint(steamcompmgr_win_t *window, steamcompmgr_win_t *fit, str
layer->zpos = g_zposCursor; // cursor, on top of both bottom layers
layer->applyColorMgmt = false;
layer->allowBlending = true;
layer->tex = m_texture;
layer->fbid = BIsNested() ? 0 : m_texture->fbid();
@ -2093,6 +2094,7 @@ paint_window(steamcompmgr_win_t *w, steamcompmgr_win_t *scaleW, struct FrameInfo
layer->blackBorder = flags & PaintWindowFlag::DrawBorders;
layer->applyColorMgmt = true;
layer->allowBlending = true;
layer->zpos = g_zposBase;
if ( w != scaleW )
@ -2401,17 +2403,18 @@ paint_all(bool async)
bool bNeedsNearest = g_upscaleFilter == GamescopeUpscaleFilter::NEAREST && frameInfo.layers[0].scale.x != 1.0f && frameInfo.layers[0].scale.y != 1.0f;
bool bWantsPartialComposite = frameInfo.layerCount >= 3;
bool bNeedsComposite = BIsNested();
bNeedsComposite |= alwaysComposite;
bNeedsComposite |= pw_buffer != nullptr;
bNeedsComposite |= bWasFirstFrame;
bNeedsComposite |= frameInfo.useFSRLayer0;
bNeedsComposite |= frameInfo.useNISLayer0;
bNeedsComposite |= frameInfo.blurLayer0;
bNeedsComposite |= bNeedsNearest;
bNeedsComposite |= bDrewCursor;
bNeedsComposite |= g_bColorSliderInUse;
bool bNeedsFullComposite = BIsNested();
bNeedsFullComposite |= alwaysComposite;
bNeedsFullComposite |= pw_buffer != nullptr;
bNeedsFullComposite |= bWasFirstFrame;
bNeedsFullComposite |= frameInfo.useFSRLayer0;
bNeedsFullComposite |= frameInfo.useNISLayer0;
bNeedsFullComposite |= frameInfo.blurLayer0;
bNeedsFullComposite |= bNeedsNearest;
bNeedsFullComposite |= bDrewCursor;
bNeedsFullComposite |= g_bColorSliderInUse;
for (uint32_t i = 0; i < EOTF_Count; i++)
{
@ -2424,17 +2427,25 @@ paint_all(bool async)
if ( !BIsNested() && g_bOutputHDREnabled )
{
bNeedsComposite |= g_bHDRItmEnable;
bNeedsFullComposite |= g_bHDRItmEnable;
if ( !drm_supports_color_mgmt(&g_DRM) )
bNeedsComposite |= ( frameInfo.layerCount > 1 || frameInfo.layers[0].colorspace != GAMESCOPE_APP_TEXTURE_COLORSPACE_HDR10_PQ );
bNeedsFullComposite |= ( frameInfo.layerCount > 1 || frameInfo.layers[0].colorspace != GAMESCOPE_APP_TEXTURE_COLORSPACE_HDR10_PQ );
}
bNeedsComposite |= !!(g_uCompositeDebug & CompositeDebugFlag::Heatmap);
bNeedsFullComposite |= !!(g_uCompositeDebug & CompositeDebugFlag::Heatmap);
if ( !bNeedsComposite )
static bool g_bWasPartialComposite = false;
static int g_nLastSingleOverlayZPos = 0;
if ( !bNeedsFullComposite && !bWantsPartialComposite )
{
int ret = drm_prepare( &g_DRM, async, &frameInfo );
if ( ret == 0 )
{
bDoComposite = false;
g_bWasPartialComposite = false;
if ( frameInfo.layerCount == 2 )
g_nLastSingleOverlayZPos = frameInfo.layers[1].zpos;
}
else if ( ret == -EACCES )
return;
}
@ -2451,7 +2462,65 @@ paint_all(bool async)
pPipewireTexture = pw_buffer->texture;
}
#endif
bool bResult = vulkan_composite( &frameInfo, pPipewireTexture );
struct FrameInfo_t compositeFrameInfo = frameInfo;
if ( compositeFrameInfo.layerCount == 1 )
{
// If we failed to flip a single plane then
// we definitely need to composite for some reason...
bNeedsFullComposite = true;
}
if ( !bNeedsFullComposite )
{
// If we want to partial composite, fallback to full
// composite if we have mismatching colorspaces in our overlays.
// This is 2, and we do i-1 so 1...layerCount. So AFTER we have removed baseplane.
// Overlays only.
//
// Josh:
// We could handle mismatching colorspaces for partial composition
// but I want to keep overlay -> partial composition promotion as simple
// as possible, using the same 3D + SHAPER LUTs + BLEND in DRM
// as changing them is incredibly expensive!! It takes forever.
// We can't just point it to random BDA or whatever, it has to be uploaded slowly
// thru registers which is SUPER SLOW.
// This avoids stutter.
for ( int i = 2; i < compositeFrameInfo.layerCount; i++ )
{
if ( frameInfo.layers[i - 1].colorspace != frameInfo.layers[i].colorspace )
{
bNeedsFullComposite = true;
break;
}
}
}
// If doing a partial composition then remove the baseplane
// from our frameinfo to composite.
if ( !bNeedsFullComposite )
{
for ( int i = 1; i < compositeFrameInfo.layerCount; i++ )
compositeFrameInfo.layers[i - 1] = compositeFrameInfo.layers[i];
compositeFrameInfo.layerCount -= 1;
// When doing partial composition, apply the shaper + 3D LUT stuff
// at scanout.
for ( uint32_t nEOTF = 0; nEOTF < EOTF_Count; nEOTF++ ) {
compositeFrameInfo.shaperLut[ nEOTF ] = nullptr;
compositeFrameInfo.lut3D[ nEOTF ] = nullptr;
}
// If using composite debug markers, make sure we mark them as partial
// so we know!
if ( g_uCompositeDebug & CompositeDebugFlag::Markers )
g_uCompositeDebug |= CompositeDebugFlag::Markers_Partial;
}
bool bResult = vulkan_composite( &compositeFrameInfo, pPipewireTexture, !bNeedsFullComposite );
g_uCompositeDebug &= ~CompositeDebugFlag::Markers_Partial;
if ( bResult != true )
{
@ -2477,23 +2546,89 @@ paint_all(bool async)
}
else
{
struct FrameInfo_t compositeFrameInfo = {};
compositeFrameInfo = {};
compositeFrameInfo.applyOutputColorMgmt = false;
compositeFrameInfo.layerCount = 1;
FrameInfo_t::Layer_t *layer = &compositeFrameInfo.layers[ 0 ];
layer->scale.x = 1.0;
layer->scale.y = 1.0;
layer->opacity = 1.0;
struct FrameInfo_t presentCompFrameInfo = {};
layer->tex = vulkan_get_last_output_image();
layer->fbid = layer->tex->fbid();
layer->applyColorMgmt = false;
if ( bNeedsFullComposite )
{
presentCompFrameInfo.applyOutputColorMxgmt = false;
presentCompFrameInfo.layerCount = 1;
layer->linearFilter = false;
layer->colorspace = g_bOutputHDREnabled ? GAMESCOPE_APP_TEXTURE_COLORSPACE_HDR10_PQ : GAMESCOPE_APP_TEXTURE_COLORSPACE_SRGB;
FrameInfo_t::Layer_t *baseLayer = &presentCompFrameInfo.layers[ 0 ];
baseLayer->scale.x = 1.0;
baseLayer->scale.y = 1.0;
baseLayer->opacity = 1.0;
baseLayer->zpos = g_zposBase;
int ret = drm_prepare( &g_DRM, async, &compositeFrameInfo );
baseLayer->tex = vulkan_get_last_output_image( false );
baseLayer->fbid = baseLayer->tex->fbid();
baseLayer->applyColorMgmt = false;
baseLayer->allowBlending = false;
baseLayer->linearFilter = false;
baseLayer->colorspace = g_bOutputHDREnabled ? GAMESCOPE_APP_TEXTURE_COLORSPACE_HDR10_PQ : GAMESCOPE_APP_TEXTURE_COLORSPACE_SRGB;
g_bWasPartialComposite = false;
}
else
{
if ( g_bWasPartialComposite )
{
presentCompFrameInfo.applyOutputColorMgmt = true;
presentCompFrameInfo.layerCount = 2;
presentCompFrameInfo.layers[ 0 ] = frameInfo.layers[ 0 ];
presentCompFrameInfo.layers[ 0 ].zpos = g_zposBase;
FrameInfo_t::Layer_t *overlayLayer = &presentCompFrameInfo.layers[ 1 ];
overlayLayer->scale.x = 1.0;
overlayLayer->scale.y = 1.0;
overlayLayer->opacity = 1.0;
overlayLayer->zpos = g_zposOverlay;
overlayLayer->tex = vulkan_get_last_output_image( true );
overlayLayer->fbid = overlayLayer->tex->fbid();
overlayLayer->applyColorMgmt = true;
overlayLayer->allowBlending = true;
overlayLayer->linearFilter = false;
// Partial composition stuff has the same colorspace.
// So read that from the composite frame info
overlayLayer->colorspace = compositeFrameInfo.layers[0].colorspace;
}
else
{
// Use whatever overlay we had last while waiting for the
// partial composition to have anything queued.
presentCompFrameInfo.applyOutputColorMgmt = true;
presentCompFrameInfo.layerCount = 1;
presentCompFrameInfo.layers[ 0 ] = frameInfo.layers[ 0 ];
presentCompFrameInfo.layers[ 0 ].zpos = g_zposBase;
FrameInfo_t::Layer_t *lastPresentedOverlayLayer = nullptr;
for (int i = 0; i < frameInfo.layerCount; i++)
{
if (frameInfo.layers[i].zpos == g_nLastSingleOverlayZPos)
{
lastPresentedOverlayLayer = &frameInfo.layers[i];
break;
}
}
if (lastPresentedOverlayLayer)
{
FrameInfo_t::Layer_t *overlayLayer = &presentCompFrameInfo.layers[ 1 ];
*overlayLayer = *lastPresentedOverlayLayer;
overlayLayer->zpos = g_zposOverlay;
presentCompFrameInfo.layerCount = 2;
}
}
g_bWasPartialComposite = true;
}
int ret = drm_prepare( &g_DRM, async, &presentCompFrameInfo );
// Happens when we're VT-switched away
if ( ret == -EACCES )