From 39445fa162afd60f7266f70ff6a0fba564c3acae Mon Sep 17 00:00:00 2001 From: Frank Barchard Date: Fri, 25 Sep 2026 11:34:33 -0700 Subject: [PATCH] [libyuv] Fix RISC-V CMake/GN/Bazel builds and C compiler driver linking - Use -fno-tree-vectorize and -fno-tree-slp-vectorize instead of Clang-only -fno-vectorize and -fno-slp-vectorize in CMakeLists.txt, riscv-clang.cmake, BUILD.gn, and BUILD.bazel for GCC and Clang compatibility. - Split row_rvv.cc and scale_rvv.cc into a dedicated libyuv_rvv target in BUILD.gn and define LIBYUV_RVV so callers in row.h and scale_row.h can dispatch to RVV kernels when built without global -march=rv64gcv. - Guard the x86 AVX512-BF16 vdpphps inline assembly probe in util/cpuid.c with __i386__ / __x86_64__. - Replace new/delete and new[]/delete[] with calloc/malloc/free in source/mjpeg_decoder.cc and util/yuvconvert.cc to avoid C++ standard library dependencies, and link libm for yuvconstants and libyuv_unittest in CMakeLists.txt. Test: cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ .. Bug: None Change-Id: I701c0625f2730e864806556213a5e013c931e2d6 Reviewed-on: https://chromium-review.googlesource.com/c/libyuv/libyuv/+/8464751 Reviewed-by: richard winterton Commit-Queue: Frank Barchard --- BUILD.bazel | 12 ++++++- BUILD.gn | 38 +++++++++++++++++++++-- CMakeLists.txt | 12 +++++-- include/libyuv/row.h | 3 +- include/libyuv/scale_row.h | 9 +++++- libyuv.gni | 1 + riscv_script/riscv-clang.cmake | 2 +- source/mjpeg_decoder.cc | 57 +++++++++++++++------------------- util/cpuid.c | 2 +- util/yuvconvert.cc | 34 +++++++++++--------- 10 files changed, 113 insertions(+), 57 deletions(-) diff --git a/BUILD.bazel b/BUILD.bazel index e8ce1c262..1e93dc6eb 100644 --- a/BUILD.bazel +++ b/BUILD.bazel @@ -46,6 +46,8 @@ SVE_COPTS = select({ SUPPORTS_RVV_COPTS = [ "-DLIBYUV_RVV", + "-fno-tree-vectorize", + "-fno-tree-slp-vectorize", ] ENABLE_RVV_COPTS = [ @@ -62,6 +64,14 @@ RVV_COPTS = select({ "//conditions:default": [], }) +ARCH_SUPPORT_COPTS = select({ + "@platforms//cpu:armv7": SUPPORTS_NEON_COPTS, + "@platforms//cpu:aarch64": SUPPORTS_NEON_COPTS + SUPPORTS_SVE_COPTS, + "@platforms//cpu:riscv32": SUPPORTS_RVV_COPTS, + "@platforms//cpu:riscv64": SUPPORTS_RVV_COPTS, + "//conditions:default": [], +}) + PLATFORM_COPTS = select({ "@platforms//os:android": ["-DHAVE_JPEG"], "@platforms//os:linux": ["-DHAVE_JPEG"], @@ -74,7 +84,7 @@ PLATFORM_COPTS = select({ "-DGOOGLE_COMMANDLINEFLAGS_FULL_API", ] -ALL_COPTS = PLATFORM_COPTS +ALL_COPTS = PLATFORM_COPTS + ARCH_SUPPORT_COPTS ALL_NEON_COPTS = NEON_COPTS + PLATFORM_COPTS diff --git a/BUILD.gn b/BUILD.gn index e6913efdc..99cc006fc 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -39,6 +39,8 @@ config("libyuv_config") { } if (libyuv_disable_rvv) { defines += [ "LIBYUV_DISABLE_RVV" ] + } else if (libyuv_use_rvv) { + defines += [ "LIBYUV_RVV" ] } if (!libyuv_use_lsx) { defines += [ "LIBYUV_DISABLE_LSX" ] @@ -88,6 +90,10 @@ group("libyuv") { deps += [ ":libyuv_sme" ] } + if (libyuv_use_rvv && !libyuv_disable_rvv) { + deps += [ ":libyuv_rvv" ] + } + if (libyuv_use_lsx) { deps += [ ":libyuv_lsx" ] } @@ -160,7 +166,6 @@ static_library("libyuv_internal") { "source/row_any.cc", "source/row_common.cc", "source/row_gcc.cc", - "source/row_rvv.cc", "source/row_win.cc", "source/scale.cc", "source/scale_any.cc", @@ -168,7 +173,6 @@ static_library("libyuv_internal") { "source/scale_common.cc", "source/scale_gcc.cc", "source/scale_rgb.cc", - "source/scale_rvv.cc", "source/scale_uv.cc", "source/scale_win.cc", "source/video_common.cc", @@ -274,6 +278,36 @@ if (libyuv_use_sme) { } } +if (libyuv_use_rvv && !libyuv_disable_rvv) { + static_library("libyuv_rvv") { + sources = [ + "source/row_rvv.cc", + "source/scale_rvv.cc", + ] + + deps = [ ":libyuv_internal" ] + + public_configs = [ ":libyuv_config" ] + + # The -march arguments below are incompatible with libc++ modules. + use_libcxx_modules = false + + if (current_cpu == "riscv64") { + cflags = [ + "-march=rv64gcv", + "-fno-tree-vectorize", + "-fno-tree-slp-vectorize", + ] + } else { + cflags = [ + "-march=rv32gcv", + "-fno-tree-vectorize", + "-fno-tree-slp-vectorize", + ] + } + } +} + if (libyuv_use_lsx) { static_library("libyuv_lsx") { sources = [ diff --git a/CMakeLists.txt b/CMakeLists.txt index 1622b5c05..65dfd72a1 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -154,7 +154,7 @@ int main(void) { return 0; } include(CheckCSourceCompiles) set(OLD_CMAKE_REQUIRED_FLAGS ${CMAKE_REQUIRED_FLAGS}) set(OLD_CMAKE_TRY_COMPILE_TARGET_TYPE ${CMAKE_TRY_COMPILE_TARGET_TYPE}) - set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${RISCV_COMPILER_FLAGS}") + set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} ${RISCV_COMPILER_FLAGS} -fno-tree-vectorize -fno-tree-slp-vectorize") set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) check_c_source_compiles(" int main(void) { return 0; } @@ -164,8 +164,8 @@ int main(void) { return 0; } if(CAN_COMPILE_RVV) if(NOT CMAKE_C_FLAGS MATCHES "-march=" AND NOT CMAKE_C_FLAGS MATCHES "-mcpu=") - set(CMAKE_C_FLAGS "${RISCV_COMPILER_FLAGS} -fno-vectorize -fno-slp-vectorize ${CMAKE_C_FLAGS}") - set(CMAKE_CXX_FLAGS "${RISCV_COMPILER_FLAGS} -fno-vectorize -fno-slp-vectorize ${CMAKE_CXX_FLAGS}") + set(CMAKE_C_FLAGS "${RISCV_COMPILER_FLAGS} -fno-tree-vectorize -fno-tree-slp-vectorize ${CMAKE_C_FLAGS}") + set(CMAKE_CXX_FLAGS "${RISCV_COMPILER_FLAGS} -fno-tree-vectorize -fno-tree-slp-vectorize ${CMAKE_CXX_FLAGS}") endif() else() add_definitions(-DLIBYUV_DISABLE_RVV) @@ -234,6 +234,9 @@ target_link_libraries ( yuvconvert ${ly_lib_static} ) # this creates the yuvconstants tool add_executable ( yuvconstants ${ly_base_dir}/util/yuvconstants.c ) target_link_libraries ( yuvconstants ${ly_lib_static} ) +if(NOT MSVC) + target_link_libraries ( yuvconstants m ) +endif() if (NOT LIBYUV_DISABLE_JPEG) find_package ( JPEG ) @@ -266,6 +269,9 @@ if(UNIT_TEST) add_executable(libyuv_unittest ${ly_unittest_sources}) target_link_libraries(libyuv_unittest ${ly_lib_name} ${GTEST_LIBRARY}) + if(NOT MSVC) + target_link_libraries(libyuv_unittest m) + endif() find_library(PTHREAD_LIBRARY pthread) if(NOT PTHREAD_LIBRARY STREQUAL "PTHREAD_LIBRARY-NOTFOUND") target_link_libraries(libyuv_unittest pthread) diff --git a/include/libyuv/row.h b/include/libyuv/row.h index 5dc2fd35b..37a4124d8 100644 --- a/include/libyuv/row.h +++ b/include/libyuv/row.h @@ -864,7 +864,8 @@ extern "C" { #define HAS_YUY2TOYROW_LASX #endif -#if !defined(LIBYUV_DISABLE_RVV) && defined(__riscv_vector) +#if !defined(LIBYUV_DISABLE_RVV) && \ + (defined(__riscv_vector) || defined(LIBYUV_RVV)) #define HAS_AR64TOARGBROW_RVV #define HAS_ARGBCOPYYTOALPHAROW_RVV #define HAS_ARGBEXTRACTALPHAROW_RVV diff --git a/include/libyuv/scale_row.h b/include/libyuv/scale_row.h index 505bcac87..d806867e3 100644 --- a/include/libyuv/scale_row.h +++ b/include/libyuv/scale_row.h @@ -159,8 +159,15 @@ extern "C" { #define HAS_SCALEROWDOWN34_LSX #endif -#if !defined(LIBYUV_DISABLE_RVV) && defined(__riscv_vector) +#if !defined(LIBYUV_DISABLE_RVV) && \ + ((defined(__riscv_vector) && defined(__riscv_zve64x)) || \ + (defined(LIBYUV_RVV) && \ + (!defined(__riscv_vector) || defined(__riscv_zve64x)))) #define HAS_SCALEUVROWDOWN4_RVV +#endif + +#if !defined(LIBYUV_DISABLE_RVV) && \ + (defined(__riscv_vector) || defined(LIBYUV_RVV)) #define HAS_SCALEARGBROWDOWN2_RVV #define HAS_SCALEROWDOWN34_0_BOX_RVV #define HAS_SCALEROWDOWN34_1_BOX_RVV diff --git a/libyuv.gni b/libyuv.gni index 272277aff..23e38c1b4 100644 --- a/libyuv.gni +++ b/libyuv.gni @@ -30,4 +30,5 @@ declare_args() { (current_cpu == "mips64el" || current_cpu == "mipsel") && mips_use_mmi libyuv_use_lsx = current_cpu == "loong64" && loongarch64_use_lsx libyuv_use_lasx = current_cpu == "loong64" && loongarch64_use_lasx + libyuv_use_rvv = current_cpu == "riscv64" || current_cpu == "riscv32" } diff --git a/riscv_script/riscv-clang.cmake b/riscv_script/riscv-clang.cmake index 35888aefa..41d23a5c3 100644 --- a/riscv_script/riscv-clang.cmake +++ b/riscv_script/riscv-clang.cmake @@ -37,7 +37,7 @@ if(RISCV_COMPILER_FLAGS STREQUAL "") list(APPEND RISCV_COMPILER_FLAGS "-march=rv64gcv") if(NOT USE_AUTO_VECTORIZER) # Disable auto-vectorizer - add_compile_options(-fno-vectorize -fno-slp-vectorize) + add_compile_options(-fno-tree-vectorize -fno-tree-slp-vectorize) endif() else() list(APPEND RISCV_COMPILER_FLAGS "-march=rv64gc") diff --git a/source/mjpeg_decoder.cc b/source/mjpeg_decoder.cc index 28d18c96e..76195f2e1 100644 --- a/source/mjpeg_decoder.cc +++ b/source/mjpeg_decoder.cc @@ -25,7 +25,8 @@ #endif -#include // For jpeglib.h. +#include // For jpeglib.h. +#include // For calloc(), malloc(), and free(). // C++ build requires extern C for jpeg internals. #ifdef __cplusplus @@ -71,10 +72,11 @@ MJpegDecoder::MJpegDecoder() scanlines_sizes_(NULL), databuf_(NULL), databuf_strides_(NULL) { - decompress_struct_ = new jpeg_decompress_struct; - source_mgr_ = new jpeg_source_mgr; + decompress_struct_ = static_cast( + malloc(sizeof(jpeg_decompress_struct))); + source_mgr_ = static_cast(malloc(sizeof(jpeg_source_mgr))); #ifdef HAVE_SETJMP - error_mgr_ = new SetJmpErrorMgr; + error_mgr_ = static_cast(malloc(sizeof(SetJmpErrorMgr))); decompress_struct_->err = jpeg_std_error(&error_mgr_->base); // Override standard exit()-based error handler. error_mgr_->base.error_exit = &ErrorHandler; @@ -94,10 +96,10 @@ MJpegDecoder::MJpegDecoder() MJpegDecoder::~MJpegDecoder() { jpeg_destroy_decompress(decompress_struct_); - delete decompress_struct_; - delete source_mgr_; + free(decompress_struct_); + free(source_mgr_); #ifdef HAVE_SETJMP - delete error_mgr_; + free(error_mgr_); #endif DestroyOutputBuffers(); } @@ -126,10 +128,9 @@ bool MJpegDecoder::LoadFrame(const uint8_t* src, size_t src_len) { for (int i = 0; i < num_outbufs_; ++i) { int scanlines_size = GetComponentScanlinesPerImcuRow(i); if (scanlines_sizes_[i] != scanlines_size) { - if (scanlines_[i]) { - delete[] scanlines_[i]; - } - scanlines_[i] = new uint8_t*[scanlines_size]; + free(scanlines_[i]); + scanlines_[i] = + static_cast(malloc(scanlines_size * sizeof(uint8_t*))); scanlines_sizes_[i] = scanlines_size; } @@ -147,10 +148,8 @@ bool MJpegDecoder::LoadFrame(const uint8_t* src, size_t src_len) { // - Sampling factor is stored in 4 bits, so scanlines_size is < 16. int databuf_size = scanlines_size * databuf_stride; if (databuf_strides_[i] != databuf_stride) { - if (databuf_[i]) { - delete[] databuf_[i]; - } - databuf_[i] = new uint8_t[databuf_size]; + free(databuf_[i]); + databuf_[i] = static_cast(malloc(databuf_size)); databuf_strides_[i] = databuf_stride; } @@ -481,17 +480,11 @@ void MJpegDecoder::AllocOutputBuffers(int num_outbufs) { // it. DestroyOutputBuffers(); - scanlines_ = new uint8_t**[num_outbufs]; - scanlines_sizes_ = new int[num_outbufs]; - databuf_ = new uint8_t*[num_outbufs]; - databuf_strides_ = new int[num_outbufs]; - - for (int i = 0; i < num_outbufs; ++i) { - scanlines_[i] = NULL; - scanlines_sizes_[i] = 0; - databuf_[i] = NULL; - databuf_strides_[i] = 0; - } + scanlines_ = + static_cast(calloc(num_outbufs, sizeof(uint8_t**))); + scanlines_sizes_ = static_cast(calloc(num_outbufs, sizeof(int))); + databuf_ = static_cast(calloc(num_outbufs, sizeof(uint8_t*))); + databuf_strides_ = static_cast(calloc(num_outbufs, sizeof(int))); num_outbufs_ = num_outbufs; } @@ -499,13 +492,13 @@ void MJpegDecoder::AllocOutputBuffers(int num_outbufs) { void MJpegDecoder::DestroyOutputBuffers() { for (int i = 0; i < num_outbufs_; ++i) { - delete[] scanlines_[i]; - delete[] databuf_[i]; + free(scanlines_[i]); + free(databuf_[i]); } - delete[] scanlines_; - delete[] databuf_; - delete[] scanlines_sizes_; - delete[] databuf_strides_; + free(scanlines_); + free(databuf_); + free(scanlines_sizes_); + free(databuf_strides_); scanlines_ = NULL; databuf_ = NULL; scanlines_sizes_ = NULL; diff --git a/util/cpuid.c b/util/cpuid.c index a2f6e2054..c9862dc12 100644 --- a/util/cpuid.c +++ b/util/cpuid.c @@ -42,7 +42,7 @@ static void KernelVersion(int* version) { } #endif -#ifdef __linux__ +#if defined(__linux__) && (defined(__i386__) || defined(__x86_64__)) static sigjmp_buf vdpphps_jmpbuf; static void vdpphps_sigill_handler(int sig) { (void)sig; diff --git a/util/yuvconvert.cc b/util/yuvconvert.cc index 93b526685..047e9235d 100644 --- a/util/yuvconvert.cc +++ b/util/yuvconvert.cc @@ -201,8 +201,12 @@ int main(int argc, const char* argv[]) { } // Open all files to convert to - FILE** file_rec = new FILE*[num_rec]; - memset(file_rec, 0, num_rec * sizeof(FILE*)); // NOLINT + FILE** file_rec = static_cast(calloc(num_rec, sizeof(FILE*))); + if (file_rec == NULL) { + fprintf(stderr, "No memory available\n"); + fclose(file_org); + exit(1); + } for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) { file_rec[cur_rec] = fopen(argv[fileindex_rec + cur_rec], "wb"); if (file_rec[cur_rec] == NULL) { @@ -211,7 +215,7 @@ int main(int argc, const char* argv[]) { for (int i = 0; i < cur_rec; ++i) { fclose(file_rec[i]); } - delete[] file_rec; + free(file_rec); exit(1); } } @@ -243,19 +247,19 @@ int main(int argc, const char* argv[]) { fseek(file_org, num_skip_org * total_size, SEEK_SET); #endif - uint8_t* const ch_org = new uint8_t[org_size]; - uint8_t* const ch_dst = new uint8_t[dst_size]; - uint8_t* const ch_rec = new uint8_t[total_size]; - if (ch_org == NULL || ch_rec == NULL) { + uint8_t* const ch_org = static_cast(malloc(org_size)); + uint8_t* const ch_dst = static_cast(malloc(dst_size)); + uint8_t* const ch_rec = static_cast(malloc(total_size)); + if (ch_org == NULL || ch_dst == NULL || ch_rec == NULL) { fprintf(stderr, "No memory available\n"); fclose(file_org); for (int i = 0; i < num_rec; ++i) { fclose(file_rec[i]); } - delete[] ch_org; - delete[] ch_dst; - delete[] ch_rec; - delete[] file_rec; + free(ch_org); + free(ch_dst); + free(ch_rec); + free(file_rec); exit(1); } @@ -359,9 +363,9 @@ int main(int argc, const char* argv[]) { for (int cur_rec = 0; cur_rec < num_rec; ++cur_rec) { fclose(file_rec[cur_rec]); } - delete[] ch_org; - delete[] ch_dst; - delete[] ch_rec; - delete[] file_rec; + free(ch_org); + free(ch_dst); + free(ch_rec); + free(file_rec); return 0; }