vmm: support mode change in virtio gpu

Fix genodelabs/genode#4783
This commit is contained in:
Stefan Kalkowski 2023-03-13 11:52:51 +01:00 committed by Christian Helmuth
parent cb3b6c4b88
commit 61454178c0
2 changed files with 48 additions and 39 deletions

View File

@ -43,14 +43,15 @@ void Vmm::Virtio_gpu_queue::notify(Virtio_gpu_device & dev)
void Vmm::Virtio_gpu_control_request::_get_display_info()
{
Framebuffer::Mode mode = _device.resize();
Display_info_response dir { _desc_addr(1) };
memset((void*)dir.base(), 0, Display_info_response::SIZE);
dir.write<Control_header::Type>(Control_header::Type::OK_DISPLAY_INFO);
dir.write<Display_info_response::X>(0);
dir.write<Display_info_response::Y>(0);
dir.write<Display_info_response::Width>(_device._fb_mode.area.w());
dir.write<Display_info_response::Height>(_device._fb_mode.area.h());
dir.write<Display_info_response::Width>(mode.area.w());
dir.write<Display_info_response::Height>(mode.area.h());
dir.write<Display_info_response::Enabled>(1);
dir.write<Display_info_response::Flags>(0);
}
@ -182,6 +183,9 @@ void Vmm::Virtio_gpu_control_request::_resource_flush()
uint32_t id = rf.read<Resource_flush::Resource_id>();
response.write<Control_header::Type>(Control_header::Type::ERR_INVALID_RESOURCE_ID);
if (!_device._fb_ds.constructed())
return;
using Resource = Virtio_gpu_device::Resource;
_device._resources.for_each([&] (Resource & res) {
if (res.id != id)
@ -189,20 +193,23 @@ void Vmm::Virtio_gpu_control_request::_resource_flush()
uint32_t x = rf.read<Resource_flush::X>();
uint32_t y = rf.read<Resource_flush::Y>();
uint32_t w = rf.read<Resource_flush::Width>();
uint32_t h = rf.read<Resource_flush::Height>();
uint32_t w = min(rf.read<Resource_flush::Width>(),
_device._fb_mode.area.w() - x);
uint32_t h = min(rf.read<Resource_flush::Height>(),
_device._fb_mode.area.h() - y);
if (x > res.area.w() ||
y > res.area.h() ||
w > res.area.w() ||
h > res.area.h() ||
x + w > res.area.w() ||
enum { BYTES_PER_PIXEL = Virtio_gpu_device::BYTES_PER_PIXEL };
if (x > res.area.w() ||
y > res.area.h() ||
w > res.area.w() ||
h > res.area.h() ||
x + w > res.area.w() ||
y + h > res.area.h()) {
response.write<Control_header::Type>(Control_header::Type::ERR_INVALID_PARAMETER);
return;
}
enum { BYTES_PER_PIXEL = Virtio_gpu_device::BYTES_PER_PIXEL };
response.write<Control_header::Type>(Control_header::Type::OK_NO_DATA);
void * src =
@ -211,10 +218,10 @@ void Vmm::Virtio_gpu_control_request::_resource_flush()
void * dst =
(void*)((addr_t)_device._fb_ds->local_addr<void>() +
(_device._fb_mode.area.w() * y + x) * BYTES_PER_PIXEL);
uint32_t line = res.area.w() * BYTES_PER_PIXEL;
blit(src, line, dst, line, w*BYTES_PER_PIXEL, h);
uint32_t line_src = res.area.w() * BYTES_PER_PIXEL;
uint32_t line_dst = _device._fb_mode.area.w() * BYTES_PER_PIXEL;
blit(src, line_src, dst, line_dst, w*BYTES_PER_PIXEL, h);
_device._gui.framebuffer()->refresh(x, y, w, h);
});
}

View File

@ -311,7 +311,6 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2>
Constructible<Attached_dataspace> _fb_ds { };
Framebuffer::Mode _fb_mode { _gui.mode() };
Gui::Session::View_handle _view = _gui.create_view();
bool _mode_changed { true };
using Area = Genode::Area<>;
using Rect = Genode::Rect<>;
@ -390,25 +389,25 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2>
enum {
EVENTS_READ = 0,
EVENTS_CLEAR = 4,
SCANOUTS = 8 };
SCANOUTS = 8,
NUM_CAPSETS = 12
};
enum Events { NONE = 0, DISPLAY = 1 };
Register read(Address_range & range, Cpu&) override
{
if (range.start() == EVENTS_READ && range.size() == 4)
return dev._mode_changed ? 1 : 0;
if (range.start() == EVENTS_READ)
return DISPLAY;
/* we support no multi-head, just return 1 */
if (range.start() == SCANOUTS && range.size() == 4)
if (range.start() == SCANOUTS)
return 1;
return 0;
}
void write(Address_range & range, Cpu&, Register v) override
{
if (range.start() == EVENTS_CLEAR && range.size() == 4 && v == 1)
dev._mode_changed = false;
}
void write(Address_range &, Cpu&, Register) override {}
Configuration_area(Virtio_gpu_device & device)
:
@ -420,21 +419,7 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2>
void _mode_change()
{
Genode::Mutex::Guard guard(_mutex);
_fb_mode = _gui.mode();
_gui.buffer(_fb_mode, false);
if (_fb_mode.area.count() > 0)
_fb_ds.construct(_env.rm(),
_gui.framebuffer()->dataspace());
using Command = Gui::Session::Command;
_gui.enqueue<Command::Geometry>(_view, Rect(Point(0, 0), _fb_mode.area));
_gui.enqueue<Command::To_front>(_view, Gui::Session::View_handle());
_gui.execute();
_mode_changed = true;
_config_notification();
}
void _notify(unsigned idx) override
@ -466,13 +451,30 @@ class Vmm::Virtio_gpu_device : public Virtio_device<Virtio_gpu_queue, 2>
_handler(cpu, env.ep(), *this, &Virtio_gpu_device::_mode_change)
{
_gui.mode_sigh(_handler);
_mode_change();
}
void buffer_notification()
{
_buffer_notification();
}
Framebuffer::Mode resize()
{
_fb_ds.destruct();
_fb_mode = _gui.mode();
_gui.buffer(_fb_mode, false);
if (_fb_mode.area.count() > 0)
_fb_ds.construct(_env.rm(),
_gui.framebuffer()->dataspace());
using Command = Gui::Session::Command;
_gui.enqueue<Command::Geometry>(_view, Rect(Point(0, 0), _fb_mode.area));
_gui.enqueue<Command::To_front>(_view, Gui::Session::View_handle());
_gui.execute();
return _gui.mode();
}
};
#endif /* _VIRTIO_GPU_H_ */