ocl: refactor program compilation
authorAlexander Alekhin <alexander.alekhin@intel.com>
Thu, 7 Sep 2017 13:41:19 +0000 (16:41 +0300)
committerAlexander Alekhin <alexander.a.alekhin@gmail.com>
Sun, 8 Oct 2017 16:55:01 +0000 (19:55 +0300)
modules/core/include/opencv2/core/ocl.hpp
modules/core/src/ocl.cpp

index 415ec2b..c36252a 100644 (file)
@@ -613,8 +613,10 @@ public:
     String getPrefix() const;
     static String getPrefix(const String& buildflags);
 
-protected:
+
     struct Impl;
+    inline Impl* getImpl() const { return (Impl*)p; }
+protected:
     Impl* p;
 };
 
@@ -635,8 +637,9 @@ public:
     const String& source() const;
     hash_t hash() const; // deprecated
 
-protected:
     struct Impl;
+    inline Impl* getImpl() const { return (Impl*)p; }
+protected:
     Impl* p;
 };
 
index 028c2a6..1a63d7f 100644 (file)
@@ -2618,20 +2618,27 @@ internal::ProgramEntry::operator ProgramSource&() const
 struct Program::Impl
 {
     Impl(const ProgramSource& _src,
-         const String& _buildflags, String& errmsg)
+         const String& _buildflags, String& errmsg) :
+         src(_src),
+         buildflags(_buildflags),
+         handle(NULL)
     {
-        CV_INSTRUMENT_REGION_OPENCL_COMPILE(cv::format("Compile: %" PRIx64 " options: %s", _src.hash(), _buildflags.c_str()).c_str());
         refcount = 1;
-        const Context& ctx = Context::getDefault();
-        src = _src;
-        buildflags = _buildflags;
+        compile(Context::getDefault(), errmsg);
+    }
+
+    bool compile(const Context& ctx, String& errmsg)
+    {
+        CV_Assert(handle == NULL);
+        CV_INSTRUMENT_REGION_OPENCL_COMPILE(cv::format("Compile: %" PRIx64 " options: %s", src.hash(), buildflags.c_str()).c_str());
         const String& srcstr = src.source();
         const char* srcptr = srcstr.c_str();
         size_t srclen = srcstr.size();
         cl_int retval = 0;
 
         handle = clCreateProgramWithSource((cl_context)ctx.ptr(), 1, &srcptr, &srclen, &retval);
-        if( handle && retval == CL_SUCCESS )
+        CV_OclDbgAssert(handle && retval == CL_SUCCESS);
+        if (handle && retval == CL_SUCCESS)
         {
             int i, n = (int)ctx.ndevices();
             AutoBuffer<void*> deviceListBuf(n+1);
@@ -2649,26 +2656,41 @@ struct Program::Impl
                                     (const cl_device_id*)deviceList,
                                     buildflags.c_str(), 0, 0);
 #if !CV_OPENCL_ALWAYS_SHOW_BUILD_LOG
-            if( retval != CL_SUCCESS )
+            if (retval != CL_SUCCESS)
 #endif
             {
+                AutoBuffer<char, 4096> buffer; buffer[0] = 0;
+
                 size_t retsz = 0;
-                cl_int buildInfo_retval = clGetProgramBuildInfo(handle, (cl_device_id)deviceList[0],
-                                               CL_PROGRAM_BUILD_LOG, 0, 0, &retsz);
-                if (buildInfo_retval == CL_SUCCESS && retsz > 1)
+                cl_int log_retval = clGetProgramBuildInfo(handle, (cl_device_id)deviceList[0],
+                                                          CL_PROGRAM_BUILD_LOG, 0, 0, &retsz);
+                if (log_retval == CL_SUCCESS && retsz > 1)
                 {
-                    AutoBuffer<char> bufbuf(retsz + 16);
-                    char* buf = bufbuf;
-                    buildInfo_retval = clGetProgramBuildInfo(handle, (cl_device_id)deviceList[0],
-                                                   CL_PROGRAM_BUILD_LOG, retsz+1, buf, &retsz);
-                    if (buildInfo_retval == CL_SUCCESS)
+                    buffer.resize(retsz + 16);
+                    log_retval = clGetProgramBuildInfo(handle, (cl_device_id)deviceList[0],
+                                                       CL_PROGRAM_BUILD_LOG, retsz+1, (char*)buffer, &retsz);
+                    if (log_retval == CL_SUCCESS)
+                    {
+                        if (retsz < buffer.size())
+                            buffer[retsz] = 0;
+                        else
+                            buffer[buffer.size() - 1] = 0;
+                    }
+                    else
                     {
-                        // TODO It is useful to see kernel name & program file name also
-                        errmsg = String(buf);
-                        printf("OpenCL program build log: %s\n%s\n", buildflags.c_str(), errmsg.c_str());
-                        fflush(stdout);
+                        buffer[0] = 0;
                     }
                 }
+
+                errmsg = String(buffer);
+                printf("OpenCL program build log: %s (%s)\nStatus %d: %s\n%s\n%s\n",
+                        src.getImpl()->name_.c_str(), src.getImpl()->module_.c_str(),
+                        retval, getOpenCLErrorString(retval),
+                        buildflags.c_str(), errmsg.c_str());
+                fflush(stdout);
+
+                // don't remove "retval != CL_SUCCESS" condition here:
+                // it would break CV_OPENCL_ALWAYS_SHOW_BUILD_LOG mode
                 if (retval != CL_SUCCESS && handle)
                 {
                     clReleaseProgram(handle);
@@ -2676,6 +2698,7 @@ struct Program::Impl
                 }
             }
         }
+        return handle != NULL;
     }
 
     Impl(const String& _buf, const String& _buildflags)