1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
/*
* Copyright (C) 2005-2018 Team Kodi
* This file is part of Kodi - https://kodi.tv
*
* SPDX-License-Identifier: GPL-2.0-or-later
* See LICENSES/README.md for more information.
*/
#include "GBMUtils.h"
#include "utils/log.h"
#include <mutex>
using namespace KODI::WINDOWING::GBM;
namespace
{
std::once_flag flag;
}
bool CGBMUtils::CreateDevice(int fd)
{
auto device = gbm_create_device(fd);
if (!device)
{
CLog::Log(LOGERROR, "CGBMUtils::{} - failed to create device: {}", __FUNCTION__,
strerror(errno));
return false;
}
m_device.reset(new CGBMDevice(device));
return true;
}
CGBMUtils::CGBMDevice::CGBMDevice(gbm_device* device) : m_device(device)
{
}
bool CGBMUtils::CGBMDevice::CreateSurface(
int width, int height, uint32_t format, const uint64_t* modifiers, const int modifiers_count)
{
gbm_surface* surface{nullptr};
#if defined(HAS_GBM_MODIFIERS)
if (modifiers)
{
surface = gbm_surface_create_with_modifiers(m_device, width, height, format, modifiers,
modifiers_count);
}
#endif
if (!surface)
{
surface = gbm_surface_create(m_device, width, height, format,
GBM_BO_USE_SCANOUT | GBM_BO_USE_RENDERING);
}
if (!surface)
{
CLog::Log(LOGERROR, "CGBMUtils::{} - failed to create surface: {}", __FUNCTION__,
strerror(errno));
return false;
}
CLog::Log(LOGDEBUG, "CGBMUtils::{} - created surface with size {}x{}", __FUNCTION__, width,
height);
m_surface.reset(new CGBMSurface(surface));
return true;
}
CGBMUtils::CGBMDevice::CGBMSurface::CGBMSurface(gbm_surface* surface) : m_surface(surface)
{
}
CGBMUtils::CGBMDevice::CGBMSurface::CGBMSurfaceBuffer* CGBMUtils::CGBMDevice::CGBMSurface::
LockFrontBuffer()
{
m_buffers.emplace(std::make_unique<CGBMSurfaceBuffer>(m_surface));
if (!static_cast<bool>(gbm_surface_has_free_buffers(m_surface)))
{
/*
* We want to use call_once here because we want it to be logged the first time that
* we have to release buffers. This means that the maximum amount of buffers had been reached.
* For mesa this should be 4 buffers but it may vary across other implementations.
*/
std::call_once(
flag, [this]() { CLog::Log(LOGDEBUG, "CGBMUtils - using {} buffers", m_buffers.size()); });
m_buffers.pop();
}
return m_buffers.back().get();
}
CGBMUtils::CGBMDevice::CGBMSurface::CGBMSurfaceBuffer::CGBMSurfaceBuffer(gbm_surface* surface)
: m_surface(surface), m_buffer(gbm_surface_lock_front_buffer(surface))
{
}
CGBMUtils::CGBMDevice::CGBMSurface::CGBMSurfaceBuffer::~CGBMSurfaceBuffer()
{
if (m_surface && m_buffer)
gbm_surface_release_buffer(m_surface, m_buffer);
}
|