diff --git a/include/aquamarine/output/Output.hpp b/include/aquamarine/output/Output.hpp index 7aa6307..69603d5 100644 --- a/include/aquamarine/output/Output.hpp +++ b/include/aquamarine/output/Output.hpp @@ -37,17 +37,52 @@ namespace Aquamarine { class COutputState { public: - // TODO: make this state private, this sucks - Hyprutils::Math::CRegion damage; - bool enabled = false; - bool adaptiveSync = false; - eOutputPresentationMode presentationMode = AQ_OUTPUT_PRESENTATION_VSYNC; - std::vector gammaLut; - Hyprutils::Math::Vector2D lastModeSize; - Hyprutils::Memory::CWeakPointer mode; - Hyprutils::Memory::CSharedPointer customMode; - uint32_t drmFormat = DRM_FORMAT_INVALID; - Hyprutils::Memory::CSharedPointer buffer; + enum eOutputStateProperties : uint32_t { + AQ_OUTPUT_STATE_DAMAGE = (1 << 0), + AQ_OUTPUT_STATE_ENABLED = (1 << 1), + AQ_OUTPUT_STATE_ADAPTIVE_SYNC = (1 << 2), + AQ_OUTPUT_STATE_PRESENTATION_MODE = (1 << 3), + AQ_OUTPUT_STATE_GAMMA_LUT = (1 << 4), + AQ_OUTPUT_STATE_MODE = (1 << 5), + AQ_OUTPUT_STATE_FORMAT = (1 << 6), + AQ_OUTPUT_STATE_BUFFER = (1 << 7), + }; + + struct SInternalState { + uint32_t committed = 0; // enum eOutputStateProperties + + Hyprutils::Math::CRegion damage; + bool enabled = false; + bool adaptiveSync = false; + eOutputPresentationMode presentationMode = AQ_OUTPUT_PRESENTATION_VSYNC; + std::vector gammaLut; + Hyprutils::Math::Vector2D lastModeSize; + Hyprutils::Memory::CWeakPointer mode; + Hyprutils::Memory::CSharedPointer customMode; + uint32_t drmFormat = DRM_FORMAT_INVALID; + Hyprutils::Memory::CSharedPointer buffer; + }; + + const SInternalState& state(); + + void addDamage(const Hyprutils::Math::CRegion& region); + void clearDamage(); + void setEnabled(bool enabled); + void setAdaptiveSync(bool enabled); + void setPresentationMode(eOutputPresentationMode mode); + void setGammaLut(const std::vector& lut); + void setMode(Hyprutils::Memory::CSharedPointer mode); + void setCustomMode(Hyprutils::Memory::CSharedPointer mode); + void setFormat(uint32_t drmFormat); + void setBuffer(Hyprutils::Memory::CSharedPointer buffer); + + private: + SInternalState internalState; + + void onCommit(); // clears a few props like damage and committed. + + friend class IOutput; + friend class CWaylandOutput; }; class IOutput { @@ -68,7 +103,6 @@ namespace Aquamarine { std::string name, description, make, model, serial; Hyprutils::Math::Vector2D physicalSize; bool enabled = false; - bool adaptiveSync = false; bool nonDesktop = false; eSubpixelMode subpixel = AQ_SUBPIXEL_NONE; diff --git a/src/backend/Wayland.cpp b/src/backend/Wayland.cpp index fa4e322..654b7d6 100644 --- a/src/backend/Wayland.cpp +++ b/src/backend/Wayland.cpp @@ -231,10 +231,12 @@ Aquamarine::CWaylandPointer::CWaylandPointer(SP pointer_, Hyprutils backend->backend->log(AQ_LOG_DEBUG, "New wayland pointer wl_pointer"); pointer->setMotion([this](CCWlPointer* r, uint32_t serial, wl_fixed_t x, wl_fixed_t y) { - if (!backend->focusedOutput || (!backend->focusedOutput->state->mode && !backend->focusedOutput->state->customMode)) + const auto STATE = backend->focusedOutput->state->state(); + + if (!backend->focusedOutput || (!STATE.mode && !STATE.customMode)) return; - const Vector2D size = backend->focusedOutput->state->customMode ? backend->focusedOutput->state->customMode->pixelSize : backend->focusedOutput->state->mode->pixelSize; + const Vector2D size = STATE.customMode ? STATE.customMode->pixelSize : STATE.mode->pixelSize; Vector2D local = {wl_fixed_to_double(x), wl_fixed_to_double(y)}; local = local / size; @@ -496,16 +498,16 @@ bool Aquamarine::CWaylandOutput::commit() { Vector2D pixelSize = {}; uint32_t refreshRate = 0; - if (state->customMode) - pixelSize = state->customMode->pixelSize; - else if (state->mode) - pixelSize = state->mode->pixelSize; + if (state->internalState.customMode) + pixelSize = state->internalState.customMode->pixelSize; + else if (state->internalState.mode) + pixelSize = state->internalState.mode->pixelSize; else { backend->backend->log(AQ_LOG_ERROR, std::format("Output {}: pending state rejected: invalid mode", name)); return false; } - uint32_t format = state->drmFormat; + uint32_t format = state->internalState.drmFormat; if (format == DRM_FORMAT_INVALID) { backend->backend->log(AQ_LOG_ERROR, std::format("Output {}: pending state rejected: invalid format", name)); @@ -522,12 +524,19 @@ bool Aquamarine::CWaylandOutput::commit() { return false; } - if (!state->buffer) { - backend->backend->log(AQ_LOG_ERROR, std::format("Output {}: pending state rejected: no buffer", name)); - return false; + if (!state->internalState.buffer) { + // if the consumer explicitly committed a null buffer, that's a violation. + if (state->internalState.committed & COutputState::AQ_OUTPUT_STATE_BUFFER) { + backend->backend->log(AQ_LOG_ERROR, std::format("Output {}: pending state rejected: no buffer", name)); + return false; + } + + events.commit.emit(); + state->onCommit(); + return true; } - auto wlBuffer = wlBufferFromBuffer(state->buffer); + auto wlBuffer = wlBufferFromBuffer(state->internalState.buffer); if (!wlBuffer) { backend->backend->log(AQ_LOG_ERROR, std::format("Output {}: pending state rejected: no wlBuffer??", name)); @@ -547,6 +556,8 @@ bool Aquamarine::CWaylandOutput::commit() { events.commit.emit(); + state->onCommit(); + return true; } diff --git a/src/output/Output.cpp b/src/output/Output.cpp index 207aee3..f81ee1c 100644 --- a/src/output/Output.cpp +++ b/src/output/Output.cpp @@ -26,3 +26,64 @@ void Aquamarine::IOutput::scheduleFrame() { Hyprutils::Math::Vector2D Aquamarine::IOutput::maxCursorSize() { return {}; // error } + +const Aquamarine::COutputState::SInternalState& Aquamarine::COutputState::state() { + return internalState; +} + +void Aquamarine::COutputState::addDamage(const Hyprutils::Math::CRegion& region) { + internalState.damage.add(region); + internalState.committed |= AQ_OUTPUT_STATE_DAMAGE; +} + +void Aquamarine::COutputState::clearDamage() { + internalState.damage.clear(); + internalState.committed |= AQ_OUTPUT_STATE_DAMAGE; +} + +void Aquamarine::COutputState::setEnabled(bool enabled) { + internalState.enabled = enabled; + internalState.committed |= AQ_OUTPUT_STATE_ENABLED; +} + +void Aquamarine::COutputState::setAdaptiveSync(bool enabled) { + internalState.adaptiveSync = enabled; + internalState.committed |= AQ_OUTPUT_STATE_ADAPTIVE_SYNC; +} + +void Aquamarine::COutputState::setPresentationMode(eOutputPresentationMode mode) { + internalState.presentationMode = mode; + internalState.committed |= AQ_OUTPUT_STATE_PRESENTATION_MODE; +} + +void Aquamarine::COutputState::setGammaLut(const std::vector& lut) { + internalState.gammaLut = lut; + internalState.committed |= AQ_OUTPUT_STATE_GAMMA_LUT; +} + +void Aquamarine::COutputState::setMode(Hyprutils::Memory::CSharedPointer mode) { + internalState.mode = mode; + internalState.customMode = nullptr; + internalState.committed |= AQ_OUTPUT_STATE_MODE; +} + +void Aquamarine::COutputState::setCustomMode(Hyprutils::Memory::CSharedPointer mode) { + internalState.mode.reset(); + internalState.customMode = mode; + internalState.committed |= AQ_OUTPUT_STATE_MODE; +} + +void Aquamarine::COutputState::setFormat(uint32_t drmFormat) { + internalState.drmFormat = drmFormat; + internalState.committed |= AQ_OUTPUT_STATE_FORMAT; +} + +void Aquamarine::COutputState::setBuffer(Hyprutils::Memory::CSharedPointer buffer) { + internalState.buffer = buffer; + internalState.committed |= AQ_OUTPUT_STATE_BUFFER; +} + +void Aquamarine::COutputState::onCommit() { + internalState.committed = 0; + internalState.damage.clear(); +} diff --git a/tests/SimpleWindow.cpp b/tests/SimpleWindow.cpp index b0a3a9d..52b6fda 100644 --- a/tests/SimpleWindow.cpp +++ b/tests/SimpleWindow.cpp @@ -34,16 +34,16 @@ void onFrame() { auto buf = output->swapchain->next(nullptr); - output->state->buffer = buf; + output->state->setBuffer(buf); output->commit(); } void onState(const Aquamarine::IOutput::SStateEvent& event) { std::cout << "[Client] onState with size " << std::format("{}", event.size) << "\n"; - output->state->enabled = true; - output->state->customMode = makeShared(Aquamarine::SOutputMode{.pixelSize = event.size}); - output->state->drmFormat = DRM_FORMAT_XRGB8888; + output->state->setEnabled(true); + output->state->setCustomMode(makeShared(Aquamarine::SOutputMode{.pixelSize = event.size})); + output->state->setFormat(DRM_FORMAT_XRGB8888); output->commit(); }