~ubuntu-branches/ubuntu/wily/mir/wily-proposed

« back to all changes in this revision

Viewing changes to src/server/graphics/gbm/real_kms_display_configuration.cpp

  • Committer: Package Import Robot
  • Author(s): Ubuntu daily release
  • Date: 2014-01-08 02:04:38 UTC
  • mto: This revision was merged to the branch mainline in revision 58.
  • Revision ID: package-import@ubuntu.com-20140108020438-e1npu0pm7qdv5wc4
Tags: upstream-0.1.3+14.04.20140108
ImportĀ upstreamĀ versionĀ 0.1.3+14.04.20140108

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 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 General Public License for more details.
12
 
 *
13
 
 * You should have received a copy of the GNU 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 mgg = mir::graphics::gbm;
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
 
mgg::RealKMSDisplayConfiguration::RealKMSDisplayConfiguration(int drm_fd)
71
 
    : drm_fd{drm_fd}
72
 
{
73
 
    update();
74
 
}
75
 
 
76
 
mgg::RealKMSDisplayConfiguration::RealKMSDisplayConfiguration(
77
 
    RealKMSDisplayConfiguration const& conf)
78
 
    : KMSDisplayConfiguration(), drm_fd{conf.drm_fd},
79
 
      card(conf.card), outputs{conf.outputs}
80
 
{
81
 
}
82
 
 
83
 
mgg::RealKMSDisplayConfiguration& mgg::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 mgg::RealKMSDisplayConfiguration::for_each_card(
97
 
    std::function<void(DisplayConfigurationCard const&)> f) const
98
 
{
99
 
    f(card);
100
 
}
101
 
 
102
 
void mgg::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 mgg::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 mgg::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 mgg::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 mgg::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 mgg::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<geom::PixelFormat> formats {geom::PixelFormat::argb_8888,
189
 
                                            geom::PixelFormat::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
 
mgg::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
 
mgg::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
 
}