[videodb] remove unused seasons table from episode_view
[xbmc.git] / xbmc / windowing / gbm / drm / DRMAtomic.cpp
blobff7f137d60e656845bef96dfc87f277783b78bd8
1 /*
2 * Copyright (C) 2005-2018 Team Kodi
3 * This file is part of Kodi - https://kodi.tv
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 * See LICENSES/README.md for more information.
7 */
9 #include "DRMAtomic.h"
11 #include "ServiceBroker.h"
12 #include "guilib/GUIComponent.h"
13 #include "guilib/GUIWindowManager.h"
14 #include "settings/Settings.h"
15 #include "settings/SettingsComponent.h"
16 #include "settings/lib/Setting.h"
17 #include "utils/log.h"
19 #include <errno.h>
20 #include <string.h>
22 #include <drm_fourcc.h>
23 #include <drm_mode.h>
24 #include <unistd.h>
26 using namespace KODI::WINDOWING::GBM;
28 namespace
31 const auto SETTING_VIDEOSCREEN_HW_SCALING_FILTER = "videoscreen.hwscalingfilter";
33 uint32_t GetScalingFactor(uint32_t srcWidth,
34 uint32_t srcHeight,
35 uint32_t destWidth,
36 uint32_t destHeight)
38 uint32_t factor_W = destWidth / srcWidth;
39 uint32_t factor_H = destHeight / srcHeight;
40 if (factor_W != factor_H)
41 return (factor_W < factor_H) ? factor_W : factor_H;
42 return factor_W;
45 } // namespace
47 bool CDRMAtomic::SetScalingFilter(CDRMObject* object, const char* name, const char* type)
49 std::optional<uint64_t> scalingFilter = m_gui_plane->GetPropertyValue(name, type);
50 if (!scalingFilter)
51 return false;
53 if (!AddProperty(object, name, scalingFilter.value()))
54 return false;
56 uint32_t mar_scale_factor =
57 GetScalingFactor(m_width, m_height, m_mode->hdisplay, m_mode->vdisplay);
58 AddProperty(object, "CRTC_W", (mar_scale_factor * m_width));
59 AddProperty(object, "CRTC_H", (mar_scale_factor * m_height));
61 return true;
64 void CDRMAtomic::DrmAtomicCommit(int fb_id, int flags, bool rendered, bool videoLayer)
66 uint32_t blob_id;
68 if (flags & DRM_MODE_ATOMIC_ALLOW_MODESET)
70 if (!AddProperty(m_connector, "CRTC_ID", m_crtc->GetCrtcId()))
71 return;
73 if (drmModeCreatePropertyBlob(m_fd, m_mode, sizeof(*m_mode), &blob_id) != 0)
74 return;
76 if (m_active && m_orig_crtc && m_orig_crtc->GetCrtcId() != m_crtc->GetCrtcId())
78 // if using a different CRTC than the original, disable original to avoid EINVAL
79 if (!AddProperty(m_orig_crtc, "MODE_ID", 0))
80 return;
82 if (!AddProperty(m_orig_crtc, "ACTIVE", 0))
83 return;
86 if (!AddProperty(m_crtc, "MODE_ID", blob_id))
87 return;
89 if (!AddProperty(m_crtc, "ACTIVE", m_active ? 1 : 0))
90 return;
93 if (rendered)
95 AddProperty(m_gui_plane, "FB_ID", fb_id);
96 AddProperty(m_gui_plane, "CRTC_ID", m_crtc->GetCrtcId());
97 AddProperty(m_gui_plane, "SRC_X", 0);
98 AddProperty(m_gui_plane, "SRC_Y", 0);
99 AddProperty(m_gui_plane, "SRC_W", m_width << 16);
100 AddProperty(m_gui_plane, "SRC_H", m_height << 16);
101 AddProperty(m_gui_plane, "CRTC_X", 0);
102 AddProperty(m_gui_plane, "CRTC_Y", 0);
103 //! @todo: disabled until upstream kernel changes are merged
104 // if (DisplayHardwareScalingEnabled())
105 // {
106 // SetScalingFilter(m_gui_plane, "SCALING_FILTER", "Nearest Neighbor");
107 // }
108 // else
110 AddProperty(m_gui_plane, "CRTC_W", m_mode->hdisplay);
111 AddProperty(m_gui_plane, "CRTC_H", m_mode->vdisplay);
114 if (m_inFenceFd != -1)
116 AddProperty(m_crtc, "OUT_FENCE_PTR", reinterpret_cast<uint64_t>(&m_outFenceFd));
117 AddProperty(m_gui_plane, "IN_FENCE_FD", m_inFenceFd);
120 else if (videoLayer && !CServiceBroker::GetGUI()->GetWindowManager().HasVisibleControls())
122 // disable gui plane when video layer is active and gui has no visible controls
123 AddProperty(m_gui_plane, "FB_ID", 0);
124 AddProperty(m_gui_plane, "CRTC_ID", 0);
127 if (CServiceBroker::GetLogging().CanLogComponent(LOGWINDOWING))
128 m_req->LogAtomicRequest();
130 auto ret = drmModeAtomicCommit(m_fd, m_req->Get(), flags | DRM_MODE_ATOMIC_TEST_ONLY, nullptr);
131 if (ret < 0)
133 CLog::Log(LOGERROR,
134 "CDRMAtomic::{} - test commit failed: ({}) - falling back to last successful atomic "
135 "request",
136 __FUNCTION__, strerror(errno));
138 auto oldRequest = m_atomicRequestQueue.front().get();
139 CDRMAtomicRequest::LogAtomicDiff(m_req, oldRequest);
140 m_req = oldRequest;
142 // update the old atomic request with the new fb id to avoid tearing
143 if (rendered)
144 AddProperty(m_gui_plane, "FB_ID", fb_id);
147 ret = drmModeAtomicCommit(m_fd, m_req->Get(), flags, nullptr);
148 if (ret < 0)
150 CLog::Log(LOGERROR, "CDRMAtomic::{} - atomic commit failed: {}", __FUNCTION__,
151 strerror(errno));
154 if (m_inFenceFd != -1)
156 close(m_inFenceFd);
157 m_inFenceFd = -1;
160 if (flags & DRM_MODE_ATOMIC_ALLOW_MODESET)
162 if (drmModeDestroyPropertyBlob(m_fd, blob_id) != 0)
163 CLog::Log(LOGERROR, "CDRMAtomic::{} - failed to destroy property blob: {}", __FUNCTION__,
164 strerror(errno));
167 if (m_atomicRequestQueue.size() > 1)
168 m_atomicRequestQueue.pop_back();
170 m_atomicRequestQueue.emplace_back(std::make_unique<CDRMAtomicRequest>());
171 m_req = m_atomicRequestQueue.back().get();
174 void CDRMAtomic::FlipPage(struct gbm_bo* bo, bool rendered, bool videoLayer, bool async)
176 struct drm_fb *drm_fb = nullptr;
177 uint32_t flags = 0;
179 if (rendered)
181 if (videoLayer)
182 m_gui_plane->SetFormat(CDRMUtils::FourCCWithAlpha(m_gui_plane->GetFormat()));
183 else
184 m_gui_plane->SetFormat(CDRMUtils::FourCCWithoutAlpha(m_gui_plane->GetFormat()));
186 drm_fb = CDRMUtils::DrmFbGetFromBo(bo);
187 if (!drm_fb)
189 CLog::Log(LOGERROR, "CDRMAtomic::{} - Failed to get a new FBO", __FUNCTION__);
190 return;
193 if (async && !m_need_modeset)
194 flags |= DRM_MODE_ATOMIC_NONBLOCK;
197 if (m_need_modeset)
199 flags |= DRM_MODE_ATOMIC_ALLOW_MODESET;
200 m_need_modeset = false;
201 CLog::Log(LOGDEBUG, "CDRMAtomic::{} - Execute modeset at next commit", __FUNCTION__);
204 DrmAtomicCommit(!drm_fb ? 0 : drm_fb->fb_id, flags, rendered, videoLayer);
207 bool CDRMAtomic::InitDrm()
209 if (!CDRMUtils::OpenDrm(true))
210 return false;
212 auto ret = drmSetClientCap(m_fd, DRM_CLIENT_CAP_ATOMIC, 1);
213 if (ret)
215 CLog::Log(LOGERROR, "CDRMAtomic::{} - no atomic modesetting support: {}", __FUNCTION__,
216 strerror(errno));
217 return false;
220 m_atomicRequestQueue.emplace_back(std::make_unique<CDRMAtomicRequest>());
221 m_req = m_atomicRequestQueue.back().get();
223 if (!CDRMUtils::InitDrm())
224 return false;
226 for (auto& plane : m_planes)
228 AddProperty(plane.get(), "FB_ID", 0);
229 AddProperty(plane.get(), "CRTC_ID", 0);
232 CLog::Log(LOGDEBUG, "CDRMAtomic::{} - initialized atomic DRM", __FUNCTION__);
234 //! @todo: disabled until upstream kernel changes are merged
235 // if (m_gui_plane->SupportsProperty("SCALING_FILTER"))
236 // {
237 // const std::shared_ptr<CSettings> settings =
238 // CServiceBroker::GetSettingsComponent()->GetSettings();
239 // settings->GetSetting(SETTING_VIDEOSCREEN_HW_SCALING_FILTER)->SetVisible(true);
240 // }
242 return true;
245 void CDRMAtomic::DestroyDrm()
247 CDRMUtils::DestroyDrm();
250 bool CDRMAtomic::SetVideoMode(const RESOLUTION_INFO& res, struct gbm_bo *bo)
252 m_need_modeset = true;
254 return true;
257 bool CDRMAtomic::SetActive(bool active)
259 m_need_modeset = true;
260 m_active = active;
262 return true;
265 bool CDRMAtomic::AddProperty(CDRMObject* object, const char* name, uint64_t value)
267 return m_req->AddProperty(object, name, value);
270 bool CDRMAtomic::DisplayHardwareScalingEnabled()
272 auto settings = CServiceBroker::GetSettingsComponent()->GetSettings();
274 if (settings && settings->GetBool(SETTING_VIDEOSCREEN_HW_SCALING_FILTER))
275 return true;
277 return false;
280 CDRMAtomic::CDRMAtomicRequest::CDRMAtomicRequest() : m_atomicRequest(drmModeAtomicAlloc())
284 bool CDRMAtomic::CDRMAtomicRequest::AddProperty(CDRMObject* object, const char* name, uint64_t value)
286 uint32_t propertyId = object->GetPropertyId(name);
287 if (propertyId == 0)
288 return false;
290 int ret = drmModeAtomicAddProperty(m_atomicRequest.get(), object->GetId(), propertyId, value);
291 if (ret < 0)
292 return false;
294 m_atomicRequestItems[object][propertyId] = value;
295 return true;
298 void CDRMAtomic::CDRMAtomicRequest::LogAtomicDiff(CDRMAtomicRequest* current,
299 CDRMAtomicRequest* old)
301 std::map<CDRMObject*, std::map<uint32_t, uint64_t>> atomicDiff;
303 for (const auto& object : current->m_atomicRequestItems)
305 auto sameObject = old->m_atomicRequestItems.find(object.first);
306 if (sameObject != old->m_atomicRequestItems.end())
308 std::map<uint32_t, uint64_t> propertyDiff;
310 std::set_difference(current->m_atomicRequestItems[object.first].begin(),
311 current->m_atomicRequestItems[object.first].end(),
312 old->m_atomicRequestItems[object.first].begin(),
313 old->m_atomicRequestItems[object.first].end(),
314 std::inserter(propertyDiff, propertyDiff.begin()));
316 atomicDiff[object.first] = propertyDiff;
318 else
320 atomicDiff[object.first] = current->m_atomicRequestItems[object.first];
324 CLog::Log(LOGDEBUG, "CDRMAtomicRequest::{} - DRM Atomic Request Diff:", __FUNCTION__);
326 LogAtomicRequest(LOGERROR, atomicDiff);
329 void CDRMAtomic::CDRMAtomicRequest::LogAtomicRequest()
331 CLog::Log(LOGDEBUG, "CDRMAtomicRequest::{} - DRM Atomic Request:", __FUNCTION__);
332 LogAtomicRequest(LOGDEBUG, m_atomicRequestItems);
335 void CDRMAtomic::CDRMAtomicRequest::LogAtomicRequest(
336 uint8_t logLevel, std::map<CDRMObject*, std::map<uint32_t, uint64_t>>& atomicRequestItems)
338 std::string message;
339 for (const auto& object : atomicRequestItems)
341 message.append("\nObject: " + object.first->GetTypeName() +
342 "\tID: " + std::to_string(object.first->GetId()));
343 for (const auto& property : object.second)
344 message.append("\n Property: " + object.first->GetPropertyName(property.first) +
345 "\tID: " + std::to_string(property.first) +
346 "\tValue: " + std::to_string(property.second));
349 CLog::Log(logLevel, "{}", message);
352 void CDRMAtomic::CDRMAtomicRequest::DrmModeAtomicReqDeleter::operator()(drmModeAtomicReqPtr p) const
354 drmModeAtomicFree(p);