~raof/mir/waylanding-again

« back to all changes in this revision

Viewing changes to src/server/frontend/wayland/wayland_connector.cpp

  • Committer: Christopher James Halse Rogers
  • Date: 2017-08-31 07:40:41 UTC
  • Revision ID: christopher.halse.rogers@canonical.com-20170831074041-7dksfdb5qjkg3fig
Wayland: Rework frame notification to be protocol-compliant.

The set of requested frame notification callbacks is a wl_surface property, not a
wl_buffer property.

That is, if a client commits a wl_buffer and a frame callback, then commits *another*
wl_buffer and frame callback before the compositor has triggered the first callback
the first access should trigger *both* frame callbacks, in order requested.

Show diffs side-by-side

added added

removed removed

Lines of Context:
290
290
public:
291
291
    WlShmBuffer(
292
292
        wl_resource* buffer,
293
 
        std::shared_ptr<mir::Executor> const& executor,
294
 
        std::vector<std::unique_ptr<wl_resource, void(*)(wl_resource*)>>&& frames)
 
293
        std::function<void()>&& on_consumed)
295
294
        : buffer{wl_shm_buffer_get(buffer)},
296
295
          resource{buffer},
297
 
          executor{executor},
298
 
          frames{std::move(frames)}
 
296
          consumed{false},
 
297
          on_consumed{std::move(on_consumed)}
299
298
    {
300
299
        if (!buffer)
301
300
        {
357
356
               });
358
357
        }
359
358
 
360
 
        for (auto&& frame : frames)
 
359
        if (!consumed)
361
360
        {
362
 
            auto framer = std::move(frame);
363
 
            executor->spawn(
364
 
                [frame = framer.release(), deleter = framer.get_deleter()]()
365
 
                {
366
 
                    wl_callback_send_done(frame, 0);
367
 
                    wl_client_flush(wl_resource_get_client(frame));
368
 
                    deleter(frame);
369
 
                });
 
361
            on_consumed();
 
362
            consumed = true;
370
363
        }
371
 
        frames.clear();
372
364
    }
373
365
 
374
366
    void bind() override
404
396
private:
405
397
    wl_shm_buffer* const buffer;
406
398
    wl_resource* const resource;
407
 
    std::shared_ptr<mir::Executor> const& executor;
408
 
    std::vector<std::unique_ptr<wl_resource, void(*)(wl_resource*)>> frames;
 
399
    bool consumed;
 
400
    std::function<void()> on_consumed;
409
401
};
410
402
 
411
403
class WlSurface : public wayland::Surface
420
412
        : Surface(client, parent, id),
421
413
          allocator{allocator},
422
414
          executor{executor},
423
 
          pending_buffer{nullptr}
 
415
          pending_buffer{nullptr},
 
416
          pending_frames{std::make_shared<std::vector<wl_resource*>>()}
424
417
    {
425
418
        auto session = session_for_client(client);
426
419
        mg::BufferProperties const props{
440
433
    std::shared_ptr<mir::Executor> const executor;
441
434
 
442
435
    wl_resource* pending_buffer;
443
 
    std::vector<std::unique_ptr<wl_resource, decltype(&wl_resource_destroy)>> pending_frames;
 
436
    std::shared_ptr<std::vector<wl_resource*>> const pending_frames;
444
437
 
445
438
    void destroy();
446
439
    void attach(std::experimental::optional<wl_resource*> const& buffer, int32_t x, int32_t y);
492
485
 
493
486
void WlSurface::frame(uint32_t callback)
494
487
{
495
 
    pending_frames.emplace_back(
496
 
        wl_resource_create(client, &wl_callback_interface, 1, callback),
497
 
        &wl_resource_destroy);
 
488
    pending_frames->emplace_back(
 
489
        wl_resource_create(client, &wl_callback_interface, 1, callback));
498
490
}
499
491
 
500
492
void WlSurface::set_opaque_region(const std::experimental::optional<wl_resource*>& region)
513
505
    {
514
506
        std::shared_ptr<mg::Buffer> mir_buffer;
515
507
        auto shm_buffer = wl_shm_buffer_get(pending_buffer);
 
508
        auto send_frame_notifications =
 
509
            [executor = executor, frames = pending_frames]()
 
510
            {
 
511
                executor->spawn(
 
512
                    [frames]()
 
513
                    {
 
514
                        /*
 
515
                         * There is no synchronisation required here -
 
516
                         * This is run on the WaylandExecutor, and is guaranteed to run on the
 
517
                         * wl_event_loop's thread.
 
518
                         *
 
519
                         * The only other accessors of WlSurface are also on the wl_event_loop,
 
520
                         * so this is guaranteed not to be reentrant.
 
521
                         */
 
522
                        for (auto frame : *frames)
 
523
                        {
 
524
                            wl_callback_send_done(frame, 0);
 
525
                            wl_resource_destroy(frame);
 
526
                        }
 
527
                        frames->clear();
 
528
                    });
 
529
            };
 
530
 
516
531
        if (shm_buffer)
517
532
        {
518
 
            mir_buffer = std::make_shared<WlShmBuffer>(pending_buffer, executor, std::move(pending_frames));
 
533
            mir_buffer = std::make_shared<WlShmBuffer>(
 
534
                pending_buffer,
 
535
                std::move(send_frame_notifications));
519
536
        }
520
537
        else if (
521
538
            allocator &&
522
 
            (mir_buffer = allocator->buffer_from_resource(pending_buffer, executor, std::move(pending_frames))))
 
539
            (mir_buffer = allocator->buffer_from_resource(
 
540
                pending_buffer,
 
541
                std::move(send_frame_notifications))))
523
542
        {
524
543
        }
525
544
        else
530
549
        stream->submit_buffer(mir_buffer);
531
550
 
532
551
        pending_buffer = nullptr;
533
 
        pending_frames.clear();
534
552
    }
535
553
}
536
554