From 7518551ebb7a1bafa291cdecd2b1f001d9e0e115 Mon Sep 17 00:00:00 2001 From: Abishek <52214183+r-abishek@users.noreply.github.com> Date: Mon, 8 Apr 2024 23:30:39 -0700 Subject: [PATCH] RPP BitwiseAND and BitwiseOR Tensor on HOST and HIP (#318) * HOST test suite update for voxel processing * Initial commit - Implements PLN1 Fmadd Kernel * Add dependencies for fmadd kernel * Implement NDHWC variant for Fmadd Includes testsuite changes to support 3 channels * Implement Slice HOST Kernel Includes testsuite changes * Fix NCDHW variant for Slice * Cleanup * Fix NDHWC variant * Fix stride used for NDHWC * Fix NDHWC layout handling in testsuite Temporarily converts pln3 inputs into pkd3 inputs later stores them as pln3 after processing * Add sample input .nii file Also fixes build error in testsuite * Fix NDHWC layout for fmadd and slice Also includes fixes in voxel testsuite * Initial commit - Bitwise AND HOST Tensor * Match u8 and i8 outputs with BatchPD variant * Fix i8 PKD3 -> PLN3 * Initial commit - Bitwise AND HIP Tensor Also includes fixing f16 and f32 datatype of HOST * Add reference outputs * License - updates to 2024 and consistency changes (#298) * Match all CMakeLists.txt license as per RPP's outermost LICENSE file * Match all python files' license as per RPP's outermost LICENSE file * Match all .hpp files' license as per RPP's outermost LICENSE file * Match all .cpp files' license as per RPP's outermost LICENSE file * Match all .h files' license as per RPP's outermost LICENSE file * Remove all rights reserved as per LICENSE file * Remove double space in "Copyright (c) 2019 - 2023 Advanced Micro Devices, Inc." * Match all .cmake files' license as per RPP's outermost LICENSE file * Match all .cpp.in files' license as per RPP's outermost LICENSE file * Replace 283 occurrences in 282 files - 2023 to 2024 * Add "MIT License" title to 281 instances * Add missing license * Test - Update README.md for test_suite (#299) * Modify reference outputs Update Copywrite * Combine templated functions to support all datatypes * Initial commit - Bitwise OR HOST * Fix GPU kernel details * Fix case number for HOST testsuite * Initial commit - Bitwise OR HIP Includes reference output * Bump rocm-docs-core[api_reference] from 0.33.0 to 0.33.1 in /docs/sphinx (#301) Bumps [rocm-docs-core[api_reference]](https://github.com/RadeonOpenCompute/rocm-docs-core) from 0.33.0 to 0.33.1. - [Release notes](https://github.com/RadeonOpenCompute/rocm-docs-core/releases) - [Changelog](https://github.com/ROCm/rocm-docs-core/blob/develop/CHANGELOG.md) - [Commits](https://github.com/RadeonOpenCompute/rocm-docs-core/compare/v0.33.0...v0.33.1) --- updated-dependencies: - dependency-name: rocm-docs-core[api_reference] dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Bump rocm-docs-core[api_reference] from 0.33.1 to 0.33.2 in /docs/sphinx (#302) Bumps [rocm-docs-core[api_reference]](https://github.com/RadeonOpenCompute/rocm-docs-core) from 0.33.1 to 0.33.2. - [Release notes](https://github.com/RadeonOpenCompute/rocm-docs-core/releases) - [Changelog](https://github.com/ROCm/rocm-docs-core/blob/develop/CHANGELOG.md) - [Commits](https://github.com/RadeonOpenCompute/rocm-docs-core/compare/v0.33.1...v0.33.2) --- updated-dependencies: - dependency-name: rocm-docs-core[api_reference] dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Address review comments * Update doc codeowners (#303) * Documentation - Bump rocm-docs-core[api_reference] from 0.33.2 to 0.34.0 in /docs/sphinx (#304) Bumps [rocm-docs-core[api_reference]](https://github.com/RadeonOpenCompute/rocm-docs-core) from 0.33.2 to 0.34.0. - [Release notes](https://github.com/RadeonOpenCompute/rocm-docs-core/releases) - [Changelog](https://github.com/ROCm/rocm-docs-core/blob/develop/CHANGELOG.md) - [Commits](https://github.com/RadeonOpenCompute/rocm-docs-core/compare/v0.33.2...v0.34.0) --- updated-dependencies: - dependency-name: rocm-docs-core[api_reference] dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Test suite - upgrade 5 qa perf (#305) * experimental changes for adding qa mode for performance tests * made changes to add display more information w.r.t QA results summary for performance tests * minor changes * Add changes to dump qa results to excel file * Add performance QA for three new tensor functions * update prerequisites in readme * added changes to handle unsupported cases * removed treshold dictionary and added performance Noise treshold add new dataset for performance QA * RPP Test Suite Upgrade 4 - CSV to BIN conversions for file size reduction (#293) * change golden outputs from .csv files to .bin files * Changed comparision funtions to use .bin files * Address review comments * minor change * Address review comments * minor change --------- Co-authored-by: HazarathKumarM * Changes to the performane summary dataframe * minor changes * Update CMakeLists.txt to add ${CMAKE_CURRENT_SOURCE_DIR} for CI * Update CMakeLists.txt fix * Update CMakeLists.txt fix * remove tabulate dependency * Update README.md to remove tabulate pip install * Fix for CI machine failure * Add note on performance --------- Co-authored-by: sampath1117 Co-authored-by: HazarathKumarM Co-authored-by: Abishek <52214183+r-abishek@users.noreply.github.com> Co-authored-by: Snehaa Giridharan Co-authored-by: r-abishek * RPP Color Temperature on HOST and HIP (#271) * Initial commit - Color Temperature HOST Tensor * Initial commit - Color Temperature HIP Tensor * Add color temperature golden outputs * address review comments * Use reinterpret_cast instead of static_cast * Combine templated functions to support all datatypes into one (got minor perf difference of order 3%) Also fixes indentation * Fix i8 datatype * Cleanup * RPP Test Suite Upgrade 4 - CSV to BIN conversions for file size reduction (#293) * change golden outputs from .csv files to .bin files * Changed comparision funtions to use .bin files * Address review comments * minor change * Address review comments * minor change --------- Co-authored-by: HazarathKumarM * Fix PLN3 variant outputs Also modifies reference outputs * Update color_temperature.hpp license * Delete color_temperature_u8_Tensor_PKD3.csv * Delete color_temperature_u8_Tensor_PLN3.csv --------- Co-authored-by: snehaa8 Co-authored-by: HazarathKumarM Co-authored-by: Snehaa-Giridharan <118163708+snehaa8@users.noreply.github.com> * RPP Voxel 3D Tensor Add/Subtract scalar on HOST and HIP (#272) * added HOST support for voxel add kernel * added HIP support for voxel add kernel * added test suite support for add scalar * added Doxygen support and modified hip kernel function names as per new standard * added HOST support for voxel subtract kernel * added HIP support for voxel subtract kernel * added test suite support * updated the golden outputs for subtract with correct values * removed unnessary validation checks * Remove double spaces * Fix header * Fix all retval docs * Fix docs to add memory type * Fix comment * Add divider comment * Use post-increment efficiently * RPP Test Suite Upgrade 4 - CSV to BIN conversions for file size reduction (#293) * change golden outputs from .csv files to .bin files * Changed comparision funtions to use .bin files * Address review comments * minor change * Address review comments * minor change --------- Co-authored-by: HazarathKumarM * converted add and subtract scalar golden outputs to bin files * changed copyright from 2023 to 2024 * Update add_scalar.hpp license * Update subtract_scalar.hpp license --------- Co-authored-by: sampath1117 Co-authored-by: HazarathKumarM * RPP Magnitude on HOST and HIP (#278) * Initial commit - Magnitude HOST Tensor * Add QA reference outputs * Update runTests.py * Initial commit - Magnitude HIP Tensor * Add dual input support in testsuite * Optimize HOST kernel further * Optimize i8 datatype further * Modify comments * RPP Test Suite Upgrade 4 - CSV to BIN conversions for file size reduction (#293) * change golden outputs from .csv files to .bin files * Changed comparision funtions to use .bin files * Address review comments * minor change * Address review comments * minor change --------- Co-authored-by: HazarathKumarM * Bump rocm-docs-core[api_reference] from 0.31.0 to 0.33.0 in /docs/sphinx (#294) Bumps [rocm-docs-core[api_reference]](https://github.com/RadeonOpenCompute/rocm-docs-core) from 0.31.0 to 0.33.0. - [Release notes](https://github.com/RadeonOpenCompute/rocm-docs-core/releases) - [Changelog](https://github.com/ROCm/rocm-docs-core/blob/develop/CHANGELOG.md) - [Commits](https://github.com/RadeonOpenCompute/rocm-docs-core/compare/v0.31.0...v0.33.0) --- updated-dependencies: - dependency-name: rocm-docs-core[api_reference] dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Update Copywright year * Combine templated functions to support all datatypes * Modify format of reference outputs * Update rppi_arithmetic_operations.h license * Update rppt_tensor_arithmetic_operations.h license * Update host_tensor_arithmetic_operations.hpp * Update magnitude.hpp license * Update hip_tensor_arithmetic_operations.hpp license * Delete magnitude_u8_Tensor_PKD3.csv * Delete magnitude_u8_Tensor_PLN1.csv * Delete magnitude_u8_Tensor_PLN3.csv * Update rpp_test_suite_common.h license * Update runTests.py license * Update Tensor_hip.cpp license * Update runTests.py license * Update Tensor_host.cpp license --------- Signed-off-by: dependabot[bot] Co-authored-by: Snehaa Giridharan Co-authored-by: HazarathKumarM Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Snehaa-Giridharan <118163708+snehaa8@users.noreply.github.com> * Bump rocm-docs-core[api_reference] from 0.34.0 to 0.34.2 in /docs/sphinx (#309) Bumps [rocm-docs-core[api_reference]](https://github.com/RadeonOpenCompute/rocm-docs-core) from 0.34.0 to 0.34.2. - [Release notes](https://github.com/RadeonOpenCompute/rocm-docs-core/releases) - [Changelog](https://github.com/ROCm/rocm-docs-core/blob/develop/CHANGELOG.md) - [Commits](https://github.com/RadeonOpenCompute/rocm-docs-core/compare/v0.34.0...v0.34.2) --- updated-dependencies: - dependency-name: rocm-docs-core[api_reference] dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * RPP Tensor Audio Support - Down Mixing (#296) * Initial commit - Non slient region detection Includes unittest setup * Initial commit - To Decibels Includes unittest setup * Intial commit - pre_emphasis_filter * Intial commit - down_mixing * Replace vectors with arrays * Cleanup * Minor cleanup * Optimize downmixing Kernel Includes cleanup * Replace Rpp64s with Rpp32s * Cleanup * Optimize and precompute cutOff * Fix buffer used * Fix buffer used * Additional Cleanup * Optimize post incrmeent operation * Optimize post increment operation * Update testsuite for Audio * code cleanup * Add Readme file for Audio test suite * changes based on review comments * minor change * Remove unittest folders and updated README.md * Remove unit tests * minor change * code cleanup * added common header file for audio helper functions * removed unncessary audio wav files fixed bug in ROI updation for audio test suite resolved issue in summary generation for performance tests in python * removed log file * added doxygen support for audio * added doxygen changes for to_decibels * updated test suite support for to_decibels * minor change * added doxygen changes for preemphasis filter * updated changes for preemphasis filter in test suite * removed the usage of getMax function and used std::max_element * modularized code in test suite * merge with latest changes * minor change * minor change * minor change * resolved codacy warnings * Codacy fix - Remove unused cpuTime * CMakeLists - Version Update 1.5.0 - TOT Version * CHANGELOG Updates Version 1.5.0 placeholder * resolved issue with file_system dependency in test suite * Doxygen changes changed malloc to new in NSR kernel * RPP RICAP Tensor for HOST and HIP (#213) * Initial commit - Ricap HOST Tensor Includes testsuite changes * Add QA tests for RICAP Used three_images_224x224_src1 folder to create golden outputs * Add three_images_224x224_src1 into TEST_IMAGES * Support HIP Backend for RICAP * Fix HIP pkd3->pkd3 variant * regenerated golden outputs for RICAP minor changes in HOST shell script for handling RICAP in QA mode * minor bug fix in RICAP HIP kernels * Improve readability and Cleanup * Additional cleanup * Cleanup testsuite Includes new golden outputs * Additional testuite fixes * Minor cleanup * Fix codacy warnings * Address other codacy warnings * Update ricap.hpp with reference paper * Add RICAP dataset path in readme * Make changes to error codes returned * Modify roi crop region for unit and perf tests * RPP Tensor Water Augmentation on HOST and HIP (#181) * added water HOST and HIP codes * added water case in test suite * added golden outputs for water * added omp thread changes for water augmentation * experimental changes * fixed output issue with AVX2 instructions * added AVX2 support for PKD3 load function minor changes in PLN variant load functions * nwc commit - added avx2 changes for u8 layout toggle variants but need to add store functions for completion * Add Avx2 implementation for F32 and U8 toggle variants * Add AVX2 support for u8 pkd3-pln3 and i8 pkd3-pln3 for water augmentation * change F32 load and store logic * optimized the store function for F32 PLN3-PKD3 * reverted back irrelevant changes * minor change * optimized load and store functions for water U8 and F32 variants in host removed commented code * removed golden outputs for water * minor changes * renamed few functions and removed unused functions updated i8 pln1 load as per the optimized u8 pln1 load * fixed bug in i8 load function * changed cast to c++ style resolved spacing issues and added comments for AVX codes for better understanding made changes to handle cases where QA Tests are not supported * added golden outputs for water * updated golden outputs with latest changes * modified the u8, i8 pkd3-pln3 function and added comments for the vectorized code * fixed minor bug in I8 variants * made to changes to resolve codacy warnings * changed cast to c++ style in hip kernel * changed generic nn F32 loads using gather and setr instructions * added comments for latest changes * minor change * added definition for storing 32 and 64 bits from a 128bit register --------- Co-authored-by: sampath1117 Co-authored-by: HazarathKumarM * Fix build error * CMakeLists - Version Update 1.5.0 - TOT Version * CHANGELOG Updates Version 1.5.0 placeholder * Boost deps fix for test suite --------- Co-authored-by: Snehaa Giridharan Co-authored-by: sampath1117 Co-authored-by: Snehaa-Giridharan <118163708+snehaa8@users.noreply.github.com> Co-authored-by: HazarathKumarM Co-authored-by: Kiriti Gowda * Documentation - Readme & changelog updates (#251) * readme and changelog updates for 6.0 * minor update * added ctests for audio test suite for CI made changes to add more clarity on the QA Tests results * Cmake mods for ctest * HOST-only build error bugfix * added qa mode paramter to python audio script added golden output map for QA testing of Non silent region detection * minor change * Documentation - Bump rocm-docs-core[api_reference] from 0.26.0 to 0.27.0 in /docs/sphinx (#253) Bumps [rocm-docs-core[api_reference]](https://github.com/RadeonOpenCompute/rocm-docs-core) from 0.26.0 to 0.27.0. - [Release notes](https://github.com/RadeonOpenCompute/rocm-docs-core/releases) - [Changelog](https://github.com/RadeonOpenCompute/rocm-docs-core/blob/develop/CHANGELOG.md) - [Commits](https://github.com/RadeonOpenCompute/rocm-docs-core/compare/v0.26.0...v0.27.0) --- updated-dependencies: - dependency-name: rocm-docs-core[api_reference] dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * RPP Resize Mirror Normalize Bugfix (#252) * added fix for hipMemset * remove pixel check for U8-F32 and U8-F16 for HOST codes --------- Co-authored-by: sampath1117 * added example for MMS calculation in comments for better understanding * Sphinx - updates (#257) * Sphinx - updates * Doxygen - Updates * Docs - Remove index.md * updated info used to for running audio test suite * removed bitdepth variable from audio test suite * added more information on computing NSR outputs in the example added * Fix doxygen for decibels Also removes extra QA reference files * move tensor_host_audio.cpp to host folder * Fix build errors and qa tests in Audio Test suite * Fix build errors and qa tests in Audio Test suite * Add reference output and test samples for downmix * Add down_mix in augmentation list and supported cases * Remove auto-merge repeated funcs * Improve clarity of header docs * Remove blank line * Improve clarity on header docs * Add Doxygen comments * minor change * converted golden outputs to binary file for downmixing * removed old golden output file for preemphasis and todecibels * modified info for downmixing as per new changes used handle memory for temporary buffers * formatting changes * moved the common code for SSE and AVX to outside * Update down_mixing.hpp license * Update rppt_tensor_audio_augmentations.h * combined the srcLength and channels tensors into single tensor --------- Signed-off-by: dependabot[bot] Co-authored-by: Snehaa Giridharan Co-authored-by: HazarathKumarM Co-authored-by: sampath1117 Co-authored-by: Kiriti Gowda Co-authored-by: Snehaa-Giridharan <118163708+snehaa8@users.noreply.github.com> Co-authored-by: Lisa Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sundarrajan98 * RPP Voxel 3D Tensor Multiply scalar on HOST and HIP (#306) * added HIP support for voxel scalar multiply kernel * added HOST support for voxel multiply kernel added golden outputs for voxel multiply kernel * merge with master * RPP Test Suite Upgrade 4 - CSV to BIN conversions for file size reduction (#293) * change golden outputs from .csv files to .bin files * Changed comparision funtions to use .bin files * Address review comments * minor change * Address review comments * minor change --------- Co-authored-by: HazarathKumarM * converted multiply scalar voxel golden outputs to bin files * changed copyright from 2023 to 2024 --------- Co-authored-by: sampath1117 Co-authored-by: HazarathKumarM * Test Suite Bugfix (#307) * experimental changes for adding qa mode for performance tests * made changes to add display more information w.r.t QA results summary for performance tests * minor changes * Add changes to dump qa results to excel file * Add performance QA for three new tensor functions * update prerequisites in readme * added changes to handle unsupported cases * removed treshold dictionary and added performance Noise treshold add new dataset for performance QA * RPP Test Suite Upgrade 4 - CSV to BIN conversions for file size reduction (#293) * change golden outputs from .csv files to .bin files * Changed comparision funtions to use .bin files * Address review comments * minor change * Address review comments * minor change --------- Co-authored-by: HazarathKumarM * Changes to the performane summary dataframe * minor changes * Update CMakeLists.txt to add ${CMAKE_CURRENT_SOURCE_DIR} for CI * Update CMakeLists.txt fix * Update CMakeLists.txt fix * remove tabulate dependency * Update README.md to remove tabulate pip install * Fix for CI machine failure * Add note on performance * Fix segmentation fault * Revert QAmode to restrict HIP bitdepths * Use Rpp64u for HOST while comparing outputs * Fix ambiguous abs call * Fix for SLES CI HIP fail - error: incompatible pointer types assigning to 'unsigned long *' from 'unsigned long long *' - refOutput = TensorSumReferenceOutputs[numChannels].data(); --------- Co-authored-by: sampath1117 Co-authored-by: HazarathKumarM Co-authored-by: Snehaa Giridharan Co-authored-by: Pavel Tcherniaev * Update rppt_tensor_arithmetic_operations.h * Update rppt_tensor_arithmetic_operations.h * Bump rocm-docs-core[api_reference] from 0.34.2 to 0.35.0 in /docs/sphinx (#313) Bumps [rocm-docs-core[api_reference]](https://github.com/RadeonOpenCompute/rocm-docs-core) from 0.34.2 to 0.35.0. - [Release notes](https://github.com/RadeonOpenCompute/rocm-docs-core/releases) - [Changelog](https://github.com/ROCm/rocm-docs-core/blob/develop/CHANGELOG.md) - [Commits](https://github.com/RadeonOpenCompute/rocm-docs-core/compare/v0.34.2...v0.35.0) --- updated-dependencies: - dependency-name: rocm-docs-core[api_reference] dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * RPP Reduction - Tensor min and Tensor max on HOST and HIP (#260) * Minor Change * Add Validation check for DST_FOLDER path * added water HOST and HIP codes * added water case in test suite * added golden outputs for water * Add Validation checks for all options in testAllScript.sh * Add sanity check for dual Input cases Set Max Dimension and Max Image Dump Replaced Fast DCT tag with Accurate DCT * Regenerate golden outputs using accurate dct Flag Add golden outputs for some new augmentations * Fix Flip golden outputs mismatch Fix PLN3 variants mismatch in QA mode * Add MAX_BATCH_SIZE check removed Augmentations function calls for failing Qa modes code cleanup * Add crop and gamma correction augmentations code cleanup * Add comments to functions in rpp_test_suite_common.h * minor change * code cleanup * minor code changes * Change roi and Image sizes for crop augmentation * Change numIterations option to numRuns Addressed PR comments * added omp thread changes for water augmentation * experimental changes * fixed output issue with AVX2 instructions * added AVX2 support for PKD3 load function minor changes in PLN variant load functions * Add turboJpeg header to update maxHeight and maxWidth values * nwc commit - added avx2 changes for u8 layout toggle variants but need to add store functions for completion * Change the performance Timings logic * Add Avx2 implementation for F32 and U8 toggle variants * minor change to support u8_f16 and u8_f32 cases * Regenerate LUT golden outputs with ACCURATE_DCT tag * Minor code changes * Add AVX2 support for u8 pkd3-pln3 and i8 pkd3-pln3 for water augmentation * Made changes to the runTests.py in Host to remove testAllScipts.sh * Made changes to the runTests.py in HIP to remove testAllScipts.sh * Initial commit - Image min and max Reduction kernel Includes * u8 datatype for both min and max HOST Tensor of all variants. * Testsuite changes. * NWC -initial code for min max PLN3 - PLN3 * made changes to split min and max kernels seperately * splitted kernels for min and max * made changes to print final max/min in the R,G,B channels * fixed inaccuracies in min/max computation * made changes to typecast intermediate output to output requested by user added comments for the code code cleanup and minor changes in test suite * fixed build issues removed image folders used for min, max and sum reverted unwanted file changes * minor changes in test suite * removed support for unwanted test case in Tensor_hip.cpp * Adds new option roi * remove testAllScripts.sh * Adds roi Option in HIP backend * Implement f32 variants * Implement f16 and i8 datatype variants * change F32 load and store logic * Add build flags in CMakeLists.txt to set AVX/SSE flags based on the system configuration * minor code changes * Initial commit - Image sum Reduction kernel Includes u8 PLN1 -> PLN1 conversion for HOST Tensor * Implement PKD3 and PLN3 for Image sum Tensor HOST * Support i8, f16 and f32 datatypes * Initial commit - Image sum Reduction HIP kernel Includes u8 PLN1 -> PLN1 conversion for Tensor * Implement PKD3 and PLN3 for Image sum Tensor HIP * Add support in testsuite Revert normalization for i8 HOST Tensor variants * Fix HIP testsuite Remove additional blanks for 1 channel output * Modify print statement in HIP testsuite * Improve readability for testsuite outputs * optimized the store function for F32 PLN3-PKD3 * reverted back irrelevant changes * minor change * Fix HIP to support larger inputs * optimized load and store functions for water U8 and F32 variants in host removed commented code * Cleanup * removed golden outputs for water * minor changes * Cleanup Support Reduction QA test in testsuite * renamed few functions and removed unused functions updated i8 pln1 load as per the optimized u8 pln1 load * fixed bug in i8 load function * Remove unused variables and C style casting * changed cast to c++ style resolved spacing issues and added comments for AVX codes for better understanding made changes to handle cases where QA Tests are not supported * added golden outputs for water * updated golden outputs with latest changes * modified the u8, i8 pkd3-pln3 function and added comments for the vectorized code * fixed minor bug in I8 variants * Optimize u8 datatype further * Fix static_cast * made to changes to resolve codacy warnings * changed cast to c++ style in hip kernel * Initial commit - Ricap HOST Tensor Includes testsuite changes * Add QA tests for RICAP Used three_images_224x224_src1 folder to create golden outputs * Add three_images_224x224_src1 into TEST_IMAGES * added rotate case with golden outputs changed generic bilinear HOST codes to match with HIP codes * Add golden output for remaining all tensor augmentations * fix python script issues * Optimize u8 and i8 datatype Uses uint and int internal processing instead of float * Fix testsuite build errors * minor change * Fix QA check * Modify api naming from image_sum to tensor_sum Includes changes for both HOST and HIP * Support HIP Backend for RICAP * change rcm and rmn golden outputs * Fix HIP pkd3->pkd3 variant * changes based on review comments * change test_suite folder to tests * Optimize u8 and i8 datatype of HIP Includes modification in naming of shared memory * minor fix * changed generic nn F32 loads using gather and setr instructions * Optimize and cleanup U8 HIP * regenerated golden outputs for RICAP minor changes in HOST shell script for handling RICAP in QA mode * minor bug fix in RICAP HIP kernels * Fix i8 datatype variants Includes cleanup * Fix the issues with color_to_greyscale * remove the empty folder creation * reverting back the folder name change * minor change * added comments for latest changes * minor change * Improve readability and Cleanup * Fix QA for HIP Includes cleanup * resolved review comments * minor change * Modify api naming from image_ to tensor_ for HOST * Add support for QA tests * removed range check for RMN U8-F32 and U8-F16 variants changed from hipMemset to hipMemsetAsync for RMN HIP Kernel removed multiplication by 255 for stdDev in RMN HOST U8-F16 and U8-F32 variants * Modify naming of shared memory with _smem in HIP Includes cleanup * Typecast and reuse markArr for HIP U8 and I8 * Cleanup and minor optimization * minor fix * fix codacy warnings * Additional cleanup * Cleanup and move #define * Changed the complexity of if statements in runTests.py * Cleanup testsuite Includes new golden outputs * Additional testuite fixes * Minor cleanup * Codacy fixes * Fix codacy warnings * Codacy fix * Address other codacy warnings * cleanup * Change Image functions to generic * Update ricap.hpp with reference paper * resolved minor issues happened with merge * minor changes * fixed minor issue with getting profiler times * minor formatting changes * resolved build issues in test suite renamed the min and max kernel file names * RPP RICAP Tensor for HOST and HIP (#213) * Initial commit - Ricap HOST Tensor Includes testsuite changes * Add QA tests for RICAP Used three_images_224x224_src1 folder to create golden outputs * Add three_images_224x224_src1 into TEST_IMAGES * Support HIP Backend for RICAP * Fix HIP pkd3->pkd3 variant * regenerated golden outputs for RICAP minor changes in HOST shell script for handling RICAP in QA mode * minor bug fix in RICAP HIP kernels * Improve readability and Cleanup * Additional cleanup * Cleanup testsuite Includes new golden outputs * Additional testuite fixes * Minor cleanup * Fix codacy warnings * Address other codacy warnings * Update ricap.hpp with reference paper * Add RICAP dataset path in readme * Make changes to error codes returned * Modify roi crop region for unit and perf tests * RPP Tensor Water Augmentation on HOST and HIP (#181) * added water HOST and HIP codes * added water case in test suite * added golden outputs for water * added omp thread changes for water augmentation * experimental changes * fixed output issue with AVX2 instructions * added AVX2 support for PKD3 load function minor changes in PLN variant load functions * nwc commit - added avx2 changes for u8 layout toggle variants but need to add store functions for completion * Add Avx2 implementation for F32 and U8 toggle variants * Add AVX2 support for u8 pkd3-pln3 and i8 pkd3-pln3 for water augmentation * change F32 load and store logic * optimized the store function for F32 PLN3-PKD3 * reverted back irrelevant changes * minor change * optimized load and store functions for water U8 and F32 variants in host removed commented code * removed golden outputs for water * minor changes * renamed few functions and removed unused functions updated i8 pln1 load as per the optimized u8 pln1 load * fixed bug in i8 load function * changed cast to c++ style resolved spacing issues and added comments for AVX codes for better understanding made changes to handle cases where QA Tests are not supported * added golden outputs for water * updated golden outputs with latest changes * modified the u8, i8 pkd3-pln3 function and added comments for the vectorized code * fixed minor bug in I8 variants * made to changes to resolve codacy warnings * changed cast to c++ style in hip kernel * changed generic nn F32 loads using gather and setr instructions * added comments for latest changes * minor change * added definition for storing 32 and 64 bits from a 128bit register --------- Co-authored-by: sampath1117 Co-authored-by: HazarathKumarM * Fix build error * CMakeLists - Version Update 1.5.0 - TOT Version * CHANGELOG Updates Version 1.5.0 placeholder * Boost deps fix for test suite --------- Co-authored-by: Snehaa Giridharan Co-authored-by: sampath1117 Co-authored-by: Snehaa-Giridharan <118163708+snehaa8@users.noreply.github.com> Co-authored-by: HazarathKumarM Co-authored-by: Kiriti Gowda * Documentation - Readme & changelog updates (#251) * readme and changelog updates for 6.0 * minor update * Documentation - Bump rocm-docs-core[api_reference] from 0.26.0 to 0.27.0 in /docs/sphinx (#253) Bumps [rocm-docs-core[api_reference]](https://github.com/RadeonOpenCompute/rocm-docs-core) from 0.26.0 to 0.27.0. - [Release notes](https://github.com/RadeonOpenCompute/rocm-docs-core/releases) - [Changelog](https://github.com/RadeonOpenCompute/rocm-docs-core/blob/develop/CHANGELOG.md) - [Commits](https://github.com/RadeonOpenCompute/rocm-docs-core/compare/v0.26.0...v0.27.0) --- updated-dependencies: - dependency-name: rocm-docs-core[api_reference] dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * RPP Resize Mirror Normalize Bugfix (#252) * added fix for hipMemset * remove pixel check for U8-F32 and U8-F16 for HOST codes --------- Co-authored-by: sampath1117 * Cmake fix to prevent warning * Fix paths in new python scripts * Sphinx - updates (#257) * Sphinx - updates * Doxygen - Updates * Docs - Remove index.md * Test suite fixes after tensor_min / tensor_max HOST merge * Fix max case * QA tests fix for hip and host * naming convention changes as per new std * Substitute imagePartial with partial * Substitute imageMin/imageMax with min/max * Replace hipMemset with hipMemsetAsync, and replace hipDeviceSynchronize with hipStreamSynchronize * Use variable instead of batchCount*4 * Use post increment effectivly * Resolve codacy warnings * Additional cleanup * remove unused variable * Documentation - Bump rocm-docs-core[api_reference] from 0.28.0 to 0.29.0 in /docs/sphinx (#265) Bumps [rocm-docs-core[api_reference]](https://github.com/RadeonOpenCompute/rocm-docs-core) from 0.28.0 to 0.29.0. - [Release notes](https://github.com/RadeonOpenCompute/rocm-docs-core/releases) - [Changelog](https://github.com/RadeonOpenCompute/rocm-docs-core/blob/develop/CHANGELOG.md) - [Commits](https://github.com/RadeonOpenCompute/rocm-docs-core/compare/v0.28.0...v0.29.0) --- updated-dependencies: - dependency-name: rocm-docs-core[api_reference] dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Remove auto merge boost * Spaces formatting * Bump rocm-docs-core[api_reference] from 0.29.0 to 0.30.1 in /docs/sphinx (#268) Bumps [rocm-docs-core[api_reference]](https://github.com/RadeonOpenCompute/rocm-docs-core) from 0.29.0 to 0.30.1. - [Release notes](https://github.com/RadeonOpenCompute/rocm-docs-core/releases) - [Changelog](https://github.com/RadeonOpenCompute/rocm-docs-core/blob/develop/CHANGELOG.md) - [Commits](https://github.com/RadeonOpenCompute/rocm-docs-core/compare/v0.29.0...v0.30.1) --- updated-dependencies: - dependency-name: rocm-docs-core[api_reference] dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * add support for mi300 (#269) * Documentation - Bump rocm-docs-core[api_reference] from 0.30.1 to 0.30.2 in /docs/sphinx (#273) Bumps [rocm-docs-core[api_reference]](https://github.com/RadeonOpenCompute/rocm-docs-core) from 0.30.1 to 0.30.2. - [Release notes](https://github.com/RadeonOpenCompute/rocm-docs-core/releases) - [Changelog](https://github.com/RadeonOpenCompute/rocm-docs-core/blob/develop/CHANGELOG.md) - [Commits](https://github.com/RadeonOpenCompute/rocm-docs-core/compare/v0.30.1...v0.30.2) --- updated-dependencies: - dependency-name: rocm-docs-core[api_reference] dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Cleanup by removing oneliner functions as inline * RPP Tensor Audio Support - To Decibels (#258) * Initial commit - Non slient region detection Includes unittest setup * Initial commit - To Decibels Includes unittest setup * Replace vectors with arrays * Cleanup * Replace Rpp64s with Rpp32s * Optimize and precompute cutOff * Fix buffer used * Fix buffer used * Additional Cleanup * Update testsuite for Audio * code cleanup * Add Readme file for Audio test suite * changes based on review comments * minor change * Remove unittest folders and updated README.md * Remove unit tests * minor change * code cleanup * added common header file for audio helper functions * removed unncessary audio wav files fixed bug in ROI updation for audio test suite resolved issue in summary generation for performance tests in python * removed log file * added doxygen support for audio * added doxygen changes for to_decibels * updated test suite support for to_decibels * minor change * removed the usage of getMax function and used std::max_element * modularized code in test suite * merge with latest changes * minor change * minor change * resolved codacy warnings * Codacy fix - Remove unused cpuTime * CMakeLists - Version Update 1.5.0 - TOT Version * CHANGELOG Updates Version 1.5.0 placeholder * resolved issue with file_system dependency in test suite * Doxygen changes changed malloc to new in NSR kernel * RPP RICAP Tensor for HOST and HIP (#213) * Initial commit - Ricap HOST Tensor Includes testsuite changes * Add QA tests for RICAP Used three_images_224x224_src1 folder to create golden outputs * Add three_images_224x224_src1 into TEST_IMAGES * Support HIP Backend for RICAP * Fix HIP pkd3->pkd3 variant * regenerated golden outputs for RICAP minor changes in HOST shell script for handling RICAP in QA mode * minor bug fix in RICAP HIP kernels * Improve readability and Cleanup * Additional cleanup * Cleanup testsuite Includes new golden outputs * Additional testuite fixes * Minor cleanup * Fix codacy warnings * Address other codacy warnings * Update ricap.hpp with reference paper * Add RICAP dataset path in readme * Make changes to error codes returned * Modify roi crop region for unit and perf tests * RPP Tensor Water Augmentation on HOST and HIP (#181) * added water HOST and HIP codes * added water case in test suite * added golden outputs for water * added omp thread changes for water augmentation * experimental changes * fixed output issue with AVX2 instructions * added AVX2 support for PKD3 load function minor changes in PLN variant load functions * nwc commit - added avx2 changes for u8 layout toggle variants but need to add store functions for completion * Add Avx2 implementation for F32 and U8 toggle variants * Add AVX2 support for u8 pkd3-pln3 and i8 pkd3-pln3 for water augmentation * change F32 load and store logic * optimized the store function for F32 PLN3-PKD3 * reverted back irrelevant changes * minor change * optimized load and store functions for water U8 and F32 variants in host removed commented code * removed golden outputs for water * minor changes * renamed few functions and removed unused functions updated i8 pln1 load as per the optimized u8 pln1 load * fixed bug in i8 load function * changed cast to c++ style resolved spacing issues and added comments for AVX codes for better understanding made changes to handle cases where QA Tests are not supported * added golden outputs for water * updated golden outputs with latest changes * modified the u8, i8 pkd3-pln3 function and added comments for the vectorized code * fixed minor bug in I8 variants * made to changes to resolve codacy warnings * changed cast to c++ style in hip kernel * changed generic nn F32 loads using gather and setr instructions * added comments for latest changes * minor change * added definition for storing 32 and 64 bits from a 128bit register --------- Co-authored-by: sampath1117 Co-authored-by: HazarathKumarM * Fix build error * CMakeLists - Version Update 1.5.0 - TOT Version * CHANGELOG Updates Version 1.5.0 placeholder * Boost deps fix for test suite --------- Co-authored-by: Snehaa Giridharan Co-authored-by: sampath1117 Co-authored-by: Snehaa-Giridharan <118163708+snehaa8@users.noreply.github.com> Co-authored-by: HazarathKumarM Co-authored-by: Kiriti Gowda * Documentation - Readme & changelog updates (#251) * readme and changelog updates for 6.0 * minor update * added ctests for audio test suite for CI made changes to add more clarity on the QA Tests results * Cmake mods for ctest * HOST-only build error bugfix * added qa mode paramter to python audio script added golden output map for QA testing of Non silent region detection * minor change * Documentation - Bump rocm-docs-core[api_reference] from 0.26.0 to 0.27.0 in /docs/sphinx (#253) Bumps [rocm-docs-core[api_reference]](https://github.com/RadeonOpenCompute/rocm-docs-core) from 0.26.0 to 0.27.0. - [Release notes](https://github.com/RadeonOpenCompute/rocm-docs-core/releases) - [Changelog](https://github.com/RadeonOpenCompute/rocm-docs-core/blob/develop/CHANGELOG.md) - [Commits](https://github.com/RadeonOpenCompute/rocm-docs-core/compare/v0.26.0...v0.27.0) --- updated-dependencies: - dependency-name: rocm-docs-core[api_reference] dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * RPP Resize Mirror Normalize Bugfix (#252) * added fix for hipMemset * remove pixel check for U8-F32 and U8-F16 for HOST codes --------- Co-authored-by: sampath1117 * added example for MMS calculation in comments for better understanding * Sphinx - updates (#257) * Sphinx - updates * Doxygen - Updates * Docs - Remove index.md * updated info used to for running audio test suite * removed bitdepth variable from audio test suite * added more information on computing NSR outputs in the example added * Fix doxygen for decibels Also removes extra QA reference files * Fix build errors and qa tests in Audio Test suite * Remove auto-merge repeated funcs * Improve clarity on header docs * made changes based on review comments * stored golden outputs of to_decibels in binary file removed golden output text files for non silent region * removed unused parameter in verify_output function * updated list of cases supported in python script * added error handling for opening golden output file * Codacy fix and tests warning fix * Codacy fix * Codacy fix trial * codacy fix for checking boundaries of fstream --------- Signed-off-by: dependabot[bot] Co-authored-by: Snehaa Giridharan Co-authored-by: HazarathKumarM Co-authored-by: sampath1117 Co-authored-by: Kiriti Gowda Co-authored-by: Snehaa-Giridharan <118163708+snehaa8@users.noreply.github.com> Co-authored-by: Lisa Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Documentation - Bump rocm-docs-core[api_reference] from 0.30.2 to 0.30.3 in /docs/sphinx (#274) Bumps [rocm-docs-core[api_reference]](https://github.com/RadeonOpenCompute/rocm-docs-core) from 0.30.2 to 0.30.3. - [Release notes](https://github.com/RadeonOpenCompute/rocm-docs-core/releases) - [Changelog](https://github.com/RadeonOpenCompute/rocm-docs-core/blob/develop/CHANGELOG.md) - [Commits](https://github.com/RadeonOpenCompute/rocm-docs-core/compare/v0.30.2...v0.30.3) --- updated-dependencies: - dependency-name: rocm-docs-core[api_reference] dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Adding issue template (#270) * Add files via upload * added ROCm v6, MI300, default component * Fix cast used in testsuite Includes minor fixes * Fix displaying f16 outputs * Optimize HOST min/max reduce function further * Fix spacing in HIP kernels * Fix PLN1 outputs for u8 and i8 datatypes of HOST backend * RPP Test Suite Upgrade 4 - CSV to BIN conversions for file size reduction (#293) * change golden outputs from .csv files to .bin files * Changed comparision funtions to use .bin files * Address review comments * minor change * Address review comments * minor change --------- Co-authored-by: HazarathKumarM * Bump rocm-docs-core[api_reference] from 0.31.0 to 0.33.0 in /docs/sphinx (#294) Bumps [rocm-docs-core[api_reference]](https://github.com/RadeonOpenCompute/rocm-docs-core) from 0.31.0 to 0.33.0. - [Release notes](https://github.com/RadeonOpenCompute/rocm-docs-core/releases) - [Changelog](https://github.com/ROCm/rocm-docs-core/blob/develop/CHANGELOG.md) - [Commits](https://github.com/RadeonOpenCompute/rocm-docs-core/compare/v0.31.0...v0.33.0) --- updated-dependencies: - dependency-name: rocm-docs-core[api_reference] dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Store reference outputs via map for min and max kernels * Update tensor_max.hpp license * Update tensor_min.hpp license * Fix output comparison check * Merge branch 'ar/opt_tensor_min_tensor_max' of https://github.com/r-abishek/rpp into sn/tensor_min_max * Modify exit condition used in outer most kernel * Modify srcIdx for HIP Tensor min * Using maximum as 255 for HIP Tensor min * Modify srcIdx for HIP Tensor max kernel Also fixes build error in testsuite * Fix corrupted outputs displayed for Tensor sum * Fix corruption issue seen with tensor sum kernel * Fix minimum for I8 Tensor max kernel * Modified HIP buffer initialization with a common function * Fix redefinition * Remove additional variables xAlignedLength * Remove unwanted xAlignedLength and xDiff * Remove redefinition of TensorSumReferenceOutputs * Fix for CI issue * Add parenthesis --------- Signed-off-by: dependabot[bot] Co-authored-by: HazarathKumarM Co-authored-by: sampath1117 Co-authored-by: Snehaa Giridharan Co-authored-by: Snehaa-Giridharan <118163708+snehaa8@users.noreply.github.com> Co-authored-by: fiona-gladwin Co-authored-by: Kiriti Gowda Co-authored-by: Lisa Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Lakshmi Kumar Co-authored-by: abhimeda <138710508+abhimeda@users.noreply.github.com> * CI - Update precheckin.groovy * Move bitwise operations into under logical ops * Fix doxygen comments * Merge with master * Cleanup * Revert change in CMakeLists.txt * Add docs outputs * Cleanup --------- Signed-off-by: dependabot[bot] Co-authored-by: Snehaa Giridharan Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Sam Wu Co-authored-by: Kiriti Gowda Co-authored-by: sampath1117 Co-authored-by: HazarathKumarM Co-authored-by: Snehaa-Giridharan <118163708+snehaa8@users.noreply.github.com> Co-authored-by: Lisa Co-authored-by: Sundarrajan98 Co-authored-by: Pavel Tcherniaev Co-authored-by: fiona-gladwin Co-authored-by: Lakshmi Kumar Co-authored-by: abhimeda <138710508+abhimeda@users.noreply.github.com> --- .Doxyfile | 5 +- ...ical_operations_bitwise_and_img150x150.png | Bin 0 -> 19072 bytes ...gical_operations_bitwise_or_img150x150.png | Bin 0 -> 19003 bytes docs/doxygen/Doxyfile | 3 +- include/rppdefs.h | 15 +- include/rppt.h | 1 + include/rppt_tensor_arithmetic_operations.h | 14 +- include/rppt_tensor_logical_operations.h | 139 +++ src/include/cpu/rpp_cpu_simd.hpp | 52 + src/include/hip/rpp_hip_common.hpp | 28 + .../cpu/host_tensor_logical_operations.hpp | 31 + src/modules/cpu/kernel/bitwise_and.hpp | 965 ++++++++++++++++++ src/modules/cpu/kernel/bitwise_or.hpp | 965 ++++++++++++++++++ .../hip/hip_tensor_logical_operations.hpp | 31 + src/modules/hip/kernel/bitwise_and.hpp | 247 +++++ src/modules/hip/kernel/bitwise_or.hpp | 247 +++++ .../rppt_tensor_logical_operations.cpp | 300 ++++++ utilities/test_suite/HIP/Tensor_hip.cpp | 26 +- utilities/test_suite/HIP/runTests.py | 7 +- utilities/test_suite/HOST/Tensor_host.cpp | 28 +- utilities/test_suite/HOST/runTests.py | 8 +- .../bitwise_and/bitwise_and_u8_Tensor.bin | Bin 0 -> 273600 bytes .../bitwise_or/bitwise_or_u8_Tensor.bin | Bin 0 -> 273600 bytes utilities/test_suite/rpp_test_suite_common.h | 2 + 24 files changed, 3094 insertions(+), 20 deletions(-) create mode 100644 docs/data/doxygenOutputs/logical_operations_bitwise_and_img150x150.png create mode 100644 docs/data/doxygenOutputs/logical_operations_bitwise_or_img150x150.png create mode 100644 include/rppt_tensor_logical_operations.h create mode 100644 src/modules/cpu/host_tensor_logical_operations.hpp create mode 100644 src/modules/cpu/kernel/bitwise_and.hpp create mode 100644 src/modules/cpu/kernel/bitwise_or.hpp create mode 100644 src/modules/hip/hip_tensor_logical_operations.hpp create mode 100644 src/modules/hip/kernel/bitwise_and.hpp create mode 100644 src/modules/hip/kernel/bitwise_or.hpp create mode 100644 src/modules/rppt_tensor_logical_operations.cpp create mode 100644 utilities/test_suite/REFERENCE_OUTPUT/bitwise_and/bitwise_and_u8_Tensor.bin create mode 100644 utilities/test_suite/REFERENCE_OUTPUT/bitwise_or/bitwise_or_u8_Tensor.bin diff --git a/.Doxyfile b/.Doxyfile index 77e66d9e9..066a53c02 100644 --- a/.Doxyfile +++ b/.Doxyfile @@ -967,8 +967,9 @@ INPUT = README.md \ include/rppt_tensor_geometric_augmentations.h \ include/rppt_tensor_morphological_operations.h \ include/rppt_tensor_statistical_operations.h \ - include/rppt_tensor_arithmetic_operations.h - include/rppt_tensor_audio_augmentations.h + include/rppt_tensor_arithmetic_operations.h \ + include/rppt_tensor_audio_augmentations.h \ + include/rppt_tensor_logical_operations.h # This tag can be used to specify the character encoding of the source files diff --git a/docs/data/doxygenOutputs/logical_operations_bitwise_and_img150x150.png b/docs/data/doxygenOutputs/logical_operations_bitwise_and_img150x150.png new file mode 100644 index 0000000000000000000000000000000000000000..8ff97bd5848af5e69b67f63a0c18f621ba427fd8 GIT binary patch literal 19072 zcmbTdWl$VX*gd+q2MG`y5+JxcY#@Z-0fIXO4=nDk!QF!=xH~NF?(XiAgh#n}H%NXRItXy_O( zX5hS3Xd-wq9|h&bXtWoLUuyfk+y|f%q7l92kwky3YJ&03iI_Ji@i!*@r@CGewOJ?w zpQ&>&7B=Y{GI9#W_e{(zto#CkLc$`VQlF(|WaZ=))HO7mL{#8Xg%Po10%) zTv}dPUEAH;KR7%(J~=&uU0vV&y}g6qKm3Oa34rpyuwL^2M_hz2xRC$r1C0N0At8Ib zoG65-Xm5GYi6m7qOq^c7;|;O6~0%D}(N2>TD({~-H+2Q2vi z7qb5g*#C`d4SQ5s#sua^R{(;v_ZkZ>n}R1v1O+aU?VDFd=&FCi6euPhJK;7y)M5}W^?nM-orPah<&gcfb zT{2VzP9cd4+I^;c2u=3S)~Y40i|a?{#hY4fM)G#~A6_x-QBcu~Dnp&psRp_e0gYAv6RE%#&gx40Ru*Fp_b)9sohvfh&^(nzpD)yFIe+iPsJ;~V0=27 zUlb3o2mS#X?)qw|Pwyz=L+I<~1e)D=Fb}W(V4^vbf9jf$DM9;m_|wWmZx876$mgpJ zwfnKw^c-zns-vfW4}P;|IJJv>jB)s_p1RympxomG?AJ!M2_80%iZ9eVy=_A{Wic=>E7>L~Its5J zk)xQG?$aTA*O^U%eEH!20DG6XXHF~dW6iX4#Uz2y>aX#F%MLhinNbu(?!opBdl+;T zF4|qhi~Q00piULp&c>))3Em-}EbTb4&>pdb+WR4LFDmB`UK6cyTW=!MJ{5hm8~MmY zUqW)C)@x2yS*>~)mE1MPvh|?5-hI|QvrXG;Afk`K3;h>#R>&o&>j|BnMZ7$3(WhbVIgU|sV z+K`4zZ0^N&F$MxiJzoz9dOO?vakakKk8|zNr4iFXOinY1DIYol`$JJ_6c-lT5t*Kri_fA-YU3hCor^6ep4Ci`gT-=@S z%$Qu09d@;j>g_j;*7Kq*I~e1}3QtXcoz1A-*@%fT&1pBN>HC1Y9^O6}bwjuN)6NS{ zy2vv)cAQP*2-O5eNBiC{_KE=GoL!V)5(C1F^IgNgSLJPRo?t1geA##gDa8G0t-IGnIK_lj2keQRS(4=MXjNb|m^|grpE&7*va}WWXadya&`VO{m zUr%l%R!>f?+ybHf=-aYpWIC;|dA`2fx|C^JF=X0P?xy+uddtYG4ui(r|I=0LF_l~O z_<;Cp=w&=YjJGI8s2S|EcQsQ(6f!02xJtf{N|+c%1#5E%0?K+(|Cog<>5MwDZhitg zvjNd%2uH%ll6}zD6Od!7G1O!(LlDyYib5fhFqI$1QXSo&^;w7}Nvv83(_B%U)_!pA zz6I`-;as5~4#NY6RvF3n&rB#{B_cP)bT2Q!AU(viqD@wFu03z8$WD&j`FOdb(~**4 z3AK9Lp~Ji%1(0h`<pS51>b%LB30@+sP^YCD+56P-kx{zZ zn`v?;rZ|yU$w&B;fB{#_C-hg z7;bV2Z-buo*qFZ6FEl~kO9nOvJ-PY` z5Zn#$_&wSPeDtES4+nXs9U%}rKcI7~rW*H%ylU&ZBkq|z6-w}$=AT5BdYzPh(yO_) zvR=n-W{z|bldC{wUZ+60V3k)Fk>~|Zz#)D%{H*t%SS;5xl;yrSq4>Oz$)kVlJ0h&l61jLjJ~%e8!>pdYR*_I8Zw1{Xm}aq&$Fe^Yq=YVEvdE|lkK+; z-!GAn)TNPl$^m+SJePUiW(ph=y0kO>GQtl~7?^#2YRh%|f_rG ztfp+~evA!~AVUJ-+0&K8<5YHfE&Xn_hmx_LQfyRHt=y%y#ey+rMd(R%oBW-vWb!8thETb>4L0L7F z_>f%wWdHrVR_MCX-%C4^%IS{XKi5%?EyAj0hF3MAHraZ1LIv{R%kMXOVl-CJe}G%R zX6R5dyAk93Zrtf1mwPfJUh+?OeE6+1Rzzd1<~0sqXyRFPkwYKc?dT*P&|b?i%6F_T8TXIvw^U ztk@>AL+k2~ zhUo?tzM3#?-amkjrjo2tlQF~ao9Pzuc{jcA~k^AexXFgcf-{)47{dKLbg@d?_ z4~vu8AdZr>14uMss@w`6DPanG5A^_B_+#dG^TnIJTke4?$iC+mLE^}ir@-~}@RQlT zY^VT8pM!RQ^ueN|l5}cXZf>H%P)=SGS?L!kyX*+Q0d8Cq)U)OlT)8}#4Nv-Oc7W$0 zIdg@yVYTk4B!|eKY^_*hO$Vv)YlMt`gaYv{)B6G|(#`v1WvDU;BtSerd)1ut?3Cb_ zZy3vhid!Ejp?bz+DA8~CrpF_5!U3lJb7tvbIyqW@!MP=4i}Qa_l&?-NwN#TC$7hG5`Efkz~H?9?WlM2GFQOniixm{96yZ*#yFJ3{G6)8K$pl_PoSbyz&2K`Cks`-OE)40}JP>#%d zC%v+H4@*4wb49U~EhQ6O#7C1vDy)Q=l$SIv}&nNw*U(ro7yUhL8EEQaH zmY*KoHhh^sZX~FOJX3Sc&x+rmXsIhJf!Rbrb_WZc=bZ5}o>qfgNHu-`0JPh18YTIf zu7P)xGvVV~MhwXp7q({pqPcmYBsbaqADWgMOKnWX8d${IsT$C_Rzy@f|r zT15PS@#|-avuCWG-b-^TVcu%e??ydHiVu2R>cg=Z&daE6e{FcH6goQpD zNdpjRK$3SeuVaDmSB$xBsB(A2Wx(%EUp{fl#$alZHLC@?7&C|pU-MuJZT1LuAeA|> zw0dlG`@m?6B1h5ijSH1D8gXm!uNr2S!VQZ_wrf2t-)a^SFWL_S2###%H14?21W3J1 zSAn(CdW$={jFHB3%=yT}j_IPrOI*`6<4?F^EwnivJ-KMDpO{;=UN}*cP)4E+fO5iP zU>w0{#-IKMJ1!~domK)A9o_T%Jgy0n-bRyE@uRkL{?~WZE$axsx&D|0G56zO*0c&} zdXM)+tV`($VI4Lx=AmcLFd#4nqZ_%~ugA($&a|^*-btx2t!i9FV7ux`p!I&rFngCp z!?_I0t1pp8DA=P7?!eiRbEAzCE%|X1k^FhSFy}Z^=xT12FlY65j9p?~f-qBP?+9{37qMr! z%Ci3}c^JB%W&daB#O*(T?fmm9mM;G~`8%RIFAA;g_s6EnpGpA$r!**E9I!^$haHVI z<=p1!kOW8ObW0_}-Mab=LMzwtX`I{ftEarC59mAF*_x6uh+|pXFZCJJ3h&Q1*#5kn z4jX2;(AuILMMb-9-V!2AKH&?w*OY?!^lmZCmn?BoD9Zn_?;A@Wkg<$4EZ}{+8Lq;k z>-@@t?Umf1w?teQ_DL=;G(D2NLtuZJz-B&H;bLDYYam$BqISXkH#li_i$}B{=RLuI zf?bki1`-*3UJ||t6YKM5hP|pQuz@g6br&~vB5Fzvp+!y%-DYKH=|Us`ZCmv7MRL;&XQAwC-y*%l`61gwt=ebbzcer7fGH@kS2eMoKw_ z7s+rtKXqfH6Iv42$VSh<3muL6)IlX}k2ay2_sW+g9|rBlVfcL&#nNTgnUSehA7P5b zVv8w(&V@w9U1o5Q6U<{@qiv=h*8SrEh9AwLD_{(H5}XrDMjo~`OTzk$$JT&pes5-& zc#r-i{QFi{Gu(K`I5>?42P{exYFBpRK_u6_>@K=7kJoc}E1YtSL3f><#AmD$0yFt) zlV&EHDo_!6l>Gd6flA#&QRc>O-Qvi~Kt1u`=U+wcBIfDxkfY|Mqoc2LdRP3Nhm?Qj z1%QMS@kAmxa9X|4C9T+k*7;%sh^Y|E5T>v&eXt1mq?@RFATXe4oD{rU>cCNi5|I0A zm~Q%;oYslAYqi6zGdv!ezDL(l2jy4?-KJgS@11Kl$aJXg~sJBxyud@k9ge1|b; z#tTk+V=5p1+?kW$f^o>0ou+_IswZBMQ$4B3Q?q^Y-Q`Oz>-X6o4lOq{D(8I8mX*Qa ziG98%y(T#yarwd3G8w18jmDk!<+tt^FK*FZUf33E+`|xUc&1X-P@W}(rzvxH?`mK8 zV;S8BsemOO*o>fkk-OyE5WHdkAK;ZQ&x}0>P~WfYZSMAXsGaM*xvoc=YV#*l$w0K` zbS>=ekNy=Q@`)ei87So_6=Hw69_L+O8gvh+1iegGsU-$FHkq!xvd)D@^wnApw=MKX zXp*=hs8(BDZ=w+5JyyiOBc>IiT%f)VxLaU1iL2qcGY_j&l!L$^Z(giD&i(pP`% zh1L%gaFm!6E_*(Whn{>Q;%Tku;kXfdEb_AboFq-Lb3sJ|2Sh=+vl){XN;qv4`1Hhz zmwhTGFa6KUy{jZ#cg4w}=P|sa`@H3^iwl^rJ~?c~Bq>kvra%g`8Y}PGwSesg@EVwv z`U1s80Pz`x7ySXaq1DH8(OC}Z>vhaN6BA03le9Ox)>3lPRnKF~*zh$HJc?~59#`#$ zh8c5VySj0O)jSuzb2%tYP(Hvdpa&5bt_vj@3KEm5I(1nq)3in{9YLbMKz6L`$qmd6 zKi6%`3$NOZHr)UQbGy@R{KEg{f;hjZiTek@yMesXY@ffVL>;NrBc=7yY=|Ko8FKXV zV>_k}*qO>I8)g?p?HgQ44I_JZ?@gG~5$LaZ0GJFELYj1+nXXN?o>CTXtMYsE_e!|_ zl7NR#SqJeh#q`gi{OX%tR(wohFvXZ8wY3wk1YQHy}})uPZ<_4sX-drM>z}m zy*g4Cxd%&z1af(_)cTkhr2c|Baz+pBx$~Wp+E6?8y;#x}FXjX}Oze(t1QI~E%Tr^E z{uJ((hkpRW)XdPmn#I!^B@VyEoQs;)d+lf{eRa_?Trh@$e_xh*N?{d*$$WSG&82g% z$otK#thE_sgP2>sLAFT>nO1`flU}Oqn7=!><>2&mtwjDf;IOnXCX%K2FOOTu9Jt9) zz^>Xf%nO@M-z%|!Ft&i4yk`hqg2;P$%9!jQ02C1Vi~(;1;_Y=>RGH3l|J$viB3`#iUtp(^n0|q9!l;9usAJ3^R$JWlK2bPAm@8sfdtzvoJksa*3 zPMz93PHYJ|+J4<_8xXnH9PI-=GRE<=U)%mVXWq1U2=4MJ^!QHIF)NQ6OLi~c=MOC# zVc!TkFcNB?cf)^k=Fb7Mukhyj8(n7qMF`L|p~Mh#FRZC1Kec~|#*~WFQ=PtZ+^hS{ z4WE~T&MX&)t1KRPhMvxuCsb5&B0j%5M$7-E>==@^i&c|U6g^ru`PCJoE238sJLl2O z=b3K% z56Z)?7RS-|6)?0se1ej~t0BE${-X~kF{rHJ2#u9E9(1q;25D4Flz zD?^AhL5FYM^Q;|wK#YNJ*iT6Z5=P(o6<9|mu-i^>M>)%(`c3Yr1a;9v<3bDI@w=8y zyH#E?iKI!%Hfuhz;<+$B_K76s>nJRAy&)M&as{?NV!G33Hvb_#A;{~(RqI@~&X(p5 za7MM7KIXS;@-fKwAXnCRQ#dTNJQ^4mF+L)0tirgTy;xkPl$sYWvg+I7`?k}$+#Bly zvcB#Cld%S}R}8>O$@bdnrE3l{hvfXZONR=AOLOk+h|xT)c?1LOlzS+aOw)?eS*Pwk zBa)U!f(0e+iJPqnE(>!Qpm_x&O|9}&9L%hA7xgbd1wSaoP7&#hY9`-tj)jgP6YmHA z3dSUR2+;lq2$r*M`=PdOO-o*V(NsXmwf1ZNQ{Q+483EQS#aC5Fp=-mKh31}NHU9vp zkf+iPhCFEUnLoxtAQe`x)zhQ^ zW1=uQhe^UbE54tcNsTb+PR#~p02Z(BAd)LJ{U(G0W}+kV$sMiu9zwnnmA`vmF^wPUJ`EF>*l#gc*B$z|R%(rC`gswF|+{WS>FKuB+x_ z(sx{(6+pqa!Wt!o`CAp`dWPbsC6-M}CuRtB=ydqsZ7ikTZj#eUHwP~oa#M%4{#21? zf>$3L9le8$bGHN<7CM;rCZ+m4)apQ#_Z)X)u>@{ftW+%IbTNcym~;uw0Wt_pkj;!& zdhfwk%s9!{q+h;KC7v#4B2J!4Z*+ZyU@Atle^DG97&0rDvG6K{RXF8!XQ-~o-hTB# z#)RleRtlo57fsCBZzmbYPq#ie1bf|@JU8rfr<6Y?7neKhJq)SF3wGlirn9$=!8($n zWPxpd9m59^alGzCNQmyIfFhE}UkYi+@>UD)W3v%;{nMz&Odd2j5_HVf8#G)b5&c62 zzZMb82$TmqOV4OdZyty09Di-&$OpFlZekl64w;sA%WG4*oJ!uWDD$})63<GZlMpw_Ud!K|78;NfF8w!q>j7!&)d* zRM-Ci=QUjcJ9%m1_zPV$!~0d7EdJYdw!Zfs?a04nw)($M3GZ0NWz>h*yiE&?v+4gPHHdMa6lKdue z5I>0zXCCf#z=g}q-Kj5j(T+R#RePopzOSq$u?Chp9RiEoOIOOfL(qwHeylK1BpDnDc%x!jG zy{gDo>EB3ZojA2*RX0ddR#kFVV)7BQBiG;B8hbu(ik~!I)qlo{+%t|o!jCb2?JMh3 zpnJxb6)nv1OC!n0Gzvw|;+{U{!mxxvt|Tb<$5Z!jBVPu%ZrRB;Qin+Sn?+8$W_`x4 zZ22@XH&y!AR3`7R+89N!qb#t|g=-4CztgT>uxb0@>@G(*n1u;H$Olm50XcQjkUU6H zsAyB(lJ`^j?*8(h&I}Ll_z1Mdy~_*(TkU#%Ygl@o`z&}5Xf`o;%eXJLsgCl^NM%gC z25UgX$oP{munQYerr@A;(Hu1=s<+&DDPeMv*CeV*gTV|)Lb*Z!lp6`kPX*8=uUM-1Vkjd;X zM~$t-M2i?w7SE}e^d&F!eD2@147aM9_H>h56TYAwh{@~JOkofA{i5v^@$$!KvTKY^XgHHDCb` zC(}%s^M?2vvk6o`REbsp1H|qwnI3DO%^$~z)QrF1AIr&3+dA)h_P&TW?SO0UjsR8M z_Qmk=R%OeK=!70Zi^?(DRti~1G@TFVznSL(P&yrHDa6U)O#LA`Prr|$ipFwVRGHHT z0dM2iY*Vo;zHj_+c7JD2@AR=iOa?;}YPE-!7oESr55k-q*M&mP*WuCqSHTRC;WWNp zAFo)34jBmFaSzR3aTPS@6~V`)S|W5m&Nd`FhU6T2GNhhov)qwY419`vmsMby?0t1| zW7ymfHLowQU6P?r8&SX_JvgMiu~EG-uE?cmlbX3&k`F%Cj&!4>UD>})?8@rtLid;r zsD1ZHQkpCKsKH*rAH--nsB0DWiDXD247>JPvXTRj~7??loU-Fo}DjniY zzN@@95GjO!s_m-%Q^y5E_v0}sBQngAKK}zKB88n$Cg_LUc|X`|)kFt?3|Z&*JmM?_ zwX|+c2Ma=}I1%N+B^b-Ovd%f}-W?JIZa&+qU{(0JHPw>f(t}q6c;VaC1fR-V9o*T# z3nP-$Cma(U0=eG%ZS9wMU%T8?^+Us^Jnw-lZWTi~gY#h4+ty<*)a!+#&OcSAPW-9T zmtt2ZDV1}pr^os3^$und7%hGW9V)RC*Iwn~eN>6+zE!QA7Sw(xMKl_V^Uhj}Bsa7_ zC`dY6K`mV~6X^SNWLlSjqHcHjWgEWVp+$v9Y}#$DsOF74cADqIQ|_6WhDY) z52OBA6@J4v<}D3$C7j09vdYscy#nwYns6($^gw$K*9ZrQeeR)hh8^h03+r9IaB9zp zsUg9YC^G{XIX*lO`gM9;==K}Dm!@oII_hDw?cO$Ad4ZF{kQGk+sn=Ggl8Nyn7p5-K zmK2MJ%?<+TQQnhYW%h8+Er4J{Kg<+)x@2SmF2TZx;*{ibEONdb4WEZu^>^_s7u3(G zi9J!%$C~B(5Vi3aK)TxvcH3L} zItXvhO5?V_T1&UqRj>8VEpEMwK(uWVwO|D4_>K@HoTH}yl2Uga&NfV-HwFE^>=McT zS61r%VB^m~oqHdP@7ZklKk?2&r^^uj@a|nMEF*j@8@-_JgcJ1_f+%=f2w07dIZ7|` z{CY4z@NRGE60#P{6pS&S5T6)|3__DbiQqv!z& zels&ubLIni2UxA&`sqAohw2}|=R5shiCY~wZRPXii!jJCYsUe9bA8+9)Y_rM#^@~| zDMEnj5qtGNeC||5% zUS$MrP3oSz=63UKiVGnO>grlL=G=7cZTUgcPIz-8IE~h6Ych^PB45mM$zp<~z0wjN zC9NM2LYY$~`Qs(0x9XLm4DK%IuCWZRxru|@6G(l-+{sY~W%U<7g-ZyBSCs1yL&NtHfQ5&K0;^v3h^J8{^ z{K_`bWE3kRGc}chGSorI-55?xC`S^4a<==yx+TE%=pr@FrA6zKjy#Pu{|ZpmJ(D(@ zs|jnvu^Y`&hlXY&NTz0TQNYgC%IT%;XrRVH2nX2yK&}Mb&oq&LZqmiO*?mv=K;!L~ z3-_3@D{hX3t|K$B_2xkUGKBvhAiV2^b@`D#5d6Jp-i>S`rXsD0bs~H!vOCnAEy-Ck zmAjC%+UR^wI~J(8_x7p6&%+0JXK6(=aWVg8@Vm+Y+<0zAhk7ZNz*6Mfv?@G#BR+0(tYof%xK88der@l zue^Rm1w_q`W{g7y0(hQkX>unJyKg2M>rufp#cldXbf+_UxG|`5Ejq|F(CYrVvIsIF4X|rGzl{POxcA#kO zRIZv-qNaDvJf~u0N6Sv{dT~+Yeshu}z5+LURE5V6 zobCqDte%Yk4NWT6t%W=U6J?e?z(i%4TWgB$JYETVVp*03W!JzOjyodC3;f{P6N>J^ ztQ?=-T+z1N;ejpchW5Hy+s0A*f}p5TRypbbcbvkApN#TIUgYY=iQ70;2)|#({{YsW zmMg{vXSH5h4e}s{Nvd%ds?+yZzdac0`ZjjLxSp3JK1-O_tR?SCgm%%{Jb+`K`K*m- zo8_ig-Y;-<#3yZ!H)D5ssy32kByfu6i&euP&9SysF&D%@Zh|RuWWHQk#LD zc^db(#4xb#rF4#r@dW3!SGbW>XB{dvC)tQLrVkvR(n3{@gZvp_vVTrXM_G@a^WGu6fkVwCviE z{4>7y=i!@V$lUZBm-M2xax1~^tji}V5a~w;|1s^l?*3Sheepbpe*i4y=)=_w9bmfq zwZ0->kNz}RJCujPKD%YbA5J#u+q%EK_WBkD?z3CC+(G^lxgkF1MoSyRqaimjJbIrg zl;jmW5J9d=hBpyfs~Yi5>}q4EkX|$ux|m&5XhC7W+^%)x9wpx{K)uiEwK&Le1?SlnjO7zEjX74MNg{a*Cx#ZE<A8^m8}TiBoueqW`d z8W}W_)GGgZBazHW<&1LcE!sw}49G~h&mR$F-g)GzKoQn*XVF*A+O{sXL*q$2pzh9^ z+&rj?a(dVbtD|a-k!qeML=90UF#*fMe`S-P{A;R+P>0zX3*!u9`39lf_!7bl`fNK! z!+cvqsVyvWxe$^J*SP%zsz~+$ai@{neI1HX*bVz*MIYF^oH()`*HYDu=_#ZSkF3#y zYxlP)jB{4Frkx#T2O49Wi|e(gYLeSU{UN48>B;w%%;?LxUod?F-Z+#LT+hJXvfH!P zF!CSV`Bs!@Ju>{FJhy!`=)X9uT)O;g>*@uIKI1oW0J)jOaE=}Fd#){GS)V)t2;WT*r(UMyEZ zqo`aTg)aqE0wu^gKI~@EQl9?<;5$?{w%^aJ<3zWp9>skcp3vBuBlzvCk)KfHZEtX8 zL?3l7mE`17%3gXhN}7Y~JWf3F@oB$pc${d^DRl)vZhO>46vu`YJT1`|}vn&ougLw3c3R<&D&v<DV0?a=)Uk0B(C4YWT&p@0aq5WYSq%_lwS_z9N$xmUe5f$ z)mgJGuXCmJy8rInf_*69&(enKahNeneqjB@*D-%fmNc3cdW=N9`Hv5=rS*$V5TL=J zNMyG4=TULxnJrzv^@gdKJ_qlO7YNAe7ht?ujuW_R(pa6Nd(0 z>SWiEJl5KI_D5D{^Rt3_ZT0LuP}ZR^Evu|!43S_VD_SCq;106vs2jYh(uL; zKX*}iI7ZlL!TYP0x*p%irYSFMS#!y9wu|z#xq`RCu;J{X@I53y)_3S?`%u&Lw_GGv zx^oKdW0b}@v|#vQBhQo;|Dy4dO*>hseZdXy!(Man1KH{!*xf0JwUpCTLKrKyFq>A% zoIJ&X%ccmuD!<-N?C+w!;s<_fzPU0fLPoN$N1>Z(>CQHzg_$-Ft0$MP&9e}=tYkAR z^&-zIKjB+@`{S3{QRI=YtTDSEQMuQK-*(xDwDNP>^OL)^`hF02{BYd?Q$ZWC?dR=? zLdV|ws4(~gm8yIPSGyJ=0w;HY&g(7=4{#{CZu%(Y6vYyUlQy4{4rN5O8nZX%4bG-} zOb%^v4Q;(%@-=~(DZwy;x~Oc#S>hB&tC?zRYg=>065`5FfU(tQupz}1dcY1hlb>(1 z?$5a)OYz>tr)_zTy{yeH&56b>PRQ_e*8isBUlK%jI@J5+zMx`9vLUgJlevz z((t!apUs*?C}qV_gL2Q>?G#zC?Jx{;~iLrHC6UI8P~& zGgqq~tizbtK!J#*w~xV13`I@b46T0b{RgOX=&hoZ=JuTaY)oK-ENjhm(2_|aV`bVB zY8;C4ZEZbBAE7enqd;r;tV!xRfm6%I3fH>SO?6X(yaOt;~alc zN5=(1SU(7a>XCad?hIofq@1Z`SNCBmm< zR>fay^-lf4yLud}p*ko|R% z{~f#iA#n|do?631y)xMp_iW$tZ8eL`sXQa|wRF4ms*6v#>ZbU){M6S%>tx5yeLtm9>c;Is5t$+>t!SjOZ%d|KVwtpK*A-s;d#8x zZ-$E98dK8(yV7uEgE+8-cM3B&~Lnt(B8@r=C4{H|~JaRe~3Dfa@ z#E!09kfg8$1vgz!)$OR@%e>KTg*9qDRI2$Usl4JNZD)UPo=7C-S$MU~N);0PE2-<7 zBj}>u*3f|XFrvTgg){S(dDEF&R=i(x?XzasxUOhKzw1rz>v(-T<`UoTVPmg%@++ly z8E9KXoYI<7LPFw3TOv;SB5>fL-CGJOu>sRIYKLD!iohAB9kafZGGZPqWRZd$wGNI! z3A_1hx8F4e?j4(eFY6rCtEap!Y+b=J82xRwpCx9lbh_d!e`ytGq+H=Pkv#jnE%vT% zWK7_%7*aQr>)a-veQKg3wjvnGRJvQqc6aJ)MGE89roJ!^20}q-$RP$ZiiOOD;4<6Z z{(k&x&tBIdJB5c^nEsz}KVRG=*~5y1TIV0UDW*~c3XbS#pJ51x$RTlq;iRl39*t#w zxAhG08_%uFR0lUQ0gqi#T_bGHh7u-a(Jn7G-O}cDZABkl=O%}!NAJ$`m=2QCfoIx9 z^X|^tIl5phM(`YP#A<$b1?Kl_U;<06=#D@;gXH7Z-;-Sar;?f*eB3opE3Jh_pBilI zSt+#c@FqjI3%%0<UEYJeN`@@)(DQDEkC+`L8Ph(a{2Icb z`*!uRWgup(!9!WN!?id+XD+3{{7*W++SkUS3MJW1Jtp(4;}ITBmbQjb?kIc@=DtZG z1laDHsXRqT{ zxO82O3oWGP>OMK9WgNNofZJhB@!Q8O+>R8w9U&u9|u|4|2dY z{vem`YPh2WifX*brNhg8WnjE#&-7P;I&p{@ zKJVMIXiVMUEBAzrAD=F;bJ;Lt z*Y=B3a;lRJYNOUz)`Tuu8e6yJ24x5@#L*BSm{p+tVH314(<0~T37kxoo|dHsO9e|) z)knStv2Yx=(oy|zE(?!7;|in^g>?_)z1p^+5sX#|ev$KbelKj8?>PBveTaKsH!-F7 zx*N^80F`v3vI$0$P}A|SFqNZwQE#T z%O-NSy+Z${k)m2SZcZjOO)$koOM<&zDO6ic;ds|GJ+St=Qe%C19J^NB`%&GRsg`2!4Kh0I&{*kD3Gy() zYl0D*@>#n%?yc&7l@=x+JqU_{Etdk3Vp50whx3}2L;RWG_5rvEnR#_7m`oP?_IjIp zlWnb}onu_YN&H*(82Rb6vr6tUzC%8u?#z~Cj{S)Sk&3XQv_+@r*&2|lyoY*BQj#An z$N=#Vz_t?)3i?qlQzDRhZ-!%B)j52NsJC;-lCpYFxqMIE96ULt)9ax*DEnK6*0+@xp7Qc(7H)7olr>lOCJ z1-$4V6`tx|c(U%-->XIi@w!SRQia{*dkpod6LrQ*l zoUf;08bW2&lWQ0lyB`6IBXVc@F*4?0@j^cGKpT6E-WhdCewm9hGxy36m1~$ zt?n9s26zLMuRp=ab8B5L_~D^n?RCKSvxf2vqR;Nux7l>ky#@q=hw{BP_w%=jFJ4Km zFA20JY%g8`RuVQEykz#2v3skyO5^4UmyPyp{$jUL%{wur?T)>C436k}{XA<-c{2=; zggNXEeMYy0JH`tI9U+!=5MN``B7 zXo@6qThZ=7sVfREo*oQ;>7v*`HWj-!sV_#>nX;?!d?sTJ)eZ{?k}!hTiFhoZf=AD517QUW?w2i2N}-de8AXU*rb@AyNr`fWi7Ver15Z(w;3m<-bl{}8oJJf;x7ewpGy{3 zQR#M5+*;|aaU8o+?34h=$_kK9WgT}e!r2*CJ-yF}bl(!_>n^Y1%Y91QQ$>SC(j=LO z+Gj~gYnchy!X)yTqGNNFXJDWZyW(@~f3;Pvo3huNd%NZK~tohvUp-5ws$|h40?utZKZM##n z@fL^TpAui`8rR#kcxIExzSSD;Stj$YnjnRyb&xg`q7ADcU8%H^TYY)wjr?V)c*ad% z#(IW^nq1ZvhQTebbwrrYaTVMqMN|lc>`B-+QS*X11dpN0F>=gZ3N-!L#m8;boSb8$ z)xo`PxvZDG_DkZhS*8+vMLcdIEx66f>&`Dorj??bU0da~+SMH8?!W&42=tL8x_e5` z63U9Rgc!?n(C3ieow+%zX|MH7cFA;2GTCH~DU8v=7?yzokQB&IL7a2WN8wxYu94$w z=zKU!L3ur+%^c0MWK1odM1;Fwux1J{G53KPBL^?x&w+0>J!LF)E6A*3jIzyhCE`XC zFSUkusVt$3Z3iSTp$5M~%cd)3H*55}z4cpNSm*T(Mf6L#?X7M^k~Cr_+BWZB<4!>%k&N&T)9YPTpNafU zq-q*wr7^sJJ{Z-)sQIwWsui=6?7ud5Zq7Rl3jY8TJ{eEpEjrR2J>j~a?K@Ki!7<0qVRns_|#4UUtW znw>dWD|LFQZ`HN6`f1kjlwd2*5jbJ$^1f9#a>=;0&8EF#pSs_h(Vp4i4;Oqf{jGGf zVet#%K7-+p80hR){{UF=Ca5eeyhUoP>jdp^hB5Z2qiEu2-!CEra9d*t%JFZ6ehl#? z?}&AMFGJH>?(P*<7zmCc$px}V7$h~bO~oo?@oi+Pb(hqR8^1A?l%P$@-zX@Q|mt$L1nwS8M{{8CoF_OeRX zx8BcdE2T=T!QMMrr7yv;TANS9{1r_&vABLk} zGo74$Kat7AIGWf@rYe<^l9lvU_@mLSH+y$1=w2GW@oaY5lWGO6Ug*Ot zlDi3sRfw<)^DY6G3UkjSj@5I-+D4J0T;J=HTC?f*8jZ=b(&8Z_hzDJO;C5GDoySA8 z8Yr)$tBI|O$5W+M-Y(i~w3eG%&qc41@Y!VM=k1%ky_~iC{{W}ospy{yG_MMHlS{Ck z$4Ez#c3m{- zrrHLR;oUmJLTyORIeS>jd5s}vxZwu*IRT_4Q|CD#1CF?=aCm=Kx7O}FMQNb-N2T(7_gD5N_Hs zF^Iz`X&v|cBjNo+Le?JJ?Do+MS?(;K$+%|PktAexixh~a-~)(%SCQ#YSvvW+P2nhbtLgdhYyG}{VT(I zr0;#F-AZgOBf4fuC1}`4W@e3mCl<^w6?uGuqbhv6!CD2Je-?aR5xn^={5f%TZnH$I z98W2X;Zyr5brtKK|FKUB^6v-QgWUizuW!ht4F0> zHZXWR(z);8@Ys1!Q*ceoSEp0|+3V5)vj6}9 literal 0 HcmV?d00001 diff --git a/docs/data/doxygenOutputs/logical_operations_bitwise_or_img150x150.png b/docs/data/doxygenOutputs/logical_operations_bitwise_or_img150x150.png new file mode 100644 index 0000000000000000000000000000000000000000..d9dbccabbb8de6e5db9223bbac807f8acfe1fa5a GIT binary patch literal 19003 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 faS{5hc~hd?VxGyn9!4hc!VCX&%>(I5ZW8VT|# literal 0 HcmV?d00001 diff --git a/docs/doxygen/Doxyfile b/docs/doxygen/Doxyfile index f77dd11b2..2f633152e 100644 --- a/docs/doxygen/Doxyfile +++ b/docs/doxygen/Doxyfile @@ -966,7 +966,8 @@ INPUT = ../../README.md \ ../../include/rppt_tensor_filter_augmentations.h \ ../../include/rppt_tensor_geometric_augmentations.h \ ../../include/rppt_tensor_morphological_operations.h \ - ../../include/rppt_tensor_statistical_operations.h + ../../include/rppt_tensor_statistical_operations.h \ + ../../include/rppt_tensor_logical_operations.h # This tag can be used to specify the character encoding of the source files diff --git a/include/rppdefs.h b/include/rppdefs.h index b12fcda78..c1eb322f8 100644 --- a/include/rppdefs.h +++ b/include/rppdefs.h @@ -311,7 +311,7 @@ typedef struct int y; } RppiPoint; -/*! \brief RPPI Image 2D Rectangle (XYWH format) type struct +/*! \brief RPPI Image 3D point type struct * \ingroup group_rppdefs */ typedef struct @@ -321,6 +321,9 @@ typedef struct int z; } RppiPoint3D; +/*! \brief RPPI Image 2D Rectangle (XYWH format) type struct + * \ingroup group_rppdefs + */ typedef struct { int x; @@ -373,7 +376,7 @@ typedef enum XYWH // X-Y-Width-Height } RpptRoiType; -/*! \brief RPPT Tensor subpixel layout type enum +/*! \brief RPPT Tensor 3D ROI type enum * \ingroup group_rppdefs */ typedef enum @@ -382,6 +385,9 @@ typedef enum XYZWHD // X-Y-Z-Width-Height-Depth } RpptRoi3DType; +/*! \brief RPPT Tensor subpixel layout type enum + * \ingroup group_rppdefs + */ typedef enum { RGBtype, @@ -493,7 +499,7 @@ typedef struct RpptLayout layout; } RpptDesc, *RpptDescPtr; -/*! \brief RPPT Tensor 8-bit uchar RGB type struct +/*! \brief RPPT Tensor Generic descriptor type struct * \ingroup group_rppdefs */ typedef struct @@ -506,6 +512,9 @@ typedef struct RpptLayout layout; } RpptGenericDesc, *RpptGenericDescPtr; +/*! \brief RPPT Tensor 8-bit uchar RGB type struct + * \ingroup group_rppdefs + */ typedef struct { Rpp8u R; diff --git a/include/rppt.h b/include/rppt.h index 0a20921d8..b466fa373 100644 --- a/include/rppt.h +++ b/include/rppt.h @@ -46,6 +46,7 @@ extern "C" { #include "rppt_tensor_arithmetic_operations.h" #include "rppt_tensor_statistical_operations.h" #include "rppt_tensor_audio_augmentations.h" +#include "rppt_tensor_logical_operations.h" #ifdef __cplusplus } diff --git a/include/rppt_tensor_arithmetic_operations.h b/include/rppt_tensor_arithmetic_operations.h index c03ee5de0..943a08b34 100644 --- a/include/rppt_tensor_arithmetic_operations.h +++ b/include/rppt_tensor_arithmetic_operations.h @@ -244,21 +244,21 @@ RppStatus rppt_multiply_scalar_gpu(RppPtr_t srcPtr, RpptGenericDescPtr srcGeneri RppStatus rppt_magnitude_host(RppPtr_t srcPtr1, RppPtr_t srcPtr2, RpptDescPtr srcDescPtr, RppPtr_t dstPtr, RpptDescPtr dstDescPtr, RpptROIPtr roiTensorPtrSrc, RpptRoiType roiType, rppHandle_t rppHandle); #ifdef GPU_SUPPORT -/*! \brief Magnitude computation on HOST backend for a NCHW/NHWC layout tensor +/*! \brief Magnitude computation on HIP backend for a NCHW/NHWC layout tensor * \details This function computes magnitude of corresponding pixels for a batch of RGB(3 channel) / greyscale(1 channel) images with an NHWC/NCHW tensor layout.
* srcPtr depth ranges - Rpp8u (0 to 255), Rpp16f (0 to 1), Rpp32f (0 to 1), Rpp8s (-128 to 127). * dstPtr depth ranges - Will be same depth as srcPtr.
* \image html img150x150.png Sample Input1 * \image html img150x150_2.png Sample Input2 * \image html arithmetic_operations_magnitude_img150x150.png Sample Output - * \param [in] srcPtr1 source1 tensor in HOST memory - * \param [in] srcPtr2 source2 tensor in HOST memory + * \param [in] srcPtr1 source1 tensor in HIP memory + * \param [in] srcPtr2 source2 tensor in HIP memory * \param [in] srcDescPtr source tensor descriptor (Restrictions - numDims = 4, offsetInBytes >= 0, dataType = U8/F16/F32/I8, layout = NCHW/NHWC, c = 1/3) - * \param [out] dstPtr destination tensor in HOST memory + * \param [out] dstPtr destination tensor in HIP memory * \param [in] dstDescPtr destination tensor descriptor (Restrictions - numDims = 4, offsetInBytes >= 0, dataType = U8/F16/F32/I8, layout = NCHW/NHWC, c = same as that of srcDescPtr) - * \param [in] roiTensorSrc ROI data in HOST memory, for each image in source tensor (2D tensor of size batchSize * 4, in either format - XYWH(xy.x, xy.y, roiWidth, roiHeight) or LTRB(lt.x, lt.y, rb.x, rb.y)) + * \param [in] roiTensorSrc ROI data in HIP memory, for each image in source tensor (2D tensor of size batchSize * 4, in either format - XYWH(xy.x, xy.y, roiWidth, roiHeight) or LTRB(lt.x, lt.y, rb.x, rb.y)) * \param [in] roiType ROI type used (RpptRoiType::XYWH or RpptRoiType::LTRB) - * \param [in] rppHandle RPP HOST handle created with \ref rppCreateWithStreamAndBatchSize() + * \param [in] rppHandle RPP HIP handle created with \ref rppCreateWithStreamAndBatchSize() * \return A \ref RppStatus enumeration. * \retval RPP_SUCCESS Successful completion. * \retval RPP_ERROR* Unsuccessful completion. @@ -272,4 +272,4 @@ RppStatus rppt_magnitude_gpu(RppPtr_t srcPtr1, RppPtr_t srcPtr2, RpptDescPtr src #ifdef __cplusplus } #endif -#endif // RPPT_TENSOR_ARITHMETIC_OPERATIONS_H \ No newline at end of file +#endif // RPPT_TENSOR_ARITHMETIC_OPERATIONS_H diff --git a/include/rppt_tensor_logical_operations.h b/include/rppt_tensor_logical_operations.h new file mode 100644 index 000000000..29eefa466 --- /dev/null +++ b/include/rppt_tensor_logical_operations.h @@ -0,0 +1,139 @@ +/* +MIT License + +Copyright (c) 2019 - 2024 Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef RPPT_TENSOR_LOGICAL_OPERATIONS_H +#define RPPT_TENSOR_LOGICAL_OPERATIONS_H + +#include "rpp.h" +#include "rppdefs.h" +#ifdef __cplusplus +extern "C" { +#endif + +/*! + * \file + * \brief RPPT Tensor Operations - Logical Operations. + * \defgroup group_tensor_logical_operations RPPT Tensor Operations - Logical Operations. + * \brief RPPT Tensor Operations - Logical Operations. + */ + +/*! \addtogroup group_rppt_tensor_logical_operations + * @{ + */ + +/*! \brief Bitwise AND computation on HOST backend for a NCHW/NHWC layout tensor + * \details This function computes bitwise AND of corresponding pixels for a batch of RGB(3 channel) / greyscale(1 channel) images with an NHWC/NCHW tensor layout.
+ * srcPtr depth ranges - Rpp8u (0 to 255), Rpp16f (0 to 1), Rpp32f (0 to 1), Rpp8s (-128 to 127). + * dstPtr depth ranges - Will be same depth as srcPtr. + * \image html img150x150.png Sample Input1 + * \image html img150x150_2.png Sample Input2 + * \image html logical_operations_bitwise_and_img150x150.png Sample Output + * \param [in] srcPtr1 source1 tensor in HOST memory + * \param [in] srcPtr2 source2 tensor in HOST memory + * \param [in] srcDescPtr source tensor descriptor (Restrictions - numDims = 4, offsetInBytes >= 0, dataType = U8/F16/F32/I8, layout = NCHW/NHWC, c = 1/3) + * \param [out] dstPtr destination tensor in HOST memory + * \param [in] dstDescPtr destination tensor descriptor (Restrictions - numDims = 4, offsetInBytes >= 0, dataType = U8/F16/F32/I8, layout = NCHW/NHWC, c = same as that of srcDescPtr) + * \param [in] roiTensorSrc ROI data in HOST memory, for each image in source tensor (2D tensor of size batchSize * 4, in either format - XYWH(xy.x, xy.y, roiWidth, roiHeight) or LTRB(lt.x, lt.y, rb.x, rb.y)) + * \param [in] roiType ROI type used (RpptRoiType::XYWH or RpptRoiType::LTRB) + * \param [in] rppHandle RPP HOST handle created with \ref rppCreateWithBatchSize() + * \return A \ref RppStatus enumeration. + * \retval RPP_SUCCESS Successful completion. + * \retval RPP_ERROR* Unsuccessful completion. + */ +RppStatus rppt_bitwise_and_host(RppPtr_t srcPtr1, RppPtr_t srcPtr2, RpptDescPtr srcDescPtr, RppPtr_t dstPtr, RpptDescPtr dstDescPtr, RpptROIPtr roiTensorPtrSrc, RpptRoiType roiType, rppHandle_t rppHandle); + +#ifdef GPU_SUPPORT +/*! \brief Bitwise AND computation on HIP backend for a NCHW/NHWC layout tensor + * \details This function computes bitwise AND of corresponding pixels for a batch of RGB(3 channel) / greyscale(1 channel) images with an NHWC/NCHW tensor layout.
+ * srcPtr depth ranges - Rpp8u (0 to 255), Rpp16f (0 to 1), Rpp32f (0 to 1), Rpp8s (-128 to 127). + * dstPtr depth ranges - Will be same depth as srcPtr. + * \image html img150x150.png Sample Input1 + * \image html img150x150_2.png Sample Input2 + * \image html logical_operations_bitwise_and_img150x150.png Sample Output + * \param [in] srcPtr1 source1 tensor in HIP memory + * \param [in] srcPtr2 source2 tensor in HIP memory + * \param [in] srcDescPtr source tensor descriptor (Restrictions - numDims = 4, offsetInBytes >= 0, dataType = U8/F16/F32/I8, layout = NCHW/NHWC, c = 1/3) + * \param [out] dstPtr destination tensor in HIP memory + * \param [in] dstDescPtr destination tensor descriptor (Restrictions - numDims = 4, offsetInBytes >= 0, dataType = U8/F16/F32/I8, layout = NCHW/NHWC, c = same as that of srcDescPtr) + * \param [in] roiTensorSrc ROI data in HIP memory, for each image in source tensor (2D tensor of size batchSize * 4, in either format - XYWH(xy.x, xy.y, roiWidth, roiHeight) or LTRB(lt.x, lt.y, rb.x, rb.y)) + * \param [in] roiType ROI type used (RpptRoiType::XYWH or RpptRoiType::LTRB) + * \param [in] rppHandle RPP HIP handle created with \ref rppCreateWithStreamAndBatchSize() + * \return A \ref RppStatus enumeration. + * \retval RPP_SUCCESS Successful completion. + * \retval RPP_ERROR* Unsuccessful completion. + */ +RppStatus rppt_bitwise_and_gpu(RppPtr_t srcPtr1, RppPtr_t srcPtr2, RpptDescPtr srcDescPtr, RppPtr_t dstPtr, RpptDescPtr dstDescPtr, RpptROIPtr roiTensorPtrSrc, RpptRoiType roiType, rppHandle_t rppHandle); +#endif // GPU_SUPPORT + +/*! \brief Bitwise OR computation on HOST backend for a NCHW/NHWC layout tensor + * \details This function computes bitwise OR of corresponding pixels for a batch of RGB(3 channel) / greyscale(1 channel) images with an NHWC/NCHW tensor layout.
+ * srcPtr depth ranges - Rpp8u (0 to 255), Rpp16f (0 to 1), Rpp32f (0 to 1), Rpp8s (-128 to 127). + * dstPtr depth ranges - Will be same depth as srcPtr. + * \image html img150x150.png Sample Input1 + * \image html img150x150_2.png Sample Input2 + * \image html logical_operations_bitwise_or_img150x150.png Sample Output + * \param [in] srcPtr1 source1 tensor in HOST memory + * \param [in] srcPtr2 source2 tensor in HOST memory + * \param [in] srcDescPtr source tensor descriptor (Restrictions - numDims = 4, offsetInBytes >= 0, dataType = U8/F16/F32/I8, layout = NCHW/NHWC, c = 1/3) + * \param [out] dstPtr destination tensor in HOST memory + * \param [in] dstDescPtr destination tensor descriptor (Restrictions - numDims = 4, offsetInBytes >= 0, dataType = U8/F16/F32/I8, layout = NCHW/NHWC, c = same as that of srcDescPtr) + * \param [in] roiTensorSrc ROI data in HOST memory, for each image in source tensor (2D tensor of size batchSize * 4, in either format - XYWH(xy.x, xy.y, roiWidth, roiHeight) or LTRB(lt.x, lt.y, rb.x, rb.y)) + * \param [in] roiType ROI type used (RpptRoiType::XYWH or RpptRoiType::LTRB) + * \param [in] rppHandle RPP HOST handle created with \ref rppCreateWithBatchSize() + * \return A \ref RppStatus enumeration. + * \retval RPP_SUCCESS Successful completion. + * \retval RPP_ERROR* Unsuccessful completion. + */ +RppStatus rppt_bitwise_or_host(RppPtr_t srcPtr1, RppPtr_t srcPtr2, RpptDescPtr srcDescPtr, RppPtr_t dstPtr, RpptDescPtr dstDescPtr, RpptROIPtr roiTensorPtrSrc, RpptRoiType roiType, rppHandle_t rppHandle); + +#ifdef GPU_SUPPORT +/*! \brief Bitwise OR computation on HIP backend for a NCHW/NHWC layout tensor + * \details This function computes bitwise OR of corresponding pixels for a batch of RGB(3 channel) / greyscale(1 channel) images with an NHWC/NCHW tensor layout.
+ * srcPtr depth ranges - Rpp8u (0 to 255), Rpp16f (0 to 1), Rpp32f (0 to 1), Rpp8s (-128 to 127). + * dstPtr depth ranges - Will be same depth as srcPtr. + * \image html img150x150.png Sample Input1 + * \image html img150x150_2.png Sample Input2 + * \image html logical_operations_bitwise_or_img150x150.png Sample Output + * \param [in] srcPtr1 source1 tensor in HIP memory + * \param [in] srcPtr2 source2 tensor in HIP memory + * \param [in] srcDescPtr source tensor descriptor (Restrictions - numDims = 4, offsetInBytes >= 0, dataType = U8/F16/F32/I8, layout = NCHW/NHWC, c = 1/3) + * \param [out] dstPtr destination tensor in HIP memory + * \param [in] dstDescPtr destination tensor descriptor (Restrictions - numDims = 4, offsetInBytes >= 0, dataType = U8/F16/F32/I8, layout = NCHW/NHWC, c = same as that of srcDescPtr) + * \param [in] roiTensorSrc ROI data in HIP memory, for each image in source tensor (2D tensor of size batchSize * 4, in either format - XYWH(xy.x, xy.y, roiWidth, roiHeight) or LTRB(lt.x, lt.y, rb.x, rb.y)) + * \param [in] roiType ROI type used (RpptRoiType::XYWH or RpptRoiType::LTRB) + * \param [in] rppHandle RPP HIP handle created with \ref rppCreateWithStreamAndBatchSize() + * \return A \ref RppStatus enumeration. + * \retval RPP_SUCCESS Successful completion. + * \retval RPP_ERROR* Unsuccessful completion. + */ +RppStatus rppt_bitwise_or_gpu(RppPtr_t srcPtr1, RppPtr_t srcPtr2, RpptDescPtr srcDescPtr, RppPtr_t dstPtr, RpptDescPtr dstDescPtr, RpptROIPtr roiTensorPtrSrc, RpptRoiType roiType, rppHandle_t rppHandle); +#endif // GPU_SUPPORT + +/*! @} + */ + +#ifdef __cplusplus +} +#endif +#endif // RPPT_TENSOR_LOGICAL_OPERATIONS_H \ No newline at end of file diff --git a/src/include/cpu/rpp_cpu_simd.hpp b/src/include/cpu/rpp_cpu_simd.hpp index d03ec0e79..19121957b 100644 --- a/src/include/cpu/rpp_cpu_simd.hpp +++ b/src/include/cpu/rpp_cpu_simd.hpp @@ -719,6 +719,29 @@ inline void rpp_load48_i8pkd3_to_i8pln3(Rpp8s *srcPtr, __m128i *px) px[2] = _mm_shuffle_epi8(_mm_unpacklo_epi8(pxSrc[6], pxSrc[7]), pxMaskRGB); /* unpack 8 lo-pixels of pxSrc[6] and pxSrc[7] to get B01-16 */ } +inline void rpp_load48_i8pkd3_to_u8pln3(Rpp8s *srcPtr, __m128i *px) +{ + __m128i pxSrc[8]; + __m128i pxMask = _mm_setr_epi8(0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11, 12, 13, 14, 15); + __m128i pxMaskRGB = _mm_setr_epi8(0, 4, 8, 12, 2, 6, 10, 14, 1, 5, 9, 13, 3, 7, 11, 15); + + pxSrc[0] = _mm_loadu_si128((__m128i *)srcPtr); /* load [R01|G01|B01|R02|G02|B02|R03|G03|B03|R04|G04|B04|R05|G05|B05|R06] - Need RGB 01-04 */ + pxSrc[1] = _mm_loadu_si128((__m128i *)(srcPtr + 12)); /* load [R05|G05|B05|R06|G06|B06|R07|G07|B07|R08|G08|B08|R09|G09|B09|R10] - Need RGB 05-08 */ + pxSrc[2] = _mm_loadu_si128((__m128i *)(srcPtr + 24)); /* load [R09|G09|B09|R10|G10|B10|R11|G11|B11|R12|G12|B12|R13|G13|B13|R14] - Need RGB 09-12 */ + pxSrc[3] = _mm_loadu_si128((__m128i *)(srcPtr + 36)); /* load [R13|G13|B13|R14|G14|B14|R15|G15|B15|R16|G16|B16|R17|G17|B17|R18] - Need RGB 13-16 */ + pxSrc[0] = _mm_shuffle_epi8(pxSrc[0], pxMask); /* shuffle to get [R01|R02|R03|R04|G01|G02|G03|G04 || B01|B02|B03|B04|R05|G05|B05|R06] - Need R01-04, G01-04, B01-04 */ + pxSrc[1] = _mm_shuffle_epi8(pxSrc[1], pxMask); /* shuffle to get [R05|R06|R07|R08|G05|G06|G07|G08 || B05|B06|B07|B08|R09|G09|B09|R10] - Need R05-08, G05-08, B05-08 */ + pxSrc[2] = _mm_shuffle_epi8(pxSrc[2], pxMask); /* shuffle to get [R09|R10|R11|R12|G09|G10|G11|G12 || B09|B10|B11|B12|R13|G13|B13|R14] - Need R09-12, G09-12, B09-12 */ + pxSrc[3] = _mm_shuffle_epi8(pxSrc[3], pxMask); /* shuffle to get [R13|R14|R15|R16|G13|G14|G15|G16 || B13|B14|B15|B16|R17|G17|B17|R18] - Need R13-16, G13-16, B13-16 */ + pxSrc[4] = _mm_unpacklo_epi8(pxSrc[0], pxSrc[1]); /* unpack 8 lo-pixels of pxSrc[0] and pxSrc[1] */ + pxSrc[5] = _mm_unpacklo_epi8(pxSrc[2], pxSrc[3]); /* unpack 8 lo-pixels of pxSrc[2] and pxSrc[3] */ + pxSrc[6] = _mm_unpackhi_epi8(pxSrc[0], pxSrc[1]); /* unpack 8 hi-pixels of pxSrc[0] and pxSrc[1] */ + pxSrc[7] = _mm_unpackhi_epi8(pxSrc[2], pxSrc[3]); /* unpack 8 hi-pixels of pxSrc[2] and pxSrc[3] */ + px[0] = _mm_add_epi8(xmm_pxConvertI8, _mm_shuffle_epi8(_mm_unpacklo_epi8(pxSrc[4], pxSrc[5]), pxMaskRGB)); /* unpack 8 lo-pixels of pxSrc[4] and pxSrc[5] to get R01-16 and add 128 to get u8 from i8 */ + px[1] = _mm_add_epi8(xmm_pxConvertI8, _mm_shuffle_epi8(_mm_unpackhi_epi8(pxSrc[4], pxSrc[5]), pxMaskRGB)); /* unpack 8 hi-pixels of pxSrc[4] and pxSrc[5] to get G01-16 and add 128 to get u8 from i8 */ + px[2] = _mm_add_epi8(xmm_pxConvertI8, _mm_shuffle_epi8(_mm_unpacklo_epi8(pxSrc[6], pxSrc[7]), pxMaskRGB)); /* unpack 8 lo-pixels of pxSrc[6] and pxSrc[7] to get B01-16 and add 128 to get u8 from i8 */ +} + inline void rpp_store48_i8pln3_to_i8pln3(Rpp8s *dstPtrR, Rpp8s *dstPtrG, Rpp8s *dstPtrB, __m128i *px) { _mm_storeu_si128((__m128i *)dstPtrR, px[0]); /* store [R01|R02|R03|R04|R05|R06|R07|R08|R09|R10|R11|R12|R13|R14|R15|R16] */ @@ -726,6 +749,13 @@ inline void rpp_store48_i8pln3_to_i8pln3(Rpp8s *dstPtrR, Rpp8s *dstPtrG, Rpp8s * _mm_storeu_si128((__m128i *)dstPtrB, px[2]); /* store [B01|B02|B03|B04|B05|B06|B07|B08|B09|B10|B11|B12|B13|B14|B15|B16] */ } +inline void rpp_store48_u8pln3_to_i8pln3(Rpp8s *dstPtrR, Rpp8s *dstPtrG, Rpp8s *dstPtrB, __m128i *px) +{ + _mm_storeu_si128((__m128i *)dstPtrR, _mm_sub_epi8(px[0], xmm_pxConvertI8)); /* store [R01|R02|R03|R04|R05|R06|R07|R08|R09|R10|R11|R12|R13|R14|R15|R16] */ + _mm_storeu_si128((__m128i *)dstPtrG, _mm_sub_epi8(px[1], xmm_pxConvertI8)); /* store [G01|G02|G03|G04|G05|G06|G07|G08|G09|G10|G11|G12|G13|G14|G15|G16] */ + _mm_storeu_si128((__m128i *)dstPtrB, _mm_sub_epi8(px[2], xmm_pxConvertI8)); /* store [B01|B02|B03|B04|B05|B06|B07|B08|B09|B10|B11|B12|B13|B14|B15|B16] */ +} + inline void rpp_load48_i8pkd3_to_i32pln3_avx(Rpp8s *srcPtr, __m256i *p) { __m128i pxSrc[8]; @@ -759,6 +789,13 @@ inline void rpp_load48_i8pln3_to_i8pln3(Rpp8s *srcPtrR, Rpp8s *srcPtrG, Rpp8s *s px[2] = _mm_loadu_si128((__m128i *)srcPtrB); /* load [B01|B02|B03|B04|B05|B06|B07|B08|B09|B10|B11|B12|B13|B14|B15|B16] */ } +inline void rpp_load48_i8pln3_to_u8pln3(Rpp8s *srcPtrR, Rpp8s *srcPtrG, Rpp8s *srcPtrB, __m128i *px) +{ + px[0] = _mm_add_epi8(xmm_pxConvertI8, _mm_loadu_si128((__m128i *)srcPtrR)); /* load and convert to u8 [R01|R02|R03|R04|R05|R06|R07|R08|R09|R10|R11|R12|R13|R14|R15|R16] */ + px[1] = _mm_add_epi8(xmm_pxConvertI8, _mm_loadu_si128((__m128i *)srcPtrG)); /* load and convert to u8 [G01|G02|G03|G04|G05|G06|G07|G08|G09|G10|G11|G12|G13|G14|G15|G16] */ + px[2] = _mm_add_epi8(xmm_pxConvertI8, _mm_loadu_si128((__m128i *)srcPtrB)); /* load and convert to u8 [B01|B02|B03|B04|B05|B06|B07|B08|B09|B10|B11|B12|B13|B14|B15|B16] */ +} + inline void rpp_store48_i8pln3_to_i8pkd3(Rpp8s *dstPtr, __m128i *px) { __m128i pxDst[4]; @@ -774,6 +811,21 @@ inline void rpp_store48_i8pln3_to_i8pkd3(Rpp8s *dstPtr, __m128i *px) _mm_storeu_si128((__m128i *)(dstPtr + 36), _mm_shuffle_epi8(_mm_unpackhi_epi8(pxDst[3], pxDst[1]), pxMaskRGBAtoRGB)); /* store [R13|G13|B13|R14|G14|B14|R15|G15|B15|R16|G16|B16|00|00|00|00] */ } +inline void rpp_store48_u8pln3_to_i8pkd3(Rpp8s *dstPtr, __m128i *px) +{ + __m128i pxDst[4]; + __m128i pxZero = _mm_setzero_si128(); + __m128i pxMaskRGBAtoRGB = _mm_setr_epi8(0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 3, 7, 11, 15); + pxDst[0] = _mm_unpacklo_epi8(px[1], pxZero); /* unpack 8 lo-pixels of px[1] and pxZero */ + pxDst[1] = _mm_unpackhi_epi8(px[1], pxZero); /* unpack 8 hi-pixels of px[1] and pxZero */ + pxDst[2] = _mm_unpacklo_epi8(px[0], px[2]); /* unpack 8 lo-pixels of px[0] and px[2] */ + pxDst[3] = _mm_unpackhi_epi8(px[0], px[2]); /* unpack 8 hi-pixels of px[0] and px[2] */ + _mm_storeu_si128((__m128i *)dstPtr, _mm_sub_epi8(_mm_shuffle_epi8(_mm_unpacklo_epi8(pxDst[2], pxDst[0]), pxMaskRGBAtoRGB), xmm_pxConvertI8)); /* store [R01|G01|B01|R02|G02|B02|R03|G03|B03|R04|G04|B04|00|00|00|00] */ + _mm_storeu_si128((__m128i *)(dstPtr + 12), _mm_sub_epi8(_mm_shuffle_epi8(_mm_unpackhi_epi8(pxDst[2], pxDst[0]), pxMaskRGBAtoRGB), xmm_pxConvertI8)); /* store [R05|G05|B05|R06|G06|B06|R07|G07|B07|R08|G08|B08|00|00|00|00] */ + _mm_storeu_si128((__m128i *)(dstPtr + 24), _mm_sub_epi8(_mm_shuffle_epi8(_mm_unpacklo_epi8(pxDst[3], pxDst[1]), pxMaskRGBAtoRGB), xmm_pxConvertI8)); /* store [R09|G09|B09|R10|G10|B10|R11|G11|B11|R12|G12|B12|00|00|00|00] */ + _mm_storeu_si128((__m128i *)(dstPtr + 36), _mm_sub_epi8(_mm_shuffle_epi8(_mm_unpackhi_epi8(pxDst[3], pxDst[1]), pxMaskRGBAtoRGB), xmm_pxConvertI8)); /* store [R13|G13|B13|R14|G14|B14|R15|G15|B15|R16|G16|B16|00|00|00|00] */ +} + inline void rpp_load16_i8_to_f32(Rpp8s *srcPtr, __m128 *p) { __m128i px = _mm_loadu_si128((__m128i *)srcPtr); /* load pixels 0-15 */ diff --git a/src/include/hip/rpp_hip_common.hpp b/src/include/hip/rpp_hip_common.hpp index d894d2efd..e2e7df9f6 100644 --- a/src/include/hip/rpp_hip_common.hpp +++ b/src/include/hip/rpp_hip_common.hpp @@ -1727,6 +1727,34 @@ __device__ __forceinline__ void rpp_hip_math_multiply24_const(d_float24 *src_f24 dst_f24->f4[5] = src_f24->f4[5] * multiplier_f4; } +// d_float8 bitwiseAND + +__device__ __forceinline__ void rpp_hip_math_bitwiseAnd8(d_float8 *src1_f8, d_float8 *src2_f8, d_float8 *dst_f8) +{ + dst_f8->f1[0] = (float)((uchar)(src1_f8->f1[0]) & (uchar)(src2_f8->f1[0])); + dst_f8->f1[1] = (float)((uchar)(src1_f8->f1[1]) & (uchar)(src2_f8->f1[1])); + dst_f8->f1[2] = (float)((uchar)(src1_f8->f1[2]) & (uchar)(src2_f8->f1[2])); + dst_f8->f1[3] = (float)((uchar)(src1_f8->f1[3]) & (uchar)(src2_f8->f1[3])); + dst_f8->f1[4] = (float)((uchar)(src1_f8->f1[4]) & (uchar)(src2_f8->f1[4])); + dst_f8->f1[5] = (float)((uchar)(src1_f8->f1[5]) & (uchar)(src2_f8->f1[5])); + dst_f8->f1[6] = (float)((uchar)(src1_f8->f1[6]) & (uchar)(src2_f8->f1[6])); + dst_f8->f1[7] = (float)((uchar)(src1_f8->f1[7]) & (uchar)(src2_f8->f1[7])); +} + +// d_float8 bitwiseOR + +__device__ __forceinline__ void rpp_hip_math_bitwiseOr8(d_float8 *src1_f8, d_float8 *src2_f8, d_float8 *dst_f8) +{ + dst_f8->f1[0] = (float)((uchar)(src1_f8->f1[0]) | (uchar)(src2_f8->f1[0])); + dst_f8->f1[1] = (float)((uchar)(src1_f8->f1[1]) | (uchar)(src2_f8->f1[1])); + dst_f8->f1[2] = (float)((uchar)(src1_f8->f1[2]) | (uchar)(src2_f8->f1[2])); + dst_f8->f1[3] = (float)((uchar)(src1_f8->f1[3]) | (uchar)(src2_f8->f1[3])); + dst_f8->f1[4] = (float)((uchar)(src1_f8->f1[4]) | (uchar)(src2_f8->f1[4])); + dst_f8->f1[5] = (float)((uchar)(src1_f8->f1[5]) | (uchar)(src2_f8->f1[5])); + dst_f8->f1[6] = (float)((uchar)(src1_f8->f1[6]) | (uchar)(src2_f8->f1[6])); + dst_f8->f1[7] = (float)((uchar)(src1_f8->f1[7]) | (uchar)(src2_f8->f1[7])); +} + __device__ __forceinline__ float rpp_hip_math_inverse_sqrt1(float x) { float xHalf = 0.5f * x; diff --git a/src/modules/cpu/host_tensor_logical_operations.hpp b/src/modules/cpu/host_tensor_logical_operations.hpp new file mode 100644 index 000000000..0fb3fe5eb --- /dev/null +++ b/src/modules/cpu/host_tensor_logical_operations.hpp @@ -0,0 +1,31 @@ +/* +MIT License + +Copyright (c) 2019 - 2024 Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef HOST_TENSOR_LOGICAL_OPERATIONS_HPP +#define HOST_TENSOR_LOGICAL_OPERATIONS_HPP + +#include "kernel/bitwise_and.hpp" +#include "kernel/bitwise_or.hpp" + +#endif // HOST_TENSOR_LOGICAL_OPERATIONS_HPP \ No newline at end of file diff --git a/src/modules/cpu/kernel/bitwise_and.hpp b/src/modules/cpu/kernel/bitwise_and.hpp new file mode 100644 index 000000000..6f1caf1d3 --- /dev/null +++ b/src/modules/cpu/kernel/bitwise_and.hpp @@ -0,0 +1,965 @@ +/* +MIT License + +Copyright (c) 2019 - 2024 Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "rppdefs.h" +#include "rpp_cpu_simd.hpp" +#include "rpp_cpu_common.hpp" + +RppStatus bitwise_and_u8_u8_host_tensor(Rpp8u *srcPtr1, + Rpp8u *srcPtr2, + RpptDescPtr srcDescPtr, + Rpp8u *dstPtr, + RpptDescPtr dstDescPtr, + RpptROIPtr roiTensorPtrSrc, + RpptRoiType roiType, + RppLayoutParams layoutParams, + rpp::Handle& handle) +{ + RpptROI roiDefault = {0, 0, (Rpp32s)srcDescPtr->w, (Rpp32s)srcDescPtr->h}; + Rpp32u numThreads = handle.GetNumThreads(); + + omp_set_dynamic(0); +#pragma omp parallel for num_threads(numThreads) + for(int batchCount = 0; batchCount < dstDescPtr->n; batchCount++) + { + RpptROI roi; + RpptROIPtr roiPtrInput = &roiTensorPtrSrc[batchCount]; + compute_roi_validation_host(roiPtrInput, &roi, &roiDefault, roiType); + + Rpp8u *srcPtr1Image, *srcPtr2Image, *dstPtrImage; + srcPtr1Image = srcPtr1 + batchCount * srcDescPtr->strides.nStride; + srcPtr2Image = srcPtr2 + batchCount * srcDescPtr->strides.nStride; + dstPtrImage = dstPtr + batchCount * dstDescPtr->strides.nStride; + + Rpp32u bufferLength = roi.xywhROI.roiWidth * layoutParams.bufferMultiplier; + + Rpp8u *srcPtr1Channel, *srcPtr2Channel, *dstPtrChannel; + srcPtr1Channel = srcPtr1Image + (roi.xywhROI.xy.y * srcDescPtr->strides.hStride) + (roi.xywhROI.xy.x * layoutParams.bufferMultiplier); + srcPtr2Channel = srcPtr2Image + (roi.xywhROI.xy.y * srcDescPtr->strides.hStride) + (roi.xywhROI.xy.x * layoutParams.bufferMultiplier); + dstPtrChannel = dstPtrImage; + + Rpp32u alignedLength = (bufferLength / 48) * 48; + Rpp32u vectorIncrement = 48; + Rpp32u vectorIncrementPerChannel = 16; + + // Bitwise AND with fused output-layout toggle (NHWC -> NCHW) + if ((srcDescPtr->c == 3) && (srcDescPtr->layout == RpptLayout::NHWC) && (dstDescPtr->layout == RpptLayout::NCHW)) + { + Rpp8u *srcPtr1Row, *srcPtr2Row, *dstPtrRowR, *dstPtrRowG, *dstPtrRowB; + srcPtr1Row = srcPtr1Channel; + srcPtr2Row = srcPtr2Channel; + dstPtrRowR = dstPtrChannel; + dstPtrRowG = dstPtrRowR + dstDescPtr->strides.cStride; + dstPtrRowB = dstPtrRowG + dstDescPtr->strides.cStride; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp8u *srcPtr1Temp, *srcPtr2Temp, *dstPtrTempR, *dstPtrTempG, *dstPtrTempB; + srcPtr1Temp = srcPtr1Row; + srcPtr2Temp = srcPtr2Row; + dstPtrTempR = dstPtrRowR; + dstPtrTempG = dstPtrRowG; + dstPtrTempB = dstPtrRowB; + + int vectorLoopCount = 0; + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrement) + { + __m128i p1[3], p2[3]; + + rpp_simd_load(rpp_load48_u8pkd3_to_u8pln3, srcPtr1Temp, p1); // simd loads + rpp_simd_load(rpp_load48_u8pkd3_to_u8pln3, srcPtr2Temp, p2); // simd loads + p1[0] = _mm_and_si128(p1[0], p2[0]); // bitwise_and computation + p1[1] = _mm_and_si128(p1[1], p2[1]); // bitwise_and computation + p1[2] = _mm_and_si128(p1[2], p2[2]); // bitwise_and computation + rpp_simd_store(rpp_store48_u8pln3_to_u8pln3, dstPtrTempR, dstPtrTempG, dstPtrTempB, p1); // simd stores + + srcPtr1Temp += vectorIncrement; + srcPtr2Temp += vectorIncrement; + dstPtrTempR += vectorIncrementPerChannel; + dstPtrTempG += vectorIncrementPerChannel; + dstPtrTempB += vectorIncrementPerChannel; + } + + for (; vectorLoopCount < bufferLength; vectorLoopCount += 3) + { + *dstPtrTempR++ = srcPtr1Temp[0] & srcPtr2Temp[0]; + *dstPtrTempG++ = srcPtr1Temp[1] & srcPtr2Temp[1]; + *dstPtrTempB++ = srcPtr1Temp[2] & srcPtr2Temp[2]; + + srcPtr1Temp += 3; + srcPtr2Temp += 3; + } + + srcPtr1Row += srcDescPtr->strides.hStride; + srcPtr2Row += srcDescPtr->strides.hStride; + dstPtrRowR += dstDescPtr->strides.hStride; + dstPtrRowG += dstDescPtr->strides.hStride; + dstPtrRowB += dstDescPtr->strides.hStride; + } + } + + // Bitwise AND with fused output-layout toggle (NCHW -> NHWC) + else if ((srcDescPtr->c == 3) && (srcDescPtr->layout == RpptLayout::NCHW) && (dstDescPtr->layout == RpptLayout::NHWC)) + { + Rpp8u *srcPtr1RowR, *srcPtr1RowG, *srcPtr1RowB, *srcPtr2RowR, *srcPtr2RowG, *srcPtr2RowB, *dstPtrRow; + srcPtr1RowR = srcPtr1Channel; + srcPtr1RowG = srcPtr1RowR + srcDescPtr->strides.cStride; + srcPtr1RowB = srcPtr1RowG + srcDescPtr->strides.cStride; + srcPtr2RowR = srcPtr2Channel; + srcPtr2RowG = srcPtr2RowR + srcDescPtr->strides.cStride; + srcPtr2RowB = srcPtr2RowG + srcDescPtr->strides.cStride; + dstPtrRow = dstPtrChannel; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp8u *srcPtr1TempR, *srcPtr1TempG, *srcPtr1TempB, *srcPtr2TempR, *srcPtr2TempG, *srcPtr2TempB, *dstPtrTemp; + srcPtr1TempR = srcPtr1RowR; + srcPtr1TempG = srcPtr1RowG; + srcPtr1TempB = srcPtr1RowB; + srcPtr2TempR = srcPtr2RowR; + srcPtr2TempG = srcPtr2RowG; + srcPtr2TempB = srcPtr2RowB; + dstPtrTemp = dstPtrRow; + + int vectorLoopCount = 0; + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrementPerChannel) + { + __m128i p1[3], p2[3]; + + rpp_simd_load(rpp_load48_u8pln3_to_u8pln3, srcPtr1TempR, srcPtr1TempG, srcPtr1TempB, p1); // simd loads + rpp_simd_load(rpp_load48_u8pln3_to_u8pln3, srcPtr2TempR, srcPtr2TempG, srcPtr2TempB, p2); // simd loads + p1[0] = _mm_and_si128(p1[0], p2[0]); // bitwise_and computation + p1[1] = _mm_and_si128(p1[1], p2[1]); // bitwise_and computation + p1[2] = _mm_and_si128(p1[2], p2[2]); // bitwise_and computation + rpp_simd_store(rpp_store48_u8pln3_to_u8pkd3, dstPtrTemp, p1); // simd stores + + srcPtr1TempR += vectorIncrementPerChannel; + srcPtr1TempG += vectorIncrementPerChannel; + srcPtr1TempB += vectorIncrementPerChannel; + srcPtr2TempR += vectorIncrementPerChannel; + srcPtr2TempG += vectorIncrementPerChannel; + srcPtr2TempB += vectorIncrementPerChannel; + dstPtrTemp += vectorIncrement; + } + + for (; vectorLoopCount < bufferLength; vectorLoopCount++) + { + dstPtrTemp[0] = *srcPtr1TempR & *srcPtr2TempR; + dstPtrTemp[1] = *srcPtr1TempG & *srcPtr2TempG; + dstPtrTemp[2] = *srcPtr1TempB & *srcPtr2TempB; + + srcPtr1TempR++; + srcPtr1TempG++; + srcPtr1TempB++; + srcPtr2TempR++; + srcPtr2TempG++; + srcPtr2TempB++; + dstPtrTemp += 3; + } + + srcPtr1RowR += srcDescPtr->strides.hStride; + srcPtr1RowG += srcDescPtr->strides.hStride; + srcPtr1RowB += srcDescPtr->strides.hStride; + srcPtr2RowR += srcDescPtr->strides.hStride; + srcPtr2RowG += srcDescPtr->strides.hStride; + srcPtr2RowB += srcDescPtr->strides.hStride; + dstPtrRow += dstDescPtr->strides.hStride; + } + } + + // Bitwise AND without fused output-layout toggle (NHWC -> NHWC or NCHW -> NCHW) + else + { + alignedLength = bufferLength & ~15; + + for(int c = 0; c < layoutParams.channelParam; c++) + { + Rpp8u *srcPtr1Row, *srcPtr2Row, *dstPtrRow; + srcPtr1Row = srcPtr1Channel; + srcPtr2Row = srcPtr2Channel; + dstPtrRow = dstPtrChannel; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp8u *srcPtr1Temp, *srcPtr2Temp, *dstPtrTemp; + srcPtr1Temp = srcPtr1Row; + srcPtr2Temp = srcPtr2Row; + dstPtrTemp = dstPtrRow; + + int vectorLoopCount = 0; + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrementPerChannel) + { + __m128i p1, p2; + + p1 = _mm_loadu_si128((__m128i *)srcPtr1Temp); // simd loads + p2 = _mm_loadu_si128((__m128i *)srcPtr2Temp); // simd loads + p1 = _mm_and_si128(p1, p2); // bitwise_and computation + _mm_storeu_si128((__m128i *)dstPtrTemp, p1); // simd stores + + srcPtr1Temp += vectorIncrementPerChannel; + srcPtr2Temp += vectorIncrementPerChannel; + dstPtrTemp += vectorIncrementPerChannel; + } + + for (; vectorLoopCount < bufferLength; vectorLoopCount++) + { + *dstPtrTemp++ = *srcPtr1Temp & *srcPtr2Temp; + + srcPtr1Temp++; + srcPtr2Temp++; + } + + srcPtr1Row += srcDescPtr->strides.hStride; + srcPtr2Row += srcDescPtr->strides.hStride; + dstPtrRow += dstDescPtr->strides.hStride; + } + + srcPtr1Channel += srcDescPtr->strides.cStride; + srcPtr2Channel += srcDescPtr->strides.cStride; + dstPtrChannel += dstDescPtr->strides.cStride; + } + } + } + + return RPP_SUCCESS; +} + +/* BitwiseAND is logical operation only on U8/I8 types. + For a Rpp32f precision image (pixel values from 0-1), the BitwiseAND is applied on a 0-255 + range-translated approximation, of the original 0-1 decimal-range image. + Link: https://stackoverflow.com/questions/1723575/how-to-perform-a-bitwise-operation-on-floating-point-numbers */ +RppStatus bitwise_and_f32_f32_host_tensor(Rpp32f *srcPtr1, + Rpp32f *srcPtr2, + RpptDescPtr srcDescPtr, + Rpp32f *dstPtr, + RpptDescPtr dstDescPtr, + RpptROIPtr roiTensorPtrSrc, + RpptRoiType roiType, + RppLayoutParams layoutParams, + rpp::Handle& handle) +{ + RpptROI roiDefault = {0, 0, (Rpp32s)srcDescPtr->w, (Rpp32s)srcDescPtr->h}; + Rpp32u numThreads = handle.GetNumThreads(); + + omp_set_dynamic(0); +#pragma omp parallel for num_threads(numThreads) + for(int batchCount = 0; batchCount < dstDescPtr->n; batchCount++) + { + RpptROI roi; + RpptROIPtr roiPtrInput = &roiTensorPtrSrc[batchCount]; + compute_roi_validation_host(roiPtrInput, &roi, &roiDefault, roiType); + + Rpp32f *srcPtr1Image, *srcPtr2Image, *dstPtrImage; + srcPtr1Image = srcPtr1 + batchCount * srcDescPtr->strides.nStride; + srcPtr2Image = srcPtr2 + batchCount * srcDescPtr->strides.nStride; + dstPtrImage = dstPtr + batchCount * dstDescPtr->strides.nStride; + + Rpp32u bufferLength = roi.xywhROI.roiWidth * layoutParams.bufferMultiplier; + + Rpp32f *srcPtr1Channel, *srcPtr2Channel, *dstPtrChannel; + srcPtr1Channel = srcPtr1Image + (roi.xywhROI.xy.y * srcDescPtr->strides.hStride) + (roi.xywhROI.xy.x * layoutParams.bufferMultiplier); + srcPtr2Channel = srcPtr2Image + (roi.xywhROI.xy.y * srcDescPtr->strides.hStride) + (roi.xywhROI.xy.x * layoutParams.bufferMultiplier); + dstPtrChannel = dstPtrImage; + +#if __AVX2__ + Rpp32u alignedLength = (bufferLength / 24) * 24; + Rpp32u vectorIncrement = 24; + Rpp32u vectorIncrementPerChannel = 8; +#endif + + // Bitwise AND with fused output-layout toggle (NHWC -> NCHW) + if ((srcDescPtr->c == 3) && (srcDescPtr->layout == RpptLayout::NHWC) && (dstDescPtr->layout == RpptLayout::NCHW)) + { + Rpp32f *srcPtr1Row, *srcPtr2Row, *dstPtrRowR, *dstPtrRowG, *dstPtrRowB; + srcPtr1Row = srcPtr1Channel; + srcPtr2Row = srcPtr2Channel; + dstPtrRowR = dstPtrChannel; + dstPtrRowG = dstPtrRowR + dstDescPtr->strides.cStride; + dstPtrRowB = dstPtrRowG + dstDescPtr->strides.cStride; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp32f *srcPtr1Temp, *srcPtr2Temp, *dstPtrTempR, *dstPtrTempG, *dstPtrTempB; + srcPtr1Temp = srcPtr1Row; + srcPtr2Temp = srcPtr2Row; + dstPtrTempR = dstPtrRowR; + dstPtrTempG = dstPtrRowG; + dstPtrTempB = dstPtrRowB; + + int vectorLoopCount = 0; +#if __AVX2__ + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrement) + { + __m256 p1[3], p2[3]; + + rpp_simd_load(rpp_load24_f32pkd3_to_f32pln3_avx, srcPtr1Temp, p1); // simd loads + rpp_simd_load(rpp_load24_f32pkd3_to_f32pln3_avx, srcPtr2Temp, p2); // simd loads + p1[0] = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[0], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[0], avx_p255)))); // bitwise_and computation + p1[1] = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[1], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[1], avx_p255)))); // bitwise_and computation + p1[2] = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[2], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[2], avx_p255)))); // bitwise_and computation + p1[0] = _mm256_mul_ps(p1[0], avx_p1op255); + p1[1] = _mm256_mul_ps(p1[1], avx_p1op255); + p1[2] = _mm256_mul_ps(p1[2], avx_p1op255); + rpp_simd_store(rpp_store24_f32pln3_to_f32pln3_avx, dstPtrTempR, dstPtrTempG, dstPtrTempB, p1); // simd stores + + srcPtr1Temp += vectorIncrement; + srcPtr2Temp += vectorIncrement; + dstPtrTempR += vectorIncrementPerChannel; + dstPtrTempG += vectorIncrementPerChannel; + dstPtrTempB += vectorIncrementPerChannel; + } +#endif + for (; vectorLoopCount < bufferLength; vectorLoopCount += 3) + { + *dstPtrTempR++ = RPPPIXELCHECKF32((float)((uint)(srcPtr1Temp[0] * 255) & (uint)(srcPtr2Temp[0] * 255)) / 255); + *dstPtrTempG++ = RPPPIXELCHECKF32((float)((uint)(srcPtr1Temp[1] * 255) & (uint)(srcPtr2Temp[1] * 255)) / 255); + *dstPtrTempB++ = RPPPIXELCHECKF32((float)((uint)(srcPtr1Temp[2] * 255) & (uint)(srcPtr2Temp[2] * 255)) / 255); + + srcPtr1Temp += 3; + srcPtr2Temp += 3; + } + + srcPtr1Row += srcDescPtr->strides.hStride; + srcPtr2Row += srcDescPtr->strides.hStride; + dstPtrRowR += dstDescPtr->strides.hStride; + dstPtrRowG += dstDescPtr->strides.hStride; + dstPtrRowB += dstDescPtr->strides.hStride; + } + } + + // Bitwise AND with fused output-layout toggle (NCHW -> NHWC) + else if ((srcDescPtr->c == 3) && (srcDescPtr->layout == RpptLayout::NCHW) && (dstDescPtr->layout == RpptLayout::NHWC)) + { + Rpp32f *srcPtr1RowR, *srcPtr1RowG, *srcPtr1RowB, *srcPtr2RowR, *srcPtr2RowG, *srcPtr2RowB, *dstPtrRow; + srcPtr1RowR = srcPtr1Channel; + srcPtr1RowG = srcPtr1RowR + srcDescPtr->strides.cStride; + srcPtr1RowB = srcPtr1RowG + srcDescPtr->strides.cStride; + srcPtr2RowR = srcPtr2Channel; + srcPtr2RowG = srcPtr2RowR + srcDescPtr->strides.cStride; + srcPtr2RowB = srcPtr2RowG + srcDescPtr->strides.cStride; + dstPtrRow = dstPtrChannel; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp32f *srcPtr1TempR, *srcPtr1TempG, *srcPtr1TempB, *srcPtr2TempR, *srcPtr2TempG, *srcPtr2TempB, *dstPtrTemp; + srcPtr1TempR = srcPtr1RowR; + srcPtr1TempG = srcPtr1RowG; + srcPtr1TempB = srcPtr1RowB; + srcPtr2TempR = srcPtr2RowR; + srcPtr2TempG = srcPtr2RowG; + srcPtr2TempB = srcPtr2RowB; + dstPtrTemp = dstPtrRow; + + int vectorLoopCount = 0; +#if __AVX2__ + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrementPerChannel) + { + __m256 p1[3], p2[3]; + + rpp_simd_load(rpp_load24_f32pln3_to_f32pln3_avx, srcPtr1TempR, srcPtr1TempG, srcPtr1TempB, p1); // simd loads + rpp_simd_load(rpp_load24_f32pln3_to_f32pln3_avx, srcPtr2TempR, srcPtr2TempG, srcPtr2TempB, p2); // simd loads + p1[0] = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[0], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[0], avx_p255)))); // bitwise_and computation + p1[1] = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[1], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[1], avx_p255)))); // bitwise_and computation + p1[2] = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[2], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[2], avx_p255)))); // bitwise_and computation + p1[0] = _mm256_mul_ps(p1[0], avx_p1op255); + p1[1] = _mm256_mul_ps(p1[1], avx_p1op255); + p1[2] = _mm256_mul_ps(p1[2], avx_p1op255); + rpp_simd_store(rpp_store24_f32pln3_to_f32pkd3_avx, dstPtrTemp, p1); // simd stores + + srcPtr1TempR += vectorIncrementPerChannel; + srcPtr1TempG += vectorIncrementPerChannel; + srcPtr1TempB += vectorIncrementPerChannel; + srcPtr2TempR += vectorIncrementPerChannel; + srcPtr2TempG += vectorIncrementPerChannel; + srcPtr2TempB += vectorIncrementPerChannel; + dstPtrTemp += vectorIncrement; + } +#endif + for (; vectorLoopCount < bufferLength; vectorLoopCount++) + { + dstPtrTemp[0] = RPPPIXELCHECKF32((float)((uint)(*srcPtr1TempR * 255) & (uint)(*srcPtr2TempR * 255)) / 255); + dstPtrTemp[1] = RPPPIXELCHECKF32((float)((uint)(*srcPtr1TempG * 255) & (uint)(*srcPtr2TempG * 255)) / 255); + dstPtrTemp[2] = RPPPIXELCHECKF32((float)((uint)(*srcPtr1TempB * 255) & (uint)(*srcPtr2TempB * 255)) / 255); + + srcPtr1TempR++; + srcPtr1TempG++; + srcPtr1TempB++; + srcPtr2TempR++; + srcPtr2TempG++; + srcPtr2TempB++; + dstPtrTemp += 3; + } + + srcPtr1RowR += srcDescPtr->strides.hStride; + srcPtr1RowG += srcDescPtr->strides.hStride; + srcPtr1RowB += srcDescPtr->strides.hStride; + srcPtr2RowR += srcDescPtr->strides.hStride; + srcPtr2RowG += srcDescPtr->strides.hStride; + srcPtr2RowB += srcDescPtr->strides.hStride; + dstPtrRow += dstDescPtr->strides.hStride; + } + } + + // Bitwise AND without fused output-layout toggle (NHWC -> NHWC or NCHW -> NCHW) + else + { +#if __AVX2__ + alignedLength = bufferLength & ~7; +#endif + + for(int c = 0; c < layoutParams.channelParam; c++) + { + Rpp32f *srcPtr1Row, *srcPtr2Row, *dstPtrRow; + srcPtr1Row = srcPtr1Channel; + srcPtr2Row = srcPtr2Channel; + dstPtrRow = dstPtrChannel; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp32f *srcPtr1Temp, *srcPtr2Temp, *dstPtrTemp; + srcPtr1Temp = srcPtr1Row; + srcPtr2Temp = srcPtr2Row; + dstPtrTemp = dstPtrRow; + + int vectorLoopCount = 0; +#if __AVX2__ + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrementPerChannel) + { + __m256 p1[1], p2[1]; + + rpp_simd_load(rpp_load8_f32_to_f32_avx, srcPtr1Temp, p1); // simd loads + rpp_simd_load(rpp_load8_f32_to_f32_avx, srcPtr2Temp, p2); // simd loads + p1[0] = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[0], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[0], avx_p255)))); // bitwise_and computation + p1[0] = _mm256_mul_ps(p1[0], avx_p1op255); + rpp_simd_store(rpp_store8_f32_to_f32_avx, dstPtrTemp, p1); // simd stores + + srcPtr1Temp += vectorIncrementPerChannel; + srcPtr2Temp += vectorIncrementPerChannel; + dstPtrTemp += vectorIncrementPerChannel; + } +#endif + for (; vectorLoopCount < bufferLength; vectorLoopCount++) + { + *dstPtrTemp++ = RPPPIXELCHECKF32((float)((uint)(*srcPtr1Temp * 255) & (uint)(*srcPtr2Temp * 255)) / 255); + + srcPtr1Temp++; + srcPtr2Temp++; + } + + srcPtr1Row += srcDescPtr->strides.hStride; + srcPtr2Row += srcDescPtr->strides.hStride; + dstPtrRow += dstDescPtr->strides.hStride; + } + + srcPtr1Channel += srcDescPtr->strides.cStride; + srcPtr2Channel += srcDescPtr->strides.cStride; + dstPtrChannel += dstDescPtr->strides.cStride; + } + } + } + + return RPP_SUCCESS; +} + +RppStatus bitwise_and_f16_f16_host_tensor(Rpp16f *srcPtr1, + Rpp16f *srcPtr2, + RpptDescPtr srcDescPtr, + Rpp16f *dstPtr, + RpptDescPtr dstDescPtr, + RpptROIPtr roiTensorPtrSrc, + RpptRoiType roiType, + RppLayoutParams layoutParams, + rpp::Handle& handle) +{ + RpptROI roiDefault = {0, 0, (Rpp32s)srcDescPtr->w, (Rpp32s)srcDescPtr->h}; + Rpp32u numThreads = handle.GetNumThreads(); + + omp_set_dynamic(0); +#pragma omp parallel for num_threads(numThreads) + for(int batchCount = 0; batchCount < dstDescPtr->n; batchCount++) + { + RpptROI roi; + RpptROIPtr roiPtrInput = &roiTensorPtrSrc[batchCount]; + compute_roi_validation_host(roiPtrInput, &roi, &roiDefault, roiType); + + Rpp16f *srcPtr1Image, *srcPtr2Image, *dstPtrImage; + srcPtr1Image = srcPtr1 + batchCount * srcDescPtr->strides.nStride; + srcPtr2Image = srcPtr2 + batchCount * srcDescPtr->strides.nStride; + dstPtrImage = dstPtr + batchCount * dstDescPtr->strides.nStride; + + Rpp32u bufferLength = roi.xywhROI.roiWidth * layoutParams.bufferMultiplier; + + Rpp16f *srcPtr1Channel, *srcPtr2Channel, *dstPtrChannel; + srcPtr1Channel = srcPtr1Image + (roi.xywhROI.xy.y * srcDescPtr->strides.hStride) + (roi.xywhROI.xy.x * layoutParams.bufferMultiplier); + srcPtr2Channel = srcPtr2Image + (roi.xywhROI.xy.y * srcDescPtr->strides.hStride) + (roi.xywhROI.xy.x * layoutParams.bufferMultiplier); + dstPtrChannel = dstPtrImage; + +#if __AVX2__ + Rpp32u alignedLength = (bufferLength / 24) * 24; + Rpp32u vectorIncrement = 24; + Rpp32u vectorIncrementPerChannel = 8; +#endif + + // Bitwise AND with fused output-layout toggle (NHWC -> NCHW) + if ((srcDescPtr->c == 3) && (srcDescPtr->layout == RpptLayout::NHWC) && (dstDescPtr->layout == RpptLayout::NCHW)) + { + Rpp16f *srcPtr1Row, *srcPtr2Row, *dstPtrRowR, *dstPtrRowG, *dstPtrRowB; + srcPtr1Row = srcPtr1Channel; + srcPtr2Row = srcPtr2Channel; + dstPtrRowR = dstPtrChannel; + dstPtrRowG = dstPtrRowR + dstDescPtr->strides.cStride; + dstPtrRowB = dstPtrRowG + dstDescPtr->strides.cStride; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp16f *srcPtr1Temp, *srcPtr2Temp, *dstPtrTempR, *dstPtrTempG, *dstPtrTempB; + srcPtr1Temp = srcPtr1Row; + srcPtr2Temp = srcPtr2Row; + dstPtrTempR = dstPtrRowR; + dstPtrTempG = dstPtrRowG; + dstPtrTempB = dstPtrRowB; + + int vectorLoopCount = 0; +#if __AVX2__ + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrement) + { + Rpp32f srcPtr1Temp_ps[24], srcPtr2Temp_ps[24]; + + for(int cnt = 0; cnt < vectorIncrement; cnt++) + { + srcPtr1Temp_ps[cnt] = static_cast(srcPtr1Temp[cnt]); + srcPtr2Temp_ps[cnt] = static_cast(srcPtr2Temp[cnt]); + } + + __m256 p1[3], p2[3]; + + rpp_simd_load(rpp_load24_f32pkd3_to_f32pln3_avx, srcPtr1Temp_ps, p1); // simd loads + rpp_simd_load(rpp_load24_f32pkd3_to_f32pln3_avx, srcPtr2Temp_ps, p2); // simd loads + p1[0] = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[0], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[0], avx_p255)))); // bitwise_and computation + p1[1] = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[1], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[1], avx_p255)))); // bitwise_and computation + p1[2] = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[2], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[2], avx_p255)))); // bitwise_and computation + p1[0] = _mm256_mul_ps(p1[0], avx_p1op255); + p1[1] = _mm256_mul_ps(p1[1], avx_p1op255); + p1[2] = _mm256_mul_ps(p1[2], avx_p1op255); + rpp_simd_store(rpp_store24_f32pln3_to_f16pln3_avx, dstPtrTempR, dstPtrTempG, dstPtrTempB, p1); // simd stores + + srcPtr1Temp += vectorIncrement; + srcPtr2Temp += vectorIncrement; + dstPtrTempR += vectorIncrementPerChannel; + dstPtrTempG += vectorIncrementPerChannel; + dstPtrTempB += vectorIncrementPerChannel; + } +#endif + for (; vectorLoopCount < bufferLength; vectorLoopCount += 3) + { + *dstPtrTempR++ = static_cast(RPPPIXELCHECKF32((float)((uint)(srcPtr1Temp[0] * 255) & (uint)(srcPtr2Temp[0] * 255)) / 255)); + *dstPtrTempG++ = static_cast(RPPPIXELCHECKF32((float)((uint)(srcPtr1Temp[1] * 255) & (uint)(srcPtr2Temp[1] * 255)) / 255)); + *dstPtrTempB++ = static_cast(RPPPIXELCHECKF32((float)((uint)(srcPtr1Temp[2] * 255) & (uint)(srcPtr2Temp[2] * 255)) / 255)); + + srcPtr1Temp += 3; + srcPtr2Temp += 3; + } + + srcPtr1Row += srcDescPtr->strides.hStride; + srcPtr2Row += srcDescPtr->strides.hStride; + dstPtrRowR += dstDescPtr->strides.hStride; + dstPtrRowG += dstDescPtr->strides.hStride; + dstPtrRowB += dstDescPtr->strides.hStride; + } + } + + // Bitwise AND with fused output-layout toggle (NCHW -> NHWC) + else if ((srcDescPtr->c == 3) && (srcDescPtr->layout == RpptLayout::NCHW) && (dstDescPtr->layout == RpptLayout::NHWC)) + { + Rpp16f *srcPtr1RowR, *srcPtr1RowG, *srcPtr1RowB, *srcPtr2RowR, *srcPtr2RowG, *srcPtr2RowB, *dstPtrRow; + srcPtr1RowR = srcPtr1Channel; + srcPtr1RowG = srcPtr1RowR + srcDescPtr->strides.cStride; + srcPtr1RowB = srcPtr1RowG + srcDescPtr->strides.cStride; + srcPtr2RowR = srcPtr2Channel; + srcPtr2RowG = srcPtr2RowR + srcDescPtr->strides.cStride; + srcPtr2RowB = srcPtr2RowG + srcDescPtr->strides.cStride; + dstPtrRow = dstPtrChannel; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp16f *srcPtr1TempR, *srcPtr1TempG, *srcPtr1TempB, *srcPtr2TempR, *srcPtr2TempG, *srcPtr2TempB, *dstPtrTemp; + srcPtr1TempR = srcPtr1RowR; + srcPtr1TempG = srcPtr1RowG; + srcPtr1TempB = srcPtr1RowB; + srcPtr2TempR = srcPtr2RowR; + srcPtr2TempG = srcPtr2RowG; + srcPtr2TempB = srcPtr2RowB; + dstPtrTemp = dstPtrRow; + + int vectorLoopCount = 0; +#if __AVX2__ + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrementPerChannel) + { + Rpp32f srcPtr1Temp_ps[24], srcPtr2Temp_ps[24]; + + for(int cnt = 0; cnt < vectorIncrementPerChannel; cnt++) + { + srcPtr1Temp_ps[cnt] = static_cast(srcPtr1TempR[cnt]); + srcPtr1Temp_ps[cnt + 8] = static_cast(srcPtr1TempG[cnt]); + srcPtr1Temp_ps[cnt + 16] = static_cast(srcPtr1TempB[cnt]); + + srcPtr2Temp_ps[cnt] = static_cast(srcPtr2TempR[cnt]); + srcPtr2Temp_ps[cnt + 8] = static_cast(srcPtr2TempG[cnt]); + srcPtr2Temp_ps[cnt + 16] = static_cast(srcPtr2TempB[cnt]); + } + + __m256 p1[4], p2[4]; + + rpp_simd_load(rpp_load24_f32pln3_to_f32pln3_avx, srcPtr1Temp_ps, srcPtr1Temp_ps + 8, srcPtr1Temp_ps + 16, p1); // simd loads + rpp_simd_load(rpp_load24_f32pln3_to_f32pln3_avx, srcPtr2Temp_ps, srcPtr2Temp_ps + 8, srcPtr2Temp_ps + 16, p2); // simd loads + p1[0] = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[0], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[0], avx_p255)))); // bitwise_and computation + p1[1] = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[1], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[1], avx_p255)))); // bitwise_and computation + p1[2] = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[2], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[2], avx_p255)))); // bitwise_and computation + p1[0] = _mm256_mul_ps(p1[0], avx_p1op255); + p1[1] = _mm256_mul_ps(p1[1], avx_p1op255); + p1[2] = _mm256_mul_ps(p1[2], avx_p1op255); + rpp_simd_store(rpp_store24_f32pln3_to_f16pkd3_avx, dstPtrTemp, p1); // simd stores + + srcPtr1TempR += vectorIncrementPerChannel; + srcPtr1TempG += vectorIncrementPerChannel; + srcPtr1TempB += vectorIncrementPerChannel; + srcPtr2TempR += vectorIncrementPerChannel; + srcPtr2TempG += vectorIncrementPerChannel; + srcPtr2TempB += vectorIncrementPerChannel; + dstPtrTemp += vectorIncrement; + } +#endif + for (; vectorLoopCount < bufferLength; vectorLoopCount++) + { + dstPtrTemp[0] = static_cast(RPPPIXELCHECKF32((float)((uint)(*srcPtr1TempR * 255) & (uint)(*srcPtr2TempR * 255)) / 255)); + dstPtrTemp[1] = static_cast(RPPPIXELCHECKF32((float)((uint)(*srcPtr1TempG * 255) & (uint)(*srcPtr2TempG * 255)) / 255)); + dstPtrTemp[2] = static_cast(RPPPIXELCHECKF32((float)((uint)(*srcPtr1TempB * 255) & (uint)(*srcPtr2TempB * 255)) / 255)); + + srcPtr1TempR++; + srcPtr1TempG++; + srcPtr1TempB++; + srcPtr2TempR++; + srcPtr2TempG++; + srcPtr2TempB++; + dstPtrTemp += 3; + } + + srcPtr1RowR += srcDescPtr->strides.hStride; + srcPtr1RowG += srcDescPtr->strides.hStride; + srcPtr1RowB += srcDescPtr->strides.hStride; + srcPtr2RowR += srcDescPtr->strides.hStride; + srcPtr2RowG += srcDescPtr->strides.hStride; + srcPtr2RowB += srcDescPtr->strides.hStride; + dstPtrRow += dstDescPtr->strides.hStride; + } + } + + // Bitwise AND without fused output-layout toggle (NHWC -> NHWC or NCHW -> NCHW) + else + { +#if __AVX2__ + alignedLength = bufferLength & ~7; +#endif + + for(int c = 0; c < layoutParams.channelParam; c++) + { + Rpp16f *srcPtr1Row, *srcPtr2Row, *dstPtrRow; + srcPtr1Row = srcPtr1Channel; + srcPtr2Row = srcPtr2Channel; + dstPtrRow = dstPtrChannel; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp16f *srcPtr1Temp, *srcPtr2Temp, *dstPtrTemp; + srcPtr1Temp = srcPtr1Row; + srcPtr2Temp = srcPtr2Row; + dstPtrTemp = dstPtrRow; + + int vectorLoopCount = 0; +#if __AVX2__ + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrementPerChannel) + { + Rpp32f srcPtr1Temp_ps[8], srcPtr2Temp_ps[8]; + + for(int cnt = 0; cnt < vectorIncrementPerChannel; cnt++) + { + srcPtr1Temp_ps[cnt] = static_cast(srcPtr1Temp[cnt]); + srcPtr2Temp_ps[cnt] = static_cast(srcPtr2Temp[cnt]); + } + + __m256 p1[1], p2[1]; + + rpp_simd_load(rpp_load8_f32_to_f32_avx, srcPtr1Temp_ps, p1); // simd loads + rpp_simd_load(rpp_load8_f32_to_f32_avx, srcPtr2Temp_ps, p2); // simd loads + p1[0] = _mm256_cvtepi32_ps(_mm256_and_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[0], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[0], avx_p255)))); // bitwise_and computation + p1[0] = _mm256_mul_ps(p1[0], avx_p1op255); + rpp_simd_store(rpp_store8_f32_to_f16_avx, dstPtrTemp, p1); // simd stores + + srcPtr1Temp += vectorIncrementPerChannel; + srcPtr2Temp += vectorIncrementPerChannel; + dstPtrTemp += vectorIncrementPerChannel; + } +#endif + for (; vectorLoopCount < bufferLength; vectorLoopCount++) + { + *dstPtrTemp++ = static_cast(RPPPIXELCHECKF32((float)((uint)(*srcPtr1Temp * 255) & (uint)(*srcPtr2Temp * 255)) / 255)); + + srcPtr1Temp++; + srcPtr2Temp++; + } + + srcPtr1Row += srcDescPtr->strides.hStride; + srcPtr2Row += srcDescPtr->strides.hStride; + dstPtrRow += dstDescPtr->strides.hStride; + } + + srcPtr1Channel += srcDescPtr->strides.cStride; + srcPtr2Channel += srcDescPtr->strides.cStride; + dstPtrChannel += dstDescPtr->strides.cStride; + } + } + } + + return RPP_SUCCESS; +} + +RppStatus bitwise_and_i8_i8_host_tensor(Rpp8s *srcPtr1, + Rpp8s *srcPtr2, + RpptDescPtr srcDescPtr, + Rpp8s *dstPtr, + RpptDescPtr dstDescPtr, + RpptROIPtr roiTensorPtrSrc, + RpptRoiType roiType, + RppLayoutParams layoutParams, + rpp::Handle& handle) +{ + RpptROI roiDefault = {0, 0, (Rpp32s)srcDescPtr->w, (Rpp32s)srcDescPtr->h}; + Rpp32u numThreads = handle.GetNumThreads(); + + omp_set_dynamic(0); +#pragma omp parallel for num_threads(numThreads) + for(int batchCount = 0; batchCount < dstDescPtr->n; batchCount++) + { + RpptROI roi; + RpptROIPtr roiPtrInput = &roiTensorPtrSrc[batchCount]; + compute_roi_validation_host(roiPtrInput, &roi, &roiDefault, roiType); + + Rpp8s *srcPtr1Image, *srcPtr2Image, *dstPtrImage; + srcPtr1Image = srcPtr1 + batchCount * srcDescPtr->strides.nStride; + srcPtr2Image = srcPtr2 + batchCount * srcDescPtr->strides.nStride; + dstPtrImage = dstPtr + batchCount * dstDescPtr->strides.nStride; + + Rpp32u bufferLength = roi.xywhROI.roiWidth * layoutParams.bufferMultiplier; + + Rpp8s *srcPtr1Channel, *srcPtr2Channel, *dstPtrChannel; + srcPtr1Channel = srcPtr1Image + (roi.xywhROI.xy.y * srcDescPtr->strides.hStride) + (roi.xywhROI.xy.x * layoutParams.bufferMultiplier); + srcPtr2Channel = srcPtr2Image + (roi.xywhROI.xy.y * srcDescPtr->strides.hStride) + (roi.xywhROI.xy.x * layoutParams.bufferMultiplier); + dstPtrChannel = dstPtrImage; + + Rpp32u alignedLength = (bufferLength / 48) * 48; + Rpp32u vectorIncrement = 48; + Rpp32u vectorIncrementPerChannel = 16; + + // Bitwise AND with fused output-layout toggle (NHWC -> NCHW) + if ((srcDescPtr->c == 3) && (srcDescPtr->layout == RpptLayout::NHWC) && (dstDescPtr->layout == RpptLayout::NCHW)) + { + Rpp8s *srcPtr1Row, *srcPtr2Row, *dstPtrRowR, *dstPtrRowG, *dstPtrRowB; + srcPtr1Row = srcPtr1Channel; + srcPtr2Row = srcPtr2Channel; + dstPtrRowR = dstPtrChannel; + dstPtrRowG = dstPtrRowR + dstDescPtr->strides.cStride; + dstPtrRowB = dstPtrRowG + dstDescPtr->strides.cStride; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp8s *srcPtr1Temp, *srcPtr2Temp, *dstPtrTempR, *dstPtrTempG, *dstPtrTempB; + srcPtr1Temp = srcPtr1Row; + srcPtr2Temp = srcPtr2Row; + dstPtrTempR = dstPtrRowR; + dstPtrTempG = dstPtrRowG; + dstPtrTempB = dstPtrRowB; + + int vectorLoopCount = 0; + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrement) + { + __m128i p1[3], p2[3]; + + rpp_simd_load(rpp_load48_i8pkd3_to_u8pln3, srcPtr1Temp, p1); // simd loads + rpp_simd_load(rpp_load48_i8pkd3_to_u8pln3, srcPtr2Temp, p2); // simd loads + p1[0] = _mm_and_si128(p1[0], p2[0]); // bitwise_and computation + p1[1] = _mm_and_si128(p1[1], p2[1]); // bitwise_and computation + p1[2] = _mm_and_si128(p1[2], p2[2]); // bitwise_and computation + rpp_simd_store(rpp_store48_u8pln3_to_i8pln3, dstPtrTempR, dstPtrTempG, dstPtrTempB, p1); // simd stores + + srcPtr1Temp += vectorIncrement; + srcPtr2Temp += vectorIncrement; + dstPtrTempR += vectorIncrementPerChannel; + dstPtrTempG += vectorIncrementPerChannel; + dstPtrTempB += vectorIncrementPerChannel; + } + + for (; vectorLoopCount < bufferLength; vectorLoopCount += 3) + { + *dstPtrTempR++ = static_cast(RPPPIXELCHECKI8(((srcPtr1Temp[0] + 128) & (srcPtr2Temp[0] + 128)) - 128)); + *dstPtrTempG++ = static_cast(RPPPIXELCHECKI8(((srcPtr1Temp[1] + 128) & (srcPtr2Temp[1] + 128)) - 128)); + *dstPtrTempB++ = static_cast(RPPPIXELCHECKI8(((srcPtr1Temp[2] + 128) & (srcPtr2Temp[2] + 128)) - 128)); + + srcPtr1Temp += 3; + srcPtr2Temp += 3; + } + + srcPtr1Row += srcDescPtr->strides.hStride; + srcPtr2Row += srcDescPtr->strides.hStride; + dstPtrRowR += dstDescPtr->strides.hStride; + dstPtrRowG += dstDescPtr->strides.hStride; + dstPtrRowB += dstDescPtr->strides.hStride; + } + } + + // Bitwise AND with fused output-layout toggle (NCHW -> NHWC) + else if ((srcDescPtr->c == 3) && (srcDescPtr->layout == RpptLayout::NCHW) && (dstDescPtr->layout == RpptLayout::NHWC)) + { + Rpp8s *srcPtr1RowR, *srcPtr1RowG, *srcPtr1RowB, *srcPtr2RowR, *srcPtr2RowG, *srcPtr2RowB, *dstPtrRow; + srcPtr1RowR = srcPtr1Channel; + srcPtr1RowG = srcPtr1RowR + srcDescPtr->strides.cStride; + srcPtr1RowB = srcPtr1RowG + srcDescPtr->strides.cStride; + srcPtr2RowR = srcPtr2Channel; + srcPtr2RowG = srcPtr2RowR + srcDescPtr->strides.cStride; + srcPtr2RowB = srcPtr2RowG + srcDescPtr->strides.cStride; + dstPtrRow = dstPtrChannel; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp8s *srcPtr1TempR, *srcPtr1TempG, *srcPtr1TempB, *srcPtr2TempR, *srcPtr2TempG, *srcPtr2TempB, *dstPtrTemp; + srcPtr1TempR = srcPtr1RowR; + srcPtr1TempG = srcPtr1RowG; + srcPtr1TempB = srcPtr1RowB; + srcPtr2TempR = srcPtr2RowR; + srcPtr2TempG = srcPtr2RowG; + srcPtr2TempB = srcPtr2RowB; + dstPtrTemp = dstPtrRow; + + int vectorLoopCount = 0; + + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrementPerChannel) + { + __m128i p1[3], p2[3]; + + rpp_simd_load(rpp_load48_i8pln3_to_u8pln3, srcPtr1TempR, srcPtr1TempG, srcPtr1TempB, p1); // simd loads + rpp_simd_load(rpp_load48_i8pln3_to_u8pln3, srcPtr2TempR, srcPtr2TempG, srcPtr2TempB, p2); // simd loads + p1[0] = _mm_and_si128(p1[0], p2[0]); // bitwise_and computation + p1[1] = _mm_and_si128(p1[1], p2[1]); // bitwise_and computation + p1[2] = _mm_and_si128(p1[2], p2[2]); // bitwise_and computation + rpp_simd_store(rpp_store48_u8pln3_to_i8pkd3, dstPtrTemp, p1); // simd stores + + + srcPtr1TempR += vectorIncrementPerChannel; + srcPtr1TempG += vectorIncrementPerChannel; + srcPtr1TempB += vectorIncrementPerChannel; + srcPtr2TempR += vectorIncrementPerChannel; + srcPtr2TempG += vectorIncrementPerChannel; + srcPtr2TempB += vectorIncrementPerChannel; + dstPtrTemp += vectorIncrement; + } + for (; vectorLoopCount < bufferLength; vectorLoopCount++) + { + dstPtrTemp[0] = static_cast(RPPPIXELCHECKI8(((static_cast((*srcPtr1TempR + 128) & static_cast(*srcPtr2TempR + 128)))) - 128)); + dstPtrTemp[1] = static_cast(RPPPIXELCHECKI8(((static_cast((*srcPtr1TempG + 128) & static_cast(*srcPtr2TempG + 128)))) - 128)); + dstPtrTemp[2] = static_cast(RPPPIXELCHECKI8(((static_cast((*srcPtr1TempB + 128) & static_cast(*srcPtr2TempB + 128)))) - 128)); + + srcPtr1TempR++; + srcPtr1TempG++; + srcPtr1TempB++; + srcPtr2TempR++; + srcPtr2TempG++; + srcPtr2TempB++; + dstPtrTemp += 3; + } + + srcPtr1RowR += srcDescPtr->strides.hStride; + srcPtr1RowG += srcDescPtr->strides.hStride; + srcPtr1RowB += srcDescPtr->strides.hStride; + srcPtr2RowR += srcDescPtr->strides.hStride; + srcPtr2RowG += srcDescPtr->strides.hStride; + srcPtr2RowB += srcDescPtr->strides.hStride; + dstPtrRow += dstDescPtr->strides.hStride; + } + } + + // Bitwise AND without fused output-layout toggle (NHWC -> NHWC or NCHW -> NCHW) + else + { + alignedLength = bufferLength & ~15; + + for(int c = 0; c < layoutParams.channelParam; c++) + { + Rpp8s *srcPtr1Row, *srcPtr2Row, *dstPtrRow; + srcPtr1Row = srcPtr1Channel; + srcPtr2Row = srcPtr2Channel; + dstPtrRow = dstPtrChannel; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp8s *srcPtr1Temp, *srcPtr2Temp, *dstPtrTemp; + srcPtr1Temp = srcPtr1Row; + srcPtr2Temp = srcPtr2Row; + dstPtrTemp = dstPtrRow; + + int vectorLoopCount = 0; + + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrementPerChannel) + { + __m128i p1, p2; + + p1 = _mm_add_epi8(xmm_pxConvertI8, _mm_loadu_si128((__m128i *)srcPtr1Temp)); // simd loads + p2 = _mm_add_epi8(xmm_pxConvertI8, _mm_loadu_si128((__m128i *)srcPtr2Temp)); // simd loads + p1 = _mm_and_si128(p1, p2); // bitwise_and computation + _mm_storeu_si128((__m128i *)dstPtrTemp, _mm_sub_epi8(p1, xmm_pxConvertI8)); // simd stores + + srcPtr1Temp += vectorIncrementPerChannel; + srcPtr2Temp += vectorIncrementPerChannel; + dstPtrTemp += vectorIncrementPerChannel; + } + for (; vectorLoopCount < bufferLength; vectorLoopCount++) + { + *dstPtrTemp++ = static_cast(RPPPIXELCHECKI8(((static_cast((*srcPtr1Temp + 128) & static_cast(*srcPtr2Temp + 128)))) - 128)); + + srcPtr1Temp++; + srcPtr2Temp++; + } + + srcPtr1Row += srcDescPtr->strides.hStride; + srcPtr2Row += srcDescPtr->strides.hStride; + dstPtrRow += dstDescPtr->strides.hStride; + } + + srcPtr1Channel += srcDescPtr->strides.cStride; + srcPtr2Channel += srcDescPtr->strides.cStride; + dstPtrChannel += dstDescPtr->strides.cStride; + } + } + } + + return RPP_SUCCESS; +} diff --git a/src/modules/cpu/kernel/bitwise_or.hpp b/src/modules/cpu/kernel/bitwise_or.hpp new file mode 100644 index 000000000..40803e933 --- /dev/null +++ b/src/modules/cpu/kernel/bitwise_or.hpp @@ -0,0 +1,965 @@ +/* +MIT License + +Copyright (c) 2019 - 2024 Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software OR associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, OR/or sell +copies of the Software, OR to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice OR this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "rppdefs.h" +#include "rpp_cpu_simd.hpp" +#include "rpp_cpu_common.hpp" + +RppStatus bitwise_or_u8_u8_host_tensor(Rpp8u *srcPtr1, + Rpp8u *srcPtr2, + RpptDescPtr srcDescPtr, + Rpp8u *dstPtr, + RpptDescPtr dstDescPtr, + RpptROIPtr roiTensorPtrSrc, + RpptRoiType roiType, + RppLayoutParams layoutParams, + rpp::Handle& Handle) +{ + RpptROI roiDefault = {0, 0, (Rpp32s)srcDescPtr->w, (Rpp32s)srcDescPtr->h}; + Rpp32u numThreads = Handle.GetNumThreads(); + + omp_set_dynamic(0); +#pragma omp parallel for num_threads(numThreads) + for(int batchCount = 0; batchCount < dstDescPtr->n; batchCount++) + { + RpptROI roi; + RpptROIPtr roiPtrInput = &roiTensorPtrSrc[batchCount]; + compute_roi_validation_host(roiPtrInput, &roi, &roiDefault, roiType); + + Rpp8u *srcPtr1Image, *srcPtr2Image, *dstPtrImage; + srcPtr1Image = srcPtr1 + batchCount * srcDescPtr->strides.nStride; + srcPtr2Image = srcPtr2 + batchCount * srcDescPtr->strides.nStride; + dstPtrImage = dstPtr + batchCount * dstDescPtr->strides.nStride; + + Rpp32u bufferLength = roi.xywhROI.roiWidth * layoutParams.bufferMultiplier; + + Rpp8u *srcPtr1Channel, *srcPtr2Channel, *dstPtrChannel; + srcPtr1Channel = srcPtr1Image + (roi.xywhROI.xy.y * srcDescPtr->strides.hStride) + (roi.xywhROI.xy.x * layoutParams.bufferMultiplier); + srcPtr2Channel = srcPtr2Image + (roi.xywhROI.xy.y * srcDescPtr->strides.hStride) + (roi.xywhROI.xy.x * layoutParams.bufferMultiplier); + dstPtrChannel = dstPtrImage; + + Rpp32u alignedLength = (bufferLength / 48) * 48; + Rpp32u vectorIncrement = 48; + Rpp32u vectorIncrementPerChannel = 16; + + // Bitwise OR with fused output-layout toggle (NHWC -> NCHW) + if ((srcDescPtr->c == 3) && (srcDescPtr->layout == RpptLayout::NHWC) && (dstDescPtr->layout == RpptLayout::NCHW)) + { + Rpp8u *srcPtr1Row, *srcPtr2Row, *dstPtrRowR, *dstPtrRowG, *dstPtrRowB; + srcPtr1Row = srcPtr1Channel; + srcPtr2Row = srcPtr2Channel; + dstPtrRowR = dstPtrChannel; + dstPtrRowG = dstPtrRowR + dstDescPtr->strides.cStride; + dstPtrRowB = dstPtrRowG + dstDescPtr->strides.cStride; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp8u *srcPtr1Temp, *srcPtr2Temp, *dstPtrTempR, *dstPtrTempG, *dstPtrTempB; + srcPtr1Temp = srcPtr1Row; + srcPtr2Temp = srcPtr2Row; + dstPtrTempR = dstPtrRowR; + dstPtrTempG = dstPtrRowG; + dstPtrTempB = dstPtrRowB; + + int vectorLoopCount = 0; + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrement) + { + __m128i p1[3], p2[3]; + + rpp_simd_load(rpp_load48_u8pkd3_to_u8pln3, srcPtr1Temp, p1); // simd loads + rpp_simd_load(rpp_load48_u8pkd3_to_u8pln3, srcPtr2Temp, p2); // simd loads + p1[0] = _mm_or_si128(p1[0], p2[0]); // bitwise_or computation + p1[1] = _mm_or_si128(p1[1], p2[1]); // bitwise_or computation + p1[2] = _mm_or_si128(p1[2], p2[2]); // bitwise_or computation + rpp_simd_store(rpp_store48_u8pln3_to_u8pln3, dstPtrTempR, dstPtrTempG, dstPtrTempB, p1); // simd stores + + srcPtr1Temp += vectorIncrement; + srcPtr2Temp += vectorIncrement; + dstPtrTempR += vectorIncrementPerChannel; + dstPtrTempG += vectorIncrementPerChannel; + dstPtrTempB += vectorIncrementPerChannel; + } + + for (; vectorLoopCount < bufferLength; vectorLoopCount += 3) + { + *dstPtrTempR++ = srcPtr1Temp[0] | srcPtr2Temp[0]; + *dstPtrTempG++ = srcPtr1Temp[1] | srcPtr2Temp[1]; + *dstPtrTempB++ = srcPtr1Temp[2] | srcPtr2Temp[2]; + + srcPtr1Temp += 3; + srcPtr2Temp += 3; + } + + srcPtr1Row += srcDescPtr->strides.hStride; + srcPtr2Row += srcDescPtr->strides.hStride; + dstPtrRowR += dstDescPtr->strides.hStride; + dstPtrRowG += dstDescPtr->strides.hStride; + dstPtrRowB += dstDescPtr->strides.hStride; + } + } + + // Bitwise OR with fused output-layout toggle (NCHW -> NHWC) + else if ((srcDescPtr->c == 3) && (srcDescPtr->layout == RpptLayout::NCHW) && (dstDescPtr->layout == RpptLayout::NHWC)) + { + Rpp8u *srcPtr1RowR, *srcPtr1RowG, *srcPtr1RowB, *srcPtr2RowR, *srcPtr2RowG, *srcPtr2RowB, *dstPtrRow; + srcPtr1RowR = srcPtr1Channel; + srcPtr1RowG = srcPtr1RowR + srcDescPtr->strides.cStride; + srcPtr1RowB = srcPtr1RowG + srcDescPtr->strides.cStride; + srcPtr2RowR = srcPtr2Channel; + srcPtr2RowG = srcPtr2RowR + srcDescPtr->strides.cStride; + srcPtr2RowB = srcPtr2RowG + srcDescPtr->strides.cStride; + dstPtrRow = dstPtrChannel; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp8u *srcPtr1TempR, *srcPtr1TempG, *srcPtr1TempB, *srcPtr2TempR, *srcPtr2TempG, *srcPtr2TempB, *dstPtrTemp; + srcPtr1TempR = srcPtr1RowR; + srcPtr1TempG = srcPtr1RowG; + srcPtr1TempB = srcPtr1RowB; + srcPtr2TempR = srcPtr2RowR; + srcPtr2TempG = srcPtr2RowG; + srcPtr2TempB = srcPtr2RowB; + dstPtrTemp = dstPtrRow; + + int vectorLoopCount = 0; + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrementPerChannel) + { + __m128i p1[3], p2[3]; + + rpp_simd_load(rpp_load48_u8pln3_to_u8pln3, srcPtr1TempR, srcPtr1TempG, srcPtr1TempB, p1); // simd loads + rpp_simd_load(rpp_load48_u8pln3_to_u8pln3, srcPtr2TempR, srcPtr2TempG, srcPtr2TempB, p2); // simd loads + p1[0] = _mm_or_si128(p1[0], p2[0]); // bitwise_or computation + p1[1] = _mm_or_si128(p1[1], p2[1]); // bitwise_or computation + p1[2] = _mm_or_si128(p1[2], p2[2]); // bitwise_or computation + rpp_simd_store(rpp_store48_u8pln3_to_u8pkd3, dstPtrTemp, p1); // simd stores + + srcPtr1TempR += vectorIncrementPerChannel; + srcPtr1TempG += vectorIncrementPerChannel; + srcPtr1TempB += vectorIncrementPerChannel; + srcPtr2TempR += vectorIncrementPerChannel; + srcPtr2TempG += vectorIncrementPerChannel; + srcPtr2TempB += vectorIncrementPerChannel; + dstPtrTemp += vectorIncrement; + } + + for (; vectorLoopCount < bufferLength; vectorLoopCount++) + { + dstPtrTemp[0] = *srcPtr1TempR | *srcPtr2TempR; + dstPtrTemp[1] = *srcPtr1TempG | *srcPtr2TempG; + dstPtrTemp[2] = *srcPtr1TempB | *srcPtr2TempB; + + srcPtr1TempR++; + srcPtr1TempG++; + srcPtr1TempB++; + srcPtr2TempR++; + srcPtr2TempG++; + srcPtr2TempB++; + dstPtrTemp += 3; + } + + srcPtr1RowR += srcDescPtr->strides.hStride; + srcPtr1RowG += srcDescPtr->strides.hStride; + srcPtr1RowB += srcDescPtr->strides.hStride; + srcPtr2RowR += srcDescPtr->strides.hStride; + srcPtr2RowG += srcDescPtr->strides.hStride; + srcPtr2RowB += srcDescPtr->strides.hStride; + dstPtrRow += dstDescPtr->strides.hStride; + } + } + + // Bitwise OR without fused output-layout toggle (NHWC -> NHWC or NCHW -> NCHW) + else + { + alignedLength = bufferLength & ~15; + + for(int c = 0; c < layoutParams.channelParam; c++) + { + Rpp8u *srcPtr1Row, *srcPtr2Row, *dstPtrRow; + srcPtr1Row = srcPtr1Channel; + srcPtr2Row = srcPtr2Channel; + dstPtrRow = dstPtrChannel; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp8u *srcPtr1Temp, *srcPtr2Temp, *dstPtrTemp; + srcPtr1Temp = srcPtr1Row; + srcPtr2Temp = srcPtr2Row; + dstPtrTemp = dstPtrRow; + + int vectorLoopCount = 0; + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrementPerChannel) + { + __m128i p1, p2; + + p1 = _mm_loadu_si128((__m128i *)srcPtr1Temp); // simd loads + p2 = _mm_loadu_si128((__m128i *)srcPtr2Temp); // simd loads + p1 = _mm_or_si128(p1, p2); // bitwise_or computation + _mm_storeu_si128((__m128i *)dstPtrTemp, p1); // simd stores + + srcPtr1Temp += vectorIncrementPerChannel; + srcPtr2Temp += vectorIncrementPerChannel; + dstPtrTemp += vectorIncrementPerChannel; + } + + for (; vectorLoopCount < bufferLength; vectorLoopCount++) + { + *dstPtrTemp++ = *srcPtr1Temp | *srcPtr2Temp; + + srcPtr1Temp++; + srcPtr2Temp++; + } + + srcPtr1Row += srcDescPtr->strides.hStride; + srcPtr2Row += srcDescPtr->strides.hStride; + dstPtrRow += dstDescPtr->strides.hStride; + } + + srcPtr1Channel += srcDescPtr->strides.cStride; + srcPtr2Channel += srcDescPtr->strides.cStride; + dstPtrChannel += dstDescPtr->strides.cStride; + } + } + } + + return RPP_SUCCESS; +} + +/* BitwiseOR is logical operation only on U8/I8 types. + For a Rpp32f precision image (pixel values from 0-1), the BitwiseOR is applied on a 0-255 + range-translated approximation, of the original 0-1 decimal-range image. + Link: https://stackoverflow.com/questions/1723575/how-to-perform-a-bitwise-operation-on-floating-point-numbers */ +RppStatus bitwise_or_f32_f32_host_tensor(Rpp32f *srcPtr1, + Rpp32f *srcPtr2, + RpptDescPtr srcDescPtr, + Rpp32f *dstPtr, + RpptDescPtr dstDescPtr, + RpptROIPtr roiTensorPtrSrc, + RpptRoiType roiType, + RppLayoutParams layoutParams, + rpp::Handle& Handle) +{ + RpptROI roiDefault = {0, 0, (Rpp32s)srcDescPtr->w, (Rpp32s)srcDescPtr->h}; + Rpp32u numThreads = Handle.GetNumThreads(); + + omp_set_dynamic(0); +#pragma omp parallel for num_threads(numThreads) + for(int batchCount = 0; batchCount < dstDescPtr->n; batchCount++) + { + RpptROI roi; + RpptROIPtr roiPtrInput = &roiTensorPtrSrc[batchCount]; + compute_roi_validation_host(roiPtrInput, &roi, &roiDefault, roiType); + + Rpp32f *srcPtr1Image, *srcPtr2Image, *dstPtrImage; + srcPtr1Image = srcPtr1 + batchCount * srcDescPtr->strides.nStride; + srcPtr2Image = srcPtr2 + batchCount * srcDescPtr->strides.nStride; + dstPtrImage = dstPtr + batchCount * dstDescPtr->strides.nStride; + + Rpp32u bufferLength = roi.xywhROI.roiWidth * layoutParams.bufferMultiplier; + + Rpp32f *srcPtr1Channel, *srcPtr2Channel, *dstPtrChannel; + srcPtr1Channel = srcPtr1Image + (roi.xywhROI.xy.y * srcDescPtr->strides.hStride) + (roi.xywhROI.xy.x * layoutParams.bufferMultiplier); + srcPtr2Channel = srcPtr2Image + (roi.xywhROI.xy.y * srcDescPtr->strides.hStride) + (roi.xywhROI.xy.x * layoutParams.bufferMultiplier); + dstPtrChannel = dstPtrImage; + +#if __AVX2__ + Rpp32u alignedLength = (bufferLength / 24) * 24; + Rpp32u vectorIncrement = 24; + Rpp32u vectorIncrementPerChannel = 8; +#endif + + // Bitwise OR with fused output-layout toggle (NHWC -> NCHW) + if ((srcDescPtr->c == 3) && (srcDescPtr->layout == RpptLayout::NHWC) && (dstDescPtr->layout == RpptLayout::NCHW)) + { + Rpp32f *srcPtr1Row, *srcPtr2Row, *dstPtrRowR, *dstPtrRowG, *dstPtrRowB; + srcPtr1Row = srcPtr1Channel; + srcPtr2Row = srcPtr2Channel; + dstPtrRowR = dstPtrChannel; + dstPtrRowG = dstPtrRowR + dstDescPtr->strides.cStride; + dstPtrRowB = dstPtrRowG + dstDescPtr->strides.cStride; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp32f *srcPtr1Temp, *srcPtr2Temp, *dstPtrTempR, *dstPtrTempG, *dstPtrTempB; + srcPtr1Temp = srcPtr1Row; + srcPtr2Temp = srcPtr2Row; + dstPtrTempR = dstPtrRowR; + dstPtrTempG = dstPtrRowG; + dstPtrTempB = dstPtrRowB; + + int vectorLoopCount = 0; +#if __AVX2__ + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrement) + { + __m256 p1[3], p2[3]; + + rpp_simd_load(rpp_load24_f32pkd3_to_f32pln3_avx, srcPtr1Temp, p1); // simd loads + rpp_simd_load(rpp_load24_f32pkd3_to_f32pln3_avx, srcPtr2Temp, p2); // simd loads + p1[0] = _mm256_cvtepi32_ps(_mm256_or_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[0], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[0], avx_p255)))); // bitwise_or computation + p1[1] = _mm256_cvtepi32_ps(_mm256_or_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[1], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[1], avx_p255)))); // bitwise_or computation + p1[2] = _mm256_cvtepi32_ps(_mm256_or_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[2], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[2], avx_p255)))); // bitwise_or computation + p1[0] = _mm256_mul_ps(p1[0], avx_p1op255); + p1[1] = _mm256_mul_ps(p1[1], avx_p1op255); + p1[2] = _mm256_mul_ps(p1[2], avx_p1op255); + rpp_simd_store(rpp_store24_f32pln3_to_f32pln3_avx, dstPtrTempR, dstPtrTempG, dstPtrTempB, p1); // simd stores + + srcPtr1Temp += vectorIncrement; + srcPtr2Temp += vectorIncrement; + dstPtrTempR += vectorIncrementPerChannel; + dstPtrTempG += vectorIncrementPerChannel; + dstPtrTempB += vectorIncrementPerChannel; + } +#endif + for (; vectorLoopCount < bufferLength; vectorLoopCount += 3) + { + *dstPtrTempR++ = RPPPIXELCHECKF32((float)((uint)(srcPtr1Temp[0] * 255) | (uint)(srcPtr2Temp[0] * 255)) / 255); + *dstPtrTempG++ = RPPPIXELCHECKF32((float)((uint)(srcPtr1Temp[1] * 255) | (uint)(srcPtr2Temp[1] * 255)) / 255); + *dstPtrTempB++ = RPPPIXELCHECKF32((float)((uint)(srcPtr1Temp[2] * 255) | (uint)(srcPtr2Temp[2] * 255)) / 255); + + srcPtr1Temp += 3; + srcPtr2Temp += 3; + } + + srcPtr1Row += srcDescPtr->strides.hStride; + srcPtr2Row += srcDescPtr->strides.hStride; + dstPtrRowR += dstDescPtr->strides.hStride; + dstPtrRowG += dstDescPtr->strides.hStride; + dstPtrRowB += dstDescPtr->strides.hStride; + } + } + + // Bitwise OR with fused output-layout toggle (NCHW -> NHWC) + else if ((srcDescPtr->c == 3) && (srcDescPtr->layout == RpptLayout::NCHW) && (dstDescPtr->layout == RpptLayout::NHWC)) + { + Rpp32f *srcPtr1RowR, *srcPtr1RowG, *srcPtr1RowB, *srcPtr2RowR, *srcPtr2RowG, *srcPtr2RowB, *dstPtrRow; + srcPtr1RowR = srcPtr1Channel; + srcPtr1RowG = srcPtr1RowR + srcDescPtr->strides.cStride; + srcPtr1RowB = srcPtr1RowG + srcDescPtr->strides.cStride; + srcPtr2RowR = srcPtr2Channel; + srcPtr2RowG = srcPtr2RowR + srcDescPtr->strides.cStride; + srcPtr2RowB = srcPtr2RowG + srcDescPtr->strides.cStride; + dstPtrRow = dstPtrChannel; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp32f *srcPtr1TempR, *srcPtr1TempG, *srcPtr1TempB, *srcPtr2TempR, *srcPtr2TempG, *srcPtr2TempB, *dstPtrTemp; + srcPtr1TempR = srcPtr1RowR; + srcPtr1TempG = srcPtr1RowG; + srcPtr1TempB = srcPtr1RowB; + srcPtr2TempR = srcPtr2RowR; + srcPtr2TempG = srcPtr2RowG; + srcPtr2TempB = srcPtr2RowB; + dstPtrTemp = dstPtrRow; + + int vectorLoopCount = 0; +#if __AVX2__ + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrementPerChannel) + { + __m256 p1[3], p2[3]; + + rpp_simd_load(rpp_load24_f32pln3_to_f32pln3_avx, srcPtr1TempR, srcPtr1TempG, srcPtr1TempB, p1); // simd loads + rpp_simd_load(rpp_load24_f32pln3_to_f32pln3_avx, srcPtr2TempR, srcPtr2TempG, srcPtr2TempB, p2); // simd loads + p1[0] = _mm256_cvtepi32_ps(_mm256_or_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[0], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[0], avx_p255)))); // bitwise_or computation + p1[1] = _mm256_cvtepi32_ps(_mm256_or_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[1], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[1], avx_p255)))); // bitwise_or computation + p1[2] = _mm256_cvtepi32_ps(_mm256_or_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[2], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[2], avx_p255)))); // bitwise_or computation + p1[0] = _mm256_mul_ps(p1[0], avx_p1op255); + p1[1] = _mm256_mul_ps(p1[1], avx_p1op255); + p1[2] = _mm256_mul_ps(p1[2], avx_p1op255); + rpp_simd_store(rpp_store24_f32pln3_to_f32pkd3_avx, dstPtrTemp, p1); // simd stores + + srcPtr1TempR += vectorIncrementPerChannel; + srcPtr1TempG += vectorIncrementPerChannel; + srcPtr1TempB += vectorIncrementPerChannel; + srcPtr2TempR += vectorIncrementPerChannel; + srcPtr2TempG += vectorIncrementPerChannel; + srcPtr2TempB += vectorIncrementPerChannel; + dstPtrTemp += vectorIncrement; + } +#endif + for (; vectorLoopCount < bufferLength; vectorLoopCount++) + { + dstPtrTemp[0] = RPPPIXELCHECKF32((float)((uint)(*srcPtr1TempR * 255) | (uint)(*srcPtr2TempR * 255)) / 255); + dstPtrTemp[1] = RPPPIXELCHECKF32((float)((uint)(*srcPtr1TempG * 255) | (uint)(*srcPtr2TempG * 255)) / 255); + dstPtrTemp[2] = RPPPIXELCHECKF32((float)((uint)(*srcPtr1TempB * 255) | (uint)(*srcPtr2TempB * 255)) / 255); + + srcPtr1TempR++; + srcPtr1TempG++; + srcPtr1TempB++; + srcPtr2TempR++; + srcPtr2TempG++; + srcPtr2TempB++; + dstPtrTemp += 3; + } + + srcPtr1RowR += srcDescPtr->strides.hStride; + srcPtr1RowG += srcDescPtr->strides.hStride; + srcPtr1RowB += srcDescPtr->strides.hStride; + srcPtr2RowR += srcDescPtr->strides.hStride; + srcPtr2RowG += srcDescPtr->strides.hStride; + srcPtr2RowB += srcDescPtr->strides.hStride; + dstPtrRow += dstDescPtr->strides.hStride; + } + } + + // Bitwise OR without fused output-layout toggle (NHWC -> NHWC or NCHW -> NCHW) + else + { +#if __AVX2__ + alignedLength = bufferLength & ~7; +#endif + + for(int c = 0; c < layoutParams.channelParam; c++) + { + Rpp32f *srcPtr1Row, *srcPtr2Row, *dstPtrRow; + srcPtr1Row = srcPtr1Channel; + srcPtr2Row = srcPtr2Channel; + dstPtrRow = dstPtrChannel; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp32f *srcPtr1Temp, *srcPtr2Temp, *dstPtrTemp; + srcPtr1Temp = srcPtr1Row; + srcPtr2Temp = srcPtr2Row; + dstPtrTemp = dstPtrRow; + + int vectorLoopCount = 0; +#if __AVX2__ + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrementPerChannel) + { + __m256 p1[1], p2[1]; + + rpp_simd_load(rpp_load8_f32_to_f32_avx, srcPtr1Temp, p1); // simd loads + rpp_simd_load(rpp_load8_f32_to_f32_avx, srcPtr2Temp, p2); // simd loads + p1[0] = _mm256_cvtepi32_ps(_mm256_or_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[0], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[0], avx_p255)))); // bitwise_or computation + p1[0] = _mm256_mul_ps(p1[0], avx_p1op255); + rpp_simd_store(rpp_store8_f32_to_f32_avx, dstPtrTemp, p1); // simd stores + + srcPtr1Temp += vectorIncrementPerChannel; + srcPtr2Temp += vectorIncrementPerChannel; + dstPtrTemp += vectorIncrementPerChannel; + } +#endif + for (; vectorLoopCount < bufferLength; vectorLoopCount++) + { + *dstPtrTemp++ = RPPPIXELCHECKF32((float)((uint)(*srcPtr1Temp * 255) | (uint)(*srcPtr2Temp * 255)) / 255); + + srcPtr1Temp++; + srcPtr2Temp++; + } + + srcPtr1Row += srcDescPtr->strides.hStride; + srcPtr2Row += srcDescPtr->strides.hStride; + dstPtrRow += dstDescPtr->strides.hStride; + } + + srcPtr1Channel += srcDescPtr->strides.cStride; + srcPtr2Channel += srcDescPtr->strides.cStride; + dstPtrChannel += dstDescPtr->strides.cStride; + } + } + } + + return RPP_SUCCESS; +} + +RppStatus bitwise_or_f16_f16_host_tensor(Rpp16f *srcPtr1, + Rpp16f *srcPtr2, + RpptDescPtr srcDescPtr, + Rpp16f *dstPtr, + RpptDescPtr dstDescPtr, + RpptROIPtr roiTensorPtrSrc, + RpptRoiType roiType, + RppLayoutParams layoutParams, + rpp::Handle& Handle) +{ + RpptROI roiDefault = {0, 0, (Rpp32s)srcDescPtr->w, (Rpp32s)srcDescPtr->h}; + Rpp32u numThreads = Handle.GetNumThreads(); + + omp_set_dynamic(0); +#pragma omp parallel for num_threads(numThreads) + for(int batchCount = 0; batchCount < dstDescPtr->n; batchCount++) + { + RpptROI roi; + RpptROIPtr roiPtrInput = &roiTensorPtrSrc[batchCount]; + compute_roi_validation_host(roiPtrInput, &roi, &roiDefault, roiType); + + Rpp16f *srcPtr1Image, *srcPtr2Image, *dstPtrImage; + srcPtr1Image = srcPtr1 + batchCount * srcDescPtr->strides.nStride; + srcPtr2Image = srcPtr2 + batchCount * srcDescPtr->strides.nStride; + dstPtrImage = dstPtr + batchCount * dstDescPtr->strides.nStride; + + Rpp32u bufferLength = roi.xywhROI.roiWidth * layoutParams.bufferMultiplier; + + Rpp16f *srcPtr1Channel, *srcPtr2Channel, *dstPtrChannel; + srcPtr1Channel = srcPtr1Image + (roi.xywhROI.xy.y * srcDescPtr->strides.hStride) + (roi.xywhROI.xy.x * layoutParams.bufferMultiplier); + srcPtr2Channel = srcPtr2Image + (roi.xywhROI.xy.y * srcDescPtr->strides.hStride) + (roi.xywhROI.xy.x * layoutParams.bufferMultiplier); + dstPtrChannel = dstPtrImage; + +#if __AVX2__ + Rpp32u alignedLength = (bufferLength / 24) * 24; + Rpp32u vectorIncrement = 24; + Rpp32u vectorIncrementPerChannel = 8; +#endif + + // Bitwise OR with fused output-layout toggle (NHWC -> NCHW) + if ((srcDescPtr->c == 3) && (srcDescPtr->layout == RpptLayout::NHWC) && (dstDescPtr->layout == RpptLayout::NCHW)) + { + Rpp16f *srcPtr1Row, *srcPtr2Row, *dstPtrRowR, *dstPtrRowG, *dstPtrRowB; + srcPtr1Row = srcPtr1Channel; + srcPtr2Row = srcPtr2Channel; + dstPtrRowR = dstPtrChannel; + dstPtrRowG = dstPtrRowR + dstDescPtr->strides.cStride; + dstPtrRowB = dstPtrRowG + dstDescPtr->strides.cStride; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp16f *srcPtr1Temp, *srcPtr2Temp, *dstPtrTempR, *dstPtrTempG, *dstPtrTempB; + srcPtr1Temp = srcPtr1Row; + srcPtr2Temp = srcPtr2Row; + dstPtrTempR = dstPtrRowR; + dstPtrTempG = dstPtrRowG; + dstPtrTempB = dstPtrRowB; + + int vectorLoopCount = 0; +#if __AVX2__ + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrement) + { + Rpp32f srcPtr1Temp_ps[24], srcPtr2Temp_ps[24]; + + for(int cnt = 0; cnt < vectorIncrement; cnt++) + { + srcPtr1Temp_ps[cnt] = static_cast(srcPtr1Temp[cnt]); + srcPtr2Temp_ps[cnt] = static_cast(srcPtr2Temp[cnt]); + } + + __m256 p1[3], p2[3]; + + rpp_simd_load(rpp_load24_f32pkd3_to_f32pln3_avx, srcPtr1Temp_ps, p1); // simd loads + rpp_simd_load(rpp_load24_f32pkd3_to_f32pln3_avx, srcPtr2Temp_ps, p2); // simd loads + p1[0] = _mm256_cvtepi32_ps(_mm256_or_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[0], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[0], avx_p255)))); // bitwise_or computation + p1[1] = _mm256_cvtepi32_ps(_mm256_or_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[1], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[1], avx_p255)))); // bitwise_or computation + p1[2] = _mm256_cvtepi32_ps(_mm256_or_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[2], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[2], avx_p255)))); // bitwise_or computation + p1[0] = _mm256_mul_ps(p1[0], avx_p1op255); + p1[1] = _mm256_mul_ps(p1[1], avx_p1op255); + p1[2] = _mm256_mul_ps(p1[2], avx_p1op255); + rpp_simd_store(rpp_store24_f32pln3_to_f16pln3_avx, dstPtrTempR, dstPtrTempG, dstPtrTempB, p1); // simd stores + + srcPtr1Temp += vectorIncrement; + srcPtr2Temp += vectorIncrement; + dstPtrTempR += vectorIncrementPerChannel; + dstPtrTempG += vectorIncrementPerChannel; + dstPtrTempB += vectorIncrementPerChannel; + } +#endif + for (; vectorLoopCount < bufferLength; vectorLoopCount += 3) + { + *dstPtrTempR++ = static_cast(RPPPIXELCHECKF32((float)((uint)(srcPtr1Temp[0] * 255) | (uint)(srcPtr2Temp[0] * 255)) / 255)); + *dstPtrTempG++ = static_cast(RPPPIXELCHECKF32((float)((uint)(srcPtr1Temp[1] * 255) | (uint)(srcPtr2Temp[1] * 255)) / 255)); + *dstPtrTempB++ = static_cast(RPPPIXELCHECKF32((float)((uint)(srcPtr1Temp[2] * 255) | (uint)(srcPtr2Temp[2] * 255)) / 255)); + + srcPtr1Temp += 3; + srcPtr2Temp += 3; + } + + srcPtr1Row += srcDescPtr->strides.hStride; + srcPtr2Row += srcDescPtr->strides.hStride; + dstPtrRowR += dstDescPtr->strides.hStride; + dstPtrRowG += dstDescPtr->strides.hStride; + dstPtrRowB += dstDescPtr->strides.hStride; + } + } + + // Bitwise OR with fused output-layout toggle (NCHW -> NHWC) + else if ((srcDescPtr->c == 3) && (srcDescPtr->layout == RpptLayout::NCHW) && (dstDescPtr->layout == RpptLayout::NHWC)) + { + Rpp16f *srcPtr1RowR, *srcPtr1RowG, *srcPtr1RowB, *srcPtr2RowR, *srcPtr2RowG, *srcPtr2RowB, *dstPtrRow; + srcPtr1RowR = srcPtr1Channel; + srcPtr1RowG = srcPtr1RowR + srcDescPtr->strides.cStride; + srcPtr1RowB = srcPtr1RowG + srcDescPtr->strides.cStride; + srcPtr2RowR = srcPtr2Channel; + srcPtr2RowG = srcPtr2RowR + srcDescPtr->strides.cStride; + srcPtr2RowB = srcPtr2RowG + srcDescPtr->strides.cStride; + dstPtrRow = dstPtrChannel; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp16f *srcPtr1TempR, *srcPtr1TempG, *srcPtr1TempB, *srcPtr2TempR, *srcPtr2TempG, *srcPtr2TempB, *dstPtrTemp; + srcPtr1TempR = srcPtr1RowR; + srcPtr1TempG = srcPtr1RowG; + srcPtr1TempB = srcPtr1RowB; + srcPtr2TempR = srcPtr2RowR; + srcPtr2TempG = srcPtr2RowG; + srcPtr2TempB = srcPtr2RowB; + dstPtrTemp = dstPtrRow; + + int vectorLoopCount = 0; +#if __AVX2__ + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrementPerChannel) + { + Rpp32f srcPtr1Temp_ps[24], srcPtr2Temp_ps[24]; + + for(int cnt = 0; cnt < vectorIncrementPerChannel; cnt++) + { + srcPtr1Temp_ps[cnt] = static_cast(srcPtr1TempR[cnt]); + srcPtr1Temp_ps[cnt + 8] = static_cast(srcPtr1TempG[cnt]); + srcPtr1Temp_ps[cnt + 16] = static_cast(srcPtr1TempB[cnt]); + + srcPtr2Temp_ps[cnt] = static_cast(srcPtr2TempR[cnt]); + srcPtr2Temp_ps[cnt + 8] = static_cast(srcPtr2TempG[cnt]); + srcPtr2Temp_ps[cnt + 16] = static_cast(srcPtr2TempB[cnt]); + } + + __m256 p1[4], p2[4]; + + rpp_simd_load(rpp_load24_f32pln3_to_f32pln3_avx, srcPtr1Temp_ps, srcPtr1Temp_ps + 8, srcPtr1Temp_ps + 16, p1); // simd loads + rpp_simd_load(rpp_load24_f32pln3_to_f32pln3_avx, srcPtr2Temp_ps, srcPtr2Temp_ps + 8, srcPtr2Temp_ps + 16, p2); // simd loads + p1[0] = _mm256_cvtepi32_ps(_mm256_or_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[0], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[0], avx_p255)))); // bitwise_or computation + p1[1] = _mm256_cvtepi32_ps(_mm256_or_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[1], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[1], avx_p255)))); // bitwise_or computation + p1[2] = _mm256_cvtepi32_ps(_mm256_or_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[2], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[2], avx_p255)))); // bitwise_or computation + p1[0] = _mm256_mul_ps(p1[0], avx_p1op255); + p1[1] = _mm256_mul_ps(p1[1], avx_p1op255); + p1[2] = _mm256_mul_ps(p1[2], avx_p1op255); + rpp_simd_store(rpp_store24_f32pln3_to_f16pkd3_avx, dstPtrTemp, p1); // simd stores + + srcPtr1TempR += vectorIncrementPerChannel; + srcPtr1TempG += vectorIncrementPerChannel; + srcPtr1TempB += vectorIncrementPerChannel; + srcPtr2TempR += vectorIncrementPerChannel; + srcPtr2TempG += vectorIncrementPerChannel; + srcPtr2TempB += vectorIncrementPerChannel; + dstPtrTemp += vectorIncrement; + } +#endif + for (; vectorLoopCount < bufferLength; vectorLoopCount++) + { + dstPtrTemp[0] = static_cast(RPPPIXELCHECKF32((float)((uint)(*srcPtr1TempR * 255) | (uint)(*srcPtr2TempR * 255)) / 255)); + dstPtrTemp[1] = static_cast(RPPPIXELCHECKF32((float)((uint)(*srcPtr1TempG * 255) | (uint)(*srcPtr2TempG * 255)) / 255)); + dstPtrTemp[2] = static_cast(RPPPIXELCHECKF32((float)((uint)(*srcPtr1TempB * 255) | (uint)(*srcPtr2TempB * 255)) / 255)); + + srcPtr1TempR++; + srcPtr1TempG++; + srcPtr1TempB++; + srcPtr2TempR++; + srcPtr2TempG++; + srcPtr2TempB++; + dstPtrTemp += 3; + } + + srcPtr1RowR += srcDescPtr->strides.hStride; + srcPtr1RowG += srcDescPtr->strides.hStride; + srcPtr1RowB += srcDescPtr->strides.hStride; + srcPtr2RowR += srcDescPtr->strides.hStride; + srcPtr2RowG += srcDescPtr->strides.hStride; + srcPtr2RowB += srcDescPtr->strides.hStride; + dstPtrRow += dstDescPtr->strides.hStride; + } + } + + // Bitwise OR without fused output-layout toggle (NHWC -> NHWC or NCHW -> NCHW) + else + { +#if __AVX2__ + alignedLength = bufferLength & ~7; +#endif + + for(int c = 0; c < layoutParams.channelParam; c++) + { + Rpp16f *srcPtr1Row, *srcPtr2Row, *dstPtrRow; + srcPtr1Row = srcPtr1Channel; + srcPtr2Row = srcPtr2Channel; + dstPtrRow = dstPtrChannel; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp16f *srcPtr1Temp, *srcPtr2Temp, *dstPtrTemp; + srcPtr1Temp = srcPtr1Row; + srcPtr2Temp = srcPtr2Row; + dstPtrTemp = dstPtrRow; + + int vectorLoopCount = 0; +#if __AVX2__ + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrementPerChannel) + { + Rpp32f srcPtr1Temp_ps[8], srcPtr2Temp_ps[8]; + + for(int cnt = 0; cnt < vectorIncrementPerChannel; cnt++) + { + srcPtr1Temp_ps[cnt] = static_cast(srcPtr1Temp[cnt]); + srcPtr2Temp_ps[cnt] = static_cast(srcPtr2Temp[cnt]); + } + + __m256 p1[1], p2[1]; + + rpp_simd_load(rpp_load8_f32_to_f32_avx, srcPtr1Temp_ps, p1); // simd loads + rpp_simd_load(rpp_load8_f32_to_f32_avx, srcPtr2Temp_ps, p2); // simd loads + p1[0] = _mm256_cvtepi32_ps(_mm256_or_si256(_mm256_cvttps_epi32(_mm256_mul_ps(p1[0], avx_p255)), _mm256_cvttps_epi32(_mm256_mul_ps(p2[0], avx_p255)))); // bitwise_or computation + p1[0] = _mm256_mul_ps(p1[0], avx_p1op255); + rpp_simd_store(rpp_store8_f32_to_f16_avx, dstPtrTemp, p1); // simd stores + + srcPtr1Temp += vectorIncrementPerChannel; + srcPtr2Temp += vectorIncrementPerChannel; + dstPtrTemp += vectorIncrementPerChannel; + } +#endif + for (; vectorLoopCount < bufferLength; vectorLoopCount++) + { + *dstPtrTemp++ = static_cast(RPPPIXELCHECKF32((float)((uint)(*srcPtr1Temp * 255) | (uint)(*srcPtr2Temp * 255)) / 255)); + + srcPtr1Temp++; + srcPtr2Temp++; + } + + srcPtr1Row += srcDescPtr->strides.hStride; + srcPtr2Row += srcDescPtr->strides.hStride; + dstPtrRow += dstDescPtr->strides.hStride; + } + + srcPtr1Channel += srcDescPtr->strides.cStride; + srcPtr2Channel += srcDescPtr->strides.cStride; + dstPtrChannel += dstDescPtr->strides.cStride; + } + } + } + + return RPP_SUCCESS; +} + +RppStatus bitwise_or_i8_i8_host_tensor(Rpp8s *srcPtr1, + Rpp8s *srcPtr2, + RpptDescPtr srcDescPtr, + Rpp8s *dstPtr, + RpptDescPtr dstDescPtr, + RpptROIPtr roiTensorPtrSrc, + RpptRoiType roiType, + RppLayoutParams layoutParams, + rpp::Handle& Handle) +{ + RpptROI roiDefault = {0, 0, (Rpp32s)srcDescPtr->w, (Rpp32s)srcDescPtr->h}; + Rpp32u numThreads = Handle.GetNumThreads(); + + omp_set_dynamic(0); +#pragma omp parallel for num_threads(numThreads) + for(int batchCount = 0; batchCount < dstDescPtr->n; batchCount++) + { + RpptROI roi; + RpptROIPtr roiPtrInput = &roiTensorPtrSrc[batchCount]; + compute_roi_validation_host(roiPtrInput, &roi, &roiDefault, roiType); + + Rpp8s *srcPtr1Image, *srcPtr2Image, *dstPtrImage; + srcPtr1Image = srcPtr1 + batchCount * srcDescPtr->strides.nStride; + srcPtr2Image = srcPtr2 + batchCount * srcDescPtr->strides.nStride; + dstPtrImage = dstPtr + batchCount * dstDescPtr->strides.nStride; + + Rpp32u bufferLength = roi.xywhROI.roiWidth * layoutParams.bufferMultiplier; + + Rpp8s *srcPtr1Channel, *srcPtr2Channel, *dstPtrChannel; + srcPtr1Channel = srcPtr1Image + (roi.xywhROI.xy.y * srcDescPtr->strides.hStride) + (roi.xywhROI.xy.x * layoutParams.bufferMultiplier); + srcPtr2Channel = srcPtr2Image + (roi.xywhROI.xy.y * srcDescPtr->strides.hStride) + (roi.xywhROI.xy.x * layoutParams.bufferMultiplier); + dstPtrChannel = dstPtrImage; + + Rpp32u alignedLength = (bufferLength / 48) * 48; + Rpp32u vectorIncrement = 48; + Rpp32u vectorIncrementPerChannel = 16; + + // Bitwise OR with fused output-layout toggle (NHWC -> NCHW) + if ((srcDescPtr->c == 3) && (srcDescPtr->layout == RpptLayout::NHWC) && (dstDescPtr->layout == RpptLayout::NCHW)) + { + Rpp8s *srcPtr1Row, *srcPtr2Row, *dstPtrRowR, *dstPtrRowG, *dstPtrRowB; + srcPtr1Row = srcPtr1Channel; + srcPtr2Row = srcPtr2Channel; + dstPtrRowR = dstPtrChannel; + dstPtrRowG = dstPtrRowR + dstDescPtr->strides.cStride; + dstPtrRowB = dstPtrRowG + dstDescPtr->strides.cStride; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp8s *srcPtr1Temp, *srcPtr2Temp, *dstPtrTempR, *dstPtrTempG, *dstPtrTempB; + srcPtr1Temp = srcPtr1Row; + srcPtr2Temp = srcPtr2Row; + dstPtrTempR = dstPtrRowR; + dstPtrTempG = dstPtrRowG; + dstPtrTempB = dstPtrRowB; + + int vectorLoopCount = 0; + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrement) + { + __m128i p1[3], p2[3]; + + rpp_simd_load(rpp_load48_i8pkd3_to_u8pln3, srcPtr1Temp, p1); // simd loads + rpp_simd_load(rpp_load48_i8pkd3_to_u8pln3, srcPtr2Temp, p2); // simd loads + p1[0] = _mm_or_si128(p1[0], p2[0]); // bitwise_or computation + p1[1] = _mm_or_si128(p1[1], p2[1]); // bitwise_or computation + p1[2] = _mm_or_si128(p1[2], p2[2]); // bitwise_or computation + rpp_simd_store(rpp_store48_u8pln3_to_i8pln3, dstPtrTempR, dstPtrTempG, dstPtrTempB, p1); // simd stores + + srcPtr1Temp += vectorIncrement; + srcPtr2Temp += vectorIncrement; + dstPtrTempR += vectorIncrementPerChannel; + dstPtrTempG += vectorIncrementPerChannel; + dstPtrTempB += vectorIncrementPerChannel; + } + + for (; vectorLoopCount < bufferLength; vectorLoopCount += 3) + { + *dstPtrTempR++ = static_cast(RPPPIXELCHECKI8(((srcPtr1Temp[0] + 128) | (srcPtr2Temp[0] + 128)) - 128)); + *dstPtrTempG++ = static_cast(RPPPIXELCHECKI8(((srcPtr1Temp[1] + 128) | (srcPtr2Temp[1] + 128)) - 128)); + *dstPtrTempB++ = static_cast(RPPPIXELCHECKI8(((srcPtr1Temp[2] + 128) | (srcPtr2Temp[2] + 128)) - 128)); + + srcPtr1Temp += 3; + srcPtr2Temp += 3; + } + + srcPtr1Row += srcDescPtr->strides.hStride; + srcPtr2Row += srcDescPtr->strides.hStride; + dstPtrRowR += dstDescPtr->strides.hStride; + dstPtrRowG += dstDescPtr->strides.hStride; + dstPtrRowB += dstDescPtr->strides.hStride; + } + } + + // Bitwise OR with fused output-layout toggle (NCHW -> NHWC) + else if ((srcDescPtr->c == 3) && (srcDescPtr->layout == RpptLayout::NCHW) && (dstDescPtr->layout == RpptLayout::NHWC)) + { + Rpp8s *srcPtr1RowR, *srcPtr1RowG, *srcPtr1RowB, *srcPtr2RowR, *srcPtr2RowG, *srcPtr2RowB, *dstPtrRow; + srcPtr1RowR = srcPtr1Channel; + srcPtr1RowG = srcPtr1RowR + srcDescPtr->strides.cStride; + srcPtr1RowB = srcPtr1RowG + srcDescPtr->strides.cStride; + srcPtr2RowR = srcPtr2Channel; + srcPtr2RowG = srcPtr2RowR + srcDescPtr->strides.cStride; + srcPtr2RowB = srcPtr2RowG + srcDescPtr->strides.cStride; + dstPtrRow = dstPtrChannel; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp8s *srcPtr1TempR, *srcPtr1TempG, *srcPtr1TempB, *srcPtr2TempR, *srcPtr2TempG, *srcPtr2TempB, *dstPtrTemp; + srcPtr1TempR = srcPtr1RowR; + srcPtr1TempG = srcPtr1RowG; + srcPtr1TempB = srcPtr1RowB; + srcPtr2TempR = srcPtr2RowR; + srcPtr2TempG = srcPtr2RowG; + srcPtr2TempB = srcPtr2RowB; + dstPtrTemp = dstPtrRow; + + int vectorLoopCount = 0; + + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrementPerChannel) + { + __m128i p1[3], p2[3]; + + rpp_simd_load(rpp_load48_i8pln3_to_u8pln3, srcPtr1TempR, srcPtr1TempG, srcPtr1TempB, p1); // simd loads + rpp_simd_load(rpp_load48_i8pln3_to_u8pln3, srcPtr2TempR, srcPtr2TempG, srcPtr2TempB, p2); // simd loads + p1[0] = _mm_or_si128(p1[0], p2[0]); // bitwise_or computation + p1[1] = _mm_or_si128(p1[1], p2[1]); // bitwise_or computation + p1[2] = _mm_or_si128(p1[2], p2[2]); // bitwise_or computation + rpp_simd_store(rpp_store48_u8pln3_to_i8pkd3, dstPtrTemp, p1); // simd stores + + + srcPtr1TempR += vectorIncrementPerChannel; + srcPtr1TempG += vectorIncrementPerChannel; + srcPtr1TempB += vectorIncrementPerChannel; + srcPtr2TempR += vectorIncrementPerChannel; + srcPtr2TempG += vectorIncrementPerChannel; + srcPtr2TempB += vectorIncrementPerChannel; + dstPtrTemp += vectorIncrement; + } + for (; vectorLoopCount < bufferLength; vectorLoopCount++) + { + dstPtrTemp[0] = static_cast(RPPPIXELCHECKI8(((static_cast((*srcPtr1TempR + 128) | static_cast(*srcPtr2TempR + 128)))) - 128)); + dstPtrTemp[1] = static_cast(RPPPIXELCHECKI8(((static_cast((*srcPtr1TempG + 128) | static_cast(*srcPtr2TempG + 128)))) - 128)); + dstPtrTemp[2] = static_cast(RPPPIXELCHECKI8(((static_cast((*srcPtr1TempB + 128) | static_cast(*srcPtr2TempB + 128)))) - 128)); + + srcPtr1TempR++; + srcPtr1TempG++; + srcPtr1TempB++; + srcPtr2TempR++; + srcPtr2TempG++; + srcPtr2TempB++; + dstPtrTemp += 3; + } + + srcPtr1RowR += srcDescPtr->strides.hStride; + srcPtr1RowG += srcDescPtr->strides.hStride; + srcPtr1RowB += srcDescPtr->strides.hStride; + srcPtr2RowR += srcDescPtr->strides.hStride; + srcPtr2RowG += srcDescPtr->strides.hStride; + srcPtr2RowB += srcDescPtr->strides.hStride; + dstPtrRow += dstDescPtr->strides.hStride; + } + } + + // Bitwise OR without fused output-layout toggle (NHWC -> NHWC or NCHW -> NCHW) + else + { + alignedLength = bufferLength & ~15; + + for(int c = 0; c < layoutParams.channelParam; c++) + { + Rpp8s *srcPtr1Row, *srcPtr2Row, *dstPtrRow; + srcPtr1Row = srcPtr1Channel; + srcPtr2Row = srcPtr2Channel; + dstPtrRow = dstPtrChannel; + + for(int i = 0; i < roi.xywhROI.roiHeight; i++) + { + Rpp8s *srcPtr1Temp, *srcPtr2Temp, *dstPtrTemp; + srcPtr1Temp = srcPtr1Row; + srcPtr2Temp = srcPtr2Row; + dstPtrTemp = dstPtrRow; + + int vectorLoopCount = 0; + + for (; vectorLoopCount < alignedLength; vectorLoopCount += vectorIncrementPerChannel) + { + __m128i p1, p2; + + p1 = _mm_add_epi8(xmm_pxConvertI8, _mm_loadu_si128((__m128i *)srcPtr1Temp)); // simd loads + p2 = _mm_add_epi8(xmm_pxConvertI8, _mm_loadu_si128((__m128i *)srcPtr2Temp)); // simd loads + p1 = _mm_or_si128(p1, p2); // bitwise_or computation + _mm_storeu_si128((__m128i *)dstPtrTemp, _mm_sub_epi8(p1, xmm_pxConvertI8)); // simd stores + + srcPtr1Temp += vectorIncrementPerChannel; + srcPtr2Temp += vectorIncrementPerChannel; + dstPtrTemp += vectorIncrementPerChannel; + } + for (; vectorLoopCount < bufferLength; vectorLoopCount++) + { + *dstPtrTemp++ = static_cast(RPPPIXELCHECKI8(((static_cast((*srcPtr1Temp + 128) | static_cast(*srcPtr2Temp + 128)))) - 128)); + + srcPtr1Temp++; + srcPtr2Temp++; + } + + srcPtr1Row += srcDescPtr->strides.hStride; + srcPtr2Row += srcDescPtr->strides.hStride; + dstPtrRow += dstDescPtr->strides.hStride; + } + + srcPtr1Channel += srcDescPtr->strides.cStride; + srcPtr2Channel += srcDescPtr->strides.cStride; + dstPtrChannel += dstDescPtr->strides.cStride; + } + } + } + + return RPP_SUCCESS; +} diff --git a/src/modules/hip/hip_tensor_logical_operations.hpp b/src/modules/hip/hip_tensor_logical_operations.hpp new file mode 100644 index 000000000..636789246 --- /dev/null +++ b/src/modules/hip/hip_tensor_logical_operations.hpp @@ -0,0 +1,31 @@ +/* +MIT License + +Copyright (c) 2019 - 2024 Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef HIP_TENSOR_LOGICAL_OPERATIONS_HPP +#define HIP_TENSOR_LOGICAL_OPERATIONS_HPP + +#include "kernel/bitwise_and.hpp" +#include "kernel/bitwise_or.hpp" + +#endif // HIP_TENSOR_LOGICAL_OPERATIONS_HPP \ No newline at end of file diff --git a/src/modules/hip/kernel/bitwise_and.hpp b/src/modules/hip/kernel/bitwise_and.hpp new file mode 100644 index 000000000..ca9f30c11 --- /dev/null +++ b/src/modules/hip/kernel/bitwise_and.hpp @@ -0,0 +1,247 @@ +#include +#include "rpp_hip_common.hpp" + +/* BitwiseAND is logical operation only on U8/I8 types. + For a Rpp32f precision image (pixel values from 0-1), the BitwiseAND is applied on a 0-255 + range-translated approximation, of the original 0-1 decimal-range image. + Link: https://stackoverflow.com/questions/1723575/how-to-perform-a-bitwise-operation-on-floating-point-numbers */ +template +__device__ void bitwise_and_hip_compute(T *srcPtr, d_float8 *src1_f8, d_float8 *src2_f8, d_float8 *dst_f8) +{ + if constexpr ((std::is_same::value) || (std::is_same::value)) + { + rpp_hip_math_multiply8_const(src1_f8, src1_f8, (float4)255); + rpp_hip_math_multiply8_const(src2_f8, src2_f8, (float4)255); + rpp_hip_math_bitwiseAnd8(src1_f8, src2_f8, dst_f8); + rpp_hip_math_multiply8_const(dst_f8, dst_f8, (float4)ONE_OVER_255); + } + else if constexpr (std::is_same::value) + { + rpp_hip_math_add8_const(src1_f8, src1_f8, (float4)128); + rpp_hip_math_add8_const(src2_f8, src2_f8, (float4)128); + rpp_hip_math_bitwiseAnd8(src1_f8, src2_f8, dst_f8); + rpp_hip_math_subtract8_const(dst_f8, dst_f8, (float4)128); + } + else + rpp_hip_math_bitwiseAnd8(src1_f8, src2_f8, dst_f8); +} + +template +__global__ void bitwise_and_pkd_hip_tensor(T *srcPtr1, + T *srcPtr2, + uint2 srcStridesNH, + T *dstPtr, + uint2 dstStridesNH, + RpptROIPtr roiTensorPtrSrc) +{ + int id_x = (hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x) * 8; + int id_y = hipBlockIdx_y * hipBlockDim_y + hipThreadIdx_y; + int id_z = hipBlockIdx_z * hipBlockDim_z + hipThreadIdx_z; + + if ((id_y >= roiTensorPtrSrc[id_z].xywhROI.roiHeight) || (id_x >= roiTensorPtrSrc[id_z].xywhROI.roiWidth)) + { + return; + } + + uint srcIdx = (id_z * srcStridesNH.x) + ((id_y + roiTensorPtrSrc[id_z].xywhROI.xy.y) * srcStridesNH.y) + (id_x + roiTensorPtrSrc[id_z].xywhROI.xy.x) * 3; + uint dstIdx = (id_z * dstStridesNH.x) + (id_y * dstStridesNH.y) + id_x * 3; + + d_float24 src1_f24, src2_f24, dst_f24; + + rpp_hip_load24_pkd3_and_unpack_to_float24_pln3(srcPtr1 + srcIdx, &src1_f24); + rpp_hip_load24_pkd3_and_unpack_to_float24_pln3(srcPtr2 + srcIdx, &src2_f24); + bitwise_and_hip_compute(srcPtr1, &src1_f24.f8[0], &src2_f24.f8[0], &dst_f24.f8[0]); + bitwise_and_hip_compute(srcPtr1, &src1_f24.f8[1], &src2_f24.f8[1], &dst_f24.f8[1]); + bitwise_and_hip_compute(srcPtr1, &src1_f24.f8[2], &src2_f24.f8[2], &dst_f24.f8[2]); + rpp_hip_pack_float24_pln3_and_store24_pkd3(dstPtr + dstIdx, &dst_f24); +} + +template +__global__ void bitwise_and_pln_hip_tensor(T *srcPtr1, + T *srcPtr2, + uint3 srcStridesNCH, + T *dstPtr, + uint3 dstStridesNCH, + int channelsDst, + RpptROIPtr roiTensorPtrSrc) +{ + int id_x = (hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x) * 8; + int id_y = hipBlockIdx_y * hipBlockDim_y + hipThreadIdx_y; + int id_z = hipBlockIdx_z * hipBlockDim_z + hipThreadIdx_z; + + if ((id_y >= roiTensorPtrSrc[id_z].xywhROI.roiHeight) || (id_x >= roiTensorPtrSrc[id_z].xywhROI.roiWidth)) + { + return; + } + + uint srcIdx = (id_z * srcStridesNCH.x) + ((id_y + roiTensorPtrSrc[id_z].xywhROI.xy.y) * srcStridesNCH.z) + (id_x + roiTensorPtrSrc[id_z].xywhROI.xy.x); + uint dstIdx = (id_z * dstStridesNCH.x) + (id_y * dstStridesNCH.z) + id_x; + + d_float8 src1_f8, src2_f8, dst_f8; + + rpp_hip_load8_and_unpack_to_float8(srcPtr1 + srcIdx, &src1_f8); + rpp_hip_load8_and_unpack_to_float8(srcPtr2 + srcIdx, &src2_f8); + bitwise_and_hip_compute(srcPtr1, &src1_f8, &src2_f8, &dst_f8); + rpp_hip_pack_float8_and_store8(dstPtr + dstIdx, &dst_f8); + + if (channelsDst == 3) + { + srcIdx += srcStridesNCH.y; + dstIdx += dstStridesNCH.y; + + rpp_hip_load8_and_unpack_to_float8(srcPtr1 + srcIdx, &src1_f8); + rpp_hip_load8_and_unpack_to_float8(srcPtr2 + srcIdx, &src2_f8); + bitwise_and_hip_compute(srcPtr1, &src1_f8, &src2_f8, &dst_f8); + rpp_hip_pack_float8_and_store8(dstPtr + dstIdx, &dst_f8); + + srcIdx += srcStridesNCH.y; + dstIdx += dstStridesNCH.y; + + rpp_hip_load8_and_unpack_to_float8(srcPtr1 + srcIdx, &src1_f8); + rpp_hip_load8_and_unpack_to_float8(srcPtr2 + srcIdx, &src2_f8); + bitwise_and_hip_compute(srcPtr1, &src1_f8, &src2_f8, &dst_f8); + rpp_hip_pack_float8_and_store8(dstPtr + dstIdx, &dst_f8); + } +} + +template +__global__ void bitwise_and_pkd3_pln3_hip_tensor(T *srcPtr1, + T *srcPtr2, + uint2 srcStridesNH, + T *dstPtr, + uint3 dstStridesNCH, + RpptROIPtr roiTensorPtrSrc) +{ + int id_x = (hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x) * 8; + int id_y = hipBlockIdx_y * hipBlockDim_y + hipThreadIdx_y; + int id_z = hipBlockIdx_z * hipBlockDim_z + hipThreadIdx_z; + + if ((id_y >= roiTensorPtrSrc[id_z].xywhROI.roiHeight) || (id_x >= roiTensorPtrSrc[id_z].xywhROI.roiWidth)) + { + return; + } + + uint srcIdx = (id_z * srcStridesNH.x) + ((id_y + roiTensorPtrSrc[id_z].xywhROI.xy.y) * srcStridesNH.y) + ((id_x + roiTensorPtrSrc[id_z].xywhROI.xy.x) * 3); + uint dstIdx = (id_z * dstStridesNCH.x) + (id_y * dstStridesNCH.z) + id_x; + + d_float24 src1_f24, src2_f24, dst_f24; + + rpp_hip_load24_pkd3_and_unpack_to_float24_pln3(srcPtr1 + srcIdx, &src1_f24); + rpp_hip_load24_pkd3_and_unpack_to_float24_pln3(srcPtr2 + srcIdx, &src2_f24); + bitwise_and_hip_compute(srcPtr1, &src1_f24.f8[0], &src2_f24.f8[0], &dst_f24.f8[0]); + bitwise_and_hip_compute(srcPtr1, &src1_f24.f8[1], &src2_f24.f8[1], &dst_f24.f8[1]); + bitwise_and_hip_compute(srcPtr1, &src1_f24.f8[2], &src2_f24.f8[2], &dst_f24.f8[2]); + rpp_hip_pack_float24_pln3_and_store24_pln3(dstPtr + dstIdx, dstStridesNCH.y, &dst_f24); +} + +template +__global__ void bitwise_and_pln3_pkd3_hip_tensor(T *srcPtr1, + T *srcPtr2, + uint3 srcStridesNCH, + T *dstPtr, + uint2 dstStridesNH, + RpptROIPtr roiTensorPtrSrc) +{ + int id_x = (hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x) * 8; + int id_y = hipBlockIdx_y * hipBlockDim_y + hipThreadIdx_y; + int id_z = hipBlockIdx_z * hipBlockDim_z + hipThreadIdx_z; + + if ((id_y >= roiTensorPtrSrc[id_z].xywhROI.roiHeight) || (id_x >= roiTensorPtrSrc[id_z].xywhROI.roiWidth)) + { + return; + } + + uint srcIdx = (id_z * srcStridesNCH.x) + ((id_y + roiTensorPtrSrc[id_z].xywhROI.xy.y) * srcStridesNCH.z) + (id_x + roiTensorPtrSrc[id_z].xywhROI.xy.x); + uint dstIdx = (id_z * dstStridesNH.x) + (id_y * dstStridesNH.y) + id_x * 3; + + d_float24 src1_f24, src2_f24, dst_f24; + + rpp_hip_load24_pln3_and_unpack_to_float24_pkd3(srcPtr1 + srcIdx, srcStridesNCH.y, &src1_f24); + rpp_hip_load24_pln3_and_unpack_to_float24_pkd3(srcPtr2 + srcIdx, srcStridesNCH.y, &src2_f24); + bitwise_and_hip_compute(srcPtr1, &src1_f24.f8[0], &src2_f24.f8[0], &dst_f24.f8[0]); + bitwise_and_hip_compute(srcPtr1, &src1_f24.f8[1], &src2_f24.f8[1], &dst_f24.f8[1]); + bitwise_and_hip_compute(srcPtr1, &src1_f24.f8[2], &src2_f24.f8[2], &dst_f24.f8[2]); + rpp_hip_pack_float24_pkd3_and_store24_pkd3(dstPtr + dstIdx, &dst_f24); +} + +template +RppStatus hip_exec_bitwise_and_tensor(T *srcPtr1, + T *srcPtr2, + RpptDescPtr srcDescPtr, + T *dstPtr, + RpptDescPtr dstDescPtr, + RpptROIPtr roiTensorPtrSrc, + RpptRoiType roiType, + rpp::Handle& handle) +{ + if (roiType == RpptRoiType::LTRB) + hip_exec_roi_converison_ltrb_to_xywh(roiTensorPtrSrc, handle); + + int globalThreads_x = (dstDescPtr->w + 7) >> 3; + int globalThreads_y = dstDescPtr->h; + int globalThreads_z = handle.GetBatchSize(); + + if ((srcDescPtr->layout == RpptLayout::NHWC) && (dstDescPtr->layout == RpptLayout::NHWC)) + { + hipLaunchKernelGGL(bitwise_and_pkd_hip_tensor, + dim3(ceil((float)globalThreads_x/LOCAL_THREADS_X), ceil((float)globalThreads_y/LOCAL_THREADS_Y), ceil((float)globalThreads_z/LOCAL_THREADS_Z)), + dim3(LOCAL_THREADS_X, LOCAL_THREADS_Y, LOCAL_THREADS_Z), + 0, + handle.GetStream(), + srcPtr1, + srcPtr2, + make_uint2(srcDescPtr->strides.nStride, srcDescPtr->strides.hStride), + dstPtr, + make_uint2(dstDescPtr->strides.nStride, dstDescPtr->strides.hStride), + roiTensorPtrSrc); + } + else if ((srcDescPtr->layout == RpptLayout::NCHW) && (dstDescPtr->layout == RpptLayout::NCHW)) + { + hipLaunchKernelGGL(bitwise_and_pln_hip_tensor, + dim3(ceil((float)globalThreads_x/LOCAL_THREADS_X), ceil((float)globalThreads_y/LOCAL_THREADS_Y), ceil((float)globalThreads_z/LOCAL_THREADS_Z)), + dim3(LOCAL_THREADS_X, LOCAL_THREADS_Y, LOCAL_THREADS_Z), + 0, + handle.GetStream(), + srcPtr1, + srcPtr2, + make_uint3(srcDescPtr->strides.nStride, srcDescPtr->strides.cStride, srcDescPtr->strides.hStride), + dstPtr, + make_uint3(dstDescPtr->strides.nStride, dstDescPtr->strides.cStride, dstDescPtr->strides.hStride), + dstDescPtr->c, + roiTensorPtrSrc); + } + else if ((srcDescPtr->c == 3) && (dstDescPtr->c == 3)) + { + if ((srcDescPtr->layout == RpptLayout::NHWC) && (dstDescPtr->layout == RpptLayout::NCHW)) + { + hipLaunchKernelGGL(bitwise_and_pkd3_pln3_hip_tensor, + dim3(ceil((float)globalThreads_x/LOCAL_THREADS_X), ceil((float)globalThreads_y/LOCAL_THREADS_Y), ceil((float)globalThreads_z/LOCAL_THREADS_Z)), + dim3(LOCAL_THREADS_X, LOCAL_THREADS_Y, LOCAL_THREADS_Z), + 0, + handle.GetStream(), + srcPtr1, + srcPtr2, + make_uint2(srcDescPtr->strides.nStride, srcDescPtr->strides.hStride), + dstPtr, + make_uint3(dstDescPtr->strides.nStride, dstDescPtr->strides.cStride, dstDescPtr->strides.hStride), + roiTensorPtrSrc); + } + else if ((srcDescPtr->layout == RpptLayout::NCHW) && (dstDescPtr->layout == RpptLayout::NHWC)) + { + globalThreads_x = (srcDescPtr->strides.hStride + 7) >> 3; + hipLaunchKernelGGL(bitwise_and_pln3_pkd3_hip_tensor, + dim3(ceil((float)globalThreads_x/LOCAL_THREADS_X), ceil((float)globalThreads_y/LOCAL_THREADS_Y), ceil((float)globalThreads_z/LOCAL_THREADS_Z)), + dim3(LOCAL_THREADS_X, LOCAL_THREADS_Y, LOCAL_THREADS_Z), + 0, + handle.GetStream(), + srcPtr1, + srcPtr2, + make_uint3(srcDescPtr->strides.nStride, srcDescPtr->strides.cStride, srcDescPtr->strides.hStride), + dstPtr, + make_uint2(dstDescPtr->strides.nStride, dstDescPtr->strides.hStride), + roiTensorPtrSrc); + } + } + + return RPP_SUCCESS; +} \ No newline at end of file diff --git a/src/modules/hip/kernel/bitwise_or.hpp b/src/modules/hip/kernel/bitwise_or.hpp new file mode 100644 index 000000000..ab0c962ef --- /dev/null +++ b/src/modules/hip/kernel/bitwise_or.hpp @@ -0,0 +1,247 @@ +#include +#include "rpp_hip_common.hpp" + +/* BitwiseOR is logical operation only on U8/I8 types. + For a Rpp32f precision image (pixel values from 0-1), the BitwiseOR is applied on a 0-255 + range-translated approximation, of the original 0-1 decimal-range image. + Link: https://stackoverflow.com/questions/1723575/how-to-perform-a-bitwise-operation-on-floating-point-numbers */ +template +__device__ void bitwise_or_hip_compute(T *srcPtr, d_float8 *src1_f8, d_float8 *src2_f8, d_float8 *dst_f8) +{ + if constexpr ((std::is_same::value) || (std::is_same::value)) + { + rpp_hip_math_multiply8_const(src1_f8, src1_f8, (float4)255); + rpp_hip_math_multiply8_const(src2_f8, src2_f8, (float4)255); + rpp_hip_math_bitwiseOr8(src1_f8, src2_f8, dst_f8); + rpp_hip_math_multiply8_const(dst_f8, dst_f8, (float4)ONE_OVER_255); + } + else if constexpr (std::is_same::value) + { + rpp_hip_math_add8_const(src1_f8, src1_f8, (float4)128); + rpp_hip_math_add8_const(src2_f8, src2_f8, (float4)128); + rpp_hip_math_bitwiseOr8(src1_f8, src2_f8, dst_f8); + rpp_hip_math_subtract8_const(dst_f8, dst_f8, (float4)128); + } + else + rpp_hip_math_bitwiseOr8(src1_f8, src2_f8, dst_f8); +} + +template +__global__ void bitwise_or_pkd_hip_tensor(T *srcPtr1, + T *srcPtr2, + uint2 srcStridesNH, + T *dstPtr, + uint2 dstStridesNH, + RpptROIPtr roiTensorPtrSrc) +{ + int id_x = (hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x) * 8; + int id_y = hipBlockIdx_y * hipBlockDim_y + hipThreadIdx_y; + int id_z = hipBlockIdx_z * hipBlockDim_z + hipThreadIdx_z; + + if ((id_y >= roiTensorPtrSrc[id_z].xywhROI.roiHeight) || (id_x >= roiTensorPtrSrc[id_z].xywhROI.roiWidth)) + { + return; + } + + uint srcIdx = (id_z * srcStridesNH.x) + ((id_y + roiTensorPtrSrc[id_z].xywhROI.xy.y) * srcStridesNH.y) + (id_x + roiTensorPtrSrc[id_z].xywhROI.xy.x) * 3; + uint dstIdx = (id_z * dstStridesNH.x) + (id_y * dstStridesNH.y) + id_x * 3; + + d_float24 src1_f24, src2_f24, dst_f24; + + rpp_hip_load24_pkd3_and_unpack_to_float24_pln3(srcPtr1 + srcIdx, &src1_f24); + rpp_hip_load24_pkd3_and_unpack_to_float24_pln3(srcPtr2 + srcIdx, &src2_f24); + bitwise_or_hip_compute(srcPtr1, &src1_f24.f8[0], &src2_f24.f8[0], &dst_f24.f8[0]); + bitwise_or_hip_compute(srcPtr1, &src1_f24.f8[1], &src2_f24.f8[1], &dst_f24.f8[1]); + bitwise_or_hip_compute(srcPtr1, &src1_f24.f8[2], &src2_f24.f8[2], &dst_f24.f8[2]); + rpp_hip_pack_float24_pln3_and_store24_pkd3(dstPtr + dstIdx, &dst_f24); +} + +template +__global__ void bitwise_or_pln_hip_tensor(T *srcPtr1, + T *srcPtr2, + uint3 srcStridesNCH, + T *dstPtr, + uint3 dstStridesNCH, + int channelsDst, + RpptROIPtr roiTensorPtrSrc) +{ + int id_x = (hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x) * 8; + int id_y = hipBlockIdx_y * hipBlockDim_y + hipThreadIdx_y; + int id_z = hipBlockIdx_z * hipBlockDim_z + hipThreadIdx_z; + + if ((id_y >= roiTensorPtrSrc[id_z].xywhROI.roiHeight) || (id_x >= roiTensorPtrSrc[id_z].xywhROI.roiWidth)) + { + return; + } + + uint srcIdx = (id_z * srcStridesNCH.x) + ((id_y + roiTensorPtrSrc[id_z].xywhROI.xy.y) * srcStridesNCH.z) + (id_x + roiTensorPtrSrc[id_z].xywhROI.xy.x); + uint dstIdx = (id_z * dstStridesNCH.x) + (id_y * dstStridesNCH.z) + id_x; + + d_float8 src1_f8, src2_f8, dst_f8; + + rpp_hip_load8_and_unpack_to_float8(srcPtr1 + srcIdx, &src1_f8); + rpp_hip_load8_and_unpack_to_float8(srcPtr2 + srcIdx, &src2_f8); + bitwise_or_hip_compute(srcPtr1, &src1_f8, &src2_f8, &dst_f8); + rpp_hip_pack_float8_and_store8(dstPtr + dstIdx, &dst_f8); + + if (channelsDst == 3) + { + srcIdx += srcStridesNCH.y; + dstIdx += dstStridesNCH.y; + + rpp_hip_load8_and_unpack_to_float8(srcPtr1 + srcIdx, &src1_f8); + rpp_hip_load8_and_unpack_to_float8(srcPtr2 + srcIdx, &src2_f8); + bitwise_or_hip_compute(srcPtr1, &src1_f8, &src2_f8, &dst_f8); + rpp_hip_pack_float8_and_store8(dstPtr + dstIdx, &dst_f8); + + srcIdx += srcStridesNCH.y; + dstIdx += dstStridesNCH.y; + + rpp_hip_load8_and_unpack_to_float8(srcPtr1 + srcIdx, &src1_f8); + rpp_hip_load8_and_unpack_to_float8(srcPtr2 + srcIdx, &src2_f8); + bitwise_or_hip_compute(srcPtr1, &src1_f8, &src2_f8, &dst_f8); + rpp_hip_pack_float8_and_store8(dstPtr + dstIdx, &dst_f8); + } +} + +template +__global__ void bitwise_or_pkd3_pln3_hip_tensor(T *srcPtr1, + T *srcPtr2, + uint2 srcStridesNH, + T *dstPtr, + uint3 dstStridesNCH, + RpptROIPtr roiTensorPtrSrc) +{ + int id_x = (hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x) * 8; + int id_y = hipBlockIdx_y * hipBlockDim_y + hipThreadIdx_y; + int id_z = hipBlockIdx_z * hipBlockDim_z + hipThreadIdx_z; + + if ((id_y >= roiTensorPtrSrc[id_z].xywhROI.roiHeight) || (id_x >= roiTensorPtrSrc[id_z].xywhROI.roiWidth)) + { + return; + } + + uint srcIdx = (id_z * srcStridesNH.x) + ((id_y + roiTensorPtrSrc[id_z].xywhROI.xy.y) * srcStridesNH.y) + ((id_x + roiTensorPtrSrc[id_z].xywhROI.xy.x) * 3); + uint dstIdx = (id_z * dstStridesNCH.x) + (id_y * dstStridesNCH.z) + id_x; + + d_float24 src1_f24, src2_f24, dst_f24; + + rpp_hip_load24_pkd3_and_unpack_to_float24_pln3(srcPtr1 + srcIdx, &src1_f24); + rpp_hip_load24_pkd3_and_unpack_to_float24_pln3(srcPtr2 + srcIdx, &src2_f24); + bitwise_or_hip_compute(srcPtr1, &src1_f24.f8[0], &src2_f24.f8[0], &dst_f24.f8[0]); + bitwise_or_hip_compute(srcPtr1, &src1_f24.f8[1], &src2_f24.f8[1], &dst_f24.f8[1]); + bitwise_or_hip_compute(srcPtr1, &src1_f24.f8[2], &src2_f24.f8[2], &dst_f24.f8[2]); + rpp_hip_pack_float24_pln3_and_store24_pln3(dstPtr + dstIdx, dstStridesNCH.y, &dst_f24); +} + +template +__global__ void bitwise_or_pln3_pkd3_hip_tensor(T *srcPtr1, + T *srcPtr2, + uint3 srcStridesNCH, + T *dstPtr, + uint2 dstStridesNH, + RpptROIPtr roiTensorPtrSrc) +{ + int id_x = (hipBlockIdx_x * hipBlockDim_x + hipThreadIdx_x) * 8; + int id_y = hipBlockIdx_y * hipBlockDim_y + hipThreadIdx_y; + int id_z = hipBlockIdx_z * hipBlockDim_z + hipThreadIdx_z; + + if ((id_y >= roiTensorPtrSrc[id_z].xywhROI.roiHeight) || (id_x >= roiTensorPtrSrc[id_z].xywhROI.roiWidth)) + { + return; + } + + uint srcIdx = (id_z * srcStridesNCH.x) + ((id_y + roiTensorPtrSrc[id_z].xywhROI.xy.y) * srcStridesNCH.z) + (id_x + roiTensorPtrSrc[id_z].xywhROI.xy.x); + uint dstIdx = (id_z * dstStridesNH.x) + (id_y * dstStridesNH.y) + id_x * 3; + + d_float24 src1_f24, src2_f24, dst_f24; + + rpp_hip_load24_pln3_and_unpack_to_float24_pkd3(srcPtr1 + srcIdx, srcStridesNCH.y, &src1_f24); + rpp_hip_load24_pln3_and_unpack_to_float24_pkd3(srcPtr2 + srcIdx, srcStridesNCH.y, &src2_f24); + bitwise_or_hip_compute(srcPtr1, &src1_f24.f8[0], &src2_f24.f8[0], &dst_f24.f8[0]); + bitwise_or_hip_compute(srcPtr1, &src1_f24.f8[1], &src2_f24.f8[1], &dst_f24.f8[1]); + bitwise_or_hip_compute(srcPtr1, &src1_f24.f8[2], &src2_f24.f8[2], &dst_f24.f8[2]); + rpp_hip_pack_float24_pkd3_and_store24_pkd3(dstPtr + dstIdx, &dst_f24); +} + +template +RppStatus hip_exec_bitwise_or_tensor(T *srcPtr1, + T *srcPtr2, + RpptDescPtr srcDescPtr, + T *dstPtr, + RpptDescPtr dstDescPtr, + RpptROIPtr roiTensorPtrSrc, + RpptRoiType roiType, + rpp::Handle& handle) +{ + if (roiType == RpptRoiType::LTRB) + hip_exec_roi_converison_ltrb_to_xywh(roiTensorPtrSrc, handle); + + int globalThreads_x = (dstDescPtr->w + 7) >> 3; + int globalThreads_y = dstDescPtr->h; + int globalThreads_z = handle.GetBatchSize(); + + if ((srcDescPtr->layout == RpptLayout::NHWC) && (dstDescPtr->layout == RpptLayout::NHWC)) + { + hipLaunchKernelGGL(bitwise_or_pkd_hip_tensor, + dim3(ceil((float)globalThreads_x/LOCAL_THREADS_X), ceil((float)globalThreads_y/LOCAL_THREADS_Y), ceil((float)globalThreads_z/LOCAL_THREADS_Z)), + dim3(LOCAL_THREADS_X, LOCAL_THREADS_Y, LOCAL_THREADS_Z), + 0, + handle.GetStream(), + srcPtr1, + srcPtr2, + make_uint2(srcDescPtr->strides.nStride, srcDescPtr->strides.hStride), + dstPtr, + make_uint2(dstDescPtr->strides.nStride, dstDescPtr->strides.hStride), + roiTensorPtrSrc); + } + else if ((srcDescPtr->layout == RpptLayout::NCHW) && (dstDescPtr->layout == RpptLayout::NCHW)) + { + hipLaunchKernelGGL(bitwise_or_pln_hip_tensor, + dim3(ceil((float)globalThreads_x/LOCAL_THREADS_X), ceil((float)globalThreads_y/LOCAL_THREADS_Y), ceil((float)globalThreads_z/LOCAL_THREADS_Z)), + dim3(LOCAL_THREADS_X, LOCAL_THREADS_Y, LOCAL_THREADS_Z), + 0, + handle.GetStream(), + srcPtr1, + srcPtr2, + make_uint3(srcDescPtr->strides.nStride, srcDescPtr->strides.cStride, srcDescPtr->strides.hStride), + dstPtr, + make_uint3(dstDescPtr->strides.nStride, dstDescPtr->strides.cStride, dstDescPtr->strides.hStride), + dstDescPtr->c, + roiTensorPtrSrc); + } + else if ((srcDescPtr->c == 3) && (dstDescPtr->c == 3)) + { + if ((srcDescPtr->layout == RpptLayout::NHWC) && (dstDescPtr->layout == RpptLayout::NCHW)) + { + hipLaunchKernelGGL(bitwise_or_pkd3_pln3_hip_tensor, + dim3(ceil((float)globalThreads_x/LOCAL_THREADS_X), ceil((float)globalThreads_y/LOCAL_THREADS_Y), ceil((float)globalThreads_z/LOCAL_THREADS_Z)), + dim3(LOCAL_THREADS_X, LOCAL_THREADS_Y, LOCAL_THREADS_Z), + 0, + handle.GetStream(), + srcPtr1, + srcPtr2, + make_uint2(srcDescPtr->strides.nStride, srcDescPtr->strides.hStride), + dstPtr, + make_uint3(dstDescPtr->strides.nStride, dstDescPtr->strides.cStride, dstDescPtr->strides.hStride), + roiTensorPtrSrc); + } + else if ((srcDescPtr->layout == RpptLayout::NCHW) && (dstDescPtr->layout == RpptLayout::NHWC)) + { + globalThreads_x = (srcDescPtr->strides.hStride + 7) >> 3; + hipLaunchKernelGGL(bitwise_or_pln3_pkd3_hip_tensor, + dim3(ceil((float)globalThreads_x/LOCAL_THREADS_X), ceil((float)globalThreads_y/LOCAL_THREADS_Y), ceil((float)globalThreads_z/LOCAL_THREADS_Z)), + dim3(LOCAL_THREADS_X, LOCAL_THREADS_Y, LOCAL_THREADS_Z), + 0, + handle.GetStream(), + srcPtr1, + srcPtr2, + make_uint3(srcDescPtr->strides.nStride, srcDescPtr->strides.cStride, srcDescPtr->strides.hStride), + dstPtr, + make_uint2(dstDescPtr->strides.nStride, dstDescPtr->strides.hStride), + roiTensorPtrSrc); + } + } + + return RPP_SUCCESS; +} \ No newline at end of file diff --git a/src/modules/rppt_tensor_logical_operations.cpp b/src/modules/rppt_tensor_logical_operations.cpp new file mode 100644 index 000000000..7d28fe96b --- /dev/null +++ b/src/modules/rppt_tensor_logical_operations.cpp @@ -0,0 +1,300 @@ +/* +MIT License + +Copyright (c) 2019 - 2024 Advanced Micro Devices, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#include "rppdefs.h" +#include "rppi_validate.hpp" +#include "rppt_tensor_logical_operations.h" +#include "cpu/host_tensor_logical_operations.hpp" + +#ifdef HIP_COMPILE + #include + #include "hip/hip_tensor_logical_operations.hpp" +#endif // HIP_COMPILE + +/******************** bitwise AND ********************/ + +RppStatus rppt_bitwise_and_host(RppPtr_t srcPtr1, + RppPtr_t srcPtr2, + RpptDescPtr srcDescPtr, + RppPtr_t dstPtr, + RpptDescPtr dstDescPtr, + RpptROIPtr roiTensorPtrSrc, + RpptRoiType roiType, + rppHandle_t rppHandle) +{ + RppLayoutParams layoutParams = get_layout_params(srcDescPtr->layout, srcDescPtr->c); + + if ((srcDescPtr->dataType == RpptDataType::U8) && (dstDescPtr->dataType == RpptDataType::U8)) + { + bitwise_and_u8_u8_host_tensor(static_cast(srcPtr1) + srcDescPtr->offsetInBytes, + static_cast(srcPtr2) + srcDescPtr->offsetInBytes, + srcDescPtr, + static_cast(dstPtr) + dstDescPtr->offsetInBytes, + dstDescPtr, + roiTensorPtrSrc, + roiType, + layoutParams, + rpp::deref(rppHandle)); + } + else if ((srcDescPtr->dataType == RpptDataType::F16) && (dstDescPtr->dataType == RpptDataType::F16)) + { + bitwise_and_f16_f16_host_tensor(reinterpret_cast(static_cast(srcPtr1) + srcDescPtr->offsetInBytes), + reinterpret_cast(static_cast(srcPtr2) + srcDescPtr->offsetInBytes), + srcDescPtr, + reinterpret_cast(static_cast(dstPtr) + dstDescPtr->offsetInBytes), + dstDescPtr, + roiTensorPtrSrc, + roiType, + layoutParams, + rpp::deref(rppHandle)); + } + else if ((srcDescPtr->dataType == RpptDataType::F32) && (dstDescPtr->dataType == RpptDataType::F32)) + { + bitwise_and_f32_f32_host_tensor(reinterpret_cast(static_cast(srcPtr1) + srcDescPtr->offsetInBytes), + reinterpret_cast(static_cast(srcPtr2) + srcDescPtr->offsetInBytes), + srcDescPtr, + reinterpret_cast(static_cast(dstPtr) + dstDescPtr->offsetInBytes), + dstDescPtr, + roiTensorPtrSrc, + roiType, + layoutParams, + rpp::deref(rppHandle)); + } + else if ((srcDescPtr->dataType == RpptDataType::I8) && (dstDescPtr->dataType == RpptDataType::I8)) + { + bitwise_and_i8_i8_host_tensor(static_cast(srcPtr1) + srcDescPtr->offsetInBytes, + static_cast(srcPtr2) + srcDescPtr->offsetInBytes, + srcDescPtr, + static_cast(dstPtr) + dstDescPtr->offsetInBytes, + dstDescPtr, + roiTensorPtrSrc, + roiType, + layoutParams, + rpp::deref(rppHandle)); + } + + return RPP_SUCCESS; +} + +/******************** bitwise OR ********************/ + +RppStatus rppt_bitwise_or_host(RppPtr_t srcPtr1, + RppPtr_t srcPtr2, + RpptDescPtr srcDescPtr, + RppPtr_t dstPtr, + RpptDescPtr dstDescPtr, + RpptROIPtr roiTensorPtrSrc, + RpptRoiType roiType, + rppHandle_t rppHandle) +{ + RppLayoutParams layoutParams = get_layout_params(srcDescPtr->layout, srcDescPtr->c); + + if ((srcDescPtr->dataType == RpptDataType::U8) && (dstDescPtr->dataType == RpptDataType::U8)) + { + bitwise_or_u8_u8_host_tensor(static_cast(srcPtr1) + srcDescPtr->offsetInBytes, + static_cast(srcPtr2) + srcDescPtr->offsetInBytes, + srcDescPtr, + static_cast(dstPtr) + dstDescPtr->offsetInBytes, + dstDescPtr, + roiTensorPtrSrc, + roiType, + layoutParams, + rpp::deref(rppHandle)); + } + else if ((srcDescPtr->dataType == RpptDataType::F16) && (dstDescPtr->dataType == RpptDataType::F16)) + { + bitwise_or_f16_f16_host_tensor(reinterpret_cast(static_cast(srcPtr1) + srcDescPtr->offsetInBytes), + reinterpret_cast(static_cast(srcPtr2) + srcDescPtr->offsetInBytes), + srcDescPtr, + reinterpret_cast(static_cast(dstPtr) + dstDescPtr->offsetInBytes), + dstDescPtr, + roiTensorPtrSrc, + roiType, + layoutParams, + rpp::deref(rppHandle)); + } + else if ((srcDescPtr->dataType == RpptDataType::F32) && (dstDescPtr->dataType == RpptDataType::F32)) + { + bitwise_or_f32_f32_host_tensor(reinterpret_cast(static_cast(srcPtr1) + srcDescPtr->offsetInBytes), + reinterpret_cast(static_cast(srcPtr2) + srcDescPtr->offsetInBytes), + srcDescPtr, + reinterpret_cast(static_cast(dstPtr) + dstDescPtr->offsetInBytes), + dstDescPtr, + roiTensorPtrSrc, + roiType, + layoutParams, + rpp::deref(rppHandle)); + } + else if ((srcDescPtr->dataType == RpptDataType::I8) && (dstDescPtr->dataType == RpptDataType::I8)) + { + bitwise_or_i8_i8_host_tensor(static_cast(srcPtr1) + srcDescPtr->offsetInBytes, + static_cast(srcPtr2) + srcDescPtr->offsetInBytes, + srcDescPtr, + static_cast(dstPtr) + dstDescPtr->offsetInBytes, + dstDescPtr, + roiTensorPtrSrc, + roiType, + layoutParams, + rpp::deref(rppHandle)); + } + + return RPP_SUCCESS; +} + + +/********************************************************************************************************************/ +/*********************************************** RPP_GPU_SUPPORT = ON ***********************************************/ +/********************************************************************************************************************/ + +#ifdef GPU_SUPPORT + +/******************** bitwise AND ********************/ + +RppStatus rppt_bitwise_and_gpu(RppPtr_t srcPtr1, + RppPtr_t srcPtr2, + RpptDescPtr srcDescPtr, + RppPtr_t dstPtr, + RpptDescPtr dstDescPtr, + RpptROIPtr roiTensorPtrSrc, + RpptRoiType roiType, + rppHandle_t rppHandle) +{ +#ifdef HIP_COMPILE + + if ((srcDescPtr->dataType == RpptDataType::U8) && (dstDescPtr->dataType == RpptDataType::U8)) + { + hip_exec_bitwise_and_tensor(static_cast(srcPtr1) + srcDescPtr->offsetInBytes, + static_cast(srcPtr2) + srcDescPtr->offsetInBytes, + srcDescPtr, + static_cast(dstPtr) + dstDescPtr->offsetInBytes, + dstDescPtr, + roiTensorPtrSrc, + roiType, + rpp::deref(rppHandle)); + } + else if ((srcDescPtr->dataType == RpptDataType::F16) && (dstDescPtr->dataType == RpptDataType::F16)) + { + hip_exec_bitwise_and_tensor(reinterpret_cast(static_cast(srcPtr1) + srcDescPtr->offsetInBytes), + reinterpret_cast(static_cast(srcPtr2) + srcDescPtr->offsetInBytes), + srcDescPtr, + reinterpret_cast(static_cast(dstPtr) + dstDescPtr->offsetInBytes), + dstDescPtr, + roiTensorPtrSrc, + roiType, + rpp::deref(rppHandle)); + } + else if ((srcDescPtr->dataType == RpptDataType::F32) && (dstDescPtr->dataType == RpptDataType::F32)) + { + hip_exec_bitwise_and_tensor(reinterpret_cast(static_cast(srcPtr1) + srcDescPtr->offsetInBytes), + reinterpret_cast(static_cast(srcPtr2) + srcDescPtr->offsetInBytes), + srcDescPtr, + reinterpret_cast(static_cast(dstPtr) + dstDescPtr->offsetInBytes), + dstDescPtr, + roiTensorPtrSrc, + roiType, + rpp::deref(rppHandle)); + } + else if ((srcDescPtr->dataType == RpptDataType::I8) && (dstDescPtr->dataType == RpptDataType::I8)) + { + hip_exec_bitwise_and_tensor(static_cast(srcPtr1) + srcDescPtr->offsetInBytes, + static_cast(srcPtr2) + srcDescPtr->offsetInBytes, + srcDescPtr, + static_cast(dstPtr) + dstDescPtr->offsetInBytes, + dstDescPtr, + roiTensorPtrSrc, + roiType, + rpp::deref(rppHandle)); + } + + return RPP_SUCCESS; +#elif defined(OCL_COMPILE) + return RPP_ERROR_NOT_IMPLEMENTED; +#endif // backend +} + +/******************** bitwise OR ********************/ + +RppStatus rppt_bitwise_or_gpu(RppPtr_t srcPtr1, + RppPtr_t srcPtr2, + RpptDescPtr srcDescPtr, + RppPtr_t dstPtr, + RpptDescPtr dstDescPtr, + RpptROIPtr roiTensorPtrSrc, + RpptRoiType roiType, + rppHandle_t rppHandle) +{ +#ifdef HIP_COMPILE + + if ((srcDescPtr->dataType == RpptDataType::U8) && (dstDescPtr->dataType == RpptDataType::U8)) + { + hip_exec_bitwise_or_tensor(static_cast(srcPtr1) + srcDescPtr->offsetInBytes, + static_cast(srcPtr2) + srcDescPtr->offsetInBytes, + srcDescPtr, + static_cast(dstPtr) + dstDescPtr->offsetInBytes, + dstDescPtr, + roiTensorPtrSrc, + roiType, + rpp::deref(rppHandle)); + } + else if ((srcDescPtr->dataType == RpptDataType::F16) && (dstDescPtr->dataType == RpptDataType::F16)) + { + hip_exec_bitwise_or_tensor(reinterpret_cast(static_cast(srcPtr1) + srcDescPtr->offsetInBytes), + reinterpret_cast(static_cast(srcPtr2) + srcDescPtr->offsetInBytes), + srcDescPtr, + reinterpret_cast(static_cast(dstPtr) + dstDescPtr->offsetInBytes), + dstDescPtr, + roiTensorPtrSrc, + roiType, + rpp::deref(rppHandle)); + } + else if ((srcDescPtr->dataType == RpptDataType::F32) && (dstDescPtr->dataType == RpptDataType::F32)) + { + hip_exec_bitwise_or_tensor(reinterpret_cast(static_cast(srcPtr1) + srcDescPtr->offsetInBytes), + reinterpret_cast(static_cast(srcPtr2) + srcDescPtr->offsetInBytes), + srcDescPtr, + reinterpret_cast(static_cast(dstPtr) + dstDescPtr->offsetInBytes), + dstDescPtr, + roiTensorPtrSrc, + roiType, + rpp::deref(rppHandle)); + } + else if ((srcDescPtr->dataType == RpptDataType::I8) && (dstDescPtr->dataType == RpptDataType::I8)) + { + hip_exec_bitwise_or_tensor(static_cast(srcPtr1) + srcDescPtr->offsetInBytes, + static_cast(srcPtr2) + srcDescPtr->offsetInBytes, + srcDescPtr, + static_cast(dstPtr) + dstDescPtr->offsetInBytes, + dstDescPtr, + roiTensorPtrSrc, + roiType, + rpp::deref(rppHandle)); + } + + return RPP_SUCCESS; +#elif defined(OCL_COMPILE) + return RPP_ERROR_NOT_IMPLEMENTED; +#endif // backend +} + +#endif // GPU_SUPPORT diff --git a/utilities/test_suite/HIP/Tensor_hip.cpp b/utilities/test_suite/HIP/Tensor_hip.cpp index c2f7665f2..2743c4e1f 100644 --- a/utilities/test_suite/HIP/Tensor_hip.cpp +++ b/utilities/test_suite/HIP/Tensor_hip.cpp @@ -65,7 +65,7 @@ int main(int argc, char **argv) bool additionalParamCase = (testCase == 8 || testCase == 21 || testCase == 23|| testCase == 24 || testCase == 40 || testCase == 41 || testCase == 49 || testCase == 54); bool kernelSizeCase = (testCase == 40 || testCase == 41 || testCase == 49 || testCase == 54); - bool dualInputCase = (testCase == 2 || testCase == 30 || testCase == 61 || testCase == 63); + bool dualInputCase = (testCase == 2 || testCase == 30 || testCase == 61 || testCase == 63 || testCase == 65 || testCase == 68); bool randomOutputCase = (testCase == 84 || testCase == 49 || testCase == 54); bool interpolationTypeCase = (testCase == 21 || testCase == 23 || testCase == 24); bool reductionTypeCase = (testCase == 87 || testCase == 88 || testCase == 89); @@ -903,6 +903,30 @@ int main(int argc, char **argv) break; } + case 65: + { + testCaseName = "bitwise_and"; + + startWallTime = omp_get_wtime(); + if (inputBitDepth == 0 || inputBitDepth == 1 || inputBitDepth == 2 || inputBitDepth == 5) + rppt_bitwise_and_gpu(d_input, d_input_second, srcDescPtr, d_output, dstDescPtr, roiTensorPtrSrc, roiTypeSrc, handle); + else + missingFuncFlag = 1; + + break; + } + case 68: + { + testCaseName = "bitwise_or"; + + startWallTime = omp_get_wtime(); + if (inputBitDepth == 0 || inputBitDepth == 1 || inputBitDepth == 2 || inputBitDepth == 5) + rppt_bitwise_or_gpu(d_input, d_input_second, srcDescPtr, d_output, dstDescPtr, roiTensorPtrSrc, roiTypeSrc, handle); + else + missingFuncFlag = 1; + + break; + } case 70: { testCaseName = "copy"; diff --git a/utilities/test_suite/HIP/runTests.py b/utilities/test_suite/HIP/runTests.py index 4dc9023f7..14fb0270a 100644 --- a/utilities/test_suite/HIP/runTests.py +++ b/utilities/test_suite/HIP/runTests.py @@ -63,8 +63,10 @@ def func_group_finder(case_number): return "filter_augmentations" elif case_number < 40: return "geometric_augmentations" - elif case_number == 61: + elif case_number < 62: return "arithmetic_operations" + elif case_number < 69: + return "logical_operations" elif case_number < 87: return "data_exchange_operations" elif case_number < 88: @@ -325,7 +327,7 @@ def rpp_test_suite_parser_and_validator(): subprocess.run(["make", "-j16"], cwd=".") # nosec # List of cases supported -supportedCaseList = ['0', '1', '2', '4', '8', '13', '20', '21', '23', '29', '30', '31', '34', '36', '37', '38', '39', '45', '46', '54', '61', '63', '70', '80', '82', '83', '84', '85', '86', '87', '88', '89'] +supportedCaseList = ['0', '1', '2', '4', '8', '13', '20', '21', '23', '29', '30', '31', '34', '36', '37', '38', '39', '45', '46', '54', '61', '63', '65', '68', '70', '80', '82', '83', '84', '85', '86', '87', '88', '89'] # Create folders based on testType and profilingOption if testType == 1 and profilingOption == "YES": @@ -517,6 +519,7 @@ def rpp_test_suite_parser_and_validator(): "geometric_augmentations", "morphological_operations", "arithmetic_operations", + "logical_operations", "statistical_operations" ] for log_file in log_file_list: diff --git a/utilities/test_suite/HOST/Tensor_host.cpp b/utilities/test_suite/HOST/Tensor_host.cpp index ffc9c0d3a..5c9d3c7dc 100644 --- a/utilities/test_suite/HOST/Tensor_host.cpp +++ b/utilities/test_suite/HOST/Tensor_host.cpp @@ -65,7 +65,7 @@ int main(int argc, char **argv) int batchSize = atoi(argv[14]); bool additionalParamCase = (testCase == 8 || testCase == 21 || testCase == 23 || testCase == 24); - bool dualInputCase = (testCase == 2 || testCase == 30 || testCase == 61 || testCase == 63); + bool dualInputCase = (testCase == 2 || testCase == 30 || testCase == 61 || testCase == 63 || testCase == 65 || testCase == 68); bool randomOutputCase = (testCase == 84); bool interpolationTypeCase = (testCase == 21 || testCase == 23 || testCase == 24); bool reductionTypeCase = (testCase == 87 || testCase == 88 || testCase == 89); @@ -875,6 +875,32 @@ int main(int argc, char **argv) break; } + case 65: + { + testCaseName = "bitwise_and"; + + startWallTime = omp_get_wtime(); + startCpuTime = clock(); + if (inputBitDepth == 0 || inputBitDepth == 1 || inputBitDepth == 2 || inputBitDepth == 5) + rppt_bitwise_and_host(input, input_second, srcDescPtr, output, dstDescPtr, roiTensorPtrSrc, roiTypeSrc, handle); + else + missingFuncFlag = 1; + + break; + } + case 68: + { + testCaseName = "bitwise_or"; + + startWallTime = omp_get_wtime(); + startCpuTime = clock(); + if (inputBitDepth == 0 || inputBitDepth == 1 || inputBitDepth == 2 || inputBitDepth == 5) + rppt_bitwise_or_host(input, input_second, srcDescPtr, output, dstDescPtr, roiTensorPtrSrc, roiTypeSrc, handle); + else + missingFuncFlag = 1; + + break; + } case 70: { testCaseName = "copy"; diff --git a/utilities/test_suite/HOST/runTests.py b/utilities/test_suite/HOST/runTests.py index f106a9649..00ae0a48e 100644 --- a/utilities/test_suite/HOST/runTests.py +++ b/utilities/test_suite/HOST/runTests.py @@ -56,10 +56,12 @@ def func_group_finder(case_number): return "color_augmentations" elif case_number == 8 or case_number == 30 or case_number == 82 or case_number == 83 or case_number == 84: return "effects_augmentations" - elif case_number < 40: + elif case_number < 40 or case_number == 63: return "geometric_augmentations" - elif case_number == 61: + elif case_number < 62: return "arithmetic_operations" + elif case_number < 69: + return "logical_operations" elif case_number < 87: return "data_exchange_operations" elif case_number < 88: @@ -281,7 +283,7 @@ def rpp_test_suite_parser_and_validator(): subprocess.run(["make", "-j16"], cwd=".") # nosec # List of cases supported -supportedCaseList = ['0', '1', '2', '4', '8', '13', '20', '21', '23', '29', '30', '31', '34', '36', '37', '38', '39', '45', '46', '54', '61', '63', '70', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89'] +supportedCaseList = ['0', '1', '2', '4', '8', '13', '20', '21', '23', '29', '30', '31', '34', '36', '37', '38', '39', '45', '46', '54', '61', '63', '65', '68', '70', '80', '81', '82', '83', '84', '85', '86', '87', '88', '89'] print("\n\n\n\n\n") print("##########################################################################################") diff --git a/utilities/test_suite/REFERENCE_OUTPUT/bitwise_and/bitwise_and_u8_Tensor.bin b/utilities/test_suite/REFERENCE_OUTPUT/bitwise_and/bitwise_and_u8_Tensor.bin new file mode 100644 index 0000000000000000000000000000000000000000..952959dc5f5dc953d766780c8cf26d1713b7b4a6 GIT binary patch literal 273600 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

|ftQ0Cb5F1mTk))QLSW#4# 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 literal 0 HcmV?d00001 diff --git a/utilities/test_suite/REFERENCE_OUTPUT/bitwise_or/bitwise_or_u8_Tensor.bin b/utilities/test_suite/REFERENCE_OUTPUT/bitwise_or/bitwise_or_u8_Tensor.bin new file mode 100644 index 0000000000000000000000000000000000000000..2d10766147edf651fe03a0f856d711ff0f3c1117 GIT binary patch literal 273600 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 I9D3;g0_ytY761SM literal 0 HcmV?d00001 diff --git a/utilities/test_suite/rpp_test_suite_common.h b/utilities/test_suite/rpp_test_suite_common.h index 55fc90abf..b1b12fdd4 100644 --- a/utilities/test_suite/rpp_test_suite_common.h +++ b/utilities/test_suite/rpp_test_suite_common.h @@ -92,6 +92,8 @@ std::map augmentationMap = {54, "gaussian_filter"}, {61, "magnitude"}, {63, "phase"}, + {65, "bitwise_and"}, + {68, "bitwise_or"}, {70, "copy"}, {80, "resize_mirror_normalize"}, {81, "color_jitter"},