Skip to content

Commit 04e8d4d

Browse files
Development/compositor race conditions (#912)
* Compositor: Simplified the backend state to just an idle flag * Compositor: Remove state from client * Compositor: Remove continue flag from presenter * Compositor: Replace compositor state tracking with Commit protection * Compositor: update README * Compositor: DRM backend clean up * Compositor: Remove unused states --------- Co-authored-by: Pierre Wielders <pierre@wielders.net>
1 parent 2542bf9 commit 04e8d4d

File tree

7 files changed

+684
-422
lines changed

7 files changed

+684
-422
lines changed

Compositor/lib/Mesa/Compositor.cpp

Lines changed: 39 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -138,12 +138,6 @@ namespace Plugin {
138138
private:
139139
using BaseClass = Graphics::ServerBufferType<1>;
140140

141-
enum class State : uint8_t {
142-
IDLE = 0x00,
143-
RENDERING = 0x01,
144-
PRESENTING = 0x02,
145-
};
146-
147141
class Remote : public Exchange::IComposition::IClient {
148142
public:
149143
Remote() = delete;
@@ -240,7 +234,6 @@ namespace Plugin {
240234
, _geometry({ 0, 0, width, height })
241235
, _texture()
242236
, _remoteClient(*this)
243-
, _state(State::IDLE)
244237
, _geometryChanged(false)
245238
{
246239
Core::ResourceMonitor::Instance().Register(*this);
@@ -284,34 +277,17 @@ namespace Plugin {
284277
*/
285278
void Request() override
286279
{
287-
State expected(State::IDLE);
288-
289-
if (_state.compare_exchange_strong(expected, State::RENDERING) == true) {
290-
_parent.Render(); // Trigger rendering operations
291-
} else {
292-
TRACE(Trace::Error, (_T("Surface %s[%d] is not idle, but received a Request event while in %d"), _callsign.c_str(), _id, _state.load()));
293-
ASSERT(false);
294-
}
280+
_parent.Render();
295281
}
296282

297283
void Pending()
298284
{
299-
State expected(State::RENDERING);
300-
301-
if (_state.compare_exchange_strong(expected, State::PRESENTING) == true) {
302-
Rendered();
303-
} else {
304-
TRACE(Trace::Error, (_T("Surface %s[%d] is not rendering, but received a Pending event while in %d"), _callsign.c_str(), _id, _state.load()));
305-
}
285+
Rendered();
306286
}
307287

308288
void Completed()
309289
{
310-
State expected(State::PRESENTING);
311-
312-
if (_state.compare_exchange_strong(expected, State::IDLE) == true) {
313-
Published();
314-
}
290+
Published();
315291
}
316292

317293
/**
@@ -390,8 +366,7 @@ namespace Plugin {
390366
Exchange::IComposition::Rectangle _geometry; // the actual geometry of the surface on the composition
391367
Core::ProxyType<Compositor::IRenderer::ITexture> _texture; // the texture handle that is known in the GPU/Renderer.
392368
Remote _remoteClient;
393-
std::atomic<State> _state;
394-
bool _geometryChanged = false;
369+
bool _geometryChanged;
395370

396371
static uint32_t _sequence;
397372
}; // class Client
@@ -550,9 +525,9 @@ namespace Plugin {
550525
return _connector;
551526
}
552527

553-
void Commit()
528+
uint32_t Commit()
554529
{
555-
_connector->Commit();
530+
return _connector->Commit();
556531
}
557532

558533
private:
@@ -586,8 +561,10 @@ namespace Plugin {
586561
, _renderDescriptor(Compositor::InvalidFileDescriptor)
587562
, _renderNode()
588563
, _present(*this)
589-
, _state(State::IDLE)
590564
, _autoScale(true)
565+
, _commitMutex()
566+
, _commitCV()
567+
, _canCommit(true)
591568
{
592569
}
593570
~CompositorImplementation() override
@@ -643,10 +620,10 @@ namespace Plugin {
643620
_renderer = Compositor::IRenderer::Instance(_renderDescriptor);
644621
ASSERT(_renderer.IsValid());
645622

646-
if(config.AutoScale.IsSet() == true) {
623+
if (config.AutoScale.IsSet() == true) {
647624
_autoScale = config.AutoScale.Value();
648-
}
649-
625+
}
626+
650627
if (config.Output.IsSet() == false) {
651628
return Core::ERROR_INCOMPLETE_CONFIG;
652629
} else {
@@ -813,12 +790,6 @@ namespace Plugin {
813790
END_INTERFACE_MAP
814791

815792
private:
816-
enum class State : uint8_t {
817-
IDLE = 0x00,
818-
PRESENTING = 0x01,
819-
PENDING = 0x02,
820-
};
821-
822793
void VSync(const Compositor::IOutput* output VARIABLE_IS_NOT_USED, const uint32_t sequence VARIABLE_IS_NOT_USED, const uint64_t pts VARIABLE_IS_NOT_USED /*usec since epoch*/)
823794
{
824795
{
@@ -828,28 +799,16 @@ namespace Plugin {
828799
});
829800
}
830801

831-
State expected = State::PRESENTING;
832-
833-
if (_state.compare_exchange_strong(expected, State::IDLE) == false) {
834-
expected = State::PENDING;
835-
836-
if (_state.compare_exchange_strong(expected, State::PRESENTING) == true) {
837-
_present.Trigger();
838-
}
802+
{
803+
std::lock_guard<std::mutex> lock(_commitMutex);
804+
_canCommit.store(true, std::memory_order_release);
839805
}
806+
_commitCV.notify_one();
840807
}
841808

842809
void Render()
843810
{
844-
State expected = State::PRESENTING;
845-
846-
if (_state.compare_exchange_strong(expected, State::PENDING) == false) {
847-
expected = State::IDLE;
848-
849-
if (_state.compare_exchange_strong(expected, State::PRESENTING) == true) {
850-
_present.Trigger();
851-
}
852-
}
811+
_present.Run();
853812
}
854813

855814
IComposition::IClient* CreateClient(const string& name, const uint32_t width, const uint32_t height) override
@@ -890,6 +849,7 @@ namespace Plugin {
890849

891850
{
892851
std::lock_guard<std::mutex> lock(_clientLock);
852+
893853
_clients.Visit([&](const string& /*name*/, const Core::ProxyType<Client> client) {
894854
RenderClient(client); // ~500-900 uS rpi4
895855
});
@@ -899,7 +859,24 @@ namespace Plugin {
899859

900860
_renderer->Unbind(frameBuffer);
901861

902-
_output->Commit(); // Blit to screen
862+
// Block until VSync allows commit
863+
{
864+
std::unique_lock<std::mutex> lock(_commitMutex);
865+
866+
if (_commitCV.wait_for(lock, std::chrono::milliseconds(100), [this] {
867+
return _canCommit.load(std::memory_order_acquire); // Wait for permission
868+
})) {
869+
// Got permission, reset it for next frame
870+
_canCommit.store(false, std::memory_order_release);
871+
} else {
872+
TRACE(Trace::Error, (_T("Timeout waiting for VSync, forcing commit")));
873+
// Don't reset _canCommit on timeout - let VSync handle it
874+
}
875+
}
876+
877+
uint32_t commit = _output->Commit();
878+
879+
ASSERT(commit == Core::ERROR_NONE);
903880

904881
return Core::Time::Now().Ticks();
905882
}
@@ -951,35 +928,25 @@ namespace Plugin {
951928
Presenter(CompositorImplementation& parent)
952929
: Core::Thread(Thread::DefaultStackSize(), PresenterThreadName)
953930
, _parent(parent)
954-
, _continue(false)
955931
{
956932
}
957933

958934
~Presenter() override
959935
{
960936
Core::Thread::Stop();
961-
962937
Core::Thread::Wait(Core::Thread::STOPPED, 100);
963938
}
964939

965-
void Trigger()
966-
{
967-
Thread::Run();
968-
}
969-
970940
private:
971941
uint32_t Worker() override
972942
{
973943
Core::Thread::Block();
974-
975944
_parent.RenderOutput(); // 3000us
976-
977945
return Core::infinite;
978946
}
979947

980948
private:
981949
CompositorImplementation& _parent;
982-
std::atomic<bool> _continue;
983950
};
984951

985952
private:
@@ -1014,8 +981,10 @@ namespace Plugin {
1014981
int _renderDescriptor;
1015982
std::string _renderNode;
1016983
Presenter _present;
1017-
std::atomic<State> _state;
1018984
bool _autoScale;
985+
std::mutex _commitMutex;
986+
std::condition_variable _commitCV;
987+
std::atomic<bool> _canCommit;
1019988
};
1020989

1021990
SERVICE_REGISTRATION(CompositorImplementation, 1, 0)

0 commit comments

Comments
 (0)