From 69d3f080beee6ba156d538238a6a96fc5d81f28f Mon Sep 17 00:00:00 2001 From: Anders Roxell Date: Mon, 19 Jan 2026 11:47:39 +0100 Subject: [PATCH] ethosu: fix RESIZE upscale mode The upscale field was a bool which happened to work since true maps to 1 which is NEAREST in the hardware. Change from bool to an enum ethosu_upscale_mode so the intent is clear and we dont rely on the bool-to-int mapping. Also add a check in operation_supported so RESIZE only accepts 2x upscaling since thats what the NPU can do with IFM_UPSCALE. Other sizes fall back to CPU. Keep the original zero_points from tensors in RESIZE and STRIDED_SLICE instead of forcing them to 0 since the requantization needs them. Fixes the RESIZE_NEAREST_NEIGHBOR operations in EfficientDet-Lite models that use BiFPN with 2x nearest neighbor upsampling. Signed-off-by: Anders Roxell Part-of: --- src/gallium/drivers/ethosu/ethosu_lower.c | 7 ++----- src/gallium/drivers/ethosu/ethosu_ml.c | 10 +++++++++- src/gallium/drivers/ethosu/ethosu_ml.h | 9 ++++++++- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/src/gallium/drivers/ethosu/ethosu_lower.c b/src/gallium/drivers/ethosu/ethosu_lower.c index 10cd5b9594c..a69a61ecca8 100644 --- a/src/gallium/drivers/ethosu/ethosu_lower.c +++ b/src/gallium/drivers/ethosu/ethosu_lower.c @@ -3,6 +3,7 @@ * SPDX-License-Identifier: MIT */ +#include "ethosu_device.h" #include "ethosu_lower.h" #include "ethosu_coefs.h" #include "ethosu_sched.h" @@ -261,8 +262,6 @@ ethosu_lower_resize(struct ethosu_subgraph *subgraph, operation->pooling.avg = true; set_feature_maps(poperation->input_tensors[0], poperation->output_tensors[0], operation); - operation->ifm.zero_point = 0; - operation->ofm.zero_point = 0; operation->kernel.height = 1; operation->kernel.width = 1; @@ -271,7 +270,7 @@ ethosu_lower_resize(struct ethosu_subgraph *subgraph, operation->kernel.dilation_y = 1; operation->kernel.dilation_x = 1; - operation->upscale = true; + operation->upscale = ETHOSU_UPSCALE_NEAREST; allocate_feature_maps(subgraph, operation); ethosu_sched_operation(subgraph, operation); @@ -287,8 +286,6 @@ ethosu_lower_strided_slice(struct ethosu_subgraph *subgraph, set_feature_maps(poperation->input_tensors[0], poperation->output_tensors[0], operation); operation->ifm.shape = operation->ofm.shape; - operation->ifm.zero_point = 0; - operation->ofm.zero_point = 0; operation->kernel.height = 1; operation->kernel.width = 1; diff --git a/src/gallium/drivers/ethosu/ethosu_ml.c b/src/gallium/drivers/ethosu/ethosu_ml.c index 32d0ff08250..efab4ad744d 100644 --- a/src/gallium/drivers/ethosu/ethosu_ml.c +++ b/src/gallium/drivers/ethosu/ethosu_ml.c @@ -161,9 +161,17 @@ ethosu_ml_operation_supported(struct pipe_context *pcontext, case PIPE_ML_OPERATION_TYPE_POOLING: case PIPE_ML_OPERATION_TYPE_STRIDED_SLICE: case PIPE_ML_OPERATION_TYPE_PAD: - case PIPE_ML_OPERATION_TYPE_RESIZE: supported = true; break; + case PIPE_ML_OPERATION_TYPE_RESIZE: { + /* NPU only supports 2x nearest neighbor upscaling */ + struct pipe_tensor *input = operation->input_tensors[0]; + struct pipe_tensor *output = operation->output_tensors[0]; + bool is_2x_height = (output->dims[1] == 2 * input->dims[1]); + bool is_2x_width = (output->dims[2] == 2 * input->dims[2]); + supported = is_2x_height && is_2x_width; + break; + } case PIPE_ML_OPERATION_TYPE_CONCATENATION: supported = operation->conc.axis == 3 || operation->conc.axis == -1; diff --git a/src/gallium/drivers/ethosu/ethosu_ml.h b/src/gallium/drivers/ethosu/ethosu_ml.h index 1ce7ce7ac5c..d275b6140b2 100644 --- a/src/gallium/drivers/ethosu/ethosu_ml.h +++ b/src/gallium/drivers/ethosu/ethosu_ml.h @@ -62,6 +62,13 @@ enum ethosu_rounding_mode { ETHOSU_ROUNDING_TRUNCATE, ETHOSU_ROUNDING_NATURAL, }; + +enum ethosu_upscale_mode { + ETHOSU_UPSCALE_NONE = 0, + ETHOSU_UPSCALE_NEAREST = 1, + ETHOSU_UPSCALE_ZEROS = 2, +}; + struct ethosu_feature_map { unsigned tensor_idx; struct ethosu_block shape; @@ -158,7 +165,7 @@ struct ethosu_operation { struct ethosu_kernel kernel; struct ethosu_padding pad; - bool upscale; + enum ethosu_upscale_mode upscale; enum ethosu_rounding_mode round_mode; struct ethosu_address_range read_accesses[MAX_MEMORY_ACCESSES];