void ImageImporter::execute() { if (mFilename == "") throw Exception("No filename was supplied to the ImageImporter"); uchar* convertedPixelData; // Load image from disk using Qt QImage image; reportInfo() << "Trying to load image..." << Reporter::end(); if(!image.load(mFilename.c_str())) { throw FileNotFoundException(mFilename); } reportInfo() << "Loaded image with size " << image.width() << " " << image.height() << Reporter::end(); QImage::Format format; if(mGrayscale) { format = QImage::Format_Grayscale8; } else { format = QImage::Format_RGB888; } QImage convertedImage = image.convertToFormat(format); // Get pixel data convertedPixelData = convertedImage.bits(); Image::pointer output = getOutputData<Image>(); std::cout << "image info" << std::endl; std::cout << convertedImage.width() << std::endl; std::cout << convertedImage.depth() << std::endl; std::cout << convertedImage.bytesPerLine() << std::endl; if(convertedImage.width()*convertedImage.depth()/8 != convertedImage.bytesPerLine()) { const int bytesPerPixel = (convertedImage.depth()/8); std::unique_ptr<uchar[]> fixedPixelData = std::make_unique<uchar[]>(image.width()*image.height()); // Misalignment for(int scanline = 0; scanline < image.height(); ++scanline) { std::memcpy( &fixedPixelData[scanline*image.width()*bytesPerPixel], &convertedPixelData[scanline*convertedImage.bytesPerLine()], image.width()*bytesPerPixel ); } output->create( image.width(), image.height(), TYPE_UINT8, mGrayscale ? 1 : 3, getMainDevice(), fixedPixelData.get() ); } else { output->create( image.width(), image.height(), TYPE_UINT8, mGrayscale ? 1 : 3, getMainDevice(), convertedPixelData ); } }
void BinaryThresholding::execute() { if(!mLowerThresholdSet && !mUpperThresholdSet) { throw Exception("BinaryThresholding need at least one threshold to be set."); } Image::pointer input = getStaticInputData<Image>(0); Segmentation::pointer output = getStaticOutputData<Segmentation>(0); output->createFromImage(input); if(getMainDevice()->isHost()) { throw Exception("Not implemented yet."); } else { OpenCLDevice::pointer device = OpenCLDevice::pointer(getMainDevice()); cl::Program program; if(input->getDimensions() == 3) { program = getOpenCLProgram(device, "3D"); } else { program = getOpenCLProgram(device, "2D"); } cl::Kernel kernel; if(mLowerThresholdSet && mUpperThresholdSet) { kernel = cl::Kernel(program, "tresholding"); kernel.setArg(3, mLowerThreshold); kernel.setArg(4, mUpperThreshold); } else if(mLowerThresholdSet) { kernel = cl::Kernel(program, "thresholdingWithOnlyLower"); kernel.setArg(3, mLowerThreshold); } else { kernel = cl::Kernel(program, "thresholdingWithOnlyUpper"); kernel.setArg(3, mUpperThreshold); } cl::NDRange globalSize; OpenCLImageAccess::pointer access = input->getOpenCLImageAccess(ACCESS_READ, device); if(input->getDimensions() == 2) { OpenCLImageAccess::pointer access2 = output->getOpenCLImageAccess(ACCESS_READ_WRITE, device); kernel.setArg(0, *access->get2DImage()); kernel.setArg(1, *access2->get2DImage()); globalSize = cl::NDRange(output->getWidth(), output->getHeight()); } else { // TODO no 3d image write support OpenCLImageAccess::pointer access2 = output->getOpenCLImageAccess(ACCESS_READ_WRITE, device); kernel.setArg(0, *access->get3DImage()); kernel.setArg(1, *access2->get3DImage()); globalSize = cl::NDRange(output->getWidth(), output->getHeight(), output->getDepth()); } kernel.setArg(2, (uchar)mLabel); cl::CommandQueue queue = device->getCommandQueue(); queue.enqueueNDRangeKernel( kernel, cl::NullRange, globalSize, cl::NullRange ); } }
void SeededRegionGrowing::recompileOpenCLCode(Image::pointer input) { // Check if there is a need to recompile OpenCL code if(input->getDimensions() == mDimensionCLCodeCompiledFor && input->getDataType() == mTypeCLCodeCompiledFor) return; OpenCLDevice::pointer device = getMainDevice(); std::string buildOptions = ""; if(input->getDataType() == TYPE_FLOAT) { buildOptions = "-DTYPE_FLOAT"; } else if(input->getDataType() == TYPE_INT8 || input->getDataType() == TYPE_INT16) { buildOptions = "-DTYPE_INT"; } else { buildOptions = "-DTYPE_UINT"; } std::string filename; if(input->getDimensions() == 2) { filename = "Algorithms/SeededRegionGrowing/SeededRegionGrowing2D.cl"; } else { filename = "Algorithms/SeededRegionGrowing/SeededRegionGrowing3D.cl"; } int programNr = device->createProgramFromSource(std::string(FAST_SOURCE_DIR) + filename, buildOptions); mKernel = cl::Kernel(device->getProgram(programNr), "seededRegionGrowing"); mDimensionCLCodeCompiledFor = input->getDimensions(); mTypeCLCodeCompiledFor = input->getDataType(); }
void Dilation::execute() { Image::pointer input = getInputData<Image>(); if(input->getDataType() != TYPE_UINT8) { throw Exception("Data type of image given to Dilation must be UINT8"); } Image::pointer output = getOutputData<Image>(); output->createFromImage(input); SceneGraph::setParentNode(output, input); output->fill(0); OpenCLDevice::pointer device = std::dynamic_pointer_cast<OpenCLDevice>(getMainDevice()); cl::CommandQueue queue = device->getCommandQueue(); cl::Program program = getOpenCLProgram(device); cl::Kernel dilateKernel(program, "dilate"); Vector3ui size = input->getSize(); OpenCLImageAccess::pointer access = input->getOpenCLImageAccess(ACCESS_READ, device); dilateKernel.setArg(0, *access->get3DImage()); dilateKernel.setArg(2, mSize/2); if(!device->isWritingTo3DTexturesSupported()) { OpenCLBufferAccess::pointer access2 = output->getOpenCLBufferAccess(ACCESS_READ_WRITE, device); dilateKernel.setArg(1, *access2->get()); queue.enqueueNDRangeKernel( dilateKernel, cl::NullRange, cl::NDRange(size.x(), size.y(), size.z()), cl::NullRange ); } else { OpenCLImageAccess::pointer access2 = output->getOpenCLImageAccess(ACCESS_READ_WRITE, device); dilateKernel.setArg(1, *access2->get3DImage()); queue.enqueueNDRangeKernel( dilateKernel, cl::NullRange, cl::NDRange(size.x(), size.y(), size.z()), cl::NullRange ); } }
void MeshRenderer::draw() { boost::lock_guard<boost::mutex> lock(mMutex); glEnable(GL_NORMALIZE); glShadeModel(GL_SMOOTH); glEnable(GL_LIGHTING); boost::unordered_map<uint, Mesh::pointer>::iterator it; for(it = mMeshToRender.begin(); it != mMeshToRender.end(); it++) { Mesh::pointer surfaceToRender = it->second; if(surfaceToRender->getDimensions() != 3) continue; // Draw the triangles in the VBO AffineTransformation::pointer transform = SceneGraph::getAffineTransformationFromData(surfaceToRender); glPushMatrix(); glMultMatrixf(transform->data()); float opacity = mDefaultOpacity; Color color = mDefaultColor; ProcessObjectPort port = getInputPort(it->first); if(mInputOpacities.count(port) > 0) { opacity = mInputOpacities[port]; } if(mInputColors.count(port) > 0) { color = mInputColors[port]; } // Set material properties if(opacity < 1) { // Enable transparency glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } GLfloat GLcolor[] = { color.getRedValue(), color.getGreenValue(), color.getBlueValue(), opacity }; glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, GLcolor); GLfloat specReflection[] = { mDefaultSpecularReflection, mDefaultSpecularReflection, mDefaultSpecularReflection, 1.0f }; glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specReflection); GLfloat shininess[] = { 16.0f }; glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess); VertexBufferObjectAccess::pointer access = surfaceToRender->getVertexBufferObjectAccess(ACCESS_READ, getMainDevice()); GLuint* VBO_ID = access->get(); // Normal Buffer glBindBuffer(GL_ARRAY_BUFFER, *VBO_ID); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glVertexPointer(3, GL_FLOAT, 24, 0); glNormalPointer(GL_FLOAT, 24, (float*)(sizeof(GLfloat)*3)); glDrawArrays(GL_TRIANGLES, 0, surfaceToRender->getNrOfTriangles()*3); // Release buffer glBindBuffer(GL_ARRAY_BUFFER, 0); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); if(opacity < 1) { // Disable transparency glDisable(GL_BLEND); } glPopMatrix(); } glDisable(GL_LIGHTING); glDisable(GL_NORMALIZE); glColor3f(1.0f, 1.0f, 1.0f); // Reset color }
void MeshRenderer::draw2D( cl::BufferGL PBO, uint width, uint height, Eigen::Transform<float, 3, Eigen::Affine> pixelToViewportTransform, float PBOspacing, Vector2f translation ) { boost::lock_guard<boost::mutex> lock(mMutex); OpenCLDevice::pointer device = getMainDevice(); cl::CommandQueue queue = device->getCommandQueue(); std::vector<cl::Memory> v; v.push_back(PBO); queue.enqueueAcquireGLObjects(&v); // Map would probably be better here, but doesn't work on NVIDIA, segfault surprise! //float* pixels = (float*)queue.enqueueMapBuffer(PBO, CL_TRUE, CL_MAP_WRITE, 0, width*height*sizeof(float)*4); boost::shared_array<float> pixels(new float[width*height*sizeof(float)*4]); queue.enqueueReadBuffer(PBO, CL_TRUE, 0, width*height*4*sizeof(float), pixels.get()); boost::unordered_map<uint, Mesh::pointer>::iterator it; for(it = mMeshToRender.begin(); it != mMeshToRender.end(); it++) { Mesh::pointer mesh = it->second; if(mesh->getDimensions() != 2) // Mesh must be 2D continue; Color color = mDefaultColor; ProcessObjectPort port = getInputPort(it->first); if(mInputColors.count(port) > 0) { color = mInputColors[port]; } MeshAccess::pointer access = mesh->getMeshAccess(ACCESS_READ); std::vector<VectorXui> lines = access->getLines(); std::vector<MeshVertex> vertices = access->getVertices(); // Draw each line for(int i = 0; i < lines.size(); ++i) { Vector2ui line = lines[i]; Vector2f a = vertices[line.x()].getPosition(); Vector2f b = vertices[line.y()].getPosition(); Vector2f direction = b - a; float lengthInPixels = ceil(direction.norm() / PBOspacing); // Draw the line for(int j = 0; j <= lengthInPixels; ++j) { Vector2f positionInMM = a + direction*((float)j/lengthInPixels); Vector2f positionInPixels = positionInMM / PBOspacing; int x = round(positionInPixels.x()); int y = round(positionInPixels.y()); y = height - 1 - y; if(x < 0 || y < 0 || x >= width || y >= height) continue; pixels[4*(x + y*width)] = color.getRedValue(); pixels[4*(x + y*width) + 1] = color.getGreenValue(); pixels[4*(x + y*width) + 2] = color.getBlueValue(); } } } //queue.enqueueUnmapMemObject(PBO, pixels); queue.enqueueWriteBuffer(PBO, CL_TRUE, 0, width*height*4*sizeof(float), pixels.get()); queue.enqueueReleaseGLObjects(&v); }
void ImageFileStreamer::producerStream() { Streamer::pointer pointerToSelf = mPtr.lock(); // try to avoid this object from being destroyed until this function is finished uint i = mStartNumber; while(true) { std::string filename = mFilenameFormat; std::string frameNumber = boost::lexical_cast<std::string>(i); if(mZeroFillDigits > 0 && frameNumber.size() < mZeroFillDigits) { std::string zeroFilling = ""; for(uint z = 0; z < mZeroFillDigits-frameNumber.size(); z++) { zeroFilling += "0"; } frameNumber = zeroFilling + frameNumber; } filename.replace( filename.find("#"), 1, frameNumber ); try { ImageFileImporter::pointer importer = ImageFileImporter::New(); importer->setFilename(filename); importer->setMainDevice(getMainDevice()); importer->update(); Image::pointer image = importer->getOutputData<Image>(); DynamicData::pointer ptr = getOutputData<Image>(); if(ptr.isValid()) { try { ptr->addFrame(image); if(mSleepTime > 0) boost::this_thread::sleep(boost::posix_time::milliseconds(mSleepTime)); } catch(NoMoreFramesException &e) { throw e; } catch(Exception &e) { std::cout << "streamer has been deleted, stop" << std::endl; break; } if(!mFirstFrameIsInserted) { { boost::lock_guard<boost::mutex> lock(mFirstFrameMutex); mFirstFrameIsInserted = true; } mFirstFrameCondition.notify_one(); } } else { std::cout << "DynamicImage object destroyed, stream can stop." << std::endl; break; } mNrOfFrames++; i += mStepSize; } catch(FileNotFoundException &e) { if(i > 0) { std::cout << "Reached end of stream" << std::endl; // If there where no files found at all, we need to release the execute method if(!mFirstFrameIsInserted) { { boost::lock_guard<boost::mutex> lock(mFirstFrameMutex); mFirstFrameIsInserted = true; } mFirstFrameCondition.notify_one(); } if(mLoop) { // Restart stream i = mStartNumber; continue; } mHasReachedEnd = true; // Reached end of stream break; } else { throw e; } } } }
void BinaryThresholding::waitToFinish() { OpenCLDevice::pointer device = OpenCLDevice::pointer(getMainDevice()); device->getCommandQueue().finish(); }
void SeededRegionGrowing::waitToFinish() { if(!getMainDevice()->isHost()) { OpenCLDevice::pointer device = getMainDevice(); device->getCommandQueue().finish(); } }
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 ImageSlicer::orthogonalSlicing(Image::pointer input, Image::pointer output) { OpenCLDevice::pointer device = getMainDevice(); // Determine slice nr and width and height unsigned int sliceNr; if(mOrthogonalSliceNr < 0) { switch(mOrthogonalSlicePlane) { case PLANE_X: sliceNr = input->getWidth()/2; break; case PLANE_Y: sliceNr = input->getHeight()/2; break; case PLANE_Z: sliceNr = input->getDepth()/2; break; } } else { // Check that mSliceNr is valid sliceNr = mOrthogonalSliceNr; switch(mOrthogonalSlicePlane) { case PLANE_X: if(sliceNr >= input->getWidth()) sliceNr = input->getWidth()-1; break; case PLANE_Y: if(sliceNr >= input->getHeight()) sliceNr = input->getHeight()-1; break; case PLANE_Z: if(sliceNr >= input->getDepth()) sliceNr = input->getDepth()-1; break; } } unsigned int slicePlaneNr, width, height; Vector3f spacing(0,0,0); switch(mOrthogonalSlicePlane) { case PLANE_X: slicePlaneNr = 0; width = input->getHeight(); height = input->getDepth(); spacing.x() = input->getSpacing().y(); spacing.y() = input->getSpacing().z(); break; case PLANE_Y: slicePlaneNr = 1; width = input->getWidth(); height = input->getDepth(); spacing.x() = input->getSpacing().x(); spacing.y() = input->getSpacing().z(); break; case PLANE_Z: slicePlaneNr = 2; width = input->getWidth(); height = input->getHeight(); spacing.x() = input->getSpacing().x(); spacing.y() = input->getSpacing().y(); break; } output->create(width, height, input->getDataType(), input->getNrOfComponents()); output->setSpacing(spacing); OpenCLImageAccess::pointer inputAccess = input->getOpenCLImageAccess(ACCESS_READ, device); OpenCLImageAccess::pointer outputAccess = output->getOpenCLImageAccess(ACCESS_READ_WRITE, device); cl::CommandQueue queue = device->getCommandQueue(); cl::Program program = getOpenCLProgram(device); cl::Kernel kernel(program, "orthogonalSlicing"); kernel.setArg(0, *inputAccess->get3DImage()); kernel.setArg(1, *outputAccess->get2DImage()); kernel.setArg(2, sliceNr); kernel.setArg(3, slicePlaneNr); queue.enqueueNDRangeKernel( kernel, cl::NullRange, cl::NDRange(width, height), cl::NullRange ); // TODO set scene graph transformation }
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); }