~vanvugt/mir/fix-1583532

« back to all changes in this revision

Viewing changes to src/platforms/mesa/server/kms/real_kms_output.cpp

  • Committer: Daniel van Vugt
  • Date: 2016-05-26 02:12:27 UTC
  • mfrom: (3515.2.8 development-branch)
  • Revision ID: daniel.van.vugt@canonical.com-20160526021227-mimlsa3hpy4o7hiv
Merge latest trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
#include "real_kms_output.h"
20
20
#include "page_flipper.h"
 
21
#include "kms-utils/kms_connector.h"
21
22
#include "mir/fatal.h"
22
23
#include "mir/log.h"
23
24
#include <string.h> // strcmp
24
25
 
25
26
namespace mg = mir::graphics;
26
27
namespace mgm = mg::mesa;
 
28
namespace mgk = mg::kms;
27
29
namespace geom = mir::geometry;
28
30
 
29
 
namespace
30
 
{
31
 
 
32
 
bool encoder_is_used(mgm::DRMModeResources const& resources, uint32_t encoder_id)
33
 
{
34
 
    bool encoder_used{false};
35
 
 
36
 
    resources.for_each_connector([&](mgm::DRMModeConnectorUPtr connector)
37
 
    {
38
 
        if (connector->encoder_id == encoder_id &&
39
 
            connector->connection == DRM_MODE_CONNECTED)
40
 
        {
41
 
            auto encoder = resources.encoder(connector->encoder_id);
42
 
            if (encoder)
43
 
            {
44
 
                auto crtc = resources.crtc(encoder->crtc_id);
45
 
                if (crtc)
46
 
                    encoder_used = true;
47
 
            }
48
 
        }
49
 
    });
50
 
 
51
 
    return encoder_used;
52
 
}
53
 
 
54
 
bool crtc_is_used(mgm::DRMModeResources const& resources, uint32_t crtc_id)
55
 
{
56
 
    bool crtc_used{false};
57
 
 
58
 
    resources.for_each_connector([&](mgm::DRMModeConnectorUPtr connector)
59
 
    {
60
 
        if (connector->connection == DRM_MODE_CONNECTED)
61
 
        {
62
 
            auto encoder = resources.encoder(connector->encoder_id);
63
 
            if (encoder)
64
 
            {
65
 
                if (encoder->crtc_id == crtc_id)
66
 
                    crtc_used = true;
67
 
            }
68
 
        }
69
 
    });
70
 
 
71
 
    return crtc_used;
72
 
}
73
 
 
74
 
std::vector<mgm::DRMModeEncoderUPtr>
75
 
connector_available_encoders(mgm::DRMModeResources const& resources,
76
 
                             drmModeConnector const* connector)
77
 
{
78
 
    std::vector<mgm::DRMModeEncoderUPtr> encoders;
79
 
 
80
 
    for (int i = 0; i < connector->count_encoders; i++)
81
 
    {
82
 
        if (!encoder_is_used(resources, connector->encoders[i]))
83
 
            encoders.push_back(resources.encoder(connector->encoders[i]));
84
 
    }
85
 
 
86
 
    return encoders;
87
 
}
88
 
 
89
 
bool encoder_supports_crtc_index(drmModeEncoder const* encoder, uint32_t crtc_index)
90
 
{
91
 
    return (encoder->possible_crtcs & (1 << crtc_index));
92
 
}
93
 
 
94
 
const char *connector_type_name(uint32_t type)
95
 
{
96
 
    static const int nnames = 15;
97
 
    static const char * const names[nnames] =
98
 
    {   // Ordered according to xf86drmMode.h
99
 
        "Unknown",
100
 
        "VGA",
101
 
        "DVII",
102
 
        "DVID",
103
 
        "DVIA",
104
 
        "Composite",
105
 
        "SVIDEO",
106
 
        "LVDS",
107
 
        "Component",
108
 
        "9PinDIN",
109
 
        "DisplayPort",
110
 
        "HDMIA",
111
 
        "HDMIB",
112
 
        "TV",
113
 
        "eDP"
114
 
    };
115
 
 
116
 
    if (type >= nnames)
117
 
        type = 0;
118
 
 
119
 
    return names[type];
120
 
}
121
 
 
122
 
std::string connector_name(const drmModeConnector *conn)
123
 
{
124
 
    std::string name = connector_type_name(conn->connector_type);
125
 
    name += '-';
126
 
    name += std::to_string(conn->connector_type_id);
127
 
    return name;
128
 
}
129
 
 
130
 
}
131
 
 
132
31
mgm::RealKMSOutput::RealKMSOutput(int drm_fd, uint32_t connector_id,
133
32
                                  std::shared_ptr<PageFlipper> const& page_flipper)
134
33
    : drm_fd{drm_fd}, connector_id{connector_id}, page_flipper{page_flipper},
138
37
{
139
38
    reset();
140
39
 
141
 
    DRMModeResources resources{drm_fd};
 
40
    kms::DRMModeResources resources{drm_fd};
142
41
 
143
 
    auto encoder = resources.encoder(connector->encoder_id);
144
 
    if (encoder)
 
42
    if (connector->encoder_id)
145
43
    {
146
 
        auto crtc = resources.crtc(encoder->crtc_id);
147
 
        if (crtc)
148
 
            saved_crtc = *crtc;
 
44
        auto encoder = resources.encoder(connector->encoder_id);
 
45
        if (encoder->crtc_id)
 
46
        {
 
47
            saved_crtc = *resources.crtc(encoder->crtc_id);
 
48
        }
149
49
    }
150
50
}
151
51
 
156
56
 
157
57
void mgm::RealKMSOutput::reset()
158
58
{
159
 
    DRMModeResources resources{drm_fd};
 
59
    kms::DRMModeResources resources{drm_fd};
160
60
 
161
61
    /* Update the connector to ensure we have the latest information */
162
 
    connector = resources.connector(connector_id);
163
 
 
164
 
    if (!connector)
165
 
        fatal_error("No DRM connector found");
 
62
    try
 
63
    {
 
64
        connector = resources.connector(connector_id);
 
65
    }
 
66
    catch (std::exception const& e)
 
67
    {
 
68
        fatal_error(e.what());
 
69
    }
166
70
 
167
71
    // TODO: What if we can't locate the DPMS property?
168
72
    for (int i = 0; i < connector->count_props; i++)
208
112
    if (!ensure_crtc())
209
113
    {
210
114
        fatal_error("Output %s has no associated CRTC to set a framebuffer on",
211
 
                    connector_name(connector.get()).c_str());
 
115
                    mgk::connector_name(connector).c_str());
212
116
    }
213
117
 
214
118
    auto ret = drmModeSetCrtc(drm_fd, current_crtc->crtc_id,
227
131
 
228
132
void mgm::RealKMSOutput::clear_crtc()
229
133
{
230
 
    /*
231
 
     * In order to actually clear the output, we need to have a crtc
232
 
     * connected to the output/connector so that we can disconnect
233
 
     * it. However, not being able to get a crtc is OK, since it means
234
 
     * that the output cannot be displaying anything anyway.
235
 
     */
236
 
    if (!ensure_crtc())
 
134
    try
 
135
    {
 
136
        ensure_crtc();
 
137
    }
 
138
    catch (...)
 
139
    {
 
140
        /*
 
141
         * In order to actually clear the output, we need to have a crtc
 
142
         * connected to the output/connector so that we can disconnect
 
143
         * it. However, not being able to get a crtc is OK, since it means
 
144
         * that the output cannot be displaying anything anyway.
 
145
         */
237
146
        return;
 
147
    }
238
148
 
239
149
    auto result = drmModeSetCrtc(drm_fd, current_crtc->crtc_id,
240
150
                                 0, 0, 0, nullptr, 0, nullptr);
241
151
    if (result)
242
152
    {
243
153
        fatal_error("Couldn't clear output %s (drmModeSetCrtc = %d)",
244
 
                   connector_name(connector.get()).c_str(), result);
 
154
                   mgk::connector_name(connector).c_str(), result);
245
155
    }
246
156
 
247
157
    current_crtc = nullptr;
255
165
    if (!current_crtc)
256
166
    {
257
167
        fatal_error("Output %s has no associated CRTC to schedule page flips on",
258
 
                   connector_name(connector.get()).c_str());
 
168
                   mgk::connector_name(connector).c_str());
259
169
    }
260
170
    return page_flipper->schedule_flip(current_crtc->crtc_id, fb_id);
261
171
}
268
178
    if (!current_crtc)
269
179
    {
270
180
        fatal_error("Output %s has no associated CRTC to wait on",
271
 
                   connector_name(connector.get()).c_str());
 
181
                   mgk::connector_name(connector).c_str());
272
182
    }
273
183
    page_flipper->wait_for_flip(current_crtc->crtc_id);
274
184
}
334
244
    if (connector->connection != DRM_MODE_CONNECTED)
335
245
        return false;
336
246
 
337
 
    DRMModeResources resources{drm_fd};
338
 
 
339
 
    /* Check to see if there is a crtc already connected */
340
 
    auto encoder = resources.encoder(connector->encoder_id);
341
 
    if (encoder)
342
 
        current_crtc = resources.crtc(encoder->crtc_id);
343
 
 
344
 
    /* If we don't have a current crtc, try to find one */
345
 
    if (!current_crtc)
346
 
    {
347
 
        auto available_encoders = connector_available_encoders(resources, connector.get());
348
 
 
349
 
        int crtc_index = 0;
350
 
 
351
 
        resources.for_each_crtc([&](DRMModeCrtcUPtr crtc)
352
 
        {
353
 
            if (!current_crtc && !crtc_is_used(resources, crtc->crtc_id))
354
 
            {
355
 
                for (auto& enc : available_encoders)
356
 
                {
357
 
                    if (encoder_supports_crtc_index(enc.get(), crtc_index))
358
 
                    {
359
 
                        current_crtc = std::move(crtc);
360
 
                        break;
361
 
                    }
362
 
                }
363
 
            }
364
 
 
365
 
            crtc_index++;
366
 
        });
367
 
    }
 
247
    current_crtc = mgk::find_crtc_for_connector(drm_fd, connector);
 
248
 
368
249
 
369
250
    return (current_crtc != nullptr);
370
251
}