summaryrefslogtreecommitdiff
path: root/src/protocols/MesaDRM.cpp
diff options
context:
space:
mode:
authorVaxry <43317083+vaxerski@users.noreply.github.com>2024-06-08 10:07:59 +0200
committerGitHub <noreply@github.com>2024-06-08 10:07:59 +0200
commit6967a31450441fc5605c05db6f65505dace4b263 (patch)
tree255a3cff7f3e2eb8a50c952eab9b270a7937561d /src/protocols/MesaDRM.cpp
parentc31d9ef4172452f6f219f91d9b87a24d91f0cf3a (diff)
wayland/core: move to new impl (#6268)
* wayland/core/dmabuf: move to new impl it's the final countdown
Diffstat (limited to 'src/protocols/MesaDRM.cpp')
-rw-r--r--src/protocols/MesaDRM.cpp133
1 files changed, 133 insertions, 0 deletions
diff --git a/src/protocols/MesaDRM.cpp b/src/protocols/MesaDRM.cpp
new file mode 100644
index 00000000..0bcf4a9c
--- /dev/null
+++ b/src/protocols/MesaDRM.cpp
@@ -0,0 +1,133 @@
+#include "MesaDRM.hpp"
+#include <algorithm>
+#include <xf86drm.h>
+#include "../Compositor.hpp"
+#include <wlr/render/drm_format_set.h>
+#include "types/WLBuffer.hpp"
+
+#define LOGM PROTO::mesaDRM->protoLog
+
+CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, SDMABUFAttrs attrs_) {
+ LOGM(LOG, "Creating a Mesa dmabuf, with id {}: size {}, fmt {}, planes {}", id, attrs_.size, attrs_.format, attrs_.planes);
+ for (int i = 0; i < attrs_.planes; ++i) {
+ LOGM(LOG, " | plane {}: mod {} fd {} stride {} offset {}", i, attrs_.modifier, attrs_.fds[i], attrs_.strides[i], attrs_.offsets[i]);
+ }
+
+ buffer = makeShared<CDMABuffer>(id, client, attrs_);
+ buffer->resource->buffer = buffer;
+
+ listeners.bufferResourceDestroy = buffer->events.destroy.registerListener([this](std::any d) {
+ listeners.bufferResourceDestroy.reset();
+ PROTO::mesaDRM->destroyResource(this);
+ });
+
+ if (!buffer->success)
+ LOGM(ERR, "Possibly compositor bug: buffer failed to create");
+}
+
+CMesaDRMBufferResource::~CMesaDRMBufferResource() {
+ if (buffer && buffer->resource)
+ buffer->resource->sendRelease();
+ buffer.reset();
+ listeners.bufferResourceDestroy.reset();
+}
+
+bool CMesaDRMBufferResource::good() {
+ return buffer && buffer->good();
+}
+
+CMesaDRMResource::CMesaDRMResource(SP<CWlDrm> resource_) : resource(resource_) {
+ if (!good())
+ return;
+
+ resource->setOnDestroy([this](CWlDrm* r) { PROTO::mesaDRM->destroyResource(this); });
+
+ resource->setAuthenticate([this](CWlDrm* r, uint32_t token) {
+ // we don't need this
+ resource->sendAuthenticated();
+ });
+
+ resource->setCreateBuffer([](CWlDrm* r, uint32_t, uint32_t, int32_t, int32_t, uint32_t, uint32_t) { r->error(WL_DRM_ERROR_INVALID_NAME, "Not supported, use prime instead"); });
+
+ resource->setCreatePlanarBuffer([](CWlDrm* r, uint32_t, uint32_t, int32_t, int32_t, uint32_t, int32_t, int32_t, int32_t, int32_t, int32_t, int32_t) {
+ r->error(WL_DRM_ERROR_INVALID_NAME, "Not supported, use prime instead");
+ });
+
+ resource->setCreatePrimeBuffer(
+ [this](CWlDrm* r, uint32_t id, int32_t nameFd, int32_t w, int32_t h, uint32_t fmt, int32_t off0, int32_t str0, int32_t off1, int32_t str1, int32_t off2, int32_t str2) {
+ if (off0 < 0 || w <= 0 || h <= 0) {
+ r->error(WL_DRM_ERROR_INVALID_FORMAT, "Invalid w, h, or offset");
+ return;
+ }
+
+ SDMABUFAttrs attrs;
+ attrs.success = true;
+ attrs.size = {w, h};
+ attrs.modifier = DRM_FORMAT_MOD_INVALID;
+ attrs.planes = 1;
+ attrs.offsets[0] = off0;
+ attrs.strides[0] = str0;
+ attrs.fds[0] = nameFd;
+ attrs.format = fmt;
+
+ const auto RESOURCE = PROTO::mesaDRM->m_vBuffers.emplace_back(makeShared<CMesaDRMBufferResource>(id, resource->client(), attrs));
+
+ if (!RESOURCE->good()) {
+ r->noMemory();
+ PROTO::mesaDRM->m_vBuffers.pop_back();
+ return;
+ }
+
+ // append instance so that buffer knows its owner
+ RESOURCE->buffer->resource->buffer = RESOURCE->buffer;
+ });
+
+ resource->sendDevice(PROTO::mesaDRM->nodeName.c_str());
+ resource->sendCapabilities(WL_DRM_CAPABILITY_PRIME);
+
+ auto fmts = g_pHyprOpenGL->getDRMFormats();
+ for (auto& fmt : fmts) {
+ resource->sendFormat(fmt.format);
+ }
+}
+
+bool CMesaDRMResource::good() {
+ return resource->resource();
+}
+
+CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
+ drmDevice* dev = nullptr;
+ int drmFD = wlr_renderer_get_drm_fd(g_pCompositor->m_sWLRRenderer);
+ if (drmGetDevice2(drmFD, 0, &dev) != 0) {
+ LOGM(ERR, "Failed to get device");
+ PROTO::mesaDRM.reset();
+ return;
+ }
+
+ if (dev->available_nodes & (1 << DRM_NODE_RENDER)) {
+ nodeName = dev->nodes[DRM_NODE_RENDER];
+ } else {
+ ASSERT(dev->available_nodes & (1 << DRM_NODE_PRIMARY));
+ LOGM(WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]);
+ nodeName = dev->nodes[DRM_NODE_PRIMARY];
+ }
+ drmFreeDevice(&dev);
+}
+
+void CMesaDRMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
+ const auto RESOURCE = m_vManagers.emplace_back(makeShared<CMesaDRMResource>(makeShared<CWlDrm>(client, ver, id)));
+
+ if (!RESOURCE->good()) {
+ wl_client_post_no_memory(client);
+ m_vManagers.pop_back();
+ return;
+ }
+}
+
+void CMesaDRMProtocol::destroyResource(CMesaDRMResource* resource) {
+ std::erase_if(m_vManagers, [&](const auto& other) { return other.get() == resource; });
+}
+
+void CMesaDRMProtocol::destroyResource(CMesaDRMBufferResource* resource) {
+ std::erase_if(m_vBuffers, [&](const auto& other) { return other.get() == resource; });
+}