1# Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import logging
6import os
7import re
8from autotest_lib.client.bin import test, utils
9from autotest_lib.client.common_lib import error
10from autotest_lib.client.cros.graphics import graphics_utils
11
12
13class graphics_GLAPICheck(test.test):
14    """
15    Verify correctness of OpenGL/GLES and X11 versions/extensions.
16    """
17    version = 1
18    preserve_srcdir = True
19    error_message = ''
20    GSC = None
21
22    def setup(self):
23        os.chdir(self.srcdir)
24        utils.make('clean')
25        utils.make('all')
26
27    def __check_extensions(self, info, ext_entries):
28        info_split = info.split()
29        comply = True
30        for extension in ext_entries:
31            match = extension in info_split
32            if not match:
33                self.error_message += ' ' + extension
34                comply = False
35        return comply
36
37    def __check_gl_extensions_1x(self, info):
38        extensions = [
39            'GL_ARB_vertex_buffer_object',
40            'GL_ARB_shader_objects',
41            'GL_ARB_texture_non_power_of_two',
42            'GL_ARB_point_sprite',
43            'GL_EXT_framebuffer_object',
44            'GLX_EXT_texture_from_pixmap'
45        ]
46        return self.__check_extensions(info, extensions)
47
48    def __check_gl_extensions_2x(self, info):
49        extensions = [
50            'GL_EXT_framebuffer_object',
51            'GLX_EXT_texture_from_pixmap'
52        ]
53        return self.__check_extensions(info, extensions)
54
55    def __check_gles_extensions(self, info):
56        extensions = [
57            'GL_OES_EGL_image',
58            'EGL_KHR_image'
59        ]
60        extensions2 = [
61            'GL_OES_EGL_image',
62            'EGL_KHR_image_base',
63            'EGL_KHR_image_pixmap'
64        ]
65        return (self.__check_extensions(info, extensions) or
66                self.__check_extensions(info, extensions2))
67
68    def __check_gl(self, result):
69        version = re.findall(r'GL_VERSION = ([0-9]+).([0-9]+)', result)
70        if version:
71            version_major = int(version[0][0])
72            version_minor = int(version[0][1])
73            version_info = (' GL_VERSION = %d.%d' %
74                            (version_major, version_minor))
75            if version_major == 1:
76                if version_minor < 4:
77                    self.error_message = version_info
78                    return False
79                return self.__check_gl_extensions_1x(result)
80            elif version_major >= 2:
81                return self.__check_gl_extensions_2x(result)
82            else:
83                self.error_message = version_info
84                return False
85        # No GL version info found.
86        self.error_message = ' missing GL version info'
87        return False
88
89    def __check_gles(self, result):
90        version = re.findall(r'GLES_VERSION = OpenGL ES.* ([0-9]+).([0-9]+)',
91                             result)
92        if version:
93            # GLES version has to be 2.0 or above.
94            version_major = int(version[0][0])
95            version_minor = int(version[0][1])
96            version_info = (' GLES_VERSION = %d.%d' %
97                            (version_major, version_minor))
98            if version_major < 2:
99                self.error_message = version_info
100                return False
101            # EGL version has to be 1.3 or above.
102            version = re.findall(r'EGL_VERSION = ([0-9]+).([0-9]+)', result)
103            if version:
104                version_major = int(version[0][0])
105                version_minor = int(version[0][1])
106                version_info = ('EGL_VERSION = %d.%d' %
107                                (version_major, version_minor))
108                if (version_major == 1 and version_minor >= 3 or
109                    version_major > 1):
110                    return self.__check_gles_extensions(result)
111                else:
112                    self.error_message = version_info
113                    return False
114            # No EGL version info found.
115            self.error_message = ' missing EGL version info'
116            return False
117        # No GLES version info found.
118        self.error_message = ' missing GLES version info'
119        return False
120
121    def __check_x_extensions(self, result):
122        extensions = [
123            'DAMAGE',
124            'Composite'
125        ]
126        return self.__check_extensions(result, extensions)
127
128    def __run_x_cmd(self, cmd):
129        cmd = graphics_utils.xcommand(cmd)
130        result = utils.system_output(cmd, retain_output=True,
131                                     ignore_status=True)
132        return result
133
134    def __check_wflinfo(self):
135        # TODO(ihf): Extend this function once gl(es)_APICheck code has
136        # been upstreamed to waffle.
137        version_major, version_minor = graphics_utils.get_gles_version()
138        if version_major:
139            version_info = ('GLES_VERSION = %d.%d' %
140                            (version_major, version_minor))
141            logging.info(version_info)
142            # GLES version has to be 2.0 or above.
143            if version_major < 2:
144                self.error_message = ' %s' % version_info
145                return False
146            version_major, version_minor = graphics_utils.get_egl_version()
147            if version_major:
148                version_info = ('EGL_VERSION = %d.%d' %
149                                (version_major, version_minor))
150                logging.info(version_info)
151                # EGL version has to be 1.3 or above.
152                if (version_major == 1 and version_minor >= 3 or
153                    version_major > 1):
154                    logging.warning('Please add missing extension check. '
155                                    'Details crbug.com/413079')
156                    # return self.__check_gles_extensions(wflinfo + eglinfo)
157                    return True
158                else:
159                    self.error_message = version_info
160                    return False
161            # No EGL version info found.
162            self.error_message = ' missing EGL version info'
163            return False
164        # No GLES version info found.
165        self.error_message = ' missing GLES version info'
166        return False
167
168    def initialize(self):
169        self.GSC = graphics_utils.GraphicsStateChecker()
170
171    def cleanup(self):
172        if self.GSC:
173            self.GSC.finalize()
174
175    def run_once(self):
176        if utils.is_freon():
177            if not self.__check_wflinfo():
178                raise error.TestFail('Failed: GLES API insufficient:' +
179                                     self.error_message)
180            return
181
182        # TODO(ihf): Remove this once all boards are switched to freon.
183        cmd_gl = os.path.join(self.bindir, 'gl_APICheck')
184        cmd_gles = os.path.join(self.bindir, 'gles_APICheck')
185        exist_gl = os.path.isfile(cmd_gl)
186        exist_gles = os.path.isfile(cmd_gles)
187        if not exist_gl and not exist_gles:
188            raise error.TestFail(
189                'Failed: Found neither gl_APICheck nor gles_APICheck. '
190                'Test setup error.')
191        elif exist_gl and exist_gles:
192            raise error.TestFail(
193                'Failed: Found both gl_APICheck and gles_APICheck. '
194                'Test setup error.')
195        elif exist_gl:
196            self.error_message = ''
197            result = self.__run_x_cmd(cmd_gl)
198            errors = re.findall(r'ERROR: ', result)
199            run_through = re.findall(r'SUCCEED: run to the end', result)
200            if not errors and run_through:
201                check_result = self.__check_gl(result)
202                if not check_result:
203                    raise error.TestFail('Failed: GL API insufficient:' +
204                                         self.error_message)
205            else:
206                raise error.TestFail('Failed: gl_APICheck error: ' + result)
207        else:
208            self.error_message = ''
209            # TODO(zmo@): smarter mechanism with GLES & EGL library names.
210            result = self.__run_x_cmd(cmd_gles + ' libGLESv2.so libEGL.so')
211            errors = re.findall(r'ERROR: ', result)
212            run_through = re.findall(r'SUCCEED: run to the end', result)
213            if not errors and run_through:
214                check_result = self.__check_gles(result)
215                if not check_result:
216                    raise error.TestFail('Failed: GLES API insufficient:' +
217                                         self.error_message)
218            else:
219                raise error.TestFail('Failed: gles_APICheck error: ' + result)
220
221        # Check X11 extensions.
222        self.error_message = ''
223        check_result = self.__check_x_extensions(result)
224        if not check_result:
225            raise error.TestFail('Failed: X extensions insufficient:' +
226                                 self.error_message)
227