AtlatestRepositorysigil-wm

sigil-wm / tree / src / coutput-pending.h

1/* SPDX-License-Identifier: BSD-3-Clause
2 * Coalesce configuration and power intents over one native loop idle. */
3struct pending_output_batch {
4 struct wl_list link;
5 uint64_t token;
6 int kind;
7 size_t count;
8 int64_t words[];
9};
10static void output_flush(void *data) {
11 struct server *s=data;
12 s->output_idle=NULL;
13 struct output_control_request *request,*next_request;
14 /* A single protocol client can issue all heads before policy replies.
15 * Wait for those replies to join this idle instead of splitting a wake. */
16 wl_list_for_each(request,&s->output_controls,link)
17 if(request->kind==0 && !request->resolved) return;
18 struct wlr_output_configuration_v1 *configuration=output_configuration(s,false);
19 uint64_t selected[64];
20 bool enabled[64];
21 size_t count=0;
22 bool valid=configuration!=NULL;
23 struct output *output;
24 wl_list_for_each(output,&s->outputs,link) {
25 if(count==64) { valid=false; break; }
26 selected[count]=output->id;
27 enabled[count++]=output->configured_enabled;
28 }
29 struct pending_output_batch *batch,*next_batch;
30 wl_list_for_each(batch,&s->pending_outputs,link) {
31 uint64_t ids[64];
32 bool choices[64];
33 size_t choices_count=0;
34 int64_t single[13];
35 const int64_t *words=batch->words+1;
36 size_t words_count=batch->count-1;
37 if(batch->kind==2) {
38 const int64_t *w=batch->words;
39 output=find_output(s,w[0]);
40 single[0]=1;
41 for(int index=0;index<10;index++) single[index+1]=w[index];
42 single[11]=output && output->native->adaptive_sync_status==WLR_OUTPUT_ADAPTIVE_SYNC_ENABLED;
43 single[12]=w[1];
44 words=single; words_count=13;
45 }
46 if(!valid || !output_configuration_settings(s,configuration,words,words_count,
47 ids,choices,&choices_count)) { valid=false; continue; }
48 for(size_t chosen=0;chosen<choices_count;chosen++)
49 for(size_t index=0;index<count;index++)
50 if(selected[index]==ids[chosen]) enabled[index]=choices[chosen];
51 }
52 bool power=false,wake=false;
53 if(configuration) {
54 struct wlr_output_configuration_head_v1 *head;
55 wl_list_for_each(head,&configuration->heads,link) {
56 output=head->state.output->data;
57 if(output->pending_power) {
58 head->state.enabled=output->pending_on;
59 power=true;
60 wake=wake || output->pending_on;
61 }
62 }
63 }
64 bool pending=power || !wl_list_empty(&s->pending_outputs);
65 int rollback=0;
66 bool success=valid && pending && count &&
67 output_configuration_commit(s,configuration,selected,enabled,count,true,&rollback);
68 if(!success && valid && wake && count) {
69 /* After the atomic attempt and rollback, retry a wake once with
70 * independent heads. Lock ownership still controls the scene. */
71 wlr_log(WLR_ERROR,"OUTPUT_WAKE_RETRY outputs=%zu mode=per-output",count);
72 success=output_configuration_commit_mode(s,configuration,selected,enabled,count,true,true,&rollback);
73 wlr_log(WLR_ERROR,"OUTPUT_WAKE_RETRY_RESULT success=%d",success);
74 }
75 if(configuration) wlr_output_configuration_v1_destroy(configuration);
76 if(success) s->output_revision++;
77 wl_list_for_each(output,&s->outputs,link) {
78 if(!output->pending_power) continue;
79 output->pending_power=false;
80 if(success) {
81 if(output->native->enabled) {
82 output->gamma_pending=true;
83 wlr_output_schedule_frame(output->native);
84 }
85 EVENT(93,output->id,output->native->enabled);
86 }
87 }
88 wl_list_for_each_safe(request,next_request,&s->output_controls,link) {
89 if(request->kind!=0 || !request->resolved) continue;
90 EVENT(92,request->token,0,request->output,request->accepted && success);
91 output_control_remove(request);
92 }
93 wl_list_for_each_safe(batch,next_batch,&s->pending_outputs,link) {
94 EVENT(24,batch->token,batch->kind,success,rollback);
95 wl_list_remove(&batch->link);
96 free(batch);
97 s->pending_output_count--;
98 }
99 publish_output_management(s);
101static void queue_output_flush(struct server *s) {
102 if(!s->output_idle && !s->stopping)
103 s->output_idle=wl_event_loop_add_idle(wl_display_get_event_loop(s->display),output_flush,s);
105static bool queue_output_batch(struct server *s,int kind,uint64_t token,const int64_t *words,size_t count) {
106 if(s->pending_output_count>=64 || count>770 || (kind==2 && count!=10) || count<2) return false;
107 struct pending_output_batch *batch=calloc(1,sizeof(*batch)+count*sizeof(*words));
108 if(!batch) return false;
109 batch->token=token; batch->kind=kind; batch->count=count;
110 memcpy(batch->words,words,count*sizeof(*words));
111 if(kind==2 && words[1]) {
112 struct output *output=find_output(s,words[0]);
113 if(output && !output->wake_requested) output->wake_requested=now_ms();
114 } else if(kind==10 && count>=2 && words[1]>0 && words[1]<=64 &&
115 count==2+(size_t)words[1]*12) {
116 for(int index=0;index<words[1];index++) {
117 const int64_t *record=words+2+index*12;
118 struct output *output=find_output(s,record[0]);
119 if(output && record[1] && record[11] && !output->wake_requested)
120 output->wake_requested=now_ms();
121 }
122 }
123 wl_list_insert(s->pending_outputs.prev,&batch->link);
124 s->pending_output_count++;
125 queue_output_flush(s);
126 return true;
128static void output_batch(struct server *s,uint64_t token,const int64_t *words,size_t count) {
129 if(count>1 && words[0]==1) { output_batch_now(s,token,words,count); return; }
130 if(count<2 || words[0]!=0 || !queue_output_batch(s,10,token,words,count))
131 EVENT(24,token,10,0);
133static void output_pending_finish(struct server *s) {
134 if(s->output_idle) wl_event_source_remove(s->output_idle);
135 s->output_idle=NULL;
136 struct pending_output_batch *batch,*next;
137 wl_list_for_each_safe(batch,next,&s->pending_outputs,link) {
138 wl_list_remove(&batch->link);
139 free(batch);
140 }
141 s->pending_output_count=0;