Repository: silx-kit/silx
Issue: [opencl] Convolution tests fail

I disabled my intel drivers (which we have in CI AFAIK) and I only have the nvidia drivers enabled (debian10, python 3.7.3):

```
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 390.116                Driver Version: 390.116                   |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce GTX 580     Off  | 00000000:17:00.0 N/A |                  N/A |
| 41%   46C   P12    N/A /  N/A |    137MiB /  1474MiB |     N/A      Default |
+-------------------------------+----------------------+----------------------+
|   1  Quadro P400         Off  | 00000000:73:00.0 Off |                  N/A |
| 34%   34C    P8    N/A /  N/A |     17MiB /  1999MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+
```

Some kernels do not compile (something to do with textures according to @kif ). I'm only showing one of them:

```python
python run_tests.py silx.opencl.test.test_convolution.test_convolution

ERROR: test_1D (silx.opencl.test.test_convolution.TestConvolution)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/mntdirect/_data_id21_inhouse/wout/dev/silx/build/lib.linux-x86_64-3.7/silx/opencl/test/test_convolution.py", line 198, in test_1D
    self.template_test("test_1D")
  File "/mntdirect/_data_id21_inhouse/wout/dev/silx/build/lib.linux-x86_64-3.7/silx/opencl/test/test_convolution.py", line 176, in template_test
    conv = self.instantiate_convol(data.shape, kernel)
  File "/mntdirect/_data_id21_inhouse/wout/dev/silx/build/lib.linux-x86_64-3.7/silx/opencl/test/test_convolution.py", line 126, in instantiate_convol
    extra_options={"dont_use_textures": not(self.param["use_textures"])}
  File "/mntdirect/_data_id21_inhouse/wout/dev/silx/build/lib.linux-x86_64-3.7/silx/opencl/convolution.py", line 83, in __init__
    self._init_kernels()
  File "/mntdirect/_data_id21_inhouse/wout/dev/silx/build/lib.linux-x86_64-3.7/silx/opencl/convolution.py", line 245, in _init_kernels
    compile_options=compile_options
  File "/mntdirect/_data_id21_inhouse/wout/dev/silx/build/lib.linux-x86_64-3.7/silx/opencl/processing.py", line 265, in compile_kernels
    self.program = pyopencl.Program(self.ctx, kernel_src).build(options=compile_options)
  File "/mntdirect/_data_id21_inhouse/wout/dev/virtualenvs/lid21data/silx/py37/lib/python3.7/site-packages/pyopencl/__init__.py", line 522, in build
    options_bytes=options_bytes, source=self._source)
  File "/mntdirect/_data_id21_inhouse/wout/dev/virtualenvs/lid21data/silx/py37/lib/python3.7/site-packages/pyopencl/__init__.py", line 566, in _build_and_catch_errors
    raise err
pyopencl._cl.RuntimeError: clBuildProgram failed: BUILD_PROGRAM_FAILURE - clBuildProgram failed: BUILD_PROGRAM_FAILURE - clBuildProgram failed: BUILD_PROGRAM_FAILURE

Build on <pyopencl.Device 'GeForce GTX 580' on 'NVIDIA CUDA' at 0x15a7b30>:

<kernel>:173:31: error: no matching function for call to 'read_imagef'
        sum += READ_IMAGE_X * READ_FILTER_VAL(jx);
                              ^~~~~~~~~~~~~~~~~~~
<kernel>:99:32: note: expanded from macro 'READ_FILTER_VAL'
    #define READ_FILTER_VAL(j) READ_FILTER_1D(j)
                               ^~~~~~~~~~~~~~~~~
<kernel>:48:27: note: expanded from macro 'READ_FILTER_1D'
#define READ_FILTER_1D(j) read_imagef(filter, (int2) (FILTER_INDEX(j), 0)).x;
                          ^~~~~~~~~~~
cl_kernel.h:18365:25: note: candidate function not viable: requires 3 arguments, but 2 were provided
float4 __OVERLOADABLE__ read_imagef(image3d_t image, sampler_t sampler, float4 coord);
                        ^
cl_kernel.h:18364:25: note: candidate function not viable: requires 3 arguments, but 2 were provided
float4 __OVERLOADABLE__ read_imagef(image3d_t image, sampler_t sampler, int4 coord);
                        ^
cl_kernel.h:18363:25: note: candidate function not viable: requires 3 arguments, but 2 were provided
float4 __OVERLOADABLE__ read_imagef(image2d_t image, sampler_t sampler, float2 coord);
                        ^
cl_kernel.h:18362:25: note: candidate function not viable: requires 3 arguments, but 2 were provided
float4 __OVERLOADABLE__ read_imagef(image2d_t image, sampler_t sampler, int2 coord);
                        ^

(options: -DUSED_CONV_MODE=0 -DIMAGE_DIMS=1 -DFILTER_DIMS=1 -I /mntdirect/_data_id21_inhouse/wout/dev/virtualenvs/lid21data/silx/py37/lib/python3.7/site-packages/pyopencl/cl)
(source saved as /tmp/tmpik4ni302.cl)

======================================================================
SKIPPED: test_1D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_batched_2D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_nonseparable_2D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_nonseparable_3D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_separable_2D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_separable_3D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_1D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_batched_2D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_nonseparable_2D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_nonseparable_3D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_separable_2D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_separable_3D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_1D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_batched_2D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_nonseparable_2D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_nonseparable_3D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_separable_2D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_separable_3D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_1D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_batched_2D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_nonseparable_2D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_nonseparable_3D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_separable_2D (silx.opencl.test.test_convolution.TestConvolution)
SKIPPED: test_separable_3D (silx.opencl.test.test_convolution.TestConvolution)
----------------------------------------------------------------------
mode=constant not implemented without textures
----------------------------------------------------------------------
Ran 192 tests in 8.292s

FAILED (errors=96, skipped=24)
```

Changed files:
silx/opencl/test/test_convolution.py, silx/opencl/convolution.py

diff --git a/silx/opencl/convolution.py b/silx/opencl/convolution.py
index b8dd8f612..138b98559 100644
--- a/silx/opencl/convolution.py
+++ b/silx/opencl/convolution.py
@@ -94,6 +94,14 @@ class Convolution(OpenclProcessing):
         self.is_cpu = (self.device.type == "CPU")
         self.use_textures = not(self.extra_options["dont_use_textures"])
         self.use_textures *= not(self.is_cpu)
+        # Nvidia Fermi GPUs (compute capability 2.X) do not support opencl read_imagef
+        try:
+            cc = self.ctx.devices[0].compute_capability_major_nv
+            self.use_textures *= (cc >= 3)
+        except cl.LogicError: # probably not a Nvidia GPU
+            pass
+        except AttributeError: # probably not a Nvidia GPU
+            pass
 
     def _get_dimensions(self, shape, kernel):
         self.shape = shape
diff --git a/silx/opencl/test/test_convolution.py b/silx/opencl/test/test_convolution.py
index c21380818..27cb8a922 100644
--- a/silx/opencl/test/test_convolution.py
+++ b/silx/opencl/test/test_convolution.py
@@ -113,9 +113,18 @@ class TestConvolution(unittest.TestCase):
         )
 
     def instantiate_convol(self, shape, kernel, axes=None):
+        def is_fermi_device(dev):
+            try:
+                res = (dev.compute_capability_major_nv < 3)
+            except cl.LogicError:
+                res = False
+            except AttributeError:
+                res = False
+            return res
         if (self.mode == "constant") and (
             not(self.param["use_textures"])
                 or (self.ctx.devices[0].type == cl._cl.device_type.CPU)
+                or (is_fermi_device(self.ctx.devices[0]))
             ):
                 self.skipTest("mode=constant not implemented without textures")
         C = Convolution(