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"
31
30
#include <unistd.h>
38
37
namespace mp = mir::protobuf;
39
38
namespace gp = google::protobuf;
40
#define SERIALIZE_OPTION_IF_SET(option, message) \
41
if (option.is_set()) \
42
message.set_##option(option.value());
43
void null_callback(MirSurface*, void*) {}
44
mp::DisplayServer::Stub null_server{nullptr};
46
46
std::mutex handle_mutex;
47
47
std::unordered_set<MirSurface*> valid_surfaces;
50
MirSurfaceSpec::MirSurfaceSpec(
51
MirConnection* connection, int width, int height, MirPixelFormat format)
52
: connection{connection},
59
MirSurfaceSpec::MirSurfaceSpec(MirConnection* connection, MirSurfaceParameters const& params)
60
: connection{connection},
62
height{params.height},
63
pixel_format{params.pixel_format},
64
buffer_usage{params.buffer_usage}
66
if (params.output_id != mir_display_output_id_invalid)
68
output_id = params.output_id;
69
state = mir_surface_state_fullscreen;
73
mir::protobuf::SurfaceParameters MirSurfaceSpec::serialize() const
75
mir::protobuf::SurfaceParameters message;
77
message.set_width(width);
78
message.set_height(height);
79
message.set_pixel_format(pixel_format);
80
message.set_buffer_usage(buffer_usage);
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())
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);
96
SERIALIZE_OPTION_IF_SET(edge_attachment, message);
50
100
MirSurface::MirSurface(std::string const& error)
51
: server{null_server},
54
102
surface.set_error(error);
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,
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)
116
: server{&the_server},
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)
92
const char* report_target = getenv("MIR_CLIENT_PERF_REPORT");
93
if (report_target && !strcmp(report_target, "log"))
95
auto& logger = connection->the_logger();
96
perf_report = std::make_shared<mir::client::logging::PerfReport>(logger);
100
perf_report = std::make_shared<mir::client::NullPerfReport>();
102
perf_report->name_surface(params.name);
104
123
for (int i = 0; i < mir_surface_attribs; i++)
105
124
attrib_cache[i] = -1;
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);
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));
130
server->create_surface(0, &message, &surface, gp::NewCallback(this, &MirSurface::created, callback, context));
132
catch (std::exception const& ex)
134
surface.set_error(std::string{"Error invoking create surface: "} +
135
boost::diagnostic_information(ex));
118
138
std::lock_guard<decltype(handle_mutex)> lock(handle_mutex);
119
139
valid_surfaces.insert(this);
137
157
for (auto i = 0, end = surface.fd_size(); i != end; ++i)
138
158
close(surface.fd(i));
140
release_cpu_region();
143
161
MirSurfaceParameters MirSurface::get_parameters() const
145
163
std::lock_guard<decltype(mutex)> lock(mutex);
147
return MirSurfaceParameters {
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();
156
168
char const * MirSurface::get_error_message()
184
void MirSurface::get_cpu_region(MirGraphicsRegion& region_out)
186
std::lock_guard<decltype(mutex)> lock(mutex);
188
auto buffer = buffer_depository->current_buffer();
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();
198
void MirSurface::release_cpu_region()
200
secured_region.reset();
203
MirWaitHandle* MirSurface::next_buffer(mir_surface_callback callback, void * context)
205
std::unique_lock<decltype(mutex)> lock(mutex);
206
release_cpu_region();
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());
214
next_buffer_wait_handle.expect_result();
215
server.exchange_buffer(
218
surface.mutable_buffer(),
219
google::protobuf::NewCallback(this, &MirSurface::new_buffer, callback, context));
221
return &next_buffer_wait_handle;
224
196
MirWaitHandle* MirSurface::get_create_wait_handle()
226
198
return &create_wait_handle;
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
233
205
return static_cast<MirPixelFormat>(pf);
236
void MirSurface::process_incoming_buffer()
238
auto const& buffer = surface.buffer();
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").
245
if (buffer.has_width() && buffer.has_height())
247
surface.set_width(buffer.width());
248
surface.set_height(buffer.height());
251
auto surface_size = geom::Size{surface.width(), surface.height()};
252
auto surface_pf = convert_ipc_pf_to_geometry(surface.pixel_format());
254
auto ipc_package = std::make_shared<MirBufferPackage>();
255
populate(*ipc_package);
259
buffer_depository->deposit_package(std::move(ipc_package),
261
surface_size, surface_pf);
262
perf_report->begin_frame(buffer.buffer_id());
264
catch (const std::runtime_error& err)
266
// TODO: Report the error
270
208
void MirSurface::created(mir_surface_callback callback, void * context)
272
auto platform = connection->get_client_platform();
211
std::lock_guard<decltype(mutex)> lock(mutex);
212
if (!surface.has_id())
214
if (!surface.has_error())
215
surface.set_error("Error processing surface create response, no ID (disconnected?)");
217
callback(this, context);
218
create_wait_handle.result_received();
277
225
std::lock_guard<decltype(mutex)> lock(mutex);
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);
282
230
for(int i = 0; i < surface.attributes_size(); i++)
298
246
create_wait_handle.result_received();
301
void MirSurface::new_buffer(mir_surface_callback callback, void * context)
304
std::lock_guard<decltype(mutex)> lock(mutex);
305
process_incoming_buffer();
308
callback(this, context);
309
next_buffer_wait_handle.result_received();
312
249
MirWaitHandle* MirSurface::release_surface(
313
250
mir_surface_callback callback,
253
bool was_valid = false;
317
255
std::lock_guard<decltype(handle_mutex)> lock(handle_mutex);
256
if (valid_surfaces.count(this))
318
258
valid_surfaces.erase(this);
260
if (this->surface.has_error())
321
263
MirWaitHandle* wait_handle{nullptr};
264
if (connection && was_valid)
324
266
wait_handle = connection->release_surface(this, callback, context);
332
274
return wait_handle;
335
MirNativeBuffer* MirSurface::get_current_buffer_package()
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());
343
std::shared_ptr<mcl::ClientBuffer> MirSurface::get_current_buffer()
345
std::lock_guard<decltype(mutex)> lock(mutex);
347
return buffer_depository->current_buffer();
350
uint32_t MirSurface::get_current_buffer_id() const
352
std::lock_guard<decltype(mutex)> lock(mutex);
354
return buffer_depository->current_buffer_id();
357
void MirSurface::populate(MirBufferPackage& buffer_package)
359
if (!surface.has_error() && surface.has_buffer())
361
auto const& buffer = surface.buffer();
363
buffer_package.data_items = buffer.data_size();
364
for (int i = 0; i != buffer.data_size(); ++i)
366
buffer_package.data[i] = buffer.data(i);
369
buffer_package.fd_items = buffer.fd_size();
371
for (int i = 0; i != buffer.fd_size(); ++i)
373
buffer_package.fd[i] = buffer.fd(i);
376
buffer_package.stride = buffer.stride();
377
buffer_package.flags = buffer.flags();
378
buffer_package.width = buffer.width();
379
buffer_package.height = buffer.height();
383
buffer_package.data_items = 0;
384
buffer_package.fd_items = 0;
385
buffer_package.stride = 0;
389
EGLNativeWindowType MirSurface::generate_native_window()
391
std::lock_guard<decltype(mutex)> lock(mutex);
393
return *accelerated_window;
396
277
MirWaitHandle* MirSurface::configure_cursor(MirCursorConfiguration const* cursor)
398
279
mp::CursorSetting setting;
414
295
MirWaitHandle* MirSurface::configure(MirSurfaceAttrib at, int value)
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)
303
buffer_stream->set_swap_interval(value);
304
return &configure_wait_handle;
416
307
std::unique_lock<decltype(mutex)> lock(mutex);
417
309
mp::SurfaceSetting setting;
418
310
setting.mutable_surfaceid()->CopyFrom(surface.id());
419
311
setting.set_attrib(at);
545
445
std::unique_lock<decltype(mutex)> lock(mutex);
447
switch (mir_event_get_type(&e))
549
449
case mir_event_type_surface:
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);
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));
572
MirPlatformType MirSurface::platform_type()
574
std::lock_guard<decltype(mutex)> lock(mutex);
576
auto platform = connection->get_client_platform();
577
return platform->platform_type();
580
void MirSurface::request_and_wait_for_next_buffer()
582
next_buffer(null_callback, nullptr)->wait_for_all();
585
472
void MirSurface::request_and_wait_for_configure(MirSurfaceAttrib a, int value)
587
474
configure(a, value)->wait_for_all();