4#include "../core/common.hpp"
5#include "../core/exceptions.hpp"
9#include <cuda_runtime.h>
10#include <device_launch_parameters.h>
12#define cudaCheck(fn) do {cudaError_t e = fn; if (e != cudaSuccess) throw CellularAutomata::exception::CudaRuntime(cudaGetErrorString(e)); } while(false)
24__device__ __forceinline__
unsigned int modP(
const int a,
const int n)
33__device__
void loadShared_recursive(
const T* __restrict__ input, T* shared,
const uint2 inputShape,
const uint2 sharedShape,
const unsigned int kernelSize,
const uint4 valid)
35 const int halo = kernelSize / 2;
36 const int tid = threadIdx.y * blockDim.x + threadIdx.x;
37 const int memSize = sharedShape.y * sharedShape.x;
38 const int threadsPerBlock = blockDim.y * blockDim.x;
41 for (
int i = tid; i < memSize; i += threadsPerBlock)
44 int y = i / sharedShape.x;
45 int x = i % sharedShape.x;
48 if (y < (valid.w + kernelSize - 1) && x < (valid.z + kernelSize - 1))
52 y = modP(y + valid.y - halo, inputShape.y);
53 x = modP(x + valid.x - halo, inputShape.x);
56 shared[i] = input[y * inputShape.x + x];
62__device__
void loadShared_simple(
const T* __restrict__ input, T* shared,
const int inputWidth,
const int sharedWidth,
const unsigned int kernelSize,
const uint4 valid)
64 const int halo = kernelSize / 2;
66 if (threadIdx.y < valid.w && threadIdx.x < valid.z)
69 shared[(threadIdx.y + halo) * sharedWidth + (threadIdx.x + halo)] = input[threadIdx.y * inputWidth + threadIdx.x];
73template<
typename T,
typename Activation>
74__global__
void convKernel(
75 const T* __restrict__ input,
76 const T* __restrict__ kernel,
79 const uint2 inputShape,
80 const unsigned int kernelSize,
83 extern __shared__ T shared[];
85#pragma region Variables
88 const uint2 pos{ blockIdx.x * blockDim.x + threadIdx.x, blockIdx.y * blockDim.y + threadIdx.y };
91 const uint2 sharedShape{ blockDim.x + kernelSize - 1, blockDim.y + kernelSize - 1 };
96 blockIdx.x * blockDim.x,
97 blockIdx.y * blockDim.y,
98 min(inputShape.x - (blockIdx.x * blockDim.x), blockDim.x),
99 min(inputShape.y - (blockIdx.y * blockDim.y), blockDim.y)
102#pragma endregion Variables
105#pragma region Loading
108 loadShared_recursive(input, shared, inputShape, sharedShape, kernelSize, valid);
110 loadShared_simple(input, shared, inputShape.x, sharedShape.x, kernelSize, valid);
112#pragma endregion Loading
116#pragma region Matrix mul
119 if (threadIdx.x < valid.z && threadIdx.y < valid.w)
124 for (
int y = 0; y < kernelSize; y++)
126 for (
int x = 0; x < kernelSize; x++)
128 int _shared = (threadIdx.y + y) * sharedShape.x + (threadIdx.x + x);
130 temp += shared[_shared] * kernel[y * kernelSize + x];
134 output[pos.y * inputShape.x + pos.x] = fn(temp);
147 cudaCheck(cudaMalloc(arrayPtr, bytes));
152 cudaCheck(cudaMallocHost(arrayPtr, bytes));
157 cudaCheck(cudaFree(array));
162 cudaCheck(cudaFreeHost(array));
167 cudaCheck(cudaMemcpy(dst, src, bytes, cudaMemcpyKind::cudaMemcpyDefault));
170 template <
typename T,
typename Activation>
172 T* input, T* kernel, T* output, Activation fn,
173 const unsigned int h,
const unsigned int w,
const unsigned int s,
const bool r)
175 dim3 grid(((w - 1) / TILE_SIZE) + 1, ((h - 1) / TILE_SIZE) + 1);
176 dim3 block(TILE_SIZE, TILE_SIZE);
177 size_t memSize = (TILE_SIZE + s - 1) * (TILE_SIZE + s - 1) *
sizeof(T);
183 convKernel<<<grid, block, memSize>>> (
184 input, kernel, output, fn,
185 uint2{ h, w }, s, r);
194 cudaCheck(cudaDeviceSynchronize());
void copyCUDA(void *src, Device from, void *dst, Device to, size_t bytes)
Memcopy between devices and host.
Definition cuda.inl:165
void allocateHost(void **arrayPtr, size_t bytes)
Allocated memory on the host device (CPU)
Definition cuda.inl:150
void allocateCUDA(void **arrayPtr, size_t bytes)
Allocated memory on a CUDA device.
Definition cuda.inl:145
void freeCUDA(void *array)
Frees memory on a CUDA device.
Definition cuda.inl:155
void freeHost(void *array)
Frees memory on the host device (CPU)
Definition cuda.inl:160
Main namespace.
Definition common.hpp:33
Device
Computational device.
Definition common.hpp:39