Skip to content

Commit d005ce7

Browse files
committed
misc: Add strict typing to attachment manager
1 parent 09b3fd5 commit d005ce7

File tree

6 files changed

+64
-77
lines changed

6 files changed

+64
-77
lines changed

include/aquamarine/backend/DRM.hpp

-6
Original file line numberDiff line numberDiff line change
@@ -25,9 +25,6 @@ namespace Aquamarine {
2525
virtual ~CDRMBufferAttachment() {
2626
;
2727
}
28-
virtual eAttachmentType type() {
29-
return AQ_ATTACHMENT_DRM_BUFFER;
30-
}
3128

3229
Hyprutils::Memory::CSharedPointer<CDRMFB> fb;
3330
};
@@ -40,9 +37,6 @@ namespace Aquamarine {
4037
virtual ~CDRMBufferUnimportable() {
4138
;
4239
}
43-
virtual eAttachmentType type() {
44-
return AQ_ATTACHMENT_DRM_KMS_UNIMPORTABLE;
45-
}
4640
};
4741

4842
class CDRMLease {

include/aquamarine/misc/Attachment.hpp

+38-15
Original file line numberDiff line numberDiff line change
@@ -2,33 +2,56 @@
22

33
#include <vector>
44
#include <hyprutils/memory/SharedPtr.hpp>
5+
#include <unordered_map>
6+
#include <typeindex>
57

68
namespace Aquamarine {
7-
enum eAttachmentType : uint32_t {
8-
AQ_ATTACHMENT_DRM_BUFFER = 0,
9-
AQ_ATTACHMENT_DRM_KMS_UNIMPORTABLE,
10-
AQ_ATTACHMENT_DRM_RENDERER_DATA,
11-
};
12-
139
class IAttachment {
1410
public:
1511
virtual ~IAttachment() {
1612
;
1713
}
18-
19-
virtual eAttachmentType type() = 0;
2014
};
2115

16+
template <typename T>
17+
concept AttachmentConcept = std::is_base_of_v<IAttachment, T>;
18+
19+
// CAttachmentManager is a registry for arbitrary attachment types.
20+
// Any type implementing IAttachment can be added, retrieved, and removed from the registry.
21+
// However, only one attachment of a given type is permitted.
2222
class CAttachmentManager {
2323
public:
24-
bool has(eAttachmentType type);
25-
Hyprutils::Memory::CSharedPointer<IAttachment> get(eAttachmentType type);
26-
void add(Hyprutils::Memory::CSharedPointer<IAttachment> attachment);
27-
void remove(Hyprutils::Memory::CSharedPointer<IAttachment> attachment);
28-
void removeByType(eAttachmentType type);
29-
void clear();
24+
// has checks if the manager has an attachment of the specified type
25+
template <AttachmentConcept T>
26+
bool has() const {
27+
return attachments.contains(typeid(T));
28+
}
29+
// get retrieves the attachment on the specified type,
30+
// returning nullptr if no attachment of the specified type is present.
31+
template <AttachmentConcept T>
32+
const Hyprutils::Memory::CSharedPointer<T>& get() const {
33+
auto it = attachments.find(typeid(T));
34+
if (it == attachments.end())
35+
return nullptr;
36+
// Reinterpret SP<IAttachment> into SP<T>.
37+
// This is safe because we looked up this attachment by typeid(T),
38+
// so it must be an SP<T>.
39+
return *reinterpret_cast<Hyprutils::Memory::CSharedPointer<T>*>(&it->second);
40+
}
41+
// add adds an attachment, removing the previous attachment of the same type if it exists
42+
void add(Hyprutils::Memory::CSharedPointer<IAttachment> attachment);
43+
// remove removes the specified attachment, doing nothing if it does not exist.
44+
// Note that this will not remove a different attachment of the same type.
45+
void remove(Hyprutils::Memory::CSharedPointer<IAttachment> attachment);
46+
// remove removes the attachment of the specified type, doing nothing if it does not exist
47+
template <AttachmentConcept T>
48+
void removeByType() {
49+
attachments.erase(typeid(T));
50+
}
51+
// clear removes all attachments
52+
void clear();
3053

3154
private:
32-
std::vector<Hyprutils::Memory::CSharedPointer<IAttachment>> attachments;
55+
std::unordered_map<std::type_index, Hyprutils::Memory::CSharedPointer<IAttachment>> attachments;
3356
};
3457
};

src/backend/drm/DRM.cpp

+4-5
Original file line numberDiff line numberDiff line change
@@ -1621,7 +1621,7 @@ bool Aquamarine::CDRMOutput::commitState(bool onlyTest) {
16211621
return false;
16221622
}
16231623

1624-
if ((COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_BUFFER) && STATE.buffer->attachments.has(AQ_ATTACHMENT_DRM_KMS_UNIMPORTABLE)) {
1624+
if ((COMMITTED & COutputState::eOutputStateProperties::AQ_OUTPUT_STATE_BUFFER) && STATE.buffer->attachments.has<CDRMBufferUnimportable>()) {
16251625
TRACE(backend->backend->log(AQ_LOG_TRACE, "drm: Cannot commit a KMS-unimportable buffer."));
16261626
return false;
16271627
}
@@ -2003,9 +2003,8 @@ SP<CDRMFB> Aquamarine::CDRMFB::create(SP<IBuffer> buffer_, Hyprutils::Memory::CW
20032003
if (isNew)
20042004
*isNew = true;
20052005

2006-
if (buffer_->attachments.has(AQ_ATTACHMENT_DRM_BUFFER)) {
2007-
auto at = (CDRMBufferAttachment*)buffer_->attachments.get(AQ_ATTACHMENT_DRM_BUFFER).get();
2008-
fb = at->fb;
2006+
if (auto at = buffer_->attachments.get<CDRMBufferAttachment>()) {
2007+
fb = at->fb;
20092008
TRACE(backend_->log(AQ_LOG_TRACE, std::format("drm: CDRMFB: buffer has drmfb attachment with fb {:x}", (uintptr_t)fb.get())));
20102009
}
20112010

@@ -2036,7 +2035,7 @@ void Aquamarine::CDRMFB::import() {
20362035
return;
20372036
}
20382037

2039-
if (buffer->attachments.has(AQ_ATTACHMENT_DRM_KMS_UNIMPORTABLE)) {
2038+
if (buffer->attachments.has<CDRMBufferUnimportable>()) {
20402039
backend->backend->log(AQ_LOG_ERROR, "drm: Buffer submitted is unimportable");
20412040
return;
20422041
}

src/backend/drm/Renderer.cpp

+16-26
Original file line numberDiff line numberDiff line change
@@ -698,14 +698,10 @@ constexpr GLenum PIXEL_BUFFER_FORMAT = GL_RGBA;
698698

699699
void CDRMRenderer::readBuffer(Hyprutils::Memory::CSharedPointer<IBuffer> buf, std::span<uint8_t> out) {
700700
CEglContextGuard eglContext(*this);
701-
auto hadAttachment = buf->attachments.get(AQ_ATTACHMENT_DRM_RENDERER_DATA);
702-
auto att = (CDRMRendererBufferAttachment*)hadAttachment.get();
703-
if (!hadAttachment) {
704-
// should never remove anything, but JIC. We'll leak an EGLImage if this removes anything.
705-
buf->attachments.removeByType(AQ_ATTACHMENT_DRM_RENDERER_DATA);
706-
auto newAttachment = makeShared<CDRMRendererBufferAttachment>(self, buf, nullptr, 0, 0, SGLTex{}, std::vector<uint8_t>());
707-
att = newAttachment.get();
708-
buf->attachments.add(newAttachment);
701+
auto att = buf->attachments.get<CDRMRendererBufferAttachment>();
702+
if (!att) {
703+
att = makeShared<CDRMRendererBufferAttachment>(self, buf, nullptr, 0, 0, SGLTex{}, std::vector<uint8_t>());
704+
buf->attachments.add(att);
709705
}
710706

711707
auto dma = buf->dmabuf();
@@ -886,31 +882,28 @@ CDRMRenderer::SBlitResult CDRMRenderer::blit(SP<IBuffer> from, SP<IBuffer> to, S
886882
auto fromDma = from->dmabuf();
887883
std::span<uint8_t> intermediateBuf;
888884
{
889-
auto attachment = from->attachments.get(AQ_ATTACHMENT_DRM_RENDERER_DATA);
885+
auto attachment = from->attachments.get<CDRMRendererBufferAttachment>();
890886
if (attachment) {
891887
TRACE(backend->log(AQ_LOG_TRACE, "EGL (blit): From attachment found"));
892-
auto att = (CDRMRendererBufferAttachment*)attachment.get();
893-
fromTex = att->tex;
894-
intermediateBuf = att->intermediateBuf;
888+
fromTex = attachment->tex;
889+
intermediateBuf = attachment->intermediateBuf;
895890
}
896891

897892
if (!fromTex.image && intermediateBuf.empty()) {
898893
backend->log(AQ_LOG_DEBUG, "EGL (blit): No attachment in from, creating a new image");
899894
fromTex = glTex(from);
900895

901-
auto newAttachment = makeShared<CDRMRendererBufferAttachment>(self, from, nullptr, 0, 0, fromTex, std::vector<uint8_t>());
896+
attachment = makeShared<CDRMRendererBufferAttachment>(self, from, nullptr, 0, 0, fromTex, std::vector<uint8_t>());
897+
from->attachments.add(attachment);
898+
902899
if (!fromTex.image && primaryRenderer) {
903900
backend->log(AQ_LOG_DEBUG, "EGL (blit): Failed to create image from source buffer directly, allocating intermediate buffer");
904901
static_assert(PIXEL_BUFFER_FORMAT == GL_RGBA); // If the pixel buffer format changes, the below size calculation probably needs to as well.
905-
newAttachment->intermediateBuf.resize(fromDma.size.x * fromDma.size.y * 4);
906-
intermediateBuf = newAttachment->intermediateBuf;
902+
attachment->intermediateBuf.resize(fromDma.size.x * fromDma.size.y * 4);
903+
intermediateBuf = attachment->intermediateBuf;
907904
fromTex.target = GL_TEXTURE_2D;
908905
GLCALL(glGenTextures(1, &fromTex.texid));
909906
}
910-
911-
// should never remove anything, but JIC. We'll leak an EGLImage if this removes anything.
912-
from->attachments.removeByType(AQ_ATTACHMENT_DRM_RENDERER_DATA);
913-
from->attachments.add(newAttachment);
914907
}
915908

916909
if (!intermediateBuf.empty() && primaryRenderer) {
@@ -936,13 +929,12 @@ CDRMRenderer::SBlitResult CDRMRenderer::blit(SP<IBuffer> from, SP<IBuffer> to, S
936929
}
937930

938931
{
939-
auto attachment = to->attachments.get(AQ_ATTACHMENT_DRM_RENDERER_DATA);
932+
auto attachment = to->attachments.get<CDRMRendererBufferAttachment>();
940933
if (attachment) {
941934
TRACE(backend->log(AQ_LOG_TRACE, "EGL (blit): To attachment found"));
942-
auto att = (CDRMRendererBufferAttachment*)attachment.get();
943-
rboImage = att->eglImage;
944-
fboID = att->fbo;
945-
rboID = att->rbo;
935+
rboImage = attachment->eglImage;
936+
fboID = attachment->fbo;
937+
rboID = attachment->rbo;
946938
}
947939

948940
if (!rboImage) {
@@ -968,8 +960,6 @@ CDRMRenderer::SBlitResult CDRMRenderer::blit(SP<IBuffer> from, SP<IBuffer> to, S
968960
return {};
969961
}
970962

971-
// should never remove anything, but JIC. We'll leak an RBO and FBO if this removes anything.
972-
to->attachments.removeByType(AQ_ATTACHMENT_DRM_RENDERER_DATA);
973963
to->attachments.add(makeShared<CDRMRendererBufferAttachment>(self, to, rboImage, fboID, rboID, SGLTex{}, std::vector<uint8_t>()));
974964
}
975965
}

src/backend/drm/Renderer.hpp

-3
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,6 @@ namespace Aquamarine {
2929
virtual ~CDRMRendererBufferAttachment() {
3030
;
3131
}
32-
virtual eAttachmentType type() {
33-
return AQ_ATTACHMENT_DRM_RENDERER_DATA;
34-
}
3532

3633
EGLImageKHR eglImage = nullptr;
3734
GLuint fbo = 0, rbo = 0;

src/misc/Attachment.cpp

+6-22
Original file line numberDiff line numberDiff line change
@@ -4,32 +4,16 @@ using namespace Aquamarine;
44
using namespace Hyprutils::Memory;
55
#define SP CSharedPointer
66

7-
bool Aquamarine::CAttachmentManager::has(eAttachmentType type) {
8-
for (auto const& a : attachments) {
9-
if (a->type() == type)
10-
return true;
11-
}
12-
return false;
13-
}
14-
15-
SP<IAttachment> Aquamarine::CAttachmentManager::get(eAttachmentType type) {
16-
for (auto const& a : attachments) {
17-
if (a->type() == type)
18-
return a;
19-
}
20-
return nullptr;
21-
}
22-
237
void Aquamarine::CAttachmentManager::add(SP<IAttachment> attachment) {
24-
attachments.emplace_back(attachment);
8+
const IAttachment& att = *attachment;
9+
attachments[typeid(att)] = attachment;
2510
}
2611

2712
void Aquamarine::CAttachmentManager::remove(SP<IAttachment> attachment) {
28-
std::erase(attachments, attachment);
29-
}
30-
31-
void Aquamarine::CAttachmentManager::removeByType(eAttachmentType type) {
32-
std::erase_if(attachments, [type](const auto& e) { return e->type() == type; });
13+
const IAttachment& att = *attachment;
14+
auto it = attachments.find(typeid(att));
15+
if (it != attachments.end())
16+
attachments.erase(it);
3317
}
3418

3519
void Aquamarine::CAttachmentManager::clear() {

0 commit comments

Comments
 (0)