cl_image.h 7.1 KB
Newer Older
L
liuruilong 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.

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. */

#pragma once

17 18 19
#include <vector>

#include "CL/cl.h"
L
liuruilong 已提交
20

L
liuruilong 已提交
21
#include "framework/cl/cl_deleter.h"
L
liuruilong 已提交
22
#include "framework/cl/cl_engine.h"
L
liuruilong 已提交
23 24 25
#include "framework/cl/cl_half.h"
#include "framework/cl/cl_image_converter.h"
#include "framework/cl/cl_tool.h"
L
liuruilong 已提交
26 27 28 29 30 31 32 33
#include "framework/ddim.h"
#include "framework/tensor.h"

namespace paddle_mobile {
namespace framework {

class CLImage {
 public:
L
liuruilong 已提交
34 35
  CLImage() = default;

L
liuruilong 已提交
36 37 38 39 40 41 42 43 44
  ~CLImage() {
    if (tensor_data_ != nullptr) {
      delete[](tensor_data_);
    }

    if (image_converter_) {
      delete (image_converter_);
    }
  }
L
liuruilong 已提交
45 46 47 48 49 50 51
  /*
   * will not hold input tensor data, memcpy in this method
   * */
  void SetTensorData(float *tensorData, const DDim &dim) {
    int numel = product(dim);
    if (tensor_data_ != nullptr) {
      delete[](tensor_data_);
L
liuruilong 已提交
52
      tensor_data_ = nullptr;
L
liuruilong 已提交
53 54
    }
    tensor_data_ = new float[numel];
L
liuruilong 已提交
55
    memcpy(tensor_data_, tensorData, numel * sizeof(float));
L
liuruilong 已提交
56 57 58 59 60
    tensor_dims_ = dim;
  }

  /*
   * need call SetTensorData first
L
liuruilong 已提交
61 62
   *
   * folder when one dim or two dim
L
liuruilong 已提交
63
   * */
L
liuruilong 已提交
64
  void InitCLImage(cl_context context, cl_command_queue command_queue) {
L
liuruilong 已提交
65 66 67 68 69 70 71 72 73 74
    PADDLE_MOBILE_ENFORCE(tensor_data_ != nullptr,
                          " need call SetTensorData first");
    CLImageConverterFolder *folder_converter = new CLImageConverterFolder();
    InitCLImage(context, command_queue, folder_converter);
  }

  void InitCLImage(cl_context context, cl_command_queue command_queue,
                   CLImageConverterBase *converter) {
    if (image_converter_ != nullptr) {
      delete (image_converter_);
D
dolphin8 已提交
75
    }
L
liuruilong 已提交
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91

    PADDLE_MOBILE_ENFORCE(tensor_data_ != nullptr,
                          " need call SetTensorData first");

    DLOG << " begin init cl image ";
    image_dims_ = converter->InitImageDimInfoWith(tensor_dims_);

    half_t *image_data = new half_t[product(image_dims_) * 4];

    DLOG << " convert to image";
    converter->NCHWToImage(tensor_data_, image_data, tensor_dims_);
    DLOG << " end convert to image";

    InitCLImage(context, image_dims_[0], image_dims_[1], image_data);

    delete[](image_data);
L
liuruilong 已提交
92
    delete[](tensor_data_);
L
liuruilong 已提交
93 94

    command_queue_ = command_queue;
L
liuruilong 已提交
95
    tensor_data_ = nullptr;
L
liuruilong 已提交
96
    image_converter_ = converter;
L
liuruilong 已提交
97
    initialized_ = true;
L
liuruilong 已提交
98
    DLOG << " end init cl image";
L
liuruilong 已提交
99 100
  }

L
liuruilong 已提交
101
  void InitNImage(cl_context context, cl_command_queue command_queue) {
Y
yangfei 已提交
102 103 104
    if (tensor_data_ == nullptr) {
      PADDLE_MOBILE_THROW_EXCEPTION(" need call SetTensorData first");
    }
L
liuruilong 已提交
105 106 107
    CLImageConverterNWBlock *folder_converter = new CLImageConverterNWBlock();
    InitCLImage(context, command_queue, folder_converter);
    PADDLE_MOBILE_ENFORCE(tensor_dims_.size() == 4, " tensor dim is not 4");
Y
yangfei 已提交
108
  }
Y
yangfei 已提交
109 110 111 112 113 114 115 116
  void InitDWImage(cl_context context, cl_command_queue command_queue) {
    if (tensor_data_ == nullptr) {
      PADDLE_MOBILE_THROW_EXCEPTION(" need call SetTensorData first");
    }
    CLImageConverterDWBlock *dw_converter = new CLImageConverterDWBlock();
    InitCLImage(context, command_queue, dw_converter);
    PADDLE_MOBILE_ENFORCE(tensor_dims_.size() == 4, " tensor dim is not 4");
  }
Y
yangfei 已提交
117

L
liuruilong 已提交
118 119
  void InitEmptyImage(cl_context context, cl_command_queue command_queue,
                      const DDim &dim) {
L
liuruilong 已提交
120 121
    PADDLE_MOBILE_ENFORCE(tensor_data_ == nullptr,
                          " empty image tensor data shouldn't have value");
L
liuruilong 已提交
122

Y
yangfei 已提交
123 124 125
    //    CLImageConverterFolder *folder_converter = new
    //    CLImageConverterFolder();
    CLImageConverterNormal *normal_converter = new CLImageConverterNormal();
L
liuruilong 已提交
126 127

    DLOG << " to get image dims ";
Y
yangfei 已提交
128
    image_dims_ = normal_converter->InitImageDimInfoWith(dim);
L
liuruilong 已提交
129
    DLOG << " end get image dims " << image_dims_;
L
liuruilong 已提交
130

L
liuruilong 已提交
131
    InitCLImage(context, image_dims_[0], image_dims_[1], nullptr);
L
liuruilong 已提交
132

L
liuruilong 已提交
133 134
    tensor_dims_ = dim;
    command_queue_ = command_queue;
Y
yangfei 已提交
135
    image_converter_ = normal_converter;
L
liuruilong 已提交
136
    cl_event_ = CLEngine::Instance()->CreateEvent(context);
L
liuruilong 已提交
137
    initialized_ = true;
L
liuruilong 已提交
138
    DLOG << " end init cl image";
L
liuruilong 已提交
139 140
  }

L
liuruilong 已提交
141
  cl_mem GetCLImage() const { return cl_image_.get(); }
L
liuruilong 已提交
142

Y
yangfei 已提交
143
  const DDim &ImageDims() const { return image_dims_; }
L
liuruilong 已提交
144

L
liuruilong 已提交
145
  inline size_t ImageWidth() const { return image_dims_[0]; }
L
liuruilong 已提交
146

L
liuruilong 已提交
147
  inline size_t ImageHeight() const { return image_dims_[1]; }
L
liuruilong 已提交
148

L
liuruilong 已提交
149
  inline cl_command_queue CommandQueue() const { return command_queue_; }
Y
yangfei 已提交
150

L
liuruilong 已提交
151 152 153 154 155 156 157 158 159 160 161 162
  /*
   *  resize original tensor dim
   * */
  inline CLImage &Resize(const DDim &dims) {
    tensor_dims_ = dims;
    return *this;
  }

  template <typename T>
  T *data() const {
    if (initialized_) {
      PADDLE_MOBILE_THROW_EXCEPTION(
L
liuruilong 已提交
163 164
          " cl image has initialized, tensor data has been deleted, can't use "
          "tensor data");
L
liuruilong 已提交
165 166 167 168 169 170 171 172 173 174 175 176 177 178
    }
    return reinterpret_cast<T *>(tensor_data_);
  }

  /*
   *  numel of tensor dim
   * */
  inline int64_t numel() const { return product(tensor_dims_); }

  /*
   *  original tensor dim
   * */
  const DDim &dims() const { return tensor_dims_; }

L
liuruilong 已提交
179 180
  cl_event GetClEvent() const { return cl_event_.get(); }

L
liuruilong 已提交
181
  CLImageConverterBase *Converter() const { return image_converter_; }
D
dolphin8 已提交
182

L
liuruilong 已提交
183
 private:
L
liuruilong 已提交
184
  void InitCLImage(cl_context context, int width, int height, void *data) {
D
dolphin8 已提交
185 186 187
    cl_image_format cf = {.image_channel_order = CL_RGBA,
                          .image_channel_data_type = CL_HALF_FLOAT};
    cl_image_desc cid = {
L
liuruilong 已提交
188 189 190 191 192 193 194 195 196 197
        .image_type = CL_MEM_OBJECT_IMAGE2D,
        .image_width = width,
        .image_height = height,
        .image_depth = 1,
        .image_array_size = 1,
        .image_row_pitch = 0,
        .image_slice_pitch = 0,
        .num_mip_levels = 0,
        .num_samples = 0,
        // .buffer = nullptr
D
dolphin8 已提交
198 199 200
    };
    cid.buffer = nullptr;
    cl_int err;
L
liuruilong 已提交
201
    cl_mem cl_image = clCreateImage(
L
liuruilong 已提交
202 203 204 205 206
        context, CL_MEM_READ_WRITE | (data ? CL_MEM_COPY_HOST_PTR : 0),
        &cf,   // const cl_image_format *image_format
        &cid,  // const cl_image_desc *image_desc
        data,  // void *host_ptr
        &err);
L
liuruilong 已提交
207
    cl_image_.reset(cl_image);
D
dolphin8 已提交
208 209 210 211 212
    if (err != CL_SUCCESS) {
      CL_CHECK_ERRORS(err);
      PADDLE_MOBILE_THROW_EXCEPTION(" create image 2d error ");
    }
  }
L
liuruilong 已提交
213

L
liuruilong 已提交
214
  bool initialized_ = false;
L
liuruilong 已提交
215
  std::unique_ptr<_cl_mem, CLMemDeleter> cl_image_;
L
liuruilong 已提交
216
  std::unique_ptr<_cl_event, CLEventDeleter> cl_event_;
217
  DDim tensor_dims_;
L
liuruilong 已提交
218
  DDim image_dims_;
L
liuruilong 已提交
219
  float *tensor_data_ = nullptr;
L
liuruilong 已提交
220
  cl_context context_;
Y
yangfei 已提交
221
  cl_command_queue command_queue_;
L
liuruilong 已提交
222
  CLImageConverterBase *image_converter_ = nullptr;
L
liuruilong 已提交
223 224
};

L
liuruilong 已提交
225 226
void TensorToCLImage(Tensor *tensor, CLImage *image,
                     cl_command_queue commandQueue);
Y
yangfei 已提交
227

L
liuruilong 已提交
228 229
void CLImageToTensor(CLImage *image, Tensor *tensor,
                     cl_command_queue commandQueue);
L
liuruilong 已提交
230

L
liuruilong 已提交
231 232 233 234
#ifdef PADDLE_MOBILE_DEBUG
Print &operator<<(Print &printer, const CLImage &image);
#endif

235 236
}  // namespace framework
}  // namespace paddle_mobile