~alan-griffiths/mir/fix-1654023

« back to all changes in this revision

Viewing changes to src/client/mir_surface.cpp

  • Committer: Daniel van Vugt
  • Date: 2015-02-22 07:46:25 UTC
  • mfrom: (2332 development-branch)
  • mto: This revision was merged to the branch mainline in revision 2673.
  • Revision ID: daniel.van.vugt@canonical.com-20150222074625-8t23m2sif3dc0j3t
Merge latest trunk and fix conflicts.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
#include "mir_toolkit/mir_client_library.h"
20
20
#include "mir/frontend/client_constants.h"
21
 
#include "client_buffer.h"
 
21
#include "mir/client_buffer.h"
22
22
#include "mir_surface.h"
23
23
#include "cursor_configuration.h"
 
24
#include "client_buffer_stream_factory.h"
24
25
#include "mir_connection.h"
25
26
#include "mir/input/input_receiver_thread.h"
26
27
#include "mir/input/input_platform.h"
27
 
#include "perf_report.h"
28
 
#include "logging/perf_report.h"
29
28
 
30
29
#include <cassert>
31
30
#include <unistd.h>
38
37
namespace mp = mir::protobuf;
39
38
namespace gp = google::protobuf;
40
39
 
 
40
#define SERIALIZE_OPTION_IF_SET(option, message) \
 
41
    if (option.is_set()) \
 
42
        message.set_##option(option.value());
 
43
 
41
44
namespace
42
45
{
43
 
void null_callback(MirSurface*, void*) {}
44
 
mp::DisplayServer::Stub null_server{nullptr};
45
 
 
46
46
std::mutex handle_mutex;
47
47
std::unordered_set<MirSurface*> valid_surfaces;
48
48
}
49
49
 
 
50
MirSurfaceSpec::MirSurfaceSpec(
 
51
    MirConnection* connection, int width, int height, MirPixelFormat format)
 
52
    : connection{connection},
 
53
      width{width},
 
54
      height{height},
 
55
      pixel_format{format}
 
56
{
 
57
}
 
58
 
 
59
MirSurfaceSpec::MirSurfaceSpec(MirConnection* connection, MirSurfaceParameters const& params)
 
60
    : connection{connection},
 
61
      width{params.width},
 
62
      height{params.height},
 
63
      pixel_format{params.pixel_format},
 
64
      buffer_usage{params.buffer_usage}
 
65
{
 
66
    if (params.output_id != mir_display_output_id_invalid)
 
67
    {
 
68
        output_id = params.output_id;
 
69
        state = mir_surface_state_fullscreen;
 
70
    }
 
71
}
 
72
 
 
73
mir::protobuf::SurfaceParameters MirSurfaceSpec::serialize() const
 
74
{
 
75
    mir::protobuf::SurfaceParameters message;
 
76
 
 
77
    message.set_width(width);
 
78
    message.set_height(height);
 
79
    message.set_pixel_format(pixel_format);
 
80
    message.set_buffer_usage(buffer_usage);
 
81
 
 
82
    SERIALIZE_OPTION_IF_SET(surface_name, message);
 
83
    SERIALIZE_OPTION_IF_SET(output_id, message);
 
84
    SERIALIZE_OPTION_IF_SET(type, message);
 
85
    SERIALIZE_OPTION_IF_SET(state, message);
 
86
    SERIALIZE_OPTION_IF_SET(pref_orientation, message);
 
87
    if (parent.is_set() && parent.value() != nullptr)
 
88
        message.set_parent_id(parent.value()->id());
 
89
    if (aux_rect.is_set())
 
90
    {
 
91
        message.mutable_aux_rect()->set_left(aux_rect.value().left);
 
92
        message.mutable_aux_rect()->set_top(aux_rect.value().top);
 
93
        message.mutable_aux_rect()->set_width(aux_rect.value().width);
 
94
        message.mutable_aux_rect()->set_height(aux_rect.value().height);
 
95
    }
 
96
    SERIALIZE_OPTION_IF_SET(edge_attachment, message);
 
97
    return message;
 
98
}
 
99
 
50
100
MirSurface::MirSurface(std::string const& error)
51
 
    : server{null_server},
52
 
      connection{nullptr}
53
101
{
54
102
    surface.set_error(error);
55
103
 
59
107
 
60
108
MirSurface::MirSurface(
61
109
    MirConnection *allocating_connection,
62
 
    mp::DisplayServer::Stub & server,
63
 
    std::shared_ptr<mcl::ClientBufferFactory> const& factory,
64
 
    std::shared_ptr<mircv::InputPlatform> const& input_platform,
65
 
    MirSurfaceParameters const & params,
66
 
    mir_surface_callback callback, void * context)
67
 
    : MirSurface(allocating_connection,
68
 
                 server,
69
 
                 nullptr,
70
 
                 factory,
71
 
                 input_platform,
72
 
                 params,
73
 
                 callback, context)
74
 
{
75
 
}
76
 
 
77
 
 
78
 
MirSurface::MirSurface(
79
 
    MirConnection *allocating_connection,
80
 
    mp::DisplayServer::Stub & server,
 
110
    mp::DisplayServer::Stub& the_server,
81
111
    mp::Debug::Stub* debug,
82
 
    std::shared_ptr<mcl::ClientBufferFactory> const& factory,
 
112
    std::shared_ptr<mcl::ClientBufferStreamFactory> const& buffer_stream_factory,
83
113
    std::shared_ptr<mircv::InputPlatform> const& input_platform,
84
 
    MirSurfaceParameters const & params,
 
114
    MirSurfaceSpec const& spec,
85
115
    mir_surface_callback callback, void * context)
86
 
    : server(server),
 
116
    : server{&the_server},
87
117
      debug{debug},
 
118
      name{spec.surface_name.value()},
88
119
      connection(allocating_connection),
89
 
      buffer_depository(std::make_shared<mcl::ClientBufferDepository>(factory, mir::frontend::client_buffer_cache_size)),
 
120
      buffer_stream_factory(buffer_stream_factory),
90
121
      input_platform(input_platform)
91
122
{
92
 
    const char* report_target = getenv("MIR_CLIENT_PERF_REPORT");
93
 
    if (report_target && !strcmp(report_target, "log"))
94
 
    {
95
 
        auto& logger = connection->the_logger();
96
 
        perf_report = std::make_shared<mir::client::logging::PerfReport>(logger);
97
 
    }
98
 
    else
99
 
    {
100
 
        perf_report = std::make_shared<mir::client::NullPerfReport>();
101
 
    }
102
 
    perf_report->name_surface(params.name);
103
 
 
104
123
    for (int i = 0; i < mir_surface_attribs; i++)
105
124
        attrib_cache[i] = -1;
106
125
 
107
 
    mir::protobuf::SurfaceParameters message;
108
 
    message.set_surface_name(params.name ? params.name : std::string());
109
 
    message.set_width(params.width);
110
 
    message.set_height(params.height);
111
 
    message.set_pixel_format(params.pixel_format);
112
 
    message.set_buffer_usage(params.buffer_usage);
113
 
    message.set_output_id(params.output_id);
114
 
 
 
126
    auto const message = spec.serialize();
115
127
    create_wait_handle.expect_result();
116
 
    server.create_surface(0, &message, &surface, gp::NewCallback(this, &MirSurface::created, callback, context));
 
128
    try 
 
129
    {
 
130
        server->create_surface(0, &message, &surface, gp::NewCallback(this, &MirSurface::created, callback, context));
 
131
    }
 
132
    catch (std::exception const& ex)
 
133
    {
 
134
        surface.set_error(std::string{"Error invoking create surface: "} +
 
135
                          boost::diagnostic_information(ex));
 
136
    }
117
137
 
118
138
    std::lock_guard<decltype(handle_mutex)> lock(handle_mutex);
119
139
    valid_surfaces.insert(this);
136
156
 
137
157
    for (auto i = 0, end = surface.fd_size(); i != end; ++i)
138
158
        close(surface.fd(i));
139
 
 
140
 
    release_cpu_region();
141
159
}
142
160
 
143
161
MirSurfaceParameters MirSurface::get_parameters() const
144
162
{
145
163
    std::lock_guard<decltype(mutex)> lock(mutex);
146
164
 
147
 
    return MirSurfaceParameters {
148
 
        0,
149
 
        surface.width(),
150
 
        surface.height(),
151
 
        static_cast<MirPixelFormat>(surface.pixel_format()),
152
 
        static_cast<MirBufferUsage>(surface.buffer_usage()),
153
 
        mir_display_output_id_invalid};
 
165
    return buffer_stream->get_parameters();
154
166
}
155
167
 
156
168
char const * MirSurface::get_error_message()
181
193
    return false;
182
194
}
183
195
 
184
 
void MirSurface::get_cpu_region(MirGraphicsRegion& region_out)
185
 
{
186
 
    std::lock_guard<decltype(mutex)> lock(mutex);
187
 
 
188
 
    auto buffer = buffer_depository->current_buffer();
189
 
 
190
 
    secured_region = buffer->secure_for_cpu_write();
191
 
    region_out.width = secured_region->width.as_uint32_t();
192
 
    region_out.height = secured_region->height.as_uint32_t();
193
 
    region_out.stride = secured_region->stride.as_uint32_t();
194
 
    region_out.pixel_format = secured_region->format;
195
 
    region_out.vaddr = secured_region->vaddr.get();
196
 
}
197
 
 
198
 
void MirSurface::release_cpu_region()
199
 
{
200
 
    secured_region.reset();
201
 
}
202
 
 
203
 
MirWaitHandle* MirSurface::next_buffer(mir_surface_callback callback, void * context)
204
 
{
205
 
    std::unique_lock<decltype(mutex)> lock(mutex);
206
 
    release_cpu_region();
207
 
 
208
 
    //TODO: we have extract the per-message information from the buffer
209
 
    *buffer_request.mutable_id() = surface.id();
210
 
    buffer_request.mutable_buffer()->set_buffer_id(surface.buffer().buffer_id());
211
 
    perf_report->end_frame(surface.buffer().buffer_id());
212
 
    lock.unlock();
213
 
 
214
 
    next_buffer_wait_handle.expect_result();
215
 
    server.exchange_buffer(
216
 
        0,
217
 
        &buffer_request,
218
 
        surface.mutable_buffer(),
219
 
        google::protobuf::NewCallback(this, &MirSurface::new_buffer, callback, context));
220
 
 
221
 
    return &next_buffer_wait_handle;
222
 
}
223
 
 
224
196
MirWaitHandle* MirSurface::get_create_wait_handle()
225
197
{
226
198
    return &create_wait_handle;
228
200
 
229
201
/* todo: all these conversion functions are a bit of a kludge, probably
230
202
         better to have a more developed MirPixelFormat that can handle this */
231
 
MirPixelFormat MirSurface::convert_ipc_pf_to_geometry(gp::int32 pf)
 
203
MirPixelFormat MirSurface::convert_ipc_pf_to_geometry(gp::int32 pf) const
232
204
{
233
205
    return static_cast<MirPixelFormat>(pf);
234
206
}
235
207
 
236
 
void MirSurface::process_incoming_buffer()
237
 
{
238
 
    auto const& buffer = surface.buffer();
239
 
 
240
 
    /*
241
 
     * On most frames when the properties aren't changing, the server won't
242
 
     * fill in the width and height. I think this is an intentional
243
 
     * protocol optimization ("need_full_ipc").
244
 
     */
245
 
    if (buffer.has_width() && buffer.has_height())
246
 
    {
247
 
        surface.set_width(buffer.width());
248
 
        surface.set_height(buffer.height());
249
 
    }
250
 
 
251
 
    auto surface_size = geom::Size{surface.width(), surface.height()};
252
 
    auto surface_pf = convert_ipc_pf_to_geometry(surface.pixel_format());
253
 
 
254
 
    auto ipc_package = std::make_shared<MirBufferPackage>();
255
 
    populate(*ipc_package);
256
 
 
257
 
    try
258
 
    {
259
 
        buffer_depository->deposit_package(std::move(ipc_package),
260
 
                                           buffer.buffer_id(),
261
 
                                           surface_size, surface_pf);
262
 
        perf_report->begin_frame(buffer.buffer_id());
263
 
    }
264
 
    catch (const std::runtime_error& err)
265
 
    {
266
 
        // TODO: Report the error
267
 
    }
268
 
}
269
 
 
270
208
void MirSurface::created(mir_surface_callback callback, void * context)
271
209
{
272
 
    auto platform = connection->get_client_platform();
 
210
    {
 
211
    std::lock_guard<decltype(mutex)> lock(mutex);
 
212
    if (!surface.has_id())
 
213
    {
 
214
        if (!surface.has_error())
 
215
            surface.set_error("Error processing surface create response, no ID (disconnected?)");
273
216
 
 
217
        callback(this, context);
 
218
        create_wait_handle.result_received();
 
219
        return;
 
220
    }
 
221
    }
274
222
    try
275
223
    {
276
224
        {
277
225
            std::lock_guard<decltype(mutex)> lock(mutex);
278
226
 
279
 
            process_incoming_buffer();
280
 
            accelerated_window = platform->create_egl_native_window(this);
 
227
            buffer_stream = buffer_stream_factory->
 
228
                make_producer_stream(*server, surface.buffer_stream(), name);
281
229
 
282
230
            for(int i = 0; i < surface.attributes_size(); i++)
283
231
            {
298
246
    create_wait_handle.result_received();
299
247
}
300
248
 
301
 
void MirSurface::new_buffer(mir_surface_callback callback, void * context)
302
 
{
303
 
    {
304
 
        std::lock_guard<decltype(mutex)> lock(mutex);
305
 
        process_incoming_buffer();
306
 
    }
307
 
 
308
 
    callback(this, context);
309
 
    next_buffer_wait_handle.result_received();
310
 
}
311
 
 
312
249
MirWaitHandle* MirSurface::release_surface(
313
250
        mir_surface_callback callback,
314
251
        void * context)
315
252
{
 
253
    bool was_valid = false;
316
254
    {
317
255
        std::lock_guard<decltype(handle_mutex)> lock(handle_mutex);
 
256
        if (valid_surfaces.count(this))
 
257
            was_valid = true;
318
258
        valid_surfaces.erase(this);
319
259
    }
 
260
    if (this->surface.has_error())
 
261
        was_valid = false;
320
262
 
321
263
    MirWaitHandle* wait_handle{nullptr};
322
 
    if (connection)
 
264
    if (connection && was_valid)
323
265
    {
324
266
        wait_handle = connection->release_surface(this, callback, context);
325
267
    }
332
274
    return wait_handle;
333
275
}
334
276
 
335
 
MirNativeBuffer* MirSurface::get_current_buffer_package()
336
 
{
337
 
    auto platform = connection->get_client_platform();
338
 
    auto buffer = get_current_buffer();
339
 
    auto handle = buffer->native_buffer_handle();
340
 
    return platform->convert_native_buffer(handle.get());
341
 
}
342
 
 
343
 
std::shared_ptr<mcl::ClientBuffer> MirSurface::get_current_buffer()
344
 
{
345
 
    std::lock_guard<decltype(mutex)> lock(mutex);
346
 
 
347
 
    return buffer_depository->current_buffer();
348
 
}
349
 
 
350
 
uint32_t MirSurface::get_current_buffer_id() const
351
 
{
352
 
    std::lock_guard<decltype(mutex)> lock(mutex);
353
 
 
354
 
    return buffer_depository->current_buffer_id();
355
 
}
356
 
 
357
 
void MirSurface::populate(MirBufferPackage& buffer_package)
358
 
{
359
 
    if (!surface.has_error() && surface.has_buffer())
360
 
    {
361
 
        auto const& buffer = surface.buffer();
362
 
 
363
 
        buffer_package.data_items = buffer.data_size();
364
 
        for (int i = 0; i != buffer.data_size(); ++i)
365
 
        {
366
 
            buffer_package.data[i] = buffer.data(i);
367
 
        }
368
 
 
369
 
        buffer_package.fd_items = buffer.fd_size();
370
 
 
371
 
        for (int i = 0; i != buffer.fd_size(); ++i)
372
 
        {
373
 
            buffer_package.fd[i] = buffer.fd(i);
374
 
        }
375
 
 
376
 
        buffer_package.stride = buffer.stride();
377
 
        buffer_package.flags = buffer.flags();
378
 
        buffer_package.width = buffer.width();
379
 
        buffer_package.height = buffer.height();
380
 
    }
381
 
    else
382
 
    {
383
 
        buffer_package.data_items = 0;
384
 
        buffer_package.fd_items = 0;
385
 
        buffer_package.stride = 0;
386
 
    }
387
 
}
388
 
 
389
 
EGLNativeWindowType MirSurface::generate_native_window()
390
 
{
391
 
    std::lock_guard<decltype(mutex)> lock(mutex);
392
 
 
393
 
    return *accelerated_window;
394
 
}
395
 
 
396
277
MirWaitHandle* MirSurface::configure_cursor(MirCursorConfiguration const* cursor)
397
278
{
398
279
    mp::CursorSetting setting;
405
286
    }
406
287
    
407
288
    configure_cursor_wait_handle.expect_result();
408
 
    server.configure_cursor(0, &setting, &void_response,
 
289
    server->configure_cursor(0, &setting, &void_response,
409
290
        google::protobuf::NewCallback(this, &MirSurface::on_cursor_configured));
410
291
    
411
292
    return &configure_cursor_wait_handle;
413
294
 
414
295
MirWaitHandle* MirSurface::configure(MirSurfaceAttrib at, int value)
415
296
{
 
297
    // TODO: This is obviously strange. It should be
 
298
    // possible to eliminate it in the second phase of buffer
 
299
    // stream where the existing MirSurface swap interval functions
 
300
    // may be deprecated in terms of mir_buffer_stream_ alternatives
 
301
    if (at == mir_surface_attrib_swapinterval)
 
302
    {
 
303
        buffer_stream->set_swap_interval(value);
 
304
        return &configure_wait_handle;
 
305
    }
 
306
 
416
307
    std::unique_lock<decltype(mutex)> lock(mutex);
 
308
 
417
309
    mp::SurfaceSetting setting;
418
310
    setting.mutable_surfaceid()->CopyFrom(surface.id());
419
311
    setting.set_attrib(at);
421
313
    lock.unlock();
422
314
 
423
315
    configure_wait_handle.expect_result();
424
 
    server.configure_surface(0, &setting, &configure_result,
 
316
    server->configure_surface(0, &setting, &configure_result,
425
317
              google::protobuf::NewCallback(this, &MirSurface::on_configured));
426
318
 
427
319
    return &configure_wait_handle;
485
377
        case mir_surface_attrib_type:
486
378
        case mir_surface_attrib_state:
487
379
        case mir_surface_attrib_focus:
488
 
        case mir_surface_attrib_swapinterval:
489
380
        case mir_surface_attrib_dpi:
 
381
        case mir_surface_attrib_preferred_orientation:
490
382
            if (configure_result.has_ivalue())
491
383
                attrib_cache[a] = configure_result.ivalue();
492
384
            else
511
403
{
512
404
    std::lock_guard<decltype(mutex)> lock(mutex);
513
405
 
 
406
    if (at == mir_surface_attrib_swapinterval)
 
407
    {
 
408
        if (buffer_stream)
 
409
            return buffer_stream->swap_interval();
 
410
        else // Surface creation is not finalized
 
411
            return 1;
 
412
    }
 
413
 
514
414
    return attrib_cache[at];
515
415
}
516
416
 
544
444
{
545
445
    std::unique_lock<decltype(mutex)> lock(mutex);
546
446
 
547
 
    switch (e.type)
 
447
    switch (mir_event_get_type(&e))
548
448
    {
549
449
    case mir_event_type_surface:
550
450
    {
551
 
        MirSurfaceAttrib a = e.surface.attrib;
 
451
        auto sev = mir_event_get_surface_event(&e);
 
452
        auto a = mir_surface_event_get_attribute(sev);
552
453
        if (a < mir_surface_attribs)
553
 
            attrib_cache[a] = e.surface.value;
 
454
            attrib_cache[a] = mir_surface_event_get_attribute_value(sev);
554
455
        break;
555
456
    }
556
457
    case mir_event_type_orientation:
557
 
        orientation = e.orientation.direction;
 
458
        orientation = mir_orientation_event_get_direction(mir_event_get_orientation_event(&e));
558
459
        break;
559
 
 
560
460
    default:
561
461
        break;
562
462
    };
569
469
    }
570
470
}
571
471
 
572
 
MirPlatformType MirSurface::platform_type()
573
 
{
574
 
    std::lock_guard<decltype(mutex)> lock(mutex);
575
 
 
576
 
    auto platform = connection->get_client_platform();
577
 
    return platform->platform_type();
578
 
}
579
 
 
580
 
void MirSurface::request_and_wait_for_next_buffer()
581
 
{
582
 
    next_buffer(null_callback, nullptr)->wait_for_all();
583
 
}
584
 
 
585
472
void MirSurface::request_and_wait_for_configure(MirSurfaceAttrib a, int value)
586
473
{
587
474
    configure(a, value)->wait_for_all();
593
480
 
594
481
    return orientation;
595
482
}
 
483
 
 
484
MirWaitHandle* MirSurface::set_preferred_orientation(MirOrientationMode mode)
 
485
{
 
486
    return configure(mir_surface_attrib_preferred_orientation, mode);
 
487
}
 
488
 
 
489
mir::client::ClientBufferStream* MirSurface::get_buffer_stream()
 
490
{
 
491
    std::lock_guard<decltype(mutex)> lock(mutex);
 
492
    
 
493
    return buffer_stream.get();
 
494
}