text: /**
   * Copyright 2019 Huawei Technologies Co., Ltd
   *
   * Licensed under the Apache License, Version 2.0 (the "License");
   * you may not use this file except in compliance with the License.
   * You may obtain a copy of the License at
   *
   * http://www.apache.org/licenses/LICENSE-2.0
   *
   * Unless required by applicable law or agreed to in writing, software
   * distributed under the License is distributed on an "AS IS" BASIS,
   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   * See the License for the specific language governing permissions and
   * limitations under the License.
   */
  
  #include <set>
  #include <string>
  #include "include/errorcode.h"
  #include "src/kernel_registry.h"
  #include "src/runtime/opencl/opencl_runtime.h"
  #include "src/runtime/kernel/opencl/kernel/transpose.h"
  #ifndef PROGRAM_WITH_IL
  #include "src/runtime/kernel/opencl/cl/fp16/transpose.cl.inc"
  #include "src/runtime/kernel/opencl/cl/fp32/transpose.cl.inc"
  #endif
  
  using mindspore::kernel::KERNEL_ARCH::kGPU;
  using mindspore::lite::KernelRegistrar;
  using mindspore::lite::RET_ERROR;
  using mindspore::lite::RET_OK;
  using mindspore::schema::PrimitiveType_Transpose;
  
  namespace mindspore::kernel {
  
  int TransposeOpenCLKernel::Init() {
    std::string kernel_name = "transpose";
    auto ocl_runtime = lite::opencl::OpenCLRuntime::GetInstance();
  
  #ifdef PROGRAM_WITH_IL
    ocl_runtime->CreateKernelFromIL(kernel_(), kernel_name);
  #else
    std::set<std::string> build_options;
  #ifdef ENABLE_FP16
    std::string source = transpose_source_fp16;
  #else
    std::string source = transpose_source_fp32;
  #endif
    std::string program_name = "transpose";
    ocl_runtime->LoadSource(program_name, source);
    ocl_runtime->BuildKernel(kernel_, program_name, kernel_name, build_options);
  #endif
    auto input_format = inputs_[0]->GetFormat();
    if (input_format != schema::Format_NHWC4) {
      MS_LOG(ERROR) << "input format(" << input_format << ") "
                    << "format not support!";
      return RET_ERROR;
    }
    if ((inputs_[0]->Height() * inputs_[0]->Width()) % 4 != 0) {
      MS_LOG(ERROR) << "input H * W % 4 != 0 not support!";
      return RET_ERROR;
    }
    outputs_[0]->SetFormat(schema::Format_NCHW);
    MS_LOG(DEBUG) << kernel_name << " Init Done!";
    return RET_OK;
  }
  
  int TransposeOpenCLKernel::ReSize() { return 0; }
  
  int TransposeOpenCLKernel::Run() {
    MS_LOG(DEBUG) << this->Name() << " Running!";
    std::vector<int> shapex = inputs_[0]->shape();
    int h = shapex[1];
    int w = shapex[2];
    int c = shapex[3];
    int c4 = UP_DIV(c, 4);
    int hw4 = UP_DIV(h * w, 4);
    auto ocl_runtime = lite::opencl::OpenCLRuntime::GetInstance();
    // local size should less than MAX_GROUP_SIZE
    std::vector<size_t> local = {16, 16};
    std::vector<size_t> global = {UP_ROUND(hw4, local[0]), UP_ROUND(c4, local[1])};
  
    cl_int2 HW = {h * w, hw4};
    cl_int2 C = {c, c4};
    ocl_runtime->SetKernelArg(kernel_, 0, inputs_[0]->Data());
    ocl_runtime->SetKernelArg(kernel_, 1, outputs_[0]->Data());
    ocl_runtime->SetKernelArg(kernel_, 2, HW);
    ocl_runtime->SetKernelArg(kernel_, 3, C);
    ocl_runtime->RunKernel(kernel_, global, local, nullptr);
    return 0;
  }
  
  kernel::LiteKernel *OpenCLTransposeKernelCreator(const std::vector<lite::tensor::Tensor *> &inputs,
                                                   const std::vector<lite::tensor::Tensor *> &outputs,
                                                   OpParameter *opParameter, const lite::Context *ctx,
                                                   const kernel::KernelKey &desc, const lite::Primitive *primitive) {
    auto *kernel = new TransposeOpenCLKernel(reinterpret_cast<OpParameter *>(opParameter), inputs, outputs);
    auto ret = kernel->Init();
    if (0 != ret) {
      delete kernel;
      return nullptr;
    }
    return kernel;
  }
  
  REG_KERNEL(kGPU, kNumberTypeFloat32, PrimitiveType_Transpose, OpenCLTransposeKernelCreator)
  }  // namespace mindspore::kernel
  