JuliaGPU / CUDA.jl

CUDA programming in Julia.
https://juliagpu.org/cuda/
Other
1.21k stars 221 forks source link

Document kernel indexing for 2D arrays #218

Open grassofsky opened 4 years ago

grassofsky commented 4 years ago

need more example for multi array operation.

I try to write some learning code. But compile failed, and don't know what todo. So need more examples to learn how to use this package. Thankyou all

maleadt commented 4 years ago

What do you mean by 'multi array operation'? Did you read the introduction tutorial?

grassofsky commented 4 years ago

What do you mean by 'multi array operation'? Did you read the introduction tutorial?

Thank you for replying.

I am newbie on gpu calculating. I read the tutorial on https://juliagpu.gitlab.io/CUDA.jl/tutorials/introduction/.

The tutorial is very clear for me. But it only contains vector-related operation. The multi-dimention operation (2-D array) is like this:

n = 320
pixels = Array{Float32}(undef, n*2, n)

function paint!(pixels::Array{Float32}, t)
    pixels_size = size(pixels)
    for i = 1:pixels_size[1]
        for j = 1:pixels_size[2]
            c = Complex(-0.8, cos(t)*0.2)
            z = Complex(i / n - 1, j / n - 0.5) * 2
            iterations = 0
            while abs(z) < 20 && iterations < 50
                z = z^2 + c 
                iterations += 1
            end
            pixels[i, j] = 1 - iterations * 0.02
        end
    end

    return
end

for i in 1:2
    paint!(pixels, i*0.03)
end

I search the internet, much examples are related to cudanative.jl. (I am not familiar with that too). Does some other rich tutorial for introducing to use Cuda.jl?

Thank you.

maleadt commented 4 years ago

I search the internet, much examples are related to cudanative.jl. (I am not familiar with that too). Does some other rich tutorial for introducing to use Cuda.jl?

CUDA.jl contains what used to be called CUDAnative.jl (together with CuArrays.jl and CUDAdrv.jl).

Ellipse0934 commented 4 years ago

@grassofsky There are basically two ways you can go about it. The first is to write a custom kernel where given the input 2-D array each GPU thread computes for an individual pixel. Here threadIdx().x and threadIdx().y will give the respective x and y coordinates. This is more like the CUDA C code you will generally encounter.

The second way is to use broadcasting to apply the paint function to every element of the pixels array. You should look into native julia features like broadcasting and advanced indexing to enable you to write GPU code with ease.

Rewriting the original paint function ->

function paint2(pixel, index, n, t)
           (i, j) = index.I
           c = Complex(-0.8, CUDA.cos(t)*0.2)
           z = Complex(i / n - 1, j / n - 0.5) * 2
           iterations = 0
           while CUDA.abs(z) < 20 && iterations < 50
               z = z^2 + c 
               iterations += 1
           end
           pixel = 1 - iterations * 0.02
           return pixel
end

Then to execute on the GPU

julia> using ImageView, CUDA

julia> pixels2 = CuArray{Float32}(undef, 2*n, n);

julia> for i in 1:2
             pixels2 .= paint2.(pixels2, CartesianIndices(pixels2), n, i*0.03);
         end
julia> image = collect(pixels2);

julia> imshow(image);

The annoying thing is of course that we had to write CUDA.cos and CUDA.abs which is currently a problem, but in the future when this gets resolved you should be able to simple write cos and it will run on both the CPU and GPU depending on where the input array is stored.