-
Notifications
You must be signed in to change notification settings - Fork 620
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support negative stride #1324
base: main
Are you sure you want to change the base?
Support negative stride #1324
Conversation
|
1ec9090
to
55bdfd1
Compare
@@ -1546,7 +1548,7 @@ copyFromFrameBuffer ( | |||
{ | |||
case OPENEXR_IMF_INTERNAL_NAMESPACE::UINT: | |||
|
|||
while (localReadPtr <= endPtr) | |||
while (localReadPtr != endPtr) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same comment about pre-testing the validity of the input parameters.
@@ -150,7 +150,7 @@ class IMF_EXPORT_TYPE AcesOutputFile | |||
//------------------------------------------------ | |||
|
|||
IMF_EXPORT | |||
void setFrameBuffer (const Rgba* base, size_t xStride, size_t yStride); | |||
void setFrameBuffer (const Rgba* base, ptrdiff_t xStride, ptrdiff_t yStride); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
since an API change is involved, there'd be a version bump to OpenEXR required. Perhaps we should retain the existing signature in addition to introducing a new one, and have the size_t variant call the ptrdiff_t variant with appropriate casting to silence warnings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think both gcc and clang (-Wall) would not produce warnings when passing size_t
argument to ptrdiff_t
parameter.
But these changes do break the ABI. However, OpenEXR usually has version number in its soname. So the binary capability would break after the next minor release anyway. Should I try to keep ABI capability in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It strikes me that supporting flipping images on read is definitely a useful missing feature, but doing it by passing a negative stride is kind of a hack, rather than a clean friendly API feature. In particular, it's not obvious what the base pointer should be when the image dataWindow doesn't match the displayWindow.
One option would be to leave the constructor using size_t, but use ptrdiff_t internally, and add a new Make() static method for flipped images that createa a Slice with a negative stride and computes the correct base pointer for you.
That should also be a less significant ABI change than modifying the constructor.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm writing a python extension. In my use case, I would definitely want to pass negative strides directly, because I could get negative strides from NumPy.
If we want to be more friendly to C++ users, instead of adding more Make
overloads, how about adding Slice::flipX()
and Slice::flipY()
methods that negate the strides of an existing Slice
and compute the base pointer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To my way of thinking, passing ptrdiff_t is less confusing at first blush than creating an unflipped datawindow. The displayWindow has to be an "increasing in memory, 0,0 upper left window".
would it make sense to say displaywindow and datawindow have to be in harmony?
in other words, if xs < 0, then origin is right instead of left, if ys < 0, origin is bottom instead of top?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you mean the base
pointer, then yes. the base
pointer always points to the logical (0,0) pixel in the .exr file, but may not point to the first byte in the FrameBuffer Slice with negative stride. And this formula should always hold true:
openexr/src/lib/OpenEXR/ImfFrameBuffer.h
Line 49 in 55bdfd1
// base + (xp / xSampling) * xStride + (yp / ySampling) * yStride |
.header().dataWindow().min
should still less than or equal to .header().dataWindow().max
ffdd48b
to
e212b8f
Compare
ce047cb
to
ef6ab36
Compare
Add support for negative stride to FrameBuffer Slice. Change data type of stride from size_t to ptrdiff_t. Add support for negative stride in `copyIntoFrameBuffer` and `copyFromFrameBuffer`. Add a new `testNegativeStride` test. Fixes: AcademySoftwareFoundation#614 Signed-off-by: 胡玮文 <[email protected]>
Signed-off-by: 胡玮文 <[email protected]>
ef6ab36
to
785c1fa
Compare
CI now works in my fork. I've added the missing includes. |
Hi all, anything I can do to push this PR forward? |
@peterhillman ~ @huww98 has addressed my structural comments about the code. Have you had a chance to think about the negative stride issues that you brought up earlier? In my mind, I'm not quite picturing how the proposed MakeFlipped use case would look, since it would seem like you'd have to set up an incorrect positive stride and then heal it later. The advantage of the negative stride at construction is that the pointers are never in an unworkable state. But maybe I'm misunderstanding the construction suggested? |
I think all those changes are good. |
Ah, thank you, now I understand :) |
@peterhillman I agree that computing the base pointer for the user can be helpful. But should we defer that to another PR? I think adding more 'Make' overload can result in a combination explosion in the future. Maybe we should just add two parameters ( auto slice = Slice::Make(..., /*flipY=*/true); is equivalent to auto slice = Slice::Make(...);
slice.flipY(); |
I just noticed
Should I change it to |
I don't think Make() is useful with negative xStride or yStride, as currently implemented. Make() assumes it is provided with the pointer to the beginning of the user array (plus an offset to account for the channel index), and it computes the offset to pixel 0,0 for you, so the Slice is initialized correctly. If we are happy with 'negative stride' implying the image will be flipped on read, The Make method might as well follow the same convention, which should mean new overloads or extra parameters aren't required to indicate flips. But it does need extra logic to test for negatives and get the pointer right. I've not properly thought this through but the overload that takes a dataWindow could be passed negative strides to indicate flipping or flopping, and that would compute the correct base pointer for you, using dataWindow.max as well as dataWindow.min. It might also be possible to implement that in the "origin,width,height" overload, but perhaps that's more confusing, as it's not obvious which 'origin' it wants when the image is flipped, and whether width and height should also be negative. Perhaps it would be clearer if that overload stayed as it was, with unsigned strides, so it' doesn't support flipping. Is it possible to implement Slice::flipY()? Slice doesn't know the size of the dataWindow, which is required to adjust the base pointer. Usually Make is used something like |
I would like the new semantic of
If we decide to add
if (flipY) {
ptr += yStride * (h - 1);
yStride = -yStride;
} So we can just pass in the pointer to the beginning of the user array and get a flipped slice. I think this is simple for most use cases and easy to understand.
Yes, we may need |
Add support for negative stride to FrameBuffer Slice.
Change data type of stride from size_t to ptrdiff_t.
Add support for negative stride in
copyIntoFrameBuffer
andcopyFromFrameBuffer
.Add a new
testNegativeStride
test.Fixes: #614
Signed-off-by: 胡玮文 [email protected]