AtlatestRepositorysigil-wm
1
/* SPDX-License-Identifier: BSD-3-Clause2
* Coalesce configuration and power intents over one native loop idle. */3
struct pending_output_batch {4
struct wl_list link;5
uint64_t token;6
int kind;7
size_t count;8
int64_t words[];9
};10
static 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 with70
* 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);100
}101
static 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);104
}105
static 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;127
}128
static 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);132
}133
static 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;142
}