extractChannel() stopped supporting in-place operation (dst aliasing
src) after commit 416bf3253 (PR #23473), which replaced
Mat src = _src.getMat();
_dst.create(src.dims, &src.size[0], depth);
with a single up-front
_dst.createSameSize(_src, depth);
...
Mat src = _src.getMat();
When _src and _dst reference the same array, the up-front reallocation
reshapes the shared buffer to a single channel before the multi-channel
source header is fetched. mixChannels() then sees a 1-channel source and
throws for any coi >= 1.
Move createSameSize() back to after the source Mat/UMat is obtained, so
the source header keeps the original multi-channel data alive across the
destination reallocation. This preserves the 0D/1D handling introduced
by createSameSize while restoring the pre-existing in-place contract.
Adds regression test Core_Mat.extractChannel_inplace_29568.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The 16-bit icvCvt_* helpers in utils.cpp advance the row pointer with
step/sizeof(x[0]) - size.width*N at the end of each row. sizeof is size_t
(unsigned), so the whole subtraction is done in unsigned math and wraps to
a huge offset when the caller passes step == 0.
The TIFF tile decoder does exactly that: it walks rows itself and calls
these helpers with step = 0 and Size(width, 1), so decoding a 16-bit
4-channel TIFF forms an out of range pointer. UBSan reports it as an
unsigned offset overflow (issue #29615).
Cast sizeof(...) to int so the step math is signed. The result is the same
for valid multi-row calls and no longer overflows when step is 0.
Added Imgcodecs_Tiff.regression_29615_16UC4 which round-trips a CV_16UC4
TIFF in memory.
Core, Highgui: OpenGL wrappers & window free-callback API #29485
This PR is a continuation of the work started in [20371](https://github.com/opencv/opencv/pull/20371)
### Pull Request Readiness Checklist
See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request
- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [x] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
Patch to opencv_extra has the same branch name.
- [x] The feature is well documented and sample code can be built with the project CMake
* dnn:rvv: restore the fixed block size C0 == 8
#29304 made the net-wide block size follow the RVV vector width
(defaultC0 = max(8, vlanes())), so the blocked memory layout of every tensor
depended on the host's VLEN and on the LMUL of the universal intrinsics in core.
The same model gets a different layout on a 128-, 256- or 1024-bit machine.
Restore the fixed default of 8, which is the mainstream, well-tested setting on
every platform. C0/K0 become compile-time constants again on RVV as they already
were elsewhere, so the runtime block-size plumbing and the vlanes()-based scratch
sizing are dropped, and getConvFunc_ no longer advertises block sizes the kernels
cannot handle.
The blocked kernels currently require C0 == vlanes(), which this alone does not
satisfy; the next commit removes that requirement.
* dnn:rvv: pin the vector length to the channel block
The blocked kernels assumed one channel block is exactly one vector
(C0 == vlanes()). That is not a property of the layout, it is a property of the
hardware, so the kernels only worked where the two happened to coincide: with
C0 fixed at 8 they break wherever vlanes() != 8 -- under-filling the block when
the vector is narrower (silently leaving output channels unwritten) and
overrunning it when the vector is wider (CV_Assert).
The universal intrinsics cannot express this: v_float32 is always vlanes() wide
and there is no way to make it span exactly C0 elements. So the RVV paths drop to
native intrinsics and set the vector length explicitly:
const size_t _vl = __riscv_vsetvl_e32m2(C0); // == 8 on every VLEN >= 128
LMUL=2 is required, not incidental: vlmax(e32,m2) = VLEN/32*2 >= 8 even at
VLEN=128, the narrowest RVV configuration, so _vl == C0 on every RVV 1.0 core.
One vector then spans precisely one channel block regardless of VLEN, and the
C0-vs-vlanes asserts and VLEN-dependent branches are removed rather than extended.
The existing int8 kernels already choose LMUL=2 for the same reason
(conv2_int8_kernels.simd.hpp).
This is a native per-kernel choice and is independent of the LMUL the universal
intrinsics are built with; dnn no longer reads the vector width of
intrin_rvv_scalable.hpp at all.
conv, deconv, maxpool, avgpool and depthwise use native intrinsics. batch_norm
stays portable and instead replicates the C0-wide coefficient pattern across the
vector, which keeps full lane utilisation where a fixed vl would idle most of it.
The x86/ARM paths are restored to their pre-#29304 form and are unchanged.
Tested on SpaceMIT K3 (X100 VLEN=256, A100 VLEN=1024), opencv_test_dnn: no
regressions against upstream on either core.
* core:rvv: switch scalable universal intrinsics from LMUL=2 to LMUL=1
Move the RVV universal-intrinsic types (v_uint8..v_float64) from m2 (paired
registers, 16 usable) to m1 (individual registers, 32 usable) per #29454, to
relieve register pressure in the complex kernels that rely on universal
intrinsics. Simple kernels that regress can take native RVV branches; the complex
ones cannot, so the default should suit them.
Only intrin_rvv_scalable.hpp changes. The widening/narrowing cascades and
max_nlanes are adjusted, and helpers that spell an LMUL into the intrinsic name
shift down one step (m2->m1, m1->mf2): v_popcount, v_lut (vector and f64 paths),
the f64 dot-product reduction (#27003), v_matmul, and the byte-indexed v_lut
added by #29250, whose __riscv_vluxei8_v_u8m2 no longer matches the m1 base type.
VLEN=1024 needs no change: under m1, max_nlanes = CV_RVV_MAX_VLEN/SZ equals
vlanes() at 1024, and CV_RVV_MAX_VLEN already defaults to 1024. Verified on a
1024-bit core.
Tested on SpaceMIT K3, which exposes both a 256-bit (X100) and a 1024-bit (A100)
core. opencv_test_core: 5605/5612, the 7 failures (filestorage_base64, globbing)
non-SIMD and failing identically on the m2 baseline. Perf (x-factor = m2/m1,
>1 = m1 faster), median >= 300us: core 0.966 -> 0.996 and imgproc 0.950 -> 1.038
as VLEN goes 256 -> 1024, i.e. m2's width advantage disappears once both are wide
while m1's register headroom persists. m1 wins resize (1.50/1.41), Exp (1.28),
gaussianBlur (1.23), norm (1.22), scharr (1.20); m2 still wins the light
memory-streaming kernels addWeighted (0.76), compare (0.82) and dot (0.87), which
are the natural candidates for native RVV branches.
* Revert "dnn:rvv: pin the vector length to the channel block"
This reverts commit 40587c6dd9.
* dnn:rvv: disable CV_SIMD_SCALABLE in the new-engine conv kernel
Under the m1 switch the RVV conv kernel breaks at VLEN=128: it assumes
K0 == vlanes(), but m1 makes vlanes()=4 while the block stays C0=K0=8, so it
computes only half of each output block. Temporarily disable the RVV
(CV_SIMD_SCALABLE) branches so conv runs scalar on RVV, exactly as #29180 did for
the other new-engine layers. The vectorized path will be restored in a follow-up.
Only conv is affected: maxpool/avgpool/depthwise/deconv/batch_norm already handle
C0 == 2*vlanes (the SSE/NEON case) and stay on their universal-intrinsic paths.
* dnn:rvv: document the supported VLEN range and the v_setvlmax follow-up
With the fixed C0=8 the RVV blocked kernels cover VLEN=128 and 256 (C0 >= vlanes);
VLEN>=512 (C0 < vlanes) is not yet handled. Add TODO notes recording this and
pointing at the planned fix: a portable v_setvlmax<VT>(n) universal intrinsic that
caps the vector to the block (no-op on fixed-width ISAs, sets the vl/mask on
RVV/SVE), with an optimized multi-pixel variant as a later step, possibly an RVV
HAL for the new dnn engine. See the #29493 discussion.
* dnn:rvv: disable CV_SIMD_SCALABLE in max/avg pooling and depthwise
These three blocked kernels assert (C0 == nlanes || ...) at VLEN>=512, where the
fixed C0=8 is narrower than the vector register — breaking whole networks
(AlexNet/ResNet/YOLO) on wide RVV cores, though CI (VLEN=128) is unaffected.
Disable their RVV (CV_SIMD_SCALABLE) paths so they run scalar on RVV at every
VLEN, matching #29180's scope. Verified on a SpaceMIT K3: this removes the 92
VLEN=1024 assert failures, with no change at VLEN=128/256.
deconv and batch_norm are left enabled: they degrade to scalar at VLEN>=512
(deconv's C0 % vlanes guard, batch_norm's vector-loop bound) without asserting,
so they stay correct and keep their 128/256 vectorization. All of these
re-vectorize uniformly via the v_setvlmax<VT>(n) follow-up.
Add Scan layer to the new engine #29577
### Pull Request Readiness Checklist
See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request
- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [x] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
Patch to opencv_extra has the same branch name.
- [x] The feature is well documented and sample code can be built with the project CMake
Added Cumprod and Causalconv layers in new dnn engine #29579
### Pull Request Readiness Checklist
See details at https://github.com/opencv/opencv/wiki/How_to_contribute#making-a-good-pull-request
- [x] I agree to contribute to the project under Apache 2 License.
- [x] To the best of my knowledge, the proposed patch is not based on a code under GPL or another license that is incompatible with OpenCV
- [x] The PR is proposed to the proper branch
- [x] There is a reference to the original bug report and related work
- [x] There is accuracy test, performance test and test data in opencv_extra repository, if applicable
Patch to opencv_extra has the same branch name.
- [x] The feature is well documented and sample code can be built with the project CMake
cv::Mat_<bool>::depth() returns CV_Bool in 5.0 where it returned CV_8U in
4.x, so distanceTransform started rejecting boolean masks. CV_Bool is a
1-byte type whose values are only zero-tested here, so accept it wherever
a CV_8UC1 mask was previously accepted, matching the 4.x behaviour and the
4->5 migration guide.
Relaxes the type checks on all four reachable paths: the public wrapper,
distanceTransform_L1_8U, trueDistTrans (DIST_MASK_PRECISE) and
distanceATS_L1_8u (CV_8U output).
Closes#29596