(Regarding swscale, this is a limitation of the library. We cannot crop after scaling, as that would obviously cause bleeding of the cropped edges into the picture. The only solution would be to copy-crop explicitly before swscale.)
If I remember clear, it's not uncommon that source->i_visible_width equal interop->fmt_out.i_visible_width and so on. Then we got right and/or bottom > 1.0. It doesn't looks right.
I'm not saying that commit 85f85230 is bugfree. And it's known that x_offset/y_offset don't get handled consistently, for example, packetizer output top/left crop as right/bottom crop.
I agree with your reasoning. So your commit (bisect/bad) looks quite correct, I would only apply this small change (the full width is not only visible and left margin, but also right margin, this is unrelated to this bug):
After investigations, it seems that the problem observed with this sample is related to the software interop: the tex_widths and tex_heights passed as parameter are the full width/height (544×432), not the visible ones (540×432). But the GL_UNPACK_ROW_LENGTH value was computed assuming the parameters were the visible values, so it used a row length of 548 (544*544/540).
Removing these GL_UNPACK_ROW_LENGTH values "fixes" the problem:
But in the end there is a green bar on the right, so something is still wrong. Moreover, for software interop, we could copy only the relevant part of the input picture to the texture, so there's more work to do.
To remove the green bar, you need to ensure that there is no rounding to the right of the visible pitch border.
But in the end there is a green bar on the right, so something is still wrong. Moreover, for software interop, we could copy only the relevant part of the input picture to the texture, so there's more work to do.
We can upload only the relevant part, but then it would still have the same result with the other interop, and you'd need to re-upload (even if we already do that the way it's written) the picture to change the visibility setting, and uploading would change the size then too, which is harder to handle.
When a SPU picture is created (by freetype.c, which calls in the end picture_Setup()), its i_pitch may be different from its i_visible_pitch, typically due to rounding. For example, if the format is {width=472, height=51, i_visible_width=472, i_visible_height=51}, then the plane i_visible_pitch = 1888 (472 × 4 bytes), but i_pitch = 1920 (480 × 4 bytes).
In the OpenGL interop, this difference is compensated here(and in other places in the same file) to compute the actual row length (the number of pixels to skip to go to the next line vertically): the width (472) is multiplied by pitch / visible_pitch, so the GL_UNPACK_ROW_LENGTH is 480. Therefore, this works for this case (the SPU).
Note that 480 cannot be deduced from the format only (the plane_ti_pitch and i_visible_pitch are required): in the format, both i_width and i_visible_width are 472.
However, the difference between i_pitch and i_visible_pitch, computed respectively from the format i_width and i_visible_width can result from different causes:
the rounding of the width by picture_Setup(), which impacts the actual pitch (e.g. rounding 472→480 makes each row take more bytes);
the initial difference between i_width and i_visible_width, for example due to padding (e.g. if i_x_offset > 0 like in this issue), which DOES NOT impact the actual pitch (reducing the i_visible_width does not change the number of bytes used to store the picture).
Thus, in the interop, there is currently no way to get both cases correct (e.g. on master, the kiki_Theora_Vorbis_kate.ogg sample is broken, but the SPU are ok; this patch fixes the picture (it remains a green bar on the right to be investigated), but breaks the SPU).
For now, it's not clear to me how to fix the problem.
Btw, the name i_visible_pitch is confusing: the pitch (or stride) is the number of bytes to skip to point to the next line vertically. With this definition, a visible pitch is meaningless: there is always the same amount of bytes (or even pixels) to go to the next line, regardless of what is considered "visible". This is just a naming issue, since its meaning is documented: How many visible pixels are there? (implicitly, "in a row").
But it's still not clear how to use it properly. For example, if the format describes a picture with an offset:
However, the difference between i_pitch and i_visible_pitch, computed respectively from the format i_width and i_visible_width can result from different causes:
the rounding of the width by picture_Setup(), which impacts the actual pitch (e.g. rounding 472→480 makes each row take more bytes);
the initial difference between i_width and i_visible_width, for example due to padding (e.g. if i_x_offset > 0 like in this issue), which DOES NOT impact the actual pitch (reducing the i_visible_width does not change the number of bytes used to store the picture).
This is the root cause: the initial difference between i_width and i_visible_width should not have impact on the plane_t content area.
plane_t does not expose any offset, so i_visible_pitch alone is quite meaningless.
Because i_visible_pitch does not define the visible pitch, but the plane content area before alignment.
I submitted a MR to fix the problem: !2879 (closed). See the description for more details.