diff --git a/src/array.jl b/src/array.jl index 08bfb03..473edde 100644 --- a/src/array.jl +++ b/src/array.jl @@ -167,6 +167,49 @@ const copyfun = VERSION >= v"0.7.0-DEV.3057" ? :(copyto!) : :(copy!) Mem.transfer!(dst.buf, src.buf, length(src) * sizeof(T)) return dst end + + """ + $copyfun{T}(dst::CuArray{T}, src::SubArray{T,N,<:DenseArray,I,true}) + + Copy an array view from a host array `src` to a device array `dst` in place. Both arrays + should have an equal length, and the view must have a contiguous memory layout. + """ + function Base.$copyfun(dst::CuArray{T}, src::SubArray{T,N,<:DenseArray,I,true}) where {T,N,I} + if length(dst) != length(src) + throw(ArgumentError("Inconsistent array length.")) + end + if any(strides(src) .!= strides(parent(src))) + throw(ArgumentError("Transfers from an array view require contiguous memory layout.")) + end + Mem.upload!(dst.buf, pointer(src), length(src) * sizeof(T)) + return dst + end + + function Base.$copyfun(dst::CuArray, src::SubArray) + throw(ArgumentError("Transfers from an array view require a contiguous memory layout.")) + end + + """ + $copyfun{T}(dst::SubArray{T,N,A,I,true}, src::CuArray{T}) + + Copy an array from a device array `src` to a host array view `dst` in place. Both arrays + should have an equal length, and the view must have a contiguous memory layout. + """ + function Base.$copyfun(dst::SubArray{T,N,<:DenseArray,I,true}, src::CuArray{T}) where {T,N,I} + if length(dst) != length(src) + throw(ArgumentError("Inconsistent array length.")) + end + if any(strides(dst) .!= strides(parent(dst))) + throw(ArgumentError("Transfers to an array view require contiguous memory layout.")) + end + Mem.download!(pointer(dst), src.buf, length(src) * sizeof(T)) + return dst + end + + function Base.$copyfun(dst::SubArray, src::CuArray) + throw(ArgumentError("Transfers to an array view require a contiguous memory layout.")) + end + end diff --git a/test/array.jl b/test/array.jl index bcd67a7..8672978 100644 --- a/test/array.jl +++ b/test/array.jl @@ -98,6 +98,33 @@ let @assert cpu == cpu_back end + # copy views to and from device + let + gpu = CuArray{Float32}(10,10,3) + cpu = rand(Float32, 10,10,10) + + cpuv1 = view(cpu, :, :, 1:3) + + copy!(gpu, cpuv1) + + cpu_back = Array{Float32}(uninitialized, 10, 10, 3) + copy!(cpu_back, gpu) + @assert cpuv1 == cpu_back + + cpuv1 .= 0 + copy!(cpuv1, gpu) + @assert cpuv1 == cpu[:,:,1:3] + + cpuv2 = view(cpu, 1:3, :, :) # correct length, not contiguous + @test_throws ArgumentError copy!(gpu, cpuv2) + + cpuv3 = view(cpu, :, :, 1:4) # wrong dimensions, but contiguous + @test_throws ArgumentError copy!(gpu, cpuv3) + + end + + + # copy on device let gpu = CuArray(rand(Float32, 10)) gpu_copy = copy(gpu)