~hikiko/mir/mir.unity8-desktop-session

« back to all changes in this revision

Viewing changes to src/platform/graphics/mesa/real_kms_display_configuration.cpp

  • Committer: Package Import Robot
  • Author(s): Ubuntu daily release, Daniel van Vugt, Ubuntu daily release
  • Date: 2014-01-08 02:04:38 UTC
  • mfrom: (1.1.54)
  • Revision ID: package-import@ubuntu.com-20140108020438-ikbu7qqm9v2l026y
Tags: 0.1.3+14.04.20140108-0ubuntu1
[ Daniel van Vugt ]
* Preparing for release 0.1.3

[ Ubuntu daily release ]
* Automatic snapshot from revision 1170

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright © 2013 Canonical Ltd.
 
3
 *
 
4
 * This program is free software: you can redistribute it and/or modify it
 
5
 * under the terms of the GNU Lesser General Public License version 3,
 
6
 * as published by the Free Software Foundation.
 
7
 *
 
8
 * This program is distributed in the hope that it will be useful,
 
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
11
 * GNU Lesser General Public License for more details.
 
12
 *
 
13
 * You should have received a copy of the GNU Lesser General Public License
 
14
 * along with this program. If not, see <http://www.gnu.org/licenses/>.
 
15
 *
 
16
 * Authored by: Alexandros Frantzis <alexandros.frantzis@canonical.com>
 
17
 */
 
18
 
 
19
#include "real_kms_display_configuration.h"
 
20
#include "drm_mode_resources.h"
 
21
 
 
22
#include <cmath>
 
23
#include <limits>
 
24
 
 
25
#include <boost/throw_exception.hpp>
 
26
#include <stdexcept>
 
27
#include <algorithm>
 
28
 
 
29
namespace mg = mir::graphics;
 
30
namespace mgm = mir::graphics::mesa;
 
31
namespace geom = mir::geometry;
 
32
 
 
33
namespace
 
34
{
 
35
 
 
36
bool kms_modes_are_equal(drmModeModeInfo const& info1, drmModeModeInfo const& info2)
 
37
{
 
38
    return (info1.clock == info2.clock &&
 
39
            info1.hdisplay == info2.hdisplay &&
 
40
            info1.hsync_start == info2.hsync_start &&
 
41
            info1.hsync_end == info2.hsync_end &&
 
42
            info1.htotal == info2.htotal &&
 
43
            info1.hskew == info2.hskew &&
 
44
            info1.vdisplay == info2.vdisplay &&
 
45
            info1.vsync_start == info2.vsync_start &&
 
46
            info1.vsync_end == info2.vsync_end &&
 
47
            info1.vtotal == info2.vtotal);
 
48
}
 
49
 
 
50
double calculate_vrefresh_hz(drmModeModeInfo const& mode)
 
51
{
 
52
    if (mode.htotal == 0 || mode.vtotal == 0)
 
53
        return 0.0;
 
54
 
 
55
    /* mode.clock is in KHz */
 
56
    double vrefresh_hz = mode.clock * 1000.0 / (mode.htotal * mode.vtotal);
 
57
 
 
58
    /* Round to first decimal */
 
59
    return round(vrefresh_hz * 10.0) / 10.0;
 
60
}
 
61
 
 
62
mg::DisplayConfigurationOutputType
 
63
kms_connector_type_to_output_type(uint32_t connector_type)
 
64
{
 
65
    return static_cast<mg::DisplayConfigurationOutputType>(connector_type);
 
66
}
 
67
 
 
68
}
 
69
 
 
70
mgm::RealKMSDisplayConfiguration::RealKMSDisplayConfiguration(int drm_fd)
 
71
    : drm_fd{drm_fd}
 
72
{
 
73
    update();
 
74
}
 
75
 
 
76
mgm::RealKMSDisplayConfiguration::RealKMSDisplayConfiguration(
 
77
    RealKMSDisplayConfiguration const& conf)
 
78
    : KMSDisplayConfiguration(), drm_fd{conf.drm_fd},
 
79
      card(conf.card), outputs{conf.outputs}
 
80
{
 
81
}
 
82
 
 
83
mgm::RealKMSDisplayConfiguration& mgm::RealKMSDisplayConfiguration::operator=(
 
84
    RealKMSDisplayConfiguration const& conf)
 
85
{
 
86
    if (&conf != this)
 
87
    {
 
88
        drm_fd = conf.drm_fd;
 
89
        card = conf.card;
 
90
        outputs = conf.outputs;
 
91
    }
 
92
 
 
93
    return *this;
 
94
}
 
95
 
 
96
void mgm::RealKMSDisplayConfiguration::for_each_card(
 
97
    std::function<void(DisplayConfigurationCard const&)> f) const
 
98
{
 
99
    f(card);
 
100
}
 
101
 
 
102
void mgm::RealKMSDisplayConfiguration::for_each_output(
 
103
    std::function<void(DisplayConfigurationOutput const&)> f) const
 
104
{
 
105
    for (auto const& output : outputs)
 
106
        f(output);
 
107
}
 
108
 
 
109
void mgm::RealKMSDisplayConfiguration::configure_output(
 
110
    DisplayConfigurationOutputId id, bool used,
 
111
    geometry::Point top_left, size_t mode_index,
 
112
    MirPowerMode power_mode)
 
113
{
 
114
    auto iter = find_output_with_id(id);
 
115
 
 
116
    if (iter != outputs.end())
 
117
    {
 
118
        auto& output = *iter;
 
119
 
 
120
        if (used && mode_index >= output.modes.size())
 
121
            BOOST_THROW_EXCEPTION(std::runtime_error("Invalid mode_index for used output"));
 
122
 
 
123
        output.used = used;
 
124
        output.top_left = top_left;
 
125
        output.current_mode_index = mode_index;
 
126
        output.power_mode = power_mode;
 
127
    }
 
128
    else
 
129
    {
 
130
        BOOST_THROW_EXCEPTION(std::runtime_error("Trying to configure invalid output"));
 
131
    }
 
132
}
 
133
 
 
134
uint32_t mgm::RealKMSDisplayConfiguration::get_kms_connector_id(
 
135
    DisplayConfigurationOutputId id) const
 
136
{
 
137
    auto iter = find_output_with_id(id);
 
138
 
 
139
    if (iter == outputs.end())
 
140
    {
 
141
        BOOST_THROW_EXCEPTION(
 
142
            std::runtime_error("Failed to find DisplayConfigurationOutput with provided id"));
 
143
    }
 
144
 
 
145
    return id.as_value();
 
146
}
 
147
 
 
148
size_t mgm::RealKMSDisplayConfiguration::get_kms_mode_index(
 
149
    DisplayConfigurationOutputId id,
 
150
    size_t conf_mode_index) const
 
151
{
 
152
    auto iter = find_output_with_id(id);
 
153
 
 
154
    if (iter == outputs.end() || conf_mode_index >= iter->modes.size())
 
155
    {
 
156
        BOOST_THROW_EXCEPTION(
 
157
            std::runtime_error("Failed to find valid mode index for DisplayConfigurationOutput with provided id/mode_index"));
 
158
    }
 
159
 
 
160
    return conf_mode_index;
 
161
}
 
162
void mgm::RealKMSDisplayConfiguration::update()
 
163
{
 
164
    DRMModeResources resources{drm_fd};
 
165
 
 
166
    size_t max_outputs = std::min(resources.num_crtcs(), resources.num_connectors());
 
167
    card = {mg::DisplayConfigurationCardId{0}, max_outputs};
 
168
 
 
169
    resources.for_each_connector([&](DRMModeConnectorUPtr connector)
 
170
    {
 
171
        add_or_update_output(resources, *connector);
 
172
    });
 
173
}
 
174
 
 
175
void mgm::RealKMSDisplayConfiguration::add_or_update_output(
 
176
    DRMModeResources const& resources,
 
177
    drmModeConnector const& connector)
 
178
{
 
179
    DisplayConfigurationOutputId id{static_cast<int>(connector.connector_id)};
 
180
    DisplayConfigurationCardId card_id{0};
 
181
    DisplayConfigurationOutputType const type{
 
182
        kms_connector_type_to_output_type(connector.connector_type)};
 
183
    geom::Size physical_size{connector.mmWidth, connector.mmHeight};
 
184
    bool connected{connector.connection == DRM_MODE_CONNECTED};
 
185
    size_t current_mode_index{std::numeric_limits<size_t>::max()};
 
186
    size_t preferred_mode_index{std::numeric_limits<size_t>::max()};
 
187
    std::vector<DisplayConfigurationMode> modes;
 
188
    std::vector<MirPixelFormat> formats {mir_pixel_format_argb_8888,
 
189
                                         mir_pixel_format_xrgb_8888};
 
190
 
 
191
    drmModeModeInfo current_mode_info = drmModeModeInfo();
 
192
 
 
193
    /* Get information about the current mode */
 
194
    auto encoder = resources.encoder(connector.encoder_id);
 
195
    if (encoder)
 
196
    {
 
197
        auto crtc = resources.crtc(encoder->crtc_id);
 
198
        if (crtc)
 
199
            current_mode_info = crtc->mode;
 
200
    }
 
201
 
 
202
    /* Add all the available modes and find the current and preferred one */
 
203
    for (int m = 0; m < connector.count_modes; m++)
 
204
    {
 
205
        drmModeModeInfo& mode_info = connector.modes[m];
 
206
 
 
207
        geom::Size size{mode_info.hdisplay, mode_info.vdisplay};
 
208
 
 
209
        double vrefresh_hz = calculate_vrefresh_hz(mode_info);
 
210
 
 
211
        modes.push_back({size, vrefresh_hz});
 
212
 
 
213
        if (kms_modes_are_equal(mode_info, current_mode_info))
 
214
            current_mode_index = m;
 
215
 
 
216
        if ((mode_info.type & DRM_MODE_TYPE_PREFERRED) == DRM_MODE_TYPE_PREFERRED)
 
217
            preferred_mode_index = m;
 
218
    }
 
219
 
 
220
    /* Add or update the output */
 
221
    auto iter = find_output_with_id(id);
 
222
 
 
223
    if (iter == outputs.end())
 
224
    {
 
225
        outputs.push_back({id, card_id, type, formats, modes, preferred_mode_index,
 
226
                           physical_size, connected, false, geom::Point(),
 
227
                           current_mode_index, 0u, mir_power_mode_on});
 
228
    }
 
229
    else
 
230
    {
 
231
        auto& output = *iter;
 
232
 
 
233
        output.modes = modes;
 
234
        output.preferred_mode_index = preferred_mode_index;
 
235
        output.physical_size_mm = physical_size;
 
236
        output.connected = connected;
 
237
        output.current_mode_index = current_mode_index;
 
238
    }
 
239
}
 
240
 
 
241
std::vector<mg::DisplayConfigurationOutput>::iterator
 
242
mgm::RealKMSDisplayConfiguration::find_output_with_id(DisplayConfigurationOutputId id)
 
243
{
 
244
    return std::find_if(outputs.begin(), outputs.end(),
 
245
                        [id](DisplayConfigurationOutput const& output)
 
246
                        {
 
247
                            return output.id == id;
 
248
                        });
 
249
}
 
250
 
 
251
std::vector<mg::DisplayConfigurationOutput>::const_iterator
 
252
mgm::RealKMSDisplayConfiguration::find_output_with_id(DisplayConfigurationOutputId id) const
 
253
{
 
254
    return std::find_if(outputs.begin(), outputs.end(),
 
255
                        [id](DisplayConfigurationOutput const& output)
 
256
                        {
 
257
                            return output.id == id;
 
258
                        });
 
259
}