gpu: Change sorting for ops

The previous algorithm would reverse the order of subpasses, whcih leads
to unexpected behavior if dependent subpasses are not added as children
of a subpass, but just as a previous subpass - like when a subpass is
used multiple times later.

An example for this is a shadow node with multiple shadows - the source
of the shadow is used by the multiple shadows.

So ensure that adjacent subpasses stay in the same order.
This commit is contained in:
Benjamin Otte 2023-09-21 02:35:38 +02:00
parent 30e9d98f0d
commit 7431a58617

View File

@ -216,6 +216,8 @@ gsk_gpu_frame_sort_render_pass (GskGpuFrame *self,
GskGpuOp *op, GskGpuOp *op,
SortData *sort_data) SortData *sort_data)
{ {
SortData subpasses = { { NULL, NULL }, { NULL, NULL } };
while (op) while (op)
{ {
switch (op->op_class->stage) switch (op->op_class->stage)
@ -240,40 +242,30 @@ gsk_gpu_frame_sort_render_pass (GskGpuFrame *self,
break; break;
case GSK_GPU_STAGE_PASS: case GSK_GPU_STAGE_PASS:
if (sort_data->command.first == NULL) if (subpasses.command.first == NULL)
sort_data->command.first = op; subpasses.command.first = op;
else else
sort_data->command.last->next = op; subpasses.command.last->next = op;
sort_data->command.last = op; subpasses.command.last = op;
op = op->next; op = op->next;
break; break;
case GSK_GPU_STAGE_BEGIN_PASS: case GSK_GPU_STAGE_BEGIN_PASS:
{ if (subpasses.command.first == NULL)
SortData pass_data = { { NULL, NULL }, { op, op } }; subpasses.command.first = op;
op = gsk_gpu_frame_sort_render_pass (self, op->next, &pass_data);
if (pass_data.upload.first)
{
if (sort_data->upload.last == NULL)
sort_data->upload.last = pass_data.upload.last;
else else
pass_data.upload.last->next = sort_data->upload.first; subpasses.command.last->next = op;
sort_data->upload.first = pass_data.upload.first; subpasses.command.last = op;
}
if (sort_data->command.last == NULL) /* append subpass to existing subpasses */
sort_data->command.last = pass_data.command.last; op = gsk_gpu_frame_sort_render_pass (self, op->next, &subpasses);
else
pass_data.command.last->next = sort_data->command.first;
sort_data->command.first = pass_data.command.first;
}
break; break;
case GSK_GPU_STAGE_END_PASS: case GSK_GPU_STAGE_END_PASS:
sort_data->command.last->next = op; sort_data->command.last->next = op;
sort_data->command.last = op; sort_data->command.last = op;
return op->next; op = op->next;
goto out;
default: default:
g_assert_not_reached (); g_assert_not_reached ();
@ -281,6 +273,25 @@ gsk_gpu_frame_sort_render_pass (GskGpuFrame *self,
} }
} }
out:
/* prepend subpasses to the current pass */
if (subpasses.upload.first)
{
if (sort_data->upload.first != NULL)
subpasses.upload.last->next = sort_data->upload.first;
else
sort_data->upload.last = subpasses.upload.last;
sort_data->upload.first = subpasses.upload.first;
}
if (subpasses.command.first)
{
if (sort_data->command.first != NULL)
subpasses.command.last->next = sort_data->command.first;
else
sort_data->command.last = subpasses.command.last;
sort_data->command.first = subpasses.command.first;
}
return op; return op;
} }