core: refactor and improve surface commit (#9805)
* make CHLBufferReference not a SP anymore
* copy over release and acquire points in CHLBufferReference
* use CHLBufferReference in screencopy and toplevel export
TODO: use CHLBufferReference in direct scanout properly
the only problem is the scanout buffer release timing,
specifically the onBackendRelease mechanism
* cleanup SSurfaceState and surface pending commit tracking
* move surface code from DRMSyncobj, and move acquire to SSurfaceState
* use queue for comitted pending surface states like proto says
"The content update is placed in a queue until it becomes active." - wl_surface::commit
* drop, not release, prev buffer if 2nd buffer wl_surface.attach is sent
"A wl_buffer that has been attached and then replaced by another attach instead of committed will not receive a release event, and is not used by the compositor." - wl_surface::attach
This commit is contained in:
parent
70ae99f521
commit
da86db43d4
15 changed files with 285 additions and 223 deletions
|
|
@ -40,13 +40,61 @@ void IHLBuffer::onBackendRelease(const std::function<void()>& fn) {
|
|||
});
|
||||
}
|
||||
|
||||
CHLBufferReference::CHLBufferReference(SP<IHLBuffer> buffer_, SP<CWLSurfaceResource> surface_) : buffer(buffer_), surface(surface_) {
|
||||
buffer->lock();
|
||||
CHLBufferReference::CHLBufferReference() : buffer(nullptr) {
|
||||
;
|
||||
}
|
||||
|
||||
CHLBufferReference::CHLBufferReference(const CHLBufferReference& other) : release(other.release), buffer(other.buffer) {
|
||||
if (buffer)
|
||||
buffer->lock();
|
||||
}
|
||||
|
||||
CHLBufferReference::CHLBufferReference(SP<IHLBuffer> buffer_) : buffer(buffer_) {
|
||||
if (buffer)
|
||||
buffer->lock();
|
||||
}
|
||||
|
||||
CHLBufferReference::~CHLBufferReference() {
|
||||
if (buffer)
|
||||
buffer->unlock();
|
||||
}
|
||||
|
||||
CHLBufferReference& CHLBufferReference::operator=(const CHLBufferReference& other) {
|
||||
if (other.buffer)
|
||||
other.buffer->lock();
|
||||
if (buffer)
|
||||
buffer->unlock();
|
||||
buffer = other.buffer;
|
||||
release = other.release;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool CHLBufferReference::operator==(const CHLBufferReference& other) const {
|
||||
return buffer == other.buffer;
|
||||
}
|
||||
|
||||
bool CHLBufferReference::operator==(const SP<IHLBuffer>& other) const {
|
||||
return buffer == other;
|
||||
}
|
||||
|
||||
bool CHLBufferReference::operator==(const SP<Aquamarine::IBuffer>& other) const {
|
||||
return buffer == other;
|
||||
}
|
||||
|
||||
SP<IHLBuffer> CHLBufferReference::operator->() const {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
CHLBufferReference::operator bool() const {
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void CHLBufferReference::drop() {
|
||||
if (!buffer)
|
||||
return;
|
||||
|
||||
buffer->unlock();
|
||||
buffer->nLocks--;
|
||||
ASSERT(buffer->nLocks >= 0);
|
||||
|
||||
buffer = nullptr;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include <aquamarine/buffer/Buffer.hpp>
|
||||
|
||||
class CSyncReleaser;
|
||||
class CHLBufferReference;
|
||||
|
||||
class IHLBuffer : public Aquamarine::IBuffer {
|
||||
public:
|
||||
|
|
@ -36,19 +37,28 @@ class IHLBuffer : public Aquamarine::IBuffer {
|
|||
|
||||
private:
|
||||
int nLocks = 0;
|
||||
|
||||
friend class CHLBufferReference;
|
||||
};
|
||||
|
||||
// for ref-counting. Releases in ~dtor
|
||||
// surface optional
|
||||
class CHLBufferReference {
|
||||
public:
|
||||
CHLBufferReference(SP<IHLBuffer> buffer, SP<CWLSurfaceResource> surface);
|
||||
CHLBufferReference();
|
||||
CHLBufferReference(const CHLBufferReference& other);
|
||||
CHLBufferReference(SP<IHLBuffer> buffer);
|
||||
~CHLBufferReference();
|
||||
|
||||
SP<IHLBuffer> buffer;
|
||||
UP<CDRMSyncPointState> acquire;
|
||||
UP<CDRMSyncPointState> release;
|
||||
CHLBufferReference& operator=(const CHLBufferReference& other);
|
||||
bool operator==(const CHLBufferReference& other) const;
|
||||
bool operator==(const SP<IHLBuffer>& other) const;
|
||||
bool operator==(const SP<Aquamarine::IBuffer>& other) const;
|
||||
SP<IHLBuffer> operator->() const;
|
||||
operator bool() const;
|
||||
|
||||
private:
|
||||
WP<CWLSurfaceResource> surface;
|
||||
// unlock and drop the buffer without sending release
|
||||
void drop();
|
||||
|
||||
CDRMSyncPointState release;
|
||||
SP<IHLBuffer> buffer;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ CRegion SSurfaceState::accumulateBufferDamage() {
|
|||
}
|
||||
|
||||
void SSurfaceState::updateSynchronousTexture(SP<CTexture> lastTexture) {
|
||||
auto [dataPtr, fmt, size] = buffer->buffer->beginDataPtr(0);
|
||||
auto [dataPtr, fmt, size] = buffer->beginDataPtr(0);
|
||||
if (dataPtr) {
|
||||
auto drmFmt = NFormatUtils::shmToDRM(fmt);
|
||||
auto stride = bufferSize.y ? size / bufferSize.y : 0;
|
||||
|
|
@ -45,49 +45,56 @@ void SSurfaceState::updateSynchronousTexture(SP<CTexture> lastTexture) {
|
|||
} else
|
||||
texture = makeShared<CTexture>(drmFmt, dataPtr, stride, bufferSize);
|
||||
}
|
||||
buffer->buffer->endDataPtr();
|
||||
buffer->endDataPtr();
|
||||
}
|
||||
|
||||
void SSurfaceState::reset() {
|
||||
updated.all = false;
|
||||
|
||||
// After commit, there is no pending buffer until the next attach.
|
||||
buffer = {};
|
||||
|
||||
// applies only to the buffer that is attached to the surface
|
||||
acquire = {};
|
||||
|
||||
// wl_surface.commit assings pending ... and clears pending damage.
|
||||
damage.clear();
|
||||
bufferDamage.clear();
|
||||
transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
scale = 1;
|
||||
offset = {};
|
||||
size = {};
|
||||
}
|
||||
|
||||
void SSurfaceState::updateFrom(SSurfaceState& ref) {
|
||||
updated = ref.updated;
|
||||
|
||||
if (ref.updated & SURFACE_UPDATED_BUFFER) {
|
||||
ref.updated &= ~SURFACE_UPDATED_BUFFER;
|
||||
*this = ref;
|
||||
ref.damage.clear();
|
||||
ref.bufferDamage.clear();
|
||||
ref.buffer.reset();
|
||||
} else {
|
||||
if (ref.updated & SURFACE_UPDATED_DAMAGE) {
|
||||
damage = ref.damage;
|
||||
bufferDamage = ref.bufferDamage;
|
||||
}
|
||||
|
||||
if (ref.updated & SURFACE_UPDATED_INPUT)
|
||||
input = ref.input;
|
||||
|
||||
if (ref.updated & SURFACE_UPDATED_OPAQUE)
|
||||
opaque = ref.opaque;
|
||||
|
||||
if (ref.updated & SURFACE_UPDATED_OFFSET)
|
||||
offset = ref.offset;
|
||||
|
||||
if (ref.updated & SURFACE_UPDATED_SCALE)
|
||||
scale = ref.scale;
|
||||
|
||||
if (ref.updated & SURFACE_UPDATED_VIEWPORT)
|
||||
viewport = ref.viewport;
|
||||
|
||||
if (ref.updated & SURFACE_UPDATED_TRANSFORM)
|
||||
transform = ref.transform;
|
||||
if (ref.updated.buffer) {
|
||||
buffer = ref.buffer;
|
||||
texture = ref.texture;
|
||||
size = ref.size;
|
||||
bufferSize = ref.bufferSize;
|
||||
}
|
||||
|
||||
if (ref.updated.damage) {
|
||||
damage = ref.damage;
|
||||
bufferDamage = ref.bufferDamage;
|
||||
}
|
||||
|
||||
if (ref.updated.input)
|
||||
input = ref.input;
|
||||
|
||||
if (ref.updated.opaque)
|
||||
opaque = ref.opaque;
|
||||
|
||||
if (ref.updated.offset)
|
||||
offset = ref.offset;
|
||||
|
||||
if (ref.updated.scale)
|
||||
scale = ref.scale;
|
||||
|
||||
if (ref.updated.transform)
|
||||
transform = ref.transform;
|
||||
|
||||
if (ref.updated.viewport)
|
||||
viewport = ref.viewport;
|
||||
|
||||
if (ref.updated.acquire)
|
||||
acquire = ref.acquire;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,44 +2,59 @@
|
|||
|
||||
#include "../../helpers/math/Math.hpp"
|
||||
#include "../WaylandProtocol.hpp"
|
||||
#include "./Buffer.hpp"
|
||||
|
||||
class CHLBufferReference;
|
||||
class CTexture;
|
||||
class CDRMSyncPointState;
|
||||
|
||||
struct SSurfaceState {
|
||||
enum eUpdatedProperties : uint8_t {
|
||||
SURFACE_UPDATED_OPAQUE = 1 << 0,
|
||||
SURFACE_UPDATED_INPUT = 1 << 1,
|
||||
SURFACE_UPDATED_DAMAGE = 1 << 2,
|
||||
SURFACE_UPDATED_SCALE = 1 << 3,
|
||||
SURFACE_UPDATED_BUFFER = 1 << 4,
|
||||
SURFACE_UPDATED_OFFSET = 1 << 5,
|
||||
SURFACE_UPDATED_VIEWPORT = 1 << 6,
|
||||
SURFACE_UPDATED_TRANSFORM = 1 << 7,
|
||||
};
|
||||
union {
|
||||
uint16_t all = 0;
|
||||
struct {
|
||||
bool buffer : 1;
|
||||
bool damage : 1;
|
||||
bool opaque : 1;
|
||||
bool input : 1;
|
||||
bool transform : 1;
|
||||
bool scale : 1;
|
||||
bool offset : 1;
|
||||
bool viewport : 1;
|
||||
bool acquire : 1;
|
||||
};
|
||||
} updated;
|
||||
|
||||
CRegion opaque, input = CBox{{}, {INT32_MAX, INT32_MAX}}, damage, bufferDamage = CBox{{}, {INT32_MAX, INT32_MAX}} /* initial damage */;
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL;
|
||||
int scale = 1;
|
||||
SP<CHLBufferReference> buffer; // buffer ref will be released once the buffer is no longer locked. For checking if a buffer is attached to this state, check texture.
|
||||
SP<CTexture> texture;
|
||||
Vector2D offset;
|
||||
Vector2D size, bufferSize;
|
||||
bool rejected = false;
|
||||
|
||||
// initial values, copied from protocol text
|
||||
CHLBufferReference buffer = {}; // The initial surface contents are void
|
||||
CRegion damage, bufferDamage; // The initial value for pending damage is empty
|
||||
CRegion opaque; // The initial value for an opaque region is empty
|
||||
CRegion input = CBox{{}, {INT32_MAX, INT32_MAX}}; // The initial value for an input region is infinite
|
||||
wl_output_transform transform = WL_OUTPUT_TRANSFORM_NORMAL; // A newly created surface has its buffer transformation set to normal
|
||||
int scale = 1; // A newly created surface has its buffer scale set to 1
|
||||
|
||||
// these don't have well defined initial values in the protocol, but these work
|
||||
Vector2D size, bufferSize;
|
||||
Vector2D offset;
|
||||
|
||||
// viewporter protocol surface state
|
||||
struct {
|
||||
bool hasDestination = false;
|
||||
bool hasSource = false;
|
||||
Vector2D destination;
|
||||
CBox source;
|
||||
} viewport;
|
||||
bool rejected = false;
|
||||
uint8_t updated = 0; // eUpdatedProperties. Stores what the last update changed
|
||||
|
||||
Vector2D sourceSize();
|
||||
// Translates damage into bufferDamage, clearing damage and returning the updated bufferDamage
|
||||
CRegion accumulateBufferDamage();
|
||||
void updateSynchronousTexture(SP<CTexture> lastTexture);
|
||||
void reset();
|
||||
// updates this state from a reference state. Mutates the reference state. If a new buffer is committed,
|
||||
// reference state gets its damage and buffer cleared.
|
||||
void updateFrom(SSurfaceState& ref);
|
||||
|
||||
// drm syncobj protocol surface state
|
||||
CDRMSyncPointState acquire;
|
||||
|
||||
// texture of surface content, used for rendering
|
||||
SP<CTexture> texture;
|
||||
void updateSynchronousTexture(SP<CTexture> lastTexture);
|
||||
|
||||
// helpers
|
||||
CRegion accumulateBufferDamage(); // transforms state.damage and merges it into state.bufferDamage
|
||||
void updateFrom(SSurfaceState& ref); // updates this state based on a reference state.
|
||||
void reset(); // resets pending state after commit
|
||||
};
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue