libdrm/iris: import GPU buffers lazy optimization

Do not import a freshly allocated buffer to all contexts eagerly.
Instead check buffer list in context's 'exec_buffer' call and import
only buffers needed and not present before GPU execution. This leads to
improved performance for applications that use many OpenGL contexts
(e.g., VirtualBox 6).

issue #4380
This commit is contained in:
Sebastian Sumpf 2022-01-14 10:43:05 +01:00 committed by Norman Feske
parent 3c97fdbc0e
commit 4cb8c91b08

View File

@ -283,7 +283,9 @@ struct Drm::Context
} }
}; };
Gpu::Connection &_gpu; Gpu::Connection &_gpu;
Gpu::Connection &_gpu_master;
Genode::Allocator &_alloc;
Gpu::Info_intel const &_gpu_info { Gpu::Info_intel const &_gpu_info {
*_gpu.attached_info<Gpu::Info_intel>() }; *_gpu.attached_info<Gpu::Info_intel>() };
@ -367,9 +369,12 @@ struct Drm::Context
buffer.gpu_vaddr_valid = false; buffer.gpu_vaddr_valid = false;
} }
Context(Gpu::Connection &gpu, int fd, Genode::Id_space<Context> &space) Context(Gpu::Connection &gpu, Gpu::Connection &gpu_master,
Genode::Allocator &alloc, int fd,
Genode::Id_space<Context> &space)
: :
_gpu(gpu), _fd(fd), _elem (*this, space) { } _gpu(gpu), _gpu_master(gpu_master), _alloc(alloc), _fd(fd),
_elem (*this, space) { }
unsigned long id() const unsigned long id() const
{ {
@ -383,8 +388,7 @@ struct Drm::Context
int fd() const { return _fd; } int fd() const { return _fd; }
void import_buffer(Genode::Allocator &alloc, void import_buffer(Gpu::Buffer_capability buffer_cap,
Gpu::Buffer_capability buffer_cap,
Gpu::Buffer_id id) Gpu::Buffer_id id)
{ {
Genode::retry<Gpu::Session::Out_of_ram>( Genode::retry<Gpu::Session::Out_of_ram>(
@ -392,7 +396,7 @@ struct Drm::Context
Genode::retry<Gpu::Session::Out_of_caps>( Genode::retry<Gpu::Session::Out_of_caps>(
[&] () { [&] () {
_gpu.import_buffer(buffer_cap, id); _gpu.import_buffer(buffer_cap, id);
new (alloc) Buffer(_buffer_space, id); new (_alloc) Buffer(_buffer_space, id);
}, },
[&] () { [&] () {
_gpu.upgrade_caps(2); _gpu.upgrade_caps(2);
@ -403,23 +407,23 @@ struct Drm::Context
}); });
} }
void free_buffer(Genode::Allocator &alloc, Gpu::Buffer_id id) void free_buffer(Gpu::Buffer_id id)
{ {
try { try {
_buffer_space.apply<Buffer>(Buffer::Id_space::Id { .value = id.value }, _buffer_space.apply<Buffer>(Buffer::Id_space::Id { .value = id.value },
[&] (Buffer &buffer) { [&] (Buffer &buffer) {
destroy(alloc, &buffer); destroy(_alloc, &buffer);
}); });
} catch (Buffer::Id_space::Unknown_id) { return; } } catch (Buffer::Id_space::Unknown_id) { return; }
_gpu.free_buffer(id); _gpu.free_buffer(id);
} }
void free_buffers(Genode::Allocator &alloc) void free_buffers()
{ {
while (_buffer_space.apply_any<Buffer>([&] (Buffer &buffer) { while (_buffer_space.apply_any<Buffer>([&] (Buffer &buffer) {
Gpu::Buffer_id id = buffer.buffer_id(); Gpu::Buffer_id id = buffer.buffer_id();
destroy(alloc, &buffer); destroy(_alloc, &buffer);
_gpu.free_buffer(id); _gpu.free_buffer(id);
})) { } })) { }
} }
@ -484,7 +488,13 @@ struct Drm::Context
ret = 0; ret = 0;
}); });
} catch (Buffer::Id_space::Unknown_id) { } } catch (Buffer::Id_space::Unknown_id) {
Gpu::Buffer_id buffer_id { .value = id.value };
Gpu::Buffer_capability buffer_cap = _gpu_master.export_buffer(buffer_id);
import_buffer(buffer_cap, buffer_id);
i--;
continue;
}
if (ret) { if (ret) {
Genode::error("handle: ", obj[i].handle, " invalid, ret=", ret); Genode::error("handle: ", obj[i].handle, " invalid, ret=", ret);
@ -854,13 +864,6 @@ class Drm_call
if (buffer) if (buffer)
fn(*buffer); fn(*buffer);
Gpu::Buffer_capability buffer_cap = _gpu_session.export_buffer(buffer->id());
_context_space.for_each<Drm::Context>([&](Drm::Context &context) {
try {
context.import_buffer(_heap, buffer_cap, buffer->id());
} catch (...) { }
});
} }
int _free_buffer(Gpu::Buffer_id const id) int _free_buffer(Gpu::Buffer_id const id)
@ -874,7 +877,7 @@ class Drm_call
_resources.free_buffer(b.size); _resources.free_buffer(b.size);
_context_space.for_each<Drm::Context>([&] (Drm::Context &context) { _context_space.for_each<Drm::Context>([&] (Drm::Context &context) {
context.free_buffer(_heap, b.id()); }); context.free_buffer(b.id()); });
Genode::destroy(&_heap, &b); Genode::destroy(&_heap, &b);
}); });
@ -1105,19 +1108,11 @@ class Drm_call
return -1; return -1;
} }
Drm::Context *context = new (_heap) Drm::Context(*gpu, fd, _context_space); Drm::Context *context = new (_heap) Drm::Context(*gpu, _gpu_session, _heap,
fd, _context_space);
p->ctx_id = context->id(); p->ctx_id = context->id();
/* import all current buffers */
_buffer_space.for_each<Buffer>([&](Buffer &b) {
Gpu::Buffer_capability buffer_cap = _gpu_session.export_buffer(b.id());
try {
context->import_buffer(_heap, buffer_cap, b.id());
} catch (...) { }
});
Genode::error("CREATE Context: ", p->ctx_id, " gpu: ", gpu);
return 0; return 0;
} }
@ -1125,11 +1120,10 @@ class Drm_call
{ {
unsigned long ctx_id = reinterpret_cast<drm_i915_gem_context_destroy *>(arg)->ctx_id; unsigned long ctx_id = reinterpret_cast<drm_i915_gem_context_destroy *>(arg)->ctx_id;
Context_id const id = Drm::Context::id(ctx_id); Context_id const id = Drm::Context::id(ctx_id);
Genode::error("DESTROY Context: ", ctx_id);
try { try {
_context_space.apply<Drm::Context>(id, [&] (Drm::Context &context) { _context_space.apply<Drm::Context>(id, [&] (Drm::Context &context) {
context.free_buffers(_heap); context.free_buffers();
Libc::close(context.fd()); Libc::close(context.fd());
destroy(_heap, &context); destroy(_heap, &context);
}); });
@ -1465,7 +1459,8 @@ class Drm_call
prime_handle = id; prime_handle = id;
if (prime_handle.value != id.value) { if (prime_handle.value != id.value) {
Genode::warning("prime handle changed: ", id.value); if (verbose_ioctl)
Genode::warning("prime handle changed: ", id.value);
prime_handle = id; prime_handle = id;
} }
}); });