#include "MesaDRM.hpp" #include #include #include "../Compositor.hpp" #include "types/WLBuffer.hpp" #include "../render/OpenGL.hpp" CMesaDRMBufferResource::CMesaDRMBufferResource(uint32_t id, wl_client* client, Aquamarine::SDMABUFAttrs attrs_) { LOGM(Log::DEBUG, "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::DEBUG, " | plane {}: mod {} fd {} stride {} offset {}", i, attrs_.modifier, attrs_.fds[i], attrs_.strides[i], attrs_.offsets[i]); } m_buffer = makeShared(id, client, attrs_); m_buffer->m_resource->m_buffer = m_buffer; m_listeners.bufferResourceDestroy = m_buffer->events.destroy.listen([this] { m_listeners.bufferResourceDestroy.reset(); PROTO::mesaDRM->destroyResource(this); }); if (!m_buffer->m_success) LOGM(Log::ERR, "Possibly compositor bug: buffer failed to create"); } CMesaDRMBufferResource::~CMesaDRMBufferResource() { if (m_buffer && m_buffer->m_resource) m_buffer->m_resource->sendRelease(); m_buffer.reset(); m_listeners.bufferResourceDestroy.reset(); } bool CMesaDRMBufferResource::good() { return m_buffer && m_buffer->good(); } CMesaDRMResource::CMesaDRMResource(SP resource_) : m_resource(resource_) { if UNLIKELY (!good()) return; m_resource->setOnDestroy([this](CWlDrm* r) { PROTO::mesaDRM->destroyResource(this); }); m_resource->setAuthenticate([this](CWlDrm* r, uint32_t token) { // we don't need this m_resource->sendAuthenticated(); }); m_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"); }); m_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"); }); m_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; } uint64_t mod = DRM_FORMAT_MOD_INVALID; auto fmts = g_pHyprOpenGL->getDRMFormats(); for (auto const& f : fmts) { if (f.drmFormat != fmt) continue; for (auto const& m : f.modifiers) { if (m == DRM_FORMAT_MOD_LINEAR) continue; mod = m; break; } break; } Aquamarine::SDMABUFAttrs attrs; attrs.success = true; attrs.size = {w, h}; attrs.modifier = mod; attrs.planes = 1; attrs.offsets[0] = off0; attrs.strides[0] = str0; attrs.fds[0] = nameFd; attrs.format = fmt; const auto RESOURCE = PROTO::mesaDRM->m_buffers.emplace_back(makeShared(id, m_resource->client(), attrs)); if UNLIKELY (!RESOURCE->good()) { r->noMemory(); PROTO::mesaDRM->m_buffers.pop_back(); return; } // append instance so that buffer knows its owner RESOURCE->m_buffer->m_resource->m_buffer = RESOURCE->m_buffer; }); m_resource->sendDevice(PROTO::mesaDRM->m_nodeName.c_str()); m_resource->sendCapabilities(WL_DRM_CAPABILITY_PRIME); auto fmts = g_pHyprOpenGL->getDRMFormats(); for (auto const& fmt : fmts) { m_resource->sendFormat(fmt.drmFormat); } } bool CMesaDRMResource::good() { return m_resource->resource(); } CMesaDRMProtocol::CMesaDRMProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { drmDevice* dev = nullptr; int drmFD = g_pCompositor->m_drmRenderNode.fd >= 0 ? g_pCompositor->m_drmRenderNode.fd : g_pCompositor->m_drm.fd; if (drmGetDevice2(drmFD, 0, &dev) != 0) { LOGM(Log::ERR, "Failed to get device from fd {}, disabling MesaDRM", drmFD); removeGlobal(); return; } if (dev->available_nodes & (1 << DRM_NODE_RENDER) && dev->nodes[DRM_NODE_RENDER]) { m_nodeName = dev->nodes[DRM_NODE_RENDER]; } else if (dev->available_nodes & (1 << DRM_NODE_PRIMARY) && dev->nodes[DRM_NODE_PRIMARY]) { LOGM(Log::WARN, "No DRM render node, falling back to primary {}", dev->nodes[DRM_NODE_PRIMARY]); m_nodeName = dev->nodes[DRM_NODE_PRIMARY]; } else { LOGM(Log::ERR, "No usable DRM node (render or primary) found, disabling MesaDRM"); drmFreeDevice(&dev); removeGlobal(); return; } drmFreeDevice(&dev); } void CMesaDRMProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) { const auto RESOURCE = m_managers.emplace_back(makeShared(makeShared(client, ver, id))); if UNLIKELY (!RESOURCE->good()) { wl_client_post_no_memory(client); m_managers.pop_back(); return; } } void CMesaDRMProtocol::destroyResource(CMesaDRMResource* resource) { std::erase_if(m_managers, [&](const auto& other) { return other.get() == resource; }); } void CMesaDRMProtocol::destroyResource(CMesaDRMBufferResource* resource) { std::erase_if(m_buffers, [&](const auto& other) { return other.get() == resource; }); }