void getIntensitySumFromOpenCLImage(OpenCLDevice::pointer device, cl::Image2D image, DataType type, float* sum) { // Get power of two size unsigned int powerOfTwoSize = getPowerOfTwoSize(std::max(image.getImageInfo<CL_IMAGE_WIDTH>(), image.getImageInfo<CL_IMAGE_HEIGHT>())); // Create image levels unsigned int size = powerOfTwoSize; size /= 2; std::vector<cl::Image2D> levels; while(size >= 4) { cl::Image2D level = cl::Image2D(device->getContext(), CL_MEM_READ_WRITE, getOpenCLImageFormat(device, CL_MEM_OBJECT_IMAGE2D, TYPE_FLOAT, 1), size, size); levels.push_back(level); size /= 2; } // Compile OpenCL code std::string buildOptions = ""; switch(type) { case TYPE_FLOAT: buildOptions = "-DTYPE_FLOAT"; break; case TYPE_UINT8: buildOptions = "-DTYPE_UINT8"; break; case TYPE_INT8: buildOptions = "-DTYPE_INT8"; break; case TYPE_UINT16: buildOptions = "-DTYPE_UINT16"; break; case TYPE_INT16: buildOptions = "-DTYPE_INT16"; break; } std::string sourceFilename = std::string(FAST_SOURCE_DIR) + "/ImageSum.cl"; std::string programName = sourceFilename + buildOptions; // Only create program if it doesn't exist for this device from before if(!device->hasProgram(programName)) device->createProgramFromSourceWithName(programName, sourceFilename, buildOptions); cl::Program program = device->getProgram(programName); cl::CommandQueue queue = device->getCommandQueue(); // Fill first level size = powerOfTwoSize/2; cl::Kernel firstLevel(program, "createFirstSumImage2DLevel"); firstLevel.setArg(0, image); firstLevel.setArg(1, levels[0]); queue.enqueueNDRangeKernel( firstLevel, cl::NullRange, cl::NDRange(size,size), cl::NullRange ); // Fill all other levels cl::Kernel createLevel(program, "createSumImage2DLevel"); int i = 0; size /= 2; while(size >= 4) { createLevel.setArg(0, levels[i]); createLevel.setArg(1, levels[i+1]); queue.enqueueNDRangeKernel( createLevel, cl::NullRange, cl::NDRange(size,size), cl::NullRange ); i++; size /= 2; } // Get result from the last level unsigned int nrOfElements = 4*4; unsigned int nrOfComponents = getOpenCLImageFormat(device, CL_MEM_OBJECT_IMAGE2D, TYPE_FLOAT, 1).image_channel_order == CL_RGBA ? 4 : 1; float* result = (float*)allocateDataArray(nrOfElements,TYPE_FLOAT,nrOfComponents); queue.enqueueReadImage(levels[levels.size()-1],CL_TRUE,createOrigoRegion(),createRegion(4,4,1),0,0,result); *sum = getSumFromOpenCLImageResult<float>(result, nrOfElements, nrOfComponents); delete[] result; }
void SeededRegionGrowing::execute() { if(mSeedPoints.size() == 0) throw Exception("No seed points supplied to SeededRegionGrowing"); Image::pointer input = getStaticInputData<Image>(); if(input->getNrOfComponents() != 1) throw Exception("Seeded region growing currently doesn't support images with several components."); Segmentation::pointer output = getStaticOutputData<Segmentation>(); // Initialize output image output->createFromImage(input, getMainDevice()); if(getMainDevice()->isHost()) { ImageAccess::pointer inputAccess = input->getImageAccess(ACCESS_READ); void* inputData = inputAccess->get(); switch(input->getDataType()) { fastSwitchTypeMacro(executeOnHost<FAST_TYPE>((FAST_TYPE*)inputData, output)); } } else { OpenCLDevice::pointer device = getMainDevice(); recompileOpenCLCode(input); ImageAccess::pointer access = output->getImageAccess(ACCESS_READ_WRITE); uchar* outputData = (uchar*)access->get(); // Initialize to all 0s memset(outputData,0,sizeof(uchar)*output->getWidth()*output->getHeight()*output->getDepth()); // Add sedd points for(int i = 0; i < mSeedPoints.size(); i++) { Vector3ui pos = mSeedPoints[i]; // Check if seed point is in bounds if(pos.x() < 0 || pos.y() < 0 || pos.z() < 0 || pos.x() >= output->getWidth() || pos.y() >= output->getHeight() || pos.z() >= output->getDepth()) throw Exception("One of the seed points given to SeededRegionGrowing was out of bounds."); outputData[pos.x() + pos.y()*output->getWidth() + pos.z()*output->getWidth()*output->getHeight()] = 2; } access->release(); cl::NDRange globalSize; if(output->getDimensions() == 2) { globalSize = cl::NDRange(input->getWidth(),input->getHeight()); OpenCLImageAccess2D::pointer inputAccess = input->getOpenCLImageAccess2D(ACCESS_READ, device); mKernel.setArg(0, *inputAccess->get()); } else { globalSize = cl::NDRange(input->getWidth(),input->getHeight(), input->getDepth()); OpenCLImageAccess3D::pointer inputAccess = input->getOpenCLImageAccess3D(ACCESS_READ, device); mKernel.setArg(0, *inputAccess->get()); } OpenCLBufferAccess::pointer outputAccess = output->getOpenCLBufferAccess(ACCESS_READ_WRITE, device); cl::Buffer stopGrowingBuffer = cl::Buffer( device->getContext(), CL_MEM_READ_WRITE, sizeof(char)); cl::CommandQueue queue = device->getCommandQueue(); mKernel.setArg(1, *outputAccess->get()); mKernel.setArg(2, stopGrowingBuffer); mKernel.setArg(3, mMinimumIntensity); mKernel.setArg(4, mMaximumIntensity); bool stopGrowing = false; char stopGrowingInit = 1; char * stopGrowingResult = new char; int iterations = 0; do { iterations++; queue.enqueueWriteBuffer(stopGrowingBuffer, CL_TRUE, 0, sizeof(char), &stopGrowingInit); queue.enqueueNDRangeKernel( mKernel, cl::NullRange, globalSize, cl::NullRange ); queue.enqueueReadBuffer(stopGrowingBuffer, CL_TRUE, 0, sizeof(char), stopGrowingResult); if(*stopGrowingResult == 1) stopGrowing = true; } while(!stopGrowing); } }
void getMaxAndMinFromOpenCLBuffer(OpenCLDevice::pointer device, cl::Buffer buffer, unsigned int size, DataType type, float* min, float* max) { // Compile OpenCL code std::string buildOptions = ""; switch(type) { case TYPE_FLOAT: buildOptions = "-DTYPE_FLOAT"; break; case TYPE_UINT8: buildOptions = "-DTYPE_UINT8"; break; case TYPE_INT8: buildOptions = "-DTYPE_INT8"; break; case TYPE_UINT16: buildOptions = "-DTYPE_UINT16"; break; case TYPE_INT16: buildOptions = "-DTYPE_INT16"; break; } std::string sourceFilename = std::string(FAST_SOURCE_DIR) + "/ImageMinMax.cl"; std::string programName = sourceFilename + buildOptions; // Only create program if it doesn't exist for this device from before if(!device->hasProgram(programName)) device->createProgramFromSourceWithName(programName, sourceFilename, buildOptions); cl::Program program = device->getProgram(programName); cl::CommandQueue queue = device->getCommandQueue(); // Nr of work groups must be set so that work-group size does not exceed max work-group size (256 on AMD) int length = size; cl::Kernel reduce(program, "reduce"); cl::Buffer current = buffer; cl::Buffer clResult; int workGroupSize = 256; int workGroups = 256; int X = ceil((float)length / (workGroups*workGroupSize)); clResult = cl::Buffer(device->getContext(), CL_MEM_READ_WRITE, getSizeOfDataType(type,1)*workGroups*2); reduce.setArg(0, current); reduce.setArg(1, workGroupSize * getSizeOfDataType(type,1), NULL); reduce.setArg(2, workGroupSize * getSizeOfDataType(type,1), NULL); reduce.setArg(3, size); reduce.setArg(4, X); reduce.setArg(5, clResult); queue.enqueueNDRangeKernel( reduce, cl::NullRange, cl::NDRange(workGroups*workGroupSize), cl::NDRange(workGroupSize) ); length = workGroups; void* result = allocateDataArray(length, type, 2); unsigned int nrOfElements = length; queue.enqueueReadBuffer(clResult,CL_TRUE,0,getSizeOfDataType(type,1)*workGroups*2,result); switch(type) { case TYPE_FLOAT: getMaxAndMinFromOpenCLImageResult<float>(result, nrOfElements, 2, min, max); break; case TYPE_INT8: getMaxAndMinFromOpenCLImageResult<char>(result, nrOfElements, 2, min, max); break; case TYPE_UINT8: getMaxAndMinFromOpenCLImageResult<uchar>(result, nrOfElements, 2, min, max); break; case TYPE_INT16: getMaxAndMinFromOpenCLImageResult<short>(result, nrOfElements, 2, min, max); break; case TYPE_UINT16: getMaxAndMinFromOpenCLImageResult<ushort>(result, nrOfElements, 2, min, max); break; } deleteArray(result, type); }
void SegmentationRenderer::draw(Matrix4f perspectiveMatrix, Matrix4f viewingMatrix, float zNear, float zFar, bool mode2D) { std::lock_guard<std::mutex> lock(mMutex); OpenCLDevice::pointer device = std::dynamic_pointer_cast<OpenCLDevice>(getMainDevice()); if(mColorsModified) { // Transfer colors to device (this doesn't have to happen every render call..) std::unique_ptr<float[]> colorData(new float[3*mLabelColors.size()]); std::unordered_map<int, Color>::iterator it; for(it = mLabelColors.begin(); it != mLabelColors.end(); it++) { colorData[it->first*3] = it->second.getRedValue(); colorData[it->first*3+1] = it->second.getGreenValue(); colorData[it->first*3+2] = it->second.getBlueValue(); } mColorBuffer = cl::Buffer( device->getContext(), CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(float)*3*mLabelColors.size(), colorData.get() ); } if(mFillAreaModified) { // Transfer colors to device (this doesn't have to happen every render call..) std::unique_ptr<char[]> fillAreaData(new char[mLabelColors.size()]); std::unordered_map<int, Color>::iterator it; for(it = mLabelColors.begin(); it != mLabelColors.end(); it++) { if(mLabelFillArea.count(it->first) == 0) { // Use default value fillAreaData[it->first] = mFillArea; } else { fillAreaData[it->first] = mLabelFillArea[it->first]; } } mFillAreaBuffer = cl::Buffer( device->getContext(), CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof(char)*mLabelColors.size(), fillAreaData.get() ); } mKernel = cl::Kernel(getOpenCLProgram(device), "renderToTexture"); mKernel.setArg(2, mColorBuffer); mKernel.setArg(3, mFillAreaBuffer); mKernel.setArg(4, mBorderRadius); mKernel.setArg(5, mOpacity); for(auto it : mDataToRender) { Image::pointer input = std::static_pointer_cast<Image>(it.second); uint inputNr = it.first; if(input->getDimensions() != 2) throw Exception("SegmentationRenderer only supports 2D images. Use ImageSlicer to extract a 2D slice from a 3D image."); if(input->getDataType() != TYPE_UINT8) throw Exception("SegmentationRenderer only support images with dat type uint8."); // Check if a texture has already been created for this image if(mTexturesToRender.count(inputNr) > 0 && mImageUsed[inputNr] == input) continue; // If it has already been created, skip it // If it has not been created, create the texture OpenCLImageAccess::pointer access = input->getOpenCLImageAccess(ACCESS_READ, device); cl::Image2D *clImage = access->get2DImage(); // Run kernel to fill the texture cl::CommandQueue queue = device->getCommandQueue(); if (mTexturesToRender.count(inputNr) > 0) { // Delete old texture glDeleteTextures(1, &mTexturesToRender[inputNr]); mTexturesToRender.erase(inputNr); glDeleteVertexArrays(1, &mVAO[inputNr]); mVAO.erase(inputNr); } cl::Image2D image; cl::ImageGL imageGL; std::vector<cl::Memory> v; GLuint textureID; // TODO The GL-CL interop here is causing glClear to not work on AMD systems and therefore disabled /* if(DeviceManager::isGLInteropEnabled()) { // Create OpenGL texture glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, input->getWidth(), input->getHeight(), 0, GL_RGBA, GL_FLOAT, 0); // Create CL-GL image imageGL = cl::ImageGL( device->getContext(), CL_MEM_READ_WRITE, GL_TEXTURE_2D, 0, textureID ); glBindTexture(GL_TEXTURE_2D, 0); glFinish(); mKernel.setArg(1, imageGL); v.push_back(imageGL); queue.enqueueAcquireGLObjects(&v); } else { */ image = cl::Image2D( device->getContext(), CL_MEM_READ_WRITE, cl::ImageFormat(CL_RGBA, CL_FLOAT), input->getWidth(), input->getHeight() ); mKernel.setArg(1, image); //} mKernel.setArg(0, *clImage); queue.enqueueNDRangeKernel( mKernel, cl::NullRange, cl::NDRange(input->getWidth(), input->getHeight()), cl::NullRange ); /*if(DeviceManager::isGLInteropEnabled()) { queue.enqueueReleaseGLObjects(&v); } else {*/ // Copy data from CL image to CPU auto data = make_uninitialized_unique<float[]>(input->getWidth() * input->getHeight() * 4); queue.enqueueReadImage( image, CL_TRUE, createOrigoRegion(), createRegion(input->getWidth(), input->getHeight(), 1), 0, 0, data.get() ); // Copy data from CPU to GL texture glGenTextures(1, &textureID); glBindTexture(GL_TEXTURE_2D, textureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, input->getWidth(), input->getHeight(), 0, GL_RGBA, GL_FLOAT, data.get()); glBindTexture(GL_TEXTURE_2D, 0); glFinish(); //} mTexturesToRender[inputNr] = textureID; mImageUsed[inputNr] = input; queue.finish(); } glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); drawTextures(perspectiveMatrix, viewingMatrix, mode2D); glDisable(GL_BLEND); }