* HistogramRect * Otsu Thresholding Operations * histogramAllChannels is laid out as all channel 0, then all channel 1... * only supports 1 or 4 channels (bytes_per_pixel) ************************************************************************/
| 1766 | * only supports 1 or 4 channels (bytes_per_pixel) |
| 1767 | ************************************************************************/ |
| 1768 | int OpenclDevice::HistogramRectOCL(unsigned char *imageData, |
| 1769 | int bytes_per_pixel, int bytes_per_line, |
| 1770 | int left, // always 0 |
| 1771 | int top, // always 0 |
| 1772 | int width, int height, int kHistogramSize, |
| 1773 | int *histogramAllChannels) { |
| 1774 | PERF_COUNT_START("HistogramRectOCL") |
| 1775 | cl_int clStatus; |
| 1776 | int retVal = 0; |
| 1777 | KernelEnv histKern; |
| 1778 | SetKernelEnv(&histKern); |
| 1779 | KernelEnv histRedKern; |
| 1780 | SetKernelEnv(&histRedKern); |
| 1781 | /* map imagedata to device as read only */ |
| 1782 | // USE_HOST_PTR uses onion+ bus which is slowest option; also happens to be |
| 1783 | // coherent which we don't need. |
| 1784 | // faster option would be to allocate initial image buffer |
| 1785 | // using a garlic bus memory type |
| 1786 | cl_mem imageBuffer = clCreateBuffer( |
| 1787 | histKern.mpkContext, CL_MEM_READ_ONLY | CL_MEM_USE_HOST_PTR, |
| 1788 | width * height * bytes_per_pixel * sizeof(char), imageData, &clStatus); |
| 1789 | CHECK_OPENCL(clStatus, "clCreateBuffer imageBuffer"); |
| 1790 | |
| 1791 | /* setup work group size parameters */ |
| 1792 | int block_size = 256; |
| 1793 | cl_uint numCUs; |
| 1794 | clStatus = clGetDeviceInfo(gpuEnv.mpDevID, CL_DEVICE_MAX_COMPUTE_UNITS, |
| 1795 | sizeof(numCUs), &numCUs, NULL); |
| 1796 | CHECK_OPENCL(clStatus, "clCreateBuffer imageBuffer"); |
| 1797 | |
| 1798 | int requestedOccupancy = 10; |
| 1799 | int numWorkGroups = numCUs * requestedOccupancy; |
| 1800 | int numThreads = block_size * numWorkGroups; |
| 1801 | size_t local_work_size[] = {static_cast<size_t>(block_size)}; |
| 1802 | size_t global_work_size[] = {static_cast<size_t>(numThreads)}; |
| 1803 | size_t red_global_work_size[] = { |
| 1804 | static_cast<size_t>(block_size * kHistogramSize * bytes_per_pixel)}; |
| 1805 | |
| 1806 | /* map histogramAllChannels as write only */ |
| 1807 | |
| 1808 | cl_mem histogramBuffer = clCreateBuffer( |
| 1809 | histKern.mpkContext, CL_MEM_READ_WRITE | CL_MEM_USE_HOST_PTR, |
| 1810 | kHistogramSize * bytes_per_pixel * sizeof(int), histogramAllChannels, |
| 1811 | &clStatus); |
| 1812 | CHECK_OPENCL(clStatus, "clCreateBuffer histogramBuffer"); |
| 1813 | |
| 1814 | /* intermediate histogram buffer */ |
| 1815 | int histRed = 256; |
| 1816 | int tmpHistogramBins = kHistogramSize * bytes_per_pixel * histRed; |
| 1817 | |
| 1818 | cl_mem tmpHistogramBuffer = |
| 1819 | clCreateBuffer(histKern.mpkContext, CL_MEM_READ_WRITE, |
| 1820 | tmpHistogramBins * sizeof(cl_uint), NULL, &clStatus); |
| 1821 | CHECK_OPENCL(clStatus, "clCreateBuffer tmpHistogramBuffer"); |
| 1822 | |
| 1823 | /* atomic sync buffer */ |
| 1824 | int *zeroBuffer = new int[1]; |
| 1825 | zeroBuffer[0] = 0; |