all_by_grace
all_by_grace

Reputation: 2345

Need help on a very simple Cuda and C++ program

I am a newbie in Cuda programming. I am trying to create a simple cuda and cpp image processing program, to alter the image's brightness, saturation, contrast, etc. I started with a very simple function, just to change the brightness of the image, by multiplying all the RGB components of the image with an alpha value.

This is my CPP program:

#include <cutil_inline.h>
#include <cutil_gl_inline.h>

#include <cuda_runtime_api.h>
#include <cuda_gl_interop.h>

using namespace std;

struct ImageData {
    unsigned char *data;    /* Points to large array of R,G,B-order data */
    int  height;
    int width;
};

ImageData imageData;
float *imageResult; // to store the image result from cuda after running the kernel
unsigned char *d_Input;
unsigned char *d_Output;
unsigned char *h_Output;

// These are CUDA functions to handle allocation and launching the kernels
extern "C" void initInput( unsigned char *data, unsigned char **device, unsigned int size); 
extern "C" void filter(unsigned char *d_src, unsigned char *d_dest, int width, int height, int filterMode, 
                float alpha, float contrast, float saturation, bool use_array );

void initCuda()
{
        unsigned int size = imageData.width * imageData.height * 3 * sizeof(unsigned char);
        cutilSafeCall(cudaMalloc ((void**) &d_Input, size));  // allocate storage for device image input
        cutilSafeCall(cudaMalloc ((void**) &d_Output, size)); // allocate storage for device image output
    initInput( imageData.data, &d_Input, size); 
}

int main () {


    loadPPMImageData( (char *)"boxes.ppm", &imageData); //this function is defined in another file
    cudaGLSetGLDevice( 0 );
    initCuda();
    filter(  d_Input, d_Output, imageData.width, imageData.height, 1, 0.8, 1.0, 1.0, 1 );

    cutilSafeCall(cudaMemcpy( h_Output, d_Output, size, cudaMemcpyDeviceToHost)); // copy output data from device to host
    //print the output
    for (int i = 0; i < imageData.size; i++) {
        cout << d_Output
    }
    // do some memory cleanups

    //done
    return 0
}

And this is my kernel.cu file:

#include <iostream>
#include <cstdlib>
#include <string>
#include <cmath>

#include <shrUtils.h>
#include <cutil_inline.h>
#include <cutil_math.h>


//Kernel function
__global__ void
applyAlpha(unsigned char* input, unsigned char* output, int width, int height, float alpha) 
{
// calculate normalized coordinates
unsigned int x = blockIdx.x * blockDim.x + threadIdx.x;
unsigned int y = blockIdx.y * blockDim.y + threadIdx.y;
output[ ((y * width + x) * 3) + 0] = (int) ( (int)input [ ((y * width + x) * 3) + 0] * alpha); // r
output[ ((y * width + x) * 3) + 1] = (int) ( (int)input [ ((y * width + x) * 3) + 1] * alpha); // g
output[ ((y * width + x) * 3) + 2] = (int) ( (int)input [ ((y * width + x) * 3) + 2] * alpha); // b
}


extern "C"
int iDivUp( int a, int b ){
    return (a % b != 0) ? (a / b + 1) : (a / b);
}


extern "C" 
void initInput( unsigned char *data, unsigned char **deviceArray, unsigned int size) // /* image data, device pointer, etc */ )
{
    /* TODO: Array version DONE
     *  Initialize device memory for array version
     *  and cuda arrays for texture version here
     */
    cutilSafeCall(cudaMemcpy( deviceArray, data, size, cudaMemcpyHostToDevice)); // copy image data from host to device (array version)
    //TODO: Texture version

}


extern "C" 
void filter( unsigned char *d_src, unsigned char *d_dest, int width, int height, int filter_mode, float alpha, float contrast, float saturation, bool use_array )
{
    /*  TODO
     * run different kernels for array and texture version
     */

    dim3 dimBlock(16, 16, 1);
    dim3 dimGrid( iDivUp (width, dimBlock.x), iDivUp( height, dimBlock.y), 1);

    if (use_array) { // Array version
        if (filter_mode == 1) { // filter mode: brightness (alpha)

            applyAlpha<<< dimGrid, dimBlock >>>(d_src, d_dest, width, height, alpha);

            // check if kernel execution generated an error
            cutilCheckMsg("Kernel execution failed");

            cutilSafeCall( cutilDeviceSynchronize() );
        }
    }
    else { //Texture Version
        //not yet implemented
    }

}

//EDIT I have modified the above file, based on the answer from Andrew. However now I got the following errors after compiling it:

ld: warning: ignoring file kernel.o, file was built for i386 which is not the architecture being linked (x86_64)
Undefined symbols for architecture x86_64:
  "_initInput", referenced from:
      initCuda()    in CS380_prog4.o
  "_filter", referenced from:
      display()     in CS380_prog4.o
     (maybe you meant: ___GLEW_SGIS_texture_filter4, ___GLEW_EXT_texture_filter_anisotropic , ___GLEW_NV_multisample_filter_hint )
ld: symbol(s) not found for architecture x86_64
collect2: ld returned 1 exit status
make: *** [testprog] Error 1

I have used the "extern C" command in both of those functions : initInput, and filter. The function declaration (in test.cpp) and definition (in kernel.cu) also have the same arguments, but it is still complaining that it cannot find the function. How can I fix this linking problem?

Upvotes: 1

Views: 5356

Answers (2)

karlphillip
karlphillip

Reputation: 93468

There's a fine example in cuda-grayscale.

It used to compile on CUDA 3.1. There's a Makefile in there, take a peak at it.

CXX=g++

CUDA_INSTALL_PATH=/usr/local/cuda
CFLAGS= -I. -I$(CUDA_INSTALL_PATH)/include `pkg-config --cflags opencv`
LDFLAGS= -L$(CUDA_INSTALL_PATH)/lib -lcudart `pkg-config --libs opencv`    

all:
        $(CXX) $(CFLAGS) -c main.cpp -o Debug/main.o
        nvcc $(CUDAFLAGS) -c kernel_gpu.cu -o Debug/kernel_gpu.o
        $(CXX) $(LDFLAGS) Debug/main.o Debug/kernel_gpu.o -o Debug/grayscale

clean:
        rm -f Debug/*.o Debug/grayscale

Upvotes: 0

asm
asm

Reputation: 8898

You're including your .cu file directly in the .cpp file which effectively copies the contents into the .cpp file. nvcc will use a standard C++ compiler to compile it (g++ on a unix platform) which will have no idea what any of the Cuda syntax means.

You have to compile each one as an object file and then link them with the C++ compiler, making a header for the exported functions in the .cu file the same way you would for standard C.

Upvotes: 4

Related Questions